diff --git a/.flake8 b/.flake8 index da9f0bef01..eda227ab4a 100644 --- a/.flake8 +++ b/.flake8 @@ -140,15 +140,16 @@ exclude = .git, __pycache__, # submodules - components/esptool_py/esptool, components/bootloader/subproject/components/micro-ecc/micro-ecc, - components/nghttp/nghttp2, - components/libsodium/libsodium, - components/json/cJSON, - components/mbedtls/mbedtls, + components/esptool_py/esptool, components/expat/expat, + components/json/cJSON, + components/libsodium/libsodium, + components/mbedtls/mbedtls, + components/nghttp/nghttp2, + components/bt/host/nimble/nimble, components/unity/unity, - examples/build_system/cmake/import_lib/main/lib/tinyxml2 + examples/build_system/cmake/import_lib/main/lib/tinyxml2, # other third-party libraries tools/kconfig_new/kconfiglib.py, # autogenerated scripts @@ -156,6 +157,8 @@ exclude = components/protocomm/python/sec0_pb2.py, components/protocomm/python/sec1_pb2.py, components/protocomm/python/session_pb2.py, + 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/.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 }} diff --git a/.gitignore b/.gitignore index f6b52b9f04..dedb5745d9 100644 --- a/.gitignore +++ b/.gitignore @@ -58,20 +58,17 @@ 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 .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 diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 175f7b69bb..5bf113b946 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -19,10 +19,12 @@ variables: GET_SOURCES_ATTEMPTS: "10" ARTIFACT_DOWNLOAD_ATTEMPTS: "10" - # We use get-full-sources.sh script to fetch the submodules and/or re-fetch the repo - # if it was corrupted (if submodule update fails this can happen) - GIT_STRATEGY: fetch - GIT_SUBMODULE_STRATEGY: none + # GIT_STRATEGY is not defined here. + # Use an option from "CI / CD Settings" - "General pipelines". + + # "normal" strategy for fetching only top-level submodules since nothing requires the sub-submodules code for building IDF. + # If the "recursive" strategy is used we have a problem with using relative URLs for sub-submodules. + GIT_SUBMODULE_STRATEGY: normal UNIT_TEST_BUILD_SYSTEM: make # IDF environment @@ -36,19 +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" -# When 'fetch' strategy is used, Gitlab removes untracked files before checking out -# new revision. However if the new revision doesn't include some of the submodules -# which were present in the old revision, such submodule directories would not be -# removed by the checkout. This extra step ensures that these stale submodules -# are removed. -.git_clean_stale_submodules: &git_clean_stale_submodules > - find . -name '.git' -not -path './.git' -printf '%P\n' - | sed 's|/.git||' - | xargs -I {} sh -c ' - grep -q "path = {}" .gitmodules - || (echo "Removing {}, has .git directory but not in .gitmodules file" - && rm -rf {});' # before each job, we need to check if this job is filtered by bot stage/job filter .apply_bot_filter: &apply_bot_filter @@ -78,9 +70,13 @@ variables: tools/idf_tools.py --non-interactive install && eval "$(tools/idf_tools.py --non-interactive export)" || exit 1 fi +.show_submodule_urls: &show_submodule_urls | + git config --get-regexp '^submodule\..*\.url$' || true + before_script: + - echo "Running common script" + - *show_submodule_urls - source tools/ci/setup_python.sh - - *git_clean_stale_submodules # apply bot filter in before script - *apply_bot_filter # add gitlab ssh key @@ -90,2358 +86,58 @@ before_script: - 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 - - # Set IS_PRIVATE or IS_PUBLIC depending on if our branch is public or not - # - # (the same regular expressions are used to set these are used in 'only:' sections below + # Set some options and environment for CI - source tools/ci/configure_ci_environment.sh - *setup_tools_unless_target_test - *setup_custom_toolchain - # fetch the submodules (& if necessary re-fetch repo) from gitlab - - time ./tools/ci/get-full-sources.sh - # used for check scripts which we want to run unconditionally -.do_nothing_before_no_filter: - before_script: &do_nothing_before_no_filter +.before_script_lesser_nofilter: + variables: + GIT_SUBMODULE_STRATEGY: none + before_script: + - echo "Not setting up GitLab key, not fetching submodules, not applying bot filter" - source tools/ci/setup_python.sh - - *git_clean_stale_submodules + - source tools/ci/configure_ci_environment.sh - *setup_custom_toolchain # used for everything else where we want to do no prep, except for bot filter -.do_nothing_before: - before_script: &do_nothing_before - - source tools/ci/setup_python.sh - - *git_clean_stale_submodules - # apply bot filter in before script - - *apply_bot_filter +.before_script_lesser: + variables: + GIT_SUBMODULE_STRATEGY: none + before_script: - echo "Not setting up GitLab key, not fetching submodules" - - source tools/ci/configure_ci_environment.sh - - *setup_custom_toolchain - -.add_gitlab_key_before: - before_script: &add_gitlab_key_before - source tools/ci/setup_python.sh - - *git_clean_stale_submodules # apply bot filter in before script - *apply_bot_filter - - echo "Not fetching submodules" - source tools/ci/configure_ci_environment.sh - *setup_custom_toolchain - # add gitlab ssh key - - 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 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} - - 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 - # 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_template: &build_ssc_template - <<: *build_template - 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 - - 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 - -# 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_template: &build_examples_make_template - <<: *build_template - # 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 "${CI_JOB_NAME}" - -# same as above, but for CMake -.build_examples_cmake_template: &build_examples_cmake_template - <<: *build_template - 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 - 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 "${CI_JOB_NAME}" - -.build_examples_cmake_esp32_template: &build_examples_cmake_esp32_template - <<: *build_examples_cmake_template - variables: - LOG_PATH: "$CI_PROJECT_DIR/log_examples_cmake" - IDF_TARGET: "esp32" - -.build_examples_cmake_esp32s2_template: &build_examples_cmake_esp32s2_template - <<: *build_examples_cmake_template - variables: - LOG_PATH: "$CI_PROJECT_DIR/log_examples_cmake" - IDF_TARGET: "esp32s2beta" - -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_esp32_template - -build_examples_cmake_01: - <<: *build_examples_cmake_esp32_template - -build_examples_cmake_02: - <<: *build_examples_cmake_esp32_template - -build_examples_cmake_03: - <<: *build_examples_cmake_esp32_template - -build_examples_cmake_04: - <<: *build_examples_cmake_esp32_template - -build_examples_cmake_05: - <<: *build_examples_cmake_esp32_template - -build_examples_cmake_06: - <<: *build_examples_cmake_esp32_template - -build_examples_cmake_07: - <<: *build_examples_cmake_esp32_template - -build_examples_cmake_s2_00: - <<: *build_examples_cmake_esp32s2_template - -build_examples_cmake_s2_01: - <<: *build_examples_cmake_esp32s2_template - -build_examples_cmake_s2_02: - <<: *build_examples_cmake_esp32s2_template - -build_examples_cmake_s2_03: - <<: *build_examples_cmake_esp32s2_template - - -# 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 - # TODO: revert it before release esp32s2 - # - ../check_doc_warnings.sh - - cd ../zh_CN - - make gh-linkcheck - - make html - # TODO: revert it before release esp32s2 - # - ../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: *do_nothing_before_no_filter + 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 - -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 - - feature/esp32s2beta - - /^release\/v/ - - /^v\d+\.\d+(\.\d+)?($|-)/ - when: on_success - dependencies: [] - before_script: *do_nothing_before - 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: *do_nothing_before - 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 - - 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 - # 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 - - 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} - -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_examples_cmake_make: - <<: *check_job_template - except: - - master - - /^release\/v/ - - /^v\d+\.\d+(\.\d+)?($|-)/ - before_script: *do_nothing_before - 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: *do_nothing_before - 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 - before_script: *do_nothing_before - 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: +.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: *do_nothing_before - script: - - tools/ci/check_ut_cmake_make.sh - -check_submodule_sync: - <<: *check_job_template - tags: - - github_sync - variables: - GIT_STRATEGY: clone - retry: 2 - script: - # check if all submodules are correctly synced to public repostory - # disable this test temporarily because the esptool branch is on gitlab - - git submodule update --init --recursive - - git submodule - -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_00 - - build_ssc_01 - - build_ssc_02 - - 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 - - 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 - -.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_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_cmake_s2_00 - - build_examples_cmake_s2_01 - - build_examples_cmake_s2_02 - - build_examples_cmake_s2_03 - 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.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 - - cd ci-test-runner-configs - - python $CHECKOUT_REF_SCRIPT 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.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_00 - - build_ssc_01 - - build_ssc_02 - artifacts: - when: always - reports: - junit: $LOG_PATH/*/XUNIT_RESULT.xml - paths: - - $LOG_PATH - expire_in: 1 week - variables: - 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.yml" - before_script: *add_gitlab_key_before - 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 - - cd ci-test-runner-configs - - python $CHECKOUT_REF_SCRIPT ci-test-runner-configs - # clone test bench - - git clone $TEST_SCRIPT_REPOSITORY - - 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 - -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 - - cd ci-test-runner-configs - - python $CHECKOUT_REF_SCRIPT ci-test-runner-configs - # clone test bench - - git clone $TEST_SCRIPT_REPOSITORY - - cd auto_test_script - - git checkout ${CI_COMMIT_REF_NAME} || echo "Using default branch..." - # 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_01: - <<: *example_test_template - tags: - - ESP32 - - Example_WIFI - -example_test_001_02: - <<: *example_test_template - tags: - - ESP32 - - Example_WIFI - -example_test_002_01: - <<: *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_template - tags: - - ESP32 - - Example_SDIO - -example_test_004_01: - <<: *example_test_template - tags: - - ESP32 - - Example_CAN - -example_test_005_01: - <<: *example_test_template - tags: - - ESP32 - - Example_WIFI_BT - -example_test_006_01: - <<: *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_01: - <<: *example_test_template - tags: - - ESP32 - - Example_I2C_CCS811_SENSOR - -UT_001_01: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_001_02: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -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_43: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - -UT_002_01: - <<: *unit_test_template - 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: - <<: *unit_test_template - 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_004_20: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - - psram - -UT_004_21: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - - psram - -UT_004_22: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_1 - - psram - -UT_005_01: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_SDMODE - - psram - -UT_005_02: - <<: *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: - <<: *unit_test_template - 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: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_GPIO - - psram - -UT_007_01: - <<: *unit_test_template - 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: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_PCNT - - psram - -UT_008_01: - <<: *unit_test_template - 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: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_LEDC - - psram - -UT_009_01: - <<: *unit_test_template - 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: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T2_RS485 - - psram - -UT_010_01: - <<: *unit_test_template - 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: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_RMT - - psram - -UT_011_01: - <<: *unit_test_template - 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: - <<: *unit_test_template - 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: - <<: *unit_test_template - 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: - <<: *unit_test_template - tags: - - ESP32_IDF - - Example_SPI_Multi_device - - psram - -UT_014_01: - <<: *unit_test_template - 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: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T2_I2C - - psram - -UT_015_01: - <<: *unit_test_template - 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: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_MCPWM - - psram - -UT_016_01: - <<: *unit_test_template - 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: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T1_I2S - - psram - -UT_017_01: - <<: *unit_test_template - 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: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T2_1 - - psram - -UT_017_06: - <<: *unit_test_template - tags: - - ESP32_IDF - - UT_T2_1 - - 8Mpsram - -UT_017_06: - <<: *unit_test_template - 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: - <<: *test_template - 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: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T1_2 - -IT_003_01: - <<: *test_template - 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: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T1_APC - -IT_005_01: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T1_5 - -IT_005_02: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T1_5 - -IT_006_01: - <<: *test_template - 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: - <<: *test_template - 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: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T1_8 - -IT_009_01: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T1_3 - -IT_010_01: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T5_1 - -IT_011_01: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T1_MESH1 - -IT_011_02: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T2_MESH1 - -IT_011_03: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T2_MESH1 - -IT_011_04: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T3_MESH1 - -IT_011_05: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T6_MESH1 - -IT_011_06: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T12_MESH1 - -IT_011_07: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T50_MESH1 - -IT_011_08: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T1_MESH2 - -IT_012_01: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T1_9 - -IT_012_02: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T1_9 - -IT_013_01: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T2_2 - -IT_013_02: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T2_2 - -IT_014_01: - <<: *test_template - tags: - - ESP32_IDF - - SSC_T2_3 - -IT_015_01: - <<: *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/.gitmodules b/.gitmodules index 6fd2dc42dc..41265df6fb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,71 +1,81 @@ +# +# 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"] path = components/esptool_py/esptool - url = https://github.com/espressif/esptool.git + url = ../../espressif/esptool.git -[submodule "components/bt/lib"] - path = components/bt/lib - url = https://github.com/espressif/esp32-bt-lib.git +[submodule "components/bt/controller/lib"] + path = components/bt/controller/lib + url = ../../espressif/esp32-bt-lib.git [submodule "components/bootloader/subproject/components/micro-ecc/micro-ecc"] path = components/bootloader/subproject/components/micro-ecc/micro-ecc - url = https://github.com/kmackay/micro-ecc.git + url = ../../kmackay/micro-ecc.git [submodule "components/coap/libcoap"] path = components/coap/libcoap - url = https://github.com/obgm/libcoap.git + url = ../../obgm/libcoap.git [submodule "components/nghttp/nghttp2"] path = components/nghttp/nghttp2 - url = https://github.com/nghttp2/nghttp2.git + url = ../../nghttp2/nghttp2.git [submodule "components/libsodium/libsodium"] path = components/libsodium/libsodium - url = https://github.com/jedisct1/libsodium.git + url = ../../jedisct1/libsodium.git [submodule "components/spiffs/spiffs"] path = components/spiffs/spiffs - url = https://github.com/pellepl/spiffs.git + url = ../../pellepl/spiffs.git [submodule "components/json/cJSON"] path = components/json/cJSON - url = https://github.com/DaveGamble/cJSON.git + url = ../../DaveGamble/cJSON.git [submodule "components/mbedtls/mbedtls"] path = components/mbedtls/mbedtls - url = https://github.com/espressif/mbedtls.git + url = ../../espressif/mbedtls.git [submodule "components/asio/asio"] path = components/asio/asio - url = https://github.com/espressif/asio.git + url = ../../espressif/asio.git [submodule "components/expat/expat"] path = components/expat/expat - url = https://github.com/libexpat/libexpat.git + url = ../../libexpat/libexpat.git [submodule "components/lwip/lwip"] path = components/lwip/lwip - url = https://github.com/espressif/esp-lwip.git + url = ../../espressif/esp-lwip.git [submodule "components/mqtt/esp-mqtt"] path = components/mqtt/esp-mqtt - url = https://github.com/espressif/esp-mqtt.git + url = ../../espressif/esp-mqtt.git [submodule "components/protobuf-c/protobuf-c"] path = components/protobuf-c/protobuf-c - url = https://github.com/protobuf-c/protobuf-c + url = ../../protobuf-c/protobuf-c.git [submodule "components/unity/unity"] path = components/unity/unity - url = https://github.com/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 = https://github.com/leethomason/tinyxml2 + url = ../../leethomason/tinyxml2.git [submodule "components/esp_wifi/lib_esp32"] path = components/esp_wifi/lib_esp32 - url = https://github.com/espressif/esp32-wifi-lib.git + url = ../../espressif/esp32-wifi-lib.git [submodule "components/esp_wifi/lib_esp32s2beta"] path = components/esp_wifi/lib_esp32s2beta - url = https://github.com/espressif/esp32-wifi-lib.git + url = ../../espressif/esp32-wifi-lib.git + +[submodule "components/bt/host/nimble/nimble"] + path = components/bt/host/nimble/nimble + url = ../../espressif/esp-nimble.git + 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 diff --git a/CMakeLists.txt b/CMakeLists.txt index 141f903892..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() @@ -70,39 +71,13 @@ 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) - 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() - -# Establish dependencies between components -idf_build_get_property(build_components BUILD_COMPONENTS) -foreach(build_component ${build_components}) - __component_get_target(component_target ${build_component}) - __component_get_property(component_lib ${component_target} COMPONENT_LIB) - __component_get_property(reqs ${component_target} __REQUIRES) - foreach(req ${reqs}) - __component_get_property(req_lib ${req} COMPONENT_LIB) - if(TARGET ${req_lib}) - set_property(TARGET ${component_lib} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${req_lib}) - endif() - endforeach() - - get_property(type TARGET ${component_lib} PROPERTY TYPE) - if(type STREQUAL STATIC_LIBRARY) - __component_get_property(reqs ${component_target} __REQUIRES) - __component_get_property(priv_reqs ${component_target} __PRIV_REQUIRES) - foreach(req ${reqs} ${priv_reqs}) - __component_get_property(req_lib ${req} COMPONENT_LIB) - if(TARGET ${req_lib}) - set_property(TARGET ${component_lib} APPEND PROPERTY LINK_LIBRARIES ${req_lib}) - endif() - endforeach() - endif() -endforeach() diff --git a/Kconfig b/Kconfig index 3230ed9bc8..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 @@ -56,11 +57,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 @@ -70,6 +71,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 55487c9b2c..4be36b48d3 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. @@ -25,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 -r 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. @@ -41,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/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/components/app_trace/CMakeLists.txt b/components/app_trace/CMakeLists.txt index 741f4db41a..b9bcdddccc 100644 --- a/components/app_trace/CMakeLists.txt +++ b/components/app_trace/CMakeLists.txt @@ -1,34 +1,36 @@ -set(COMPONENT_SRCS "app_trace.c" - "app_trace_util.c" - "host_file_io.c" - "gcov/gcov_rtio.c") -set(COMPONENT_ADD_INCLUDEDIRS "include") +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) - 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" - "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) - 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 target_compile_options(${COMPONENT_LIB} PRIVATE "-fno-profile-arcs" "-fno-test-coverage") -target_link_libraries(${COMPONENT_LIB} gcov ${LIBC} ${LIBM} gcc) +target_link_libraries(${COMPONENT_LIB} PUBLIC gcov ${LIBC} ${LIBM} gcc) diff --git a/components/app_trace/app_trace.c b/components/app_trace/app_trace.c index 5a577a70dc..bc0d0c20b5 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,22 +372,22 @@ 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(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; } -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..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 @@ -114,7 +115,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(); @@ -124,13 +125,13 @@ void esp_gcov_dump() #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/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/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/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 25a05a8bc1..4d359ebad3 100644 --- a/components/app_trace/sys_view/Config/SEGGER_SYSVIEW_Conf.h +++ b/components/app_trace/sys_view/Config/SEGGER_SYSVIEW_Conf.h @@ -168,7 +168,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 2530fee8f9..baa7644fad 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 @@ -245,7 +245,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. @@ -317,7 +317,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; @@ -330,15 +330,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/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_trace/test/test_trace.c b/components/app_trace/test/test_trace.c index 6d95a87c55..2e19e58083 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) { @@ -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(); @@ -383,7 +343,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 +373,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; @@ -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/app_update/CMakeLists.txt b/components/app_update/CMakeLists.txt index f0aa569b51..8d0e45dbb0 100644 --- a/components/app_update/CMakeLists.txt +++ b/components/app_update/CMakeLists.txt @@ -1,15 +1,11 @@ -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) -set(COMPONENT_PRIV_REQUIRES) - -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. -target_link_libraries(${COMPONENT_LIB} "-u esp_app_desc") +target_link_libraries(${COMPONENT_LIB} INTERFACE "-u esp_app_desc") # cut PROJECT_VER and PROJECT_NAME to required 32 characters. idf_build_get_property(project_ver PROJECT_VER) @@ -34,21 +30,27 @@ 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) + add_dependencies(flash blank_ota_data) 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} --partition-table-file ${PARTITION_CSV_PATH} read_otadata) + 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} --partition-table-file ${PARTITION_CSV_PATH} erase_otadata) + COMMAND ${otatool_py} ${esptool_args} + --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 435d7535ac..4081aab976 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) ) @@ -29,17 +28,26 @@ 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) erase_otadata + $(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) read_otadata + $(OTATOOL_PY) $(ESPTOOL_ARGS) --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." all: blank_ota_data flash: blank_ota_data +ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT +encrypted-flash: blank_ota_data +endif TMP_DEFINES := $(BUILD_DIR_BASE)/app_update/tmp_cppflags.txt export TMP_DEFINES diff --git a/components/app_update/esp_ota_ops.c b/components/app_update/esp_ota_ops.c index d8574d9b55..baf4c3b861 100644 --- a/components/app_update/esp_ota_ops.c +++ b/components/app_update/esp_ota_ops.c @@ -689,12 +689,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); } @@ -717,7 +717,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/otatool.py b/components/app_update/otatool.py index aead479d92..20f69fa923 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,72 @@ 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, 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, 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 - 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 +126,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 +168,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 +183,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() + + 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 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") @@ -281,20 +254,29 @@ 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. - 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("--baud", "-b", help="baudrate to use", type=int) - parser.add_argument("--partition-table-offset", "-o", help="offset to read the partition table from", default="0x8000") + 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") 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 +284,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 +304,84 @@ 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 + + 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 + + if args.baud: + target_args["baud"] = args.baud + + 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/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/app_update/test/test_switch_ota.c b/components/app_update/test/test_switch_ota.c index 5622f1e057..f0d056d9bd 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()); @@ -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"); @@ -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) { @@ -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"); @@ -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) { @@ -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"); @@ -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" @@ -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"); @@ -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); 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 a9dbf01afe..afe1ad639b 100644 --- a/components/bootloader/CMakeLists.txt +++ b/components/bootloader/CMakeLists.txt @@ -1,14 +1,21 @@ -register_component() +idf_component_register(PRIV_REQUIRES partition_table) # Do not generate flash file when building bootloader or is in early expansion of the build if(BOOTLOADER_BUILD) return() endif() +# When secure boot is enabled, do not flash bootloader along with invocation of `idf.py flash` +if(NOT CONFIG_SECURE_BOOT_ENABLED) + set(flash_bootloader FLASH_IN_PROJECT) +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 + ${flash_bootloader} + FLASH_FILE_TEMPLATE flash_bootloader_args.in) + +esptool_py_custom_target(bootloader-flash bootloader "bootloader") +add_dependencies(bootloader partition_table) diff --git a/components/bootloader/Kconfig.projbuild b/components/bootloader/Kconfig.projbuild index 00b0f1042b..8627aa8f59 100644 --- a/components/bootloader/Kconfig.projbuild +++ b/components/bootloader/Kconfig.projbuild @@ -409,7 +409,8 @@ menu "Security features" Note: After first boot, the system will be permanently encrypted. Re-flashing an encrypted system is complicated and not always possible. - Read https://docs.espressif.com/projects/esp-idf/en/latest/security/flash-encryption.html before enabling. + Read https://docs.espressif.com/projects/esp-idf/en/latest/security/flash-encryption.html + before enabling. choice SECURE_FLASH_ENCRYPTION_KEYSIZE bool "Size of generated AES-XTS key" @@ -431,31 +432,40 @@ menu "Security features" bool "AES-256 (512-bit key)" endchoice - config SECURE_FLASH_ENC_INSECURE - bool "Allow potentially insecure options" + choice SECURE_FLASH_ENCRYPTION_MODE + bool "Enable usage mode" depends on SECURE_FLASH_ENC_ENABLED - default N + default SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT help - You can disable some of the default protections offered by flash encryption, in order to enable testing or - a custom combination of security features. + By default Development mode is enabled which allows UART bootloader to perform flash encryption operations - Only enable these options if you are very sure. + Select Release mode only for production or manufacturing. Once enabled you can not reflash using UART + bootloader Refer to https://docs.espressif.com/projects/esp-idf/en/latest/security/secure-boot.html and https://docs.espressif.com/projects/esp-idf/en/latest/security/flash-encryption.html for details. + config SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT + bool "Development(NOT SECURE)" + select SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC + + config SECURE_FLASH_ENCRYPTION_MODE_RELEASE + bool "Release" + + endchoice + menu "Potentially insecure options" - visible if SECURE_FLASH_ENC_INSECURE || SECURE_BOOT_INSECURE + visible if SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT || SECURE_BOOT_INSECURE # NOTE: Options in this menu NEED to have SECURE_BOOT_INSECURE - # and/or SECURE_FLASH_ENC_INSECURE in "depends on", as the menu + # and/or SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT in "depends on", as the menu # itself doesn't enable/disable its children (if it's not set, # it's possible for the insecure menu to be disabled but the insecure option # to remain on which is very bad.) config SECURE_BOOT_ALLOW_ROM_BASIC bool "Leave ROM BASIC Interpreter available on reset" - depends on SECURE_BOOT_INSECURE || SECURE_FLASH_ENC_INSECURE + depends on SECURE_BOOT_INSECURE || SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT default N help By default, the BASIC ROM Console starts on reset if no valid bootloader is @@ -469,7 +479,7 @@ menu "Security features" config SECURE_BOOT_ALLOW_JTAG bool "Allow JTAG Debugging" - depends on SECURE_BOOT_INSECURE || SECURE_FLASH_ENC_INSECURE + depends on SECURE_BOOT_INSECURE || SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT default N help If not set (default), the bootloader will permanently disable JTAG (across entire chip) on first boot @@ -496,7 +506,7 @@ menu "Security features" config SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC bool "Leave UART bootloader encryption enabled" - depends on SECURE_FLASH_ENC_INSECURE + depends on SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT default N help If not set (default), the bootloader will permanently disable UART bootloader encryption access on @@ -506,7 +516,7 @@ menu "Security features" config SECURE_FLASH_UART_BOOTLOADER_ALLOW_DEC bool "Leave UART bootloader decryption enabled" - depends on SECURE_FLASH_ENC_INSECURE + depends on SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT default N help If not set (default), the bootloader will permanently disable UART bootloader decryption access on @@ -517,7 +527,7 @@ menu "Security features" config SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE bool "Leave UART bootloader flash cache enabled" - depends on SECURE_FLASH_ENC_INSECURE + depends on SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT default N help If not set (default), the bootloader will permanently disable UART bootloader flash cache access on @@ -527,3 +537,4 @@ menu "Security features" endmenu # Potentially Insecure endmenu # Security features + 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/bootloader/project_include.cmake b/components/bootloader/project_include.cmake index a4faae97e3..019d1df71e 100644 --- a/components/bootloader/project_include.cmake +++ b/components/bootloader/project_include.cmake @@ -1,32 +1,10 @@ -# Do not generate flash file when building bootloader or is in early expansion of the build +set(BOOTLOADER_OFFSET 0x1000) + +# Do not generate flash file when building bootloader if(BOOTLOADER_BUILD) return() endif() -idf_build_get_property(project_dir PROJECT_DIR) - -# This is for tracking the top level project path -if(BOOTLOADER_BUILD) - set(main_project_path "${CMAKE_BINARY_DIR}/../..") -else() - set(main_project_path "${project_dir}") -endif() - -get_filename_component(secure_boot_signing_key - "${CONFIG_SECURE_BOOT_SIGNING_KEY}" - ABSOLUTE BASE_DIR "${main_project_path}") -if(NOT EXISTS ${secure_boot_signing_key}) - # If the signing key is not found, create a phony gen_secure_boot_signing_key target that - # fails the build. fail_at_build_time also touches CMakeCache.txt to cause a cmake run next time - # (to pick up a new signing key if one exists, etc.) - fail_at_build_time(gen_secure_boot_signing_key - "Secure Boot Signing Key ${CONFIG_SECURE_BOOT_SIGNING_KEY} does not exist. Generate using:" - "\tespsecure.py generate_signing_key ${CONFIG_SECURE_BOOT_SIGNING_KEY}") -else() - add_custom_target(gen_secure_boot_signing_key) -endif() - - # Glue to build the bootloader subproject binary as an external # cmake project under this one # @@ -39,37 +17,104 @@ set(bootloader_binary_files "${BOOTLOADER_BUILD_DIR}/bootloader.map" ) -# These additional files may get generated -if(CONFIG_SECURE_BOOTLOADER_REFLASHABLE) - set(bootloader_binary_files - ${bootloader_binary_files} - "${BOOTLOADER_BUILD_DIR}/bootloader-reflash-digest.bin" - "${BOOTLOADER_BUILD_DIR}/secure-bootloader-key-192.bin" - "${BOOTLOADER_BUILD_DIR}/secure-bootloader-key-256.bin" - ) +idf_build_get_property(project_dir PROJECT_DIR) + +# There are some additional processing when CONFIG_CONFIG_SECURE_SIGNED_APPS. This happens +# when either CONFIG_SECURE_BOOT_ENABLED or SECURE_BOOT_BUILD_SIGNED_BINARIES. +# For both cases, the user either sets binaries to be signed during build or not +# using CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES. +# +# Regardless, pass the main project's keys (signing/verification) to the bootloader subproject +# via config. +if(CONFIG_SECURE_SIGNED_APPS) + add_custom_target(gen_secure_boot_keys) + + if(CONFIG_SECURE_BOOT_ENABLED) + # Check that the configuration is sane + if((CONFIG_SECURE_BOOTLOADER_REFLASHABLE AND CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH) OR + (NOT CONFIG_SECURE_BOOTLOADER_REFLASHABLE AND NOT CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH)) + fail_at_build_time(bootloader "Invalid bootloader target: bad sdkconfig?") + endif() + + if(CONFIG_SECURE_BOOTLOADER_REFLASHABLE) + set(bootloader_binary_files + ${bootloader_binary_files} + "${BOOTLOADER_BUILD_DIR}/bootloader-reflash-digest.bin" + "${BOOTLOADER_BUILD_DIR}/secure-bootloader-key-192.bin" + "${BOOTLOADER_BUILD_DIR}/secure-bootloader-key-256.bin" + ) + endif() + endif() + + # Since keys are usually given relative to main project dir, get the absolute paths to the keys + # for use by the bootloader subproject. Replace the values in config with these absolute paths, + # so that bootloader subproject does not need to assume main project dir to obtain path to the keys. + if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) + get_filename_component(secure_boot_signing_key + "${CONFIG_SECURE_BOOT_SIGNING_KEY}" + ABSOLUTE BASE_DIR "${project_dir}") + + if(NOT EXISTS ${secure_boot_signing_key}) + # If the signing key is not found, create a phony gen_secure_boot_signing_key target that + # fails the build. fail_at_build_time causes a cmake run next time + # (to pick up a new signing key if one exists, etc.) + fail_at_build_time(gen_secure_boot_signing_key + "Secure Boot Signing Key ${CONFIG_SECURE_BOOT_SIGNING_KEY} does not exist. Generate using:" + "\tespsecure.py generate_signing_key ${CONFIG_SECURE_BOOT_SIGNING_KEY}") + else() + add_custom_target(gen_secure_boot_signing_key) + endif() + + set(SECURE_BOOT_SIGNING_KEY ${secure_boot_signing_key}) # needed by some other components + set(sign_key_arg "-DSECURE_BOOT_SIGNING_KEY=${secure_boot_signing_key}") + + add_dependencies(gen_secure_boot_keys gen_secure_boot_signing_key) + else() + + get_filename_component(secure_boot_verification_key + ${CONFIG_SECURE_BOOT_VERIFICATION_KEY} + ABSOLUTE BASE_DIR "${project_dir}") + + if(NOT EXISTS ${secure_boot_verification_key}) + # If the verification key is not found, create a phony gen_secure_boot_verification_key target that + # fails the build. fail_at_build_time causes a cmake run next time + # (to pick up a new verification key if one exists, etc.) + fail_at_build_time(gen_secure_boot_verification_key + "Secure Boot Verification Public Key ${CONFIG_SECURE_BOOT_VERIFICATION_KEY} does not exist." + "\tThis can be extracted from the private signing key." + "\tSee docs/security/secure-boot.rst for details.") + else() + add_custom_target(gen_secure_boot_verification_key) + endif() + + set(ver_key_arg "-DSECURE_BOOT_VERIFICATION_KEY=${secure_boot_verification_key}") + + add_dependencies(gen_secure_boot_keys gen_secure_boot_verification_key) + endif() endif() -if((NOT CONFIG_SECURE_BOOT_ENABLED) OR - CONFIG_SECURE_BOOTLOADER_REFLASHABLE OR - CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH) - idf_build_get_property(idf_path IDF_PATH) - idf_build_get_property(sdkconfig SDKCONFIG) - idf_build_get_property(idf_target IDF_TARGET) - externalproject_add(bootloader - # TODO: support overriding the bootloader in COMPONENT_PATHS - SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/subproject" - BINARY_DIR "${BOOTLOADER_BUILD_DIR}" - CMAKE_ARGS -DSDKCONFIG=${sdkconfig} -DIDF_PATH=${idf_path} -DIDF_TARGET=${idf_target} - -DSECURE_BOOT_SIGNING_KEY=${secure_boot_signing_key} - -DPYTHON_DEPS_CHECKED=1 - -DEXTRA_COMPONENT_DIRS=${CMAKE_CURRENT_LIST_DIR} - INSTALL_COMMAND "" - BUILD_ALWAYS 1 # no easy way around this... - BUILD_BYPRODUCTS ${bootloader_binary_files} - DEPENDS gen_secure_boot_signing_key - ) -else() - fail_at_build_time(bootloader "Invalid bootloader target: bad sdkconfig?") +idf_build_get_property(idf_path IDF_PATH) +idf_build_get_property(idf_target IDF_TARGET) +idf_build_get_property(sdkconfig SDKCONFIG) + +externalproject_add(bootloader + SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/subproject" + BINARY_DIR "${BOOTLOADER_BUILD_DIR}" + CMAKE_ARGS -DSDKCONFIG=${sdkconfig} -DIDF_PATH=${idf_path} -DIDF_TARGET=${idf_target} + -DPYTHON_DEPS_CHECKED=1 + -DEXTRA_COMPONENT_DIRS=${CMAKE_CURRENT_LIST_DIR} + ${sign_key_arg} ${ver_key_arg} + # 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} + ) + +if(CONFIG_SECURE_SIGNED_APPS) + add_dependencies(bootloader gen_secure_boot_keys) endif() # this is a hack due to an (annoying) shortcoming in cmake, it can't diff --git a/components/bootloader/sdkconfig.rename b/components/bootloader/sdkconfig.rename index b28f9335d3..7d2277283a 100644 --- a/components/bootloader/sdkconfig.rename +++ b/components/bootloader/sdkconfig.rename @@ -16,7 +16,7 @@ CONFIG_APP_SECURE_VERSION_SIZE_EFUSE_FIELD CONFIG_BOOTLOADER_AP CONFIG_EFUSE_SECURE_VERSION_EMULATE CONFIG_BOOTLOADER_EFUSE_SECURE_VERSION_EMULATE CONFIG_FLASH_ENCRYPTION_ENABLED CONFIG_SECURE_FLASH_ENC_ENABLED -CONFIG_FLASH_ENCRYPTION_INSECURE CONFIG_SECURE_FLASH_ENC_INSECURE +CONFIG_FLASH_ENCRYPTION_INSECURE CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT CONFIG_FLASH_ENCRYPTION_UART_BOOTLOADER_ALLOW_ENCRYPT CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC CONFIG_FLASH_ENCRYPTION_UART_BOOTLOADER_ALLOW_DECRYPT CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_DEC CONFIG_FLASH_ENCRYPTION_UART_BOOTLOADER_ALLOW_CACHE CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE diff --git a/components/bootloader/subproject/CMakeLists.txt b/components/bootloader/subproject/CMakeLists.txt index 1f39199152..c125cc5581 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}") @@ -29,8 +29,6 @@ project(bootloader) idf_build_set_property(COMPILE_DEFINITIONS "-DBOOTLOADER_BUILD=1" APPEND) idf_build_set_property(COMPILE_OPTIONS "-fno-stack-protector" APPEND) -set(secure_boot_signing_key ${SECURE_BOOT_SIGNING_KEY}) - string(REPLACE ";" " " espsecurepy "${ESPSECUREPY}") string(REPLACE ";" " " espefusepy "${ESPEFUSEPY}") set(esptoolpy_write_flash "${ESPTOOLPY_WRITE_FLASH_STR}") @@ -53,7 +51,7 @@ if(CONFIG_SECURE_BOOTLOADER_REFLASHABLE) add_custom_command(OUTPUT "${secure_bootloader_key}" COMMAND ${ESPSECUREPY} digest_private_key --keylen "${key_digest_len}" - --keyfile "${secure_boot_signing_key}" + --keyfile "${SECURE_BOOT_SIGNING_KEY}" "${secure_bootloader_key}" VERBATIM) @@ -67,7 +65,7 @@ if(CONFIG_SECURE_BOOTLOADER_REFLASHABLE) "\nTo generate one, you can use this command:" "\n\t${espsecurepy} generate_flash_encryption_key ${secure_bootloader_key}" "\nIf a signing key is present, then instead use:" - "\n\t${ESPSECUREPY} digest_private_key " + "\n\t${espsecurepy} digest_private_key " "--keylen (192/256) --keyfile KEYFILE " "${secure_bootloader_key}") endif() @@ -78,14 +76,14 @@ if(CONFIG_SECURE_BOOTLOADER_REFLASHABLE) COMMAND ${CMAKE_COMMAND} -E echo "DIGEST ${bootloader_digest_bin}" COMMAND ${ESPSECUREPY} digest_secure_bootloader --keyfile "${secure_bootloader_key}" -o "${bootloader_digest_bin}" "${CMAKE_BINARY_DIR}/bootloader.bin" - DEPENDS gen_secure_bootloader_key "${CMAKE_BINARY_DIR}/bootloader.bin" + DEPENDS gen_secure_bootloader_key gen_project_binary VERBATIM) add_custom_target (gen_bootloader_digest_bin ALL DEPENDS "${bootloader_digest_bin}") endif() if(CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH) - add_custom_command(TARGET bootloader POST_BUILD + add_custom_command(TARGET bootloader.elf POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo "==============================================================================" COMMAND ${CMAKE_COMMAND} -E echo @@ -97,9 +95,8 @@ if(CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH) COMMAND ${CMAKE_COMMAND} -E echo "* IMPORTANT: After first boot, BOOTLOADER CANNOT BE RE-FLASHED on same device" VERBATIM) - elseif(CONFIG_SECURE_BOOTLOADER_REFLASHABLE) - add_custom_command(TARGET bootloader POST_BUILD + add_custom_command(TARGET bootloader.elf POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo "==============================================================================" COMMAND ${CMAKE_COMMAND} -E echo 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 e04c31433c..82760cad09 100644 --- a/components/bootloader/subproject/main/CMakeLists.txt +++ b/components/bootloader/subproject/main/CMakeLists.txt @@ -5,4 +5,5 @@ idf_build_get_property(target IDF_TARGET) set(scripts "ld/${target}/bootloader.ld" "ld/${target}/bootloader.rom.ld") -target_linker_script(${COMPONENT_LIB} "${scripts}") +target_linker_script(${COMPONENT_LIB} INTERFACE "${scripts}") + diff --git a/components/bootloader/subproject/main/bootloader_start.c b/components/bootloader/subproject/main/bootloader_start.c index 638292fbfa..fbffa0f629 100644 --- a/components/bootloader/subproject/main/bootloader_start.c +++ b/components/bootloader/subproject/main/bootloader_start.c @@ -38,7 +38,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) { @@ -117,7 +117,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/CMakeLists.txt b/components/bootloader_support/CMakeLists.txt index 3b0ce529c2..f9ed448ab5 100644 --- a/components/bootloader_support/CMakeLists.txt +++ b/components/bootloader_support/CMakeLists.txt @@ -1,64 +1,75 @@ -set(COMPONENT_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" + "src/bootloader_flash_config_${IDF_TARGET}.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) - 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" - "src/${IDF_TARGET}/bootloader_${IDF_TARGET}.c" - "src/${IDF_TARGET}/bootloader_clock_${IDF_TARGET}.c") - - if(CONFIG_SECURE_SIGNED_APPS) - get_filename_component(secure_boot_verification_key - "signature_verification_key.bin" - ABSOLUTE BASE_DIR "${CMAKE_BINARY_DIR}") - if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) - add_custom_command(OUTPUT "${secure_boot_verification_key}" - COMMAND ${ESPSECUREPY} - extract_public_key --keyfile "${secure_boot_signing_key}" - "${secure_boot_verification_key}" - DEPENDS gen_secure_boot_signing_key - VERBATIM) - else() - get_filename_component(orig_secure_boot_verification_key - "${CONFIG_SECURE_BOOT_VERIFICATION_KEY}" - ABSOLUTE BASE_DIR "${main_project_path}") - if(NOT EXISTS ${orig_secure_boot_verification_key}) - message(FATAL_ERROR - "Secure Boot Verification Public Key ${CONFIG_SECURE_BOOT_VERIFICATION_KEY} does not exist." - "\nThis can be extracted from the private signing key." - "\nSee docs/security/secure-boot.rst for details.") - endif() - - add_custom_command(OUTPUT "${secure_boot_verification_key}" - COMMAND ${CMAKE_COMMAND} -E copy "${orig_secure_boot_verification_key}" - "${secure_boot_verification_key}" - DEPENDS "${orig_secure_boot_verification_key}" - VERBATIM) - endif() - set(COMPONENT_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 mbedtls soc) #unfortunately the header directly uses SOC registers - set(COMPONENT_PRIV_REQUIRES spi_flash efuse) +if(CONFIG_IDF_TARGET_ESP32) + # Not supported on ESP32S2Beta yet + list(APPEND srcs "src/flash_encrypt.c") endif() -register_component() \ No newline at end of file +if(BOOTLOADER_BUILD) + set(include_dirs "include" "include_bootloader") + # 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" + "src/${IDF_TARGET}/flash_encrypt.c" + "src/${IDF_TARGET}/secure_boot_signatures.c" + "src/${IDF_TARGET}/secure_boot.c" + "src/${IDF_TARGET}/bootloader_${IDF_TARGET}.c" + "src/${IDF_TARGET}/bootloader_clock_${IDF_TARGET}.c" + ) +else() + 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(priv_requires spi_flash mbedtls efuse) +endif() + +set(requires soc) #unfortunately the header directly uses SOC registers + +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS "${include_dirs}" + PRIV_INCLUDE_DIRS "${priv_include_dirs}" + REQUIRES "${requires}" + PRIV_REQUIRES "${priv_requires}") + +if(BOOTLOADER_BUILD AND CONFIG_SECURE_SIGNED_APPS) + # Whether CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES or not, we need verification key to embed + # in the library. + if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) + # We generate the key from the signing key. The signing key is passed from the main project. + get_filename_component(secure_boot_signing_key + "${SECURE_BOOT_SIGNING_KEY}" + ABSOLUTE BASE_DIR "${project_dir}") + get_filename_component(secure_boot_verification_key + "signature_verification_key.bin" + ABSOLUTE BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}") + add_custom_command(OUTPUT "${secure_boot_verification_key}" + COMMAND ${ESPSECUREPY} + extract_public_key --keyfile "${secure_boot_signing_key}" + "${secure_boot_verification_key}" + VERBATIM) + else() + # We expect to 'inherit' the verification key passed from main project. + get_filename_component(secure_boot_verification_key + ${SECURE_BOOT_VERIFICATION_KEY} + ABSOLUTE BASE_DIR "${project_dir}") + endif() + + target_add_binary_data(${COMPONENT_LIB} "${secure_boot_verification_key}" "BINARY") + set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES + "${secure_boot_verification_key}") +endif() 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/bootloader_support/include/bootloader_clock.h b/components/bootloader_support/include/bootloader_clock.h index 369f39dcde..da3bc9e646 100644 --- a/components/bootloader_support/include/bootloader_clock.h +++ b/components/bootloader_support/include/bootloader_clock.h @@ -14,6 +14,10 @@ #pragma once +#ifdef __cplusplus +extern "C" { +#endif + /** @brief Configure clocks for early boot * * Called by bootloader, or by the app if the bootloader version is old (pre v2.1). @@ -23,3 +27,8 @@ void bootloader_clock_configure(void); /** @brief Return the rated maximum frequency of this chip */ int bootloader_clock_get_rated_freq_mhz(void); + +#ifdef __cplusplus +} +#endif + diff --git a/components/bootloader_support/include/bootloader_common.h b/components/bootloader_support/include/bootloader_common.h index 2fe2aa5e0d..798a4addf8 100644 --- a/components/bootloader_support/include/bootloader_common.h +++ b/components/bootloader_support/include/bootloader_common.h @@ -16,6 +16,10 @@ #include "esp_flash_partitions.h" #include "esp_image_format.h" +#ifdef __cplusplus +extern "C" { +#endif + /// Type of hold a GPIO in low state typedef enum { GPIO_LONG_HOLD = 1, /*!< The long hold GPIO */ @@ -147,4 +151,8 @@ 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 +} +#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..98c169f48a --- /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(void); + +/** + * @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(void); + +/** + * @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/include/bootloader_random.h b/components/bootloader_support/include/bootloader_random.h index bb3b2a81dd..98a7712f33 100644 --- a/components/bootloader_support/include/bootloader_random.h +++ b/components/bootloader_support/include/bootloader_random.h @@ -16,6 +16,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + /** * @brief Enable early entropy source for RNG * @@ -47,3 +51,7 @@ void bootloader_random_disable(void); * @param length This many bytes of random data will be copied to buffer */ void bootloader_fill_random(void *buffer, size_t length); + +#ifdef __cplusplus +} +#endif diff --git a/components/bootloader_support/include/bootloader_util.h b/components/bootloader_support/include/bootloader_util.h index 30f8bd8d2c..a1b8d89c95 100644 --- a/components/bootloader_support/include/bootloader_util.h +++ b/components/bootloader_support/include/bootloader_util.h @@ -16,6 +16,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + /** * @brief Check if half-open intervals overlap * @@ -29,6 +33,11 @@ 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); } + +#ifdef __cplusplus +} +#endif 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_flash_encrypt.h b/components/bootloader_support/include/esp_flash_encrypt.h index 4abeb58d73..80603743f1 100644 --- a/components/bootloader_support/include/esp_flash_encrypt.h +++ b/components/bootloader_support/include/esp_flash_encrypt.h @@ -11,8 +11,7 @@ // 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 __ESP32_FLASH_ENCRYPT_H -#define __ESP32_FLASH_ENCRYPT_H +#pragma once #include #include "esp_attr.h" @@ -23,6 +22,18 @@ #include "soc/efuse_periph.h" #include "sdkconfig.h" +#ifdef __cplusplus +extern "C" { +#endif + +/* @brief Flash encryption mode based on efuse values +*/ +typedef enum { + ESP_FLASH_ENC_MODE_DISABLED, // flash encryption is not enabled (flash crypt cnt=0) + ESP_FLASH_ENC_MODE_DEVELOPMENT, // flash encryption is enabled but for Development (reflash over UART allowed) + ESP_FLASH_ENC_MODE_RELEASE // flash encryption is enabled for Release (reflash over UART disabled) +} esp_flash_enc_mode_t; + /** * @file esp_partition.h * @brief Support functions for flash encryption features @@ -117,8 +128,18 @@ esp_err_t esp_flash_encrypt_region(uint32_t src_addr, size_t data_length); * is enabled but secure boot is not used. This should protect against * serial re-flashing of an unauthorised code in absence of secure boot. * + */ +void esp_flash_write_protect_crypt_cnt(void); + +/** @brief Return the flash encryption mode + * + * The API is called during boot process but can also be called by + * application to check the current flash encryption mode of ESP32 + * * @return */ -void esp_flash_write_protect_crypt_cnt(); +esp_flash_enc_mode_t esp_get_flash_encryption_mode(void); +#ifdef __cplusplus +} #endif 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/bootloader_support/include/esp_image_format.h b/components/bootloader_support/include/esp_image_format.h index 7006cae98d..d0a9469d66 100644 --- a/components/bootloader_support/include/esp_image_format.h +++ b/components/bootloader_support/include/esp_image_format.h @@ -16,6 +16,11 @@ #include #include #include "esp_flash_partitions.h" +#include "esp_app_format.h" + +#ifdef __cplusplus +extern "C" { +#endif #define ESP_ERR_IMAGE_BASE 0x2000 #define ESP_ERR_IMAGE_FLASH_FAIL (ESP_ERR_IMAGE_BASE + 1) @@ -25,91 +30,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 */ @@ -240,3 +162,7 @@ typedef struct { uint32_t irom_load_addr; uint32_t irom_size; } esp_image_flash_mapping_t; + +#ifdef __cplusplus +} +#endif diff --git a/components/bootloader_support/include/esp_secure_boot.h b/components/bootloader_support/include/esp_secure_boot.h index bf0425633e..c7c8583350 100644 --- a/components/bootloader_support/include/esp_secure_boot.h +++ b/components/bootloader_support/include/esp_secure_boot.h @@ -138,7 +138,6 @@ typedef struct { uint8_t digest[64]; } esp_secure_boot_iv_digest_t; - #ifdef __cplusplus } #endif diff --git a/components/bootloader_support/include_bootloader/bootloader_flash.h b/components/bootloader_support/include_bootloader/bootloader_flash.h index ce867d7573..18baad594b 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(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 e8c642ecd1..d61f7a9432 100644 --- a/components/bootloader_support/src/bootloader_clock.c +++ b/components/bootloader_support/src/bootloader_clock.c @@ -11,14 +11,21 @@ // 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" -void bootloader_clock_configure() +#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. // 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 d0e9a9fc75..2d5674b281 100644 --- a/components/bootloader_support/src/bootloader_common.c +++ b/components/bootloader_support/src/bootloader_common.c @@ -263,7 +263,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 c58f9fa059..96121c8230 100644 --- a/components/bootloader_support/src/bootloader_flash.c +++ b/components/bootloader_support/src/bootloader_flash.c @@ -28,6 +28,11 @@ static const char *TAG = "bootloader_mmap"; static spi_flash_mmap_handle_t map; +uint32_t bootloader_mmap_get_free_pages(void) +{ + return spi_flash_mmap_get_free_pages(SPI_FLASH_MMAP_DATA); +} + const void *bootloader_mmap(uint32_t src_addr, uint32_t size) { if (map) { @@ -104,6 +109,7 @@ static const char *TAG = "bootloader_flash"; #define MMU_BLOCK0_VADDR SOC_DROM_LOW #define MMU_SIZE (0x320000) #define MMU_BLOCK50_VADDR (MMU_BLOCK0_VADDR + MMU_SIZE) +#define FLASH_READ_VADDR MMU_BLOCK50_VADDR #elif CONFIG_IDF_TARGET_ESP32S2BETA /* Use first 63 blocks in MMU for bootloader_mmap, 63th block for bootloader_flash_read @@ -111,13 +117,25 @@ static const char *TAG = "bootloader_flash"; #define MMU_BLOCK0_VADDR SOC_DROM_LOW #define MMU_SIZE (0x3f0000) #define MMU_BLOCK63_VADDR (MMU_BLOCK0_VADDR + MMU_SIZE) +#define FLASH_READ_VADDR MMU_BLOCK63_VADDR #endif +#define MMU_FREE_PAGES (MMU_SIZE / 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(void) +{ + /** + * 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) { @@ -235,9 +253,9 @@ static esp_err_t bootloader_flash_read_allow_decrypt(size_t src_addr, void *dest #endif ESP_LOGD(TAG, "mmu set block paddr=0x%08x (was 0x%08x)", map_at, current_read_mapping); #if CONFIG_IDF_TARGET_ESP32 - int e = cache_flash_mmu_set(0, 0, MMU_BLOCK50_VADDR, map_at, 64, 1); + int e = cache_flash_mmu_set(0, 0, FLASH_READ_VADDR, map_at, 64, 1); #elif CONFIG_IDF_TARGET_ESP32S2BETA - int e = Cache_Ibus_MMU_Set(DPORT_MMU_ACCESS_FLASH, MMU_BLOCK63_VADDR, map_at, 64, 1, 0); + int e = Cache_Ibus_MMU_Set(DPORT_MMU_ACCESS_FLASH, FLASH_READ_VADDR, map_at, 64, 1, 0); #endif if (e != 0) { ESP_LOGE(TAG, "cache_flash_mmu_set failed: %d\n", e); @@ -255,11 +273,7 @@ static esp_err_t bootloader_flash_read_allow_decrypt(size_t src_addr, void *dest Cache_Resume_ICache(autoload); #endif } -#if CONFIG_IDF_TARGET_ESP32 - map_ptr = (uint32_t *)(MMU_BLOCK50_VADDR + (word_src - map_at)); -#elif CONFIG_IDF_TARGET_ESP32S2BETA - map_ptr = (uint32_t *)(MMU_BLOCK63_VADDR + (word_src - map_at)); -#endif + map_ptr = (uint32_t *)(FLASH_READ_VADDR + (word_src - map_at)); dest_words[word] = *map_ptr; } return ESP_OK; diff --git a/components/bootloader_support/src/bootloader_flash_config_esp32.c b/components/bootloader_support/src/bootloader_flash_config_esp32.c new file mode 100644 index 0000000000..091727e337 --- /dev/null +++ b/components/bootloader_support/src/bootloader_flash_config_esp32.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(void) +{ + g_rom_flashchip.device_id = bootloader_read_flash_id(); +} + +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); + 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_flash_config_esp32s2beta.c b/components/bootloader_support/src/bootloader_flash_config_esp32s2beta.c new file mode 100644 index 0000000000..f6bea6cf4b --- /dev/null +++ b/components/bootloader_support/src/bootloader_flash_config_esp32s2beta.c @@ -0,0 +1,118 @@ +// 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 "string.h" +#include "sdkconfig.h" +#include "esp_err.h" +#include "esp_log.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" +#include "soc/spi_mem_reg.h" +#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() +{ + 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_CS_HOLD_TIME_V, 1, SPI_CS_HOLD_TIME_S); + SET_PERI_REG_BITS(SPI_CTRL2_REG(0), SPI_CS_SETUP_TIME_V, 0, SPI_CS_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_CS_HOLD_TIME_V, 1, SPI_CS_HOLD_TIME_S); + SET_PERI_REG_BITS(SPI_CTRL2_REG(1), SPI_CS_SETUP_TIME_V, 0, SPI_CS_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) +{ + +} + +void IRAM_ATTR bootloader_flash_dummy_config(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; //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] = 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; + } + + bootloader_configure_spi_pins(drv); +} diff --git a/components/bootloader_support/src/bootloader_init.c b/components/bootloader_support/src/bootloader_init.c index 362d550916..9456650f7e 100644 --- a/components/bootloader_support/src/bootloader_init.c +++ b/components/bootloader_support/src/bootloader_init.c @@ -70,8 +70,10 @@ #include "bootloader_common.h" #include "bootloader_clock.h" #include "bootloader_common.h" +#include "bootloader_flash_config.h" #include "flash_qio_mode.h" +#include "hal/timer_ll.h" extern int _bss_start; extern int _bss_end; @@ -80,15 +82,15 @@ extern int _data_end; 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 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); 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(); @@ -149,9 +151,6 @@ esp_err_t bootloader_init() #endif #elif CONFIG_IDF_TARGET_ESP32S2BETA DPORT_REG_CLR_BIT(DPORT_PRO_ICACHE_CTRL1_REG, DPORT_PRO_ICACHE_MASK_DROM0); -#if !CONFIG_FREERTOS_UNICORE - DPORT_REG_CLR_BIT(DPORT_APP_ICACHE_CTRL1_REG, DPORT_APP_ICACHE_MASK_DROM0); -#endif #endif if (bootloader_main() != ESP_OK) { return ESP_FAIL; @@ -159,7 +158,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. */ @@ -169,7 +168,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); #ifdef CONFIG_IDF_TARGET_ESP32 int rated_freq = bootloader_clock_get_rated_freq_mhz(); @@ -204,8 +203,8 @@ static esp_err_t bootloader_main() /* 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(); @@ -358,134 +357,11 @@ static void print_flash_info(const esp_image_header_t *phdr) #endif } -#if CONFIG_IDF_TARGET_ESP32 -#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 -#endif - -#if CONFIG_IDF_TARGET_ESP32 -#define FLASH_IO_MATRIX_DUMMY_40M 1 -#define FLASH_IO_MATRIX_DUMMY_80M 2 -#elif CONFIG_IDF_TARGET_ESP32S2BETA -#define FLASH_IO_MATRIX_DUMMY_40M 0 -#define FLASH_IO_MATRIX_DUMMY_80M 0 -#endif -#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_DIO_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] = FLASH_IO_MATRIX_DUMMY_80M; - g_rom_spiflash_dummy_len_plus[1] = FLASH_IO_MATRIX_DUMMY_80M; -#if CONFIG_IDF_TARGET_ESP32 - 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 -#elif CONFIG_IDF_TARGET_ESP32S2BETA - 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 -#endif - 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; -#if CONFIG_IDF_TARGET_ESP32 - 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 -#elif CONFIG_IDF_TARGET_ESP32S2BETA - 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 -#endif - break; - default: - break; - } -#if CONFIG_IDF_TARGET_ESP32 - 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 - } - } -#elif CONFIG_IDF_TARGET_ESP32S2BETA - bootloader_configure_spi_pins(drv); -#endif + bootloader_flash_gpio_config(pfhdr); + bootloader_flash_dummy_config(pfhdr); + bootloader_flash_cs_timing_config(); } static void uart_console_configure(void) @@ -659,7 +535,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 || CONFIG_ESP32S2_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/bootloader_utility.c b/components/bootloader_support/src/bootloader_utility.c index 374921bec7..88c50c379e 100644 --- a/components/bootloader_support/src/bootloader_utility.c +++ b/components/bootloader_support/src/bootloader_utility.c @@ -680,7 +680,7 @@ static void set_cache_and_start_app( 64, drom_page_count, 0); #endif ESP_LOGV(TAG, "rc=%d", rc); -#if !CONFIG_FREERTOS_UNICORE +#if CONFIG_IDF_TARGET_ESP32 && !CONFIG_FREERTOS_UNICORE rc = cache_flash_mmu_set(1, 0, drom_load_addr_aligned, drom_addr & MMU_FLASH_MASK, 64, drom_page_count); ESP_LOGV(TAG, "rc=%d", rc); #endif @@ -713,11 +713,11 @@ static void set_cache_and_start_app( rc = Cache_Ibus_MMU_Set(DPORT_MMU_ACCESS_FLASH, irom_load_addr & 0xffff0000, irom_addr & 0xffff0000, 64, irom_page_count, 0); #endif ESP_LOGV(TAG, "rc=%d", rc); +#if CONFIG_IDF_TARGET_ESP32 #if !CONFIG_FREERTOS_UNICORE rc = cache_flash_mmu_set(1, 0, irom_load_addr_aligned, irom_addr & MMU_FLASH_MASK, 64, irom_page_count); ESP_LOGV(TAG, "rc=%d", rc); #endif -#if CONFIG_IDF_TARGET_ESP32 DPORT_REG_CLR_BIT( DPORT_PRO_CACHE_CTRL1_REG, (DPORT_PRO_CACHE_MASK_IRAM0) | (DPORT_PRO_CACHE_MASK_IRAM1 & 0) | (DPORT_PRO_CACHE_MASK_IROM0 & 0) | DPORT_PRO_CACHE_MASK_DROM0 | @@ -730,9 +730,6 @@ static void set_cache_and_start_app( #endif #elif CONFIG_IDF_TARGET_ESP32S2BETA DPORT_REG_CLR_BIT( DPORT_PRO_ICACHE_CTRL1_REG, (DPORT_PRO_ICACHE_MASK_IRAM0) | (DPORT_PRO_ICACHE_MASK_IRAM1 & 0) | (DPORT_PRO_ICACHE_MASK_IROM0 & 0) | DPORT_PRO_ICACHE_MASK_DROM0 ); -#if !CONFIG_FREERTOS_UNICORE - DPORT_REG_CLR_BIT( DPORT_APP_ICACHE_CTRL1_REG, (DPORT_APP_ICACHE_MASK_IRAM0) | (DPORT_APP_ICACHE_MASK_IRAM1 & 0) | (DPORT_APP_ICACHE_MASK_IROM0 & 0) | DPORT_APP_ICACHE_MASK_DROM0 ); -#endif #endif #if CONFIG_IDF_TARGET_ESP32 Cache_Read_Enable(0); diff --git a/components/bootloader_support/src/esp32/bootloader_sha.c b/components/bootloader_support/src/esp32/bootloader_sha.c index 99074598cc..79862685cf 100644 --- a/components/bootloader_support/src/esp32/bootloader_sha.c +++ b/components/bootloader_support/src/esp32/bootloader_sha.c @@ -28,7 +28,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 78c40ddf97..e04b02a544 100644 --- a/components/bootloader_support/src/esp32/flash_encrypt.c +++ b/components/bootloader_support/src/esp32/flash_encrypt.c @@ -27,12 +27,18 @@ #include "esp32/rom/cache.h" #include "esp32/rom/spi_flash.h" /* TODO: Remove this */ +/* This file implements FLASH ENCRYPTION related APIs to perform + * various operations such as programming necessary flash encryption + * eFuses, detect whether flash encryption is enabled (by reading eFuse) + * and if required encrypt the partitions in flash memory + */ + 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); @@ -203,7 +209,13 @@ static esp_err_t encrypt_flash_contents(uint32_t flash_crypt_cnt, bool flash_cry /* ffs_inv shouldn't be zero, as zero implies flash_crypt_cnt == EFUSE_RD_FLASH_CRYPT_CNT (0x7F) */ uint32_t new_flash_crypt_cnt = flash_crypt_cnt + (1 << (ffs_inv - 1)); ESP_LOGD(TAG, "FLASH_CRYPT_CNT 0x%x -> 0x%x", flash_crypt_cnt, new_flash_crypt_cnt); - REG_SET_FIELD(EFUSE_BLK0_WDATA0_REG, EFUSE_FLASH_CRYPT_CNT, new_flash_crypt_cnt); + uint32_t wdata0_reg = ((new_flash_crypt_cnt & EFUSE_FLASH_CRYPT_CNT) << EFUSE_FLASH_CRYPT_CNT_S); +#ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE + ESP_LOGI(TAG, "Write protecting FLASH_CRYPT_CNT eFuse"); + wdata0_reg |= EFUSE_WR_DIS_FLASH_CRYPT_CNT; +#endif + + REG_WRITE(EFUSE_BLK0_WDATA0_REG, wdata0_reg); esp_efuse_burn_new_values(); ESP_LOGI(TAG, "Flash encryption completed"); @@ -211,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; @@ -337,14 +349,4 @@ esp_err_t esp_flash_encrypt_region(uint32_t src_addr, size_t data_length) flash_failed: ESP_LOGE(TAG, "flash operation failed: 0x%x", err); return err; -} - -void esp_flash_write_protect_crypt_cnt() -{ - uint32_t efuse_blk0 = REG_READ(EFUSE_BLK0_RDATA0_REG); - bool flash_crypt_wr_dis = efuse_blk0 & EFUSE_WR_DIS_FLASH_CRYPT_CNT; - if(!flash_crypt_wr_dis) { - REG_WRITE(EFUSE_BLK0_WDATA0_REG, EFUSE_WR_DIS_FLASH_CRYPT_CNT); - esp_efuse_burn_new_values(); - } -} +} \ No newline at end of file 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/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; } 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/bootloader_support/src/esp_image_format.c b/components/bootloader_support/src/esp_image_format.c index 5079e76801..a4375a6540 100644 --- a/components/bootloader_support/src/esp_image_format.c +++ b/components/bootloader_support/src/esp_image_format.c @@ -380,24 +380,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); + uint32_t free_page_count = bootloader_mmap_get_free_pages(); 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); + + 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: diff --git a/components/bootloader_support/src/flash_encrypt.c b/components/bootloader_support/src/flash_encrypt.c new file mode 100644 index 0000000000..d64d2fd9d7 --- /dev/null +++ b/components/bootloader_support/src/flash_encrypt.c @@ -0,0 +1,52 @@ +// 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_efuse.h" +#include "esp_efuse_table.h" +#include "esp_flash_encrypt.h" + +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); + if (!flash_crypt_cnt_wr_dis) { + esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_FLASH_CRYPT_CNT, 1); + } +} + +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; + esp_flash_enc_mode_t mode = ESP_FLASH_ENC_MODE_DEVELOPMENT; + + if (esp_flash_encryption_enabled()) { + /* Check if FLASH CRYPT CNT is write protected */ + esp_efuse_read_field_blob(ESP_EFUSE_WR_DIS_FLASH_CRYPT_CNT, &efuse_flash_crypt_cnt_wr_protected, 1); + if (efuse_flash_crypt_cnt_wr_protected) { + esp_efuse_read_field_blob(ESP_EFUSE_DISABLE_DL_CACHE, &dis_dl_cache, 1); + esp_efuse_read_field_blob(ESP_EFUSE_DISABLE_DL_ENCRYPT, &dis_dl_enc, 1); + esp_efuse_read_field_blob(ESP_EFUSE_DISABLE_DL_DECRYPT, &dis_dl_dec, 1); + /* Check if DISABLE_DL_DECRYPT, DISABLE_DL_ENCRYPT & DISABLE_DL_CACHE are set */ + if ( dis_dl_cache && dis_dl_enc && dis_dl_dec ) { + mode = ESP_FLASH_ENC_MODE_RELEASE; + } + } + } else { + mode = ESP_FLASH_ENC_MODE_DISABLED; + } + + return mode; +} diff --git a/components/bootloader_support/src/flash_qio_mode.c b/components/bootloader_support/src/flash_qio_mode.c index 3c94318d76..577994d561 100644 --- a/components/bootloader_support/src/flash_qio_mode.c +++ b/components/bootloader_support/src/flash_qio_mode.c @@ -53,7 +53,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)) @@ -68,11 +68,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); @@ -82,7 +82,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); @@ -136,7 +136,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); @@ -289,17 +289,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); } @@ -319,7 +319,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/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 d3cc277cb1..095493c1dd 100644 --- a/components/bt/CMakeLists.txt +++ b/components/bt/CMakeLists.txt @@ -1,300 +1,510 @@ if(CONFIG_BT_ENABLED) - set(COMPONENT_SRCS "bt.c") - set(COMPONENT_ADD_INCLUDEDIRS 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 COMPONENT_PRIV_INCLUDEDIRS - 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) + list(APPEND priv_include_dirs + 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 COMPONENT_ADD_INCLUDEDIRS bluedroid/api/include/api) + list(APPEND include_dirs host/bluedroid/api/include/api) - list(APPEND COMPONENT_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/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/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() + + 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 "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 -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) target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-implicit-fallthrough -Wno-unused-const-variable) endif() - target_link_libraries(${COMPONENT_LIB} "-L${CMAKE_CURRENT_LIST_DIR}/lib") - target_link_libraries(${COMPONENT_LIB} btdm_app) + 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 a15bd7dc2f..8553cc9f70 100644 --- a/components/bt/Kconfig +++ b/components/bt/Kconfig @@ -1,6 +1,5 @@ menu Bluetooth - config BT_ENABLED bool "Bluetooth" help @@ -361,988 +360,45 @@ menu Bluetooth endmenu - menuconfig BT_BLUEDROID_ENABLED - bool "Bluedroid Enable" - depends on BTDM_CTRL_HCI_MODE_VHCI - default y + choice BT_HOST + prompt "Bluetooth Host" + depends on BT_ENABLED && BTDM_CTRL_HCI_MODE_VHCI + default BT_BLUEDROID_ENABLED help - This enables the default Bluedroid Bluetooth stack + This helps to choose Bluetooth host stack - 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_GATTS_ENABLE - bool "Include GATT server module(GATTS)" - depends on BT_BLUEDROID_ENABLED && (BTDM_CTRL_MODE_BTDM || BTDM_CTRL_MODE_BLE_ONLY) - 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" + config BT_BLUEDROID_ENABLED + bool "Bluedroid - Dual-mode" help - Manually send service change indication through API esp_ble_gatts_send_service_change_indication() + This option is recommended for classic Bluetooth or for dual-mode + usecases - config BT_GATTS_SEND_SERVICE_CHANGE_AUTO - bool "GATTS automatically send service change indication" + config BT_NIMBLE_ENABLED + bool "NimBLE - BLE only" help - Let Bluedroid handle the service change indication internally + This option is recommended for BLE only usecases to save on memory 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 + menu "Bluedroid Options" + visible if BT_BLUEDROID_ENABLED - config BT_GATTC_ENABLE - bool "Include GATT client module(GATTC)" - depends on BT_BLUEDROID_ENABLED && (BTDM_CTRL_MODE_BTDM || BTDM_CTRL_MODE_BLE_ONLY) - default y - help - This option can be close when the app work only on gatt server mode + source "$IDF_PATH/components/bt/host/bluedroid/Kconfig.in" + endmenu + menu "NimBLE Options" + visible if BT_NIMBLE_ENABLED - 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) - 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) - 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/nimble/Kconfig.in" + endmenu endmenu + +menuconfig BLE_MESH + bool "ESP BLE Mesh Support" + depends on BT_BLUEDROID_ENABLED + help + 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. + +source "$IDF_PATH/components/bt/esp_ble_mesh/Kconfig.in" diff --git a/components/bt/bluedroid/btc/core/btc_task.c b/components/bt/bluedroid/btc/core/btc_task.c deleted file mode 100644 index 86d2b4a63e..0000000000 --- a/components/bt/bluedroid/btc/core/btc_task.c +++ /dev/null @@ -1,199 +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. - -#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 "osi/allocator.h" -#include "btc/btc_main.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 "btc/btc_dm.h" -#include "btc/btc_alarm.h" -#include "bta/bta_gatt_api.h" -#if CONFIG_BT_CLASSIC_ENABLED -#include "btc/btc_profile_queue.h" -#if (BTC_GAP_BT_INCLUDED == TRUE) -#include "btc_gap_bt.h" -#endif /* BTC_GAP_BT_INCLUDED == TRUE */ -#if BTC_AV_INCLUDED -#include "btc_av.h" -#include "btc_avrc.h" -#endif /* #if BTC_AV_INCLUDED */ -#if CONFIG_BT_SPP_ENABLED -#include "btc_spp.h" -#endif /* #if CONFIG_BT_SPP_ENABLED */ -#if BTC_HF_CLIENT_INCLUDED -#include "btc_hf_client.h" -#endif /* #if BTC_HF_CLIENT_INCLUDED */ -#endif /* #if CONFIG_BT_CLASSIC_ENABLED */ - - -static xTaskHandle xBtcTaskHandle = NULL; -static xQueueHandle xBtcQueue = 0; - -static 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) - [BTC_PID_GATTS] = {btc_gatts_call_handler, btc_gatts_cb_handler }, -#endif ///GATTS_INCLUDED == TRUE -#if (GATTC_INCLUDED == TRUE) - [BTC_PID_GATTC] = {btc_gattc_call_handler, btc_gattc_cb_handler }, -#endif ///GATTC_INCLUDED == TRUE -#if (GATTS_INCLUDED == TRUE || GATTC_INCLUDED == TRUE) - [BTC_PID_GATT_COMMON] = {btc_gatt_com_call_handler, NULL }, -#endif //GATTC_INCLUDED == TRUE || GATTS_INCLUDED == TRUE - [BTC_PID_GAP_BLE] = {btc_gap_ble_call_handler, btc_gap_ble_cb_handler }, - [BTC_PID_BLE_HID] = {NULL, NULL}, - [BTC_PID_SPPLIKE] = {NULL, NULL}, -#if (GATTS_INCLUDED == TRUE) - [BTC_PID_BLUFI] = {btc_blufi_call_handler, btc_blufi_cb_handler }, -#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 (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) */ - [BTC_PID_PRF_QUE] = {btc_profile_queue_handler, NULL }, -#if BTC_AV_INCLUDED - [BTC_PID_A2DP] = {btc_a2dp_call_handler, btc_a2dp_cb_handler }, - [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 - [BTC_PID_SPP] = {btc_spp_call_handler, btc_spp_cb_handler }, -#endif /* #if CONFIG_BT_SPP_ENABLED */ -#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 */ -}; - -/***************************************************************************** -** -** Function btc_task -** -** Description Process profile Task Thread. -******************************************************************************/ -static void btc_task(void *arg) -{ - btc_msg_t msg; - - 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); - } - } - } -} - -static bt_status_t btc_task_post(btc_msg_t *msg, task_post_t timeout) -{ - if (msg == NULL) { - return BT_STATUS_PARM_INVALID; - } - - if (xQueueSend(xBtcQueue, msg, timeout) != pdTRUE) { - BTC_TRACE_ERROR("Btc Post failed\n"); - return BT_STATUS_BUSY; - } - - return BT_STATUS_SUCCESS; -} - -bt_status_t btc_transfer_context(btc_msg_t *msg, void *arg, int arg_len, btc_arg_deep_copy_t copy_func) -{ - btc_msg_t lmsg; - - if (msg == NULL) { - return BT_STATUS_PARM_INVALID; - } - - BTC_TRACE_DEBUG("%s msg %u %u %u %p\n", __func__, msg->sig, msg->pid, msg->act, arg); - - memcpy(&lmsg, msg, sizeof(btc_msg_t)); - if (arg) { - lmsg.arg = (void *)osi_malloc(arg_len); - if (lmsg.arg == NULL) { - return BT_STATUS_NOMEM; - } - memset(lmsg.arg, 0x00, arg_len); //important, avoid arg which have no length - memcpy(lmsg.arg, arg, arg_len); - if (copy_func) { - copy_func(&lmsg, lmsg.arg, arg); - } - } else { - lmsg.arg = NULL; - } - - return btc_task_post(&lmsg, TASK_POST_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){ - return BT_STATUS_NOMEM; - } - btc_gap_callback_init(); -#if SCAN_QUEUE_CONGEST_CHECK - btc_adv_list_init(); -#endif - /* TODO: initial the profile_tab */ - return BT_STATUS_SUCCESS; -} - -void btc_deinit(void) -{ - vTaskDelete(xBtcTaskHandle); - vQueueDelete(xBtcQueue); -#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) { - return true; - } - return false; -} diff --git a/components/bt/bluedroid/device/controller.c b/components/bt/bluedroid/device/controller.c deleted file mode 100644 index 45ef4ea504..0000000000 --- a/components/bt/bluedroid/device/controller.c +++ /dev/null @@ -1,552 +0,0 @@ -/****************************************************************************** - * - * 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 "common/bt_target.h" -#include "common/bt_trace.h" -#include "device/bdaddr.h" -#include "stack/bt_types.h" -#include "device/controller.h" -#include "device/event_mask.h" -#include "stack/hcimsgs.h" -#include "hci/hci_layer.h" -#include "hci/hci_packet_factory.h" -#include "hci/hci_packet_parser.h" -#include "stack/btm_ble_api.h" -#include "device/version.h" -#include "osi/future.h" - -const bt_event_mask_t BLE_EVENT_MASK = { "\x00\x00\x00\x00\x00\x00\x06\x7f" }; - -#if (BLE_INCLUDED) -const bt_event_mask_t CLASSIC_EVENT_MASK = { HCI_DUMO_EVENT_MASK_EXT }; -#else -const bt_event_mask_t CLASSIC_EVENT_MASK = { HCI_LISBON_EVENT_MASK_EXT }; -#endif - -// TODO(zachoverflow): factor out into common module -const uint8_t SCO_HOST_BUFFER_SIZE = 0xff; - -#define HCI_SUPPORTED_COMMANDS_ARRAY_SIZE 64 -#define MAX_FEATURES_CLASSIC_PAGE_COUNT 3 -#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; - -static bt_bdaddr_t address; -static bt_version_t bt_version; - -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; - -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; - -static uint8_t sco_data_size; -static 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; - -static bool readable; -static bool ble_supported; -static bool simple_pairing_supported; -static bool secure_connections_supported; - -#define AWAIT_COMMAND(command) future_await(hci->transmit_command_futured(command)) - -// Module lifecycle functions - -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); - - // 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); - -#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); -#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); -#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? - response = AWAIT_COMMAND( - packet_factory->make_host_buffer_size( - L2CAP_MTU_SIZE, - SCO_HOST_BUFFER_SIZE, - L2CAP_HOST_FC_ACL_BUFS, - 10 - ) - ); - - 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); - - // 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); - - // 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, - 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, - &page_number, - &last_features_classic_page_index, - features_classic, - MAX_FEATURES_CLASSIC_PAGE_COUNT - ); - - assert(page_number == 0); - page_number++; - - // Inform the controller what page 0 features we support, based on what - // it told us it supports. We need to do this first before we request the - // 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); -#else - 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 (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; - response = AWAIT_COMMAND( - packet_factory->make_ble_write_host_support(BTM_BLE_HOST_SUPPORT, simultaneous_le_host) - ); - - 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 && - 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, - &page_number, - &last_features_classic_page_index, - features_classic, - MAX_FEATURES_CLASSIC_PAGE_COUNT - ); - - page_number++; - } - -#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); - } -#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) { - // 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); - - // 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, - &acl_data_size_ble, - &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; - } - - // 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, - ble_supported_states, - sizeof(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, - &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( - response, - &ble_resolving_list_max_size); - } - - if (HCI_LE_DATA_LEN_EXT_SUPPORTED(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(packet_factory->make_ble_read_suggested_default_data_length()); - packet_parser->parse_ble_read_suggested_default_data_length_response( - response, - &ble_suggested_default_data_length, - &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); - } -#endif - - - response = AWAIT_COMMAND(packet_factory->make_set_event_mask(&CLASSIC_EVENT_MASK)); - 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(packet_factory->make_write_default_erroneous_data_report(1)); - packet_parser->parse_generic_command_complete(response); -#endif - readable = true; - // return future_new_immediate(FUTURE_SUCCESS); - return; -} - -static void shut_down(void) -{ - readable = false; -} - -static bool get_is_ready(void) -{ - return readable; -} - -static const bt_bdaddr_t *get_address(void) -{ - assert(readable); - return &address; -} - -static const bt_version_t *get_bt_version(void) -{ - assert(readable); - return &bt_version; -} - -// TODO(zachoverflow): hide inside, move decoder inside too -static const bt_device_features_t *get_features_classic(int index) -{ - assert(readable); - assert(index < MAX_FEATURES_CLASSIC_PAGE_COUNT); - return &features_classic[index]; -} - -static uint8_t get_last_features_classic_index(void) -{ - assert(readable); - return last_features_classic_page_index; -} - -static const bt_device_features_t *get_features_ble(void) -{ - assert(readable); - assert(ble_supported); - return &features_ble; -} - -static const uint8_t *get_ble_supported_states(void) -{ - assert(readable); - assert(ble_supported); - return ble_supported_states; -} - -static bool supports_simple_pairing(void) -{ - assert(readable); - return simple_pairing_supported; -} - -static bool supports_secure_connections(void) -{ - assert(readable); - return secure_connections_supported; -} - -static bool supports_simultaneous_le_bredr(void) -{ - assert(readable); - return HCI_SIMUL_LE_BREDR_SUPPORTED(features_classic[0].as_array); -} - -static bool supports_reading_remote_extended_features(void) -{ - assert(readable); - return HCI_READ_REMOTE_EXT_FEATURES_SUPPORTED(supported_commands); -} - -static bool supports_interlaced_inquiry_scan(void) -{ - assert(readable); - return HCI_LMP_INTERLACED_INQ_SCAN_SUPPORTED(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); -} - -static bool supports_extended_inquiry_response(void) -{ - assert(readable); - return HCI_EXT_INQ_RSP_SUPPORTED(features_classic[0].as_array); -} - -static bool supports_master_slave_role_switch(void) -{ - assert(readable); - return HCI_SWITCH_SUPPORTED(features_classic[0].as_array); -} - -static bool supports_ble(void) -{ - assert(readable); - return ble_supported; -} - -static bool supports_ble_privacy(void) -{ - assert(readable); - assert(ble_supported); - return HCI_LE_ENHANCED_PRIVACY_SUPPORTED(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); -} - -static bool supports_ble_connection_parameters_request(void) -{ - assert(readable); - assert(ble_supported); - return HCI_LE_CONN_PARAM_REQ_SUPPORTED(features_ble.as_array); -} - -static uint16_t get_acl_data_size_classic(void) -{ - assert(readable); - return acl_data_size_classic; -} - -static uint16_t get_acl_data_size_ble(void) -{ - assert(readable); - assert(ble_supported); - return acl_data_size_ble; -} - -static uint16_t get_acl_packet_size_classic(void) -{ - assert(readable); - return 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; -} - -static uint16_t get_ble_suggested_default_data_length(void) -{ - assert(readable); - assert(ble_supported); - return 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; -} - -static uint16_t get_acl_buffer_count_classic(void) -{ - assert(readable); - return acl_buffer_count_classic; -} - -static uint8_t get_acl_buffer_count_ble(void) -{ - assert(readable); - assert(ble_supported); - return acl_buffer_count_ble; -} - -static uint8_t get_ble_white_list_size(void) -{ - assert(readable); - assert(ble_supported); - return 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; -} - -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; -} - -#if (BTM_SCO_HCI_INCLUDED == TRUE) -static uint8_t get_sco_data_size(void) -{ - assert(readable); - return sco_data_size; -} - -static uint8_t get_sco_buffer_count(void) -{ - assert(readable); - return sco_buffer_count; -} -#endif /* (BTM_SCO_HCI_INCLUDED == TRUE) */ - -static const controller_t interface = { - start_up, - shut_down, - get_is_ready, - - get_address, - get_bt_version, - - get_features_classic, - get_last_features_classic_index, - - get_features_ble, - get_ble_supported_states, - - supports_simple_pairing, - supports_secure_connections, - supports_simultaneous_le_bredr, - supports_reading_remote_extended_features, - supports_interlaced_inquiry_scan, - supports_rssi_with_inquiry_results, - supports_extended_inquiry_response, - supports_master_slave_role_switch, - - supports_ble, - supports_ble_packet_extension, - supports_ble_connection_parameters_request, - supports_ble_privacy, - - get_acl_data_size_classic, - get_acl_data_size_ble, - - get_acl_packet_size_classic, - get_acl_packet_size_ble, - get_ble_suggested_default_data_length, - get_ble_suggested_default_data_txtime, - - get_acl_buffer_count_classic, - get_acl_buffer_count_ble, - - get_ble_white_list_size, - - get_ble_resolving_list_max_size, - set_ble_resolving_list_max_size, -#if (BTM_SCO_HCI_INCLUDED == TRUE) - get_sco_data_size, - get_sco_buffer_count, -#endif /* (BTM_SCO_HCI_INCLUDED == TRUE) */ -}; - -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(); - } - - return &interface; -} - diff --git a/components/bt/bluedroid/osi/include/osi/thread.h b/components/bt/bluedroid/osi/include/osi/thread.h deleted file mode 100644 index bad1e48809..0000000000 --- a/components/bt/bluedroid/osi/include/osi/thread.h +++ /dev/null @@ -1,115 +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. - -#ifndef __THREAD_H__ -#define __THREAD_H__ - -#include "freertos/xtensa_api.h" -#include "freertos/FreeRTOSConfig.h" -#include "freertos/FreeRTOS.h" -#include "freertos/queue.h" -#include "freertos/task.h" -#include "esp_task.h" -#include "common/bt_defs.h" - -#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; - -typedef bt_status_t (* BtTaskCb_t)(void *arg); - -typedef enum { - SIG_HCI_HAL_RECV_PACKET = 0, - SIG_HCI_HAL_NUM, -} SIG_HCI_HAL_t; - - -typedef enum { - SIG_HCI_HOST_SEND_AVAILABLE = 0, - SIG_HCI_HOST_NUM, -} SIG_HCI_HOST_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; - -#define TASK_PINNED_TO_CORE (CONFIG_BT_BLUEDROID_PINNED_TO_CORE < portNUM_PROCESSORS ? CONFIG_BT_BLUEDROID_PINNED_TO_CORE : tskNO_AFFINITY) - -#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 - -#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 - -#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 - -#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); - -#endif /* __THREAD_H__ */ 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 89% rename from components/bt/bluedroid/btc/core/btc_manage.c rename to components/bt/common/btc/core/btc_manage.c index 81ecad4103..6c96be3cc4 100644 --- a/components/bt/bluedroid/btc/core/btc_manage.c +++ b/components/bt/common/btc/core/btc_manage.c @@ -14,12 +14,13 @@ #include "btc/btc_task.h" -#include "common/bt_trace.h" #include "osi/thread.h" -#include "esp_bt_defs.h" -#include "esp_gatt_defs.h" -static void *btc_profile_cb_tab[BTC_PID_NUM] = {}; +#if BTC_DYNAMIC_MEMORY == 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/common/btc/core/btc_task.c b/components/bt/common/btc/core/btc_task.c new file mode 100644 index 0000000000..4ac156555b --- /dev/null +++ b/components/bt/common/btc/core/btc_task.c @@ -0,0 +1,368 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include "btc/btc_task.h" +#include "osi/thread.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" +#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" +#if CLASSIC_BT_INCLUDED +#include "btc/btc_profile_queue.h" +#if (BTC_GAP_BT_INCLUDED == TRUE) +#include "btc_gap_bt.h" +#endif /* BTC_GAP_BT_INCLUDED == TRUE */ +#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" +#endif /* #if (BTC_SPP_INCLUDED == TRUE) */ +#if BTC_HF_CLIENT_INCLUDED +#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" +#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 +#define BTC_TASK_NAME "btcT" +#define BTC_TASK_PRIO (BT_TASK_MAX_PRIORITIES - 6) + +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) + [BTC_PID_GATTS] = {btc_gatts_call_handler, btc_gatts_cb_handler }, +#endif ///GATTS_INCLUDED == TRUE +#if (GATTC_INCLUDED == TRUE) + [BTC_PID_GATTC] = {btc_gattc_call_handler, btc_gattc_cb_handler }, +#endif ///GATTC_INCLUDED == TRUE +#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) + [BTC_PID_BLUFI] = {btc_blufi_call_handler, btc_blufi_cb_handler }, +#endif ///GATTS_INCLUDED == TRUE + [BTC_PID_DM_SEC] = {NULL, btc_dm_sec_cb_handler }, + [BTC_PID_ALARM] = {btc_alarm_handler, NULL }, +#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) */ + [BTC_PID_PRF_QUE] = {btc_profile_queue_handler, NULL }, +#if BTC_AV_INCLUDED + [BTC_PID_A2DP] = {btc_a2dp_call_handler, btc_a2dp_cb_handler }, + [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 (BTC_SPP_INCLUDED == TRUE) + [BTC_PID_SPP] = {btc_spp_call_handler, btc_spp_cb_handler }, +#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 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}, + [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 */ +}; + +/***************************************************************************** +** +** Function btc_task +** +** Description Process profile Task Thread. +******************************************************************************/ +static void btc_thread_handler(void *arg) +{ + btc_msg_t *msg = (btc_msg_t *)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, uint32_t timeout) +{ + btc_msg_t *lmsg; + + lmsg = (btc_msg_t *)osi_malloc(sizeof(btc_msg_t)); + if (lmsg == NULL) { + return BT_STATUS_NOMEM; + } + + memcpy(lmsg, msg, sizeof(btc_msg_t)); + + if (osi_thread_post(btc_thread, btc_thread_handler, lmsg, 0, timeout) == false) { + return BT_STATUS_BUSY; + } + + return BT_STATUS_SUCCESS; +} + +bt_status_t btc_transfer_context(btc_msg_t *msg, void *arg, int arg_len, btc_arg_deep_copy_t copy_func) +{ + btc_msg_t lmsg; + + if (msg == NULL) { + return BT_STATUS_PARM_INVALID; + } + + BTC_TRACE_DEBUG("%s msg %u %u %u %p\n", __func__, msg->sig, msg->pid, msg->act, arg); + + memcpy(&lmsg, msg, sizeof(btc_msg_t)); + if (arg) { + lmsg.arg = (void *)osi_malloc(arg_len); + if (lmsg.arg == NULL) { + return BT_STATUS_NOMEM; + } + memset(lmsg.arg, 0x00, arg_len); //important, avoid arg which have no length + memcpy(lmsg.arg, arg, arg_len); + if (copy_func) { + copy_func(&lmsg, lmsg.arg, arg); + } + } else { + lmsg.arg = NULL; + } + + return btc_task_post(&lmsg, OSI_THREAD_MAX_TIMEOUT); + +} + +#if BTC_DYNAMIC_MEMORY + +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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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_cb_ptr = (btc_rc_cb_t *)osi_malloc(sizeof(btc_rc_cb_t))) == NULL) { + goto error_exit; + } + 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) { + 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; +} +#endif ///BTC_DYNAMIC_MEMORY + +int btc_init(void) +{ + 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; + } + +#if BTC_DYNAMIC_MEMORY + if (btc_init_mem() != BT_STATUS_SUCCESS){ + return BT_STATUS_NOMEM; + } +#endif + +#if (BLE_INCLUDED == TRUE) + btc_gap_callback_init(); +#endif ///BLE_INCLUDED == TRUE + +#if SCAN_QUEUE_CONGEST_CHECK + btc_adv_list_init(); +#endif + /* TODO: initial the profile_tab */ + return BT_STATUS_SUCCESS; +} + +void btc_deinit(void) +{ +#if BTC_DYNAMIC_MEMORY + btc_deinit_mem(); +#endif + + osi_thread_free(btc_thread); + btc_thread = NULL; + +#if SCAN_QUEUE_CONGEST_CHECK + btc_adv_list_deinit(); +#endif +} + +bool btc_check_queue_is_congest(void) +{ + if (osi_thread_queue_wait_size(btc_thread, 0) >= 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 88% rename from components/bt/bluedroid/btc/include/btc/btc_manage.h rename to components/bt/common/btc/include/btc/btc_manage.h index 46f746e8df..48ba1c5e10 100644 --- a/components/bt/bluedroid/btc/include/btc/btc_manage.h +++ b/components/bt/common/btc/include/btc/btc_manage.h @@ -19,6 +19,11 @@ #include "btc/btc_task.h" #include "esp_bt_defs.h" +#if BTC_DYNAMIC_MEMORY == 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/include/btc/btc_task.h b/components/bt/common/btc/include/btc/btc_task.h similarity index 82% rename from components/bt/bluedroid/btc/include/btc/btc_task.h rename to components/bt/common/btc/include/btc/btc_task.h index 2ea76c1772..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 @@ -53,17 +56,29 @@ 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 */ +#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/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 93% rename from components/bt/bluedroid/osi/alarm.c rename to components/bt/common/osi/alarm.c index 5307010590..c8bfc83ab7 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,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 +81,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 +110,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: @@ -251,12 +267,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 56% rename from components/bt/bluedroid/osi/allocator.c rename to components/bt/common/osi/allocator.c index 866ccc2e26..4d10e10f47 100644 --- a/components/bt/bluedroid/osi/allocator.c +++ b/components/bt/common/osi/allocator.c @@ -18,13 +18,14 @@ #include #include -#include "common/bt_defs.h" +#include "bt_common.h" #include "osi/allocator.h" 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 { @@ -35,8 +36,16 @@ 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_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) { @@ -49,7 +58,13 @@ void osi_mem_dbg_init(void) mem_dbg_info[i].line = 0; } mem_dbg_count = 0; - mem_dbg_count2 = 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) @@ -75,6 +90,19 @@ 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_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; + } + } + } } void osi_mem_dbg_clean(void *p, const char *func, int line) @@ -88,6 +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_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; @@ -112,6 +141,60 @@ 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_current_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_current_size(void) +{ + 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 @@ -130,48 +213,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/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..b1dcfeca56 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) @@ -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) { diff --git a/components/bt/bluedroid/osi/fixed_queue.c b/components/bt/common/osi/fixed_queue.c similarity index 83% rename from components/bt/bluedroid/osi/fixed_queue.c rename to components/bt/common/osi/fixed_queue.c index 30290060aa..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" @@ -129,45 +127,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 +146,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/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 85% rename from components/bt/bluedroid/osi/include/osi/allocator.h rename to components/bt/common/osi/include/osi/allocator.h index 3be366e76a..579f2b2bb6 100644 --- a/components/bt/bluedroid/osi/include/osi/allocator.h +++ b/components/bt/common/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,19 @@ 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); +uint32_t osi_mem_dbg_get_max_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 CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST +#if HEAP_ALLOCATION_FROM_SPIRAM_FIRST #define osi_malloc(size) \ ({ \ void *p; \ @@ -68,15 +72,15 @@ 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; \ }) -#endif /* #if CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST */ +#endif /* #if HEAP_ALLOCATION_FROM_SPIRAM_FIRST */ #if 0 @@ -84,11 +88,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 +101,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 +122,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/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 84% rename from components/bt/bluedroid/osi/include/osi/fixed_queue.h rename to components/bt/common/osi/include/osi/fixed_queue.h index 5ec0c07498..a25e60393c 100644 --- a/components/bt/bluedroid/osi/include/osi/fixed_queue.h +++ b/components/bt/common/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/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 95% rename from components/bt/bluedroid/osi/include/osi/mutex.h rename to components/bt/common/osi/include/osi/mutex.h index 65180a7850..1b9784d62b 100644 --- a/components/bt/bluedroid/osi/include/osi/mutex.h +++ b/components/bt/common/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/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/common/osi/include/osi/thread.h b/components/bt/common/osi/include/osi/thread.h new file mode 100644 index 0000000000..f6616a6c23 --- /dev/null +++ b/components/bt/common/osi/include/osi/thread.h @@ -0,0 +1,92 @@ +// 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 __THREAD_H__ +#define __THREAD_H__ + +#include "freertos/xtensa_api.h" +#include "freertos/FreeRTOSConfig.h" +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "freertos/task.h" +#include "osi/semaphore.h" +#include "esp_task.h" +#include "bt_common.h" + +#define portBASE_TYPE int + +#define OSI_THREAD_MAX_TIMEOUT OSI_SEM_MAX_TIMEOUT + +struct osi_thread; + +typedef struct osi_thread osi_thread_t; + +typedef void (*osi_thread_func_t)(void *context); + +typedef enum { + OSI_THREAD_CORE_0 = 0, + OSI_THREAD_CORE_1, + OSI_THREAD_CORE_AFFINITY, +} osi_thread_core_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); + +/* + * 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/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/common/osi/thread.c b/components/bt/common/osi/thread.c new file mode 100644 index 0000000000..04583061c3 --- /dev/null +++ b/components/bt/common/osi/thread.c @@ -0,0 +1,278 @@ +/****************************************************************************** + * + * 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_dequeue(thread->work_queues[idx], 0); + 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, uint32_t timeout) +{ + 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 (fixed_queue_enqueue(thread->work_queues[queue_idx], item, timeout) == 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/component.mk b/components/bt/component.mk index b77e8f6640..2e7148d22e 100644 --- a/components/bt/component.mk +++ b/components/bt/component.mk @@ -3,130 +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 +COMPONENT_ADD_INCLUDEDIRS += host/bluedroid/api/include/api \ + common/osi/include + +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 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 97% rename from components/bt/bt.c rename to components/bt/controller/bt.c index 2c665f20ac..0453a102e4 100644 --- a/components/bt/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); @@ -234,10 +235,14 @@ extern uint32_t _data_end_btdm_rom; extern uint32_t _bt_bss_start; extern uint32_t _bt_bss_end; +extern uint32_t _nimble_bss_start; +extern uint32_t _nimble_bss_end; extern uint32_t _btdm_bss_start; extern uint32_t _btdm_bss_end; extern uint32_t _bt_data_start; extern uint32_t _bt_data_end; +extern uint32_t _nimble_data_start; +extern uint32_t _nimble_data_end; extern uint32_t _btdm_data_start; extern uint32_t _btdm_data_end; @@ -889,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)) { @@ -896,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) @@ -1045,6 +1058,19 @@ esp_err_t esp_bt_mem_release(esp_bt_mode_t mode) ESP_LOGD(BTDM_LOG_TAG, "Release BT Data [0x%08x] - [0x%08x]", mem_start, mem_end); ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); } + + mem_start = (intptr_t)&_nimble_bss_start; + mem_end = (intptr_t)&_nimble_bss_end; + if (mem_start != mem_end) { + ESP_LOGD(BTDM_LOG_TAG, "Release NimBLE BSS [0x%08x] - [0x%08x]", mem_start, mem_end); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } + mem_start = (intptr_t)&_nimble_data_start; + mem_end = (intptr_t)&_nimble_data_end; + if (mem_start != mem_end) { + ESP_LOGD(BTDM_LOG_TAG, "Release NimBLE Data [0x%08x] - [0x%08x]", mem_start, mem_end); + ESP_ERROR_CHECK(try_heap_caps_add_region(mem_start, mem_end)); + } } return ESP_OK; } @@ -1311,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); @@ -1449,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 new file mode 160000 index 0000000000..717f0c6ec7 --- /dev/null +++ b/components/bt/controller/lib @@ -0,0 +1 @@ +Subproject commit 717f0c6ec71a016a0b292acffeacf239d007b8ff 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/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 new file mode 100644 index 0000000000..2a5253f907 --- /dev/null +++ b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_common_api.c @@ -0,0 +1,70 @@ +// 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 + +#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/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 new file mode 100644 index 0000000000..50e49b80ab --- /dev/null +++ b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_local_data_operation_api.c @@ -0,0 +1,80 @@ +// 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 +#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/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 new file mode 100644 index 0000000000..4d93f809ef --- /dev/null +++ b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_low_power_api.c @@ -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. + +#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/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 new file mode 100644 index 0000000000..721999bb0e --- /dev/null +++ b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_networking_api.c @@ -0,0 +1,338 @@ +// 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 +#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/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 new file mode 100644 index 0000000000..b8f12244eb --- /dev/null +++ b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_provisioning_api.c @@ -0,0 +1,423 @@ +// 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 + +#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/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 new file mode 100644 index 0000000000..4d25a656f4 --- /dev/null +++ b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_proxy_api.c @@ -0,0 +1,65 @@ +// 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 + +#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/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 new file mode 100644 index 0000000000..7f48436685 --- /dev/null +++ b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_common_api.h @@ -0,0 +1,37 @@ +// 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_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/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 new file mode 100644 index 0000000000..a1b0ff00de --- /dev/null +++ b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_local_data_operation_api.h @@ -0,0 +1,107 @@ +// 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_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. + * + * @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. + * + * @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. + * + * @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/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 new file mode 100644 index 0000000000..48238c5eba --- /dev/null +++ b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_low_power_api.h @@ -0,0 +1,20 @@ +// 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_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/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 new file mode 100644 index 0000000000..ae51b60818 --- /dev/null +++ b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_networking_api.h @@ -0,0 +1,265 @@ +// 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_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. + * + * @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/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 new file mode 100644 index 0000000000..a5a4256f44 --- /dev/null +++ b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_provisioning_api.h @@ -0,0 +1,314 @@ +// 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_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. + * + * @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/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 new file mode 100644 index 0000000000..cb67b96a0d --- /dev/null +++ b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_proxy_api.h @@ -0,0 +1,53 @@ +// 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_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. + * + * @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. + * + * @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. + * + * @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/esp_ble_mesh/api/esp_ble_mesh_defs.h b/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h new file mode 100644 index 0000000000..e72faf95e7 --- /dev/null +++ b/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h @@ -0,0 +1,1567 @@ +// 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_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" + +/*!< 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 */ +#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) + +/*!< 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 { + 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; + +/*!< 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) + +/*!< 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 struct 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; + + const uint8_t sig_model_count; /*!< SIG Model count */ + const uint8_t vnd_model_count; /*!< Vendor Model count */ + + esp_ble_mesh_model_t *sig_models; /*!< SIG Models */ + esp_ble_mesh_model_t *vnd_models; /*!< Vendor Models */ +} esp_ble_mesh_elem_t; + +/** Abstraction that describes a model publication context. + * This structure is associated with struct bt_mesh_model_pub in mesh_access.h + */ +typedef struct { + /** 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. */ + + 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; + + /** 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 */ + uint8_t dev_role; + + /** Publish Period Timer. Initialized by the stack. */ + 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, \ + } + +/** @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, \ + .min_len = _min_len, \ + .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; /*!< 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 + * 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 struct 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 struct 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 struct 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; + + /** 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 */ + 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; + + /** 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 */ + 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; + + /** 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 */ + uint8_t *prov_static_oob_val; + /** Provisioner static oob value length */ + uint8_t prov_static_oob_len; + + /** 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 */ + uint8_t flags; + + /** IV index */ + uint32_t iv_index; + + /** 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 data context. + * This structure is associated with struct bt_mesh_comp in mesh_access.h + */ +typedef struct { + 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; /*!< 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 */ +} 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) /*!< 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; /*!< 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; /*!< 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; /*!< Device address */ + esp_ble_addr_type_t addr_type; /*!< Device address type */ + }; + uint8_t uuid[16]; /*!< 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; /*!< NetKey Index */ + uint8_t flags; /*!< Flags */ + uint32_t iv_index; /*!< 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 */ +} 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, + FAST_PROV_ACT_SUSPEND, + FAST_PROV_ACT_EXIT, + 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 */ + 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; + +/*!< 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 */ + 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; + +/** + * @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; /*!< 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; /*!< 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; /*!< 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; /*!< 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; /*!< 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; /*!< 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; /*!< 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]; /*!< 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; /*!< 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; /*!< 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; /*!< 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; /*!< 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; /*!< 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; /*!< 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; /*!< 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; /*!< 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; /*!< 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]; /*!< 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; /*!< 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; /*!< 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; /*!< 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; /*!< 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; /*!< 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; /*!< 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]; /*!< String output by the Provisioner */ + uint32_t number; /*!< Number output by the Provisioner */ + }; + } 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; /*!< 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; /*!< 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; /*!< 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; /*!< 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; /*!< 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; /*!< 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; /*!< 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; /*!< 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; /*!< 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; /*!< 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; /*!< 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; /*!< 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; /*!< 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; /*!< 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; /*!< 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; /*!< 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; /*!< 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 + */ + struct ble_mesh_model_publish_comp_param { + 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; /*!< 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; /*!< 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 + */ + struct ble_mesh_model_publish_update_evt_param { + 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; + +/** Client Model user data context. */ +typedef struct { + 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; /*!< 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; + +#endif /* _ESP_BLE_MESH_DEFS_H_ */ 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 new file mode 100644 index 0000000000..593927ff2f --- /dev/null +++ b/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_config_model_api.c @@ -0,0 +1,82 @@ +// 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 + +#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/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 new file mode 100644 index 0000000000..fdf1f72d63 --- /dev/null +++ b/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_generic_model_api.c @@ -0,0 +1,75 @@ +// 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 + +#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/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 new file mode 100644 index 0000000000..cdbdb04ac4 --- /dev/null +++ b/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_health_model_api.c @@ -0,0 +1,98 @@ +// 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 + +#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/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 new file mode 100644 index 0000000000..83f0c98b5b --- /dev/null +++ b/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_lighting_model_api.c @@ -0,0 +1,76 @@ +// 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 + +#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/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 new file mode 100644 index 0000000000..20ae8bdd5e --- /dev/null +++ b/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_sensor_model_api.c @@ -0,0 +1,76 @@ +// 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 + +#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/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 new file mode 100644 index 0000000000..88c27cea98 --- /dev/null +++ b/components/bt/esp_ble_mesh/api/models/esp_ble_mesh_time_scene_model_api.c @@ -0,0 +1,76 @@ +// 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 + +#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/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 new file mode 100644 index 0000000000..66f1d17d4a --- /dev/null +++ b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_config_model_api.h @@ -0,0 +1,711 @@ +// 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_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) + +/** Configuration Server Model context */ +typedef struct esp_ble_mesh_cfg_srv { + 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 */ + + /** Heartbeat Publication */ + struct { + struct k_delayed_work timer; /*!< Heartbeat Publication timer */ + + 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; /*!< Timestamp when Heartbeat subscription period is expired */ + + 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 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 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 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 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 Config AppKey Get. */ +typedef struct { + uint16_t net_idx; /*!< The network key index */ +} esp_ble_mesh_cfg_app_key_get_t; + +/** 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 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 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 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 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 Config Beacon Set. */ +typedef struct { + uint8_t beacon; /*!< New Secure Network Beacon state */ +} esp_ble_mesh_cfg_beacon_set_t; + +/** 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 Config Friend Set. */ +typedef struct { + uint8_t friend_state; /*!< The friend state value */ +} esp_ble_mesh_cfg_friend_set_t; + +/** 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 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 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 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 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 */ + 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 Config 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 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 */ + 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 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 */ + 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 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 */ + 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 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 */ + 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 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 */ + 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 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 */ + 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 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 */ + 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 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 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 Config NetKey Delete. */ +typedef struct { + uint16_t net_idx; /*!< The network key index */ +} esp_ble_mesh_cfg_net_key_delete_t; + +/** 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 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 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 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 */ + 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 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 Config Network Transmit Set. */ +typedef struct { + uint8_t net_transmit; /*!< Network Transmit State */ +} esp_ble_mesh_cfg_net_transmit_set_t; + +/** Parameters of Config Model Heartbeat Publication Set. */ +typedef struct { + 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 Config Model Heartbeat Subscription Set. */ +typedef struct { + 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; + +/** + * @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; + +/** 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 */ + 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; + +/** 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 */ + 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; + +/** 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 */ + 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; + +/** 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 */ + 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; + +/** 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 */ + 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; + +/** 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 */ + 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; + +/** 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 */ +} 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 */ + 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; + +/** 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, + 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; + +/** Parameter of Config AppKey Add */ +typedef struct { + 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_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, +} esp_ble_mesh_cfg_server_cb_event_t; + +/** + * @brief Bluetooth Mesh Config Client and Server Model functions. + */ + +/** + * @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 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); + +/** + * @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 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. + * 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 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. + * 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/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 new file mode 100644 index 0000000000..e34c706302 --- /dev/null +++ b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_generic_model_api.h @@ -0,0 +1,529 @@ +// 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. + +/** @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. + */ + +/** 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) */ +} 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) */ +} 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) */ +} 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) */ +} 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 */ +} 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 */ +} 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) */ +} 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 */ +} 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 */ +} 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 */ +} 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 */ +} 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 */ +} 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 */ +} 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 */ +} 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 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 */ +} 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 */ +} 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 */ +} 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*/ + 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; + +/** + * @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 */ + 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. + */ + +/** 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) */ +} 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) */ +} 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 */ +} 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 */ +} 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) */ +} 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 */ +} 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 */ +} 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 */ +} 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 */ +} 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 */ +} 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 */ +} 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 */ +} 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) */ +} 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 */ +} 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) */ +} 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 */ +} 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) */ +} 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 */ +} 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 */ + 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; + +/** 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, + 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 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); + +/** + * @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 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. + * 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 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. + * 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/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 new file mode 100644 index 0000000000..b35cb0e0b1 --- /dev/null +++ b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_health_model_api.h @@ -0,0 +1,282 @@ +// 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_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) + +/** Health Server Model callbacks */ +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; + +/** Health Server Model Context */ +typedef struct { + /** Pointer to Health Server Model */ + 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; + +/** Parameter of Health Fault Get */ +typedef struct { + uint16_t company_id; /*!< Bluetooth assigned 16-bit Company ID */ +} esp_ble_mesh_health_fault_get_t; + +/** Parameter of Health Attention Set */ +typedef struct { + uint8_t attention; /*!< Value of the Attention Timer state */ +} esp_ble_mesh_health_attention_set_t; + +/** Parameter of Health Period Set */ +typedef struct { + uint8_t fast_period_divisor; /*!< Divider for the Publish Period */ +} esp_ble_mesh_health_period_set_t; + +/** 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 */ +} esp_ble_mesh_health_fault_test_t; + +/** Parameter of Health Fault Clear */ +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; + +/** 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 */ + 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; + +/** 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, + 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; + +/** 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, +} esp_ble_mesh_health_server_cb_event_t; + +/** + * @brief Bluetooth Mesh Health Client and Server Model function. + */ + +/** + * @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 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); + +/** + * @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 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. + * 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 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. + * 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/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 new file mode 100644 index 0000000000..d40ead593b --- /dev/null +++ b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_lighting_model_api.h @@ -0,0 +1,585 @@ +// 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. + +/** @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. + */ + +/** 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) */ +} 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) */ +} 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 */ +} 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 */ +} 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) */ +} 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) */ +} 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 */ +} 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 */ +} 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) */ +} 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) */ +} 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) */ +} 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 */ +} esp_ble_mesh_light_hsl_default_set_t; + +/** 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; + +/** 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; + +/** 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; + +/** 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; + +/** 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; + +/** 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; + +/** 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; + +/** 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; + +/** 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 */ + 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. + */ + +/** 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) */ +} 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) */ +} 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 */ +} 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 */ +} 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 */ +} 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) */ +} 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) */ +} 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 */ +} 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 */ +} 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) */ +} 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) */ +} 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) */ +} 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) */ +} 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 */ +} 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 */ +} 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) */ +} 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) */ +} 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 */ +} 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 */ +} 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 */ +} 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 */ +} 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) */ +} 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 */ +} 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 */ + 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; + +/** 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, + 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 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); + +/** + * @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 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. + * 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 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. + * 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/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 new file mode 100644 index 0000000000..d303e63a14 --- /dev/null +++ b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_sensor_model_api.h @@ -0,0 +1,261 @@ +// 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. + +/** @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. + */ + +/** 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) */ +} esp_ble_mesh_sensor_descriptor_get_t; + +/** Parameter of Sensor Cadence Get */ +typedef struct { + 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 */ +} esp_ble_mesh_sensor_cadence_set_t; + +/** Parameter of Sensor Settings Get */ +typedef struct { + 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 */ +} 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 */ +} 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) */ +} 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 */ +} 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) */ +} 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 */ + 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; + +/** + * @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 */ +} esp_ble_mesh_sensor_client_set_state_t; + +/** + * @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) */ +} 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 */ +} 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) */ +} 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 */ +} 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) */ +} 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 */ +} 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 */ +} 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 */ + 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; + +/** 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. + * 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; + +/** 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, + 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 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); + +/** + * @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 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. + * 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 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. + * 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/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 new file mode 100644 index 0000000000..da45b40517 --- /dev/null +++ b/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_time_scene_model_api.h @@ -0,0 +1,319 @@ +// 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. + +/** @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. + */ + +/** 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 */ +} 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 */ +} 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 */ +} 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 */ +} esp_ble_mesh_time_role_set_t; + +/** Parameter of Scene Store */ +typedef struct { + 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) */ +} esp_ble_mesh_scene_recall_t; + +/** Parameter of Scene Delete */ +typedef struct { + 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 */ +} 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 */ +} esp_ble_mesh_scheduler_act_set_t; + +/** + * @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 */ + 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. + */ + +/** 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 */ +} 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 */ +} 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 */ +} 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 */ +} 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) */ +} 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 */ +} 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 */ +} 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 */ +} 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 */ + 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; + +/** 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, + 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 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); + +/** + * @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 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. + * 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 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. + * 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/esp_ble_mesh/btc/btc_ble_mesh_config_model.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_config_model.c new file mode 100644 index 0000000000..0937721bb2 --- /dev/null +++ b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_config_model.c @@ -0,0 +1,725 @@ +// 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 +#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/esp_ble_mesh/btc/btc_ble_mesh_generic_model.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_generic_model.c new file mode 100644 index 0000000000..761fbeebe5 --- /dev/null +++ b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_generic_model.c @@ -0,0 +1,540 @@ +// 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 +#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/esp_ble_mesh/btc/btc_ble_mesh_health_model.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_health_model.c new file mode 100644 index 0000000000..1f6d88340b --- /dev/null +++ b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_health_model.c @@ -0,0 +1,592 @@ +// 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 +#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/esp_ble_mesh/btc/btc_ble_mesh_lighting_model.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_lighting_model.c new file mode 100644 index 0000000000..d07dba47a0 --- /dev/null +++ b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_lighting_model.c @@ -0,0 +1,381 @@ +// 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 +#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/esp_ble_mesh/btc/btc_ble_mesh_prov.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c new file mode 100644 index 0000000000..c825e93907 --- /dev/null +++ b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c @@ -0,0 +1,1528 @@ +// 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 +#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/esp_ble_mesh/btc/btc_ble_mesh_sensor_model.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_sensor_model.c new file mode 100644 index 0000000000..b9f3de6bde --- /dev/null +++ b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_sensor_model.c @@ -0,0 +1,632 @@ +// 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 +#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/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 new file mode 100644 index 0000000000..4f03567dc9 --- /dev/null +++ b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_time_scene_model.c @@ -0,0 +1,383 @@ +// 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 +#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/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 new file mode 100644 index 0000000000..87889923cc --- /dev/null +++ b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_config_model.h @@ -0,0 +1,64 @@ +// 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 _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/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 new file mode 100644 index 0000000000..21a159f20a --- /dev/null +++ b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_generic_model.h @@ -0,0 +1,52 @@ +// 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 _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/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 new file mode 100644 index 0000000000..a00efb0c1e --- /dev/null +++ b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_health_model.h @@ -0,0 +1,78 @@ +// 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 _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/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 new file mode 100644 index 0000000000..98353c6acd --- /dev/null +++ b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_lighting_model.h @@ -0,0 +1,53 @@ +// 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 _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/esp_ble_mesh/btc/include/btc_ble_mesh_prov.h b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_prov.h new file mode 100644 index 0000000000..ff0f4154fd --- /dev/null +++ b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_prov.h @@ -0,0 +1,210 @@ +// 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 _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/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 new file mode 100644 index 0000000000..e94ccdc4b0 --- /dev/null +++ b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_sensor_model.h @@ -0,0 +1,53 @@ +// 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 _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/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 new file mode 100644 index 0000000000..0ee1d244c8 --- /dev/null +++ b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_time_scene_model.h @@ -0,0 +1,53 @@ +// 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 _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/esp_ble_mesh/mesh_core/access.c b/components/bt/esp_ble_mesh/mesh_core/access.c new file mode 100644 index 0000000000..6184d30091 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/access.h b/components/bt/esp_ble_mesh/mesh_core/access.h new file mode 100644 index 0000000000..114c1662be --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/adv.c b/components/bt/esp_ble_mesh/mesh_core/adv.c new file mode 100644 index 0000000000..87ef363061 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/adv.h b/components/bt/esp_ble_mesh/mesh_core/adv.h new file mode 100644 index 0000000000..b827af59ea --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/beacon.c b/components/bt/esp_ble_mesh/mesh_core/beacon.c new file mode 100644 index 0000000000..a62cf073ad --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/beacon.h b/components/bt/esp_ble_mesh/mesh_core/beacon.h new file mode 100644 index 0000000000..f410fa5d59 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/cfg_cli.c b/components/bt/esp_ble_mesh/mesh_core/cfg_cli.c new file mode 100644 index 0000000000..aa2daf0da8 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/cfg_srv.c b/components/bt/esp_ble_mesh/mesh_core/cfg_srv.c new file mode 100644 index 0000000000..4e330e61a0 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/crypto.c b/components/bt/esp_ble_mesh/mesh_core/crypto.c new file mode 100644 index 0000000000..d2e6507882 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/crypto.h b/components/bt/esp_ble_mesh/mesh_core/crypto.h new file mode 100644 index 0000000000..d8e9b1452e --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/foundation.h b/components/bt/esp_ble_mesh/mesh_core/foundation.h new file mode 100644 index 0000000000..d1ccd31ae4 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/friend.c b/components/bt/esp_ble_mesh/mesh_core/friend.c new file mode 100644 index 0000000000..b47e86fe81 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/friend.h b/components/bt/esp_ble_mesh/mesh_core/friend.h new file mode 100644 index 0000000000..008a342c9b --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/health_cli.c b/components/bt/esp_ble_mesh/mesh_core/health_cli.c new file mode 100644 index 0000000000..c66e42afcd --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/health_srv.c b/components/bt/esp_ble_mesh/mesh_core/health_srv.c new file mode 100644 index 0000000000..96e16692dd --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/include/cfg_cli.h b/components/bt/esp_ble_mesh/mesh_core/include/cfg_cli.h new file mode 100644 index 0000000000..b001d84b8a --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/include/cfg_srv.h b/components/bt/esp_ble_mesh/mesh_core/include/cfg_srv.h new file mode 100644 index 0000000000..d5f77e7b01 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/include/health_cli.h b/components/bt/esp_ble_mesh/mesh_core/include/health_cli.h new file mode 100644 index 0000000000..9d7230ebac --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/include/health_srv.h b/components/bt/esp_ble_mesh/mesh_core/include/health_srv.h new file mode 100644 index 0000000000..4e9b840776 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/include/mesh_access.h b/components/bt/esp_ble_mesh/mesh_core/include/mesh_access.h new file mode 100644 index 0000000000..bdabab15ca --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/include/mesh_aes_encrypt.h b/components/bt/esp_ble_mesh/mesh_core/include/mesh_aes_encrypt.h new file mode 100644 index 0000000000..afaa6b27dd --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/include/mesh_atomic.h b/components/bt/esp_ble_mesh/mesh_core/include/mesh_atomic.h new file mode 100644 index 0000000000..5c8bf17b89 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/include/mesh_bearer_adapt.h b/components/bt/esp_ble_mesh/mesh_core/include/mesh_bearer_adapt.h new file mode 100644 index 0000000000..1382031878 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/include/mesh_buf.h b/components/bt/esp_ble_mesh/mesh_core/include/mesh_buf.h new file mode 100644 index 0000000000..e6c62877ea --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/include/mesh_dlist.h b/components/bt/esp_ble_mesh/mesh_core/include/mesh_dlist.h new file mode 100644 index 0000000000..31eef746ec --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/include/mesh_hci.h b/components/bt/esp_ble_mesh/mesh_core/include/mesh_hci.h new file mode 100644 index 0000000000..1c3e093e0b --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/include/mesh_kernel.h b/components/bt/esp_ble_mesh/mesh_core/include/mesh_kernel.h new file mode 100644 index 0000000000..785b8b8dfb --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/include/mesh_main.h b/components/bt/esp_ble_mesh/mesh_core/include/mesh_main.h new file mode 100644 index 0000000000..374c6a0770 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/include/mesh_proxy.h b/components/bt/esp_ble_mesh/mesh_core/include/mesh_proxy.h new file mode 100644 index 0000000000..0b14d9e184 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/include/mesh_slist.h b/components/bt/esp_ble_mesh/mesh_core/include/mesh_slist.h new file mode 100644 index 0000000000..4ddf427e6a --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/include/mesh_trace.h b/components/bt/esp_ble_mesh/mesh_core/include/mesh_trace.h new file mode 100644 index 0000000000..325c807f93 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/include/mesh_types.h b/components/bt/esp_ble_mesh/mesh_core/include/mesh_types.h new file mode 100644 index 0000000000..66df1ec75e --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/include/mesh_util.h b/components/bt/esp_ble_mesh/mesh_core/include/mesh_util.h new file mode 100644 index 0000000000..8258e2c691 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/include/mesh_uuid.h b/components/bt/esp_ble_mesh/mesh_core/include/mesh_uuid.h new file mode 100644 index 0000000000..de03df5c32 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/lpn.c b/components/bt/esp_ble_mesh/mesh_core/lpn.c new file mode 100644 index 0000000000..8adf2a24bb --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/lpn.h b/components/bt/esp_ble_mesh/mesh_core/lpn.h new file mode 100644 index 0000000000..ad870e99e1 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/mesh.h b/components/bt/esp_ble_mesh/mesh_core/mesh.h new file mode 100644 index 0000000000..c536184aa9 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/mesh_aes_encrypt.c b/components/bt/esp_ble_mesh/mesh_core/mesh_aes_encrypt.c new file mode 100644 index 0000000000..2d1842cc4b --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/mesh_atomic.c b/components/bt/esp_ble_mesh/mesh_core/mesh_atomic.c new file mode 100644 index 0000000000..ce73638053 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/mesh_bearer_adapt.c b/components/bt/esp_ble_mesh/mesh_core/mesh_bearer_adapt.c new file mode 100644 index 0000000000..67bea67e03 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/mesh_buf.c b/components/bt/esp_ble_mesh/mesh_core/mesh_buf.c new file mode 100644 index 0000000000..d6e0cd710e --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/mesh_hci.c b/components/bt/esp_ble_mesh/mesh_core/mesh_hci.c new file mode 100644 index 0000000000..72da73a389 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/mesh_kernel.c b/components/bt/esp_ble_mesh/mesh_core/mesh_kernel.c new file mode 100644 index 0000000000..d1d1ca6670 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/mesh_main.c b/components/bt/esp_ble_mesh/mesh_core/mesh_main.c new file mode 100644 index 0000000000..03760d957c --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/mesh_util.c b/components/bt/esp_ble_mesh/mesh_core/mesh_util.c new file mode 100644 index 0000000000..4650bb2603 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/net.c b/components/bt/esp_ble_mesh/mesh_core/net.c new file mode 100644 index 0000000000..020ea02707 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/net.h b/components/bt/esp_ble_mesh/mesh_core/net.h new file mode 100644 index 0000000000..90515fd2ca --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/prov.c b/components/bt/esp_ble_mesh/mesh_core/prov.c new file mode 100644 index 0000000000..0a3329ff65 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/prov.h b/components/bt/esp_ble_mesh/mesh_core/prov.h new file mode 100644 index 0000000000..f96ed7707f --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/provisioner_beacon.c b/components/bt/esp_ble_mesh/mesh_core/provisioner_beacon.c new file mode 100644 index 0000000000..0790b538de --- /dev/null +++ b/components/bt/esp_ble_mesh/mesh_core/provisioner_beacon.c @@ -0,0 +1,71 @@ +// 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 +#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/esp_ble_mesh/mesh_core/provisioner_beacon.h b/components/bt/esp_ble_mesh/mesh_core/provisioner_beacon.h new file mode 100644 index 0000000000..a58de225fe --- /dev/null +++ b/components/bt/esp_ble_mesh/mesh_core/provisioner_beacon.h @@ -0,0 +1,20 @@ +// 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 _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/esp_ble_mesh/mesh_core/provisioner_main.c b/components/bt/esp_ble_mesh/mesh_core/provisioner_main.c new file mode 100644 index 0000000000..586fd33842 --- /dev/null +++ b/components/bt/esp_ble_mesh/mesh_core/provisioner_main.c @@ -0,0 +1,1278 @@ +// 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 +#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/esp_ble_mesh/mesh_core/provisioner_main.h b/components/bt/esp_ble_mesh/mesh_core/provisioner_main.h new file mode 100644 index 0000000000..50bb656b2c --- /dev/null +++ b/components/bt/esp_ble_mesh/mesh_core/provisioner_main.h @@ -0,0 +1,122 @@ +// 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 _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/esp_ble_mesh/mesh_core/provisioner_prov.c b/components/bt/esp_ble_mesh/mesh_core/provisioner_prov.c new file mode 100644 index 0000000000..dbaae8ebb6 --- /dev/null +++ b/components/bt/esp_ble_mesh/mesh_core/provisioner_prov.c @@ -0,0 +1,3287 @@ +// 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 +#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/esp_ble_mesh/mesh_core/provisioner_prov.h b/components/bt/esp_ble_mesh/mesh_core/provisioner_prov.h new file mode 100644 index 0000000000..103a223f21 --- /dev/null +++ b/components/bt/esp_ble_mesh/mesh_core/provisioner_prov.h @@ -0,0 +1,379 @@ +// 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 _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/esp_ble_mesh/mesh_core/provisioner_proxy.c b/components/bt/esp_ble_mesh/mesh_core/provisioner_proxy.c new file mode 100644 index 0000000000..022994f382 --- /dev/null +++ b/components/bt/esp_ble_mesh/mesh_core/provisioner_proxy.c @@ -0,0 +1,608 @@ +// 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 +#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/esp_ble_mesh/mesh_core/provisioner_proxy.h b/components/bt/esp_ble_mesh/mesh_core/provisioner_proxy.h new file mode 100644 index 0000000000..6a64167b39 --- /dev/null +++ b/components/bt/esp_ble_mesh/mesh_core/provisioner_proxy.h @@ -0,0 +1,89 @@ +// 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 _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/esp_ble_mesh/mesh_core/proxy.c b/components/bt/esp_ble_mesh/mesh_core/proxy.c new file mode 100644 index 0000000000..fd9807f54b --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/proxy.h b/components/bt/esp_ble_mesh/mesh_core/proxy.h new file mode 100644 index 0000000000..07120e0950 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/settings.c b/components/bt/esp_ble_mesh/mesh_core/settings.c new file mode 100644 index 0000000000..6606142c2b --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/settings.h b/components/bt/esp_ble_mesh/mesh_core/settings.h new file mode 100644 index 0000000000..84b5e182b4 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/settings/settings_nvs.c b/components/bt/esp_ble_mesh/mesh_core/settings/settings_nvs.c new file mode 100644 index 0000000000..59e9ac1142 --- /dev/null +++ b/components/bt/esp_ble_mesh/mesh_core/settings/settings_nvs.c @@ -0,0 +1,374 @@ +// 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 +#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/esp_ble_mesh/mesh_core/settings/settings_nvs.h b/components/bt/esp_ble_mesh/mesh_core/settings/settings_nvs.h new file mode 100644 index 0000000000..a4216fadca --- /dev/null +++ b/components/bt/esp_ble_mesh/mesh_core/settings/settings_nvs.h @@ -0,0 +1,44 @@ +// 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 _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/esp_ble_mesh/mesh_core/test.c b/components/bt/esp_ble_mesh/mesh_core/test.c new file mode 100644 index 0000000000..f61beb8720 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/test.h b/components/bt/esp_ble_mesh/mesh_core/test.h new file mode 100644 index 0000000000..60e3d0d8f1 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/transport.c b/components/bt/esp_ble_mesh/mesh_core/transport.c new file mode 100644 index 0000000000..a456ebbfc8 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_core/transport.h b/components/bt/esp_ble_mesh/mesh_core/transport.h new file mode 100644 index 0000000000..13845f345c --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_docs/BLE-Mesh_FAQs_EN.md b/components/bt/esp_ble_mesh/mesh_docs/BLE-Mesh_FAQs_EN.md new file mode 100644 index 0000000000..3e3ba69684 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_docs/BLE-Mesh_Feature_List_EN.md b/components/bt/esp_ble_mesh/mesh_docs/BLE-Mesh_Feature_List_EN.md new file mode 100644 index 0000000000..cf54f7985e --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_docs/BLE-Mesh_Getting_Started_EN.md b/components/bt/esp_ble_mesh/mesh_docs/BLE-Mesh_Getting_Started_EN.md new file mode 100644 index 0000000000..5ac15427a7 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_docs/BLE-Mesh_Known_Issues_EN.md b/components/bt/esp_ble_mesh/mesh_docs/BLE-Mesh_Known_Issues_EN.md new file mode 100644 index 0000000000..034d2388d3 --- /dev/null +++ b/components/bt/esp_ble_mesh/mesh_docs/BLE-Mesh_Known_Issues_EN.md @@ -0,0 +1 @@ +To be added. diff --git a/components/bt/esp_ble_mesh/mesh_docs/README.md b/components/bt/esp_ble_mesh/mesh_docs/README.md new file mode 100644 index 0000000000..65775ebf98 --- /dev/null +++ b/components/bt/esp_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/esp_ble_mesh/mesh_models/generic_client.c b/components/bt/esp_ble_mesh/mesh_models/generic_client.c new file mode 100644 index 0000000000..9e963095dd --- /dev/null +++ b/components/bt/esp_ble_mesh/mesh_models/generic_client.c @@ -0,0 +1,1225 @@ +// 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 +#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/esp_ble_mesh/mesh_models/include/generic_client.h b/components/bt/esp_ble_mesh/mesh_models/include/generic_client.h new file mode 100644 index 0000000000..e82587d766 --- /dev/null +++ b/components/bt/esp_ble_mesh/mesh_models/include/generic_client.h @@ -0,0 +1,491 @@ +// 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. + +/** @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/esp_ble_mesh/mesh_models/include/lighting_client.h b/components/bt/esp_ble_mesh/mesh_models/include/lighting_client.h new file mode 100644 index 0000000000..9e9789a821 --- /dev/null +++ b/components/bt/esp_ble_mesh/mesh_models/include/lighting_client.h @@ -0,0 +1,492 @@ +// 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. + +/** @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/esp_ble_mesh/mesh_models/include/mesh_common.h b/components/bt/esp_ble_mesh/mesh_models/include/mesh_common.h new file mode 100644 index 0000000000..468cf65afc --- /dev/null +++ b/components/bt/esp_ble_mesh/mesh_models/include/mesh_common.h @@ -0,0 +1,46 @@ +// 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. + +/** @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/esp_ble_mesh/mesh_models/include/model_common.h b/components/bt/esp_ble_mesh/mesh_models/include/model_common.h new file mode 100644 index 0000000000..486cdb769d --- /dev/null +++ b/components/bt/esp_ble_mesh/mesh_models/include/model_common.h @@ -0,0 +1,133 @@ +// 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 _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/esp_ble_mesh/mesh_models/include/model_opcode.h b/components/bt/esp_ble_mesh/mesh_models/include/model_opcode.h new file mode 100644 index 0000000000..d9a49e71de --- /dev/null +++ b/components/bt/esp_ble_mesh/mesh_models/include/model_opcode.h @@ -0,0 +1,276 @@ +// 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 _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/esp_ble_mesh/mesh_models/include/sensor_client.h b/components/bt/esp_ble_mesh/mesh_models/include/sensor_client.h new file mode 100644 index 0000000000..095499ef5d --- /dev/null +++ b/components/bt/esp_ble_mesh/mesh_models/include/sensor_client.h @@ -0,0 +1,167 @@ +// 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. + +/** @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/esp_ble_mesh/mesh_models/include/time_scene_client.h b/components/bt/esp_ble_mesh/mesh_models/include/time_scene_client.h new file mode 100644 index 0000000000..a37cf878f4 --- /dev/null +++ b/components/bt/esp_ble_mesh/mesh_models/include/time_scene_client.h @@ -0,0 +1,257 @@ +// 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. + +/** @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/esp_ble_mesh/mesh_models/lighting_client.c b/components/bt/esp_ble_mesh/mesh_models/lighting_client.c new file mode 100644 index 0000000000..8f0481b86d --- /dev/null +++ b/components/bt/esp_ble_mesh/mesh_models/lighting_client.c @@ -0,0 +1,1400 @@ +// 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 +#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/esp_ble_mesh/mesh_models/mesh_common.c b/components/bt/esp_ble_mesh/mesh_models/mesh_common.c new file mode 100644 index 0000000000..bb4aa6f934 --- /dev/null +++ b/components/bt/esp_ble_mesh/mesh_models/mesh_common.c @@ -0,0 +1,46 @@ +// 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 +#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/esp_ble_mesh/mesh_models/model_common.c b/components/bt/esp_ble_mesh/mesh_models/model_common.c new file mode 100644 index 0000000000..cc694082cd --- /dev/null +++ b/components/bt/esp_ble_mesh/mesh_models/model_common.c @@ -0,0 +1,336 @@ +// 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 +#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/esp_ble_mesh/mesh_models/sensor_client.c b/components/bt/esp_ble_mesh/mesh_models/sensor_client.c new file mode 100644 index 0000000000..26ea1f8d7e --- /dev/null +++ b/components/bt/esp_ble_mesh/mesh_models/sensor_client.c @@ -0,0 +1,616 @@ +// 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 +#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/esp_ble_mesh/mesh_models/time_scene_client.c b/components/bt/esp_ble_mesh/mesh_models/time_scene_client.c new file mode 100644 index 0000000000..921c504ae3 --- /dev/null +++ b/components/bt/esp_ble_mesh/mesh_models/time_scene_client.c @@ -0,0 +1,694 @@ +// 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 +#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/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 89% rename from components/bt/bluedroid/api/esp_avrc_api.c rename to components/bt/host/bluedroid/api/esp_avrc_api.c index 9b9e6616c2..cbfa71a035 100644 --- a/components/bt/bluedroid/api/esp_avrc_api.c +++ b/components/bt/host/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/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 99% rename from components/bt/bluedroid/api/esp_bt_main.c rename to components/bt/host/bluedroid/api/esp_bt_main.c index 1620ae9d80..8097956d10 100644 --- a/components/bt/bluedroid/api/esp_bt_main.c +++ b/components/bt/host/bluedroid/api/esp_bt_main.c @@ -128,10 +128,12 @@ 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 + 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_gap_ble_api.c b/components/bt/host/bluedroid/api/esp_gap_ble_api.c similarity index 98% rename from components/bt/bluedroid/api/esp_gap_ble_api.c rename to components/bt/host/bluedroid/api/esp_gap_ble_api.c index cc9983b537..aef6b3d6d6 100644 --- a/components/bt/bluedroid/api/esp_gap_ble_api.c +++ b/components/bt/host/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/esp_gap_bt_api.c b/components/bt/host/bluedroid/api/esp_gap_bt_api.c similarity index 91% rename from components/bt/bluedroid/api/esp_gap_bt_api.c rename to components/bt/host/bluedroid/api/esp_gap_bt_api.c index ff3f945c48..f096b0fd01 100644 --- a/components/bt/bluedroid/api/esp_gap_bt_api.c +++ b/components/bt/host/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/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 99% rename from components/bt/bluedroid/api/esp_hf_client_api.c rename to components/bt/host/bluedroid/api/esp_hf_client_api.c index fbc5d475cc..7db990206a 100644 --- a/components/bt/bluedroid/api/esp_hf_client_api.c +++ b/components/bt/host/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/host/bluedroid/api/esp_spp_api.c similarity index 94% rename from components/bt/bluedroid/api/esp_spp_api.c rename to components/bt/host/bluedroid/api/esp_spp_api.c index 46878d659e..d68511cf4b 100644 --- a/components/bt/bluedroid/api/esp_spp_api.c +++ b/components/bt/host/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) { @@ -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/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 94% 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 index 814f2be338..e75eb637df 100644 --- a/components/bt/bluedroid/api/include/api/esp_avrc_api.h +++ b/components/bt/host/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/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 97% 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 index 7e1063c71c..51044d45c7 100644 --- a/components/bt/bluedroid/api/include/api/esp_bt_defs.h +++ b/components/bt/host/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_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 98% 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 index 96123e8bce..f6097dfe70 100644 --- 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 @@ -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_gap_bt_api.h b/components/bt/host/bluedroid/api/include/api/esp_gap_bt_api.h similarity index 88% 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 index 084cabec23..076f59caf7 100644 --- 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 @@ -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/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 96% 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 index d6c140a140..1ffffbb510 100644 --- a/components/bt/bluedroid/api/include/api/esp_gatt_defs.h +++ b/components/bt/host/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 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*/ +#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 @@ -387,6 +392,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/host/bluedroid/api/include/api/esp_gattc_api.h similarity index 99% 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 index d18b2e4c4e..d8f8bf7ece 100644 --- a/components/bt/bluedroid/api/include/api/esp_gattc_api.h +++ b/components/bt/host/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/host/bluedroid/api/include/api/esp_gatts_api.h similarity index 99% 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 index 97296b1c7a..341e71b796 100644 --- a/components/bt/bluedroid/api/include/api/esp_gatts_api.h +++ b/components/bt/host/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 */ /** @@ -255,6 +256,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/api/include/api/esp_hf_client_api.h b/components/bt/host/bluedroid/api/include/api/esp_hf_client_api.h similarity index 99% 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 index dfc06ed5d1..8e3dc956b7 100644 --- 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 @@ -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/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 99% 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 index 31bcf1c687..1b96cbbe04 100644 --- a/components/bt/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/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 83% rename from components/bt/bluedroid/bta/av/bta_av_cfg.c rename to components/bt/host/bluedroid/bta/av/bta_av_cfg.c index b8a86831c5..9f39239f5c 100644 --- a/components/bt/bluedroid/bta/av/bta_av_cfg.c +++ b/components/bt/host/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_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 98% rename from components/bt/bluedroid/bta/av/bta_av_main.c rename to components/bt/host/bluedroid/bta/av/bta_av_main.c index bc352c8fa4..f669365268 100644 --- a/components/bt/bluedroid/bta/av/bta_av_main.c +++ b/components/bt/host/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/av/bta_av_sbc.c b/components/bt/host/bluedroid/bta/av/bta_av_sbc.c similarity index 96% rename from components/bt/bluedroid/bta/av/bta_av_sbc.c rename to components/bt/host/bluedroid/bta/av/bta_av_sbc.c index 30f178efb3..4e034c4246 100644 --- a/components/bt/bluedroid/bta/av/bta_av_sbc.c +++ b/components/bt/host/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/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 96% 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 index 16a70f3ef3..9fb6c06c52 100644 --- a/components/bt/bluedroid/bta/av/include/bta_av_int.h +++ b/components/bt/host/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/host/bluedroid/bta/dm/bta_dm_act.c similarity index 94% rename from components/bt/bluedroid/bta/dm/bta_dm_act.c rename to components/bt/host/bluedroid/bta/dm/bta_dm_act.c index c02987c9fb..978edbf0fa 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_act.c +++ b/components/bt/host/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,13 +127,16 @@ 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); - +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 */ @@ -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, @@ -233,10 +242,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; /******************************************************************************* ** @@ -325,6 +336,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 +426,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 +457,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; @@ -521,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 @@ -588,32 +657,81 @@ 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) { + 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) { +#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 } /******************************************************************************* @@ -629,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 */ @@ -993,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 } /******************************************************************************* @@ -1008,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; @@ -1025,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 @@ -1167,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 } /******************************************************************************* @@ -2202,7 +2335,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; @@ -2395,7 +2528,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; @@ -2689,6 +2822,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) /******************************************************************************* ** @@ -2775,6 +2910,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 /******************************************************************************* ** @@ -3719,23 +3855,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 +3900,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 +3943,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 +3951,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); + } } /******************************************************************************* @@ -5622,6 +5830,7 @@ static void bta_dm_gattc_register(void) } } #endif /* GATTC_INCLUDED == TRUE */ + /******************************************************************************* ** ** Function btm_dm_start_disc_gatt_services @@ -5631,6 +5840,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 + @@ -5642,6 +5852,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 */ /******************************************************************************* ** @@ -5702,6 +5913,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; @@ -5759,6 +5971,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) */ /******************************************************************************* ** @@ -5828,6 +6041,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 @@ -5837,6 +6051,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; @@ -5867,6 +6082,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/host/bluedroid/bta/dm/bta_dm_api.c similarity index 97% rename from components/bt/bluedroid/bta/dm/bta_dm_api.c rename to components/bt/host/bluedroid/bta/dm/bta_dm_api.c index 078903d31a..141d9ce2dd 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_api.c +++ b/components/bt/host/bluedroid/bta/dm/bta_dm_api.c @@ -183,6 +183,49 @@ 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); + } +} + +#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; @@ -206,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) { @@ -433,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 @@ -487,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) /******************************************************************************* @@ -552,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; @@ -587,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 @@ -663,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 /******************************************************************************* ** @@ -947,7 +994,6 @@ void BTA_DmBleSecurityGrant(BD_ADDR bd_addr, tBTA_DM_BLE_SEC_GRANT res) } } #endif ///SMP_INCLUDED == TRUE -#endif ///BLE_INCLUDED == TRUE /******************************************************************************* @@ -1165,7 +1211,7 @@ void BTA_DmSetBleAdvParamsAll (UINT16 adv_int_min, UINT16 adv_int_max, } #endif } - +#endif ///BLE_INCLUDED == TRUE /******************************************************************************* @@ -1754,6 +1800,8 @@ void BTA_DmBleUpdateConnectionParam(BD_ADDR bd_addr, UINT16 min_int, } #endif } + +#if BLE_INCLUDED == TRUE /******************************************************************************* ** ** Function BTA_DmBleConfigLocalPrivacy @@ -1784,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/bta_dm_cfg.c b/components/bt/host/bluedroid/bta/dm/bta_dm_cfg.c similarity index 95% rename from components/bt/bluedroid/bta/dm/bta_dm_cfg.c rename to components/bt/host/bluedroid/bta/dm/bta_dm_cfg.c index e9ad1f38d2..6769e7141e 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_cfg.c +++ b/components/bt/host/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) @@ -111,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 */ @@ -374,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) */ @@ -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_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 99% rename from components/bt/bluedroid/bta/dm/bta_dm_main.c rename to components/bt/host/bluedroid/bta/dm/bta_dm_main.c index 0f45dfbe97..aa4b3250df 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_main.c +++ b/components/bt/host/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 */ @@ -159,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 }; @@ -357,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 ); } @@ -409,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/bluedroid/bta/dm/bta_dm_pm.c b/components/bt/host/bluedroid/bta/dm/bta_dm_pm.c similarity index 99% rename from components/bt/bluedroid/bta/dm/bta_dm_pm.c rename to components/bt/host/bluedroid/bta/dm/bta_dm_pm.c index cf55b1c341..ff42a65a17 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_pm.c +++ b/components/bt/host/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); @@ -42,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, @@ -997,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/bluedroid/bta/dm/bta_dm_sco.c b/components/bt/host/bluedroid/bta/dm/bta_dm_sco.c similarity index 95% rename from components/bt/bluedroid/bta/dm/bta_dm_sco.c rename to components/bt/host/bluedroid/bta/dm/bta_dm_sco.c index 9acfa9544a..df91799a87 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_sco.c +++ b/components/bt/host/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/host/bluedroid/bta/dm/include/bta_dm_int.h similarity index 96% 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 index 9ff577481c..c87708e358 100644 --- a/components/bt/bluedroid/bta/dm/include/bta_dm_int.h +++ b/components/bt/host/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, @@ -156,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 }; @@ -188,6 +191,21 @@ 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; + +#if (BLE_INCLUDED == TRUE) typedef struct { BT_HDR hdr; BOOLEAN add_remove; @@ -208,6 +226,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; @@ -387,8 +406,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) @@ -478,7 +497,7 @@ typedef struct { typedef struct { BT_HDR hdr; - BOOLEAN add; + BOOLEAN add; UINT32 static_passkey; } tBTA_DM_API_SET_DEFAULT_PASSKEY; @@ -784,10 +803,14 @@ typedef union { tBTA_DM_API_ENABLE enable; 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; @@ -923,8 +946,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; @@ -960,7 +983,6 @@ typedef struct { } tBTA_DM_CONNECTED_SRVCS; -extern tBTA_DM_CONNECTED_SRVCS bta_dm_conn_srvcs; #if (BTA_DM_PM_INCLUDED == TRUE) @@ -1016,6 +1038,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; @@ -1025,8 +1049,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; @@ -1134,8 +1160,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 { @@ -1176,16 +1202,16 @@ 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) */ /* 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 */ @@ -1212,6 +1238,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); @@ -1222,6 +1261,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/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 99% rename from components/bt/bluedroid/bta/gatt/bta_gattc_act.c rename to components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c index ed066d006c..9f8f2b5198 100644 --- a/components/bt/bluedroid/bta/gatt/bta_gattc_act.c +++ b/components/bt/host/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, @@ -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_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 99% rename from components/bt/bluedroid/bta/gatt/bta_gattc_cache.c rename to components/bt/host/bluedroid/bta/gatt/bta_gattc_cache.c index 355d619a09..1da1000ae7 100644 --- a/components/bt/bluedroid/bta/gatt/bta_gattc_cache.c +++ b/components/bt/host/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_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 76% rename from components/bt/bluedroid/bta/gatt/bta_gattc_co.c rename to components/bt/host/bluedroid/bta/gatt/bta_gattc_co.c index c11fb95895..0573b7bf77 100644 --- a/components/bt/bluedroid/bta/gatt/bta_gattc_co.c +++ b/components/bt/host/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 @@ -47,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); @@ -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; +static 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,9 +267,9 @@ 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); + 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 @@ -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,23 @@ 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); + 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) { + APPL_TRACE_ERROR("%s malloc failed!", __func__); + osi_free(p_buf); + 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 +406,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 +431,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 +447,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 +469,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 +484,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 +497,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 +520,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 +567,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 +579,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 +594,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 +614,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 +624,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 +649,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 +661,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_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 99% rename from components/bt/bluedroid/bta/gatt/bta_gattc_utils.c rename to components/bt/host/bluedroid/bta/gatt/bta_gattc_utils.c index d202451447..ed9e4c20e4 100644 --- a/components/bt/bluedroid/bta/gatt/bta_gattc_utils.c +++ b/components/bt/host/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/host/bluedroid/bta/gatt/bta_gatts_act.c similarity index 98% rename from components/bt/bluedroid/bta/gatt/bta_gatts_act.c rename to components/bt/host/bluedroid/bta/gatt/bta_gatts_act.c index 47bad4afba..4dd804a47a 100644 --- a/components/bt/bluedroid/bta/gatt/bta_gatts_act.c +++ b/components/bt/host/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, @@ -48,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, @@ -58,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 }; @@ -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/bta_gatts_api.c b/components/bt/host/bluedroid/bta/gatt/bta_gatts_api.c similarity index 98% rename from components/bt/bluedroid/bta/gatt/bta_gatts_api.c rename to components/bt/host/bluedroid/bta/gatt/bta_gatts_api.c index 87e559ab72..aefe62d65a 100644 --- a/components/bt/bluedroid/bta/gatt/bta_gatts_api.c +++ b/components/bt/host/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/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 99% 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 index c25f5ddb30..9715ac681e 100644 --- a/components/bt/bluedroid/bta/gatt/include/bta_gattc_int.h +++ b/components/bt/host/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/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 99% 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 index 33ae293483..43a2af6abe 100644 --- 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 @@ -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/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 99% 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 index 60dfc759c3..fd52b3aef7 100644 --- 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 @@ -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/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 98% rename from components/bt/bluedroid/bta/include/bta/bta_api.h rename to components/bt/host/bluedroid/bta/include/bta/bta_api.h index c7bad21fed..c9349e80ec 100644 --- a/components/bt/bluedroid/bta/include/bta/bta_api.h +++ b/components/bt/host/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 @@ -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,24 +296,34 @@ 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 +// #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 @@ -499,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 */ @@ -1450,9 +1461,23 @@ 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); + +#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); @@ -1786,6 +1811,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 ** @@ -2292,8 +2328,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_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 99% 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 index 351c0bc61f..5efc2662c4 100644 --- a/components/bt/bluedroid/bta/include/bta/bta_av_api.h +++ b/components/bt/host/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/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 99% 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 index b9e98b4653..3ef102c5aa 100644 --- a/components/bt/bluedroid/bta/include/bta/bta_dm_co.h +++ b/components/bt/host/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/spi_flash/esp_spi_flash_chip.h b/components/bt/host/bluedroid/bta/include/bta/bta_gap_bt_co.h similarity index 55% rename from components/spi_flash/esp_spi_flash_chip.h rename to components/bt/host/bluedroid/bta/include/bta/bta_gap_bt_co.h index a33bb13c68..9e030ec354 100644 --- a/components/spi_flash/esp_spi_flash_chip.h +++ b/components/bt/host/bluedroid/bta/include/bta/bta_gap_bt_co.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 @@ -12,20 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -/* Private header with chip-specific routines for SPI flash interaction */ -#pragma once -#include -#include -#include "sdkconfig.h" -#include "esp_attr.h" -#if CONFIG_IDF_TARGET_ESP32 -#include "esp32/rom/spi_flash.h" -#elif CONFIG_IDF_TARGET_ESP32S2BETA -#include "esp32s2beta/rom/spi_flash.h" -#endif +/****************************************************************************** + * + * This is the interface file for BT GAP call-out functions. + * + ******************************************************************************/ +#ifndef BTA_GAP_BT_CO_H +#define BTA_GAP_BT_CO_H -esp_rom_spiflash_result_t spi_flash_write_encrypted_chip(size_t dest_addr, const void *src, size_t size); +#if (BTC_GAP_BT_INCLUDED == TRUE) -esp_rom_spiflash_result_t IRAM_ATTR spi_flash_unlock(); +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/bta/include/bta/bta_gatt_api.h b/components/bt/host/bluedroid/bta/include/bta/bta_gatt_api.h similarity index 98% 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 index 896ca151cc..d2d89f0789 100644 --- a/components/bt/bluedroid/bta/include/bta/bta_gatt_api.h +++ b/components/bt/host/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 @@ -201,6 +200,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 +408,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 +616,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 { @@ -873,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, @@ -1198,7 +1205,7 @@ extern void BTA_GATTC_ConfigureMTU (UINT16 conn_id); ** Returns None ** *******************************************************************************/ -extern void BTA_GATTS_Init(); +extern void BTA_GATTS_Init(void); /******************************************************************************* ** @@ -1226,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); /******************************************************************************* @@ -1261,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); /******************************************************************************* @@ -1296,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); /******************************************************************************* @@ -1319,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_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 92% 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 index b88c0c263c..1d32b9204f 100644 --- a/components/bt/bluedroid/bta/include/bta/bta_sdp_api.h +++ b/components/bt/host/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/include/bta/bta_sys.h b/components/bt/host/bluedroid/bta/include/bta/bta_sys.h similarity index 99% rename from components/bt/bluedroid/bta/include/bta/bta_sys.h rename to components/bt/host/bluedroid/bta/include/bta/bta_sys.h index a58773de73..a466028b95 100644 --- a/components/bt/bluedroid/bta/include/bta/bta_sys.h +++ b/components/bt/host/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/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 99% rename from components/bt/bluedroid/bta/jv/bta_jv_act.c rename to components/bt/host/bluedroid/bta/jv/bta_jv_act.c index ecef90b122..eca76c9a43 100644 --- a/components/bt/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/bluedroid/bta/jv/bta_jv_api.c b/components/bt/host/bluedroid/bta/jv/bta_jv_api.c similarity index 98% rename from components/bt/bluedroid/bta/jv/bta_jv_api.c rename to components/bt/host/bluedroid/bta/jv/bta_jv_api.c index 5430d36bcb..98465701db 100644 --- a/components/bt/bluedroid/bta/jv/bta_jv_api.c +++ b/components/bt/host/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/host/bluedroid/bta/jv/bta_jv_cfg.c similarity index 94% rename from components/bt/bluedroid/bta/jv/bta_jv_cfg.c rename to components/bt/host/bluedroid/bta/jv/bta_jv_cfg.c index f617dfc513..9020efb8ab 100644 --- a/components/bt/bluedroid/bta/jv/bta_jv_cfg.c +++ b/components/bt/host/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/host/bluedroid/bta/jv/bta_jv_main.c similarity index 99% rename from components/bt/bluedroid/bta/jv/bta_jv_main.c rename to components/bt/host/bluedroid/bta/jv/bta_jv_main.c index 9523d6e893..b09ebcd469 100644 --- a/components/bt/bluedroid/bta/jv/bta_jv_main.c +++ b/components/bt/host/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/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 86% rename from components/bt/bluedroid/bta/sdp/bta_sdp_api.c rename to components/bt/host/bluedroid/bta/sdp/bta_sdp_api.c index 1d027cb79e..e26f93910c 100644 --- a/components/bt/bluedroid/bta/sdp/bta_sdp_api.c +++ b/components/bt/host/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/host/bluedroid/bta/sdp/bta_sdp_cfg.c similarity index 92% rename from components/bt/bluedroid/bta/sdp/bta_sdp_cfg.c rename to components/bt/host/bluedroid/bta/sdp/bta_sdp_cfg.c index fff5e321a2..322b25caec 100644 --- a/components/bt/bluedroid/bta/sdp/bta_sdp_cfg.c +++ b/components/bt/host/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/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 99% rename from components/bt/bluedroid/bta/sys/bta_sys_main.c rename to components/bt/host/bluedroid/bta/sys/bta_sys_main.c index e3b8c77fa9..1ea2ccd702 100644 --- a/components/bt/bluedroid/bta/sys/bta_sys_main.c +++ b/components/bt/host/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" @@ -481,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; @@ -571,7 +574,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_MAX_TIMEOUT) == false) { osi_free(p_msg); } } @@ -591,7 +594,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_MAX_TIMEOUT); } void bta_sys_start_timer(TIMER_LIST_ENT *p_tle, UINT16 type, INT32 timeout_ms) 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 99% rename from components/bt/bluedroid/btc/core/btc_ble_storage.c rename to components/bt/host/bluedroid/btc/core/btc_ble_storage.c index c8590ce803..ecbe709364 100644 --- a/components/bt/bluedroid/btc/core/btc_ble_storage.c +++ b/components/bt/host/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) { @@ -774,7 +777,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 +820,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)) { @@ -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_config.c b/components/bt/host/bluedroid/btc/core/btc_config.c similarity index 99% rename from components/bt/bluedroid/btc/core/btc_config.c rename to components/bt/host/bluedroid/btc/core/btc_config.c index b987a32e0c..fdababfe08 100644 --- a/components/bt/bluedroid/btc/core/btc_config.c +++ b/components/bt/host/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 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 85% rename from components/bt/bluedroid/btc/core/btc_dm.c rename to components/bt/host/bluedroid/btc/core/btc_dm.c index f3b9caeb42..5b712dbf17 100644 --- a/components/bt/bluedroid/btc/core/btc_dm.c +++ b/components/bt/host/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_MEMORY == FALSE +btc_dm_cb_t btc_dm_cb = {0}; +#else +btc_dm_cb_t *btc_dm_cb_ptr; #endif /****************************************************************************** @@ -129,23 +129,24 @@ static void btc_disable_bluetooth_evt(void) } #if (SMP_INCLUDED == TRUE) +#if (BLE_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 +154,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 +174,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 +184,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 +253,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); } @@ -297,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) @@ -487,12 +488,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 +531,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 +544,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); @@ -570,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 */ @@ -634,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; @@ -655,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) { @@ -669,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; @@ -693,9 +698,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 +708,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 +717,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 +726,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 +735,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 +744,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 +783,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 +806,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_main.c b/components/bt/host/bluedroid/btc/core/btc_main.c similarity index 96% rename from components/bt/bluedroid/btc/core/btc_main.c rename to components/bt/host/bluedroid/btc/core/btc_main.c index 75a2cd45cf..c91aedfb18 100644 --- a/components/bt/bluedroid/btc/core/btc_main.c +++ b/components/bt/host/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_profile_queue.c b/components/bt/host/bluedroid/btc/core/btc_profile_queue.c similarity index 99% rename from components/bt/bluedroid/btc/core/btc_profile_queue.c rename to components/bt/host/bluedroid/btc/core/btc_profile_queue.c index 6d01b0d19f..3e5603db83 100644 --- a/components/bt/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/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 90% rename from components/bt/bluedroid/btc/core/btc_util.c rename to components/bt/host/bluedroid/btc/core/btc_util.c index 633b03c60d..4174a1152f 100644 --- a/components/bt/bluedroid/btc/core/btc_util.c +++ b/components/bt/host/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_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 89% rename from components/bt/bluedroid/btc/include/btc/btc_dm.h rename to components/bt/host/bluedroid/btc/include/btc/btc_dm.h index b6e7741ef6..4035969214 100644 --- a/components/bt/bluedroid/btc/include/btc/btc_dm.h +++ b/components/bt/host/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_MEMORY == 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_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 96% rename from components/bt/bluedroid/btc/include/btc/btc_util.h rename to components/bt/host/bluedroid/btc/include/btc/btc_util.h index df44297c3b..bc0570dd37 100644 --- a/components/bt/bluedroid/btc/include/btc/btc_util.h +++ b/components/bt/host/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/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 98% 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 index 45c220b3ba..25ebba40d8 100644 --- a/components/bt/bluedroid/btc/profile/esp/blufi/blufi_prf.c +++ b/components/bt/host/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/host/bluedroid/btc/profile/esp/blufi/blufi_protocol.c similarity index 99% 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 index b962d10051..ab81eac507 100644 --- a/components/bt/bluedroid/btc/profile/esp/blufi/blufi_protocol.c +++ b/components/bt/host/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/host/bluedroid/btc/profile/esp/blufi/include/blufi_int.h similarity index 93% 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 index 08be6703f5..cd6f5a200b 100644 --- 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 @@ -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/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 95% 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 index 2e72bd8cba..a3250cdac5 100644 --- 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 @@ -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.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 70% 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 index a5d09b2ca1..9ef243231c 100644 --- 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 @@ -45,6 +45,8 @@ #if (BTC_AV_SINK_INCLUDED == TRUE) +extern osi_thread_t *btc_thread; + /***************************************************************************** ** Constants *****************************************************************************/ @@ -64,10 +66,6 @@ enum { BTC_A2DP_SINK_STATE_SHUTTING_DOWN = 2 }; -enum { - BTC_A2DP_SINK_DATA_EVT = 0, -}; - /* * CONGESTION COMPENSATION CTRL :: * @@ -90,6 +88,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; @@ -104,6 +107,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); @@ -115,19 +127,19 @@ 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 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) { @@ -143,21 +155,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 @@ -174,26 +171,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(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(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 +201,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 +212,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) @@ -245,38 +227,21 @@ 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"); + 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; } -#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); - if (btc_aa_snk_task_hdl == NULL) { - goto error_exit; - } - - btc_a2dp_sink_ctrl_post(BTC_MEDIA_TASK_SINK_INIT, NULL); APPL_TRACE_EVENT("## A2DP SINK MEDIA THREAD STARTED ##\n"); @@ -284,38 +249,12 @@ bool btc_a2dp_sink_startup(void) error_exit:; APPL_TRACE_ERROR("%s unable to start up media thread\n", __func__); + a2dp_sink_local_param.btc_aa_snk_task_hdl = NULL; - if (btc_aa_snk_task_hdl != NULL) { - vTaskDelete(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); - 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; } @@ -326,34 +265,18 @@ 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; - vTaskDelete(btc_aa_snk_task_hdl); - btc_aa_snk_task_hdl = NULL; + a2dp_sink_local_param.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; - - 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 } /***************************************************************************** @@ -364,7 +287,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(); @@ -379,7 +302,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); } @@ -392,16 +315,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(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(a2dp_sink_local_param.btc_aa_snk_task_hdl, btc_a2dp_sink_data_ready, NULL, 2, OSI_THREAD_MAX_TIMEOUT); } /******************************************************************************* @@ -415,15 +336,14 @@ 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 */ 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; } /***************************************************************************** @@ -457,20 +377,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_dequeue(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ, 0); if ( p_msg == NULL ) { APPL_TRACE_ERROR("Insufficient data in que "); break; @@ -510,13 +430,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); } @@ -632,14 +552,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; } @@ -653,7 +573,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); @@ -667,7 +587,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)); } /******************************************************************************* @@ -681,12 +601,11 @@ 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; } - 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); } /******************************************************************************* @@ -703,7 +622,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) @@ -759,13 +678,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 + "); @@ -776,13 +695,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); - btc_a2dp_sink_data_post(BTC_A2DP_SINK_DATA_EVT); + 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 */ 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) @@ -802,18 +721,18 @@ 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)); } } 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(); } @@ -826,9 +745,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/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c similarity index 72% 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 index 64e563b440..9cf21b91a1 100644 --- 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 @@ -50,6 +50,8 @@ #if BTC_AV_SRC_INCLUDED +extern osi_thread_t *btc_thread; + /***************************************************************************** ** Constants *****************************************************************************/ @@ -72,9 +74,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 +126,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; @@ -156,9 +160,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); @@ -174,24 +186,16 @@ 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 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) { @@ -226,7 +230,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) @@ -234,26 +238,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 bool 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; + return false; } 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); - } + 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(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 +274,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 +288,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) @@ -314,36 +303,21 @@ 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"); + 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; } -#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); - 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"); @@ -351,30 +325,13 @@ bool btc_a2dp_source_startup(void) error_exit:; APPL_TRACE_ERROR("%s unable to start up media thread\n", __func__); + a2dp_source_local_param.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 A2D_DYNAMIC_MEMORY == TRUE + osi_free(a2dp_source_local_param_ptr); + a2dp_source_local_param_ptr = NULL; +#endif - 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; } @@ -384,28 +341,18 @@ 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; - vTaskDelete(btc_aa_src_task_hdl); - btc_aa_src_task_hdl = NULL; + a2dp_source_local_param.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; -#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 } /***************************************************************************** @@ -438,7 +385,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(); @@ -466,20 +413,18 @@ 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(); } -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(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; @@ -497,7 +442,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); } @@ -506,7 +451,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; } /***************************************************************************** @@ -565,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(btc_aa_src_cb.TxAaQ); + return fixed_queue_dequeue(a2dp_source_local_param.btc_aa_src_cb.TxAaQ, 0); } /******************************************************************************* @@ -604,9 +549,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 +645,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; } @@ -817,35 +770,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); } @@ -862,7 +815,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; @@ -873,9 +826,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; @@ -954,19 +907,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 { @@ -983,10 +936,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)); } } @@ -1017,10 +970,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; @@ -1029,10 +982,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; @@ -1042,21 +995,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__); } @@ -1078,13 +1031,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; @@ -1108,10 +1061,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); } @@ -1129,35 +1082,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; } @@ -1166,7 +1119,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); } @@ -1174,7 +1127,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; } @@ -1194,13 +1147,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 @@ -1213,7 +1166,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; @@ -1228,19 +1181,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; } } @@ -1249,7 +1202,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; @@ -1265,26 +1218,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); @@ -1299,7 +1252,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; @@ -1307,34 +1260,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; } @@ -1354,13 +1307,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; } @@ -1371,53 +1324,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); @@ -1425,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(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); } @@ -1448,24 +1401,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_dequeue(a2dp_source_local_param.btc_aa_src_cb.TxAaQ, 0)); } // 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; } } @@ -1505,7 +1458,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"); @@ -1515,7 +1468,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(); } /******************************************************************************* @@ -1530,17 +1483,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); } } @@ -1556,26 +1509,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); } /******************************************************************************* @@ -1589,17 +1542,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 @@ -1617,8 +1570,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(); @@ -1636,18 +1589,18 @@ 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)); } } 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(); } @@ -1660,9 +1613,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/host/bluedroid/btc/profile/std/a2dp/btc_av.c similarity index 97% 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 index f428150bae..be1f1f9628 100644 --- a/components/bt/bluedroid/btc/profile/std/a2dp/btc_av.c +++ b/components/bt/host/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/host/bluedroid/btc/profile/std/a2dp/include/btc_av_co.h similarity index 69% 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 index cacaa01d8f..a7943b70cb 100644 --- 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 @@ -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/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 94% 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 index 6e204be482..0e4d0e4922 100644 --- a/components/bt/bluedroid/btc/profile/std/avrc/btc_avrc.c +++ b/components/bt/host/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, @@ -101,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 */ @@ -665,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 * @@ -852,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); } @@ -1031,7 +1016,7 @@ 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)); } } @@ -1059,7 +1044,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__); @@ -1085,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 @@ -1118,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 @@ -1152,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 @@ -1194,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 @@ -1368,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/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/host/bluedroid/btc/profile/std/gap/bta_gap_bt_co.c b/components/bt/host/bluedroid/btc/profile/std/gap/bta_gap_bt_co.c new file mode 100644 index 0000000000..9710dcfa7a --- /dev/null +++ b/components/bt/host/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_ble.c b/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c similarity index 99% 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 index ffac0c35f6..9f02cc26f5 100644 --- 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 @@ -31,8 +31,15 @@ #include "osi/mutex.h" #include "esp_bt.h" +#if (BLE_INCLUDED == TRUE) +#if BTC_DYNAMIC_MEMORY == 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; @@ -1366,3 +1373,4 @@ void btc_adv_list_unlock(void) osi_mutex_unlock(&adv_list_lock); } #endif +#endif ///BLE_INCLUDED == TRUE 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 91% 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 index 8de802f2ea..af2cfd2068 100644 --- 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 @@ -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/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 99% 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 index 8653f60561..37497a8afc 100644 --- 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 @@ -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_gattc.c b/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gattc.c similarity index 99% 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 index 5eaee361b8..73214a67dc 100644 --- a/components/bt/bluedroid/btc/profile/std/gatt/btc_gattc.c +++ b/components/bt/host/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/host/bluedroid/btc/profile/std/gatt/btc_gatts.c similarity index 98% 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 index eff4d41a1e..117b6b8614 100644 --- a/components/bt/bluedroid/btc/profile/std/gatt/btc_gatts.c +++ b/components/bt/host/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,13 +411,15 @@ 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; memcpy(¶m.add_attr_tab.svc_uuid, &btc_creat_tab_env.svc_uuid, sizeof(esp_bt_uuid_t)); - btc_gatts_cb_to_app(ESP_GATTS_CREAT_ATTR_TAB_EVT, gatts_if, ¶m); + 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)); @@ -502,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); } @@ -566,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; @@ -661,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; @@ -670,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; } @@ -698,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: { @@ -783,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; } @@ -901,7 +895,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/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 97% 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 index 6e756fc6ce..99b9280304 100644 --- 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 @@ -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; /******************************************************************************* ** @@ -212,30 +212,32 @@ 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:; + 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; + } + +#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; } @@ -272,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/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 76% 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 index 3ae296cf0f..d3ccd66997 100644 --- 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 @@ -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,9 +161,9 @@ 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 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; @@ -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/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 65% 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 index 7eaabecc17..2ff164b50d 100644 --- a/components/bt/bluedroid/btc/profile/std/include/btc_avrc.h +++ b/components/bt/host/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 */ @@ -86,6 +96,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_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 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/host/bluedroid/btc/profile/std/include/btc_gap_ble.h similarity index 95% 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 index be818269b2..3af1559ff8 100644 --- 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 @@ -18,6 +18,14 @@ #include "esp_bt_defs.h" #include "esp_gap_ble_api.h" +#if BTC_DYNAMIC_MEMORY == 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_gap_bt.h b/components/bt/host/bluedroid/btc/profile/std/include/btc_gap_bt.h similarity index 94% 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 51e685965b..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" @@ -32,6 +33,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 +50,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 +127,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/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 90% 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 index cad973a8a6..5cf1e84161 100644 --- a/components/bt/bluedroid/btc/profile/std/include/btc_gatts.h +++ b/components/bt/host/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/host/bluedroid/btc/profile/std/include/btc_hf_client.h similarity index 78% 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 index 6500b9d878..04226e72a2 100644 --- 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 @@ -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/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 99% 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 index e1ec079b4a..c6bbadea7f 100644 --- 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 @@ -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/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 97% 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 index bc2d62427d..912c57035a 100644 --- a/components/bt/bluedroid/btc/profile/std/spp/btc_spp.c +++ b/components/bt/host/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) @@ -816,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/common/include/common/bluedroid_user_config.h b/components/bt/host/bluedroid/common/include/common/bluedroid_user_config.h new file mode 100644 index 0000000000..b107a01e15 --- /dev/null +++ b/components/bt/host/bluedroid/common/include/common/bluedroid_user_config.h @@ -0,0 +1,317 @@ +// 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 __BLUEDROID_USER_CONFIG_H__ +#define __BLUEDROID_USER_CONFIG_H__ + +/* All the configuration from SDK defined here */ +#include "bt_common.h" +#include "bt_user_config.h" + +/********************************************************** + * Thread/Task reference + **********************************************************/ + +#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 + +//BLE +#ifdef CONFIG_BT_BLE_ENABLED +#define UC_BT_BLE_ENABLED CONFIG_BT_BLE_ENABLED +#else +#define UC_BT_BLE_ENABLED FALSE +#endif + +//GATTS +#ifdef CONFIG_BT_GATTS_ENABLE +#define UC_BT_GATTS_ENABLE CONFIG_BT_GATTS_ENABLE +#else +#define UC_BT_GATTS_ENABLE FALSE +#endif + +//GATTC +#ifdef CONFIG_BT_GATTC_ENABLE +#define UC_BT_GATTC_ENABLE CONFIG_BT_GATTC_ENABLE +#else +#define UC_BT_GATTC_ENABLE 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_ENABLE CONFIG_BT_SMP_ENABLE +#else +#define UC_BT_SMP_ENABLE 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 + **********************************************************/ + +//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_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_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 /* __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 77719bc847..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,31 +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_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 93% rename from components/bt/bluedroid/common/include/common/bt_target.h rename to components/bt/host/bluedroid/common/include/common/bt_target.h index 0ea6939f81..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,17 +36,22 @@ #include "bdroid_buildcfg.h" #endif -#include "sdkconfig.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 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 @@ -53,7 +60,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 @@ -66,15 +73,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 @@ -87,96 +94,91 @@ #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_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 #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 +#if (BLE_INCLUDED == TRUE) +#define BLE_PRIVACY_SPT TRUE #else -#define SMP_INCLUDED FALSE -#define BLE_PRIVACY_SPT FALSE -#endif /* CONFIG_BT_SMP_ENABLE */ +#define BLE_PRIVACY_SPT FALSE +#endif /*BLE_INCLUDED*/ +#else +#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--------------------- @@ -333,7 +335,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 @@ -349,34 +351,26 @@ #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 @@ -404,7 +398,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 @@ -589,11 +583,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 */ @@ -1035,7 +1029,7 @@ ******************************************************************************/ #ifndef BLE_INCLUDED -#define BLE_INCLUDED TRUE +#define BLE_INCLUDED FALSE #endif #ifndef BLE_ANDROID_CONTROLLER_SCAN_FILTER @@ -1073,6 +1067,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 @@ -1119,7 +1121,7 @@ #endif #ifndef ATT_DEBUG -#define ATT_DEBUG FALSE//TRUE +#define ATT_DEBUG FALSE #endif #ifndef BLE_PERIPHERAL_MODE_SUPPORT @@ -1184,12 +1186,6 @@ #endif #endif - -#if SMP_INCLUDED == TRUE && BLE_INCLUDED == FALSE -#error "can't have SMP without BLE" -#endif - - /****************************************************************************** ** ** SMP @@ -1203,10 +1199,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 @@ -1521,12 +1513,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 /* @@ -1534,7 +1526,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 @@ -1647,22 +1639,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 */ @@ -1984,7 +1976,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 /****************************************************************************** @@ -2026,7 +2018,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 /****************************************************************************** @@ -2037,7 +2029,19 @@ 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 #include "common/bt_trace.h" 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 79% rename from components/bt/bluedroid/common/include/common/bt_trace.h rename to components/bt/host/bluedroid/common/include/common/bt_trace.h index a0dbf9bc72..09412ca7f3 100644 --- a/components/bt/bluedroid/common/include/common/bt_trace.h +++ b/components/bt/host/bluedroid/common/include/common/bt_trace.h @@ -19,43 +19,11 @@ #ifndef _BT_TRACE_H_ #define _BT_TRACE_H_ -#include "sdkconfig.h" - #include #include +#include "bluedroid_user_config.h" #include "stack/bt_types.h" - -#ifndef LOG_LOCAL_LEVEL -#ifndef BOOTLOADER_BUILD -#define LOG_LOCAL_LEVEL CONFIG_LOG_DEFAULT_LEVEL -#else -#define LOG_LOCAL_LEVEL CONFIG_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) { @@ -217,135 +185,29 @@ 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 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__); } @@ -498,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);} @@ -672,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...) @@ -695,7 +525,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_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/host/bluedroid/device/controller.c b/components/bt/host/bluedroid/device/controller.c new file mode 100644 index 0000000000..2c2ac129f2 --- /dev/null +++ b/components/bt/host/bluedroid/device/controller.c @@ -0,0 +1,563 @@ +/****************************************************************************** + * + * 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 "common/bt_target.h" +#include "common/bt_trace.h" +#include "device/bdaddr.h" +#include "stack/bt_types.h" +#include "device/controller.h" +#include "device/event_mask.h" +#include "stack/hcimsgs.h" +#include "hci/hci_layer.h" +#include "hci/hci_packet_factory.h" +#include "hci/hci_packet_parser.h" +#include "stack/btm_ble_api.h" +#include "device/version.h" +#include "osi/future.h" + +const bt_event_mask_t BLE_EVENT_MASK = { "\x00\x00\x00\x00\x00\x00\x06\x7f" }; + +#if (BLE_INCLUDED) +const bt_event_mask_t CLASSIC_EVENT_MASK = { HCI_DUMO_EVENT_MASK_EXT }; +#else +const bt_event_mask_t CLASSIC_EVENT_MASK = { HCI_LISBON_EVENT_MASK_EXT }; +#endif + +// TODO(zachoverflow): factor out into common module +const uint8_t SCO_HOST_BUFFER_SIZE = 0xff; + +#define HCI_SUPPORTED_COMMANDS_ARRAY_SIZE 64 +#define MAX_FEATURES_CLASSIC_PAGE_COUNT 3 +#define BLE_SUPPORTED_STATES_SIZE 8 +#define BLE_SUPPORTED_FEATURES_SIZE 8 + +typedef struct { + const hci_t *hci; + const hci_packet_factory_t *packet_factory; + const hci_packet_parser_t *packet_parser; + + bt_version_t bt_version; + bt_bdaddr_t address; + + 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]; + + uint16_t acl_data_size_classic; + uint16_t acl_data_size_ble; + uint16_t acl_buffer_count_classic; + uint8_t acl_buffer_count_ble; + + uint8_t sco_data_size; + uint16_t sco_buffer_count; + + 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; + + bool readable; + bool ble_supported; + bool simple_pairing_supported; + bool secure_connections_supported; +} controller_local_param_t; + +#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 + +static void start_up(void) +{ + BT_HDR *response; + + // Send the initial reset command + 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(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(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 + 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? + response = AWAIT_COMMAND( + controller_param.packet_factory->make_host_buffer_size( + L2CAP_MTU_SIZE, + SCO_HOST_BUFFER_SIZE, + L2CAP_HOST_FC_ACL_BUFS, + 10 + ) + ); + + 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(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(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(controller_param.packet_factory->make_read_local_supported_commands()); + controller_param.packet_parser->parse_read_local_supported_commands_response( + response, + 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(controller_param.packet_factory->make_read_local_extended_features(page_number)); + controller_param.packet_parser->parse_read_local_extended_features_response( + response, + &page_number, + &controller_param.last_features_classic_page_index, + controller_param.features_classic, + MAX_FEATURES_CLASSIC_PAGE_COUNT + ); + + assert(page_number == 0); + page_number++; + + // Inform the controller what page 0 features we support, based on what + // it told us it supports. We need to do this first before we request the + // 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) + controller_param.simple_pairing_supported = HCI_SIMPLE_PAIRING_SUPPORTED(controller_param.features_classic[0].as_array); +#else + controller_param.simple_pairing_supported = false; +#endif + + 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(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( + controller_param.packet_factory->make_ble_write_host_support(BTM_BLE_HOST_SUPPORT, simultaneous_le_host) + ); + + 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 <= controller_param.last_features_classic_page_index && + page_number < MAX_FEATURES_CLASSIC_PAGE_COUNT) { + 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, + &controller_param.last_features_classic_page_index, + controller_param.features_classic, + MAX_FEATURES_CLASSIC_PAGE_COUNT + ); + + page_number++; + } + +#if (SC_MODE_INCLUDED == TRUE) + 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) + 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(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(controller_param.packet_factory->make_ble_read_buffer_size()); + controller_param.packet_parser->parse_ble_read_buffer_size_response( + response, + &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 (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(controller_param.packet_factory->make_ble_read_supported_states()); + controller_param.packet_parser->parse_ble_read_supported_states_response( + response, + controller_param.ble_supported_states, + sizeof(controller_param.ble_supported_states) + ); + + // Request the ble supported features next + 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, + &controller_param.features_ble + ); + + 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, + &controller_param.ble_resolving_list_max_size); + } + + if (HCI_LE_DATA_LEN_EXT_SUPPORTED(controller_param.features_ble.as_array)) { + /* set default tx data length to MAX 251 */ + 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(controller_param.packet_factory->make_ble_read_suggested_default_data_length()); + controller_param.packet_parser->parse_ble_read_suggested_default_data_length_response( + response, + &controller_param.ble_suggested_default_data_length, + &controller_param.ble_suggested_default_data_txtime); + } + + // Set the ble event mask next + 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(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(controller_param.packet_factory->make_write_sync_flow_control_enable(1)); + controller_param.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 + controller_param.readable = true; + // return future_new_immediate(FUTURE_SUCCESS); + return; +} + +static void shut_down(void) +{ + controller_param.readable = false; +} + +static bool get_is_ready(void) +{ + return controller_param.readable; +} + +static const bt_bdaddr_t *get_address(void) +{ + assert(controller_param.readable); + return &controller_param.address; +} + +static const bt_version_t *get_bt_version(void) +{ + 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(controller_param.readable); + assert(index < MAX_FEATURES_CLASSIC_PAGE_COUNT); + return &controller_param.features_classic[index]; +} + +static uint8_t get_last_features_classic_index(void) +{ + assert(controller_param.readable); + return controller_param.last_features_classic_page_index; +} + +static const bt_device_features_t *get_features_ble(void) +{ + assert(controller_param.readable); + assert(controller_param.ble_supported); + return &controller_param.features_ble; +} + +static const uint8_t *get_ble_supported_states(void) +{ + assert(controller_param.readable); + assert(controller_param.ble_supported); + return controller_param.ble_supported_states; +} + +static bool supports_simple_pairing(void) +{ + assert(controller_param.readable); + return controller_param.simple_pairing_supported; +} + +static bool supports_secure_connections(void) +{ + assert(controller_param.readable); + return controller_param.secure_connections_supported; +} + +static bool supports_simultaneous_le_bredr(void) +{ + 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(controller_param.readable); + return HCI_READ_REMOTE_EXT_FEATURES_SUPPORTED(controller_param.supported_commands); +} + +static bool supports_interlaced_inquiry_scan(void) +{ + 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(controller_param.readable); + return HCI_LMP_INQ_RSSI_SUPPORTED(controller_param.features_classic[0].as_array); +} + +static bool supports_extended_inquiry_response(void) +{ + 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(controller_param.readable); + return HCI_SWITCH_SUPPORTED(controller_param.features_classic[0].as_array); +} + +static bool supports_ble(void) +{ + assert(controller_param.readable); + return controller_param.ble_supported; +} + +static bool supports_ble_privacy(void) +{ + 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(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(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(controller_param.readable); + return controller_param.acl_data_size_classic; +} + +static uint16_t get_acl_data_size_ble(void) +{ + 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(controller_param.readable); + return controller_param.acl_data_size_classic + HCI_DATA_PREAMBLE_SIZE; +} + +static uint16_t get_acl_packet_size_ble(void) +{ + 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(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(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(controller_param.readable); + return controller_param.acl_buffer_count_classic; +} + +static uint8_t get_acl_buffer_count_ble(void) +{ + 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(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(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(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(controller_param.readable); + return controller_param.sco_data_size; +} + +static uint8_t get_sco_buffer_count(void) +{ + assert(controller_param.readable); + return controller_param.sco_buffer_count; +} +#endif /* (BTM_SCO_HCI_INCLUDED == TRUE) */ + +static const controller_t interface = { + start_up, + shut_down, + get_is_ready, + + get_address, + get_bt_version, + + get_features_classic, + get_last_features_classic_index, + + get_features_ble, + get_ble_supported_states, + + supports_simple_pairing, + supports_secure_connections, + supports_simultaneous_le_bredr, + supports_reading_remote_extended_features, + supports_interlaced_inquiry_scan, + supports_rssi_with_inquiry_results, + supports_extended_inquiry_response, + supports_master_slave_role_switch, + + supports_ble, + supports_ble_packet_extension, + supports_ble_connection_parameters_request, + supports_ble_privacy, + + get_acl_data_size_classic, + get_acl_data_size_ble, + + get_acl_packet_size_classic, + get_acl_packet_size_ble, + get_ble_suggested_default_data_length, + get_ble_suggested_default_data_txtime, + + get_acl_buffer_count_classic, + get_acl_buffer_count_ble, + + get_ble_white_list_size, + + get_ble_resolving_list_max_size, + set_ble_resolving_list_max_size, +#if (BTM_SCO_HCI_INCLUDED == TRUE) + get_sco_data_size, + get_sco_buffer_count, +#endif /* (BTM_SCO_HCI_INCLUDED == TRUE) */ +}; + +const controller_t *controller_get_interface(void) +{ + static bool loaded = false; + if (!loaded) { + loaded = 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 + 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/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 98% rename from components/bt/bluedroid/device/include/device/controller.h rename to components/bt/host/bluedroid/device/include/device/controller.h index 704b456d7f..bb09863528 100644 --- a/components/bt/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/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 98% 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 index 12878f3156..a2d6db43c8 100644 --- a/components/bt/bluedroid/external/sbc/encoder/srce/sbc_analysis.c +++ b/components/bt/host/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/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 88% rename from components/bt/bluedroid/hci/hci_hal_h4.c rename to components/bt/host/bluedroid/hci/hci_hal_h4.c index 89fba87b5d..85d3598dc1 100644 --- a/components/bt/bluedroid/hci/hci_hal_h4.c +++ b/components/bt/host/bluedroid/hci/hci_hal_h4.c @@ -30,6 +30,7 @@ #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 +64,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); @@ -100,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 @@ -110,8 +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 - 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_t *)task_thread; //register vhci host cb if (esp_vhci_host_register_callback(&vhci_host_cb) != ESP_OK) { @@ -121,13 +121,11 @@ static bool hal_open(const hci_hal_callbacks_t *upper_callbacks) return true; } -static void hal_close() +static void hal_close(void) { hci_hal_env_deinit(); - /* delete task and queue */ - vTaskDelete(xHciH4TaskHandle); - vQueueDelete(xHciH4Queue); + hci_h4_thread = NULL; } /** @@ -169,30 +167,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(uint32_t timeout) { - 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, 1, timeout); } #if (C2H_FLOW_CONTROL_INCLUDED == TRUE) @@ -321,7 +301,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; } @@ -334,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); } } @@ -343,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(TASK_POST_BLOCKING); + hci_host_task_post(OSI_THREAD_MAX_TIMEOUT); } static int host_recv_pkt_cb(uint8_t *data, uint16_t len) @@ -367,9 +347,10 @@ 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); + 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); return 0; @@ -386,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/bluedroid/hci/hci_layer.c b/components/bt/host/bluedroid/hci/hci_layer.c similarity index 87% rename from components/bt/bluedroid/hci/hci_layer.c rename to components/bt/host/bluedroid/hci/hci_layer.c index c2b6223ce7..2068062bf9 100644 --- a/components/bt/bluedroid/hci/hci_layer.c +++ b/components/bt/host/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,11 @@ #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 (BT_TASK_MAX_PRIORITIES - 3) +#define HCI_HOST_TASK_NAME "hciT" + typedef struct { uint16_t opcode; future_t *complete_future; @@ -70,10 +76,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,11 +105,13 @@ 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, 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; @@ -124,28 +129,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(uint32_t timeout) { - 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, timeout); } static int hci_layer_init_env(void) @@ -218,27 +210,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); } } } @@ -270,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(TASK_POST_BLOCKING); + fixed_queue_enqueue(hci_host_env.command_queue, wait_entry, FIXED_QUEUE_MAX_TIMEOUT); + hci_host_task_post(OSI_THREAD_MAX_TIMEOUT); } @@ -291,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(TASK_POST_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; } @@ -302,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(TASK_POST_BLOCKING); + hci_host_task_post(OSI_THREAD_MAX_TIMEOUT); } @@ -315,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) @@ -341,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); @@ -479,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(TASK_POST_BLOCKING); + hci_host_task_post(OSI_THREAD_MAX_TIMEOUT); } if (wait_entry) { @@ -507,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, TASK_POST_BLOCKING) != TASK_POST_SUCCESS) { + if (btu_task_post(SIG_BTU_HCI_MSG, packet, OSI_THREAD_MAX_TIMEOUT) == false) { osi_free(packet); } } @@ -553,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; @@ -573,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/bluedroid/hci/hci_packet_factory.c b/components/bt/host/bluedroid/hci/hci_packet_factory.c similarity index 99% rename from components/bt/bluedroid/hci/hci_packet_factory.c rename to components/bt/host/bluedroid/hci/hci_packet_factory.c index 19641d1046..0145a138b4 100644 --- a/components/bt/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/bluedroid/hci/hci_packet_parser.c b/components/bt/host/bluedroid/hci/hci_packet_parser.c similarity index 99% rename from components/bt/bluedroid/hci/hci_packet_parser.c rename to components/bt/host/bluedroid/hci/hci_packet_parser.c index eb4dc72f0b..a99ef8b0d1 100644 --- a/components/bt/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/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 97% rename from components/bt/bluedroid/hci/include/hci/hci_hal.h rename to components/bt/host/bluedroid/hci/include/hci/hci_hal.h index 2928f29ad3..daf3dfb81a 100644 --- a/components/bt/bluedroid/hci/include/hci/hci_hal.h +++ b/components/bt/host/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); 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 96% rename from components/bt/bluedroid/hci/include/hci/hci_layer.h rename to components/bt/host/bluedroid/hci/include/hci/hci_layer.h index 4b1018098b..6bfacdff5c 100644 --- a/components/bt/bluedroid/hci/include/hci/hci_layer.h +++ b/components/bt/host/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 */ @@ -90,10 +92,11 @@ 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); +bool hci_host_task_post(uint32_t timeout); #endif /* _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 97% 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 index fd8731fbc2..37ced06be3 100644 --- a/components/bt/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/bluedroid/hci/include/hci/hci_packet_parser.h b/components/bt/host/bluedroid/hci/include/hci/hci_packet_parser.h similarity index 97% 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 index b0cc4b3b49..e20e52fb5e 100644 --- a/components/bt/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/bluedroid/hci/include/hci/packet_fragmenter.h b/components/bt/host/bluedroid/hci/include/hci/packet_fragmenter.h similarity index 97% rename from components/bt/bluedroid/hci/include/hci/packet_fragmenter.h rename to components/bt/host/bluedroid/hci/include/hci/packet_fragmenter.h index 2855554275..02a13fb956 100644 --- a/components/bt/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/bluedroid/hci/packet_fragmenter.c b/components/bt/host/bluedroid/hci/packet_fragmenter.c similarity index 98% rename from components/bt/bluedroid/hci/packet_fragmenter.c rename to components/bt/host/bluedroid/hci/packet_fragmenter.c index 87cb99c74f..53c6b77212 100644 --- a/components/bt/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/bluedroid/main/bte_init.c b/components/bt/host/bluedroid/main/bte_init.c similarity index 73% rename from components/bt/bluedroid/main/bte_init.c rename to components/bt/host/bluedroid/main/bte_init.c index 38cfc812fb..7f3723ae55 100644 --- a/components/bt/bluedroid/main/bte_init.c +++ b/components/bt/host/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 @@ -144,153 +143,6 @@ tBTA_JV_CB *bta_jv_cb_ptr = NULL; ** 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; - } - 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_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 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)); -#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 @@ -308,55 +160,101 @@ 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; + 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 + 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_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) + GAP_Deinit(); +#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) @@ -366,4 +264,184 @@ void BTE_DeinitStack(void) #if (defined(A2D_INCLUDED) && A2D_INCLUDED == TRUE) A2D_Deinit(); #endif + +#if (defined(RFCOMM_INCLUDED) && RFCOMM_INCLUDED == TRUE) + 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/main/bte_main.c b/components/bt/host/bluedroid/main/bte_main.c similarity index 98% rename from components/bt/bluedroid/main/bte_main.c rename to components/bt/host/bluedroid/main/bte_main.c index 61c30e2824..c47bdc15f9 100644 --- a/components/bt/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/bluedroid/stack/a2dp/a2d_api.c b/components/bt/host/bluedroid/stack/a2dp/a2d_api.c similarity index 98% rename from components/bt/bluedroid/stack/a2dp/a2d_api.c rename to components/bt/host/bluedroid/stack/a2dp/a2d_api.c index 937e46b1e1..8adb200dcd 100644 --- a/components/bt/bluedroid/stack/a2dp/a2d_api.c +++ b/components/bt/host/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/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 99% rename from components/bt/bluedroid/stack/avct/avct_lcb_act.c rename to components/bt/host/bluedroid/stack/avct/avct_lcb_act.c index 02ac96039b..b83219dceb 100644 --- a/components/bt/bluedroid/stack/avct/avct_lcb_act.c +++ b/components/bt/host/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/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 99% rename from components/bt/bluedroid/stack/avdt/avdt_api.c rename to components/bt/host/bluedroid/stack/avdt/avdt_api.c index 88d3741306..c0adc07e6f 100644 --- a/components/bt/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/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 99% rename from components/bt/bluedroid/stack/avdt/avdt_ccb_act.c rename to components/bt/host/bluedroid/stack/avdt/avdt_ccb_act.c index 9f7b0ee9d0..7d7e7c6e77 100644 --- a/components/bt/bluedroid/stack/avdt/avdt_ccb_act.c +++ b/components/bt/host/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_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 99% rename from components/bt/bluedroid/stack/avdt/avdt_msg.c rename to components/bt/host/bluedroid/stack/avdt/avdt_msg.c index 91e993233d..4ebca9a063 100644 --- a/components/bt/bluedroid/stack/avdt/avdt_msg.c +++ b/components/bt/host/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.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 99% rename from components/bt/bluedroid/stack/avdt/avdt_scb_act.c rename to components/bt/host/bluedroid/stack/avdt/avdt_scb_act.c index b4bbcec066..4cdc5a2e36 100644 --- a/components/bt/bluedroid/stack/avdt/avdt_scb_act.c +++ b/components/bt/host/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/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 98% rename from components/bt/bluedroid/stack/avrc/avrc_sdp.c rename to components/bt/host/bluedroid/stack/avrc/avrc_sdp.c index d3616f3233..11a994d7ac 100644 --- a/components/bt/bluedroid/stack/avrc/avrc_sdp.c +++ b/components/bt/host/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/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 99% rename from components/bt/bluedroid/stack/btm/btm_acl.c rename to components/bt/host/bluedroid/stack/btm/btm_acl.c index e42724f235..d15fc6c7d6 100644 --- a/components/bt/bluedroid/stack/btm/btm_acl.c +++ b/components/bt/host/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 /******************************************************************************* ** @@ -2361,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; @@ -2392,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); } @@ -2416,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", @@ -2426,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.c b/components/bt/host/bluedroid/stack/btm/btm_ble.c similarity index 98% rename from components/bt/bluedroid/stack/btm/btm_ble.c rename to components/bt/host/bluedroid/stack/btm/btm_ble.c index 73f6387a8d..c2000d8d55 100644 --- a/components/bt/bluedroid/stack/btm/btm_ble.c +++ b/components/bt/host/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 @@ -1931,9 +1932,7 @@ void btm_ble_conn_complete(UINT8 *p, UINT16 evt_len, BOOLEAN enhanced) UINT8 role, status, bda_type; UINT16 handle; BD_ADDR bda; -#if (BLE_PRIVACY_SPT == TRUE) BD_ADDR local_rpa, peer_rpa; -#endif ///BLE_PRIVACY_SPT == TRUE UINT16 conn_interval, conn_latency, conn_timeout; BOOLEAN match = FALSE; UNUSED(evt_len); @@ -1944,14 +1943,13 @@ void btm_ble_conn_complete(UINT8 *p, UINT16 evt_len, BOOLEAN enhanced) STREAM_TO_BDADDR (bda, p); BTM_TRACE_DEBUG("status = %d, handle = %d, role = %d, bda_type = %d",status,handle,role,bda_type); if (status == 0) { -#if (BLE_PRIVACY_SPT == TRUE ) - peer_addr_type = bda_type; - match = btm_identity_addr_to_random_pseudo (bda, &bda_type, TRUE); - if (enhanced) { STREAM_TO_BDADDR (local_rpa, p); STREAM_TO_BDADDR (peer_rpa, p); } +#if (BLE_PRIVACY_SPT == TRUE ) + peer_addr_type = bda_type; + match = btm_identity_addr_to_random_pseudo (bda, &bda_type, TRUE); /* possiblly receive connection complete with resolvable random on slave role while the device has been paired */ @@ -2113,10 +2111,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]); @@ -2732,4 +2729,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_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 96% 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 index 578e2c5dbc..54cdc189f8 100644 --- a/components/bt/bluedroid/stack/btm/btm_ble_adv_filter.c +++ b/components/bt/host/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, @@ -82,18 +90,18 @@ 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; #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/host/bluedroid/stack/btm/btm_ble_batchscan.c similarity index 97% rename from components/bt/bluedroid/stack/btm/btm_ble_batchscan.c rename to components/bt/host/bluedroid/stack/btm/btm_ble_batchscan.c index d9af18d5e1..5b0fcd8ff0 100644 --- a/components/bt/bluedroid/stack/btm/btm_ble_batchscan.c +++ b/components/bt/host/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_bgconn.c b/components/bt/host/bluedroid/stack/btm/btm_ble_bgconn.c similarity index 98% rename from components/bt/bluedroid/stack/btm/btm_ble_bgconn.c rename to components/bt/host/bluedroid/stack/btm/btm_ble_bgconn.c index 0766715480..9fd3bd26fb 100644 --- a/components/bt/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) { @@ -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_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 98% rename from components/bt/bluedroid/stack/btm/btm_ble_gap.c rename to components/bt/host/bluedroid/stack/btm/btm_ble_gap.c index fff66affa8..c18d941a1a 100644 --- a/components/bt/bluedroid/stack/btm/btm_ble_gap.c +++ b/components/bt/host/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; @@ -241,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); @@ -250,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); @@ -259,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); @@ -268,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); @@ -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, @@ -1654,6 +1659,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 +1807,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; @@ -2007,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__); @@ -2024,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__); @@ -2045,6 +2055,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 @@ -4267,10 +4302,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); @@ -4315,6 +4358,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/host/bluedroid/stack/btm/btm_ble_multi_adv.c similarity index 96% 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 index 5457324130..b18d68e39a 100644 --- a/components/bt/bluedroid/stack/btm/btm_ble_multi_adv.c +++ b/components/bt/host/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 @@ -762,8 +769,17 @@ 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)); + 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/host/bluedroid/stack/btm/btm_ble_privacy.c similarity index 99% rename from components/bt/bluedroid/stack/btm/btm_ble_privacy.c rename to components/bt/host/bluedroid/stack/btm/btm_ble_privacy.c index 71f06eb82f..0ec69d953e 100644 --- a/components/bt/bluedroid/stack/btm/btm_ble_privacy.c +++ b/components/bt/host/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/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 99% rename from components/bt/bluedroid/stack/btm/btm_devctl.c rename to components/bt/host/bluedroid/stack/btm/btm_devctl.c index dfd2c3bf60..437a3cd1a3 100644 --- a/components/bt/bluedroid/stack/btm/btm_devctl.c +++ b/components/bt/host/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); } @@ -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_inq.c b/components/bt/host/bluedroid/stack/btm/btm_inq.c similarity index 99% rename from components/bt/bluedroid/stack/btm/btm_inq.c rename to components/bt/host/bluedroid/stack/btm/btm_inq.c index 7feda0e6ab..4845ac5ab0 100644 --- a/components/bt/bluedroid/stack/btm/btm_inq.c +++ b/components/bt/host/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/btm/btm_main.c b/components/bt/host/bluedroid/stack/btm/btm_main.c similarity index 95% rename from components/bt/bluedroid/stack/btm/btm_main.c rename to components/bt/host/bluedroid/stack/btm/btm_main.c index b6b853d5c6..cf950f21a9 100644 --- a/components/bt/bluedroid/stack/btm/btm_main.c +++ b/components/bt/host/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/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 99% rename from components/bt/bluedroid/stack/btm/btm_sco.c rename to components/bt/host/bluedroid/stack/btm/btm_sco.c index 661caba638..25d8c4183c 100644 --- a/components/bt/bluedroid/stack/btm/btm_sco.c +++ b/components/bt/host/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/host/bluedroid/stack/btm/btm_sec.c similarity index 99% rename from components/bt/bluedroid/stack/btm/btm_sec.c rename to components/bt/host/bluedroid/stack/btm/btm_sec.c index 1ad3cfce3b..fc711d9180 100644 --- a/components/bt/bluedroid/stack/btm/btm_sec.c +++ b/components/bt/host/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); } /******************************************************************************* @@ -1789,53 +1804,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 +1867,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 +1929,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; @@ -2776,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) { @@ -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); @@ -5761,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); } @@ -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; } @@ -5857,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; } @@ -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_ble_int.h b/components/bt/host/bluedroid/stack/btm/include/btm_ble_int.h similarity index 99% 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 index 369e60264f..4fc915e471 100644 --- a/components/bt/bluedroid/stack/btm/include/btm_ble_int.h +++ b/components/bt/host/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/btm/include/btm_int.h b/components/bt/host/bluedroid/stack/btm/include/btm_int.h similarity index 99% rename from components/bt/bluedroid/stack/btm/include/btm_int.h rename to components/bt/host/bluedroid/stack/btm/include/btm_int.h index 455ce7ca36..4ef7285084 100644 --- a/components/bt/bluedroid/stack/btm/include/btm_int.h +++ b/components/bt/host/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 @@ -1142,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_hcif.c b/components/bt/host/bluedroid/stack/btu/btu_hcif.c similarity index 99% rename from components/bt/bluedroid/stack/btu/btu_hcif.c rename to components/bt/host/bluedroid/stack/btu/btu_hcif.c index 7f0395a5b3..de7693ee84 100644 --- a/components/bt/bluedroid/stack/btu/btu_hcif.c +++ b/components/bt/host/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_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, TASK_POST_BLOCKING); + btu_task_post(SIG_BTU_HCI_MSG, event, OSI_THREAD_MAX_TIMEOUT); } /******************************************************************************* @@ -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/btu/btu_init.c b/components/bt/host/bluedroid/stack/btu/btu_init.c similarity index 85% rename from components/bt/bluedroid/stack/btu/btu_init.c rename to components/bt/host/bluedroid/stack/btu/btu_init.c index 7014cfde00..80678bef82 100644 --- a/components/bt/bluedroid/stack/btu/btu_init.c +++ b/components/bt/host/bluedroid/stack/btu/btu_init.c @@ -44,6 +44,11 @@ #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 (BT_TASK_MAX_PRIORITIES - 5) +#define BTU_TASK_NAME "btuT" + 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 +61,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_start_up(void * param); void btu_task_shut_down(void); + /***************************************************************************** ** V A R I A B L E S * ******************************************************************************/ @@ -126,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(); } /***************************************************************************** @@ -178,10 +181,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_MAX_TIMEOUT) == false) { + goto error_exit; + } return; @@ -190,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 @@ -206,17 +222,14 @@ void BTU_ShutDown(void) hash_map_free(btu_l2cap_alarm_hash_map); osi_mutex_free(&btu_l2cap_alarm_lock); - vTaskDelete(xBtuTaskHandle); - vQueueDelete(xBtuQueue); + 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 +249,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) >= BT_QUEUE_CONGEST_SIZE) { return true; } + return false; } #endif diff --git a/components/bt/bluedroid/stack/btu/btu_task.c b/components/bt/host/bluedroid/stack/btu/btu_task.c similarity index 87% rename from components/bt/bluedroid/stack/btu/btu_task.c rename to components/bt/host/bluedroid/stack/btu/btu_task.c index 644731504d..3e73cbb85c 100644 --- a/components/bt/bluedroid/stack/btu/btu_task.c +++ b/components/bt/host/bluedroid/stack/btu/btu_task.c @@ -81,11 +81,16 @@ 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 -extern void BTE_InitStack(void); +extern bt_status_t BTE_InitStack(void); extern void BTE_DeinitStack(void); /* Define BTU storage area @@ -107,24 +112,26 @@ 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 */ 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 { @@ -191,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); @@ -208,70 +216,42 @@ 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) +bool btu_task_post(uint32_t sig, void *param, uint32_t timeout) { - BtTaskEvt_t e; + bool status = false; - 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 (sig) { + case SIG_BTU_START_UP: + status = osi_thread_post(btu_thread, btu_task_start_up, param, 0, timeout); + break; + case SIG_BTU_HCI_MSG: + 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 *)e.par); - break; - case SIG_BTU_BTA_ALARM: - btu_bta_alarm_process((TIMER_LIST_ENT *)e.par); - break; + case SIG_BTU_BTA_MSG: + status = osi_thread_post(btu_thread, bta_sys_event, param, 0, timeout); + break; + case SIG_BTU_BTA_ALARM: + status = osi_thread_post(btu_thread, btu_bta_alarm_process, param, 0, timeout); + 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; - } - } - } -} - - -task_post_status_t btu_task_post(uint32_t sig, void *param, task_post_t timeout) -{ - BtTaskEvt_t evt; - - evt.sig = sig; - evt.par = param; - - if (xQueueSend(xBtuQueue, &evt, timeout) != pdTRUE) { - HCI_TRACE_ERROR("xBtuQueue failed\n"); - return TASK_POST_FAIL; + case SIG_BTU_GENERAL_ALARM: + case SIG_BTU_ONESHOT_ALARM: + status = osi_thread_post(btu_thread, btu_general_alarm_process, param, 0, timeout); + break; + case SIG_BTU_L2CAP_ALARM: + status = osi_thread_post(btu_thread, btu_l2cap_alarm_process, param, 0, timeout); + break; + default: + break; } - return TASK_POST_SUCCESS; + return status; } -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) */ @@ -314,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) { @@ -426,7 +407,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_MAX_TIMEOUT); } void btu_start_timer(TIMER_LIST_ENT *p_tle, UINT16 type, UINT32 timeout_sec) @@ -520,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) { @@ -540,7 +522,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_MAX_TIMEOUT); } void btu_start_quick_timer(TIMER_LIST_ENT *p_tle, UINT16 type, UINT32 timeout_ticks) @@ -623,7 +605,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_MAX_TIMEOUT); } /* diff --git a/components/bt/bluedroid/stack/gap/gap_api.c b/components/bt/host/bluedroid/stack/gap/gap_api.c similarity index 72% rename from components/bt/bluedroid/stack/gap/gap_api.c rename to components/bt/host/bluedroid/stack/gap/gap_api.c index 305eadee0a..b4e7c1b4fb 100644 --- a/components/bt/bluedroid/stack/gap/gap_api.c +++ b/components/bt/host/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 /******************************************************************************* ** @@ -52,11 +57,18 @@ 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)); #if defined(GAP_INITIAL_TRACE_LEVEL) @@ -72,5 +84,26 @@ void GAP_Init(void) #if BLE_INCLUDED == TRUE && GATTS_INCLUDED == TRUE gap_attr_db_init(); #endif + + return BT_STATUS_SUCCESS; } +/******************************************************************************* +** +** 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 + 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/gap/gap_ble.c b/components/bt/host/bluedroid/stack/gap/gap_ble.c similarity index 98% rename from components/bt/bluedroid/stack/gap/gap_ble.c rename to components/bt/host/bluedroid/stack/gap/gap_ble.c index bb5db8c1b1..5aab51fc1b 100644 --- a/components/bt/bluedroid/stack/gap/gap_ble.c +++ b/components/bt/host/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, @@ -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/host/bluedroid/stack/gap/gap_conn.c similarity index 98% rename from components/bt/bluedroid/stack/gap/gap_conn.c rename to components/bt/host/bluedroid/stack/gap/gap_conn.c index 671ffa7427..db9065de81 100644 --- a/components/bt/bluedroid/stack/gap/gap_conn.c +++ b/components/bt/host/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/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 98% rename from components/bt/bluedroid/stack/gap/include/gap_int.h rename to components/bt/host/bluedroid/stack/gap/include/gap_int.h index e278141184..8a3ae0e2f0 100644 --- a/components/bt/bluedroid/stack/gap/include/gap_int.h +++ b/components/bt/host/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/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 99% rename from components/bt/bluedroid/stack/gatt/gatt_api.c rename to components/bt/host/bluedroid/stack/gatt/gatt_api.c index 7f360d52db..d093d2b9d4 100644 --- a/components/bt/bluedroid/stack/gatt/gatt_api.c +++ b/components/bt/host/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/host/bluedroid/stack/gatt/gatt_attr.c similarity index 99% rename from components/bt/bluedroid/stack/gatt/gatt_attr.c rename to components/bt/host/bluedroid/stack/gatt/gatt_attr.c index 5036241317..3a67a8bf25 100644 --- a/components/bt/bluedroid/stack/gatt/gatt_attr.c +++ b/components/bt/host/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_auth.c b/components/bt/host/bluedroid/stack/gatt/gatt_auth.c similarity index 98% rename from components/bt/bluedroid/stack/gatt/gatt_auth.c rename to components/bt/host/bluedroid/stack/gatt/gatt_auth.c index e233ea0cad..b72cb6faee 100644 --- a/components/bt/bluedroid/stack/gatt/gatt_auth.c +++ b/components/bt/host/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_cl.c b/components/bt/host/bluedroid/stack/gatt/gatt_cl.c similarity index 99% rename from components/bt/bluedroid/stack/gatt/gatt_cl.c rename to components/bt/host/bluedroid/stack/gatt/gatt_cl.c index daa911e8c2..4ffd7ca5a0 100644 --- a/components/bt/bluedroid/stack/gatt/gatt_cl.c +++ b/components/bt/host/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/gatt/gatt_db.c b/components/bt/host/bluedroid/stack/gatt/gatt_db.c similarity index 99% rename from components/bt/bluedroid/stack/gatt/gatt_db.c rename to components/bt/host/bluedroid/stack/gatt/gatt_db.c index 8a05117482..a860e19e09 100644 --- a/components/bt/bluedroid/stack/gatt/gatt_db.c +++ b/components/bt/host/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_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 99% rename from components/bt/bluedroid/stack/gatt/gatt_sr.c rename to components/bt/host/bluedroid/stack/gatt/gatt_sr.c index eccc9ec979..6bad33b5c8 100644 --- a/components/bt/bluedroid/stack/gatt/gatt_sr.c +++ b/components/bt/host/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/host/bluedroid/stack/gatt/gatt_utils.c similarity index 99% rename from components/bt/bluedroid/stack/gatt/gatt_utils.c rename to components/bt/host/bluedroid/stack/gatt/gatt_utils.c index 2455f746f3..8f9303f0bb 100644 --- a/components/bt/bluedroid/stack/gatt/gatt_utils.c +++ b/components/bt/host/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/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 99% rename from components/bt/bluedroid/stack/hcic/hciblecmds.c rename to components/bt/host/bluedroid/stack/hcic/hciblecmds.c index 87785749b2..1d814cc8d0 100644 --- a/components/bt/bluedroid/stack/hcic/hciblecmds.c +++ b/components/bt/host/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/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 99% rename from components/bt/bluedroid/stack/include/stack/a2d_api.h rename to components/bt/host/bluedroid/stack/include/stack/a2d_api.h index 7509544fb5..466f9fad72 100644 --- a/components/bt/bluedroid/stack/include/stack/a2d_api.h +++ b/components/bt/host/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/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 99% rename from components/bt/bluedroid/stack/include/stack/avrc_api.h rename to components/bt/host/bluedroid/stack/include/stack/avrc_api.h index 85e8db1b2e..cbbb4b1c69 100644 --- a/components/bt/bluedroid/stack/include/stack/avrc_api.h +++ b/components/bt/host/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/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 52385cb513..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; @@ -446,6 +439,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 @@ -524,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 99% rename from components/bt/bluedroid/stack/include/stack/btm_api.h rename to components/bt/host/bluedroid/stack/include/stack/btm_api.h index 03a0e79d4d..641dd93f52 100644 --- a/components/bt/bluedroid/stack/include/stack/btm_api.h +++ b/components/bt/host/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 */ @@ -642,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; @@ -980,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; /******************* @@ -1391,12 +1395,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; @@ -3867,13 +3871,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/btm_ble_api.h b/components/bt/host/bluedroid/stack/include/stack/btm_ble_api.h similarity index 99% 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 index cdbb2db617..a8900ec321 100644 --- a/components/bt/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); /******************************************************************************* ** @@ -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 } diff --git a/components/bt/bluedroid/stack/include/stack/btu.h b/components/bt/host/bluedroid/stack/include/stack/btu.h similarity index 95% rename from components/bt/bluedroid/stack/include/stack/btu.h rename to components/bt/host/bluedroid/stack/include/stack/btu.h index 449b18da7e..fd5d1c989d 100644 --- a/components/bt/bluedroid/stack/include/stack/btu.h +++ b/components/bt/host/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. @@ -271,11 +283,13 @@ 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); +bool btu_task_post(uint32_t sig, void *param, uint32_t timeout); + /* #ifdef __cplusplus } 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 89% rename from components/bt/bluedroid/stack/include/stack/dyn_mem.h rename to components/bt/host/bluedroid/stack/include/stack/dyn_mem.h index f3f33537ca..fa1ed4982a 100644 --- a/components/bt/bluedroid/stack/include/stack/dyn_mem.h +++ b/components/bt/host/bluedroid/stack/include/stack/dyn_mem.h @@ -18,8 +18,9 @@ #ifndef DYN_MEM_H #define DYN_MEM_H -#include "sdkconfig.h" -#if CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY +#include "common/bluedroid_user_config.h" + +#if UC_BT_BLE_DYNAMIC_ENV_MEMORY #define BTU_DYNAMIC_MEMORY TRUE #define BTM_DYNAMIC_MEMORY TRUE #define L2C_DYNAMIC_MEMORY TRUE @@ -27,6 +28,7 @@ #define SMP_DYNAMIC_MEMORY TRUE #define BTA_DYNAMIC_MEMORY 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 +53,16 @@ #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 CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY */ +#else /* #if UC_BT_BLE_DYNAMIC_ENV_MEMORY */ +#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 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 +87,10 @@ #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 CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY */ +#endif /* #if UC_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. @@ -99,6 +107,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 +220,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_MEMORY +#define BTC_DYNAMIC_MEMORY FALSE +#endif +#endif /* #ifdef DYN_MEM_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 97% rename from components/bt/bluedroid/stack/include/stack/gap_api.h rename to components/bt/host/bluedroid/stack/include/stack/gap_api.h index 5d8d87645d..62062d2f21 100644 --- a/components/bt/bluedroid/stack/include/stack/gap_api.h +++ b/components/bt/host/bluedroid/stack/include/stack/gap_api.h @@ -320,10 +320,22 @@ 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); + +/******************************************************************************* +** +** 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/host/bluedroid/stack/include/stack/gatt_api.h similarity index 99% rename from components/bt/bluedroid/stack/include/stack/gatt_api.h rename to components/bt/host/bluedroid/stack/include/stack/gatt_api.h index b2cecb0578..c250f9a3c1 100644 --- a/components/bt/bluedroid/stack/include/stack/gatt_api.h +++ b/components/bt/host/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/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 99% rename from components/bt/bluedroid/stack/include/stack/hcidefs.h rename to components/bt/host/bluedroid/stack/include/stack/hcidefs.h index 6249f2c395..b1b73efa78 100644 --- a/components/bt/bluedroid/stack/include/stack/hcidefs.h +++ b/components/bt/host/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 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 index 147ed6c74c..33abaec7b3 100644 --- a/components/bt/bluedroid/stack/include/stack/l2c_api.h +++ b/components/bt/host/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/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 98% rename from components/bt/bluedroid/stack/include/stack/port_api.h rename to components/bt/host/bluedroid/stack/include/stack/port_api.h index 10b0378681..145ef22889 100644 --- a/components/bt/bluedroid/stack/include/stack/port_api.h +++ b/components/bt/host/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,8 +622,19 @@ 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); +/******************************************************************************* +** +** 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/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 99% rename from components/bt/bluedroid/stack/include/stack/smp_api.h rename to components/bt/host/bluedroid/stack/include/stack/smp_api.h index 390f6209e6..1064237c8d 100644 --- a/components/bt/bluedroid/stack/include/stack/smp_api.h +++ b/components/bt/host/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/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 99% rename from components/bt/bluedroid/stack/l2cap/l2c_api.c rename to components/bt/host/bluedroid/stack/l2cap/l2c_api.c index 906b961d20..4074cef841 100644 --- a/components/bt/bluedroid/stack/l2cap/l2c_api.c +++ b/components/bt/host/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) /******************************************************************************* @@ -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/host/bluedroid/stack/l2cap/l2c_ble.c similarity index 99% rename from components/bt/bluedroid/stack/l2cap/l2c_ble.c rename to components/bt/host/bluedroid/stack/l2cap/l2c_ble.c index 9a26969fac..efc3785767 100644 --- a/components/bt/bluedroid/stack/l2cap/l2c_ble.c +++ b/components/bt/host/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; -} /******************************************************************************* ** @@ -353,7 +331,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); @@ -1383,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", @@ -1428,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); @@ -1484,10 +1462,32 @@ 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; } #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_csm.c b/components/bt/host/bluedroid/stack/l2cap/l2c_csm.c similarity index 99% rename from components/bt/bluedroid/stack/l2cap/l2c_csm.c rename to components/bt/host/bluedroid/stack/l2cap/l2c_csm.c index ddfe53dba3..ff7fbb0ec0 100644 --- a/components/bt/bluedroid/stack/l2cap/l2c_csm.c +++ b/components/bt/host/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/host/bluedroid/stack/l2cap/l2c_fcr.c similarity index 99% rename from components/bt/bluedroid/stack/l2cap/l2c_fcr.c rename to components/bt/host/bluedroid/stack/l2cap/l2c_fcr.c index 3a7085c803..ecf0bd6c68 100644 --- a/components/bt/bluedroid/stack/l2cap/l2c_fcr.c +++ b/components/bt/host/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_link.c b/components/bt/host/bluedroid/stack/l2cap/l2c_link.c similarity index 99% rename from components/bt/bluedroid/stack/l2cap/l2c_link.c rename to components/bt/host/bluedroid/stack/l2cap/l2c_link.c index 15de6060b1..1117a0abae 100644 --- a/components/bt/bluedroid/stack/l2cap/l2c_link.c +++ b/components/bt/host/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/host/bluedroid/stack/l2cap/l2c_main.c similarity index 99% rename from components/bt/bluedroid/stack/l2cap/l2c_main.c rename to components/bt/host/bluedroid/stack/l2cap/l2c_main.c index 1035b44c6a..e50e59dceb 100644 --- a/components/bt/bluedroid/stack/l2cap/l2c_main.c +++ b/components/bt/host/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 /******************************************************************************* ** @@ -294,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); @@ -925,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){ @@ -932,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_ucd.c b/components/bt/host/bluedroid/stack/l2cap/l2c_ucd.c similarity index 97% rename from components/bt/bluedroid/stack/l2cap/l2c_ucd.c rename to components/bt/host/bluedroid/stack/l2cap/l2c_ucd.c index 8618042c5b..2b130c3490 100644 --- a/components/bt/bluedroid/stack/l2cap/l2c_ucd.c +++ b/components/bt/host/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/host/bluedroid/stack/l2cap/l2c_utils.c similarity index 99% rename from components/bt/bluedroid/stack/l2cap/l2c_utils.c rename to components/bt/host/bluedroid/stack/l2cap/l2c_utils.c index 4768d8808a..841e510a9a 100644 --- a/components/bt/bluedroid/stack/l2cap/l2c_utils.c +++ b/components/bt/host/bluedroid/stack/l2cap/l2c_utils.c @@ -243,12 +243,13 @@ 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) { 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); } @@ -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; @@ -928,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); } @@ -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 /******************************************************************************* @@ -3483,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); @@ -3520,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/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 98% rename from components/bt/bluedroid/stack/rfcomm/port_api.c rename to components/bt/host/bluedroid/stack/rfcomm/port_api.c index fd8246c53d..dacf544b9b 100644 --- a/components/bt/bluedroid/stack/rfcomm/port_api.c +++ b/components/bt/host/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 /******************************************************************************* ** @@ -1097,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); } @@ -1114,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); } @@ -1217,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(); @@ -1273,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; @@ -1339,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); @@ -1710,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) +#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 */ @@ -1727,6 +1733,27 @@ void RFCOMM_Init (void) #endif rfcomm_l2cap_if_init (); + return BT_STATUS_SUCCESS; +} + +/******************************************************************************* +** +** 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 + if (rfc_cb_ptr){ + osi_free(rfc_cb_ptr); + rfc_cb_ptr = NULL; + } +#endif } /******************************************************************************* diff --git a/components/bt/bluedroid/stack/rfcomm/port_rfc.c b/components/bt/host/bluedroid/stack/rfcomm/port_rfc.c similarity index 99% rename from components/bt/bluedroid/stack/rfcomm/port_rfc.c rename to components/bt/host/bluedroid/stack/rfcomm/port_rfc.c index 46b3e07116..4a47fb46ca 100644 --- a/components/bt/bluedroid/stack/rfcomm/port_rfc.c +++ b/components/bt/host/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/host/bluedroid/stack/rfcomm/port_utils.c similarity index 99% rename from components/bt/bluedroid/stack/rfcomm/port_utils.c rename to components/bt/host/bluedroid/stack/rfcomm/port_utils.c index 0da8b3d76b..0b08c0f1f3 100644 --- a/components/bt/bluedroid/stack/rfcomm/port_utils.c +++ b/components/bt/host/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_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 99% rename from components/bt/bluedroid/stack/rfcomm/rfc_mx_fsm.c rename to components/bt/host/bluedroid/stack/rfcomm/rfc_mx_fsm.c index 6d1bf3c93a..dd2af3b803 100644 --- a/components/bt/bluedroid/stack/rfcomm/rfc_mx_fsm.c +++ b/components/bt/host/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_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 99% rename from components/bt/bluedroid/stack/rfcomm/rfc_utils.c rename to components/bt/host/bluedroid/stack/rfcomm/rfc_utils.c index 8b1e043116..0d1fbdcb39 100644 --- a/components/bt/bluedroid/stack/rfcomm/rfc_utils.c +++ b/components/bt/host/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; } 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 89% 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 index f91d6056b2..172dd24f10 100644 --- 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 @@ -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/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 99% rename from components/bt/bluedroid/stack/smp/include/smp_int.h rename to components/bt/host/bluedroid/stack/smp/include/smp_int.h index a261e14cba..d8fb55c381 100644 --- a/components/bt/bluedroid/stack/smp/include/smp_int.h +++ b/components/bt/host/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" @@ -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); @@ -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/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 97% 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 index 0f7ab3ec41..aceb0b209a 100644 --- a/components/bt/bluedroid/stack/smp/p_256_ecc_pp.c +++ b/components/bt/host/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/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 98% rename from components/bt/bluedroid/stack/smp/smp_act.c rename to components/bt/host/bluedroid/stack/smp/smp_act.c index d11506e650..487dadf62c 100644 --- a/components/bt/bluedroid/stack/smp/smp_act.c +++ b/components/bt/host/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 } /******************************************************************************* @@ -283,6 +295,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 +305,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 @@ -363,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); @@ -371,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 } /******************************************************************************* @@ -379,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. @@ -439,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); @@ -476,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 @@ -530,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 @@ -650,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 @@ -675,6 +696,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 +716,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 @@ -819,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 @@ -838,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; @@ -962,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 @@ -976,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 @@ -997,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, @@ -1004,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 } /******************************************************************************* @@ -1040,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); } @@ -1054,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__); @@ -1069,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); } @@ -1103,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. @@ -1143,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 @@ -1242,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; @@ -1250,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. @@ -1413,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 @@ -1477,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 @@ -1702,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 @@ -1789,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. @@ -2055,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 @@ -2083,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 @@ -2093,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/host/bluedroid/stack/smp/smp_api.c similarity index 97% rename from components/bt/bluedroid/stack/smp/smp_api.c rename to components/bt/host/bluedroid/stack/smp/smp_api.c index 8c3c3d8bc7..89a32308e5 100644 --- a/components/bt/bluedroid/stack/smp/smp_api.c +++ b/components/bt/host/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 */ } @@ -177,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; @@ -206,6 +213,7 @@ tSMP_STATUS SMP_BR_PairWith (BD_ADDR bd_addr) return SMP_STARTED; } +#endif ///CLASSIC_BT_INCLUDED == TRUE /******************************************************************************* ** @@ -252,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 || @@ -265,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/host/bluedroid/stack/smp/smp_br_main.c similarity index 99% rename from components/bt/bluedroid/stack/smp/smp_br_main.c rename to components/bt/host/bluedroid/stack/smp/smp_br_main.c index ba2eb97456..5ef7a7c694 100644 --- a/components/bt/bluedroid/stack/smp/smp_br_main.c +++ b/components/bt/host/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_cmac.c b/components/bt/host/bluedroid/stack/smp/smp_cmac.c similarity index 99% rename from components/bt/bluedroid/stack/smp/smp_cmac.c rename to components/bt/host/bluedroid/stack/smp/smp_cmac.c index 753c5188f2..0e7bab02c1 100644 --- a/components/bt/bluedroid/stack/smp/smp_cmac.c +++ b/components/bt/host/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/host/bluedroid/stack/smp/smp_keys.c similarity index 99% rename from components/bt/bluedroid/stack/smp/smp_keys.c rename to components/bt/host/bluedroid/stack/smp/smp_keys.c index 4c523787c1..4c39635d9f 100644 --- a/components/bt/bluedroid/stack/smp/smp_keys.c +++ b/components/bt/host/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 @@ -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 /******************************************************************************* ** @@ -378,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; } @@ -430,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/host/bluedroid/stack/smp/smp_l2c.c similarity index 97% rename from components/bt/bluedroid/stack/smp/smp_l2c.c rename to components/bt/host/bluedroid/stack/smp/smp_l2c.c index a3ac356aca..67dd1ac5ae 100644 --- a/components/bt/bluedroid/stack/smp/smp_l2c.c +++ b/components/bt/host/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/host/bluedroid/stack/smp/smp_main.c similarity index 99% rename from components/bt/bluedroid/stack/smp/smp_main.c rename to components/bt/host/bluedroid/stack/smp/smp_main.c index 0880fe910f..1becb36f01 100644 --- a/components/bt/bluedroid/stack/smp/smp_main.c +++ b/components/bt/host/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/host/bluedroid/stack/smp/smp_utils.c similarity index 98% rename from components/bt/bluedroid/stack/smp/smp_utils.c rename to components/bt/host/bluedroid/stack/smp/smp_utils.c index 19c2cde99b..165b11a2a3 100644 --- a/components/bt/bluedroid/stack/smp/smp_utils.c +++ b/components/bt/host/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); } @@ -866,9 +875,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++) { @@ -964,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 @@ -982,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; @@ -996,6 +1013,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) { @@ -1005,7 +1023,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) { @@ -1404,7 +1425,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 ** @@ -1557,7 +1578,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/components/bt/host/nimble/Kconfig.in b/components/bt/host/nimble/Kconfig.in new file mode 100644 index 0000000000..2fcbf91c78 --- /dev/null +++ b/components/bt/host/nimble/Kconfig.in @@ -0,0 +1,252 @@ + +config BT_NIMBLE_MAX_CONNECTIONS + int "Maximum number of concurrent connections" + range 1 10 + default 1 + depends on BT_NIMBLE_ENABLED + 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 + depends on BT_NIMBLE_ENABLED + default 0 + help + Defines maximum number of BLE Connection Oriented Channels. When set to (0), BLE COC is not compiled in + +choice BT_NIMBLE_PINNED_TO_CORE_CHOICE + prompt "The CPU core on which NimBLE host will run" + depends on BT_NIMBLE_ENABLED && !FREERTOS_UNICORE + help + The CPU core on which NimBLE host will run. You can choose Core 0 or Core 1. + Cannot specify no-affinity + + config BT_NIMBLE_PINNED_TO_CORE_0 + bool "Core 0 (PRO CPU)" + config BT_NIMBLE_PINNED_TO_CORE_1 + bool "Core 1 (APP CPU)" + depends on !FREERTOS_UNICORE +endchoice + +config BT_NIMBLE_PINNED_TO_CORE + int + depends on BT_NIMBLE_ENABLED + default 0 if BT_NIMBLE_PINNED_TO_CORE_0 + default 1 if BT_NIMBLE_PINNED_TO_CORE_1 + default 0 + +config BT_NIMBLE_ROLE_CENTRAL + bool "Enable BLE Central role" + depends on BT_NIMBLE_ENABLED + default y + +config BT_NIMBLE_ROLE_PERIPHERAL + bool "Enable BLE Peripheral role" + depends on BT_NIMBLE_ENABLED + default y + +config BT_NIMBLE_ROLE_BROADCASTER + bool "Enable BLE Broadcaster role" + depends on BT_NIMBLE_ENABLED + default y + +config BT_NIMBLE_ROLE_OBSERVER + bool "Enable BLE Observer role" + depends on BT_NIMBLE_ENABLED + default y + +config BT_NIMBLE_NVS_PERSIST + bool "Persist the BLE Bonding keys in NVS" + depends on BT_NIMBLE_ENABLED + default y + help + Enable this flag to make bonding persistent across device reboots + +config BT_NIMBLE_SM_LEGACY + bool "Security manager legacy pairing" + depends on BT_NIMBLE_ENABLED + default y + help + Enable security manager legacy pairing + +config BT_NIMBLE_SM_SC + bool "Security manager secure connections (4.2)" + depends on BT_NIMBLE_ENABLED + default y + help + Enable security manager secure connections + +config BT_NIMBLE_DEBUG + bool "Enable host debugging" + default n + depends on BT_NIMBLE_ENABLED + help + This enables extra runtime assertions + +config BT_NIMBLE_SVC_GAP_DEVICE_NAME + string "BLE GAP default device name" + depends on BT_NIMBLE_ENABLED + default "nimble" + help + The Device Name characteristic shall contain the name of the device as an UTF-8 string. + This name can be changed by using API ble_svc_gap_device_name_set() + +config BT_NIMBLE_GAP_DEVICE_NAME_MAX_LEN + int "Maximum length of BLE device name in octets" + depends on BT_NIMBLE_ENABLED + default 31 + help + Device Name characteristic value shall be 0 to 248 octets in length + +config BT_NIMBLE_ATT_PREFERRED_MTU + int "Preferred MTU size in octets" + depends on BT_NIMBLE_ENABLED + default 256 + help + This is the default value of ATT MTU indicated by the device during an ATT MTU exchange. + This value can be changed using API ble_att_set_preferred_mtu() + +config BT_NIMBLE_SVC_GAP_APPEARANCE + hex "External appearance of the device" + depends on BT_NIMBLE_ENABLED + default 0 + help + Standard BLE GAP Appearance value in HEX format e.g. 0x02C0 + +config BT_NIMBLE_ACL_BUF_COUNT + int "ACL Buffer count" + depends on BT_NIMBLE_ENABLED + default 12 + help + The number of ACL data buffers. + +config BT_NIMBLE_ACL_BUF_SIZE + int "ACL Buffer size" + depends on BT_NIMBLE_ENABLED + default 255 + help + This is the maximum size of the data portion of HCI ACL data packets. + It does not include the HCI data header (of 4 bytes) + +config BT_NIMBLE_HCI_EVT_BUF_SIZE + int "HCI Event Buffer size" + depends on BT_NIMBLE_ENABLED + default 70 + help + This is the size of each HCI event buffer in bytes + +config BT_NIMBLE_HCI_EVT_HI_BUF_COUNT + int "High Priority HCI Event Buffer count" + depends on BT_NIMBLE_ENABLED + default 30 + help + This is the high priority HCI events' buffer size. High-priority + event buffers are for everything except advertising reports. If there + are no free high-priority event buffers then host will try to allocate a + low-priority buffer instead + +config BT_NIMBLE_HCI_EVT_LO_BUF_COUNT + int "Low Priority HCI Event Buffer count" + depends on BT_NIMBLE_ENABLED + default 8 + help + This is the low priority HCI events' buffer size. Low-priority event + buffers are only used for advertising reports. If there are no free + low-priority event buffers, then an incoming advertising report will + get dropped + +menuconfig BT_NIMBLE_MESH + bool "Enable BLE mesh functionality" + select BT_NIMBLE_SM_SC + depends on BT_NIMBLE_ENABLED + default n + help + Enable BLE Mesh functionality + +config BT_NIMBLE_MESH_PROXY + bool "Enable mesh proxy functionality" + default n + depends on BT_NIMBLE_MESH + help + Enable proxy. This is automatically set whenever NIMBLE_MESH_PB_GATT or + NIMBLE_MESH_GATT_PROXY is set + + +config BT_NIMBLE_MESH_PROV + bool "Enable BLE mesh provisioning" + default y + depends on BT_NIMBLE_MESH + help + Enable mesh provisioning + +config BT_NIMBLE_MESH_PB_ADV + bool "Enable mesh provisioning over advertising bearer" + default y + depends on BT_NIMBLE_MESH_PROV + help + Enable this option to allow the device to be provisioned over + the advertising bearer + + +config BT_NIMBLE_MESH_PB_GATT + bool "Enable mesh provisioning over GATT bearer" + default y + select BT_NIMBLE_MESH_PROXY + depends on BT_NIMBLE_MESH_PROV + help + Enable this option to allow the device to be provisioned over the GATT + bearer + +config BT_NIMBLE_MESH_GATT_PROXY + bool "Enable GATT Proxy functionality" + default y + select BT_NIMBLE_MESH_PROXY + depends on BT_NIMBLE_MESH + help + This option enables support for the Mesh GATT Proxy Service, + i.e. the ability to act as a proxy between a Mesh GATT Client + and a Mesh network + +config BT_NIMBLE_MESH_RELAY + bool "Enable mesh relay functionality" + default n + depends on BT_NIMBLE_MESH + help + Support for acting as a Mesh Relay Node + +config BT_NIMBLE_MESH_LOW_POWER + bool "Enable mesh low power mode" + default n + depends on BT_NIMBLE_MESH + help + Enable this option to be able to act as a Low Power Node + +config BT_NIMBLE_MESH_FRIEND + bool "Enable mesh friend functionality" + default n + depends on BT_NIMBLE_MESH + help + Enable this option to be able to act as a Friend Node + +config BT_NIMBLE_MESH_DEVICE_NAME + string "Set mesh device name" + default "nimble-mesh-node" + depends on BT_NIMBLE_MESH + help + This value defines Bluetooth Mesh device/node name + diff --git a/components/bt/host/nimble/esp-hci/include/esp_nimble_hci.h b/components/bt/host/nimble/esp-hci/include/esp_nimble_hci.h new file mode 100644 index 0000000000..e10436f3c7 --- /dev/null +++ b/components/bt/host/nimble/esp-hci/include/esp_nimble_hci.h @@ -0,0 +1,138 @@ +/* + * Copyright 2019 Espressif Systems (Shanghai) PTE LTD + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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_NIMBLE_HCI_H__ +#define __ESP_NIMBLE_HCI_H__ + +#include "nimble/ble_hci_trans.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define BLE_HCI_UART_H4_NONE 0x00 +#define BLE_HCI_UART_H4_CMD 0x01 +#define BLE_HCI_UART_H4_ACL 0x02 +#define BLE_HCI_UART_H4_SCO 0x03 +#define BLE_HCI_UART_H4_EVT 0x04 + +/** + * @brief Initialize VHCI transport layer between NimBLE Host and + * ESP Bluetooth controller + * + * This function initializes the transport buffers to be exchanged + * between NimBLE host and ESP controller. It also registers required + * host callbacks with the controller. + * + * @return + * - ESP_OK if the initialization is successful + * - Appropriate error code from esp_err_t in case of an error + */ +esp_err_t esp_nimble_hci_init(void); + +/** + * @brief Initialize ESP Bluetooth controller(link layer) and VHCI transport + * layer between NimBLE Host and ESP Bluetooth controller + * + * This function initializes ESP controller in BLE only mode and the + * transport buffers to be exchanged between NimBLE host and ESP controller. + * It also registers required host callbacks with the controller. + * + * Below is the sequence of APIs to be called to init/enable NimBLE host and ESP controller: + * + * @code{c} + * void ble_host_task(void *param) + * { + * nimble_port_run(); //This function will return only when nimble_port_stop() is executed. + * nimble_port_freertos_deinit(); + * } + * + * int ret = esp_nimble_hci_and_controller_init(); + * if (ret != ESP_OK) { + ESP_LOGE(TAG, "esp_nimble_hci_and_controller_init() failed with error: %d", ret); + * return; + * } + * + * nimble_port_init(); + * + * //Initialize the NimBLE Host configuration + * + * nimble_port_freertos_init(ble_host_task); + * @endcode + * + * nimble_port_freertos_init() is an optional call that creates a new task in which the NimBLE + * host will run. The task function should have a call to nimble_port_run(). If a separate task + * is not required, calling nimble_port_run() will run the NimBLE host in the current task. + * + * @return + * - ESP_OK if the initialization is successful + * - Appropriate error code from esp_err_t in case of an error + */ +esp_err_t esp_nimble_hci_and_controller_init(void); + +/** + * @brief Deinitialize VHCI transport layer between NimBLE Host and + * ESP Bluetooth controller + * + * @note This function should be called after the NimBLE host is deinitialized. + * + * @return + * - ESP_OK if the deinitialization is successful + * - Appropriate error codes from esp_err_t in case of an error + */ +esp_err_t esp_nimble_hci_deinit(void); + +/** + * @brief Deinitialize VHCI transport layer between NimBLE Host and + * ESP Bluetooth controller and disable and deinitialize the controller + * + * @note This function should not be executed in the context of Bluetooth host task. + * + * @note This function should be called after the NimBLE host is deinitialized. + * + * Below is the sequence of APIs to be called to disable/deinit NimBLE host and ESP controller: + * + * @code{c} + * int 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); + * } + * } + * @endcode + * + * If nimble_port_freertos_init() is used during initialization, then + * nimble_port_freertos_deinit() should be called in the host task after nimble_port_run(). + * + * @return + * - ESP_OK if the deinitialization is successful + * - Appropriate error codes from esp_err_t in case of an error + */ +esp_err_t esp_nimble_hci_and_controller_deinit(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __ESP_NIMBLE_HCI_H__ */ diff --git a/components/bt/host/nimble/esp-hci/src/esp_nimble_hci.c b/components/bt/host/nimble/esp-hci/src/esp_nimble_hci.c new file mode 100644 index 0000000000..545334e920 --- /dev/null +++ b/components/bt/host/nimble/esp-hci/src/esp_nimble_hci.c @@ -0,0 +1,434 @@ +/* + * Copyright 2019 Espressif Systems (Shanghai) PTE LTD + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 "sysinit/sysinit.h" +#include "nimble/hci_common.h" +#include "host/ble_hs.h" +#include "nimble/nimble_port.h" +#include "nimble/nimble_port_freertos.h" +#include "esp_nimble_hci.h" +#include "esp_bt.h" + +static ble_hci_trans_rx_cmd_fn *ble_hci_rx_cmd_hs_cb; +static void *ble_hci_rx_cmd_hs_arg; + +static ble_hci_trans_rx_acl_fn *ble_hci_rx_acl_hs_cb; +static void *ble_hci_rx_acl_hs_arg; + +static struct os_mbuf_pool ble_hci_acl_mbuf_pool; +static struct os_mempool_ext ble_hci_acl_pool; +/* + * The MBUF payload size must accommodate the HCI data header size plus the + * maximum ACL data packet length. The ACL block size is the size of the + * mbufs we will allocate. + */ +#define ACL_BLOCK_SIZE OS_ALIGN(MYNEWT_VAL(BLE_ACL_BUF_SIZE) \ + + BLE_MBUF_MEMBLOCK_OVERHEAD \ + + BLE_HCI_DATA_HDR_SZ, OS_ALIGNMENT) + +static os_membuf_t ble_hci_acl_buf[ + OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_ACL_BUF_COUNT), + ACL_BLOCK_SIZE)]; + +static struct os_mempool ble_hci_cmd_pool; +static os_membuf_t ble_hci_cmd_buf[ + OS_MEMPOOL_SIZE(1, BLE_HCI_TRANS_CMD_SZ) +]; + +static struct os_mempool ble_hci_evt_hi_pool; +static os_membuf_t ble_hci_evt_hi_buf[ + OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), + MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)) +]; + +static struct os_mempool ble_hci_evt_lo_pool; +static os_membuf_t ble_hci_evt_lo_buf[ + OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), + MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)) +]; + +void ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *cmd_cb, + void *cmd_arg, + ble_hci_trans_rx_acl_fn *acl_cb, + void *acl_arg) +{ + ble_hci_rx_cmd_hs_cb = cmd_cb; + ble_hci_rx_cmd_hs_arg = cmd_arg; + ble_hci_rx_acl_hs_cb = acl_cb; + ble_hci_rx_acl_hs_arg = acl_arg; +} + + +int ble_hci_trans_hs_cmd_tx(uint8_t *cmd) +{ + uint16_t len; + + assert(cmd != NULL); + *cmd = BLE_HCI_UART_H4_CMD; + len = BLE_HCI_CMD_HDR_LEN + cmd[3] + 1; + while (!esp_vhci_host_check_send_available()) { + } + esp_vhci_host_send_packet(cmd, len); + + ble_hci_trans_buf_free(cmd); + return 0; +} + +int ble_hci_trans_ll_evt_tx(uint8_t *hci_ev) +{ + int rc = ESP_FAIL; + + if (ble_hci_rx_cmd_hs_cb) { + rc = ble_hci_rx_cmd_hs_cb(hci_ev, ble_hci_rx_cmd_hs_arg); + } + return rc; +} + +int ble_hci_trans_hs_acl_tx(struct os_mbuf *om) +{ + uint16_t len = 0; + uint8_t data[MYNEWT_VAL(BLE_ACL_BUF_SIZE) + 1]; + /* If this packet is zero length, just free it */ + if (OS_MBUF_PKTLEN(om) == 0) { + os_mbuf_free_chain(om); + return 0; + } + data[0] = BLE_HCI_UART_H4_ACL; + len++; + + while (!esp_vhci_host_check_send_available()) { + vTaskDelay(1000 / portTICK_PERIOD_MS); + } + + os_mbuf_copydata(om, 0, OS_MBUF_PKTLEN(om), &data[1]); + len += OS_MBUF_PKTLEN(om); + + esp_vhci_host_send_packet(data, len); + + os_mbuf_free_chain(om); + + return 0; +} + +int ble_hci_trans_ll_acl_tx(struct os_mbuf *om) +{ + int rc = ESP_FAIL; + + if (ble_hci_rx_acl_hs_cb) { + rc = ble_hci_rx_acl_hs_cb(om, ble_hci_rx_acl_hs_arg); + } + return rc; +} + +uint8_t *ble_hci_trans_buf_alloc(int type) +{ + uint8_t *buf; + + switch (type) { + case BLE_HCI_TRANS_BUF_CMD: + buf = os_memblock_get(&ble_hci_cmd_pool); + break; + + case BLE_HCI_TRANS_BUF_EVT_HI: + buf = os_memblock_get(&ble_hci_evt_hi_pool); + if (buf == NULL) { + /* If no high-priority event buffers remain, try to grab a + * low-priority one. + */ + buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); + } + break; + + case BLE_HCI_TRANS_BUF_EVT_LO: + buf = os_memblock_get(&ble_hci_evt_lo_pool); + break; + + default: + assert(0); + buf = NULL; + } + + return buf; +} + +void ble_hci_trans_buf_free(uint8_t *buf) +{ + int rc; + /* XXX: this may look a bit odd, but the controller uses the command + * buffer to send back the command complete/status as an immediate + * response to the command. This was done to insure that the controller + * could always send back one of these events when a command was received. + * Thus, we check to see which pool the buffer came from so we can free + * it to the appropriate pool + */ + if (os_memblock_from(&ble_hci_evt_hi_pool, buf)) { + rc = os_memblock_put(&ble_hci_evt_hi_pool, buf); + assert(rc == 0); + } else if (os_memblock_from(&ble_hci_evt_lo_pool, buf)) { + rc = os_memblock_put(&ble_hci_evt_lo_pool, buf); + assert(rc == 0); + } else { + assert(os_memblock_from(&ble_hci_cmd_pool, buf)); + rc = os_memblock_put(&ble_hci_cmd_pool, buf); + assert(rc == 0); + } +} + +/** + * Unsupported; the RAM transport does not have a dedicated ACL data packet + * pool. + */ +int ble_hci_trans_set_acl_free_cb(os_mempool_put_fn *cb, void *arg) +{ + return BLE_ERR_UNSUPPORTED; +} + +int ble_hci_trans_reset(void) +{ + /* No work to do. All allocated buffers are owned by the host or + * controller, and they will get freed by their owners. + */ + return 0; +} + +/** + * Allocates a buffer (mbuf) for ACL operation. + * + * @return The allocated buffer on success; + * NULL on buffer exhaustion. + */ +static struct os_mbuf *ble_hci_trans_acl_buf_alloc(void) +{ + struct os_mbuf *m; + uint8_t usrhdr_len; + +#if MYNEWT_VAL(BLE_DEVICE) + usrhdr_len = sizeof(struct ble_mbuf_hdr); +#elif MYNEWT_VAL(BLE_HS_FLOW_CTRL) + usrhdr_len = BLE_MBUF_HS_HDR_LEN; +#else + usrhdr_len = 0; +#endif + + m = os_mbuf_get_pkthdr(&ble_hci_acl_mbuf_pool, usrhdr_len); + return m; +} + +static void ble_hci_rx_acl(uint8_t *data, uint16_t len) +{ + struct os_mbuf *m; + int sr; + if (len < BLE_HCI_DATA_HDR_SZ || len > MYNEWT_VAL(BLE_ACL_BUF_SIZE)) { + return; + } + + m = ble_hci_trans_acl_buf_alloc(); + + if (!m) { + return; + } + if (os_mbuf_append(m, data, len)) { + os_mbuf_free_chain(m); + return; + } + OS_ENTER_CRITICAL(sr); + if (ble_hci_rx_acl_hs_cb) { + ble_hci_rx_acl_hs_cb(m, NULL); + } + OS_EXIT_CRITICAL(sr); +} + +static void ble_hci_transport_init(void) +{ + int rc; + + /* Ensure this function only gets called by sysinit. */ + SYSINIT_ASSERT_ACTIVE(); + + rc = os_mempool_ext_init(&ble_hci_acl_pool, + MYNEWT_VAL(BLE_ACL_BUF_COUNT), + ACL_BLOCK_SIZE, + ble_hci_acl_buf, + "ble_hci_acl_pool"); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = os_mbuf_pool_init(&ble_hci_acl_mbuf_pool, + &ble_hci_acl_pool.mpe_mp, + ACL_BLOCK_SIZE, + MYNEWT_VAL(BLE_ACL_BUF_COUNT)); + SYSINIT_PANIC_ASSERT(rc == 0); + + /* + * Create memory pool of HCI command buffers. NOTE: we currently dont + * allow this to be configured. The controller will only allow one + * outstanding command. We decided to keep this a pool in case we allow + * allow the controller to handle more than one outstanding command. + */ + rc = os_mempool_init(&ble_hci_cmd_pool, + 1, + BLE_HCI_TRANS_CMD_SZ, + ble_hci_cmd_buf, + "ble_hci_cmd_pool"); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = os_mempool_init(&ble_hci_evt_hi_pool, + MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), + MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), + ble_hci_evt_hi_buf, + "ble_hci_evt_hi_pool"); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = os_mempool_init(&ble_hci_evt_lo_pool, + MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), + MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), + ble_hci_evt_lo_buf, + "ble_hci_evt_lo_pool"); + SYSINIT_PANIC_ASSERT(rc == 0); +} + +/* + * @brief: BT controller callback function, used to notify the upper layer that + * controller is ready to receive command + */ +static void controller_rcv_pkt_ready(void) +{ +} + +/* + * @brief: BT controller callback function, to transfer data packet to the host + */ +static int host_rcv_pkt(uint8_t *data, uint16_t len) +{ + + if (data[0] == BLE_HCI_UART_H4_EVT) { + uint8_t *evbuf; + int totlen; + int rc; + + totlen = BLE_HCI_EVENT_HDR_LEN + data[2]; + assert(totlen <= UINT8_MAX + BLE_HCI_EVENT_HDR_LEN); + + if (data[1] == BLE_HCI_EVCODE_HW_ERROR) { + assert(0); + } + + /* Allocate LE Advertising Report Event from lo pool only */ + if ((data[1] == BLE_HCI_EVCODE_LE_META) && (data[3] == BLE_HCI_LE_SUBEV_ADV_RPT)) { + evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); + /* Skip advertising report if we're out of memory */ + if (!evbuf) { + return 0; + } + } else { + evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + assert(evbuf != NULL); + } + + memcpy(evbuf, &data[1], totlen); + + rc = ble_hci_trans_ll_evt_tx(evbuf); + assert(rc == 0); + } else if (data[0] == BLE_HCI_UART_H4_ACL) { + ble_hci_rx_acl(data + 1, len - 1); + } + return 0; +} + +static esp_vhci_host_callback_t vhci_host_cb = { + controller_rcv_pkt_ready, + host_rcv_pkt +}; + +esp_err_t esp_nimble_hci_init(void) +{ + esp_err_t ret; + if ((ret = esp_vhci_host_register_callback(&vhci_host_cb)) != ESP_OK) { + return ret; + } + + ble_hci_transport_init(); + + return ESP_OK; +} + +esp_err_t esp_nimble_hci_and_controller_init(void) +{ + esp_err_t ret; + + esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT); + + esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); + + if ((ret = esp_bt_controller_init(&bt_cfg)) != ESP_OK) { + return ret; + } + + if ((ret = esp_bt_controller_enable(ESP_BT_MODE_BLE)) != ESP_OK) { + return ret; + } + return esp_nimble_hci_init(); +} + +static esp_err_t ble_hci_transport_deinit(void) +{ + int ret = 0; + + ret += os_mempool_clear(&ble_hci_evt_lo_pool); + + ret += os_mempool_clear(&ble_hci_evt_hi_pool); + + ret += os_mempool_clear(&ble_hci_cmd_pool); + + ret += os_mempool_ext_clear(&ble_hci_acl_pool); + + if (ret) { + return ESP_FAIL; + } else { + return ESP_OK; + } +} + +esp_err_t esp_nimble_hci_deinit(void) +{ + return ble_hci_transport_deinit(); +} + +esp_err_t esp_nimble_hci_and_controller_deinit(void) +{ + int ret; + ret = esp_nimble_hci_deinit(); + if (ret != ESP_OK) { + return ret; + } + + ret = esp_bt_controller_disable(); + if (ret != ESP_OK) { + return ret; + } + + ret = esp_bt_controller_deinit(); + if (ret != ESP_OK) { + return ret; + } + + return ESP_OK; +} diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble new file mode 160000 index 0000000000..4839d84f61 --- /dev/null +++ b/components/bt/host/nimble/nimble @@ -0,0 +1 @@ +Subproject commit 4839d84f61296b7d7479350ebb92908b0fdb1329 diff --git a/components/bt/host/nimble/port/include/console/console.h b/components/bt/host/nimble/port/include/console/console.h new file mode 100644 index 0000000000..96f965159f --- /dev/null +++ b/components/bt/host/nimble/port/include/console/console.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 _CONSOLE_H +#define _CONSOLE_H + +#include + +#define console_printf printf + +#endif diff --git a/components/bt/host/nimble/port/include/esp_nimble_cfg.h b/components/bt/host/nimble/port/include/esp_nimble_cfg.h new file mode 100644 index 0000000000..7b9da75217 --- /dev/null +++ b/components/bt/host/nimble/port/include/esp_nimble_cfg.h @@ -0,0 +1,1065 @@ + +#ifndef __ESP_NIMBLE_CFG__ +#define __ESP_NIMBLE_CFG__ +#include "sdkconfig.h" + +/** + * This macro exists to ensure code includes this header when needed. If code + * checks the existence of a setting directly via ifdef without including this + * header, the setting macro will silently evaluate to 0. In contrast, an + * attempt to use these macros without including this header will result in a + * compiler error. + */ +#define MYNEWT_VAL(x) MYNEWT_VAL_ ## x + +/*** kernel/os */ +#ifndef MYNEWT_VAL_MSYS_1_BLOCK_COUNT +#ifdef CONFIG_BT_NIMBLE_MESH +#define MYNEWT_VAL_MSYS_1_BLOCK_COUNT (20) +#else +#define MYNEWT_VAL_MSYS_1_BLOCK_COUNT (12) +#endif +#endif + +#ifndef MYNEWT_VAL_MSYS_1_BLOCK_SIZE +#define MYNEWT_VAL_MSYS_1_BLOCK_SIZE (292) +#endif + +#ifndef MYNEWT_VAL_MSYS_2_BLOCK_COUNT +#define MYNEWT_VAL_MSYS_2_BLOCK_COUNT (0) +#endif + +#ifndef MYNEWT_VAL_MSYS_2_BLOCK_SIZE +#define MYNEWT_VAL_MSYS_2_BLOCK_SIZE (0) +#endif + +#ifndef MYNEWT_VAL_OS_CPUTIME_FREQ +#define MYNEWT_VAL_OS_CPUTIME_FREQ (1000000) +#endif + +#ifndef MYNEWT_VAL_OS_CPUTIME_TIMER_NUM +#define MYNEWT_VAL_OS_CPUTIME_TIMER_NUM (0) +#endif + +/*** nimble */ +#ifndef MYNEWT_VAL_BLE_EXT_ADV +#define MYNEWT_VAL_BLE_EXT_ADV (0) +#endif + +#ifndef MYNEWT_VAL_BLE_EXT_ADV_MAX_SIZE +#define MYNEWT_VAL_BLE_EXT_ADV_MAX_SIZE (31) +#endif + +#ifndef MYNEWT_VAL_BLE_MAX_CONNECTIONS +#define MYNEWT_VAL_BLE_MAX_CONNECTIONS CONFIG_BT_NIMBLE_MAX_CONNECTIONS +#endif + +#ifndef MYNEWT_VAL_BLE_MULTI_ADV_INSTANCES +#define MYNEWT_VAL_BLE_MULTI_ADV_INSTANCES (0) +#endif + +#ifndef MYNEWT_VAL_BLE_ROLE_BROADCASTER +#ifdef CONFIG_BT_NIMBLE_ROLE_BROADCASTER +#define MYNEWT_VAL_BLE_ROLE_BROADCASTER (1) +#else +#define MYNEWT_VAL_BLE_ROLE_BROADCASTER (0) +#endif +#endif + +#ifndef MYNEWT_VAL_BLE_ROLE_CENTRAL +#ifdef CONFIG_BT_NIMBLE_ROLE_CENTRAL +#define MYNEWT_VAL_BLE_ROLE_CENTRAL (1) +#else +#define MYNEWT_VAL_BLE_ROLE_CENTRAL (0) +#endif +#endif + +#ifndef MYNEWT_VAL_BLE_ROLE_OBSERVER +#ifdef CONFIG_BT_NIMBLE_ROLE_OBSERVER +#define MYNEWT_VAL_BLE_ROLE_OBSERVER (1) +#else +#define MYNEWT_VAL_BLE_ROLE_OBSERVER (0) +#endif +#endif + +#ifndef MYNEWT_VAL_BLE_ROLE_PERIPHERAL +#ifdef CONFIG_BT_NIMBLE_ROLE_PERIPHERAL +#define MYNEWT_VAL_BLE_ROLE_PERIPHERAL (1) +#else +#define MYNEWT_VAL_BLE_ROLE_PERIPHERAL (0) +#endif +#endif + +#ifndef MYNEWT_VAL_BLE_WHITELIST +#define MYNEWT_VAL_BLE_WHITELIST (1) +#endif + +/*** @apache-mynewt-nimble/nimble/controller */ +#ifndef MYNEWT_VAL_BLE_DEVICE +#define MYNEWT_VAL_BLE_DEVICE (0) +#endif + +/* Overridden by @apache-mynewt-nimble/nimble/controller (defined by @apache-mynewt-nimble/nimble/controller) */ +#ifndef MYNEWT_VAL_BLE_HW_WHITELIST_ENABLE +#define MYNEWT_VAL_BLE_HW_WHITELIST_ENABLE (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_ADD_STRICT_SCHED_PERIODS +#define MYNEWT_VAL_BLE_LL_ADD_STRICT_SCHED_PERIODS (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_CONN_PARAM_REQ +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_CONN_PARAM_REQ (1) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_DATA_LEN_EXT +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_DATA_LEN_EXT (1) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_EXT_SCAN_FILT +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_EXT_SCAN_FILT (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_2M_PHY +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_2M_PHY (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_CODED_PHY +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_CODED_PHY (0) +#endif + +/* Overridden by @apache-mynewt-nimble/nimble/controller (defined by @apache-mynewt-nimble/nimble/controller) */ +#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_CSA2 +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_CSA2 (1) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_ENCRYPTION +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_ENCRYPTION (1) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_PING +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_PING (MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_ENCRYPTION) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_EXT_ADV +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_EXT_ADV (MYNEWT_VAL_BLE_EXT_ADV) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_PRIVACY +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_PRIVACY (1) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_SLAVE_INIT_FEAT_XCHG +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_SLAVE_INIT_FEAT_XCHG (1) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CONN_INIT_MAX_TX_BYTES +#define MYNEWT_VAL_BLE_LL_CONN_INIT_MAX_TX_BYTES (27) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CONN_INIT_MIN_WIN_OFFSET +#define MYNEWT_VAL_BLE_LL_CONN_INIT_MIN_WIN_OFFSET (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CONN_INIT_SLOTS +#define MYNEWT_VAL_BLE_LL_CONN_INIT_SLOTS (4) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_DIRECT_TEST_MODE +#define MYNEWT_VAL_BLE_LL_DIRECT_TEST_MODE (0) +#endif + +/* Overridden by @apache-mynewt-nimble/nimble/controller (defined by @apache-mynewt-nimble/nimble/controller) */ +#ifndef MYNEWT_VAL_BLE_LL_EXT_ADV_AUX_PTR_CNT +#define MYNEWT_VAL_BLE_LL_EXT_ADV_AUX_PTR_CNT (5) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_MASTER_SCA +#define MYNEWT_VAL_BLE_LL_MASTER_SCA (4) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_MAX_PKT_SIZE +#define MYNEWT_VAL_BLE_LL_MAX_PKT_SIZE (251) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_MFRG_ID +#define MYNEWT_VAL_BLE_LL_MFRG_ID (0xFFFF) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_NUM_SCAN_DUP_ADVS +#define MYNEWT_VAL_BLE_LL_NUM_SCAN_DUP_ADVS (8) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_NUM_SCAN_RSP_ADVS +#define MYNEWT_VAL_BLE_LL_NUM_SCAN_RSP_ADVS (8) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_OUR_SCA +#define MYNEWT_VAL_BLE_LL_OUR_SCA (60) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_PRIO +#define MYNEWT_VAL_BLE_LL_PRIO (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_RESOLV_LIST_SIZE +#define MYNEWT_VAL_BLE_LL_RESOLV_LIST_SIZE (4) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_RNG_BUFSIZE +#define MYNEWT_VAL_BLE_LL_RNG_BUFSIZE (32) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_STRICT_CONN_SCHEDULING +#define MYNEWT_VAL_BLE_LL_STRICT_CONN_SCHEDULING (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_SUPP_MAX_RX_BYTES +#define MYNEWT_VAL_BLE_LL_SUPP_MAX_RX_BYTES (MYNEWT_VAL_BLE_LL_MAX_PKT_SIZE) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_SUPP_MAX_TX_BYTES +#define MYNEWT_VAL_BLE_LL_SUPP_MAX_TX_BYTES (MYNEWT_VAL_BLE_LL_MAX_PKT_SIZE) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_SYSVIEW +#define MYNEWT_VAL_BLE_LL_SYSVIEW (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_TX_PWR_DBM +#define MYNEWT_VAL_BLE_LL_TX_PWR_DBM (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_USECS_PER_PERIOD +#define MYNEWT_VAL_BLE_LL_USECS_PER_PERIOD (3250) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_VND_EVENT_ON_ASSERT +#define MYNEWT_VAL_BLE_LL_VND_EVENT_ON_ASSERT (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_WHITELIST_SIZE +#define MYNEWT_VAL_BLE_LL_WHITELIST_SIZE (8) +#endif + +#ifndef MYNEWT_VAL_BLE_LP_CLOCK +#define MYNEWT_VAL_BLE_LP_CLOCK (1) +#endif + +#ifndef MYNEWT_VAL_BLE_NUM_COMP_PKT_RATE +#define MYNEWT_VAL_BLE_NUM_COMP_PKT_RATE ((2 * OS_TICKS_PER_SEC)) +#endif + +#ifndef MYNEWT_VAL_BLE_PUBLIC_DEV_ADDR +#define MYNEWT_VAL_BLE_PUBLIC_DEV_ADDR ((uint8_t[6]){0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) +#endif + +#ifndef MYNEWT_VAL_BLE_XTAL_SETTLE_TIME +#define MYNEWT_VAL_BLE_XTAL_SETTLE_TIME (0) +#endif + +/*** @apache-mynewt-nimble/nimble/host */ +#ifndef MYNEWT_VAL_BLE_ATT_PREFERRED_MTU +#define MYNEWT_VAL_BLE_ATT_PREFERRED_MTU CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_FIND_INFO +#define MYNEWT_VAL_BLE_ATT_SVR_FIND_INFO (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_FIND_TYPE +#define MYNEWT_VAL_BLE_ATT_SVR_FIND_TYPE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_INDICATE +#define MYNEWT_VAL_BLE_ATT_SVR_INDICATE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_MAX_PREP_ENTRIES +#define MYNEWT_VAL_BLE_ATT_SVR_MAX_PREP_ENTRIES (64) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_NOTIFY +#define MYNEWT_VAL_BLE_ATT_SVR_NOTIFY (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE +#define MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE_TMO +#define MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE_TMO (30000) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_READ +#define MYNEWT_VAL_BLE_ATT_SVR_READ (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_READ_BLOB +#define MYNEWT_VAL_BLE_ATT_SVR_READ_BLOB (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_READ_GROUP_TYPE +#define MYNEWT_VAL_BLE_ATT_SVR_READ_GROUP_TYPE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_READ_MULT +#define MYNEWT_VAL_BLE_ATT_SVR_READ_MULT (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_READ_TYPE +#define MYNEWT_VAL_BLE_ATT_SVR_READ_TYPE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_SIGNED_WRITE +#define MYNEWT_VAL_BLE_ATT_SVR_SIGNED_WRITE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_WRITE +#define MYNEWT_VAL_BLE_ATT_SVR_WRITE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_WRITE_NO_RSP +#define MYNEWT_VAL_BLE_ATT_SVR_WRITE_NO_RSP (1) +#endif + +#ifndef MYNEWT_VAL_BLE_GAP_MAX_PENDING_CONN_PARAM_UPDATE +#define MYNEWT_VAL_BLE_GAP_MAX_PENDING_CONN_PARAM_UPDATE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_DISC_ALL_CHRS +#define MYNEWT_VAL_BLE_GATT_DISC_ALL_CHRS (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_DISC_ALL_DSCS +#define MYNEWT_VAL_BLE_GATT_DISC_ALL_DSCS (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_DISC_ALL_SVCS +#define MYNEWT_VAL_BLE_GATT_DISC_ALL_SVCS (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_DISC_CHR_UUID +#define MYNEWT_VAL_BLE_GATT_DISC_CHR_UUID (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_DISC_SVC_UUID +#define MYNEWT_VAL_BLE_GATT_DISC_SVC_UUID (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_FIND_INC_SVCS +#define MYNEWT_VAL_BLE_GATT_FIND_INC_SVCS (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_INDICATE +#define MYNEWT_VAL_BLE_GATT_INDICATE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_MAX_PROCS +#define MYNEWT_VAL_BLE_GATT_MAX_PROCS (4) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_NOTIFY +#define MYNEWT_VAL_BLE_GATT_NOTIFY (1) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_READ +#define MYNEWT_VAL_BLE_GATT_READ (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_READ_LONG +#define MYNEWT_VAL_BLE_GATT_READ_LONG (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_READ_MAX_ATTRS +#define MYNEWT_VAL_BLE_GATT_READ_MAX_ATTRS (8) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_READ_MULT +#define MYNEWT_VAL_BLE_GATT_READ_MULT (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_READ_UUID +#define MYNEWT_VAL_BLE_GATT_READ_UUID (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_RESUME_RATE +#define MYNEWT_VAL_BLE_GATT_RESUME_RATE (1000) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_SIGNED_WRITE +#define MYNEWT_VAL_BLE_GATT_SIGNED_WRITE (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_WRITE +#define MYNEWT_VAL_BLE_GATT_WRITE (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_WRITE_LONG +#define MYNEWT_VAL_BLE_GATT_WRITE_LONG (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_WRITE_MAX_ATTRS +#define MYNEWT_VAL_BLE_GATT_WRITE_MAX_ATTRS (4) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_WRITE_NO_RSP +#define MYNEWT_VAL_BLE_GATT_WRITE_NO_RSP (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_WRITE_RELIABLE +#define MYNEWT_VAL_BLE_GATT_WRITE_RELIABLE (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_HOST +#define MYNEWT_VAL_BLE_HOST (1) +#endif + +#ifndef MYNEWT_VAL_BLE_HS_DEBUG +#ifdef CONFIG_BT_NIMBLE_DEBUG +#define MYNEWT_VAL_BLE_HS_DEBUG (1) +#else +#define MYNEWT_VAL_BLE_HS_DEBUG (0) +#endif +#endif + +#ifndef MYNEWT_VAL_BLE_HS_AUTO_START +#define MYNEWT_VAL_BLE_HS_AUTO_START (1) +#endif + +#ifndef MYNEWT_VAL_BLE_HS_FLOW_CTRL +#define MYNEWT_VAL_BLE_HS_FLOW_CTRL (0) +#endif + +#ifndef MYNEWT_VAL_BLE_HS_FLOW_CTRL_ITVL +#define MYNEWT_VAL_BLE_HS_FLOW_CTRL_ITVL (1000) +#endif + +#ifndef MYNEWT_VAL_BLE_HS_FLOW_CTRL_THRESH +#define MYNEWT_VAL_BLE_HS_FLOW_CTRL_THRESH (2) +#endif + +#ifndef MYNEWT_VAL_BLE_HS_FLOW_CTRL_TX_ON_DISCONNECT +#define MYNEWT_VAL_BLE_HS_FLOW_CTRL_TX_ON_DISCONNECT (0) +#endif + +#ifndef MYNEWT_VAL_BLE_HS_PHONY_HCI_ACKS +#define MYNEWT_VAL_BLE_HS_PHONY_HCI_ACKS (0) +#endif + +#ifndef MYNEWT_VAL_BLE_HS_REQUIRE_OS +#define MYNEWT_VAL_BLE_HS_REQUIRE_OS (1) +#endif + +#ifndef MYNEWT_VAL_BLE_L2CAP_COC_MAX_NUM +#define MYNEWT_VAL_BLE_L2CAP_COC_MAX_NUM CONFIG_BT_NIMBLE_L2CAP_COC_MAX_NUM +#endif + +#ifndef MYNEWT_VAL_BLE_L2CAP_JOIN_RX_FRAGS +#define MYNEWT_VAL_BLE_L2CAP_JOIN_RX_FRAGS (1) +#endif + +#ifndef MYNEWT_VAL_BLE_L2CAP_MAX_CHANS +#define MYNEWT_VAL_BLE_L2CAP_MAX_CHANS (3*MYNEWT_VAL_BLE_MAX_CONNECTIONS) +#endif + +#ifndef MYNEWT_VAL_BLE_L2CAP_RX_FRAG_TIMEOUT +#define MYNEWT_VAL_BLE_L2CAP_RX_FRAG_TIMEOUT (30000) +#endif + +#ifndef MYNEWT_VAL_BLE_L2CAP_SIG_MAX_PROCS +#define MYNEWT_VAL_BLE_L2CAP_SIG_MAX_PROCS (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH +#ifdef CONFIG_BT_NIMBLE_MESH +#define MYNEWT_VAL_BLE_MESH (1) +#else +#define MYNEWT_VAL_BLE_MESH (0) +#endif +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE (128) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT +#define MYNEWT_VAL_BLE_MONITOR_RTT (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME ("monitor") +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE (256) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART +#define MYNEWT_VAL_BLE_MONITOR_UART (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE +#define MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE (1000000) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE (64) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_DEV +#define MYNEWT_VAL_BLE_MONITOR_UART_DEV ("uart0") +#endif + +#ifndef MYNEWT_VAL_BLE_RPA_TIMEOUT +#define MYNEWT_VAL_BLE_RPA_TIMEOUT (300) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_BONDING +#define MYNEWT_VAL_BLE_SM_BONDING (1) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_IO_CAP +#define MYNEWT_VAL_BLE_SM_IO_CAP (BLE_HS_IO_NO_INPUT_OUTPUT) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_KEYPRESS +#define MYNEWT_VAL_BLE_SM_KEYPRESS (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_LEGACY +#ifdef CONFIG_BT_NIMBLE_SM_LEGACY +#define MYNEWT_VAL_BLE_SM_LEGACY (1) +#else +#define MYNEWT_VAL_BLE_SM_LEGACY (0) +#endif +#endif + +#ifndef MYNEWT_VAL_BLE_SM_MAX_PROCS +#define MYNEWT_VAL_BLE_SM_MAX_PROCS (1) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_MITM +#define MYNEWT_VAL_BLE_SM_MITM (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_OOB_DATA_FLAG +#define MYNEWT_VAL_BLE_SM_OOB_DATA_FLAG (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_OUR_KEY_DIST +#define MYNEWT_VAL_BLE_SM_OUR_KEY_DIST (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_SC +#ifdef CONFIG_BT_NIMBLE_SM_SC +#define MYNEWT_VAL_BLE_SM_SC (1) +#else +#define MYNEWT_VAL_BLE_SM_SC (0) +#endif +#endif + +#ifndef MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST +#define MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST (0) +#endif + +#ifndef MYNEWT_VAL_BLE_STORE_MAX_BONDS +#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 CONFIG_BT_NIMBLE_MAX_CCCDS +#endif + +#ifndef MYNEWT_VAL_BLE_STORE_CONFIG_PERSIST +#ifdef CONFIG_BT_NIMBLE_NVS_PERSIST +#define MYNEWT_VAL_BLE_STORE_CONFIG_PERSIST (1) +#else +#define MYNEWT_VAL_BLE_STORE_CONFIG_PERSIST (0) +#endif +#endif + +/*** nimble/host/services/ans */ +#ifndef MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT +#define MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT (0) +#endif + + +#ifndef MYNEWT_VAL_BLE_SVC_ANS_UNR_ALERT_CAT +#define MYNEWT_VAL_BLE_SVC_ANS_UNR_ALERT_CAT (0) +#endif + +/*** nimble/host/services/bas */ +#ifndef MYNEWT_VAL_BLE_SVC_BAS_BATTERY_LEVEL_NOTIFY_ENABLE +#define MYNEWT_VAL_BLE_SVC_BAS_BATTERY_LEVEL_NOTIFY_ENABLE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_BAS_BATTERY_LEVEL_READ_PERM +#define MYNEWT_VAL_BLE_SVC_BAS_BATTERY_LEVEL_READ_PERM (0) +#endif +#ifndef MYNEWT_VAL_BLE_MESH_ADV_TASK_PRIO +#define MYNEWT_VAL_BLE_MESH_ADV_TASK_PRIO (9) +#endif + + +/*** @apache-mynewt-nimble/nimble/host/mesh */ +/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_ADV_BUF_COUNT +#define MYNEWT_VAL_BLE_MESH_ADV_BUF_COUNT (20) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_APP_KEY_COUNT +#define MYNEWT_VAL_BLE_MESH_APP_KEY_COUNT (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_CFG_CLI +#define MYNEWT_VAL_BLE_MESH_CFG_CLI (0) +#endif +#ifndef MYNEWT_VAL_BLE_MESH_CRPL +#define MYNEWT_VAL_BLE_MESH_CRPL (10) +#endif + +/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG +#define MYNEWT_VAL_BLE_MESH_DEBUG (1) +#endif + +/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_ACCESS +#define MYNEWT_VAL_BLE_MESH_DEBUG_ACCESS (1) +#endif + +/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_ADV +#define MYNEWT_VAL_BLE_MESH_DEBUG_ADV (1) +#endif + +/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG +#define MYNEWT_VAL_BLE_MESH_DEBUG (1) +#endif + +/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_ACCESS +#define MYNEWT_VAL_BLE_MESH_DEBUG_ACCESS (1) +#endif + +/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_ADV +#define MYNEWT_VAL_BLE_MESH_DEBUG_ADV (1) +#endif + +/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_BEACON +#define MYNEWT_VAL_BLE_MESH_DEBUG_BEACON (1) +#endif + +/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_CRYPTO +#define MYNEWT_VAL_BLE_MESH_DEBUG_CRYPTO (1) +#endif + +/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_FRIEND +#define MYNEWT_VAL_BLE_MESH_DEBUG_FRIEND (1) +#endif + +/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_LOW_POWER +#define MYNEWT_VAL_BLE_MESH_DEBUG_LOW_POWER (1) +#endif + +/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_MODEL +#define MYNEWT_VAL_BLE_MESH_DEBUG_MODEL (1) +#endif + +/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_NET +#define MYNEWT_VAL_BLE_MESH_DEBUG_NET (1) +#endif + +/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_PROV +#define MYNEWT_VAL_BLE_MESH_DEBUG_PROV (1) +#endif + +/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_PROXY +#define MYNEWT_VAL_BLE_MESH_DEBUG_PROXY (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_SETTINGS +#define MYNEWT_VAL_BLE_MESH_DEBUG_SETTINGS (1) +#endif + +/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_TRANS +#define MYNEWT_VAL_BLE_MESH_DEBUG_TRANS (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_DEVICE_NAME +#define MYNEWT_VAL_BLE_MESH_DEVICE_NAME CONFIG_BT_NIMBLE_MESH_DEVICE_NAME +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_DEV_UUID +#define MYNEWT_VAL_BLE_MESH_DEV_UUID (((uint8_t[16]){0x11, 0x22, 0})) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_FRIEND +#ifdef CONFIG_BT_NIMBLE_MESH_FRIEND +#define MYNEWT_VAL_BLE_MESH_FRIEND (1) +#else +#define MYNEWT_VAL_BLE_MESH_FRIEND (0) +#endif +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_LPN_COUNT +#define MYNEWT_VAL_BLE_MESH_FRIEND_LPN_COUNT (2) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_QUEUE_SIZE +#define MYNEWT_VAL_BLE_MESH_FRIEND_QUEUE_SIZE (16) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_RECV_WIN +#define MYNEWT_VAL_BLE_MESH_FRIEND_RECV_WIN (255) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_SEG_RX +#define MYNEWT_VAL_BLE_MESH_FRIEND_SEG_RX (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_SUB_LIST_SIZE +#define MYNEWT_VAL_BLE_MESH_FRIEND_SUB_LIST_SIZE (3) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_GATT_PROXY +#ifdef CONFIG_BT_NIMBLE_MESH_GATT_PROXY +#define MYNEWT_VAL_BLE_MESH_GATT_PROXY (1) +#else +#define MYNEWT_VAL_BLE_MESH_GATT_PROXY (0) +#endif +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_HEALTH_CLI +#define MYNEWT_VAL_BLE_MESH_HEALTH_CLI (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_IVU_DIVIDER +#define MYNEWT_VAL_BLE_MESH_IVU_DIVIDER (4) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_IV_UPDATE_TEST +#define MYNEWT_VAL_BLE_MESH_IV_UPDATE_TEST (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LABEL_COUNT +#define MYNEWT_VAL_BLE_MESH_LABEL_COUNT (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LOW_POWER +#ifdef CONFIG_BT_NIMBLE_MESH_LOW_POWER +#define MYNEWT_VAL_BLE_MESH_LOW_POWER (1) +#else +#define MYNEWT_VAL_BLE_MESH_LOW_POWER (0) +#endif +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LPN_AUTO +#define MYNEWT_VAL_BLE_MESH_LPN_AUTO (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LPN_AUTO_TIMEOUT +#define MYNEWT_VAL_BLE_MESH_LPN_AUTO_TIMEOUT (15) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LPN_ESTABLISHMENT +#define MYNEWT_VAL_BLE_MESH_LPN_ESTABLISHMENT (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LPN_GROUPS +#define MYNEWT_VAL_BLE_MESH_LPN_GROUPS (10) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LPN_INIT_POLL_TIMEOUT +#define MYNEWT_VAL_BLE_MESH_LPN_INIT_POLL_TIMEOUT (MYNEWT_VAL_BLE_MESH_LPN_POLL_TIMEOUT) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LPN_MIN_QUEUE_SIZE +#define MYNEWT_VAL_BLE_MESH_LPN_MIN_QUEUE_SIZE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LPN_POLL_TIMEOUT +#define MYNEWT_VAL_BLE_MESH_LPN_POLL_TIMEOUT (300) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LPN_RECV_DELAY +#define MYNEWT_VAL_BLE_MESH_LPN_RECV_DELAY (100) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LPN_RECV_WIN_FACTOR +#define MYNEWT_VAL_BLE_MESH_LPN_RECV_WIN_FACTOR (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LPN_RETRY_TIMEOUT +#define MYNEWT_VAL_BLE_MESH_LPN_RETRY_TIMEOUT (8) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LPN_RSSI_FACTOR +#define MYNEWT_VAL_BLE_MESH_LPN_RSSI_FACTOR (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LPN_SCAN_LATENCY +#define MYNEWT_VAL_BLE_MESH_LPN_SCAN_LATENCY (10) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_MODEL_GROUP_COUNT +#define MYNEWT_VAL_BLE_MESH_MODEL_GROUP_COUNT (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_MODEL_KEY_COUNT +#define MYNEWT_VAL_BLE_MESH_MODEL_KEY_COUNT (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_MSG_CACHE_SIZE +#define MYNEWT_VAL_BLE_MESH_MSG_CACHE_SIZE (10) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_NODE_ID_TIMEOUT +#define MYNEWT_VAL_BLE_MESH_NODE_ID_TIMEOUT (60) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_OOB_INPUT_ACTIONS +#define MYNEWT_VAL_BLE_MESH_OOB_INPUT_ACTIONS (((BT_MESH_NO_INPUT))) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_OOB_INPUT_SIZE +#define MYNEWT_VAL_BLE_MESH_OOB_INPUT_SIZE (4) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_OOB_OUTPUT_ACTIONS +#define MYNEWT_VAL_BLE_MESH_OOB_OUTPUT_ACTIONS (((BT_MESH_DISPLAY_NUMBER))) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_OOB_OUTPUT_SIZE +#define MYNEWT_VAL_BLE_MESH_OOB_OUTPUT_SIZE (4) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_PB_ADV +#ifdef CONFIG_BT_NIMBLE_MESH_PB_ADV +#define MYNEWT_VAL_BLE_MESH_PB_ADV (1) +#else +#define MYNEWT_VAL_BLE_MESH_PB_ADV (0) +#endif +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_PB_GATT +#ifdef CONFIG_BT_NIMBLE_MESH_PB_GATT +#define MYNEWT_VAL_BLE_MESH_PB_GATT (1) +#else +#define MYNEWT_VAL_BLE_MESH_PB_GATT (0) +#endif +#endif + +/* Overridden by @apache-mynewt-nimble/nimble/host/mesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_PROV +#ifdef CONFIG_BT_NIMBLE_MESH_PROV +#define MYNEWT_VAL_BLE_MESH_PROV (1) +#else +#define MYNEWT_VAL_BLE_MESH_PROV (0) +#endif +#endif + +/* Overridden by @apache-mynewt-nimble/nimble/host/mesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_PROXY +#ifdef CONFIG_BT_NIMBLE_MESH_PROXY +#define MYNEWT_VAL_BLE_MESH_PROXY (1) +#else +#define MYNEWT_VAL_BLE_MESH_PROXY (0) +#endif +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_PROXY_FILTER_SIZE +#define MYNEWT_VAL_BLE_MESH_PROXY_FILTER_SIZE (1) +#endif + + +#ifndef MYNEWT_VAL_BLE_MESH_RELAY +#ifdef CONFIG_BT_NIMBLE_MESH_RELAY +#define MYNEWT_VAL_BLE_MESH_RELAY (1) +#else +#define MYNEWT_VAL_BLE_MESH_RELAY (0) +#endif +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_RPL_STORE_TIMEOUT +#define MYNEWT_VAL_BLE_MESH_RPL_STORE_TIMEOUT (5) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_RX_SDU_MAX +#define MYNEWT_VAL_BLE_MESH_RX_SDU_MAX (72) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_RX_SEG_MSG_COUNT +#define MYNEWT_VAL_BLE_MESH_RX_SEG_MSG_COUNT (2) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_SEQ_STORE_RATE +#define MYNEWT_VAL_BLE_MESH_SEQ_STORE_RATE (128) +#endif + +/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_SETTINGS +#define MYNEWT_VAL_BLE_MESH_SETTINGS (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_SHELL +#define MYNEWT_VAL_BLE_MESH_SHELL (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_SHELL_MODELS +#define MYNEWT_VAL_BLE_MESH_SHELL_MODELS (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_STORE_TIMEOUT +#define MYNEWT_VAL_BLE_MESH_STORE_TIMEOUT (2) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_SUBNET_COUNT +#define MYNEWT_VAL_BLE_MESH_SUBNET_COUNT (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_TESTING +#define MYNEWT_VAL_BLE_MESH_TESTING (0) +#endif + +/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_TX_SEG_MAX +#define MYNEWT_VAL_BLE_MESH_TX_SEG_MAX (6) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_TX_SEG_MSG_COUNT +#define MYNEWT_VAL_BLE_MESH_TX_SEG_MSG_COUNT (4) +#endif + +/*** @apache-mynewt-nimble/nimble/host/services/gap */ +#ifndef MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE +#define MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE CONFIG_BT_NIMBLE_SVC_GAP_APPEARANCE +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE_WRITE_PERM +#define MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE_WRITE_PERM (-1) +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_GAP_CENTRAL_ADDRESS_RESOLUTION +#define MYNEWT_VAL_BLE_SVC_GAP_CENTRAL_ADDRESS_RESOLUTION (-1) +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME +#define MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME_MAX_LENGTH +#define MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME_MAX_LENGTH CONFIG_BT_NIMBLE_GAP_DEVICE_NAME_MAX_LEN +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME_WRITE_PERM +#define MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME_WRITE_PERM (-1) +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_GAP_PPCP_MAX_CONN_INTERVAL +#define MYNEWT_VAL_BLE_SVC_GAP_PPCP_MAX_CONN_INTERVAL (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_GAP_PPCP_MIN_CONN_INTERVAL +#define MYNEWT_VAL_BLE_SVC_GAP_PPCP_MIN_CONN_INTERVAL (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_GAP_PPCP_SLAVE_LATENCY +#define MYNEWT_VAL_BLE_SVC_GAP_PPCP_SLAVE_LATENCY (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_GAP_PPCP_SUPERVISION_TMO +#define MYNEWT_VAL_BLE_SVC_GAP_PPCP_SUPERVISION_TMO (0) +#endif + +/*** nimble/transport */ +#ifndef MYNEWT_VAL_BLE_HCI_TRANSPORT_EMSPI +#define MYNEWT_VAL_BLE_HCI_TRANSPORT_EMSPI (0) +#endif + +/* Overridden by targets/porting-nimble (defined by nimble/transport) */ +#ifndef MYNEWT_VAL_BLE_HCI_TRANSPORT_NIMBLE_BUILTIN +#define MYNEWT_VAL_BLE_HCI_TRANSPORT_NIMBLE_BUILTIN (0) +#endif + +#ifndef MYNEWT_VAL_BLE_HCI_TRANSPORT_RAM +#define MYNEWT_VAL_BLE_HCI_TRANSPORT_RAM (0) +#endif + +#ifndef MYNEWT_VAL_BLE_HCI_TRANSPORT_SOCKET +#define MYNEWT_VAL_BLE_HCI_TRANSPORT_SOCKET (0) +#endif + +/* Overridden by targets/porting-nimble (defined by nimble/transport) */ +#ifndef MYNEWT_VAL_BLE_HCI_TRANSPORT_UART +#define MYNEWT_VAL_BLE_HCI_TRANSPORT_UART (1) +#endif + +/*** nimble/transport/uart */ +#ifndef MYNEWT_VAL_BLE_ACL_BUF_COUNT +#define MYNEWT_VAL_BLE_ACL_BUF_COUNT CONFIG_BT_NIMBLE_ACL_BUF_COUNT +#endif + +#ifndef MYNEWT_VAL_BLE_ACL_BUF_SIZE +#define MYNEWT_VAL_BLE_ACL_BUF_SIZE CONFIG_BT_NIMBLE_ACL_BUF_SIZE +#endif + +#ifndef MYNEWT_VAL_BLE_HCI_ACL_OUT_COUNT +#define MYNEWT_VAL_BLE_HCI_ACL_OUT_COUNT (12) +#endif + +#ifndef MYNEWT_VAL_BLE_HCI_EVT_BUF_SIZE +#define MYNEWT_VAL_BLE_HCI_EVT_BUF_SIZE CONFIG_BT_NIMBLE_HCI_EVT_BUF_SIZE +#endif + +#ifndef MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT +#define MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT CONFIG_BT_NIMBLE_HCI_EVT_HI_BUF_COUNT +#endif + +#ifndef MYNEWT_VAL_BLE_HCI_EVT_LO_BUF_COUNT +#define MYNEWT_VAL_BLE_HCI_EVT_LO_BUF_COUNT CONFIG_BT_NIMBLE_HCI_EVT_LO_BUF_COUNT +#endif + +/* Overridden by targets/porting-nimble (defined by nimble/transport/uart) */ +#ifndef MYNEWT_VAL_BLE_HCI_UART_BAUD +#define MYNEWT_VAL_BLE_HCI_UART_BAUD (115200) +#endif + +#ifndef MYNEWT_VAL_BLE_HCI_UART_DATA_BITS +#define MYNEWT_VAL_BLE_HCI_UART_DATA_BITS (8) +#endif + +/* Overridden by targets/porting-nimble (defined by nimble/transport/uart) */ +#ifndef MYNEWT_VAL_BLE_HCI_UART_FLOW_CTRL +#define MYNEWT_VAL_BLE_HCI_UART_FLOW_CTRL (0) +#endif + +#ifndef MYNEWT_VAL_BLE_HCI_UART_PARITY +#define MYNEWT_VAL_BLE_HCI_UART_PARITY (HAL_UART_PARITY_NONE) +#endif + +#ifndef MYNEWT_VAL_BLE_HCI_UART_PORT +#define MYNEWT_VAL_BLE_HCI_UART_PORT (0) +#endif + +#ifndef MYNEWT_VAL_BLE_HCI_UART_STOP_BITS +#define MYNEWT_VAL_BLE_HCI_UART_STOP_BITS (1) +#endif + +#endif diff --git a/components/bt/include/esp_bt.h b/components/bt/include/esp_bt.h index 1157843218..a650d98468 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); @@ -417,6 +416,8 @@ esp_err_t esp_bt_controller_mem_release(esp_bt_mode_t mode); * esp_bt_controller_deinit(); * esp_bt_mem_release(ESP_BT_MODE_BTDM); * + * @note In case of NimBLE host, to release BSS and data memory to heap, the mode needs to be + * set to ESP_BT_MODE_BTDM as controller is dual mode. * @param mode : the mode whose memory is to be released * @return ESP_OK - success, other - failed */ diff --git a/components/bt/lib b/components/bt/lib deleted file mode 160000 index 6834a6bfcf..0000000000 --- a/components/bt/lib +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6834a6bfcfd395acc37249fae1c3121fc2e705cb 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..3b2da20ce8 100644 --- a/components/coap/CMakeLists.txt +++ b/components/coap/CMakeLists.txt @@ -1,31 +1,32 @@ -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" - "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" + "port/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_io.c" + "port/coap_mbedtls.c") -set(COMPONENT_REQUIRES lwip) - -register_component() +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS "${include_dirs}" + REQUIRES lwip mbedtls) # 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/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/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 58391add6b..0000000000 --- a/components/coap/port/coap_io.c +++ /dev/null @@ -1,1422 +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() { - 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 */ -}; - -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) -/* 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 d675b7a583..dc1166090d 100644 --- a/components/coap/port/include/coap_config_posix.h +++ b/components/coap/port/include/coap_config_posix.h @@ -21,19 +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 IP_PKTINFO IP_MULTICAST_IF #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/console/CMakeLists.txt b/components/console/CMakeLists.txt index 33dddc81a9..cb20200cd6 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/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/CMakeLists.txt b/components/cxx/CMakeLists.txt index f1f9b35c25..4e81992ad0 100644 --- a/components/cxx/CMakeLists.txt +++ b/components/cxx/CMakeLists.txt @@ -1,10 +1,9 @@ -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} stdc++ gcc) -target_link_libraries(${COMPONENT_LIB} "-u __cxa_guard_dummy") +target_link_libraries(${COMPONENT_LIB} PUBLIC stdc++ gcc) +target_link_libraries(${COMPONENT_LIB} INTERFACE "-u __cxa_guard_dummy") if(NOT CONFIG_COMPILER_CXX_EXCEPTIONS) - target_link_libraries(${COMPONENT_LIB} "-u __cxx_fatal_exception") + target_link_libraries(${COMPONENT_LIB} INTERFACE "-u __cxx_fatal_exception") endif() 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/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/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/driver/CMakeLists.txt b/components/driver/CMakeLists.txt index eeeea7d9a4..cf1f7e7c1a 100644 --- a/components/driver/CMakeLists.txt +++ b/components/driver/CMakeLists.txt @@ -1,43 +1,44 @@ -set(COMPONENT_SRCS "can.c" - "gpio.c" - "i2c.c" - "i2s.c" - "ledc.c" - "pcnt.c" - "periph_ctrl.c" - "rmt.c" - "rtc_module.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(srcs + "can.c" + "gpio.c" + "i2c.c" + "i2s.c" + "ledc.c" + "pcnt.c" + "periph_ctrl.c" + "rmt.c" + "rtc_module.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(includes "include") if(CONFIG_IDF_TARGET_ESP32) # SDMMC and MCPWM are in ESP32 only. - list(APPEND COMPONENT_SRCS "mcpwm.c" - "sdio_slave.c" - "sdmmc_host.c" - "sdmmc_transaction.c") + list(APPEND srcs "mcpwm.c" + "sdio_slave.c" + "sdmmc_host.c" + "sdmmc_transaction.c") endif() -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 - if(CONFIG_IDF_TARGET_ESP32S2BETA) - list(APPEND COMPONENT_SRCS "${CONFIG_IDF_TARGET}/rtc_tempsensor.c" - "${CONFIG_IDF_TARGET}/rtc_touchpad.c") - - list(APPEND COMPONENT_ADD_INCLUDEDIRS "${CONFIG_IDF_TARGET}/include") + list(APPEND srcs "esp32s2beta/rtc_tempsensor.c" + "esp32s2beta/rtc_touchpad.c") + # currently only S2 beta has its own target-specific includes + list(APPEND includes "esp32s2beta/include") endif() -register_component() - +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS ${includes} + 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 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 63b95dd36c..b837ad2e2c 100644 --- a/components/driver/can.c +++ b/components/driver/can.c @@ -142,7 +142,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 @@ -152,7 +152,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. */ @@ -161,7 +161,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; @@ -287,23 +287,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 @@ -329,7 +329,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; } @@ -354,7 +354,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) { @@ -479,10 +479,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 @@ -721,7 +726,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; @@ -757,7 +762,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(); @@ -787,7 +792,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(); @@ -924,7 +929,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 @@ -978,7 +983,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); @@ -993,7 +998,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/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/gpio.c b/components/driver/gpio.c index d8d5c26948..774271514b 100644 --- a/components/driver/gpio.c +++ b/components/driver/gpio.c @@ -22,21 +22,34 @@ #include "soc/rtc_cntl_reg.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) @@ -118,7 +131,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 CONFIG_IDF_TARGET_ESP32 if (core_id == 0) { @@ -136,7 +148,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) @@ -377,16 +395,25 @@ 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; + uint32_t gpio_intr_status; +#ifdef CONFIG_IDF_TARGET_ESP32 + gpio_intr_status = (isr_core_id == 0) ? GPIO.pcpu_int : GPIO.acpu_int; +#else + gpio_intr_status = GPIO.pcpu_int; +#endif 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; + uint32_t gpio_intr_status_h; +#ifdef CONFIG_IDF_TARGET_ESP32 + gpio_intr_status_h = (isr_core_id == 0) ? GPIO.pcpu_int1.intr : GPIO.acpu_int1.intr; +#else + gpio_intr_status_h = GPIO.pcpu_int1.intr; +#endif if (gpio_intr_status_h) { gpio_isr_loop(gpio_intr_status_h, 32); GPIO.status1_w1tc.intr_st = gpio_intr_status_h; @@ -428,16 +455,16 @@ 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; } -void gpio_uninstall_isr_service() +void gpio_uninstall_isr_service(void) { if (gpio_isr_func == NULL) { return; @@ -446,14 +473,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/i2c.c b/components/driver/i2c.c index a9130801c1..264eefa1c1 100644 --- a/components/driver/i2c.c +++ b/components/driver/i2c.c @@ -985,7 +985,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 904f1ef156..d601995771 100644 --- a/components/driver/i2s.c +++ b/components/driver/i2s.c @@ -91,6 +91,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 @@ -185,6 +186,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(i2s_periph_signal[i2s_num].irq, intr_alloc_flags, fn, arg, handle); @@ -265,7 +272,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; } @@ -275,11 +282,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 ++) { @@ -479,6 +496,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b I2S[i2s_num]->clkm_conf.clk_sel = 1; #endif 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 { @@ -493,6 +511,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); } @@ -756,7 +775,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); @@ -924,7 +943,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 @@ -936,7 +955,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; diff --git a/components/driver/include/driver/adc.h b/components/driver/include/driver/adc.h index bc108847d8..e3b1ac74a1 100644 --- a/components/driver/include/driver/adc.h +++ b/components/driver/include/driver/adc.h @@ -235,13 +235,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 @@ -298,7 +298,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 @@ -319,7 +319,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 8318d9cb05..820b913a8c 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 87c68b95d4..7223d6f465 100644 --- a/components/driver/include/driver/gpio.h +++ b/components/driver/include/driver/gpio.h @@ -637,7 +637,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 a793ac60ad..eaa902e612 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/i2s.h b/components/driver/include/driver/i2s.h index 225cde85b4..b1b767cab8 100644 --- a/components/driver/include/driver/i2s.h +++ b/components/driver/include/driver/i2s.h @@ -509,6 +509,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/include/driver/ledc.h b/components/driver/include/driver/ledc.h index bd54c23de4..bb7e577547 100644 --- a/components/driver/include/driver/ledc.h +++ b/components/driver/include/driver/ledc.h @@ -53,6 +53,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 */ @@ -129,6 +136,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; @@ -439,7 +449,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 53ca2b5669..73ede43419 100644 --- a/components/driver/include/driver/rtc_io.h +++ b/components/driver/include/driver/rtc_io.h @@ -230,7 +230,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 @@ -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/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_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/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 138014e4ff..9faf25c455 100644 --- a/components/driver/include/driver/spi_common.h +++ b/components/driver/include/driver/spi_common.h @@ -1,9 +1,9 @@ -// Copyright 2010-2018 Espressif Systems (Shanghai) PTE LTD +// 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 @@ -12,9 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. - -#ifndef _DRIVER_SPI_COMMON_H_ -#define _DRIVER_SPI_COMMON_H_ +#pragma once #include #include @@ -62,35 +60,6 @@ extern "C" */ #define SPI_SWAP_DATA_RX(data, len) (__builtin_bswap32(data)>>(32-len)) -/** - * Transform unsigned integer of length <= 32 bits to the format which can be - * sent by the SPI driver directly. - * - * E.g. to send 9 bits of data, you can: - * - * uint16_t data = SPI_SWAP_DATA_TX(0x145, 9); - * - * Then points tx_buffer to ``&data``. - * - * @param data Data to be sent, can be uint8_t, uint16_t or uint32_t. @param - * len Length of data to be sent, since the SPI peripheral sends from the MSB, - * this helps to shift the data to the MSB. - */ -#define SPI_SWAP_DATA_TX(data, len) __builtin_bswap32((uint32_t)data<<(32-len)) - -/** - * Transform received data of length <= 32 bits to the format of an unsigned integer. - * - * E.g. to transform the data of 15 bits placed in a 4-byte array to integer: - * - * uint16_t data = SPI_SWAP_DATA_RX(*(uint32_t*)t->rx_data, 15); - * - * @param data Data to be rearranged, can be uint8_t, uint16_t or uint32_t. - * @param len Length of data received, since the SPI peripheral writes from - * the MSB, this helps to shift the data to the LSB. - */ -#define SPI_SWAP_DATA_RX(data, len) (__builtin_bswap32(data)>>(32-len)) - /** * @brief This is a configuration structure for a SPI bus. * @@ -116,6 +85,50 @@ typedef struct { } spi_bus_config_t; +/** + * @brief Initialize a SPI bus + * + * @warning For now, only supports HSPI and VSPI. + * + * @param host SPI peripheral that controls this bus + * @param bus_config Pointer to a spi_bus_config_t struct specifying how the host should be initialized + * @param dma_chan Either channel 1 or 2, or 0 in the case when no DMA is required. Selecting a DMA channel + * for a SPI bus allows transfers on the bus to have sizes only limited by the amount of + * internal memory. Selecting no DMA channel (by passing the value 0) limits the amount of + * bytes transfered to a maximum of 64. Set to 0 if only the SPI flash uses + * this bus. + * + * @warning If a DMA channel is selected, any transmit and receive buffer used should be allocated in + * DMA-capable memory. + * + * @warning The ISR of SPI is always executed on the core which calls this + * function. Never starve the ISR on this core or the SPI transactions will not + * be handled. + * + * @return + * - ESP_ERR_INVALID_ARG if configuration is invalid + * - ESP_ERR_INVALID_STATE if host already is in use + * - ESP_ERR_NO_MEM if out of memory + * - ESP_OK on success + */ +esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus_config, int dma_chan); + +/** + * @brief Free a SPI bus + * + * @warning In order for this to succeed, all devices have to be removed first. + * + * @param host SPI peripheral to free + * @return + * - ESP_ERR_INVALID_ARG if parameter is invalid + * - ESP_ERR_INVALID_STATE if not all devices on the bus are freed + * - ESP_OK on success + */ +esp_err_t spi_bus_free(spi_host_device_t host); + + +/** @cond */ //Doxygen command to hide deprecated function (or non-public) from API Reference + /** * @brief Try to claim a SPI peripheral * @@ -124,27 +137,19 @@ typedef struct { * @param host Peripheral to claim * @param source The caller indentification string. * + * @note This public API is deprecated. + * * @return True if peripheral is claimed successfully; false if peripheral already is claimed. */ 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. * * @param host Peripheral to check. * + * @note This public API is deprecated. + * * @return True if in use, otherwise false. */ bool spicommon_periph_in_use(spi_host_device_t host); @@ -153,6 +158,9 @@ bool spicommon_periph_in_use(spi_host_device_t host); * @brief Return the SPI peripheral so another driver can claim it. * * @param host Peripheral to return + * + * @note This public API is deprecated. + * * @return True if peripheral is returned successfully; false if peripheral was free to claim already. */ bool spicommon_periph_free(spi_host_device_t host); @@ -164,6 +172,8 @@ bool spicommon_periph_free(spi_host_device_t host); * * @param dma_chan channel to claim * + * @note This public API is deprecated. + * * @return True if success; false otherwise. */ bool spicommon_dma_chan_claim(int dma_chan); @@ -173,6 +183,8 @@ bool spicommon_dma_chan_claim(int dma_chan); * * @param dma_chan DMA channel to check. * + * @note This public API is deprecated. + * * @return True if in use, otherwise false. */ bool spicommon_dma_chan_in_use(int dma_chan); @@ -182,10 +194,13 @@ bool spicommon_dma_chan_in_use(int dma_chan); * * @param dma_chan channel to return * + * @note This public API is deprecated. + * * @return True if success; false otherwise. */ bool spicommon_dma_chan_free(int dma_chan); +/// @note macros deprecated from public API #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_IOMUX_PINS (1<<1) ///< Check using iomux pins. Or indicates the pins are configured through the IO mux rather than GPIO matrix. @@ -206,6 +221,9 @@ bool spicommon_dma_chan_free(int dma_chan); * the arguments. Depending on the IO-pads requested, the routing is done either using the * IO_mux or using the GPIO matrix. * + * @note This public API is deprecated. Please call ``spi_bus_initialize`` for master + * bus initialization and ``spi_slave_initialize`` for slave initialization. + * * @param host SPI peripheral to be routed * @param bus_config Pointer to a spi_bus_config struct detailing the GPIO pins * @param dma_chan DMA-channel (1 or 2) to use, or 0 for no DMA. @@ -234,18 +252,9 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf /** * @brief Free the IO used by a SPI peripheral - * @deprecated Use spicommon_bus_free_io_cfg instead. * - * @param host SPI peripheral to be freed - * - * @return - * - ESP_ERR_INVALID_ARG if parameter is invalid - * - ESP_OK on success - */ -esp_err_t spicommon_bus_free_io(spi_host_device_t host) __attribute__((deprecated)); - -/** - * @brief Free the IO used by a SPI peripheral + * @note This public API is deprecated. Please call ``spi_bus_free`` for master + * bus deinitialization and ``spi_slave_free`` for slave deinitialization. * * @param bus_cfg Bus config struct which defines which pins to be used. * @@ -258,6 +267,8 @@ esp_err_t spicommon_bus_free_io_cfg(const spi_bus_config_t *bus_cfg); /** * @brief Initialize a Chip Select pin for a specific SPI peripheral * + * @note This public API is deprecated. Please call corresponding device initialization + * functions. * * @param host SPI peripheral * @param cs_io_num GPIO pin to route @@ -265,59 +276,61 @@ esp_err_t spicommon_bus_free_io_cfg(const spi_bus_config_t *bus_cfg); * @param force_gpio_matrix If true, CS will always be routed through the GPIO matrix. If false, * if the GPIO number allows it, the routing will happen through the IO_mux. */ - void spicommon_cs_initialize(spi_host_device_t host, int cs_io_num, int cs_num, int force_gpio_matrix); -/** - * @brief Free a chip select line - * @deprecated Use spicommon_cs_io, which inputs the gpio num rather than the cs id instead. - * - * @param host SPI peripheral - * @param cs_num CS id to free - */ -void spicommon_cs_free(spi_host_device_t host, int cs_num) __attribute__((deprecated)); - /** * @brief Free a chip select line * * @param cs_gpio_num CS gpio num to free + * + * @note This public API is deprecated. */ void spicommon_cs_free_io(int cs_gpio_num); /** - * @brief Setup a DMA link chain + * @brief Check whether all pins used by a host are through IOMUX. * - * This routine will set up a chain of linked DMA descriptors in the array pointed to by - * ``dmadesc``. Enough DMA descriptors will be used to fit the buffer of ``len`` bytes in, and the - * descriptors will point to the corresponding positions in ``buffer`` and linked together. The - * end result is that feeding ``dmadesc[0]`` into DMA hardware results in the entirety ``len`` bytes - * of ``data`` being read or written. + * @param host SPI peripheral * - * @param dmadesc Pointer to array of DMA descriptors big enough to be able to convey ``len`` bytes - * @param len Length of buffer - * @param data Data buffer to use for DMA transfer - * @param isrx True if data is to be written into ``data``, false if it's to be read from ``data``. + * @note This public API is deprecated. + * + * @return false if any pins are through the GPIO matrix, otherwise true. */ -void spicommon_setup_dma_desc_links(lldesc_t *dmadesc, int len, const uint8_t *data, bool isrx); +bool spicommon_bus_using_iomux(spi_host_device_t host); /** - * @brief Get the position of the hardware registers for a specific SPI host + * @brief Check whether all pins used by a host are through IOMUX. * - * @param host The SPI host + * @param host SPI peripheral * - * @return A register descriptor stuct pointer, pointed at the hardware registers + * @note This public API is deprecated. + * + * @return false if any pins are through the GPIO matrix, otherwise true. */ -spi_dev_t *spicommon_hw_for_host(spi_host_device_t host); +bool spicommon_bus_using_iomux(spi_host_device_t host); /** * @brief Get the IRQ source for a specific SPI host * * @param host The SPI host * + * @note This public API is deprecated. + * * @return The hosts IRQ source */ 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 + * + * @note This public API is deprecated. + * + * @return The hosts IRQ source + */ +int spicommon_irqdma_source_for_host(spi_host_device_t host); + /** * @brief Get the IRQ source for a specific SPI DMA * @@ -349,6 +362,8 @@ typedef void(*dmaworkaround_cb_t)(void *arg); * @param cb Callback to call in case DMA channel cannot be reset immediately * @param arg Argument to the callback * + * @note This public API is deprecated. + * * @return True when a DMA reset could be executed immediately. False when it could not; in this * case the callback will be called with the specified argument when the logic can execute * a reset, after that reset. @@ -359,9 +374,11 @@ bool spicommon_dmaworkaround_req_reset(int dmachan, dmaworkaround_cb_t cb, void /** * @brief Check if a DMA reset is requested but has not completed yet * + * @note This public API is deprecated. + * * @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); /** @@ -369,6 +386,8 @@ bool spicommon_dmaworkaround_reset_in_progress(); * * A call to this function tells the workaround logic that this channel will * not be affected by a global SPI DMA reset. + * + * @note This public API is deprecated. */ void spicommon_dmaworkaround_idle(int dmachan); @@ -377,13 +396,13 @@ void spicommon_dmaworkaround_idle(int dmachan); * * A call to this function tells the workaround logic that this channel will * be affected by a global SPI DMA reset, and a reset like that should not be attempted. + * + * @note This public API is deprecated. */ void spicommon_dmaworkaround_transfer_active(int dmachan); - +/** @endcond */ #ifdef __cplusplus } #endif - -#endif diff --git a/components/driver/include/driver/spi_master.h b/components/driver/include/driver/spi_master.h index 1cf3aebc65..4753a780c8 100644 --- a/components/driver/include/driver/spi_master.h +++ b/components/driver/include/driver/spi_master.h @@ -1,9 +1,9 @@ -// Copyright 2010-2018 Espressif Systems (Shanghai) PTE LTD +// 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 @@ -12,14 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. - -#ifndef _DRIVER_SPI_MASTER_H_ -#define _DRIVER_SPI_MASTER_H_ +#pragma once #include "esp_err.h" #include "freertos/FreeRTOS.h" -#include "freertos/semphr.h" - +//for spi_bus_initialization funcions. to be back-compatible #include "driver/spi_common.h" /** SPI master clock is divided by 80MHz apb clock. Below defines are example frequencies, and are accurate. Be free to specify a random frequency, it will be rounded to closest frequency (to macros below if above 8MHz). @@ -164,47 +161,6 @@ typedef struct { typedef struct spi_device_t* spi_device_handle_t; ///< Handle for a device on a SPI bus - -/** - * @brief Initialize a SPI bus - * - * @warning For now, only supports HSPI and VSPI. - * - * @param host SPI peripheral that controls this bus - * @param bus_config Pointer to a spi_bus_config_t struct specifying how the host should be initialized - * @param dma_chan Either channel 1 or 2, or 0 in the case when no DMA is required. Selecting a DMA channel - * for a SPI bus allows transfers on the bus to have sizes only limited by the amount of - * internal memory. Selecting no DMA channel (by passing the value 0) limits the amount of - * bytes transfered to a maximum of 32. - * - * @warning If a DMA channel is selected, any transmit and receive buffer used should be allocated in - * DMA-capable memory. - * - * @warning The ISR of SPI is always executed on the core which calls this - * function. Never starve the ISR on this core or the SPI transactions will not - * be handled. - * - * @return - * - ESP_ERR_INVALID_ARG if configuration is invalid - * - ESP_ERR_INVALID_STATE if host already is in use - * - ESP_ERR_NO_MEM if out of memory - * - ESP_OK on success - */ -esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus_config, int dma_chan); - -/** - * @brief Free a SPI bus - * - * @warning In order for this to succeed, all devices have to be removed first. - * - * @param host SPI peripheral to free - * @return - * - ESP_ERR_INVALID_ARG if parameter is invalid - * - ESP_ERR_INVALID_STATE if not all devices on the bus are freed - * - ESP_OK on success - */ -esp_err_t spi_bus_free(spi_host_device_t host); - /** * @brief Allocate a device on a SPI bus * @@ -439,4 +395,3 @@ int spi_get_freq_limit(bool gpio_is_used, int input_delay_ns); } #endif -#endif diff --git a/components/driver/include/driver/timer.h b/components/driver/include/driver/timer.h index b694bc8393..c760fb3898 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, /*!= 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/soc/include/soc/spi_periph.h b/components/soc/include/soc/spi_periph.h index 7e816e56ac..7748b6fbec 100644 --- a/components/soc/include/soc/spi_periph.h +++ b/components/soc/include/soc/spi_periph.h @@ -16,6 +16,8 @@ #include #include "soc/soc.h" #include "soc/periph_defs.h" + +//include soc related (generated) definitions #include "soc/spi_caps.h" #include "soc/spi_reg.h" #include "soc/spi_struct.h" diff --git a/components/soc/linker.lf b/components/soc/linker.lf index d91f728b6d..21aa0a0331 100644 --- a/components/soc/linker.lf +++ b/components/soc/linker.lf @@ -12,4 +12,12 @@ 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) + 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) 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..56a525baac --- /dev/null +++ b/components/soc/src/hal/spi_flash_hal_iram.c @@ -0,0 +1,155 @@ +// 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); + + /* + * 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; +} + +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/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/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 41e58876dd..63b19cd968 100644 --- a/components/spi_flash/CMakeLists.txt +++ b/components/spi_flash/CMakeLists.txt @@ -1,23 +1,39 @@ +set(priv_requires bootloader_support soc) if(BOOTLOADER_BUILD) - if (CONFIG_IDF_TARGET_ESP32) - # ESP32 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) + # on ESP32, we will include spi_flash_rom_patch.c + # but on other platforms no source files are needed for bootloader + set(srcs) +else() + set(srcs + "cache_utils.c" + "flash_mmap.c" + "flash_ops.c" + "partition.c" + "spi_flash_chip_drivers.c" + "spi_flash_chip_generic.c" + "spi_flash_chip_issi.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") endif() -else() # not BOOTLOADER_BUILD - set(COMPONENT_SRCS "cache_utils.c" - "flash_mmap.c" - "flash_ops.c" - "partition.c" - "spi_flash_rom_patch.c" - "${IDF_TARGET}/flash_ops_${IDF_TARGET}.c") - set(COMPONENT_REQUIRES app_update) - set(COMPONENT_PRIV_REQUIRES bootloader_support soc) + + 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() -set(COMPONENT_ADD_INCLUDEDIRS include) -set(COMPONENT_PRIV_INCLUDEDIRS ".") -set(COMPONENT_ADD_LDFRAGMENTS linker.lf) +if(CONFIG_IDF_TARGET_ESP32) + list(APPEND srcs "spi_flash_rom_patch.c") +endif() + +idf_component_register(SRCS "${srcs}" + PRIV_REQUIRES "${priv_requires}" + INCLUDE_DIRS include + PRIV_INCLUDE_DIRS private_include + LDFRAGMENTS linker.lf) -register_component() diff --git a/components/spi_flash/Kconfig b/components/spi_flash/Kconfig index 7ffb5660a3..edd8892fc9 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,14 +69,38 @@ 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_DANGEROUS_WRITE_ABORTS + bool "Aborts" + config SPI_FLASH_DANGEROUS_WRITE_FAILS + bool "Fails" + config SPI_FLASH_DANGEROUS_WRITE_ALLOWED + 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 + 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 807b592d28..f9c7ecaa09 100644 --- a/components/spi_flash/README.rst +++ b/components/spi_flash/README.rst @@ -1,80 +1,105 @@ -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 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. +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. -SPI flash access APIs ---------------------- +.. note:: -This is the set of APIs for working with data in flash: + 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. -- :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_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 `. +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). + +Initializing a flash device +--------------------------- + +To use ``esp_flash_*`` APIs, you need to have a chip initialized on a certain +SPI bus. + +1. Call :cpp:func:`spi_bus_initialize` to properly initialize an SPI bus. + This functions initialize the resources (I/O, DMA, interrupts) shared + among devices attached to this bus. + +2. Call :cpp:func:`spi_bus_add_flash_device` to attach the flash device onto + the bus. This allocates memory, and fill the members for the + ``esp_flash_t`` structure. The CS I/O is also initialized here. + +3. Call :cpp:func:`esp_flash_init` to actually communicate with the chip. + This will also detect the chip type, and influence the following + operations. + +.. note:: Multiple flash chips can be attached to the same bus now. However, + using ``esp_flash_*`` devices and ``spi_device_*`` devices on the + same SPI bus is not supported yet. + +SPI flash access API +-------------------- + +This is the set of API functions for working with data in flash: + +- :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 to the "main" SPI +flash chip in favour 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 project configuration. -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 ``esp_flash_*`` functions (in both software & ROM) to check the bounds. -Concurrency Constraints ------------------------ +Concurrency Constraints for flash on SPI1 +----------------------------------------- -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 SPI1 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. +There are no such constraints and impacts for flash chips on other SPI buses than SPI0/1. -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. +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 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 +118,120 @@ 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``. + +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 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). + +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 low-level 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 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) +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 periodically. + + +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..a9a2c69135 --- /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 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. + +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/cache_utils.c b/components/spi_flash/cache_utils.c index 8b0adf870f..d206bbd7ce 100644 --- a/components/spi_flash/cache_utils.c +++ b/components/spi_flash/cache_utils.c @@ -51,18 +51,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); } @@ -96,7 +96,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(); @@ -147,7 +147,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; @@ -184,7 +184,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; @@ -197,7 +197,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(); @@ -209,36 +209,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(); @@ -246,7 +246,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]); @@ -322,7 +322,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) { #if CONFIG_IDF_TARGET_ESP32 bool result = (DPORT_REG_GET_BIT(DPORT_PRO_CACHE_CTRL_REG, DPORT_PRO_CACHE_ENABLE) != 0); diff --git a/components/spi_flash/cache_utils.h b/components/spi_flash/cache_utils.h index a04b04959d..e57494c5af 100644 --- a/components/spi_flash/cache_utils.h +++ b/components/spi_flash/cache_utils.h @@ -25,30 +25,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/component.mk b/components/spi_flash/component.mk index b575ceabb4..74bcce42c8 100644 --- a/components/spi_flash/component.mk +++ b/components/spi_flash/component.mk @@ -1,6 +1,8 @@ COMPONENT_ADD_INCLUDEDIRS := include + COMPONENT_SRCDIRS := . $(IDF_TARGET) -COMPONENT_PRIV_INCLUDEDIRS := . +COMPONENT_PRIV_INCLUDEDIRS := private_include + COMPONENT_ADD_LDFRAGMENTS += linker.lf ifdef IS_BOOTLOADER_BUILD diff --git a/components/spi_flash/esp32/flash_ops_esp32.c b/components/spi_flash/esp32/flash_ops_esp32.c index 4a33eaa38b..77c90c95c0 100644 --- a/components/spi_flash/esp32/flash_ops_esp32.c +++ b/components/spi_flash/esp32/flash_ops_esp32.c @@ -12,13 +12,11 @@ // 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" -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) { @@ -26,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) { @@ -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/esp32s2beta/flash_ops_esp32s2beta.c b/components/spi_flash/esp32s2beta/flash_ops_esp32s2beta.c index bc02514a82..6241f399d2 100644 --- a/components/spi_flash/esp32s2beta/flash_ops_esp32s2beta.c +++ b/components/spi_flash/esp32s2beta/flash_ops_esp32s2beta.c @@ -63,3 +63,74 @@ esp_rom_spiflash_result_t IRAM_ATTR spi_flash_write_encrypted_chip(size_t dest_a return rc; } } + +#define SPICACHE SPIMEM0 +#define SPIFLASH SPIMEM1 +#define FLASH_WRAP_CMD 0x77 +esp_err_t spi_flash_wrap_set(spi_flash_wrap_mode_t mode) +{ + uint32_t reg_bkp_ctrl = SPIFLASH.ctrl.val; + uint32_t reg_bkp_usr = SPIFLASH.user.val; + SPIFLASH.user.fwrite_dio = 0; + SPIFLASH.user.fwrite_dual = 0; + SPIFLASH.user.fwrite_qio = 1; + SPIFLASH.user.fwrite_quad = 0; + SPIFLASH.ctrl.fcmd_dual = 0; + SPIFLASH.ctrl.fcmd_quad = 0; + SPIFLASH.user.usr_dummy = 0; + SPIFLASH.user.usr_addr = 1; + SPIFLASH.user.usr_command = 1; + SPIFLASH.user2.usr_command_bitlen = 7; + SPIFLASH.user2.usr_command_value = FLASH_WRAP_CMD; + SPIFLASH.user1.usr_addr_bitlen = 23; + SPIFLASH.addr = 0; + SPIFLASH.user.usr_miso = 0; + SPIFLASH.user.usr_mosi = 1; + SPIFLASH.mosi_dlen.usr_mosi_bit_len = 7; + SPIFLASH.data_buf[0] = (uint32_t) mode << 4;; + SPIFLASH.cmd.usr = 1; + while(SPIFLASH.cmd.usr != 0) + { } + + SPIFLASH.ctrl.val = reg_bkp_ctrl; + SPIFLASH.user.val = reg_bkp_usr; + return ESP_OK; +} + +esp_err_t spi_flash_enable_wrap(uint32_t wrap_size) +{ + switch(wrap_size) { + case 8: + return spi_flash_wrap_set(FLASH_WRAP_MODE_8B); + case 16: + return spi_flash_wrap_set(FLASH_WRAP_MODE_16B); + case 32: + return spi_flash_wrap_set(FLASH_WRAP_MODE_32B); + case 64: + return spi_flash_wrap_set(FLASH_WRAP_MODE_64B); + default: + return ESP_FAIL; + } +} + +void spi_flash_disable_wrap() +{ + spi_flash_wrap_set(FLASH_WRAP_MODE_DISABLE); +} + +bool spi_flash_support_wrap_size(uint32_t wrap_size) +{ + if (!REG_GET_BIT(SPI_MEM_CTRL_REG(0), SPI_MEM_FREAD_QIO) || !REG_GET_BIT(SPI_MEM_CTRL_REG(0), SPI_MEM_FASTRD_MODE)){ + return ESP_FAIL; + } + switch(wrap_size) { + case 0: + case 8: + case 16: + case 32: + case 64: + return true; + default: + return false; + } +} diff --git a/components/spi_flash/esp_flash_api.c b/components/spi_flash/esp_flash_api.c new file mode 100644 index 0000000000..0e16fc80d2 --- /dev/null +++ b/components/spi_flash/esp_flash_api.c @@ -0,0 +1,655 @@ +// 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 "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_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 *out_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 (out_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, out_id); + + return spiflash_end(chip, err); +} + +esp_err_t IRAM_ATTR esp_flash_get_size(esp_flash_t *chip, uint32_t *out_size) +{ + VERIFY_OP(detect_size); + if (out_size == NULL) { + return ESP_ERR_INVALID_ARG; + } + if (chip->size != 0) { + *out_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); + + esp_err_t err = spiflash_start(chip); + if (err != ESP_OK) { + return err; + } + + 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; + + 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 protected regions overlapping the erase region + 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) { + 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 *out_write_protected) +{ + VERIFY_OP(get_chip_write_protect); + if (out_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, out_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) +{ + 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); + + return spiflash_end(chip, err); +} + +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(out_num_regions != NULL) { + *out_num_regions = 0; // In case caller doesn't check result + } + VERIFY_OP(get_protected_regions); + + if(out_regions == NULL || out_num_regions == NULL) { + return ESP_ERR_INVALID_ARG; + } + + *out_num_regions = chip->chip_drv->num_protectable_regions; + *out_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 *out_protected) +{ + VERIFY_OP(get_protected_regions); + + if (out_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) { + *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 protect) +{ + 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 (protect) { + 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); +} + + +/*------------------------------------------------------------------------------ + 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) { + 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; +} + +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); +} + +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(void) +{ + esp_err_t err = esp_flash_set_chip_write_protect(NULL, false); + return spi_flash_translate_rc(err); +} + +#endif // CONFIG_SPI_FLASH_USE_LEGACY_IMPL diff --git a/components/spi_flash/esp_flash_spi_init.c b/components/spi_flash/esp_flash_spi_init.c new file mode 100644 index 0000000000..c554f4a292 --- /dev/null +++ b/components/spi_flash/esp_flash_spi_init.c @@ -0,0 +1,206 @@ +// 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 "sdkconfig.h" +#include "esp_flash.h" +#include "memspi_host_driver.h" +#include "esp_flash_spi_init.h" +#include "driver/gpio.h" +#include "esp32/rom/spi_flash.h" +#include "esp_log.h" +#include "esp_heap_caps.h" +#include "hal/spi_types.h" +#include "driver/spi_common.h" + +static const char TAG[] = "spi_flash"; + +#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 the ``CONFIG_ESPTOOLPY_FLASHFREQ_*`` options. +#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 + +static IRAM_ATTR void cs_initialize(esp_flash_t *chip, const esp_flash_spi_device_config_t *config, bool use_iomux) +{ + //Not using spicommon_cs_initialize since we don't want to put the whole + //spi_periph_signal into the DRAM. Copy these data from flash before the + //cache disabling + int cs_io_num = config->cs_io_num; + int spics_in = spi_periph_signal[config->host_id].spics_in; + int spics_out = spi_periph_signal[config->host_id].spics_out[config->cs_id]; + uint32_t iomux_reg = GPIO_PIN_MUX_REG[cs_io_num]; + + //To avoid the panic caused by flash data line conflicts during cs line + //initialization, disable the cache temporarily + chip->os_func->start(chip->os_func_data); + 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, 1); + } 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 (config->cs_id == 0) { + gpio_matrix_in(cs_io_num, spics_in, false); + } + PIN_FUNC_SELECT(iomux_reg, PIN_FUNC_GPIO); + } + chip->os_func->end(chip->os_func_data); +} + +esp_err_t spi_bus_add_flash_device(esp_flash_t **out_chip, const esp_flash_spi_device_config_t *config) +{ + if (out_chip == NULL) { + return ESP_ERR_INVALID_ARG; + } + esp_flash_t *chip = NULL; + spi_flash_host_driver_t *host = NULL; + memspi_host_data_t *host_data = NULL; + esp_err_t ret = ESP_OK; + + uint32_t caps = MALLOC_CAP_DEFAULT; + if (config->host_id == SPI_HOST) caps = MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT; + + chip = (esp_flash_t*)heap_caps_malloc(sizeof(esp_flash_t), caps); + host = (spi_flash_host_driver_t*)heap_caps_malloc(sizeof(spi_flash_host_driver_t), caps); + host_data = (memspi_host_data_t*)heap_caps_malloc(sizeof(memspi_host_data_t), caps); + if (!chip || !host || !host_data) { + ret = ESP_ERR_NO_MEM; + goto fail; + } + + *chip = (esp_flash_t) { + .read_mode = config->io_mode, + .host = host, + }; + esp_err_t err = esp_flash_init_os_functions(chip, config->host_id); + if (err != ESP_OK) { + ret = err; + goto fail; + } + + bool use_iomux = spicommon_bus_using_iomux(config->host_id); + memspi_host_config_t host_cfg = { + .host_id = config->host_id, + .cs_num = config->cs_id, + .iomux = use_iomux, + .input_delay_ns = config->input_delay_ns, + .speed = config->speed, + }; + err = memspi_host_init_pointers(host, host_data, &host_cfg); + if (err != ESP_OK) { + ret = err; + goto fail; + } + + cs_initialize(chip, config, use_iomux); + *out_chip = chip; + return ret; +fail: + spi_bus_remove_flash_device(chip); + return ret; +} + +esp_err_t spi_bus_remove_flash_device(esp_flash_t *chip) +{ + if (chip==NULL) { + return ESP_ERR_INVALID_ARG; + } + if (chip->host) { + free(chip->host->driver_data); + free(chip->host); + } + free(chip); + return ESP_OK; +} + +#define ESP_FLASH_HOST_CONFIG_DEFAULT() (memspi_host_config_t){ \ + .host_id = SPI_HOST,\ + .speed = DEFAULT_FLASH_SPEED, \ + .cs_num = 0, \ + .iomux = false, \ + .input_delay_ns = 0,\ +} + +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 = NULL; + +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 + 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(%dk) larger than the size in the binary image header(%dk). Using the size in the binary image header.", default_chip.size/1024, g_rom_flashchip.chip_size/1024); + 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; +} + +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 b5502ec0ef..011dab9ef8 100644 --- a/components/spi_flash/flash_mmap.c +++ b/components/spi_flash/flash_mmap.c @@ -84,7 +84,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 */ @@ -322,7 +322,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(); @@ -338,7 +338,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 dfb51e7f4b..99b2db2371 100644 --- a/components/spi_flash/flash_ops.c +++ b/components/spi_flash/flash_ops.c @@ -30,7 +30,6 @@ #include "esp_ipc.h" #include "esp_attr.h" #include "esp_spi_flash.h" -#include "esp_spi_flash_chip.h" #include "esp_log.h" #if CONFIG_IDF_TARGET_ESP32 #include "esp32/clk.h" @@ -39,9 +38,8 @@ #include "soc/spi_mem_reg.h" #endif #include "esp_flash_partitions.h" -#include "esp_ota_ops.h" #include "cache_utils.h" -#include "soc/spi_periph.h" +#include "esp_flash.h" /* bytes erased by SPIEraseBlock() ROM function */ #define BLOCK_ERASE_SIZE 65536 @@ -84,7 +82,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 }; @@ -94,14 +92,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 @@ -111,7 +109,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 { \ @@ -119,28 +117,18 @@ 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) { - 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; } -void spi_flash_init() +void spi_flash_init(void) { spi_flash_init_lock(); #if CONFIG_SPI_FLASH_ENABLE_COUNTERS @@ -153,45 +141,46 @@ 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(); } } -esp_rom_spiflash_result_t IRAM_ATTR spi_flash_unlock() +#ifdef CONFIG_SPI_FLASH_USE_LEGACY_IMPL +static esp_rom_spiflash_result_t IRAM_ATTR spi_flash_unlock(void) { static bool unlocked = false; if (!unlocked) { @@ -205,6 +194,16 @@ 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(void) +{ + 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) { @@ -212,7 +211,9 @@ 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); } -esp_err_t IRAM_ATTR spi_flash_erase_range(uint32_t start_addr, uint32_t size) +#ifdef CONFIG_SPI_FLASH_USE_LEGACY_IMPL +//deprecated, only used in compatible mode +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) { @@ -423,10 +424,12 @@ 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) { CHECK_WRITE_ADDRESS(dest_addr, size); + const uint8_t *ssrc = (const uint8_t *)src; if ((dest_addr % 16) != 0) { return ESP_ERR_INVALID_ARG; } @@ -436,7 +439,49 @@ esp_err_t IRAM_ATTR spi_flash_write_encrypted(size_t dest_addr, const void *src, COUNTER_START(); esp_rom_spiflash_result_t rc; - rc = spi_flash_write_encrypted_chip(dest_addr, src, size); + rc = spi_flash_unlock(); + if (rc == ESP_ROM_SPIFLASH_RESULT_OK) { + /* esp_rom_spiflash_write_encrypted encrypts data in RAM as it writes, + so copy to a temporary buffer - 32 bytes at a time. + + Each call to esp_rom_spiflash_write_encrypted takes a 32 byte "row" of + data to encrypt, and each row is two 16 byte AES blocks + that share a key (as derived from flash address). + */ + uint8_t encrypt_buf[32] __attribute__((aligned(4))); + uint32_t row_size; + for (size_t i = 0; i < size; i += row_size) { + uint32_t row_addr = dest_addr + i; + if (i == 0 && (row_addr % 32) != 0) { + /* writing to second block of a 32 byte row */ + row_size = 16; + row_addr -= 16; + /* copy to second block in buffer */ + memcpy(encrypt_buf + 16, ssrc + i, 16); + /* decrypt the first block from flash, will reencrypt to same bytes */ + spi_flash_read_encrypted(row_addr, encrypt_buf, 16); + } else if (size - i == 16) { + /* 16 bytes left, is first block of a 32 byte row */ + row_size = 16; + /* copy to first block in buffer */ + memcpy(encrypt_buf, ssrc + i, 16); + /* decrypt the second block from flash, will reencrypt to same bytes */ + spi_flash_read_encrypted(row_addr + 16, encrypt_buf + 16, 16); + } else { + /* Writing a full 32 byte row (2 blocks) */ + row_size = 32; + memcpy(encrypt_buf, ssrc + i, 32); + } + + spi_flash_guard_start(); + rc = esp_rom_spiflash_write_encrypted(row_addr, (uint32_t *)encrypt_buf, 32); + spi_flash_guard_end(); + if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { + break; + } + } + bzero(encrypt_buf, sizeof(encrypt_buf)); + } COUNTER_ADD_BYTES(write, size); COUNTER_STOP(write); @@ -447,6 +492,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 @@ -588,6 +634,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) { @@ -635,17 +682,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"); @@ -654,75 +701,7 @@ void spi_flash_dump_counters() #endif //CONFIG_SPI_FLASH_ENABLE_COUNTERS -#if CONFIG_IDF_TARGET_ESP32S2BETA -#define SPICACHE SPIMEM0 -#define SPIFLASH SPIMEM1 -#define FLASH_WRAP_CMD 0x77 -esp_err_t spi_flash_wrap_set(spi_flash_wrap_mode_t mode) -{ - uint32_t reg_bkp_ctrl = SPIFLASH.ctrl.val; - uint32_t reg_bkp_usr = SPIFLASH.user.val; - SPIFLASH.user.fwrite_dio = 0; - SPIFLASH.user.fwrite_dual = 0; - SPIFLASH.user.fwrite_qio = 1; - SPIFLASH.user.fwrite_quad = 0; - SPIFLASH.ctrl.fcmd_dual = 0; - SPIFLASH.ctrl.fcmd_quad = 0; - SPIFLASH.user.usr_dummy = 0; - SPIFLASH.user.usr_addr = 1; - SPIFLASH.user.usr_command = 1; - SPIFLASH.user2.usr_command_bitlen = 7; - SPIFLASH.user2.usr_command_value = FLASH_WRAP_CMD; - SPIFLASH.user1.usr_addr_bitlen = 23; - SPIFLASH.addr = 0; - SPIFLASH.user.usr_miso = 0; - SPIFLASH.user.usr_mosi = 1; - SPIFLASH.mosi_dlen.usr_mosi_bit_len = 7; - SPIFLASH.data_buf[0] = (uint32_t) mode << 4;; - SPIFLASH.cmd.usr = 1; - while(SPIFLASH.cmd.usr != 0) - { } - - SPIFLASH.ctrl.val = reg_bkp_ctrl; - SPIFLASH.user.val = reg_bkp_usr; - return ESP_OK; -} - -esp_err_t spi_flash_enable_wrap(uint32_t wrap_size) -{ - switch(wrap_size) { - case 8: - return spi_flash_wrap_set(FLASH_WRAP_MODE_8B); - case 16: - return spi_flash_wrap_set(FLASH_WRAP_MODE_16B); - case 32: - return spi_flash_wrap_set(FLASH_WRAP_MODE_32B); - case 64: - return spi_flash_wrap_set(FLASH_WRAP_MODE_64B); - default: - return ESP_FAIL; - } -} - -void spi_flash_disable_wrap() -{ - spi_flash_wrap_set(FLASH_WRAP_MODE_DISABLE); -} - -bool spi_flash_support_wrap_size(uint32_t wrap_size) -{ - if (!REG_GET_BIT(SPI_MEM_CTRL_REG(0), SPI_MEM_FREAD_QIO) || !REG_GET_BIT(SPI_MEM_CTRL_REG(0), SPI_MEM_FASTRD_MODE)){ - return ESP_FAIL; - } - switch(wrap_size) { - case 0: - case 8: - case 16: - case 32: - case 64: - return true; - default: - return false; - } -} +#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 diff --git a/components/spi_flash/include/esp_flash.h b/components/spi_flash/include/esp_flash.h new file mode 100644 index 0000000000..4a7c184de4 --- /dev/null +++ b/components/spi_flash/include/esp_flash.h @@ -0,0 +1,298 @@ +// 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 "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; + +typedef struct esp_flash_t esp_flash_t; + +/** @brief Structure for describing a region of flash */ +typedef struct { + 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 */ +typedef struct { + /** + * 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 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. + + 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 ``esp_flash_init`` is called. + uint32_t size; ///< Size of SPI flash in bytes. If 0, size will be detected during initialisation. +}; + + +/** @brief Initialise SPI flash chip interface. + * + * This function must be called before any other API functions are called for this chip. + * + * @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 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. + */ +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. + * + * @param chip Pointer to identify flash chip. Must have been successfully initialised via esp_flash_init() + * @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 *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] 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 *out_size); + +/** @brief Erase flash chip contents + * + * @param chip Pointer to identify flash chip. Must have been successfully initialised via esp_flash_init() + * + * + * @return ESP_OK on success, or a flash error code if operation failed. + */ +esp_err_t esp_flash_erase_chip(esp_flash_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.) 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 ESP_OK on success, or a flash error code if operation failed. + */ +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 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_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_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). + * + * 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 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); + + +/** @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[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 **out_regions, uint32_t *out_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] 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 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_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 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. + * + * @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_set_protected_region(esp_flash_t *chip, const esp_flash_region_t *region, bool protect); + +/** @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. 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. + * + * 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 + * - 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_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. 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 ESP_OK on success, or a flash error code if operation failed. + */ +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 + * + * @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 ESP_OK on success, or a flash error code if operation failed. + */ +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 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_err_t esp_flash_init_default_chip(void); + +/** + * 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(void); + +/** + * 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, 1 for SPI1, 2 for SPI2 (HSPI), 3 for SPI3 (VSPI) + * + * @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); + + +#ifdef __cplusplus +} +#endif diff --git a/components/spi_flash/include/esp_flash_spi_init.h b/components/spi_flash/include/esp_flash_spi_init.h new file mode 100644 index 0000000000..4a26a4fd1b --- /dev/null +++ b/components/spi_flash/include/esp_flash_spi_init.h @@ -0,0 +1,55 @@ +// 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_types.h" +#include "esp_flash.h" + +/// Configurations for the SPI Flash to init +typedef struct { + spi_host_device_t host_id; ///< Bus to use + int cs_id; ///< CS pin (signal) to use + int cs_io_num; ///< GPIO pin to output the CS signal + esp_flash_read_mode_t io_mode; ///< IO mode to read from the Flash + esp_flash_speed_t speed; ///< Speed of the Flash clock + int input_delay_ns; ///< Input delay of the data pins, in ns. Set to 0 if unknown. +} esp_flash_spi_device_config_t; + +/** + * Add a SPI Flash device onto the SPI bus. + * + * The bus should be already initialized by ``spi_bus_initialization``. + * + * @param out_chip Pointer to hold the initialized chip. + * @param config Configuration of the chips to initialize. + * + * @return + * - ESP_ERR_INVALID_ARG: out_chip is NULL, or some field in the config is invalid. + * - ESP_ERR_NO_MEM: failed to allocate memory for the chip structures. + * - ESP_OK: success. + */ +esp_err_t spi_bus_add_flash_device(esp_flash_t **out_chip, const esp_flash_spi_device_config_t *config); + +/** + * Remove a SPI Flash device from the SPI bus. + * + * @param chip The flash device to remove. + * + * @return + * - ESP_ERR_INVALID_ARG: The chip is invalid. + * - ESP_OK: success. + */ +esp_err_t spi_bus_remove_flash_device(esp_flash_t *chip); + diff --git a/components/spi_flash/include/esp_partition.h b/components/spi_flash/include/esp_partition.h index 6537967eb7..42ac6777c9 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 */ @@ -246,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. * @@ -257,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 offset, size_t size); /** * @brief Configure MMU to map partition into data memory @@ -284,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); @@ -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/include/esp_spi_flash.h b/components/spi_flash/include/esp_spi_flash.h index 55dcb19d39..63b18b2756 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) @@ -60,7 +59,7 @@ esp_err_t spi_flash_wrap_set(spi_flash_wrap_mode_t mode); * 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 @@ -69,7 +68,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. @@ -257,7 +256,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 @@ -312,7 +311,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. @@ -354,7 +353,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.). * @@ -372,7 +371,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; @@ -393,7 +392,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 @@ -428,12 +427,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 @@ -441,7 +440,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/include/memspi_host_driver.h b/components/spi_flash/include/memspi_host_driver.h new file mode 100644 index 0000000000..434361d970 --- /dev/null +++ b/components/spi_flash/include/memspi_host_driver.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 +#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 + ******************************************************************************/ + +/** + * @brief Read the Status Register read from RDSR (05h). + * + * 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_chip_driver.h b/components/spi_flash/include/spi_flash_chip_driver.h new file mode 100644 index 0000000000..9dd8ffa971 --- /dev/null +++ b/components/spi_flash/include/spi_flash_chip_driver.h @@ -0,0 +1,162 @@ +// 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_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 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. 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 chip driver functions directly in other contexts. + * + * 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. + */ +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. + * + * 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 ESP_OK if probing was successful, an error otherwise. Driver may + * assume that returning ESP_OK means it has claimed this chip. + */ + esp_err_t (*probe)(esp_flash_t *chip, uint32_t flash_id); + + esp_err_t (*reset)(esp_flash_t *chip); + + + /* Detect SPI flash size + * + * Interrogate the chip to detect its 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_err_t (*erase_chip)(esp_flash_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_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_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_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 chip_write_protect); + + /* 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_err_t (*read)(esp_flash_t *chip, void *buffer, uint32_t address, uint32_t length); + + /* Write any amount of data to the chip. + */ + 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. + * + * 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_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_err_t (*write_encrypted)(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length); + + + /* 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 ESP_ERR_TIMEOUT. This is useful to avoid hanging + if the chip is otherwise unresponsive (ie returns all 0xFF or similar.) + */ + 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 ESP_ERR_FLASH_UNSUPPORTED_HOST or ESP_ERR_FLASH_UNSUPPORTED_CHIP if the specified mode is unsupported. + */ + 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. + + 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 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..672ca6550b --- /dev/null +++ b/components/spi_flash/include/spi_flash_chip_generic.h @@ -0,0 +1,294 @@ +// 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 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 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 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 + * + * @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 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 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. + * @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_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. + * + * @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 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. If required, + * set and check the QE bit in the flash chip to enable the QIO/QOUT mode. + * + * 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. + * + * 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 + * @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 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. + * + * @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/linker.lf b/components/spi_flash/linker.lf index fbbb64ea74..e5d886ca4b 100644 --- a/components/spi_flash/linker.lf +++ b/components/spi_flash/linker.lf @@ -1,5 +1,8 @@ [mapping:spi_flash] archive: libspi_flash.a -entries: +entries: spi_flash_rom_patch (noflash_text) + 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..14de32c9f5 100644 --- a/components/spi_flash/partition.c +++ b/components/spi_flash/partition.c @@ -19,11 +19,14 @@ #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 */ @@ -34,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; @@ -49,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 = @@ -141,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; @@ -162,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 */ @@ -192,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) @@ -207,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); @@ -217,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); @@ -241,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; @@ -275,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; @@ -286,23 +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; } - return spi_flash_erase_range(partition->address + start_addr, size); - +#ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL + return esp_flash_erase_region(partition->flash_chip, partition->address + offset, size); +#else + return spi_flash_erase_range(partition->address + offset, size); +#endif // CONFIG_SPI_FLASH_USE_LEGACY_IMPL } /* @@ -313,7 +417,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) { @@ -324,6 +428,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; @@ -355,3 +462,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/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/sim/flash_mock.cpp b/components/spi_flash/sim/flash_mock.cpp index 9535bf29b1..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(); } @@ -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/sim/flash_mock_util.c b/components/spi_flash/sim/flash_mock_util.c index a22b2854cc..2db51c58ae 100644 --- a/components/spi_flash/sim/flash_mock_util.c +++ b/components/spi_flash/sim/flash_mock_util.c @@ -4,54 +4,47 @@ #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; } -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/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/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_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..8bbb9d1374 --- /dev/null +++ b/components/spi_flash/spi_flash_chip_generic.c @@ -0,0 +1,413 @@ +// 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_chip_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_chip_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_chip_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_chip_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_set_write_protect(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); + } + + 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; + } + + *out_write_protect = ((status & SR_WREN) == 0); + 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_chip_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_chip_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 = 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. + .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, + + .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 new file mode 100644 index 0000000000..71684ec195 --- /dev/null +++ b/components/spi_flash/spi_flash_chip_issi.c @@ -0,0 +1,77 @@ +// 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_generic.h" +#include "spi_flash_defs.h" + +/* Driver for ISSI flash chip, as used in ESP32 D2WD */ + +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 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 ESP_ERR_NOT_FOUND; + } + + return ESP_OK; +} + +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; + return spi_flash_common_set_read_mode(chip, CMD_RDSR, CMD_WRSR, 8, BIT_QE); +} + +static const char chip_name[] = "issi"; + +// 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, + + .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, + .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, + + .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_os_func_app.c b/components/spi_flash/spi_flash_os_func_app.c new file mode 100644 index 0000000000..7328250eba --- /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 "esp_attr.h" +#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. + * + * 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 esp_flash_spi1_default_os_functions = { + .start = spi1_start, + .end = spi1_end, + .delay_ms = delay_ms, +}; + +const esp_flash_os_functions_t esp_flash_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 = &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 = &esp_flash_spi23_default_os_functions; + chip->os_func_data = (host_id == 1) ? &spi2_arg : &spi3_arg; + } else { + return ESP_ERR_INVALID_ARG; + } + return ESP_OK; +} + + diff --git a/components/spi_flash/spi_flash_os_func_noos.c b/components/spi_flash/spi_flash_os_func_noos.c new file mode 100644 index 0000000000..0e4cc34a83 --- /dev/null +++ b/components/spi_flash/spi_flash_os_func_noos.c @@ -0,0 +1,53 @@ +// 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 "sdkconfig.h" +#include "esp_flash.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) +{ + Cache_Read_Disable(0); + Cache_Read_Disable(1); + return ESP_OK; +} +static esp_err_t end(void *arg) +{ + Cache_Flush(0); + Cache_Flush(1); + Cache_Read_Enable(0); + Cache_Read_Enable(1); + return ESP_OK; +} + +static esp_err_t delay_ms(void *arg, unsigned ms) +{ + ets_delay_us(1000 * ms); + return ESP_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/spi_flash_rom_patch.c b/components/spi_flash/spi_flash_rom_patch.c index 295ef44f3b..efbe883ea0 100644 --- a/components/spi_flash/spi_flash_rom_patch.c +++ b/components/spi_flash/spi_flash_rom_patch.c @@ -64,7 +64,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; @@ -383,6 +383,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)) { @@ -443,7 +444,7 @@ static void spi_cache_mode_switch(uint32_t modebit) #endif } -esp_rom_spiflash_result_t esp_rom_spiflash_lock() +esp_rom_spiflash_result_t esp_rom_spiflash_lock(void) { uint32_t status; @@ -518,7 +519,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/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/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..19a93c8bf4 --- /dev/null +++ b/components/spi_flash/test/test_esp_flash.c @@ -0,0 +1,524 @@ +#include +#include +#include +#include +#include + +#include +#include "esp_flash.h" +#include "driver/spi_common.h" +#include "esp_flash_spi_init.h" +#include +#include "esp_log.h" + +#include + +#include "unity.h" +#include "driver/spi_common.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 + +#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 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 + +#if 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 0 +# define EXTRA_SPI1_CLK_IO 17 //the pin which is usually used by the PSRAM clk + +#elif defined TEST_SPI2_CS0 + +# define TEST_HOST HSPI_HOST +# define TEST_CS 0 +# define TEST_CS_PIN HSPI_IOMUX_PIN_NUM_CS +# 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 TEST_INPUT_DELAY 0 + +#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 void setup_bus(spi_host_device_t host_id) +{ + if (host_id == SPI_HOST) { + ESP_LOGI(TAG, "setup flash on SPI1 CS1...\n"); + //no need to initialize the bus, however the CLK may need one more output if it's on the usual place of PSRAM +#ifdef EXTRA_SPI1_CLK_IO + gpio_matrix_out(EXTRA_SPI1_CLK_IO, SPICLK_OUT_IDX, 0, 0); +#endif + //currently the SPI bus for main flash chip is initialized through GPIO matrix + } else if (host_id == HSPI_HOST) { + ESP_LOGI(TAG, "setup flash on SPI2 (HSPI) CS0...\n"); + 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 + esp_err_t ret = spi_bus_initialize(host_id, &hspi_bus_cfg, 0); + TEST_ESP_OK(ret); + } else if (host_id == VSPI_HOST) { + ESP_LOGI(TAG, "setup flash on SPI3 (VSPI) CS0...\n"); + 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 + esp_err_t ret = spi_bus_initialize(host_id, &vspi_bus_cfg, 0); + TEST_ESP_OK(ret); + } else { + ESP_LOGE(TAG, "invalid bus"); + } +} + +static void release_bus(int host_id) +{ + if (host_id == HSPI_HOST || host_id == VSPI_HOST) { + spi_bus_free(host_id); + } +} + +static void setup_new_chip(esp_flash_read_mode_t io_mode, esp_flash_speed_t speed) +{ + //the bus should be initialized before the flash is attached to the bus + setup_bus(TEST_HOST); + + esp_flash_spi_device_config_t dev_cfg = { + .host_id = TEST_HOST, + .io_mode = io_mode, + .speed = speed, + .cs_id = TEST_CS, + .cs_io_num = TEST_CS_PIN, + .input_delay_ns = TEST_INPUT_DELAY, + }; + esp_err_t err = spi_bus_add_flash_device(&test_chip, &dev_cfg); + TEST_ESP_OK(err); + err = esp_flash_init(test_chip); + TEST_ESP_OK(err); +} + +void teardown_test_chip(void) +{ + spi_bus_remove_flash_device(test_chip); + test_chip = NULL; + release_bus(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 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, + 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); +} \ No newline at end of file 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_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_mmap.c b/components/spi_flash/test/test_mmap.c index 4cdb775943..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(); @@ -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 3c9b017476..bc4a5d5745 100644 --- a/components/spi_flash/test/test_out_of_bounds_write.c +++ b/components/spi_flash/test/test_out_of_bounds_write.c @@ -4,14 +4,14 @@ #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 -#define TEST_TAGS "[spi_flash]" +#if CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS +#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_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)); +} 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 3311cb813f..09ed0073af 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(); @@ -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 bd135a0c7f..a9ba4e3107 100644 --- a/components/spi_flash/test/test_spi_flash.c +++ b/components/spi_flash/test/test_spi_flash.c @@ -112,8 +112,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++; } @@ -128,7 +128,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 = { @@ -174,7 +174,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/CMakeLists.txt b/components/spiffs/CMakeLists.txt index 034d1b721d..1aea86c73c 100644 --- a/components/spiffs/CMakeLists.txt +++ b/components/spiffs/CMakeLists.txt @@ -1,14 +1,11 @@ -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/Makefile.projbuild b/components/spiffs/Makefile.projbuild index 2fab90b172..4d8f39c081 100644 --- a/components/spiffs/Makefile.projbuild +++ b/components/spiffs/Makefile.projbuild @@ -19,11 +19,10 @@ endif # have the created image flashed using `make flash` define spiffs_create_partition_image - -$(1)_bin: $(PARTITION_TABLE_BIN) | check_python_dependencies - partition_size=`$(GET_PART_INFO) --partition-name $(1) \ +$(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 --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) \ @@ -35,11 +34,13 @@ 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), \ -$(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/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 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/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/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/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/spiffs/test_spiffs_host/sdkconfig/sdkconfig.h b/components/spiffs/test_spiffs_host/sdkconfig/sdkconfig.h index c0987d641d..1afb29924f 100644 --- a/components/spiffs/test_spiffs_host/sdkconfig/sdkconfig.h +++ b/components/spiffs/test_spiffs_host/sdkconfig/sdkconfig.h @@ -17,3 +17,6 @@ #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 1 + 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/tcp_transport/CMakeLists.txt b/components/tcp_transport/CMakeLists.txt index 9c2ef846b8..db4afb8752 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" + INCLUDE_DIRS "include" + PRIV_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 e163a010cd..39e694f058 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); @@ -33,12 +33,14 @@ 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 * * @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, @@ -91,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 @@ -298,6 +300,21 @@ 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 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 + * - valid pointer of esp_error_handle_t + * - NULL if invalid transport handle + */ +esp_tls_error_handle_t esp_transport_get_error_handle(esp_transport_handle_t t); + + + #ifdef __cplusplus } #endif diff --git a/components/tcp_transport/include/esp_transport_ssl.h b/components/tcp_transport/include/esp_transport_ssl.h index c42fd09353..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" { @@ -27,7 +28,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). @@ -40,6 +41,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 +70,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 +92,40 @@ 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 + * + * @note Skipping CN validation is not recommended + * + * @param t ssl transport + */ +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/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/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/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/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)); +} diff --git a/components/tcp_transport/transport.c b/components/tcp_transport/transport.c index 44756e1d4b..d5bc57bb48 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" @@ -41,7 +42,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_tls_error_handle_t error_handle; /*!< Pointer to esp-tls error handle */ STAILQ_ENTRY(esp_transport_item_t) next; }; @@ -52,6 +54,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_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) { /* @@ -60,36 +70,39 @@ 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 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_tls_last_error_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,30 +110,28 @@ 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); - if (item->_destroy) { - item->_destroy(item); - } esp_transport_destroy(item); item = tmp; } - STAILQ_INIT(list); + STAILQ_INIT(&h->list); 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); @@ -137,6 +148,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); } @@ -277,3 +291,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_tls_error_handle_t esp_transport_get_error_handle(esp_transport_handle_t t) +{ + 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 1ea4049878..d5b13490ac 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"; @@ -51,7 +52,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 +70,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_sync(host, strlen(host), port, &ssl->cfg, ssl->tls) < 0) { ESP_LOGE(TAG, "Failed to open a new connection"); + esp_transport_set_errors(t, ssl->tls->error_handle); + esp_tls_conn_delete(ssl->tls); + ssl->tls = NULL; return -1; } return 0; @@ -112,6 +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_errors(t, ssl->tls->error_handle); } return ret; } @@ -129,6 +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_errors(t, ssl->tls->error_handle); } if (ret == 0) { ret = -1; @@ -163,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); @@ -172,6 +186,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_buf = (void *)data; + ssl->cfg.cacert_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); @@ -181,6 +204,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_buf = (void *)data; + ssl->cfg.clientcert_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); @@ -190,7 +222,24 @@ void esp_transport_ssl_set_client_key_data(esp_transport_handle_t t, const char } } -esp_transport_handle_t esp_transport_ssl_init() +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_buf = (void *)data; + ssl->cfg.clientkey_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); + if (t && ssl) { + ssl->cfg.skip_common_name = true; + } +} + +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_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_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/tcp_transport/transport_ws.c b/components/tcp_transport/transport_ws.c index e31149e178..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" @@ -25,12 +24,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; @@ -63,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"); @@ -80,7 +80,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 +98,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,40 +155,78 @@ 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; } - return esp_transport_write(ws->parent, buffer, len, timeout_ms); + if (len == 0) { + return 0; + } + + 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) +{ + 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) @@ -279,6 +320,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 +330,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(); @@ -296,7 +339,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); @@ -312,3 +358,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/components/tcpip_adapter/CMakeLists.txt b/components/tcpip_adapter/CMakeLists.txt index b728811ef2..a63bcdddeb 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 esp_eth) diff --git a/components/tcpip_adapter/event_handlers.c b/components/tcpip_adapter/event_handlers.c index c4f2fc7c1e..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); @@ -54,10 +54,10 @@ static void handle_eth_start(void *arg, esp_event_base_t base, int32_t event_id, { tcpip_adapter_ip_info_t eth_ip; uint8_t eth_mac[6]; - - esp_eth_get_mac(eth_mac); + esp_eth_handle_t eth_handle = *(esp_eth_handle_t*)data; + esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, eth_mac); tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_ETH, ð_ip); - tcpip_adapter_eth_start(eth_mac, ð_ip); + tcpip_adapter_eth_start(eth_mac, ð_ip, eth_handle); } static void handle_eth_stop(void *arg, esp_event_base_t base, int32_t event_id, void *data) @@ -202,7 +202,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); @@ -252,7 +252,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); @@ -265,8 +265,9 @@ esp_err_t tcpip_adapter_clear_default_wifi_handlers() return ESP_OK; } -#if CONFIG_IDF_TARGET_ESP32 -esp_err_t tcpip_adapter_set_default_eth_handlers() + +#if CONFIG_ETH_ENABLED +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); @@ -301,7 +302,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 033dfd0e76..f880511f71 100644 --- a/components/tcpip_adapter/include/tcpip_adapter.h +++ b/components/tcpip_adapter/include/tcpip_adapter.h @@ -189,13 +189,14 @@ void tcpip_adapter_init(void); * * @param[in] mac Set MAC address of this interface * @param[in] ip_info Set IP address of this interface + * @param[in] args extra args passed to tcpip_adapter * * @return * - ESP_OK * - ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS * - ESP_ERR_NO_MEM */ -esp_err_t tcpip_adapter_eth_start(uint8_t *mac, tcpip_adapter_ip_info_t *ip_info); +esp_err_t tcpip_adapter_eth_start(uint8_t *mac, tcpip_adapter_ip_info_t *ip_info, void *args); /** * @brief Cause the TCP/IP stack to start the Wi-Fi station interface with specified MAC and IP @@ -713,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 @@ -721,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) @@ -729,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) @@ -737,8 +738,16 @@ 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 + * @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 c8570a832c..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" @@ -29,9 +28,12 @@ #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" +#ifdef CONFIG_ETH_ENABLED #include "netif/ethernetif.h" +#endif #include "netif/nettestif.h" #include "dhcpserver/dhcpserver.h" @@ -49,19 +51,19 @@ static tcpip_adapter_ip_lost_timer_t esp_ip_lost_timer[TCPIP_ADAPTER_IF_MAX]; static tcpip_adapter_dhcp_status_t dhcps_status = TCPIP_ADAPTER_DHCP_INIT; static tcpip_adapter_dhcp_status_t dhcpc_status[TCPIP_ADAPTER_IF_MAX] = {TCPIP_ADAPTER_DHCP_INIT}; -static esp_err_t tcpip_adapter_start_api(tcpip_adapter_api_msg_t * msg); -static esp_err_t tcpip_adapter_stop_api(tcpip_adapter_api_msg_t * msg); -static esp_err_t tcpip_adapter_up_api(tcpip_adapter_api_msg_t * msg); -static esp_err_t tcpip_adapter_down_api(tcpip_adapter_api_msg_t * msg); -static esp_err_t tcpip_adapter_set_ip_info_api(tcpip_adapter_api_msg_t * msg); -static esp_err_t tcpip_adapter_set_dns_info_api(tcpip_adapter_api_msg_t * msg); -static esp_err_t tcpip_adapter_get_dns_info_api(tcpip_adapter_api_msg_t * msg); -static esp_err_t tcpip_adapter_create_ip6_linklocal_api(tcpip_adapter_api_msg_t * msg); -static esp_err_t tcpip_adapter_dhcps_start_api(tcpip_adapter_api_msg_t * msg); -static esp_err_t tcpip_adapter_dhcps_stop_api(tcpip_adapter_api_msg_t * msg); -static esp_err_t tcpip_adapter_dhcpc_start_api(tcpip_adapter_api_msg_t * msg); -static esp_err_t tcpip_adapter_dhcpc_stop_api(tcpip_adapter_api_msg_t * msg); -static esp_err_t tcpip_adapter_set_hostname_api(tcpip_adapter_api_msg_t * msg); +static esp_err_t tcpip_adapter_start_api(tcpip_adapter_api_msg_t *msg); +static esp_err_t tcpip_adapter_stop_api(tcpip_adapter_api_msg_t *msg); +static esp_err_t tcpip_adapter_up_api(tcpip_adapter_api_msg_t *msg); +static esp_err_t tcpip_adapter_down_api(tcpip_adapter_api_msg_t *msg); +static esp_err_t tcpip_adapter_set_ip_info_api(tcpip_adapter_api_msg_t *msg); +static esp_err_t tcpip_adapter_set_dns_info_api(tcpip_adapter_api_msg_t *msg); +static esp_err_t tcpip_adapter_get_dns_info_api(tcpip_adapter_api_msg_t *msg); +static esp_err_t tcpip_adapter_create_ip6_linklocal_api(tcpip_adapter_api_msg_t *msg); +static esp_err_t tcpip_adapter_dhcps_start_api(tcpip_adapter_api_msg_t *msg); +static esp_err_t tcpip_adapter_dhcps_stop_api(tcpip_adapter_api_msg_t *msg); +static esp_err_t tcpip_adapter_dhcpc_start_api(tcpip_adapter_api_msg_t *msg); +static esp_err_t tcpip_adapter_dhcpc_stop_api(tcpip_adapter_api_msg_t *msg); +static esp_err_t tcpip_adapter_set_hostname_api(tcpip_adapter_api_msg_t *msg); static esp_err_t tcpip_adapter_reset_ip_info(tcpip_adapter_if_t tcpip_if); static esp_err_t tcpip_adapter_start_ip_lost_timer(tcpip_adapter_if_t tcpip_if); static void tcpip_adapter_ip_lost_timer(void *arg); @@ -69,13 +71,13 @@ static sys_sem_t api_sync_sem = NULL; static bool tcpip_inited = false; static sys_sem_t api_lock_sem = NULL; extern sys_thread_t g_lwip_task; -static const char* TAG = "tcpip_adapter"; +static const char *TAG = "tcpip_adapter"; ESP_EVENT_DEFINE_BASE(IP_EVENT); -static void tcpip_adapter_api_cb(void* api_msg) +static void tcpip_adapter_api_cb(void *api_msg) { - tcpip_adapter_api_msg_t *msg = (tcpip_adapter_api_msg_t*)api_msg; + tcpip_adapter_api_msg_t *msg = (tcpip_adapter_api_msg_t *)api_msg; if (!msg || !msg->api_fn) { ESP_LOGD(TAG, "null msg/api_fn"); @@ -91,8 +93,8 @@ static void tcpip_adapter_api_cb(void* api_msg) static void tcpip_adapter_dhcps_cb(u8_t client_ip[4]) { - ESP_LOGI(TAG,"softAP assign IP to station,IP is: %d.%d.%d.%d", - client_ip[0],client_ip[1],client_ip[2],client_ip[3]); + ESP_LOGI(TAG, "softAP assign IP to station,IP is: %d.%d.%d.%d", + client_ip[0], client_ip[1], client_ip[2], client_ip[3]); system_event_t evt; memset(&evt, 0, sizeof(system_event_t)); evt.event_id = SYSTEM_EVENT_AP_STAIPASSIGNED; @@ -129,10 +131,11 @@ void tcpip_adapter_init(void) static inline netif_init_fn tcpip_if_to_netif_init_fn(tcpip_adapter_if_t tcpip_if) { - if (tcpip_if < TCPIP_ADAPTER_IF_MAX) - return esp_netif_init_fn[tcpip_if]; - else - return NULL; + if (tcpip_if < TCPIP_ADAPTER_IF_MAX) { + return esp_netif_init_fn[tcpip_if]; + } else { + return NULL; + } } static int tcpip_adapter_ipc_check(tcpip_adapter_api_msg_t *msg) @@ -156,24 +159,24 @@ 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]); } return ESP_OK; } -static esp_err_t tcpip_adapter_start(tcpip_adapter_if_t tcpip_if, uint8_t *mac, tcpip_adapter_ip_info_t *ip_info) +static esp_err_t tcpip_adapter_start(tcpip_adapter_if_t tcpip_if, uint8_t *mac, tcpip_adapter_ip_info_t *ip_info, void *args) { netif_init_fn netif_init; - TCPIP_ADAPTER_IPC_CALL(tcpip_if, mac, ip_info, 0, tcpip_adapter_start_api); + TCPIP_ADAPTER_IPC_CALL(tcpip_if, mac, ip_info, args, tcpip_adapter_start_api); if (tcpip_if >= TCPIP_ADAPTER_IF_MAX || mac == NULL || ip_info == NULL) { return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS; @@ -191,7 +194,8 @@ 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, NULL, netif_init, tcpip_input); + 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]); @@ -205,11 +209,11 @@ static esp_err_t tcpip_adapter_start(tcpip_adapter_if_t tcpip_if, uint8_t *mac, if (dhcps_status == TCPIP_ADAPTER_DHCP_INIT) { dhcps_set_new_lease_cb(tcpip_adapter_dhcps_cb); - + dhcps_start(esp_netif[tcpip_if], ip_info->ip); ESP_LOGD(TAG, "dhcp server start:(ip: " IPSTR ", mask: " IPSTR ", gw: " IPSTR ")", - IP2STR(&ip_info->ip), IP2STR(&ip_info->netmask), IP2STR(&ip_info->gw)); + IP2STR(&ip_info->ip), IP2STR(&ip_info->netmask), IP2STR(&ip_info->gw)); dhcps_status = TCPIP_ADAPTER_DHCP_STARTED; } @@ -222,34 +226,38 @@ static esp_err_t tcpip_adapter_start(tcpip_adapter_if_t tcpip_if, uint8_t *mac, return ESP_OK; } -esp_err_t tcpip_adapter_eth_start(uint8_t *mac, tcpip_adapter_ip_info_t *ip_info) +esp_err_t tcpip_adapter_eth_start(uint8_t *mac, tcpip_adapter_ip_info_t *ip_info, void *args) { - esp_netif_init_fn[TCPIP_ADAPTER_IF_ETH] = ethernetif_init; - return tcpip_adapter_start(TCPIP_ADAPTER_IF_ETH, mac, ip_info); +#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) { - esp_netif_init_fn[TCPIP_ADAPTER_IF_STA] = wlanif_init_sta; - return tcpip_adapter_start(TCPIP_ADAPTER_IF_STA, mac, ip_info); + esp_netif_init_fn[TCPIP_ADAPTER_IF_STA] = wlanif_init_sta; + return tcpip_adapter_start(TCPIP_ADAPTER_IF_STA, mac, ip_info, NULL); } esp_err_t tcpip_adapter_test_start(uint8_t *mac, tcpip_adapter_ip_info_t *ip_info) { - esp_netif_init_fn[TCPIP_ADAPTER_IF_TEST] = nettestif_init; - return tcpip_adapter_start(TCPIP_ADAPTER_IF_TEST, mac, ip_info); + esp_netif_init_fn[TCPIP_ADAPTER_IF_TEST] = nettestif_init; + return tcpip_adapter_start(TCPIP_ADAPTER_IF_TEST, mac, ip_info, NULL); } esp_err_t tcpip_adapter_ap_start(uint8_t *mac, tcpip_adapter_ip_info_t *ip_info) { - esp_netif_init_fn[TCPIP_ADAPTER_IF_AP] = wlanif_init_ap; - return tcpip_adapter_start(TCPIP_ADAPTER_IF_AP, mac, ip_info); + esp_netif_init_fn[TCPIP_ADAPTER_IF_AP] = wlanif_init_ap; + return tcpip_adapter_start(TCPIP_ADAPTER_IF_AP, mac, ip_info, NULL); } -static esp_err_t tcpip_adapter_start_api(tcpip_adapter_api_msg_t * msg) +static esp_err_t tcpip_adapter_start_api(tcpip_adapter_api_msg_t *msg) { - return tcpip_adapter_start(msg->tcpip_if, msg->mac, msg->ip_info); + return tcpip_adapter_start(msg->tcpip_if, msg->mac, msg->ip_info, msg->data); } esp_err_t tcpip_adapter_stop(tcpip_adapter_if_t tcpip_if) @@ -291,7 +299,7 @@ esp_err_t tcpip_adapter_stop(tcpip_adapter_if_t tcpip_if) return ESP_OK; } -static esp_err_t tcpip_adapter_stop_api(tcpip_adapter_api_msg_t * msg) +static esp_err_t tcpip_adapter_stop_api(tcpip_adapter_api_msg_t *msg) { msg->ret = tcpip_adapter_stop(msg->tcpip_if); return msg->ret; @@ -316,7 +324,7 @@ esp_err_t tcpip_adapter_up(tcpip_adapter_if_t tcpip_if) return ESP_OK; } -static esp_err_t tcpip_adapter_up_api(tcpip_adapter_api_msg_t * msg) +static esp_err_t tcpip_adapter_up_api(tcpip_adapter_api_msg_t *msg) { msg->ret = tcpip_adapter_up(msg->tcpip_if); return msg->ret; @@ -349,12 +357,12 @@ esp_err_t tcpip_adapter_down(tcpip_adapter_if_t tcpip_if) return ESP_OK; } -static esp_err_t tcpip_adapter_down_api(tcpip_adapter_api_msg_t * msg) +static esp_err_t tcpip_adapter_down_api(tcpip_adapter_api_msg_t *msg) { return tcpip_adapter_down(msg->tcpip_if); } -esp_err_t tcpip_adapter_set_old_ip_info_api(tcpip_adapter_api_msg_t * msg) +esp_err_t tcpip_adapter_set_old_ip_info_api(tcpip_adapter_api_msg_t *msg) { memcpy(&esp_ip_old[msg->tcpip_if], msg->ip_info, sizeof(tcpip_adapter_ip_info_t)); return ESP_OK; @@ -468,7 +476,7 @@ esp_err_t tcpip_adapter_set_ip_info(tcpip_adapter_if_t tcpip_if, const tcpip_ada return ESP_OK; } -static esp_err_t tcpip_adapter_set_ip_info_api(tcpip_adapter_api_msg_t * msg) +static esp_err_t tcpip_adapter_set_ip_info_api(tcpip_adapter_api_msg_t *msg) { return tcpip_adapter_set_ip_info(msg->tcpip_if, msg->ip_info); } @@ -528,7 +536,7 @@ esp_err_t tcpip_adapter_create_ip6_linklocal(tcpip_adapter_if_t tcpip_if) } } -static esp_err_t tcpip_adapter_create_ip6_linklocal_api(tcpip_adapter_api_msg_t * msg) +static esp_err_t tcpip_adapter_create_ip6_linklocal_api(tcpip_adapter_api_msg_t *msg) { return tcpip_adapter_create_ip6_linklocal(msg->tcpip_if); } @@ -683,7 +691,7 @@ esp_err_t tcpip_adapter_dhcps_option(tcpip_adapter_dhcp_option_mode_t opt_op, tc if (*(uint8_t *)opt_val) { *(uint8_t *)opt_info |= OFFER_ROUTER; } else { - *(uint8_t *)opt_info &= ((~OFFER_ROUTER)&0xFF); + *(uint8_t *)opt_info &= ((~OFFER_ROUTER) & 0xFF); } break; } @@ -691,15 +699,15 @@ esp_err_t tcpip_adapter_dhcps_option(tcpip_adapter_dhcp_option_mode_t opt_op, tc if (*(uint8_t *)opt_val) { *(uint8_t *)opt_info |= OFFER_DNS; } else { - *(uint8_t *)opt_info &= ((~OFFER_DNS)&0xFF); + *(uint8_t *)opt_info &= ((~OFFER_DNS) & 0xFF); } break; } - + default: break; } - dhcps_set_option_info(opt_id, opt_info,opt_len); + dhcps_set_option_info(opt_id, opt_info, opt_len); } else { return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS; } @@ -720,7 +728,7 @@ esp_err_t tcpip_adapter_set_dns_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_ ESP_LOGD(TAG, "set dns invalid if=%d", tcpip_if); return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS; } - + if (!dns) { ESP_LOGD(TAG, "set dns null dns"); return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS; @@ -730,7 +738,7 @@ esp_err_t tcpip_adapter_set_dns_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_ ESP_LOGD(TAG, "set dns invalid type=%d", type); return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS; } - + if (ip4_addr_isany_val(dns->ip.u_addr.ip4)) { ESP_LOGD(TAG, "set dns invalid dns"); return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS; @@ -753,20 +761,22 @@ esp_err_t tcpip_adapter_set_dns_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_ return ESP_OK; } -static esp_err_t tcpip_adapter_set_dns_info_api(tcpip_adapter_api_msg_t * msg) +static esp_err_t tcpip_adapter_set_dns_info_api(tcpip_adapter_api_msg_t *msg) { - tcpip_adapter_dns_param_t *dns_param = (tcpip_adapter_dns_param_t*)msg->data; + tcpip_adapter_dns_param_t *dns_param = (tcpip_adapter_dns_param_t *)msg->data; return tcpip_adapter_set_dns_info(msg->tcpip_if, dns_param->dns_type, dns_param->dns_info); } esp_err_t tcpip_adapter_get_dns_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_dns_type_t type, tcpip_adapter_dns_info_t *dns) -{ +{ tcpip_adapter_dns_param_t dns_param; 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) { ESP_LOGD(TAG, "get dns null dns"); @@ -777,14 +787,17 @@ esp_err_t tcpip_adapter_get_dns_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_ ESP_LOGD(TAG, "get dns invalid type=%d", type); return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS; } - + if (tcpip_if >= TCPIP_ADAPTER_IF_MAX) { - ESP_LOGD(TAG, "get dns invalid tcpip_if=%d",tcpip_if); + ESP_LOGD(TAG, "get dns invalid tcpip_if=%d", tcpip_if); return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS; } 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(); } @@ -792,9 +805,9 @@ esp_err_t tcpip_adapter_get_dns_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_ return ESP_OK; } -static esp_err_t tcpip_adapter_get_dns_info_api(tcpip_adapter_api_msg_t * msg) +static esp_err_t tcpip_adapter_get_dns_info_api(tcpip_adapter_api_msg_t *msg) { - tcpip_adapter_dns_param_t *dns_param = (tcpip_adapter_dns_param_t*)msg->data; + tcpip_adapter_dns_param_t *dns_param = (tcpip_adapter_dns_param_t *)msg->data; return tcpip_adapter_get_dns_info(msg->tcpip_if, dns_param->dns_type, dns_param->dns_info); } @@ -837,7 +850,7 @@ esp_err_t tcpip_adapter_dhcps_start(tcpip_adapter_if_t tcpip_if) return ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STARTED; } -static esp_err_t tcpip_adapter_dhcps_start_api(tcpip_adapter_api_msg_t * msg) +static esp_err_t tcpip_adapter_dhcps_start_api(tcpip_adapter_api_msg_t *msg) { return tcpip_adapter_dhcps_start(msg->tcpip_if); } @@ -872,7 +885,7 @@ esp_err_t tcpip_adapter_dhcps_stop(tcpip_adapter_if_t tcpip_if) return ESP_OK; } -static esp_err_t tcpip_adapter_dhcps_stop_api(tcpip_adapter_api_msg_t * msg) +static esp_err_t tcpip_adapter_dhcps_stop_api(tcpip_adapter_api_msg_t *msg) { return tcpip_adapter_dhcps_stop(msg->tcpip_if); } @@ -894,11 +907,11 @@ static void tcpip_adapter_dhcpc_cb(struct netif *netif) return; } - if( netif == esp_netif[TCPIP_ADAPTER_IF_STA] ) { + if ( netif == esp_netif[TCPIP_ADAPTER_IF_STA] ) { tcpip_if = TCPIP_ADAPTER_IF_STA; - } else if(netif == esp_netif[TCPIP_ADAPTER_IF_ETH] ) { + } else if (netif == esp_netif[TCPIP_ADAPTER_IF_ETH] ) { tcpip_if = TCPIP_ADAPTER_IF_ETH; - } else { + } else { ESP_LOGD(TAG, "err netif=%p", netif); return; } @@ -908,7 +921,7 @@ static void tcpip_adapter_dhcpc_cb(struct netif *netif) ip_info_old = &esp_ip_old[tcpip_if]; if ( !ip4_addr_cmp(ip_2_ip4(&netif->ip_addr), IP4_ADDR_ANY4) ) { - + //check whether IP is changed if ( !ip4_addr_cmp(ip_2_ip4(&netif->ip_addr), (&ip_info->ip)) || !ip4_addr_cmp(ip_2_ip4(&netif->netmask), (&ip_info->netmask)) || @@ -967,13 +980,13 @@ static esp_err_t tcpip_adapter_start_ip_lost_timer(tcpip_adapter_if_t tcpip_if) if ( netif && (CONFIG_NETIF_IP_LOST_TIMER_INTERVAL > 0) && !ip4_addr_isany_val(ip_info_old->ip)) { esp_ip_lost_timer[tcpip_if].timer_running = true; - sys_timeout(CONFIG_NETIF_IP_LOST_TIMER_INTERVAL*1000, tcpip_adapter_ip_lost_timer, (void*)tcpip_if); + sys_timeout(CONFIG_NETIF_IP_LOST_TIMER_INTERVAL * 1000, tcpip_adapter_ip_lost_timer, (void *)tcpip_if); ESP_LOGD(TAG, "if%d start ip lost tmr: interval=%d", tcpip_if, CONFIG_NETIF_IP_LOST_TIMER_INTERVAL); return ESP_OK; } - ESP_LOGD(TAG, "if%d start ip lost tmr: no need start because netif=%p interval=%d ip=%x", - tcpip_if, netif, CONFIG_NETIF_IP_LOST_TIMER_INTERVAL, ip_info_old->ip.addr); + ESP_LOGD(TAG, "if%d start ip lost tmr: no need start because netif=%p interval=%d ip=%x", + tcpip_if, netif, CONFIG_NETIF_IP_LOST_TIMER_INTERVAL, ip_info_old->ip.addr); return ESP_OK; } @@ -988,7 +1001,7 @@ static void tcpip_adapter_ip_lost_timer(void *arg) if (tcpip_if == TCPIP_ADAPTER_IF_STA) { struct netif *netif = esp_netif[tcpip_if]; - if ( (!netif) || (netif && ip4_addr_cmp(ip_2_ip4(&netif->ip_addr), IP4_ADDR_ANY4))){ + if ( (!netif) || (netif && ip4_addr_cmp(ip_2_ip4(&netif->ip_addr), IP4_ADDR_ANY4))) { system_event_t evt; memset(&evt, 0, sizeof(system_event_t)); @@ -1062,7 +1075,7 @@ esp_err_t tcpip_adapter_dhcpc_start(tcpip_adapter_if_t tcpip_if) return ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STARTED; } -static esp_err_t tcpip_adapter_dhcpc_start_api(tcpip_adapter_api_msg_t * msg) +static esp_err_t tcpip_adapter_dhcpc_start_api(tcpip_adapter_api_msg_t *msg) { return tcpip_adapter_dhcpc_start(msg->tcpip_if); } @@ -1096,19 +1109,23 @@ esp_err_t tcpip_adapter_dhcpc_stop(tcpip_adapter_if_t tcpip_if) dhcpc_status[tcpip_if] = TCPIP_ADAPTER_DHCP_STOPPED; LWIP_DHCP_IP_ADDR_ERASE(); - + return ESP_OK; } -static esp_err_t tcpip_adapter_dhcpc_stop_api(tcpip_adapter_api_msg_t * msg) +static esp_err_t tcpip_adapter_dhcpc_stop_api(tcpip_adapter_api_msg_t *msg) { return tcpip_adapter_dhcpc_stop(msg->tcpip_if); } 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) @@ -1193,9 +1210,9 @@ esp_err_t tcpip_adapter_set_hostname(tcpip_adapter_if_t tcpip_if, const char *ho #endif } -static esp_err_t tcpip_adapter_set_hostname_api(tcpip_adapter_api_msg_t * msg) +static esp_err_t tcpip_adapter_set_hostname_api(tcpip_adapter_api_msg_t *msg) { - const char *hostname = (char*) msg->data; + const char *hostname = (char *) msg->data; return tcpip_adapter_set_hostname(msg->tcpip_if, hostname); } @@ -1228,7 +1245,7 @@ static esp_err_t tcpip_adapter_reset_ip_info(tcpip_adapter_if_t tcpip_if) return ESP_OK; } -esp_err_t tcpip_adapter_get_netif(tcpip_adapter_if_t tcpip_if, void ** netif) +esp_err_t tcpip_adapter_get_netif(tcpip_adapter_if_t tcpip_if, void **netif) { if (tcpip_if >= TCPIP_ADAPTER_IF_MAX) { return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS; @@ -1251,4 +1268,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/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/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/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/ulp/ulp.c b/components/ulp/ulp.c index c19130b729..34d8531253 100644 --- a/components/ulp/ulp.c +++ b/components/ulp/ulp.c @@ -32,7 +32,7 @@ #include "soc/rtc_cntl_reg.h" #include "soc/sens_reg.h" - +#include "ulp_private.h" typedef struct { uint32_t magic; @@ -77,10 +77,10 @@ esp_err_t ulp_load_binary(uint32_t load_addr, const uint8_t* program_binary, siz if (program_size_bytes < sizeof(ulp_binary_header_t)) { return ESP_ERR_INVALID_SIZE; } - if (load_addr_bytes > CONFIG_ESP32_ULP_COPROC_RESERVE_MEM) { + if (load_addr_bytes > ULP_RESERVE_MEM) { return ESP_ERR_INVALID_ARG; } - if (load_addr_bytes + program_size_bytes > CONFIG_ESP32_ULP_COPROC_RESERVE_MEM) { + if (load_addr_bytes + program_size_bytes > ULP_RESERVE_MEM) { return ESP_ERR_INVALID_SIZE; } diff --git a/components/ulp/ulp_macro.c b/components/ulp/ulp_macro.c index c9b6e6dcbd..249ecfc43b 100644 --- a/components/ulp/ulp_macro.c +++ b/components/ulp/ulp_macro.c @@ -20,6 +20,7 @@ #include "esp_err.h" #include "esp_log.h" #include "esp32/ulp.h" +#include "ulp_private.h" #include "soc/soc.h" #include "soc/rtc_cntl_reg.h" @@ -167,7 +168,7 @@ esp_err_t ulp_process_macros_and_load(uint32_t load_addr, const ulp_insn_t* prog ++read_ptr; } size_t real_program_size = *psize - macro_count; - const size_t ulp_mem_end = CONFIG_ESP32_ULP_COPROC_RESERVE_MEM / sizeof(ulp_insn_t); + const size_t ulp_mem_end = ULP_RESERVE_MEM / sizeof(ulp_insn_t); if (load_addr > ulp_mem_end) { ESP_LOGW(TAG, "invalid load address %x, max is %x", load_addr, ulp_mem_end); 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/unity/CMakeLists.txt b/components/unity/CMakeLists.txt index 3f8ecac230..d98b05d8df 100644 --- a/components/unity/CMakeLists.txt +++ b/components/unity/CMakeLists.txt @@ -1,18 +1,21 @@ -set(COMPONENT_SRCS "unity/src/unity.c" - "unity_port_esp32.c") +set(srcs + "unity/src/unity.c" + "unity_port_esp32.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") + 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/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/unity/include/unity_test_runner.h b/components/unity/include/unity_test_runner.h index 8f41eb83d7..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_, \ @@ -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 1a25bc1a66..dcc01156bf 100644 --- a/components/unity/unity_port_esp32.c +++ b/components/unity/unity_port_esp32.c @@ -36,7 +36,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/CMakeLists.txt b/components/vfs/CMakeLists.txt index 1d8fb06ec0..d62c9e0393 100644 --- a/components/vfs/CMakeLists.txt +++ b/components/vfs/CMakeLists.txt @@ -1,9 +1,8 @@ -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 -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/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/README.rst b/components/vfs/README.rst index 95ccefd840..c296e81a68 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); @@ -67,9 +66,29 @@ Case 2: API functions are declared with an extra context pointer (FS driver supp 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: +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 @@ -82,25 +101,62 @@ then you need to register the VFS with :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 functions -:cpp:func:`esp_vfs_dev_uart_register`, :cpp:func:`uart_start_select` and -:cpp:func:`uart_end_select`. +: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` for more information. -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/uart_select` + - :example:`system/select` -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 -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 ----- -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 +167,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 +217,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/vfs/include/esp_vfs.h b/components/vfs/include/esp_vfs.h index 1d8abd8b35..2f39ca62f5 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); @@ -196,7 +204,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,10 +233,10 @@ 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); + 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 */ @@ -236,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)(); + esp_err_t (*end_select)(void *end_select_args); } esp_vfs_t; @@ -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/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/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/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/vfs/test/test_vfs_access.c b/components/vfs/test/test_vfs_access.c index 4f3988842a..e6549093d4 100644 --- a/components/vfs/test/test_vfs_access.c +++ b/components/vfs/test/test_vfs_access.c @@ -68,7 +68,7 @@ TEST_CASE("Can use access() for UART", "[vfs]") #endif } -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, @@ -78,7 +78,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..2ce2270b8a 100644 --- a/components/vfs/test/test_vfs_select.c +++ b/components/vfs/test/test_vfs_select.c @@ -31,9 +31,19 @@ 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() +static int open_dummy_socket(void) { const struct addrinfo hints = { .ai_family = AF_INET, @@ -51,7 +61,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 +93,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, @@ -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/test/test_vfs_uart.c b/components/vfs/test/test_vfs_uart.c index d46c7cb757..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; @@ -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..681a9ec614 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"; @@ -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) { @@ -767,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)); + } } } } @@ -828,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(); @@ -920,6 +952,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]; @@ -931,16 +972,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; @@ -979,7 +1022,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); } @@ -988,6 +1031,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); @@ -1032,7 +1076,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 +1174,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) { @@ -1222,7 +1266,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 36fade118a..c9af488460 100644 --- a/components/vfs/vfs_uart.c +++ b/components/vfs/vfs_uart.c @@ -115,20 +115,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(); +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) { @@ -347,135 +348,159 @@ 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() +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_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) { @@ -925,9 +950,9 @@ 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() +void esp_vfs_dev_uart_register(void) { esp_vfs_t vfs = { .flags = ESP_VFS_FLAG_DEFAULT, @@ -941,12 +966,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)); } 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/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/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/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/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/components/wear_levelling/test_wl_host/sdkconfig/sdkconfig.h b/components/wear_levelling/test_wl_host/sdkconfig/sdkconfig.h index 5c65e5b7db..f9df47d6c2 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 1 + 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; diff --git a/components/wifi_provisioning/CMakeLists.txt b/components/wifi_provisioning/CMakeLists.txt index 46665bbc9b..41e09b17f3 100644 --- a/components/wifi_provisioning/CMakeLists.txt +++ b/components/wifi_provisioning/CMakeLists.txt @@ -1,21 +1,22 @@ -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 json) -set(COMPONENT_PRIV_REQUIRES protobuf-c bt mdns) +set(srcs "src/wifi_config.c" + "src/wifi_scan.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_scan.pb-c.c" + "proto-c/wifi_constants.pb-c.c") if(CONFIG_BT_ENABLED) - if(CONFIG_BT_BLUEDROID_ENABLED) - list(APPEND COMPONENT_SRCS + if(CONFIG_BT_BLUEDROID_ENABLED OR CONFIG_BT_NIMBLE_ENABLED) + 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/wifi_provisioning/Kconfig b/components/wifi_provisioning/Kconfig new file mode 100644 index 0000000000..d850f4052a --- /dev/null +++ b/components/wifi_provisioning/Kconfig @@ -0,0 +1,10 @@ +menu "Wi-Fi Provisioning Manager" + + config WIFI_PROV_SCAN_MAX_ENTRIES + int "Max Wi-Fi Scan Result Entries" + default 16 + range 1 255 + help + This sets the maximum number of entries of Wi-Fi scan results that will be kept by the provisioning manager + +endmenu 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/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/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/include/wifi_provisioning/wifi_scan.h b/components/wifi_provisioning/include/wifi_provisioning/wifi_scan.h new file mode 100644 index 0000000000..a4ebb7e570 --- /dev/null +++ b/components/wifi_provisioning/include/wifi_provisioning/wifi_scan.h @@ -0,0 +1,166 @@ +// 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 _PROV_WIFI_SCAN_H_ +#define _PROV_WIFI_SCAN_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define WIFI_SSID_LEN sizeof(((wifi_ap_record_t *)0)->ssid) +#define WIFI_BSSID_LEN sizeof(((wifi_ap_record_t *)0)->bssid) + +/** + * @brief Type of context data passed to each get/set/apply handler + * function set in `wifi_prov_scan_handlers` structure. + * + * This is passed as an opaque pointer, thereby allowing it be defined + * later in application code as per requirements. + */ +typedef struct wifi_prov_scan_ctx wifi_prov_scan_ctx_t; + +/** + * @brief Structure of entries in the scan results list + */ +typedef struct { + /** + * SSID of Wi-Fi AP + */ + char ssid[WIFI_SSID_LEN]; + + /** + * BSSID of Wi-Fi AP + */ + char bssid[WIFI_BSSID_LEN]; + + /** + * Wi-Fi channel number + */ + uint8_t channel; + + /** + * Signal strength + */ + int rssi; + + /** + * Wi-Fi security mode + */ + uint8_t auth; +} wifi_prov_scan_result_t; + +/** + * @brief Internal handlers for receiving and responding to protocomm + * requests from client + * + * This is to be passed as priv_data for protocomm request handler + * (refer to `wifi_prov_scan_handler()`) when calling `protocomm_add_endpoint()`. + */ +typedef struct wifi_prov_scan_handlers { + /** + * Handler function called when scan start command is received + * with various scan parameters : + * + * blocking (input) - If true, the function should return only + * when the scanning is finished + * + * passive (input) - If true, scan is to be started in passive + * mode (this may be slower) instead of active mode + * + * group_channels (input) - This specifies whether to scan + * all channels in one go (when zero) or perform scanning of + * channels in groups, with 120ms delay between scanning of + * consecutive groups, and the value of this parameter sets the + * number of channels in each group. This is useful when transport + * mode is SoftAP, where scanning all channels in one go may not + * give the Wi-Fi driver enough time to send out beacons, and + * hence may cause disconnection with any connected stations. + * When scanning in groups, the manager will wait for atleast + * 120ms after completing scan on a group of channels, and thus + * allow the driver to send out the beacons. For example, given + * that the total number of Wi-Fi channels is 14, then setting + * group_channels to 4, will create 5 groups, with each group + * having 3 channels, except the last one which will have + * 14 % 3 = 2 channels. So, when scan is started, the first 3 + * channels will be scanned, followed by a 120ms delay, and then + * the next 3 channels, and so on, until all the 14 channels have + * been scanned. One may need to adjust this parameter as having + * only few channels in a group may slow down the overall scan + * time, while having too many may again cause disconnection. + * Usually a value of 4 should work for most cases. Note that + * for any other mode of transport, e.g. BLE, this can be safely + * set to 0, and hence achieve the fastest overall scanning time. + * + * period_ms (input) - Scan parameter specifying how long to + * wait on each channel (in milli-seconds) + */ + esp_err_t (*scan_start)(bool blocking, bool passive, + uint8_t group_channels, uint32_t period_ms, + wifi_prov_scan_ctx_t **ctx); + + /** + * Handler function called when scan status is requested. Status + * is given the parameters : + * + * scan_finished (output) - When scan has finished this returns true + * + * result_count (output) - This gives the total number of results + * obtained till now. If scan is yet happening this number will + * keep on updating + */ + esp_err_t (*scan_status)(bool *scan_finished, + uint16_t *result_count, + wifi_prov_scan_ctx_t **ctx); + + /** + * Handler function called when scan result is requested. Parameters : + * + * scan_result - For fetching scan results. This can be called even + * if scan is still on going + * + * start_index (input) - Starting index from where to fetch the + * entries from the results list + * + * count (input) - Number of entries to fetch from the starting index + * + * entries (output) - List of entries returned. Each entry consists + * of ssid, channel and rssi information + */ + esp_err_t (*scan_result)(uint16_t result_index, + wifi_prov_scan_result_t *result, + wifi_prov_scan_ctx_t **ctx); + + /** + * Context pointer to be passed to above handler functions upon invocation + */ + wifi_prov_scan_ctx_t *ctx; +} wifi_prov_scan_handlers_t; + +/** + * @brief Handler for sending on demand Wi-Fi scan results + * + * This is to be registered as the `prov-scan` endpoint handler + * (protocomm `protocomm_req_handler_t`) using `protocomm_add_endpoint()` + */ +esp_err_t wifi_prov_scan_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen, + uint8_t **outbuf, ssize_t *outlen, void *priv_data); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/wifi_provisioning/proto-c/wifi_scan.pb-c.c b/components/wifi_provisioning/proto-c/wifi_scan.pb-c.c new file mode 100644 index 0000000000..4cf5b5dc3b --- /dev/null +++ b/components/wifi_provisioning/proto-c/wifi_scan.pb-c.c @@ -0,0 +1,878 @@ +/* Generated by the protocol buffer compiler. DO NOT EDIT! */ +/* Generated from: wifi_scan.proto */ + +/* Do not generate deprecated warnings for self */ +#ifndef PROTOBUF_C__NO_DEPRECATED +#define PROTOBUF_C__NO_DEPRECATED +#endif + +#include "wifi_scan.pb-c.h" +void cmd_scan_start__init + (CmdScanStart *message) +{ + static const CmdScanStart init_value = CMD_SCAN_START__INIT; + *message = init_value; +} +size_t cmd_scan_start__get_packed_size + (const CmdScanStart *message) +{ + assert(message->base.descriptor == &cmd_scan_start__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t cmd_scan_start__pack + (const CmdScanStart *message, + uint8_t *out) +{ + assert(message->base.descriptor == &cmd_scan_start__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t cmd_scan_start__pack_to_buffer + (const CmdScanStart *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &cmd_scan_start__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +CmdScanStart * + cmd_scan_start__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (CmdScanStart *) + protobuf_c_message_unpack (&cmd_scan_start__descriptor, + allocator, len, data); +} +void cmd_scan_start__free_unpacked + (CmdScanStart *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &cmd_scan_start__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void resp_scan_start__init + (RespScanStart *message) +{ + static const RespScanStart init_value = RESP_SCAN_START__INIT; + *message = init_value; +} +size_t resp_scan_start__get_packed_size + (const RespScanStart *message) +{ + assert(message->base.descriptor == &resp_scan_start__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t resp_scan_start__pack + (const RespScanStart *message, + uint8_t *out) +{ + assert(message->base.descriptor == &resp_scan_start__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t resp_scan_start__pack_to_buffer + (const RespScanStart *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &resp_scan_start__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +RespScanStart * + resp_scan_start__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (RespScanStart *) + protobuf_c_message_unpack (&resp_scan_start__descriptor, + allocator, len, data); +} +void resp_scan_start__free_unpacked + (RespScanStart *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &resp_scan_start__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void cmd_scan_status__init + (CmdScanStatus *message) +{ + static const CmdScanStatus init_value = CMD_SCAN_STATUS__INIT; + *message = init_value; +} +size_t cmd_scan_status__get_packed_size + (const CmdScanStatus *message) +{ + assert(message->base.descriptor == &cmd_scan_status__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t cmd_scan_status__pack + (const CmdScanStatus *message, + uint8_t *out) +{ + assert(message->base.descriptor == &cmd_scan_status__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t cmd_scan_status__pack_to_buffer + (const CmdScanStatus *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &cmd_scan_status__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +CmdScanStatus * + cmd_scan_status__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (CmdScanStatus *) + protobuf_c_message_unpack (&cmd_scan_status__descriptor, + allocator, len, data); +} +void cmd_scan_status__free_unpacked + (CmdScanStatus *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &cmd_scan_status__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void resp_scan_status__init + (RespScanStatus *message) +{ + static const RespScanStatus init_value = RESP_SCAN_STATUS__INIT; + *message = init_value; +} +size_t resp_scan_status__get_packed_size + (const RespScanStatus *message) +{ + assert(message->base.descriptor == &resp_scan_status__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t resp_scan_status__pack + (const RespScanStatus *message, + uint8_t *out) +{ + assert(message->base.descriptor == &resp_scan_status__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t resp_scan_status__pack_to_buffer + (const RespScanStatus *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &resp_scan_status__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +RespScanStatus * + resp_scan_status__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (RespScanStatus *) + protobuf_c_message_unpack (&resp_scan_status__descriptor, + allocator, len, data); +} +void resp_scan_status__free_unpacked + (RespScanStatus *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &resp_scan_status__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void cmd_scan_result__init + (CmdScanResult *message) +{ + static const CmdScanResult init_value = CMD_SCAN_RESULT__INIT; + *message = init_value; +} +size_t cmd_scan_result__get_packed_size + (const CmdScanResult *message) +{ + assert(message->base.descriptor == &cmd_scan_result__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t cmd_scan_result__pack + (const CmdScanResult *message, + uint8_t *out) +{ + assert(message->base.descriptor == &cmd_scan_result__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t cmd_scan_result__pack_to_buffer + (const CmdScanResult *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &cmd_scan_result__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +CmdScanResult * + cmd_scan_result__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (CmdScanResult *) + protobuf_c_message_unpack (&cmd_scan_result__descriptor, + allocator, len, data); +} +void cmd_scan_result__free_unpacked + (CmdScanResult *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &cmd_scan_result__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void wi_fi_scan_result__init + (WiFiScanResult *message) +{ + static const WiFiScanResult init_value = WI_FI_SCAN_RESULT__INIT; + *message = init_value; +} +size_t wi_fi_scan_result__get_packed_size + (const WiFiScanResult *message) +{ + assert(message->base.descriptor == &wi_fi_scan_result__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t wi_fi_scan_result__pack + (const WiFiScanResult *message, + uint8_t *out) +{ + assert(message->base.descriptor == &wi_fi_scan_result__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t wi_fi_scan_result__pack_to_buffer + (const WiFiScanResult *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &wi_fi_scan_result__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +WiFiScanResult * + wi_fi_scan_result__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (WiFiScanResult *) + protobuf_c_message_unpack (&wi_fi_scan_result__descriptor, + allocator, len, data); +} +void wi_fi_scan_result__free_unpacked + (WiFiScanResult *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &wi_fi_scan_result__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void resp_scan_result__init + (RespScanResult *message) +{ + static const RespScanResult init_value = RESP_SCAN_RESULT__INIT; + *message = init_value; +} +size_t resp_scan_result__get_packed_size + (const RespScanResult *message) +{ + assert(message->base.descriptor == &resp_scan_result__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t resp_scan_result__pack + (const RespScanResult *message, + uint8_t *out) +{ + assert(message->base.descriptor == &resp_scan_result__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t resp_scan_result__pack_to_buffer + (const RespScanResult *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &resp_scan_result__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +RespScanResult * + resp_scan_result__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (RespScanResult *) + protobuf_c_message_unpack (&resp_scan_result__descriptor, + allocator, len, data); +} +void resp_scan_result__free_unpacked + (RespScanResult *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &resp_scan_result__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void wi_fi_scan_payload__init + (WiFiScanPayload *message) +{ + static const WiFiScanPayload init_value = WI_FI_SCAN_PAYLOAD__INIT; + *message = init_value; +} +size_t wi_fi_scan_payload__get_packed_size + (const WiFiScanPayload *message) +{ + assert(message->base.descriptor == &wi_fi_scan_payload__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t wi_fi_scan_payload__pack + (const WiFiScanPayload *message, + uint8_t *out) +{ + assert(message->base.descriptor == &wi_fi_scan_payload__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t wi_fi_scan_payload__pack_to_buffer + (const WiFiScanPayload *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &wi_fi_scan_payload__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +WiFiScanPayload * + wi_fi_scan_payload__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (WiFiScanPayload *) + protobuf_c_message_unpack (&wi_fi_scan_payload__descriptor, + allocator, len, data); +} +void wi_fi_scan_payload__free_unpacked + (WiFiScanPayload *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &wi_fi_scan_payload__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +static const ProtobufCFieldDescriptor cmd_scan_start__field_descriptors[4] = +{ + { + "blocking", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_BOOL, + 0, /* quantifier_offset */ + offsetof(CmdScanStart, blocking), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "passive", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_BOOL, + 0, /* quantifier_offset */ + offsetof(CmdScanStart, passive), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "group_channels", + 3, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(CmdScanStart, group_channels), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "period_ms", + 4, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(CmdScanStart, period_ms), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned cmd_scan_start__field_indices_by_name[] = { + 0, /* field[0] = blocking */ + 2, /* field[2] = group_channels */ + 1, /* field[1] = passive */ + 3, /* field[3] = period_ms */ +}; +static const ProtobufCIntRange cmd_scan_start__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 4 } +}; +const ProtobufCMessageDescriptor cmd_scan_start__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "CmdScanStart", + "CmdScanStart", + "CmdScanStart", + "", + sizeof(CmdScanStart), + 4, + cmd_scan_start__field_descriptors, + cmd_scan_start__field_indices_by_name, + 1, cmd_scan_start__number_ranges, + (ProtobufCMessageInit) cmd_scan_start__init, + NULL,NULL,NULL /* reserved[123] */ +}; +#define resp_scan_start__field_descriptors NULL +#define resp_scan_start__field_indices_by_name NULL +#define resp_scan_start__number_ranges NULL +const ProtobufCMessageDescriptor resp_scan_start__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "RespScanStart", + "RespScanStart", + "RespScanStart", + "", + sizeof(RespScanStart), + 0, + resp_scan_start__field_descriptors, + resp_scan_start__field_indices_by_name, + 0, resp_scan_start__number_ranges, + (ProtobufCMessageInit) resp_scan_start__init, + NULL,NULL,NULL /* reserved[123] */ +}; +#define cmd_scan_status__field_descriptors NULL +#define cmd_scan_status__field_indices_by_name NULL +#define cmd_scan_status__number_ranges NULL +const ProtobufCMessageDescriptor cmd_scan_status__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "CmdScanStatus", + "CmdScanStatus", + "CmdScanStatus", + "", + sizeof(CmdScanStatus), + 0, + cmd_scan_status__field_descriptors, + cmd_scan_status__field_indices_by_name, + 0, cmd_scan_status__number_ranges, + (ProtobufCMessageInit) cmd_scan_status__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor resp_scan_status__field_descriptors[2] = +{ + { + "scan_finished", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_BOOL, + 0, /* quantifier_offset */ + offsetof(RespScanStatus, scan_finished), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "result_count", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(RespScanStatus, result_count), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned resp_scan_status__field_indices_by_name[] = { + 1, /* field[1] = result_count */ + 0, /* field[0] = scan_finished */ +}; +static const ProtobufCIntRange resp_scan_status__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 2 } +}; +const ProtobufCMessageDescriptor resp_scan_status__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "RespScanStatus", + "RespScanStatus", + "RespScanStatus", + "", + sizeof(RespScanStatus), + 2, + resp_scan_status__field_descriptors, + resp_scan_status__field_indices_by_name, + 1, resp_scan_status__number_ranges, + (ProtobufCMessageInit) resp_scan_status__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor cmd_scan_result__field_descriptors[2] = +{ + { + "start_index", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(CmdScanResult, start_index), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "count", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(CmdScanResult, count), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned cmd_scan_result__field_indices_by_name[] = { + 1, /* field[1] = count */ + 0, /* field[0] = start_index */ +}; +static const ProtobufCIntRange cmd_scan_result__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 2 } +}; +const ProtobufCMessageDescriptor cmd_scan_result__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "CmdScanResult", + "CmdScanResult", + "CmdScanResult", + "", + sizeof(CmdScanResult), + 2, + cmd_scan_result__field_descriptors, + cmd_scan_result__field_indices_by_name, + 1, cmd_scan_result__number_ranges, + (ProtobufCMessageInit) cmd_scan_result__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor wi_fi_scan_result__field_descriptors[5] = +{ + { + "ssid", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_BYTES, + 0, /* quantifier_offset */ + offsetof(WiFiScanResult, ssid), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "channel", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(WiFiScanResult, channel), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "rssi", + 3, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_INT32, + 0, /* quantifier_offset */ + offsetof(WiFiScanResult, rssi), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "bssid", + 4, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_BYTES, + 0, /* quantifier_offset */ + offsetof(WiFiScanResult, bssid), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "auth", + 5, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_ENUM, + 0, /* quantifier_offset */ + offsetof(WiFiScanResult, auth), + &wifi_auth_mode__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned wi_fi_scan_result__field_indices_by_name[] = { + 4, /* field[4] = auth */ + 3, /* field[3] = bssid */ + 1, /* field[1] = channel */ + 2, /* field[2] = rssi */ + 0, /* field[0] = ssid */ +}; +static const ProtobufCIntRange wi_fi_scan_result__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 5 } +}; +const ProtobufCMessageDescriptor wi_fi_scan_result__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "WiFiScanResult", + "WiFiScanResult", + "WiFiScanResult", + "", + sizeof(WiFiScanResult), + 5, + wi_fi_scan_result__field_descriptors, + wi_fi_scan_result__field_indices_by_name, + 1, wi_fi_scan_result__number_ranges, + (ProtobufCMessageInit) wi_fi_scan_result__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor resp_scan_result__field_descriptors[1] = +{ + { + "entries", + 1, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(RespScanResult, n_entries), + offsetof(RespScanResult, entries), + &wi_fi_scan_result__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned resp_scan_result__field_indices_by_name[] = { + 0, /* field[0] = entries */ +}; +static const ProtobufCIntRange resp_scan_result__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 1 } +}; +const ProtobufCMessageDescriptor resp_scan_result__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "RespScanResult", + "RespScanResult", + "RespScanResult", + "", + sizeof(RespScanResult), + 1, + resp_scan_result__field_descriptors, + resp_scan_result__field_indices_by_name, + 1, resp_scan_result__number_ranges, + (ProtobufCMessageInit) resp_scan_result__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor wi_fi_scan_payload__field_descriptors[8] = +{ + { + "msg", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_ENUM, + 0, /* quantifier_offset */ + offsetof(WiFiScanPayload, msg), + &wi_fi_scan_msg_type__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "status", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_ENUM, + 0, /* quantifier_offset */ + offsetof(WiFiScanPayload, status), + &status__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "cmd_scan_start", + 10, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(WiFiScanPayload, payload_case), + offsetof(WiFiScanPayload, cmd_scan_start), + &cmd_scan_start__descriptor, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "resp_scan_start", + 11, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(WiFiScanPayload, payload_case), + offsetof(WiFiScanPayload, resp_scan_start), + &resp_scan_start__descriptor, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "cmd_scan_status", + 12, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(WiFiScanPayload, payload_case), + offsetof(WiFiScanPayload, cmd_scan_status), + &cmd_scan_status__descriptor, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "resp_scan_status", + 13, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(WiFiScanPayload, payload_case), + offsetof(WiFiScanPayload, resp_scan_status), + &resp_scan_status__descriptor, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "cmd_scan_result", + 14, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(WiFiScanPayload, payload_case), + offsetof(WiFiScanPayload, cmd_scan_result), + &cmd_scan_result__descriptor, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "resp_scan_result", + 15, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(WiFiScanPayload, payload_case), + offsetof(WiFiScanPayload, resp_scan_result), + &resp_scan_result__descriptor, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned wi_fi_scan_payload__field_indices_by_name[] = { + 6, /* field[6] = cmd_scan_result */ + 2, /* field[2] = cmd_scan_start */ + 4, /* field[4] = cmd_scan_status */ + 0, /* field[0] = msg */ + 7, /* field[7] = resp_scan_result */ + 3, /* field[3] = resp_scan_start */ + 5, /* field[5] = resp_scan_status */ + 1, /* field[1] = status */ +}; +static const ProtobufCIntRange wi_fi_scan_payload__number_ranges[2 + 1] = +{ + { 1, 0 }, + { 10, 2 }, + { 0, 8 } +}; +const ProtobufCMessageDescriptor wi_fi_scan_payload__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "WiFiScanPayload", + "WiFiScanPayload", + "WiFiScanPayload", + "", + sizeof(WiFiScanPayload), + 8, + wi_fi_scan_payload__field_descriptors, + wi_fi_scan_payload__field_indices_by_name, + 2, wi_fi_scan_payload__number_ranges, + (ProtobufCMessageInit) wi_fi_scan_payload__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCEnumValue wi_fi_scan_msg_type__enum_values_by_number[6] = +{ + { "TypeCmdScanStart", "WI_FI_SCAN_MSG_TYPE__TypeCmdScanStart", 0 }, + { "TypeRespScanStart", "WI_FI_SCAN_MSG_TYPE__TypeRespScanStart", 1 }, + { "TypeCmdScanStatus", "WI_FI_SCAN_MSG_TYPE__TypeCmdScanStatus", 2 }, + { "TypeRespScanStatus", "WI_FI_SCAN_MSG_TYPE__TypeRespScanStatus", 3 }, + { "TypeCmdScanResult", "WI_FI_SCAN_MSG_TYPE__TypeCmdScanResult", 4 }, + { "TypeRespScanResult", "WI_FI_SCAN_MSG_TYPE__TypeRespScanResult", 5 }, +}; +static const ProtobufCIntRange wi_fi_scan_msg_type__value_ranges[] = { +{0, 0},{0, 6} +}; +static const ProtobufCEnumValueIndex wi_fi_scan_msg_type__enum_values_by_name[6] = +{ + { "TypeCmdScanResult", 4 }, + { "TypeCmdScanStart", 0 }, + { "TypeCmdScanStatus", 2 }, + { "TypeRespScanResult", 5 }, + { "TypeRespScanStart", 1 }, + { "TypeRespScanStatus", 3 }, +}; +const ProtobufCEnumDescriptor wi_fi_scan_msg_type__descriptor = +{ + PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC, + "WiFiScanMsgType", + "WiFiScanMsgType", + "WiFiScanMsgType", + "", + 6, + wi_fi_scan_msg_type__enum_values_by_number, + 6, + wi_fi_scan_msg_type__enum_values_by_name, + 1, + wi_fi_scan_msg_type__value_ranges, + NULL,NULL,NULL,NULL /* reserved[1234] */ +}; diff --git a/components/wifi_provisioning/proto-c/wifi_scan.pb-c.h b/components/wifi_provisioning/proto-c/wifi_scan.pb-c.h new file mode 100644 index 0000000000..9caea2c7cd --- /dev/null +++ b/components/wifi_provisioning/proto-c/wifi_scan.pb-c.h @@ -0,0 +1,350 @@ +/* Generated by the protocol buffer compiler. DO NOT EDIT! */ +/* Generated from: wifi_scan.proto */ + +#ifndef PROTOBUF_C_wifi_5fscan_2eproto__INCLUDED +#define PROTOBUF_C_wifi_5fscan_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" +#include "wifi_constants.pb-c.h" + +typedef struct _CmdScanStart CmdScanStart; +typedef struct _RespScanStart RespScanStart; +typedef struct _CmdScanStatus CmdScanStatus; +typedef struct _RespScanStatus RespScanStatus; +typedef struct _CmdScanResult CmdScanResult; +typedef struct _WiFiScanResult WiFiScanResult; +typedef struct _RespScanResult RespScanResult; +typedef struct _WiFiScanPayload WiFiScanPayload; + + +/* --- enums --- */ + +typedef enum _WiFiScanMsgType { + WI_FI_SCAN_MSG_TYPE__TypeCmdScanStart = 0, + WI_FI_SCAN_MSG_TYPE__TypeRespScanStart = 1, + WI_FI_SCAN_MSG_TYPE__TypeCmdScanStatus = 2, + WI_FI_SCAN_MSG_TYPE__TypeRespScanStatus = 3, + WI_FI_SCAN_MSG_TYPE__TypeCmdScanResult = 4, + WI_FI_SCAN_MSG_TYPE__TypeRespScanResult = 5 + PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(WI_FI_SCAN_MSG_TYPE) +} WiFiScanMsgType; + +/* --- messages --- */ + +struct _CmdScanStart +{ + ProtobufCMessage base; + protobuf_c_boolean blocking; + protobuf_c_boolean passive; + uint32_t group_channels; + uint32_t period_ms; +}; +#define CMD_SCAN_START__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&cmd_scan_start__descriptor) \ + , 0, 0, 0, 0 } + + +struct _RespScanStart +{ + ProtobufCMessage base; +}; +#define RESP_SCAN_START__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&resp_scan_start__descriptor) \ + } + + +struct _CmdScanStatus +{ + ProtobufCMessage base; +}; +#define CMD_SCAN_STATUS__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&cmd_scan_status__descriptor) \ + } + + +struct _RespScanStatus +{ + ProtobufCMessage base; + protobuf_c_boolean scan_finished; + uint32_t result_count; +}; +#define RESP_SCAN_STATUS__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&resp_scan_status__descriptor) \ + , 0, 0 } + + +struct _CmdScanResult +{ + ProtobufCMessage base; + uint32_t start_index; + uint32_t count; +}; +#define CMD_SCAN_RESULT__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&cmd_scan_result__descriptor) \ + , 0, 0 } + + +struct _WiFiScanResult +{ + ProtobufCMessage base; + ProtobufCBinaryData ssid; + uint32_t channel; + int32_t rssi; + ProtobufCBinaryData bssid; + WifiAuthMode auth; +}; +#define WI_FI_SCAN_RESULT__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&wi_fi_scan_result__descriptor) \ + , {0,NULL}, 0, 0, {0,NULL}, WIFI_AUTH_MODE__Open } + + +struct _RespScanResult +{ + ProtobufCMessage base; + size_t n_entries; + WiFiScanResult **entries; +}; +#define RESP_SCAN_RESULT__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&resp_scan_result__descriptor) \ + , 0,NULL } + + +typedef enum { + WI_FI_SCAN_PAYLOAD__PAYLOAD__NOT_SET = 0, + WI_FI_SCAN_PAYLOAD__PAYLOAD_CMD_SCAN_START = 10, + WI_FI_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_START = 11, + WI_FI_SCAN_PAYLOAD__PAYLOAD_CMD_SCAN_STATUS = 12, + WI_FI_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_STATUS = 13, + WI_FI_SCAN_PAYLOAD__PAYLOAD_CMD_SCAN_RESULT = 14, + WI_FI_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_RESULT = 15 + PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(WI_FI_SCAN_PAYLOAD__PAYLOAD) +} WiFiScanPayload__PayloadCase; + +struct _WiFiScanPayload +{ + ProtobufCMessage base; + WiFiScanMsgType msg; + Status status; + WiFiScanPayload__PayloadCase payload_case; + union { + CmdScanStart *cmd_scan_start; + RespScanStart *resp_scan_start; + CmdScanStatus *cmd_scan_status; + RespScanStatus *resp_scan_status; + CmdScanResult *cmd_scan_result; + RespScanResult *resp_scan_result; + }; +}; +#define WI_FI_SCAN_PAYLOAD__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&wi_fi_scan_payload__descriptor) \ + , WI_FI_SCAN_MSG_TYPE__TypeCmdScanStart, STATUS__Success, WI_FI_SCAN_PAYLOAD__PAYLOAD__NOT_SET, {0} } + + +/* CmdScanStart methods */ +void cmd_scan_start__init + (CmdScanStart *message); +size_t cmd_scan_start__get_packed_size + (const CmdScanStart *message); +size_t cmd_scan_start__pack + (const CmdScanStart *message, + uint8_t *out); +size_t cmd_scan_start__pack_to_buffer + (const CmdScanStart *message, + ProtobufCBuffer *buffer); +CmdScanStart * + cmd_scan_start__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void cmd_scan_start__free_unpacked + (CmdScanStart *message, + ProtobufCAllocator *allocator); +/* RespScanStart methods */ +void resp_scan_start__init + (RespScanStart *message); +size_t resp_scan_start__get_packed_size + (const RespScanStart *message); +size_t resp_scan_start__pack + (const RespScanStart *message, + uint8_t *out); +size_t resp_scan_start__pack_to_buffer + (const RespScanStart *message, + ProtobufCBuffer *buffer); +RespScanStart * + resp_scan_start__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void resp_scan_start__free_unpacked + (RespScanStart *message, + ProtobufCAllocator *allocator); +/* CmdScanStatus methods */ +void cmd_scan_status__init + (CmdScanStatus *message); +size_t cmd_scan_status__get_packed_size + (const CmdScanStatus *message); +size_t cmd_scan_status__pack + (const CmdScanStatus *message, + uint8_t *out); +size_t cmd_scan_status__pack_to_buffer + (const CmdScanStatus *message, + ProtobufCBuffer *buffer); +CmdScanStatus * + cmd_scan_status__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void cmd_scan_status__free_unpacked + (CmdScanStatus *message, + ProtobufCAllocator *allocator); +/* RespScanStatus methods */ +void resp_scan_status__init + (RespScanStatus *message); +size_t resp_scan_status__get_packed_size + (const RespScanStatus *message); +size_t resp_scan_status__pack + (const RespScanStatus *message, + uint8_t *out); +size_t resp_scan_status__pack_to_buffer + (const RespScanStatus *message, + ProtobufCBuffer *buffer); +RespScanStatus * + resp_scan_status__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void resp_scan_status__free_unpacked + (RespScanStatus *message, + ProtobufCAllocator *allocator); +/* CmdScanResult methods */ +void cmd_scan_result__init + (CmdScanResult *message); +size_t cmd_scan_result__get_packed_size + (const CmdScanResult *message); +size_t cmd_scan_result__pack + (const CmdScanResult *message, + uint8_t *out); +size_t cmd_scan_result__pack_to_buffer + (const CmdScanResult *message, + ProtobufCBuffer *buffer); +CmdScanResult * + cmd_scan_result__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void cmd_scan_result__free_unpacked + (CmdScanResult *message, + ProtobufCAllocator *allocator); +/* WiFiScanResult methods */ +void wi_fi_scan_result__init + (WiFiScanResult *message); +size_t wi_fi_scan_result__get_packed_size + (const WiFiScanResult *message); +size_t wi_fi_scan_result__pack + (const WiFiScanResult *message, + uint8_t *out); +size_t wi_fi_scan_result__pack_to_buffer + (const WiFiScanResult *message, + ProtobufCBuffer *buffer); +WiFiScanResult * + wi_fi_scan_result__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void wi_fi_scan_result__free_unpacked + (WiFiScanResult *message, + ProtobufCAllocator *allocator); +/* RespScanResult methods */ +void resp_scan_result__init + (RespScanResult *message); +size_t resp_scan_result__get_packed_size + (const RespScanResult *message); +size_t resp_scan_result__pack + (const RespScanResult *message, + uint8_t *out); +size_t resp_scan_result__pack_to_buffer + (const RespScanResult *message, + ProtobufCBuffer *buffer); +RespScanResult * + resp_scan_result__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void resp_scan_result__free_unpacked + (RespScanResult *message, + ProtobufCAllocator *allocator); +/* WiFiScanPayload methods */ +void wi_fi_scan_payload__init + (WiFiScanPayload *message); +size_t wi_fi_scan_payload__get_packed_size + (const WiFiScanPayload *message); +size_t wi_fi_scan_payload__pack + (const WiFiScanPayload *message, + uint8_t *out); +size_t wi_fi_scan_payload__pack_to_buffer + (const WiFiScanPayload *message, + ProtobufCBuffer *buffer); +WiFiScanPayload * + wi_fi_scan_payload__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void wi_fi_scan_payload__free_unpacked + (WiFiScanPayload *message, + ProtobufCAllocator *allocator); +/* --- per-message closures --- */ + +typedef void (*CmdScanStart_Closure) + (const CmdScanStart *message, + void *closure_data); +typedef void (*RespScanStart_Closure) + (const RespScanStart *message, + void *closure_data); +typedef void (*CmdScanStatus_Closure) + (const CmdScanStatus *message, + void *closure_data); +typedef void (*RespScanStatus_Closure) + (const RespScanStatus *message, + void *closure_data); +typedef void (*CmdScanResult_Closure) + (const CmdScanResult *message, + void *closure_data); +typedef void (*WiFiScanResult_Closure) + (const WiFiScanResult *message, + void *closure_data); +typedef void (*RespScanResult_Closure) + (const RespScanResult *message, + void *closure_data); +typedef void (*WiFiScanPayload_Closure) + (const WiFiScanPayload *message, + void *closure_data); + +/* --- services --- */ + + +/* --- descriptors --- */ + +extern const ProtobufCEnumDescriptor wi_fi_scan_msg_type__descriptor; +extern const ProtobufCMessageDescriptor cmd_scan_start__descriptor; +extern const ProtobufCMessageDescriptor resp_scan_start__descriptor; +extern const ProtobufCMessageDescriptor cmd_scan_status__descriptor; +extern const ProtobufCMessageDescriptor resp_scan_status__descriptor; +extern const ProtobufCMessageDescriptor cmd_scan_result__descriptor; +extern const ProtobufCMessageDescriptor wi_fi_scan_result__descriptor; +extern const ProtobufCMessageDescriptor resp_scan_result__descriptor; +extern const ProtobufCMessageDescriptor wi_fi_scan_payload__descriptor; + +PROTOBUF_C__END_DECLS + + +#endif /* PROTOBUF_C_wifi_5fscan_2eproto__INCLUDED */ 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/components/wifi_provisioning/proto/wifi_scan.proto b/components/wifi_provisioning/proto/wifi_scan.proto new file mode 100644 index 0000000000..ea240f20f7 --- /dev/null +++ b/components/wifi_provisioning/proto/wifi_scan.proto @@ -0,0 +1,63 @@ +syntax = "proto3"; + +import "constants.proto"; +import "wifi_constants.proto"; + +message CmdScanStart { + bool blocking = 1; + bool passive = 2; + uint32 group_channels = 3; + uint32 period_ms = 4; +} + +message RespScanStart { + +} + +message CmdScanStatus { + +} + +message RespScanStatus { + bool scan_finished = 1; + uint32 result_count = 2; +} + +message CmdScanResult { + uint32 start_index = 1; + uint32 count = 2; +} + +message WiFiScanResult { + bytes ssid = 1; + uint32 channel = 2; + int32 rssi = 3; + bytes bssid = 4; + WifiAuthMode auth = 5; +} + +message RespScanResult { + repeated WiFiScanResult entries = 1; +} + +enum WiFiScanMsgType { + TypeCmdScanStart = 0; + TypeRespScanStart = 1; + TypeCmdScanStatus = 2; + TypeRespScanStatus = 3; + TypeCmdScanResult = 4; + TypeRespScanResult = 5; +} + +message WiFiScanPayload { + WiFiScanMsgType msg = 1; + Status status = 2; + oneof payload { + CmdScanStart cmd_scan_start = 10; + RespScanStart resp_scan_start = 11; + CmdScanStatus cmd_scan_status = 12; + RespScanStatus resp_scan_status = 13; + CmdScanResult cmd_scan_result = 14; + RespScanResult resp_scan_result = 15; + } +} diff --git a/components/wifi_provisioning/python/wifi_scan_pb2.py b/components/wifi_provisioning/python/wifi_scan_pb2.py new file mode 100644 index 0000000000..2e95d8f505 --- /dev/null +++ b/components/wifi_provisioning/python/wifi_scan_pb2.py @@ -0,0 +1,522 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: wifi_scan.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 +import wifi_constants_pb2 as wifi__constants__pb2 + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='wifi_scan.proto', + package='', + syntax='proto3', + serialized_options=None, + serialized_pb=_b('\n\x0fwifi_scan.proto\x1a\x0f\x63onstants.proto\x1a\x14wifi_constants.proto\"\\\n\x0c\x43mdScanStart\x12\x10\n\x08\x62locking\x18\x01 \x01(\x08\x12\x0f\n\x07passive\x18\x02 \x01(\x08\x12\x16\n\x0egroup_channels\x18\x03 \x01(\r\x12\x11\n\tperiod_ms\x18\x04 \x01(\r\"\x0f\n\rRespScanStart\"\x0f\n\rCmdScanStatus\"=\n\x0eRespScanStatus\x12\x15\n\rscan_finished\x18\x01 \x01(\x08\x12\x14\n\x0cresult_count\x18\x02 \x01(\r\"3\n\rCmdScanResult\x12\x13\n\x0bstart_index\x18\x01 \x01(\r\x12\r\n\x05\x63ount\x18\x02 \x01(\r\"i\n\x0eWiFiScanResult\x12\x0c\n\x04ssid\x18\x01 \x01(\x0c\x12\x0f\n\x07\x63hannel\x18\x02 \x01(\r\x12\x0c\n\x04rssi\x18\x03 \x01(\x05\x12\r\n\x05\x62ssid\x18\x04 \x01(\x0c\x12\x1b\n\x04\x61uth\x18\x05 \x01(\x0e\x32\r.WifiAuthMode\"2\n\x0eRespScanResult\x12 \n\x07\x65ntries\x18\x01 \x03(\x0b\x32\x0f.WiFiScanResult\"\xd8\x02\n\x0fWiFiScanPayload\x12\x1d\n\x03msg\x18\x01 \x01(\x0e\x32\x10.WiFiScanMsgType\x12\x17\n\x06status\x18\x02 \x01(\x0e\x32\x07.Status\x12\'\n\x0e\x63md_scan_start\x18\n \x01(\x0b\x32\r.CmdScanStartH\x00\x12)\n\x0fresp_scan_start\x18\x0b \x01(\x0b\x32\x0e.RespScanStartH\x00\x12)\n\x0f\x63md_scan_status\x18\x0c \x01(\x0b\x32\x0e.CmdScanStatusH\x00\x12+\n\x10resp_scan_status\x18\r \x01(\x0b\x32\x0f.RespScanStatusH\x00\x12)\n\x0f\x63md_scan_result\x18\x0e \x01(\x0b\x32\x0e.CmdScanResultH\x00\x12+\n\x10resp_scan_result\x18\x0f \x01(\x0b\x32\x0f.RespScanResultH\x00\x42\t\n\x07payload*\x9c\x01\n\x0fWiFiScanMsgType\x12\x14\n\x10TypeCmdScanStart\x10\x00\x12\x15\n\x11TypeRespScanStart\x10\x01\x12\x15\n\x11TypeCmdScanStatus\x10\x02\x12\x16\n\x12TypeRespScanStatus\x10\x03\x12\x15\n\x11TypeCmdScanResult\x10\x04\x12\x16\n\x12TypeRespScanResult\x10\x05\x62\x06proto3') + , + dependencies=[constants__pb2.DESCRIPTOR,wifi__constants__pb2.DESCRIPTOR,]) + +_WIFISCANMSGTYPE = _descriptor.EnumDescriptor( + name='WiFiScanMsgType', + full_name='WiFiScanMsgType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='TypeCmdScanStart', index=0, number=0, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='TypeRespScanStart', index=1, number=1, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='TypeCmdScanStatus', index=2, number=2, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='TypeRespScanStatus', index=3, number=3, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='TypeCmdScanResult', index=4, number=4, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='TypeRespScanResult', index=5, number=5, + serialized_options=None, + type=None), + ], + containing_type=None, + serialized_options=None, + serialized_start=809, + serialized_end=965, +) +_sym_db.RegisterEnumDescriptor(_WIFISCANMSGTYPE) + +WiFiScanMsgType = enum_type_wrapper.EnumTypeWrapper(_WIFISCANMSGTYPE) +TypeCmdScanStart = 0 +TypeRespScanStart = 1 +TypeCmdScanStatus = 2 +TypeRespScanStatus = 3 +TypeCmdScanResult = 4 +TypeRespScanResult = 5 + + + +_CMDSCANSTART = _descriptor.Descriptor( + name='CmdScanStart', + full_name='CmdScanStart', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='blocking', full_name='CmdScanStart.blocking', index=0, + number=1, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='passive', full_name='CmdScanStart.passive', index=1, + number=2, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='group_channels', full_name='CmdScanStart.group_channels', 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='period_ms', full_name='CmdScanStart.period_ms', 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), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=58, + serialized_end=150, +) + + +_RESPSCANSTART = _descriptor.Descriptor( + name='RespScanStart', + full_name='RespScanStart', + 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=152, + serialized_end=167, +) + + +_CMDSCANSTATUS = _descriptor.Descriptor( + name='CmdScanStatus', + full_name='CmdScanStatus', + 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=169, + serialized_end=184, +) + + +_RESPSCANSTATUS = _descriptor.Descriptor( + name='RespScanStatus', + full_name='RespScanStatus', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='scan_finished', full_name='RespScanStatus.scan_finished', index=0, + number=1, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='result_count', full_name='RespScanStatus.result_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=186, + serialized_end=247, +) + + +_CMDSCANRESULT = _descriptor.Descriptor( + name='CmdScanResult', + full_name='CmdScanResult', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='start_index', full_name='CmdScanResult.start_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='count', full_name='CmdScanResult.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=249, + serialized_end=300, +) + + +_WIFISCANRESULT = _descriptor.Descriptor( + name='WiFiScanResult', + full_name='WiFiScanResult', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='ssid', full_name='WiFiScanResult.ssid', index=0, + number=1, 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), + _descriptor.FieldDescriptor( + name='channel', full_name='WiFiScanResult.channel', 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), + _descriptor.FieldDescriptor( + name='rssi', full_name='WiFiScanResult.rssi', index=2, + number=3, type=5, cpp_type=1, 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='bssid', full_name='WiFiScanResult.bssid', index=3, + number=4, 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), + _descriptor.FieldDescriptor( + name='auth', full_name='WiFiScanResult.auth', index=4, + number=5, 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=302, + serialized_end=407, +) + + +_RESPSCANRESULT = _descriptor.Descriptor( + name='RespScanResult', + full_name='RespScanResult', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='entries', full_name='RespScanResult.entries', 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=409, + serialized_end=459, +) + + +_WIFISCANPAYLOAD = _descriptor.Descriptor( + name='WiFiScanPayload', + full_name='WiFiScanPayload', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='msg', full_name='WiFiScanPayload.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='status', full_name='WiFiScanPayload.status', index=1, + number=2, 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_scan_start', full_name='WiFiScanPayload.cmd_scan_start', index=2, + 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_scan_start', full_name='WiFiScanPayload.resp_scan_start', index=3, + 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_scan_status', full_name='WiFiScanPayload.cmd_scan_status', index=4, + 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_scan_status', full_name='WiFiScanPayload.resp_scan_status', index=5, + 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_scan_result', full_name='WiFiScanPayload.cmd_scan_result', index=6, + 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_scan_result', full_name='WiFiScanPayload.resp_scan_result', index=7, + 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='WiFiScanPayload.payload', + index=0, containing_type=None, fields=[]), + ], + serialized_start=462, + serialized_end=806, +) + +_WIFISCANRESULT.fields_by_name['auth'].enum_type = wifi__constants__pb2._WIFIAUTHMODE +_RESPSCANRESULT.fields_by_name['entries'].message_type = _WIFISCANRESULT +_WIFISCANPAYLOAD.fields_by_name['msg'].enum_type = _WIFISCANMSGTYPE +_WIFISCANPAYLOAD.fields_by_name['status'].enum_type = constants__pb2._STATUS +_WIFISCANPAYLOAD.fields_by_name['cmd_scan_start'].message_type = _CMDSCANSTART +_WIFISCANPAYLOAD.fields_by_name['resp_scan_start'].message_type = _RESPSCANSTART +_WIFISCANPAYLOAD.fields_by_name['cmd_scan_status'].message_type = _CMDSCANSTATUS +_WIFISCANPAYLOAD.fields_by_name['resp_scan_status'].message_type = _RESPSCANSTATUS +_WIFISCANPAYLOAD.fields_by_name['cmd_scan_result'].message_type = _CMDSCANRESULT +_WIFISCANPAYLOAD.fields_by_name['resp_scan_result'].message_type = _RESPSCANRESULT +_WIFISCANPAYLOAD.oneofs_by_name['payload'].fields.append( + _WIFISCANPAYLOAD.fields_by_name['cmd_scan_start']) +_WIFISCANPAYLOAD.fields_by_name['cmd_scan_start'].containing_oneof = _WIFISCANPAYLOAD.oneofs_by_name['payload'] +_WIFISCANPAYLOAD.oneofs_by_name['payload'].fields.append( + _WIFISCANPAYLOAD.fields_by_name['resp_scan_start']) +_WIFISCANPAYLOAD.fields_by_name['resp_scan_start'].containing_oneof = _WIFISCANPAYLOAD.oneofs_by_name['payload'] +_WIFISCANPAYLOAD.oneofs_by_name['payload'].fields.append( + _WIFISCANPAYLOAD.fields_by_name['cmd_scan_status']) +_WIFISCANPAYLOAD.fields_by_name['cmd_scan_status'].containing_oneof = _WIFISCANPAYLOAD.oneofs_by_name['payload'] +_WIFISCANPAYLOAD.oneofs_by_name['payload'].fields.append( + _WIFISCANPAYLOAD.fields_by_name['resp_scan_status']) +_WIFISCANPAYLOAD.fields_by_name['resp_scan_status'].containing_oneof = _WIFISCANPAYLOAD.oneofs_by_name['payload'] +_WIFISCANPAYLOAD.oneofs_by_name['payload'].fields.append( + _WIFISCANPAYLOAD.fields_by_name['cmd_scan_result']) +_WIFISCANPAYLOAD.fields_by_name['cmd_scan_result'].containing_oneof = _WIFISCANPAYLOAD.oneofs_by_name['payload'] +_WIFISCANPAYLOAD.oneofs_by_name['payload'].fields.append( + _WIFISCANPAYLOAD.fields_by_name['resp_scan_result']) +_WIFISCANPAYLOAD.fields_by_name['resp_scan_result'].containing_oneof = _WIFISCANPAYLOAD.oneofs_by_name['payload'] +DESCRIPTOR.message_types_by_name['CmdScanStart'] = _CMDSCANSTART +DESCRIPTOR.message_types_by_name['RespScanStart'] = _RESPSCANSTART +DESCRIPTOR.message_types_by_name['CmdScanStatus'] = _CMDSCANSTATUS +DESCRIPTOR.message_types_by_name['RespScanStatus'] = _RESPSCANSTATUS +DESCRIPTOR.message_types_by_name['CmdScanResult'] = _CMDSCANRESULT +DESCRIPTOR.message_types_by_name['WiFiScanResult'] = _WIFISCANRESULT +DESCRIPTOR.message_types_by_name['RespScanResult'] = _RESPSCANRESULT +DESCRIPTOR.message_types_by_name['WiFiScanPayload'] = _WIFISCANPAYLOAD +DESCRIPTOR.enum_types_by_name['WiFiScanMsgType'] = _WIFISCANMSGTYPE +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +CmdScanStart = _reflection.GeneratedProtocolMessageType('CmdScanStart', (_message.Message,), dict( + DESCRIPTOR = _CMDSCANSTART, + __module__ = 'wifi_scan_pb2' + # @@protoc_insertion_point(class_scope:CmdScanStart) + )) +_sym_db.RegisterMessage(CmdScanStart) + +RespScanStart = _reflection.GeneratedProtocolMessageType('RespScanStart', (_message.Message,), dict( + DESCRIPTOR = _RESPSCANSTART, + __module__ = 'wifi_scan_pb2' + # @@protoc_insertion_point(class_scope:RespScanStart) + )) +_sym_db.RegisterMessage(RespScanStart) + +CmdScanStatus = _reflection.GeneratedProtocolMessageType('CmdScanStatus', (_message.Message,), dict( + DESCRIPTOR = _CMDSCANSTATUS, + __module__ = 'wifi_scan_pb2' + # @@protoc_insertion_point(class_scope:CmdScanStatus) + )) +_sym_db.RegisterMessage(CmdScanStatus) + +RespScanStatus = _reflection.GeneratedProtocolMessageType('RespScanStatus', (_message.Message,), dict( + DESCRIPTOR = _RESPSCANSTATUS, + __module__ = 'wifi_scan_pb2' + # @@protoc_insertion_point(class_scope:RespScanStatus) + )) +_sym_db.RegisterMessage(RespScanStatus) + +CmdScanResult = _reflection.GeneratedProtocolMessageType('CmdScanResult', (_message.Message,), dict( + DESCRIPTOR = _CMDSCANRESULT, + __module__ = 'wifi_scan_pb2' + # @@protoc_insertion_point(class_scope:CmdScanResult) + )) +_sym_db.RegisterMessage(CmdScanResult) + +WiFiScanResult = _reflection.GeneratedProtocolMessageType('WiFiScanResult', (_message.Message,), dict( + DESCRIPTOR = _WIFISCANRESULT, + __module__ = 'wifi_scan_pb2' + # @@protoc_insertion_point(class_scope:WiFiScanResult) + )) +_sym_db.RegisterMessage(WiFiScanResult) + +RespScanResult = _reflection.GeneratedProtocolMessageType('RespScanResult', (_message.Message,), dict( + DESCRIPTOR = _RESPSCANRESULT, + __module__ = 'wifi_scan_pb2' + # @@protoc_insertion_point(class_scope:RespScanResult) + )) +_sym_db.RegisterMessage(RespScanResult) + +WiFiScanPayload = _reflection.GeneratedProtocolMessageType('WiFiScanPayload', (_message.Message,), dict( + DESCRIPTOR = _WIFISCANPAYLOAD, + __module__ = 'wifi_scan_pb2' + # @@protoc_insertion_point(class_scope:WiFiScanPayload) + )) +_sym_db.RegisterMessage(WiFiScanPayload) + + +# @@protoc_insertion_point(module_scope) diff --git a/components/wifi_provisioning/src/handlers.c b/components/wifi_provisioning/src/handlers.c index 0a57ef56cc..a53c9d6e43 100644 --- a/components/wifi_provisioning/src/handlers.c +++ b/components/wifi_provisioning/src/handlers.c @@ -21,6 +21,7 @@ #include #include "wifi_provisioning/wifi_config.h" +#include "wifi_provisioning/wifi_scan.h" #include "wifi_provisioning/manager.h" #include "wifi_provisioning_priv.h" @@ -134,13 +135,65 @@ static esp_err_t apply_config_handler(wifi_prov_ctx_t **ctx) return ret; } -wifi_prov_config_handlers_t get_wifi_prov_handlers(void) +esp_err_t get_wifi_prov_handlers(wifi_prov_config_handlers_t *ptr) { - wifi_prov_config_handlers_t wifi_prov_handlers = { - .get_status_handler = get_status_handler, - .set_config_handler = set_config_handler, - .apply_config_handler = apply_config_handler, - .ctx = NULL - }; - return wifi_prov_handlers; + if (!ptr) { + return ESP_ERR_INVALID_ARG; + } + ptr->get_status_handler = get_status_handler; + ptr->set_config_handler = set_config_handler; + ptr->apply_config_handler = apply_config_handler; + ptr->ctx = NULL; + return ESP_OK; +} + +/*************************************************************************/ + +static esp_err_t scan_start(bool blocking, bool passive, + uint8_t group_channels, uint32_t period_ms, + wifi_prov_scan_ctx_t **ctx) +{ + return wifi_prov_mgr_wifi_scan_start(blocking, passive, group_channels, period_ms); +} + +static esp_err_t scan_status(bool *scan_finished, + uint16_t *result_count, + wifi_prov_scan_ctx_t **ctx) +{ + *scan_finished = wifi_prov_mgr_wifi_scan_finished(); + *result_count = wifi_prov_mgr_wifi_scan_result_count(); + return ESP_OK; +} + +static esp_err_t scan_result(uint16_t result_index, + wifi_prov_scan_result_t *result, + wifi_prov_scan_ctx_t **ctx) +{ + const wifi_ap_record_t *record = wifi_prov_mgr_wifi_scan_result(result_index); + if (!record) { + return ESP_FAIL; + } + + /* Compile time check ensures memory safety in case SSID length in + * record / result structure definition changes in future */ + _Static_assert(sizeof(result->ssid) == sizeof(record->ssid), + "source and destination should be of same size"); + memcpy(result->ssid, record->ssid, sizeof(record->ssid)); + memcpy(result->bssid, record->bssid, sizeof(record->bssid)); + result->channel = record->primary; + result->rssi = record->rssi; + result->auth = record->authmode; + return ESP_OK; +} + +esp_err_t get_wifi_scan_handlers(wifi_prov_scan_handlers_t *ptr) +{ + if (!ptr) { + return ESP_ERR_INVALID_ARG; + } + ptr->scan_start = scan_start; + ptr->scan_status = scan_status; + ptr->scan_result = scan_result; + ptr->ctx = NULL; + return ESP_OK; } diff --git a/components/wifi_provisioning/src/manager.c b/components/wifi_provisioning/src/manager.c index 5f772a7dff..7959885399 100644 --- a/components/wifi_provisioning/src/manager.c +++ b/components/wifi_provisioning/src/manager.c @@ -13,6 +13,7 @@ // limitations under the License. #include +#include #include #include @@ -31,10 +32,16 @@ #include "wifi_provisioning_priv.h" -#define WIFI_PROV_MGR_VERSION "v1.0" +#define WIFI_PROV_MGR_VERSION "v1.1" +#define MAX_SCAN_RESULTS CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES + +#define ACQUIRE_LOCK(mux) assert(xSemaphoreTake(mux, portMAX_DELAY) == pdTRUE) +#define RELEASE_LOCK(mux) assert(xSemaphoreGive(mux) == pdTRUE) static const char *TAG = "wifi_prov_mgr"; +ESP_EVENT_DEFINE_BASE(WIFI_PROV_EVENT); + typedef enum { WIFI_PROV_STATE_IDLE, WIFI_PROV_STATE_STARTING, @@ -50,6 +57,9 @@ typedef enum { * the provisioning service */ struct wifi_prov_capabilities { + /* Security 0 is used */ + bool no_sec; + /* Proof of Possession is not required for establishing session */ bool no_pop; @@ -101,6 +111,9 @@ struct wifi_prov_mgr_ctx { /* Protocomm handlers for Wi-Fi configuration endpoint */ wifi_prov_config_handlers_t *wifi_prov_handlers; + /* Protocomm handlers for Wi-Fi scan endpoint */ + wifi_prov_scan_handlers_t *wifi_scan_handlers; + /* Count of used endpoint UUIDs */ unsigned int endpoint_uuid_used; @@ -113,6 +126,15 @@ struct wifi_prov_mgr_ctx { /* Delay after which resources will be cleaned up asynchronously * upon execution of wifi_prov_mgr_stop_provisioning() */ uint32_t cleanup_delay; + + /* Wi-Fi scan parameters and state variables */ + bool scanning; + uint8_t channels_per_group; + uint16_t curr_channel; + uint16_t ap_list_len[14]; // 14 entries corresponding to each channel + wifi_ap_record_t *ap_list[14]; + wifi_ap_record_t *ap_list_sorted[MAX_SCAN_RESULTS]; + wifi_scan_config_t scan_cfg; }; /* Mutex to lock/unlock access to provisioning singleton @@ -135,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); @@ -148,7 +170,7 @@ static void execute_event_cb(wifi_prov_cb_event_t event_id, void *event_data) /* Release the mutex before executing the callbacks. This is done so that * wifi_prov_mgr_event_handler() doesn't stay blocked for the duration */ - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); if (scheme_cb) { /* Call scheme specific event handler */ @@ -160,7 +182,13 @@ static void execute_event_cb(wifi_prov_cb_event_t event_id, void *event_data) app_cb(app_data, event_id, event_data); } - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + 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); } } @@ -177,7 +205,7 @@ esp_err_t wifi_prov_mgr_set_app_info(const char *label, const char *version, } esp_err_t ret = ESP_FAIL; - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); if (prov_ctx && prov_ctx->prov_state == WIFI_PROV_STATE_IDLE) { if (!prov_ctx->app_info_json) { @@ -198,12 +226,12 @@ esp_err_t wifi_prov_mgr_set_app_info(const char *label, const char *version, cJSON_AddItemToArray(capabilities_json, cJSON_CreateString(capabilities[i])); } } - + ret = ESP_OK; } else { ret = ESP_ERR_INVALID_STATE; } - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ret; } @@ -223,13 +251,22 @@ static cJSON* wifi_prov_get_info_json(void) /* Capabilities field */ cJSON_AddItemToObject(prov_info_json, "cap", prov_capabilities); - /* If Proof of Possession is not used, indicate in capabilities */ - if (prov_ctx->mgr_info.capabilities.no_pop) { + /* If Security / Proof of Possession is not used, indicate in capabilities */ + if (prov_ctx->mgr_info.capabilities.no_sec) { + cJSON_AddItemToArray(prov_capabilities, cJSON_CreateString("no_sec")); + } else if (prov_ctx->mgr_info.capabilities.no_pop) { cJSON_AddItemToArray(prov_capabilities, cJSON_CreateString("no_pop")); } + + /* Indicate capability for performing Wi-Fi scan */ + cJSON_AddItemToArray(prov_capabilities, cJSON_CreateString("wifi_scan")); 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; @@ -259,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"); @@ -287,12 +326,13 @@ static esp_err_t wifi_prov_mgr_start_service(const char *service_name, const cha } prov_ctx->wifi_prov_handlers = malloc(sizeof(wifi_prov_config_handlers_t)); - if (!prov_ctx->wifi_prov_handlers) { + ret = get_wifi_prov_handlers(prov_ctx->wifi_prov_handlers); + if (ret != ESP_OK) { ESP_LOGD(TAG, "Failed to allocate memory for provisioning handlers"); scheme->prov_stop(prov_ctx->pc); protocomm_delete(prov_ctx->pc); + return ESP_ERR_NO_MEM; } - *prov_ctx->wifi_prov_handlers = get_wifi_prov_handlers(); /* Add protocomm endpoint for Wi-Fi station configuration */ ret = protocomm_add_endpoint(prov_ctx->pc, "prov-config", @@ -306,6 +346,54 @@ static esp_err_t wifi_prov_mgr_start_service(const char *service_name, const cha return ret; } + prov_ctx->wifi_scan_handlers = malloc(sizeof(wifi_prov_scan_handlers_t)); + ret = get_wifi_scan_handlers(prov_ctx->wifi_scan_handlers); + if (ret != ESP_OK) { + ESP_LOGD(TAG, "Failed to allocate memory for Wi-Fi scan handlers"); + free(prov_ctx->wifi_prov_handlers); + scheme->prov_stop(prov_ctx->pc); + protocomm_delete(prov_ctx->pc); + return ESP_ERR_NO_MEM; + } + + /* Add endpoint for scanning Wi-Fi APs and sending scan list */ + ret = protocomm_add_endpoint(prov_ctx->pc, "prov-scan", + wifi_prov_scan_handler, + prov_ctx->wifi_scan_handlers); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to set Wi-Fi scan endpoint"); + 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; + } + + /* 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; @@ -320,7 +408,7 @@ esp_err_t wifi_prov_mgr_endpoint_create(const char *ep_name) esp_err_t err = ESP_FAIL; - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); if (prov_ctx && prov_ctx->prov_state == WIFI_PROV_STATE_IDLE) { err = prov_ctx->mgr_config.scheme.set_config_endpoint( @@ -332,7 +420,7 @@ esp_err_t wifi_prov_mgr_endpoint_create(const char *ep_name) } else { prov_ctx->endpoint_uuid_used++; } - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return err; } @@ -345,13 +433,13 @@ esp_err_t wifi_prov_mgr_endpoint_register(const char *ep_name, protocomm_req_han esp_err_t err = ESP_FAIL; - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); if (prov_ctx && prov_ctx->prov_state > WIFI_PROV_STATE_STARTING && prov_ctx->prov_state < WIFI_PROV_STATE_STOPPING) { err = protocomm_add_endpoint(prov_ctx->pc, ep_name, handler, user_ctx); } - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); if (err != ESP_OK) { ESP_LOGE(TAG, "Failed to register handler for endpoint"); @@ -366,13 +454,13 @@ void wifi_prov_mgr_endpoint_unregister(const char *ep_name) return; } - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); if (prov_ctx && prov_ctx->prov_state > WIFI_PROV_STATE_STARTING && prov_ctx->prov_state < WIFI_PROV_STATE_STOPPING) { protocomm_remove_endpoint(prov_ctx->pc, ep_name); } - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); } static void prov_stop_task(void *arg) @@ -403,15 +491,19 @@ static void prov_stop_task(void *arg) free(prov_ctx->wifi_prov_handlers); prov_ctx->wifi_prov_handlers = NULL; + free(prov_ctx->wifi_scan_handlers->ctx); + free(prov_ctx->wifi_scan_handlers); + prov_ctx->wifi_scan_handlers = NULL; + /* Switch device to Wi-Fi STA mode irrespective of * whether provisioning was completed or not */ esp_wifi_set_mode(WIFI_MODE_STA); ESP_LOGI(TAG, "Provisioning stopped"); if (is_this_a_task) { - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); prov_ctx->prov_state = WIFI_PROV_STATE_IDLE; - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); ESP_LOGD(TAG, "execute_event_cb : %d", WIFI_PROV_END); if (scheme_cb) { @@ -420,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); } } @@ -445,18 +541,18 @@ static bool wifi_prov_mgr_stop_service(bool blocking) while (prov_ctx && ( prov_ctx->prov_state == WIFI_PROV_STATE_STARTING || prov_ctx->prov_state == WIFI_PROV_STATE_STOPPING)) { - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); vTaskDelay(100 / portTICK_PERIOD_MS); - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); } } else { /* Wait for any ongoing call to wifi_prov_mgr_start_service() * from another thread to finish */ while (prov_ctx && prov_ctx->prov_state == WIFI_PROV_STATE_STARTING) { - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); vTaskDelay(100 / portTICK_PERIOD_MS); - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); } if (prov_ctx && prov_ctx->prov_state == WIFI_PROV_STATE_STOPPING) { @@ -486,12 +582,28 @@ static bool wifi_prov_mgr_stop_service(bool blocking) prov_ctx->pop.data = NULL; } + /* Delete all scan results */ + for (uint16_t channel = 0; channel < 14; channel++) { + free(prov_ctx->ap_list[channel]); + prov_ctx->ap_list[channel] = NULL; + } + prov_ctx->scanning = false; + for (uint8_t i = 0; i < MAX_SCAN_RESULTS; i++) { + 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 */ - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); prov_stop_task((void *)0); - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); prov_ctx->prov_state = WIFI_PROV_STATE_IDLE; } else { /* Launch cleanup task to perform the cleanup asynchronously. @@ -521,16 +633,17 @@ esp_err_t wifi_prov_mgr_disable_auto_stop(uint32_t cleanup_delay) } esp_err_t ret = ESP_FAIL; - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); if (prov_ctx && prov_ctx->prov_state == WIFI_PROV_STATE_IDLE) { prov_ctx->mgr_info.capabilities.no_auto_stop = true; prov_ctx->cleanup_delay = cleanup_delay; + ret = ESP_OK; } else { ret = ESP_ERR_INVALID_STATE; } - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ret; } @@ -542,57 +655,182 @@ esp_err_t wifi_prov_mgr_done(void) return ESP_ERR_INVALID_STATE; } - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); - /* Stop provisioning if auto stop is not disabled */ + bool auto_stop_enabled = false; + ACQUIRE_LOCK(prov_ctx_lock); if (prov_ctx && !prov_ctx->mgr_info.capabilities.no_auto_stop) { + auto_stop_enabled = true; + } + RELEASE_LOCK(prov_ctx_lock); + + /* Stop provisioning if auto stop is enabled */ + if (auto_stop_enabled) { wifi_prov_mgr_stop_provisioning(); } - xSemaphoreGiveRecursive(prov_ctx_lock); return ESP_OK; } -/* Event handler for starting/stopping provisioning. +static esp_err_t update_wifi_scan_results(void) +{ + if (!prov_ctx->scanning) { + return ESP_ERR_INVALID_STATE; + } + ESP_LOGD(TAG, "Scan finished"); + + esp_err_t ret = ESP_FAIL; + uint16_t count = 0; + uint16_t curr_channel = prov_ctx->curr_channel; + + if (prov_ctx->ap_list[curr_channel]) { + free(prov_ctx->ap_list[curr_channel]); + prov_ctx->ap_list[curr_channel] = NULL; + prov_ctx->ap_list_len[curr_channel] = 0; + } + + if (esp_wifi_scan_get_ap_num(&count) != ESP_OK) { + ESP_LOGE(TAG, "Failed to get count of scanned APs"); + goto exit; + } + + if (!count) { + ESP_LOGD(TAG, "Scan result empty"); + ret = ESP_OK; + goto exit; + } + + prov_ctx->ap_list[curr_channel] = (wifi_ap_record_t *) calloc(count, sizeof(wifi_ap_record_t)); + if (!prov_ctx->ap_list[curr_channel]) { + ESP_LOGE(TAG, "Failed to allocate memory for AP list"); + goto exit; + } + if (esp_wifi_scan_get_ap_records(&count, prov_ctx->ap_list[curr_channel]) != ESP_OK) { + ESP_LOGE(TAG, "Failed to get scanned AP records"); + goto exit; + } + prov_ctx->ap_list_len[curr_channel] = count; + + if (prov_ctx->channels_per_group) { + ESP_LOGD(TAG, "Scan results for channel %d :", curr_channel); + } else { + ESP_LOGD(TAG, "Scan results :"); + } + ESP_LOGD(TAG, "\tS.N. %-32s %-12s %s %s", "SSID", "BSSID", "RSSI", "AUTH"); + for (uint8_t i = 0; i < prov_ctx->ap_list_len[curr_channel]; i++) { + ESP_LOGD(TAG, "\t[%2d] %-32s %02x%02x%02x%02x%02x%02x %4d %4d", i, + prov_ctx->ap_list[curr_channel][i].ssid, + prov_ctx->ap_list[curr_channel][i].bssid[0], + prov_ctx->ap_list[curr_channel][i].bssid[1], + prov_ctx->ap_list[curr_channel][i].bssid[2], + prov_ctx->ap_list[curr_channel][i].bssid[3], + prov_ctx->ap_list[curr_channel][i].bssid[4], + prov_ctx->ap_list[curr_channel][i].bssid[5], + prov_ctx->ap_list[curr_channel][i].rssi, + prov_ctx->ap_list[curr_channel][i].authmode); + } + + /* Store results in sorted list */ + { + int rc = MIN(count, MAX_SCAN_RESULTS); + int is = MAX_SCAN_RESULTS - rc - 1; + while (rc > 0 && is >= 0) { + if (prov_ctx->ap_list_sorted[is]) { + if (prov_ctx->ap_list_sorted[is]->rssi > prov_ctx->ap_list[curr_channel][rc - 1].rssi) { + prov_ctx->ap_list_sorted[is + rc] = &prov_ctx->ap_list[curr_channel][rc - 1]; + rc--; + continue; + } + prov_ctx->ap_list_sorted[is + rc] = prov_ctx->ap_list_sorted[is]; + } + is--; + } + while (rc > 0) { + prov_ctx->ap_list_sorted[rc - 1] = &prov_ctx->ap_list[curr_channel][rc - 1]; + rc--; + } + } + + ret = ESP_OK; + exit: + + if (!prov_ctx->channels_per_group) { + /* All channel scan was performed + * so nothing more to do */ + prov_ctx->scanning = false; + goto final; + } + + curr_channel = prov_ctx->curr_channel = (prov_ctx->curr_channel + 1) % 14; + if (ret != ESP_OK || curr_channel == 0) { + prov_ctx->scanning = false; + goto final; + } + + if ((curr_channel % prov_ctx->channels_per_group) == 0) { + vTaskDelay(120 / portTICK_PERIOD_MS); + } + + ESP_LOGD(TAG, "Scan starting on channel %u...", curr_channel); + prov_ctx->scan_cfg.channel = curr_channel; + ret = esp_wifi_scan_start(&prov_ctx->scan_cfg, false); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to start scan"); + prov_ctx->scanning = false; + goto final; + } + ESP_LOGD(TAG, "Scan started"); + + final: + + return ret; +} + +/* 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; } - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); /* If pointer to provisioning application data is NULL * then provisioning manager is not running, therefore * return with error to allow the global handler to act */ if (!prov_ctx) { - xSemaphoreGiveRecursive(prov_ctx_lock); - return ESP_ERR_INVALID_STATE; + RELEASE_LOCK(prov_ctx_lock); + return; + } + + /* If scan completed then update scan result */ + if (prov_ctx->prov_state == WIFI_PROV_STATE_STARTED && + event_base == WIFI_EVENT && + event_id == WIFI_EVENT_SCAN_DONE) { + update_wifi_scan_results(); } /* Only handle events when credential is received and * Wi-Fi STA is yet to complete trying the connection */ if (prov_ctx->prov_state != WIFI_PROV_STATE_CRED_RECV) { - xSemaphoreGiveRecursive(prov_ctx_lock); - return ESP_OK; + RELEASE_LOCK(prov_ctx_lock); + 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; @@ -605,28 +843,27 @@ 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_ASSOC_EXPIRE: 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: @@ -642,20 +879,150 @@ 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; } - xSemaphoreGiveRecursive(prov_ctx_lock); - return ret; + RELEASE_LOCK(prov_ctx_lock); +} + +esp_err_t wifi_prov_mgr_wifi_scan_start(bool blocking, bool passive, + uint8_t group_channels, uint32_t period_ms) +{ + if (!prov_ctx_lock) { + ESP_LOGE(TAG, "Provisioning manager not initialized"); + return ESP_ERR_INVALID_STATE; + } + ACQUIRE_LOCK(prov_ctx_lock); + + if (!prov_ctx) { + ESP_LOGE(TAG, "Provisioning manager not initialized"); + RELEASE_LOCK(prov_ctx_lock); + return ESP_ERR_INVALID_STATE; + } + + if (prov_ctx->scanning) { + ESP_LOGD(TAG, "Scan already running"); + RELEASE_LOCK(prov_ctx_lock); + return ESP_OK; + } + + /* Clear sorted list for new entries */ + for (uint8_t i = 0; i < MAX_SCAN_RESULTS; i++) { + prov_ctx->ap_list_sorted[i] = NULL; + } + + if (passive) { + prov_ctx->scan_cfg.scan_type = WIFI_SCAN_TYPE_PASSIVE; + prov_ctx->scan_cfg.scan_time.passive = period_ms; + } else { + prov_ctx->scan_cfg.scan_type = WIFI_SCAN_TYPE_ACTIVE; + prov_ctx->scan_cfg.scan_time.active.min = period_ms; + prov_ctx->scan_cfg.scan_time.active.max = period_ms; + } + prov_ctx->channels_per_group = group_channels; + + if (prov_ctx->channels_per_group) { + ESP_LOGD(TAG, "Scan starting on channel 1..."); + prov_ctx->scan_cfg.channel = 1; + } else { + ESP_LOGD(TAG, "Scan starting..."); + prov_ctx->scan_cfg.channel = 0; + } + + if (esp_wifi_scan_start(&prov_ctx->scan_cfg, false) != ESP_OK) { + ESP_LOGE(TAG, "Failed to start scan"); + return ESP_FAIL; + } + + ESP_LOGD(TAG, "Scan started"); + prov_ctx->scanning = true; + prov_ctx->curr_channel = prov_ctx->scan_cfg.channel; + RELEASE_LOCK(prov_ctx_lock); + + /* If scan is to be non-blocking, return immediately */ + if (!blocking) { + return ESP_OK; + } + + /* Loop till scan is complete */ + bool scanning = true; + while (scanning) { + ACQUIRE_LOCK(prov_ctx_lock); + scanning = (prov_ctx && prov_ctx->scanning); + RELEASE_LOCK(prov_ctx_lock); + + /* 120ms delay is sufficient for Wi-Fi beacons to be sent */ + vTaskDelay(120 / portTICK_PERIOD_MS); + } + return ESP_OK; +} + +bool wifi_prov_mgr_wifi_scan_finished(void) +{ + bool scan_finished = true; + if (!prov_ctx_lock) { + ESP_LOGE(TAG, "Provisioning manager not initialized"); + return scan_finished; + } + + ACQUIRE_LOCK(prov_ctx_lock); + if (!prov_ctx) { + ESP_LOGE(TAG, "Provisioning manager not initialized"); + RELEASE_LOCK(prov_ctx_lock); + return scan_finished; + } + + scan_finished = !prov_ctx->scanning; + RELEASE_LOCK(prov_ctx_lock); + return scan_finished; +} + +uint16_t wifi_prov_mgr_wifi_scan_result_count(void) +{ + uint16_t rval = 0; + if (!prov_ctx_lock) { + ESP_LOGE(TAG, "Provisioning manager not initialized"); + return rval; + } + + ACQUIRE_LOCK(prov_ctx_lock); + if (!prov_ctx) { + ESP_LOGE(TAG, "Provisioning manager not initialized"); + RELEASE_LOCK(prov_ctx_lock); + return rval; + } + + while (rval < MAX_SCAN_RESULTS) { + if (!prov_ctx->ap_list_sorted[rval]) { + break; + } + rval++; + } + RELEASE_LOCK(prov_ctx_lock); + return rval; +} + +const wifi_ap_record_t *wifi_prov_mgr_wifi_scan_result(uint16_t index) +{ + const wifi_ap_record_t *rval = NULL; + if (!prov_ctx_lock) { + ESP_LOGE(TAG, "Provisioning manager not initialized"); + return rval; + } + + ACQUIRE_LOCK(prov_ctx_lock); + if (!prov_ctx) { + ESP_LOGE(TAG, "Provisioning manager not initialized"); + RELEASE_LOCK(prov_ctx_lock); + return rval; + } + + if (index < MAX_SCAN_RESULTS) { + rval = prov_ctx->ap_list_sorted[index]; + } + RELEASE_LOCK(prov_ctx_lock); + return rval; } esp_err_t wifi_prov_mgr_get_wifi_state(wifi_prov_sta_state_t *state) @@ -665,14 +1032,14 @@ esp_err_t wifi_prov_mgr_get_wifi_state(wifi_prov_sta_state_t *state) return ESP_ERR_INVALID_STATE; } - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); if (prov_ctx == NULL || state == NULL) { - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_FAIL; } *state = prov_ctx->wifi_state; - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_OK; } @@ -683,19 +1050,19 @@ esp_err_t wifi_prov_mgr_get_wifi_disconnect_reason(wifi_prov_sta_fail_reason_t * return ESP_ERR_INVALID_STATE; } - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); if (prov_ctx == NULL || reason == NULL) { - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_FAIL; } if (prov_ctx->wifi_state != WIFI_PROV_STA_DISCONNECTED) { - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_FAIL; } *reason = prov_ctx->wifi_disconnect_reason; - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_OK; } @@ -745,15 +1112,15 @@ esp_err_t wifi_prov_mgr_configure_sta(wifi_config_t *wifi_cfg) return ESP_ERR_INVALID_STATE; } - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); if (!prov_ctx) { ESP_LOGE(TAG, "Invalid state of Provisioning app"); - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_FAIL; } if (prov_ctx->prov_state >= WIFI_PROV_STATE_CRED_RECV) { ESP_LOGE(TAG, "Wi-Fi credentials already received by provisioning app"); - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_FAIL; } debug_print_wifi_credentials(wifi_cfg->sta, "Received"); @@ -761,7 +1128,7 @@ esp_err_t wifi_prov_mgr_configure_sta(wifi_config_t *wifi_cfg) /* Configure Wi-Fi as both AP and/or Station */ if (esp_wifi_set_mode(prov_ctx->mgr_config.scheme.wifi_mode) != ESP_OK) { ESP_LOGE(TAG, "Failed to set Wi-Fi mode"); - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_FAIL; } @@ -774,26 +1141,20 @@ esp_err_t wifi_prov_mgr_configure_sta(wifi_config_t *wifi_cfg) * provided credentials on NVS */ if (esp_wifi_set_storage(WIFI_STORAGE_FLASH) != ESP_OK) { ESP_LOGE(TAG, "Failed to set storage Wi-Fi"); - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_FAIL; } /* Configure Wi-Fi station with host credentials * provided during provisioning */ if (esp_wifi_set_config(ESP_IF_WIFI_STA, wifi_cfg) != ESP_OK) { ESP_LOGE(TAG, "Failed to set Wi-Fi configuration"); - xSemaphoreGiveRecursive(prov_ctx_lock); - return ESP_FAIL; - } - /* (Re)Start Wi-Fi */ - if (esp_wifi_start() != ESP_OK) { - ESP_LOGE(TAG, "Failed to set Wi-Fi configuration"); - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_FAIL; } /* Connect to AP */ if (esp_wifi_connect() != ESP_OK) { ESP_LOGE(TAG, "Failed to connect Wi-Fi"); - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_FAIL; } /* This delay allows channel change to complete */ @@ -803,8 +1164,8 @@ 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); - xSemaphoreGiveRecursive(prov_ctx_lock); + execute_event_cb(WIFI_PROV_CRED_RECV, (void *)&wifi_cfg->sta, sizeof(wifi_cfg->sta)); + RELEASE_LOCK(prov_ctx_lock); return ESP_OK; } @@ -817,7 +1178,7 @@ esp_err_t wifi_prov_mgr_init(wifi_prov_mgr_config_t config) * other thread is trying to take this mutex while it is being * deleted from another thread then the reference may become * invalid and cause exception */ - prov_ctx_lock = xSemaphoreCreateRecursiveMutex(); + prov_ctx_lock = xSemaphoreCreateMutex(); if (!prov_ctx_lock) { ESP_LOGE(TAG, "Failed to create mutex"); return ESP_ERR_NO_MEM; @@ -840,10 +1201,10 @@ esp_err_t wifi_prov_mgr_init(wifi_prov_mgr_config_t config) } } - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); if (prov_ctx) { ESP_LOGE(TAG, "Provisioning manager already initialized"); - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_ERR_INVALID_STATE; } @@ -851,7 +1212,7 @@ esp_err_t wifi_prov_mgr_init(wifi_prov_mgr_config_t config) prov_ctx = (struct wifi_prov_mgr_ctx *) calloc(1, sizeof(struct wifi_prov_mgr_ctx)); if (!prov_ctx) { ESP_LOGE(TAG, "Error allocating memory for singleton instance"); - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_ERR_NO_MEM; } @@ -869,6 +1230,12 @@ esp_err_t wifi_prov_mgr_init(wifi_prov_mgr_config_t config) goto exit; } + ret = scheme->set_config_endpoint(prov_ctx->prov_scheme_config, "prov-scan", 0xFF50); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "failed to configure Wi-Fi scanning endpoint"); + goto exit; + } + ret = scheme->set_config_endpoint(prov_ctx->prov_scheme_config, "prov-session", 0xFF51); if (ret != ESP_OK) { ESP_LOGE(TAG, "failed to configure security endpoint"); @@ -902,9 +1269,9 @@ exit: } free(prov_ctx); } else { - execute_event_cb(WIFI_PROV_INIT, NULL); + execute_event_cb(WIFI_PROV_INIT, NULL, 0); } - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ret; } @@ -916,16 +1283,16 @@ void wifi_prov_mgr_wait(void) } while (1) { - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); if (prov_ctx && prov_ctx->prov_state != WIFI_PROV_STATE_IDLE) { - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); vTaskDelay(1000 / portTICK_PERIOD_MS); continue; } break; } - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); } void wifi_prov_mgr_deinit(void) @@ -935,7 +1302,7 @@ void wifi_prov_mgr_deinit(void) return; } - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); /* This will do one of these: * 1) if found running, stop the provisioning service (returns true) @@ -949,7 +1316,7 @@ void wifi_prov_mgr_deinit(void) * was not even initialized */ if (!service_was_running && !prov_ctx) { ESP_LOGD(TAG, "Manager already de-initialized"); - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return; } @@ -971,7 +1338,7 @@ void wifi_prov_mgr_deinit(void) /* Free manager context */ free(prov_ctx); prov_ctx = NULL; - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); /* If a running service was also stopped during de-initialization * then WIFI_PROV_END event also needs to be emitted before deinit */ @@ -983,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); @@ -994,6 +1364,9 @@ void wifi_prov_mgr_deinit(void) if (app_cb) { app_cb(app_data, WIFI_PROV_DEINIT, NULL); } + 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, @@ -1004,16 +1377,16 @@ esp_err_t wifi_prov_mgr_start_provisioning(wifi_prov_security_t security, const return ESP_ERR_INVALID_STATE; } - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); if (!prov_ctx) { ESP_LOGE(TAG, "Provisioning manager not initialized"); - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_ERR_INVALID_STATE; } if (prov_ctx->prov_state != WIFI_PROV_STATE_IDLE) { ESP_LOGE(TAG, "Provisioning service already started"); - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_ERR_INVALID_STATE; } @@ -1023,6 +1396,21 @@ esp_err_t wifi_prov_mgr_start_provisioning(wifi_prov_security_t security, const * thread doesn't interfere with this process */ prov_ctx->prov_state = WIFI_PROV_STATE_STARTING; + /* Start Wi-Fi in Station Mode. + * This is necessary for scanning to work */ + esp_err_t err = esp_wifi_set_mode(WIFI_MODE_STA); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to set Wi-Fi mode to STA"); + RELEASE_LOCK(prov_ctx_lock); + return err; + } + err = esp_wifi_start(); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to start Wi-Fi"); + RELEASE_LOCK(prov_ctx_lock); + return err; + } + /* Change Wi-Fi storage to RAM temporarily and erase any old * credentials (i.e. without erasing the copy on NVS). Also * call disconnect to make sure device doesn't remain connected @@ -1030,12 +1418,29 @@ esp_err_t wifi_prov_mgr_start_provisioning(wifi_prov_security_t security, const wifi_config_t wifi_cfg_empty, wifi_cfg_old; memset(&wifi_cfg_empty, 0, sizeof(wifi_config_t)); esp_wifi_get_config(ESP_IF_WIFI_STA, &wifi_cfg_old); - esp_wifi_set_storage(WIFI_STORAGE_RAM); + err = esp_wifi_set_storage(WIFI_STORAGE_RAM); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to set Wi-Fi storage to RAM"); + RELEASE_LOCK(prov_ctx_lock); + return err; + } esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_cfg_empty); - esp_wifi_disconnect(); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to set empty Wi-Fi credentials"); + RELEASE_LOCK(prov_ctx_lock); + return err; + } + err = esp_wifi_disconnect(); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to disconnect"); + RELEASE_LOCK(prov_ctx_lock); + return err; + } /* Initialize app data */ - if (pop) { + if (security == WIFI_PROV_SECURITY_0) { + prov_ctx->mgr_info.capabilities.no_sec = true; + } else if (pop) { prov_ctx->pop.len = strlen(pop); prov_ctx->pop.data = malloc(prov_ctx->pop.len); if (!prov_ctx->pop.data) { @@ -1070,7 +1475,7 @@ esp_err_t wifi_prov_mgr_start_provisioning(wifi_prov_security_t security, const * which may trigger system level events. Hence, releasing the context lock will * ensure that wifi_prov_mgr_event_handler() doesn't block the global event_loop * handler when system events need to be handled */ - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); /* Start provisioning service */ ret = wifi_prov_mgr_start_service(service_name, service_key); @@ -1078,11 +1483,11 @@ esp_err_t wifi_prov_mgr_start_provisioning(wifi_prov_security_t security, const esp_timer_delete(prov_ctx->timer); free((void *)prov_ctx->pop.data); } - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); 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; } @@ -1092,7 +1497,7 @@ err: esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_cfg_old); exit: - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ret; } @@ -1103,7 +1508,7 @@ void wifi_prov_mgr_stop_provisioning(void) return; } - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); /* Launches task for stopping the provisioning service. This will do one of these: * 1) start a task for stopping the provisioning service (returns true) @@ -1113,5 +1518,5 @@ void wifi_prov_mgr_stop_provisioning(void) */ wifi_prov_mgr_stop_service(0); - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); } diff --git a/components/wifi_provisioning/src/scheme_softap.c b/components/wifi_provisioning/src/scheme_softap.c index 270ef1f587..84262e9375 100644 --- a/components/wifi_provisioning/src/scheme_softap.c +++ b/components/wifi_provisioning/src/scheme_softap.c @@ -54,8 +54,8 @@ static esp_err_t start_wifi_ap(const char *ssid, const char *pass) wifi_config.ap.authmode = WIFI_AUTH_WPA_WPA2_PSK; } - /* Start Wi-Fi in AP mode with configuration built above */ - esp_err_t err = esp_wifi_set_mode(WIFI_MODE_AP); + /* Run Wi-Fi in AP + STA mode with configuration built above */ + esp_err_t err = esp_wifi_set_mode(WIFI_MODE_APSTA); if (err != ESP_OK) { ESP_LOGE(TAG, "Failed to set Wi-Fi mode : %d", err); return err; @@ -65,12 +65,7 @@ static esp_err_t start_wifi_ap(const char *ssid, const char *pass) ESP_LOGE(TAG, "Failed to set Wi-Fi config : %d", err); return err; } - err = esp_wifi_start(); - if (err != ESP_OK) { - ESP_LOGE(TAG, "Failed to start Wi-Fi : %d", err); - return err; - } - ESP_LOGD(TAG, "Wi-Fi SoftAP started"); + return ESP_OK; } 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; diff --git a/components/wifi_provisioning/src/wifi_provisioning_priv.h b/components/wifi_provisioning/src/wifi_provisioning_priv.h index e93c0859d9..756e82f452 100644 --- a/components/wifi_provisioning/src/wifi_provisioning_priv.h +++ b/components/wifi_provisioning/src/wifi_provisioning_priv.h @@ -21,6 +21,7 @@ #include "wifi_provisioning/manager.h" #include "wifi_provisioning/wifi_config.h" +#include "wifi_provisioning/wifi_scan.h" /** * @brief Notify manager that provisioning is done @@ -36,9 +37,68 @@ */ esp_err_t wifi_prov_mgr_done(void); +/** + * @brief Start Wi-Fi AP Scan + * + * @param[in] blocking Set true to return only after scanning is complete + * @param[in] passive Set true to perform passive scan instead of default active scan + * @param[in] group_channels Number of channels to scan in one go + * (set to 0 for scanning all channels in one go) + * @param[in] period_ms Scan time (in milli-seconds) on each channel + * + * @return + * - ESP_OK : Successfully started Wi-Fi scanning + * - ESP_FAIL : Provisioning app not running + */ +esp_err_t wifi_prov_mgr_wifi_scan_start(bool blocking, bool passive, + uint8_t group_channels, + uint32_t period_ms); + +/** + * @brief Use to query the state of Wi-Fi scan + * + * @return + * - true : Scan finished + * - false : Scan running + */ +bool wifi_prov_mgr_wifi_scan_finished(void); + +/** + * @brief Get the count of results in the scan list + * + * @return + * - count : Number of Wi-Fi Access Points detected while scanning + */ +uint16_t wifi_prov_mgr_wifi_scan_result_count(void); + +/** + * @brief Get AP record for a particular index in the scan list result + * + * @param[out] index Index of the result to fetch + * + * @return + * - result : Pointer to Access Point record + */ +const wifi_ap_record_t *wifi_prov_mgr_wifi_scan_result(uint16_t index); + /** * @brief Get protocomm handlers for wifi_config provisioning endpoint * - * @return wifi_prov_config_handlers_t structure + * @param[out] ptr pointer to structure to be set + * + * @return + * - ESP_OK : success + * - ESP_ERR_INVALID_ARG : null argument */ -wifi_prov_config_handlers_t get_wifi_prov_handlers(void); +esp_err_t get_wifi_prov_handlers(wifi_prov_config_handlers_t *ptr); + +/** + * @brief Get protocomm handlers for wifi_scan provisioning endpoint + * + * @param[out] ptr pointer to structure to be set + * + * @return + * - ESP_OK : success + * - ESP_ERR_INVALID_ARG : null argument + */ +esp_err_t get_wifi_scan_handlers(wifi_prov_scan_handlers_t *ptr); diff --git a/components/wifi_provisioning/src/wifi_scan.c b/components/wifi_provisioning/src/wifi_scan.c new file mode 100644 index 0000000000..8ab3980dc1 --- /dev/null +++ b/components/wifi_provisioning/src/wifi_scan.c @@ -0,0 +1,297 @@ +// 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 "wifi_scan.pb-c.h" + +#include + +static const char *TAG = "proto_wifi_scan"; + +typedef struct wifi_prov_scan_cmd { + int cmd_num; + esp_err_t (*command_handler)(WiFiScanPayload *req, + WiFiScanPayload *resp, void *priv_data); +} wifi_prov_scan_cmd_t; + +static esp_err_t cmd_scan_start_handler(WiFiScanPayload *req, + WiFiScanPayload *resp, + void *priv_data); + +static esp_err_t cmd_scan_status_handler(WiFiScanPayload *req, + WiFiScanPayload *resp, + void *priv_data); + +static esp_err_t cmd_scan_result_handler(WiFiScanPayload *req, + WiFiScanPayload *resp, + void *priv_data); + +static wifi_prov_scan_cmd_t cmd_table[] = { + { + .cmd_num = WI_FI_SCAN_MSG_TYPE__TypeCmdScanStart, + .command_handler = cmd_scan_start_handler + }, + { + .cmd_num = WI_FI_SCAN_MSG_TYPE__TypeCmdScanStatus, + .command_handler = cmd_scan_status_handler + }, + { + .cmd_num = WI_FI_SCAN_MSG_TYPE__TypeCmdScanResult, + .command_handler = cmd_scan_result_handler + } +}; + +static esp_err_t cmd_scan_start_handler(WiFiScanPayload *req, + WiFiScanPayload *resp, void *priv_data) +{ + wifi_prov_scan_handlers_t *h = (wifi_prov_scan_handlers_t *) priv_data; + if (!h) { + ESP_LOGE(TAG, "Command invoked without handlers"); + return ESP_ERR_INVALID_STATE; + } + + RespScanStart *resp_payload = (RespScanStart *) malloc(sizeof(RespScanStart)); + if (!resp_payload) { + ESP_LOGE(TAG, "Error allocating memory"); + return ESP_ERR_NO_MEM; + } + + resp_scan_start__init(resp_payload); + resp->status = (h->scan_start(req->cmd_scan_start->blocking, + req->cmd_scan_start->passive, + req->cmd_scan_start->group_channels, + req->cmd_scan_start->period_ms, + &h->ctx) == ESP_OK ? + STATUS__Success : STATUS__InternalError); + resp->payload_case = WI_FI_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_START; + resp->resp_scan_start = resp_payload; + return ESP_OK; +} + +static esp_err_t cmd_scan_status_handler(WiFiScanPayload *req, + WiFiScanPayload *resp, void *priv_data) +{ + bool scan_finished = false; + uint16_t result_count = 0; + + wifi_prov_scan_handlers_t *h = (wifi_prov_scan_handlers_t *) priv_data; + if (!h) { + ESP_LOGE(TAG, "Command invoked without handlers"); + return ESP_ERR_INVALID_STATE; + } + + RespScanStatus *resp_payload = (RespScanStatus *) malloc(sizeof(RespScanStatus)); + if (!resp_payload) { + ESP_LOGE(TAG, "Error allocating memory"); + return ESP_ERR_NO_MEM; + } + + resp_scan_status__init(resp_payload); + resp->status = (h->scan_status(&scan_finished, &result_count, &h->ctx) == ESP_OK ? + STATUS__Success : STATUS__InternalError); + resp_payload->scan_finished = scan_finished; + resp_payload->result_count = result_count; + resp->payload_case = WI_FI_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_STATUS; + resp->resp_scan_status = resp_payload; + return ESP_OK; +} + +static esp_err_t cmd_scan_result_handler(WiFiScanPayload *req, + WiFiScanPayload *resp, void *priv_data) +{ + esp_err_t err; + wifi_prov_scan_result_t scan_result = {{0}, {0}, 0, 0, 0}; + WiFiScanResult **results = NULL; + wifi_prov_scan_handlers_t *h = (wifi_prov_scan_handlers_t *) priv_data; + if (!h) { + ESP_LOGE(TAG, "Command invoked without handlers"); + return ESP_ERR_INVALID_STATE; + } + + RespScanResult *resp_payload = (RespScanResult *) malloc(sizeof(RespScanResult)); + if (!resp_payload) { + ESP_LOGE(TAG, "Error allocating memory"); + return ESP_ERR_NO_MEM; + } + resp_scan_result__init(resp_payload); + + resp->status = STATUS__Success; + resp->payload_case = WI_FI_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_RESULT; + resp->resp_scan_result = resp_payload; + + results = (WiFiScanResult **) calloc(req->cmd_scan_result->count, + sizeof(WiFiScanResult *)); + if (!results) { + ESP_LOGE(TAG, "Failed to allocate memory for results array"); + return ESP_ERR_NO_MEM; + } + resp_payload->entries = results; + resp_payload->n_entries = req->cmd_scan_result->count; + + for (uint16_t i = 0; i < req->cmd_scan_result->count; i++) { + err = h->scan_result(i + req->cmd_scan_result->start_index, + &scan_result, &h->ctx); + if (err != ESP_OK) { + resp->status = STATUS__InternalError; + break; + } + + results[i] = (WiFiScanResult *) malloc(sizeof(WiFiScanResult)); + if (!results[i]) { + ESP_LOGE(TAG, "Failed to allocate memory for result entry"); + return ESP_ERR_NO_MEM; + } + wi_fi_scan_result__init(results[i]); + + results[i]->ssid.len = strnlen(scan_result.ssid, 32); + results[i]->ssid.data = (uint8_t *) strndup(scan_result.ssid, 32); + if (!results[i]->ssid.data) { + ESP_LOGE(TAG, "Failed to allocate memory for scan result entry SSID"); + return ESP_ERR_NO_MEM; + } + + results[i]->channel = scan_result.channel; + results[i]->rssi = scan_result.rssi; + results[i]->auth = scan_result.auth; + + results[i]->bssid.len = sizeof(scan_result.bssid); + results[i]->bssid.data = malloc(results[i]->bssid.len); + if (!results[i]->bssid.data) { + ESP_LOGE(TAG, "Failed to allocate memory for scan result entry BSSID"); + return ESP_ERR_NO_MEM; + } + memcpy(results[i]->bssid.data, scan_result.bssid, results[i]->bssid.len); + } + return ESP_OK; +} + + +static int lookup_cmd_handler(int cmd_id) +{ + int i; + + for (i = 0; i < sizeof(cmd_table)/sizeof(wifi_prov_scan_cmd_t); i++) { + if (cmd_table[i].cmd_num == cmd_id) { + return i; + } + } + + return -1; +} + +static void wifi_prov_scan_cmd_cleanup(WiFiScanPayload *resp, void *priv_data) +{ + switch (resp->msg) { + case WI_FI_SCAN_MSG_TYPE__TypeRespScanStart: + { + free(resp->resp_scan_start); + } + break; + case WI_FI_SCAN_MSG_TYPE__TypeRespScanStatus: + { + free(resp->resp_scan_status); + } + break; + case WI_FI_SCAN_MSG_TYPE__TypeRespScanResult: + { + if (!resp->resp_scan_result) return; + if (resp->resp_scan_result->entries) { + for (uint16_t i = 0; i < resp->resp_scan_result->n_entries; i++) { + if (!resp->resp_scan_result->entries[i]) continue; + free(resp->resp_scan_result->entries[i]->ssid.data); + free(resp->resp_scan_result->entries[i]->bssid.data); + free(resp->resp_scan_result->entries[i]); + } + free(resp->resp_scan_result->entries); + } + free(resp->resp_scan_result); + } + break; + default: + ESP_LOGE(TAG, "Unsupported response type in cleanup_handler"); + break; + } + return; +} + +static esp_err_t wifi_prov_scan_cmd_dispatcher(WiFiScanPayload *req, + WiFiScanPayload *resp, void *priv_data) +{ + esp_err_t ret; + + ESP_LOGD(TAG, "In wifi_prov_scan_cmd_dispatcher Cmd=%d", req->msg); + + int cmd_index = lookup_cmd_handler(req->msg); + if (cmd_index < 0) { + ESP_LOGE(TAG, "Invalid command handler lookup"); + return ESP_FAIL; + } + + ret = cmd_table[cmd_index].command_handler(req, resp, priv_data); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Error executing command handler"); + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t wifi_prov_scan_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen, + uint8_t **outbuf, ssize_t *outlen, void *priv_data) +{ + WiFiScanPayload *req; + WiFiScanPayload resp; + esp_err_t ret = ESP_OK; + + req = wi_fi_scan_payload__unpack(NULL, inlen, inbuf); + if (!req) { + ESP_LOGE(TAG, "Unable to unpack scan message"); + return ESP_ERR_INVALID_ARG; + } + + wi_fi_scan_payload__init(&resp); + ret = wifi_prov_scan_cmd_dispatcher(req, &resp, priv_data); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Command dispatcher error %d", ret); + ret = ESP_FAIL; + goto exit; + } + + resp.msg = req->msg + 1; /* Response is request + 1 */ + *outlen = wi_fi_scan_payload__get_packed_size(&resp); + if (*outlen <= 0) { + ESP_LOGE(TAG, "Invalid encoding for response"); + ret = ESP_FAIL; + goto exit; + } + + *outbuf = (uint8_t *) malloc(*outlen); + if (!*outbuf) { + ESP_LOGE(TAG, "System out of memory"); + ret = ESP_ERR_NO_MEM; + goto exit; + } + wi_fi_scan_payload__pack(&resp, *outbuf); + ESP_LOGD(TAG, "Response packet size : %d", *outlen); + exit: + + wi_fi_scan_payload__free_unpacked(req, NULL); + wifi_prov_scan_cmd_cleanup(&resp, priv_data); + return ret; +} diff --git a/components/wpa_supplicant/CMakeLists.txt b/components/wpa_supplicant/CMakeLists.txt index 35bf0bbdb3..330b94d6c2 100644 --- a/components/wpa_supplicant/CMakeLists.txt +++ b/components/wpa_supplicant/CMakeLists.txt @@ -1,88 +1,94 @@ -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/ap/ap_config.c" + "src/ap/ieee802_1x.c" + "src/ap/wpa_auth.c" + "src/ap/wpa_auth_ie.c" + "src/common/wpa_common.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_ops.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/eap_peer/chap.c" + "src/eap_peer/eap.c" + "src/eap_peer/eap_common.c" + "src/eap_peer/eap_mschapv2.c" + "src/eap_peer/eap_peap.c" + "src/eap_peer/eap_peap_common.c" + "src/eap_peer/eap_tls.c" + "src/eap_peer/eap_tls_common.c" + "src/eap_peer/eap_ttls.c" + "src/eap_peer/mschapv2.c" + "src/esp_supplicant/esp_hostap.c" + "src/esp_supplicant/esp_wpa2.c" + "src/esp_supplicant/esp_wpa_main.c" + "src/esp_supplicant/esp_wpas_glue.c" + "src/esp_supplicant/esp_wps.c" + "src/rsn_supp/wpa.c" + "src/rsn_supp/wpa_ie.c" + "src/tls/asn1.c" + "src/tls/bignum.c" + "src/tls/pkcs1.c" + "src/tls/pkcs5.c" + "src/tls/pkcs8.c" + "src/tls/rsa.c" + "src/tls/tls_internal.c" + "src/tls/tlsv1_client.c" + "src/tls/tlsv1_client_read.c" + "src/tls/tlsv1_client_write.c" + "src/tls/tlsv1_common.c" + "src/tls/tlsv1_cred.c" + "src/tls/tlsv1_record.c" + "src/tls/tlsv1_server.c" + "src/tls/tlsv1_server_read.c" + "src/tls/tlsv1_server_write.c" + "src/tls/x509v3.c" + "src/utils/base64.c" + "src/utils/common.c" + "src/utils/ext_password.c" + "src/utils/uuid.c" + "src/utils/wpabuf.c" + "src/utils/wpa_debug.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 include/esp_supplicant + PRIV_INCLUDE_DIRS src + PRIV_REQUIRES mbedtls) target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-strict-aliasing) target_compile_definitions(${COMPONENT_LIB} PRIVATE __ets__ - EMBEDDED_SUPP + ESP_SUPPLICANT IEEE8021X_EAPOL EAP_PEER_METHOD EAP_MSCHAPv2 diff --git a/components/wpa_supplicant/Kconfig b/components/wpa_supplicant/Kconfig new file mode 100644 index 0000000000..927dc0165a --- /dev/null +++ b/components/wpa_supplicant/Kconfig @@ -0,0 +1,9 @@ +menu "Supplicant" + + 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 f4a57ef7e2..e85e9979fb 100644 --- a/components/wpa_supplicant/component.mk +++ b/components/wpa_supplicant/component.mk @@ -1,4 +1,5 @@ -COMPONENT_ADD_INCLUDEDIRS := include port/include -COMPONENT_SRCDIRS := src/crypto port src/fast_crypto src/wpa2/eap_peer src/wpa2/tls src/wpa2/utils src/wps +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 += -DEMBEDDED_SUPP -DIEEE8021X_EAPOL -DEAP_PEER_METHOD -DEAP_MSCHAPv2 -DEAP_TTLS -DEAP_TLS -DEAP_PEAP -DUSE_WPA2_TASK -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -DESPRESSIF_USE -DESP32_WORKAROUND -D__ets__ -DCONFIG_ECC -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/include/crypto/common.h b/components/wpa_supplicant/include/crypto/common.h deleted file mode 100644 index 319b861e45..0000000000 --- a/components/wpa_supplicant/include/crypto/common.h +++ /dev/null @@ -1,481 +0,0 @@ -/* - * 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. - */ - -#ifndef COMMON_H -#define COMMON_H - -#include "os.h" - -#if defined(__XTENSA__) -#include -#define __BYTE_ORDER BYTE_ORDER -#define __LITTLE_ENDIAN LITTLE_ENDIAN -#define __BIG_ENDIAN BIG_ENDIAN -#endif /*__XTENSA__*/ - -#if defined(__linux__) || defined(__GLIBC__) -#include -#include -#endif /* __linux__ */ - -#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \ - defined(__OpenBSD__) -#include -#include -#define __BYTE_ORDER _BYTE_ORDER -#define __LITTLE_ENDIAN _LITTLE_ENDIAN -#define __BIG_ENDIAN _BIG_ENDIAN -#ifdef __OpenBSD__ -#define bswap_16 swap16 -#define bswap_32 swap32 -#define bswap_64 swap64 -#else /* __OpenBSD__ */ -#define bswap_16 bswap16 -#define bswap_32 bswap32 -#define bswap_64 bswap64 -#endif /* __OpenBSD__ */ -#endif /* defined(__FreeBSD__) || defined(__NetBSD__) || - * defined(__DragonFly__) || defined(__OpenBSD__) */ - -#ifdef __APPLE__ -#include -#include -#define __BYTE_ORDER _BYTE_ORDER -#define __LITTLE_ENDIAN _LITTLE_ENDIAN -#define __BIG_ENDIAN _BIG_ENDIAN -static inline unsigned short bswap_16(unsigned short v) -{ - return ((v & 0xff) << 8) | (v >> 8); -} - -static inline unsigned int bswap_32(unsigned int v) -{ - return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | - ((v & 0xff0000) >> 8) | (v >> 24); -} -#endif /* __APPLE__ */ - -#ifdef CONFIG_TI_COMPILER -#define __BIG_ENDIAN 4321 -#define __LITTLE_ENDIAN 1234 -#ifdef __big_endian__ -#define __BYTE_ORDER __BIG_ENDIAN -#else -#define __BYTE_ORDER __LITTLE_ENDIAN -#endif -#endif /* CONFIG_TI_COMPILER */ - -#ifdef __SYMBIAN32__ -#define __BIG_ENDIAN 4321 -#define __LITTLE_ENDIAN 1234 -#define __BYTE_ORDER __LITTLE_ENDIAN -#endif /* __SYMBIAN32__ */ - -#ifdef CONFIG_NATIVE_WINDOWS -#include - -typedef int socklen_t; - -#ifndef MSG_DONTWAIT -#define MSG_DONTWAIT 0 /* not supported */ -#endif - -#endif /* CONFIG_NATIVE_WINDOWS */ - -#ifdef _MSC_VER -#define inline __inline - -#undef vsnprintf -#define vsnprintf _vsnprintf -#undef close -#define close closesocket -#endif /* _MSC_VER */ - - -/* Define platform specific integer types */ - -#ifdef _MSC_VER -typedef UINT64 u64; -typedef UINT32 u32; -typedef UINT16 u16; -typedef UINT8 u8; -typedef INT64 s64; -typedef INT32 s32; -typedef INT16 s16; -typedef INT8 s8; -#define WPA_TYPES_DEFINED -#endif /* _MSC_VER */ - -#ifdef __vxworks -typedef unsigned long long u64; -typedef UINT32 u32; -typedef UINT16 u16; -typedef UINT8 u8; -typedef long long s64; -typedef INT32 s32; -typedef INT16 s16; -typedef INT8 s8; -#define WPA_TYPES_DEFINED -#endif /* __vxworks */ - -#ifdef CONFIG_TI_COMPILER -#ifdef _LLONG_AVAILABLE -typedef unsigned long long u64; -#else -/* - * TODO: 64-bit variable not available. Using long as a workaround to test the - * build, but this will likely not work for all operations. - */ -typedef unsigned long u64; -#endif -typedef unsigned int u32; -typedef unsigned short u16; -typedef unsigned char u8; -#define WPA_TYPES_DEFINED -#endif /* CONFIG_TI_COMPILER */ - -#ifdef __SYMBIAN32__ -#define __REMOVE_PLATSEC_DIAGNOSTICS__ -#include -typedef TUint64 u64; -typedef TUint32 u32; -typedef TUint16 u16; -typedef TUint8 u8; -#define WPA_TYPES_DEFINED -#endif /* __SYMBIAN32__ */ - -#ifndef WPA_TYPES_DEFINED -#ifdef CONFIG_USE_INTTYPES_H -#include -#else -#include -#endif - -typedef uint64_t u64; -typedef uint32_t u32; -typedef uint16_t u16; -typedef uint8_t u8; -typedef int64_t s64; -typedef int32_t s32; -typedef int16_t s16; -typedef int8_t s8; -#define WPA_TYPES_DEFINED -#endif /* !WPA_TYPES_DEFINED */ - - -/* Define platform specific byte swapping macros */ - -#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS) - -static inline unsigned short wpa_swap_16(unsigned short v) -{ - return ((v & 0xff) << 8) | (v >> 8); -} - -static inline unsigned int wpa_swap_32(unsigned int v) -{ - return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | - ((v & 0xff0000) >> 8) | (v >> 24); -} - -#define le_to_host16(n) (n) -#define host_to_le16(n) (n) -#define be_to_host16(n) wpa_swap_16(n) -#define host_to_be16(n) wpa_swap_16(n) -#define le_to_host32(n) (n) -#define be_to_host32(n) wpa_swap_32(n) -#define host_to_be32(n) wpa_swap_32(n) - -#define WPA_BYTE_SWAP_DEFINED - -#endif /* __CYGWIN__ || CONFIG_NATIVE_WINDOWS */ - - -#ifndef WPA_BYTE_SWAP_DEFINED - -#ifndef __BYTE_ORDER -#ifndef __LITTLE_ENDIAN -#ifndef __BIG_ENDIAN -#define __LITTLE_ENDIAN 1234 -#define __BIG_ENDIAN 4321 -#if defined(sparc) -#define __BYTE_ORDER __BIG_ENDIAN -#endif -#endif /* __BIG_ENDIAN */ -#endif /* __LITTLE_ENDIAN */ -#endif /* __BYTE_ORDER */ - -#if __BYTE_ORDER == __LITTLE_ENDIAN -#define le_to_host16(n) ((__force u16) (le16) (n)) -#define host_to_le16(n) ((__force le16) (u16) (n)) -#define be_to_host16(n) bswap_16((__force u16) (be16) (n)) -#define host_to_be16(n) ((__force be16) bswap_16((n))) -#define le_to_host32(n) ((__force u32) (le32) (n)) -#define host_to_le32(n) ((__force le32) (u32) (n)) -#define be_to_host32(n) bswap_32((__force u32) (be32) (n)) -#define host_to_be32(n) ((__force be32) bswap_32((n))) -#define le_to_host64(n) ((__force u64) (le64) (n)) -#define host_to_le64(n) ((__force le64) (u64) (n)) -#define be_to_host64(n) bswap_64((__force u64) (be64) (n)) -#define host_to_be64(n) ((__force be64) bswap_64((n))) -#elif __BYTE_ORDER == __BIG_ENDIAN -#define le_to_host16(n) bswap_16(n) -#define host_to_le16(n) bswap_16(n) -#define be_to_host16(n) (n) -#define host_to_be16(n) (n) -#define le_to_host32(n) bswap_32(n) -#define be_to_host32(n) (n) -#define host_to_be32(n) (n) -#define le_to_host64(n) bswap_64(n) -#define host_to_le64(n) bswap_64(n) -#define be_to_host64(n) (n) -#define host_to_be64(n) (n) -#ifndef WORDS_BIGENDIAN -#define WORDS_BIGENDIAN -#endif -#else -#error Could not determine CPU byte order -#endif - -#define WPA_BYTE_SWAP_DEFINED -#endif /* !WPA_BYTE_SWAP_DEFINED */ - - -/* Macros for handling unaligned memory accesses */ - -#define WPA_GET_BE16(a) ((u16) (((a)[0] << 8) | (a)[1])) -#define WPA_PUT_BE16(a, val) \ - do { \ - (a)[0] = ((u16) (val)) >> 8; \ - (a)[1] = ((u16) (val)) & 0xff; \ - } while (0) - -#define WPA_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0])) -#define WPA_PUT_LE16(a, val) \ - do { \ - (a)[1] = ((u16) (val)) >> 8; \ - (a)[0] = ((u16) (val)) & 0xff; \ - } while (0) - -#define WPA_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \ - ((u32) (a)[2])) -#define WPA_PUT_BE24(a, val) \ - do { \ - (a)[0] = (u8) ((((u32) (val)) >> 16) & 0xff); \ - (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ - (a)[2] = (u8) (((u32) (val)) & 0xff); \ - } while (0) - -#define WPA_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \ - (((u32) (a)[2]) << 8) | ((u32) (a)[3])) -#define WPA_PUT_BE32(a, val) \ - do { \ - (a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff); \ - (a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff); \ - (a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff); \ - (a)[3] = (u8) (((u32) (val)) & 0xff); \ - } while (0) - -#define WPA_GET_LE32(a) ((((u32) (a)[3]) << 24) | (((u32) (a)[2]) << 16) | \ - (((u32) (a)[1]) << 8) | ((u32) (a)[0])) -#define WPA_PUT_LE32(a, val) \ - do { \ - (a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff); \ - (a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff); \ - (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ - (a)[0] = (u8) (((u32) (val)) & 0xff); \ - } while (0) - -#define WPA_GET_BE64(a) ((((u64) (a)[0]) << 56) | (((u64) (a)[1]) << 48) | \ - (((u64) (a)[2]) << 40) | (((u64) (a)[3]) << 32) | \ - (((u64) (a)[4]) << 24) | (((u64) (a)[5]) << 16) | \ - (((u64) (a)[6]) << 8) | ((u64) (a)[7])) -#define WPA_PUT_BE64(a, val) \ - do { \ - (a)[0] = (u8) (((u64) (val)) >> 56); \ - (a)[1] = (u8) (((u64) (val)) >> 48); \ - (a)[2] = (u8) (((u64) (val)) >> 40); \ - (a)[3] = (u8) (((u64) (val)) >> 32); \ - (a)[4] = (u8) (((u64) (val)) >> 24); \ - (a)[5] = (u8) (((u64) (val)) >> 16); \ - (a)[6] = (u8) (((u64) (val)) >> 8); \ - (a)[7] = (u8) (((u64) (val)) & 0xff); \ - } while (0) - -#define WPA_GET_LE64(a) ((((u64) (a)[7]) << 56) | (((u64) (a)[6]) << 48) | \ - (((u64) (a)[5]) << 40) | (((u64) (a)[4]) << 32) | \ - (((u64) (a)[3]) << 24) | (((u64) (a)[2]) << 16) | \ - (((u64) (a)[1]) << 8) | ((u64) (a)[0])) - - -#ifndef ETH_ALEN -#define ETH_ALEN 6 -#endif -#ifndef IFNAMSIZ -#define IFNAMSIZ 16 -#endif -#ifndef ETH_P_ALL -#define ETH_P_ALL 0x0003 -#endif -#ifndef ETH_P_PAE -#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ -#endif /* ETH_P_PAE */ -#ifndef ETH_P_EAPOL -#define ETH_P_EAPOL ETH_P_PAE -#endif /* ETH_P_EAPOL */ -#ifndef ETH_P_RSN_PREAUTH -#define ETH_P_RSN_PREAUTH 0x88c7 -#endif /* ETH_P_RSN_PREAUTH */ -#ifndef ETH_P_RRB -#define ETH_P_RRB 0x890D -#endif /* ETH_P_RRB */ - - -#ifdef __GNUC__ -#define PRINTF_FORMAT(a,b) __attribute__ ((format (printf, (a), (b)))) -#define STRUCT_PACKED __attribute__ ((packed)) -#else -#define PRINTF_FORMAT(a,b) -#define STRUCT_PACKED -#endif - -#ifdef CONFIG_ANSI_C_EXTRA - -#if !defined(_MSC_VER) || _MSC_VER < 1400 -/* snprintf - used in number of places; sprintf() is _not_ a good replacement - * due to possible buffer overflow; see, e.g., - * http://www.ijs.si/software/snprintf/ for portable implementation of - * snprintf. */ -int snprintf(char *str, size_t size, const char *format, ...); - -/* vsnprintf - only used for wpa_msg() in wpa_supplicant.c */ -int vsnprintf(char *str, size_t size, const char *format, va_list ap); -#endif /* !defined(_MSC_VER) || _MSC_VER < 1400 */ - -/* getopt - only used in main.c */ -int getopt(int argc, char *const argv[], const char *optstring); -extern char *optarg; -extern int optind; - -#ifndef CONFIG_NO_SOCKLEN_T_TYPEDEF -#ifndef __socklen_t_defined -typedef int socklen_t; -#endif -#endif - -/* inline - define as __inline or just define it to be empty, if needed */ -#ifdef CONFIG_NO_INLINE -#define inline -#else -#define inline __inline -#endif - -#ifndef __func__ -#define __func__ "__func__ not defined" -#endif - -#ifndef bswap_16 -#define bswap_16(a) ((((u16) (a) << 8) & 0xff00) | (((u16) (a) >> 8) & 0xff)) -#endif - -#ifndef bswap_32 -#define bswap_32(a) ((((u32) (a) << 24) & 0xff000000) | \ - (((u32) (a) << 8) & 0xff0000) | \ - (((u32) (a) >> 8) & 0xff00) | \ - (((u32) (a) >> 24) & 0xff)) -#endif - -#ifndef MSG_DONTWAIT -#define MSG_DONTWAIT 0 -#endif - -#ifdef _WIN32_WCE -void perror(const char *s); -#endif /* _WIN32_WCE */ - -#endif /* CONFIG_ANSI_C_EXTRA */ - -#ifndef MAC2STR -#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] -#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" -#endif - -#ifndef BIT -#define BIT(x) (1 << (x)) -#endif - -/* - * Definitions for sparse validation - * (http://kernel.org/pub/linux/kernel/people/josh/sparse/) - */ -#ifdef __CHECKER__ -#define __force __attribute__((force)) -#define __bitwise __attribute__((bitwise)) -#else -#define __force -#define __bitwise -#endif - -typedef u16 __bitwise be16; -typedef u16 __bitwise le16; -typedef u32 __bitwise be32; -typedef u32 __bitwise le32; -typedef u64 __bitwise be64; -typedef u64 __bitwise le64; - -#ifndef __must_check -#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) -#define __must_check __attribute__((__warn_unused_result__)) -#else -#define __must_check -#endif /* __GNUC__ */ -#endif /* __must_check */ - -int hwaddr_aton(const char *txt, u8 *addr); -int hwaddr_aton2(const char *txt, u8 *addr); -int hexstr2bin(const char *hex, u8 *buf, size_t len); -void inc_byte_array(u8 *counter, size_t len); -void wpa_get_ntp_timestamp(u8 *buf); -int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len); -int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data, - size_t len); - -#ifdef CONFIG_NATIVE_WINDOWS -void wpa_unicode2ascii_inplace(TCHAR *str); -TCHAR * wpa_strdup_tchar(const char *str); -#else /* CONFIG_NATIVE_WINDOWS */ -#define wpa_unicode2ascii_inplace(s) do { } while (0) -#define wpa_strdup_tchar(s) strdup((s)) -#endif /* CONFIG_NATIVE_WINDOWS */ - -const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len); - -static inline int is_zero_ether_addr(const u8 *a) -{ - return !(a[0] | a[1] | a[2] | a[3] | a[4] | a[5]); -} - -/* - * gcc 4.4 ends up generating strict-aliasing warnings about some very common - * networking socket uses that do not really result in a real problem and - * cannot be easily avoided with union-based type-punning due to struct - * definitions including another struct in system header files. To avoid having - * to fully disable strict-aliasing warnings, provide a mechanism to hide the - * typecast from aliasing for now. A cleaner solution will hopefully be found - * in the future to handle these cases. - */ -void * __hide_aliasing_typecast(void *foo); -#define aliasing_hide_typecast(a,t) (t *) __hide_aliasing_typecast((a)) - -#endif /* COMMON_H */ diff --git a/components/wpa_supplicant/include/esp_supplicant/esp_wpa.h b/components/wpa_supplicant/include/esp_supplicant/esp_wpa.h new file mode 100644 index 0000000000..c7fbcfacbe --- /dev/null +++ b/components/wpa_supplicant/include/esp_supplicant/esp_wpa.h @@ -0,0 +1,69 @@ +// 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_WPA_H__ +#define __ESP_WPA_H__ + +#include +#include +#include "esp_err.h" +#include "esp_wifi_crypto_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup WiFi_APIs WiFi Related APIs + * @brief WiFi APIs + */ + +/** @addtogroup WiFi_APIs + * @{ + */ + +/** \defgroup WPA_APIs WPS APIs + * @brief ESP32 Supplicant APIs + * + */ + +/** @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 + * + * @return + * - ESP_OK : succeed + * - ESP_ERR_NO_MEM : out of memory + */ +esp_err_t esp_supplicant_init(void); + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ESP_WPA_H__ */ diff --git a/components/esp_wifi/include/esp_wpa2.h b/components/wpa_supplicant/include/esp_supplicant/esp_wpa2.h similarity index 93% rename from components/esp_wifi/include/esp_wpa2.h rename to components/wpa_supplicant/include/esp_supplicant/esp_wpa2.h index 1b2dfa5103..5315606598 100644 --- a/components/esp_wifi/include/esp_wpa2.h +++ b/components/wpa_supplicant/include/esp_supplicant/esp_wpa2.h @@ -1,4 +1,4 @@ -// Hardware crypto support Copyright 2017 Espressif Systems (Shanghai) PTE LTD +// Hardware crypto support 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. @@ -12,28 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef ESP_WPA2_H -#define ESP_WPA2_H +#ifndef _ESP_WPA2_H +#define _ESP_WPA2_H #include #include "esp_err.h" -#include "esp_wifi_crypto_types.h" #ifdef __cplusplus extern "C" { #endif -extern const wpa2_crypto_funcs_t g_wifi_default_wpa2_crypto_funcs; - -typedef struct { - const wpa2_crypto_funcs_t *crypto_funcs; -}esp_wpa2_config_t; - -#define WPA2_CONFIG_INIT_DEFAULT() { \ - .crypto_funcs = &g_wifi_default_wpa2_crypto_funcs \ -} - /** * @brief Enable wpa2 enterprise authentication. * @@ -44,7 +33,7 @@ typedef struct { * - ESP_OK: succeed. * - ESP_ERR_NO_MEM: fail(internal memory malloc fail) */ -esp_err_t esp_wifi_sta_wpa2_ent_enable(const esp_wpa2_config_t *config); +esp_err_t esp_wifi_sta_wpa2_ent_enable(void); /** * @brief Disable wpa2 enterprise authentication. diff --git a/components/esp_wifi/include/esp_wps.h b/components/wpa_supplicant/include/esp_supplicant/esp_wps.h similarity index 94% rename from components/esp_wifi/include/esp_wps.h rename to components/wpa_supplicant/include/esp_supplicant/esp_wps.h index 9bd61cc3af..5bf61d3090 100644 --- a/components/esp_wifi/include/esp_wps.h +++ b/components/wpa_supplicant/include/esp_supplicant/esp_wps.h @@ -1,4 +1,4 @@ -// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// 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. @@ -54,8 +54,6 @@ typedef enum wps_type { WPS_TYPE_MAX, } wps_type_t; -extern const wps_crypto_funcs_t g_wifi_default_wps_crypto_funcs; - #define WPS_MAX_MANUFACTURER_LEN 65 #define WPS_MAX_MODEL_NUMBER_LEN 33 #define WPS_MAX_MODEL_NAME_LEN 33 @@ -70,13 +68,11 @@ typedef struct { typedef struct { wps_type_t wps_type; - const wps_crypto_funcs_t *crypto_funcs; wps_factory_information_t factory_info; } esp_wps_config_t; #define WPS_CONFIG_INIT_DEFAULT(type) { \ .wps_type = type, \ - .crypto_funcs = &g_wifi_default_wps_crypto_funcs, \ .factory_info = { \ .manufacturer = "ESPRESSIF", \ .model_number = "ESP32", \ diff --git a/components/wpa_supplicant/include/wpa/common.h b/components/wpa_supplicant/include/utils/common.h similarity index 99% rename from components/wpa_supplicant/include/wpa/common.h rename to components/wpa_supplicant/include/utils/common.h index 2e6012f868..6fadca049b 100644 --- a/components/wpa_supplicant/include/wpa/common.h +++ b/components/wpa_supplicant/include/utils/common.h @@ -18,6 +18,7 @@ #if defined(__ets__) #endif /* ets */ #include "os.h" +#include "esp_bit_defs.h" /* Define platform specific variable type macros */ #if defined(ESP_PLATFORM) diff --git a/components/wpa_supplicant/include/wpa/wpa_debug.h b/components/wpa_supplicant/include/utils/wpa_debug.h similarity index 99% rename from components/wpa_supplicant/include/wpa/wpa_debug.h rename to components/wpa_supplicant/include/utils/wpa_debug.h index 10fe928c3e..b204ec7d87 100644 --- a/components/wpa_supplicant/include/wpa/wpa_debug.h +++ b/components/wpa_supplicant/include/utils/wpa_debug.h @@ -75,6 +75,7 @@ void wpa_debug_print_timestamp(void); #ifdef DEBUG_PRINT #define wpa_printf(level,fmt, args...) ESP_LOG_LEVEL_LOCAL(level, TAG, fmt, ##args) +void wpa_dump_mem(char* desc, uint8_t *addr, uint16_t len); static inline void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len) { diff --git a/components/wpa_supplicant/include/wpa/wpabuf.h b/components/wpa_supplicant/include/utils/wpabuf.h similarity index 100% rename from components/wpa_supplicant/include/wpa/wpabuf.h rename to components/wpa_supplicant/include/utils/wpabuf.h diff --git a/components/wpa_supplicant/include/wpa/hostapd.h b/components/wpa_supplicant/include/wpa/hostapd.h deleted file mode 100644 index 1d52659a22..0000000000 --- a/components/wpa_supplicant/include/wpa/hostapd.h +++ /dev/null @@ -1,312 +0,0 @@ -/* - * hostapd / Initialization and configuration - * Copyright (c) 2002-2009, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef HOSTAPD_H -#define HOSTAPD_H - -#include "wpa/defs.h" -#include "wpa/ap_config.h" - -struct wpa_driver_ops; -struct wpa_ctrl_dst; -struct radius_server_data; -struct upnp_wps_device_sm; -struct hostapd_data; -struct sta_info; -struct hostap_sta_driver_data; -struct ieee80211_ht_capabilities; -struct full_dynamic_vlan; -enum wps_event; -union wps_event_data; - -struct hostapd_iface; - -struct hapd_interfaces { - int (*reload_config)(struct hostapd_iface *iface); - struct hostapd_config * (*config_read_cb)(const char *config_fname); - int (*ctrl_iface_init)(struct hostapd_data *hapd); - void (*ctrl_iface_deinit)(struct hostapd_data *hapd); - int (*for_each_interface)(struct hapd_interfaces *interfaces, - int (*cb)(struct hostapd_iface *iface, - void *ctx), void *ctx); - int (*driver_init)(struct hostapd_iface *iface); - - size_t count; - int global_ctrl_sock; - char *global_iface_path; - char *global_iface_name; - struct hostapd_iface **iface; -}; - - -struct hostapd_probereq_cb { - int (*cb)(void *ctx, const u8 *sa, const u8 *da, const u8 *bssid, - const u8 *ie, size_t ie_len, int ssi_signal); - void *ctx; -}; - -#define HOSTAPD_RATE_BASIC 0x00000001 - -struct hostapd_rate_data { - int rate; /* rate in 100 kbps */ - int flags; /* HOSTAPD_RATE_ flags */ -}; - -struct hostapd_frame_info { - u32 channel; - u32 datarate; - int ssi_signal; /* dBm */ -}; - - -/** - * struct hostapd_data - hostapd per-BSS data structure - */ -struct hostapd_data { -// struct hostapd_iface *iface; - struct hostapd_config *iconf; - struct hostapd_bss_config *conf; - int interface_added; /* virtual interface added for this BSS */ - - u8 own_addr[ETH_ALEN]; - - int num_sta; /* number of entries in sta_list */ -// struct sta_info *sta_list; /* STA info list head */ -//#define STA_HASH_SIZE 256 -//#define STA_HASH(sta) (sta[5]) -// struct sta_info *sta_hash[STA_HASH_SIZE]; - -// /* -// * Bitfield for indicating which AIDs are allocated. Only AID values -// * 1-2007 are used and as such, the bit at index 0 corresponds to AID -// * 1. -// */ -//#define AID_WORDS ((2008 + 31) / 32) -// u32 sta_aid[AID_WORDS]; - -// const struct wpa_driver_ops *driver; -// void *drv_priv; - -// void (*new_assoc_sta_cb)(struct hostapd_data *hapd, -// struct sta_info *sta, int reassoc); - -// void *msg_ctx; /* ctx for wpa_msg() calls */ -// void *msg_ctx_parent; /* parent interface ctx for wpa_msg() calls */ - -// struct radius_client_data *radius; -// u32 acct_session_id_hi, acct_session_id_lo; -// struct radius_das_data *radius_das; - -// struct iapp_data *iapp; - -// struct hostapd_cached_radius_acl *acl_cache; -// struct hostapd_acl_query_data *acl_queries; - - struct wpa_authenticator *wpa_auth; -// struct eapol_authenticator *eapol_auth; - -// struct rsn_preauth_interface *preauth_iface; -// time_t michael_mic_failure; -// int michael_mic_failures; -// int tkip_countermeasures; - -// int ctrl_sock; -// struct wpa_ctrl_dst *ctrl_dst; - -// void *ssl_ctx; -// void *eap_sim_db_priv; -// struct radius_server_data *radius_srv; - -// int parameter_set_count; - - /* Time Advertisement */ -// u8 time_update_counter; -// struct wpabuf *time_adv; - -#ifdef CONFIG_FULL_DYNAMIC_VLAN - struct full_dynamic_vlan *full_dynamic_vlan; -#endif /* CONFIG_FULL_DYNAMIC_VLAN */ - -// struct l2_packet_data *l2; -// struct wps_context *wps; - -// int beacon_set_done; -// struct wpabuf *wps_beacon_ie; -// struct wpabuf *wps_probe_resp_ie; -#ifdef CONFIG_WPS - unsigned int ap_pin_failures; - unsigned int ap_pin_failures_consecutive; - struct upnp_wps_device_sm *wps_upnp; - unsigned int ap_pin_lockout_time; -#endif /* CONFIG_WPS */ - -// struct hostapd_probereq_cb *probereq_cb; -// size_t num_probereq_cb; - -// void (*public_action_cb)(void *ctx, const u8 *buf, size_t len, -// int freq); -// void *public_action_cb_ctx; - -// int (*vendor_action_cb)(void *ctx, const u8 *buf, size_t len, -// int freq); -// void *vendor_action_cb_ctx; - -// void (*wps_reg_success_cb)(void *ctx, const u8 *mac_addr, -// const u8 *uuid_e); -// void *wps_reg_success_cb_ctx; - -// void (*wps_event_cb)(void *ctx, enum wps_event event, -// union wps_event_data *data); -// void *wps_event_cb_ctx; - -// void (*sta_authorized_cb)(void *ctx, const u8 *mac_addr, -// int authorized, const u8 *p2p_dev_addr); -// void *sta_authorized_cb_ctx; - -// void (*setup_complete_cb)(void *ctx); -// void *setup_complete_cb_ctx; - -#ifdef CONFIG_P2P - struct p2p_data *p2p; - struct p2p_group *p2p_group; - struct wpabuf *p2p_beacon_ie; - struct wpabuf *p2p_probe_resp_ie; - - /* Number of non-P2P association stations */ - int num_sta_no_p2p; - - /* Periodic NoA (used only when no non-P2P clients in the group) */ - int noa_enabled; - int noa_start; - int noa_duration; -#endif /* CONFIG_P2P */ -#ifdef CONFIG_INTERWORKING - size_t gas_frag_limit; -#endif /* CONFIG_INTERWORKING */ - -#ifdef CONFIG_SQLITE - struct hostapd_eap_user tmp_eap_user; -#endif /* CONFIG_SQLITE */ -}; - -#if 0 -/** - * struct hostapd_iface - hostapd per-interface data structure - */ -struct hostapd_iface { - struct hapd_interfaces *interfaces; - void *owner; - char *config_fname; - struct hostapd_config *conf; - - size_t num_bss; - struct hostapd_data **bss; - - int num_ap; /* number of entries in ap_list */ - struct ap_info *ap_list; /* AP info list head */ - struct ap_info *ap_hash[STA_HASH_SIZE]; - struct ap_info *ap_iter_list; - - unsigned int drv_flags; - - /* - * A bitmap of supported protocols for probe response offload. See - * struct wpa_driver_capa in driver.h - */ - unsigned int probe_resp_offloads; - - struct hostapd_hw_modes *hw_features; - int num_hw_features; - struct hostapd_hw_modes *current_mode; - /* Rates that are currently used (i.e., filtered copy of - * current_mode->channels */ - int num_rates; - struct hostapd_rate_data *current_rates; - int *basic_rates; - int freq; - - u16 hw_flags; - - /* Number of associated Non-ERP stations (i.e., stations using 802.11b - * in 802.11g BSS) */ - int num_sta_non_erp; - - /* Number of associated stations that do not support Short Slot Time */ - int num_sta_no_short_slot_time; - - /* Number of associated stations that do not support Short Preamble */ - int num_sta_no_short_preamble; - - int olbc; /* Overlapping Legacy BSS Condition */ - - /* Number of HT associated stations that do not support greenfield */ - int num_sta_ht_no_gf; - - /* Number of associated non-HT stations */ - int num_sta_no_ht; - - /* Number of HT associated stations 20 MHz */ - int num_sta_ht_20mhz; - - /* Overlapping BSS information */ - int olbc_ht; - - u16 ht_op_mode; - void (*scan_cb)(struct hostapd_iface *iface); -}; -#endif - -#if 0 -/* hostapd.c */ -int hostapd_for_each_interface(struct hapd_interfaces *interfaces, - int (*cb)(struct hostapd_iface *iface, - void *ctx), void *ctx); -int hostapd_reload_config(struct hostapd_iface *iface); -struct hostapd_data * -hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface, - struct hostapd_config *conf, - struct hostapd_bss_config *bss); -int hostapd_setup_interface(struct hostapd_iface *iface); -int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err); -void hostapd_interface_deinit(struct hostapd_iface *iface); -void hostapd_interface_free(struct hostapd_iface *iface); -void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, - int reassoc); -void hostapd_interface_deinit_free(struct hostapd_iface *iface); -int hostapd_enable_iface(struct hostapd_iface *hapd_iface); -int hostapd_reload_iface(struct hostapd_iface *hapd_iface); -int hostapd_disable_iface(struct hostapd_iface *hapd_iface); -int hostapd_add_iface(struct hapd_interfaces *ifaces, char *buf); -int hostapd_remove_iface(struct hapd_interfaces *ifaces, char *buf); - -/* utils.c */ -int hostapd_register_probereq_cb(struct hostapd_data *hapd, - int (*cb)(void *ctx, const u8 *sa, - const u8 *da, const u8 *bssid, - const u8 *ie, size_t ie_len, - int ssi_signal), - void *ctx); -void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr); - -/* drv_callbacks.c (TODO: move to somewhere else?) */ -int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, - const u8 *ie, size_t ielen, int reassoc); -void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr); -void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr); -int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da, - const u8 *bssid, const u8 *ie, size_t ie_len, - int ssi_signal); -void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, - int offset); - -const struct hostapd_eap_user * -hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity, - size_t identity_len, int phase2); -#endif - -#endif /* HOSTAPD_H */ diff --git a/components/wpa_supplicant/include/wpa/ieee80211_crypto.h b/components/wpa_supplicant/include/wpa/ieee80211_crypto.h deleted file mode 100644 index be0fb9aa12..0000000000 --- a/components/wpa_supplicant/include/wpa/ieee80211_crypto.h +++ /dev/null @@ -1,226 +0,0 @@ -/*- - * Copyright (c) 2001 Atsushi Onoe - * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting - * All rights reserved. - * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. - * - * $FreeBSD$ - */ - -/* - * copyright (c) 2010-2011 Espressif System - */ -#ifndef _NET80211_IEEE80211_CRYPTO_H_ -#define _NET80211_IEEE80211_CRYPTO_H_ - -//#include "pp/esf_buf.h" - -/* - * 802.11 protocol crypto-related definitions. - */ -#define IEEE80211_KEYBUF_SIZE 16 -#define IEEE80211_MICBUF_SIZE (8+8) /* space for both tx+rx keys */ - -/* - * Old WEP-style key. Deprecated. - */ - -#if 0 -struct ieee80211_rsnparms { - uint8_t rsn_mcastcipher; /* mcast/group cipher */ - uint8_t rsn_mcastkeylen; /* mcast key length */ - uint8_t rsn_ucastcipher; /* selected unicast cipher */ - uint8_t rsn_ucastkeylen; /* unicast key length */ - uint8_t rsn_keymgmt; /* selected key mgmt algo */ - uint16_t rsn_caps; /* capabilities */ -}; -#endif //0000 - -/* - * Template for a supported cipher. Ciphers register with the - * crypto code and are typically loaded as separate modules - * (the null cipher is always present). - * XXX may need refcnts - */ - -/* - * Crypto key state. There is sufficient room for all supported - * ciphers (see below). The underlying ciphers are handled - * separately through loadable cipher modules that register with - * the generic crypto support. A key has a reference to an instance - * of the cipher; any per-key state is hung off wk_private by the - * cipher when it is attached. Ciphers are automatically called - * to detach and cleanup any such state when the key is deleted. - * - * The generic crypto support handles encap/decap of cipher-related - * frame contents for both hardware- and software-based implementations. - * A key requiring software crypto support is automatically flagged and - * the cipher is expected to honor this and do the necessary work. - * Ciphers such as TKIP may also support mixed hardware/software - * encrypt/decrypt and MIC processing. - */ -typedef uint16_t ieee80211_keyix; /* h/w key index */ - -struct ieee80211_key { - uint8_t wk_keylen; /* key length in bytes */ - uint8_t wk_pad; - uint16_t wk_flags; -#define IEEE80211_KEY_XMIT 0x0001 /* key used for xmit */ -#define IEEE80211_KEY_RECV 0x0002 /* key used for recv */ -#define IEEE80211_KEY_GROUP 0x0004 /* key used for WPA group operation */ -#define IEEE80211_KEY_SWENCRYPT 0x0010 /* host-based encrypt */ -#define IEEE80211_KEY_SWDECRYPT 0x0020 /* host-based decrypt */ -#define IEEE80211_KEY_SWENMIC 0x0040 /* host-based enmic */ -#define IEEE80211_KEY_SWDEMIC 0x0080 /* host-based demic */ -#define IEEE80211_KEY_DEVKEY 0x0100 /* device key request completed */ -#define IEEE80211_KEY_CIPHER0 0x1000 /* cipher-specific action 0 */ -#define IEEE80211_KEY_CIPHER1 0x2000 /* cipher-specific action 1 */ -#define IEEE80211_KEY_EMPTY 0x0000 - ieee80211_keyix wk_keyix; /* h/w key index */ - ieee80211_keyix wk_rxkeyix; /* optional h/w rx key index */ - uint8_t wk_key[IEEE80211_KEYBUF_SIZE+IEEE80211_MICBUF_SIZE]; -#define wk_txmic wk_key+IEEE80211_KEYBUF_SIZE+0 /* XXX can't () right */ -#define wk_rxmic wk_key+IEEE80211_KEYBUF_SIZE+8 /* XXX can't () right */ - /* key receive sequence counter */ - uint64_t wk_keyrsc[IEEE80211_TID_SIZE]; - uint64_t wk_keytsc; /* key transmit sequence counter */ - const struct ieee80211_cipher *wk_cipher; - //void *wk_private; /* private cipher state */ - //uint8_t wk_macaddr[IEEE80211_ADDR_LEN]; //JLU: no need ... -}; -#define IEEE80211_KEY_COMMON /* common flags passed in by apps */\ - (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV | IEEE80211_KEY_GROUP) -#define IEEE80211_KEY_DEVICE /* flags owned by device driver */\ - (IEEE80211_KEY_DEVKEY|IEEE80211_KEY_CIPHER0|IEEE80211_KEY_CIPHER1) - -#define IEEE80211_KEY_SWCRYPT \ - (IEEE80211_KEY_SWENCRYPT | IEEE80211_KEY_SWDECRYPT) -#define IEEE80211_KEY_SWMIC (IEEE80211_KEY_SWENMIC | IEEE80211_KEY_SWDEMIC) - -//#define IEEE80211_KEYIX_NONE ((ieee80211_keyix) -1) - -/* - * NB: these values are ordered carefully; there are lots of - * of implications in any reordering. Beware that 4 is used - * only to indicate h/w TKIP MIC support in driver capabilities; - * there is no separate cipher support (it's rolled into the - * TKIP cipher support). - */ -#define IEEE80211_CIPHER_NONE 0 /* pseudo value */ -#define IEEE80211_CIPHER_TKIP 1 -#define IEEE80211_CIPHER_AES_OCB 2 -#define IEEE80211_CIPHER_AES_CCM 3 -#define IEEE80211_CIPHER_TKIPMIC 4 /* TKIP MIC capability */ -#define IEEE80211_CIPHER_CKIP 5 -#define IEEE80211_CIPHER_WEP 6 -#define IEEE80211_CIPHER_WEP40 7 -#define IEEE80211_CIPHER_WEP104 8 - - -#define IEEE80211_CIPHER_MAX (IEEE80211_CIPHER_NONE+2) - -/* capability bits in ic_cryptocaps/iv_cryptocaps */ -#define IEEE80211_CRYPTO_NONE (1<wk_cipher == &ieee80211_cipher_none) - -struct ieee80211_key *ieee80211_crypto_encap(struct ieee80211_conn *, - esf_buf *); - -struct ieee80211_key *ieee80211_crypto_decap(struct ieee80211_conn *, - esf_buf *, int); - -#if 0 //H/W MIC -/* - * Check and remove any MIC. - */ -static INLINE int -ieee80211_crypto_demic(struct ieee80211vap *vap, struct ieee80211_key *k, - esf_buf *m, int force) -{ - const struct ieee80211_cipher *cip = k->wk_cipher; - return (cip->ic_miclen > 0 ? cip->ic_demic(k, m, force) : 1); -} - -/* - * Add any MIC. - */ -static INLINE int -ieee80211_crypto_enmic(struct ieee80211vap *vap, - struct ieee80211_key *k, esf_buf *m, int force) -{ - const struct ieee80211_cipher *cip = k->wk_cipher; - return (cip->ic_miclen > 0 ? cip->ic_enmic(k, m, force) : 1); -} -#endif //0000 - -/* - * Setup crypto support for a device/shared instance. - */ -void ieee80211_crypto_attach(struct ieee80211com *ic); - -/* - * Reset key state to an unused state. The crypto - * key allocation mechanism insures other state (e.g. - * key data) is properly setup before a key is used. - */ -static inline void -ieee80211_crypto_resetkey(struct ieee80211_key *k) -{ - k->wk_cipher = NULL; - k->wk_flags = IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV; -} - -/* - * Crypt-related notification methods. - */ -//void ieee80211_notify_replay_failure(const struct ieee80211_frame *, const struct ieee80211_key *, -// uint64_t rsc, int tid); -//void ieee80211_notify_michael_failure(const struct ieee80211_frame *, u_int keyix); - -#endif /* _NET80211_IEEE80211_CRYPTO_H_ */ diff --git a/components/wpa_supplicant/include/wpa/ieee802_1x.h b/components/wpa_supplicant/include/wpa/ieee802_1x.h deleted file mode 100644 index e10ff7b310..0000000000 --- a/components/wpa_supplicant/include/wpa/ieee802_1x.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * hostapd / IEEE 802.1X-2004 Authenticator - * Copyright (c) 2002-2012, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef IEEE802_1X_H -#define IEEE802_1X_H - -struct hostapd_data; -struct sta_info; -struct eapol_state_machine; -struct hostapd_config; -struct hostapd_bss_config; -struct hostapd_radius_attr; -struct radius_msg; - - -void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, - size_t len); - -#if 0 -void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta); -void ieee802_1x_free_station(struct sta_info *sta); - -void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta); -void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta); -void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd, - struct sta_info *sta, int authorized); -void ieee802_1x_dump_state(FILE *f, const char *prefix, struct sta_info *sta); -int ieee802_1x_init(struct hostapd_data *hapd); -void ieee802_1x_deinit(struct hostapd_data *hapd); -int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta, - const u8 *buf, size_t len, int ack); -int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta, - const u8 *data, int len, int ack); -u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len); -u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len, - int idx); -struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm); -const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len); -void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm, - int enabled); -void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm, - int valid); -void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth); -int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen); -int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, - char *buf, size_t buflen); -void hostapd_get_ntp_timestamp(u8 *buf); -char *eap_type_text(u8 type); - -const char *radius_mode_txt(struct hostapd_data *hapd); -int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta); - -int add_common_radius_attr(struct hostapd_data *hapd, - struct hostapd_radius_attr *req_attr, - struct sta_info *sta, - struct radius_msg *msg); -#endif - -#endif /* IEEE802_1X_H */ diff --git a/components/wpa_supplicant/include/wpa/includes.h b/components/wpa_supplicant/include/wpa/includes.h deleted file mode 100644 index 993bc49941..0000000000 --- a/components/wpa_supplicant/include/wpa/includes.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * wpa_supplicant/hostapd - Default include files - * Copyright (c) 2005-2006, 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. - * - * This header file is included into all C files so that commonly used header - * files can be selected with OS specific ifdef blocks in one place instead of - * having to have OS/C library specific selection in many files. - */ - -#ifndef INCLUDES_H -#define INCLUDES_H - -/* Include possible build time configuration before including anything else */ -//#include "build_config.h" //don't need anymore - -//#include -//#include -//#include -//#include -//#include - -#endif /* INCLUDES_H */ diff --git a/components/wpa_supplicant/include/wpa/wpas_glue.h b/components/wpa_supplicant/include/wpa/wpas_glue.h deleted file mode 100644 index 7e254a2d7d..0000000000 --- a/components/wpa_supplicant/include/wpa/wpas_glue.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * WPA Supplicant - Glue code to setup EAPOL and RSN modules - * 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. - */ - -#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, uint8 reason_code); - -void wpa_sm_disassociate(struct wpa_sm *sm, int reason_code); - -int wpa_sm_get_beacon_ie(struct wpa_sm *sm); - -#endif /* WPAS_GLUE_H */ diff --git a/components/wpa_supplicant/include/wpa2/utils/base64.h b/components/wpa_supplicant/include/wpa2/utils/base64.h deleted file mode 100644 index aa21fd0fc1..0000000000 --- a/components/wpa_supplicant/include/wpa2/utils/base64.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Base64 encoding/decoding (RFC1341) - * Copyright (c) 2005, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef BASE64_H -#define BASE64_H - -unsigned char * base64_encode(const unsigned char *src, size_t len, - size_t *out_len); -unsigned char * base64_decode(const unsigned char *src, size_t len, - size_t *out_len); - -#endif /* BASE64_H */ diff --git a/components/wpa_supplicant/port/include/endian.h b/components/wpa_supplicant/port/include/endian.h index 0d0d4f5ba4..392b40168b 100644 --- a/components/wpa_supplicant/port/include/endian.h +++ b/components/wpa_supplicant/port/include/endian.h @@ -98,10 +98,6 @@ typedef __uint64_t uint64_t; #define le32toh(x) ((uint32_t)(x)) #define le64toh(x) ((uint64_t)(x)) -#ifndef htons -#define htons htobe16 -#endif //htons - #else /* _BYTE_ORDER != _LITTLE_ENDIAN */ #define htobe16(x) ((uint16_t)(x)) #define htobe32(x) ((uint32_t)(x)) diff --git a/components/wpa_supplicant/port/include/supplicant_opt.h b/components/wpa_supplicant/port/include/supplicant_opt.h new file mode 100644 index 0000000000..12d607add3 --- /dev/null +++ b/components/wpa_supplicant/port/include/supplicant_opt.h @@ -0,0 +1,24 @@ +// 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 _SUPPLICANT_OPT_H +#define _SUPPLICANT_OPT_H + +#include "sdkconfig.h" + +#if CONFIG_WPA_MBEDTLS_CRYPTO +#define USE_MBEDTLS_CRYPTO 1 +#endif + +#endif /* _SUPPLICANT_OPT_H */ diff --git a/components/wpa_supplicant/port/os_xtensa.c b/components/wpa_supplicant/port/os_xtensa.c index 2ab31825f2..6f52a85ea1 100644 --- a/components/wpa_supplicant/port/os_xtensa.c +++ b/components/wpa_supplicant/port/os_xtensa.c @@ -27,7 +27,7 @@ #include #include #include "esp_system.h" -#include "crypto/common.h" +#include "utils/common.h" int os_get_time(struct os_time *t) { diff --git a/components/wpa_supplicant/src/ap/ap_config.c b/components/wpa_supplicant/src/ap/ap_config.c new file mode 100644 index 0000000000..14f73547ed --- /dev/null +++ b/components/wpa_supplicant/src/ap/ap_config.c @@ -0,0 +1,248 @@ +/* + * hostapd / Configuration helper functions + * Copyright (c) 2003-2012, Jouni Malinen + * + * 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/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_supplicant/esp_wifi_driver.h" +#include "esp_wifi_types.h" + +void hostapd_config_defaults_bss(struct hostapd_bss_config *bss) +{ + bss->auth_algs = WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED; + + bss->wep_rekeying_period = 300; + /* use key0 in individual key and key1 in broadcast key */ + bss->broadcast_key_idx_min = 1; + bss->broadcast_key_idx_max = 2; + + bss->wpa_group_rekey = 600; + bss->wpa_gmk_rekey = 86400; + bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK; + bss->wpa_pairwise = WPA_CIPHER_TKIP; + bss->wpa_group = WPA_CIPHER_TKIP; + bss->rsn_pairwise = 0; + + bss->max_num_sta = MAX_STA_COUNT; + + bss->dtim_period = 2; + + bss->ap_max_inactivity = 5*60; //AP_MAX_INACTIVITY; + bss->eapol_version = EAPOL_VERSION; + + bss->max_listen_interval = 65535; + +#ifdef CONFIG_IEEE80211W + bss->assoc_sa_query_max_timeout = 1000; + bss->assoc_sa_query_retry_timeout = 201; +#endif /* CONFIG_IEEE80211W */ +#ifdef EAP_SERVER_FAST + /* both anonymous and authenticated provisioning */ + bss->eap_fast_prov = 3; + bss->pac_key_lifetime = 7 * 24 * 60 * 60; + bss->pac_key_refresh_time = 1 * 24 * 60 * 60; +#endif /* EAP_SERVER_FAST */ + + /* Set to -1 as defaults depends on HT in setup */ + bss->wmm_enabled = -1; + +#ifdef CONFIG_IEEE80211R + bss->ft_over_ds = 1; +#endif /* CONFIG_IEEE80211R */ + +} + + +struct hostapd_config * hostapd_config_defaults(void) +{ +#define ecw2cw(ecw) ((1 << (ecw)) - 1) + + struct hostapd_config *conf; + struct hostapd_bss_config *bss; +#undef ecw2cw + + conf = (struct hostapd_config *)os_zalloc(sizeof(*conf)); + bss = (struct hostapd_bss_config *)os_zalloc(sizeof(*bss)); + if (conf == NULL || bss == NULL) { + wpa_printf(MSG_DEBUG, "Failed to allocate memory for " + "configuration data."); + os_free(conf); + os_free(bss); + return NULL; + } + + hostapd_config_defaults_bss(bss); + + conf->num_bss = 1; + conf->bss = bss; + + conf->beacon_int = 100; + conf->rts_threshold = -1; /* use driver default: 2347 */ + conf->fragm_threshold = -1; /* user driver default: 2346 */ + conf->send_probe_response = 1; + + conf->ht_capab = HT_CAP_INFO_SMPS_DISABLED; + + conf->ap_table_max_size = 255; + conf->ap_table_expiration_time = 60; + + return conf; +} + + +int hostapd_mac_comp(const void *a, const void *b) +{ + return memcmp(a, b, sizeof(macaddr)); +} + + +int hostapd_mac_comp_empty(const void *a) +{ + u8 empty[ETH_ALEN]; + + os_bzero(empty, ETH_ALEN); + + return memcmp(a, empty, ETH_ALEN); +} + +static int hostapd_derive_psk(struct hostapd_ssid *ssid) +{ + ssid->wpa_psk = (struct hostapd_wpa_psk *)os_zalloc(sizeof(struct hostapd_wpa_psk)); + if (ssid->wpa_psk == NULL) { + wpa_printf(MSG_ERROR, "Unable to alloc space for PSK"); + return -1; + } + wpa_hexdump_ascii(MSG_DEBUG, "SSID", + (u8 *) ssid->ssid, ssid->ssid_len); + wpa_hexdump_ascii_key(MSG_DEBUG, "PSK (ASCII passphrase)", + (u8 *) ssid->wpa_passphrase, + strlen(ssid->wpa_passphrase)); +#ifdef ESP_SUPPLICANT + memcpy(ssid->wpa_psk->psk, esp_wifi_ap_get_prof_pmk_internal(), PMK_LEN); +#else + /* It's too SLOW */ + pbkdf2_sha1(ssid->wpa_passphrase, + ssid->ssid, ssid->ssid_len, + 4096, ssid->wpa_psk->psk, PMK_LEN); +#endif + wpa_hexdump_key(MSG_DEBUG, "PSK (from passphrase)", + ssid->wpa_psk->psk, PMK_LEN); + return 0; +} + + +int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf) +{ + struct hostapd_ssid *ssid = &conf->ssid; + + if (ssid->wpa_passphrase != NULL) { + if (ssid->wpa_psk != NULL) { + wpa_printf(MSG_DEBUG, "Using pre-configured WPA PSK " + "instead of passphrase"); + } else { + wpa_printf(MSG_DEBUG, "Deriving WPA PSK based on " + "passphrase\n"); + if (hostapd_derive_psk(ssid) < 0) + return -1; + } + ssid->wpa_psk->group = 1; + } + + return 0; +} + + +int hostapd_wep_key_cmp(struct hostapd_wep_keys *a, struct hostapd_wep_keys *b) +{ + int i; + + if (a->idx != b->idx || a->default_len != b->default_len) + return 1; + for (i = 0; i < NUM_WEP_KEYS; i++) + if (a->len[i] != b->len[i] || + memcmp(a->key[i], b->key[i], a->len[i]) != 0) + return 1; + return 0; +} + +/** + * hostapd_maclist_found - Find a MAC address from a list + * @list: MAC address list + * @num_entries: Number of addresses in the list + * @addr: Address to search for + * @vlan_id: Buffer for returning VLAN ID or %NULL if not needed + * Returns: 1 if address is in the list or 0 if not. + * + * Perform a binary search for given MAC address from a pre-sorted list. + */ +int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries, + const u8 *addr, int *vlan_id) +{ + int start, end, middle, res; + + start = 0; + end = num_entries - 1; + + while (start <= end) { + middle = (start + end) / 2; + res = memcmp(list[middle].addr, addr, ETH_ALEN); + if (res == 0) { + if (vlan_id) + *vlan_id = list[middle].vlan_id; + return 1; + } + if (res < 0) + start = middle + 1; + else + end = middle - 1; + } + + return 0; +} + + +int hostapd_rate_found(int *list, int rate) +{ + int i; + + if (list == NULL) + return 0; + + for (i = 0; list[i] >= 0; i++) + if (list[i] == rate) + return 1; + + return 0; +} + +const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf, + const u8 *addr, const u8 *prev_psk) +{ + struct hostapd_wpa_psk *psk; + int next_ok = prev_psk == NULL; + + for (psk = conf->ssid.wpa_psk; psk != NULL; psk = psk->next) { + if (next_ok && + (psk->group || memcmp(psk->addr, addr, ETH_ALEN) == 0)) + return psk->psk; + + if (psk->psk == prev_psk) + next_ok = 1; + } + + return NULL; +} + diff --git a/components/wpa_supplicant/include/wpa/ap_config.h b/components/wpa_supplicant/src/ap/ap_config.h similarity index 63% rename from components/wpa_supplicant/include/wpa/ap_config.h rename to components/wpa_supplicant/src/ap/ap_config.h index 761becb484..ca695851fa 100644 --- a/components/wpa_supplicant/include/wpa/ap_config.h +++ b/components/wpa_supplicant/src/ap/ap_config.h @@ -9,11 +9,8 @@ #ifndef HOSTAPD_CONFIG_H #define HOSTAPD_CONFIG_H -#include "wpa/defs.h" -//#include "ip_addr.h" -#include "wpa/wpa_common.h" -//#include "common/ieee802_11_common.h" -//#include "wps/wps.h" +#include "common/defs.h" +#include "common/wpa_common.h" #define MAX_STA_COUNT 4 #define MAX_VLAN_ID 4094 @@ -54,12 +51,8 @@ struct hostapd_ssid { unsigned int ssid_set:1; unsigned int utf8_ssid:1; -// char vlan[IFNAMSIZ + 1]; -// secpolicy security_policy; - struct hostapd_wpa_psk *wpa_psk; char *wpa_passphrase; -// char *wpa_psk_file; struct hostapd_wep_keys wep; @@ -183,70 +176,22 @@ struct hostapd_nai_realm_data { * struct hostapd_bss_config - Per-BSS configuration */ struct hostapd_bss_config { -// char iface[IFNAMSIZ + 1]; -// char bridge[IFNAMSIZ + 1]; -// char wds_bridge[IFNAMSIZ + 1]; - -// enum hostapd_logger_level logger_syslog_level, logger_stdout_level; - -// unsigned int logger_syslog; /* module bitfield */ -// unsigned int logger_stdout; /* module bitfield */ - -// char *dump_log_name; /* file name for state dump (SIGUSR1) */ - int max_num_sta; /* maximum number of STAs in station table */ int dtim_period; int ieee802_1x; /* use IEEE 802.1X */ int eapol_version; -// int eap_server; /* Use internal EAP server instead of external -// * RADIUS server */ -// struct hostapd_eap_user *eap_user; -// char *eap_user_sqlite; -// char *eap_sim_db; -// struct hostapd_ip_addr own_ip_addr; -// char *nas_identifier; -// struct hostapd_radius_servers *radius; -// int acct_interim_interval; -// int radius_request_cui; -// struct hostapd_radius_attr *radius_auth_req_attr; -// struct hostapd_radius_attr *radius_acct_req_attr; -// int radius_das_port; -// unsigned int radius_das_time_window; -// int radius_das_require_event_timestamp; -// struct hostapd_ip_addr radius_das_client_addr; -// u8 *radius_das_shared_secret; -// size_t radius_das_shared_secret_len; - struct hostapd_ssid ssid; -// char *eap_req_id_text; /* optional displayable message sent with -// * EAP Request-Identity */ -// size_t eap_req_id_text_len; -// int eapol_key_index_workaround; - -// size_t default_wep_key_len; -// int individual_wep_key_len; int wep_rekeying_period; int broadcast_key_idx_min, broadcast_key_idx_max; -// int eap_reauth_period; - -// int ieee802_11f; /* use IEEE 802.11f (IAPP) */ -// char iapp_iface[IFNAMSIZ + 1]; /* interface used with IAPP broadcast -// * frames */ enum { ACCEPT_UNLESS_DENIED = 0, DENY_UNLESS_ACCEPTED = 1, USE_EXTERNAL_RADIUS_AUTH = 2 } macaddr_acl; -// struct mac_acl_entry *accept_mac; -// int num_accept_mac; -// struct mac_acl_entry *deny_mac; -// int num_deny_mac; -// int wds_sta; -// int isolate; int auth_algs; /* bitfield of allowed IEEE 802.11 authentication * algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */ @@ -288,49 +233,12 @@ struct hostapd_bss_config { int ft_over_ds; #endif /* CONFIG_IEEE80211R */ -// char *ctrl_interface; /* directory for UNIX domain sockets */ -#ifndef CONFIG_NATIVE_WINDOWS -// gid_t ctrl_interface_gid; -#endif /* CONFIG_NATIVE_WINDOWS */ -// int ctrl_interface_gid_set; - -// char *ca_cert; -// char *server_cert; -// char *private_key; -// char *private_key_passwd; -// int check_crl; -// char *dh_file; -// u8 *pac_opaque_encr_key; -// u8 *eap_fast_a_id; -// size_t eap_fast_a_id_len; -// char *eap_fast_a_id_info; -// int eap_fast_prov; -// int pac_key_lifetime; -// int pac_key_refresh_time; -// int eap_sim_aka_result_ind; -// int tnc; -// int fragment_size; -// u16 pwd_group; - -// char *radius_server_clients; -// int radius_server_auth_port; -// int radius_server_ipv6; - -// char *test_socket; /* UNIX domain socket path for driver_test */ - -// int use_pae_group_addr; /* Whether to send EAPOL frames to PAE group -// * address instead of individual address -// * (for driver_wired.c). -// */ - int ap_max_inactivity; int ignore_broadcast_ssid; int wmm_enabled; int wmm_uapsd; -// struct hostapd_vlan *vlan, *vlan_tail; - macaddr bssid; /* @@ -340,10 +248,6 @@ struct hostapd_bss_config { */ u16 max_listen_interval; -// int disable_pmksa_caching; -// int okc; /* Opportunistic Key Caching */ - -// int wps_state; #ifdef CONFIG_WPS int ap_setup_locked; u8 uuid[16]; @@ -375,71 +279,6 @@ struct hostapd_bss_config { struct wpabuf *wps_nfc_dh_privkey; struct wpabuf *wps_nfc_dev_pw; #endif /* CONFIG_WPS */ -// int pbc_in_m1; - -#define P2P_ENABLED BIT(0) -#define P2P_GROUP_OWNER BIT(1) -#define P2P_GROUP_FORMATION BIT(2) -#define P2P_MANAGE BIT(3) -#define P2P_ALLOW_CROSS_CONNECTION BIT(4) -// int p2p; - -// int disassoc_low_ack; -// int skip_inactivity_poll; - -#define TDLS_PROHIBIT BIT(0) -#define TDLS_PROHIBIT_CHAN_SWITCH BIT(1) -// int tdls; -// int disable_11n; -// int disable_11ac; - - /* IEEE 802.11v */ -// int time_advertisement; -// char *time_zone; -// int wnm_sleep_mode; -// int bss_transition; - - /* IEEE 802.11u - Interworking */ -// int interworking; -// int access_network_type; -// int internet; -// int asra; -// int esr; -// int uesa; -// int venue_info_set; -// u8 venue_group; -// u8 venue_type; -// u8 hessid[ETH_ALEN]; - - /* IEEE 802.11u - Roaming Consortium list */ -// unsigned int roaming_consortium_count; -// struct hostapd_roaming_consortium *roaming_consortium; - - /* IEEE 802.11u - Venue Name duples */ -// unsigned int venue_name_count; -// struct hostapd_lang_string *venue_name; - - /* IEEE 802.11u - Network Authentication Type */ -// u8 *network_auth_type; -// size_t network_auth_type_len; - - /* IEEE 802.11u - IP Address Type Availability */ -// u8 ipaddr_type_availability; -// u8 ipaddr_type_configured; - - /* IEEE 802.11u - 3GPP Cellular Network */ -// u8 *anqp_3gpp_cell_net; -// size_t anqp_3gpp_cell_net_len; - - /* IEEE 802.11u - Domain Name */ -// u8 *domain_name; -// size_t domain_name_len; - -// unsigned int nai_realm_count; -// struct hostapd_nai_realm_data *nai_realm_data; - -// u16 gas_comeback_delay; -// int gas_frag_limit; #ifdef CONFIG_HS20 int hs20; @@ -453,13 +292,10 @@ struct hostapd_bss_config { u8 hs20_operating_class_len; #endif /* CONFIG_HS20 */ -// u8 wps_rf_bands; /* RF bands for WPS (WPS_RF_*) */ - #ifdef CONFIG_RADIUS_TEST char *dump_msk_file; #endif /* CONFIG_RADIUS_TEST */ -// struct wpabuf *vendor_elements; }; @@ -498,8 +334,6 @@ struct hostapd_config { int ieee80211d; -// struct hostapd_tx_queue_params tx_queue[NUM_TX_QUEUES]; - /* * WMM AC parameters, in same order as 802.1D, i.e. * 0 = BE (best effort) @@ -507,7 +341,6 @@ struct hostapd_config { * 2 = VI (video) * 3 = VO (voice) */ -// struct hostapd_wmm_ac_params wmm_ac_params[4]; int ht_op_mode_fixed; u16 ht_capab; @@ -536,9 +369,7 @@ int hostapd_wep_key_cmp(struct hostapd_wep_keys *a, const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf, const u8 *addr, const u8 *prev_psk); int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf); -//const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, -// int vlan_id); -//struct hostapd_radius_attr * -//hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type); +bool wpa_ap_join(void** sm, uint8_t *bssid, uint8_t *wpa_ie, uint8_t wpa_ie_len); +bool wpa_ap_remove(void* sm); #endif /* HOSTAPD_CONFIG_H */ diff --git a/components/wpa_supplicant/src/ap/hostapd.h b/components/wpa_supplicant/src/ap/hostapd.h new file mode 100644 index 0000000000..5bedf09d0a --- /dev/null +++ b/components/wpa_supplicant/src/ap/hostapd.h @@ -0,0 +1,115 @@ +/* + * hostapd / Initialization and configuration + * Copyright (c) 2002-2009, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef HOSTAPD_H +#define HOSTAPD_H + +#include "common/defs.h" +#include "ap/ap_config.h" + +struct wpa_driver_ops; +struct wpa_ctrl_dst; +struct radius_server_data; +struct upnp_wps_device_sm; +struct hostapd_data; +struct sta_info; +struct hostap_sta_driver_data; +struct ieee80211_ht_capabilities; +struct full_dynamic_vlan; +enum wps_event; +union wps_event_data; + +struct hostapd_iface; + +struct hapd_interfaces { + int (*reload_config)(struct hostapd_iface *iface); + struct hostapd_config * (*config_read_cb)(const char *config_fname); + int (*ctrl_iface_init)(struct hostapd_data *hapd); + void (*ctrl_iface_deinit)(struct hostapd_data *hapd); + int (*for_each_interface)(struct hapd_interfaces *interfaces, + int (*cb)(struct hostapd_iface *iface, + void *ctx), void *ctx); + int (*driver_init)(struct hostapd_iface *iface); + + size_t count; + int global_ctrl_sock; + char *global_iface_path; + char *global_iface_name; + struct hostapd_iface **iface; +}; + + +struct hostapd_probereq_cb { + int (*cb)(void *ctx, const u8 *sa, const u8 *da, const u8 *bssid, + const u8 *ie, size_t ie_len, int ssi_signal); + void *ctx; +}; + +#define HOSTAPD_RATE_BASIC 0x00000001 + +struct hostapd_rate_data { + int rate; /* rate in 100 kbps */ + int flags; /* HOSTAPD_RATE_ flags */ +}; + +struct hostapd_frame_info { + u32 channel; + u32 datarate; + int ssi_signal; /* dBm */ +}; + + +/** + * struct hostapd_data - hostapd per-BSS data structure + */ +struct hostapd_data { + struct hostapd_config *iconf; + struct hostapd_bss_config *conf; + int interface_added; /* virtual interface added for this BSS */ + + u8 own_addr[ETH_ALEN]; + + int num_sta; /* number of entries in sta_list */ + + struct wpa_authenticator *wpa_auth; + +#ifdef CONFIG_FULL_DYNAMIC_VLAN + struct full_dynamic_vlan *full_dynamic_vlan; +#endif /* CONFIG_FULL_DYNAMIC_VLAN */ + +#ifdef CONFIG_WPS + unsigned int ap_pin_failures; + unsigned int ap_pin_failures_consecutive; + struct upnp_wps_device_sm *wps_upnp; + unsigned int ap_pin_lockout_time; +#endif /* CONFIG_WPS */ + +#ifdef CONFIG_P2P + struct p2p_data *p2p; + struct p2p_group *p2p_group; + struct wpabuf *p2p_beacon_ie; + struct wpabuf *p2p_probe_resp_ie; + + /* Number of non-P2P association stations */ + int num_sta_no_p2p; + + /* Periodic NoA (used only when no non-P2P clients in the group) */ + int noa_enabled; + int noa_start; + int noa_duration; +#endif /* CONFIG_P2P */ +#ifdef CONFIG_INTERWORKING + size_t gas_frag_limit; +#endif /* CONFIG_INTERWORKING */ + +#ifdef CONFIG_SQLITE + struct hostapd_eap_user tmp_eap_user; +#endif /* CONFIG_SQLITE */ +}; + +#endif /* HOSTAPD_H */ diff --git a/components/wpa_supplicant/src/ap/ieee802_1x.c b/components/wpa_supplicant/src/ap/ieee802_1x.c new file mode 100644 index 0000000000..62de7f5940 --- /dev/null +++ b/components/wpa_supplicant/src/ap/ieee802_1x.c @@ -0,0 +1,77 @@ +/* + * hostapd / IEEE 802.1X-2004 Authenticator + * Copyright (c) 2002-2012, Jouni Malinen + * + * 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 "common/ieee802_11_defs.h" +#include "hostapd.h" +#include "ap/sta_info.h" +#include "ap/wpa_auth.h" +#include "ap/ap_config.h" +#include "ap/ieee802_1x.h" +#include "utils/wpa_debug.h" + +/** + * ieee802_1x_receive - Process the EAPOL frames from the Supplicant + * @hapd: hostapd BSS data + * @sa: Source address (sender of the EAPOL frame) + * @buf: EAPOL frame + * @len: Length of buf in octets + * + * This function is called for each incoming EAPOL frame from the interface + */ +void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, + size_t len) +{ + struct sta_info *sta; + struct ieee802_1x_hdr *hdr; + struct ieee802_1x_eapol_key *key; + u16 datalen; + + wpa_printf( MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR, + (unsigned long) len, MAC2STR(sa)); + sta = ap_get_sta(hapd, sa); + if (!sta || !(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH))) { + wpa_printf( MSG_DEBUG, "IEEE 802.1X data frame from not " + "associated/Pre-authenticating STA"); + return; + } + + if (len < sizeof(*hdr)) { + wpa_printf( MSG_DEBUG, " too short IEEE 802.1X packet\n"); + return; + } + + hdr = (struct ieee802_1x_hdr *) buf; + datalen = be_to_host16(hdr->length); + wpa_printf( MSG_DEBUG, " IEEE 802.1X: version=%d type=%d length=%d", + hdr->version, hdr->type, datalen); + + if (len - sizeof(*hdr) < datalen) { + wpa_printf( MSG_DEBUG, " frame too short for this IEEE 802.1X packet\n"); + return; + } + if (len - sizeof(*hdr) > datalen) { + wpa_printf( MSG_DEBUG, " ignoring %lu extra octets after " + "IEEE 802.1X packet", + (unsigned long) len - sizeof(*hdr) - datalen); + } + + key = (struct ieee802_1x_eapol_key *) (hdr + 1); + if (datalen >= sizeof(struct ieee802_1x_eapol_key) && + hdr->type == IEEE802_1X_TYPE_EAPOL_KEY && + (key->type == EAPOL_KEY_TYPE_WPA || + key->type == EAPOL_KEY_TYPE_RSN)) { + wpa_receive(hapd->wpa_auth, sta->wpa_sm, (u8 *) hdr, + sizeof(*hdr) + datalen); + return; + } +} + diff --git a/components/wpa_supplicant/src/ap/ieee802_1x.h b/components/wpa_supplicant/src/ap/ieee802_1x.h new file mode 100644 index 0000000000..60051ee5a0 --- /dev/null +++ b/components/wpa_supplicant/src/ap/ieee802_1x.h @@ -0,0 +1,24 @@ +/* + * hostapd / IEEE 802.1X-2004 Authenticator + * Copyright (c) 2002-2012, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef IEEE802_1X_H +#define IEEE802_1X_H + +struct hostapd_data; +struct sta_info; +struct eapol_state_machine; +struct hostapd_config; +struct hostapd_bss_config; +struct hostapd_radius_attr; +struct radius_msg; + + +void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, + size_t len); + +#endif /* IEEE802_1X_H */ diff --git a/components/wpa_supplicant/include/wpa/sta_info.h b/components/wpa_supplicant/src/ap/sta_info.h similarity index 74% rename from components/wpa_supplicant/include/wpa/sta_info.h rename to components/wpa_supplicant/src/ap/sta_info.h index 44874a2ff9..b187933f7e 100644 --- a/components/wpa_supplicant/include/wpa/sta_info.h +++ b/components/wpa_supplicant/src/ap/sta_info.h @@ -48,61 +48,14 @@ struct sta_info { u16 listen_interval; /* or beacon_int for APs */ u8 supported_rates[WLAN_SUPP_RATES_MAX]; int supported_rates_len; -// u8 qosinfo; /* Valid when WLAN_STA_WMM is set */ - -// unsigned int nonerp_set:1; -// unsigned int no_short_slot_time_set:1; -// unsigned int no_short_preamble_set:1; -// unsigned int no_ht_gf_set:1; -// unsigned int no_ht_set:1; -// unsigned int ht_20mhz_set:1; -// unsigned int no_p2p_set:1; u16 auth_alg; -// u8 previous_ap[6]; enum { STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE } timeout_next; -// u16 deauth_reason; -// u16 disassoc_reason; - - /* IEEE 802.1X related data */ -// struct eapol_state_machine *eapol_sm; - - /* IEEE 802.11f (IAPP) related data */ -// struct ieee80211_mgmt *last_assoc_req; - -// u32 acct_session_id_hi; -// u32 acct_session_id_lo; -// time_t acct_session_start; -// int acct_session_started; -// int acct_terminate_cause; /* Acct-Terminate-Cause */ -// int acct_interim_interval; /* Acct-Interim-Interval */ - -// unsigned long last_rx_bytes; -// unsigned long last_tx_bytes; -// u32 acct_input_gigawords; /* Acct-Input-Gigawords */ -// u32 acct_output_gigawords; /* Acct-Output-Gigawords */ - -// u8 *challenge; /* IEEE 802.11 Shared Key Authentication Challenge */ - struct wpa_state_machine *wpa_sm; -// struct rsn_preauth_interface *preauth_iface; - - struct hostapd_ssid *ssid; /* SSID selection based on (Re)AssocReq */ -// struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */ - -// int vlan_id; - /* PSKs from RADIUS authentication server */ -// struct hostapd_sta_wpa_psk_short *psk; - -// char *identity; /* User-Name from RADIUS */ -// char *radius_cui; /* Chargeable-User-Identity from RADIUS */ - -// struct ieee80211_ht_capabilities *ht_capabilities; -// struct ieee80211_vht_capabilities *vht_capabilities; #ifdef CONFIG_IEEE80211W int sa_query_count; /* number of pending SA Query requests; @@ -120,12 +73,6 @@ struct sta_info { u8 gas_dialog_next; #endif /* CONFIG_INTERWORKING */ -// struct wpabuf *wps_ie; /* WPS IE from (Re)Association Request */ -// struct wpabuf *p2p_ie; /* P2P IE from (Re)Association Request */ -// struct wpabuf *hs20_ie; /* HS 2.0 IE from (Re)Association Request */ - -// struct os_time connected_time; - #ifdef CONFIG_SAE enum { SAE_INIT, SAE_COMMIT, SAE_CONFIRM } sae_state; u16 sae_send_confirm; diff --git a/components/wpa_supplicant/src/ap/wpa_auth.c b/components/wpa_supplicant/src/ap/wpa_auth.c new file mode 100644 index 0000000000..58625bb553 --- /dev/null +++ b/components/wpa_supplicant/src/ap/wpa_auth.c @@ -0,0 +1,2439 @@ +/* + * IEEE 802.11 RSN / WPA Authenticator + * Copyright (c) 2004-2011, Jouni Malinen + * + * 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 "utils/state_machine.h" +#include "common/ieee802_11_defs.h" +#include "ap/wpa_auth.h" +#include "ap/wpa_auth_i.h" +#include "ap/wpa_auth_ie.h" +#include "utils/wpa_debug.h" +#include "hostapd.h" +#include "rsn_supp/wpa.h" +#include "ap/ap_config.h" +#include "common/wpa_common.h" + +#include "crypto/aes_wrap.h" +#include "crypto/crypto.h" +#include "crypto/sha1.h" +#include "crypto/sha256.h" +#include "crypto/random.h" + +#include "esp_supplicant/esp_wifi_driver.h" +#include "esp_wifi.h" +#include "esp_private/wifi.h" + +#define STATE_MACHINE_DATA struct wpa_state_machine +#define STATE_MACHINE_DEBUG_PREFIX "WPA" +#define STATE_MACHINE_ADDR sm->addr + + +static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx); +static int wpa_sm_step(struct wpa_state_machine *sm); +static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len); +static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth, + struct wpa_group *group); +static void wpa_request_new_ptk(struct wpa_state_machine *sm); +static int wpa_gtk_update(struct wpa_authenticator *wpa_auth, + struct wpa_group *group); +static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth, + struct wpa_group *group); + +static const u32 dot11RSNAConfigGroupUpdateCount = 4; +static const u32 dot11RSNAConfigPairwiseUpdateCount = 4; +static const u32 eapol_key_timeout_first = 100; /* ms */ +static const u32 eapol_key_timeout_subseq = 1000; /* ms */ +static const u32 eapol_key_timeout_first_group = 500; /* ms */ + +#define WPA_SM_MAX_INDEX 16 +static void *s_sm_table[WPA_SM_MAX_INDEX]; +static u32 s_sm_valid_bitmap = 0; + +static struct wpa_state_machine * wpa_auth_get_sm(u32 index) +{ + if ( (index < WPA_SM_MAX_INDEX) && (BIT(index) & s_sm_valid_bitmap)){ + return s_sm_table[index]; + } + + return NULL; +} + +static void wpa_auth_add_sm(struct wpa_state_machine *sm) +{ + if (sm) { + u8 i; + for (i=0; iindex = i; + wpa_printf( MSG_DEBUG, "add sm, index=%d bitmap=%x\n", i, s_sm_valid_bitmap); + return; + } + } +} + +static void wpa_auth_del_sm(struct wpa_state_machine *sm) +{ + if (sm && (sm->index < WPA_SM_MAX_INDEX)) { + if (sm != s_sm_table[sm->index]) { + wpa_printf( MSG_INFO, "del sm error %d", sm->index); + } + s_sm_table[sm->index] = NULL; + s_sm_valid_bitmap &= ~BIT(sm->index); + wpa_printf( MSG_DEBUG, "del sm, index=%d bitmap=%x\n", sm->index, s_sm_valid_bitmap); + } +} + +static inline int wpa_auth_mic_failure_report( + struct wpa_authenticator *wpa_auth, const u8 *addr) +{ + return 0; +} + + +static inline void wpa_auth_set_eapol(struct wpa_authenticator *wpa_auth, + const u8 *addr, wpa_eapol_variable var, + int value) +{ +} + + +static inline int wpa_auth_get_eapol(struct wpa_authenticator *wpa_auth, + const u8 *addr, wpa_eapol_variable var) +{ + return -1; +} + +static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth, + const u8 *addr, const u8 *prev_psk) +{ + struct hostapd_data *hapd = (struct hostapd_data *)esp_wifi_get_hostap_private_internal(); + + if (!hapd){ + return NULL; + } + + return (u8*)hostapd_get_psk(hapd->conf, addr, prev_psk); +} + +static inline int wpa_auth_get_msk(struct wpa_authenticator *wpa_auth, + const u8 *addr, u8 *msk, size_t *len) +{ + return -1; +} + +static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth, + int vlan_id, + enum wpa_alg alg, const u8 *addr, int idx, + u8 *key, size_t key_len) +{ + return esp_wifi_set_ap_key_internal(alg, addr, idx, key, key_len); +} + + +static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth, + const u8 *addr, int idx, u8 *seq) +{ + return -1; +} + +/* fix buf for tx for now */ +#define WPA_TX_MSG_BUFF_MAXLEN 200 + +static inline int +wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr, + const u8 *data, size_t data_len, int encrypt) +{ + void *buffer = os_malloc(256); + struct l2_ethhdr *eth = buffer; + + if (!buffer){ + wpa_printf( MSG_DEBUG, "send_eapol, buffer=%p\n", buffer); + return -1; + } + + memcpy(eth->h_dest, addr, ETH_ALEN); + memcpy(eth->h_source, wpa_auth->addr, ETH_ALEN); + eth->h_proto = host_to_be16(ETH_P_EAPOL); + + memcpy((char *)buffer + sizeof(struct l2_ethhdr), data, data_len); + esp_wifi_internal_tx(1, buffer, sizeof(struct l2_ethhdr) + data_len); + os_free(buffer); + return 0; +} + +int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth, + int (*cb)(struct wpa_state_machine *sm, void *ctx), + void *cb_ctx) +{ + return 0; +} + +static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth, + const u8 *addr) +{ + wpa_printf(MSG_DEBUG, "wpa_sta_disconnect STA " MACSTR, MAC2STR(addr)); + esp_wifi_ap_deauth_internal((uint8_t*)addr, WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT); + return; +} + +static int wpa_use_aes_cmac(struct wpa_state_machine *sm) +{ + int ret = 0; +#ifdef CONFIG_IEEE80211R + if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) + ret = 1; +#endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_IEEE80211W + if (wpa_key_mgmt_sha256(sm->wpa_key_mgmt)) + ret = 1; +#endif /* CONFIG_IEEE80211W */ + return ret; +} + +static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_authenticator *wpa_auth = eloop_ctx; + struct wpa_group *group; + + for (group = wpa_auth->group; group; group = group->next) { + group->GTKReKey = TRUE; + do { + group->changed = FALSE; + wpa_group_sm_step(wpa_auth, group); + } while (group->changed); + } + + if (wpa_auth->conf.wpa_group_rekey) { + eloop_register_timeout(wpa_auth->conf.wpa_group_rekey, + 0, wpa_rekey_gtk, wpa_auth, NULL); + } +} + + +static void wpa_rekey_ptk(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_state_machine *sm = timeout_ctx; + + wpa_request_new_ptk(sm); + wpa_sm_step(sm); +} + +static int wpa_group_init_gmk_and_counter(struct wpa_authenticator *wpa_auth, + struct wpa_group *group) +{ + u8 buf[ETH_ALEN + 8 + sizeof(group)]; + u8 rkey[32]; + + if (os_get_random(group->GMK, WPA_GMK_LEN) < 0) + return -1; + wpa_hexdump_key(MSG_DEBUG, "GMK", group->GMK, WPA_GMK_LEN); + + /* + * Counter = PRF-256(Random number, "Init Counter", + * Local MAC Address || Time) + */ + memcpy(buf, wpa_auth->addr, ETH_ALEN); + wpa_get_ntp_timestamp(buf + ETH_ALEN); + memcpy(buf + ETH_ALEN + 8, &group, sizeof(group)); + if (os_get_random(rkey, sizeof(rkey)) < 0) + return -1; + + if (sha1_prf(rkey, sizeof(rkey), "Init Counter", buf, sizeof(buf), + group->Counter, WPA_NONCE_LEN) < 0) + return -1; + wpa_hexdump_key(MSG_DEBUG, "Key Counter", + group->Counter, WPA_NONCE_LEN); + + return 0; +} + +static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth, + int vlan_id, int delay_init) +{ + struct wpa_group *group; + group = (struct wpa_group *)os_zalloc(sizeof(struct wpa_group)); + if (group == NULL) + return NULL; + + group->GTKAuthenticator = TRUE; + group->GTK_len = wpa_cipher_key_len(wpa_auth->conf.wpa_group); + + if (random_pool_ready() != 1) { + wpa_printf( MSG_INFO, "WPA: Not enough entropy in random pool " + "for secure operations - update keys later when " + "the first station connects"); + } + + /* + * Set initial GMK/Counter value here. The actual values that will be + * used in negotiations will be set once the first station tries to + * connect. This allows more time for collecting additional randomness + * on embedded devices. + */ + if (wpa_group_init_gmk_and_counter(wpa_auth, group) < 0) { + wpa_printf( MSG_ERROR, "Failed to get random data for WPA " + "initialization."); + os_free(group); + return NULL; + } + + group->GInit = TRUE; + if (delay_init) { + wpa_printf( MSG_DEBUG, "WPA: Delay group state machine start " + "until Beacon frames have been configured\n"); + /* Initialization is completed in wpa_init_keys(). */ + } else { + wpa_group_sm_step(wpa_auth, group); + group->GInit = FALSE; + wpa_group_sm_step(wpa_auth, group); + } + + return group; +} + + +/** + * wpa_init - Initialize WPA authenticator + * @addr: Authenticator address + * @conf: Configuration for WPA authenticator + * @cb: Callback functions for WPA authenticator + * Returns: Pointer to WPA authenticator data or %NULL on failure + */ +struct wpa_authenticator * wpa_init(const u8 *addr, + struct wpa_auth_config *conf, + struct wpa_auth_callbacks *cb) +{ + struct wpa_authenticator *wpa_auth; + wpa_auth = (struct wpa_authenticator *)os_zalloc(sizeof(struct wpa_authenticator)); + if (wpa_auth == NULL) + return NULL; + memcpy(wpa_auth->addr, addr, ETH_ALEN); + memcpy(&wpa_auth->conf, conf, sizeof(*conf)); + + if (wpa_auth_gen_wpa_ie(wpa_auth)) { + wpa_printf( MSG_ERROR, "Could not generate WPA IE."); + os_free(wpa_auth); + return NULL; + } + + wpa_auth->group = wpa_group_init(wpa_auth, 0, 0); + if (wpa_auth->group == NULL) { + os_free(wpa_auth->wpa_ie); + os_free(wpa_auth); + return NULL; + } + +#ifdef CONFIG_IEEE80211R + wpa_auth->ft_pmk_cache = wpa_ft_pmk_cache_init(); + if (wpa_auth->ft_pmk_cache == NULL) { + wpa_printf( MSG_ERROR, "FT PMK cache initialization failed."); + os_free(wpa_auth->wpa_ie); + pmksa_cache_auth_deinit(wpa_auth->pmksa); + os_free(wpa_auth); + return NULL; + } +#endif /* CONFIG_IEEE80211R */ + + return wpa_auth; +} + +struct wpa_state_machine * +wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr) +{ + struct wpa_state_machine *sm; + + sm = (struct wpa_state_machine *)os_zalloc(sizeof(struct wpa_state_machine)); + if (sm == NULL) + return NULL; + memcpy(sm->addr, addr, ETH_ALEN); + + sm->wpa_auth = wpa_auth; + sm->group = wpa_auth->group; + wpa_auth_add_sm(sm); + + return sm; +} + +int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm) +{ + if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL) + return -1; + +#ifdef CONFIG_IEEE80211R + if (sm->ft_completed) { + wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, + "FT authentication already completed - do not " + "start 4-way handshake"); + return 0; + } +#endif /* CONFIG_IEEE80211R */ + + if (sm->started) { + memset(&sm->key_replay, 0, sizeof(sm->key_replay)); + sm->ReAuthenticationRequest = TRUE; + return wpa_sm_step(sm); + } + + sm->started = 1; + + sm->Init = TRUE; + if (wpa_sm_step(sm) == 1) + return 1; /* should not really happen */ + sm->Init = FALSE; + sm->AuthenticationRequest = TRUE; + return wpa_sm_step(sm); +} + + +void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm) +{ + /* WPA/RSN was not used - clear WPA state. This is needed if the STA + * reassociates back to the same AP while the previous entry for the + * STA has not yet been removed. */ + if (sm == NULL) + return; + + sm->wpa_key_mgmt = 0; +} + + +static void wpa_free_sta_sm(struct wpa_state_machine *sm) +{ + wpa_auth_del_sm(sm); + if (sm->GUpdateStationKeys) { + sm->group->GKeyDoneStations--; + sm->GUpdateStationKeys = FALSE; + } +#ifdef CONFIG_IEEE80211R + os_free(sm->assoc_resp_ftie); +#endif /* CONFIG_IEEE80211R */ + wpa_printf( MSG_DEBUG, "wpa_free_sta_sm: free eapol=%p\n", sm->last_rx_eapol_key); + os_free(sm->last_rx_eapol_key); + os_free(sm->wpa_ie); + os_free(sm); +} + + +void wpa_auth_sta_deinit(struct wpa_state_machine *sm) +{ + wpa_printf( MSG_DEBUG, "deinit sm=%p\n", sm); + if (sm == NULL) + return; + + ets_timer_disarm(&sm->resend_eapol); + ets_timer_done(&sm->resend_eapol); + + if (sm->in_step_loop) { + /* Must not free state machine while wpa_sm_step() is running. + * Freeing will be completed in the end of wpa_sm_step(). */ + wpa_printf( MSG_DEBUG, "WPA: Registering pending STA state " + "machine deinit for " MACSTR, MAC2STR(sm->addr)); + sm->pending_deinit = 1; + } else + wpa_free_sta_sm(sm); +} + + +static void wpa_request_new_ptk(struct wpa_state_machine *sm) +{ + if (sm == NULL) + return; + + sm->PTKRequest = TRUE; + sm->PTK_valid = 0; +} + +static int wpa_replay_counter_valid(struct wpa_key_replay_counter *ctr, + const u8 *replay_counter) +{ + int i; + for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) { + if (!ctr[i].valid) + break; + if (memcmp(replay_counter, ctr[i].counter, + WPA_REPLAY_COUNTER_LEN) == 0) + return 1; + } + return 0; +} + +static void wpa_replay_counter_mark_invalid(struct wpa_key_replay_counter *ctr, + const u8 *replay_counter) +{ + int i; + for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) { + if (ctr[i].valid && + (replay_counter == NULL || + memcmp(replay_counter, ctr[i].counter, + WPA_REPLAY_COUNTER_LEN) == 0)) + ctr[i].valid = FALSE; + } +} + +#ifdef CONFIG_IEEE80211R +static int ICACHE_FLASH_ATTR ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm, + struct wpa_eapol_ie_parse *kde) +{ + struct wpa_ie_data ie; + struct rsn_mdie *mdie; + + if (wpa_parse_wpa_ie_rsn(kde->rsn_ie, kde->rsn_ie_len, &ie) < 0 || + ie.num_pmkid != 1 || ie.pmkid == NULL) { + wpa_printf( MSG_DEBUG, "FT: No PMKR1Name in " + "FT 4-way handshake message 2/4"); + return -1; + } + + memcpy(sm->sup_pmk_r1_name, ie.pmkid, PMKID_LEN); + wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from Supplicant", + sm->sup_pmk_r1_name, PMKID_LEN); + + if (!kde->mdie || !kde->ftie) { + wpa_printf( MSG_DEBUG, "FT: No %s in FT 4-way handshake " + "message 2/4", kde->mdie ? "FTIE" : "MDIE"); + return -1; + } + + mdie = (struct rsn_mdie *) (kde->mdie + 2); + if (kde->mdie[1] < sizeof(struct rsn_mdie) || + memcmp(wpa_auth->conf.mobility_domain, mdie->mobility_domain, + MOBILITY_DOMAIN_ID_LEN) != 0) { + wpa_printf( MSG_DEBUG, "FT: MDIE mismatch"); + return -1; + } + + if (sm->assoc_resp_ftie && + (kde->ftie[1] != sm->assoc_resp_ftie[1] || + memcmp(kde->ftie, sm->assoc_resp_ftie, + 2 + sm->assoc_resp_ftie[1]) != 0)) { + wpa_printf( MSG_DEBUG, "FT: FTIE mismatch"); + wpa_hexdump(MSG_DEBUG, "FT: FTIE in EAPOL-Key msg 2/4", + kde->ftie, kde->ftie_len); + wpa_hexdump(MSG_DEBUG, "FT: FTIE in (Re)AssocResp", + sm->assoc_resp_ftie, 2 + sm->assoc_resp_ftie[1]); + return -1; + } + + return 0; +} +#endif /* CONFIG_IEEE80211R */ + +static int wpa_receive_error_report(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm, int group) +{ + if (group && wpa_auth->conf.wpa_group != WPA_CIPHER_TKIP) { + } else if (!group && sm->pairwise != WPA_CIPHER_TKIP) { + } else { + if (wpa_auth_mic_failure_report(wpa_auth, sm->addr) > 0) + return 1; /* STA entry was removed */ + } + + /* + * Error report is not a request for a new key handshake, but since + * Authenticator may do it, let's change the keys now anyway. + */ + wpa_request_new_ptk(sm); + return 0; +} + +void wpa_receive(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, u8 *data, size_t data_len) +{ + struct ieee802_1x_hdr *hdr; + struct wpa_eapol_key *key; + u16 key_info, key_data_length; + enum { PAIRWISE_2, PAIRWISE_4, GROUP_2, REQUEST, + SMK_M1, SMK_M3, SMK_ERROR } msg; + struct wpa_eapol_ie_parse kde; + int ft; + const u8 *eapol_key_ie; + size_t eapol_key_ie_len; + + if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL) + return; + + if (data_len < sizeof(*hdr) + sizeof(*key)) + return; + + hdr = (struct ieee802_1x_hdr *) data; + key = (struct wpa_eapol_key *) (hdr + 1); + key_info = WPA_GET_BE16(key->key_info); + key_data_length = WPA_GET_BE16(key->key_data_length); + wpa_printf( MSG_DEBUG, "WPA: Received EAPOL-Key from " MACSTR + " key_info=0x%x type=%u key_data_length=%u\n", + MAC2STR(sm->addr), key_info, key->type, key_data_length); + if (key_data_length > data_len - sizeof(*hdr) - sizeof(*key)) { + wpa_printf( MSG_INFO, "WPA: Invalid EAPOL-Key frame - " + "key_data overflow (%d > %lu)\n", + key_data_length, + (unsigned long) (data_len - sizeof(*hdr) - + sizeof(*key))); + return; + } + + if (sm->wpa == WPA_VERSION_WPA2) { + if (key->type == EAPOL_KEY_TYPE_WPA) { + /* + * Some deployed station implementations seem to send + * msg 4/4 with incorrect type value in WPA2 mode. + */ + wpa_printf( MSG_DEBUG, "Workaround: Allow EAPOL-Key " + "with unexpected WPA type in RSN mode\n"); + } else if (key->type != EAPOL_KEY_TYPE_RSN) { + wpa_printf( MSG_DEBUG, "Ignore EAPOL-Key with " + "unexpected type %d in RSN mode\n", + key->type); + return; + } + } else { + if (key->type != EAPOL_KEY_TYPE_WPA) { + wpa_printf( MSG_DEBUG, "Ignore EAPOL-Key with " + "unexpected type %d in WPA mode\n", + key->type); + return; + } + } + + wpa_hexdump(MSG_DEBUG, "WPA: Received Key Nonce", key->key_nonce, + WPA_NONCE_LEN); + wpa_hexdump(MSG_DEBUG, "WPA: Received Replay Counter", + key->replay_counter, WPA_REPLAY_COUNTER_LEN); + + /* FIX: verify that the EAPOL-Key frame was encrypted if pairwise keys + * are set */ + + if ((key_info & (WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_REQUEST)) == + (WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_REQUEST)) { + if (key_info & WPA_KEY_INFO_ERROR) { + msg = SMK_ERROR; + } else { + msg = SMK_M1; + } + } else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) { + msg = SMK_M3; + } else if (key_info & WPA_KEY_INFO_REQUEST) { + msg = REQUEST; + } else if (!(key_info & WPA_KEY_INFO_KEY_TYPE)) { + msg = GROUP_2; + } else if (key_data_length == 0) { + msg = PAIRWISE_4; + } else { + msg = PAIRWISE_2; + } + + /* TODO: key_info type validation for PeerKey */ + if (msg == REQUEST || msg == PAIRWISE_2 || msg == PAIRWISE_4 || + msg == GROUP_2) { + u16 ver = key_info & WPA_KEY_INFO_TYPE_MASK; + if (sm->pairwise == WPA_CIPHER_CCMP || + sm->pairwise == WPA_CIPHER_GCMP) { + if (wpa_use_aes_cmac(sm) && + ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) { + return; + } + + if (!wpa_use_aes_cmac(sm) && + ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { + return; + } + } + } + + if (key_info & WPA_KEY_INFO_REQUEST) { + if (sm->req_replay_counter_used && + memcmp(key->replay_counter, sm->req_replay_counter, + WPA_REPLAY_COUNTER_LEN) <= 0) { + return; + } + } + + if (!(key_info & WPA_KEY_INFO_REQUEST) && + !wpa_replay_counter_valid(sm->key_replay, key->replay_counter)) { + int i; + + if (msg == PAIRWISE_2 && + wpa_replay_counter_valid(sm->prev_key_replay, + key->replay_counter) && + sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING && + memcmp(sm->SNonce, key->key_nonce, WPA_NONCE_LEN) != 0) + { + /* + * Some supplicant implementations (e.g., Windows XP + * WZC) update SNonce for each EAPOL-Key 2/4. This + * breaks the workaround on accepting any of the + * pending requests, so allow the SNonce to be updated + * even if we have already sent out EAPOL-Key 3/4. + */ + sm->update_snonce = 1; + wpa_replay_counter_mark_invalid(sm->prev_key_replay, + key->replay_counter); + goto continue_processing; + } + + if (msg == PAIRWISE_2 && + wpa_replay_counter_valid(sm->prev_key_replay, + key->replay_counter) && + sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING) { + } else { + } + for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) { + if (!sm->key_replay[i].valid) + break; + wpa_hexdump(MSG_DEBUG, "pending replay counter", + sm->key_replay[i].counter, + WPA_REPLAY_COUNTER_LEN); + } + wpa_hexdump(MSG_DEBUG, "received replay counter", + key->replay_counter, WPA_REPLAY_COUNTER_LEN); + return; + } + +continue_processing: + switch (msg) { + case PAIRWISE_2: + if (sm->wpa_ptk_state != WPA_PTK_PTKSTART && + sm->wpa_ptk_state != WPA_PTK_PTKCALCNEGOTIATING && + (!sm->update_snonce || + sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING)) { + return; + } + random_add_randomness(key->key_nonce, WPA_NONCE_LEN); + if (sm->group->reject_4way_hs_for_entropy) { + /* + * The system did not have enough entropy to generate + * strong random numbers. Reject the first 4-way + * handshake(s) and collect some entropy based on the + * information from it. Once enough entropy is + * available, the next atempt will trigger GMK/Key + * Counter update and the station will be allowed to + * continue. + */ + wpa_printf( MSG_DEBUG, "WPA: Reject 4-way handshake to " + "collect more entropy for random number " + "generation"); + random_mark_pool_ready(); + wpa_sta_disconnect(wpa_auth, sm->addr); + return; + } + if (wpa_parse_kde_ies((u8 *) (key + 1), key_data_length, + &kde) < 0) { + return; + } + if (kde.rsn_ie) { + eapol_key_ie = kde.rsn_ie; + eapol_key_ie_len = kde.rsn_ie_len; + } else { + eapol_key_ie = kde.wpa_ie; + eapol_key_ie_len = kde.wpa_ie_len; + } + ft = sm->wpa == WPA_VERSION_WPA2 && + wpa_key_mgmt_ft(sm->wpa_key_mgmt); + if (sm->wpa_ie == NULL || + wpa_compare_rsn_ie(ft, + sm->wpa_ie, sm->wpa_ie_len, + eapol_key_ie, eapol_key_ie_len)) { + if (sm->wpa_ie) { + wpa_hexdump(MSG_DEBUG, "WPA IE in AssocReq", + sm->wpa_ie, sm->wpa_ie_len); + } + wpa_hexdump(MSG_DEBUG, "WPA IE in msg 2/4", + eapol_key_ie, eapol_key_ie_len); + /* MLME-DEAUTHENTICATE.request */ + wpa_sta_disconnect(wpa_auth, sm->addr); + return; + } +#ifdef CONFIG_IEEE80211R + if (ft && ft_check_msg_2_of_4(wpa_auth, sm, &kde) < 0) { + wpa_sta_disconnect(wpa_auth, sm->addr); + return; + } +#endif /* CONFIG_IEEE80211R */ + break; + case PAIRWISE_4: + if (sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING || + !sm->PTK_valid) { + return; + } + break; + case GROUP_2: + if (sm->wpa_ptk_group_state != WPA_PTK_GROUP_REKEYNEGOTIATING + || !sm->PTK_valid) { + return; + } + break; +#ifdef CONFIG_PEERKEY + case SMK_M1: + case SMK_M3: + case SMK_ERROR: + if (!wpa_auth->conf.peerkey) { + wpa_printf( MSG_DEBUG, "RSN: SMK M1/M3/Error, but " + "PeerKey use disabled - ignoring message"); + return; + } + if (!sm->PTK_valid) { + return; + } + break; +#else /* CONFIG_PEERKEY */ + case SMK_M1: + case SMK_M3: + case SMK_ERROR: + return; /* STSL disabled - ignore SMK messages */ +#endif /* CONFIG_PEERKEY */ + case REQUEST: + break; + } + + + if (key_info & WPA_KEY_INFO_ACK) { + return; + } + + if (!(key_info & WPA_KEY_INFO_MIC)) { + return; + } + + sm->MICVerified = FALSE; + if (sm->PTK_valid && !sm->update_snonce) { + if (wpa_verify_key_mic(&sm->PTK, data, data_len)) { + return; + } + sm->MICVerified = TRUE; + eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm); + ets_timer_disarm(&sm->resend_eapol); + ets_timer_done(&sm->resend_eapol); + sm->pending_1_of_4_timeout = 0; + } + + if (key_info & WPA_KEY_INFO_REQUEST) { + if (sm->MICVerified) { + sm->req_replay_counter_used = 1; + memcpy(sm->req_replay_counter, key->replay_counter, + WPA_REPLAY_COUNTER_LEN); + } else { + return; + } + + /* + * TODO: should decrypt key data field if encryption was used; + * even though MAC address KDE is not normally encrypted, + * supplicant is allowed to encrypt it. + */ + if (msg == SMK_ERROR) { +#ifdef CONFIG_PEERKEY + wpa_smk_error(wpa_auth, sm, key); +#endif /* CONFIG_PEERKEY */ + return; + } else if (key_info & WPA_KEY_INFO_ERROR) { + if (wpa_receive_error_report( + wpa_auth, sm, + !(key_info & WPA_KEY_INFO_KEY_TYPE)) > 0) + return; /* STA entry was removed */ + } else if (key_info & WPA_KEY_INFO_KEY_TYPE) { + wpa_request_new_ptk(sm); +#ifdef CONFIG_PEERKEY + } else if (msg == SMK_M1) { + wpa_smk_m1(wpa_auth, sm, key); +#endif /* CONFIG_PEERKEY */ + } else if (key_data_length > 0 && + wpa_parse_kde_ies((const u8 *) (key + 1), + key_data_length, &kde) == 0 && + kde.mac_addr) { + } else { + eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL); + wpa_rekey_gtk(wpa_auth, NULL); + } + } else { + /* Do not allow the same key replay counter to be reused. */ + wpa_replay_counter_mark_invalid(sm->key_replay, + key->replay_counter); + + if (msg == PAIRWISE_2) { + /* + * Maintain a copy of the pending EAPOL-Key frames in + * case the EAPOL-Key frame was retransmitted. This is + * needed to allow EAPOL-Key msg 2/4 reply to another + * pending msg 1/4 to update the SNonce to work around + * unexpected supplicant behavior. + */ + memcpy(sm->prev_key_replay, sm->key_replay, + sizeof(sm->key_replay)); + } else { + memset(sm->prev_key_replay, 0, + sizeof(sm->prev_key_replay)); + } + + /* + * Make sure old valid counters are not accepted anymore and + * do not get copied again. + */ + wpa_replay_counter_mark_invalid(sm->key_replay, NULL); + } + +#ifdef CONFIG_PEERKEY + if (msg == SMK_M3) { + wpa_smk_m3(wpa_auth, sm, key); + return; + } +#endif /* CONFIG_PEERKEY */ + + wpa_printf( MSG_DEBUG, "wpa_rx: free eapol=%p\n", sm->last_rx_eapol_key); + os_free(sm->last_rx_eapol_key); + sm->last_rx_eapol_key = (u8 *)os_malloc(data_len); + if (sm->last_rx_eapol_key == NULL) + return; + wpa_printf( MSG_DEBUG, "wpa_rx: new eapol=%p\n", sm->last_rx_eapol_key); + memcpy(sm->last_rx_eapol_key, data, data_len); + sm->last_rx_eapol_key_len = data_len; + + sm->rx_eapol_key_secure = !!(key_info & WPA_KEY_INFO_SECURE); + sm->EAPOLKeyReceived = TRUE; + sm->EAPOLKeyPairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE); + sm->EAPOLKeyRequest = !!(key_info & WPA_KEY_INFO_REQUEST); + memcpy(sm->SNonce, key->key_nonce, WPA_NONCE_LEN); + wpa_sm_step(sm); +} + + +static int wpa_gmk_to_gtk(const u8 *gmk, const char *label, const u8 *addr, + const u8 *gnonce, u8 *gtk, size_t gtk_len) +{ + u8 data[ETH_ALEN + WPA_NONCE_LEN + 8 + 16]; + u8 *pos; + int ret = 0; + + /* GTK = PRF-X(GMK, "Group key expansion", + * AA || GNonce || Time || random data) + * The example described in the IEEE 802.11 standard uses only AA and + * GNonce as inputs here. Add some more entropy since this derivation + * is done only at the Authenticator and as such, does not need to be + * exactly same. + */ + memcpy(data, addr, ETH_ALEN); + memcpy(data + ETH_ALEN, gnonce, WPA_NONCE_LEN); + pos = data + ETH_ALEN + WPA_NONCE_LEN; + wpa_get_ntp_timestamp(pos); + pos += 8; + if (os_get_random(pos, 16) < 0) + ret = -1; + +#ifdef CONFIG_IEEE80211W + 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; +#endif /* CONFIG_IEEE80211W */ + + return ret; +} + + +static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_state_machine *sm = timeout_ctx; + + sm->pending_1_of_4_timeout = 0; + sm->TimeoutEvt = TRUE; + wpa_sm_step(sm); +} + + +void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm, int key_info, + const u8 *key_rsc, const u8 *nonce, + const u8 *kde, size_t kde_len, + int keyidx, int encr, int force_version) +{ + struct ieee802_1x_hdr *hdr; + struct wpa_eapol_key *key; + size_t len; + int alg; + int key_data_len, pad_len = 0; + u8 *buf, *pos; + int version, pairwise; + int i; + + wpa_printf( MSG_DEBUG, "wpa_auth=%p sm=%p kdersc=%p kde=%p nounce=%p kde_len=%u keyidx=%d encr=%d force=%d\n", + wpa_auth,sm, key_rsc, kde, nonce, kde_len, keyidx, encr, force_version); + len = sizeof(struct ieee802_1x_hdr) + sizeof(struct wpa_eapol_key); + + if (force_version) + version = force_version; + else if (wpa_use_aes_cmac(sm)) + version = WPA_KEY_INFO_TYPE_AES_128_CMAC; + else if (sm->pairwise != WPA_CIPHER_TKIP) + version = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES; + else + version = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4; + + pairwise = key_info & WPA_KEY_INFO_KEY_TYPE; + + wpa_printf( MSG_DEBUG, "WPA: Send EAPOL(version=%d secure=%d mic=%d " + "ack=%d install=%d pairwise=%d kde_len=%lu keyidx=%d " + "encr=%d)\n", + version, + (key_info & WPA_KEY_INFO_SECURE) ? 1 : 0, + (key_info & WPA_KEY_INFO_MIC) ? 1 : 0, + (key_info & WPA_KEY_INFO_ACK) ? 1 : 0, + (key_info & WPA_KEY_INFO_INSTALL) ? 1 : 0, + pairwise, (unsigned long) kde_len, keyidx, encr); + + key_data_len = kde_len; + + if ((version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES || + version == WPA_KEY_INFO_TYPE_AES_128_CMAC) && encr) { + pad_len = key_data_len % 8; + if (pad_len) + pad_len = 8 - pad_len; + key_data_len += pad_len + 8; + } + + len += key_data_len; + + hdr = (struct ieee802_1x_hdr *)os_zalloc(len); + if (hdr == NULL) + return; + hdr->version = wpa_auth->conf.eapol_version; + hdr->type = IEEE802_1X_TYPE_EAPOL_KEY; + hdr->length = host_to_be16(len - sizeof(*hdr)); + key = (struct wpa_eapol_key *) (hdr + 1); + + key->type = sm->wpa == WPA_VERSION_WPA2 ? + EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; + key_info |= version; + if (encr && sm->wpa == WPA_VERSION_WPA2) + key_info |= WPA_KEY_INFO_ENCR_KEY_DATA; + if (sm->wpa != WPA_VERSION_WPA2) + key_info |= keyidx << WPA_KEY_INFO_KEY_INDEX_SHIFT; + WPA_PUT_BE16(key->key_info, key_info); + + alg = pairwise ? sm->pairwise : wpa_auth->conf.wpa_group; + WPA_PUT_BE16(key->key_length, wpa_cipher_key_len(alg)); + if (key_info & WPA_KEY_INFO_SMK_MESSAGE) + WPA_PUT_BE16(key->key_length, 0); + + /* FIX: STSL: what to use as key_replay_counter? */ + for (i = RSNA_MAX_EAPOL_RETRIES - 1; i > 0; i--) { + sm->key_replay[i].valid = sm->key_replay[i - 1].valid; + memcpy(sm->key_replay[i].counter, + sm->key_replay[i - 1].counter, + WPA_REPLAY_COUNTER_LEN); + } + inc_byte_array(sm->key_replay[0].counter, WPA_REPLAY_COUNTER_LEN); + memcpy(key->replay_counter, sm->key_replay[0].counter, + WPA_REPLAY_COUNTER_LEN); + sm->key_replay[0].valid = TRUE; + + if (nonce) + memcpy(key->key_nonce, nonce, WPA_NONCE_LEN); + + if (key_rsc) + memcpy(key->key_rsc, key_rsc, WPA_KEY_RSC_LEN); + + if (kde && !encr) { + memcpy(key + 1, kde, kde_len); + WPA_PUT_BE16(key->key_data_length, kde_len); + } else if (encr && kde) { + buf = (u8 *)os_zalloc(key_data_len); + if (buf == NULL) { + os_free(hdr); + return; + } + pos = buf; + memcpy(pos, kde, kde_len); + pos += kde_len; + + if (pad_len) + *pos++ = 0xdd; + + wpa_hexdump_key(MSG_DEBUG, "Plaintext EAPOL-Key Key Data", + buf, key_data_len); + if (version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES || + version == WPA_KEY_INFO_TYPE_AES_128_CMAC) { + if (aes_wrap(sm->PTK.kek, (key_data_len - 8) / 8, buf, + (u8 *) (key + 1))) { + os_free(hdr); + os_free(buf); + return; + } + WPA_PUT_BE16(key->key_data_length, key_data_len); + } else { + u8 ek[32]; + memcpy(key->key_iv, + sm->group->Counter + WPA_NONCE_LEN - 16, 16); + inc_byte_array(sm->group->Counter, WPA_NONCE_LEN); + memcpy(ek, key->key_iv, 16); + memcpy(ek + 16, sm->PTK.kek, 16); + memcpy(key + 1, buf, key_data_len); + rc4_skip(ek, 32, 256, (u8 *) (key + 1), key_data_len); + WPA_PUT_BE16(key->key_data_length, key_data_len); + } + os_free(buf); + } + + if (key_info & WPA_KEY_INFO_MIC) { + if (!sm->PTK_valid) { + os_free(hdr); + return; + } + wpa_eapol_key_mic(sm->PTK.kck, version, (u8 *) hdr, len, + key->key_mic); + } + + wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_inc_EapolFramesTx, 1); + wpa_auth_send_eapol(wpa_auth, sm->addr, (u8 *) hdr, len, sm->pairwise_set); + os_free(hdr); +} + +int hostap_eapol_resend_process(void *timeout_ctx) +{ + u32 index = (u32)timeout_ctx; + struct wpa_state_machine *sm = wpa_auth_get_sm(index); + + wpa_printf( MSG_DEBUG, "resend eapol1"); + + if(sm) { + sm->pending_1_of_4_timeout = 0; + sm->TimeoutEvt = TRUE; + sm->in_step_loop = 0; + wpa_sm_step(sm); + } else { + wpa_printf( MSG_INFO, "Station left, stop send EAPOL frame"); + } + + return ESP_OK; +} + +void resend_eapol_handle(void *timeout_ctx) +{ + wifi_ipc_config_t cfg; + + cfg.fn = hostap_eapol_resend_process; + cfg.arg = timeout_ctx; + cfg.arg_size = 0; + esp_wifi_ipc_internal(&cfg, false); +} + +static void wpa_send_eapol(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm, int key_info, + const u8 *key_rsc, const u8 *nonce, + const u8 *kde, size_t kde_len, + int keyidx, int encr) +{ + int timeout_ms; + int pairwise = key_info & WPA_KEY_INFO_KEY_TYPE; + int ctr; + + if (sm == NULL) + return; + + __wpa_send_eapol(wpa_auth, sm, key_info, key_rsc, nonce, kde, kde_len, + keyidx, encr, 0); + + ctr = pairwise ? sm->TimeoutCtr : sm->GTimeoutCtr; + if (ctr == 1 && wpa_auth->conf.tx_status) + timeout_ms = pairwise ? eapol_key_timeout_first : + eapol_key_timeout_first_group; + else + timeout_ms = eapol_key_timeout_subseq; + if (pairwise && ctr == 1 && !(key_info & WPA_KEY_INFO_MIC)) + sm->pending_1_of_4_timeout = 1; + wpa_printf( MSG_DEBUG, "WPA: Use EAPOL-Key timeout of %u ms (retry " + "counter %d)\n", timeout_ms, ctr); + eloop_register_timeout(timeout_ms / 1000, (timeout_ms % 1000) * 1000, + wpa_send_eapol_timeout, wpa_auth, sm); + ets_timer_disarm(&sm->resend_eapol); + ets_timer_setfn(&sm->resend_eapol, (ETSTimerFunc *)resend_eapol_handle, (void*)(sm->index)); + ets_timer_arm(&sm->resend_eapol, 1000, 0); +} + + +static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len) +{ + struct ieee802_1x_hdr *hdr; + struct wpa_eapol_key *key; + u16 key_info; + int ret = 0; + int mic_ret = 0; + u8 mic[16]; + char debug_log[8]; + + if (data_len < sizeof(*hdr) + sizeof(*key)){ + wpa_printf( MSG_DEBUG, "invalid data length, len=%u\n", data_len); + return -1; + } + + hdr = (struct ieee802_1x_hdr *) data; + key = (struct wpa_eapol_key *) (hdr + 1); + key_info = WPA_GET_BE16(key->key_info); + memcpy(mic, key->key_mic, 16); + memset(key->key_mic, 0, 16); + + mic_ret = wpa_eapol_key_mic(PTK->kck, key_info & WPA_KEY_INFO_TYPE_MASK, data, data_len, key->key_mic); + if ( mic_ret || memcmp(mic, key->key_mic, 16) != 0) { + ret = -1; + } + os_memset(debug_log, 0, 8); + os_memcpy(debug_log, "you mic", sizeof("you mic")); + wpa_dump_mem(debug_log, mic, 16); + os_memset(debug_log, 0, 8); + os_memcpy(debug_log, "my mic", sizeof("my mic")); + wpa_dump_mem(debug_log, key->key_mic, 16); + + memcpy(key->key_mic, mic, 16); + return ret; +} + + +void wpa_remove_ptk(struct wpa_state_machine *sm) +{ + sm->PTK_valid = FALSE; + memset(&sm->PTK, 0, sizeof(sm->PTK)); + wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 0, NULL, 0); + sm->pairwise_set = FALSE; + eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm); +} + + +int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event) +{ + int remove_ptk = 1; + + if (sm == NULL) + return -1; + + switch (event) { + case WPA_AUTH: + case WPA_ASSOC: + break; + case WPA_DEAUTH: + case WPA_DISASSOC: + sm->DeauthenticationRequest = TRUE; + break; + case WPA_REAUTH: + case WPA_REAUTH_EAPOL: + if (!sm->started) { + /* + * When using WPS, we may end up here if the STA + * manages to re-associate without the previous STA + * entry getting removed. Consequently, we need to make + * sure that the WPA state machines gets initialized + * properly at this point. + */ + wpa_printf( MSG_DEBUG, "WPA state machine had not been " + "started - initialize now"); + sm->started = 1; + sm->Init = TRUE; + if (wpa_sm_step(sm) == 1) + return 1; /* should not really happen */ + sm->Init = FALSE; + sm->AuthenticationRequest = TRUE; + break; + } + if (sm->GUpdateStationKeys) { + /* + * Reauthentication cancels the pending group key + * update for this STA. + */ + sm->group->GKeyDoneStations--; + sm->GUpdateStationKeys = FALSE; + sm->PtkGroupInit = TRUE; + } + sm->ReAuthenticationRequest = TRUE; + break; + case WPA_ASSOC_FT: +#ifdef CONFIG_IEEE80211R + wpa_printf( MSG_DEBUG, "FT: Retry PTK configuration " + "after association"); + wpa_ft_install_ptk(sm); + + /* Using FT protocol, not WPA auth state machine */ + sm->ft_completed = 1; + return 0; +#else /* CONFIG_IEEE80211R */ + break; +#endif /* CONFIG_IEEE80211R */ + } + +#ifdef CONFIG_IEEE80211R + sm->ft_completed = 0; +#endif /* CONFIG_IEEE80211R */ + +#ifdef CONFIG_IEEE80211W + if (sm->mgmt_frame_prot && event == WPA_AUTH) + remove_ptk = 0; +#endif /* CONFIG_IEEE80211W */ + + if (remove_ptk) { + sm->PTK_valid = FALSE; + memset(&sm->PTK, 0, sizeof(sm->PTK)); + + if (event != WPA_REAUTH_EAPOL) + wpa_remove_ptk(sm); + } + + return wpa_sm_step(sm); +} + + +SM_STATE(WPA_PTK, INITIALIZE) +{ + SM_ENTRY_MA(WPA_PTK, INITIALIZE, wpa_ptk); + if (sm->Init) { + /* Init flag is not cleared here, so avoid busy + * loop by claiming nothing changed. */ + sm->changed = FALSE; + } + + sm->keycount = 0; + if (sm->GUpdateStationKeys) + sm->group->GKeyDoneStations--; + sm->GUpdateStationKeys = FALSE; + if (sm->wpa == WPA_VERSION_WPA) + sm->PInitAKeys = FALSE; + if (1 /* Unicast cipher supported AND (ESS OR ((IBSS or WDS) and + * Local AA > Remote AA)) */) { + sm->Pair = TRUE; + } + wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portEnabled, 0); + wpa_remove_ptk(sm); + wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portValid, 0); + sm->TimeoutCtr = 0; + if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) { + wpa_auth_set_eapol(sm->wpa_auth, sm->addr, + WPA_EAPOL_authorized, 0); + } +} + + +SM_STATE(WPA_PTK, DISCONNECT) +{ + SM_ENTRY_MA(WPA_PTK, DISCONNECT, wpa_ptk); + sm->Disconnect = FALSE; + wpa_sta_disconnect(sm->wpa_auth, sm->addr); +} + + +SM_STATE(WPA_PTK, DISCONNECTED) +{ + SM_ENTRY_MA(WPA_PTK, DISCONNECTED, wpa_ptk); + sm->DeauthenticationRequest = FALSE; +} + + +SM_STATE(WPA_PTK, AUTHENTICATION) +{ + SM_ENTRY_MA(WPA_PTK, AUTHENTICATION, wpa_ptk); + memset(&sm->PTK, 0, sizeof(sm->PTK)); + sm->PTK_valid = FALSE; + wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portControl_Auto, + 1); + wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portEnabled, 1); + sm->AuthenticationRequest = FALSE; +} + + +static void wpa_group_ensure_init(struct wpa_authenticator *wpa_auth, + struct wpa_group *group) +{ + if (group->first_sta_seen) + return; + /* + * System has run bit further than at the time hostapd was started + * potentially very early during boot up. This provides better chances + * of collecting more randomness on embedded systems. Re-initialize the + * GMK and Counter here to improve their strength if there was not + * enough entropy available immediately after system startup. + */ + wpa_printf( MSG_DEBUG, "WPA: Re-initialize GMK/Counter on first " + "station\n"); + if (random_pool_ready() != 1) { + wpa_printf( MSG_INFO, "WPA: Not enough entropy in random pool " + "to proceed - reject first 4-way handshake"); + group->reject_4way_hs_for_entropy = TRUE; + } else { + group->first_sta_seen = TRUE; + group->reject_4way_hs_for_entropy = FALSE; + } + + wpa_group_init_gmk_and_counter(wpa_auth, group); + wpa_gtk_update(wpa_auth, group); + wpa_group_config_group_keys(wpa_auth, group); +} + + +SM_STATE(WPA_PTK, AUTHENTICATION2) +{ + SM_ENTRY_MA(WPA_PTK, AUTHENTICATION2, wpa_ptk); + + wpa_group_ensure_init(sm->wpa_auth, sm->group); + + /* + * Definition of ANonce selection in IEEE Std 802.11i-2004 is somewhat + * ambiguous. The Authenticator state machine uses a counter that is + * incremented by one for each 4-way handshake. However, the security + * analysis of 4-way handshake points out that unpredictable nonces + * help in preventing precomputation attacks. Instead of the state + * machine definition, use an unpredictable nonce value here to provide + * stronger protection against potential precomputation attacks. + */ + if (os_get_random(sm->ANonce, WPA_NONCE_LEN)) { + wpa_printf( MSG_ERROR, "WPA: Failed to get random data for " + "ANonce."); + wpa_sta_disconnect(sm->wpa_auth, sm->addr); + return; + } + wpa_hexdump(MSG_DEBUG, "WPA: Assign ANonce", sm->ANonce, + WPA_NONCE_LEN); + sm->ReAuthenticationRequest = FALSE; + /* IEEE 802.11i does not clear TimeoutCtr here, but this is more + * logical place than INITIALIZE since AUTHENTICATION2 can be + * re-entered on ReAuthenticationRequest without going through + * INITIALIZE. */ + sm->TimeoutCtr = 0; +} + + +SM_STATE(WPA_PTK, INITPMK) +{ + u8 msk[2 * PMK_LEN]; + size_t len = 2 * PMK_LEN; + + SM_ENTRY_MA(WPA_PTK, INITPMK, wpa_ptk); +#ifdef CONFIG_IEEE80211R + sm->xxkey_len = 0; +#endif /* CONFIG_IEEE80211R */ + + if (wpa_auth_get_msk(sm->wpa_auth, sm->addr, msk, &len) == 0) { + wpa_printf( MSG_DEBUG, "WPA: PMK from EAPOL state machine " + "(len=%lu)", (unsigned long) len); + memcpy(sm->PMK, msk, PMK_LEN); +#ifdef CONFIG_IEEE80211R + if (len >= 2 * PMK_LEN) { + memcpy(sm->xxkey, msk + PMK_LEN, PMK_LEN); + sm->xxkey_len = PMK_LEN; + } +#endif /* CONFIG_IEEE80211R */ + } else { + wpa_printf( MSG_DEBUG, "WPA: Could not get PMK"); + } + + sm->req_replay_counter_used = 0; + /* IEEE 802.11i does not set keyRun to FALSE, but not doing this + * will break reauthentication since EAPOL state machines may not be + * get into AUTHENTICATING state that clears keyRun before WPA state + * machine enters AUTHENTICATION2 state and goes immediately to INITPMK + * state and takes PMK from the previously used AAA Key. This will + * eventually fail in 4-Way Handshake because Supplicant uses PMK + * derived from the new AAA Key. Setting keyRun = FALSE here seems to + * be good workaround for this issue. */ + wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyRun, 0); +} + + +SM_STATE(WPA_PTK, INITPSK) +{ + const u8 *psk; + SM_ENTRY_MA(WPA_PTK, INITPSK, wpa_ptk); + psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, NULL); + if (psk) { + memcpy(sm->PMK, psk, PMK_LEN); +#ifdef CONFIG_IEEE80211R + memcpy(sm->xxkey, psk, PMK_LEN); + sm->xxkey_len = PMK_LEN; +#endif /* CONFIG_IEEE80211R */ + } + sm->req_replay_counter_used = 0; +} + + +SM_STATE(WPA_PTK, PTKSTART) +{ + u8 buf[2 + RSN_SELECTOR_LEN + PMKID_LEN], *pmkid = NULL; + size_t pmkid_len = 0; + + SM_ENTRY_MA(WPA_PTK, PTKSTART, wpa_ptk); + sm->PTKRequest = FALSE; + sm->TimeoutEvt = FALSE; + + sm->TimeoutCtr++; + if (sm->TimeoutCtr > (int) dot11RSNAConfigPairwiseUpdateCount) { + /* No point in sending the EAPOL-Key - we will disconnect + * immediately following this. */ + return; + } + + /* + * TODO: Could add PMKID even with WPA2-PSK, but only if there is only + * one possible PSK for this STA. + */ + if (sm->wpa == WPA_VERSION_WPA2 && + wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt)) { + pmkid = buf; + pmkid_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN; + pmkid[0] = WLAN_EID_VENDOR_SPECIFIC; + pmkid[1] = RSN_SELECTOR_LEN + PMKID_LEN; + RSN_SELECTOR_PUT(&pmkid[2], RSN_KEY_DATA_PMKID); + + { + /* + * Calculate PMKID since no PMKSA cache entry was + * available with pre-calculated PMKID. + */ + rsn_pmkid(sm->PMK, PMK_LEN, sm->wpa_auth->addr, + sm->addr, &pmkid[2 + RSN_SELECTOR_LEN], + wpa_key_mgmt_sha256(sm->wpa_key_mgmt)); + } + } + wpa_send_eapol(sm->wpa_auth, sm, + WPA_KEY_INFO_ACK | WPA_KEY_INFO_KEY_TYPE, NULL, + sm->ANonce, pmkid, pmkid_len, 0, 0); +} + + +static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *pmk, + struct wpa_ptk *ptk) +{ + size_t ptk_len = sm->pairwise != WPA_CIPHER_TKIP ? 48 : 64; +#ifdef CONFIG_IEEE80211R + if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) + return wpa_auth_derive_ptk_ft(sm, pmk, ptk, ptk_len); +#endif /* CONFIG_IEEE80211R */ + + wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion", + sm->wpa_auth->addr, sm->addr, sm->ANonce, sm->SNonce, + (u8 *) ptk, ptk_len, + wpa_key_mgmt_sha256(sm->wpa_key_mgmt)); + + return 0; +} + + +SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) +{ + struct wpa_ptk PTK; + int ok = 0; + const u8 *pmk = NULL; + + SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk); + sm->EAPOLKeyReceived = FALSE; + sm->update_snonce = FALSE; + + /* WPA with IEEE 802.1X: use the derived PMK from EAP + * WPA-PSK: iterate through possible PSKs and select the one matching + * the packet */ + for (;;) { + if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) { + wpa_printf( MSG_DEBUG, "wpa psk\n"); + pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, pmk); + if (pmk == NULL){ + wpa_printf( MSG_DEBUG, "pmk is null\n"); + break; + } + } else { + pmk = sm->PMK; + } + + wpa_derive_ptk(sm, pmk, &PTK); + + if (wpa_verify_key_mic(&PTK, sm->last_rx_eapol_key, + sm->last_rx_eapol_key_len) == 0) { + wpa_printf( MSG_DEBUG, "mic verify ok, pmk=%p\n", pmk); + ok = 1; + break; + } else { + wpa_printf( MSG_DEBUG, "mic verify fail, pmk=%p\n", pmk); + } + + if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)){ + wpa_printf( MSG_DEBUG, "wpa_key_mgmt=%x\n", sm->wpa_key_mgmt); + break; + } + } + + if (!ok) { + return; + } + +#ifdef CONFIG_IEEE80211R + if (sm->wpa == WPA_VERSION_WPA2 && wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { + /* + * Verify that PMKR1Name from EAPOL-Key message 2/4 matches + * with the value we derived. + */ + if (memcmp(sm->sup_pmk_r1_name, sm->pmk_r1_name, + WPA_PMK_NAME_LEN) != 0) { + wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from " + "Supplicant", + sm->sup_pmk_r1_name, WPA_PMK_NAME_LEN); + wpa_hexdump(MSG_DEBUG, "FT: Derived PMKR1Name", + sm->pmk_r1_name, WPA_PMK_NAME_LEN); + return; + } + } +#endif /* CONFIG_IEEE80211R */ + + sm->pending_1_of_4_timeout = 0; + eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm); + + if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) { + /* PSK may have changed from the previous choice, so update + * state machine data based on whatever PSK was selected here. + */ + memcpy(sm->PMK, pmk, PMK_LEN); + } + + sm->MICVerified = TRUE; + + memcpy(&sm->PTK, &PTK, sizeof(PTK)); + sm->PTK_valid = TRUE; +} + + +SM_STATE(WPA_PTK, PTKCALCNEGOTIATING2) +{ + SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING2, wpa_ptk); + sm->TimeoutCtr = 0; +} + + +#ifdef CONFIG_IEEE80211W + +static int ieee80211w_kde_len(struct wpa_state_machine *sm) +{ + if (sm->mgmt_frame_prot) { + return 2 + RSN_SELECTOR_LEN + sizeof(struct wpa_igtk_kde); + } + + return 0; +} + + +static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos) +{ + struct wpa_igtk_kde igtk; + struct wpa_group *gsm = sm->group; + + if (!sm->mgmt_frame_prot) + return pos; + + igtk.keyid[0] = gsm->GN_igtk; + igtk.keyid[1] = 0; + if (gsm->wpa_group_state != WPA_GROUP_SETKEYSDONE || + wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, igtk.pn) < 0) + memset(igtk.pn, 0, sizeof(igtk.pn)); + memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN); + if (sm->wpa_auth->conf.disable_gtk) { + /* + * Provide unique random IGTK to each STA to prevent use of + * IGTK in the BSS. + */ + if (os_get_random(igtk.igtk, WPA_IGTK_LEN) < 0) + return pos; + } + pos = wpa_add_kde(pos, RSN_KEY_DATA_IGTK, + (const u8 *) &igtk, sizeof(igtk), NULL, 0); + + return pos; +} + +#else /* CONFIG_IEEE80211W */ + +static int ieee80211w_kde_len(struct wpa_state_machine *sm) +{ + return 0; +} + + +static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos) +{ + return pos; +} + +#endif /* CONFIG_IEEE80211W */ + + +SM_STATE(WPA_PTK, PTKINITNEGOTIATING) +{ + u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos, dummy_gtk[32]; + size_t gtk_len, kde_len; + struct wpa_group *gsm = sm->group; + u8 *wpa_ie; + int wpa_ie_len, secure, keyidx, encr = 0; + + SM_ENTRY_MA(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk); + sm->TimeoutEvt = FALSE; + + sm->TimeoutCtr++; + if (sm->TimeoutCtr > (int) dot11RSNAConfigPairwiseUpdateCount) { + /* No point in sending the EAPOL-Key - we will disconnect + * immediately following this. */ + return; + } + + /* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE], + GTK[GN], IGTK, [FTIE], [TIE * 2]) + */ + memset(rsc, 0, WPA_KEY_RSC_LEN); + wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc); + /* If FT is used, wpa_auth->wpa_ie includes both RSNIE and MDIE */ + wpa_ie = sm->wpa_auth->wpa_ie; + wpa_ie_len = sm->wpa_auth->wpa_ie_len; + if (sm->wpa == WPA_VERSION_WPA && + (sm->wpa_auth->conf.wpa & WPA_PROTO_RSN) && + wpa_ie_len > wpa_ie[1] + 2 && wpa_ie[0] == WLAN_EID_RSN) { + /* WPA-only STA, remove RSN IE */ + wpa_ie = wpa_ie + wpa_ie[1] + 2; + wpa_ie_len = wpa_ie[1] + 2; + } + if (sm->wpa == WPA_VERSION_WPA2) { + /* WPA2 send GTK in the 4-way handshake */ + secure = 1; + gtk = gsm->GTK[gsm->GN - 1]; + gtk_len = gsm->GTK_len; + if (sm->wpa_auth->conf.disable_gtk) { + /* + * Provide unique random GTK to each STA to prevent use + * of GTK in the BSS. + */ + if (os_get_random(dummy_gtk, gtk_len) < 0) + return; + gtk = dummy_gtk; + } + keyidx = gsm->GN; + _rsc = rsc; + encr = 1; + } else { + /* WPA does not include GTK in msg 3/4 */ + secure = 0; + gtk = NULL; + gtk_len = 0; + keyidx = 0; + _rsc = NULL; + if (sm->rx_eapol_key_secure) { + /* + * It looks like Windows 7 supplicant tries to use + * Secure bit in msg 2/4 after having reported Michael + * MIC failure and it then rejects the 4-way handshake + * if msg 3/4 does not set Secure bit. Work around this + * by setting the Secure bit here even in the case of + * WPA if the supplicant used it first. + */ + secure = 1; + } + } + + kde_len = wpa_ie_len + ieee80211w_kde_len(sm); + if (gtk) + kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len; +#ifdef CONFIG_IEEE80211R + if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { + kde_len += 2 + PMKID_LEN; /* PMKR1Name into RSN IE */ + kde_len += 300; /* FTIE + 2 * TIE */ + } +#endif /* CONFIG_IEEE80211R */ + kde = (u8 *)os_malloc(kde_len); + if (kde == NULL) + return; + + pos = kde; + memcpy(pos, wpa_ie, wpa_ie_len); + pos += wpa_ie_len; +#ifdef CONFIG_IEEE80211R + if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { + int res = wpa_insert_pmkid(kde, pos - kde, sm->pmk_r1_name); + if (res < 0) { + wpa_printf( MSG_ERROR, "FT: Failed to insert " + "PMKR1Name into RSN IE in EAPOL-Key data"); + os_free(kde); + return; + } + pos += res; + } +#endif /* CONFIG_IEEE80211R */ + if (gtk) { + u8 hdr[2]; + hdr[0] = keyidx & 0x03; + hdr[1] = 0; + pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2, + gtk, gtk_len); + } + pos = ieee80211w_kde_add(sm, pos); + +#ifdef CONFIG_IEEE80211R + if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { + int res; + struct wpa_auth_config *conf; + + conf = &sm->wpa_auth->conf; + res = wpa_write_ftie(conf, conf->r0_key_holder, + conf->r0_key_holder_len, + NULL, NULL, pos, kde + kde_len - pos, + NULL, 0); + if (res < 0) { + wpa_printf( MSG_ERROR, "FT: Failed to insert FTIE " + "into EAPOL-Key Key Data"); + os_free(kde); + return; + } + pos += res; + + /* TIE[ReassociationDeadline] (TU) */ + *pos++ = WLAN_EID_TIMEOUT_INTERVAL; + *pos++ = 5; + *pos++ = WLAN_TIMEOUT_REASSOC_DEADLINE; + WPA_PUT_LE32(pos, conf->reassociation_deadline); + pos += 4; + + /* TIE[KeyLifetime] (seconds) */ + *pos++ = WLAN_EID_TIMEOUT_INTERVAL; + *pos++ = 5; + *pos++ = WLAN_TIMEOUT_KEY_LIFETIME; + WPA_PUT_LE32(pos, conf->r0_key_lifetime * 60); + pos += 4; + } +#endif /* CONFIG_IEEE80211R */ + + wpa_send_eapol(sm->wpa_auth, sm, + (secure ? WPA_KEY_INFO_SECURE : 0) | WPA_KEY_INFO_MIC | + WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL | + WPA_KEY_INFO_KEY_TYPE, + _rsc, sm->ANonce, kde, pos - kde, keyidx, encr); + os_free(kde); +} + + +SM_STATE(WPA_PTK, PTKINITDONE) +{ + SM_ENTRY_MA(WPA_PTK, PTKINITDONE, wpa_ptk); + sm->EAPOLKeyReceived = FALSE; + if (sm->Pair) { + enum wpa_alg alg = wpa_cipher_to_alg(sm->pairwise); + int klen = wpa_cipher_key_len(sm->pairwise); + if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0, + sm->PTK.tk1, klen)) { + wpa_sta_disconnect(sm->wpa_auth, sm->addr); + return; + } + /* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */ + sm->pairwise_set = TRUE; + + if (sm->wpa_auth->conf.wpa_ptk_rekey) { + eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm); + eloop_register_timeout(sm->wpa_auth->conf. + wpa_ptk_rekey, 0, wpa_rekey_ptk, + sm->wpa_auth, sm); + } + + if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) { + wpa_auth_set_eapol(sm->wpa_auth, sm->addr, + WPA_EAPOL_authorized, 1); + } + } + + if (0 /* IBSS == TRUE */) { + sm->keycount++; + if (sm->keycount == 2) { + wpa_auth_set_eapol(sm->wpa_auth, sm->addr, + WPA_EAPOL_portValid, 1); + } + } else { + wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portValid, + 1); + } + wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyAvailable, 0); + wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyDone, 1); + if (sm->wpa == WPA_VERSION_WPA) + sm->PInitAKeys = TRUE; + else + sm->has_GTK = TRUE; + + +{ + esp_wifi_wpa_ptk_init_done_internal(sm->addr); +} +#ifdef CONFIG_IEEE80211R + wpa_ft_push_pmk_r1(sm->wpa_auth, sm->addr); +#endif /* CONFIG_IEEE80211R */ +} + + +SM_STEP(WPA_PTK) +{ + + if (sm->Init) + SM_ENTER(WPA_PTK, INITIALIZE); + else if (sm->Disconnect + /* || FIX: dot11RSNAConfigSALifetime timeout */) { + SM_ENTER(WPA_PTK, DISCONNECT); + } + else if (sm->DeauthenticationRequest) + SM_ENTER(WPA_PTK, DISCONNECTED); + else if (sm->AuthenticationRequest) + SM_ENTER(WPA_PTK, AUTHENTICATION); + else if (sm->ReAuthenticationRequest) + SM_ENTER(WPA_PTK, AUTHENTICATION2); + else if (sm->PTKRequest) + SM_ENTER(WPA_PTK, PTKSTART); + else switch (sm->wpa_ptk_state) { + case WPA_PTK_INITIALIZE: + break; + case WPA_PTK_DISCONNECT: + SM_ENTER(WPA_PTK, DISCONNECTED); + break; + case WPA_PTK_DISCONNECTED: + SM_ENTER(WPA_PTK, INITIALIZE); + break; + case WPA_PTK_AUTHENTICATION: + SM_ENTER(WPA_PTK, AUTHENTICATION2); + break; + case WPA_PTK_AUTHENTICATION2: + if (wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) && + wpa_auth_get_eapol(sm->wpa_auth, sm->addr, + WPA_EAPOL_keyRun) > 0) + SM_ENTER(WPA_PTK, INITPMK); + else if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) + /* FIX: && 802.1X::keyRun */) + SM_ENTER(WPA_PTK, INITPSK); + break; + case WPA_PTK_INITPMK: + if (wpa_auth_get_eapol(sm->wpa_auth, sm->addr, + WPA_EAPOL_keyAvailable) > 0) + SM_ENTER(WPA_PTK, PTKSTART); + else { + SM_ENTER(WPA_PTK, DISCONNECT); + } + break; + case WPA_PTK_INITPSK: + if (wpa_auth_get_psk(sm->wpa_auth, sm->addr, NULL)) + SM_ENTER(WPA_PTK, PTKSTART); + else { + SM_ENTER(WPA_PTK, DISCONNECT); + } + break; + case WPA_PTK_PTKSTART: + if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest && + sm->EAPOLKeyPairwise) + SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING); + else if (sm->TimeoutCtr > + (int) dot11RSNAConfigPairwiseUpdateCount) { + SM_ENTER(WPA_PTK, DISCONNECT); + } else if (sm->TimeoutEvt) + SM_ENTER(WPA_PTK, PTKSTART); + break; + case WPA_PTK_PTKCALCNEGOTIATING: + if (sm->MICVerified) + SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING2); + else if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest && + sm->EAPOLKeyPairwise) + SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING); + else if (sm->TimeoutEvt) + SM_ENTER(WPA_PTK, PTKSTART); + break; + case WPA_PTK_PTKCALCNEGOTIATING2: + SM_ENTER(WPA_PTK, PTKINITNEGOTIATING); + break; + case WPA_PTK_PTKINITNEGOTIATING: + if (sm->update_snonce) + SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING); + else if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest && + sm->EAPOLKeyPairwise && sm->MICVerified) + SM_ENTER(WPA_PTK, PTKINITDONE); + else if (sm->TimeoutCtr > + (int) dot11RSNAConfigPairwiseUpdateCount) { + SM_ENTER(WPA_PTK, DISCONNECT); + } else if (sm->TimeoutEvt) + SM_ENTER(WPA_PTK, PTKINITNEGOTIATING); + break; + case WPA_PTK_PTKINITDONE: + break; + } +} + + +SM_STATE(WPA_PTK_GROUP, IDLE) +{ + SM_ENTRY_MA(WPA_PTK_GROUP, IDLE, wpa_ptk_group); + if (sm->Init) { + /* Init flag is not cleared here, so avoid busy + * loop by claiming nothing changed. */ + sm->changed = FALSE; + } + sm->GTimeoutCtr = 0; +} + + +SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING) +{ + u8 rsc[WPA_KEY_RSC_LEN]; + struct wpa_group *gsm = sm->group; + u8 *kde, *pos, hdr[2]; + size_t kde_len; + u8 *gtk, dummy_gtk[32]; + + SM_ENTRY_MA(WPA_PTK_GROUP, REKEYNEGOTIATING, wpa_ptk_group); + + sm->GTimeoutCtr++; + if (sm->GTimeoutCtr > (int) dot11RSNAConfigGroupUpdateCount) { + /* No point in sending the EAPOL-Key - we will disconnect + * immediately following this. */ + return; + } + + if (sm->wpa == WPA_VERSION_WPA) + sm->PInitAKeys = FALSE; + sm->TimeoutEvt = FALSE; + /* Send EAPOL(1, 1, 1, !Pair, G, RSC, GNonce, MIC(PTK), GTK[GN]) */ + memset(rsc, 0, WPA_KEY_RSC_LEN); + if (gsm->wpa_group_state == WPA_GROUP_SETKEYSDONE) + wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc); + + gtk = gsm->GTK[gsm->GN - 1]; + if (sm->wpa_auth->conf.disable_gtk) { + /* + * Provide unique random GTK to each STA to prevent use + * of GTK in the BSS. + */ + if (os_get_random(dummy_gtk, gsm->GTK_len) < 0) + return; + gtk = dummy_gtk; + } + if (sm->wpa == WPA_VERSION_WPA2) { + kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len + + ieee80211w_kde_len(sm); + kde = (u8 *)os_malloc(kde_len); + if (kde == NULL) + return; + + pos = kde; + hdr[0] = gsm->GN & 0x03; + hdr[1] = 0; + pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2, + gtk, gsm->GTK_len); + pos = ieee80211w_kde_add(sm, pos); + } else { + kde = gtk; + pos = kde + gsm->GTK_len; + } + + wpa_send_eapol(sm->wpa_auth, sm, + WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC | + WPA_KEY_INFO_ACK | + (!sm->Pair ? WPA_KEY_INFO_INSTALL : 0), + rsc, gsm->GNonce, kde, pos - kde, gsm->GN, 1); + if (sm->wpa == WPA_VERSION_WPA2) + os_free(kde); +} + + +SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED) +{ + SM_ENTRY_MA(WPA_PTK_GROUP, REKEYESTABLISHED, wpa_ptk_group); + sm->EAPOLKeyReceived = FALSE; + if (sm->GUpdateStationKeys) + sm->group->GKeyDoneStations--; + sm->GUpdateStationKeys = FALSE; + sm->GTimeoutCtr = 0; + /* FIX: MLME.SetProtection.Request(TA, Tx_Rx) */ + sm->has_GTK = TRUE; +} + + +SM_STATE(WPA_PTK_GROUP, KEYERROR) +{ + SM_ENTRY_MA(WPA_PTK_GROUP, KEYERROR, wpa_ptk_group); + if (sm->GUpdateStationKeys) + sm->group->GKeyDoneStations--; + sm->GUpdateStationKeys = FALSE; + sm->Disconnect = TRUE; +} + + +SM_STEP(WPA_PTK_GROUP) +{ + if (sm->Init || sm->PtkGroupInit) { + SM_ENTER(WPA_PTK_GROUP, IDLE); + sm->PtkGroupInit = FALSE; + } else switch (sm->wpa_ptk_group_state) { + case WPA_PTK_GROUP_IDLE: + if (sm->GUpdateStationKeys || + (sm->wpa == WPA_VERSION_WPA && sm->PInitAKeys)) + SM_ENTER(WPA_PTK_GROUP, REKEYNEGOTIATING); + break; + case WPA_PTK_GROUP_REKEYNEGOTIATING: + if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest && + !sm->EAPOLKeyPairwise && sm->MICVerified) + SM_ENTER(WPA_PTK_GROUP, REKEYESTABLISHED); + else if (sm->GTimeoutCtr > + (int) dot11RSNAConfigGroupUpdateCount) + SM_ENTER(WPA_PTK_GROUP, KEYERROR); + else if (sm->TimeoutEvt) + SM_ENTER(WPA_PTK_GROUP, REKEYNEGOTIATING); + break; + case WPA_PTK_GROUP_KEYERROR: + SM_ENTER(WPA_PTK_GROUP, IDLE); + break; + case WPA_PTK_GROUP_REKEYESTABLISHED: + SM_ENTER(WPA_PTK_GROUP, IDLE); + break; + } +} + + +static int wpa_gtk_update(struct wpa_authenticator *wpa_auth, + struct wpa_group *group) +{ + int ret = 0; + + memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN); + inc_byte_array(group->Counter, WPA_NONCE_LEN); + + if (wpa_gmk_to_gtk(group->GMK, "Group key expansion", + wpa_auth->addr, group->GNonce, + group->GTK[group->GN - 1], group->GTK_len) < 0) + ret = -1; + wpa_hexdump_key(MSG_DEBUG, "GTK", + group->GTK[group->GN - 1], group->GTK_len); + +#ifdef CONFIG_IEEE80211W + if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) { + memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN); + inc_byte_array(group->Counter, WPA_NONCE_LEN); + if (wpa_gmk_to_gtk(group->GMK, "IGTK key expansion", + wpa_auth->addr, group->GNonce, + group->IGTK[group->GN_igtk - 4], + WPA_IGTK_LEN) < 0) + ret = -1; + wpa_hexdump_key(MSG_DEBUG, "IGTK", + group->IGTK[group->GN_igtk - 4], WPA_IGTK_LEN); + } +#endif /* CONFIG_IEEE80211W */ + + return ret; +} + + +static void wpa_group_gtk_init(struct wpa_authenticator *wpa_auth, + struct wpa_group *group) +{ + wpa_printf( MSG_DEBUG, "WPA: group state machine entering state " + "GTK_INIT (VLAN-ID %d)\n", group->vlan_id); + group->changed = FALSE; /* GInit is not cleared here; avoid loop */ + group->wpa_group_state = WPA_GROUP_GTK_INIT; + + /* GTK[0..N] = 0 */ + memset(group->GTK, 0, sizeof(group->GTK)); + group->GN = 1; + group->GM = 2; +#ifdef CONFIG_IEEE80211W + group->GN_igtk = 4; + group->GM_igtk = 5; +#endif /* CONFIG_IEEE80211W */ + /* GTK[GN] = CalcGTK() */ + wpa_gtk_update(wpa_auth, group); +} + + +static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx) +{ + if (ctx != NULL && ctx != sm->group) + return 0; + + if (sm->wpa_ptk_state != WPA_PTK_PTKINITDONE) { + sm->GUpdateStationKeys = FALSE; + return 0; + } + if (sm->GUpdateStationKeys) { + /* + * This should not really happen, so add a debug log entry. + * Since we clear the GKeyDoneStations before the loop, the + * station needs to be counted here anyway. + */ + } + + /* Do not rekey GTK/IGTK when STA is in WNM-Sleep Mode */ + if (sm->is_wnmsleep) + return 0; + + sm->group->GKeyDoneStations++; + sm->GUpdateStationKeys = TRUE; + + wpa_sm_step(sm); + return 0; +} + + +#ifdef CONFIG_WNM +/* update GTK when exiting WNM-Sleep Mode */ +void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm) +{ + if (sm->is_wnmsleep) + return; + + wpa_group_update_sta(sm, NULL); +} + + +void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag) +{ + sm->is_wnmsleep = !!flag; +} + + +int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos) +{ + struct wpa_group *gsm = sm->group; + u8 *start = pos; + + /* + * GTK subelement: + * Sub-elem ID[1] | Length[1] | Key Info[2] | Key Length[1] | RSC[8] | + * Key[5..32] + */ + *pos++ = WNM_SLEEP_SUBELEM_GTK; + *pos++ = 11 + gsm->GTK_len; + /* Key ID in B0-B1 of Key Info */ + WPA_PUT_LE16(pos, gsm->GN & 0x03); + pos += 2; + *pos++ = gsm->GTK_len; + if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, pos) != 0) + return 0; + pos += 8; + memcpy(pos, gsm->GTK[gsm->GN - 1], gsm->GTK_len); + pos += gsm->GTK_len; + + wpa_printf( MSG_DEBUG, "WNM: GTK Key ID %u in WNM-Sleep Mode exit", + gsm->GN); + wpa_hexdump_key(MSG_DEBUG, "WNM: GTK in WNM-Sleep Mode exit", + gsm->GTK[gsm->GN - 1], gsm->GTK_len); + + return pos - start; +} + + +#ifdef CONFIG_IEEE80211W +int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos) +{ + struct wpa_group *gsm = sm->group; + u8 *start = pos; + + /* + * IGTK subelement: + * Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] | Key[16] + */ + *pos++ = WNM_SLEEP_SUBELEM_IGTK; + *pos++ = 2 + 6 + WPA_IGTK_LEN; + WPA_PUT_LE16(pos, gsm->GN_igtk); + pos += 2; + if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos) != 0) + return 0; + pos += 6; + + memcpy(pos, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN); + pos += WPA_IGTK_LEN; + + wpa_printf( MSG_DEBUG, "WNM: IGTK Key ID %u in WNM-Sleep Mode exit", + gsm->GN_igtk); + wpa_hexdump_key(MSG_DEBUG, "WNM: IGTK in WNM-Sleep Mode exit", + gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN); + + return pos - start; +} +#endif /* CONFIG_IEEE80211W */ +#endif /* CONFIG_WNM */ + + +static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth, + struct wpa_group *group) +{ + int tmp; + + wpa_printf( MSG_DEBUG, "WPA: group state machine entering state " + "SETKEYS (VLAN-ID %d)\n", group->vlan_id); + group->changed = TRUE; + group->wpa_group_state = WPA_GROUP_SETKEYS; + group->GTKReKey = FALSE; + tmp = group->GM; + group->GM = group->GN; + group->GN = tmp; +#ifdef CONFIG_IEEE80211W + tmp = group->GM_igtk; + group->GM_igtk = group->GN_igtk; + group->GN_igtk = tmp; +#endif /* CONFIG_IEEE80211W */ + /* "GKeyDoneStations = GNoStations" is done in more robust way by + * counting the STAs that are marked with GUpdateStationKeys instead of + * including all STAs that could be in not-yet-completed state. */ + wpa_gtk_update(wpa_auth, group); + + if (group->GKeyDoneStations) { + wpa_printf( MSG_DEBUG, "wpa_group_setkeys: Unexpected " + "GKeyDoneStations=%d when starting new GTK rekey", + group->GKeyDoneStations); + group->GKeyDoneStations = 0; + } + wpa_auth_for_each_sta(wpa_auth, wpa_group_update_sta, group); + wpa_printf( MSG_DEBUG, "wpa_group_setkeys: GKeyDoneStations=%d", + group->GKeyDoneStations); +} + + +static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth, + struct wpa_group *group) +{ + int ret = 0; + if (wpa_auth_set_key(wpa_auth, group->vlan_id, + wpa_cipher_to_alg(wpa_auth->conf.wpa_group), + (uint8_t *)broadcast_ether_addr, group->GN, + group->GTK[group->GN - 1], group->GTK_len) < 0) + ret = -1; + +#ifdef CONFIG_IEEE80211W + if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION && + wpa_auth_set_key(wpa_auth, group->vlan_id, WPA_ALG_IGTK, + broadcast_ether_addr, group->GN_igtk, + group->IGTK[group->GN_igtk - 4], + WPA_IGTK_LEN) < 0) + ret = -1; +#endif /* CONFIG_IEEE80211W */ + + return ret; +} + + +static int wpa_group_setkeysdone(struct wpa_authenticator *wpa_auth, + struct wpa_group *group) +{ + wpa_printf( MSG_DEBUG, "WPA: group state machine entering state " + "SETKEYSDONE (VLAN-ID %d)\n", group->vlan_id); + group->changed = TRUE; + group->wpa_group_state = WPA_GROUP_SETKEYSDONE; + + if (wpa_group_config_group_keys(wpa_auth, group) < 0) + return -1; + + return 0; +} + + +static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth, + struct wpa_group *group) +{ + if (group->GInit) { + wpa_group_gtk_init(wpa_auth, group); + } else if (group->wpa_group_state == WPA_GROUP_GTK_INIT && + group->GTKAuthenticator) { + wpa_group_setkeysdone(wpa_auth, group); + } else if (group->wpa_group_state == WPA_GROUP_SETKEYSDONE && + group->GTKReKey) { + wpa_group_setkeys(wpa_auth, group); + } else if (group->wpa_group_state == WPA_GROUP_SETKEYS) { + if (group->GKeyDoneStations == 0) + wpa_group_setkeysdone(wpa_auth, group); + else if (group->GTKReKey) + wpa_group_setkeys(wpa_auth, group); + } +} + + +static int wpa_sm_step(struct wpa_state_machine *sm) +{ + if (sm == NULL) + return 0; + + if (sm->in_step_loop) { + /* This should not happen, but if it does, make sure we do not + * end up freeing the state machine too early by exiting the + * recursive call. */ + wpa_printf( MSG_ERROR, "WPA: wpa_sm_step() called recursively"); + return 0; + } + + sm->in_step_loop = 1; + do { + if (sm->pending_deinit) + break; + + sm->changed = FALSE; + sm->wpa_auth->group->changed = FALSE; + + SM_STEP_RUN(WPA_PTK); + if (sm->pending_deinit) + break; + SM_STEP_RUN(WPA_PTK_GROUP); + if (sm->pending_deinit) + break; + wpa_group_sm_step(sm->wpa_auth, sm->group); + } while (sm->changed || sm->wpa_auth->group->changed); + sm->in_step_loop = 0; + + if (sm->pending_deinit) { + wpa_printf( MSG_DEBUG, "WPA: Completing pending STA state " + "machine deinit for " MACSTR, MAC2STR(sm->addr)); + wpa_free_sta_sm(sm); + return 1; + } + return 0; +} + +bool wpa_ap_join(void** sm, uint8_t *bssid, uint8_t *wpa_ie, uint8_t wpa_ie_len) +{ + struct hostapd_data *hapd = (struct hostapd_data*)esp_wifi_get_hostap_private_internal(); + struct wpa_state_machine **wpa_sm; + + if (!sm || !bssid || !wpa_ie){ + return false; + } + + + wpa_sm = (struct wpa_state_machine **)sm; + + if (hapd) { + if (hapd->wpa_auth->conf.wpa) { + if (*wpa_sm){ + wpa_auth_sta_deinit(*wpa_sm); + } + + *wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, bssid); + wpa_printf( MSG_DEBUG, "init wpa sm=%p\n", *wpa_sm); + + if (*wpa_sm == NULL) { + return false; + } + + if (wpa_validate_wpa_ie(hapd->wpa_auth, *wpa_sm, wpa_ie, wpa_ie_len)) { + return false; + } + } + + wpa_auth_sta_associated(hapd->wpa_auth, *wpa_sm); + } + + return true; +} + +bool wpa_ap_remove(void* sm) +{ + struct wpa_state_machine *wpa_sm; + if (!sm) return false; + + wpa_sm = (struct wpa_state_machine*)sm; + wpa_auth_sta_deinit(wpa_sm); + + return true; +} + diff --git a/components/wpa_supplicant/include/wpa/wpa_auth.h b/components/wpa_supplicant/src/ap/wpa_auth.h similarity index 98% rename from components/wpa_supplicant/include/wpa/wpa_auth.h rename to components/wpa_supplicant/src/ap/wpa_auth.h index c729923494..ee40c2d43d 100644 --- a/components/wpa_supplicant/include/wpa/wpa_auth.h +++ b/components/wpa_supplicant/src/ap/wpa_auth.h @@ -9,14 +9,16 @@ #ifndef WPA_AUTH_H #define WPA_AUTH_H -#include "wpa/defs.h" -#include "wpa/eapol_common.h" -#include "wpa/wpa_common.h" +#include "common/defs.h" +#include "common/eapol_common.h" +#include "common/wpa_common.h" #ifdef _MSC_VER #pragma pack(push, 1) #endif /* _MSC_VER */ +#define WPA_IS_MULTICAST(_a) (*(_a) & 0x01) + /* IEEE Std 802.11r-2008, 11A.10.3 - Remote request/response frame definition */ struct ft_rrb_frame { diff --git a/components/wpa_supplicant/include/wpa/wpa_auth_i.h b/components/wpa_supplicant/src/ap/wpa_auth_i.h similarity index 84% rename from components/wpa_supplicant/include/wpa/wpa_auth_i.h rename to components/wpa_supplicant/src/ap/wpa_auth_i.h index 53ad8ea941..6a55cdee53 100644 --- a/components/wpa_supplicant/include/wpa/wpa_auth_i.h +++ b/components/wpa_supplicant/src/ap/wpa_auth_i.h @@ -102,10 +102,6 @@ struct wpa_state_machine { } wpa; int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */ int wpa_key_mgmt; /* the selected WPA_KEY_MGMT_* */ -// struct rsn_pmksa_cache_entry *pmksa; - -// u32 dot11RSNAStatsTKIPLocalMICFailures; -// u32 dot11RSNAStatsTKIPRemoteMICFailures; #ifdef CONFIG_IEEE80211R u8 xxkey[PMK_LEN]; /* PSK or the second 256 bits of MSK */ @@ -120,6 +116,8 @@ struct wpa_state_machine { #endif /* CONFIG_IEEE80211R */ int pending_1_of_4_timeout; + u32 index; + ETSTimer resend_eapol; }; @@ -160,40 +158,18 @@ struct wpa_ft_pmk_cache; struct wpa_authenticator { struct wpa_group *group; -// unsigned int dot11RSNAStatsTKIPRemoteMICFailures; -// u32 dot11RSNAAuthenticationSuiteSelected; -// u32 dot11RSNAPairwiseCipherSelected; -// u32 dot11RSNAGroupCipherSelected; -// u8 dot11RSNAPMKIDUsed[PMKID_LEN]; -// u32 dot11RSNAAuthenticationSuiteRequested; /* FIX: update */ -// u32 dot11RSNAPairwiseCipherRequested; /* FIX: update */ -// u32 dot11RSNAGroupCipherRequested; /* FIX: update */ -// unsigned int dot11RSNATKIPCounterMeasuresInvoked; -// unsigned int dot11RSNA4WayHandshakeFailures; - -// struct wpa_stsl_negotiation *stsl_negotiations; - struct wpa_auth_config conf; -// struct wpa_auth_callbacks cb; u8 *wpa_ie; size_t wpa_ie_len; u8 addr[ETH_ALEN]; -// struct rsn_pmksa_cache *pmksa; -// struct wpa_ft_pmk_cache *ft_pmk_cache; }; int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, const u8 *pmkid); -#if 0 -void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr, - logger_level level, const char *txt); -void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr, - logger_level level, const char *fmt, ...); -#endif void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, int key_info, const u8 *key_rsc, const u8 *nonce, diff --git a/components/wpa_supplicant/src/ap/wpa_auth_ie.c b/components/wpa_supplicant/src/ap/wpa_auth_ie.c new file mode 100644 index 0000000000..34f12217db --- /dev/null +++ b/components/wpa_supplicant/src/ap/wpa_auth_ie.c @@ -0,0 +1,705 @@ +/* + * hostapd - WPA/RSN IE and KDE definitions + * Copyright (c) 2004-2008, Jouni Malinen + * + * 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 "common/ieee802_11_defs.h" +#include "ap/wpa_auth.h" +#include "ap/wpa_auth_ie.h" +#include "ap/wpa_auth_i.h" +#include "common/wpa_common.h" +#include "utils/wpa_debug.h" + +#ifdef CONFIG_RSN_TESTING +int rsn_testing = 0; +#endif /* CONFIG_RSN_TESTING */ + + +static int wpa_write_wpa_ie(struct wpa_auth_config *conf, u8 *buf, size_t len) +{ + struct wpa_ie_hdr *hdr; + int num_suites; + u8 *pos, *count; + u32 suite; + + hdr = (struct wpa_ie_hdr *) buf; + 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); + + suite = wpa_cipher_to_suite(WPA_PROTO_WPA, conf->wpa_group); + if (suite == 0) { + wpa_printf( MSG_DEBUG, "Invalid group cipher (%d).", + conf->wpa_group); + return -1; + } + RSN_SELECTOR_PUT(pos, suite); + pos += WPA_SELECTOR_LEN; + + count = pos; + pos += 2; + + num_suites = wpa_cipher_put_suites(pos, conf->wpa_pairwise); + if (num_suites == 0) { + wpa_printf( MSG_DEBUG, "Invalid pairwise cipher (%d).", + conf->wpa_pairwise); + return -1; + } + pos += num_suites * WPA_SELECTOR_LEN; + WPA_PUT_LE16(count, num_suites); + + num_suites = 0; + count = pos; + pos += 2; + + if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) { + RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X); + pos += WPA_SELECTOR_LEN; + num_suites++; + } + if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) { + RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X); + pos += WPA_SELECTOR_LEN; + num_suites++; + } + + if (num_suites == 0) { + wpa_printf( MSG_DEBUG, "Invalid key management type (%d).", + conf->wpa_key_mgmt); + return -1; + } + WPA_PUT_LE16(count, num_suites); + + /* WPA Capabilities; use defaults, so no need to include it */ + + hdr->len = (pos - buf) - 2; + + return pos - buf; +} + + +int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, + const u8 *pmkid) +{ + struct rsn_ie_hdr *hdr; + int num_suites, res; + u8 *pos, *count; + u16 capab; + u32 suite; + + hdr = (struct rsn_ie_hdr *) buf; + hdr->elem_id = WLAN_EID_RSN; + WPA_PUT_LE16(hdr->version, RSN_VERSION); + pos = (u8 *) (hdr + 1); + + suite = wpa_cipher_to_suite(WPA_PROTO_RSN, conf->wpa_group); + if (suite == 0) { + wpa_printf( MSG_DEBUG, "Invalid group cipher (%d).", + conf->wpa_group); + return -1; + } + RSN_SELECTOR_PUT(pos, suite); + pos += RSN_SELECTOR_LEN; + + num_suites = 0; + count = pos; + pos += 2; + +#ifdef CONFIG_RSN_TESTING + if (rsn_testing) { + RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 1)); + pos += RSN_SELECTOR_LEN; + num_suites++; + } +#endif /* CONFIG_RSN_TESTING */ + + res = rsn_cipher_put_suites(pos, conf->rsn_pairwise); + num_suites += res; + pos += res * RSN_SELECTOR_LEN; + +#ifdef CONFIG_RSN_TESTING + if (rsn_testing) { + RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 2)); + pos += RSN_SELECTOR_LEN; + num_suites++; + } +#endif /* CONFIG_RSN_TESTING */ + + if (num_suites == 0) { + wpa_printf( MSG_DEBUG, "Invalid pairwise cipher (%d).", + conf->rsn_pairwise); + return -1; + } + WPA_PUT_LE16(count, num_suites); + + num_suites = 0; + count = pos; + pos += 2; + +#ifdef CONFIG_RSN_TESTING + if (rsn_testing) { + RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 1)); + pos += RSN_SELECTOR_LEN; + num_suites++; + } +#endif /* CONFIG_RSN_TESTING */ + + if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) { + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X); + pos += RSN_SELECTOR_LEN; + num_suites++; + } + if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) { + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X); + pos += RSN_SELECTOR_LEN; + num_suites++; + } +#ifdef CONFIG_IEEE80211R + if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) { + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); + pos += RSN_SELECTOR_LEN; + num_suites++; + } + if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) { + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); + pos += RSN_SELECTOR_LEN; + num_suites++; + } +#endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_IEEE80211W + if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) { + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256); + pos += RSN_SELECTOR_LEN; + num_suites++; + } + if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) { + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256); + pos += RSN_SELECTOR_LEN; + num_suites++; + } +#endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_SAE + if (conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) { + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE); + pos += RSN_SELECTOR_LEN; + num_suites++; + } + if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) { + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE); + pos += RSN_SELECTOR_LEN; + num_suites++; + } +#endif /* CONFIG_SAE */ + +#ifdef CONFIG_RSN_TESTING + if (rsn_testing) { + RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 2)); + pos += RSN_SELECTOR_LEN; + num_suites++; + } +#endif /* CONFIG_RSN_TESTING */ + + if (num_suites == 0) { + wpa_printf( MSG_DEBUG, "Invalid key management type (%d).", + conf->wpa_key_mgmt); + return -1; + } + WPA_PUT_LE16(count, num_suites); + + /* RSN Capabilities */ + capab = 0; + if (conf->rsn_preauth) + capab |= WPA_CAPABILITY_PREAUTH; + if (conf->peerkey) + capab |= WPA_CAPABILITY_PEERKEY_ENABLED; + if (conf->wmm_enabled) { + /* 4 PTKSA replay counters when using WMM */ + capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2); + } +#ifdef CONFIG_IEEE80211W + if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { + capab |= WPA_CAPABILITY_MFPC; + if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) + capab |= WPA_CAPABILITY_MFPR; + } +#endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_RSN_TESTING + if (rsn_testing) + capab |= BIT(8) | BIT(14) | BIT(15); +#endif /* CONFIG_RSN_TESTING */ + WPA_PUT_LE16(pos, capab); + pos += 2; + + if (pmkid) { + if (pos + 2 + PMKID_LEN > buf + len) + return -1; + /* PMKID Count */ + WPA_PUT_LE16(pos, 1); + pos += 2; + memcpy(pos, pmkid, PMKID_LEN); + pos += PMKID_LEN; + } + +#ifdef CONFIG_IEEE80211W + if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { + if (pos + 2 + 4 > buf + len) + return -1; + if (pmkid == NULL) { + /* 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 */ + +#ifdef CONFIG_RSN_TESTING + if (rsn_testing) { + /* + * Fill in any defined fields and add extra data to the end of + * the element. + */ + int pmkid_count_set = pmkid != NULL; + if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) + pmkid_count_set = 1; + /* PMKID Count */ + WPA_PUT_LE16(pos, 0); + pos += 2; + if (conf->ieee80211w == NO_MGMT_FRAME_PROTECTION) { + /* Management Group Cipher Suite */ + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); + pos += RSN_SELECTOR_LEN; + } + + memset(pos, 0x12, 17); + pos += 17; + } +#endif /* CONFIG_RSN_TESTING */ + + hdr->len = (pos - buf) - 2; + + return pos - buf; +} + + +int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth) +{ + u8 *pos, buf[128]; + int res; + + pos = buf; + + if (wpa_auth->conf.wpa & WPA_PROTO_RSN) { + res = wpa_write_rsn_ie(&wpa_auth->conf, + pos, buf + sizeof(buf) - pos, NULL); + if (res < 0) + return res; + pos += res; + } +#ifdef CONFIG_IEEE80211R + if (wpa_key_mgmt_ft(wpa_auth->conf.wpa_key_mgmt)) { + res = wpa_write_mdie(&wpa_auth->conf, pos, + buf + sizeof(buf) - pos); + if (res < 0) + return res; + pos += res; + } +#endif /* CONFIG_IEEE80211R */ + if (wpa_auth->conf.wpa & WPA_PROTO_WPA) { + res = wpa_write_wpa_ie(&wpa_auth->conf, + pos, buf + sizeof(buf) - pos); + if (res < 0) + return res; + pos += res; + } + + os_free(wpa_auth->wpa_ie); + wpa_auth->wpa_ie = os_malloc(pos - buf); + if (wpa_auth->wpa_ie == NULL) + return -1; + memcpy(wpa_auth->wpa_ie, buf, pos - buf); + wpa_auth->wpa_ie_len = pos - buf; + + return 0; +} + +u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len, + const u8 *data2, size_t data2_len) +{ + *pos++ = WLAN_EID_VENDOR_SPECIFIC; + *pos++ = RSN_SELECTOR_LEN + data_len + data2_len; + RSN_SELECTOR_PUT(pos, kde); + pos += RSN_SELECTOR_LEN; + memcpy(pos, data, data_len); + pos += data_len; + if (data2) { + memcpy(pos, data2, data2_len); + pos += data2_len; + } + return pos; +} + +int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm, + const u8 *wpa_ie, size_t wpa_ie_len/*, + const u8 *mdie, size_t mdie_len*/) +{ + struct wpa_ie_data data; + int ciphers, key_mgmt, res, version; + u32 selector; + + if (wpa_auth == NULL || sm == NULL) + return WPA_NOT_ENABLED; + + if (wpa_ie == NULL || wpa_ie_len < 1) + return WPA_INVALID_IE; + + if (wpa_ie[0] == WLAN_EID_RSN) + version = WPA_PROTO_RSN; + else + version = WPA_PROTO_WPA; + + if (!(wpa_auth->conf.wpa & version)) { + wpa_printf( MSG_DEBUG, "Invalid WPA proto (%d) from " MACSTR, + version, MAC2STR(sm->addr)); + return WPA_INVALID_PROTO; + } + + if (version == WPA_PROTO_RSN) { + res = wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, &data); + + selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X; + if (0) { + } +#ifdef CONFIG_IEEE80211R + else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) + selector = RSN_AUTH_KEY_MGMT_FT_802_1X; + else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) + selector = RSN_AUTH_KEY_MGMT_FT_PSK; +#endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_IEEE80211W + else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) + selector = RSN_AUTH_KEY_MGMT_802_1X_SHA256; + else if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) + selector = RSN_AUTH_KEY_MGMT_PSK_SHA256; +#endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_SAE + else if (data.key_mgmt & WPA_KEY_MGMT_SAE) + selector = RSN_AUTH_KEY_MGMT_SAE; + else if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE) + selector = RSN_AUTH_KEY_MGMT_FT_SAE; +#endif /* CONFIG_SAE */ + else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) + selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X; + else if (data.key_mgmt & WPA_KEY_MGMT_PSK) + selector = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X; + + selector = wpa_cipher_to_suite(WPA_PROTO_RSN, + data.pairwise_cipher); + if (!selector) + selector = RSN_CIPHER_SUITE_CCMP; + + selector = wpa_cipher_to_suite(WPA_PROTO_RSN, + data.group_cipher); + if (!selector) + selector = RSN_CIPHER_SUITE_CCMP; + } else { + res = wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, &data); + + selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X; + if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) + selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X; + else if (data.key_mgmt & WPA_KEY_MGMT_PSK) + selector = WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X; + + selector = wpa_cipher_to_suite(WPA_PROTO_WPA, + data.pairwise_cipher); + if (!selector) + selector = RSN_CIPHER_SUITE_TKIP; + + selector = wpa_cipher_to_suite(WPA_PROTO_WPA, + data.group_cipher); + if (!selector) + selector = WPA_CIPHER_SUITE_TKIP; + } + if (res) { + wpa_printf( MSG_DEBUG, "Failed to parse WPA/RSN IE from " + MACSTR " (res=%d)", MAC2STR(sm->addr), res); + wpa_hexdump(MSG_DEBUG, "WPA/RSN IE", wpa_ie, wpa_ie_len); + return WPA_INVALID_IE; + } + + if (data.group_cipher != wpa_auth->conf.wpa_group) { + wpa_printf( MSG_DEBUG, "Invalid WPA group cipher (0x%x) from " + MACSTR, data.group_cipher, MAC2STR(sm->addr)); + return WPA_INVALID_GROUP; + } + + key_mgmt = data.key_mgmt & wpa_auth->conf.wpa_key_mgmt; + if (!key_mgmt) { + wpa_printf( MSG_DEBUG, "Invalid WPA key mgmt (0x%x) from " + MACSTR, data.key_mgmt, MAC2STR(sm->addr)); + return WPA_INVALID_AKMP; + } + if (0) { + } +#ifdef CONFIG_IEEE80211R + else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) + sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X; + else if (key_mgmt & WPA_KEY_MGMT_FT_PSK) + sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK; +#endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_IEEE80211W + else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) + sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256; + else if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256) + sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK_SHA256; +#endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_SAE + else if (key_mgmt & WPA_KEY_MGMT_SAE) + sm->wpa_key_mgmt = WPA_KEY_MGMT_SAE; + else if (key_mgmt & WPA_KEY_MGMT_FT_SAE) + sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_SAE; +#endif /* CONFIG_SAE */ + else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X) + sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X; + else + sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK; + + if (version == WPA_PROTO_RSN) + ciphers = data.pairwise_cipher & wpa_auth->conf.rsn_pairwise; + else + ciphers = data.pairwise_cipher & wpa_auth->conf.wpa_pairwise; + if (!ciphers) { + wpa_printf( MSG_DEBUG, "Invalid %s pairwise cipher (0x%x) " + "from " MACSTR, + version == WPA_PROTO_RSN ? "RSN" : "WPA", + data.pairwise_cipher, MAC2STR(sm->addr)); + return WPA_INVALID_PAIRWISE; + } + +#ifdef CONFIG_IEEE80211W + if (wpa_auth->conf.ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) { + if (!(data.capabilities & WPA_CAPABILITY_MFPC)) { + wpa_printf( MSG_DEBUG, "Management frame protection " + "required, but client did not enable it"); + return WPA_MGMT_FRAME_PROTECTION_VIOLATION; + } + + if (ciphers & WPA_CIPHER_TKIP) { + wpa_printf( MSG_DEBUG, "Management frame protection " + "cannot use TKIP"); + return WPA_MGMT_FRAME_PROTECTION_VIOLATION; + } + + if (data.mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) { + wpa_printf( MSG_DEBUG, "Unsupported management group " + "cipher %d", data.mgmt_group_cipher); + return WPA_INVALID_MGMT_GROUP_CIPHER; + } + } + + if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION || + !(data.capabilities & WPA_CAPABILITY_MFPC)) + sm->mgmt_frame_prot = 0; + else + sm->mgmt_frame_prot = 1; +#endif /* CONFIG_IEEE80211W */ + +#ifdef CONFIG_IEEE80211R + if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { + if (mdie == NULL || mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) { + wpa_printf( MSG_DEBUG, "RSN: Trying to use FT, but " + "MDIE not included"); + return WPA_INVALID_MDIE; + } + if (memcmp(mdie, wpa_auth->conf.mobility_domain, + MOBILITY_DOMAIN_ID_LEN) != 0) { + wpa_hexdump(MSG_DEBUG, "RSN: Attempted to use unknown " + "MDIE", mdie, MOBILITY_DOMAIN_ID_LEN); + return WPA_INVALID_MDIE; + } + } +#endif /* CONFIG_IEEE80211R */ + + if (ciphers & WPA_CIPHER_CCMP) + sm->pairwise = WPA_CIPHER_CCMP; + else if (ciphers & WPA_CIPHER_GCMP) + sm->pairwise = WPA_CIPHER_GCMP; + else + sm->pairwise = WPA_CIPHER_TKIP; + + /* TODO: clear WPA/WPA2 state if STA changes from one to another */ + if (wpa_ie[0] == WLAN_EID_RSN) + sm->wpa = WPA_VERSION_WPA2; + else + sm->wpa = WPA_VERSION_WPA; + + if (sm->wpa_ie == NULL || sm->wpa_ie_len < wpa_ie_len) { + os_free(sm->wpa_ie); + sm->wpa_ie = os_malloc(wpa_ie_len); + if (sm->wpa_ie == NULL) + return WPA_ALLOC_FAIL; + } + memcpy(sm->wpa_ie, wpa_ie, wpa_ie_len); + sm->wpa_ie_len = wpa_ie_len; + + return WPA_IE_OK; +} + +/** + * 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; + 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; + 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; + 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; + return 0; + } + +#ifdef CONFIG_PEERKEY + if (pos[1] > RSN_SELECTOR_LEN + 2 && + RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) { + ie->smk = pos + 2 + RSN_SELECTOR_LEN; + ie->smk_len = pos[1] - RSN_SELECTOR_LEN; + return 0; + } + + if (pos[1] > RSN_SELECTOR_LEN + 2 && + RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) { + ie->nonce = pos + 2 + RSN_SELECTOR_LEN; + ie->nonce_len = pos[1] - RSN_SELECTOR_LEN; + return 0; + } + + if (pos[1] > RSN_SELECTOR_LEN + 2 && + RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) { + ie->lifetime = pos + 2 + RSN_SELECTOR_LEN; + ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN; + return 0; + } + + if (pos[1] > RSN_SELECTOR_LEN + 2 && + RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) { + ie->error = pos + 2 + RSN_SELECTOR_LEN; + ie->error_len = pos[1] - RSN_SELECTOR_LEN; + return 0; + } +#endif /* CONFIG_PEERKEY */ + +#ifdef CONFIG_IEEE80211W + if (pos[1] > RSN_SELECTOR_LEN + 2 && + RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) { + ie->igtk = pos + 2 + RSN_SELECTOR_LEN; + ie->igtk_len = pos[1] - RSN_SELECTOR_LEN; + return 0; + } +#endif /* CONFIG_IEEE80211W */ + + return 0; +} + + +/** + * wpa_parse_kde_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_parse_kde_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) { + wpa_printf( MSG_DEBUG, "WPA: EAPOL-Key Key Data " + "underflow (ie=%d len=%d pos=%d)", + pos[0], pos[1], (int) (pos - buf)); + wpa_hexdump_key(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; +#ifdef CONFIG_IEEE80211R + } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) { + ie->mdie = pos; + ie->mdie_len = pos[1] + 2; + } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) { + ie->ftie = pos; + ie->ftie_len = pos[1] + 2; +#endif /* CONFIG_IEEE80211R */ + } 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; +} + + +int wpa_auth_uses_mfp(struct wpa_state_machine *sm) +{ + return sm ? sm->mgmt_frame_prot : 0; +} diff --git a/components/wpa_supplicant/include/wpa/wpa_auth_ie.h b/components/wpa_supplicant/src/ap/wpa_auth_ie.h similarity index 100% rename from components/wpa_supplicant/include/wpa/wpa_auth_ie.h rename to components/wpa_supplicant/src/ap/wpa_auth_ie.h diff --git a/components/wpa_supplicant/include/wpa/defs.h b/components/wpa_supplicant/src/common/defs.h similarity index 77% rename from components/wpa_supplicant/include/wpa/defs.h rename to components/wpa_supplicant/src/common/defs.h index f019cee992..578604296b 100644 --- a/components/wpa_supplicant/include/wpa/defs.h +++ b/components/wpa_supplicant/src/common/defs.h @@ -23,57 +23,13 @@ #endif typedef enum { FALSE = 0, TRUE = 1 } Boolean; -/* -#define WPA_CIPHER_NONE BIT(0) -#define WPA_CIPHER_WEP40 BIT(1) -#define WPA_CIPHER_WEP104 BIT(2) -#define WPA_CIPHER_TKIP BIT(3) -#define WPA_CIPHER_CCMP BIT(4) -#ifdef CONFIG_IEEE80211W -#define WPA_CIPHER_AES_128_CMAC BIT(5) -#endif -*/ - -/* - * NB: these values are ordered carefully; there are lots of - * of implications in any reordering. Beware that 4 is used - * only to indicate h/w TKIP MIC support in driver capabilities; - * there is no separate cipher support (it's rolled into the - * TKIP cipher support). - */ -#define IEEE80211_CIPHER_NONE 0 /* pseudo value */ -#define IEEE80211_CIPHER_TKIP 1 -#define IEEE80211_CIPHER_AES_OCB 2 -#define IEEE80211_CIPHER_AES_CCM 3 -#define IEEE80211_CIPHER_TKIPMIC 4 /* TKIP MIC capability */ -#define IEEE80211_CIPHER_CKIP 5 -#define IEEE80211_CIPHER_WEP 6 -#define IEEE80211_CIPHER_WEP40 7 -#define IEEE80211_CIPHER_WEP104 8 - - -#define IEEE80211_CIPHER_MAX (IEEE80211_CIPHER_NONE+2) - -/* capability bits in ic_cryptocaps/iv_cryptocaps */ -#define IEEE80211_CRYPTO_NONE (1< + * + * 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 "common/defs.h" +#include "common/ieee802_11_defs.h" +#include "common/wpa_common.h" +#include "rsn_supp/wpa.h" +#include "crypto/sha1.h" +#include "crypto/sha256.h" +#include "crypto/md5.h" + +#define MD5_MAC_LEN 16 + +#ifndef CONFIG_NO_WPA2 +static int rsn_selector_to_bitfield(const u8 *s) +{ + if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE) + return WPA_CIPHER_NONE; + if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP40) + return WPA_CIPHER_WEP40; + if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_TKIP) + return WPA_CIPHER_TKIP; + if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP) + return WPA_CIPHER_CCMP; + if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP104) + return WPA_CIPHER_WEP104; +#ifdef CONFIG_IEEE80211W + if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC) + return WPA_CIPHER_AES_128_CMAC; +#endif /* CONFIG_IEEE80211W */ + return 0; +} + +static int rsn_key_mgmt_to_bitfield(const u8 *s) +{ + if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_UNSPEC_802_1X) + return WPA_KEY_MGMT_IEEE8021X; + if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X) + return WPA_KEY_MGMT_PSK; +#ifdef CONFIG_IEEE80211R + if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X) + return WPA_KEY_MGMT_FT_IEEE8021X; + if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK) + return WPA_KEY_MGMT_FT_PSK; +#endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_IEEE80211W + if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256) + return WPA_KEY_MGMT_IEEE8021X_SHA256; + if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256) + return WPA_KEY_MGMT_PSK_SHA256; +#endif /* CONFIG_IEEE80211W */ + return 0; +} + +static int wpa_selector_to_bitfield(const u8 *s) +{ + if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE) + return WPA_CIPHER_NONE; + if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP40) + return WPA_CIPHER_WEP40; + if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP) + return WPA_CIPHER_TKIP; + if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP) + return WPA_CIPHER_CCMP; + if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP104) + return WPA_CIPHER_WEP104; + return 0; +} + +static int wpa_key_mgmt_to_bitfield(const u8 *s) +{ + if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X) + return WPA_KEY_MGMT_IEEE8021X; + if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X) + return WPA_KEY_MGMT_PSK; + if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE) + return WPA_KEY_MGMT_WPA_NONE; + return 0; +} +#endif /* CONFIG_NO_WPA2 */ +/** + * wpa_parse_wpa_ie_rsn - Parse RSN IE + * @rsn_ie: Buffer containing RSN IE + * @rsn_ie_len: RSN IE buffer length (including IE number and length octets) + * @data: Pointer to structure that will be filled in with parsed data + * Returns: 0 on success, <0 on failure + */ +int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, + struct wpa_ie_data *data) +{ +#ifndef CONFIG_NO_WPA2 + const struct rsn_ie_hdr *hdr; + const u8 *pos; + int left; + int i, count; + + memset(data, 0, sizeof(*data)); + data->proto = WPA_PROTO_RSN; + data->pairwise_cipher = WPA_CIPHER_CCMP; + data->group_cipher = WPA_CIPHER_CCMP; + data->key_mgmt = WPA_KEY_MGMT_IEEE8021X; + data->capabilities = 0; + data->pmkid = NULL; + data->num_pmkid = 0; + data->mgmt_group_cipher = 0; + + if (rsn_ie_len == 0) { + /* No RSN IE - fail silently */ + return -1; + } + + if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "%s: ie len too short %lu", + __func__, (unsigned long) rsn_ie_len); + #endif + return -1; + } + + hdr = (const struct rsn_ie_hdr *) rsn_ie; + + if (hdr->elem_id != WLAN_EID_RSN || + hdr->len != rsn_ie_len - 2 || + WPA_GET_LE16(hdr->version) != RSN_VERSION) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version", + __func__); + #endif + return -2; + } + + pos = (const u8 *) (hdr + 1); + left = rsn_ie_len - sizeof(*hdr); + + if (left >= RSN_SELECTOR_LEN) { + data->group_cipher = rsn_selector_to_bitfield(pos); + pos += RSN_SELECTOR_LEN; + left -= RSN_SELECTOR_LEN; + } else if (left > 0) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much", + __func__, left); + #endif + return -3; + } + + if (left >= 2) { + data->pairwise_cipher = 0; + count = WPA_GET_LE16(pos); + pos += 2; + left -= 2; + if (count == 0 || left < count * RSN_SELECTOR_LEN) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), " + "count %u left %u", __func__, count, left); + #endif + return -4; + } + for (i = 0; i < count; i++) { + data->pairwise_cipher |= rsn_selector_to_bitfield(pos); + pos += RSN_SELECTOR_LEN; + left -= RSN_SELECTOR_LEN; + } + } else if (left == 1) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)", + __func__); + #endif + return -5; + } + + if (left >= 2) { + data->key_mgmt = 0; + count = WPA_GET_LE16(pos); + pos += 2; + left -= 2; + if (count == 0 || left < count * RSN_SELECTOR_LEN) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), " + "count %u left %u", __func__, count, left); + #endif + return -6; + } + for (i = 0; i < count; i++) { + data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos); + pos += RSN_SELECTOR_LEN; + left -= RSN_SELECTOR_LEN; + } + } else if (left == 1) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)", + __func__); + #endif + return -7; + } + + if (left >= 2) { + data->capabilities = WPA_GET_LE16(pos); + pos += 2; + left -= 2; + } + + if (left >= 2) { + data->num_pmkid = WPA_GET_LE16(pos); + pos += 2; + left -= 2; + if (left < (int) data->num_pmkid * PMKID_LEN) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "%s: PMKID underflow " + "(num_pmkid=%lu left=%d)", + __func__, (unsigned long) data->num_pmkid, + left); + #endif + data->num_pmkid = 0; + return -9; + } else { + data->pmkid = pos; + pos += data->num_pmkid * PMKID_LEN; + left -= data->num_pmkid * PMKID_LEN; + } + } + + if (left > 0) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored", + __func__, left); + #endif + } + + return 0; +#else /* CONFIG_NO_WPA2 */ + return -1; +#endif /* CONFIG_NO_WPA2 */ +} + +int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len, + struct wpa_ie_data *data) +{ + const struct wpa_ie_hdr *hdr; + const u8 *pos; + int left; + int i, count; + + memset(data, 0, sizeof(*data)); + data->proto = WPA_PROTO_WPA; + data->pairwise_cipher = WPA_CIPHER_TKIP; + data->group_cipher = WPA_CIPHER_TKIP; + data->key_mgmt = WPA_KEY_MGMT_IEEE8021X; + data->capabilities = 0; + data->pmkid = NULL; + data->num_pmkid = 0; + data->mgmt_group_cipher = 0; + + if (wpa_ie_len == 0) { + /* No WPA IE - fail silently */ + return -1; + } + + if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) { + wpa_printf(MSG_DEBUG, "%s: ie len too short %lu", + __func__, (unsigned long) wpa_ie_len); + return -1; + } + + hdr = (const struct wpa_ie_hdr *) wpa_ie; + + if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC || + hdr->len != wpa_ie_len - 2 || + RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE || + WPA_GET_LE16(hdr->version) != WPA_VERSION) { + wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version", + __func__); + return -2; + } + + pos = (const u8 *) (hdr + 1); + left = wpa_ie_len - sizeof(*hdr); + + if (left >= WPA_SELECTOR_LEN) { + data->group_cipher = wpa_selector_to_bitfield(pos); + pos += WPA_SELECTOR_LEN; + left -= WPA_SELECTOR_LEN; + } else if (left > 0) { + wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much", + __func__, left); + return -3; + } + + if (left >= 2) { + data->pairwise_cipher = 0; + count = WPA_GET_LE16(pos); + pos += 2; + left -= 2; + if (count == 0 || left < count * WPA_SELECTOR_LEN) { + wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), " + "count %u left %u", __func__, count, left); + return -4; + } + for (i = 0; i < count; i++) { + data->pairwise_cipher |= wpa_selector_to_bitfield(pos); + pos += WPA_SELECTOR_LEN; + left -= WPA_SELECTOR_LEN; + } + } else if (left == 1) { + wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)", + __func__); + return -5; + } + + if (left >= 2) { + data->key_mgmt = 0; + count = WPA_GET_LE16(pos); + pos += 2; + left -= 2; + if (count == 0 || left < count * WPA_SELECTOR_LEN) { + wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), " + "count %u left %u", __func__, count, left); + return -6; + } + for (i = 0; i < count; i++) { + data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos); + pos += WPA_SELECTOR_LEN; + left -= WPA_SELECTOR_LEN; + } + } else if (left == 1) { + wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)", + __func__); + return -7; + } + + if (left >= 2) { + data->capabilities = WPA_GET_LE16(pos); + pos += 2; + left -= 2; + } + + if (left > 0) { + wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored", + __func__, left); + } + + return 0; +} + + +/** + * wpa_eapol_key_mic - Calculate EAPOL-Key MIC + * @key: EAPOL-Key Key Confirmation Key (KCK) + * @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*) + * @buf: Pointer to the beginning of the EAPOL header (version field) + * @len: Length of the EAPOL frame (from EAPOL header to the end of the frame) + * @mic: Pointer to the buffer to which the EAPOL-Key MIC is written + * Returns: 0 on success, -1 on failure + * + * Calculate EAPOL-Key MIC for an EAPOL-Key packet. The EAPOL-Key MIC field has + * to be cleared (all zeroes) when calling this function. + * + * Note: 'IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames' has an error in the + * description of the Key MIC calculation. It includes packet data from the + * beginning of the EAPOL-Key header, not EAPOL header. This incorrect change + * happened during final editing of the standard and the correct behavior is + * defined in the last draft (IEEE 802.11i/D10). + */ +int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len, + u8 *mic) +{ + u8 hash[SHA1_MAC_LEN]; + + switch (ver) { + case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4: + return hmac_md5(key, 16, buf, len, mic); + case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES: + if (hmac_sha1(key, 16, buf, len, hash)) + return -1; + memcpy(mic, hash, MD5_MAC_LEN); + break; + default: + return -1; + } + + return 0; +} + +int wpa_compare_rsn_ie(int ft_initial_assoc, + const u8 *ie1, size_t ie1len, + const u8 *ie2, size_t ie2len) +{ + if (ie1 == NULL || ie2 == NULL) + return -1; + + if (ie1len == ie2len && memcmp(ie1, ie2, ie1len) == 0) + return 0; /* identical IEs */ + +#ifdef CONFIG_IEEE80211R + if (ft_initial_assoc) { + struct wpa_ie_data ie1d, ie2d; + /* + * The PMKID-List in RSN IE is different between Beacon/Probe + * Response/(Re)Association Request frames and EAPOL-Key + * messages in FT initial mobility domain association. Allow + * for this, but verify that other parts of the RSN IEs are + * identical. + */ + if (wpa_parse_wpa_ie_rsn(ie1, ie1len, &ie1d) < 0 || + wpa_parse_wpa_ie_rsn(ie2, ie2len, &ie2d) < 0) + return -1; + if (ie1d.proto == ie2d.proto && + ie1d.pairwise_cipher == ie2d.pairwise_cipher && + ie1d.group_cipher == ie2d.group_cipher && + ie1d.key_mgmt == ie2d.key_mgmt && + ie1d.capabilities == ie2d.capabilities && + ie1d.mgmt_group_cipher == ie2d.mgmt_group_cipher) + return 0; + } +#endif /* CONFIG_IEEE80211R */ + + return -1; +} + +#ifdef DEBUG_PRINT +/** + * wpa_cipher_txt - Convert cipher suite to a text string + * @cipher: Cipher suite (WPA_CIPHER_* enum) + * Returns: Pointer to a text string of the cipher suite name + */ +const char * wpa_cipher_txt(int cipher) +{ + switch (cipher) { + case WPA_CIPHER_NONE: + return "NONE"; + case WPA_CIPHER_WEP40: + return "WEP-40"; + case WPA_CIPHER_WEP104: + return "WEP-104"; + case WPA_CIPHER_TKIP: + return "TKIP"; + case WPA_CIPHER_CCMP: + return "CCMP"; + case WPA_CIPHER_CCMP | WPA_CIPHER_TKIP: + return "CCMP+TKIP"; + default: + return "UNKNOWN"; + } +} +#endif + +/** + * wpa_pmk_to_ptk - Calculate PTK from PMK, addresses, and nonces + * @pmk: Pairwise master key + * @pmk_len: Length of PMK + * @label: Label to use in derivation + * @addr1: AA or SA + * @addr2: SA or AA + * @nonce1: ANonce or SNonce + * @nonce2: SNonce or ANonce + * @ptk: Buffer for pairwise transient key + * @ptk_len: Length of PTK + * @use_sha256: Whether to use SHA256-based KDF + * + * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy + * PTK = PRF-X(PMK, "Pairwise key expansion", + * Min(AA, SA) || Max(AA, SA) || + * Min(ANonce, SNonce) || Max(ANonce, SNonce)) + * + * STK = PRF-X(SMK, "Peer key expansion", + * Min(MAC_I, MAC_P) || Max(MAC_I, MAC_P) || + * Min(INonce, PNonce) || Max(INonce, PNonce)) + */ +void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label, + const u8 *addr1, const u8 *addr2, + const u8 *nonce1, const u8 *nonce2, + u8 *ptk, size_t ptk_len, int use_sha256) +{ + u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN]; + + if (memcmp(addr1, addr2, ETH_ALEN) < 0) { + memcpy(data, addr1, ETH_ALEN); + memcpy(data + ETH_ALEN, addr2, ETH_ALEN); + } else { + memcpy(data, addr2, ETH_ALEN); + memcpy(data + ETH_ALEN, addr1, ETH_ALEN); + } + + if (memcmp(nonce1, nonce2, WPA_NONCE_LEN) < 0) { + memcpy(data + 2 * ETH_ALEN, nonce1, WPA_NONCE_LEN); + memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce2, + WPA_NONCE_LEN); + } else { + memcpy(data + 2 * ETH_ALEN, nonce2, WPA_NONCE_LEN); + memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce1, + WPA_NONCE_LEN); + } + +#ifdef CONFIG_IEEE80211W + if (use_sha256) { + sha256_prf(pmk, pmk_len, label, data, sizeof(data), + ptk, ptk_len); + } + else +#endif /* CONFIG_IEEE80211W */ + { + sha1_prf(pmk, pmk_len, label, data, sizeof(data), ptk, ptk_len); + } + wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR"\n", + MAC2STR(addr1), MAC2STR(addr2)); + + wpa_hexdump(MSG_MSGDUMP, "WPA: PMK", pmk, pmk_len); + wpa_hexdump(MSG_MSGDUMP, "WPA: PTK", ptk, ptk_len); +} + +/** + * rsn_pmkid - Calculate PMK identifier + * @pmk: Pairwise master key + * @pmk_len: Length of pmk in bytes + * @aa: Authenticator address + * @spa: Supplicant address + * @pmkid: Buffer for PMKID + * @use_sha256: Whether to use SHA256-based KDF + * + * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy + * PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA) + */ +void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa, + u8 *pmkid, int use_sha256) +{ + char title[9]; + const u8 *addr[3]; + const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN }; + unsigned char hash[SHA256_MAC_LEN]; + + os_memcpy(title, "PMK Name", sizeof("PMK Name")); + addr[0] = (u8 *) title; + addr[1] = aa; + addr[2] = spa; + +#ifdef CONFIG_IEEE80211W + if (use_sha256) { + hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash); + } + else +#endif /* CONFIG_IEEE80211W */ + hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash); + memcpy(pmkid, hash, PMKID_LEN); +} + +int wpa_cipher_key_len(int cipher) +{ + switch (cipher) { + case WPA_CIPHER_CCMP: + case WPA_CIPHER_GCMP: + return 16; + case WPA_CIPHER_TKIP: + return 32; + case WPA_CIPHER_WEP104: + return 13; + case WPA_CIPHER_WEP40: + return 5; + } + + return 0; +} + +int wpa_cipher_to_alg(int cipher) +{ + switch (cipher) { + case WPA_CIPHER_CCMP: + return WPA_ALG_CCMP; + case WPA_CIPHER_GCMP: + return WPA_ALG_GCMP; + case WPA_CIPHER_TKIP: + return WPA_ALG_TKIP; + case WPA_CIPHER_WEP104: + case WPA_CIPHER_WEP40: + return WPA_ALG_WEP; + } + return WPA_ALG_NONE; +} + +u32 wpa_cipher_to_suite(int proto, int cipher) +{ + if (cipher & WPA_CIPHER_CCMP) + return (proto == WPA_PROTO_RSN ? + RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP); + if (cipher & WPA_CIPHER_GCMP) + return RSN_CIPHER_SUITE_GCMP; + if (cipher & WPA_CIPHER_TKIP) + return (proto == WPA_PROTO_RSN ? + RSN_CIPHER_SUITE_TKIP : WPA_CIPHER_SUITE_TKIP); + if (cipher & WPA_CIPHER_WEP104) + return (proto == WPA_PROTO_RSN ? + RSN_CIPHER_SUITE_WEP104 : WPA_CIPHER_SUITE_WEP104); + if (cipher & WPA_CIPHER_WEP40) + return (proto == WPA_PROTO_RSN ? + RSN_CIPHER_SUITE_WEP40 : WPA_CIPHER_SUITE_WEP40); + if (cipher & WPA_CIPHER_NONE) + return (proto == WPA_PROTO_RSN ? + RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE); + return 0; +} + +int rsn_cipher_put_suites(u8 *pos, int ciphers) +{ + int num_suites = 0; + + if (ciphers & WPA_CIPHER_CCMP) { + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); + pos += RSN_SELECTOR_LEN; + num_suites++; + } + if (ciphers & WPA_CIPHER_GCMP) { + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP); + pos += RSN_SELECTOR_LEN; + num_suites++; + } + if (ciphers & WPA_CIPHER_TKIP) { + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); + pos += RSN_SELECTOR_LEN; + num_suites++; + } + if (ciphers & WPA_CIPHER_NONE) { + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE); + pos += RSN_SELECTOR_LEN; + num_suites++; + } + + return num_suites; +} + +int wpa_cipher_put_suites(u8 *pos, int ciphers) +{ + int num_suites = 0; + + if (ciphers & WPA_CIPHER_CCMP) { + RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP); + pos += WPA_SELECTOR_LEN; + num_suites++; + } + if (ciphers & WPA_CIPHER_TKIP) { + RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP); + pos += WPA_SELECTOR_LEN; + num_suites++; + } + if (ciphers & WPA_CIPHER_NONE) { + RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE); + pos += WPA_SELECTOR_LEN; + num_suites++; + } + + return num_suites; +} + +#endif // ESP_SUPPLICANT + + diff --git a/components/wpa_supplicant/include/wpa/wpa_common.h b/components/wpa_supplicant/src/common/wpa_common.h similarity index 96% rename from components/wpa_supplicant/include/wpa/wpa_common.h rename to components/wpa_supplicant/src/common/wpa_common.h index 480cf0e27e..07d549aac2 100644 --- a/components/wpa_supplicant/include/wpa/wpa_common.h +++ b/components/wpa_supplicant/src/common/wpa_common.h @@ -42,9 +42,6 @@ #define WPA_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0) #define WPA_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x50, 0xf2, 1) #define WPA_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x50, 0xf2, 2) -#if 0 -#define WPA_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x50, 0xf2, 3) -#endif #define WPA_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x50, 0xf2, 4) #define WPA_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x50, 0xf2, 5) @@ -61,9 +58,6 @@ #define RSN_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x0f, 0xac, 0) #define RSN_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x0f, 0xac, 1) #define RSN_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x0f, 0xac, 2) -#if 0 -#define RSN_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x0f, 0xac, 3) -#endif #define RSN_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 4) #define RSN_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x0f, 0xac, 5) #ifdef CONFIG_IEEE80211W @@ -76,9 +70,6 @@ * GroupKey and PeerKey require encryption, otherwise, encryption is optional. */ #define RSN_KEY_DATA_GROUPKEY RSN_SELECTOR(0x00, 0x0f, 0xac, 1) -#if 0 -#define RSN_KEY_DATA_STAKEY RSN_SELECTOR(0x00, 0x0f, 0xac, 2) -#endif #define RSN_KEY_DATA_MAC_ADDR RSN_SELECTOR(0x00, 0x0f, 0xac, 3) #define RSN_KEY_DATA_PMKID RSN_SELECTOR(0x00, 0x0f, 0xac, 4) #ifdef CONFIG_PEERKEY @@ -329,4 +320,17 @@ void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label, void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa, u8 *pmkid, int use_sha256); +int wpa_cipher_key_len(int cipher); + +int wpa_cipher_to_alg(int cipher); + +u32 wpa_cipher_to_suite(int proto, int cipher); + +int wpa_cipher_put_suites(u8 *pos, int ciphers); + +int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len, + struct wpa_ie_data *data); + +int rsn_cipher_put_suites(u8 *pos, int ciphers); + #endif /* WPA_COMMON_H */ diff --git a/components/wpa_supplicant/src/common/wpa_ctrl.h b/components/wpa_supplicant/src/common/wpa_ctrl.h new file mode 100644 index 0000000000..d0055916fe --- /dev/null +++ b/components/wpa_supplicant/src/common/wpa_ctrl.h @@ -0,0 +1,196 @@ +/* + * wpa_supplicant/hostapd control interface library + * Copyright (c) 2004-2006, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef WPA_CTRL_H +#define WPA_CTRL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* wpa_supplicant control interface - fixed message prefixes */ + +/** Interactive request for identity/password/pin */ +#define WPA_CTRL_REQ "CTRL-REQ-" + +/** Response to identity/password/pin request */ +#define WPA_CTRL_RSP "CTRL-RSP-" + +/* Event messages with fixed prefix */ +/** Authentication completed successfully and data connection enabled */ +#define WPA_EVENT_CONNECTED "CTRL-EVENT-CONNECTED " +/** Disconnected, data connection is not available */ +#define WPA_EVENT_DISCONNECTED "CTRL-EVENT-DISCONNECTED " +/** Association rejected during connection attempt */ +#define WPA_EVENT_ASSOC_REJECT "CTRL-EVENT-ASSOC-REJECT " +/** wpa_supplicant is exiting */ +#define WPA_EVENT_TERMINATING "CTRL-EVENT-TERMINATING " +/** Password change was completed successfully */ +#define WPA_EVENT_PASSWORD_CHANGED "CTRL-EVENT-PASSWORD-CHANGED " +/** EAP-Request/Notification received */ +#define WPA_EVENT_EAP_NOTIFICATION "CTRL-EVENT-EAP-NOTIFICATION " +/** EAP authentication started (EAP-Request/Identity received) */ +#define WPA_EVENT_EAP_STARTED "CTRL-EVENT-EAP-STARTED " +/** EAP method proposed by the server */ +#define WPA_EVENT_EAP_PROPOSED_METHOD "CTRL-EVENT-EAP-PROPOSED-METHOD " +/** EAP method selected */ +#define WPA_EVENT_EAP_METHOD "CTRL-EVENT-EAP-METHOD " +/** EAP peer certificate from TLS */ +#define WPA_EVENT_EAP_PEER_CERT "CTRL-EVENT-EAP-PEER-CERT " +/** EAP TLS certificate chain validation error */ +#define WPA_EVENT_EAP_TLS_CERT_ERROR "CTRL-EVENT-EAP-TLS-CERT-ERROR " +/** EAP status */ +#define WPA_EVENT_EAP_STATUS "CTRL-EVENT-EAP-STATUS " +/** EAP authentication completed successfully */ +#define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS " +/** EAP authentication failed (EAP-Failure received) */ +#define WPA_EVENT_EAP_FAILURE "CTRL-EVENT-EAP-FAILURE " +/** Network block temporarily disabled (e.g., due to authentication failure) */ +#define WPA_EVENT_TEMP_DISABLED "CTRL-EVENT-SSID-TEMP-DISABLED " +/** Temporarily disabled network block re-enabled */ +#define WPA_EVENT_REENABLED "CTRL-EVENT-SSID-REENABLED " +/** New scan results available */ +#define WPA_EVENT_SCAN_RESULTS "CTRL-EVENT-SCAN-RESULTS " +/** wpa_supplicant state change */ +#define WPA_EVENT_STATE_CHANGE "CTRL-EVENT-STATE-CHANGE " +/** A new BSS entry was added (followed by BSS entry id and BSSID) */ +#define WPA_EVENT_BSS_ADDED "CTRL-EVENT-BSS-ADDED " +/** A BSS entry was removed (followed by BSS entry id and BSSID) */ +#define WPA_EVENT_BSS_REMOVED "CTRL-EVENT-BSS-REMOVED " +#ifdef ANDROID_P2P +/** Notify the Userspace about the freq conflict */ +#define WPA_EVENT_FREQ_CONFLICT "CTRL-EVENT-FREQ-CONFLICT " +#endif + +/** RSN IBSS 4-way handshakes completed with specified peer */ +#define IBSS_RSN_COMPLETED "IBSS-RSN-COMPLETED " + +/** WPS overlap detected in PBC mode */ +#define WPS_EVENT_OVERLAP "WPS-OVERLAP-DETECTED " +/** Available WPS AP with active PBC found in scan results */ +#define WPS_EVENT_AP_AVAILABLE_PBC "WPS-AP-AVAILABLE-PBC " +/** Available WPS AP with our address as authorized in scan results */ +#define WPS_EVENT_AP_AVAILABLE_AUTH "WPS-AP-AVAILABLE-AUTH " +/** Available WPS AP with recently selected PIN registrar found in scan results + */ +#define WPS_EVENT_AP_AVAILABLE_PIN "WPS-AP-AVAILABLE-PIN " +/** Available WPS AP found in scan results */ +#define WPS_EVENT_AP_AVAILABLE "WPS-AP-AVAILABLE " +/** A new credential received */ +#define WPS_EVENT_CRED_RECEIVED "WPS-CRED-RECEIVED " +/** M2D received */ +#define WPS_EVENT_M2D "WPS-M2D " +/** WPS registration failed after M2/M2D */ +#define WPS_EVENT_FAIL "WPS-FAIL " +/** WPS registration completed successfully */ +#define WPS_EVENT_SUCCESS "WPS-SUCCESS " +/** WPS enrollment attempt timed out and was terminated */ +#define WPS_EVENT_TIMEOUT "WPS-TIMEOUT " +/* PBC mode was activated */ +#define WPS_EVENT_ACTIVE "WPS-PBC-ACTIVE " +/* PBC mode was disabled */ +#define WPS_EVENT_DISABLE "WPS-PBC-DISABLE " + +#define WPS_EVENT_ENROLLEE_SEEN "WPS-ENROLLEE-SEEN " + +#define WPS_EVENT_OPEN_NETWORK "WPS-OPEN-NETWORK " + +/* WPS ER events */ +#define WPS_EVENT_ER_AP_ADD "WPS-ER-AP-ADD " +#define WPS_EVENT_ER_AP_REMOVE "WPS-ER-AP-REMOVE " +#define WPS_EVENT_ER_ENROLLEE_ADD "WPS-ER-ENROLLEE-ADD " +#define WPS_EVENT_ER_ENROLLEE_REMOVE "WPS-ER-ENROLLEE-REMOVE " +#define WPS_EVENT_ER_AP_SETTINGS "WPS-ER-AP-SETTINGS " +#define WPS_EVENT_ER_SET_SEL_REG "WPS-ER-AP-SET-SEL-REG " + +/** P2P device found */ +#define P2P_EVENT_DEVICE_FOUND "P2P-DEVICE-FOUND " + +/** P2P device lost */ +#define P2P_EVENT_DEVICE_LOST "P2P-DEVICE-LOST " + +/** A P2P device requested GO negotiation, but we were not ready to start the + * negotiation */ +#define P2P_EVENT_GO_NEG_REQUEST "P2P-GO-NEG-REQUEST " +#define P2P_EVENT_GO_NEG_SUCCESS "P2P-GO-NEG-SUCCESS " +#define P2P_EVENT_GO_NEG_FAILURE "P2P-GO-NEG-FAILURE " +#define P2P_EVENT_GROUP_FORMATION_SUCCESS "P2P-GROUP-FORMATION-SUCCESS " +#define P2P_EVENT_GROUP_FORMATION_FAILURE "P2P-GROUP-FORMATION-FAILURE " +#define P2P_EVENT_GROUP_STARTED "P2P-GROUP-STARTED " +#define P2P_EVENT_GROUP_REMOVED "P2P-GROUP-REMOVED " +#define P2P_EVENT_CROSS_CONNECT_ENABLE "P2P-CROSS-CONNECT-ENABLE " +#define P2P_EVENT_CROSS_CONNECT_DISABLE "P2P-CROSS-CONNECT-DISABLE " +/* parameters: */ +#define P2P_EVENT_PROV_DISC_SHOW_PIN "P2P-PROV-DISC-SHOW-PIN " +/* parameters: */ +#define P2P_EVENT_PROV_DISC_ENTER_PIN "P2P-PROV-DISC-ENTER-PIN " +/* parameters: */ +#define P2P_EVENT_PROV_DISC_PBC_REQ "P2P-PROV-DISC-PBC-REQ " +/* parameters: */ +#define P2P_EVENT_PROV_DISC_PBC_RESP "P2P-PROV-DISC-PBC-RESP " +/* parameters: */ +#define P2P_EVENT_PROV_DISC_FAILURE "P2P-PROV-DISC-FAILURE" +/* parameters: */ +#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..03d7a68ba6 100644 --- a/components/wpa_supplicant/src/crypto/aes-cbc.c +++ b/components/wpa_supplicant/src/crypto/aes-cbc.c @@ -12,12 +12,30 @@ * * 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 "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" -#include "crypto/aes.h" -#include "crypto/aes_wrap.h" +#include "utils/common.h" +#include "aes.h" +#include "aes_wrap.h" + +#ifdef USE_MBEDTLS_CRYPTO +#include "mbedtls/aes.h" /** * aes_128_cbc_encrypt - AES-128 CBC encryption @@ -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-internal-dec.c b/components/wpa_supplicant/src/crypto/aes-internal-dec.c index 46371c5557..8c91b5c00e 100644 --- a/components/wpa_supplicant/src/crypto/aes-internal-dec.c +++ b/components/wpa_supplicant/src/crypto/aes-internal-dec.c @@ -21,11 +21,11 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" -#include "crypto/crypto.h" -#include "crypto/aes_i.h" +#include "utils/common.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 7b1080c450..56084e4489 100644 --- a/components/wpa_supplicant/src/crypto/aes-internal-enc.c +++ b/components/wpa_supplicant/src/crypto/aes-internal-enc.c @@ -21,10 +21,10 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" -#include "crypto/common.h" -#include "crypto/crypto.h" -#include "crypto/aes_i.h" +#include "utils/includes.h" +#include "utils/common.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 9618239f93..93592f1dc8 100644 --- a/components/wpa_supplicant/src/crypto/aes-internal.c +++ b/components/wpa_supplicant/src/crypto/aes-internal.c @@ -21,12 +21,11 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -//#include "wpa/common.h" -#include "crypto/common.h" -#include "crypto/crypto.h" -#include "crypto/aes_i.h" +#include "utils/common.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 4a92f1cd31..090c2a9095 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 "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" -#include "crypto/aes.h" -#include "crypto/aes_wrap.h" +#include "utils/common.h" +#ifdef USE_MBEDTLS_CRYPTO +#include "mbedtls/aes.h" +#else /* USE_MBEDTLS_CRYPTO */ +#include "aes.h" +#include "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 388dd97a82..42e60660b6 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 "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" -#include "crypto/aes.h" -#include "crypto/aes_wrap.h" +#include "utils/common.h" +#include "aes.h" +#include "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/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/include/crypto/aes_i.h b/components/wpa_supplicant/src/crypto/aes_i.h similarity index 100% rename from components/wpa_supplicant/include/crypto/aes_i.h rename to components/wpa_supplicant/src/crypto/aes_i.h diff --git a/components/wpa_supplicant/include/crypto/aes_wrap.h b/components/wpa_supplicant/src/crypto/aes_wrap.h similarity index 80% rename from components/wpa_supplicant/include/crypto/aes_wrap.h rename to components/wpa_supplicant/src/crypto/aes_wrap.h index 933031e4ba..e6912054f0 100644 --- a/components/wpa_supplicant/include/crypto/aes_wrap.h +++ b/components/wpa_supplicant/src/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/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/include/crypto/crypto.h b/components/wpa_supplicant/src/crypto/crypto.h similarity index 83% rename from components/wpa_supplicant/include/crypto/crypto.h rename to components/wpa_supplicant/src/crypto/crypto.h index f6b7b2f2c4..9c57c50db1 100644 --- a/components/wpa_supplicant/include/crypto/crypto.h +++ b/components/wpa_supplicant/src/crypto/crypto.h @@ -27,7 +27,7 @@ #ifndef CRYPTO_H #define CRYPTO_H -#include "common.h" +#include "utils/common.h" /** * md4_vector - MD4 hash for data vector @@ -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/src/crypto/crypto_internal-cipher.c b/components/wpa_supplicant/src/crypto/crypto_internal-cipher.c index 7d89795797..9ca428cfe3 100644 --- a/components/wpa_supplicant/src/crypto/crypto_internal-cipher.c +++ b/components/wpa_supplicant/src/crypto/crypto_internal-cipher.c @@ -5,21 +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 "wpa/includes.h" - -//#include "wpa/common.h" -#include "crypto/common.h" -#include "crypto/crypto.h" -#include "crypto/aes.h" +#include "utils/common.h" +#include "utils/includes.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 MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; -#endif - +#ifdef USE_MBEDTLS_CRYPTO +#include "mbedtls/aes.h" +#endif /* USE_MBEDTLS_CRYPTO */ struct crypto_cipher { enum crypto_cipher_alg alg; @@ -31,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 { @@ -73,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); @@ -84,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 @@ -135,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; @@ -202,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); @@ -254,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 ea97857005..8d9d7fe83d 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 "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" +#include "utils/common.h" +#ifdef USE_MBEDTLS_CRYPTO +#include "mbedtls/bignum.h" +#else /* USE_MBEDTLS_CRYPTO */ #include "bignum.h" -#include "crypto/crypto.h" +#endif /* USE_MBEDTLS_CRYPTO */ +#include "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-rsa.c b/components/wpa_supplicant/src/crypto/crypto_internal-rsa.c index 19934f063b..1d63137fa5 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 "crypto/crypto.h" +#include "utils/common.h" +#include "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..ca82d0d52b 100644 --- a/components/wpa_supplicant/src/crypto/crypto_internal.c +++ b/components/wpa_supplicant/src/crypto/crypto_internal.c @@ -5,27 +5,42 @@ * 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 "crypto/includes.h" -#include "crypto/common.h" -//#include "wpa/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__; +#include "utils/includes.h" +#include "utils/common.h" +#include "crypto.h" +#include "sha1_i.h" +#include "md5_i.h" +#ifdef USE_MBEDTLS_CRYPTO +#include "mbedtls/sha256.h" #endif - struct crypto_hash { enum crypto_hash_alg alg; union { 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]; @@ -56,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: @@ -100,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; } @@ -114,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: @@ -144,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: @@ -193,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: @@ -245,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/crypto_mbedtls.c b/components/wpa_supplicant/src/crypto/crypto_mbedtls.c index 7bbee6d253..d6a91b5329 100644 --- a/components/wpa_supplicant/src/crypto/crypto_mbedtls.c +++ b/components/wpa_supplicant/src/crypto/crypto_mbedtls.c @@ -17,9 +17,9 @@ #include "mbedtls/bignum.h" #endif -#include "crypto/includes.h" -#include "crypto/common.h" -#include "crypto/crypto.h" +#include "utils/includes.h" +#include "utils/common.h" +#include "crypto.h" #include "mbedtls/ecp.h" #include "mbedtls/entropy.h" diff --git a/components/wpa_supplicant/src/crypto/crypto_ops.c b/components/wpa_supplicant/src/crypto/crypto_ops.c new file mode 100644 index 0000000000..f46d823dfe --- /dev/null +++ b/components/wpa_supplicant/src/crypto/crypto_ops.c @@ -0,0 +1,57 @@ +// 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 "utils/common.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 + * 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)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, + .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 mesh_crypto_funcs_t g_wifi_default_mesh_crypto_funcs = { + .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/src/crypto/des-internal.c b/components/wpa_supplicant/src/crypto/des-internal.c index a29c21a1bb..077b7d013c 100644 --- a/components/wpa_supplicant/src/crypto/des-internal.c +++ b/components/wpa_supplicant/src/crypto/des-internal.c @@ -9,10 +9,10 @@ */ -#include "wpa/includes.h" +#include "utils/includes.h" -#include "wpa/common.h" -#include "crypto/crypto.h" +#include "utils/common.h" +#include "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..d5adaf24fd 100644 --- a/components/wpa_supplicant/src/crypto/dh_group5.c +++ b/components/wpa_supplicant/src/crypto/dh_group5.c @@ -12,11 +12,11 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" -#include "crypto/dh_groups.h" -#include "crypto/dh_group5.h" +#include "utils/common.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 96% rename from components/wpa_supplicant/include/crypto/dh_group5.h rename to components/wpa_supplicant/src/crypto/dh_group5.h index f92c1115d5..822d47a6e3 100644 --- a/components/wpa_supplicant/include/crypto/dh_group5.h +++ b/components/wpa_supplicant/src/crypto/dh_group5.h @@ -15,7 +15,7 @@ #ifndef DH_GROUP5_H #define DH_GROUP5_H -#include "wpa/wpabuf.h" +#include "utils/wpabuf.h" void * dh5_init(struct wpabuf **priv, struct wpabuf **publ); struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public, diff --git a/components/wpa_supplicant/src/crypto/dh_groups.c b/components/wpa_supplicant/src/crypto/dh_groups.c index c08f8f29df..6f699d9be6 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 "crypto/crypto.h" -#include "crypto/random.h" -#include "crypto/dh_groups.h" -#include "wpa/wpabuf.h" -#include "wpa/wpa_debug.h" +#include "utils/common.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" -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 (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 (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/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 a3ad58129a..9c99b7cbe1 100644 --- a/components/wpa_supplicant/src/crypto/md4-internal.c +++ b/components/wpa_supplicant/src/crypto/md4-internal.c @@ -4,9 +4,9 @@ * This software may be distributed under the terms of BSD license. */ -#include "crypto/includes.h" -#include "crypto/common.h" -#include "crypto/crypto.h" +#include "utils/includes.h" +#include "utils/common.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 a430e297a5..a6b394006b 100644 --- a/components/wpa_supplicant/src/crypto/md5-internal.c +++ b/components/wpa_supplicant/src/crypto/md5-internal.c @@ -12,12 +12,12 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" -#include "crypto/md5.h" -#include "crypto/md5_i.h" -#include "crypto/crypto.h" +#include "utils/common.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 3125c98311..57ec4ea983 100644 --- a/components/wpa_supplicant/src/crypto/md5.c +++ b/components/wpa_supplicant/src/crypto/md5.c @@ -12,11 +12,11 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" -#include "crypto/md5.h" -#include "crypto/crypto.h" +#include "utils/common.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/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..750a4083bd 100644 --- a/components/wpa_supplicant/src/crypto/ms_funcs.c +++ b/components/wpa_supplicant/src/crypto/ms_funcs.c @@ -7,12 +7,12 @@ */ -#include "wpa/includes.h" +#include "utils/includes.h" -#include "wpa/common.h" -#include "crypto/sha1.h" -#include "crypto/ms_funcs.h" -#include "crypto/crypto.h" +#include "utils/common.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 678632297f..a014afe6e3 100644 --- a/components/wpa_supplicant/src/crypto/rc4.c +++ b/components/wpa_supplicant/src/crypto/rc4.c @@ -12,10 +12,10 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" -#include "crypto/crypto.h" +#include "utils/common.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 a1c255e416..9210af03fe 100644 --- a/components/wpa_supplicant/src/crypto/sha1-internal.c +++ b/components/wpa_supplicant/src/crypto/sha1-internal.c @@ -12,19 +12,25 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" -#include "crypto/sha1.h" -#include "crypto/sha1_i.h" -#include "crypto/md5.h" -#include "crypto/crypto.h" +#include "utils/common.h" +#include "sha1.h" +#include "sha1_i.h" +#include "md5.h" +#include "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 915a23aa78..79e1bc382c 100644 --- a/components/wpa_supplicant/src/crypto/sha1-pbkdf2.c +++ b/components/wpa_supplicant/src/crypto/sha1-pbkdf2.c @@ -12,16 +12,69 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" -#include "crypto/common.h" -#include "crypto/sha1.h" -#include "crypto/md5.h" -#include "crypto/crypto.h" +#include "utils/includes.h" +#include "utils/common.h" +#include "sha1.h" +#include "md5.h" +#include "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 diff --git a/components/wpa_supplicant/src/crypto/sha1.c b/components/wpa_supplicant/src/crypto/sha1.c index 3d6da417ac..27cf58b685 100644 --- a/components/wpa_supplicant/src/crypto/sha1.c +++ b/components/wpa_supplicant/src/crypto/sha1.c @@ -12,11 +12,11 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" -#include "crypto/sha1.h" -#include "crypto/crypto.h" +#include "utils/common.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/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..d6af5b5e9a 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 "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" -#include "crypto/sha256.h" -#include "crypto/crypto.h" +#include "utils/common.h" +#ifdef USE_MBEDTLS_CRYPTO +#include "mbedtls/sha256.h" +#else /* USE_MBEDTLS_CRYPTO */ +#include "sha256.h" +#include "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 f62cc11827..3e955b4d47 100644 --- a/components/wpa_supplicant/src/crypto/sha256.c +++ b/components/wpa_supplicant/src/crypto/sha256.c @@ -11,12 +11,27 @@ * * 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 "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" -#include "crypto/sha256.h" -#include "crypto/crypto.h" +#include "utils/common.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 67% rename from components/wpa_supplicant/include/crypto/sha256.h rename to components/wpa_supplicant/src/crypto/sha256.h index 8025a29de3..dc597f09b5 100644 --- a/components/wpa_supplicant/include/crypto/sha256.h +++ b/components/wpa_supplicant/src/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/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 93% rename from components/wpa_supplicant/include/wpa2/eap_peer/eap_i.h rename to components/wpa_supplicant/src/eap_peer/eap_i.h index 6204f46538..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" @@ -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; @@ -128,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..7e032685ee 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) @@ -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/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..b014dbd395 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,19 @@ * See README for more details. */ +#include "utils/includes.h" + #ifdef EAP_TTLS - -#include "wpa/includes.h" - -#include "wpa/common.h" -#include "crypto/ms_funcs.h" +#include "utils/common.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 +69,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 +78,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 +181,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 +212,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 +311,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 +353,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 +361,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 +597,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 +699,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 +791,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..62d2d6246e --- /dev/null +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h @@ -0,0 +1,222 @@ +// 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" + +#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); +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; + 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 ) +{ + 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; + 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: + wpa2_start_eapol_internal(); + break; + case SIG_WPA2_RX: { + struct wpa2_rx_param *param = NULL; + + 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); + } + 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; + } + + 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) { + 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); + + wpa2_rxq_enqueue(param); + return wpa2_post(SIG_WPA2_RX, 0); + } +#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; + } + + 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); + 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; + } + + wpa2_rxq_init(); + + 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 (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; +} + +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 + 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 + + 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..51f9e40f46 --- /dev/null +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c @@ -0,0 +1,238 @@ +// 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 "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(void) +{ + 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(void) +{ + 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..cbcd351973 --- /dev/null +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wps.c @@ -0,0 +1,2185 @@ +// 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; + STAILQ_ENTRY(wps_rx_param) bqentry; +}; +static STAILQ_HEAD(,wps_rx_param) s_wps_rxq; + +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); +} + +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 ) +{ + 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 = 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); + } + 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) +{ + if (buffer != NULL) { + 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); + wps_sm_free_eapol(buf); + 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); + wps_sm_free_eapol(buf); + 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); + + wps_rxq_enqueue(param); + return wps_post(SIG_WPS_RX, 0); + } +#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 +} + +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; + } + esp_wifi_set_wps_start_flag_internal(true); + return ESP_OK; +} + +int wps_task_deinit(void) +{ + wpa_printf(MSG_DEBUG, "wps task deinit"); + + 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"); + } + + 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; +} + +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; + } + + 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"); + 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(); + esp_wifi_set_wps_start_flag_internal(false); + 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 deleted file mode 100644 index 5c362fa225..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 "crypto/includes.h" -#include "crypto/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 fd4a49ff43..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 "crypto/includes.h" -#include "crypto/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 3b9eec1c16..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 "crypto/includes.h" - -#include "crypto/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 826d365e8c..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 "wpa/includes.h" - -//#include "wpa/common.h" -#include "crypto/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 66d4aa2de6..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 "crypto/includes.h" - -#include "crypto/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 a0f7da83ae..0000000000 --- a/components/wpa_supplicant/src/fast_crypto/fast_crypto_internal.c +++ /dev/null @@ -1,282 +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 "crypto/includes.h" -#include "crypto/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 { - 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 7650cb87ed..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 "crypto/includes.h" -#include "crypto/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 b0fb03e4f8..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 "crypto/includes.h" - -#include "crypto/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 new file mode 100644 index 0000000000..2f01471264 --- /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" + +/** + * 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 (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 (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_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_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_ap_info_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 59% rename from components/wpa_supplicant/include/wpa/wpa_i.h rename to components/wpa_supplicant/src/rsn_supp/wpa.h index a43c33d332..b7c9a3588c 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,37 @@ * See README and COPYING for more details. */ -#ifndef WPA_I_H -#define WPA_I_H +#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" +#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 +89,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 71% rename from components/wpa_supplicant/include/wpa/wpa.h rename to components/wpa_supplicant/src/rsn_supp/wpa_i.h index f2ab9898d4..69fc1a5e3d 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)(); + void (*wpa_neg_complete)(void); 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); + +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 96% rename from components/wpa_supplicant/src/wpa2/tls/asn1.c rename to components/wpa_supplicant/src/tls/asn1.c index ced8018464..08d476254f 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) { @@ -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) 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..4697074074 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 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; - } + 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; - } + 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)crypto_cipher_decrypt(ctx, enc_data, eb, enc_data_len) < 0) { + wpa_printf(MSG_DEBUG, "PKCS #5: Failed to decrypt EB"); + 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; - } + 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..a585f20603 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 || + 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..53a1b33881 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 || + 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 || + 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..f0ba62f270 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 = 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 || 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) + crypto_hash_update(verify->sha256_client, buf, len); + if (verify->sha256_server) + crypto_hash_update(verify->sha256_server, buf, len); + if (verify->sha256_cert) + 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; - } + 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; #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..8e3077d873 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; - } + 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 = 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; - } + 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 = 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 = 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; - } + crypto_hash_update(hmac, rl->write_seq_num, TLS_SEQ_NUM_LEN); + /* type + version + length + fragment */ + 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"); - 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; - } - + 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)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)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)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 = 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; - } + crypto_hash_update(hmac, rl->read_seq_num, TLS_SEQ_NUM_LEN); + /* type + version + length + fragment */ + crypto_hash_update(hmac, in_data - TLS_RECORD_HEADER_LEN, 3); + WPA_PUT_BE16(len, plen); + crypto_hash_update(hmac, len, 2); + 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)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..cc42662689 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 || + 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..3d393bc9c7 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 || + 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..2a5b5f3b48 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; - } + 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 2618589cbd..3f49f513b9 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..b19e187a46 100644 --- a/components/wpa_supplicant/src/wps/wps.c +++ b/components/wpa_supplicant/src/wps/wps.c @@ -7,20 +7,18 @@ */ #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 "crypto/dh_group5.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 "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 +107,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 +149,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 b9a1b1071a..5821634193 100644 --- a/components/wpa_supplicant/include/wps/wps.h +++ b/components/wpa_supplicant/src/wps/wps.h @@ -31,7 +31,6 @@ enum wsc_op_code { }; struct wps_registrar; -//struct upnp_wps_device_sm; struct wps_er; struct wps_parse_attr; @@ -196,10 +195,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); /** @@ -751,10 +748,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; @@ -802,11 +796,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 @@ -1013,9 +1007,18 @@ 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 +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" @@ -1055,7 +1058,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..437c92b69a 100644 --- a/components/wpa_supplicant/src/wps/wps_attr_build.c +++ b/components/wpa_supplicant/src/wps/wps_attr_build.c @@ -5,17 +5,17 @@ * 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" -#include "crypto/dh_group5.h" #include "crypto/sha256.h" #include "crypto/random.h" +#include "crypto/dh_group5.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; - } + 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; - } + 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 (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; - } + 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); @@ -434,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_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..112d683a3f 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; - } + 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; - } + 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..ead31af3e0 100644 --- a/components/wpa_supplicant/src/wps/wps_common.c +++ b/components/wpa_supplicant/src/wps/wps_common.c @@ -7,14 +7,14 @@ */ #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" -#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" @@ -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 ; - } + 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; - } + 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; - } + 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, + 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 ; - } + 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 (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 bd1655f96b..3a47303abf 100644 --- a/components/wpa_supplicant/src/wps/wps_enrollee.c +++ b/components/wpa_supplicant/src/wps/wps_enrollee.c @@ -7,12 +7,10 @@ */ #if CONFIG_IDF_TARGET_ESP32 #include "esp32/rom/ets_sys.h" -#elif CONFIG_IDF_TARGET_ESP32S2BETA -#include "esp32s2beta/rom/ets_sys.h" #endif -#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" @@ -77,12 +75,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; - } + 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"); @@ -92,12 +85,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; - } + 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; @@ -606,12 +594,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; - } + 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"); @@ -651,12 +634,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; - } + 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..e197dfdc06 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; - } + 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; - } + 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; - } + 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; - } + 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; - } + 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/test/CMakeLists.txt b/components/wpa_supplicant/test/CMakeLists.txt index 28ca784c09..0fd0a625ce 100644 --- a/components/wpa_supplicant/test/CMakeLists.txt +++ b/components/wpa_supplicant/test/CMakeLists.txt @@ -1,6 +1,12 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." "${CMAKE_CURRENT_BINARY_DIR}" + PRIV_INCLUDE_DIRS "../src" + REQUIRES unity esp_common test_utils wpa_supplicant mbedtls) -set(COMPONENT_REQUIRES unity wpa_supplicant mbedtls) +idf_component_get_property(esp_supplicant_dir wpa_supplicant COMPONENT_DIR) -register_component() +# 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/components/xtensa/CMakeLists.txt b/components/xtensa/CMakeLists.txt index e44679ebf3..ce33679c27 100644 --- a/components/xtensa/CMakeLists.txt +++ b/components/xtensa/CMakeLists.txt @@ -1,18 +1,24 @@ -if(NOT BOOTLOADER_BUILD) - set(COMPONENT_SRCS "eri.c") - if(IDF_TARGET STREQUAL "esp32") - list(APPEND COMPONENT_SRCS "trax.c") +if(BOOTLOADER_BUILD) + # bootloader only needs headers from this component + set(priv_requires soc) +else() + set(priv_requires soc freertos) + set(srcs "debug_helpers.c" + "debug_helpers_asm.S" + "eri.c" + "stdatomic.c") + + if(CONFIG_IDF_TARGET_ESP32) + list(APPEND srcs "trax.c") endif() - list(APPEND COMPONENT_SRCS "stdatomic.c") endif() -set(COMPONENT_ADD_INCLUDEDIRS "include" "${IDF_TARGET}/include") +idf_build_get_property(target IDF_TARGET) +idf_component_register(SRCS ${srcs} + INCLUDE_DIRS include ${target}/include + LDFRAGMENTS linker.lf + PRIV_REQUIRES ${priv_requires}) -set(COMPONENT_ADD_LDFRAGMENTS linker.lf) -set(COMPONENT_PRIV_REQUIRES soc) - -register_component() - -if (NOT BOOTLOADER_BUILD) - target_link_libraries(${COMPONENT_LIB} "${CMAKE_CURRENT_SOURCE_DIR}/${IDF_TARGET}/libhal.a") +if(NOT BOOTLOADER_BUILD) + target_link_libraries(${COMPONENT_LIB} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/${target}/libhal.a") endif() diff --git a/components/xtensa/debug_helpers.c b/components/xtensa/debug_helpers.c new file mode 100644 index 0000000000..74f66a6cc4 --- /dev/null +++ b/components/xtensa/debug_helpers.c @@ -0,0 +1,78 @@ +// 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 "sdkconfig.h" +#include "esp_types.h" +#include "esp_attr.h" +#include "esp_err.h" +#include "esp_debug_helpers.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 + 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_attr.h b/components/xtensa/include/esp_attr.h index 7a3ec771d1..34458948a7 100644 --- a/components/xtensa/include/esp_attr.h +++ b/components/xtensa/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" @@ -73,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/xtensa/include/esp_debug_helpers.h b/components/xtensa/include/esp_debug_helpers.h index b2abf8f119..ad2681de29 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 @@ -13,6 +27,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. @@ -38,7 +70,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 * @@ -48,12 +79,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/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; diff --git a/docs/Doxyfile b/docs/Doxyfile index 7d00c4cc1c..55a915b062 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -39,32 +39,47 @@ 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/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 ## - ../../components/ethernet/include/esp_eth.h \ - ../../components/ethernet/include/eth_phy/phy.h \ - ../../components/ethernet/include/eth_phy/phy_tlk110.h \ - ../../components/ethernet/include/eth_phy/phy_lan8720.h \ - ../../components/ethernet/include/eth_phy/phy_ip101.h \ + ../../components/esp_eth/include/esp_eth.h \ + ../../components/esp_eth/include/esp_eth_com.h \ + ../../components/esp_eth/include/esp_eth_mac.h \ + ../../components/esp_eth/include/esp_eth_phy.h \ ## ## Peripherals - API Reference ## @@ -106,8 +121,12 @@ 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 \ + ## 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 ## @@ -125,13 +144,16 @@ INPUT = \ ../../components/wifi_provisioning/include/wifi_provisioning/scheme_softap.h \ ../../components/wifi_provisioning/include/wifi_provisioning/scheme_console.h \ ../../components/wifi_provisioning/include/wifi_provisioning/wifi_config.h \ + ../../components/wifi_provisioning/include/wifi_provisioning/wifi_scan.h \ ## ## Storage - API Reference ## ## SPI Flash and Partition APIs - ../../components/spi_flash/include/esp_spi_flash.h \ + ../../components/spi_flash/include/esp_flash_spi_init.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 @@ -150,8 +172,11 @@ INPUT = \ ../../components/vfs/include/esp_vfs_semihost.h \ ## FAT Filesystem ## NOTE: for two lines below header_file.inc is not used - ../../components/fatfs/src/esp_vfs_fat.h \ - ../../components/fatfs/src/diskio.h \ + ../../components/fatfs/vfs/esp_vfs_fat.h \ + ../../components/fatfs/diskio/diskio_impl.h \ + ../../components/fatfs/diskio/diskio_sdmmc.h \ + ../../components/fatfs/diskio/diskio_wl.h \ + ../../components/fatfs/diskio/diskio_rawflash.h \ ## Wear Levelling ../../components/wear_levelling/include/wear_levelling.h \ ## @@ -185,6 +210,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 ## @@ -205,6 +232,8 @@ INPUT = \ ../../components/esp_event/include/esp_event_base.h \ ### eFuse Manager ../../components/efuse/include/esp_efuse.h \ + ### App Image Format + ../../components/bootloader_support/include/esp_app_format.h \ ### ESP Pthread parameters ../../components/pthread/include/esp_pthread.h \ ### 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/_static/api-guides.gif b/docs/_static/api-guides.gif deleted file mode 100644 index bc9dd36dba..0000000000 Binary files a/docs/_static/api-guides.gif and /dev/null differ diff --git a/docs/_static/api-guides.png b/docs/_static/api-guides.png new file mode 100644 index 0000000000..885e36bba1 Binary files /dev/null and b/docs/_static/api-guides.png differ diff --git a/docs/_static/api-reference.gif b/docs/_static/api-reference.gif deleted file mode 100644 index 7fd81755b9..0000000000 Binary files a/docs/_static/api-reference.gif and /dev/null differ diff --git a/docs/_static/api-reference.png b/docs/_static/api-reference.png new file mode 100644 index 0000000000..91b09ad6e7 Binary files /dev/null and b/docs/_static/api-reference.png differ diff --git a/docs/_static/contribute.gif b/docs/_static/contribute.gif deleted file mode 100644 index 48a4508909..0000000000 Binary files a/docs/_static/contribute.gif and /dev/null differ diff --git a/docs/_static/contribute.png b/docs/_static/contribute.png new file mode 100644 index 0000000000..1984736545 Binary files /dev/null and b/docs/_static/contribute.png differ 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 3c9e64fcf5..0000000000 Binary files a/docs/_static/esp32-pico-kit-v4.1-layout.jpg and /dev/null differ diff --git a/docs/_static/esp32_nimble_stack.png b/docs/_static/esp32_nimble_stack.png new file mode 100644 index 0000000000..4aba0ae882 Binary files /dev/null and b/docs/_static/esp32_nimble_stack.png differ diff --git a/docs/_static/get-started-garbled-output.png b/docs/_static/get-started-garbled-output.png new file mode 100644 index 0000000000..2e6dd68ca3 Binary files /dev/null and b/docs/_static/get-started-garbled-output.png differ diff --git a/docs/_static/get-started.gif b/docs/_static/get-started.gif deleted file mode 100644 index 7a7a8023b6..0000000000 Binary files a/docs/_static/get-started.gif and /dev/null differ diff --git a/docs/_static/get-started.png b/docs/_static/get-started.png new file mode 100644 index 0000000000..3444635115 Binary files /dev/null and b/docs/_static/get-started.png differ diff --git a/docs/_static/hw-reference.gif b/docs/_static/hw-reference.gif deleted file mode 100644 index 0b969c2099..0000000000 Binary files a/docs/_static/hw-reference.gif and /dev/null differ diff --git a/docs/_static/hw-reference.png b/docs/_static/hw-reference.png new file mode 100644 index 0000000000..ec31ab52b9 Binary files /dev/null and b/docs/_static/hw-reference.png differ diff --git a/docs/_static/mesh-events-delivery.png b/docs/_static/mesh-events-delivery.png index 40341bb1dd..ceedadf829 100644 Binary files a/docs/_static/mesh-events-delivery.png and b/docs/_static/mesh-events-delivery.png differ diff --git a/docs/_static/resources.gif b/docs/_static/resources.gif deleted file mode 100644 index cde4bd8094..0000000000 Binary files a/docs/_static/resources.gif and /dev/null differ diff --git a/docs/_static/resources.png b/docs/_static/resources.png new file mode 100644 index 0000000000..8989b62987 Binary files /dev/null and b/docs/_static/resources.png differ 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: ' '; +} diff --git a/docs/conf_common.py b/docs/conf_common.py index a008829bda..505dab8a0c 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, @@ -92,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' ] @@ -235,19 +239,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'),] +# 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/en/COPYRIGHT.rst b/docs/en/COPYRIGHT.rst index e9aa5a4ed8..2891e13f58 100644 --- a/docs/en/COPYRIGHT.rst +++ b/docs/en/COPYRIGHT.rst @@ -56,6 +56,10 @@ 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 + +* `mynewt-nimble`_ Apache Mynewt NimBLE, Copyright 2015-2018, The Apache Software Foundation, is licensed under Apache License 2.0. + Build Tools ----------- @@ -158,3 +162,5 @@ 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 +.. _mynewt-nimble: https://github.com/apache/mynewt-nimble 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/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/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/en/api-guides/bootloader.rst b/docs/en/api-guides/bootloader.rst index 6e5efbcc04..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: @@ -33,7 +34,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 @@ -42,13 +43,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/build-system-cmake.rst b/docs/en/api-guides/build-system-cmake.rst deleted file mode 100644 index 36c90e6863..0000000000 --- a/docs/en/api-guides/build-system-cmake.rst +++ /dev/null @@ -1,1303 +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. -- ``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_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) - -Add a directory *component_dir* that contains a component to the build. - -.. 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 - starting components for trimming the build; components not in the list are automatically if they are required in the expanded dependency tree - -.. 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..52ca8642c5 --- /dev/null +++ b/docs/en/api-guides/build-system-legacy.rst @@ -0,0 +1,652 @@ +Build System (Legacy GNU Make) +****************************** +:link_to_translation:`zh_CN:[中文]` + +.. 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 an ESP-IDF project using GNU Make build system. + +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 Wi-Fi 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-legacy: + +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-legacy: + +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 8c85c65d3c..2eed1fa5ab 100644 --- a/docs/en/api-guides/build-system.rst +++ b/docs/en/api-guides/build-system.rst @@ -1,18 +1,12 @@ Build System ************ + :link_to_translation:`zh_CN:[中文]` -This document explains the Espressif IoT Development Framework build system and the -concept of "components" +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. -Read this document if you want to know how to organise a new ESP-IDF project. +.. 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. -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 ======== @@ -20,7 +14,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,444 +23,520 @@ 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: -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: + +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`. -- ``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: + +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: -- 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. +Overriding Parts of the Project +=============================== -.. _make-size: +.. _project_include.cmake: -Advanced Make Targets +project_include.cmake --------------------- -- ``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. +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` 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`. + +``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 The Make Process --------------------------- +Debugging CMake +=============== -Some tips for debugging the esp-idf build system: +For full details about CMake_ and CMake commands, see the `CMake v3.5 documentation`_. -- 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. +Some tips for debugging the ESP-IDF CMake-based build system: -For more debugging tips and general make information, see the `GNU Make Manual`. +- 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, 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`. +If you don't want this behaviour, it can be disabled by passing ``--no-warnings`` to ``idf.py``. -Note that this option doesn't trigger a warning if ``ifdef`` or ``ifndef`` are used in Makefiles. +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 -------------------------------- - -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`. +.. _gnu-make-to-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. - -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``:: @@ -475,17 +545,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: @@ -508,28 +576,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 @@ -538,112 +612,756 @@ 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 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +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: 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. + +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 +====================================== + +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/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..f96d4e2cb0 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`): @@ -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 @@ -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/external-ram.rst b/docs/en/api-guides/external-ram.rst index f7c509abcd..fa22c06d31 100644 --- a/docs/en/api-guides/external-ram.rst +++ b/docs/en/api-guides/external-ram.rst @@ -1,47 +1,46 @@ Support for external RAM ************************ +:link_to_translation:`zh_CN:[中文]` + .. toctree:: :maxdepth: 1 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 +49,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 +90,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 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/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/index.rst b/docs/en/api-guides/index.rst index 17ab34fed0..fdfd58c984 100644 --- a/docs/en/api-guides/index.rst +++ b/docs/en/api-guides/index.rst @@ -3,34 +3,35 @@ API Guides :link_to_translation:`zh_CN:[中文]` .. toctree:: - :maxdepth: 1 + :maxdepth: 1 - General Notes - Build System - Build System (CMake) - 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 (CMake) - Unit Testing - Unit Testing (CMake) - Application Level Tracing - Console Component - ROM debug console - RF Calibration - WiFi Driver - ESP-MESH - BluFi - External SPI-connected RAM - Linker Script Generation + 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-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 diff --git a/docs/en/api-guides/jtag-debugging/configure-wrover.rst b/docs/en/api-guides/jtag-debugging/configure-wrover.rst index c985e640ac..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:`../../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`. 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/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/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/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 diff --git a/docs/en/api-guides/partition-tables.rst b/docs/en/api-guides/partition-tables.rst index 502c7118c9..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 ------------------------- @@ -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). @@ -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,11 +162,107 @@ 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 ``idf.py 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 -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. .. _secure boot: security/secure-boot.rst 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/idf-monitor.rst b/docs/en/api-guides/tools/idf-monitor.rst index f48275d8fb..c7da5f1e08 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,15 +30,15 @@ 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 | 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. | +| - 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. | +-------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | - Ctrl+Y | Stop/resume log output printing on screen | Discards all incoming serial data while activated. Allows to quickly pause and examine log output without quitting the monitor. | +-------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | - Ctrl+L | Stop/resume log output saved to file | Creates a file in the project directory and the output is written to that file until this is disabled with the same keyboard shortcut (or IDF Monitor exits). | +-------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| - Ctrl+H | Display all keyboard shortcuts | | +| - Ctrl+H (or H) | Display all keyboard shortcuts | | +-------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+ Any keys pressed, other than ``Ctrl-]`` and ``Ctrl-T``, will be sent through the serial port. @@ -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/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/en/api-guides/ulp-cmake.rst b/docs/en/api-guides/ulp-legacy.rst similarity index 79% rename from docs/en/api-guides/ulp-cmake.rst rename to docs/en/api-guides/ulp-legacy.rst index 0391ab73d1..658ee49e45 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 (Legacy GNU Make) +================================= .. toctree:: :maxdepth: 1 @@ -9,6 +7,7 @@ ULP coprocessor programming (CMake) 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. @@ -27,35 +26,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 +74,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 +85,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 +139,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 e59c3cc751..df3b813c75 100644 --- a/docs/en/api-guides/ulp.rst +++ b/docs/en/api-guides/ulp.rst @@ -1,5 +1,7 @@ ULP coprocessor programming -=========================== +=================================== + +: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. `make 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 76% rename from docs/en/api-guides/unit-tests-cmake.rst rename to docs/en/api-guides/unit-tests-legacy.rst index 355b7f4ed0..60e39bf857 100644 --- a/docs/en/api-guides/unit-tests-cmake.rst +++ b/docs/en/api-guides/unit-tests-legacy.rst @@ -1,8 +1,8 @@ -Unit Testing in ESP32 (CMake) -============================= +Unit Testing (Legacy GNU Make) +============================== :link_to_translation:`zh_CN:[中文]` -.. include:: ../cmake-warning.rst +.. 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. @@ -28,18 +28,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 +78,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 +133,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 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). +* `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 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 ``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 +182,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..f2b564aa68 100644 --- a/docs/en/api-guides/unit-tests.rst +++ b/docs/en/api-guides/unit-tests.rst @@ -1,5 +1,5 @@ Unit Testing in ESP32 -===================== +============================= :link_to_translation:`zh_CN:[中文]` 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. @@ -26,9 +26,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 +85,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 +126,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 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 ``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 +175,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/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. 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 4e1e2d14b4..d250083586 100644 --- a/docs/en/api-reference/bluetooth/index.rst +++ b/docs/en/api-reference/bluetooth/index.rst @@ -4,12 +4,17 @@ Bluetooth API :link_to_translation:`zh_CN:[中文]` .. toctree:: - :maxdepth: 2 + :maxdepth: 2 - Bluetooth Controller && VHCI - Bluetooth Common - Bluetooth LE - Bluetooth Classic + 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. +* For BLE-only usecases, using NimBLE is recommended. It is less demanding in terms of code footprint and runtime memory, making it suitable for such scenarios. For the overview of the ESP32 Bluetooth stack architecture, follow the links below: @@ -17,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/en/api-reference/bluetooth/nimble/index.rst b/docs/en/api-reference/bluetooth/nimble/index.rst new file mode 100644 index 0000000000..e035c61999 --- /dev/null +++ b/docs/en/api-reference/bluetooth/nimble/index.rst @@ -0,0 +1,44 @@ +NimBLE-based host APIs +********************** +Overview +======== + +Apache MyNewt NimBLE is a highly configurable and BT SIG qualifiable BLE stack providing both host and controller functionalities. ESP-IDF supports NimBLE host stack which is specifically ported for ESP32 platform and FreeRTOS. The underlying controller is still the same (as in case of Bluedroid) providing VHCI interface. Refer to `NimBLE user guide `_ for a complete list of features and additional information on NimBLE stack. Most features of NimBLE including BLE Mesh are supported by ESP-IDF. The porting layer is kept cleaner by maintaining all the existing APIs of NimBLE along with a single ESP-NimBLE API for initialization, making it simpler for the application developers. + +Architecture +============ + +Currently, NimBLE host and controller support different transports such as UART and RAM between them. However, RAM transport cannot be used as is in case of ESP as ESP controller supports VHCI interface and buffering schemes used by NimBLE host is incompatible with that used by ESP controller. Therefore, a new transport between NimBLE host and ESP controller has been added. This is depicted in the figure below. This layer is responsible for maintaining pool of transport buffers and formatting buffers exchanges between host and controller as per the requirements. + +.. figure:: ../../../../_static/esp32_nimble_stack.png + :align: center + :alt: ESP NimBLE Stack. + :scale: 50 + + ESP NimBLE Stack + + +Threading Model +=============== + +The NimBLE host can run inside the application thread or can have its own independent thread. This flexibility is inherently provided by NimBLE design. By default, a thread is spawned by the porting function ``nimble_port_freertos_init``. This behavior can be changed by overriding the same function. For BLE Mesh, additional thread (advertising thread) is used which keeps on feeding advertisement events to the main thread. + +Programming Sequence +==================== + +To begin with, make sure that the NimBLE stack is enabled from menuconfig :ref:`choose NimBLE for the Bluetooth host `. + +Typical programming sequence with NimBLE stack consists of the following steps: + * Initialize NVS flash using :cpp:func:`nvs_flash_init` API. This is because ESP controller uses NVS during initialization. + * Call :cpp:func:`esp_nimble_hci_and_controller_init` to initialize ESP controller as well as transport layer. This will also link the host and controller modules together. Alternatively, if ESP controller is already initialized, then :cpp:func:`esp_nimble_hci_init` can be called for the remaining initialization. + * Initialize the host stack using ``nimble_port_init``. + * Initialize the required NimBLE host configuration parameters and callbacks + * Perform application specific tasks/initialization + * Run the thread for host stack using ``nimble_port_freertos_init`` + +This documentation does not cover NimBLE APIs. Refer to `NimBLE tutorial `_ for more details on the programming sequence/NimBLE APIs for different scenarios. + +API Reference +============= + +.. include:: /_build/inc/esp_nimble_hci.inc 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/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/network/esp_eth.rst b/docs/en/api-reference/network/esp_eth.rst index 362ad8a340..78a1ea1f74 100644 --- a/docs/en/api-reference/network/esp_eth.rst +++ b/docs/en/api-reference/network/esp_eth.rst @@ -7,48 +7,47 @@ Application Example - Ethernet basic example: :example:`ethernet/ethernet`. - Ethernet iperf example: :example:`ethernet/iperf`. -PHY Interfaces --------------- +Ethernet Driver Model +--------------------- -The configured PHY model(s) are set in software by configuring the eth_config_t structure for the given PHY. + * :component_file:`esp_eth/include/esp_eth.h` -Headers include a default configuration structure. These default configurations will need some members overriden or re-set before they can be used for a particular PHY hardware configuration. Consult the Ethernet example to see how this is done. +Ethernet Common Interface +------------------------- - * :component_file:`ethernet/include/eth_phy/phy.h` (common) - * :component_file:`ethernet/include/eth_phy/phy_tlk110.h` - * :component_file:`ethernet/include/eth_phy/phy_lan8720.h` - * :component_file:`ethernet/include/eth_phy/phy_ip101.h` + * :component_file:`esp_eth/include/esp_eth_com.h` -PHY Configuration Constants -^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Ethernet MAC Interface +---------------------- -.. doxygenvariable:: phy_tlk110_default_ethernet_config -.. doxygenvariable:: phy_lan8720_default_ethernet_config -.. doxygenvariable:: phy_ip101_default_ethernet_config + * :component_file:`esp_eth/include/esp_eth_mac.h` +Ethernet PHY Interface +---------------------- -API Reference - Ethernet ------------------------- + * :component_file:`esp_eth/include/esp_eth_phy.h` + +Ethernet PHY Common Registers +----------------------------- + + * :component_file:`esp_eth/include/eth_phy_regs_struct.h` + +API Reference - Driver Model +---------------------------- .. include:: /_build/inc/esp_eth.inc -API Reference - PHY Common --------------------------- +API Reference - Common Interface +-------------------------------- -.. include:: /_build/inc/phy.inc +.. include:: /_build/inc/esp_eth_com.inc -API Reference - PHY TLK110 --------------------------- +API Reference - MAC Interface +----------------------------- -.. include:: /_build/inc/phy_tlk110.inc +.. include:: /_build/inc/esp_eth_mac.inc -API Reference - PHY LAN8720 ---------------------------- - -.. include:: /_build/inc/phy_lan8720.inc - -API Reference - PHY IP101 -------------------------- - -.. include:: /_build/inc/phy_ip101.inc +API Reference - PHY Interface +----------------------------- +.. include:: /_build/inc/esp_eth_phy.inc diff --git a/docs/en/api-reference/network/esp_mesh.rst b/docs/en/api-reference/network/esp_mesh.rst index 299a8b9529..b5ae9efdf3 100644 --- a/docs/en/api-reference/network/esp_mesh.rst +++ b/docs/en/api-reference/network/esp_mesh.rst @@ -51,9 +51,9 @@ An application interfaces with ESP-MESH via **ESP-MESH Events**. Since ESP-MESH ESP-MESH System Events Delivery -The :cpp:type:`mesh_event_id_t` defines all possible ESP-MESH system events and can indicate events such as the connection/disconnection of parent/child. Before ESP-MESH system events can be used, the application must register a **Mesh Event Callback** via :cpp:func:`esp_mesh_set_config`. The callback is used to receive events from the ESP-MESH stack as well as the LwIP Stack and should contain handlers for each event relevant to the application. +The :cpp:type:`mesh_event_id_t` defines all possible ESP-MESH events and can indicate events such as the connection/disconnection of parent/child. Before ESP-MESH events can be used, the application must register a **Mesh Events handler** via :cpp:func:`esp_event_handler_register` to the default event task. Should contain handlers for each event relevant to the application. -Typical use cases of system events include using events such as :cpp:enumerator:`MESH_EVENT_PARENT_CONNECTED` and :cpp:enumerator:`MESH_EVENT_CHILD_CONNECTED` to indicate when a node can begin transmitting data upstream and downstream respectively. Likewise, :cpp:enumerator:`MESH_EVENT_ROOT_GOT_IP` and :cpp:enumerator:`MESH_EVENT_ROOT_LOST_IP` can be used to indicate when the root node can and cannot transmit data to the external IP network. +Typical use cases of mesh events include using events such as :cpp:enumerator:`MESH_EVENT_PARENT_CONNECTED` and :cpp:enumerator:`MESH_EVENT_CHILD_CONNECTED` to indicate when a node can begin transmitting data upstream and downstream respectively. Likewise, :cpp:enumerator:`IP_EVENT_STA_GOT_IP` and :cpp:enumerator:`IP_EVENT_STA_LOST_IP` can be used to indicate when the root node can and cannot transmit data to the external IP network. .. warning:: When using ESP-MESH under self-organized mode, users must ensure that no calls to Wi-Fi API are made. This is due to the fact that the self-organizing mode will internally make Wi-Fi API calls to connect/disconnect/scan etc. **Any Wi-Fi calls from the application (including calls from callbacks and handlers of Wi-Fi events) may interfere with ESP-MESH's self-organizing behavior**. Therefore, user's should not call Wi-Fi APIs after :cpp:func:`esp_mesh_start` is called, and before :cpp:func:`esp_mesh_stop` is called. @@ -81,8 +81,6 @@ The following code snippet demonstrates how to initialize LwIP for ESP-MESH appl */ ESP_ERROR_CHECK(tcpip_adapter_dhcps_stop(TCPIP_ADAPTER_IF_AP)); ESP_ERROR_CHECK(tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA)); - /* do not specify system event callback, use NULL instead. */ - ESP_ERROR_CHECK(esp_event_loop_init(NULL, NULL)); .. note:: @@ -108,12 +106,15 @@ The prerequisites for starting ESP-MESH is to initialize LwIP and Wi-Fi, The fol */ ESP_ERROR_CHECK(tcpip_adapter_dhcps_stop(TCPIP_ADAPTER_IF_AP)); ESP_ERROR_CHECK(tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA)); - /* do not specify system event callback, use NULL instead. */ - ESP_ERROR_CHECK(esp_event_loop_init(NULL, NULL)); + + /* event initialization */ + ESP_ERROR_CHECK(esp_event_loop_create_default()); /* Wi-Fi initialization */ wifi_init_config_t config = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&config)); + /* register IP events handler */ + 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()); @@ -134,6 +135,8 @@ The following code snippet demonstrates how to initialize ESP-MESH /* mesh initialization */ ESP_ERROR_CHECK(esp_mesh_init()); + /* register mesh events handler */ + ESP_ERROR_CHECK(esp_event_handler_register(MESH_EVENT, ESP_EVENT_ANY_ID, &mesh_event_handler, NULL)); .. _mesh-configuring-mesh: @@ -149,9 +152,6 @@ ESP-MESH is configured via :cpp:func:`esp_mesh_set_config` which receives its ar +==================+=====================================+ | Channel | Range from 1 to 14 | +------------------+-------------------------------------+ -| Event Callback | Callback for Mesh Events, | -| | see :cpp:type:`mesh_event_cb_t` | -+------------------+-------------------------------------+ | Mesh ID | ID of ESP-MESH Network, | | | see :cpp:type:`mesh_addr_t` | +------------------+-------------------------------------+ @@ -173,8 +173,6 @@ The following code snippet demonstrates how to configure ESP-MESH. 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; /* channel (must match the router's channel) */ cfg.channel = CONFIG_MESH_CHANNEL; /* router */ 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/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 77913eab91..6aff1448ae 100644 --- a/docs/en/api-reference/peripherals/index.rst +++ b/docs/en/api-reference/peripherals/index.rst @@ -4,27 +4,27 @@ 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 - Temp sensor - 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 + Temp sensor + 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/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 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/docs/en/api-reference/peripherals/sdmmc_host.rst b/docs/en/api-reference/peripherals/sdmmc_host.rst index 59bc75d697..f2a866a2ba 100644 --- a/docs/en/api-reference/peripherals/sdmmc_host.rst +++ b/docs/en/api-reference/peripherals/sdmmc_host.rst @@ -4,12 +4,12 @@ SDMMC Host Driver Overview -------- -On the ESP32, SDMMC host peripheral has two slots: +ESP32's SDMMC host peripheral has two slots: - Slot 0 (:c:macro:`SDMMC_HOST_SLOT_0`) is an 8-bit slot. It uses ``HS1_*`` signals in the PIN MUX. - Slot 1 (:c:macro:`SDMMC_HOST_SLOT_1`) is a 4-bit slot. It uses ``HS2_*`` signals in the PIN MUX. -Pin mappings of these slots are given in the following table: +Pin mappings of these slots are given in the table below. +--------+-------------+-------------+ | Signal | Slot 0 | Slot 1 | @@ -39,44 +39,55 @@ Pin mappings of these slots are given in the following table: | WP | any input via GPIO matrix | +--------+---------------------------+ -Card Detect and Write Protect signals can be routed to arbitrary pins using GPIO matrix. To use these pins, set ``gpio_cd`` and ``gpio_wp`` members of :cpp:class:`sdmmc_slot_config_t` structure before calling :cpp:func:`sdmmc_host_init_slot`. Note that it is not advised to specify Card Detect pin when working with SDIO cards, because in ESP32 card detect signal can also trigger SDIO slave interrupt. +The Card Detect and Write Protect signals can be routed to arbitrary pins using the GPIO matrix. To reserve the pins, set the ``gpio_cd`` and ``gpio_wp`` members of the :cpp:class:`sdmmc_slot_config_t` structure before calling :cpp:func:`sdmmc_host_init_slot`. Please note that it is not advised to specify a Card Detect pin when working with SDIO cards, because the card detect signal in ESP32 can also trigger SDIO slave interrupt. .. warning:: - Pins used by slot 0 (``HS1_*``) are also used to connect SPI flash chip in ESP-WROOM32 and ESP32-WROVER modules. These pins can not be shared between SD card and SPI flash. If you need to use Slot 0, connect SPI flash to different pins and set Efuses accordingly. + Pins used by Slot 0 (``HS1_*``) are also used to connect the SPI flash chip in ESP32-WROOM and ESP32-WROVER modules. These pins cannot be shared between an SD card and SPI flash. If you need to use Slot 0, connect SPI flash to different pins and set eFuses accordingly. -Supported speed modes + +Supported Speed Modes --------------------- SDMMC Host driver supports the following speed modes: -- Default Speed (20MHz), 4-line/1-line (with SD cards), and 8-line (with 3.3V eMMC). -- High Speed (40MHz), 4-line/1-line (with SD cards), and 8-line (with 3.3V eMMC) -- High Speed DDR (40MHz), 4-line (with 3.3V eMMC) +- Default Speed (20 MHz), 4-line/1-line (with SD cards), and 8-line (with 3.3 V eMMC) +- High Speed (40 MHz), 4-line/1-line (with SD cards), and 8-line (with 3.3 V eMMC) +- High Speed DDR (40 MHz), 4-line (with 3.3 V eMMC) -Not supported at present are: +Speed modes not supported at present: - High Speed DDR mode, 8-line eMMC -- UHS-I 1.8V modes, 4-line SD cards +- UHS-I 1.8 V modes, 4-line SD cards -Using the SDMMC Host driver + +Using the SDMMC Host Driver --------------------------- -Of all the funtions listed below, only :cpp:func:`sdmmc_host_init`, :cpp:func:`sdmmc_host_init_slot`, and :cpp:func:`sdmmc_host_deinit` will be used directly by most applications. +Of all the functions listed below, only the following ones will be used directly by most applications: -Other functions, such as :cpp:func:`sdmmc_host_set_bus_width`, :cpp:func:`sdmmc_host_set_card_clk`, and :cpp:func:`sdmmc_host_do_transaction` will be called by the SD/MMC protocol layer via function pointers in :cpp:class:`sdmmc_host_t` structure. +- :cpp:func:`sdmmc_host_init` +- :cpp:func:`sdmmc_host_init_slot` +- :cpp:func:`sdmmc_host_deinit` -Configuring bus width and frequency +Other functions, such as the ones given below, will be called by the SD/MMC protocol layer via function pointers in the :cpp:class:`sdmmc_host_t` structure: + +- :cpp:func:`sdmmc_host_set_bus_width` +- :cpp:func:`sdmmc_host_set_card_clk` +- :cpp:func:`sdmmc_host_do_transaction` + + +Configuring Bus Width and Frequency ----------------------------------- -With the default initializers for :cpp:class:`sdmmc_host_t` and :cpp:class:`sdmmc_slot_config_t` (:c:macro:`SDMMC_HOST_DEFAULT` and :c:macro:`SDMMC_SLOT_CONFIG_DEFAULT`), SDMMC Host driver will attempt to use widest bus supported by the card (4 lines for SD, 8 lines for eMMC) and 20MHz frequency. +With the default initializers for :cpp:class:`sdmmc_host_t` and :cpp:class:`sdmmc_slot_config_t` (:c:macro:`SDMMC_HOST_DEFAULT` and :c:macro:`SDMMC_SLOT_CONFIG_DEFAULT`), SDMMC Host driver will attempt to use the widest bus supported by the card (4 lines for SD, 8 lines for eMMC) and the frequency of 20 MHz. -In designs where communication at 40MHz frequency can be achieved, it is possible to increase the bus frequency to by changing ``max_freq_khz`` field of :cpp:class:`sdmmc_host_t`:: +In the designs where communication at 40 MHz frequency can be achieved, it is possible to increase the bus frequency by changing the ``max_freq_khz`` field of :cpp:class:`sdmmc_host_t`:: sdmmc_host_t host = SDMMC_HOST_DEFAULT(); host.max_freq_khz = SDMMC_FREQ_HIGHSPEED; -To configure bus width, set ``width`` field of :cpp:class:`sdmmc_slot_config_t`. For example, to set 1-line mode:: +To configure the bus width, set the ``width`` field of :cpp:class:`sdmmc_slot_config_t`. For example, to set 1-line mode:: sdmmc_slot_config_t slot = SDMMC_SLOT_CONFIG_DEFAULT(); slot.width = 1; @@ -87,9 +98,10 @@ See also See :doc:`SD/SDIO/MMC Driver <../storage/sdmmc>` for the higher level driver which implements the protocol layer. -See :doc:`SD SPI Host Driver ` for a similar driver which uses SPI controller and is limited to SPI mode of SD protocol. +See :doc:`SD SPI Host Driver ` for a similar driver which uses the SPI controller and is limited to SD protocol's SPI mode. + +See :doc:`sd_pullup_requirements` for pullup support and compatibilities of modules and development kits. -See :doc:`sd_pullup_requirements` for pullup support and compatiblities about modules and devkits. API Reference ------------- 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 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); 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/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..36af219894 100644 --- a/docs/en/api-reference/protocols/index.rst +++ b/docs/en/api-reference/protocols/index.rst @@ -3,16 +3,18 @@ Application Protocols :link_to_translation:`zh_CN:[中文]` .. toctree:: - :maxdepth: 1 + :maxdepth: 1 - mDNS - ESP-TLS - HTTP Client - HTTP Server - HTTPS Server - ASIO - ESP-MQTT - Modbus + 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/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/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/provisioning/wifi_provisioning.rst b/docs/en/api-reference/provisioning/wifi_provisioning.rst index 54797d5cfb..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(); } } @@ -234,6 +201,9 @@ Once connected to the device, the provisioning related protocomm endpoints can b * - prov-session - http://.local/prov-session - Security endpoint used for session establishment + * - prov-scan + - http://wifi-prov.local/prov-scan + - Endpoint used for starting Wi-Fi scan and receiving scan results * - prov-config - http://.local/prov-config - Endpoint used for configuring Wi-Fi credentials on device @@ -245,14 +215,31 @@ 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 * `apply_config` - For applying the credentials saved during `set_config` and start the Wi-Fi station +After session establishment, client can also request Wi-Fi scan results from the device. The results returned is a list of AP SSIDs, sorted in descending order of signal strength. This allows client applications to display APs nearby to the device at the time of provisioning, and users can select one of the SSIDs and provide the password which is then sent using the `wifi_config` commands described above. The `wifi_scan` endpoint supports the following protobuf commands : + + * `scan_start` - For starting Wi-Fi scan with various options : + + * `blocking` (input) - If true, the command returns only when the scanning is finished + * `passive` (input) - If true scan is started in passive mode (this may be slower) instead of active mode + * `group_channels` (input) - This specifies whether to scan all channels in one go (when zero) or perform scanning of channels in groups, with 120ms delay between scanning of consecutive groups, and the value of this parameter sets the number of channels in each group. This is useful when transport mode is SoftAP, where scanning all channels in one go may not give the Wi-Fi driver enough time to send out beacons, and hence may cause disconnection with any connected stations. When scanning in groups, the manager will wait for atleast 120ms after completing scan on a group of channels, and thus allow the driver to send out the beacons. For example, given that the total number of Wi-Fi channels is 14, then setting group_channels to 4, will create 5 groups, with each group having 3 channels, except the last one which will have 14 % 3 = 2 channels. So, when scan is started, the first 3 channels will be scanned, followed by a 120ms delay, and then the next 3 channels, and so on, until all the 14 channels have been scanned. One may need to adjust this parameter as having only few channels in a group may slow down the overall scan time, while having too many may again cause disconnection. Usually a value of 4 should work for most cases. Note that for any other mode of transport, e.g. BLE, this can be safely set to 0, and hence achieve the fastest overall scanning time. + * `period_ms` (input) - Scan parameter specifying how long to wait on each channel + * `scan_status` - Gives the status of scanning process : + + * `scan_finished` (output) - When scan has finished this returns true + * `result_count` (output) - This gives the total number of results obtained till now. If scan is yet happening this number will keep on updating + * `scan_result` - For fetching scan results. This can be called even if scan is still on going + + * `start_index` (input) - Starting index from where to fetch the entries from the results list + * `count` (input) - Number of entries to fetch from the starting index + * `entries` (output) - List of entries returned. Each entry consists of `ssid`, `channel` and `rssi` information Additional Endpoints ^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/en/api-reference/storage/fatfs.rst b/docs/en/api-reference/storage/fatfs.rst index 6ad0163e12..6e91897a5f 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/vfs/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/vfs/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,20 +59,24 @@ 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/vfs/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 :members: .. doxygenfunction:: ff_diskio_register_sdmmc +.. doxygenfunction:: ff_diskio_register_wl_partition +.. doxygenfunction:: ff_diskio_register_raw_partition + diff --git a/docs/en/api-reference/storage/index.rst b/docs/en/api-reference/storage/index.rst index b4a6903560..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 -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..d9169c3dfc 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,40 +13,27 @@ 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 ------------------------- -.. include:: /_build/inc/esp_spi_flash.inc +.. include:: /_build/inc/esp_flash_spi_init.inc +.. include:: /_build/inc/esp_flash.inc +.. include:: /_build/inc/spi_flash_types.inc API Reference - Partition Table ------------------------------- diff --git a/docs/en/api-reference/storage/spiffs.rst b/docs/en/api-reference/storage/spiffs.rst index 4c7b3cf779..5620e83d77 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,76 +22,94 @@ 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:: - $(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 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. + +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 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:: +``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 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/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. -For an example, see :example:`examples/storage/spiffsgen>`. +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>`. 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 +117,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 +133,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/docs/en/api-reference/system/app_image_format.rst b/docs/en/api-reference/system/app_image_format.rst new file mode 100644 index 0000000000..7044b302ef --- /dev/null +++ b/docs/en/api-reference/system/app_image_format.rst @@ -0,0 +1,108 @@ +App Image Format +================ + +An application image consists of the following structures: + +1. The :cpp:type:`esp_image_header_t` structure describes the mode of SPI flash and the count of memory segments. +2. The :cpp:type:`esp_image_segment_header_t` structure describes each segment, its length, and its location in ESP32's memory, followed by the data with a length of ``data_len``. The data offset for each segment in the image is calculated in the following way: + + * offset for 0 Segment = sizeof(:cpp:type:`esp_image_header_t`) + sizeof(:cpp:type:`esp_image_segment_header_t`). + * offset for 1 Segment = offset for 0 Segment + length of 0 Segment + sizeof(:cpp:type:`esp_image_segment_header_t`). + * offset for 2 Segment = offset for 1 Segment + length of 1 Segment + sizeof(:cpp:type:`esp_image_segment_header_t`). + * ... + +The count of each segment is defined in the ``segment_count`` field that is stored in :cpp:type:`esp_image_header_t`. The count cannot be more than :cpp:type:`ESP_IMAGE_MAX_SEGMENTS`. + +To get the list of your image segments, please run the following command: + +:: + + esptool.py --chip esp32 image_info build/app.bin + +:: + + esptool.py v2.3.1 + Image version: 1 + Entry point: 40080ea4 + 13 segments + Segment 1: len 0x13ce0 load 0x3f400020 file_offs 0x00000018 SOC_DROM + Segment 2: len 0x00000 load 0x3ff80000 file_offs 0x00013d00 SOC_RTC_DRAM + Segment 3: len 0x00000 load 0x3ff80000 file_offs 0x00013d08 SOC_RTC_DRAM + Segment 4: len 0x028e0 load 0x3ffb0000 file_offs 0x00013d10 DRAM + Segment 5: len 0x00000 load 0x3ffb28e0 file_offs 0x000165f8 DRAM + Segment 6: len 0x00400 load 0x40080000 file_offs 0x00016600 SOC_IRAM + Segment 7: len 0x09600 load 0x40080400 file_offs 0x00016a08 SOC_IRAM + Segment 8: len 0x62e4c load 0x400d0018 file_offs 0x00020010 SOC_IROM + Segment 9: len 0x06cec load 0x40089a00 file_offs 0x00082e64 SOC_IROM + Segment 10: len 0x00000 load 0x400c0000 file_offs 0x00089b58 SOC_RTC_IRAM + Segment 11: len 0x00004 load 0x50000000 file_offs 0x00089b60 SOC_RTC_DATA + Segment 12: len 0x00000 load 0x50000004 file_offs 0x00089b6c SOC_RTC_DATA + Segment 13: len 0x00000 load 0x50000004 file_offs 0x00089b74 SOC_RTC_DATA + Checksum: e8 (valid)Validation Hash: 407089ca0eae2bbf83b4120979d3354b1c938a49cb7a0c997f240474ef2ec76b (valid) + +You can also see the information on segments in the IDF logs while your application is booting: + +:: + + I (443) esp_image: segment 0: paddr=0x00020020 vaddr=0x3f400020 size=0x13ce0 ( 81120) map + I (489) esp_image: segment 1: paddr=0x00033d08 vaddr=0x3ff80000 size=0x00000 ( 0) load + I (530) esp_image: segment 2: paddr=0x00033d10 vaddr=0x3ff80000 size=0x00000 ( 0) load + I (571) esp_image: segment 3: paddr=0x00033d18 vaddr=0x3ffb0000 size=0x028e0 ( 10464) load + I (612) esp_image: segment 4: paddr=0x00036600 vaddr=0x3ffb28e0 size=0x00000 ( 0) load + I (654) esp_image: segment 5: paddr=0x00036608 vaddr=0x40080000 size=0x00400 ( 1024) load + I (695) esp_image: segment 6: paddr=0x00036a10 vaddr=0x40080400 size=0x09600 ( 38400) load + I (737) esp_image: segment 7: paddr=0x00040018 vaddr=0x400d0018 size=0x62e4c (405068) map + I (847) esp_image: segment 8: paddr=0x000a2e6c vaddr=0x40089a00 size=0x06cec ( 27884) load + I (888) esp_image: segment 9: paddr=0x000a9b60 vaddr=0x400c0000 size=0x00000 ( 0) load + I (929) esp_image: segment 10: paddr=0x000a9b68 vaddr=0x50000000 size=0x00004 ( 4) load + I (971) esp_image: segment 11: paddr=0x000a9b74 vaddr=0x50000004 size=0x00000 ( 0) load + I (1012) esp_image: segment 12: paddr=0x000a9b7c vaddr=0x50000004 size=0x00000 ( 0) load + +For more details on the type of memory segments and their address ranges, see the ESP32 Technical Reference Manual, Section 1.3.2 *Embedded Memory*. + +3. The image has a single checksum byte after the last segment. This byte is written on a sixteen byte padded boundary, so the application image might need padding. +4. If the ``hash_appended`` field from :cpp:type:`esp_image_header_t` is set then a SHA256 checksum will be appended. The value of SHA256 is calculated on the range from first byte and up to this field. The length of this field is 32 bytes. +5. If the options :ref:`CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT` or :ref:`CONFIG_SECURE_BOOT_ENABLED` are enabled then the application image will have additional 68 bytes for an ECDSA signature, which includes: + + * version word (4 bytes), + * signature data (64 bytes). + +Application Description +----------------------- + +The ``DROM`` segment starts with the :cpp:type:`esp_app_desc_t` structure which carries specific fields describing the application: + + * ``secure_version`` - see :doc:`Anti-rollback`. + * ``version`` - see :doc:`App version`. ``*`` + * ``project_name`` is filled from ``PROJECT_NAME``. ``*`` + * ``time`` and ``date`` - compile time and date. + * ``idf_ver`` - version of ESP-IDF. ``*`` + * ``app_elf_sha256`` - contains sha256 for the elf application file. + +``*`` - The maximum length is 32 characters, including null-termination character. For example, if the length of ``PROJECT_NAME`` exceeds 32 characters, the excess characters will be disregarded. + +This structure is useful for identification of images uploaded OTA because it has a fixed offset = sizeof(:cpp:type:`esp_image_header_t`) + sizeof(:cpp:type:`esp_image_segment_header_t`). As soon as a device receives the first fragment containing this structure, it has all the information to determine whether the update should be continued or not. + +Adding a Custom Structure to an Application +------------------------------------------- + +Customer also has the opportunity to have similar structure with a fixed offset relative to the beginning of the image. +The following pattern can be used to add a custom structure to your image: + +:: + + const __attribute__((section(".rodata_custom_desc"))) esp_custom_app_desc_t custom_app_desc = { ... } + +Offset for custom structure is sizeof(:cpp:type:`esp_image_header_t`) + sizeof(:cpp:type:`esp_image_segment_header_t`) + sizeof(:cpp:type:`esp_app_desc_t`). + +To guarantee that the custom structure is located in the image even if it is not used, you need to add: + + * For Make: add ``COMPONENT_ADD_LDFLAGS += -u custom_app_desc`` into ``component.mk`` + * For Cmake: add ``target_link_libraries(${COMPONENT_TARGET} "-u custom_app_desc")`` into ``CMakeLists.txt`` + +API Reference +------------- + +.. include:: /_build/inc/esp_app_format.inc + + 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 969a7ce14a..24c9cb25ea 100644 --- a/docs/en/api-reference/system/freertos_additions.rst +++ b/docs/en/api-reference/system/freertos_additions.rst @@ -323,6 +323,51 @@ The following example demonstrates queue set usage with ring buffers. ... } +Ring Buffers with Static Allocation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The :cpp:func:`xRingbufferCreateStatic` can be used to create ring buffers with specific memory requirements (such as a ring buffer being allocated in external RAM). All blocks of memory used by a ring buffer must be manually allocated beforehand then passed to the :cpp:func:`xRingbufferCreateStatic` to be initialized as a ring buffer. These blocks include the following: + +- The ring buffer's data structure of type :cpp:type:`StaticRingbuffer_t` +- The ring buffer's storage area of size ``xBufferSize``. Note that ``xBufferSize`` must be 32-bit aligned for no-split/allow-split buffers. + +The manner in which these blocks are allocated will depend on the users requirements (e.g. all blocks being statically declared, or dynamically allocated with specific capabilities such as external RAM). + +.. note:: + The :ref:`CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION` option must be enabled in `menuconfig` for statically allocated ring buffers to be available. + +.. note:: + When deleting a ring buffer created via :cpp:func:`xRingbufferCreateStatic`, + the function :cpp:func:`vRingbufferDelete` will not free any of the memory blocks. This must be done manually by the user after :cpp:func:`vRingbufferDelete` is called. + +The code snippet below demonstrates a ring buffer being allocated entirely in external RAM. + +.. code-block:: c + + #include "freertos/ringbuf.h" + #include "freertos/semphr.h" + #include "esp_heap_caps.h" + + #define BUFFER_SIZE 400 //32-bit aligned size + #define BUFFER_TYPE RINGBUF_TYPE_NOSPLIT + ... + + //Allocate ring buffer data structure and storage area into external RAM + StaticRingbuffer_t *buffer_struct = (StaticRingbuffer_t *)heap_caps_malloc(sizeof(StaticRingbuffer_t), MALLOC_CAP_SPIRAM); + uint8_t *buffer_storage = (uint8_t *)heap_caps_malloc(sizeof(uint8_t)*BUFFER_SIZE, MALLOC_CAP_SPIRAM); + + //Create a ring buffer with manually allocated memory + RingbufHandle_t handle = xRingbufferCreateStatic(BUFFER_SIZE, BUFFER_TYPE, buffer_storage, buffer_struct); + + ... + + //Delete the ring buffer after used + vRingbufferDelete(handle); + + //Manually free all blocks of memory + free(buffer_struct); + free(buffer_storage); + Ring Buffer API Reference ------------------------- @@ -375,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..0c49409bbc 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. @@ -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/system/index.rst b/docs/en/api-reference/system/index.rst index 2abc62960c..8faac3a0b3 100644 --- a/docs/en/api-reference/system/index.rst +++ b/docs/en/api-reference/system/index.rst @@ -2,28 +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 - 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. diff --git a/docs/en/api-reference/system/mem_alloc.rst b/docs/en/api-reference/system/mem_alloc.rst index 7114225405..d2e5222f40 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 ^^^^^^ @@ -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 ------------------------ diff --git a/docs/en/api-reference/system/ota.rst b/docs/en/api-reference/system/ota.rst index 50938a3776..ff9251c2cc 100644 --- a/docs/en/api-reference/system/ota.rst +++ b/docs/en/api-reference/system/ota.rst @@ -188,8 +188,7 @@ Restrictions: ``security_version``: -- In application image it is stored in ``esp_app_desc`` structure. The number is set - :ref:`CONFIG_BOOTLOADER_APP_SECURE_VERSION`. +- In application image it is stored in ``esp_app_desc`` structure. The number is set :ref:`CONFIG_BOOTLOADER_APP_SECURE_VERSION`. - In ESP32 it is stored in efuse ``EFUSE_BLK3_RDATA4_REG``. (when a eFuse bit is programmed to 1, it can never be reverted to 0). The number of bits set in this register is the ``security_version`` from app. .. _secure-ota-updates: @@ -199,6 +198,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 -------- diff --git a/docs/en/api-reference/system/power_management.rst b/docs/en/api-reference/system/power_management.rst index 3ff57e21bd..a10b9b03bc 100644 --- a/docs/en/api-reference/system/power_management.rst +++ b/docs/en/api-reference/system/power_management.rst @@ -1,6 +1,8 @@ Power Management ================ +:link_to_translation:`zh_CN:[中文]` + Overview -------- @@ -125,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: diff --git a/docs/en/api-reference/system/system.rst b/docs/en/api-reference/system/system.rst index 7e5cab201c..4d72c587fe 100644 --- a/docs/en/api-reference/system/system.rst +++ b/docs/en/api-reference/system/system.rst @@ -109,21 +109,38 @@ 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. 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 ------------- .. include:: /_build/inc/esp_system.inc +.. include:: /_build/inc/esp_idf_version.inc 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/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 548fd7e257..0000000000 --- a/docs/en/cmake-pending-features.rst +++ /dev/null @@ -1,9 +0,0 @@ -.. important:: - The following features are not yet supported with the CMake-based build system: - - - Eclipse IDE Documentation - - Secure Boot - - Flash Encryption - - 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-cmake/add-idf_path-to-profile.rst b/docs/en/get-started-cmake/add-idf_path-to-profile.rst deleted file mode 100644 index 87f9ae7c8a..0000000000 --- a/docs/en/get-started-cmake/add-idf_path-to-profile.rst +++ /dev/null @@ -1,75 +0,0 @@ -Add IDF_PATH & idf.py PATH to User Profile (CMake) -================================================== - -: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`. 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/get-started-devkitc-v2.rst b/docs/en/get-started-cmake/get-started-devkitc-v2.rst deleted file mode 100644 index 977c3a455d..0000000000 --- a/docs/en/get-started-cmake/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 -------------- - -* :ref:`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-cmake: - -.. 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-cmake` 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-cmake/get-started-devkitc.rst b/docs/en/get-started-cmake/get-started-devkitc.rst deleted file mode 100644 index 2ee9835f3d..0000000000 --- a/docs/en/get-started-cmake/get-started-devkitc.rst +++ /dev/null @@ -1,152 +0,0 @@ -ESP32-DevKitC V4 Getting Started Guide (CMake) -============================================== - -: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 -------------- - -* :ref:`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: - -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-cmake: - -.. 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-cmake` 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-cmake/get-started-pico-kit-v3.rst b/docs/en/get-started-cmake/get-started-pico-kit-v3.rst deleted file mode 100644 index d93dbd692d..0000000000 --- a/docs/en/get-started-cmake/get-started-pico-kit-v3.rst +++ /dev/null @@ -1,77 +0,0 @@ -ESP32-PICO-KIT V3 Getting Started Guide (CMake) -=============================================== -: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-cmake` 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-cmake/get-started-pico-kit.rst b/docs/en/get-started-cmake/get-started-pico-kit.rst deleted file mode 100644 index 9252071362..0000000000 --- a/docs/en/get-started-cmake/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-cmake: - -.. 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-cmake`. 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-cmake: - -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-cmake` 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-cmake/get-started-wrover-kit-v2.rst b/docs/en/get-started-cmake/get-started-wrover-kit-v2.rst deleted file mode 100644 index 0324e04f1d..0000000000 --- a/docs/en/get-started-cmake/get-started-wrover-kit-v2.rst +++ /dev/null @@ -1,195 +0,0 @@ -ESP-WROVER-KIT V2 Getting Started Guide (CMake) -=============================================== -: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-cmake: - -.. 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-cmake: - -.. 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-cmake`. -================== ================================================================================================================================= - - -.. _get-started-esp-wrover-kit-v2-setup-options-cmake: - -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-cmake: - -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-cmake` 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-cmake/get-started-wrover-kit-v3.rst b/docs/en/get-started-cmake/get-started-wrover-kit-v3.rst deleted file mode 100644 index ca80c56de6..0000000000 --- a/docs/en/get-started-cmake/get-started-wrover-kit-v3.rst +++ /dev/null @@ -1,380 +0,0 @@ -ESP-WROVER-KIT V3 Getting Started Guide (CMake) -=============================================== -: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-cmake: - -.. 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-cmake: - -.. 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-cmake`. -================== ================================================================================================================================= - - -.. _get-started-esp-wrover-kit-v3-setup-options-cmake: - -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-cmake: - -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-cmake: - -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 disolder these resistors to disconnect the module's flash bus from the pin header JP13. - - -.. _get-started-esp-wrover-kit-v3-jtag-header-cmake: - -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-cmake: - -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-cmake: - -RGB LED -^^^^^^^ - -==== ========== ========= -. ESP32 Pin RGB LED -==== ========== ========= -1 GPIO0 Red -2 GPIO2 Green -3 GPIO4 Blue -==== ========== ========= - - -.. _get-started-esp-wrover-kit-v3-microsd-card-slot-cmake: - -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-cmake: - -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-cmake: - -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-cmake` 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-cmake/get-started-wrover-kit.rst b/docs/en/get-started-cmake/get-started-wrover-kit.rst deleted file mode 100644 index a1df79357f..0000000000 --- a/docs/en/get-started-cmake/get-started-wrover-kit.rst +++ /dev/null @@ -1,385 +0,0 @@ -ESP-WROVER-KIT V4.1 Getting Started Guide (CMake) -================================================= -: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-cmake: - -.. 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-cmake: - -.. 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-cmake`. -================== ================================================================================================================================= - - -.. _get-started-esp-wrover-kit-v4.1-setup-options-cmake: - -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-cmake: - -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-cmake: - -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-cmake: - -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-cmake: - -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-cmake: - -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-cmake: - -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-cmake: - -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-cmake: - -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-cmake` 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-cmake/linux-setup-scratch.rst b/docs/en/get-started-cmake/linux-setup-scratch.rst deleted file mode 100644 index a95c502842..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-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 - -.. 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``. 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`. 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 75130d71ae..0000000000 --- a/docs/en/get-started-cmake/macos-setup.rst +++ /dev/null @@ -1,92 +0,0 @@ -********************************************** -Standard Setup of Toolchain for Mac OS (CMake) -********************************************** - -:link_to_translation:`zh_CN:[中文]` - -.. include:: ../cmake-warning.rst - -Install Prerequisites -===================== - -ESP-IDF will use the version of Python installed by default on Mac OS. - -- 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 Mac OS 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``. - -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 - - -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 5c33e77f5c..0000000000 --- a/docs/en/get-started-cmake/windows-setup-scratch.rst +++ /dev/null @@ -1,93 +0,0 @@ -******************************************** -Setup Windows Toolchain 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. - -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/ - 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 fa8735aba7..0000000000 --- a/docs/en/get-started-cmake/windows-setup.rst +++ /dev/null @@ -1,73 +0,0 @@ -*********************************************** -Standard Setup of Toolchain 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 Git, a cross-compiler and the CMake build tool. We'll go over each one in this document. - -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. - -.. 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. - -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 - -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. - -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. - -Note that this installer is for the ESP-IDF Tools package, it doesn't include ESP-IDF itself. - -Installing Git -============== - -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`_. - -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. - -Using a Terminal -================ - -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. - -Next Steps -========== - -To carry on with development environment setup, proceed to :ref:`get-started-get-esp-idf-cmake`. - -Related Documents -================= - -For advanced users who want to customize the install process: - -.. 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/en/get-started-legacy/add-idf_path-to-profile.rst b/docs/en/get-started-legacy/add-idf_path-to-profile.rst new file mode 100644 index 0000000000..2745f7b0e6 --- /dev/null +++ b/docs/en/get-started-legacy/add-idf_path-to-profile.rst @@ -0,0 +1,67 @@ +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-legacy: + +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-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-legacy: + +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-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/eclipse-setup.rst b/docs/en/get-started-legacy/eclipse-setup.rst new file mode 100644 index 0000000000..087ef51e33 --- /dev/null +++ b/docs/en/get-started-legacy/eclipse-setup.rst @@ -0,0 +1,111 @@ +************************************************** +Build and Flash with Eclipse IDE (Legacy GNU Make) +************************************************** +:link_to_translation:`zh_CN:[中文]` + +.. include:: ../gnu-make-legacy.rst + +.. _eclipse-install-steps-legacy: + +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-legacy: + +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/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/establish-serial-connection.rst index a02e04c88b..83a4f933be 100644 --- a/docs/en/get-started-cmake/establish-serial-connection.rst +++ b/docs/en/get-started-legacy/establish-serial-connection.rst @@ -1,8 +1,9 @@ -Establish Serial Connection with ESP32 (CMake) -============================================== - +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. @@ -11,7 +12,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 +74,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-legacy: Adding user to ``dialout`` on Linux ----------------------------------- @@ -141,7 +138,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 +146,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-legacy` when installing s/w for ESP32 development, then go back to section :ref:`get-started-configure-legacy`. -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-cmake/index.rst b/docs/en/get-started-legacy/index.rst similarity index 54% rename from docs/en/get-started-cmake/index.rst rename to docs/en/get-started-legacy/index.rst index 5df2314f8a..c7be315a8a 100644 --- a/docs/en/get-started-cmake/index.rst +++ b/docs/en/get-started-legacy/index.rst @@ -1,16 +1,14 @@ -******************* -Get Started (CMake) -******************* +***************************** +Get Started (Legacy GNU Make) +***************************** :link_to_translation:`zh_CN:[中文]` -.. include:: ../cmake-warning.rst +.. include:: ../gnu-make-legacy.rst -.. include:: ../cmake-pending-features.rst +This document is intended to help you set up the software development environment for the hardware based on Espressif ESP32. -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. +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 @@ -40,13 +38,12 @@ Hardware: Software: -* **Toolchain** to compile code for ESP32 -* **Build tools** - CMake and Ninja to build a full **Application** for ESP32 +* **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-cmake.png +.. figure:: ../../_static/what-you-need.png :align: center :alt: Development of applications for ESP32 :figclass: align-center @@ -62,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-cmake: +.. _get-started-step-by-step-legacy: Installation Step by Step ========================= @@ -78,23 +74,22 @@ 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-esp-idf-cmake` -* :ref:`get-started-setup-path-cmake` -* :ref:`get-started-get-packages-cmake` +* :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-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: Step 1. Set up the Toolchain ============================ @@ -107,48 +102,43 @@ 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_ | `macOS`_ | ++-----------------+---------------+---------------+ .. |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: ../get-started-legacy/windows-setup.html +.. _Linux: ../get-started-legacy/linux-setup.html +.. _macOS: ../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-cmake`. +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-cmake: +.. _get-started-get-esp-idf-legacy: 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 `_. -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 -~~~~~~~~~~~~~~~ +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: @@ -158,23 +148,6 @@ 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 -~~~~~~~ - -.. 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:: @@ -185,20 +158,17 @@ Consult :doc:`/versions` for information about which ESP-IDF version to use in a git submodule update --init -.. _get-started-setup-path-cmake: +.. _get-started-setup-path-legacy: Step 3. Set Environment Variables ================================= -Set the following environment variables on your computer, so that projects can be built: +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. -- 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. - -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-cmake: +.. _get-started-get-packages-legacy: Step 4. Install the Required Python Packages ============================================ @@ -216,16 +186,16 @@ 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-cmake: +.. _get-started-start-project-legacy: 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: +Copy :example:`get-started/hello_world` to the ``~/esp`` directory: -Linux and MacOS +Linux and macOS ~~~~~~~~~~~~~~~ .. code-block:: bash @@ -249,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-cmake: +.. _get-started-connect-legacy: Step 6. Connect Your Device =========================== @@ -269,22 +239,20 @@ 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-legacy: 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-legacy` and run the project configuration utility ``menuconfig``. -Linux and MacOS +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. + make menuconfig Windows ~~~~~~~ @@ -292,13 +260,7 @@ Windows .. code-block:: batch 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`. + make menuconfig If the previous steps have been done correctly, the following menu appears: @@ -309,6 +271,8 @@ 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 @@ -319,111 +283,72 @@ 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-cmake: +.. _get-started-build-and-flash-legacy: -Step 8. Build the Project -========================= +Step 8. Build and Flash +======================= -Build the project by running:: +Build and flash the project by running:: - idf.py build + make flash -This command will compile the application and all ESP-IDF components, then it will generate the bootloader, partition table, and application binaries. +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. -.. code-block:: none +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. - $ 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' +.. highlight:: none -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 + 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 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... - -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 `. + Hard resetting... -.. _get-started-build-monitor-cmake: +If you'd like to use the Eclipse IDE instead of running ``make``, check out the :doc:`Eclipse guide `. -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). +.. _get-started-monitor-legacy: + +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:: - $ 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 --- ets Jun 8 2016 00:22:57 @@ -446,39 +371,66 @@ 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 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 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: 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:: - idf.py -p PORT flash monitor + make 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. +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-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-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. @@ -492,9 +444,10 @@ Related Documents 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 \ No newline at end of file +.. _Releases page: https://github.com/espressif/esp-idf/releases diff --git a/docs/en/get-started-legacy/linux-setup-scratch.rst b/docs/en/get-started-legacy/linux-setup-scratch.rst new file mode 100644 index 0000000000..476448a42a --- /dev/null +++ b/docs/en/get-started-legacy/linux-setup-scratch.rst @@ -0,0 +1,77 @@ +**************************************************** +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. + +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-legacy`. + +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-legacy`. diff --git a/docs/en/get-started-cmake/linux-setup.rst b/docs/en/get-started-legacy/linux-setup.rst similarity index 72% rename from docs/en/get-started-cmake/linux-setup.rst rename to docs/en/get-started-legacy/linux-setup.rst index 38766a7b7d..6eb9c20573 100644 --- a/docs/en/get-started-cmake/linux-setup.rst +++ b/docs/en/get-started-legacy/linux-setup.rst @@ -1,11 +1,10 @@ -********************************************* -Standard Setup of Toolchain for Linux (CMake) -********************************************* - +******************************************************* +Standard Setup of Toolchain for Linux (Legacy GNU Make) +******************************************************* :link_to_translation:`zh_CN:[中文]` -.. include:: ../cmake-warning.rst - +.. include:: ../gnu-make-legacy.rst + Install Prerequisites ===================== @@ -13,18 +12,19 @@ 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 + sudo yum install gcc git wget make ncurses-devel flex bison gperf python python2-cryptography - 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 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-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-pyserial python2-cryptography python2-future python2-pyparsing python2-pyelftools .. 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-legacy`. Toolchain Setup =============== @@ -51,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-cmake: +.. _setup-linux-toolchain-add-it-to-path-legacy: 2. The toolchain will be extracted into ``~/esp/xtensa-esp32-elf/`` directory. @@ -67,7 +67,7 @@ ESP32 toolchain for Linux is available for download from Espressif website: .. note:: - If you have ``/bin/bash`` set as login shell, and both ``.bash_profile`` and ``.profile`` exist, then update ``.bash_profile`` instead. + 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:: @@ -84,13 +84,13 @@ 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 ---------------- -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: @@ -105,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 :ref:`get-started-get-esp-idf-cmake`. +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-cmake/macos-setup-scratch.rst b/docs/en/get-started-legacy/macos-setup-scratch.rst similarity index 50% rename from docs/en/get-started-cmake/macos-setup-scratch.rst rename to docs/en/get-started-legacy/macos-setup-scratch.rst index dfbbc50508..f96ab3bcdc 100644 --- a/docs/en/get-started-cmake/macos-setup-scratch.rst +++ b/docs/en/get-started-legacy/macos-setup-scratch.rst @@ -1,22 +1,13 @@ -*********************************************** -Setup Toolchain for Mac OS from Scratch (CMake) -*********************************************** - +********************************************************* +Setup Toolchain for Mac OS from Scratch (Legacy GNU Make) +********************************************************* :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. +.. 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. Install Prerequisites ===================== @@ -25,32 +16,27 @@ Install Prerequisites sudo easy_install pip -- install pyserial:: +.. note:: - 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 + ``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 make + 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 make + brew install gnu-sed gawk binutils gperftools gettext wget help2man libtool autoconf automake Create a case-sensitive filesystem image:: @@ -79,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 :ref:`get-started-get-esp-idf-cmake`. +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/macos-setup.rst b/docs/en/get-started-legacy/macos-setup.rst new file mode 100644 index 0000000000..555cdda05f --- /dev/null +++ b/docs/en/get-started-legacy/macos-setup.rst @@ -0,0 +1,59 @@ +******************************************************** +Standard Setup of Toolchain for Mac OS (Legacy GNU Make) +******************************************************** +:link_to_translation:`zh_CN:[中文]` + +.. include:: ../gnu-make-legacy.rst + +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-legacy: + +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-legacy`. + + +Related Documents +================= + +.. toctree:: + :maxdepth: 1 + + macos-setup-scratch diff --git a/docs/en/get-started/make-project.rst b/docs/en/get-started-legacy/make-project.rst similarity index 95% rename from docs/en/get-started/make-project.rst rename to docs/en/get-started-legacy/make-project.rst index 8f27c89272..4a0e696806 100644 --- a/docs/en/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-cmake/toolchain-setup-scratch.rst b/docs/en/get-started-legacy/toolchain-setup-scratch.rst similarity index 70% rename from docs/en/get-started-cmake/toolchain-setup-scratch.rst rename to docs/en/get-started-legacy/toolchain-setup-scratch.rst index e96aa2fa7b..a191814315 100644 --- a/docs/en/get-started-cmake/toolchain-setup-scratch.rst +++ b/docs/en/get-started-legacy/toolchain-setup-scratch.rst @@ -1,12 +1,12 @@ -.. _get-started-customized-setup-cmake: +.. _get-started-customized-setup-legacy: -************************************* -Customized Setup of Toolchain (CMake) -************************************* +*********************************************** +Customized Setup of Toolchain (Legacy GNU Make) +*********************************************** -:link_to_translation:`zh_CN:[中文]` +Instead of downloading binary toolchain from Espressif website (see :ref:`get-started-setup-toolchain-legacy`) you may build the toolchain yourself. -Instead of downloading binary toolchain from Espressif website (see :ref:`get-started-setup-toolchain-cmake`) 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/windows-setup-scratch.rst b/docs/en/get-started-legacy/windows-setup-scratch.rst new file mode 100644 index 0000000000..6f2a291e9d --- /dev/null +++ b/docs/en/get-started-legacy/windows-setup-scratch.rst @@ -0,0 +1,119 @@ +****************************************************** +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-legacy: + +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-legacy`, 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-legacy`. + +.. _updating-existing-windows-environment-legacy: + +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/windows-setup.rst b/docs/en/get-started-legacy/windows-setup.rst new file mode 100644 index 0000000000..79597ad399 --- /dev/null +++ b/docs/en/get-started-legacy/windows-setup.rst @@ -0,0 +1,72 @@ +********************************************************* +Standard Setup of Toolchain for Windows (Legacy GNU Make) +********************************************************* +:link_to_translation:`zh_CN:[中文]` + +.. include:: ../gnu-make-legacy.rst + +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-legacy`. + +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..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,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 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..08b46fcf65 100644 --- a/docs/en/get-started/eclipse-setup.rst +++ b/docs/en/get-started/eclipse-setup.rst @@ -3,107 +3,10 @@ Build and Flash with Eclipse IDE ******************************** :link_to_translation:`zh_CN:[中文]` -.. _eclipse-install-steps: +ESP-IDF V4.0 will be released with a new CMake-based build system as the default build system. -Installing Eclipse IDE -====================== +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. -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/ +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 7e0e3a91e1..2b15682640 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 -====================================== +============================================== + :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,6 +73,10 @@ 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: @@ -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` 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 12ab81c020..713362bb72 100644 --- a/docs/en/get-started/index.rst +++ b/docs/en/get-started/index.rst @@ -1,12 +1,12 @@ -*********** +*********** 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. +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 how to build and flash firmware onto an ESP32 board. +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,7 +36,8 @@ 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 `_ @@ -57,11 +58,11 @@ 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: @@ -73,10 +74,10 @@ 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-prerequisites` 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-set-up-tools` +* :ref:`get-started-set-up-env` Creating Your First Project ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -84,25 +85,24 @@ 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-build` +* :ref:`get-started-flash` +* :ref:`get-started-build-monitor` -.. _get-started-setup-toolchain: +.. _get-started-get-prerequisites: -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| | @@ -123,21 +123,21 @@ The quickest way to start development with ESP32 is by installing a prebuilt too .. _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 build applications for the ESP32, you need the software libraries 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``. +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:: + + 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: @@ -147,43 +147,79 @@ 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-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: -.. _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-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-set-up-env: + +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-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: @@ -192,9 +228,9 @@ 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,7 +252,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: @@ -245,13 +281,15 @@ 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 +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 +297,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 +308,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 +318,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: -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: + +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`. + +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: +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,83 +445,57 @@ 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 - - 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: 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. +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. - 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`. + +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 ================= .. toctree:: :maxdepth: 1 - add-idf_path-to-profile establish-serial-connection - make-project 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/get-started/linux-setup-scratch.rst b/docs/en/get-started/linux-setup-scratch.rst index 395458153f..56e590c54a 100644 --- a/docs/en/get-started/linux-setup-scratch.rst +++ b/docs/en/get-started/linux-setup-scratch.rst @@ -1,30 +1,30 @@ -********************************** +****************************************** 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. +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 +33,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 +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``. 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 :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 7484b4c624..a9afdfc207 100644 --- a/docs/en/get-started/linux-setup.rst +++ b/docs/en/get-started/linux-setup.rst @@ -1,6 +1,7 @@ -************************************* +********************************************* Standard Setup of Toolchain for Linux -************************************* +********************************************* + :link_to_translation:`zh_CN:[中文]` Install Prerequisites @@ -10,75 +11,22 @@ 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 ------------------------------ @@ -88,7 +36,7 @@ With some Linux distributions you may get the ``Failed to open port /dev/ttyUSB0 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 +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 section :ref:`get-started-get-esp-idf`. +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 a4dfe9d7f1..faaeda54df 100644 --- a/docs/en/get-started/macos-setup-scratch.rst +++ b/docs/en/get-started/macos-setup-scratch.rst @@ -1,11 +1,20 @@ -*************************************** +*********************************************** 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. +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 +23,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 +77,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`. diff --git a/docs/en/get-started/macos-setup.rst b/docs/en/get-started/macos-setup.rst index 7e1921a6c3..caede42ece 100644 --- a/docs/en/get-started/macos-setup.rst +++ b/docs/en/get-started/macos-setup.rst @@ -1,52 +1,47 @@ -************************************** +********************************************** Standard Setup of Toolchain for Mac OS -************************************** +********************************************** + :link_to_translation:`zh_CN:[中文]` 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`. Related Documents ================= @@ -55,3 +50,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..e65233f685 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: -***************************** +************************************* Customized Setup of Toolchain -***************************** +************************************* -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`) 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..1c59b9648d 100644 --- a/docs/en/get-started/windows-setup-scratch.rst +++ b/docs/en/get-started/windows-setup-scratch.rst @@ -1,117 +1,123 @@ -************************************ +******************************************** 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. +:link_to_translation:`zh_CN:[中文]` -To quickly setup the toolchain in standard way, using a prebuilt environment, proceed to section :doc:`windows-setup`. +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`. -.. _configure-windows-toolchain-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. -Configure Toolchain & Environment from Scratch -============================================== +.. _get-esp-idf-windows-command-line: -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| +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 :ref:`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 :ref:`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 :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. + + +.. _add-directory-windows-path: + +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: 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/ -.. _MSYS2-packages issues list: https://github.com/Alexpux/MSYS2-packages/issues/ -.. _raise an IDF issue: https://github.com/espressif/esp-idf/issues/new +.. _kconfig-frontends releases page: https://github.com/espressif/kconfig-frontends/releases +.. _Stable version: https://docs.espressif.com/projects/esp-idf/en/stable/ + diff --git a/docs/en/get-started/windows-setup-update.rst b/docs/en/get-started/windows-setup-update.rst new file mode 100644 index 0000000000..a1206354d4 --- /dev/null +++ b/docs/en/get-started/windows-setup-update.rst @@ -0,0 +1,31 @@ +********************************* +Updating ESP-IDF tools on Windows +********************************* + +.. _get-started-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-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/windows-setup.rst b/docs/en/get-started/windows-setup.rst index ad7d821011..9dccad8dc5 100644 --- a/docs/en/get-started/windows-setup.rst +++ b/docs/en/get-started/windows-setup.rst @@ -1,70 +1,68 @@ -*************************************** +*********************************************** Standard Setup of Toolchain for Windows -*************************************** +*********************************************** + :link_to_translation:`zh_CN:[中文]` +.. note:: + Currently only 64-bit versions of Windows are supported. 32-bit Windows can use the :doc:`Legacy GNU Make Build System<../get-started-legacy/windows-setup>`. + 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:: + 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. -The quick setup is to download the Windows all-in-one toolchain & MSYS2 zip file from dl.espressif.com: +.. _get-started-windows-tools-installer: -https://dl.espressif.com/dl/esp32_win32_msys2_environment_and_toolchain-20181001.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`. 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/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/get-started/get-started-devkitc-v2.rst b/docs/en/hw-reference/get-started-devkitc-v2.rst similarity index 97% rename from docs/en/get-started/get-started-devkitc-v2.rst rename to docs/en/hw-reference/get-started-devkitc-v2.rst index 97d6ef6842..bef33a2780 100644 --- a/docs/en/get-started/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:[中文]` diff --git a/docs/en/get-started/get-started-devkitc.rst b/docs/en/hw-reference/get-started-devkitc.rst similarity index 100% rename from docs/en/get-started/get-started-devkitc.rst rename to docs/en/hw-reference/get-started-devkitc.rst 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/en/get-started/get-started-pico-kit-v3.rst b/docs/en/hw-reference/get-started-pico-kit-v3.rst similarity index 100% rename from docs/en/get-started/get-started-pico-kit-v3.rst rename to docs/en/hw-reference/get-started-pico-kit-v3.rst diff --git a/docs/en/get-started/get-started-pico-kit.rst b/docs/en/hw-reference/get-started-pico-kit.rst similarity index 100% rename from docs/en/get-started/get-started-pico-kit.rst rename to docs/en/hw-reference/get-started-pico-kit.rst diff --git a/docs/en/get-started/get-started-wrover-kit-v2.rst b/docs/en/hw-reference/get-started-wrover-kit-v2.rst similarity index 99% rename from docs/en/get-started/get-started-wrover-kit-v2.rst rename to docs/en/hw-reference/get-started-wrover-kit-v2.rst index 9f0b760b08..1aa0c6b595 100644 --- a/docs/en/get-started/get-started-wrover-kit-v2.rst +++ b/docs/en/hw-reference/get-started-wrover-kit-v2.rst @@ -192,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/get-started/get-started-wrover-kit-v3.rst b/docs/en/hw-reference/get-started-wrover-kit-v3.rst similarity index 99% rename from docs/en/get-started/get-started-wrover-kit-v3.rst rename to docs/en/hw-reference/get-started-wrover-kit-v3.rst index 4f290a3bf0..276c6877ba 100644 --- a/docs/en/get-started/get-started-wrover-kit-v3.rst +++ b/docs/en/hw-reference/get-started-wrover-kit-v3.rst @@ -378,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/get-started/get-started-wrover-kit.rst b/docs/en/hw-reference/get-started-wrover-kit.rst similarity index 99% rename from docs/en/get-started/get-started-wrover-kit.rst rename to docs/en/hw-reference/get-started-wrover-kit.rst index c1bd14cb0f..0be4409762 100644 --- a/docs/en/get-started/get-started-wrover-kit.rst +++ b/docs/en/hw-reference/get-started-wrover-kit.rst @@ -382,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 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 ecc9666c14..caacbc8e40 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. +:link_to_translation:`zh_CN:[中文]` -For details please refer to documentation below, provided together with description of particular boards. +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. .. 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 +=================== ============ =========== ========= ==== =============== +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 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, female 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:`../hw-reference/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:`../hw-reference/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 +- 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. + +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:`../hw-reference/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` diff --git a/docs/en/index.rst b/docs/en/index.rst index 5eb9493275..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 - Get Started (CMake Preview) API Reference H/W Reference API Guides diff --git a/docs/en/security/flash-encryption.rst b/docs/en/security/flash-encryption.rst index 136d188222..f13a27aa10 100644 --- a/docs/en/security/flash-encryption.rst +++ b/docs/en/security/flash-encryption.rst @@ -1,98 +1,505 @@ + Flash Encryption ================ -Flash Encryption is a feature for encrypting the contents of the ESP32's attached SPI flash. When flash encryption is enabled, physical readout of the SPI flash is not sufficient to recover most flash contents. +This document provides introduction to Flash encryption concept on ESP32 and demonstrates how this feature can be used during development as well as production by the user using a sample example. The primary intention of the document is to act as a quick start guide to test and verify flash encryption operations. The details of the flash encryption block can be found in the `ESP32 Technical reference manual`_. -Flash Encryption is separate from the :doc:`Secure Boot ` feature, and you can use flash encryption without enabling secure boot. However, for a secure environment both should be used simultaneously. In absence of secure boot, additional configuration needs to be performed to ensure effectiveness of flash encryption. See :ref:`flash-encryption-without-secure-boot` for more details. +.. _ESP32 Technical Reference Manual: https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf -.. important:: - Enabling flash encryption limits your options for further updates of your ESP32. Make sure to read this document (including :ref:`flash-encryption-limitations`) and understand the implications of enabling flash encryption. +Introduction +------------ -Background ----------- +Flash encryption is a feature for encrypting the contents of the ESP32's attached SPI flash. When flash encryption is enabled, physical readout of the SPI flash is not sufficient to recover most flash contents. Encryption is applied by flashing the ESP32 with plaintext data, and (if encryption is enabled) the bootloader encrypts the data in place on first boot. -- The contents of the flash are encrypted using AES-256. The flash encryption key is stored in efuse internal to the chip, and is (by default) protected from software access. - -- Flash access is transparent via the flash cache mapping feature of ESP32 - any flash regions which are mapped to the address space will be transparently decrypted when read. - -- Encryption is applied by flashing the ESP32 with plaintext data, and (if encryption is enabled) the bootloader encrypts the data in place on first boot. - -- Not all of the flash is encrypted. The following kinds of flash data are encrypted: +With flash encryption enabled, following kinds of flash data are encrypted by default: - Bootloader - - Secure boot bootloader digest (if secure boot is enabled) - Partition Table - All "app" type partitions + + Other type of flash data are encrypted conditionally: + + - Secure boot bootloader digest (if secure boot is enabled) - Any partition marked with the "encrypted" flag in the partition table - It may be desirable for some data partitions to remain unencrypted for ease of access, or to use flash-friendly update algorithms that are ineffective if the data is encrypted. NVS partitions for non-volatile storage cannot be encrypted since NVS library is not directly compatible with flash encryption. Refer to :ref:`NVS Encryption ` for more details. +Flash encryption is separate from the :doc:`Secure Boot ` feature, and you can use flash encryption without enabling secure boot. However, for a secure environment both should be used simultaneously. In absence of secure boot, additional configuration needs to be performed to ensure effectiveness of flash encryption. See :ref:`flash-encryption-without-secure-boot` for more details. -- The flash encryption key is stored in efuse key block 1, internal to the ESP32 chip. By default, this key is read- and write-protected so software cannot access it or change it. +.. important:: + Enabling flash encryption limits the options for further updates of the ESP32. Make sure to read this document (including :ref:`flash-encryption-limitations`) and understand the implications of enabling flash encryption. -- By default, the Efuse Block 1 Coding Scheme is "None" and a 256 bit key is stored in this block. On some ESP32s, the Coding Scheme is set to 3/4 Encoding (CODING_SCHEME efuse has value 1) and a 192 bit key must be stored in this block. See ESP32 Technical Reference Manual section 20.3.1.3 *System Parameter coding_scheme* for more details. The algorithm operates on a 256 bit key in all cases, 192 bit keys are extended by repeating some bits (:ref:`details `). The coding scheme is shown in the ``Features`` line when ``esptool.py`` connects to the chip, or in the ``espefuse.py summary`` output. +.. _flash-encryption-efuse: + +eFuse Used During Flash Encryption Process +------------------------------------------- +The flash encryption operation is controlled by various eFuses available on ESP32. Below is the list of eFuse and their description: + + :: + + eFuse Description Can be locked for Default + reading/writing Value + + .. code-block:: none + + Coding scheme This 2 bit wide eFuse controls the Yes 0 + actual number of bits to be used + from BLOCK1 to derive final 256 bit + AES key. The coding scheme value is + decoded as below: + 0: 256 bits + 1: 192 bits + 2: 128 bits + Final AES key is derived based on the + FLASH_CRYPT_CONFIG value + + BLOCK1 256 bit wide eFuse block for storing Yes x + AES key + + FLASH_CRYPT_CONFIG 4 bit wide eFuse which controls the Yes 0xF + AES encryption process + + download_dis_encrypt When set, disables the flash encryption Yes 0 + operation while running in UART + download mode + + download_dis_decrypt When set, disables the flash decryption Yes 0 + operation while running in UART + download mode + + FLASH_CRYPT_CNT 7 bit eFuse which enables/disables Yes 0 + encryption at boot time + + Even number of bits set (0, 2, 4, 6): + 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>`. + + +Flash Encryption Process +------------------------ + +Assuming the eFuse values are in default state and second stage bootloader is compiled to support flash encryption, the flash encryption process executes as below: + +- On first power-on reset, all data in flash is un-encrypted (plaintext). First stage loader (ROM) will load the second stage loader in IRAM. +- Second stage bootloader will read the flash_crypt_cnt (=00000000b) eFuse value and since the value is 0 (even number of bits set) it will configure and enable the flash encryption block. It will also program ``FLASH_CRYPT_CFG`` eFuse to value 0xF. +- The flash encryption block will generate AES-256 bit key and store into BLOCK1 eFuse. This operation is performed in hardware and the key can not be accessed by software. +- Next the flash encryption block will encrypt the flash contents (based on partition table flag value). Encrypting in-place can take some time (up to a minute for large partitions). +- Second stage bootloader then sets the first available bit in flash_crypt_cnt (=00000001b) to mark the flash contents as encrypted (odd number of bits set). +- For :ref:`flash_enc_release_mode` second stage bootloader will program ``download_dis_encrypt``, ``download_dis_decrypt`` & ``download_dis_cache`` eFuse bits to 1 to prevent UART bootloader from decrypting the flash contents. It will also write protect the ``FLASH_CRYPT_CNT`` eFuse bits. +- For :ref:`flash_enc_development_mode` second stage bootloader will program only ``download_dis_decrypt`` & ``download_dis_cache`` eFuse bits to allow UART bootloader reflashing of encrypted binaries. Also ``FLASH_CRYPT_CNT`` eFuse bits will NOT be write protected. +- The second stage bootloader then reboots the device to start executing encrypted image. It will transparently decrypt the flash contents and load into IRAM. + +During development stage there is a frequent need to program different plaintext flash images and test the flash encryption process. This requires UART download mode to be able to load new plaintext images as many number of times as required. However during manufacturing or production UART download mode should not be allowed to access flash contents due to security reason. Hence this requires two different ESP32 configurations: one for development and other for production. Following section describes :ref:`flash_enc_development_mode` and :ref:`flash_enc_release_mode` for flash encryption and a step by step process to use them. + +.. important:: + Development mode as the name suggests should be used ONLY DURING DEVELOPMENT as it does not prevent modification and possible read back of encrypted flash contents. + + +Steps to Setup Flash Encryption +------------------------------- + +.. _flash_enc_development_mode: + +Development Mode +^^^^^^^^^^^^^^^^ + +It is possible to run flash encryption process for development using either ESP32 internally generated key or external host generated keys. + +Using ESP32 Generated Flash Encryption Key +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +As mentioned above :ref:`flash_enc_development_mode` allows user to download as many plaintext images using UART download mode. Following steps needs to be done to test flash encryption process: + +- Ensure you have a ESP32 device with default flash encryption eFuse settings as shown in :ref:`flash-encryption-efuse`. + +- 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 :ref:`project-configuration-menu`, navigate to "Security Features". + +- Select :ref:`Enable flash encryption on boot `. + +- By default the mode is set for **Development**. + +- Select appropriate Bootloader log verbosity under Bootloader config. + +- Update to the partition table offset may be required since after enabling flash encryption the size of bootloader is increased. See :ref:`secure-boot-bootloader-size` + +- Save the configuration and exit. + +Build and flash the complete image including: bootloader, partition table and app. These partitions are initially written to the flash unencrypted. + + :: + + 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. + + :: + + --- idf_monitor on /dev/cu.SLAB_USBtoUART 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) + configsip: 0, SPIWP:0xee + clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 + mode:DIO, clock div:2 + load:0x3fff0018,len:4 + load:0x3fff001c,len:8452 + load:0x40078000,len:13608 + load:0x40080400,len:6664 + entry 0x40080764 + I (28) boot: ESP-IDF v4.0-dev-850-gc4447462d-dirty 2nd stage bootloader + I (29) boot: compile time 15:37:14 + I (30) boot: Enabling RNG early entropy source... + I (35) boot: SPI Speed : 40MHz + I (39) boot: SPI Mode : DIO + I (43) boot: SPI Flash Size : 4MB + I (47) boot: Partition Table: + I (51) boot: ## Label Usage Type ST Offset Length + I (58) boot: 0 nvs WiFi data 01 02 0000a000 00006000 + I (66) boot: 1 phy_init RF data 01 01 00010000 00001000 + I (73) boot: 2 factory factory app 00 00 00020000 00100000 + I (81) boot: End of partition table + I (85) esp_image: segment 0: paddr=0x00020020 vaddr=0x3f400020 size=0x0808c ( 32908) map + I (105) esp_image: segment 1: paddr=0x000280b4 vaddr=0x3ffb0000 size=0x01ea4 ( 7844) load + I (109) esp_image: segment 2: paddr=0x00029f60 vaddr=0x40080000 size=0x00400 ( 1024) load + 0x40080000: _WindowOverflow4 at esp-idf/esp-idf/components/freertos/xtensa_vectors.S:1778 + + I (114) esp_image: segment 3: paddr=0x0002a368 vaddr=0x40080400 size=0x05ca8 ( 23720) load + I (132) esp_image: segment 4: paddr=0x00030018 vaddr=0x400d0018 size=0x126a8 ( 75432) map + 0x400d0018: _flash_cache_start at ??:? + + I (159) esp_image: segment 5: paddr=0x000426c8 vaddr=0x400860a8 size=0x01f4c ( 8012) load + 0x400860a8: prvAddNewTaskToReadyList at esp-idf/esp-idf/components/freertos/tasks.c:4561 + + I (168) boot: Loaded app from partition at offset 0x20000 + I (168) boot: Checking flash encryption... + I (168) flash_encrypt: Generating new flash encryption key... + I (187) flash_encrypt: Read & write protecting new key... + I (187) flash_encrypt: Setting CRYPT_CONFIG efuse to 0xF + W (188) flash_encrypt: Not disabling UART bootloader encryption + I (195) flash_encrypt: Disable UART bootloader decryption... + I (201) flash_encrypt: Disable UART bootloader MMU cache... + I (208) flash_encrypt: Disable JTAG... + I (212) flash_encrypt: Disable ROM BASIC interpreter fallback... + I (219) esp_image: segment 0: paddr=0x00001020 vaddr=0x3fff0018 size=0x00004 ( 4) + I (227) esp_image: segment 1: paddr=0x0000102c vaddr=0x3fff001c size=0x02104 ( 8452) + I (239) esp_image: segment 2: paddr=0x00003138 vaddr=0x40078000 size=0x03528 ( 13608) + I (249) esp_image: segment 3: paddr=0x00006668 vaddr=0x40080400 size=0x01a08 ( 6664) + I (657) esp_image: segment 0: paddr=0x00020020 vaddr=0x3f400020 size=0x0808c ( 32908) map + I (669) esp_image: segment 1: paddr=0x000280b4 vaddr=0x3ffb0000 size=0x01ea4 ( 7844) + I (672) esp_image: segment 2: paddr=0x00029f60 vaddr=0x40080000 size=0x00400 ( 1024) + 0x40080000: _WindowOverflow4 at esp-idf/esp-idf/components/freertos/xtensa_vectors.S:1778 + + I (676) esp_image: segment 3: paddr=0x0002a368 vaddr=0x40080400 size=0x05ca8 ( 23720) + I (692) esp_image: segment 4: paddr=0x00030018 vaddr=0x400d0018 size=0x126a8 ( 75432) map + 0x400d0018: _flash_cache_start at ??:? + + I (719) esp_image: segment 5: paddr=0x000426c8 vaddr=0x400860a8 size=0x01f4c ( 8012) + 0x400860a8: prvAddNewTaskToReadyList at esp-idf/esp-idf/components/freertos/tasks.c:4561 + + I (722) flash_encrypt: Encrypting partition 2 at offset 0x20000... + I (13229) flash_encrypt: Flash encryption completed + I (13229) boot: Resetting with flash encryption enabled... + + + Once the flash encryption is enabled, on subsequent boot the output would mention that flash encryption is already enabled. + + :: + + rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) + configsip: 0, SPIWP:0xee + clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 + mode:DIO, clock div:2 + load:0x3fff0018,len:4 + load:0x3fff001c,len:8452 + load:0x40078000,len:13652 + ho 0 tail 12 room 4 + load:0x40080400,len:6664 + entry 0x40080764 + I (30) boot: ESP-IDF v4.0-dev-850-gc4447462d-dirty 2nd stage bootloader + I (30) boot: compile time 16:32:53 + I (31) boot: Enabling RNG early entropy source... + I (37) boot: SPI Speed : 40MHz + I (41) boot: SPI Mode : DIO + I (45) boot: SPI Flash Size : 4MB + I (49) boot: Partition Table: + I (52) boot: ## Label Usage Type ST Offset Length + I (60) boot: 0 nvs WiFi data 01 02 0000a000 00006000 + I (67) boot: 1 phy_init RF data 01 01 00010000 00001000 + I (75) boot: 2 factory factory app 00 00 00020000 00100000 + I (82) boot: End of partition table + I (86) esp_image: segment 0: paddr=0x00020020 vaddr=0x3f400020 size=0x0808c ( 32908) map + I (107) esp_image: segment 1: paddr=0x000280b4 vaddr=0x3ffb0000 size=0x01ea4 ( 7844) load + I (111) esp_image: segment 2: paddr=0x00029f60 vaddr=0x40080000 size=0x00400 ( 1024) load + 0x40080000: _WindowOverflow4 at esp-idf/esp-idf/components/freertos/xtensa_vectors.S:1778 + + I (116) esp_image: segment 3: paddr=0x0002a368 vaddr=0x40080400 size=0x05ca8 ( 23720) load + I (134) esp_image: segment 4: paddr=0x00030018 vaddr=0x400d0018 size=0x126a8 ( 75432) map + 0x400d0018: _flash_cache_start at ??:? + + I (162) esp_image: segment 5: paddr=0x000426c8 vaddr=0x400860a8 size=0x01f4c ( 8012) load + 0x400860a8: prvAddNewTaskToReadyList at esp-idf/esp-idf/components/freertos/tasks.c:4561 + + I (171) boot: Loaded app from partition at offset 0x20000 + I (171) boot: Checking flash encryption... + I (171) flash_encrypt: flash encryption is enabled (3 plaintext flashes left) + I (178) boot: Disabling RNG early entropy source... + I (184) cpu_start: Pro cpu up. + I (188) cpu_start: Application information: + I (193) cpu_start: Project name: flash-encryption + I (198) cpu_start: App version: v4.0-dev-850-gc4447462d-dirty + I (205) cpu_start: Compile time: Jun 17 2019 16:32:52 + I (211) cpu_start: ELF file SHA256: 8770c886bdf561a7... + I (217) cpu_start: ESP-IDF: v4.0-dev-850-gc4447462d-dirty + I (224) cpu_start: Starting app cpu, entry point is 0x40080e4c + 0x40080e4c: call_start_cpu1 at esp-idf/esp-idf/components/esp32/cpu_start.c:265 + + I (0) cpu_start: App cpu up. + I (235) heap_init: Initializing. RAM available for dynamic allocation: + I (241) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM + I (247) heap_init: At 3FFB2EC8 len 0002D138 (180 KiB): DRAM + I (254) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM + I (260) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM + I (266) heap_init: At 40087FF4 len 0001800C (96 KiB): IRAM + I (273) cpu_start: Pro cpu start user code + I (291) cpu_start: Starting scheduler on PRO CPU. + I (0) cpu_start: Starting scheduler on APP CPU. + + Sample program to check Flash Encryption + This is ESP32 chip with 2 CPU cores, WiFi/BT/BLE, silicon revision 1, 4MB external flash + Flash encryption feature is enabled + Flash encryption mode is DEVELOPMENT + Flash in encrypted mode with flash_crypt_cnt = 1 + Halting... + + +At this stage if user wants to update modified plaintext application image to flash in encrypted format it can be done using following command: + + :: + + idf.py encrypted-app-flash monitor + +.. _encrypt_partitions: + +Encrypt Multiple Partitions +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If all partitions needs to be updated in encrypted format, it can be done as + + :: + + idf.py encrypted-flash monitor + +.. _pregenerated-flash-encryption-key: + +Using Host Generated Flash Encryption Key +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +It is possible to pregenerate the flash encryption key on the host computer and burn it into the ESP32's eFuse key block. This allows data to be pre-encrypted on the host and flashed to the ESP32 without needing a plaintext flash update. This feature allows encrypted flashing in both :ref:`flash_enc_development_mode` and :ref:`flash_enc_release_mode` modes. + +- Ensure you have a ESP32 device with default flash encryption eFuse settings as shown in :ref:`flash-encryption-efuse`. + +- Generate a random key with espsecure.py:: + + espsecure.py generate_flash_encryption_key my_flash_encryption_key.bin + +- Burn the key to the device (one time only). **This must be done before first encrypted boot**, otherwise the ESP32 will generate a random key that software can't access or modify:: + + espefuse.py --port PORT burn_key flash_encryption my_flash_encryption_key.bin + +- Enable flash encryption support in second stage bootloader. In :ref:`project-configuration-menu`, navigate to "Security Features". + +- Select :ref:`Enable flash encryption on boot `. + +- By default the mode is set for **Development**. + +- Select appropriate Bootloader log verbosity under Bootloader config. + +- Update to the partition table offset may be required since after enabling flash encryption the size of bootloader is increased. See :ref:`secure-boot-bootloader-size` + +- Save the configuration and exit. + + +Build and flash the complete image including: bootloader, partition table and app. These partitions are initially written to the flash unencrypted + + :: + + 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. + +At this stage if user wants to update new plaintext application image to flash they should issue following command + + :: + + idf.py encrypted-app-flash monitor + +For reprogramming all partitions in encrypted format follow :ref:`encrypt_partitions`. + + +.. _flash_enc_release_mode: + +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 :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**. + +- Select appropriate Bootloader log verbosity under Bootloader config. + +- Update to the partition table offset may be required since after enabling flash encryption the size of bootloader is increased. See :ref:`secure-boot-bootloader-size` + +- Save the configuration and exit. + +Build and flash the complete image including: bootloader, partition table and app. These partitions are initially written to the flash unencrypted + + :: + + 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. + +Once the flash encryption is enabled in Release mode the bootloader will write protect the ``FLASH_CRYPT_CNT`` eFuse. + +For subsequent plaintext update in field OTA scheme should be used. Please refer :doc:`OTA <../api-reference/system/ota>` for further details. + +Possible Failures +^^^^^^^^^^^^^^^^^ +Once the flash encryption is enabled and if the ``FLASH_CRYPT_CNT`` eFuse value has odd number of bits set then all the partitions (which are marked with encryption flag) are expected to contain encrypted ciphertext. Below are three typical failure cases if the ESP32 is loaded with plaintext data: + +1. In case the bootloader partition is re-updated with plaintext bootloader image the ROM loader will fail to load the bootloader and following type of failure will be displayed: + + :: + + rst:0x3 (SW_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) + flash read err, 1000 + ets_main.c 371 + ets Jun 8 2016 00:22:57 + + rst:0x7 (TG0WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) + flash read err, 1000 + ets_main.c 371 + ets Jun 8 2016 00:22:57 + + rst:0x7 (TG0WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) + flash read err, 1000 + ets_main.c 371 + ets Jun 8 2016 00:22:57 + + rst:0x7 (TG0WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) + flash read err, 1000 + ets_main.c 371 + ets Jun 8 2016 00:22:57 + + rst:0x7 (TG0WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) + flash read err, 1000 + ets_main.c 371 + ets Jun 8 2016 00:22:57 + +2. In case the bootloader is encrypted but partition table is re-updated with plaintext partition table image the bootloader will fail to read the partition table and following type of failure will be displayed: + + :: + + rst:0x3 (SW_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) + configsip: 0, SPIWP:0xee + clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 + mode:DIO, clock div:2 + load:0x3fff0018,len:4 + load:0x3fff001c,len:10464 + ho 0 tail 12 room 4 + load:0x40078000,len:19168 + load:0x40080400,len:6664 + entry 0x40080764 + I (60) boot: ESP-IDF v4.0-dev-763-g2c55fae6c-dirty 2nd stage bootloader + I (60) boot: compile time 19:15:54 + I (62) boot: Enabling RNG early entropy source... + I (67) boot: SPI Speed : 40MHz + I (72) boot: SPI Mode : DIO + I (76) boot: SPI Flash Size : 4MB + E (80) flash_parts: partition 0 invalid magic number 0x94f6 + E (86) boot: Failed to verify partition table + E (91) boot: load partition table error! + +3. In case the bootloader & partition table are encrypted but application is re-updated with plaintext application image the bootloader will fail load the new application and following type of failure will be displayed: + + :: + + rst:0x3 (SW_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) + configsip: 0, SPIWP:0xee + clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 + mode:DIO, clock div:2 + load:0x3fff0018,len:4 + load:0x3fff001c,len:8452 + load:0x40078000,len:13616 + load:0x40080400,len:6664 + entry 0x40080764 + I (56) boot: ESP-IDF v4.0-dev-850-gc4447462d-dirty 2nd stage bootloader + I (56) boot: compile time 15:37:14 + I (58) boot: Enabling RNG early entropy source... + I (64) boot: SPI Speed : 40MHz + I (68) boot: SPI Mode : DIO + I (72) boot: SPI Flash Size : 4MB + I (76) boot: Partition Table: + I (79) boot: ## Label Usage Type ST Offset Length + I (87) boot: 0 nvs WiFi data 01 02 0000a000 00006000 + I (94) boot: 1 phy_init RF data 01 01 00010000 00001000 + I (102) boot: 2 factory factory app 00 00 00020000 00100000 + I (109) boot: End of partition table + E (113) esp_image: image at 0x20000 has invalid magic byte + W (120) esp_image: image at 0x20000 has invalid SPI mode 108 + W (126) esp_image: image at 0x20000 has invalid SPI size 11 + E (132) boot: Factory app partition is not bootable + E (138) boot: No bootable app partitions in the partition table + +Key Points About Flash Encryption +--------------------------------- + +- The contents of the flash are encrypted using AES-256. The flash encryption key is stored in eFuse internal to the chip, and is (by default) protected from software access. - The `flash encryption algorithm` is AES-256, where the key is "tweaked" with the offset address of each 32 byte block of flash. This means every 32 byte block (two consecutive 16 byte AES blocks) is encrypted with a unique key derived from the flash encryption key. -- Although software running on the chip can transparently decrypt flash contents, by default it is made impossible for the UART bootloader to decrypt (or encrypt) data when flash encryption is enabled. +- Flash access is transparent via the flash cache mapping feature of ESP32 - any flash regions which are mapped to the address space will be transparently decrypted when read. + + It may be desirable for some data partitions to remain unencrypted for ease of access, or to use flash-friendly update algorithms that are ineffective if the data is encrypted. NVS partitions for non-volatile storage cannot be encrypted since NVS library is not directly compatible with flash encryption. Refer to :ref:`NVS Encryption ` for more details. + - If flash encryption may be enabled, the programmer must take certain precautions when writing code that :ref:`uses encrypted flash `. -.. _flash-encryption-initialisation: - -Flash Encryption Initialisation -------------------------------- - -This is the default (and recommended) flash encryption initialisation process. It is possible to customise this process for development or other purposes, see :ref:`flash-encryption-advanced-features` for details. - -.. important:: - Once flash encryption is enabled on first boot, the hardware allows a maximum of 3 subsequent flash updates via serial re-flashing. A special procedure (documented in :ref:`updating-encrypted-flash-serial`) must be followed to perform these updates. - -- If secure boot is enabled, physical reflashing with plaintext data requires a "Reflashable" secure boot digest (see :ref:`flash-encryption-and-secure-boot`). -- OTA updates can be used to update flash content without counting towards this limit. -- When enabling flash encryption in development, use a `pregenerated flash encryption key` to allow physically re-flashing an unlimited number of times with pre-encrypted data.** - -Process to enable flash encryption: - -- The bootloader must be compiled with flash encryption support enabled. In ``make menuconfig``, navigate to "Security Features" and select "Yes" for "Enable flash encryption on boot". - -- If enabling Secure Boot at the same time, it is best to simultaneously select those options now. Read the :doc:`Secure Boot ` documentation first. - -- Build and flash the bootloader, partition table and factory app image as normal. These partitions are initially written to the flash unencrypted. +- If secure boot is enabled, reflashing the bootloader of an encrypted device requires a "Reflashable" secure boot digest (see :ref:`flash-encryption-and-secure-boot`). .. note:: The bootloader app binary ``bootloader.bin`` may become too large when both secure boot and flash encryption are enabled. See :ref:`secure-boot-bootloader-size`. -- On first boot, the bootloader sees :ref:`FLASH_CRYPT_CNT` is set to 0 (factory default) so it generates a flash encryption key using the hardware random number generator. This key is stored in efuse. The key is read and write protected against further software access. - -- All of the encrypted partitions are then encrypted in-place by the bootloader. Encrypting in-place can take some time (up to a minute for large partitions.) - .. important:: Do not interrupt power to the ESP32 while the first boot encryption pass is running. If power is interrupted, the flash contents will be corrupted and require flashing with unencrypted data again. A reflash like this will not count towards the flashing limit. -- Once flashing is complete. efuses are blown (by default) to disable encrypted flash access while the UART bootloader is running. See :ref:`uart-bootloader-encryption` for advanced details. - -- The ``FLASH_CRYPT_CONFIG`` efuse is also burned to the maximum value (``0xF``) to maximise the number of key bits which are tweaked in the flash algorithm. See :ref:`setting-flash-crypt-config` for advanced details. - -- Finally, the :ref:`FLASH_CRYPT_CNT` is burned with the initial value 1. It is this efuse which activates the transparent flash encryption layer, and limits the number of subsequent reflashes. See the :ref:`updating-encrypted-flash` section for details about :ref:`FLASH_CRYPT_CNT`. - -- The bootloader resets itself to reboot from the newly encrypted flash. .. _using-encrypted-flash: Using Encrypted Flash --------------------- -ESP32 app code can check if flash encryption is currently enabled by calling :func:`esp_flash_encryption_enabled`. +ESP32 app code can check if flash encryption is currently enabled by calling :cpp:func:`esp_flash_encryption_enabled`. Also, device can identify the flash encryption mode by calling :cpp:func:`esp_get_flash_encryption_mode`. Once flash encryption is enabled, some care needs to be taken when accessing flash contents from code. Scope of Flash Encryption ^^^^^^^^^^^^^^^^^^^^^^^^^ -Whenever the :ref:`FLASH_CRYPT_CNT` is set to a value with an odd number of bits set, all flash content which is accessed via the MMU's flash cache is transparently decrypted. This includes: +Whenever the ``FLASH_CRYPT_CNT`` eFuse is set to a value with an odd number of bits set, all flash content which is accessed via the MMU's flash cache is transparently decrypted. This includes: - Executable application code in flash (IROM). - All read-only data stored in flash (DROM). -- Any data accessed via :func:`esp_spi_flash_mmap`. +- Any data accessed via :cpp:func:`spi_flash_mmap`. - The software bootloader image when it is read by the ROM bootloader. .. important:: @@ -100,13 +507,13 @@ Whenever the :ref:`FLASH_CRYPT_CNT` is set to a value with an odd number of bits Reading Encrypted Flash ^^^^^^^^^^^^^^^^^^^^^^^ -To read data without using a flash cache MMU mapping, we recommend using the partition read function :func:`esp_partition_read`. When using this function, data will only be decrypted when it is read from an encrypted partition. Other partitions will be read unencrypted. In this way, software can access encrypted and non-encrypted flash in the same way. +To read data without using a flash cache MMU mapping, we recommend using the partition read function :cpp:func:`esp_partition_read`. When using this function, data will only be decrypted when it is read from an encrypted partition. Other partitions will be read unencrypted. In this way, software can access encrypted and non-encrypted flash in the same way. Data which is read via other SPI read APIs are not decrypted: -- Data read via :func:`esp_spi_flash_read` is not decrypted -- Data read via ROM function :func:`SPIRead` is not decrypted (this function is not supported in esp-idf apps). -- Data stored using the Non-Volatile Storage (NVS) API is always stored and read decrypted from the perspective of Flash Encryption. It is up to the library to provide encryption feature if required. Refer to :ref:`NVS Encryption ` for more details. +- Data read via :cpp:func:`spi_flash_read` is not decrypted. +- Data read via ROM function :cpp:func:`SPIRead` is not decrypted (this function is not supported in esp-idf apps). +- Data stored using the Non-Volatile Storage (NVS) API is always stored and read decrypted from the perspective of flash encryption. It is up to the library to provide encryption feature if required. Refer to :ref:`NVS Encryption ` for more details. Writing Encrypted Flash @@ -118,7 +525,7 @@ The ``esp_spi_flash_write`` function will write data when the write_encrypted pa The ROM function ``esp_rom_spiflash_write_encrypted`` will write encrypted data to flash, the ROM function ``SPIWrite`` will write unencrypted to flash. (these function are not supported in esp-idf apps). -The minimum write size for unencrypted data is 4 bytes (and the alignment is 4 bytes). Because data is encrypted in blocks, the minimum write size for encrypted data is 16 bytes (and the alignment is 16 bytes.) +Because data is encrypted in blocks, the minimum write size for encrypted data is 16 bytes (and the alignment is 16 bytes). .. _updating-encrypted-flash: @@ -134,130 +541,19 @@ OTA updates to encrypted partitions will automatically write encrypted, as long .. _updating-encrypted-flash-serial: -Serial Flashing -^^^^^^^^^^^^^^^ - -The :ref:`FLASH_CRYPT_CNT` allows the flash to be updated with new plaintext data via serial flashing (or other physical methods), up to 3 additional times. - -The process involves flashing plaintext data, and then bumping the value of :ref:`FLASH_CRYPT_CNT` which causes the bootloader to re-encrypt this data. - -Limited Updates -~~~~~~~~~~~~~~~ - -Only 4 plaintext serial update cycles of this kind are possible, including the initial encrypted flash. - -After the fourth time encryption is enabled, :ref:`FLASH_CRYPT_CNT` has the maximum value ``0x7F`` (7 bits set) and encryption is permanently enabled. - -Using :ref:`updating-encrypted-flash-ota` or :ref:`pregenerated-flash-encryption-key` allows you to exceed this limit. - -Cautions With Serial Flashing -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- When reflashing via serial, reflash every partition that was initially written with plaintext data (including bootloader). It is possible to skip app partitions which are not the "currently selected" OTA partition (these will not be re-encrypted unless a plaintext app image is found there.) However any partition marked with the "encrypt" flag will be unconditionally re-encrypted, meaning that any already encrypted data will be encrypted twice and corrupted. - - - Using ``make flash`` should flash all partitions which need to be flashed. - -- If secure boot is enabled, you can't reflash plaintext data via serial at all unless you used the "Reflashable" option for Secure Boot. See :ref:`flash-encryption-and-secure-boot`. - -Serial Re-Flashing Procedure -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- Build the application as usual. - -- Flash the device with plaintext data as usual (``make flash`` or ``esptool.py`` commands.) Flash all previously encrypted partitions, including the bootloader (see previous section). - -- At this point, the device will fail to boot (message is ``flash read err, 1000``) because it expects to see an encrypted bootloader, but the bootloader is plaintext. - -- Burn the :ref:`FLASH_CRYPT_CNT` by running the command ``espefuse.py burn_efuse FLASH_CRYPT_CNT``. espefuse.py will automatically increment the bit count by 1, which disables encryption. - -- Reset the device and it will re-encrypt plaintext partitions, then burn the :ref:`FLASH_CRYPT_CNT` again to re-enable encryption. - - -Disabling Serial Updates -~~~~~~~~~~~~~~~~~~~~~~~~ - -To prevent further plaintext updates via serial, use espefuse.py to write protect the :ref:`FLASH_CRYPT_CNT` after flash encryption has been enabled (ie after first boot is complete):: - - espefuse.py --port PORT write_protect_efuse FLASH_CRYPT_CNT - -This prevents any further modifications to disable or re-enable flash encryption. - -.. _pregenerated-flash-encryption-key: - -Reflashing via Pregenerated Flash Encryption Key -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -It is possible to pregenerate a flash encryption key on the host computer and burn it into the ESP32's efuse key block. This allows data to be pre-encrypted on the host and flashed to the ESP32 without needing a plaintext flash update. - -This is useful for development, because it removes the 4 time reflashing limit. It also allows reflashing the app with secure boot enabled, because the bootloader doesn't need to be reflashed each time. - -.. important:: - This method is intended to assist with development only, not for production devices. If pre-generating flash encryption for production, ensure the keys are generated from a high quality random number source and do not share the same flash encryption key across multiple devices. - -Pregenerating a Flash Encryption Key -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Flash encryption keys are 32 bytes of random data. You can generate a random key with espsecure.py:: - - espsecure.py generate_flash_encryption_key my_flash_encryption_key.bin - -(The randomness of this data is only as good as the OS and it's Python installation's random data source.) - -Alternatively, if you're using :doc:`secure boot ` and have a :ref:`secure boot signing key ` then you can generate a deterministic SHA-256 digest of the secure boot private signing key and use this as the flash encryption key:: - - espsecure.py digest_private_key --keyfile secure_boot_signing_key.pem --keylen 256 my_flash_encryption_key.bin - -(The same 32 bytes is used as the secure boot digest key if you enable :ref:`reflashable mode` for secure boot.) - -Generating the flash encryption key from the secure boot signing key in this way means that you only need to store one key file. However this method is **not at all suitable** for production devices. - -Burning Flash Encryption Key -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Once you have generated a flash encryption key, you need to burn it to the ESP32's efuse key block. **This must be done before first encrypted boot**, otherwise the ESP32 will generate a random key that software can't access or modify. - -To burn a key to the device (one time only):: - - espefuse.py --port PORT burn_key flash_encryption my_flash_encryption_key.bin - -First Flash with pregenerated key -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -After flashing the key, follow the same steps as for default :ref:`flash-encryption-initialisation` and flash a plaintext image for the first boot. The bootloader will enable flash encryption using the pre-burned key and encrypt all partitions. - -Reflashing with pregenerated key -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -After encryption is enabled on first boot, reflashing an encrypted image requires an additional manual step. This is where we pre-encrypt the data that we wish to update in flash. - -Suppose that this is the normal command used to flash plaintext data:: - - esptool.py --port /dev/ttyUSB0 --baud 115200 write_flash 0x10000 build/my-app.bin - -Binary app image ``build/my-app.bin`` is written to offset ``0x10000``. This file name and offset need to be used to encrypt the data, as follows:: - - espsecure.py encrypt_flash_data --keyfile my_flash_encryption_key.bin --address 0x10000 -o build/my-app-encrypted.bin build/my-app.bin - -This example command will encrypts ``my-app.bin`` using the supplied key, and produce an encrypted file ``my-app-encrypted.bin``. Be sure that the address argument matches the address where you plan to flash the binary. - -Then, flash the encrypted binary with esptool.py:: - - esptool.py --port /dev/ttyUSB0 --baud 115200 write_flash 0x10000 build/my-app-encrypted.bin - -No further steps or efuse manipulation is necessary, because the data is already encrypted when we flash it. Disabling Flash Encryption -------------------------- -If you've accidentally enabled flash encryption for some reason, the next flash of plaintext data will soft-brick the ESP32 (the device will reboot continously, printing the error ``flash read err, 1000``). +If you've accidentally enabled flash encryption for some reason, the next flash of plaintext data will soft-brick the ESP32 (the device will reboot continuously, printing the error ``flash read err, 1000``). -You can disable flash encryption again by writing :ref:`FLASH_CRYPT_CNT`: +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 ``espefuse.py`` (in ``components/esptool_py/esptool``) to disable the :ref:`FLASH_CRYPT_CNT`):: +- 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. @@ -267,13 +563,13 @@ Reset the ESP32 and flash encryption should be disabled, the bootloader will boo Limitations of Flash Encryption ------------------------------- -Flash Encryption prevents plaintext readout of the encrypted flash, to protect firmware against unauthorised readout and modification. It is important to understand the limitations of the flash encryption system: +Flash encryption prevents plaintext readout of the encrypted flash, to protect firmware against unauthorised readout and modification. It is important to understand the limitations of the flash encryption system: -- Flash encryption is only as strong as the key. For this reason, we recommend keys are generated on the device during first boot (default behaviour). If generating keys off-device (see :ref:`pregenerated-flash-encryption-key`), ensure proper procedure is followed. +- Flash encryption is only as strong as the key. For this reason, we recommend keys are generated on the device during first boot (default behaviour). If generating keys off-device, ensure proper procedure is followed. - Not all data is stored encrypted. If storing data on flash, check if the method you are using (library, API, etc.) supports flash encryption. -- Flash encryption does not prevent an attacker from understanding the high-level layout of the flash. This is because the same AES key is used for every pair of adjacent 16 byte AES blocks. When these adjacent 16 byte blocks contain identical content (such as empty or padding areas), these blocks will encrypt to produce matching pairs of encrypted blocks. This may allow an attacker to make high-level comparisons between encrypted devices (ie to tell if two devices are probably running the same firmware version). +- Flash encryption does not prevent an attacker from understanding the high-level layout of the flash. This is because the same AES key is used for every pair of adjacent 16 byte AES blocks. When these adjacent 16 byte blocks contain identical content (such as empty or padding areas), these blocks will encrypt to produce matching pairs of encrypted blocks. This may allow an attacker to make high-level comparisons between encrypted devices (i.e. to tell if two devices are probably running the same firmware version). - For the same reason, an attacker can always tell when a pair of adjacent 16 byte blocks (32 byte aligned) contain identical content. Keep this in mind if storing sensitive data on the flash, design your flash storage so this doesn't happen (using a counter byte or some other non-identical value every 16 bytes is sufficient). @@ -281,25 +577,21 @@ Flash Encryption prevents plaintext readout of the encrypted flash, to protect f .. _flash-encryption-and-secure-boot: -Flash Encryption & Secure Boot ------------------------------- +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:`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. +- :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: -Using Flash Encryption without Secure Boot +Using Flash Encryption Without Secure Boot ------------------------------------------ -If flash encryption is used without secure boot, it is possible to load unauthorised code using serial re-flashing. See :ref:`updating-encrypted-flash-serial` for details. This unauthorised code can then read all encrypted partitions (in decrypted form) making flash-encryption ineffective. This can be avoided by write-protecting :ref:`FLASH_CRYPT_CNT` and thereby disallowing serial re-flashing. :ref:`FLASH_CRYPT_CNT` can be write-protected using command:: - - espefuse.py --port PORT write_protect_efuse FLASH_CRYPT_CNT - -Alternatively, the app can call :func:`esp_flash_write_protect_crypt_cnt` during its startup process. +Even though flash encryption and secure boot can be used independently it is strongly recommended to use flash encryption ALONG with secure boot to achieve strong security. .. _flash-encryption-advanced-features: @@ -338,21 +630,21 @@ Usually left blank, if you write "encrypted" in this field then the partition wi Enabling UART Bootloader Encryption/Decryption ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -By default, on first boot the flash encryption process will burn efuses ``DISABLE_DL_ENCRYPT``, ``DISABLE_DL_DECRYPT`` and ``DISABLE_DL_CACHE``: +By default, on first boot the flash encryption process will burn eFuses ``DISABLE_DL_ENCRYPT``, ``DISABLE_DL_DECRYPT`` and ``DISABLE_DL_CACHE``: - ``DISABLE_DL_ENCRYPT`` disables the flash encryption operations when running in UART bootloader boot mode. -- ``DISABLE_DL_DECRYPT`` disables transparent flash decryption when running in UART bootloader mode, even if :ref:`FLASH_CRYPT_CNT` is set to enable it in normal operation. +- ``DISABLE_DL_DECRYPT`` disables transparent flash decryption when running in UART bootloader mode, even if FLASH_CRYPT_CNT is set to enable it in normal operation. - ``DISABLE_DL_CACHE`` disables the entire MMU flash cache when running in UART bootloader mode. -It is possible to burn only some of these efuses, and write-protect the rest (with unset value 0) before the first boot, in order to preserve them. For example:: +It is possible to burn only some of these eFuses, and write-protect the rest (with unset value 0) before the first boot, in order to preserve them. For example:: espefuse.py --port PORT burn_efuse DISABLE_DL_DECRYPT espefuse.py --port PORT write_protect_efuse DISABLE_DL_ENCRYPT -(Note that all 3 of these efuses are disabled via one write protect bit, so write protecting one will write protect all of them. For this reason, it's necessary to set any bits before write-protecting.) +(Note that all 3 of these eFuses are disabled via one write protect bit, so write protecting one will write protect all of them. For this reason, it's necessary to set any bits before write-protecting.) .. important:: - Write protecting these efuses to keep them unset is not currently very useful, as ``esptool.py`` does not support writing or reading encrypted flash. + Write protecting these eFuses to keep them unset is not currently very useful, as ``esptool.py`` does not support reading encrypted flash. .. important:: If ``DISABLE_DL_DECRYPT`` is left unset (0) this effectively makes flash encryption useless, as an attacker with physical access can use UART bootloader mode (with custom stub code) to read out the flash contents. @@ -362,13 +654,13 @@ It is possible to burn only some of these efuses, and write-protect the rest (wi Setting FLASH_CRYPT_CONFIG ^^^^^^^^^^^^^^^^^^^^^^^^^^ -The ``FLASH_CRYPT_CONFIG`` efuse determines the number of bits in the flash encryption key which are "tweaked" with the block offset. See :ref:`flash-encryption-algorithm` for details. +The ``FLASH_CRYPT_CONFIG`` eFuse determines the number of bits in the flash encryption key which are "tweaked" with the block offset. See :ref:`flash-encryption-algorithm` for details. First boot of the bootloader always sets this value to the maximum `0xF`. -It is possible to write these efuse manually, and write protect it before first boot in order to select different tweak values. This is not recommended. +It is possible to write these eFuse manually, and write protect it before first boot in order to select different tweak values. This is not recommended. -It is strongly recommended to never write protect ``FLASH_CRYPT_CONFIG`` when it the value is zero. If this efuse is set to zero, no bits in the flash encryption key are tweaked and the flash encryption algorithm is equivalent to AES ECB mode. +It is strongly recommended to never write protect ``FLASH_CRYPT_CONFIG`` when it the value is zero. If this eFuse is set to zero, no bits in the flash encryption key are tweaked and the flash encryption algorithm is equivalent to AES ECB mode. Technical Details @@ -376,27 +668,6 @@ Technical Details The following sections provide some reference information about the operation of flash encryption. -.. _FLASH_CRYPT_CNT: - -FLASH_CRYPT_CNT efuse -^^^^^^^^^^^^^^^^^^^^^ - -``FLASH_CRYPT_CNT`` is a 7-bit efuse field which controls flash encryption. Flash encryption enables or disables based on the number of bits in this efuse which are set to "1": - -- When an even number of bits (0,2,4,6) are set: Flash encryption is disabled, any encrypted data cannot be decrypted. - - - If the bootloader was built with "Enable flash encryption on boot" then it will see this situation and immediately re-encrypt the flash wherever it finds unencrypted data. Once done, it sets another bit in the efuse to '1' meaning an odd number of bits are now set. - - 1. On first plaintext boot, bit count has brand new value 0 and bootloader changes it to bit count 1 (value 0x01) following encryption. - 2. After next plaintext flash update, bit count is manually updated to 2 (value 0x03). After re-encrypting the bootloader changes efuse bit count to 3 (value 0x07). - 3. After next plaintext flash, bit count is manually updated to 4 (value 0x0F). After re-encrypting the bootloader changes efuse bit count to 5 (value 0x1F). - 4. After final plaintext flash, bit count is manually updated to 6 (value 0x3F). After re-encrypting the bootloader changes efuse bit count to 7 (value 0x7F). - -- When an odd number of bits (1,3,5,7) are set: Transparent reading of encrypted flash is enabled. - -- To avoid use of :ref:`FLASH_CRYPT_CNT` state to disable flash encryption, load unauthorised code, then re-enabled flash encryption, secure boot must be used or :ref:`FLASH_CRYPT_CNT` must be write-protected. - - .. _flash-encryption-algorithm: Flash Encryption Algorithm @@ -404,17 +675,17 @@ Flash Encryption Algorithm - AES-256 operates on 16 byte blocks of data. The flash encryption engine encrypts and decrypts data in 32 byte blocks, two AES blocks in series. -- The main flash encryption key is stored in efuse (BLOCK1) and by default is protected from further writes or software readout. +- The main flash encryption key is stored in eFuse (BLOCK1) and by default is protected from further writes or software readout. -- AES-256 key size is 256 bits (32 bytes), read from efuse block 1. The hardware AES engine uses the key in reversed byte order to the order stored in the efuse block. - - If ``CODING_SCHEME`` efuse is set to 0 (default "None" Coding Scheme) then the efuse key block is 256 bits and the key is stored as-is (in reversed byte order). - - If ``CODING_SCHEME`` efuse is set to 1 (3/4 Encoding) then the efuse key block is 192 bits (in reversed byte order), so overall entropy is reduced. The hardware flash encryption still operates on a 256-bit key, after being read (and un-reversed), the key is extended by as ``key = key[0:255] + key[64:127]``. +- AES-256 key size is 256 bits (32 bytes), read from eFuse block 1. The hardware AES engine uses the key in reversed byte order to the order stored in the eFuse block. + - If ``CODING_SCHEME`` eFuse is set to 0 (default "None" Coding Scheme) then the eFuse key block is 256 bits and the key is stored as-is (in reversed byte order). + - If ``CODING_SCHEME`` eFuse is set to 1 (3/4 Encoding) then the eFuse key block is 192 bits (in reversed byte order), so overall entropy is reduced. The hardware flash encryption still operates on a 256-bit key, after being read (and un-reversed), the key is extended by as ``key = key[0:255] + key[64:127]``. - AES algorithm is used inverted in flash encryption, so the flash encryption "encrypt" operation is AES decrypt and the "decrypt" operation is AES encrypt. This is for performance reasons and does not alter the effectiveness of the algorithm. -- Each 32 byte block (two adjacent 16 byte AES blocks) is encrypted with a unique key. The key is derived from the main flash encryption key in efuse, XORed with the offset of this block in the flash (a "key tweak"). +- Each 32 byte block (two adjacent 16 byte AES blocks) is encrypted with a unique key. The key is derived from the main flash encryption key in eFuse, XORed with the offset of this block in the flash (a "key tweak"). -- The specific tweak depends on the setting of ``FLASH_CRYPT_CONFIG`` efuse. This is a 4 bit efuse, where each bit enables XORing of a particular range of the key bits: +- The specific tweak depends on the setting of ``FLASH_CRYPT_CONFIG`` eFuse. This is a 4 bit eFuse, where each bit enables XORing of a particular range of the key bits: - Bit 1, bits 0-66 of the key are XORed. - Bit 2, bits 67-131 of the key are XORed. 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/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__": diff --git a/docs/page_redirects.txt b/docs/page_redirects.txt new file mode 100644 index 0000000000..fc1cee7988 --- /dev/null +++ b/docs/page_redirects.txt @@ -0,0 +1,52 @@ +# 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-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/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 +api-guide/unit-tests-cmake api-guide/unit-tests + diff --git a/docs/sphinx-known-warnings.txt b/docs/sphinx-known-warnings.txt index 72fb40a5b6..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 >>> @@ -77,6 +80,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 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、组件和工作流的支持。 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/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/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/build-system-cmake.rst b/docs/zh_CN/api-guides/build-system-cmake.rst deleted file mode 100644 index 19d766a83f..0000000000 --- a/docs/zh_CN/api-guides/build-system-cmake.rst +++ /dev/null @@ -1,1082 +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_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 366f7d79f6..e9616ec0c3 100644 --- a/docs/zh_CN/api-guides/build-system.rst +++ b/docs/zh_CN/api-guides/build-system.rst @@ -1,539 +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` 函数来使用该变量。 - -如果您在 ``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/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/external-ram.rst b/docs/zh_CN/api-guides/external-ram.rst index 11fe46540d..922be9483e 100644 --- a/docs/zh_CN/api-guides/external-ram.rst +++ b/docs/zh_CN/api-guides/external-ram.rst @@ -1 +1,147 @@ -.. include:: ../../en/api-guides/external-ram.rst \ No newline at end of file +片外 RAM +************************ + +:link_to_translation:`en:[English]` + +.. toctree:: + :maxdepth: 1 + +简介 +============ + +ESP32 提供了 520 KB 的片上 SRAM,可以满足大部分需求。但有些场景可能需要更多 RAM,因此 ESP32 另外提供了高达 4 MB 的片外 SPI RAM 存储器以供用户使用。片外 RAM 被添加到内存映射中,在某些范围内与片上 RAM 使用方式相同。 + +硬件 +======== + +ESP32 支持与 SPI Flash 芯片并联的 SPI PSRAM。ESP32 支持多种类型的 RAM 芯片,但 ESP32 SDK 当前仅支持 ESP-PSRAM32 芯片。 + +ESP-PSRAM32 芯片的工作电压为 1.8 V,只能与 1.8 V flash 并联使用。请确保在启动时将 MTDI 管脚设置为高电平,或者将 ESP32 中的熔丝设置为始终使用 1.8 V 的 VDD_SIO 电平,否则有可能会损坏 PSRAM 和/或 flash 芯片。 + +要将 ESP-PSRAM 芯片连接到 ESP32D0W*,请连接以下信号: + * 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 + +ESP32D2W* 芯片的连接方式有待确定。 + +.. note:: + 乐鑫同时提供 ESP32-WROVER 模组,内部搭载 ESP32 芯片,集成 1.8 V flash 和 ESP-PSRAM32,可直接用于终端产品 PCB 中。 + +.. _external_ram_config: + +配置片外 RAM +======================== + +ESP-IDF 完全支持将外部存储器集成到您的应用程序中。您可以将 ESP-IDF 配置成启动并完成初始化后以多种方式处理片外 RAM: + + * :ref:`external_ram_config_memory_map` + * :ref:`external_ram_config_capability_allocator` + * :ref:`external_ram_config_malloc` (默认) + * :ref:`external_ram_config_bss` + +.. _external_ram_config_memory_map: + +集成片外 RAM 到 ESP32 内存映射 +----------------------------------- + +在 :ref:`CONFIG_SPIRAM_USE` 中选择 "Integrate RAM into ESP32 memory map(集成片外 RAM 到 ESP32 内存映射)" 选项。 + +这是集成片外 RAM 最基础的设置选项,大多数用户需要用到其他更高级的选项。 + +ESP-IDF 启动过程中,片外 RAM 被映射到以 0x3F800000 起始的数据地址空间(字节可寻址),空间大小正好为 RAM 的大小 (4 MB)。 + +应用程序可以通过创建指向该区域的指针手动将数据放入片外存储器,同时应用程序全权负责管理片外 RAM,包括协调 Buffer 的使用、防止发生损坏等。 + +.. _external_ram_config_capability_allocator: + +添加片外 RAM 到内存分配程序 +-------------------------------------------- + +在 :ref:`CONFIG_SPIRAM_USE` 中选择 "Make RAM allocatable using heap_caps_malloc(..., MALLOC_CAP_SPIRAM)" 选项。 + +启用上述选项后,片外 RAM 被映射到地址 0x3F800000,并将这个区域添加到 :doc:`内存分配程序 ` 里携带 ``MALLOC_CAP_SPIRAM`` 的标志 + +程序如果想从片外存储器分配存储空间,则需要调用 ``heap_caps_malloc(size, MALLOC_CAP_SPIRAM)``,之后可以调用 ``free()`` 函数释放这部分存储空间。 + +.. _external_ram_config_malloc: + +调用 malloc() 分配片外 RAM +--------------------------------- + +在 :ref:`CONFIG_SPIRAM_USE` 中选择 "Make RAM allocatable using malloc() as well" 选项,该选项为默认选项。 + +启用此选项后,片外存储器将被添加到内存分配程序(与上一选项相同),同时也将被添加到由标准 ``malloc()`` 返回的 RAM 中。 + +这允许应用程序使用片外 RAM 而无需重写代码以使用 ``heap_caps_malloc(..., MALLOC_CAP_SPIRAM)``。 + +如果某次内存分配偏向于片外存储器,您也可以使用 :ref:`CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL` 设置分配空间的大小阈值,控制分配结果: + +- 如果分配的空间小于阈值,分配程序将首先选择内部存储器。 +- 如果分配的空间等于或大于阈值,分配程序将首先选择外部存储器。 + +如果优先考虑的内部或外部存储器中没有可用的存储块,分配程序则会选择其他类型存储。 + +由于有些 Buffer 仅可在内部存储器中分配,因此需要使用第二个配置项 :ref:`CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL` 定义一个内部存储池,仅限显式的内部存储器分配使用(例如用于 DMA 的存储器)。常规 ``malloc()`` 将不会从该池中分配,但可以使用 :ref:`MALLOC_CAP_DMA ` 和 ``MALLOC_CAP_INTERNAL`` 旗标从该池中分配存储器。 + +.. _external_ram_config_bss: + +允许 .bss 段放入片外存储器 +-------------------------------------------- + +设置 :ref:`CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY` 启用该选项,此选项配置与上面三个选项互不影响。 + +启用该选项后,从 0x3F800000 起始的地址空间将用于存储来自 lwip、net80211、libpp 和 bluedroid ESP-IDF 库中零初始化的数据(BSS 段)。 + +``EXT_RAM_ATTR`` 宏应用于任何静态声明(未初始化为非零值)之后,可以将附加数据从内部 BSS 段移到片外 RAM。 + +启用此选项可以减少 BSS 段占用的内部静态存储。 + +剩余的片外 RAM 也可以通过上述方法添加到内存分配程序中。 + +片外 RAM 使用限制 +=================== + +使用片外 RAM 有下面一些限制: + + * Flash cache 禁用时(比如,正在写入 flash),片外 RAM 将无法访问;同样,对片外 RAM 的读写操作也将导致 cache 访问异常。出于这个原因,ESP-IDF 不会在片外 RAM 中分配任务堆栈(详见下文)。 + + * 片外 RAM 不能用于储存 DMA 描述符,也不能用作 DMA 读写操作的缓冲区 (Buffer)。与 DMA 搭配使用的 Buffer 必须先使用 ``heap_caps_malloc(size, MALLOC_CAP_DMA)`` 进行分配,之后可以调用标准 ``free()`` 回调释放 Buffer。 + + * 片外 RAM 与片外 flash 使用相同的 cache 区域,即频繁在片外 RAM 访问的变量可以像在片上 RAM 中一样快速读取和修改。但访问大块数据时(大于 32 KB),cache 空间可能会不足,访问速度将回落到片外 RAM 访问速度。此外,访问大块数据可以“挤出” flash cache,可能会降低代码执行速度。 + + * 片外 RAM 不可用作任务堆栈存储器。因此 :cpp:func:`xTaskCreate` 及类似函数将始终为堆栈和任务 TCB 分配片上储存器,而 :cpp:func:`xTaskCreateStatic` 类型的函数将检查传递的 Buffer 是否属于片上存储器。但对于不以任何方式直接或间接调用 ROM 中代码的任务,menuconfig 选项 :ref:`CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY` 将消除 `xTaskCreateStatic` 中的检查,从而允许任务堆栈存储在外部 RAM 中。但是,不建议使用此方法。 + + * 默认情况下,片外 RAM 初始化失败将终止 ESP-IDF 启动。如果想禁用此功能,可启用 :ref:`CONFIG_SPIRAM_IGNORE_NOTFOUND` 配置选项。如果启用 :ref:`CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY`,:ref:`CONFIG_SPIRAM_IGNORE_NOTFOUND` 选项将不能使用,这是因为在链接时,链接器已经向片外 RAM 分配符号。 + + * 时钟频率为 80 MHz 时,片外 RAM 须占用 HSPI 总线或 VSPI 总线。请使用 :ref:`CONFIG_SPIRAM_OCCUPY_SPI_HOST` 选择要用的 SPI 主机。 + + +芯片版本 +============== + +有些 ESP32 芯片版本存在某些已知问题,可能会影响片外 RAM 的使用。请参考 ESP32 勘误表_,查看详细信息。为了解决这些问题,ESP-IDF 采取了以下措施: + +ESP32 rev v0 +------------ +ESP-IDF 尚未提供针对此版本硅片 bug 的解决方法,因此在 ESP32 rev v0 中,ESP-IDF 无法将片外 PSRAM 映射到 ESP32 主内存映射中。 + +ESP32 rev v1 +------------ +当某些机器指令序列在片外存储器位置上运行时,此芯片版本中的错误可能会引发芯片故障(详情见 ESP32 勘误表_ 第 3.2 章节)。 为了解决这个问题,用于编译 ESP-IDF 项目的 GCC 编译器扩展了一个旗标:-mfix-esp32-psram-cache-issue。在命令行中将此旗标传递给 GCC,编译器对这些序列进行处理,然后仅输出可以安全执行的代码。如需启用此旗标,请选择 :ref:`CONFIG_SPIRAM_CACHE_WORKAROUND`。 + +ESP-IDF 还采取了其他措施确保不同时使用 PSRAM 访问和出错指令集: + +- 链接到使用 GCC 旗标重新编译的 Newlib 版本; +- 避免使用某些 ROM 函数; +- 为 Wi-Fi 栈分配静态内存。 + +.. _勘误表: https://www.espressif.com/sites/default/files/documentation/eco_and_workarounds_for_bugs_in_esp32_cn.pdf + + + + 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..c00fa330c0 100644 --- a/docs/zh_CN/api-guides/index.rst +++ b/docs/zh_CN/api-guides/index.rst @@ -7,9 +7,9 @@ API 指南 一般注意事项 构建系统 - 构建系统 (CMake) + 构建系统 (传统 GNU Make) 错误处理 - Fatal Errors + 严重错误 Event Handling Deep Sleep Wake Stubs ESP32 Core Dump @@ -18,13 +18,13 @@ API 指南 Thread Local Storage High Level Interrupts JTAG 调试 - Bootloader + 引导加载程序 分区表 Secure Boot <../security/secure-boot> - ULP Coprocessor - ULP 协处理器 (CMake) + ULP 协处理器 + ULP ( CMake) 单元测试 - 单元测试 (CMake) + 单元测试 (传统 GNU Make) 应用层跟踪 控制台终端组件 ROM debug console @@ -34,3 +34,4 @@ API 指南 BluFi External SPI-connected RAM 链接脚本生成机制 + Tools 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..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:`../../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` 章节所描述的信息,设置 JP8 便可以启用 JTAG 功能。 2. 检查 ESP32 上用于 JTAG 通信的引脚是否被接到了其它硬件上,这可能会影响 JTAG 的工作。 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/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-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/idf-monitor.rst b/docs/zh_CN/api-guides/tools/idf-monitor.rst index 3d842fbd13..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,11 +27,11 @@ 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+A 仅编译及烧录应用程序 暂停 idf_monitor,运行 ``app-flash`` 目标,然后恢复 idf_monitor。 这与 ``flash`` 类似,但只有主应用程序被编译并被重新烧录。 +- Ctrl+F 编译并烧录此项目 暂停 idf_monitor,运行 ``idf.py flash`` 目标,然后恢复 idf_monitor。任何改动的源文件都会被重新编译,然后重新烧录。 +- Ctrl+A (A) 仅编译及烧录应用程序 暂停 idf_monitor,运行 ``app-flash`` 目标,然后恢复 idf_monitor。 这与 ``flash`` 类似,但只有主应用程序被编译并被重新烧录。 - Ctrl+Y 停止/恢复日志输出在屏幕上打印 激活时,会丢弃所有传入的串行数据。允许在不退出监视器的情况下快速暂停和检查日志输出。 - Ctrl+L 停止/恢复向文件写入日志输出 在工程目录下创建一个文件,用于写入日志输出。可使用快捷键停止/恢复该功能(退出 IDF 监视器也会终止该功能) -- Ctrl+H 显示所有快捷键 +- Ctrl+H (H) 显示所有快捷键 =================== ======================================================================== ======================================================================================================================================================================================= 除了 ``Ctrl-]`` 和 ``Ctrl-T``,其他快捷键信号会通过串口发送到目标设备。 @@ -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/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 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 c5f8898b7d..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 build -T all`` - 编译单元测试程序,测试每个组件 ``test`` +- ``make TESTS_ALL=1`` - 编译单元测试程序,测试每个组件 ``test`` 子目录下的用例。 -- ``idf.py build -T xxx`` - 编译单元测试程序,测试指定的组件。 +- ``make TEST_COMPONENTS='xxx'`` - 编译单元测试程序,测试指定的组件。 -- ``idf.py build -T all -E xxx`` - +- ``make TESTS_ALL=1 TEST_EXCLUDE_COMPONENTS='xxx'`` - 编译单元测试程序,测试所有(除开指定)的组件。例如 - ``idf.py build -T all -E ulp mbedtls`` - + ``make TESTS_ALL=1 TEST_EXCLUDE_COMPONENTS='ulp mbedtls'`` - 编译所有的单元测试,不包括 ``ulp`` 和 ``mbedtls``\ 组件。 -当编译完成时,它会打印出烧写芯片的指令。您只需要运行 ``idf.py flash`` +当编译完成时,它会打印出烧写芯片的指令。您只需要运行 ``make flash`` 即可烧写所有编译输出的文件。 -您还可以运行 ``idf.py flash -T all`` 或者 -``idf.py flash -T xxx`` +您还可以运行 ``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/api-reference/bluetooth/index.rst b/docs/zh_CN/api-reference/bluetooth/index.rst index 47e5ddd48c..2ec48307f9 100644 --- a/docs/zh_CN/api-reference/bluetooth/index.rst +++ b/docs/zh_CN/api-reference/bluetooth/index.rst @@ -10,20 +10,21 @@ Bluetooth Common Bluetooth LE Bluetooth Classic + NimBLE 请点击下方链接,查看 ESP32 蓝牙架构: `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/docs/zh_CN/api-reference/bluetooth/nimble/index.rst b/docs/zh_CN/api-reference/bluetooth/nimble/index.rst new file mode 100644 index 0000000000..48efe410c3 --- /dev/null +++ b/docs/zh_CN/api-reference/bluetooth/nimble/index.rst @@ -0,0 +1 @@ +.. include:: ../../../../en/api-reference/bluetooth/nimble/index.rst 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 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/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..d385082b3b 100644 --- a/docs/zh_CN/api-reference/protocols/index.rst +++ b/docs/zh_CN/api-reference/protocols/index.rst @@ -8,11 +8,13 @@ mDNS ESP-TLS HTTP Client + Websocket Client HTTP 服务器 HTTPS Server ASIO ESP-MQTT Modbus slave + Local Control 此 API 部分的示例代码在 ESP-IDF 示例工程的 :example:`protocols` 目录下提供。 diff --git a/docs/zh_CN/api-reference/system/app_image_format.rst b/docs/zh_CN/api-reference/system/app_image_format.rst new file mode 100644 index 0000000000..7940907170 --- /dev/null +++ b/docs/zh_CN/api-reference/system/app_image_format.rst @@ -0,0 +1 @@ +.. include:: ../../../en/api-reference/system/app_image_format.rst \ No newline at end of file diff --git a/docs/zh_CN/api-reference/system/power_management.rst b/docs/zh_CN/api-reference/system/power_management.rst index e55e0543a2..a37a97be4d 100644 --- a/docs/zh_CN/api-reference/system/power_management.rst +++ b/docs/zh_CN/api-reference/system/power_management.rst @@ -1 +1,132 @@ -.. include:: ../../../en/api-reference/system/power_management.rst \ No newline at end of file +电源管理 +================ + +:link_to_translation:`en:[English]` + +概述 +-------- + +ESP-IDF 中集成的电源管理算法可以根据应用程序组件的需求,调整外围总线 (APB) 频率、CPU 频率,并使芯片进入 Light-sleep 模式,尽可能减少运行应用程序的功耗。 + +应用程序组件可以通过创建和获取电源管理锁来控制功耗。 + +例如: + +- 对于从 APB 获得时钟频率的外设,其驱动可以要求在使用该外设时,将 APB 频率设置为 80 MHz。 +- RTOS 可以要求 CPU 在有任务准备开始运行时以最高配置频率工作。 +- 一些外设可能需要中断才能启用,因此其驱动也会要求禁用 Light-sleep 模式。 + +因为请求较高的 APB 频率或 CPU 频率,以及禁用 Light-sleep 模式会增加功耗,请将组件使用的电源管理锁降到最少。 + +电源管理配置 +------------- + +编译时可使用 :ref:`CONFIG_PM_ENABLE` 选项启用电源管理功能。 + +启用电源管理功能将会增加中断延迟。额外延迟与多个因素有关,例如:CPU 频率、单/双核模式、是否需要进行频率切换等。CPU 频率为 240 MHz 且未启用频率调节时,最小额外延迟为 0.2 us;如果启用频率调节,且在中断入口将频率由 40 MHz 调节至 80 MHz,则最大额外延迟为 40 us。 + +应用程序可以通过调用 :cpp:func:`esp_pm_configure` 函数启用动态调频 (DFS) 功能和自动 Light-sleep 模式。此函数的参数为 :cpp:class:`esp_pm_config_esp32_t`,定义了频率调节的相关设置。在此参数结构中,需要初始化下面三个字段: + +- ``max_freq_mhz``:最大 CPU 频率 (MHz),即获取 ``ESP_PM_CPU_FREQ_MAX`` 锁后所使用的频率。该字段通常设置为 :ref:`CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ`。 +- ``min_freq_mhz``:最小 CPU 频率 (MHz),即仅获取 ``ESP_PM_APB_FREQ_MAX`` 锁后所使用的频率。该字段可设置为晶振 (XTAL) 频率值,或者 XTAL 频率值除以整数。注意,10 MHz 是生成 1 MHz 的 REF_TICK 默认时钟所需的最小频率。 + +- ``light_sleep_enable``:没有获取任何管理锁时,决定系统是否需要自动进入 Light-sleep 状态 (``true``/``false``)。 + +或者,如果在 menuconfig 中启用了 :ref:`CONFIG_PM_DFS_INIT_AUTO` 选项,最大 CPU 频率将由 :ref:`CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ` 设置决定,最小 CPU 频率将锁定为 XTAL 频率。 + +.. note:: + + 1. 自动 Light-sleep 模式基于 FreeRTOS Tickless Idle 功能,因此如果在 menuconfig 中没有启用 :ref:`CONFIG_FREERTOS_USE_TICKLESS_IDLE` 选项,在请求自动 Light-sleep 时,:cpp:func:`esp_pm_configure` 将会返回 `ESP_ERR_NOT_SUPPORTED` 错误。 + 2. 在 Light-sleep 状态下,外设设有时钟门控,不会产生来自 GPIO 和内部外设的中断。:doc:`sleep_modes` 文档中所提到的唤醒源可用于从 Light-sleep 状态触发唤醒。例如,EXT0 和 EXT1 唤醒源就可以通过 GPIO 唤醒芯片。 + +电源管理锁 +---------------------- + +应用程序可以通过获取或释放管理锁来控制电源管理算法。应用程序获取电源管理锁后,电源管理算法的操作将受到下面的限制。释放电源管理锁后,限制解除。 + +电源管理锁设有获取/释放计数器,如果已多次获取电源管理锁,则需要将电源管理锁释放相同次数以解除限制。 + +ESP32 支持下表中所述的三种电源管理锁。 + +============================ ====================================================== +电源管理锁 描述 +============================ ====================================================== +``ESP_PM_CPU_FREQ_MAX`` 请求使用 :cpp:func:`esp_pm_configure` 将 CPU 频率设置为最大值。ESP32 可以将该值设置为 80 MHz、160 MHz 或 240 MHz。 + +``ESP_PM_APB_FREQ_MAX`` 请求将 APB 频率设置为最大值,ESP32 支持的最大频率为 80 MHz。 + +``ESP_PM_NO_LIGHT_SLEEP`` 禁止自动切换至 Light-sleep 模式。 +============================ ====================================================== + + +电源管理算法 +-------------------------------- + +下表列出了启用动态调频时如何切换 CPU 频率和 APB 频率。您可以使用 :cpp:func:`esp_pm_configure` 或者 :ref:`CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ` 指定 CPU 最大频率。 + ++--------------+---------------------------------------------------------+----------------------------------------------------+ +| CPU 最高频率 | 电源管理锁获取情况 | CPU 频率和 APB 频率 | ++--------------+---------------------------------------------------------+----------------------------------------------------+ +| 240 MHz | 获取 ``ESP_PM_CPU_FREQ_MAX`` 或 ``ESP_PM_APB_FREQ_MAX`` | CPU: 240 MHz APB: 80 MHz | ++ +---------------------------------------------------------+----------------------------------------------------+ +| \ | 无 | 使用 :cpp:func:`esp_pm_configure` 为二者设置最小值 | ++--------------+---------------------------------------------------------+----------------------------------------------------+ +| 160 MHz | 获取 ``ESP_PM_CPU_FREQ_MAX`` | CPU: 160 MHz APB: 80 MHz | ++ +---------------------------------------------------------+----------------------------------------------------+ +| \ | 获取 ``ESP_PM_CPU_FREQ_MAX``, | CPU: 80 MHz APB: 80 MHz | +| | 未获取 ``ESP_PM_APB_FREQ_MAX`` | | ++ +---------------------------------------------------------+----------------------------------------------------+ +| \ | 无 | 使用 :cpp:func:`esp_pm_configure` 为二者设置最小值 | ++--------------+---------------------------------------------------------+----------------------------------------------------+ +| 80 MHz | 获取 ``ESP_PM_CPU_FREQ_MAX`` 或 ``ESP_PM_APB_FREQ_MAX`` | CPU: 80 MHz APB: 80 MHz | ++ +---------------------------------------------------------+----------------------------------------------------+ +| \ | 无 | 使用 :cpp:func:`esp_pm_configure` 为二者设置最小值 | ++--------------+---------------------------------------------------------+----------------------------------------------------+ + +如果没有获取任何管理锁,调用 :cpp:func:`esp_pm_configure` 将启动 Light-sleep 模式。 Light-sleep 模式持续时间由以下因素决定: + +- 处于阻塞状态的 FreeRTOS 任务数(有限超时) +- :doc:`高分辨率定时器 ` API 注册的计数器数量 + +您也可以设置 Light-sleep 模式在最近事件(任务解除阻塞,或计时器超时)之前持续多久才唤醒芯片。 + +动态调频和外设驱动 +------------------------------------------------ + +启用动态调频后,APB 频率可在一个 RTOS 滴答周期内多次更改。有些外设不受 APB 频率变更的影响,但有些外设可能会出现问题。例如,Timer Group 外设定时器会继续计数,但定时器计数的速度将随 APB 频率的变更而变更。 + +下面的外设不受 APB 频率变更的影响: + +- **UART**:如果 REF_TICK 用作时钟源,则 UART 不受 APB 频率变更影响。请查看 :cpp:class:`uart_config_t` 中的 `use_ref_tick`。 +- **LEDC**:如果 REF_TICK 用作时钟源,则 LEDC 不受 APB 频率变更影响。请查看 :cpp:func:`ledc_timer_config` 函数。 +- **RMT**:如果 REF_TICK 用作时钟源,则 RMT 不受 APB 频率变更影响。此驱动程序尚不支持 REF_TICK,但可以清除相应通道的 ``RMT_REF_ALWAYS_ON_CHx`` 位来启用该功能。 + +目前以下外设驱动程序可感知动态调频,并在调频期间使用 ``ESP_PM_APB_FREQ_MAX`` 锁: + +- SPI master +- I2C +- I2S(如果 APLL 锁在使用中,I2S 则会启用 ``ESP_PM_NO_LIGHT_SLEEP`` 锁) +- SDMMC + +启用以下驱动程序时,将占用 ``ESP_PM_APB_FREQ_MAX`` 锁: + +- **SPI slave**:从调用 :cpp:func:`spi_slave_initialize` 至 :cpp:func:`spi_slave_free` 期间。 +- **Ethernet**:从调用 :cpp:func:`esp_eth_enable` 至 :cpp:func:`esp_eth_disable` 期间。 +- **WiFi**:从调用 :cpp:func:`esp_wifi_start` 至 :cpp:func:`esp_wifi_stop` 期间。如果启用了调制解调器睡眠模式,广播关闭时将释放此管理锁。 +- **Bluetooth**:从调用 :cpp:func:`esp_bt_controller_enable` 至 :cpp:func:`esp_bt_controller_disable` 期间。如果启用了蓝牙调制解调器,广播关闭时将释放此管理锁。但依然占用 ``ESP_PM_NO_LIGHT_SLEEP`` 锁。 +- **CAN**:从调用 :cpp:func:`can_driver_install` 至 :cpp:func:`can_driver_uninstall` 期间。 + +以下外设驱动程序无法感知动态调频,应用程序需自己获取/释放管理锁: + +- MCPWM +- PCNT +- Sigma-delta +- Timer Group + + +API 参考 +------------- + +.. include:: /_build/inc/esp_pm.inc +.. include:: /_build/inc/pm.inc + 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/get-started-pico-kit.rst b/docs/zh_CN/get-started-cmake/get-started-pico-kit.rst deleted file mode 100644 index 7e8e72e8fd..0000000000 --- a/docs/zh_CN/get-started-cmake/get-started-pico-kit.rst +++ /dev/null @@ -1,232 +0,0 @@ -ESP32-PICO-KIT V4/V4.1 入门指南(CMake) -======================================================= -: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-cmake: - -.. 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-cmake`。 - - -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 -""""""""" - -====== ================= ====== ====================================================== -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 -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-cmake: - -有关上表的说明: - -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-cmake` 章节,查看如何设置开发环境,并尝试将示例目烧录至您的开发板。 - - -开发板尺寸 ----------- - -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-cmake/linux-setup-scratch.rst b/docs/zh_CN/get-started-cmake/linux-setup-scratch.rst deleted file mode 100644 index 0ba33490c3..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-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 - - -.. 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 6104d9f431..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-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 - -.. 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.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 50% rename from docs/zh_CN/get-started-cmake/index.rst rename to docs/zh_CN/get-started-legacy/index.rst index 79d951be46..1c39ed934e 100644 --- a/docs/zh_CN/get-started-cmake/index.rst +++ b/docs/zh_CN/get-started-legacy/index.rst @@ -1,496 +1,447 @@ -******************* -快速入门(CMake) -******************* - -:link_to_translation:`en:[English]` - -.. include:: ../cmake-warning.rst - -.. include:: ../cmake-pending-features.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 代码; -* **编译工具** —— CMake 和 Ninja 编译工具,用于编译 ESP32 **应用程序**; -* 获取 **ESP-IDF** 软件开发框架。该框架已经基本包含 ESP32 使用的 API(软件库和源代码)和运行 **工具链** 的脚本; -* 安装 C 语言编程(**工程**)的 **文本编辑器**,例如 `Eclipse `_。 - - -.. figure:: ../../_static/what-you-need-cmake.png - :align: center - :alt: ESP32 应用程序开发 - :figclass: align-center - - ESP32 应用程序开发 - - -开发板简介 -========== - -请点击下方连接,了解有关具体开发板的详细信息。 - -.. 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-cmake: - -详细安装步骤 -============== - -请根据下方详细步骤,完成安装过程。 - -设置开发环境 -~~~~~~~~~~~~~~~~ - -* :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-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-cmake: - -第一步:设置工具链 -==================== - -工具链指一套用于编译代码和应用程序的程序。 - -为了加快开发进度,您可以直接使用乐鑫提供的预制工具链。请根据您的操作系统,点击下方对应的链接,并按照链接中的指导进行安装。 - -.. 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:: - - 在本文档中,Linux 和 MacOS 操作系统中 ESP-IDF 的默认安装路径为 ``~/esp``;Windows 操作系统的默认路径为 ``%userprofile%\esp``。您也可以将 ESP-IDF 安装在任何其他路径下,但请注意在使用命令行时进行相应替换。注意,ESP-IDF 不支持带有空格的路径。 - -此外, 您也可以根据自身经验和实际需求,对环境进行个性化设置,而非使用预制工具链。此时,请前往 :ref:`工具链的个性化设置` 章节获取更多信息。 - - -.. _get-started-get-esp-idf-cmake: - -第二步:获取 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-cmake: - -第三步:设置环境变量 -=========================== - -请在您的 PC 上设置以下环境变量,否则无法编译工程。 - -- ``IDF_PATH`` 应设置为 ESP-IDF 根目录的路径。 -- ``PATH`` 应包括同一 ``IDF_PATH`` 目录下的 ``tools`` 目录路径。 - -您可以在每次重启会话时手动设置,也可以在用户配置中进行永久设置,具体请前往 :doc:`add-idf_path-to-profile` 章节,查看 :ref:`Windows ` 、:ref:`Linux 及 MacOS ` 操作系统的具体设置方式。 - - -.. _get-started-get-packages-cmake: - -第四步:安装 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-cmake: - -第五步:开始创建工程 -======================= - -现在,您可以开始准备开发 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-cmake: - -第六步:连接设备 -====================== - -现在,请将您的 ESP32 开发板连接到 PC,并查看开发板使用的串口。 - -通常,串口在不同操作系统下显示的名称有所不同: - -- **Windows 操作系统:** ``COM1`` 等 -- **Linux 操作系统:** 以 ``/dev/tty`` 开始 -- **MacOS 操作系统:** 以 ``/dev/cu.`` 开始 - -有关如何查看串口名称的详细信息,请见 :doc:`establish-serial-connection`。 - -.. note:: - - 请记住串口名,您会在下面的步骤中用到。 - - -.. _get-started-configure-cmake: - -第七步:配置 -================= - -请进入 :ref:`get-started-start-project-cmake` 中提到的 ``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-cmake`。如果 ``tools`` 目录下没有 ``idf.py`` 文件,请确保 CMake 预览的分支正确无误,具体请参考 :ref:`get-started-get-esp-idf-cmake`。 - -如果之前的步骤都正确,则会显示下面的菜单: - -.. 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-cmake: - -第八步:编译工程 -================== - -请使用以下命令,编译烧录工程::: - - 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 - -请将 PORT 替换为 ESP32 开发板的串口名称,具体可见 :ref:`get-started-connect-cmake`。 - -您还可以将 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-cmake: - -第十步:监视器 -================== - -您可以使用 ``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-cmake` 中的指示,重新完成克隆。 - -如果您希望将 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 - -.. _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 +*************************** +快速入门 (传统 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-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/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-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..9f0a9ee900 100644 --- a/docs/zh_CN/get-started/index.rst +++ b/docs/zh_CN/get-started/index.rst @@ -1,446 +1,493 @@ -******** -快速入门 -******** - -: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 **应用程序**; -* 获取 **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 - ESP-WROVER-KIT - ESP32-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-and-flash` -* :ref:`get-started-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 的工作目录,使用 ``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: - -第三步:设置环境变量 -===================== - -工具链通过环境变量 ``IDF_PATH`` 获得 ESP-IDF 的目录。因此,您需要在 PC 中设置该环境变量,否则无法编译工程。 - -您可以在每次重启会话时手动设置,也可以在用户配置中进行永久设置,具体请前往 :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 - 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: - -第八步:编译和烧录 -==================== - -请使用以下命令,编译烧录工程: :: - - 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: - -第九步:监视器 -=============== - -您可以使用 ``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` 中的指示,重新完成克隆。 - -如果您希望将 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 +******************* +快速入门(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/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 348f5f6e77..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 构建工具。本文将对这些工具一一说明。 -工具链的设置 -=============== +在此入门指南中,我们通过命令提示符进行有关操作。不过,安装 ESP-IDF 后你还可以使用 :doc:`Eclipse ` 或支持 CMake 的图形化工具 IDE。 -快速设置的方法是从 dl.espressif.com 下载集成在一起的工具链和 MSYS2 压缩文件: +https://dl.espressif.com/dl/esp32_win32_msys2_environment_and_toolchain-20190611.zip -https://dl.espressif.com/dl/esp32_win32_msys2_environment_and_toolchain-20181001.zip +ESP-IDF 工具安装器 +======================= -将 zip 压缩文件解压到 ``C:\`` (或其它路径,这里假设是 ``C:\``),它会使用预先准备的环境创建一个 ``msys32`` 目录。 +安装 ESP-IDF 必备工具最简易的方式是下载 ESP-IDF 工具安装器,地址如下: -检出 -============ +https://dl.espressif.com/dl/esp-idf-tools-setup-1.2.exe -运行 ``C:\msys32\mingw32.exe`` 打开一个 MSYS2 的终端窗口。该窗口的环境是一个 bash shell。创建一个 ``esp`` 目录作为开发 ESP32 应用的默认地址。运行指令 :: +安装器会自动安装 ESP32 Xtensa gcc 工具链,Ninja_ 编译工具,以及名为 mconf-idf_ 的配置工具。此外,如果你的电脑还未安装有关 CMake_ 和 Python_ 2.7 的安装器,它还可以下载和运行与之对应的安装器。 - mkdir -p ~/esp - -输入 ``cd ~/esp`` 就进入到新创建的目录。如果没有错误信息出现则表明此步骤已完成。 +安装器默认更新 Windows ``Path`` 环境变量,因而上述工具也可在其他环境中运行。如果禁止该选项,则需自行设置 ESP-IDF 所使用的环境(终端或所选 IDE),并配置正确的路径。 +请注意,此安装器仅针对 ESP-IDF 工具包,并不包括 ESP-IDF。 -.. figure:: ../../_static/msys2-terminal-window.png - :align: center - :alt: MSYS2 MINGW32 shell window - :figclass: align-center +安装 Git +============== - MSYS2 终端窗口 +ESP-IDF 工具安装器并不会安装 Git,因为快速入门指南默认你将以命令行的模式使用它。你可以通过 `Git For Windows`_ 下载和安装 Windows 平台的命令行 Git 工具(包括 "Git Bash" 终端)。 -后续步骤将会使用这个窗口来为 ESP32 设置开发环境。 +如果你想使用其他图形化 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-20181001 .. _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/get-started-cmake/get-started-devkitc-v2.rst b/docs/zh_CN/hw-reference/get-started-devkitc-v2.rst similarity index 91% 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..2cd1075866 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]` @@ -9,7 +9,7 @@ ESP32-DevKitC V2 入门指南 (CMake) 准备工作 -------- -* :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,7 +71,8 @@ ESP32-DevKitC V2 开发板 ESP32-DevKitC V2 上电前,请首先确认开发板完好无损。 -之后,请前往 :doc:`index` 的 :ref:`get-started-step-by-step-cmake` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 +之后,请前往 :doc:`../get-started/index` 中的 :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..f75b5f80ae 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]` @@ -9,14 +9,14 @@ ESP32-DevKitC V4 入门指南 (CMake) 准备工作 ----------- -* :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,8 +121,7 @@ C15(黄色)在 ESP32-DevKitC V4 开发板上的位置 ESP32-DevKitC V4 上电前,请首先确认开发板完好无损。 -之后,请前往 :doc:`index` 的 :ref:`get-started-step-by-step-cmake` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 - +之后,请前往 :doc:`../get-started/index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 开发板尺寸 ------------- @@ -149,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-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/get-started-cmake/get-started-pico-kit-v3.rst b/docs/zh_CN/hw-reference/get-started-pico-kit-v3.rst similarity index 93% 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..a63129f83c 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,7 @@ EN 复位按键。 ESP32-PICO-KIT V3 上电前,请首先确认开发板完好无损。 -之后,请前往 :doc:`index` 中的 :ref:`get-started-step-by-step-cmake` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 +之后,请前往 :doc:`../get-started/index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 相关文档 diff --git a/docs/zh_CN/get-started/get-started-pico-kit.rst b/docs/zh_CN/hw-reference/get-started-pico-kit.rst similarity index 96% rename from docs/zh_CN/get-started/get-started-pico-kit.rst rename to docs/zh_CN/hw-reference/get-started-pico-kit.rst index a40887c5ae..10299ea2db 100644 --- a/docs/zh_CN/get-started/get-started-pico-kit.rst +++ b/docs/zh_CN/hw-reference/get-started-pico-kit.rst @@ -1,10 +1,10 @@ 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。 +本指南仅适用于 ESP32-PICO-KIT V4 和 V4.1。ESP32-PICO-KIT V4.1 与 V4 的最大差别在于桥接器,其中 V4 搭载的 CP2102 USB-to-UART 桥接器最高速率为 1 Mbps,V4.1 搭载的 CP2102N 桥接器最高传输速率 3 Mbps。 准备工作 @@ -88,6 +88,7 @@ EN 复位按键。 ================== ============================================================================================================================================= + 电源选项 -------- @@ -105,16 +106,14 @@ EN 复位按键。 管脚说明 ---------- -下表介绍了开发板 I/O 管脚的 **名称** 和 **功能**,具体布局请见 `相关文档`_ 中的原理图。请参考 :ref:`get-started-pico-kit-v4-board-front`。 - - +下表介绍了开发板 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 @@ -142,9 +141,8 @@ Header J2 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 @@ -177,7 +175,6 @@ Header J3 ====== ================= ====== ====================================================== - .. _get-started-pico-kit-v4-pin-notes: 有关上表的说明: @@ -193,7 +190,7 @@ Header J3 ESP32-PICO-KIT 上电前,请首先确认开发板完好无损。 -之后,请前往 :doc:`index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 +之后,请前往 :doc:`../get-started/index` 中的 :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 95% 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..c93c6f7833 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]` @@ -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,7 +167,7 @@ USB 供电 使能 UART 通信 正式开始开发 ^^^^^^^^^^^^^^^^^^ -现在,请前往 :doc:`index` 中的 :ref:`get-started-step-by-step-cmake` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 +请前往 :doc:`../get-started/index` 中的 :ref:`get-started-step-by-step` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 相关文档 @@ -189,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/get-started-cmake/get-started-wrover-kit-v3.rst b/docs/zh_CN/hw-reference/get-started-wrover-kit-v3.rst similarity index 94% 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..0bf1349394 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]` @@ -8,7 +8,7 @@ ESP-WROVER-KIT V3 入门指南(CMake) 准备工作 ------------- -* :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,7 +351,7 @@ USB 供电 使能 UART 通信 正式开始开发 ^^^^^^^^^^^^^^^^^^ -现在,请前往 :doc:`index` 中的 :ref:`get-started-step-by-step-cmake` 章节,查看如何设置开发环境,并尝试将示例项目烧录至您的开发板。 +请前往 :doc:`../get-started/index` 中的 :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 93% 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..98ffae468f 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]` @@ -8,7 +8,7 @@ ESP-WROVER-KIT V4.1 入门指南(CMake) 准备工作 ------------- -* :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,9 @@ USB 供电 使能 UART 通信 正式开始开发 ^^^^^^^^^^^^^^^^^^ -现在,请前往 :doc:`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` 章节。 相关文档 @@ -380,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 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 diff --git a/docs/zh_CN/index.rst b/docs/zh_CN/index.rst index 438e8dd55a..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 @@ -40,7 +40,6 @@ ESP-IDF 编程指南 :hidden: 快速入门 - 快速入门 (CMake 预览版本) API 参考 H/W 参考 API 指南 diff --git a/examples/README.md b/examples/README.md index 62e0b73bd5..9728c32166 100644 --- a/examples/README.md +++ b/examples/README.md @@ -6,7 +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. +* `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. @@ -23,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). -* `make` to build the example. -* Follow the printed instructions to flash, or run `make flash`. +* 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). +* `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/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/a2dp_gatts_coex/main/CMakeLists.txt b/examples/bluetooth/a2dp_gatts_coex/main/CMakeLists.txt deleted file mode 100644 index a55538b5fb..0000000000 --- a/examples/bluetooth/a2dp_gatts_coex/main/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -set(COMPONENT_SRCS "bt_app_av.c" - "bt_app_core.c" - "main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() diff --git a/examples/bluetooth/a2dp_sink/main/CMakeLists.txt b/examples/bluetooth/a2dp_sink/main/CMakeLists.txt deleted file mode 100644 index a55538b5fb..0000000000 --- a/examples/bluetooth/a2dp_sink/main/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -set(COMPONENT_SRCS "bt_app_av.c" - "bt_app_core.c" - "main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() diff --git a/examples/bluetooth/a2dp_source/main/CMakeLists.txt b/examples/bluetooth/a2dp_source/main/CMakeLists.txt deleted file mode 100644 index 98b05a101b..0000000000 --- a/examples/bluetooth/a2dp_source/main/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -set(COMPONENT_SRCS "bt_app_core.c" - "main.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() diff --git a/examples/bluetooth/ble_compatibility_test/main/CMakeLists.txt b/examples/bluetooth/ble_compatibility_test/main/CMakeLists.txt deleted file mode 100644 index 3435b4c563..0000000000 --- a/examples/bluetooth/ble_compatibility_test/main/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -set(COMPONENT_SRCS "ble_compatibility_test.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() diff --git a/examples/bluetooth/ble_eddystone/main/CMakeLists.txt b/examples/bluetooth/ble_eddystone/main/CMakeLists.txt deleted file mode 100644 index 66a4e1aa6c..0000000000 --- a/examples/bluetooth/ble_eddystone/main/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -set(COMPONENT_SRCS "esp_eddystone_api.c" - "esp_eddystone_demo.c") -set(COMPONENT_ADD_INCLUDEDIRS "") - -register_component() diff --git a/examples/bluetooth/ble_hid_device_demo/main/CMakeLists.txt b/examples/bluetooth/ble_hid_device_demo/main/CMakeLists.txt deleted file mode 100644 index 6445d3c5ef..0000000000 --- a/examples/bluetooth/ble_hid_device_demo/main/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -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() - -if(GCC_NOT_5_2_0) - target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-unused-const-variable) -endif() diff --git a/examples/bluetooth/ble_ibeacon/main/CMakeLists.txt b/examples/bluetooth/ble_ibeacon/main/CMakeLists.txt deleted file mode 100644 index 1ae1a02e64..0000000000 --- a/examples/bluetooth/ble_ibeacon/main/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -set(COMPONENT_SRCS "esp_ibeacon_api.c" - "ibeacon_demo.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() diff --git a/examples/bluetooth/ble_throughput/throughput_client/main/CMakeLists.txt b/examples/bluetooth/ble_throughput/throughput_client/main/CMakeLists.txt deleted file mode 100644 index 1fe275526d..0000000000 --- a/examples/bluetooth/ble_throughput/throughput_client/main/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -set(COMPONENT_SRCS "example_ble_client_throughput.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() diff --git a/examples/bluetooth/ble_throughput/throughput_server/main/CMakeLists.txt b/examples/bluetooth/ble_throughput/throughput_server/main/CMakeLists.txt deleted file mode 100644 index 3c1f62ac89..0000000000 --- a/examples/bluetooth/ble_throughput/throughput_server/main/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -set(COMPONENT_SRCS "example_ble_server_throughput.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() 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/ethernet/ethernet/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_ancs/CMakeLists.txt similarity index 91% rename from examples/ethernet/ethernet/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/ble_ancs/CMakeLists.txt index 6a5d19af02..ecfe4e5ad8 100644 --- a/examples/ethernet/ethernet/CMakeLists.txt +++ b/examples/bluetooth/bluedroid/ble/ble_ancs/CMakeLists.txt @@ -4,4 +4,4 @@ cmake_minimum_required(VERSION 3.5) set(SUPPORTED_TARGETS esp32) include($ENV{IDF_PATH}/tools/cmake/project.cmake) -project(ethernet_demo) +project(ble_ancs) diff --git a/examples/bluetooth/bluedroid/ble/ble_ancs/Makefile b/examples/bluetooth/bluedroid/ble/ble_ancs/Makefile new file mode 100644 index 0000000000..a5208ef071 --- /dev/null +++ b/examples/bluetooth/bluedroid/ble/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/bluedroid/ble/ble_ancs/README.md b/examples/bluetooth/bluedroid/ble/ble_ancs/README.md new file mode 100644 index 0000000000..06a7f4625e --- /dev/null +++ b/examples/bluetooth/bluedroid/ble/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/bluedroid/ble/ble_ancs/main/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_ancs/main/CMakeLists.txt new file mode 100644 index 0000000000..7e64fd8041 --- /dev/null +++ b/examples/bluetooth/bluedroid/ble/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/bluedroid/ble/ble_ancs/main/ble_ancs.c b/examples/bluetooth/bluedroid/ble/ble_ancs/main/ble_ancs.c new file mode 100644 index 0000000000..2035b67516 --- /dev/null +++ b/examples/bluetooth/bluedroid/ble/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/bluedroid/ble/ble_ancs/main/ble_ancs.h b/examples/bluetooth/bluedroid/ble/ble_ancs/main/ble_ancs.h new file mode 100644 index 0000000000..64608ea029 --- /dev/null +++ b/examples/bluetooth/bluedroid/ble/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/bluedroid/ble/ble_ancs/main/ble_ancs_demo.c b/examples/bluetooth/bluedroid/ble/ble_ancs/main/ble_ancs_demo.c new file mode 100644 index 0000000000..4dc89b83ac --- /dev/null +++ b/examples/bluetooth/bluedroid/ble/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 EXAMPLE_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(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); + 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(void) +{ + 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/gatt_security_server/main/component.mk b/examples/bluetooth/bluedroid/ble/ble_ancs/main/component.mk similarity index 100% rename from examples/bluetooth/gatt_security_server/main/component.mk rename to examples/bluetooth/bluedroid/ble/ble_ancs/main/component.mk diff --git a/examples/bluetooth/bluedroid/ble/ble_ancs/sdkconfig.defaults b/examples/bluetooth/bluedroid/ble/ble_ancs/sdkconfig.defaults new file mode 100644 index 0000000000..50fc4ba9d8 --- /dev/null +++ b/examples/bluetooth/bluedroid/ble/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= 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/bluedroid/ble/ble_compatibility_test/README.md b/examples/bluetooth/bluedroid/ble/ble_compatibility_test/README.md new file mode 100644 index 0000000000..3102fc5e57 --- /dev/null +++ b/examples/bluetooth/bluedroid/ble/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/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/bluedroid/ble/ble_compatibility_test/esp_ble_compatibility_test_report.md) + + 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/bluedroid/ble/ble_compatibility_test/main/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_compatibility_test/main/CMakeLists.txt new file mode 100644 index 0000000000..99553fec31 --- /dev/null +++ b/examples/bluetooth/bluedroid/ble/ble_compatibility_test/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "ble_compatibility_test.c" + INCLUDE_DIRS ".") \ No newline at end of file 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 99% 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 index fca661d2c1..7c1ca1c0b4 100644 --- a/examples/bluetooth/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/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/bluedroid/ble/ble_eddystone/main/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_eddystone/main/CMakeLists.txt new file mode 100644 index 0000000000..cdd852c570 --- /dev/null +++ b/examples/bluetooth/bluedroid/ble/ble_eddystone/main/CMakeLists.txt @@ -0,0 +1,3 @@ +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_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 99% rename from examples/bluetooth/ble_eddystone/main/esp_eddystone_demo.c rename to examples/bluetooth/bluedroid/ble/ble_eddystone/main/esp_eddystone_demo.c index 525bcd2ae3..f41ebf6c13 100644 --- a/examples/bluetooth/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/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/bluedroid/ble/ble_hid_device_demo/main/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/CMakeLists.txt new file mode 100644 index 0000000000..efba49f6b7 --- /dev/null +++ b/examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/CMakeLists.txt @@ -0,0 +1,9 @@ +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) +endif() 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 99% 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 index e26fa38d9f..b7584735a9 100644 --- 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 @@ -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/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 98% rename from examples/bluetooth/ble_ibeacon/README.md rename to examples/bluetooth/bluedroid/ble/ble_ibeacon/README.md index df698cf904..04b09711b1 100644 --- a/examples/bluetooth/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_ibeacon/main/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_ibeacon/main/CMakeLists.txt new file mode 100644 index 0000000000..50293e2a7b --- /dev/null +++ b/examples/bluetooth/bluedroid/ble/ble_ibeacon/main/CMakeLists.txt @@ -0,0 +1,3 @@ +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_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 99% rename from examples/bluetooth/ble_ibeacon/main/ibeacon_demo.c rename to examples/bluetooth/bluedroid/ble/ble_ibeacon/main/ibeacon_demo.c index dcad4dd4a2..7aa8ae26dc 100644 --- a/examples/bluetooth/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/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 99% rename from examples/bluetooth/ble_spp_client/README.md rename to examples/bluetooth/bluedroid/ble/ble_spp_client/README.md index afae60f766..a384731266 100644 --- a/examples/bluetooth/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/ble/ble_spp_client/main/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_spp_client/main/CMakeLists.txt new file mode 100644 index 0000000000..1b83a293fa --- /dev/null +++ b/examples/bluetooth/bluedroid/ble/ble_spp_client/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "spp_client_demo.c" + INCLUDE_DIRS ".") \ No newline at end of file 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 93% 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 index 03561acb8e..f1a91e9bdd 100644 --- a/examples/bluetooth/ble_spp_client/main/spp_client_demo.c +++ b/examples/bluetooth/bluedroid/ble/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){ @@ -598,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/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/bluedroid/ble/ble_spp_server/main/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_spp_server/main/CMakeLists.txt new file mode 100644 index 0000000000..be4f67ba8d --- /dev/null +++ b/examples/bluetooth/bluedroid/ble/ble_spp_server/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "ble_spp_server_demo.c" + INCLUDE_DIRS ".") \ No newline at end of file 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 99% 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 index 999b047e78..f1eaba16bc 100644 --- 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 @@ -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/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_spp_client/main/component.mk b/examples/bluetooth/bluedroid/ble/ble_spp_server/main/component.mk similarity index 100% rename from examples/bluetooth/ble_spp_client/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 52% rename from examples/bluetooth/ble_throughput/throughput_client/README.md rename to examples/bluetooth/bluedroid/ble/ble_throughput/throughput_client/README.md index 48b6b475ba..d38c4ca5ed 100644 --- a/examples/bluetooth/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_client/main/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_client/main/CMakeLists.txt new file mode 100644 index 0000000000..e4c37ee280 --- /dev/null +++ b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_client/main/CMakeLists.txt @@ -0,0 +1,2 @@ +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_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_spp_server/main/component.mk b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_client/main/component.mk similarity index 100% rename from examples/bluetooth/ble_spp_server/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 99% 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 index b0ca2daa9b..6ae2cee937 100644 --- 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 @@ -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/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 53% rename from examples/bluetooth/ble_throughput/throughput_server/README.md rename to examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/README.md index 47c86410d9..1dc21211c8 100644 --- a/examples/bluetooth/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/ble/ble_throughput/throughput_server/main/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/main/CMakeLists.txt new file mode 100644 index 0000000000..c54e45c928 --- /dev/null +++ b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "example_ble_server_throughput.c" + INCLUDE_DIRS ".") \ No newline at end of file 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_throughput/throughput_client/main/component.mk b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/main/component.mk similarity index 100% rename from examples/bluetooth/ble_throughput/throughput_client/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 99% 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 index 3467104f34..b8a8f621cf 100644 --- 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 @@ -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/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/bluedroid/ble/blufi/README.md b/examples/bluetooth/bluedroid/ble/blufi/README.md new file mode 100644 index 0000000000..c8246023ae --- /dev/null +++ b/examples/bluetooth/bluedroid/ble/blufi/README.md @@ -0,0 +1,18 @@ +ESP-IDF Blufi demo +======================= + +This is the demo for bluetooth config wifi connection to ap. + +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/bluedroid/ble/blufi/main/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/blufi/main/CMakeLists.txt new file mode 100644 index 0000000000..8e40bfbf2f --- /dev/null +++ b/examples/bluetooth/bluedroid/ble/blufi/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "blufi_example_main.c" + "blufi_security.c" + INCLUDE_DIRS ".") \ No newline at end of file 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 99% rename from examples/bluetooth/blufi/main/blufi_example_main.c rename to examples/bluetooth/bluedroid/ble/blufi/main/blufi_example_main.c index 4106dd24eb..bd3b86e219 100644 --- a/examples/bluetooth/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/blufi/main/blufi_security.c b/examples/bluetooth/bluedroid/ble/blufi/main/blufi_security.c similarity index 98% rename from examples/bluetooth/blufi/main/blufi_security.c rename to examples/bluetooth/bluedroid/ble/blufi/main/blufi_security.c index 64b989e741..f790e58e5b 100644 --- a/examples/bluetooth/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/bluetooth/ble_throughput/throughput_server/main/component.mk b/examples/bluetooth/bluedroid/ble/blufi/main/component.mk similarity index 100% rename from examples/bluetooth/ble_throughput/throughput_server/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/bluedroid/ble/gatt_client/main/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/gatt_client/main/CMakeLists.txt new file mode 100644 index 0000000000..82a30b2f71 --- /dev/null +++ b/examples/bluetooth/bluedroid/ble/gatt_client/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "gattc_demo.c" + INCLUDE_DIRS ".") \ No newline at end of file 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/blufi/main/component.mk b/examples/bluetooth/bluedroid/ble/gatt_client/main/component.mk similarity index 100% rename from examples/bluetooth/blufi/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 99% rename from examples/bluetooth/gatt_client/main/gattc_demo.c rename to examples/bluetooth/bluedroid/ble/gatt_client/main/gattc_demo.c index 2bd7798362..e53d85d338 100644 --- a/examples/bluetooth/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/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/bluedroid/ble/gatt_security_client/main/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/gatt_security_client/main/CMakeLists.txt new file mode 100644 index 0000000000..691e1edd29 --- /dev/null +++ b/examples/bluetooth/bluedroid/ble/gatt_security_client/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "example_ble_sec_gattc_demo.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/bluetooth/bt_spp_acceptor/main/component.mk b/examples/bluetooth/bluedroid/ble/gatt_security_client/main/component.mk similarity index 100% rename from examples/bluetooth/bt_spp_acceptor/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 99% 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 index fa9e8914bf..365fb40d8d 100644 --- 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 @@ -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/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/bluedroid/ble/gatt_security_server/main/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/gatt_security_server/main/CMakeLists.txt new file mode 100644 index 0000000000..6514591112 --- /dev/null +++ b/examples/bluetooth/bluedroid/ble/gatt_security_server/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "example_ble_sec_gatts_demo.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/bluetooth/bluedroid/ble/gatt_security_server/main/component.mk b/examples/bluetooth/bluedroid/ble/gatt_security_server/main/component.mk new file mode 100644 index 0000000000..f2f38c36c0 --- /dev/null +++ b/examples/bluetooth/bluedroid/ble/gatt_security_server/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/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 99% 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 index 2c1a8186f7..6cbfb71820 100644 --- 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 @@ -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, @@ -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/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/bluedroid/ble/gatt_server/main/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/gatt_server/main/CMakeLists.txt new file mode 100644 index 0000000000..e950c9ecd0 --- /dev/null +++ b/examples/bluetooth/bluedroid/ble/gatt_server/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "gatts_demo.c" + INCLUDE_DIRS ".") \ No newline at end of file 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/bt_spp_initiator/main/component.mk b/examples/bluetooth/bluedroid/ble/gatt_server/main/component.mk similarity index 100% rename from examples/bluetooth/bt_spp_initiator/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 99% rename from examples/bluetooth/gatt_server/main/gatts_demo.c rename to examples/bluetooth/bluedroid/ble/gatt_server/main/gatts_demo.c index 789f15fdad..ea140e8ccc 100644 --- a/examples/bluetooth/gatt_server/main/gatts_demo.c +++ b/examples/bluetooth/bluedroid/ble/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], @@ -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/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/bluedroid/ble/gatt_server_service_table/main/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/gatt_server_service_table/main/CMakeLists.txt new file mode 100644 index 0000000000..fbe553576b --- /dev/null +++ b/examples/bluetooth/bluedroid/ble/gatt_server_service_table/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "gatts_table_creat_demo.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/bluetooth/bt_spp_vfs_acceptor/main/component.mk b/examples/bluetooth/bluedroid/ble/gatt_server_service_table/main/component.mk similarity index 100% rename from examples/bluetooth/bt_spp_vfs_acceptor/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 99% 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 index e583578652..b6a9abffaf 100644 --- 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 @@ -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/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/bluedroid/ble/gattc_multi_connect/main/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/gattc_multi_connect/main/CMakeLists.txt new file mode 100644 index 0000000000..826febe746 --- /dev/null +++ b/examples/bluetooth/bluedroid/ble/gattc_multi_connect/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "gattc_multi_connect.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/bluetooth/bt_spp_vfs_initiator/main/component.mk b/examples/bluetooth/bluedroid/ble/gattc_multi_connect/main/component.mk similarity index 100% rename from examples/bluetooth/bt_spp_vfs_initiator/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 99% 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 index b6499a7668..175c0f98e6 100644 --- a/examples/bluetooth/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/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 96% rename from examples/bluetooth/a2dp_sink/README.md rename to examples/bluetooth/bluedroid/classic_bt/a2dp_sink/README.md index 9a3c5d611b..cd57b59d7e 100644 --- a/examples/bluetooth/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 -p PORT 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_sink/main/CMakeLists.txt b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/CMakeLists.txt new file mode 100644 index 0000000000..55f2d445aa --- /dev/null +++ b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/CMakeLists.txt @@ -0,0 +1,4 @@ +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_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_sink/main/bt_app_av.c b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_av.c similarity index 99% rename from examples/bluetooth/a2dp_sink/main/bt_app_av.c rename to examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_av.c index 8c2c59924d..17c2edbb3c 100644 --- a/examples/bluetooth/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/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 70% 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 index cd9aa99d5f..7dee9e7f40 100644 --- a/examples/bluetooth/a2dp_gatts_coex/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 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) { @@ -111,3 +115,52 @@ 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(s_ringbuf_i2s, &item_size, (portTickType)portMAX_DELAY); + if (item_size != 0){ + i2s_write(0, data, item_size, &bytes_written, portMAX_DELAY); + vRingbufferReturnItem(s_ringbuf_i2s,(void *)data); + } + } +} + +void bt_i2s_task_start_up(void) +{ + s_ringbuf_i2s = xRingbufferCreate(8 * 1024, RINGBUF_TYPE_BYTEBUF); + if(s_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; + } + + 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(s_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/a2dp_source/main/bt_app_core.h b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_core.h similarity index 91% rename from examples/bluetooth/a2dp_source/main/bt_app_core.h rename to examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/bt_app_core.h index 4415058a71..eaa390de94 100644 --- a/examples/bluetooth/a2dp_source/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/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 99% rename from examples/bluetooth/a2dp_sink/main/main.c rename to examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/main.c index adaf8ff43b..c5a90f0892 100644 --- a/examples/bluetooth/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/a2dp_sink/sdkconfig.defaults b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/sdkconfig.defaults similarity index 81% rename from examples/bluetooth/a2dp_sink/sdkconfig.defaults rename to examples/bluetooth/bluedroid/classic_bt/a2dp_sink/sdkconfig.defaults index 132f512cb2..e27427a3bd 100644 --- a/examples/bluetooth/a2dp_sink/sdkconfig.defaults +++ b/examples/bluetooth/bluedroid/classic_bt/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/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 97% rename from examples/bluetooth/a2dp_source/README.md rename to examples/bluetooth/bluedroid/classic_bt/a2dp_source/README.md index 4e9586ce98..05e0594dbc 100644 --- a/examples/bluetooth/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/a2dp_source/main/CMakeLists.txt b/examples/bluetooth/bluedroid/classic_bt/a2dp_source/main/CMakeLists.txt new file mode 100644 index 0000000000..d0a3885ddb --- /dev/null +++ b/examples/bluetooth/bluedroid/classic_bt/a2dp_source/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "bt_app_core.c" + "main.c" + INCLUDE_DIRS ".") \ No newline at end of file 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_gatts_coex/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_gatts_coex/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 80% rename from examples/bluetooth/a2dp_source/main/main.c rename to examples/bluetooth/bluedroid/classic_bt/a2dp_source/main/main.c index dbf7618b8c..25f66c90fc 100644 --- a/examples/bluetooth/a2dp_source/main/main.c +++ b/examples/bluetooth/bluedroid/classic_bt/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) @@ -96,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(); @@ -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 diff --git a/examples/bluetooth/a2dp_source/sdkconfig.defaults b/examples/bluetooth/bluedroid/classic_bt/a2dp_source/sdkconfig.defaults similarity index 79% rename from examples/bluetooth/a2dp_source/sdkconfig.defaults rename to examples/bluetooth/bluedroid/classic_bt/a2dp_source/sdkconfig.defaults index fbee626500..c7adef6a5f 100644 --- a/examples/bluetooth/a2dp_source/sdkconfig.defaults +++ b/examples/bluetooth/bluedroid/classic_bt/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/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 96% rename from examples/bluetooth/bt_discovery/README.rst rename to examples/bluetooth/bluedroid/classic_bt/bt_discovery/README.rst index 29db5e73c1..d5c857344c 100644 --- a/examples/bluetooth/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_discovery/main/CMakeLists.txt b/examples/bluetooth/bluedroid/classic_bt/bt_discovery/main/CMakeLists.txt new file mode 100644 index 0000000000..4bc23a96f4 --- /dev/null +++ b/examples/bluetooth/bluedroid/classic_bt/bt_discovery/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "bt_discovery.c" + INCLUDE_DIRS ".") \ No newline at end of file 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 99% rename from examples/bluetooth/bt_discovery/main/bt_discovery.c rename to examples/bluetooth/bluedroid/classic_bt/bt_discovery/main/bt_discovery.c index af753cb09e..cb8a687f02 100644 --- a/examples/bluetooth/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/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 78% rename from examples/bluetooth/bt_discovery/sdkconfig.defaults rename to examples/bluetooth/bluedroid/classic_bt/bt_discovery/sdkconfig.defaults index af5b5d9d66..00e3d9971e 100644 --- a/examples/bluetooth/bt_discovery/sdkconfig.defaults +++ b/examples/bluetooth/bluedroid/classic_bt/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/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 93% rename from examples/bluetooth/bt_spp_acceptor/README.rst rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/README.rst index b0a865e41d..d33e353672 100644 --- a/examples/bluetooth/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_acceptor/main/CMakeLists.txt b/examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/main/CMakeLists.txt new file mode 100644 index 0000000000..a71f85ba7c --- /dev/null +++ b/examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "example_spp_acceptor_demo.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/bluetooth/controller_hci_uart/main/component.mk b/examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/main/component.mk similarity index 100% rename from examples/bluetooth/controller_hci_uart/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 98% 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 index feadac1521..c654d86167 100644 --- 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 @@ -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; @@ -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/bt_spp_initiator/sdkconfig.defaults b/examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/sdkconfig.defaults similarity index 92% rename from examples/bluetooth/bt_spp_initiator/sdkconfig.defaults rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/sdkconfig.defaults index 7320428221..ea64364f53 100644 --- a/examples/bluetooth/bt_spp_initiator/sdkconfig.defaults +++ b/examples/bluetooth/bluedroid/classic_bt/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/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 92% rename from examples/bluetooth/bt_spp_initiator/README.rst rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/README.rst index 4d298e18f8..07bf513a1c 100644 --- a/examples/bluetooth/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_initiator/main/CMakeLists.txt b/examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/main/CMakeLists.txt new file mode 100644 index 0000000000..09a976ad1c --- /dev/null +++ b/examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "example_spp_initiator_demo.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/bluetooth/gatt_client/main/component.mk b/examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/main/component.mk similarity index 100% rename from examples/bluetooth/gatt_client/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 98% 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 index a805b73e8b..39705a9901 100644 --- 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 @@ -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); @@ -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/bt_spp_vfs_acceptor/sdkconfig.defaults b/examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/sdkconfig.defaults similarity index 92% rename from examples/bluetooth/bt_spp_vfs_acceptor/sdkconfig.defaults rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/sdkconfig.defaults index 7320428221..ea64364f53 100644 --- a/examples/bluetooth/bt_spp_vfs_acceptor/sdkconfig.defaults +++ b/examples/bluetooth/bluedroid/classic_bt/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/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 90% rename from examples/bluetooth/bt_spp_vfs_acceptor/README.rst rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/README.rst index 76571c45e3..b45593eb62 100644 --- a/examples/bluetooth/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_acceptor/main/CMakeLists.txt b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/main/CMakeLists.txt new file mode 100644 index 0000000000..369e404a15 --- /dev/null +++ b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/main/CMakeLists.txt @@ -0,0 +1,3 @@ +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/gatt_security_client/main/component.mk b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/main/component.mk similarity index 100% rename from examples/bluetooth/gatt_security_client/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 98% 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 index a24d691ecf..d24ea1053b 100644 --- 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 @@ -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; @@ -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/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_initiator/sdkconfig.defaults b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/sdkconfig.defaults similarity index 92% rename from examples/bluetooth/bt_spp_vfs_initiator/sdkconfig.defaults rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/sdkconfig.defaults index 7320428221..ea64364f53 100644 --- a/examples/bluetooth/bt_spp_vfs_initiator/sdkconfig.defaults +++ b/examples/bluetooth/bluedroid/classic_bt/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/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 90% rename from examples/bluetooth/bt_spp_vfs_initiator/README.rst rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/README.rst index efb2513d91..38d9804b9c 100644 --- a/examples/bluetooth/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/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/main/CMakeLists.txt b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/main/CMakeLists.txt new file mode 100644 index 0000000000..03781e4786 --- /dev/null +++ b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/main/CMakeLists.txt @@ -0,0 +1,3 @@ +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/gatt_server/main/component.mk b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/main/component.mk similarity index 100% rename from examples/bluetooth/gatt_server/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 98% 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 index ea8e79987c..9be627fe6d 100644 --- 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 @@ -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); @@ -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/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_acceptor/sdkconfig.defaults b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/sdkconfig.defaults similarity index 92% rename from examples/bluetooth/bt_spp_acceptor/sdkconfig.defaults rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/sdkconfig.defaults index 7320428221..ea64364f53 100644 --- a/examples/bluetooth/bt_spp_acceptor/sdkconfig.defaults +++ b/examples/bluetooth/bluedroid/classic_bt/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 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/bluedroid/coex/a2dp_gatts_coex/main/CMakeLists.txt b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/CMakeLists.txt new file mode 100644 index 0000000000..d1d916efbd --- /dev/null +++ b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/CMakeLists.txt @@ -0,0 +1,5 @@ +idf_component_register(SRCS "bt_app_av.c" + "bt_app_core.c" + "main.c" + INCLUDE_DIRS ".") + 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_gatts_coex/main/bt_app_av.c b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/bt_app_av.c similarity index 99% rename from examples/bluetooth/a2dp_gatts_coex/main/bt_app_av.c rename to examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/bt_app_av.c index 8c2c59924d..17c2edbb3c 100644 --- a/examples/bluetooth/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/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 70% 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 index cd9aa99d5f..7dee9e7f40 100644 --- a/examples/bluetooth/a2dp_sink/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 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) { @@ -111,3 +115,52 @@ 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(s_ringbuf_i2s, &item_size, (portTickType)portMAX_DELAY); + if (item_size != 0){ + i2s_write(0, data, item_size, &bytes_written, portMAX_DELAY); + vRingbufferReturnItem(s_ringbuf_i2s,(void *)data); + } + } +} + +void bt_i2s_task_start_up(void) +{ + s_ringbuf_i2s = xRingbufferCreate(8 * 1024, RINGBUF_TYPE_BYTEBUF); + if(s_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; + } + + 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(s_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/a2dp_sink/main/bt_app_core.h b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/bt_app_core.h similarity index 91% rename from examples/bluetooth/a2dp_sink/main/bt_app_core.h rename to examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/bt_app_core.h index 4415058a71..eaa390de94 100644 --- a/examples/bluetooth/a2dp_sink/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__ */ diff --git a/examples/bluetooth/bt_discovery/main/component.mk b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/component.mk similarity index 100% rename from examples/bluetooth/bt_discovery/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 99% rename from examples/bluetooth/a2dp_gatts_coex/main/main.c rename to examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/main.c index 466a2ce8d6..b69fada106 100644 --- a/examples/bluetooth/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/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/bluedroid/coex/gattc_gatts_coex/CMakeLists.txt b/examples/bluetooth/bluedroid/coex/gattc_gatts_coex/CMakeLists.txt new file mode 100644 index 0000000000..7f8c072493 --- /dev/null +++ b/examples/bluetooth/bluedroid/coex/gattc_gatts_coex/CMakeLists.txt @@ -0,0 +1,7 @@ +# 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) +set(SUPPORTED_TARGETS esp32) +project(gattc_gatts_coex) diff --git a/examples/bluetooth/bluedroid/coex/gattc_gatts_coex/Makefile b/examples/bluetooth/bluedroid/coex/gattc_gatts_coex/Makefile new file mode 100644 index 0000000000..e8b511866a --- /dev/null +++ b/examples/bluetooth/bluedroid/coex/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/bluedroid/coex/gattc_gatts_coex/README.md b/examples/bluetooth/bluedroid/coex/gattc_gatts_coex/README.md new file mode 100644 index 0000000000..0fb1bf6ce1 --- /dev/null +++ b/examples/bluetooth/bluedroid/coex/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/bt_discovery/main/CMakeLists.txt b/examples/bluetooth/bluedroid/coex/gattc_gatts_coex/main/CMakeLists.txt similarity index 58% rename from examples/bluetooth/bt_discovery/main/CMakeLists.txt rename to examples/bluetooth/bluedroid/coex/gattc_gatts_coex/main/CMakeLists.txt index 68ddbfb4c8..a3c8592c8d 100644 --- a/examples/bluetooth/bt_discovery/main/CMakeLists.txt +++ b/examples/bluetooth/bluedroid/coex/gattc_gatts_coex/main/CMakeLists.txt @@ -1,4 +1,4 @@ -set(COMPONENT_SRCS "bt_discovery.c") +set(COMPONENT_SRCS "gattc_gatts_coex.c") set(COMPONENT_ADD_INCLUDEDIRS ".") register_component() diff --git a/examples/bluetooth/gatt_server_service_table/main/component.mk b/examples/bluetooth/bluedroid/coex/gattc_gatts_coex/main/component.mk similarity index 100% rename from examples/bluetooth/gatt_server_service_table/main/component.mk rename to examples/bluetooth/bluedroid/coex/gattc_gatts_coex/main/component.mk 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 new file mode 100644 index 0000000000..00172ebd9b --- /dev/null +++ b/examples/bluetooth/bluedroid/coex/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(void) +{ + 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/bluedroid/coex/gattc_gatts_coex/sdkconfig.defaults b/examples/bluetooth/bluedroid/coex/gattc_gatts_coex/sdkconfig.defaults new file mode 100644 index 0000000000..8dbe56f4f4 --- /dev/null +++ b/examples/bluetooth/bluedroid/coex/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= 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/bluedroid/hci/controller_hci_uart/main/CMakeLists.txt b/examples/bluetooth/bluedroid/hci/controller_hci_uart/main/CMakeLists.txt new file mode 100644 index 0000000000..b4eacc768a --- /dev/null +++ b/examples/bluetooth/bluedroid/hci/controller_hci_uart/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "controller_hci_uart_demo.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/bluetooth/gattc_multi_connect/main/component.mk b/examples/bluetooth/bluedroid/hci/controller_hci_uart/main/component.mk similarity index 100% rename from examples/bluetooth/gattc_multi_connect/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 98% 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 index 0eb7ef7781..6214dec136 100644 --- 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 @@ -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/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/bluedroid/hci/controller_vhci_ble_adv/main/CMakeLists.txt b/examples/bluetooth/bluedroid/hci/controller_vhci_ble_adv/main/CMakeLists.txt new file mode 100644 index 0000000000..494d32308b --- /dev/null +++ b/examples/bluetooth/bluedroid/hci/controller_vhci_ble_adv/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "app_bt.c" + INCLUDE_DIRS ".") \ No newline at end of file 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 99% rename from examples/bluetooth/ble_adv/main/app_bt.c rename to examples/bluetooth/bluedroid/hci/controller_vhci_ble_adv/main/app_bt.c index 0a67c32468..09f78064cf 100644 --- a/examples/bluetooth/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/ethernet/ethernet/main/component.mk b/examples/bluetooth/bluedroid/hci/controller_vhci_ble_adv/main/component.mk similarity index 100% rename from examples/ethernet/ethernet/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/blufi/README.md b/examples/bluetooth/blufi/README.md deleted file mode 100644 index 3b074c72d9..0000000000 --- a/examples/bluetooth/blufi/README.md +++ /dev/null @@ -1,10 +0,0 @@ -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.. - diff --git a/examples/bluetooth/blufi/main/CMakeLists.txt b/examples/bluetooth/blufi/main/CMakeLists.txt deleted file mode 100644 index cbb9b24c36..0000000000 --- a/examples/bluetooth/blufi/main/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -set(COMPONENT_SRCS "blufi_example_main.c" - "blufi_security.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() diff --git a/examples/bluetooth/bt_spp_acceptor/main/CMakeLists.txt b/examples/bluetooth/bt_spp_acceptor/main/CMakeLists.txt deleted file mode 100644 index 0694503f92..0000000000 --- a/examples/bluetooth/bt_spp_acceptor/main/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -set(COMPONENT_SRCS "example_spp_acceptor_demo.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() diff --git a/examples/bluetooth/bt_spp_initiator/main/CMakeLists.txt b/examples/bluetooth/bt_spp_initiator/main/CMakeLists.txt deleted file mode 100644 index 1eae1b74c9..0000000000 --- a/examples/bluetooth/bt_spp_initiator/main/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -set(COMPONENT_SRCS "example_spp_initiator_demo.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() diff --git a/examples/bluetooth/bt_spp_vfs_acceptor/main/CMakeLists.txt b/examples/bluetooth/bt_spp_vfs_acceptor/main/CMakeLists.txt deleted file mode 100644 index b224db80b6..0000000000 --- a/examples/bluetooth/bt_spp_vfs_acceptor/main/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -set(COMPONENT_SRCS "example_spp_vfs_acceptor_demo.c" - "spp_task.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() diff --git a/examples/bluetooth/bt_spp_vfs_initiator/main/CMakeLists.txt b/examples/bluetooth/bt_spp_vfs_initiator/main/CMakeLists.txt deleted file mode 100644 index f3b9111353..0000000000 --- a/examples/bluetooth/bt_spp_vfs_initiator/main/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -set(COMPONENT_SRCS "example_spp_vfs_initiator_demo.c" - "spp_task.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() diff --git a/examples/bluetooth/controller_hci_uart/main/CMakeLists.txt b/examples/bluetooth/controller_hci_uart/main/CMakeLists.txt deleted file mode 100644 index 2f40a64c69..0000000000 --- a/examples/bluetooth/controller_hci_uart/main/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -set(COMPONENT_SRCS "controller_hci_uart_demo.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() 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 new file mode 100644 index 0000000000..d604182bb5 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/CMakeLists.txt @@ -0,0 +1,7 @@ +# 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) +set(SUPPORTED_TARGETS esp32) +project(ble_mesh_client_model) diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/Makefile b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/Makefile new file mode 100644 index 0000000000..384ad8ed5e --- /dev/null +++ b/examples/bluetooth/esp_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/esp_ble_mesh/ble_mesh_client_model/README.md b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/README.md new file mode 100644 index 0000000000..38aa2caee1 --- /dev/null +++ b/examples/bluetooth/esp_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/esp_ble_mesh/ble_mesh_client_model/main/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/main/CMakeLists.txt new file mode 100644 index 0000000000..1eb2d87ed2 --- /dev/null +++ b/examples/bluetooth/esp_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/esp_ble_mesh/ble_mesh_client_model/main/Kconfig.projbuild b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/main/Kconfig.projbuild new file mode 100644 index 0000000000..3bde11ff6d --- /dev/null +++ b/examples/bluetooth/esp_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/esp_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 new file mode 100644 index 0000000000..3dde33207d --- /dev/null +++ b/examples/bluetooth/esp_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/esp_ble_mesh/ble_mesh_client_model/main/board.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/main/board.c new file mode 100644 index 0000000000..d81bc58815 --- /dev/null +++ b/examples/bluetooth/esp_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/esp_ble_mesh/ble_mesh_client_model/main/board.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/main/board.h new file mode 100644 index 0000000000..4ae04b2ed4 --- /dev/null +++ b/examples/bluetooth/esp_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/esp_ble_mesh/ble_mesh_client_model/main/component.mk b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/main/component.mk new file mode 100644 index 0000000000..a98f634eae --- /dev/null +++ b/examples/bluetooth/esp_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/esp_ble_mesh/ble_mesh_client_model/sdkconfig.defaults b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/sdkconfig.defaults new file mode 100644 index 0000000000..e1aee38f72 --- /dev/null +++ b/examples/bluetooth/esp_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/esp_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 new file mode 100644 index 0000000000..49697c2ab0 --- /dev/null +++ b/examples/bluetooth/esp_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/esp_ble_mesh/ble_mesh_client_model/tutorial/images/app.png b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/tutorial/images/app.png new file mode 100644 index 0000000000..9701c13ac9 Binary files /dev/null and b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/tutorial/images/app.png differ diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/tutorial/images/message.png b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/tutorial/images/message.png new file mode 100644 index 0000000000..27745165c8 Binary files /dev/null and b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/tutorial/images/message.png differ diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/tutorial/images/picture5.png b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/tutorial/images/picture5.png new file mode 100644 index 0000000000..ff9329eb14 Binary files /dev/null and b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/tutorial/images/picture5.png differ 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 new file mode 100644 index 0000000000..5e425b2aea --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/CMakeLists.txt @@ -0,0 +1,7 @@ +# 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) +set(SUPPORTED_TARGETS esp32) +project(ble_mesh_console_node) diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/Makefile b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/Makefile new file mode 100644 index 0000000000..209aa2e0cc --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/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_node + +COMPONENT_ADD_INCLUDEDIRS := components/include + +include $(IDF_PATH)/make/project.mk diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/README.md b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/README.md new file mode 100644 index 0000000000..0bb260c816 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/README.md @@ -0,0 +1,9 @@ +# ble mesh node console demo +## Introduction +This demo implements ble mesh node basic features.Based on this demo, node can be scaned and proved by provisioner, reply get/set message to provisioner. + +Demo steps: +1. Build the ble mesh node console demo with sdkconfig.default +2. register node and set oob info, load model to init ble mesh node +3. enable bearer, so that it can be scaned and provisioned by provisioner + diff --git a/examples/bluetooth/esp_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 new file mode 100644 index 0000000000..2275f9a4e0 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/CMakeLists.txt @@ -0,0 +1,12 @@ +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_register_node_cmd.c" + "ble_mesh_register_server_cmd.c" + "register_bluetooth.c") + +set(COMPONENT_ADD_INCLUDEDIRS ".") + +register_component() 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 new file mode 100644 index 0000000000..b8d1775b34 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_adapter.c @@ -0,0 +1,164 @@ +// 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 "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[0]; + break; + case ESP_BLE_MESH_MODEL_ID_CONFIG_CLI: + model = &config_client_models[0]; + break; + 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[1]; + 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(void) +{ + 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 init fail, mesh node semaphore create fail", __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_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); + xSemaphoreGive(ble_mesh_node_sema); +} + +int ble_mesh_node_statistics_accumultate(uint8_t *data, uint32_t value, uint16_t type) +{ + uint16_t i; + uint16_t sequence_num = (data[0] << 8) | data[1]; + + xSemaphoreTake(ble_mesh_node_sema, portMAX_DELAY); + for (i = 0; i < ble_mesh_node_statistics.total_package_num; i++) { + if (ble_mesh_node_statistics.package_index[i] == sequence_num) { + xSemaphoreGive(ble_mesh_node_sema); + return 1; + } + } + + // package type wrong + if (data[2] != type) { + xSemaphoreGive(ble_mesh_node_sema); + return 1; + } + + for (i = 0; i < ble_mesh_node_statistics.total_package_num; i++) { + if (ble_mesh_node_statistics.package_index[i] == 0) { + ble_mesh_node_statistics.package_index[i] = sequence_num; + ble_mesh_node_statistics.package_num += 1; + ble_mesh_node_statistics.statistics += value; + break; + } + } + xSemaphoreGive(ble_mesh_node_sema); + return 0; +} + +int ble_mesh_node_statistics_init(uint16_t package_num) +{ + uint16_t i; + + ble_mesh_node_statistics.package_index = malloc(sizeof(uint16_t) * package_num); + ble_mesh_node_statistics.total_package_num = package_num; + if (ble_mesh_node_statistics.package_index == NULL) { + ESP_LOGE(TAG, " %s, %d malloc fail\n", __func__, __LINE__); + return 1; + } + + ble_mesh_node_statistics.package_num = 0; + for (i = 0; i < package_num; i++) { + ble_mesh_node_statistics.package_index[i] = 0; + } + return 0; +} + +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 new file mode 100644 index 0000000000..d7feee5fe4 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_adapter.h @@ -0,0 +1,97 @@ +// 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 _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_node_console" + +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 { + uint32_t statistics; + uint32_t package_num; + uint16_t *package_index; + uint32_t total_package_num; +} ble_mesh_node_statistics_t; +ble_mesh_node_statistics_t ble_mesh_node_statistics; + +extern SemaphoreHandle_t ble_mesh_node_sema; + +#define arg_int_to_value(src_msg, dst_msg, message) do { \ + if (src_msg->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); +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); +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); + +#endif //_BLE_MESH_ADAOTER_H_ 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 new file mode 100644 index 0000000000..4fa715f0c8 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_cfg_srv_model.c @@ -0,0 +1,208 @@ +// 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 "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/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 new file mode 100644 index 0000000000..eba953c4ec --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_cfg_srv_model.h @@ -0,0 +1,107 @@ +// 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 _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/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 new file mode 100644 index 0000000000..2e983265d3 --- /dev/null +++ b/examples/bluetooth/esp_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(void); + +// Register blutooth +void register_bluetooth(void); + +// Register mesh node cmd +void ble_mesh_register_mesh_node(void); + +// Register mesh config server and generic server operation cmd +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); +#endif 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 new file mode 100644 index 0000000000..efcb6766a7 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_lib.c @@ -0,0 +1,128 @@ +// 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 "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/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 new file mode 100644 index 0000000000..f0e2e77c97 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_lib.h @@ -0,0 +1,31 @@ +// 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 _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/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 new file mode 100644 index 0000000000..5dba3a050b --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_console_main.c @@ -0,0 +1,215 @@ +// 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 +#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(void) +{ + 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(void) +{ + /* 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_ESP_CONSOLE_UART_NUM, + 256, 0, 0, NULL, 0) ); + + /* Tell VFS to use UART driver */ + esp_vfs_dev_uart_use_driver(CONFIG_ESP_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/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 new file mode 100644 index 0000000000..88c0a6a0a9 --- /dev/null +++ b/examples/bluetooth/esp_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(void); +static void register_restart(void); +static void register_make(void); + +void register_system(void) +{ + 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(void) +{ + 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(void) +{ + 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(void) +{ + 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/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 new file mode 100644 index 0000000000..375c224c6c --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_node_cmd.c @@ -0,0 +1,547 @@ +// 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 "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(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_node_cmd(); +} + +int ble_mesh_register_node_cb(int argc, char** argv) +{ + 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(int argc, char** argv) +{ + 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(void) +{ + 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/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 new file mode 100644 index 0000000000..6fcb41d4f5 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/ble_mesh_register_server_cmd.c @@ -0,0 +1,83 @@ +// 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 "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(void); + +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(void) +{ + 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(void) +{ + 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/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/component.mk b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/component.mk new file mode 100644 index 0000000000..0b9d7585e7 --- /dev/null +++ b/examples/bluetooth/esp_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/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 new file mode 100644 index 0000000000..64358ba606 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/main/register_bluetooth.c @@ -0,0 +1,45 @@ +// 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 "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); + +void register_bluetooth(void) +{ + 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(void) +{ + const esp_console_cmd_t cmd = { + .command = "btmac", + .help = "get BT mac address", + .hint = NULL, + .func = &bt_mac, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&cmd)); +} + diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/sdkconfig.defaults b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/sdkconfig.defaults new file mode 100644 index 0000000000..732947bb16 --- /dev/null +++ b/examples/bluetooth/esp_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/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 new file mode 100644 index 0000000000..14941a14e5 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/CMakeLists.txt @@ -0,0 +1,7 @@ +# 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) +set(SUPPORTED_TARGETS esp32) +project(ble_mesh_console_provisioner) diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/Makefile b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/Makefile new file mode 100644 index 0000000000..6c7b6101fa --- /dev/null +++ b/examples/bluetooth/esp_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/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/README.md b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/README.md new file mode 100644 index 0000000000..3925d93cf4 --- /dev/null +++ b/examples/bluetooth/esp_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/esp_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 new file mode 100644 index 0000000000..339b93fc95 --- /dev/null +++ b/examples/bluetooth/esp_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/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 new file mode 100644 index 0000000000..eded5787bb --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.c @@ -0,0 +1,300 @@ +// 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 "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(void) +{ + 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(void) +{ + 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(void) +{ + 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(void) +{ + 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/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 new file mode 100644 index 0000000000..305026c1a9 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_adapter.h @@ -0,0 +1,123 @@ +// 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 _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); +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); +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); + +#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_cfg_srv_model.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_cfg_srv_model.c new file mode 100644 index 0000000000..705ad8d488 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_cfg_srv_model.c @@ -0,0 +1,205 @@ +// 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 "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/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 new file mode 100644 index 0000000000..eba953c4ec --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_cfg_srv_model.h @@ -0,0 +1,107 @@ +// 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 _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/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 new file mode 100644 index 0000000000..3ba4f496db --- /dev/null +++ b/examples/bluetooth/esp_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(void); + +// Register bluetooth +void register_bluetooth(void); + +// Register mesh node cmd +void ble_mesh_register_mesh_node(void); + +// Register Test Perf client cmd +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); +#endif + +#if (CONFIG_BLE_MESH_GENERIC_ONOFF_CLI) +// Register mesh client operation cmd +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); +#endif 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 new file mode 100644 index 0000000000..8116935c2c --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_lib.c @@ -0,0 +1,124 @@ +// 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 "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/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 new file mode 100644 index 0000000000..da4d7c20bf --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_lib.h @@ -0,0 +1,29 @@ +// 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 _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/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 new file mode 100644 index 0000000000..a60f70ee2b --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_console_main.c @@ -0,0 +1,228 @@ +// 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 +#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(void) +{ + 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(void) +{ + /* 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_ESP_CONSOLE_UART_NUM, + 256, 0, 0, NULL, 0) ); + + /* Tell VFS to use UART driver */ + esp_vfs_dev_uart_use_driver(CONFIG_ESP_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/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 new file mode 100644 index 0000000000..de76b11ae7 --- /dev/null +++ b/examples/bluetooth/esp_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(void); +static void register_restart(void); +static void register_make(void); + +void register_system(void) +{ + 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(void) +{ + 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(void) +{ + 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(void) +{ + 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/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 new file mode 100644 index 0000000000..59bae35ced --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_cfg_client_cmd.c @@ -0,0 +1,390 @@ +// 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 "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); +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_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(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"); + 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/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 new file mode 100644 index 0000000000..f9caa8931b --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/main/ble_mesh_reg_gen_onoff_client_cmd.c @@ -0,0 +1,180 @@ +// 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 "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); +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_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(void) +{ + 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, "