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/.gitignore b/.gitignore index f6b52b9f04..48ee2b0f16 100644 --- a/.gitignore +++ b/.gitignore @@ -58,13 +58,6 @@ TEST_LOGS coverage.info coverage_report/ -# Windows tools installer build -tools/windows/tool_setup/.* -tools/windows/tool_setup/input -tools/windows/tool_setup/dl -tools/windows/tool_setup/keys -tools/windows/tool_setup/Output - test_multi_heap_host # VS Code Settings diff --git a/.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..2987412361 100644 --- a/Kconfig +++ b/Kconfig @@ -56,11 +56,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 +70,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..19c9980dd2 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 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/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/test/CMakeLists.txt b/components/app_trace/test/CMakeLists.txt index 884ca8b6da..16aca87790 100644 --- a/components/app_trace/test/CMakeLists.txt +++ b/components/app_trace/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity) - -register_component() \ No newline at end of file +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity) \ No newline at end of file diff --git a/components/app_update/CMakeLists.txt b/components/app_update/CMakeLists.txt index 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/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..bfa7b25bee 100644 --- a/components/app_update/test/test_switch_ota.c +++ b/components/app_update/test/test_switch_ota.c @@ -296,7 +296,7 @@ static void test_flow1(void) // 3 Stage: run OTA0 -> check it -> copy OTA0 to OTA1 -> reboot --//-- // 4 Stage: run OTA1 -> check it -> copy OTA1 to OTA0 -> reboot --//-- // 5 Stage: run OTA0 -> check it -> erase OTA_DATA for next tests -> PASS -TEST_CASE_MULTIPLE_STAGES("Switching between factory, OTA0, OTA1, OTA0", "[app_update][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow1, test_flow1, test_flow1, test_flow1); +TEST_CASE_MULTIPLE_STAGES("Switching between factory, OTA0, OTA1, OTA0", "[app_update][timeout=90][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow1, test_flow1, test_flow1, test_flow1); static void test_flow2(void) { @@ -333,7 +333,7 @@ static void test_flow2(void) // 2 Stage: run factory -> check it -> copy factory to OTA0 -> reboot --//-- // 3 Stage: run OTA0 -> check it -> corrupt ota data -> reboot --//-- // 4 Stage: run factory -> check it -> erase OTA_DATA for next tests -> PASS -TEST_CASE_MULTIPLE_STAGES("Switching between factory, OTA0, corrupt ota_sec1, factory", "[app_update][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow2, test_flow2, test_flow2); +TEST_CASE_MULTIPLE_STAGES("Switching between factory, OTA0, corrupt ota_sec1, factory", "[app_update][timeout=90][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow2, test_flow2, test_flow2); static void test_flow3(void) { @@ -377,7 +377,7 @@ static void test_flow3(void) // 3 Stage: run OTA0 -> check it -> copy OTA0 to OTA1 -> reboot --//-- // 3 Stage: run OTA1 -> check it -> corrupt ota sector2 -> reboot --//-- // 4 Stage: run OTA0 -> check it -> erase OTA_DATA for next tests -> PASS -TEST_CASE_MULTIPLE_STAGES("Switching between factory, OTA0, OTA1, currupt ota_sec2, OTA0", "[app_update][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow3, test_flow3, test_flow3, test_flow3); +TEST_CASE_MULTIPLE_STAGES("Switching between factory, OTA0, OTA1, currupt ota_sec2, OTA0", "[app_update][timeout=90][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow3, test_flow3, test_flow3, test_flow3); #ifdef CONFIG_BOOTLOADER_FACTORY_RESET #define STORAGE_NAMESPACE "update_ota" @@ -444,7 +444,7 @@ static void test_flow4(void) // 2 Stage: run factory -> check it -> copy factory to OTA0 -> reboot --//-- // 3 Stage: run OTA0 -> check it -> set_pin_factory_reset -> reboot --//-- // 4 Stage: run factory -> check it -> erase OTA_DATA for next tests -> PASS -TEST_CASE_MULTIPLE_STAGES("Switching between factory, OTA0, sets pin_factory_reset, factory", "[app_update][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow4, test_flow4, test_flow4); +TEST_CASE_MULTIPLE_STAGES("Switching between factory, OTA0, sets pin_factory_reset, factory", "[app_update][timeout=90][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow4, test_flow4, test_flow4); #endif #ifdef CONFIG_BOOTLOADER_APP_TEST @@ -487,7 +487,7 @@ static void test_flow5(void) // 2 Stage: run factory -> check it -> copy factory to Test and set pin_test_app -> reboot --//-- // 3 Stage: run test -> check it -> reset pin_test_app -> reboot --//-- // 4 Stage: run factory -> check it -> erase OTA_DATA for next tests -> PASS -TEST_CASE_MULTIPLE_STAGES("Switching between factory, test, factory", "[app_update][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow5, test_flow5, test_flow5); +TEST_CASE_MULTIPLE_STAGES("Switching between factory, test, factory", "[app_update][timeout=90][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow5, test_flow5, test_flow5); #endif static const esp_partition_t* app_update(void) @@ -581,7 +581,7 @@ static void test_rollback1_1(void) // 3 Stage: run OTA0 -> check it -> esp_ota_mark_app_valid_cancel_rollback() -> reboot --//-- // 4 Stage: run OTA0 -> check it -> esp_ota_mark_app_invalid_rollback_and_reboot() -> reboot // 5 Stage: run factory -> check it -> erase OTA_DATA for next tests -> PASS -TEST_CASE_MULTIPLE_STAGES("Test rollback. factory, OTA0, OTA0, rollback -> factory", "[app_update][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET, SW_CPU_RESET]", start_test, test_rollback1, test_rollback1, test_rollback1, test_rollback1_1); +TEST_CASE_MULTIPLE_STAGES("Test rollback. factory, OTA0, OTA0, rollback -> factory", "[app_update][timeout=90][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET, SW_CPU_RESET]", start_test, test_rollback1, test_rollback1, test_rollback1, test_rollback1_1); static void test_rollback2(void) { @@ -679,7 +679,7 @@ static void test_rollback2_1(void) // 3 Stage: run OTA0 -> check it -> esp_ota_mark_app_valid_cancel_rollback(), copy to next app slot -> reboot --//-- // 4 Stage: run OTA1 -> check it -> PENDING_VERIFY/esp_ota_mark_app_invalid_rollback_and_reboot() -> reboot // 5 Stage: run OTA0(rollback) -> check it -> erase OTA_DATA for next tests -> PASS -TEST_CASE_MULTIPLE_STAGES("Test rollback. factory, OTA0, OTA1, rollback -> OTA0", "[app_update][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET, SW_CPU_RESET]", start_test, test_rollback2, test_rollback2, test_rollback2, test_rollback2_1); +TEST_CASE_MULTIPLE_STAGES("Test rollback. factory, OTA0, OTA1, rollback -> OTA0", "[app_update][timeout=90][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET, SW_CPU_RESET]", start_test, test_rollback2, test_rollback2, test_rollback2, test_rollback2_1); static void test_erase_last_app_flow(void) { @@ -730,4 +730,4 @@ static void test_erase_last_app_rollback(void) // 3 Stage: run OTA0 -> check it -> copy factory to OTA1 -> reboot --//-- // 4 Stage: run OTA1 -> check it -> erase OTA0 and rollback -> reboot // 5 Stage: run factory -> check it -> erase OTA_DATA for next tests -> PASS -TEST_CASE_MULTIPLE_STAGES("Test erase_last_boot_app_partition. factory, OTA1, OTA0, factory", "[app_update][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET, SW_CPU_RESET]", start_test, test_erase_last_app_flow, test_erase_last_app_flow, test_erase_last_app_flow, test_erase_last_app_rollback); +TEST_CASE_MULTIPLE_STAGES("Test erase_last_boot_app_partition. factory, OTA1, OTA0, factory", "[app_update][timeout=90][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET, SW_CPU_RESET]", start_test, test_erase_last_app_flow, test_erase_last_app_flow, test_erase_last_app_flow, test_erase_last_app_rollback); 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_support/CMakeLists.txt b/components/bootloader_support/CMakeLists.txt index 3b0ce529c2..df7023a120 100644 --- a/components/bootloader_support/CMakeLists.txt +++ b/components/bootloader_support/CMakeLists.txt @@ -1,64 +1,70 @@ -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_encrypt.c" + "src/flash_partitions.c" + "src/flash_qio_mode.c" + "src/${IDF_TARGET}/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() + set(include_dirs "include" "include_bootloader") + set(priv_requires micro-ecc spi_flash efuse) + list(APPEND srcs + "src/bootloader_init.c" + "src/${IDF_TARGET}/bootloader_sha.c" + "src/${IDF_TARGET}/flash_encrypt.c" + "src/${IDF_TARGET}/secure_boot_signatures.c" + "src/${IDF_TARGET}/secure_boot.c" + "src/${IDF_TARGET}/bootloader_${IDF_TARGET}.c" + "src/${IDF_TARGET}/bootloader_clock_${IDF_TARGET}.c" + ) 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) + 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() -register_component() \ No newline at end of file +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/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..d6a02dc6c2 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 */ @@ -148,3 +152,7 @@ esp_err_t bootloader_common_get_partition_description(const esp_partition_pos_t * @brief Configure VDDSDIO, call this API to rise VDDSDIO to 1.9V when VDDSDIO regulator is enabled as 1.8V mode. */ void bootloader_common_vddsdio_configure(); + +#ifdef __cplusplus +} +#endif diff --git a/components/bootloader_support/include/bootloader_flash_config.h b/components/bootloader_support/include/bootloader_flash_config.h new file mode 100644 index 0000000000..2f716cce2a --- /dev/null +++ b/components/bootloader_support/include/bootloader_flash_config.h @@ -0,0 +1,71 @@ +// Copyright 2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "esp_image_format.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Update the flash id in g_rom_flashchip(global esp_rom_spiflash_chip_t structure). + * + * @return None + */ +void bootloader_flash_update_id(); + +/** + * @brief Set the flash CS setup and hold time. + * + * @note CS setup time is recomemded to be 1.5T, and CS hold time is recommended to be 2.5T. + * cs_setup = 1, cs_setup_time = 0; cs_hold = 1, cs_hold_time = 1. + * + * @return None + */ +void bootloader_flash_cs_timing_config(); + +/** + * @brief Configure SPI flash clock. + * + * @note This function only set clock frequency for SPI0. + * + * @param pfhdr Pointer to App image header, from where to fetch flash settings. + * + * @return None + */ +void bootloader_flash_clock_config(const esp_image_header_t* pfhdr); + +/** + * @brief Configure SPI flash gpio, include the IO matrix and drive strength configuration. + * + * @param pfhdr Pointer to App image header, from where to fetch flash settings. + * + * @return None + */ +void bootloader_flash_gpio_config(const esp_image_header_t* pfhdr); + +/** + * @brief Configure SPI flash read dummy based on different mode and frequency. + * + * @param pfhdr Pointer to App image header, from where to fetch flash settings. + * + * @return None + */ +void bootloader_flash_dummy_config(const esp_image_header_t* pfhdr); + +#ifdef __cplusplus +} +#endif diff --git a/components/bootloader_support/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..27f8f9c473 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. * - * @return */ void esp_flash_write_protect_crypt_cnt(); +/** @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 + */ +esp_flash_enc_mode_t esp_get_flash_encryption_mode(); + +#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..6ac7246462 100644 --- a/components/bootloader_support/include_bootloader/bootloader_flash.h +++ b/components/bootloader_support/include_bootloader/bootloader_flash.h @@ -30,6 +30,13 @@ bootloader_support components only. */ +/** + * @brief Get number of free pages + * + * @return Number of free pages + */ +uint32_t bootloader_mmap_get_free_pages(); + /** * @brief Map a region of flash to data memory * diff --git a/components/bootloader_support/src/bootloader_flash.c b/components/bootloader_support/src/bootloader_flash.c index c58f9fa059..2169ab1e48 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() +{ + 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() +{ + /** + * 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_init.c b/components/bootloader_support/src/bootloader_init.c index 362d550916..19d72b7902 100644 --- a/components/bootloader_support/src/bootloader_init.c +++ b/components/bootloader_support/src/bootloader_init.c @@ -70,6 +70,7 @@ #include "bootloader_common.h" #include "bootloader_clock.h" #include "bootloader_common.h" +#include "bootloader_flash_config.h" #include "flash_qio_mode.h" @@ -83,7 +84,7 @@ static const char *TAG = "boot"; static esp_err_t bootloader_main(); static void print_flash_info(const esp_image_header_t *pfhdr); static void update_flash_config(const esp_image_header_t *pfhdr); -static void flash_gpio_configure(const esp_image_header_t *pfhdr); +static void bootloader_init_flash_configure(const esp_image_header_t* pfhdr); static void uart_console_configure(void); static void wdt_reset_check(void); @@ -169,7 +170,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(); @@ -358,134 +359,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) diff --git a/components/bootloader_support/src/esp32/bootloader_flash_config_esp32.c b/components/bootloader_support/src/esp32/bootloader_flash_config_esp32.c new file mode 100644 index 0000000000..53360848a3 --- /dev/null +++ b/components/bootloader_support/src/esp32/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() +{ + g_rom_flashchip.device_id = bootloader_read_flash_id(); +} + +void IRAM_ATTR bootloader_flash_cs_timing_config() +{ + SET_PERI_REG_MASK(SPI_USER_REG(0), SPI_CS_HOLD_M | SPI_CS_SETUP_M); + SET_PERI_REG_BITS(SPI_CTRL2_REG(0), SPI_HOLD_TIME_V, 1, SPI_HOLD_TIME_S); + SET_PERI_REG_BITS(SPI_CTRL2_REG(0), SPI_SETUP_TIME_V, 0, SPI_SETUP_TIME_S); + SET_PERI_REG_MASK(SPI_USER_REG(1), SPI_CS_HOLD_M | SPI_CS_SETUP_M); + SET_PERI_REG_BITS(SPI_CTRL2_REG(1), SPI_HOLD_TIME_V, 1, SPI_HOLD_TIME_S); + SET_PERI_REG_BITS(SPI_CTRL2_REG(1), SPI_SETUP_TIME_V, 0, SPI_SETUP_TIME_S); +} + +void IRAM_ATTR bootloader_flash_clock_config(const esp_image_header_t* pfhdr) +{ + uint32_t spi_clk_div = 0; + switch (pfhdr->spi_speed) { + case ESP_IMAGE_SPI_SPEED_80M: + spi_clk_div = 1; + break; + case ESP_IMAGE_SPI_SPEED_40M: + spi_clk_div = 2; + break; + case ESP_IMAGE_SPI_SPEED_26M: + spi_clk_div = 3; + break; + case ESP_IMAGE_SPI_SPEED_20M: + spi_clk_div = 4; + break; + default: + break; + } + esp_rom_spiflash_config_clk(spi_clk_div, 0); +} + +void IRAM_ATTR bootloader_flash_gpio_config(const esp_image_header_t* pfhdr) +{ + uint32_t drv = 2; + if (pfhdr->spi_speed == ESP_IMAGE_SPI_SPEED_80M) { + drv = 3; + } + + uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_PKG); + uint32_t pkg_ver = chip_ver & 0x7; + + if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5) { + // For ESP32D2WD the SPI pins are already configured + // flash clock signal should come from IO MUX. + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK); + SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S); + } else if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD2) { + // For ESP32PICOD2 the SPI pins are already configured + // flash clock signal should come from IO MUX. + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK); + SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S); + } else if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4) { + // For ESP32PICOD4 the SPI pins are already configured + // flash clock signal should come from IO MUX. + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK); + SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S); + } else { + const uint32_t spiconfig = ets_efuse_get_spiconfig(); + if (spiconfig == EFUSE_SPICONFIG_SPI_DEFAULTS) { + gpio_matrix_out(SPI_IOMUX_PIN_NUM_CS, SPICS0_OUT_IDX, 0, 0); + gpio_matrix_out(SPI_IOMUX_PIN_NUM_MISO, SPIQ_OUT_IDX, 0, 0); + gpio_matrix_in(SPI_IOMUX_PIN_NUM_MISO, SPIQ_IN_IDX, 0); + gpio_matrix_out(SPI_IOMUX_PIN_NUM_MOSI, SPID_OUT_IDX, 0, 0); + gpio_matrix_in(SPI_IOMUX_PIN_NUM_MOSI, SPID_IN_IDX, 0); + gpio_matrix_out(SPI_IOMUX_PIN_NUM_WP, SPIWP_OUT_IDX, 0, 0); + gpio_matrix_in(SPI_IOMUX_PIN_NUM_WP, SPIWP_IN_IDX, 0); + gpio_matrix_out(SPI_IOMUX_PIN_NUM_HD, SPIHD_OUT_IDX, 0, 0); + gpio_matrix_in(SPI_IOMUX_PIN_NUM_HD, SPIHD_IN_IDX, 0); + //select pin function gpio + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, PIN_FUNC_GPIO); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, PIN_FUNC_GPIO); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA2_U, PIN_FUNC_GPIO); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA3_U, PIN_FUNC_GPIO); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, PIN_FUNC_GPIO); + // flash clock signal should come from IO MUX. + // set drive ability for clock + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK); + SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S); + + uint32_t flash_id = g_rom_flashchip.device_id; + if (flash_id == FLASH_ID_GD25LQ32C) { + // Set drive ability for 1.8v flash in 80Mhz. + SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA0_U, FUN_DRV, 3, FUN_DRV_S); + SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA1_U, FUN_DRV, 3, FUN_DRV_S); + SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA2_U, FUN_DRV, 3, FUN_DRV_S); + SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA3_U, FUN_DRV, 3, FUN_DRV_S); + SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CMD_U, FUN_DRV, 3, FUN_DRV_S); + SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, 3, FUN_DRV_S); + } + } + } +} + +void IRAM_ATTR bootloader_flash_dummy_config(const esp_image_header_t* pfhdr) +{ + int spi_cache_dummy = 0; + uint32_t modebit = READ_PERI_REG(SPI_CTRL_REG(0)); + if (modebit & SPI_FASTRD_MODE) { + if (modebit & SPI_FREAD_QIO) { //SPI mode is QIO + spi_cache_dummy = SPI0_R_QIO_DUMMY_CYCLELEN; + } else if (modebit & SPI_FREAD_DIO) { //SPI mode is DIO + spi_cache_dummy = SPI0_R_DIO_DUMMY_CYCLELEN; + SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_ADDR_BITLEN_V, SPI0_R_DIO_ADDR_BITSLEN, SPI_USR_ADDR_BITLEN_S); + } else if(modebit & (SPI_FREAD_QUAD | SPI_FREAD_DUAL)) { //SPI mode is QOUT or DIO + spi_cache_dummy = SPI0_R_FAST_DUMMY_CYCLELEN; + } + } + + extern uint8_t g_rom_spiflash_dummy_len_plus[]; + switch (pfhdr->spi_speed) { + case ESP_IMAGE_SPI_SPEED_80M: + g_rom_spiflash_dummy_len_plus[0] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_80M; + g_rom_spiflash_dummy_len_plus[1] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_80M; + break; + case ESP_IMAGE_SPI_SPEED_40M: + g_rom_spiflash_dummy_len_plus[0] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_40M; + g_rom_spiflash_dummy_len_plus[1] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_40M; + break; + case ESP_IMAGE_SPI_SPEED_26M: + case ESP_IMAGE_SPI_SPEED_20M: + g_rom_spiflash_dummy_len_plus[0] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_20M; + g_rom_spiflash_dummy_len_plus[1] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_20M; + break; + default: + break; + } + + SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_DUMMY_CYCLELEN_V, spi_cache_dummy + g_rom_spiflash_dummy_len_plus[0], + SPI_USR_DUMMY_CYCLELEN_S); +} \ No newline at end of file diff --git a/components/bootloader_support/src/esp32/flash_encrypt.c b/components/bootloader_support/src/esp32/flash_encrypt.c index 78c40ddf97..f79b478876 100644 --- a/components/bootloader_support/src/esp32/flash_encrypt.c +++ b/components/bootloader_support/src/esp32/flash_encrypt.c @@ -27,6 +27,12 @@ #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 */ @@ -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"); @@ -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_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/bootloader_flash_config_esp32s2.c b/components/bootloader_support/src/esp32s2beta/bootloader_flash_config_esp32s2.c new file mode 100644 index 0000000000..fbb9eb676a --- /dev/null +++ b/components/bootloader_support/src/esp32s2beta/bootloader_flash_config_esp32s2.c @@ -0,0 +1,109 @@ +// 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 "esp32/rom/gpio.h" +#include "esp32/rom/spi_flash.h" +#include "esp32/rom/efuse.h" +#include "soc/gpio_periph.h" +#include "soc/efuse_reg.h" +#include "soc/spi_reg.h" +#include "soc/spi_caps.h" +#include "flash_qio_mode.h" +#include "bootloader_flash_config.h" + +void bootloader_flash_update_id() +{ + g_rom_flashchip.device_id = bootloader_read_flash_id(); +} + +void IRAM_ATTR bootloader_flash_cs_timing_config() +{ + SET_PERI_REG_MASK(SPI_USER_REG(0), SPI_CS_HOLD_M | SPI_CS_SETUP_M); + SET_PERI_REG_BITS(SPI_CTRL2_REG(0), SPI_HOLD_TIME_V, 1, SPI_HOLD_TIME_S); + SET_PERI_REG_BITS(SPI_CTRL2_REG(0), SPI_SETUP_TIME_V, 0, SPI_SETUP_TIME_S); + SET_PERI_REG_MASK(SPI_USER_REG(1), SPI_CS_HOLD_M | SPI_CS_SETUP_M); + SET_PERI_REG_BITS(SPI_CTRL2_REG(1), SPI_HOLD_TIME_V, 1, SPI_HOLD_TIME_S); + SET_PERI_REG_BITS(SPI_CTRL2_REG(1), SPI_SETUP_TIME_V, 0, SPI_SETUP_TIME_S); +} + +void IRAM_ATTR bootloader_flash_clock_config(const esp_image_header_t* pfhdr) +{ + uint32_t spi_clk_div = 0; + switch (pfhdr->spi_speed) { + case ESP_IMAGE_SPI_SPEED_80M: + spi_clk_div = 1; + break; + case ESP_IMAGE_SPI_SPEED_40M: + spi_clk_div = 2; + break; + case ESP_IMAGE_SPI_SPEED_26M: + spi_clk_div = 3; + break; + case ESP_IMAGE_SPI_SPEED_20M: + spi_clk_div = 4; + break; + default: + break; + } + esp_rom_spiflash_config_clk(spi_clk_div, 0); +} + +void IRAM_ATTR bootloader_flash_gpio_config(const esp_image_header_t* pfhdr) +{ + +} + +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_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 + +} 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..606cb79fb6 --- /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() +{ + 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() +{ + 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/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 98% rename from components/bt/bt.c rename to components/bt/controller/bt.c index 2c665f20ac..db19faea22 100644 --- a/components/bt/bt.c +++ b/components/bt/controller/bt.c @@ -234,10 +234,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; @@ -1045,6 +1049,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; } diff --git a/components/bt/controller/lib b/components/bt/controller/lib new file mode 160000 index 0000000000..cc2fd1177d --- /dev/null +++ b/components/bt/controller/lib @@ -0,0 +1 @@ +Subproject commit cc2fd1177d97f1a4b9e0d819035ddf52ba77079d 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 95% rename from components/bt/bluedroid/api/esp_spp_api.c rename to components/bt/host/bluedroid/api/esp_spp_api.c index 46878d659e..57c2e317ae 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) { 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 100% rename from components/bt/bluedroid/api/include/api/esp_spp_api.h rename to components/bt/host/bluedroid/api/include/api/esp_spp_api.h diff --git a/components/bt/bluedroid/bta/ar/bta_ar.c b/components/bt/host/bluedroid/bta/ar/bta_ar.c similarity index 100% rename from components/bt/bluedroid/bta/ar/bta_ar.c rename to components/bt/host/bluedroid/bta/ar/bta_ar.c diff --git a/components/bt/bluedroid/bta/ar/include/bta_ar_int.h b/components/bt/host/bluedroid/bta/ar/include/bta_ar_int.h similarity index 100% rename from components/bt/bluedroid/bta/ar/include/bta_ar_int.h rename to components/bt/host/bluedroid/bta/ar/include/bta_ar_int.h diff --git a/components/bt/bluedroid/bta/av/bta_av_aact.c b/components/bt/host/bluedroid/bta/av/bta_av_aact.c similarity index 100% rename from components/bt/bluedroid/bta/av/bta_av_aact.c rename to components/bt/host/bluedroid/bta/av/bta_av_aact.c diff --git a/components/bt/bluedroid/bta/av/bta_av_act.c b/components/bt/host/bluedroid/bta/av/bta_av_act.c similarity index 100% rename from components/bt/bluedroid/bta/av/bta_av_act.c rename to components/bt/host/bluedroid/bta/av/bta_av_act.c diff --git a/components/bt/bluedroid/bta/av/bta_av_api.c b/components/bt/host/bluedroid/bta/av/bta_av_api.c similarity index 100% rename from components/bt/bluedroid/bta/av/bta_av_api.c rename to components/bt/host/bluedroid/bta/av/bta_av_api.c diff --git a/components/bt/bluedroid/bta/av/bta_av_cfg.c b/components/bt/host/bluedroid/bta/av/bta_av_cfg.c similarity index 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..d62974ea2e 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 }; 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..5b0978bf59 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); 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..a336c23147 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 @@ -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 100% rename from components/bt/bluedroid/bta/hf_client/bta_hf_client_at.c rename to components/bt/host/bluedroid/bta/hf_client/bta_hf_client_at.c diff --git a/components/bt/bluedroid/bta/hf_client/bta_hf_client_cmd.c b/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_cmd.c similarity index 100% rename from components/bt/bluedroid/bta/hf_client/bta_hf_client_cmd.c rename to components/bt/host/bluedroid/bta/hf_client/bta_hf_client_cmd.c diff --git a/components/bt/bluedroid/bta/hf_client/bta_hf_client_main.c b/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_main.c similarity index 100% rename from components/bt/bluedroid/bta/hf_client/bta_hf_client_main.c rename to components/bt/host/bluedroid/bta/hf_client/bta_hf_client_main.c diff --git a/components/bt/bluedroid/bta/hf_client/bta_hf_client_rfc.c b/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_rfc.c similarity index 100% rename from components/bt/bluedroid/bta/hf_client/bta_hf_client_rfc.c rename to components/bt/host/bluedroid/bta/hf_client/bta_hf_client_rfc.c diff --git a/components/bt/bluedroid/bta/hf_client/bta_hf_client_sco.c b/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_sco.c similarity index 100% rename from components/bt/bluedroid/bta/hf_client/bta_hf_client_sco.c rename to components/bt/host/bluedroid/bta/hf_client/bta_hf_client_sco.c diff --git a/components/bt/bluedroid/bta/hf_client/bta_hf_client_sdp.c b/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_sdp.c similarity index 100% rename from components/bt/bluedroid/bta/hf_client/bta_hf_client_sdp.c rename to components/bt/host/bluedroid/bta/hf_client/bta_hf_client_sdp.c diff --git a/components/bt/bluedroid/bta/hf_client/include/bta_hf_client_at.h b/components/bt/host/bluedroid/bta/hf_client/include/bta_hf_client_at.h similarity index 100% rename from components/bt/bluedroid/bta/hf_client/include/bta_hf_client_at.h rename to components/bt/host/bluedroid/bta/hf_client/include/bta_hf_client_at.h diff --git a/components/bt/bluedroid/bta/hf_client/include/bta_hf_client_int.h b/components/bt/host/bluedroid/bta/hf_client/include/bta_hf_client_int.h similarity index 100% rename from components/bt/bluedroid/bta/hf_client/include/bta_hf_client_int.h rename to components/bt/host/bluedroid/bta/hf_client/include/bta_hf_client_int.h diff --git a/components/bt/bluedroid/bta/hh/bta_hh_act.c b/components/bt/host/bluedroid/bta/hh/bta_hh_act.c similarity index 100% rename from components/bt/bluedroid/bta/hh/bta_hh_act.c rename to components/bt/host/bluedroid/bta/hh/bta_hh_act.c diff --git a/components/bt/bluedroid/bta/hh/bta_hh_api.c b/components/bt/host/bluedroid/bta/hh/bta_hh_api.c similarity index 100% rename from components/bt/bluedroid/bta/hh/bta_hh_api.c rename to components/bt/host/bluedroid/bta/hh/bta_hh_api.c diff --git a/components/bt/bluedroid/bta/hh/bta_hh_cfg.c b/components/bt/host/bluedroid/bta/hh/bta_hh_cfg.c similarity index 100% rename from components/bt/bluedroid/bta/hh/bta_hh_cfg.c rename to components/bt/host/bluedroid/bta/hh/bta_hh_cfg.c diff --git a/components/bt/bluedroid/bta/hh/bta_hh_le.c b/components/bt/host/bluedroid/bta/hh/bta_hh_le.c similarity index 100% rename from components/bt/bluedroid/bta/hh/bta_hh_le.c rename to components/bt/host/bluedroid/bta/hh/bta_hh_le.c diff --git a/components/bt/bluedroid/bta/hh/bta_hh_main.c b/components/bt/host/bluedroid/bta/hh/bta_hh_main.c similarity index 100% rename from components/bt/bluedroid/bta/hh/bta_hh_main.c rename to components/bt/host/bluedroid/bta/hh/bta_hh_main.c diff --git a/components/bt/bluedroid/bta/hh/bta_hh_utils.c b/components/bt/host/bluedroid/bta/hh/bta_hh_utils.c similarity index 100% rename from components/bt/bluedroid/bta/hh/bta_hh_utils.c rename to components/bt/host/bluedroid/bta/hh/bta_hh_utils.c diff --git a/components/bt/bluedroid/bta/hh/include/bta_hh_int.h b/components/bt/host/bluedroid/bta/hh/include/bta_hh_int.h similarity index 100% rename from components/bt/bluedroid/bta/hh/include/bta_hh_int.h rename to components/bt/host/bluedroid/bta/hh/include/bta_hh_int.h diff --git a/components/bt/bluedroid/bta/include/bta/bta_api.h b/components/bt/host/bluedroid/bta/include/bta/bta_api.h similarity index 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..664536ddd1 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, @@ -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 100% rename from components/bt/bluedroid/bta/jv/bta_jv_act.c rename to components/bt/host/bluedroid/bta/jv/bta_jv_act.c diff --git a/components/bt/bluedroid/bta/jv/bta_jv_api.c b/components/bt/host/bluedroid/bta/jv/bta_jv_api.c similarity index 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 100% rename from components/bt/bluedroid/btc/core/btc_profile_queue.c rename to components/bt/host/bluedroid/btc/core/btc_profile_queue.c diff --git a/components/bt/bluedroid/btc/core/btc_sec.c b/components/bt/host/bluedroid/btc/core/btc_sec.c similarity index 100% rename from components/bt/bluedroid/btc/core/btc_sec.c rename to components/bt/host/bluedroid/btc/core/btc_sec.c diff --git a/components/bt/bluedroid/btc/core/btc_sm.c b/components/bt/host/bluedroid/btc/core/btc_sm.c similarity index 100% rename from components/bt/bluedroid/btc/core/btc_sm.c rename to components/bt/host/bluedroid/btc/core/btc_sm.c diff --git a/components/bt/bluedroid/btc/core/btc_storage.c b/components/bt/host/bluedroid/btc/core/btc_storage.c similarity index 100% rename from components/bt/bluedroid/btc/core/btc_storage.c rename to components/bt/host/bluedroid/btc/core/btc_storage.c diff --git a/components/bt/bluedroid/btc/core/btc_util.c b/components/bt/host/bluedroid/btc/core/btc_util.c similarity index 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..aff5521139 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,17 +413,15 @@ 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() @@ -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 100% rename from components/bt/bluedroid/btc/profile/std/smp/esp_app_sec.c rename to components/bt/host/bluedroid/btc/profile/std/smp/esp_app_sec.c diff --git a/components/bt/bluedroid/btc/profile/std/smp/include/esp_sec_api.h b/components/bt/host/bluedroid/btc/profile/std/smp/include/esp_sec_api.h similarity index 100% rename from components/bt/bluedroid/btc/profile/std/smp/include/esp_sec_api.h rename to components/bt/host/bluedroid/btc/profile/std/smp/include/esp_sec_api.h diff --git a/components/bt/bluedroid/btc/profile/std/spp/btc_spp.c b/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c similarity index 98% 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..93636ef71c 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) 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..96c773ebe2 --- /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() +{ + 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 100% rename from components/bt/bluedroid/device/include/device/controller.h rename to components/bt/host/bluedroid/device/include/device/controller.h diff --git a/components/bt/bluedroid/device/include/device/device_features.h b/components/bt/host/bluedroid/device/include/device/device_features.h similarity index 100% rename from components/bt/bluedroid/device/include/device/device_features.h rename to components/bt/host/bluedroid/device/include/device/device_features.h diff --git a/components/bt/bluedroid/device/include/device/event_mask.h b/components/bt/host/bluedroid/device/include/device/event_mask.h similarity index 100% rename from components/bt/bluedroid/device/include/device/event_mask.h rename to components/bt/host/bluedroid/device/include/device/event_mask.h diff --git a/components/bt/bluedroid/device/include/device/interop.h b/components/bt/host/bluedroid/device/include/device/interop.h similarity index 100% rename from components/bt/bluedroid/device/include/device/interop.h rename to components/bt/host/bluedroid/device/include/device/interop.h diff --git a/components/bt/bluedroid/device/include/device/interop_database.h b/components/bt/host/bluedroid/device/include/device/interop_database.h similarity index 100% rename from components/bt/bluedroid/device/include/device/interop_database.h rename to components/bt/host/bluedroid/device/include/device/interop_database.h diff --git a/components/bt/bluedroid/device/include/device/version.h b/components/bt/host/bluedroid/device/include/device/version.h similarity index 100% rename from components/bt/bluedroid/device/include/device/version.h rename to components/bt/host/bluedroid/device/include/device/version.h diff --git a/components/bt/bluedroid/device/interop.c b/components/bt/host/bluedroid/device/interop.c similarity index 100% rename from components/bt/bluedroid/device/interop.c rename to components/bt/host/bluedroid/device/interop.c diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_assert.h b/components/bt/host/bluedroid/external/sbc/decoder/include/oi_assert.h similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/include/oi_assert.h rename to components/bt/host/bluedroid/external/sbc/decoder/include/oi_assert.h diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_bitstream.h b/components/bt/host/bluedroid/external/sbc/decoder/include/oi_bitstream.h similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/include/oi_bitstream.h rename to components/bt/host/bluedroid/external/sbc/decoder/include/oi_bitstream.h diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_bt_spec.h b/components/bt/host/bluedroid/external/sbc/decoder/include/oi_bt_spec.h similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/include/oi_bt_spec.h rename to components/bt/host/bluedroid/external/sbc/decoder/include/oi_bt_spec.h diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_codec_sbc.h b/components/bt/host/bluedroid/external/sbc/decoder/include/oi_codec_sbc.h similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/include/oi_codec_sbc.h rename to components/bt/host/bluedroid/external/sbc/decoder/include/oi_codec_sbc.h diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_codec_sbc_private.h b/components/bt/host/bluedroid/external/sbc/decoder/include/oi_codec_sbc_private.h similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/include/oi_codec_sbc_private.h rename to components/bt/host/bluedroid/external/sbc/decoder/include/oi_codec_sbc_private.h diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_common.h b/components/bt/host/bluedroid/external/sbc/decoder/include/oi_common.h similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/include/oi_common.h rename to components/bt/host/bluedroid/external/sbc/decoder/include/oi_common.h diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_cpu_dep.h b/components/bt/host/bluedroid/external/sbc/decoder/include/oi_cpu_dep.h similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/include/oi_cpu_dep.h rename to components/bt/host/bluedroid/external/sbc/decoder/include/oi_cpu_dep.h diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_modules.h b/components/bt/host/bluedroid/external/sbc/decoder/include/oi_modules.h similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/include/oi_modules.h rename to components/bt/host/bluedroid/external/sbc/decoder/include/oi_modules.h diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_osinterface.h b/components/bt/host/bluedroid/external/sbc/decoder/include/oi_osinterface.h similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/include/oi_osinterface.h rename to components/bt/host/bluedroid/external/sbc/decoder/include/oi_osinterface.h diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_status.h b/components/bt/host/bluedroid/external/sbc/decoder/include/oi_status.h similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/include/oi_status.h rename to components/bt/host/bluedroid/external/sbc/decoder/include/oi_status.h diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_stddefs.h b/components/bt/host/bluedroid/external/sbc/decoder/include/oi_stddefs.h similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/include/oi_stddefs.h rename to components/bt/host/bluedroid/external/sbc/decoder/include/oi_stddefs.h diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_string.h b/components/bt/host/bluedroid/external/sbc/decoder/include/oi_string.h similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/include/oi_string.h rename to components/bt/host/bluedroid/external/sbc/decoder/include/oi_string.h diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_time.h b/components/bt/host/bluedroid/external/sbc/decoder/include/oi_time.h similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/include/oi_time.h rename to components/bt/host/bluedroid/external/sbc/decoder/include/oi_time.h diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_utils.h b/components/bt/host/bluedroid/external/sbc/decoder/include/oi_utils.h similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/include/oi_utils.h rename to components/bt/host/bluedroid/external/sbc/decoder/include/oi_utils.h diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/alloc.c b/components/bt/host/bluedroid/external/sbc/decoder/srce/alloc.c similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/srce/alloc.c rename to components/bt/host/bluedroid/external/sbc/decoder/srce/alloc.c diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/bitalloc-sbc.c b/components/bt/host/bluedroid/external/sbc/decoder/srce/bitalloc-sbc.c similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/srce/bitalloc-sbc.c rename to components/bt/host/bluedroid/external/sbc/decoder/srce/bitalloc-sbc.c diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/bitalloc.c b/components/bt/host/bluedroid/external/sbc/decoder/srce/bitalloc.c similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/srce/bitalloc.c rename to components/bt/host/bluedroid/external/sbc/decoder/srce/bitalloc.c diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/bitstream-decode.c b/components/bt/host/bluedroid/external/sbc/decoder/srce/bitstream-decode.c similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/srce/bitstream-decode.c rename to components/bt/host/bluedroid/external/sbc/decoder/srce/bitstream-decode.c diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/decoder-oina.c b/components/bt/host/bluedroid/external/sbc/decoder/srce/decoder-oina.c similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/srce/decoder-oina.c rename to components/bt/host/bluedroid/external/sbc/decoder/srce/decoder-oina.c diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/decoder-private.c b/components/bt/host/bluedroid/external/sbc/decoder/srce/decoder-private.c similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/srce/decoder-private.c rename to components/bt/host/bluedroid/external/sbc/decoder/srce/decoder-private.c diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/decoder-sbc.c b/components/bt/host/bluedroid/external/sbc/decoder/srce/decoder-sbc.c similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/srce/decoder-sbc.c rename to components/bt/host/bluedroid/external/sbc/decoder/srce/decoder-sbc.c diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/dequant.c b/components/bt/host/bluedroid/external/sbc/decoder/srce/dequant.c similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/srce/dequant.c rename to components/bt/host/bluedroid/external/sbc/decoder/srce/dequant.c diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/framing-sbc.c b/components/bt/host/bluedroid/external/sbc/decoder/srce/framing-sbc.c similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/srce/framing-sbc.c rename to components/bt/host/bluedroid/external/sbc/decoder/srce/framing-sbc.c diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/framing.c b/components/bt/host/bluedroid/external/sbc/decoder/srce/framing.c similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/srce/framing.c rename to components/bt/host/bluedroid/external/sbc/decoder/srce/framing.c diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/oi_codec_version.c b/components/bt/host/bluedroid/external/sbc/decoder/srce/oi_codec_version.c similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/srce/oi_codec_version.c rename to components/bt/host/bluedroid/external/sbc/decoder/srce/oi_codec_version.c diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/readsamplesjoint.inc b/components/bt/host/bluedroid/external/sbc/decoder/srce/readsamplesjoint.inc similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/srce/readsamplesjoint.inc rename to components/bt/host/bluedroid/external/sbc/decoder/srce/readsamplesjoint.inc diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/synthesis-8-generated.c b/components/bt/host/bluedroid/external/sbc/decoder/srce/synthesis-8-generated.c similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/srce/synthesis-8-generated.c rename to components/bt/host/bluedroid/external/sbc/decoder/srce/synthesis-8-generated.c diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/synthesis-dct8.c b/components/bt/host/bluedroid/external/sbc/decoder/srce/synthesis-dct8.c similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/srce/synthesis-dct8.c rename to components/bt/host/bluedroid/external/sbc/decoder/srce/synthesis-dct8.c diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/synthesis-sbc.c b/components/bt/host/bluedroid/external/sbc/decoder/srce/synthesis-sbc.c similarity index 100% rename from components/bt/bluedroid/external/sbc/decoder/srce/synthesis-sbc.c rename to components/bt/host/bluedroid/external/sbc/decoder/srce/synthesis-sbc.c diff --git a/components/bt/bluedroid/external/sbc/encoder/include/sbc_dct.h b/components/bt/host/bluedroid/external/sbc/encoder/include/sbc_dct.h similarity index 100% rename from components/bt/bluedroid/external/sbc/encoder/include/sbc_dct.h rename to components/bt/host/bluedroid/external/sbc/encoder/include/sbc_dct.h diff --git a/components/bt/bluedroid/external/sbc/encoder/include/sbc_enc_func_declare.h b/components/bt/host/bluedroid/external/sbc/encoder/include/sbc_enc_func_declare.h similarity index 100% rename from components/bt/bluedroid/external/sbc/encoder/include/sbc_enc_func_declare.h rename to components/bt/host/bluedroid/external/sbc/encoder/include/sbc_enc_func_declare.h diff --git a/components/bt/bluedroid/external/sbc/encoder/include/sbc_encoder.h b/components/bt/host/bluedroid/external/sbc/encoder/include/sbc_encoder.h similarity index 100% rename from components/bt/bluedroid/external/sbc/encoder/include/sbc_encoder.h rename to components/bt/host/bluedroid/external/sbc/encoder/include/sbc_encoder.h diff --git a/components/bt/bluedroid/external/sbc/encoder/include/sbc_if.h b/components/bt/host/bluedroid/external/sbc/encoder/include/sbc_if.h similarity index 100% rename from components/bt/bluedroid/external/sbc/encoder/include/sbc_if.h rename to components/bt/host/bluedroid/external/sbc/encoder/include/sbc_if.h diff --git a/components/bt/bluedroid/external/sbc/encoder/include/sbc_types.h b/components/bt/host/bluedroid/external/sbc/encoder/include/sbc_types.h similarity index 100% rename from components/bt/bluedroid/external/sbc/encoder/include/sbc_types.h rename to components/bt/host/bluedroid/external/sbc/encoder/include/sbc_types.h diff --git a/components/bt/bluedroid/external/sbc/encoder/srce/sbc_analysis.c b/components/bt/host/bluedroid/external/sbc/encoder/srce/sbc_analysis.c similarity index 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 89% rename from components/bt/bluedroid/hci/hci_hal_h4.c rename to components/bt/host/bluedroid/hci/hci_hal_h4.c index 89fba87b5d..031d2c028a 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) { @@ -125,9 +125,7 @@ static void hal_close() { 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; diff --git a/components/bt/bluedroid/hci/hci_layer.c b/components/bt/host/bluedroid/hci/hci_layer.c similarity index 88% rename from components/bt/bluedroid/hci/hci_layer.c rename to components/bt/host/bluedroid/hci/hci_layer.c index c2b6223ce7..6c285339cc 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); } } diff --git a/components/bt/bluedroid/hci/hci_packet_factory.c b/components/bt/host/bluedroid/hci/hci_packet_factory.c similarity index 100% rename from components/bt/bluedroid/hci/hci_packet_factory.c rename to components/bt/host/bluedroid/hci/hci_packet_factory.c diff --git a/components/bt/bluedroid/hci/hci_packet_parser.c b/components/bt/host/bluedroid/hci/hci_packet_parser.c similarity index 100% rename from components/bt/bluedroid/hci/hci_packet_parser.c rename to components/bt/host/bluedroid/hci/hci_packet_parser.c diff --git a/components/bt/bluedroid/hci/include/hci/bt_vendor_lib.h b/components/bt/host/bluedroid/hci/include/hci/bt_vendor_lib.h similarity index 100% rename from components/bt/bluedroid/hci/include/hci/bt_vendor_lib.h rename to components/bt/host/bluedroid/hci/include/hci/bt_vendor_lib.h diff --git a/components/bt/bluedroid/hci/include/hci/hci_audio.h b/components/bt/host/bluedroid/hci/include/hci/hci_audio.h similarity index 100% rename from components/bt/bluedroid/hci/include/hci/hci_audio.h rename to components/bt/host/bluedroid/hci/include/hci/hci_audio.h diff --git a/components/bt/bluedroid/hci/include/hci/hci_hal.h b/components/bt/host/bluedroid/hci/include/hci/hci_hal.h similarity index 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 98% 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..8fa5165e9f 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 */ @@ -95,5 +97,6 @@ const hci_t *hci_layer_get_interface(); int hci_start_up(void); void hci_shut_down(void); +bool hci_host_task_post(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 100% rename from components/bt/bluedroid/hci/include/hci/hci_packet_factory.h rename to components/bt/host/bluedroid/hci/include/hci/hci_packet_factory.h diff --git a/components/bt/bluedroid/hci/include/hci/hci_packet_parser.h b/components/bt/host/bluedroid/hci/include/hci/hci_packet_parser.h similarity index 100% rename from components/bt/bluedroid/hci/include/hci/hci_packet_parser.h rename to components/bt/host/bluedroid/hci/include/hci/hci_packet_parser.h diff --git a/components/bt/bluedroid/hci/include/hci/packet_fragmenter.h b/components/bt/host/bluedroid/hci/include/hci/packet_fragmenter.h similarity index 100% rename from components/bt/bluedroid/hci/include/hci/packet_fragmenter.h rename to components/bt/host/bluedroid/hci/include/hci/packet_fragmenter.h diff --git a/components/bt/bluedroid/hci/packet_fragmenter.c b/components/bt/host/bluedroid/hci/packet_fragmenter.c similarity index 100% rename from components/bt/bluedroid/hci/packet_fragmenter.c rename to components/bt/host/bluedroid/hci/packet_fragmenter.c diff --git a/components/bt/bluedroid/main/bte_init.c b/components/bt/host/bluedroid/main/bte_init.c similarity index 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 100% rename from components/bt/bluedroid/main/bte_main.c rename to components/bt/host/bluedroid/main/bte_main.c diff --git a/components/bt/bluedroid/stack/a2dp/a2d_api.c b/components/bt/host/bluedroid/stack/a2dp/a2d_api.c similarity index 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 100% rename from components/bt/bluedroid/stack/avdt/avdt_api.c rename to components/bt/host/bluedroid/stack/avdt/avdt_api.c diff --git a/components/bt/bluedroid/stack/avdt/avdt_ccb.c b/components/bt/host/bluedroid/stack/avdt/avdt_ccb.c similarity index 100% rename from components/bt/bluedroid/stack/avdt/avdt_ccb.c rename to components/bt/host/bluedroid/stack/avdt/avdt_ccb.c diff --git a/components/bt/bluedroid/stack/avdt/avdt_ccb_act.c b/components/bt/host/bluedroid/stack/avdt/avdt_ccb_act.c similarity index 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..438485359f 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, @@ -87,13 +95,13 @@ tBTM_STATUS btm_ble_obtain_vsc_details() tBTM_STATUS st = BTM_SUCCESS; #if BLE_VND_INCLUDED == TRUE - BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb); - if (0 == cmn_ble_vsc_cb.max_filter) { + BTM_BleGetVendorCapabilities(&cmn_ble_adv_vsc_cb); + if (0 == cmn_ble_adv_vsc_cb.max_filter) { st = BTM_MODE_UNSUPPORTED; return st; } #else - cmn_ble_vsc_cb.max_filter = BTM_BLE_MAX_FILTER_COUNTER; + cmn_ble_adv_vsc_cb.max_filter = BTM_BLE_MAX_FILTER_COUNTER; #endif return st; } @@ -367,7 +375,7 @@ tBTM_BLE_PF_COUNT *btm_ble_find_addr_filter_counter(tBLE_BD_ADDR *p_le_bda) return &btm_ble_adv_filt_cb.p_addr_filter_count[0]; } - for (i = 0; i < cmn_ble_vsc_cb.max_filter; i ++, p_addr_filter ++) { + for (i = 0; i < cmn_ble_adv_vsc_cb.max_filter; i ++, p_addr_filter ++) { if (p_addr_filter->in_use && memcmp(p_le_bda->bda, p_addr_filter->bd_addr, BD_ADDR_LEN) == 0) { return p_addr_filter; @@ -390,7 +398,7 @@ tBTM_BLE_PF_COUNT *btm_ble_alloc_addr_filter_counter(BD_ADDR bd_addr) UINT8 i; tBTM_BLE_PF_COUNT *p_addr_filter = &btm_ble_adv_filt_cb.p_addr_filter_count[1]; - for (i = 0; i < cmn_ble_vsc_cb.max_filter; i ++, p_addr_filter ++) { + for (i = 0; i < cmn_ble_adv_vsc_cb.max_filter; i ++, p_addr_filter ++) { if (memcmp(na_bda, p_addr_filter->bd_addr, BD_ADDR_LEN) == 0) { memcpy(p_addr_filter->bd_addr, bd_addr, BD_ADDR_LEN); p_addr_filter->in_use = TRUE; @@ -418,7 +426,7 @@ BOOLEAN btm_ble_dealloc_addr_filter_counter(tBLE_BD_ADDR *p_bd_addr, UINT8 filte memset(&btm_ble_adv_filt_cb.p_addr_filter_count[0], 0, sizeof(tBTM_BLE_PF_COUNT)); } - for (i = 0; i < cmn_ble_vsc_cb.max_filter; i ++, p_addr_filter ++) { + for (i = 0; i < cmn_ble_adv_vsc_cb.max_filter; i ++, p_addr_filter ++) { if ((p_addr_filter->in_use) && (NULL == p_bd_addr || (NULL != p_bd_addr && memcmp(p_bd_addr->bda, p_addr_filter->bd_addr, BD_ADDR_LEN) == 0))) { @@ -682,7 +690,7 @@ UINT8 btm_ble_cs_update_pf_counter(tBTM_BLE_SCAN_COND_OP action, } BTM_TRACE_DEBUG("counter = %d, maxfilt = %d, num_avbl=%d", - p_counter[cond_type], cmn_ble_vsc_cb.max_filter, num_available); + p_counter[cond_type], cmn_ble_adv_vsc_cb.max_filter, num_available); return p_counter[cond_type]; } } else { @@ -1052,12 +1060,12 @@ tBTM_STATUS BTM_BleAdvFilterParamSetup(int action, tBTM_BLE_PF_FILT_INDEX filt_i /* set onlost timeout */ UINT16_TO_STREAM(p, p_filt_params->lost_timeout); /* set num_of_track_entries for firmware greater than L-release version */ - if (cmn_ble_vsc_cb.version_supported > BTM_VSC_CHIP_CAPABILITY_L_VERSION) { + if (cmn_ble_adv_vsc_cb.version_supported > BTM_VSC_CHIP_CAPABILITY_L_VERSION) { UINT16_TO_STREAM(p, p_filt_params->num_of_tracking_entries); } } - if (cmn_ble_vsc_cb.version_supported == BTM_VSC_CHIP_CAPABILITY_L_VERSION) { + if (cmn_ble_adv_vsc_cb.version_supported == BTM_VSC_CHIP_CAPABILITY_L_VERSION) { len = BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_ADV_FILT_FEAT_SELN_LEN; } else { len = BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_ADV_FILT_FEAT_SELN_LEN + @@ -1248,14 +1256,24 @@ tBTM_STATUS BTM_BleCfgFilterCondition(tBTM_BLE_SCAN_COND_OP action, *******************************************************************************/ void btm_ble_adv_filter_init(void) { - memset(&btm_ble_adv_filt_cb, 0, sizeof(tBTM_BLE_MULTI_ADV_CB)); +#if BTM_DYNAMIC_MEMORY == TRUE + btm_ble_adv_filt_cb_ptr = (tBTM_BLE_ADV_FILTER_CB *)osi_malloc(sizeof(tBTM_BLE_ADV_FILTER_CB)); + cmn_ble_adv_vsc_cb_ptr = (tBTM_BLE_VSC_CB *)osi_malloc(sizeof(tBTM_BLE_VSC_CB)); + if (btm_ble_adv_filt_cb_ptr == NULL || cmn_ble_adv_vsc_cb_ptr == NULL) { + BTM_TRACE_ERROR("%s malloc failed", __func__); + return; + } + memset((void *)btm_ble_adv_filt_cb_ptr, 0, sizeof(tBTM_BLE_ADV_FILTER_CB)); + memset((void *)cmn_ble_adv_vsc_cb_ptr, 0, sizeof(tBTM_BLE_VSC_CB)); +#endif + memset(&btm_ble_adv_filt_cb, 0, sizeof(tBTM_BLE_ADV_FILTER_CB)); if (BTM_SUCCESS != btm_ble_obtain_vsc_details()) { return; } - if (cmn_ble_vsc_cb.max_filter > 0) { + if (cmn_ble_adv_vsc_cb.max_filter > 0) { btm_ble_adv_filt_cb.p_addr_filter_count = - (tBTM_BLE_PF_COUNT *) osi_malloc( sizeof(tBTM_BLE_PF_COUNT) * cmn_ble_vsc_cb.max_filter); + (tBTM_BLE_PF_COUNT *) osi_malloc( sizeof(tBTM_BLE_PF_COUNT) * cmn_ble_adv_vsc_cb.max_filter); } } @@ -1276,6 +1294,13 @@ void btm_ble_adv_filter_cleanup(void) osi_free(btm_ble_adv_filt_cb.p_addr_filter_count); btm_ble_adv_filt_cb.p_addr_filter_count = NULL; } + +#if BTM_DYNAMIC_MEMORY == TRUE + osi_free(btm_ble_adv_filt_cb_ptr); + btm_ble_adv_filt_cb_ptr = NULL; + osi_free(cmn_ble_adv_vsc_cb_ptr); + cmn_ble_adv_vsc_cb_ptr = NULL; +#endif } #endif diff --git a/components/bt/bluedroid/stack/btm/btm_ble_batchscan.c b/components/bt/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 99% 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..3721471f80 100644 --- a/components/bt/bluedroid/stack/btm/btm_ble_bgconn.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble_bgconn.c @@ -785,7 +785,7 @@ void btm_ble_enqueue_direct_conn_req(void *p_param) p->p_param = p_param; - fixed_queue_enqueue(btm_cb.ble_ctr_cb.conn_pending_q, p); + fixed_queue_enqueue(btm_cb.ble_ctr_cb.conn_pending_q, p, FIXED_QUEUE_MAX_TIMEOUT); } /******************************************************************************* ** @@ -801,7 +801,7 @@ BOOLEAN btm_send_pending_direct_conn(void) tBTM_BLE_CONN_REQ *p_req; BOOLEAN rt = FALSE; - p_req = (tBTM_BLE_CONN_REQ*)fixed_queue_try_dequeue(btm_cb.ble_ctr_cb.conn_pending_q); + p_req = (tBTM_BLE_CONN_REQ*)fixed_queue_dequeue(btm_cb.ble_ctr_cb.conn_pending_q, 0); if (p_req != NULL) { rt = l2cble_init_direct_conn((tL2C_LCB *)(p_req->p_param)); diff --git a/components/bt/bluedroid/stack/btm/btm_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..caacad51c9 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; @@ -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..a3ad604437 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 @@ -764,6 +771,15 @@ void btm_ble_multi_adv_vse_cback(UINT8 len, UINT8 *p) *******************************************************************************/ void btm_ble_multi_adv_init() { +#if BTM_DYNAMIC_MEMORY == TRUE + btm_multi_adv_cb_ptr = (tBTM_BLE_MULTI_ADV_CB *)osi_malloc(sizeof(tBTM_BLE_MULTI_ADV_CB)); + btm_multi_adv_idx_q_ptr = (tBTM_BLE_MULTI_ADV_INST_IDX_Q *)osi_malloc(sizeof(tBTM_BLE_MULTI_ADV_INST_IDX_Q)); + if (btm_multi_adv_cb_ptr == NULL || btm_multi_adv_idx_q_ptr == NULL) { + BTM_TRACE_ERROR("%s malloc failed", __func__); + return; + } +#endif + UINT8 i = 0; memset(&btm_multi_adv_cb, 0, sizeof(tBTM_BLE_MULTI_ADV_CB)); memset (&btm_multi_adv_idx_q, 0, sizeof (tBTM_BLE_MULTI_ADV_INST_IDX_Q)); @@ -823,6 +839,12 @@ void btm_ble_multi_adv_cleanup(void) btm_multi_adv_cb.op_q.p_inst_id = NULL; } +#if BTM_DYNAMIC_MEMORY == TRUE + osi_free(btm_multi_adv_cb_ptr); + osi_free(btm_multi_adv_idx_q_ptr); + btm_multi_adv_cb_ptr = NULL; + btm_multi_adv_idx_q_ptr = NULL; +#endif } /******************************************************************************* diff --git a/components/bt/bluedroid/stack/btm/btm_ble_privacy.c b/components/bt/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..2ac01ea2eb 100644 --- a/components/bt/bluedroid/stack/include/stack/btm_ble_api.h +++ b/components/bt/host/bluedroid/stack/include/stack/btm_ble_api.h @@ -2099,6 +2099,19 @@ tBTM_STATUS BTM_SetBleDataLength(BD_ADDR bd_addr, UINT16 tx_pdu_length); *******************************************************************************/ tBTM_STATUS BTM_UpdateBleDuplicateExceptionalList(uint8_t subcode, uint32_t type, BD_ADDR device_info, tBTM_UPDATE_DUPLICATE_EXCEPTIONAL_LIST_CMPL_CBACK update_exceptional_list_cmp_cb); + +/******************************************************************************* +** +** Function BTM_GetCurrentConnParams +** +** Description This function is called to read the current connection parameters +** of the device +** +** Returns TRUE or FALSE +** +*******************************************************************************/ + +BOOLEAN BTM_GetCurrentConnParams(BD_ADDR bda, uint16_t *interval, uint16_t *latency, uint16_t *timeout); /* #ifdef __cplusplus } 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..7600a6f603 --- /dev/null +++ b/components/bt/host/nimble/nimble @@ -0,0 +1 @@ +Subproject commit 7600a6f60308c77fec755a024d51ab2fb7d11553 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..aef9d31682 100644 --- a/components/coap/CMakeLists.txt +++ b/components/coap/CMakeLists.txt @@ -1,28 +1,31 @@ -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" + "libcoap/src/coap_debug.c" + "libcoap/src/encode.c" + "libcoap/src/mem.c" + "libcoap/src/net.c" + "libcoap/src/option.c" + "libcoap/src/pdu.c" + "libcoap/src/resource.c" + "libcoap/src/str.c" + "libcoap/src/subscribe.c" + "libcoap/src/uri.c" + "libcoap/src/coap_notls.c" + "port/coap_io.c") set(COMPONENT_REQUIRES lwip) -register_component() +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS "${include_dirs}" + REQUIRES lwip) # Silence format truncation warning, until it is fixed upstream set_source_files_properties(libcoap/src/coap_debug.c PROPERTIES COMPILE_FLAGS -Wno-format-truncation) diff --git a/components/coap/port/coap_io.c b/components/coap/port/coap_io.c index 58391add6b..a8f35c180f 100644 --- a/components/coap/port/coap_io.c +++ b/components/coap/port/coap_io.c @@ -714,11 +714,6 @@ struct in6_pktinfo { unsigned int ipi6_ifindex; /* send/recv interface index */ }; -struct in_pktinfo { - int ipi_ifindex; - struct in_addr ipi_spec_dst; - struct in_addr ipi_addr; -}; #endif #if !defined(WITH_CONTIKI) && !defined(SOL_IP) diff --git a/components/coap/port/include/coap_config_posix.h b/components/coap/port/include/coap_config_posix.h index d675b7a583..8f5a5cfb10 100644 --- a/components/coap/port/include/coap_config_posix.h +++ b/components/coap/port/include/coap_config_posix.h @@ -27,7 +27,6 @@ #define HAVE_ARPA_INET_H #define HAVE_TIME_H -#define IP_PKTINFO IP_MULTICAST_IF #define IPV6_PKTINFO IPV6_V6ONLY #define PACKAGE_NAME "libcoap-posix" diff --git a/components/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/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/test/CMakeLists.txt b/components/cxx/test/CMakeLists.txt index 884ca8b6da..16aca87790 100644 --- a/components/cxx/test/CMakeLists.txt +++ b/components/cxx/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity) - -register_component() \ No newline at end of file +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity) \ No newline at end of file diff --git a/components/driver/CMakeLists.txt b/components/driver/CMakeLists.txt index eeeea7d9a4..0bb3aee6bf 100644 --- a/components/driver/CMakeLists.txt +++ b/components/driver/CMakeLists.txt @@ -1,43 +1,40 @@ -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") 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 "${CONFIG_IDF_TARGET}/rtc_tempsensor.c" + "${CONFIG_IDF_TARGET}/rtc_touchpad.c") endif() -register_component() - +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS "include" "${CONFIG_IDF_TARGET}/include" + PRIV_INCLUDE_DIRS "include/driver" + REQUIRES esp_ringbuf soc) #cannot totally hide soc headers, since there are a lot arguments in the driver are chip-dependent if(GCC_NOT_5_2_0) # uses C11 atomic feature diff --git a/components/driver/can.c b/components/driver/can.c index 63b95dd36c..e3830bd5e8 100644 --- a/components/driver/can.c +++ b/components/driver/can.c @@ -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 diff --git a/components/driver/gpio.c b/components/driver/gpio.c index d8d5c26948..f0a7159217 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,15 @@ static void IRAM_ATTR gpio_intr_service(void* arg) if (gpio_isr_func == NULL) { return; } - //read status to get interrupt status for GPIO0-31 - const uint32_t gpio_intr_status = GPIO.status; + const uint32_t gpio_intr_status = (isr_core_id == 0) ? GPIO.pcpu_int : GPIO.acpu_int; if (gpio_intr_status) { gpio_isr_loop(gpio_intr_status, 0); GPIO.status_w1tc = gpio_intr_status; } //read status1 to get interrupt status for GPIO32-39 - const uint32_t gpio_intr_status_h = GPIO.status1.intr_st; + const uint32_t gpio_intr_status_h = (isr_core_id == 0) ? GPIO.pcpu_int1.intr : GPIO.acpu_int1.intr; if (gpio_intr_status_h) { gpio_isr_loop(gpio_intr_status_h, 32); GPIO.status1_w1tc.intr_st = gpio_intr_status_h; @@ -428,12 +445,12 @@ esp_err_t gpio_install_isr_service(int intr_alloc_flags) esp_err_t ret; portENTER_CRITICAL(&gpio_spinlock); gpio_isr_func = (gpio_isr_func_t*) calloc(GPIO_NUM_MAX, sizeof(gpio_isr_func_t)); + portEXIT_CRITICAL(&gpio_spinlock); if (gpio_isr_func == NULL) { ret = ESP_ERR_NO_MEM; } else { ret = gpio_isr_register(gpio_intr_service, NULL, intr_alloc_flags, &gpio_isr_handle); } - portEXIT_CRITICAL(&gpio_spinlock); return ret; } @@ -446,14 +463,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/i2s.c b/components/driver/i2s.c index 904f1ef156..7a2d15514e 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); } 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/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/spi_common.h b/components/driver/include/driver/spi_common.h index 138014e4ff..153471b23f 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,6 +137,8 @@ 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); @@ -145,6 +160,8 @@ bool spicommon_periph_claim(spi_host_device_t host, const char* source); * * @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 +170,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 +184,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 +195,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 +206,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 +233,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 +264,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 +279,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 +288,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 +374,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,6 +386,8 @@ 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(); @@ -369,6 +398,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 +408,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/rtc_module.c b/components/driver/rtc_module.c index c871405ca8..6997277e7c 100644 --- a/components/driver/rtc_module.c +++ b/components/driver/rtc_module.c @@ -1157,25 +1157,30 @@ esp_err_t touch_pad_filter_start(uint32_t filter_period_ms) RTC_MODULE_CHECK(filter_period_ms >= portTICK_PERIOD_MS, "Touch pad filter period error", ESP_ERR_INVALID_ARG); RTC_MODULE_CHECK(rtc_touch_mux != NULL, "Touch pad not initialized", ESP_ERR_INVALID_STATE); - esp_err_t ret = ESP_OK; xSemaphoreTake(rtc_touch_mux, portMAX_DELAY); if (s_touch_pad_filter == NULL) { s_touch_pad_filter = (touch_pad_filter_t *) calloc(1, sizeof(touch_pad_filter_t)); if (s_touch_pad_filter == NULL) { - ret = ESP_ERR_NO_MEM; + goto err_no_mem; } } if (s_touch_pad_filter->timer == NULL) { s_touch_pad_filter->timer = xTimerCreate("filter_tmr", filter_period_ms / portTICK_PERIOD_MS, pdFALSE, NULL, touch_pad_filter_cb); if (s_touch_pad_filter->timer == NULL) { - ret = ESP_ERR_NO_MEM; + free(s_touch_pad_filter); + s_touch_pad_filter = NULL; + goto err_no_mem; } s_touch_pad_filter->period = filter_period_ms; } xSemaphoreGive(rtc_touch_mux); touch_pad_filter_cb(NULL); - return ret; + return ESP_OK; + +err_no_mem: + xSemaphoreGive(rtc_touch_mux); + return ESP_ERR_NO_MEM; } esp_err_t touch_pad_filter_stop() diff --git a/components/driver/sdio_slave.c b/components/driver/sdio_slave.c index 1bd805c8e4..12d106ae59 100644 --- a/components/driver/sdio_slave.c +++ b/components/driver/sdio_slave.c @@ -360,19 +360,39 @@ static inline bool sdio_ringbuf_empty(sdio_ringbuf_t* buf) } /**************** End of Ring buffer for SDIO *****************/ -static inline void show_ll(buf_desc_t *item) +static inline void show_queue_item(buf_desc_t *item) { - ESP_EARLY_LOGD(TAG, "=> %p: size: %d(%d), eof: %d, owner: %d", item, item->size, item->length, item->eof, item->owner); - ESP_EARLY_LOGD(TAG, " buf: %p, stqe_next: %p, tqe-prev: %p", item->buf, item->qe.stqe_next, item->te.tqe_prev); + ESP_EARLY_LOGI(TAG, "=> %p: size: %d(%d), eof: %d, owner: %d", item, item->size, item->length, item->eof, item->owner); + ESP_EARLY_LOGI(TAG, " buf: %p, stqe_next: %p, tqe-prev: %p", item->buf, item->qe.stqe_next, item->te.tqe_prev); } -static void __attribute((unused)) dump_ll(buf_stailq_t *queue) +static void __attribute((unused)) dump_queue(buf_stailq_t *queue) { + int cnt = 0; buf_desc_t *item = NULL; - ESP_EARLY_LOGD(TAG, ">>>>> first: %p, last: %p <<<<<", queue->stqh_first, queue->stqh_last); + ESP_EARLY_LOGI(TAG, ">>>>> first: %p, last: %p <<<<<", queue->stqh_first, queue->stqh_last); STAILQ_FOREACH(item, queue, qe) { - show_ll(item); + cnt++; + show_queue_item(item); } + ESP_EARLY_LOGI(TAG, "total: %d", cnt); +} + +static inline void show_ll(lldesc_t *item) +{ + ESP_EARLY_LOGI(TAG, "=> %p: size: %d(%d), eof: %d, owner: %d", item, item->size, item->length, item->eof, item->owner); + ESP_EARLY_LOGI(TAG, " buf: %p, stqe_next: %p", item->buf, item->qe.stqe_next); +} +static void __attribute((unused)) dump_ll(lldesc_t *queue) +{ + int cnt = 0; + lldesc_t *item = queue; + while (item != NULL) { + cnt++; + show_ll(item); + item = STAILQ_NEXT(item, qe); + } + ESP_EARLY_LOGI(TAG, "total: %d", cnt); } static inline void deinit_context() @@ -964,7 +984,7 @@ static esp_err_t send_flush_data() buf_desc_t *last = NULL; if (context.in_flight) { buf_desc_t *desc = context.in_flight; - while(desc != NULL) { + while (desc != NULL) { xQueueSend(context.ret_queue, &desc->arg, portMAX_DELAY); last = desc; desc = STAILQ_NEXT(desc, qe); @@ -975,13 +995,14 @@ static esp_err_t send_flush_data() context.in_flight_end = NULL; } - buf_desc_t *head; - esp_err_t ret = sdio_ringbuf_recv(&context.sendbuf, (uint8_t**)&head, NULL, RINGBUF_GET_ALL, 0); + buf_desc_t *head, *tail; + esp_err_t ret = sdio_ringbuf_recv(&context.sendbuf, (uint8_t**)&head, (uint8_t**)&tail, RINGBUF_GET_ALL, 0); if (ret == ESP_OK) { buf_desc_t *desc = head; - while(desc != NULL) { + while (1) { xQueueSend(context.ret_queue, &desc->arg, portMAX_DELAY); last = desc; + if (desc == tail) break; desc = STAILQ_NEXT(desc, qe); } sdio_ringbuf_return(&context.sendbuf, (uint8_t*)head); @@ -1162,6 +1183,7 @@ esp_err_t sdio_slave_recv_load_buf(sdio_slave_buf_handle_t handle) buf_stailq_t *const queue = &context.recv_link_list; critical_enter_recv(); + assert(desc->not_receiving); TAILQ_REMOVE(&context.recv_reg_list, desc, te); desc->owner = 1; desc->not_receiving = 0; //manually remove the prev link (by set not_receiving=0), to indicate this is in the queue @@ -1253,3 +1275,9 @@ uint8_t* sdio_slave_recv_get_buf(sdio_slave_buf_handle_t handle, size_t *len_o) if (len_o!= NULL) *len_o= desc->length; return desc->buf; } + +static void __attribute((unused)) sdio_slave_recv_get_loaded_buffer_num() +{ + buf_stailq_t *const queue = &context.recv_link_list; + dump_queue(queue); +} diff --git a/components/driver/sdspi_host.c b/components/driver/sdspi_host.c index 26d9f7b3fa..3a36ed7698 100644 --- a/components/driver/sdspi_host.c +++ b/components/driver/sdspi_host.c @@ -26,6 +26,8 @@ #include "sdspi_private.h" #include "sdspi_crc.h" #include "esp_timer.h" +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" /// Max number of transactions in flight (used in start_command_write_blocks) diff --git a/components/driver/spi_common.c b/components/driver/spi_common.c index d74b62307f..2794521b1a 100644 --- a/components/driver/spi_common.c +++ b/components/driver/spi_common.c @@ -103,11 +103,6 @@ int spicommon_irqdma_source_for_host(spi_host_device_t host) return spi_periph_signal[host].irq_dma; } -spi_dev_t *spicommon_hw_for_host(spi_host_device_t host) -{ - return spi_periph_signal[host].hw; -} - static inline uint32_t get_dma_periph(int dma_chan) { #ifdef CONFIG_IDF_TARGET_ESP32S2BETA @@ -137,6 +132,7 @@ bool spicommon_dma_chan_claim (int dma_chan) spi_dma_chan_enabled |= DMA_CHANNEL_ENABLED(dma_chan); ret = true; } + #if CONFIG_IDF_TARGET_ESP32 periph_module_enable(get_dma_periph(dma_chan)); #elif CONFIG_IDF_TARGET_ESP32S2BETA @@ -393,32 +389,6 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf return ESP_OK; } - -//Find any pin with output muxed to ``func`` and reset it to GPIO -static void reset_func_to_gpio(int func) -{ - for (int x = 0; x < GPIO_PIN_COUNT; x++) { - if (GPIO_IS_VALID_GPIO(x) && (READ_PERI_REG(GPIO_FUNC0_OUT_SEL_CFG_REG + (x * 4))&GPIO_FUNC0_OUT_SEL_M) == func) { - gpio_matrix_out(x, SIG_GPIO_OUT_IDX, false, false); - } - } -} - -esp_err_t spicommon_bus_free_io(spi_host_device_t host) -{ - if (REG_GET_FIELD(GPIO_PIN_MUX_REG[spi_periph_signal[host].spid_iomux_pin], MCU_SEL) == 1) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[spi_periph_signal[host].spid_iomux_pin], PIN_FUNC_GPIO); - if (REG_GET_FIELD(GPIO_PIN_MUX_REG[spi_periph_signal[host].spiq_iomux_pin], MCU_SEL) == 1) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[spi_periph_signal[host].spiq_iomux_pin], PIN_FUNC_GPIO); - if (REG_GET_FIELD(GPIO_PIN_MUX_REG[spi_periph_signal[host].spiclk_iomux_pin], MCU_SEL) == 1) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[spi_periph_signal[host].spiclk_iomux_pin], PIN_FUNC_GPIO); - if (REG_GET_FIELD(GPIO_PIN_MUX_REG[spi_periph_signal[host].spiwp_iomux_pin], MCU_SEL) == 1) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[spi_periph_signal[host].spiwp_iomux_pin], PIN_FUNC_GPIO); - if (REG_GET_FIELD(GPIO_PIN_MUX_REG[spi_periph_signal[host].spihd_iomux_pin], MCU_SEL) == 1) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[spi_periph_signal[host].spihd_iomux_pin], PIN_FUNC_GPIO); - reset_func_to_gpio(spi_periph_signal[host].spid_out); - reset_func_to_gpio(spi_periph_signal[host].spiq_out); - reset_func_to_gpio(spi_periph_signal[host].spiclk_out); - reset_func_to_gpio(spi_periph_signal[host].spiwp_out); - reset_func_to_gpio(spi_periph_signal[host].spihd_out); - return ESP_OK; -} - esp_err_t spicommon_bus_free_io_cfg(const spi_bus_config_t *bus_cfg) { int pin_array[] = { @@ -459,26 +429,22 @@ void spicommon_cs_initialize(spi_host_device_t host, int cs_io_num, int cs_num, } } -void spicommon_cs_free(spi_host_device_t host, int cs_io_num) -{ - if (cs_io_num == 0 && REG_GET_FIELD(GPIO_PIN_MUX_REG[spi_periph_signal[host].spics0_iomux_pin], MCU_SEL) == 1) { - PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[spi_periph_signal[host].spics0_iomux_pin], PIN_FUNC_GPIO); - } - reset_func_to_gpio(spi_periph_signal[host].spics_out[cs_io_num]); -} - void spicommon_cs_free_io(int cs_gpio_num) { assert(cs_gpio_num>=0 && GPIO_IS_VALID_GPIO(cs_gpio_num)); gpio_reset_pin(cs_gpio_num); } -//Set up a list of dma descriptors. dmadesc is an array of descriptors. Data is the buffer to point to. -void IRAM_ATTR 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) { - lldesc_setup_link(dmadesc, data, len, isrx); -} +#define CHECK_IOMUX_PIN(HOST, PIN_NAME) if (GPIO.func_in_sel_cfg[spi_periph_signal[(HOST)].PIN_NAME##_in].sig_in_sel) return false + CHECK_IOMUX_PIN(host, spid); + CHECK_IOMUX_PIN(host, spiq); + CHECK_IOMUX_PIN(host, spiwp); + CHECK_IOMUX_PIN(host, spihd); + return true; +} /* Code for workaround for DMA issue in ESP32 v0/v1 silicon @@ -549,4 +515,4 @@ void IRAM_ATTR spicommon_dmaworkaround_transfer_active(int dmachan) dmaworkaround_channels_busy[dmachan-1] = 1; portEXIT_CRITICAL_ISR(&dmaworkaround_mux); #endif -} \ No newline at end of file +} diff --git a/components/driver/spi_master.c b/components/driver/spi_master.c index 50c988a5bf..400c8692d4 100644 --- a/components/driver/spi_master.c +++ b/components/driver/spi_master.c @@ -314,7 +314,7 @@ cleanup: free(spihost[host]); spihost[host] = NULL; spicommon_periph_free(host); - spicommon_dma_chan_free(dma_chan); + if (dma_chan != 0) spicommon_dma_chan_free(dma_chan); return ret; } @@ -879,7 +879,7 @@ static SPI_MASTER_ISR_ATTR esp_err_t setup_priv_desc(spi_transaction_t *trans_de } if (send_ptr && isdma && !esp_ptr_dma_capable( send_ptr )) { //if txbuf in the desc not DMA-capable, malloc a new one - ESP_LOGI( SPI_TAG, "Allocate TX buffer for DMA" ); + ESP_LOGD( SPI_TAG, "Allocate TX buffer for DMA" ); uint32_t *temp = heap_caps_malloc((trans_desc->length + 7) / 8, MALLOC_CAP_DMA); if (temp == NULL) goto clean_up; diff --git a/components/driver/spi_slave.c b/components/driver/spi_slave.c index b60584ab7f..124c6a0c48 100644 --- a/components/driver/spi_slave.c +++ b/components/driver/spi_slave.c @@ -364,12 +364,14 @@ static void SPI_SLAVE_ISR_ATTR spi_intr(void *arg) } } + //Disable interrupt before checking to avoid concurrency issue. + esp_intr_disable(host->intr); //Grab next transaction r = xQueueReceiveFromISR(host->trans_queue, &trans, &do_yield); - if (!r) { - //No packet waiting. Disable interrupt. - esp_intr_disable(host->intr); - } else { + if (r) { + //enable the interrupt again if there is packet to send + esp_intr_enable(host->intr); + //We have a transaction. Send it. host->cur_trans = trans; diff --git a/components/driver/test/CMakeLists.txt b/components/driver/test/CMakeLists.txt index b48610adcd..7102bae72e 100644 --- a/components/driver/test/CMakeLists.txt +++ b/components/driver/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ". param_test") -set(COMPONENT_ADD_INCLUDEDIRS "include param_test/include") - -set(COMPONENT_REQUIRES unity test_utils driver nvs_flash) - -register_component() \ No newline at end of file +idf_component_register(SRC_DIRS "." "param_test" + INCLUDE_DIRS "include" "param_test/include" + REQUIRES unity test_utils driver nvs_flash) \ No newline at end of file diff --git a/components/driver/test/test_gpio.c b/components/driver/test/test_gpio.c index ee07484bea..c40815683c 100644 --- a/components/driver/test/test_gpio.c +++ b/components/driver/test/test_gpio.c @@ -616,3 +616,128 @@ TEST_CASE("GPIO drive capability test", "[gpio][ignore]") drive_capability_set_get(GPIO_OUTPUT_IO, GPIO_DRIVE_CAP_3); prompt_to_continue("If this test finishes"); } + +#if !CONFIG_FREERTOS_UNICORE +void gpio_enable_task(void *param) +{ + int gpio_num = (int)param; + TEST_ESP_OK(gpio_intr_enable(gpio_num)); + vTaskDelete(NULL); +} + +/** Test the GPIO Interrupt Enable API with dual core enabled. The GPIO ISR service routine is registered on one core. + * When the GPIO interrupt on another core is enabled, the GPIO interrupt will be lost. + * First on the core 0, Do the following steps: + * 1. Configure the GPIO18 input_output mode, and enable the rising edge interrupt mode. + * 2. Trigger the GPIO18 interrupt and check if the interrupt responds correctly. + * 3. Disable the GPIO18 interrupt + * Then on the core 1, Do the following steps: + * 1. Enable the GPIO18 interrupt again. + * 2. Trigger the GPIO18 interrupt and check if the interrupt responds correctly. + * + */ +TEST_CASE("GPIO Enable/Disable interrupt on multiple cores", "[gpio][ignore]") +{ + const int test_io18 = GPIO_NUM_18; + gpio_config_t io_conf; + io_conf.intr_type = GPIO_INTR_NEGEDGE; + io_conf.mode = GPIO_MODE_INPUT_OUTPUT; + io_conf.pin_bit_mask = (1ULL << test_io18); + io_conf.pull_down_en = 0; + io_conf.pull_up_en = 1; + TEST_ESP_OK(gpio_config(&io_conf)); + TEST_ESP_OK(gpio_set_level(test_io18, 0)); + TEST_ESP_OK(gpio_install_isr_service(0)); + TEST_ESP_OK(gpio_isr_handler_add(test_io18, gpio_isr_edge_handler, (void*) test_io18)); + vTaskDelay(1000 / portTICK_RATE_MS); + TEST_ESP_OK(gpio_set_level(test_io18, 1)); + vTaskDelay(100 / portTICK_RATE_MS); + TEST_ESP_OK(gpio_set_level(test_io18, 0)); + vTaskDelay(100 / portTICK_RATE_MS); + TEST_ESP_OK(gpio_intr_disable(test_io18)); + TEST_ASSERT(edge_intr_times == 1); + xTaskCreatePinnedToCore(gpio_enable_task, "gpio_enable_task", 1024*4, (void*)test_io18, 8, NULL, (xPortGetCoreID() == 0)); + vTaskDelay(1000 / portTICK_RATE_MS); + TEST_ESP_OK(gpio_set_level(test_io18, 1)); + vTaskDelay(100 / portTICK_RATE_MS); + TEST_ESP_OK(gpio_set_level(test_io18, 0)); + vTaskDelay(100 / portTICK_RATE_MS); + TEST_ESP_OK(gpio_intr_disable(test_io18)); + TEST_ESP_OK(gpio_isr_handler_remove(test_io18)); + gpio_uninstall_isr_service(); + TEST_ASSERT(edge_intr_times == 2); +} +#endif + +typedef struct { + int gpio_num; + int isr_cnt; +} gpio_isr_param_t; + +static void gpio_isr_handler(void* arg) +{ + gpio_isr_param_t *param = (gpio_isr_param_t *)arg; + ets_printf("GPIO[%d] intr, val: %d\n", param->gpio_num, gpio_get_level(param->gpio_num)); + param->isr_cnt++; +} + +/** The previous GPIO interrupt service routine polls the interrupt raw status register to find the GPIO that triggered the interrupt. + * But this will incorrectly handle the interrupt disabled GPIOs, because the raw interrupt status register can still be set when + * the trigger signal arrives, even if the interrupt is disabled. + * First on the core 0: + * 1. Configure the GPIO18 and GPIO19 input_output mode. + * 2. Enable GPIO18 dual edge triggered interrupt, enable GPIO19 falling edge triggered interrupt. + * 3. Trigger GPIO18 interrupt, than disable the GPIO8 interrupt, and than trigger GPIO18 again(This time will not respond to the interrupt). + * 4. Trigger GPIO19 interrupt. + * If the bug is not fixed, you will see, in the step 4, the interrupt of GPIO18 will also respond. + */ +TEST_CASE("GPIO ISR service test", "[gpio][ignore]") +{ + const int test_io18 = GPIO_NUM_18; + const int test_io19 = GPIO_NUM_19; + static gpio_isr_param_t io18_param = { + .gpio_num = GPIO_NUM_18, + .isr_cnt = 0, + }; + static gpio_isr_param_t io19_param = { + .gpio_num = GPIO_NUM_19, + .isr_cnt = 0, + }; + gpio_config_t io_conf; + io_conf.intr_type = GPIO_INTR_DISABLE; + io_conf.mode = GPIO_MODE_INPUT_OUTPUT; + io_conf.pin_bit_mask = (1ULL << test_io18) | (1ULL << test_io19); + io_conf.pull_down_en = 0; + io_conf.pull_up_en = 1; + TEST_ESP_OK(gpio_config(&io_conf)); + TEST_ESP_OK(gpio_set_level(test_io18, 0)); + TEST_ESP_OK(gpio_set_level(test_io19, 0)); + TEST_ESP_OK(gpio_install_isr_service(0)); + TEST_ESP_OK(gpio_set_intr_type(test_io18, GPIO_INTR_ANYEDGE)); + TEST_ESP_OK(gpio_set_intr_type(test_io19, GPIO_INTR_NEGEDGE)); + TEST_ESP_OK(gpio_isr_handler_add(test_io18, gpio_isr_handler, (void*)&io18_param)); + TEST_ESP_OK(gpio_isr_handler_add(test_io19, gpio_isr_handler, (void*)&io19_param)); + printf("Triggering the interrupt of GPIO18\n"); + vTaskDelay(1000 / portTICK_RATE_MS); + //Rising edge + TEST_ESP_OK(gpio_set_level(test_io18, 1)); + printf("Disable the interrupt of GPIO18"); + vTaskDelay(100 / portTICK_RATE_MS); + //Disable GPIO18 interrupt, GPIO18 will not respond to the next falling edge interrupt. + TEST_ESP_OK(gpio_intr_disable(test_io18)); + vTaskDelay(100 / portTICK_RATE_MS); + //Falling edge + TEST_ESP_OK(gpio_set_level(test_io18, 0)); + + printf("Triggering the interrupt of GPIO19\n"); + vTaskDelay(100 / portTICK_RATE_MS); + TEST_ESP_OK(gpio_set_level(test_io19, 1)); + vTaskDelay(100 / portTICK_RATE_MS); + //Falling edge + TEST_ESP_OK(gpio_set_level(test_io19, 0)); + vTaskDelay(100 / portTICK_RATE_MS); + TEST_ESP_OK(gpio_isr_handler_remove(test_io18)); + TEST_ESP_OK(gpio_isr_handler_remove(test_io19)); + gpio_uninstall_isr_service(); + TEST_ASSERT((io18_param.isr_cnt == 1) && (io19_param.isr_cnt == 1)); +} \ No newline at end of file diff --git a/components/driver/test/test_i2s.c b/components/driver/test/test_i2s.c index 3afb24412f..813a906cb5 100644 --- a/components/driver/test/test_i2s.c +++ b/components/driver/test/test_i2s.c @@ -9,6 +9,7 @@ #include "freertos/task.h" #include "driver/i2s.h" #include "unity.h" +#include "math.h" #define SAMPLE_RATE (36000) #define SAMPLE_BITS (16) @@ -18,6 +19,7 @@ #define SLAVE_WS_IO 26 #define DATA_IN_IO 21 #define DATA_OUT_IO 22 +#define PERCENT_DIFF 0.0001 /** * i2s initialize test @@ -267,3 +269,54 @@ TEST_CASE("I2S memory leaking test", "[i2s]") vTaskDelay(100 / portTICK_PERIOD_MS); TEST_ASSERT(initial_size == esp_get_free_heap_size()); } + +/* + * The I2S APLL clock variation test used to test the difference between the different sample rates, different bits per sample + * and the APLL clock generate for it. The TEST_CASE passes PERCENT_DIFF variation from the provided sample rate in APLL generated clock + * The percentage difference calculated as (mod((obtained clock rate - desired clock rate)/(desired clock rate))) * 100. + */ +TEST_CASE("I2S APLL clock variation test", "[i2s]") +{ + i2s_pin_config_t pin_config = { + .bck_io_num = MASTER_BCK_IO, + .ws_io_num = MASTER_WS_IO, + .data_out_num = DATA_OUT_IO, + .data_in_num = -1 + }; + + i2s_config_t i2s_config = { + .mode = I2S_MODE_MASTER | I2S_MODE_TX, + .sample_rate = SAMPLE_RATE, + .bits_per_sample = SAMPLE_BITS, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_I2S, + .dma_buf_count = 6, + .dma_buf_len = 60, + .use_apll = true, + .intr_alloc_flags = 0, + }; + + TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL)); + TEST_ESP_OK(i2s_set_pin(I2S_NUM_0, &pin_config)); + TEST_ESP_OK(i2s_driver_uninstall(I2S_NUM_0)); + int initial_size = esp_get_free_heap_size(); + + uint32_t sample_rate_arr[8] = { 10675, 11025, 16000, 22050, 32000, 44100, 48000, 96000 }; + int bits_per_sample_arr[3] = { 16, 24, 32 }; + + for (int i = 0; i < (sizeof(sample_rate_arr)/sizeof(sample_rate_arr[0])); i++) { + for (int j = 0; j < (sizeof(bits_per_sample_arr)/sizeof(bits_per_sample_arr[0])); j++) { + i2s_config.sample_rate = sample_rate_arr[i]; + i2s_config.bits_per_sample = bits_per_sample_arr[j]; + + TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL)); + TEST_ESP_OK(i2s_set_pin(I2S_NUM_0, &pin_config)); + TEST_ASSERT((fabs((i2s_get_clk(I2S_NUM_0) - sample_rate_arr[i]))/(sample_rate_arr[i]))*100 < PERCENT_DIFF); + TEST_ESP_OK(i2s_driver_uninstall(I2S_NUM_0)); + TEST_ASSERT(initial_size == esp_get_free_heap_size()); + } + } + + vTaskDelay(100 / portTICK_PERIOD_MS); + TEST_ASSERT(initial_size == esp_get_free_heap_size()); +} diff --git a/components/driver/uart.c b/components/driver/uart.c index ed6bfb660c..df210fb0ee 100644 --- a/components/driver/uart.c +++ b/components/driver/uart.c @@ -36,6 +36,8 @@ #define UART_NUM SOC_UART_NUM +#define UART_NUM SOC_UART_NUM + #define XOFF (char)0x13 #define XON (char)0x11 @@ -596,19 +598,19 @@ esp_err_t uart_isr_register(uart_port_t uart_num, void (*fn)(void *), void *arg, int ret; UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); - switch (uart_num) { - case UART_NUM_1: - ret = esp_intr_alloc(ETS_UART1_INTR_SOURCE, intr_alloc_flags, fn, arg, handle); - break; + switch(uart_num) { + case UART_NUM_1: + ret=esp_intr_alloc(ETS_UART1_INTR_SOURCE, intr_alloc_flags, fn, arg, handle); + break; #if UART_NUM > 2 - case UART_NUM_2: - ret = esp_intr_alloc(ETS_UART2_INTR_SOURCE, intr_alloc_flags, fn, arg, handle); - break; + case UART_NUM_2: + ret=esp_intr_alloc(ETS_UART2_INTR_SOURCE, intr_alloc_flags, fn, arg, handle); + break; #endif - case UART_NUM_0: - default: - ret = esp_intr_alloc(ETS_UART0_INTR_SOURCE, intr_alloc_flags, fn, arg, handle); - break; + case UART_NUM_0: + default: + ret=esp_intr_alloc(ETS_UART0_INTR_SOURCE, intr_alloc_flags, fn, arg, handle); + break; } UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); return ret; @@ -640,34 +642,34 @@ esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int r UART_CHECK((cts_io_num < 0 || (GPIO_IS_VALID_GPIO(cts_io_num))), "cts_io_num error", ESP_FAIL); int tx_sig, rx_sig, rts_sig, cts_sig; - switch (uart_num) { - case UART_NUM_0: - tx_sig = U0TXD_OUT_IDX; - rx_sig = U0RXD_IN_IDX; - rts_sig = U0RTS_OUT_IDX; - cts_sig = U0CTS_IN_IDX; - break; - case UART_NUM_1: - tx_sig = U1TXD_OUT_IDX; - rx_sig = U1RXD_IN_IDX; - rts_sig = U1RTS_OUT_IDX; - cts_sig = U1CTS_IN_IDX; - break; + switch(uart_num) { + case UART_NUM_0: + tx_sig = U0TXD_OUT_IDX; + rx_sig = U0RXD_IN_IDX; + rts_sig = U0RTS_OUT_IDX; + cts_sig = U0CTS_IN_IDX; + break; + case UART_NUM_1: + tx_sig = U1TXD_OUT_IDX; + rx_sig = U1RXD_IN_IDX; + rts_sig = U1RTS_OUT_IDX; + cts_sig = U1CTS_IN_IDX; + break; #if UART_NUM > 2 - case UART_NUM_2: - tx_sig = U2TXD_OUT_IDX; - rx_sig = U2RXD_IN_IDX; - rts_sig = U2RTS_OUT_IDX; - cts_sig = U2CTS_IN_IDX; - break; + case UART_NUM_2: + tx_sig = U2TXD_OUT_IDX; + rx_sig = U2RXD_IN_IDX; + rts_sig = U2RTS_OUT_IDX; + cts_sig = U2CTS_IN_IDX; + break; #endif - case UART_NUM_MAX: - default: - tx_sig = U0TXD_OUT_IDX; - rx_sig = U0RXD_IN_IDX; - rts_sig = U0RTS_OUT_IDX; - cts_sig = U0CTS_IN_IDX; - break; + case UART_NUM_MAX: + default: + tx_sig = U0TXD_OUT_IDX; + rx_sig = U0RXD_IN_IDX; + rts_sig = U0RTS_OUT_IDX; + cts_sig = U0CTS_IN_IDX; + break; } if (tx_io_num >= 0) { PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[tx_io_num], PIN_FUNC_GPIO); @@ -735,7 +737,7 @@ esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_conf } else if (uart_num == UART_NUM_1) { periph_module_enable(PERIPH_UART1_MODULE); #if UART_NUM > 2 - } else if (uart_num == UART_NUM_2) { + } else if(uart_num == UART_NUM_2) { periph_module_enable(PERIPH_UART2_MODULE); #endif } @@ -775,10 +777,10 @@ esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_ #if CONFIG_IDF_TARGET_ESP32 //Hardware issue workaround: when using ref_tick, the rx timeout threshold needs increase to 10 times. //T_ref = T_apb * APB_CLK/(REF_TICK << CLKDIV_FRAG_BIT_WIDTH) - if (UART[uart_num]->conf0.tick_ref_always_on == 0) { - UART[uart_num]->conf1.rx_tout_thrhd = ((intr_conf->rx_timeout_thresh * UART_TOUT_REF_FACTOR_DEFAULT) & UART_RX_TOUT_THRHD_V); + if(UART[uart_num]->conf0.tick_ref_always_on == 0) { + UART[uart_num]->conf1.rx_tout_thrhd = (intr_conf->rx_timeout_thresh * UART_TOUT_REF_FACTOR_DEFAULT); } else { - UART[uart_num]->conf1.rx_tout_thrhd = ((intr_conf->rx_timeout_thresh) & UART_RX_TOUT_THRHD_V); + UART[uart_num]->conf1.rx_tout_thrhd = intr_conf->rx_timeout_thresh; } #elif CONFIG_IDF_TARGET_ESP32S2BETA UART[uart_num]->mem_conf.rx_tout_thrhd = ((intr_conf->rx_timeout_thresh) & UART_RX_TOUT_THRHD_V); @@ -822,14 +824,19 @@ static void uart_rx_intr_handler_default(void *param) uart_obj_t *p_uart = (uart_obj_t *) param; uint8_t uart_num = p_uart->uart_num; uart_dev_t *uart_reg = UART[uart_num]; - int rx_fifo_len = uart_reg->status.rxfifo_cnt; + int rx_fifo_len = 0; uint8_t buf_idx = 0; - uint32_t uart_intr_status = UART[uart_num]->int_st.val; + uint32_t uart_intr_status = 0; uart_event_t uart_event; portBASE_TYPE HPTaskAwoken = 0; static uint8_t pat_flg = 0; - while (uart_intr_status != 0x0) { - buf_idx = 0; + while(1) { + uart_intr_status = uart_reg->int_st.val; + // The `continue statement` may cause the interrupt to loop infinitely + // we exit the interrupt here + if(uart_intr_status == 0) { + break; + } uart_event.type = UART_EVENT_MAX; if (uart_intr_status & UART_TXFIFO_EMPTY_INT_ST_M) { uart_clear_intr_status(uart_num, UART_TXFIFO_EMPTY_INT_CLR_M); @@ -841,15 +848,12 @@ static void uart_rx_intr_handler_default(void *param) if (p_uart->tx_waiting_fifo == true && p_uart->tx_buf_size == 0) { p_uart->tx_waiting_fifo = false; xSemaphoreGiveFromISR(p_uart->tx_fifo_sem, &HPTaskAwoken); - if (HPTaskAwoken == pdTRUE) { - portYIELD_FROM_ISR(); - } } else { //We don't use TX ring buffer, because the size is zero. if (p_uart->tx_buf_size == 0) { continue; } - int tx_fifo_rem = UART_FIFO_LEN - UART[uart_num]->status.txfifo_cnt; + int tx_fifo_rem = UART_FIFO_LEN - uart_reg->status.txfifo_cnt; bool en_tx_flg = false; //We need to put a loop here, in case all the buffer items are very short. //That would cause a watch_dog reset because empty interrupt happens so often. @@ -870,10 +874,7 @@ static void uart_rx_intr_handler_default(void *param) } //We have saved the data description from the 1st item, return buffer. vRingbufferReturnItemFromISR(p_uart->tx_ring_buf, p_uart->tx_head, &HPTaskAwoken); - if (HPTaskAwoken == pdTRUE) { - portYIELD_FROM_ISR(); - } - } else if (p_uart->tx_ptr == NULL) { + }else if(p_uart->tx_ptr == NULL) { //Update the TX item pointer, we will need this to return item to buffer. p_uart->tx_ptr = (uint8_t *) p_uart->tx_head; en_tx_flg = true; @@ -904,9 +905,6 @@ static void uart_rx_intr_handler_default(void *param) if (p_uart->tx_len_cur == 0) { //Return item to ring buffer. vRingbufferReturnItemFromISR(p_uart->tx_ring_buf, p_uart->tx_head, &HPTaskAwoken); - if (HPTaskAwoken == pdTRUE) { - portYIELD_FROM_ISR(); - } p_uart->tx_head = NULL; p_uart->tx_ptr = NULL; //Sending item done, now we need to send break if there is a record. @@ -948,12 +946,8 @@ static void uart_rx_intr_handler_default(void *param) } if (p_uart->rx_buffer_full_flg == false) { //We have to read out all data in RX FIFO to clear the interrupt signal - while (buf_idx < rx_fifo_len) { -#if CONFIG_IDF_TARGET_ESP32 - p_uart->rx_data_buf[buf_idx++] = uart_reg->fifo.rw_byte; -#elif CONFIG_IDF_TARGET_ESP32S2BETA - p_uart->rx_data_buf[buf_idx++] = READ_PERI_REG(UART_FIFO_AHB_REG(uart_num)); -#endif + for(buf_idx = 0; buf_idx < rx_fifo_len; buf_idx++) { + p_uart->rx_data_buf[buf_idx] = uart_reg->fifo.rw_byte; } uint8_t pat_chr = uart_reg->at_cmd_char.data; int pat_num = uart_reg->at_cmd_char.char_num; @@ -1013,9 +1007,6 @@ static void uart_rx_intr_handler_default(void *param) p_uart->rx_buffered_len += p_uart->rx_stash_len; UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]); } - if (HPTaskAwoken == pdTRUE) { - portYIELD_FROM_ISR(); - } } else { uart_disable_intr_mask_from_isr(uart_num, UART_RXFIFO_FULL_INT_ENA_M | UART_RXFIFO_TOUT_INT_ENA_M); uart_clear_intr_status(uart_num, UART_RXFIFO_FULL_INT_CLR_M | UART_RXFIFO_TOUT_INT_CLR_M); @@ -1071,9 +1062,6 @@ static void uart_rx_intr_handler_default(void *param) p_uart->tx_waiting_brk = 0; } else { xSemaphoreGiveFromISR(p_uart->tx_brk_sem, &HPTaskAwoken); - if (HPTaskAwoken == pdTRUE) { - portYIELD_FROM_ISR(); - } } } else if (uart_intr_status & UART_TX_BRK_IDLE_DONE_INT_ST_M) { uart_disable_intr_mask_from_isr(uart_num, UART_TX_BRK_IDLE_DONE_INT_ENA_M); @@ -1104,9 +1092,6 @@ static void uart_rx_intr_handler_default(void *param) UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]); } xSemaphoreGiveFromISR(p_uart_obj[uart_num]->tx_done_sem, &HPTaskAwoken); - if (HPTaskAwoken == pdTRUE) { - portYIELD_FROM_ISR(); - } } else { uart_reg->int_clr.val = uart_intr_status; /*simply clear all other intr status*/ uart_event.type = UART_EVENT_MAX; @@ -1116,11 +1101,10 @@ static void uart_rx_intr_handler_default(void *param) if (pdFALSE == xQueueSendFromISR(p_uart->xQueueUart, (void * )&uart_event, &HPTaskAwoken)) { ESP_EARLY_LOGV(UART_TAG, "UART event queue full"); } - if (HPTaskAwoken == pdTRUE) { - portYIELD_FROM_ISR(); - } } - uart_intr_status = uart_reg->int_st.val; + } + if(HPTaskAwoken == pdTRUE) { + portYIELD_FROM_ISR(); } } @@ -1137,7 +1121,9 @@ esp_err_t uart_wait_tx_done(uart_port_t uart_num, TickType_t ticks_to_wait) return ESP_ERR_TIMEOUT; } xSemaphoreTake(p_uart_obj[uart_num]->tx_done_sem, 0); - if (UART[uart_num]->status.txfifo_cnt == 0) { + typeof(UART0.status) status = UART[uart_num]->status; + //Wait txfifo_cnt = 0, and the transmitter state machine is in idle state. + if(status.txfifo_cnt == 0 && status.st_utx_out == 0) { xSemaphoreGive(p_uart_obj[uart_num]->tx_mux); return ESP_OK; } @@ -1552,15 +1538,15 @@ esp_err_t uart_driver_delete(uart_port_t uart_num) p_uart_obj[uart_num] = NULL; if (uart_num != CONFIG_ESP_CONSOLE_UART_NUM ) { - if (uart_num == UART_NUM_0) { - periph_module_disable(PERIPH_UART0_MODULE); - } else if (uart_num == UART_NUM_1) { - periph_module_disable(PERIPH_UART1_MODULE); + if(uart_num == UART_NUM_0) { + periph_module_disable(PERIPH_UART0_MODULE); + } else if(uart_num == UART_NUM_1) { + periph_module_disable(PERIPH_UART1_MODULE); #if UART_NUM > 2 - } else if (uart_num == UART_NUM_2) { - periph_module_disable(PERIPH_UART2_MODULE); + } else if(uart_num == UART_NUM_2) { + periph_module_disable(PERIPH_UART2_MODULE); #endif - } + } } return ESP_OK; } @@ -1646,6 +1632,8 @@ esp_err_t uart_set_rx_timeout(uart_port_t uart_num, const uint8_t tout_thresh) // transmission time of one symbol (~11 bit) on current baudrate if (tout_thresh > 0) { #if CONFIG_IDF_TARGET_ESP32 + //ESP32 hardware issue workaround: when using ref_tick, the rx timeout threshold needs increase to 10 times. + //T_ref = T_apb * APB_CLK/(REF_TICK << CLKDIV_FRAG_BIT_WIDTH) if (UART[uart_num]->conf0.tick_ref_always_on == 0) { UART[uart_num]->conf1.rx_tout_thrhd = ((tout_thresh * UART_TOUT_REF_FACTOR_DEFAULT) & UART_RX_TOUT_THRHD_V); } else { diff --git a/components/efuse/CMakeLists.txt b/components/efuse/CMakeLists.txt index 4cdb846355..f73531c148 100644 --- a/components/efuse/CMakeLists.txt +++ b/components/efuse/CMakeLists.txt @@ -1,24 +1,21 @@ idf_build_get_property(soc_name IDF_TARGET) # TODO: add esp32sbeta support for efuse component -if(NOT CONFIG_IDF_TARGET_ESP32) - return() -endif() +require_idf_targets(esp32) -if(EXISTS "${COMPONENT_DIR}/${soc_name}") - include(${COMPONENT_DIR}/${soc_name}/sources.cmake) - spaces2list(EFUSE_SOC_SRCS) - add_prefix(COMPONENT_SRCS "${soc_name}/" ${EFUSE_SOC_SRCS}) - set(COMPONENT_ADD_INCLUDEDIRS include ${soc_name}/include) -endif() +include(${COMPONENT_DIR}/${soc_name}/sources.cmake) +spaces2list(EFUSE_SOC_SRCS) +add_prefix(srcs "${soc_name}/" ${EFUSE_SOC_SRCS}) +set(include_dirs include ${soc_name}/include) -list(APPEND COMPONENT_ADD_INCLUDEDIRS include) -list(APPEND COMPONENT_SRCS "src/esp_efuse_api.c" - "src/esp_efuse_fields.c" - "src/esp_efuse_utility.c") +list(APPEND srcs + "src/esp_efuse_api.c" + "src/esp_efuse_fields.c" + "src/esp_efuse_utility.c") -set(COMPONENT_PRIV_REQUIRES bootloader_support soc) -register_component() +idf_component_register(SRCS "${srcs}" + PRIV_REQUIRES bootloader_support soc spi_flash + INCLUDE_DIRS "${include_dirs}") set(GEN_EFUSE_TABLE_ARG --max_blk_len ${CONFIG_EFUSE_MAX_BLK_LEN}) diff --git a/components/efuse/src/esp_efuse_fields.c b/components/efuse/src/esp_efuse_fields.c index a456d7a944..5d440f383b 100644 --- a/components/efuse/src/esp_efuse_fields.c +++ b/components/efuse/src/esp_efuse_fields.c @@ -236,3 +236,4 @@ esp_err_t esp_efuse_update_secure_version(uint32_t secure_version) #endif return ESP_OK; } + diff --git a/components/efuse/test/CMakeLists.txt b/components/efuse/test/CMakeLists.txt index 28d0b2e7aa..e239bfe5ce 100644 --- a/components/efuse/test/CMakeLists.txt +++ b/components/efuse/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS "." "include") - -set(COMPONENT_REQUIRES unity test_utils efuse bootloader_support) - -register_component() \ No newline at end of file +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." "include" + REQUIRES unity test_utils efuse bootloader_support) \ No newline at end of file diff --git a/components/esp-tls/CMakeLists.txt b/components/esp-tls/CMakeLists.txt index 23f953d940..f6cc17c801 100644 --- a/components/esp-tls/CMakeLists.txt +++ b/components/esp-tls/CMakeLists.txt @@ -1,7 +1,5 @@ -set(COMPONENT_SRCS "esp_tls.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES mbedtls) -set(COMPONENT_PRIV_REQUIRES lwip nghttp) - -register_component() +idf_component_register(SRCS "esp_tls.c" + INCLUDE_DIRS "." + PRIVATE_INCLUDE_DIRS "private_include" + REQUIRES mbedtls + PRIV_REQUIRES lwip nghttp) diff --git a/components/esp-tls/Kconfig b/components/esp-tls/Kconfig new file mode 100644 index 0000000000..3208942717 --- /dev/null +++ b/components/esp-tls/Kconfig @@ -0,0 +1,9 @@ +menu "ESP-TLS" + + config ESP_TLS_SERVER + bool "Enable ESP-TLS Server" + help + Enable support for creating server side SSL/TLS session + +endmenu + diff --git a/components/esp-tls/component.mk b/components/esp-tls/component.mk index 7267d5f37f..06991cd1c7 100644 --- a/components/esp-tls/component.mk +++ b/components/esp-tls/component.mk @@ -1,3 +1,3 @@ COMPONENT_SRCDIRS := . -COMPONENT_ADD_INCLUDEDIRS := . +COMPONENT_ADD_INCLUDEDIRS := . private_include diff --git a/components/esp-tls/esp_tls.c b/components/esp-tls/esp_tls.c index 8d2c528ae5..65cd789f39 100644 --- a/components/esp-tls/esp_tls.c +++ b/components/esp-tls/esp_tls.c @@ -22,6 +22,7 @@ #include #include "esp_tls.h" +#include "esp_tls_error_capture_internal.h" #include static const char *TAG = "esp-tls"; @@ -34,7 +35,18 @@ static mbedtls_x509_crt *global_cacert = NULL; #define ESP_LOGE(TAG, ...) printf(__VA_ARGS__); #endif -static struct addrinfo *resolve_host_name(const char *host, size_t hostlen) +typedef struct esp_tls_pki_t { + mbedtls_x509_crt *public_cert; + mbedtls_pk_context *pk_key; + const unsigned char *publiccert_pem_buf; + unsigned int publiccert_pem_bytes; + const unsigned char *privkey_pem_buf; + unsigned int privkey_pem_bytes; + const unsigned char *privkey_password; + unsigned int privkey_password_len; +} esp_tls_pki_t; + +static esp_err_t resolve_host_name(const char *host, size_t hostlen, struct addrinfo **address_info) { struct addrinfo hints; memset(&hints, 0, sizeof(hints)); @@ -43,18 +55,17 @@ static struct addrinfo *resolve_host_name(const char *host, size_t hostlen) char *use_host = strndup(host, hostlen); if (!use_host) { - return NULL; + return ESP_ERR_NO_MEM; } ESP_LOGD(TAG, "host:%s: strlen %lu", use_host, (unsigned long)hostlen); - struct addrinfo *res; - if (getaddrinfo(use_host, NULL, &hints, &res)) { + if (getaddrinfo(use_host, NULL, &hints, address_info)) { ESP_LOGE(TAG, "couldn't get hostname for :%s:", use_host); free(use_host); - return NULL; + return ESP_ERR_ESP_TLS_CANNOT_RESOLVE_HOSTNAME; } free(use_host); - return res; + return ESP_OK; } static ssize_t tcp_read(esp_tls_t *tls, char *data, size_t datalen) @@ -70,6 +81,7 @@ static ssize_t tls_read(esp_tls_t *tls, char *data, size_t datalen) return 0; } if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret); ESP_LOGE(TAG, "read error :%d:", ret); } } @@ -82,32 +94,35 @@ static void ms_to_timeval(int timeout_ms, struct timeval *tv) tv->tv_usec = (timeout_ms % 1000) * 1000; } -static int esp_tcp_connect(const char *host, int hostlen, int port, int *sockfd, const esp_tls_cfg_t *cfg) +static esp_err_t esp_tcp_connect(const char *host, int hostlen, int port, int *sockfd, const esp_tls_t *tls, const esp_tls_cfg_t *cfg) { - int ret = -1; - struct addrinfo *res = resolve_host_name(host, hostlen); - if (!res) { + esp_err_t ret; + struct addrinfo *addrinfo; + if ((ret = resolve_host_name(host, hostlen, &addrinfo)) != ESP_OK) { return ret; } - int fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + int fd = socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol); if (fd < 0) { - ESP_LOGE(TAG, "Failed to create socket (family %d socktype %d protocol %d)", res->ai_family, res->ai_socktype, res->ai_protocol); + ESP_LOGE(TAG, "Failed to create socket (family %d socktype %d protocol %d)", addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_SYSTEM, errno); + ret = ESP_ERR_ESP_TLS_CANNOT_CREATE_SOCKET; goto err_freeaddr; } void *addr_ptr; - if (res->ai_family == AF_INET) { - struct sockaddr_in *p = (struct sockaddr_in *)res->ai_addr; + if (addrinfo->ai_family == AF_INET) { + struct sockaddr_in *p = (struct sockaddr_in *)addrinfo->ai_addr; p->sin_port = htons(port); addr_ptr = p; - } else if (res->ai_family == AF_INET6) { - struct sockaddr_in6 *p = (struct sockaddr_in6 *)res->ai_addr; + } else if (addrinfo->ai_family == AF_INET6) { + struct sockaddr_in6 *p = (struct sockaddr_in6 *)addrinfo->ai_addr; p->sin6_port = htons(port); p->sin6_family = AF_INET6; addr_ptr = p; } else { - ESP_LOGE(TAG, "Unsupported protocol family %d", res->ai_family); + ESP_LOGE(TAG, "Unsupported protocol family %d", addrinfo->ai_family); + ret = ESP_ERR_ESP_TLS_UNSUPPORTED_PROTOCOL_FAMILY; goto err_freesocket; } @@ -123,21 +138,23 @@ static int esp_tcp_connect(const char *host, int hostlen, int port, int *sockfd, } } - ret = connect(fd, addr_ptr, res->ai_addrlen); + ret = connect(fd, addr_ptr, addrinfo->ai_addrlen); if (ret < 0 && !(errno == EINPROGRESS && cfg && cfg->non_block)) { - ESP_LOGE(TAG, "Failed to connect to host (errno %d)", errno); + ESP_LOGE(TAG, "Failed to connnect to host (errno %d)", errno); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_SYSTEM, errno); + ret = ESP_ERR_ESP_TLS_FAILED_CONNECT_TO_HOST; goto err_freesocket; } *sockfd = fd; - freeaddrinfo(res); - return 0; + freeaddrinfo(addrinfo); + return ESP_OK; err_freesocket: close(fd); err_freeaddr: - freeaddrinfo(res); + freeaddrinfo(addrinfo); return ret; } @@ -169,12 +186,13 @@ esp_err_t esp_tls_set_global_ca_store(const unsigned char *cacert_pem_buf, const } ret = mbedtls_x509_crt_parse(global_cacert, cacert_pem_buf, cacert_pem_bytes); if (ret < 0) { - ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%x\n\n", -ret); + ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%x", -ret); mbedtls_x509_crt_free(global_cacert); global_cacert = NULL; return ESP_FAIL; } else if (ret > 0) { ESP_LOGE(TAG, "mbedtls_x509_crt_parse was partly successful. No. of failed certificates: %d", ret); + return ESP_ERR_MBEDTLS_CERT_PARTLY_OK; } return ESP_OK; } @@ -198,6 +216,7 @@ static void verify_certificate(esp_tls_t *tls) char buf[100]; if ((flags = mbedtls_ssl_get_verify_result(&tls->ssl)) != 0) { ESP_LOGI(TAG, "Failed to verify peer certificate!"); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS_CERT_FLAGS, flags); bzero(buf, sizeof(buf)); mbedtls_x509_crt_verify_info(buf, sizeof(buf), " ! ", flags); ESP_LOGI(TAG, "verification info: %s", buf); @@ -215,6 +234,10 @@ static void mbedtls_cleanup(esp_tls_t *tls) mbedtls_x509_crt_free(tls->cacert_ptr); } tls->cacert_ptr = NULL; +#ifdef CONFIG_ESP_TLS_SERVER + mbedtls_x509_crt_free(&tls->servercert); + mbedtls_pk_free(&tls->serverkey); +#endif mbedtls_x509_crt_free(&tls->cacert); mbedtls_x509_crt_free(&tls->clientcert); mbedtls_pk_free(&tls->clientkey); @@ -224,22 +247,136 @@ static void mbedtls_cleanup(esp_tls_t *tls) mbedtls_ssl_free(&tls->ssl); } -static int create_ssl_handle(esp_tls_t *tls, const char *hostname, size_t hostlen, const esp_tls_cfg_t *cfg) +static esp_err_t set_global_ca_store(esp_tls_t *tls) { + assert(tls); + if (global_cacert == NULL) { + ESP_LOGE(TAG, "global_cacert is NULL"); + return ESP_ERR_INVALID_STATE; + } + tls->cacert_ptr = global_cacert; + mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED); + mbedtls_ssl_conf_ca_chain(&tls->conf, tls->cacert_ptr, NULL); + return ESP_OK; +} + +static esp_err_t set_ca_cert(esp_tls_t *tls, const unsigned char *cacert, size_t cacert_len) +{ + assert(tls); + tls->cacert_ptr = &tls->cacert; + mbedtls_x509_crt_init(tls->cacert_ptr); + int ret = mbedtls_x509_crt_parse(tls->cacert_ptr, cacert, cacert_len); + if (ret < 0) { + ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%x", -ret); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret); + return ESP_ERR_MBEDTLS_X509_CRT_PARSE_FAILED; + } + mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED); + mbedtls_ssl_conf_ca_chain(&tls->conf, tls->cacert_ptr, NULL); + return ESP_OK; +} + +static esp_err_t set_pki_context(esp_tls_t *tls, const esp_tls_pki_t *pki) +{ + assert(tls); + assert(pki); int ret; - tls->server_fd.fd = tls->sockfd; - mbedtls_ssl_init(&tls->ssl); - mbedtls_ctr_drbg_init(&tls->ctr_drbg); - mbedtls_ssl_config_init(&tls->conf); - mbedtls_entropy_init(&tls->entropy); - - if ((ret = mbedtls_ctr_drbg_seed(&tls->ctr_drbg, - mbedtls_entropy_func, &tls->entropy, NULL, 0)) != 0) { - ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned %d", ret); - goto exit; + if (pki->publiccert_pem_buf != NULL && + pki->privkey_pem_buf != NULL && + pki->public_cert != NULL && + pki->pk_key != NULL) { + + mbedtls_x509_crt_init(pki->public_cert); + mbedtls_pk_init(pki->pk_key); + + ret = mbedtls_x509_crt_parse(pki->public_cert, pki->publiccert_pem_buf, pki->publiccert_pem_bytes); + if (ret < 0) { + ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%x", -ret); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret); + return ESP_ERR_MBEDTLS_X509_CRT_PARSE_FAILED; + } + + ret = mbedtls_pk_parse_key(pki->pk_key, pki->privkey_pem_buf, pki->privkey_pem_bytes, + NULL, 0); + if (ret < 0) { + ESP_LOGE(TAG, "mbedtls_pk_parse_keyfile returned -0x%x", -ret); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret); + return ESP_ERR_MBEDTLS_PK_PARSE_KEY_FAILED; + } + + ret = mbedtls_ssl_conf_own_cert(&tls->conf, pki->public_cert, pki->pk_key); + if (ret < 0) { + ESP_LOGE(TAG, "mbedtls_ssl_conf_own_cert returned -0x%x", -ret); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret); + return ESP_ERR_MBEDTLS_SSL_CONF_OWN_CERT_FAILED; + } + } else { + return ESP_ERR_INVALID_ARG; } - + return ESP_OK; +} + +#ifdef CONFIG_ESP_TLS_SERVER +static esp_err_t set_server_config(esp_tls_cfg_server_t *cfg, esp_tls_t *tls) +{ + assert(cfg != NULL); + assert(tls != NULL); + int ret; + esp_err_t esp_ret; + if ((ret = mbedtls_ssl_config_defaults(&tls->conf, + MBEDTLS_SSL_IS_SERVER, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { + ESP_LOGE(TAG, "mbedtls_ssl_config_defaults returned %d", ret); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret); + return ESP_ERR_MBEDTLS_SSL_CONFIG_DEFAULTS_FAILED; + } + +#ifdef CONFIG_MBEDTLS_SSL_ALPN + if (cfg->alpn_protos) { + mbedtls_ssl_conf_alpn_protocols(&tls->conf, cfg->alpn_protos); + } +#endif + + if (cfg->cacert_pem_buf != NULL) { + esp_ret = set_ca_cert(tls, cfg->cacert_pem_buf, cfg->cacert_pem_bytes); + if (esp_ret != ESP_OK) { + return esp_ret; + } + } else { + mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE); + } + + if (cfg->servercert_pem_buf != NULL && cfg->serverkey_pem_buf != NULL) { + esp_tls_pki_t pki = { + .public_cert = &tls->servercert, + .pk_key = &tls->serverkey, + .publiccert_pem_buf = cfg->servercert_pem_buf, + .publiccert_pem_bytes = cfg->servercert_pem_bytes, + .privkey_pem_buf = cfg->serverkey_pem_buf, + .privkey_pem_bytes = cfg->serverkey_pem_bytes, + .privkey_password = cfg->serverkey_password, + .privkey_password_len = cfg->serverkey_password_len, + }; + esp_ret = set_pki_context(tls, &pki); + if (esp_ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to set server pki context"); + return esp_ret; + } + } else { + ESP_LOGE(TAG, "Missing server certificate and/or key"); + return ESP_ERR_INVALID_STATE; + } + return ESP_OK; +} +#endif /* ! CONFIG_ESP_TLS_SERVER */ + +static esp_err_t set_client_config(const char *hostname, size_t hostlen, esp_tls_cfg_t *cfg, esp_tls_t *tls) +{ + assert(cfg != NULL); + assert(tls != NULL); + int ret; if (!cfg->skip_common_name) { char *use_host = NULL; if (cfg->common_name != NULL) { @@ -249,14 +386,14 @@ static int create_ssl_handle(esp_tls_t *tls, const char *hostname, size_t hostle } if (use_host == NULL) { - goto exit; + return ESP_ERR_NO_MEM; } - /* Hostname set here should match CN in server certificate */ if ((ret = mbedtls_ssl_set_hostname(&tls->ssl, use_host)) != 0) { ESP_LOGE(TAG, "mbedtls_ssl_set_hostname returned -0x%x", -ret); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret); free(use_host); - goto exit; + return ESP_ERR_MBEDTLS_SSL_SET_HOSTNAME_FAILED; } free(use_host); } @@ -265,62 +402,90 @@ static int create_ssl_handle(esp_tls_t *tls, const char *hostname, size_t hostle MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { - ESP_LOGE(TAG, "mbedtls_ssl_config_defaults returned %d", ret); - goto exit; + ESP_LOGE(TAG, "mbedtls_ssl_config_defaults returned -0x%x", -ret); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret); + return ESP_ERR_MBEDTLS_SSL_CONFIG_DEFAULTS_FAILED; } #ifdef CONFIG_MBEDTLS_SSL_ALPN if (cfg->alpn_protos) { - mbedtls_ssl_conf_alpn_protocols(&tls->conf, cfg->alpn_protos); + if ((ret =mbedtls_ssl_conf_alpn_protocols(&tls->conf, cfg->alpn_protos) != 0)) { + ESP_LOGE(TAG, "mbedtls_ssl_conf_alpn_protocols returned -0x%x", -ret); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret); + return ESP_ERR_MBEDTLS_SSL_CONF_ALPN_PROTOCOLS_FAILED; + } } #endif - if (cfg->use_global_ca_store == true) { - if (global_cacert == NULL) { - ESP_LOGE(TAG, "global_cacert is NULL"); - goto exit; + esp_err_t esp_ret = set_global_ca_store(tls); + if (esp_ret != ESP_OK) { + return esp_ret; } - tls->cacert_ptr = global_cacert; - mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED); - mbedtls_ssl_conf_ca_chain(&tls->conf, tls->cacert_ptr, NULL); } else if (cfg->cacert_pem_buf != NULL) { - tls->cacert_ptr = &tls->cacert; - mbedtls_x509_crt_init(tls->cacert_ptr); - ret = mbedtls_x509_crt_parse(tls->cacert_ptr, cfg->cacert_pem_buf, cfg->cacert_pem_bytes); - if (ret < 0) { - ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%x\n\n", -ret); - goto exit; + esp_err_t esp_ret = set_ca_cert(tls, cfg->cacert_pem_buf, cfg->cacert_pem_bytes); + if (esp_ret != ESP_OK) { + return esp_ret; } - mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED); - mbedtls_ssl_conf_ca_chain(&tls->conf, tls->cacert_ptr, NULL); } else { mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE); } if (cfg->clientcert_pem_buf != NULL && cfg->clientkey_pem_buf != NULL) { - mbedtls_x509_crt_init(&tls->clientcert); - mbedtls_pk_init(&tls->clientkey); - - ret = mbedtls_x509_crt_parse(&tls->clientcert, cfg->clientcert_pem_buf, cfg->clientcert_pem_bytes); - if (ret < 0) { - ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%x\n\n", -ret); - goto exit; - } - - ret = mbedtls_pk_parse_key(&tls->clientkey, cfg->clientkey_pem_buf, cfg->clientkey_pem_bytes, - cfg->clientkey_password, cfg->clientkey_password_len); - if (ret < 0) { - ESP_LOGE(TAG, "mbedtls_pk_parse_keyfile returned -0x%x\n\n", -ret); - goto exit; - } - - ret = mbedtls_ssl_conf_own_cert(&tls->conf, &tls->clientcert, &tls->clientkey); - if (ret < 0) { - ESP_LOGE(TAG, "mbedtls_ssl_conf_own_cert returned -0x%x\n\n", -ret); - goto exit; + esp_tls_pki_t pki = { + .public_cert = &tls->clientcert, + .pk_key = &tls->clientkey, + .publiccert_pem_buf = cfg->clientcert_pem_buf, + .publiccert_pem_bytes = cfg->clientcert_pem_bytes, + .privkey_pem_buf = cfg->clientkey_pem_buf, + .privkey_pem_bytes = cfg->clientkey_pem_bytes, + .privkey_password = cfg->clientkey_password, + .privkey_password_len = cfg->clientkey_password_len, + }; + esp_err_t esp_ret = set_pki_context(tls, &pki); + if (esp_ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to set server pki context"); + return esp_ret; } } else if (cfg->clientcert_pem_buf != NULL || cfg->clientkey_pem_buf != NULL) { - ESP_LOGE(TAG, "You have to provide both clientcert_pem_buf and clientkey_pem_buf for mutual authentication\n\n"); + ESP_LOGE(TAG, "You have to provide both clientcert_pem_buf and clientkey_pem_buf for mutual authentication"); + return ESP_ERR_INVALID_STATE; + } + return ESP_OK; +} + +static esp_err_t create_ssl_handle(const char *hostname, size_t hostlen, const void *cfg, esp_tls_t *tls) +{ + assert(cfg != NULL); + assert(tls != NULL); + int ret; + esp_err_t esp_ret; + tls->server_fd.fd = tls->sockfd; + mbedtls_ssl_init(&tls->ssl); + mbedtls_ctr_drbg_init(&tls->ctr_drbg); + mbedtls_ssl_config_init(&tls->conf); + mbedtls_entropy_init(&tls->entropy); + + if (tls->role == ESP_TLS_CLIENT) { + esp_ret = set_client_config(hostname, hostlen, (esp_tls_cfg_t *)cfg, tls); + if (esp_ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to set client configurations"); + goto exit; + } +#ifdef CONFIG_ESP_TLS_SERVER + } else if (tls->role == ESP_TLS_SERVER) { + esp_ret = set_server_config((esp_tls_cfg_server_t *) cfg, tls); + if (esp_ret != 0) { + ESP_LOGE(TAG, "Failed to set server configurations"); + goto exit; + } +#endif + } + + if ((ret = mbedtls_ctr_drbg_seed(&tls->ctr_drbg, + mbedtls_entropy_func, &tls->entropy, NULL, 0)) != 0) { + ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned -0x%x", -ret); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret); + esp_ret = ESP_ERR_MBEDTLS_CTR_DRBG_SEED_FAILED; goto exit; } @@ -331,15 +496,17 @@ static int create_ssl_handle(esp_tls_t *tls, const char *hostname, size_t hostle #endif if ((ret = mbedtls_ssl_setup(&tls->ssl, &tls->conf)) != 0) { - ESP_LOGE(TAG, "mbedtls_ssl_setup returned -0x%x\n\n", -ret); + ESP_LOGE(TAG, "mbedtls_ssl_setup returned -0x%x", -ret); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret); + esp_ret = ESP_ERR_MBEDTLS_SSL_SETUP_FAILED; goto exit; } mbedtls_ssl_set_bio(&tls->ssl, &tls->server_fd, mbedtls_net_send, mbedtls_net_recv, NULL); - return 0; + return ESP_OK; exit: mbedtls_cleanup(tls); - return -1; + return esp_ret; } /** @@ -354,6 +521,7 @@ void esp_tls_conn_delete(esp_tls_t *tls) } else if (tls->sockfd >= 0) { close(tls->sockfd); } + free(tls->error_handle); free(tls); } }; @@ -368,6 +536,8 @@ static ssize_t tls_write(esp_tls_t *tls, const char *data, size_t datalen) ssize_t ret = mbedtls_ssl_write(&tls->ssl, (unsigned char*) data, datalen); if (ret < 0) { if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_ESP, ESP_ERR_MBEDTLS_SSL_WRITE_FAILED); ESP_LOGE(TAG, "write error :%d:", ret); } } @@ -380,6 +550,9 @@ static int esp_tls_low_level_conn(const char *hostname, int hostlen, int port, c ESP_LOGE(TAG, "empty esp_tls parameter"); return -1; } + esp_err_t esp_ret; + int ret; + /* These states are used to keep a tab on connection progress in case of non-blocking connect, and in case of blocking connect these cases will get executed one after the other */ switch (tls->conn_state) { @@ -389,8 +562,8 @@ static int esp_tls_low_level_conn(const char *hostname, int hostlen, int port, c mbedtls_net_init(&tls->server_fd); tls->is_tls = true; } - int ret = esp_tcp_connect(hostname, hostlen, port, &tls->sockfd, cfg); - if (ret < 0) { + if ((esp_ret = esp_tcp_connect(hostname, hostlen, port, &tls->sockfd, tls, cfg)) != ESP_OK) { + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_ESP, esp_ret); return -1; } if (!cfg) { @@ -425,15 +598,18 @@ static int esp_tls_low_level_conn(const char *hostname, int hostlen, int port, c /* pending error check */ if (getsockopt(tls->sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { ESP_LOGD(TAG, "Non blocking connect failed"); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_SYSTEM, errno); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_ESP, ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED); tls->conn_state = ESP_TLS_FAIL; return -1; } } } /* By now, the connection has been established */ - ret = create_ssl_handle(tls, hostname, hostlen, cfg); - if (ret != 0) { - ESP_LOGD(TAG, "create_ssl_handshake failed"); + esp_ret = create_ssl_handle(hostname, hostlen, cfg, tls); + if (esp_ret != ESP_OK) { + ESP_LOGE(TAG, "create_ssl_handle failed"); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_ESP, esp_ret); tls->conn_state = ESP_TLS_FAIL; return -1; } @@ -450,6 +626,8 @@ static int esp_tls_low_level_conn(const char *hostname, int hostlen, int port, c } else { if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { ESP_LOGE(TAG, "mbedtls_ssl_handshake returned -0x%x", -ret); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_ESP, ESP_ERR_MBEDTLS_SSL_HANDSHAKE_FAILED); if (cfg->cacert_pem_buf != NULL || cfg->use_global_ca_store == true) { /* This is to check whether handshake failed due to invalid certificate*/ verify_certificate(tls); @@ -496,6 +674,22 @@ esp_tls_t *esp_tls_conn_new(const char *hostname, int hostlen, int port, const e return NULL; } +int esp_tls_conn_new_sync(const char *hostname, int hostlen, int port, const esp_tls_cfg_t *cfg, esp_tls_t *tls) +{ + /* esp_tls_conn_new_sync() is a sync alternative to esp_tls_conn_new_async() with symetric function prototype + it is an alternative to esp_tls_conn_new() which is left for compatibility reasons */ + while (1) { + int ret = esp_tls_low_level_conn(hostname, hostlen, port, cfg, tls); + if (ret == 1) { + return ret; + } else if (ret == -1) { + ESP_LOGE(TAG, "Failed to open new connection"); + return -1; + } + } + return 0; +} + /* * @brief Create a new TLS/SSL non-blocking connection */ @@ -527,17 +721,21 @@ esp_tls_t *esp_tls_conn_http_new(const char *url, const esp_tls_cfg_t *cfg) struct http_parser_url u; http_parser_url_init(&u); http_parser_parse_url(url, strlen(url), 0, &u); - + esp_tls_t *tls = esp_tls_init(); + if (!tls) return NULL; /* Connect to host */ - return esp_tls_conn_new(&url[u.field_data[UF_HOST].off], u.field_data[UF_HOST].len, - get_port(url, &u), cfg); + if (esp_tls_conn_new_sync(&url[u.field_data[UF_HOST].off], u.field_data[UF_HOST].len, + get_port(url, &u), cfg, tls) == 1) { + return tls; + } + return NULL; } -size_t esp_tls_get_bytes_avail(esp_tls_t *tls) +ssize_t esp_tls_get_bytes_avail(esp_tls_t *tls) { if (!tls) { ESP_LOGE(TAG, "empty arg passed to esp_tls_get_bytes_avail()"); - return ESP_FAIL; + return -1; } return mbedtls_ssl_get_bytes_avail(&tls->ssl); } @@ -556,3 +754,76 @@ int esp_tls_conn_http_new_async(const char *url, const esp_tls_cfg_t *cfg, esp_t return esp_tls_conn_new_async(&url[u.field_data[UF_HOST].off], u.field_data[UF_HOST].len, get_port(url, &u), cfg, tls); } + +#ifdef CONFIG_ESP_TLS_SERVER +/** + * @brief Create TLS/SSL server session + */ +int esp_tls_server_session_create(esp_tls_cfg_server_t *cfg, int sockfd, esp_tls_t *tls) +{ + if (tls == NULL || cfg == NULL) { + return -1; + } + tls->role = ESP_TLS_SERVER; + tls->sockfd = sockfd; + esp_err_t esp_ret = create_ssl_handle(NULL, 0, cfg, tls); + if (esp_ret != ESP_OK) { + ESP_LOGE(TAG, "create_ssl_handle failed"); + ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_ESP, esp_ret); + tls->conn_state = ESP_TLS_FAIL; + return -1; + } + tls->read = tls_read; + tls->write = tls_write; + int ret; + while ((ret = mbedtls_ssl_handshake(&tls->ssl)) != 0) { + if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { + ESP_LOGE(TAG, "mbedtls_ssl_handshake returned %d", ret); + tls->conn_state = ESP_TLS_FAIL; + return ret; + } + } + return 0; +} +/** + * @brief Close the server side TLS/SSL connection and free any allocated resources. + */ +void esp_tls_server_session_delete(esp_tls_t *tls) +{ + if (tls != NULL) { + mbedtls_cleanup(tls); + free(tls); + } +}; +#endif /* ! CONFIG_ESP_TLS_SERVER */ + +esp_tls_t *esp_tls_init() +{ + esp_tls_t *tls = (esp_tls_t *)calloc(1, sizeof(esp_tls_t)); + if (!tls) { + return NULL; + } + tls->error_handle = calloc(1, sizeof(esp_tls_last_error_t)); + if (!tls->error_handle) { + free(tls); + return NULL; + } + tls->server_fd.fd = tls->sockfd = -1; + return tls; +} + +esp_err_t esp_tls_get_and_clear_last_error(esp_tls_error_handle_t h, int *mbedtls_code, int *mbedtls_flags) +{ + if (!h) { + return ESP_ERR_INVALID_STATE; + } + esp_err_t last_err = h->last_error; + if (mbedtls_code) { + *mbedtls_code = h->mbedtls_error_code; + } + if (mbedtls_flags) { + *mbedtls_flags = h->mbedtls_flags; + } + memset(h, 0, sizeof(esp_tls_last_error_t)); + return last_err; +} diff --git a/components/esp-tls/esp_tls.h b/components/esp-tls/esp_tls.h index 41faa5b0c8..1c2f785ea5 100644 --- a/components/esp-tls/esp_tls.h +++ b/components/esp-tls/esp_tls.h @@ -31,6 +31,35 @@ extern "C" { #endif +#define ESP_ERR_ESP_TLS_BASE 0x8000 /*!< Starting number of ESP-TLS error codes */ +#define ESP_ERR_ESP_TLS_CANNOT_RESOLVE_HOSTNAME (ESP_ERR_ESP_TLS_BASE + 0x01) /*!< Error if hostname couldn't be resolved upon tls connection */ +#define ESP_ERR_ESP_TLS_CANNOT_CREATE_SOCKET (ESP_ERR_ESP_TLS_BASE + 0x02) /*!< Failed to create socket */ +#define ESP_ERR_ESP_TLS_UNSUPPORTED_PROTOCOL_FAMILY (ESP_ERR_ESP_TLS_BASE + 0x03) /*!< Unsupported protocol family */ +#define ESP_ERR_ESP_TLS_FAILED_CONNECT_TO_HOST (ESP_ERR_ESP_TLS_BASE + 0x04) /*!< Failed to connect to host */ +#define ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED (ESP_ERR_ESP_TLS_BASE + 0x05) /*!< failed to set socket option */ +#define ESP_ERR_MBEDTLS_CERT_PARTLY_OK (ESP_ERR_ESP_TLS_BASE + 0x06) /*!< mbedtls parse certificates was partly successful */ +#define ESP_ERR_MBEDTLS_CTR_DRBG_SEED_FAILED (ESP_ERR_ESP_TLS_BASE + 0x07) /*!< mbedtls api returned error */ +#define ESP_ERR_MBEDTLS_SSL_SET_HOSTNAME_FAILED (ESP_ERR_ESP_TLS_BASE + 0x08) /*!< mbedtls api returned error */ +#define ESP_ERR_MBEDTLS_SSL_CONFIG_DEFAULTS_FAILED (ESP_ERR_ESP_TLS_BASE + 0x09) /*!< mbedtls api returned error */ +#define ESP_ERR_MBEDTLS_SSL_CONF_ALPN_PROTOCOLS_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0A) /*!< mbedtls api returned error */ +#define ESP_ERR_MBEDTLS_X509_CRT_PARSE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0B) /*!< mbedtls api returned error */ +#define ESP_ERR_MBEDTLS_SSL_CONF_OWN_CERT_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0C) /*!< mbedtls api returned error */ +#define ESP_ERR_MBEDTLS_SSL_SETUP_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0D) /*!< mbedtls api returned error */ +#define ESP_ERR_MBEDTLS_SSL_WRITE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0E) /*!< mbedtls api returned error */ +#define ESP_ERR_MBEDTLS_PK_PARSE_KEY_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0F) /*!< mbedtls api returned failed */ +#define ESP_ERR_MBEDTLS_SSL_HANDSHAKE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x10) /*!< mbedtls api returned failed */ + +typedef struct esp_tls_last_error* esp_tls_error_handle_t; + +/** +* @brief Error structure containing relevant errors in case tls error occurred +*/ +typedef struct esp_tls_last_error { + esp_err_t last_error; /*!< error code (based on ESP_ERR_ESP_TLS_BASE) of the last occurred error */ + int mbedtls_error_code; /*!< mbedtls error code from last mbedtls failed api */ + int mbedtls_flags; /*!< last certification verification flags */ +} esp_tls_last_error_t; + /** * @brief ESP-TLS Connection State */ @@ -42,6 +71,11 @@ typedef enum esp_tls_conn_state { ESP_TLS_DONE, } esp_tls_conn_state_t; +typedef enum esp_tls_role { + ESP_TLS_CLIENT = 0, + ESP_TLS_SERVER, +} esp_tls_role_t; + /** * @brief ESP-TLS configuration parameters */ @@ -52,9 +86,8 @@ typedef struct esp_tls_cfg { The format is length followed by protocol name. For the most common cases the following is ok: - "\x02h2" - - where the first '2' is the length of the protocol and - - the subsequent 'h2' is the protocol name */ + const char **alpn_protos = { "h2", NULL }; + - where 'h2' is the protocol name */ const unsigned char *cacert_pem_buf; /*!< Certificate Authority's certificate in a buffer. This buffer should be NULL terminated */ @@ -64,7 +97,7 @@ typedef struct esp_tls_cfg { const unsigned char *clientcert_pem_buf;/*!< Client certificate in a buffer This buffer should be NULL terminated */ - + unsigned int clientcert_pem_bytes; /*!< Size of client certificate pointed to by clientcert_pem_buf */ @@ -94,6 +127,43 @@ typedef struct esp_tls_cfg { bool skip_common_name; /*!< Skip any validation of server certificate CN field */ } esp_tls_cfg_t; +#ifdef CONFIG_ESP_TLS_SERVER +typedef struct esp_tls_cfg_server { + const char **alpn_protos; /*!< Application protocols required for HTTP2. + If HTTP2/ALPN support is required, a list + of protocols that should be negotiated. + The format is length followed by protocol + name. + For the most common cases the following is ok: + const char **alpn_protos = { "h2", NULL }; + - where 'h2' is the protocol name */ + + const unsigned char *cacert_pem_buf; /*!< Client CA certificate in a buffer. + This buffer should be NULL terminated */ + + unsigned int cacert_pem_bytes; /*!< Size of client CA certificate + pointed to by cacert_pem_buf */ + + const unsigned char *servercert_pem_buf; /*!< Server certificate in a buffer + This buffer should be NULL terminated */ + + unsigned int servercert_pem_bytes; /*!< Size of server certificate pointed to by + servercert_pem_buf */ + + const unsigned char *serverkey_pem_buf; /*!< Server key in a buffer + This buffer should be NULL terminated */ + + unsigned int serverkey_pem_bytes; /*!< Size of server key pointed to by + serverkey_pem_buf */ + + const unsigned char *serverkey_password; /*!< Server key decryption password string */ + + unsigned int serverkey_password_len; /*!< String length of the password pointed to by + serverkey_password */ + +} esp_tls_cfg_server_t; +#endif /* ! CONFIG_ESP_TLS_SERVER */ + /** * @brief ESP-TLS Connection Handle */ @@ -120,7 +190,12 @@ typedef struct esp_tls { mbedtls_pk_context clientkey; /*!< Container for the private key of the client certificate */ +#ifdef CONFIG_ESP_TLS_SERVER + mbedtls_x509_crt servercert; /*!< Container for the X.509 server certificate */ + mbedtls_pk_context serverkey; /*!< Container for the private key of the server + certificate */ +#endif int sockfd; /*!< Underlying socket file descriptor. */ ssize_t (*read)(struct esp_tls *tls, char *data, size_t datalen); /*!< Callback function for reading data from TLS/SSL @@ -136,23 +211,70 @@ typedef struct esp_tls { fd_set wset; /*!< write file descriptors */ bool is_tls; /*!< indicates connection type (TLS or NON-TLS) */ + + esp_tls_role_t role; /*!< esp-tls role + - ESP_TLS_CLIENT + - ESP_TLS_SERVER */ + + esp_tls_error_handle_t error_handle; /*!< handle to error descriptor */ + } esp_tls_t; + +/** + * @brief Create TLS connection + * + * This function allocates and initializes esp-tls structure handle. + * + * @return tls Pointer to esp-tls as esp-tls handle if successfully initialized, + * NULL if allocation error + */ +esp_tls_t *esp_tls_init(); + + + + /** * @brief Create a new blocking TLS/SSL connection * * This function establishes a TLS/SSL connection with the specified host in blocking manner. - * + * + * Note: This API is present for backward compatibility reasons. Alternative function + * with the same functionality is `esp_tls_conn_new_sync` (and its asynchronous version + * `esp_tls_conn_new_async`) + * * @param[in] hostname Hostname of the host. * @param[in] hostlen Length of hostname. * @param[in] port Port number of the host. - * @param[in] cfg TLS configuration as esp_tls_cfg_t. If you wish to open + * @param[in] cfg TLS configuration as esp_tls_cfg_t. If you wish to open * non-TLS connection, keep this NULL. For TLS connection, * a pass pointer to esp_tls_cfg_t. At a minimum, this * structure should be zero-initialized. + * * @return pointer to esp_tls_t, or NULL if connection couldn't be opened. */ -esp_tls_t *esp_tls_conn_new(const char *hostname, int hostlen, int port, const esp_tls_cfg_t *cfg); +esp_tls_t *esp_tls_conn_new(const char *hostname, int hostlen, int port, const esp_tls_cfg_t *cfg) __attribute__ ((deprecated)); + +/** + * @brief Create a new blocking TLS/SSL connection + * + * This function establishes a TLS/SSL connection with the specified host in blocking manner. + * + * @param[in] hostname Hostname of the host. + * @param[in] hostlen Length of hostname. + * @param[in] port Port number of the host. + * @param[in] cfg TLS configuration as esp_tls_cfg_t. If you wish to open + * non-TLS connection, keep this NULL. For TLS connection, + * a pass pointer to esp_tls_cfg_t. At a minimum, this + * structure should be zero-initialized. + * @param[in] tls Pointer to esp-tls as esp-tls handle. + * + * @return + * - -1 If connection establishment fails. + * - 1 If connection establishment is successful. + * - 0 Reserved for connection state is in progress. + */ +int esp_tls_conn_new_sync(const char *hostname, int hostlen, int port, const esp_tls_cfg_t *cfg, esp_tls_t *tls); /** * @brief Create a new blocking TLS/SSL connection with a given "HTTP" url @@ -267,7 +389,7 @@ void esp_tls_conn_delete(esp_tls_t *tls); * - bytes available in the application data * record read buffer */ -size_t esp_tls_get_bytes_avail(esp_tls_t *tls); +ssize_t esp_tls_get_bytes_avail(esp_tls_t *tls); /** * @brief Create a global CA store, initially empty. @@ -323,6 +445,50 @@ mbedtls_x509_crt *esp_tls_get_global_ca_store(); */ void esp_tls_free_global_ca_store(); +/** + * @brief Returns last error in esp_tls with detailed mbedtls related error codes. + * The error information is cleared internally upon return + * + * @param[in] h esp-tls error handle. + * @param[out] mbedtls_code last error code returned from mbedtls api (set to zero if none) + * This pointer could be NULL if caller does not care about mbedtls_code + * @param[out] mbedtls_flags last certification verification flags (set to zero if none) + * This pointer could be NULL if caller does not care about mbedtls_flags + * + * @return + * - ESP_ERR_INVALID_STATE if invalid parameters + * - ESP_OK (0) if no error occurred + * - specific error code (based on ESP_ERR_ESP_TLS_BASE) otherwise + */ +esp_err_t esp_tls_get_and_clear_last_error(esp_tls_error_handle_t h, int *mbedtls_code, int *mbedtls_flags); + +#ifdef CONFIG_ESP_TLS_SERVER +/** + * @brief Create TLS/SSL server session + * + * This function creates a TLS/SSL server context for already accepted client connection + * and performs TLS/SSL handshake with the client + * + * @param[in] cfg Pointer to esp_tls_cfg_server_t + * @param[in] sockfd FD of accepted connection + * @param[out] tls Pointer to allocated esp_tls_t + * + * @return + * - 0 if successful + * - <0 in case of error + * + */ +int esp_tls_server_session_create(esp_tls_cfg_server_t *cfg, int sockfd, esp_tls_t *tls); + +/** + * @brief Close the server side TLS/SSL connection and free any allocated resources. + * + * This function should be called to close each tls connection opened with esp_tls_server_session_create() + * + * @param[in] tls pointer to esp_tls_t + */ +void esp_tls_server_session_delete(esp_tls_t *tls); +#endif /* ! CONFIG_ESP_TLS_SERVER */ #ifdef __cplusplus } diff --git a/components/esp-tls/private_include/esp_tls_error_capture_internal.h b/components/esp-tls/private_include/esp_tls_error_capture_internal.h new file mode 100644 index 0000000000..89ee4435cf --- /dev/null +++ b/components/esp-tls/private_include/esp_tls_error_capture_internal.h @@ -0,0 +1,61 @@ +// Copyright 2017-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef __ESP_TLS_ERROR_CAPTURE_INTERNAL_H__ +#define __ESP_TLS_ERROR_CAPTURE_INTERNAL_H__ +/** +* Note: this is an implementation placeholder for error logger. +* This version is internal to esp-tls component and only saves single esp_err of last occurred error +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** +* Definition of different types/sources of error codes reported +* from different components +*/ +typedef enum { + ERR_TYPE_UNKNOWN = 0, + ERR_TYPE_SYSTEM, + ERR_TYPE_MBEDTLS, + ERR_TYPE_MBEDTLS_CERT_FLAGS, + ERR_TYPE_ESP, +} err_type_t; + +/** + * Error tracker logging macro, this implementation saves latest errors of + * ERR_TYPE_ESP, ERR_TYPE_MBEDTLS and ERR_TYPE_MBEDTLS_CERT_FLAGS types + */ +#define ESP_INT_EVENT_TRACKER_CAPTURE(h, type, code) esp_int_event_tracker_capture(h, type, code) + +static inline void esp_int_event_tracker_capture(esp_tls_error_handle_t h, uint32_t type, int code) +{ + if (h) { + if (type == ERR_TYPE_ESP) { + h->last_error = code; + } else if (type == ERR_TYPE_MBEDTLS) { + h->mbedtls_error_code = code; + } else if (type == ERR_TYPE_MBEDTLS_CERT_FLAGS) { + h->mbedtls_flags = code; + } + } +} + +#ifdef __cplusplus +} +#endif + +#endif //__ESP_TLS_ERROR_CAPTURE_INTERNAL_H__ diff --git a/components/esp32/CMakeLists.txt b/components/esp32/CMakeLists.txt index 701075be99..d8dd35b0fb 100644 --- a/components/esp32/CMakeLists.txt +++ b/components/esp32/CMakeLists.txt @@ -1,75 +1,78 @@ +# TODO esp32s2beta: Support uncommenting this # require_idf_targets(esp32) -if(BOOTLOADER_BUILD AND CONFIG_IDF_TARGET_ESP32) +if(BOOTLOADER_BUILD) # For bootloader, all we need from esp32 is headers - set(COMPONENT_ADD_INCLUDEDIRS include) - register_component() - target_linker_script(${COMPONENT_LIB} "ld/esp32.peripherals.ld") -elseif(CONFIG_IDF_TARGET_ESP32) + idf_component_register(INCLUDE_DIRS include) + target_linker_script(${COMPONENT_LIB} INTERFACE "ld/esp32.peripherals.ld") +else() # Regular app build + set(srcs + "brownout.c" + "cache_err_int.c" + "cache_sram_mmu.c" + "clk.c" + "cpu_start.c" + "crosscore_int.c" + "dport_access.c" + "dport_panic_highint_hdl.S" + "esp_adapter.c" + "esp_timer_esp32.c" + "esp_himem.c" + "hw_random.c" + "int_wdt.c" + "intr_alloc.c" + "panic.c" + "pm_esp32.c" + "pm_trace.c" + "reset_reason.c" + "sleep_modes.c" + "spiram.c" + "spiram_psram.c" + "system_api.c" + "task_wdt.c") + set(include_dirs "include") - set(COMPONENT_SRCS "brownout.c" - "cache_err_int.c" - "cache_sram_mmu.c" - "clk.c" - "cpu_start.c" - "crosscore_int.c" - "dport_access.c" - "dport_panic_highint_hdl.S" - "esp_adapter.c" - "esp_timer_esp32.c" - "esp_himem.c" - "hw_random.c" - "int_wdt.c" - "intr_alloc.c" - "panic.c" - "pm_esp32.c" - "pm_trace.c" - "reset_reason.c" - "sleep_modes.c" - "spiram.c" - "spiram_psram.c" - "system_api.c" - "task_wdt.c") - set(COMPONENT_ADD_INCLUDEDIRS "include") - - set(COMPONENT_REQUIRES app_update driver esp_event efuse pthread soc) #unfortunately rom/uart uses SOC registers directly + set(requires driver esp_event efuse soc) #unfortunately rom/uart uses SOC registers directly # driver is a public requirement because esp_sleep.h uses gpio_num_t & touch_pad_t # app_update is added here because cpu_start.c uses esp_ota_get_app_description() function. - set(COMPONENT_PRIV_REQUIRES - app_trace app_update bootloader_support log mbedtls nvs_flash - smartconfig_ack spi_flash vfs wpa_supplicant espcoredump esp_common esp_wifi) + set(priv_requires app_trace app_update bootloader_support log mbedtls nvs_flash pthread + spi_flash vfs wpa_supplicant espcoredump esp_common esp_wifi) + set(fragments linker.lf ld/esp32_fragments.lf) - set(COMPONENT_ADD_LDFRAGMENTS linker.lf ld/esp32_fragments.lf) + idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS "${include_dirs}" + LDFRAGMENTS "${fragments}" + REQUIRES "${requires}" + PRIV_REQUIRES "${priv_requires}" + REQUIRED_IDF_TARGETS esp32) - register_component() - - target_linker_script(${COMPONENT_LIB} "${CMAKE_CURRENT_BINARY_DIR}/esp32_out.ld") + target_linker_script(${COMPONENT_LIB} INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/esp32_out.ld") # Rely on user code to define app_main - target_link_libraries(${COMPONENT_LIB} "-u app_main") + target_link_libraries(${COMPONENT_LIB} INTERFACE "-u app_main") if(CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY) # This has to be linked before esp32.project.ld - target_linker_script(${COMPONENT_LIB} "ld/esp32.extram.bss.ld") + target_linker_script(${COMPONENT_LIB} INTERFACE "ld/esp32.extram.bss.ld") endif() # Process the template file through the linker script generation mechanism, and use the output for linking the # final binary - target_linker_script(${COMPONENT_LIB} "${CMAKE_CURRENT_LIST_DIR}/ld/esp32.project.ld.in" PROCESS) + target_linker_script(${COMPONENT_LIB} INTERFACE "${CMAKE_CURRENT_LIST_DIR}/ld/esp32.project.ld.in" + PROCESS "${CMAKE_CURRENT_BINARY_DIR}/ld/esp32.project.ld") - target_linker_script(${COMPONENT_LIB} "ld/esp32.peripherals.ld") - target_link_libraries(${COMPONENT_LIB} gcc) - target_link_libraries(${COMPONENT_LIB} "-u call_user_start_cpu0") + target_linker_script(${COMPONENT_LIB} INTERFACE "ld/esp32.peripherals.ld") + target_link_libraries(${COMPONENT_LIB} PUBLIC gcc) + target_link_libraries(${COMPONENT_LIB} INTERFACE "-u call_user_start_cpu0") #ld_include_panic_highint_hdl is added as an undefined symbol because otherwise the #linker will ignore panic_highint_hdl.S as it has no other files depending on any #symbols in it. - target_link_libraries(${COMPONENT_LIB} "-u ld_include_panic_highint_hdl") + target_link_libraries(${COMPONENT_LIB} INTERFACE "-u ld_include_panic_highint_hdl") - idf_build_get_property(sdkconfig_header SDKCONFIG_HEADER) - get_filename_component(config_dir ${sdkconfig_header} DIRECTORY) + idf_build_get_property(config_dir CONFIG_DIR) # Preprocess esp32.ld linker script to include configuration, becomes esp32_out.ld set(LD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/ld) add_custom_command( @@ -94,6 +97,6 @@ elseif(CONFIG_IDF_TARGET_ESP32) # To handle some corner cases, the same flag is set in project_include.cmake target_compile_options(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-issue) # also, make sure we link with this option so correct toolchain libs are pulled in - target_link_libraries(${COMPONENT_LIB} -mfix-esp32-psram-cache-issue) + target_link_libraries(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-issue) endif() endif() diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index d8441d7738..f39d81fba7 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -656,6 +656,13 @@ menu "ESP32-specific" Please note that the actual length will be reduced by BT_RESERVE_DRAM if Bluetooth controller is enabled. + config ESP32_DPORT_DIS_INTERRUPT_LVL + int "Disable the interrupt level for the DPORT workarounds" + default 5 + help + To prevent interrupting DPORT workarounds, + need to disable interrupt with a maximum used level in the system. + endmenu # ESP32-Specific menu "Power Management" diff --git a/components/esp32/Makefile.projbuild b/components/esp32/Makefile.projbuild index 0ae77a69d2..cf8746f268 100644 --- a/components/esp32/Makefile.projbuild +++ b/components/esp32/Makefile.projbuild @@ -2,6 +2,7 @@ ifdef CONFIG_SPIRAM_CACHE_WORKAROUND CFLAGS+=-mfix-esp32-psram-cache-issue CXXFLAGS+=-mfix-esp32-psram-cache-issue +LDFLAGS+=-mfix-esp32-psram-cache-issue endif # Enable dynamic esp_timer overflow value if building unit tests diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index e8e1100993..f93e4cdf00 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -43,6 +43,7 @@ #include "sdkconfig.h" #include "esp_system.h" #include "esp_spi_flash.h" +#include "esp_flash.h" #include "nvs_flash.h" #include "esp_event.h" #include "esp_spi_flash.h" @@ -58,11 +59,10 @@ #include "esp_phy_init.h" #include "esp32/cache_err_int.h" #include "esp_coexist_internal.h" -#include "esp_debug_helpers.h" #include "esp_core_dump.h" #include "esp_app_trace.h" #include "esp_private/dbg_stubs.h" -#include "esp_efuse.h" +#include "esp_flash_encrypt.h" #include "esp32/spiram.h" #include "esp_clk_internal.h" #include "esp_timer.h" @@ -70,6 +70,8 @@ #include "esp_private/pm_impl.h" #include "trax.h" #include "esp_ota_ops.h" +#include "esp_efuse.h" +#include "bootloader_flash_config.h" #define STRINGIFY(s) STRINGIFY2(s) #define STRINGIFY2(s) #s @@ -202,6 +204,20 @@ void IRAM_ATTR call_start_cpu0() abort(); } ESP_EARLY_LOGI(TAG, "Starting app cpu, entry point is %p", call_start_cpu1); + + esp_flash_enc_mode_t mode; + mode = esp_get_flash_encryption_mode(); + if (mode == ESP_FLASH_ENC_MODE_DEVELOPMENT) { +#ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE + ESP_EARLY_LOGE(TAG, "Flash encryption settings error: mode should be RELEASE but is actually DEVELOPMENT"); + ESP_EARLY_LOGE(TAG, "Mismatch found in security options in menuconfig and efuse settings"); +#else + ESP_EARLY_LOGW(TAG, "Flash encryption mode is DEVELOPMENT"); +#endif + } else if (mode == ESP_FLASH_ENC_MODE_RELEASE) { + ESP_EARLY_LOGI(TAG, "Flash encryption mode is RELEASE"); + } + //Flush and enable icache for APP CPU Cache_Flush(1); Cache_Read_Enable(1); @@ -388,6 +404,10 @@ void start_cpu0_default(void) spi_flash_init(); /* init default OS-aware flash access critical section */ spi_flash_guard_set(&g_flash_guard_default_ops); + + esp_flash_app_init(); + esp_err_t flash_ret = esp_flash_init_default_chip(); + assert(flash_ret == ESP_OK); #ifdef CONFIG_PM_ENABLE esp_pm_impl_init(); #ifdef CONFIG_PM_DFS_INIT_AUTO @@ -413,6 +433,17 @@ void start_cpu0_default(void) esp_coex_adapter_register(&g_coex_adapter_funcs); #endif + bootloader_flash_update_id(); +#if !CONFIG_SPIRAM_BOOT_INIT // If psram is uninitialized, we need to improve some flash configuration. + esp_image_header_t fhdr; + const esp_partition_t *partition = esp_ota_get_running_partition(); + spi_flash_read(partition->address, &fhdr, sizeof(esp_image_header_t)); + bootloader_flash_clock_config(&fhdr); + bootloader_flash_gpio_config(&fhdr); + bootloader_flash_dummy_config(&fhdr); + bootloader_flash_cs_timing_config(); +#endif + portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main", ESP_TASK_MAIN_STACK, NULL, ESP_TASK_MAIN_PRIO, NULL, 0); diff --git a/components/esp32/dport_access.c b/components/esp32/dport_access.c index de828eb061..2c83583350 100644 --- a/components/esp32/dport_access.c +++ b/components/esp32/dport_access.c @@ -256,7 +256,7 @@ uint32_t IRAM_ATTR esp_dport_access_reg_read(uint32_t reg) unsigned int intLvl; __asm__ __volatile__ (\ "movi %[APB], "XTSTR(0x3ff40078)"\n"\ - "rsil %[LVL], "XTSTR(3)"\n"\ + "rsil %[LVL], "XTSTR(CONFIG_ESP32_DPORT_DIS_INTERRUPT_LVL)"\n"\ "l32i %[APB], %[APB], 0\n"\ "l32i %[REG], %[REG], 0\n"\ "wsr %[LVL], "XTSTR(PS)"\n"\ diff --git a/components/esp32/dport_panic_highint_hdl.S b/components/esp32/dport_panic_highint_hdl.S index 924d77b2f0..7291628635 100644 --- a/components/esp32/dport_panic_highint_hdl.S +++ b/components/esp32/dport_panic_highint_hdl.S @@ -31,9 +31,10 @@ Interrupt , a high-priority interrupt, is used for several things: */ -#define L4_INTR_STACK_SIZE 8 +#define L4_INTR_STACK_SIZE 12 #define L4_INTR_A2_OFFSET 0 #define L4_INTR_A3_OFFSET 4 +#define L4_INTR_A4_OFFSET 8 .data _l4_intr_stack: .space L4_INTR_STACK_SIZE @@ -145,10 +146,11 @@ xt_highint4: movi a0, (1< rtc_iram_seg - + /* - This section is required to skip rtc.text area because rtc_iram_seg and + This section is required to skip rtc.text area because rtc_iram_seg and rtc_data_seg are reflect the same address space on different buses. */ .rtc.dummy : @@ -28,8 +28,8 @@ SECTIONS _rtc_dummy_end = ABSOLUTE(.); } > rtc_data_seg - /* This section located in RTC FAST Memory area. - It holds data marked with RTC_FAST_ATTR attribute. + /* This section located in RTC FAST Memory area. + It holds data marked with RTC_FAST_ATTR attribute. See the file "esp_attr.h" for more information. */ .rtc.force_fast : @@ -45,7 +45,7 @@ SECTIONS data/rodata, including from any source file named rtc_wake_stub*.c and the data marked with RTC_DATA_ATTR, RTC_RODATA_ATTR attributes. - The memory location of the data is dependent on + The memory location of the data is dependent on CONFIG_ESP32_RTCDATA_IN_FAST_MEM option. */ .rtc.data : @@ -70,11 +70,11 @@ SECTIONS _rtc_bss_end = ABSOLUTE(.); } > rtc_data_location - /* This section holds data that should not be initialized at power up + /* This section holds data that should not be initialized at power up and will be retained during deep sleep. User data marked with RTC_NOINIT_ATTR will be placed - into this section. See the file "esp_attr.h" for more information. - The memory location of the data is dependent on + into this section. See the file "esp_attr.h" for more information. + The memory location of the data is dependent on CONFIG_ESP32_RTCDATA_IN_FAST_MEM option. */ .rtc_noinit (NOLOAD): @@ -86,8 +86,8 @@ SECTIONS _rtc_noinit_end = ABSOLUTE(.); } > rtc_data_location - /* This section located in RTC SLOW Memory area. - It holds data marked with RTC_SLOW_ATTR attribute. + /* This section located in RTC SLOW Memory area. + It holds data marked with RTC_SLOW_ATTR attribute. See the file "esp_attr.h" for more information. */ .rtc.force_slow : @@ -100,17 +100,17 @@ SECTIONS } > rtc_slow_seg /* Get size of rtc slow data based on rtc_data_location alias */ - _rtc_slow_length = (ORIGIN(rtc_slow_seg) == ORIGIN(rtc_data_location)) - ? (_rtc_force_slow_end - _rtc_data_start) + _rtc_slow_length = (ORIGIN(rtc_slow_seg) == ORIGIN(rtc_data_location)) + ? (_rtc_force_slow_end - _rtc_data_start) : (_rtc_force_slow_end - _rtc_force_slow_start); - _rtc_fast_length = (ORIGIN(rtc_slow_seg) == ORIGIN(rtc_data_location)) - ? (_rtc_force_fast_end - _rtc_fast_start) + _rtc_fast_length = (ORIGIN(rtc_slow_seg) == ORIGIN(rtc_data_location)) + ? (_rtc_force_fast_end - _rtc_fast_start) : (_rtc_noinit_end - _rtc_fast_start); - + ASSERT((_rtc_slow_length <= LENGTH(rtc_slow_seg)), "RTC_SLOW segment data does not fit.") - + ASSERT((_rtc_fast_length <= LENGTH(rtc_data_seg)), "RTC_FAST segment data does not fit.") @@ -178,6 +178,10 @@ SECTIONS *libbtdm_app.a:(.data .data.*) . = ALIGN (4); _btdm_data_end = ABSOLUTE(.); + _nimble_data_start = ABSOLUTE(.); + *libnimble.a:(.data .data.*) + . = ALIGN (4); + _nimble_data_end = ABSOLUTE(.); *(.gnu.linkonce.d.*) *(.data1) *(.sdata) @@ -203,7 +207,7 @@ SECTIONS { . = ALIGN(4); _noinit_start = ABSOLUTE(.); - *(.noinit .noinit.*) + *(.noinit .noinit.*) . = ALIGN(4) ; _noinit_end = ABSOLUTE(.); } > dram0_0_seg @@ -222,6 +226,10 @@ SECTIONS *libbtdm_app.a:(.bss .bss.* COMMON) . = ALIGN (4); _btdm_bss_end = ABSOLUTE(.); + _nimble_bss_start = ABSOLUTE(.); + *libnimble.a:(.bss .bss.* COMMON) + . = ALIGN (4); + _nimble_bss_end = ABSOLUTE(.); mapping[dram0_bss] @@ -243,7 +251,7 @@ SECTIONS ASSERT(((_bss_end - ORIGIN(dram0_0_seg)) <= LENGTH(dram0_0_seg)), "DRAM segment data does not fit.") - + .flash.rodata : { _rodata_start = ABSOLUTE(.); diff --git a/components/esp32/panic.c b/components/esp32/panic.c index b66ba9437a..e7ed6540e2 100644 --- a/components/esp32/panic.c +++ b/components/esp32/panic.c @@ -30,6 +30,7 @@ #include "soc/cpu.h" #include "soc/rtc.h" #include "soc/rtc_wdt.h" +#include "soc/soc_memory_layout.h" #include "esp_private/gdbstub.h" #include "esp_debug_helpers.h" @@ -446,33 +447,36 @@ static void esp_panic_dig_reset() static void putEntry(uint32_t pc, uint32_t sp) { - if (pc & 0x80000000) { - pc = (pc & 0x3fffffff) | 0x40000000; - } panicPutStr(" 0x"); panicPutHex(pc); panicPutStr(":0x"); panicPutHex(sp); } -static void doBacktrace(XtExcFrame *frame) +static void doBacktrace(XtExcFrame *exc_frame, int depth) { - uint32_t i = 0, pc = frame->pc, sp = frame->a1; + //Initialize stk_frame with first frame of stack + esp_backtrace_frame_t stk_frame = {.pc = exc_frame->pc, .sp = exc_frame->a1, .next_pc = exc_frame->a0}; panicPutStr("\r\nBacktrace:"); - /* Do not check sanity on first entry, PC could be smashed. */ - putEntry(pc, sp); - pc = frame->a0; - while (i++ < 100) { - uint32_t psp = sp; - if (!esp_stack_ptr_is_sane(sp) || i++ > 100) { - break; - } - sp = *((uint32_t *) (sp - 0x10 + 4)); - putEntry(pc - 3, sp); // stack frame addresses are return addresses, so subtract 3 to get the CALL address - pc = *((uint32_t *) (psp - 0x10)); - if (pc < 0x40000000) { - break; + putEntry(esp_cpu_process_stack_pc(stk_frame.pc), stk_frame.sp); + + //Check if first frame is valid + bool corrupted = (esp_stack_ptr_is_sane(stk_frame.sp) && + esp_ptr_executable((void*)esp_cpu_process_stack_pc(stk_frame.pc))) ? + false : true; + uint32_t i = ((depth <= 0) ? INT32_MAX : depth) - 1; //Account for stack frame that's already printed + while (i-- > 0 && stk_frame.next_pc != 0 && !corrupted) { + if (!esp_backtrace_get_next_frame(&stk_frame)) { //Get next stack frame + corrupted = true; } + putEntry(esp_cpu_process_stack_pc(stk_frame.pc), stk_frame.sp); + } + + //Print backtrace termination marker + if (corrupted) { + panicPutStr(" |<-CORRUPTED"); + } else if (stk_frame.next_pc != 0) { //Backtrace continues + panicPutStr(" |<-CONTINUES"); } panicPutStr("\r\n"); } @@ -549,7 +553,7 @@ static void commonErrorHandler_dump(XtExcFrame *frame, int core_id) panicPutStr("\r\n"); /* With windowed ABI backtracing is easy, let's do it. */ - doBacktrace(frame); + doBacktrace(frame, 100); panicPutStr("\r\n"); } diff --git a/components/esp32/spiram_psram.c b/components/esp32/spiram_psram.c index 873c8ce439..ab5d00698a 100644 --- a/components/esp32/spiram_psram.c +++ b/components/esp32/spiram_psram.c @@ -31,6 +31,7 @@ #include "esp32/rom/efuse.h" #include "soc/dport_reg.h" #include "soc/efuse_periph.h" +#include "soc/spi_caps.h" #include "driver/gpio.h" #include "driver/spi_common.h" #include "driver/periph_ctrl.h" @@ -94,8 +95,6 @@ typedef enum { // WARNING: PSRAM shares all but the CS and CLK pins with the flash, so these defines // hardcode the flash pins as well, making this code incompatible with either a setup // that has the flash on non-standard pins or ESP32s with built-in flash. -#define FLASH_CLK_IO 6 -#define FLASH_CS_IO 11 #define PSRAM_SPIQ_SD0_IO 7 #define PSRAM_SPID_SD1_IO 8 #define PSRAM_SPIWP_SD3_IO 10 @@ -134,8 +133,8 @@ typedef struct { #define PSRAM_INTERNAL_IO_28 28 #define PSRAM_INTERNAL_IO_29 29 -#define PSRAM_IO_MATRIX_DUMMY_40M 1 -#define PSRAM_IO_MATRIX_DUMMY_80M 2 +#define PSRAM_IO_MATRIX_DUMMY_40M ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_40M +#define PSRAM_IO_MATRIX_DUMMY_80M ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_80M #define _SPI_CACHE_PORT 0 #define _SPI_FLASH_PORT 1 @@ -505,9 +504,11 @@ static void IRAM_ATTR psram_gpio_config(psram_io_t *psram_io, psram_cache_mode_t { int spi_cache_dummy = 0; uint32_t rd_mode_reg = READ_PERI_REG(SPI_CTRL_REG(0)); - if (rd_mode_reg & (SPI_FREAD_QIO_M | SPI_FREAD_DIO_M)) { + if (rd_mode_reg & SPI_FREAD_QIO_M) { spi_cache_dummy = SPI0_R_QIO_DUMMY_CYCLELEN; - } else if (rd_mode_reg & (SPI_FREAD_QUAD_M | SPI_FREAD_DUAL_M)) { + } else if (rd_mode_reg & SPI_FREAD_DIO_M) { + spi_cache_dummy = SPI0_R_DIO_DUMMY_CYCLELEN; + } else if (rd_mode_reg & (SPI_FREAD_QUAD_M | SPI_FREAD_DUAL_M)) { spi_cache_dummy = SPI0_R_FAST_DUMMY_CYCLELEN; } else { spi_cache_dummy = SPI0_R_FAST_DUMMY_CYCLELEN; @@ -566,7 +567,7 @@ static void IRAM_ATTR psram_gpio_config(psram_io_t *psram_io, psram_cache_mode_t gpio_matrix_in(psram_io->psram_spihd_sd2_io, SPIHD_IN_IDX, 0); //select pin function gpio - if ((psram_io->flash_clk_io == FLASH_CLK_IO) && (psram_io->flash_clk_io != psram_io->psram_clk_io)) { + if ((psram_io->flash_clk_io == SPI_IOMUX_PIN_NUM_CLK) && (psram_io->flash_clk_io != psram_io->psram_clk_io)) { //flash clock signal should come from IO MUX. PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[psram_io->flash_clk_io], FUNC_SD_CLK_SPICLK); } else { @@ -647,8 +648,8 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad const uint32_t spiconfig = ets_efuse_get_spiconfig(); if (spiconfig == EFUSE_SPICONFIG_SPI_DEFAULTS) { - psram_io.flash_clk_io = FLASH_CLK_IO; - psram_io.flash_cs_io = FLASH_CS_IO; + psram_io.flash_clk_io = SPI_IOMUX_PIN_NUM_CLK; + psram_io.flash_cs_io = SPI_IOMUX_PIN_NUM_CS; psram_io.psram_spiq_sd0_io = PSRAM_SPIQ_SD0_IO; psram_io.psram_spid_sd1_io = PSRAM_SPID_SD1_IO; psram_io.psram_spiwp_sd3_io = PSRAM_SPIWP_SD3_IO; diff --git a/components/esp32/test/CMakeLists.txt b/components/esp32/test/CMakeLists.txt index 1ced21ed8a..624f11d598 100644 --- a/components/esp32/test/CMakeLists.txt +++ b/components/esp32/test/CMakeLists.txt @@ -1,9 +1,6 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ". ${CMAKE_CURRENT_BINARY_DIR}") - -set(COMPONENT_REQUIRES unity test_utils nvs_flash ulp esp_common) - -register_component() +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." "${CMAKE_CURRENT_BINARY_DIR}" + REQUIRES unity test_utils nvs_flash ulp esp_common) add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test_tjpgd_logo.h" COMMAND xxd -i "logo.jpg" "${CMAKE_CURRENT_BINARY_DIR}/test_tjpgd_logo.h" @@ -15,3 +12,5 @@ add_custom_target(esp32_test_logo DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/test_tjpg add_dependencies(${COMPONENT_LIB} esp32_test_logo) idf_build_set_property(COMPILE_DEFINITIONS "-DESP_TIMER_DYNAMIC_OVERFLOW_VAL" APPEND) + +target_link_libraries(${COMPONENT_LIB} INTERFACE "-u ld_include_test_dport_xt_highint5") diff --git a/components/esp32/test/component.mk b/components/esp32/test/component.mk index eefb592ac2..d4b5a9012f 100644 --- a/components/esp32/test/component.mk +++ b/components/esp32/test/component.mk @@ -4,7 +4,8 @@ COMPONENT_EXTRA_CLEAN := test_tjpgd_logo.h -COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive +COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive \ + -u ld_include_test_dport_xt_highint5 \ COMPONENT_SRCDIRS := . diff --git a/components/esp32/test/test_dport.c b/components/esp32/test/test_dport.c index ac8498631a..fc485436d5 100644 --- a/components/esp32/test/test_dport.c +++ b/components/esp32/test/test_dport.c @@ -1,5 +1,7 @@ #include #include +#include "xtensa/core-macros.h" +#include "xtensa/hal.h" #include "esp_types.h" #include "esp32/clk.h" @@ -14,11 +16,14 @@ #include "soc/uart_periph.h" #include "soc/dport_reg.h" #include "soc/rtc.h" +#include "esp_intr_alloc.h" +#include "driver/timer.h" #define MHZ (1000000) static volatile bool exit_flag; static bool dport_test_result; static bool apb_test_result; +uint32_t volatile apb_intr_test_result; static void accessDPORT(void *pvParameters) { @@ -60,6 +65,7 @@ static void accessAPB(void *pvParameters) void run_tasks(const char *task1_description, void (* task1_func)(void *), const char *task2_description, void (* task2_func)(void *), uint32_t delay_ms) { + apb_intr_test_result = 1; int i; TaskHandle_t th[2]; xSemaphoreHandle exit_sema[2]; @@ -94,7 +100,7 @@ void run_tasks(const char *task1_description, void (* task1_func)(void *), const vSemaphoreDelete(exit_sema[i]); } } - TEST_ASSERT(dport_test_result == true && apb_test_result == true); + TEST_ASSERT(dport_test_result == true && apb_test_result == true && apb_intr_test_result == 1); } TEST_CASE("access DPORT and APB at same time", "[esp32]") @@ -324,3 +330,88 @@ TEST_CASE("BENCHMARK for DPORT access performance", "[freertos]") } BENCHMARK_END("_DPORT_REG_READ"); } + +uint32_t xt_highint5_read_apb; + +#ifndef CONFIG_FREERTOS_UNICORE +timer_isr_handle_t inth; +xSemaphoreHandle sync_sema; + +static void init_hi_interrupt(void *arg) +{ + printf("init hi_interrupt on CPU%d \n", xPortGetCoreID()); + TEST_ESP_OK(esp_intr_alloc(ETS_INTERNAL_TIMER2_INTR_SOURCE, ESP_INTR_FLAG_LEVEL5 | ESP_INTR_FLAG_IRAM, NULL, NULL, &inth)); + while (exit_flag == false); + esp_intr_free(inth); + printf("disable hi_interrupt on CPU%d \n", xPortGetCoreID()); + vTaskDelete(NULL); +} + +static void accessDPORT2_stall_other_cpu(void *pvParameters) +{ + xSemaphoreHandle *sema = (xSemaphoreHandle *) pvParameters; + dport_test_result = true; + while (exit_flag == false) { + DPORT_STALL_OTHER_CPU_START(); + XTHAL_SET_CCOMPARE(2, XTHAL_GET_CCOUNT()); + xt_highint5_read_apb = 1; + for (int i = 0; i < 200; ++i) { + if (_DPORT_REG_READ(DPORT_DATE_REG) != _DPORT_REG_READ(DPORT_DATE_REG)) { + apb_test_result = false; + break; + } + } + xt_highint5_read_apb = 0; + DPORT_STALL_OTHER_CPU_END(); + } + printf("accessDPORT2_stall_other_cpu finish\n"); + + xSemaphoreGive(*sema); + vTaskDelete(NULL); +} + +TEST_CASE("Check stall workaround DPORT and Hi-interrupt", "[esp32]") +{ + xt_highint5_read_apb = 0; + dport_test_result = false; + apb_test_result = true; + TEST_ASSERT(xTaskCreatePinnedToCore(&init_hi_interrupt, "init_hi_intr", 2048, NULL, 6, NULL, 1) == pdTRUE); + // Access DPORT(stall other cpu method) - CPU0 + // STALL - CPU1 + // Hi-interrupt - CPU1 + run_tasks("accessDPORT2_stall_other_cpu", accessDPORT2_stall_other_cpu, " - ", NULL, 10000); +} + +static void accessDPORT2(void *pvParameters) +{ + xSemaphoreHandle *sema = (xSemaphoreHandle *) pvParameters; + dport_test_result = true; + + TEST_ESP_OK(esp_intr_alloc(ETS_INTERNAL_TIMER2_INTR_SOURCE, ESP_INTR_FLAG_LEVEL5 | ESP_INTR_FLAG_IRAM, NULL, NULL, &inth)); + + while (exit_flag == false) { + XTHAL_SET_CCOMPARE(2, XTHAL_GET_CCOUNT() + 21); + for (int i = 0; i < 200; ++i) { + if (DPORT_REG_READ(DPORT_DATE_REG) != DPORT_REG_READ(DPORT_DATE_REG)) { + dport_test_result = false; + break; + } + } + } + esp_intr_free(inth); + printf("accessDPORT2 finish\n"); + + xSemaphoreGive(*sema); + vTaskDelete(NULL); +} + +TEST_CASE("Check pre-read workaround DPORT and Hi-interrupt", "[esp32]") +{ + xt_highint5_read_apb = 0; + dport_test_result = false; + apb_test_result = true; + // Access DPORT(pre-read method) - CPU1 + // Hi-interrupt - CPU1 + run_tasks("accessAPB", accessAPB, "accessDPORT2", accessDPORT2, 10000); +} +#endif // CONFIG_FREERTOS_UNICORE diff --git a/components/esp32/test/test_dport_xt_highint5.S b/components/esp32/test/test_dport_xt_highint5.S new file mode 100644 index 0000000000..d2d1acabed --- /dev/null +++ b/components/esp32/test/test_dport_xt_highint5.S @@ -0,0 +1,80 @@ +#include +#include +#include +#include "freertos/xtensa_context.h" +#include "esp_private/panic_reason.h" +#include "sdkconfig.h" +#include "soc/soc.h" +#include "soc/dport_reg.h" + +#ifndef CONFIG_FREERTOS_UNICORE + +#define L5_INTR_STACK_SIZE 12 +#define L5_INTR_A2_OFFSET 0 +#define L5_INTR_A3_OFFSET 4 +#define L5_INTR_A4_OFFSET 8 + .data +_l5_intr_stack: + .space L5_INTR_STACK_SIZE + + .section .iram1,"ax" + .global xt_highint5 + .type xt_highint5,@function + .align 4 +xt_highint5: + + movi a0, xt_highint5_read_apb + l32i a0, a0, 0 + bnez a0, .read_apb_reg + +// Short interrupt + esync + rsr a0, CCOUNT + addi a0, a0, 27 + wsr a0, CCOMPARE2 + esync + + rsr a0, EXCSAVE_5 // restore a0 + rfi 5 + + + +// read APB reg 10 time. +.read_apb_reg: + movi a0, _l5_intr_stack + s32i a2, a0, L5_INTR_A2_OFFSET + s32i a3, a0, L5_INTR_A3_OFFSET + s32i a4, a0, L5_INTR_A4_OFFSET + + movi a4, 10 // count of reading + movi a0, 0x3ff40078 // read APB reg + l32i a2, a0, 0 +.loop_read_apb_reg: + l32i a3, a0, 0 + bne a3, a2, .need_set_apb_test_result + addi a4, a4, -1 + l32i a2, a0, 0 + bnez a4, .loop_read_apb_reg + j 1f +.need_set_apb_test_result: + movi a0, apb_intr_test_result // set fail + movi a2, 0 + s32i a2, a0, 0 + memw +1: + movi a0, _l5_intr_stack + l32i a2, a0, L5_INTR_A2_OFFSET + l32i a3, a0, L5_INTR_A3_OFFSET + l32i a4, a0, L5_INTR_A4_OFFSET + rsync +.L_xt_highint5_exit: + rsr a0, EXCSAVE_5 // restore a0 + rfi 5 + +/* The linker has no reason to link in this file; all symbols it exports are already defined + (weakly!) in the default int handler. Define a symbol here so we can use it to have the + linker inspect this anyway. */ + + .global ld_include_test_dport_xt_highint5 +ld_include_test_dport_xt_highint5: +#endif // CONFIG_FREERTOS_UNICORE diff --git a/components/esp32/test/test_esp_timer.c b/components/esp32/test/test_esp_timer.c index b46cca5608..e3444503a1 100644 --- a/components/esp32/test/test_esp_timer.c +++ b/components/esp32/test/test_esp_timer.c @@ -536,6 +536,61 @@ TEST_CASE("Can delete timer from callback", "[esp_timer]") vSemaphoreDelete(args.notify_from_timer_cb); } + +typedef struct { + SemaphoreHandle_t delete_start; + SemaphoreHandle_t delete_done; + SemaphoreHandle_t test_done; + esp_timer_handle_t timer; +} timer_delete_test_args_t; + +static void timer_delete_task(void* arg) +{ + timer_delete_test_args_t* args = (timer_delete_test_args_t*) arg; + xSemaphoreTake(args->delete_start, portMAX_DELAY); + printf("Deleting the timer\n"); + esp_timer_delete(args->timer); + printf("Timer deleted\n"); + xSemaphoreGive(args->delete_done); + vTaskDelete(NULL); +} + +static void timer_delete_test_callback(void* arg) +{ + timer_delete_test_args_t* args = (timer_delete_test_args_t*) arg; + printf("Timer callback called\n"); + xSemaphoreGive(args->delete_start); + xSemaphoreTake(args->delete_done, portMAX_DELAY); + printf("Callback complete\n"); + xSemaphoreGive(args->test_done); +} + +TEST_CASE("Can delete timer from a separate task, triggered from callback", "[esp_timer]") +{ + timer_delete_test_args_t args = { + .delete_start = xSemaphoreCreateBinary(), + .delete_done = xSemaphoreCreateBinary(), + .test_done = xSemaphoreCreateBinary(), + }; + + esp_timer_create_args_t timer_args = { + .callback = &timer_delete_test_callback, + .arg = &args + }; + esp_timer_handle_t timer; + TEST_ESP_OK(esp_timer_create(&timer_args, &timer)); + args.timer = timer; + + xTaskCreate(timer_delete_task, "deleter", 4096, &args, 5, NULL); + + esp_timer_start_once(timer, 100); + TEST_ASSERT(xSemaphoreTake(args.test_done, pdMS_TO_TICKS(1000))); + + vSemaphoreDelete(args.delete_done); + vSemaphoreDelete(args.delete_start); + vSemaphoreDelete(args.test_done); +} + TEST_CASE("esp_timer_impl_advance moves time base correctly", "[esp_timer]") { ref_clock_init(); diff --git a/components/esp32/test/test_reset_reason.c b/components/esp32/test/test_reset_reason.c index 9d57a7f4c0..78d051358e 100644 --- a/components/esp32/test/test_reset_reason.c +++ b/components/esp32/test/test_reset_reason.c @@ -141,12 +141,14 @@ TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_SW after restart from APP CPU", static void do_int_wdt() { + setup_values(); portENTER_CRITICAL_NESTED(); while(1); } static void do_int_wdt_hw() { + setup_values(); XTOS_SET_INTLEVEL(XCHAL_NMILEVEL); while(1); } @@ -154,6 +156,7 @@ static void do_int_wdt_hw() static void check_reset_reason_int_wdt() { TEST_ASSERT_EQUAL(ESP_RST_INT_WDT, esp_reset_reason()); + TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_noinit_val); } TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_INT_WDT after interrupt watchdog (panic)", @@ -194,6 +197,7 @@ TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_TASK_WDT after task watchdog", static void do_rtc_wdt() { + setup_values(); WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE); REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_SYS_RESET_LENGTH, 7); REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG0, RTC_WDT_STG_SEL_RESET_SYSTEM); @@ -205,6 +209,7 @@ static void do_rtc_wdt() static void check_reset_reason_any_wdt() { TEST_ASSERT_EQUAL(ESP_RST_WDT, esp_reset_reason()); + TEST_ASSERT_EQUAL_HEX32(CHECK_VALUE, s_rtc_noinit_val); } TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_WDT after RTC watchdog", diff --git a/components/esp_adc_cal/CMakeLists.txt b/components/esp_adc_cal/CMakeLists.txt index 1cfe856a1a..9a925bcd41 100644 --- a/components/esp_adc_cal/CMakeLists.txt +++ b/components/esp_adc_cal/CMakeLists.txt @@ -1,9 +1,8 @@ +# TODO esp32s2beta: Use require_idf_targets here if(IDF_TARGET STREQUAL "esp32s2beta") return() endif() -set(COMPONENT_SRCS "esp_adc_cal.c") -set(COMPONENT_ADD_INCLUDEDIRS "include") -set(COMPONENT_REQUIRES) - -register_component() +idf_component_register(SRCS "esp_adc_cal.c" + INCLUDE_DIRS "include" + REQUIRES driver) diff --git a/components/esp_common/CMakeLists.txt b/components/esp_common/CMakeLists.txt index 18ffe93678..bb9bd8a7a4 100644 --- a/components/esp_common/CMakeLists.txt +++ b/components/esp_common/CMakeLists.txt @@ -1,27 +1,19 @@ if(BOOTLOADER_BUILD) # For bootloader, all we need from esp_common is headers - set(COMPONENT_ADD_INCLUDEDIRS include) - set(COMPONENT_REQUIRES ${IDF_COMPONENTS}) - set(COMPONENT_SRCS ) - register_component() + idf_component_register(INCLUDE_DIRS include) set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-Wl,--gc-sections") else() # Regular app build - set(COMPONENT_SRCS - "src/dbg_stubs.c" - "src/esp_err_to_name.c" - "src/esp_timer.c" - "src/ets_timer_legacy.c" - "src/freertos_hooks.c" - "src/ipc.c" - "src/pm_locks.c" - "src/stack_check.c") - set(COMPONENT_ADD_INCLUDEDIRS "include") - set(COMPONENT_PRIV_INCLUDEDIRS) - set(COMPONENT_REQUIRES) - set(COMPONENT_PRIV_REQUIRES soc) - - register_component() + idf_component_register(SRCS "src/dbg_stubs.c" + "src/esp_err_to_name.c" + "src/esp_timer.c" + "src/ets_timer_legacy.c" + "src/freertos_hooks.c" + "src/ipc.c" + "src/pm_locks.c" + "src/stack_check.c" + INCLUDE_DIRS include + PRIV_REQUIRES soc) set_source_files_properties( "src/stack_check.c" diff --git a/components/esp_common/include/esp_err.h b/components/esp_common/include/esp_err.h index c46ae38372..105723976d 100644 --- a/components/esp_common/include/esp_err.h +++ b/components/esp_common/include/esp_err.h @@ -41,6 +41,7 @@ typedef int32_t esp_err_t; #define ESP_ERR_WIFI_BASE 0x3000 /*!< Starting number of WiFi error codes */ #define ESP_ERR_MESH_BASE 0x4000 /*!< Starting number of MESH error codes */ +#define ESP_ERR_FLASH_BASE 0x6000 /*!< Starting number of flash error codes */ /** * @brief Returns string for esp_err_t error codes diff --git a/components/esp_common/include/esp_idf_version.h b/components/esp_common/include/esp_idf_version.h new file mode 100644 index 0000000000..52601ca8f6 --- /dev/null +++ b/components/esp_common/include/esp_idf_version.h @@ -0,0 +1,58 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/** Major version number (X.x.x) */ +#define ESP_IDF_VERSION_MAJOR 4 +/** Minor version number (x.X.x) */ +#define ESP_IDF_VERSION_MINOR 0 +/** Patch version number (x.x.X) */ +#define ESP_IDF_VERSION_PATCH 0 + +/** + * Macro to convert IDF version number into an integer + * + * To be used in comparisons, such as ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) + */ +#define ESP_IDF_VERSION_VAL(major, minor, patch) ((major << 16) | (minor << 8) | (patch)) + +/** + * Current IDF version, as an integer + * + * To be used in comparisons, such as ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) + */ +#define ESP_IDF_VERSION ESP_IDF_VERSION_VAL(ESP_IDF_VERSION_MAJOR, \ + ESP_IDF_VERSION_MINOR, \ + ESP_IDF_VERSION_PATCH) + +/** + * Return full IDF version string, same as 'git describe' output. + * + * @note If you are printing the ESP-IDF version in a log file or other information, + * this function provides more information than using the numerical version macros. + * For example, numerical version macros don't differentiate between development, + * pre-release and release versions, but the output of this function does. + * + * @return constant string from IDF_VER + */ +const char* esp_get_idf_version(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_common/include/esp_system.h b/components/esp_common/include/esp_system.h index 47bba2fd44..9aca3b83f3 100644 --- a/components/esp_common/include/esp_system.h +++ b/components/esp_common/include/esp_system.h @@ -20,6 +20,7 @@ #include "esp_err.h" #include "esp_attr.h" #include "esp_bit_defs.h" +#include "esp_idf_version.h" #include "sdkconfig.h" @@ -315,14 +316,6 @@ esp_err_t esp_derive_local_mac(uint8_t* local_mac, const uint8_t* universal_mac) const char* system_get_sdk_version(void) __attribute__ ((deprecated)); /** @endcond */ -/** - * Get IDF version - * - * @return constant string from IDF_VER - */ -const char* esp_get_idf_version(void); - - /** * @brief Chip models */ diff --git a/components/esp_common/src/esp_timer.c b/components/esp_common/src/esp_timer.c index 616cc25458..82a2d0b85b 100644 --- a/components/esp_common/src/esp_timer.c +++ b/components/esp_common/src/esp_timer.c @@ -39,12 +39,17 @@ #endif #include "sys/queue.h" +#define EVENT_ID_DELETE_TIMER 0xF0DE1E1E + #define TIMER_EVENT_QUEUE_SIZE 16 struct esp_timer { uint64_t alarm; uint64_t period; - esp_timer_cb_t callback; + union { + esp_timer_cb_t callback; + uint32_t event_id; + }; void* arg; #if WITH_PROFILING const char* name; @@ -77,23 +82,18 @@ static LIST_HEAD(esp_timer_list, esp_timer) s_timers = // all the timers static LIST_HEAD(esp_inactive_timer_list, esp_timer) s_inactive_timers = LIST_HEAD_INITIALIZER(s_timers); -// used to keep track of the timer when executing the callback -static esp_timer_handle_t s_timer_in_callback; #endif // task used to dispatch timer callbacks static TaskHandle_t s_timer_task; // counting semaphore used to notify the timer task from ISR static SemaphoreHandle_t s_timer_semaphore; -// mutex which protects timers from deletion during callback execution -static SemaphoreHandle_t s_timer_delete_mutex; #if CONFIG_SPIRAM_USE_MALLOC -// memory for s_timer_semaphore and s_timer_delete_mutex +// memory for s_timer_semaphore static StaticQueue_t s_timer_semaphore_memory; -static StaticQueue_t s_timer_delete_mutex_memory; #endif -// lock protecting s_timers, s_inactive_timers, s_timer_in_callback +// lock protecting s_timers, s_inactive_timers static portMUX_TYPE s_timer_lock = portMUX_INITIALIZER_UNLOCKED; @@ -164,15 +164,10 @@ esp_err_t esp_timer_delete(esp_timer_handle_t timer) if (timer_armed(timer)) { return ESP_ERR_INVALID_STATE; } - xSemaphoreTakeRecursive(s_timer_delete_mutex, portMAX_DELAY); -#if WITH_PROFILING - if (timer == s_timer_in_callback) { - s_timer_in_callback = NULL; - } - timer_remove_inactive(timer); -#endif - free(timer); - xSemaphoreGiveRecursive(s_timer_delete_mutex); + timer->event_id = EVENT_ID_DELETE_TIMER; + timer->alarm = esp_timer_get_time() + 50; + timer->period = 0; + timer_insert(timer); return ESP_OK; } @@ -267,13 +262,17 @@ static void timer_process_alarm(esp_timer_dispatch_t dispatch_method) /* unused, provision to allow running callbacks from ISR */ (void) dispatch_method; - xSemaphoreTakeRecursive(s_timer_delete_mutex, portMAX_DELAY); timer_list_lock(); uint64_t now = esp_timer_impl_get_time(); esp_timer_handle_t it = LIST_FIRST(&s_timers); while (it != NULL && it->alarm < now) { LIST_REMOVE(it, list_entry); + if (it->event_id == EVENT_ID_DELETE_TIMER) { + free(it); + it = LIST_FIRST(&s_timers); + continue; + } if (it->period > 0) { it->alarm += it->period; timer_insert(it); @@ -285,21 +284,14 @@ static void timer_process_alarm(esp_timer_dispatch_t dispatch_method) } #if WITH_PROFILING uint64_t callback_start = now; - s_timer_in_callback = it; #endif timer_list_unlock(); (*it->callback)(it->arg); timer_list_lock(); now = esp_timer_impl_get_time(); #if WITH_PROFILING - /* The callback might have deleted the timer. - * If this happens, esp_timer_delete will set s_timer_in_callback - * to NULL. - */ - if (s_timer_in_callback) { - s_timer_in_callback->times_triggered++; - s_timer_in_callback->total_callback_run_time += now - callback_start; - } + it->times_triggered++; + it->total_callback_run_time += now - callback_start; #endif it = LIST_FIRST(&s_timers); } @@ -308,7 +300,6 @@ static void timer_process_alarm(esp_timer_dispatch_t dispatch_method) esp_timer_impl_set_alarm(first->alarm); } timer_list_unlock(); - xSemaphoreGiveRecursive(s_timer_delete_mutex); } static void timer_task(void* arg) @@ -356,18 +347,6 @@ esp_err_t esp_timer_init(void) goto out; } -#if CONFIG_SPIRAM_USE_MALLOC - memset(&s_timer_delete_mutex_memory, 0, sizeof(StaticQueue_t)); - s_timer_delete_mutex = xSemaphoreCreateRecursiveMutexStatic(&s_timer_delete_mutex_memory); -#else - s_timer_delete_mutex = xSemaphoreCreateRecursiveMutex(); -#endif - if (!s_timer_delete_mutex) { - err = ESP_ERR_NO_MEM; - goto out; - } - - int ret = xTaskCreatePinnedToCore(&timer_task, "esp_timer", ESP_TASK_TIMER_STACK, NULL, ESP_TASK_TIMER_PRIO, &s_timer_task, PRO_CPU_NUM); if (ret != pdPASS) { @@ -391,10 +370,6 @@ out: vSemaphoreDelete(s_timer_semaphore); s_timer_semaphore = NULL; } - if (s_timer_delete_mutex) { - vSemaphoreDelete(s_timer_delete_mutex); - s_timer_delete_mutex = NULL; - } return ESP_ERR_NO_MEM; } diff --git a/components/esp_eth/CMakeLists.txt b/components/esp_eth/CMakeLists.txt new file mode 100644 index 0000000000..3829df1885 --- /dev/null +++ b/components/esp_eth/CMakeLists.txt @@ -0,0 +1,20 @@ +set(esp_eth_srcs "src/esp_eth.c" + "src/esp_eth_phy_dp83848.c" + "src/esp_eth_phy_ip101.c" + "src/esp_eth_phy_lan8720.c" + "src/esp_eth_phy_rtl8201.c") + +if(CONFIG_ETH_USE_ESP32_EMAC) + list(APPEND esp_eth_srcs "src/esp_eth_mac_esp32.c") +endif() + +if(CONFIG_ETH_SPI_ETHERNET_DM9051) + list(APPEND esp_eth_srcs "src/esp_eth_mac_dm9051.c" + "src/esp_eth_phy_dm9051.c") +endif() + +idf_component_register(SRCS "${esp_eth_srcs}" + INCLUDE_DIRS "include" + LDFRAGMENTS "linker.lf" + REQUIRES "esp_event" + PRIV_REQUIRES "tcpip_adapter" "driver" "log") diff --git a/components/esp_eth/Kconfig b/components/esp_eth/Kconfig new file mode 100644 index 0000000000..40e7ee36dc --- /dev/null +++ b/components/esp_eth/Kconfig @@ -0,0 +1,156 @@ +menu "Ethernet" + + menuconfig ETH_USE_ESP32_EMAC + depends on IDF_TARGET_ESP32 + bool "Support ESP32 internal EMAC controller" + default y + help + ESP32 integrates a 10/100M Ethernet MAC controller. + + if ETH_USE_ESP32_EMAC + choice ETH_PHY_INTERFACE + prompt "PHY interface" + default ETH_PHY_INTERFACE_RMII + help + Select the communication interface between MAC and PHY chip. + + config ETH_PHY_INTERFACE_RMII + bool "Reduced Media Independent Interface (RMII)" + + config ETH_PHY_INTERFACE_MII + bool "Media Independent Interface (MII)" + endchoice + + if ETH_PHY_INTERFACE_RMII + choice ETH_RMII_CLK_MODE + prompt "RMII clock mode" + default ETH_RMII_CLK_INPUT + help + Select external or internal RMII clock. + + config ETH_RMII_CLK_INPUT + bool "Input RMII clock from external" + help + MAC will get RMII clock from outside. + Note that ESP32 only supports GPIO0 to input the RMII clock. + + config ETH_RMII_CLK_OUTPUT + bool "Output RMII clock from internal" + help + ESP32 can generate RMII clock by internal APLL. + This clock can be routed to the external PHY device. + ESP32 supports to route the RMII clock to GPIO0/16/17. + endchoice + endif + + if ETH_RMII_CLK_INPUT + config ETH_RMII_CLK_IN_GPIO + int + range 0 0 + default 0 + help + ESP32 only supports GPIO0 to input the RMII clock. + endif + + if ETH_RMII_CLK_OUTPUT + config ETH_RMII_CLK_OUTPUT_GPIO0 + bool "Output RMII clock from GPIO0 (Experimental!)" + default n + help + GPIO0 can be set to output a pre-divided PLL clock (test only!). + Enabling this option will configure GPIO0 to output a 50MHz clock. + In fact this clock doesn't have directly relationship with EMAC peripheral. + Sometimes this clock won't work well with your PHY chip. You might need to + add some extra devices after GPIO0 (e.g. inverter). + Note that outputting RMII clock on GPIO0 is an experimental practice. + If you want the Ethernet to work with WiFi, don't select GPIO0 output mode for stability. + + if !ETH_RMII_CLK_OUTPUT_GPIO0 + config ETH_RMII_CLK_OUT_GPIO + int "RMII clock GPIO number" + range 16 17 + default 17 + help + Set the GPIO number to output RMII Clock. + endif + endif + + config ETH_SMI_MDC_GPIO + int "SMI MDC GPIO number" + default 23 + range 0 33 + help + Set the GPIO number used by SMI MDC. + + config ETH_SMI_MDIO_GPIO + int "SMI MDIO GPIO number" + default 18 + range 0 33 + help + Set the GPIO number used by SMI MDIO. + + config ETH_PHY_USE_RST + bool "Use Reset Pin of PHY Chip" + default y + help + Set this option to true if you want to control PHY chip's reset using a GPIO. + Check the schematic of you board to make sure if it's necessary to use this feature. + + if ETH_PHY_USE_RST + config ETH_PHY_RST_GPIO + int "PHY RST GPIO number" + default 5 + range 0 33 + help + Set the GPIO number used by the PHY chip's RST pin. + endif + + config ETH_DMA_BUFFER_SIZE + int "Ethernet DMA buffer size (Byte)" + range 256 1600 + default 512 + help + Set the size of each buffer used by Ethernet MAC DMA. + + config ETH_DMA_RX_BUFFER_NUM + int "Amount of Ethernet DMA Rx buffers" + range 3 20 + default 10 + help + Number of DMA receive buffers. Each buffer's size is ETH_DMA_BUFFER_SIZE. + Larger number of buffers could increase throughput somehow. + + config ETH_DMA_TX_BUFFER_NUM + int "Amount of Ethernet DMA Tx buffers" + range 3 20 + default 10 + help + Number of DMA transmit buffers. Each buffer's size is ETH_DMA_BUFFER_SIZE. + Larger number of buffers could increase throughput somehow. + endif + + menuconfig ETH_USE_SPI_ETHERNET + bool "Support SPI to Ethernet Module" + default y + help + ESP-IDF can also support some SPI-Ethernet module. + + if ETH_USE_SPI_ETHERNET + menuconfig ETH_SPI_ETHERNET_DM9051 + bool "Use DM9051" + default y + help + DM9051 is a fast Ethernet controller with an SPI interface. + It's also integrated with a 10/100M PHY and MAC. + Set true to enable DM9051 driver. + + if ETH_SPI_ETHERNET_DM9051 + config ETH_DM9051_INT_GPIO + int "DM9051 Interrupt GPIO number" + default 4 + range 0 33 + help + Set the GPIO number used by DM9051's Interrupt pin. + endif + endif +endmenu diff --git a/components/esp_eth/component.mk b/components/esp_eth/component.mk new file mode 100644 index 0000000000..3a768fdf8c --- /dev/null +++ b/components/esp_eth/component.mk @@ -0,0 +1,14 @@ +# +# Component Makefile +# +COMPONENT_ADD_INCLUDEDIRS := include +COMPONENT_SRCDIRS := src +COMPONENT_ADD_LDFRAGMENTS += linker.lf + +ifndef CONFIG_ETH_USE_ESP32_EMAC + COMPONENT_OBJEXCLUDE += src/esp_eth_mac_esp32.o +endif + +ifndef CONFIG_ETH_SPI_ETHERNET_DM9051 + COMPONENT_OBJEXCLUDE += src/esp_eth_mac_dm9051.o src/esp_eth_phy_dm9051.o +endif diff --git a/components/esp_eth/include/esp_eth.h b/components/esp_eth/include/esp_eth.h new file mode 100644 index 0000000000..cf4b570502 --- /dev/null +++ b/components/esp_eth/include/esp_eth.h @@ -0,0 +1,174 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "esp_eth_com.h" +#include "esp_eth_mac.h" +#include "esp_eth_phy.h" + +/** +* @brief Handle of Ethernet driver +* +*/ +typedef void *esp_eth_handle_t; + +/** +* @brief Configuration of Ethernet driver +* +*/ +typedef struct { + /** + * @brief Ethernet MAC object + * + */ + esp_eth_mac_t *mac; + + /** + * @brief Ethernet PHY object + * + */ + esp_eth_phy_t *phy; + + /** + * @brief Period time of checking Ethernet link status + * + */ + uint32_t check_link_period_ms; + + /** + * @brief Input frame buffer to user's stack + * + * @param[in] eth_handle: handle of Ethernet driver + * @param[in] buffer: frame buffer that will get input to upper stack + * @param[in] length: length of the frame buffer + * + * @return + * - ESP_OK: input frame buffer to upper stack successfully + * - ESP_FAIL: error occurred when inputting buffer to upper stack + * + */ + esp_err_t (*stack_input)(esp_eth_handle_t eth_handle, uint8_t *buffer, uint32_t length); + + /** + * @brief Callback function invoked when lowlevel initialization is finished + * + * @param[in] eth_handle: handle of Ethernet driver + * + * @return + * - ESP_OK: process extra lowlevel initialization successfully + * - ESP_FAIL: error occurred when processing extra lowlevel initialization + */ + esp_err_t (*on_lowlevel_init_done)(esp_eth_handle_t eth_handle); + + /** + * @brief Callback function invoked when lowlevel deinitialization is finished + * + * @param[in] eth_handle: handle of Ethernet driver + * + * @return + * - ESP_OK: process extra lowlevel deinitialization successfully + * - ESP_FAIL: error occurred when processing extra lowlevel deinitialization + */ + esp_err_t (*on_lowlevel_deinit_done)(esp_eth_handle_t eth_handle); +} esp_eth_config_t; + +/** + * @brief Default configuration for Ethernet driver + * + */ +#define ETH_DEFAULT_CONFIG(emac, ephy) \ + { \ + .mac = emac, \ + .phy = ephy, \ + .check_link_period_ms = 2000, \ + .stack_input = NULL, \ + .on_lowlevel_init_done = NULL, \ + .on_lowlevel_deinit_done = NULL, \ + } + +/** +* @brief Install Ethernet driver +* +* @param[in] config: configuration of the Ethernet driver +* @param[out] out_hdl: handle of Ethernet driver +* +* @return +* - ESP_OK: install esp_eth driver successfully +* - ESP_ERR_INVALID_ARG: install esp_eth driver failed because of some invalid argument +* - ESP_ERR_NO_MEM: install esp_eth driver failed because there's no memory for driver +* - ESP_FAIL: install esp_eth driver failed because some other error occurred +*/ +esp_err_t esp_eth_driver_install(const esp_eth_config_t *config, esp_eth_handle_t *out_hdl); + +/** +* @brief Uninstall Ethernet driver +* +* @param[in] hdl: handle of Ethernet driver +* +* @return +* - ESP_OK: uninstall esp_eth driver successfully +* - ESP_ERR_INVALID_ARG: uninstall esp_eth driver failed because of some invalid argument +* - ESP_FAIL: uninstall esp_eth driver failed because some other error occurred +*/ +esp_err_t esp_eth_driver_uninstall(esp_eth_handle_t hdl); + +/** +* @brief General Transmit +* +* @param[in] hdl: handle of Ethernet driver +* @param[in] buf: buffer of the packet to transfer +* @param[in] length: length of the buffer to transfer +* +* @return +* - ESP_OK: transmit frame buffer successfully +* - ESP_ERR_INVALID_ARG: transmit frame buffer failed because of some invalid argument +* - ESP_FAIL: transmit frame buffer failed because some other error occurred +*/ +esp_err_t esp_eth_transmit(esp_eth_handle_t hdl, uint8_t *buf, uint32_t length); + +/** +* @brief General Receive +* +* @param[in] hdl: handle of Ethernet driver +* @param[out] buf: buffer to preserve the received packet +* @param[out] length: length of the received packet +* +* @return +* - ESP_OK: receive frame buffer successfully +* - ESP_ERR_INVALID_ARG: receive frame buffer failed because of some invalid argument +* - ESP_FAIL: receive frame buffer failed because some other error occurred +*/ +esp_err_t esp_eth_receive(esp_eth_handle_t hdl, uint8_t *buf, uint32_t *length); + +/** +* @brief Misc IO function of Etherent driver +* +* @param[in] hdl: handle of Ethernet driver +* @param[in] cmd: IO control command +* @param[in] data: specificed data for command +* +* @return +* - ESP_OK: process io command successfully +* - ESP_ERR_INVALID_ARG: process io command failed because of some invalid argument +* - ESP_FAIL: process io command failed because some other error occurred +*/ +esp_err_t esp_eth_ioctl(esp_eth_handle_t hdl, esp_eth_io_cmd_t cmd, void *data); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_eth/include/esp_eth_com.h b/components/esp_eth/include/esp_eth_com.h new file mode 100644 index 0000000000..2f40c645b7 --- /dev/null +++ b/components/esp_eth/include/esp_eth_com.h @@ -0,0 +1,211 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "esp_err.h" +#include "esp_event_base.h" + +/** + * @brief Maximum Ethernet payload size + * + */ +#define ETH_MAX_PAYLOAD_LEN (1500) + +/** + * @brief Minimum Ethernet payload size + * + */ +#define ETH_MIN_PAYLOAD_LEN (46) + +/** + * @brief Ethernet frame header size: Dest addr(6 Bytes) + Src addr(6 Bytes) + length/type(2 Bytes) + * + */ +#define ETH_HEADER_LEN (14) + +/** + * @brief Ethernet frame CRC length + * + */ +#define ETH_CRC_LEN (4) + +/** + * @brief Optional 802.1q VLAN Tag length + * + */ +#define ETH_VLAN_TAG_LEN (4) + +/** + * @brief Jumbo frame payload size + * + */ +#define ETH_JUMBO_FRAME_PAYLOAD_LEN (9000) + +/** + * @brief Maximum frame size (1522 Bytes) + * + */ +#define ETH_MAX_PACKET_SIZE (ETH_HEADER_LEN + ETH_VLAN_TAG_LEN + ETH_MAX_PAYLOAD_LEN + ETH_CRC_LEN) + +/** + * @brief Minimum frame size (64 Bytes) + * + */ +#define ETH_MIN_PACKET_SIZE (ETH_HEADER_LEN + ETH_MIN_PAYLOAD_LEN + ETH_CRC_LEN) + +/** +* @brief Ethernet driver state +* +*/ +typedef enum { + ETH_STATE_LLINIT, /*!< Lowlevel init done */ + ETH_STATE_DEINIT, /*!< Deinit done */ + ETH_STATE_LINK, /*!< Link status changed */ + ETH_STATE_SPEED, /*!< Speed updated */ + ETH_STATE_DUPLEX, /*!< Duplex updated */ +} esp_eth_state_t; + +/** +* @brief Command list for ioctl API +* +*/ +typedef enum { + ETH_CMD_G_MAC_ADDR, /*!< Get MAC address */ + ETH_CMD_S_MAC_ADDR, /*!< Set MAC address */ + ETH_CMD_G_PHY_ADDR, /*!< Get PHY address */ + ETH_CMD_S_PHY_ADDR, /*!< Set PHY address */ + ETH_CMD_G_SPEED, /*!< Get Speed */ + ETH_CMD_S_PROMISCUOUS, /*!< Set promiscuous mode */ +} esp_eth_io_cmd_t; + +/** +* @brief Ethernet link status +* +*/ +typedef enum { + ETH_LINK_UP, /*!< Ethernet link is up */ + ETH_LINK_DOWN /*!< Ethernet link is down */ +} eth_link_t; + +/** +* @brief Ethernet speed +* +*/ +typedef enum { + ETH_SPEED_10M, /*!< Ethernet speed is 10Mbps */ + ETH_SPEED_100M /*!< Ethernet speed is 100Mbps */ +} eth_speed_t; + +/** +* @brief Ethernet duplex mode +* +*/ +typedef enum { + ETH_DUPLEX_HALF, /*!< Ethernet is in half duplex */ + ETH_DUPLEX_FULL /*!< Ethernet is in full duplex */ +} eth_duplex_t; + +/** +* @brief Ethernet mediator +* +*/ +typedef struct esp_eth_mediator_s esp_eth_mediator_t; + +/** +* @brief Ethernet mediator +* +*/ +struct esp_eth_mediator_s { + /** + * @brief Read PHY register + * + * @param[in] eth: mediator of Ethernet driver + * @param[in] phy_addr: PHY Chip address (0~31) + * @param[in] phy_reg: PHY register index code + * @param[out] reg_value: PHY register value + * + * @return + * - ESP_OK: read PHY register successfully + * - ESP_FAIL: read PHY register failed because some error occurred + * + */ + esp_err_t (*phy_reg_read)(esp_eth_mediator_t *eth, uint32_t phy_addr, uint32_t phy_reg, uint32_t *reg_value); + + /** + * @brief Write PHY register + * + * @param[in] eth: mediator of Ethernet driver + * @param[in] phy_addr: PHY Chip address (0~31) + * @param[in] phy_reg: PHY register index code + * @param[in] reg_value: PHY register value + * + * @return + * - ESP_OK: write PHY register successfully + * - ESP_FAIL: write PHY register failed because some error occurred + */ + esp_err_t (*phy_reg_write)(esp_eth_mediator_t *eth, uint32_t phy_addr, uint32_t phy_reg, uint32_t reg_value); + + /** + * @brief Deliver packet to upper stack + * + * @param[in] eth: mediator of Ethernet driver + * @param[in] buffer: packet buffer + * @param[in] length: length of the packet + * + * @return + * - ESP_OK: deliver packet to upper stack successfully + * - ESP_FAIL: deliver packet failed because some error occurred + * + */ + esp_err_t (*stack_input)(esp_eth_mediator_t *eth, uint8_t *buffer, uint32_t length); + + /** + * @brief Callback on Ethernet state changed + * + * @param[in] eth: mediator of Ethernet driver + * @param[in] state: new state + * @param[in] args: optional argument for the new state + * + * @return + * - ESP_OK: process the new state successfully + * - ESP_FAIL: process the new state failed because some error occurred + * + */ + esp_err_t (*on_state_changed)(esp_eth_mediator_t *eth, esp_eth_state_t state, void *args); +}; + +/** +* @brief Ethernet event declarations +* +*/ +typedef enum { + ETHERNET_EVENT_START, /*!< Ethernet driver start */ + ETHERNET_EVENT_STOP, /*!< Ethernet driver stop */ + ETHERNET_EVENT_CONNECTED, /*!< Ethernet got a valid link */ + ETHERNET_EVENT_DISCONNECTED, /*!< Ethernet lost a valid link */ +} eth_event_t; + +/** +* @brief Ethernet event base declaration +* +*/ +ESP_EVENT_DECLARE_BASE(ETH_EVENT); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_eth/include/esp_eth_mac.h b/components/esp_eth/include/esp_eth_mac.h new file mode 100644 index 0000000000..07507cefed --- /dev/null +++ b/components/esp_eth/include/esp_eth_mac.h @@ -0,0 +1,296 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "esp_eth_com.h" +#include "sdkconfig.h" +#if CONFIG_ETH_USE_SPI_ETHERNET +#include "driver/gpio.h" +#include "driver/spi_master.h" +#endif + + +/** +* @brief Ethernet MAC +* +*/ +typedef struct esp_eth_mac_s esp_eth_mac_t; + +/** +* @brief Ethernet MAC +* +*/ +struct esp_eth_mac_s { + /** + * @brief Set mediator for Ethernet MAC + * + * @param[in] mac: Ethernet MAC instance + * @param[in] eth: Ethernet mediator + * + * @return + * - ESP_OK: set mediator for Ethernet MAC successfully + * - ESP_ERR_INVALID_ARG: set mediator for Ethernet MAC failed because of invalid argument + * + */ + esp_err_t (*set_mediator)(esp_eth_mac_t *mac, esp_eth_mediator_t *eth); + + /** + * @brief Initialize Ethernet MAC + * + * @param[in] mac: Ethernet MAC instance + * + * @return + * - ESP_OK: initialize Ethernet MAC successfully + * - ESP_ERR_TIMEOUT: initialize Ethernet MAC failed because of timeout + * - ESP_FAIL: initialize Ethernet MAC failed because some other error occurred + * + */ + esp_err_t (*init)(esp_eth_mac_t *mac); + + /** + * @brief Deinitialize Ethernet MAC + * + * @param[in] mac: Ethernet MAC instance + * + * @return + * - ESP_OK: deinitialize Ethernet MAC successfully + * - ESP_FAIL: deinitialize Ethernet MAC failed because some error occurred + * + */ + esp_err_t (*deinit)(esp_eth_mac_t *mac); + + /** + * @brief Transmit packet from Ethernet MAC + * + * @param[in] mac: Ethernet MAC instance + * @param[in] buf: packet buffer to transmit + * @param[in] length: length of packet + * + * @return + * - ESP_OK: transmit packet successfully + * - ESP_ERR_INVALID_ARG: transmit packet failed because of invalid argument + * - ESP_ERR_INVALID_STATE: transmit packet failed because of wrong state of MAC + * - ESP_FAIL: transmit packet failed because some other error occurred + * + */ + esp_err_t (*transmit)(esp_eth_mac_t *mac, uint8_t *buf, uint32_t length); + + /** + * @brief Receive packet from Ethernet MAC + * + * @param[in] mac: Ethernet MAC instance + * @param[out] buf: packet buffer which will preserve the received frame + * @param[out] length: length of the received packet + * + * @note Memory of buf is allocated in the Layer2, make sure it get free after process. + * + * @return + * - ESP_OK: receive packet successfully + * - ESP_ERR_INVALID_ARG: receive packet failed because of invalid argument + * - ESP_FAIL: receive packet failed because some other error occurred + * + */ + esp_err_t (*receive)(esp_eth_mac_t *mac, uint8_t *buf, uint32_t *length); + + /** + * @brief Read PHY register + * + * @param[in] mac: Ethernet MAC instance + * @param[in] phy_addr: PHY chip address (0~31) + * @param[in] phy_reg: PHY register index code + * @param[out] reg_value: PHY register value + * + * @return + * - ESP_OK: read PHY register successfully + * - ESP_ERR_INVALID_ARG: read PHY register failed because of invalid argument + * - ESP_ERR_INVALID_STATE: read PHY register failed because of wrong state of MAC + * - ESP_ERR_TIMEOUT: read PHY register failed because of timeout + * - ESP_FAIL: read PHY register failed because some other error occurred + * + */ + esp_err_t (*read_phy_reg)(esp_eth_mac_t *mac, uint32_t phy_addr, uint32_t phy_reg, uint32_t *reg_value); + + /** + * @brief Write PHY register + * + * @param[in] mac: Ethernet MAC instance + * @param[in] phy_addr: PHY chip address (0~31) + * @param[in] phy_reg: PHY register index code + * @param[in] reg_value: PHY register value + * + * @return + * - ESP_OK: write PHY register successfully + * - ESP_ERR_INVALID_STATE: write PHY register failed because of wrong state of MAC + * - ESP_ERR_TIMEOUT: write PHY register failed because of timeout + * - ESP_FAIL: write PHY register failed because some other error occurred + * + */ + esp_err_t (*write_phy_reg)(esp_eth_mac_t *mac, uint32_t phy_addr, uint32_t phy_reg, uint32_t reg_value); + + /** + * @brief Set MAC address + * + * @param[in] mac: Ethernet MAC instance + * @param[in] addr: MAC address + * + * @return + * - ESP_OK: set MAC address successfully + * - ESP_ERR_INVALID_ARG: set MAC address failed because of invalid argument + * - ESP_FAIL: set MAC address failed because some other error occurred + * + */ + esp_err_t (*set_addr)(esp_eth_mac_t *mac, uint8_t *addr); + + /** + * @brief Get MAC address + * + * @param[in] mac: Ethernet MAC instance + * @param[out] addr: MAC address + * + * @return + * - ESP_OK: get MAC address successfully + * - ESP_ERR_INVALID_ARG: get MAC address failed because of invalid argument + * - ESP_FAIL: get MAC address failed because some other error occurred + * + */ + esp_err_t (*get_addr)(esp_eth_mac_t *mac, uint8_t *addr); + + /** + * @brief Set speed of MAC + * + * @param[in] ma:c Ethernet MAC instance + * @param[in] speed: MAC speed + * + * @return + * - ESP_OK: set MAC speed successfully + * - ESP_ERR_INVALID_ARG: set MAC speed failed because of invalid argument + * - ESP_FAIL: set MAC speed failed because some other error occurred + * + */ + esp_err_t (*set_speed)(esp_eth_mac_t *mac, eth_speed_t speed); + + /** + * @brief Set duplex mode of MAC + * + * @param[in] mac: Ethernet MAC instance + * @param[in] duplex: MAC duplex + * + * @return + * - ESP_OK: set MAC duplex mode successfully + * - ESP_ERR_INVALID_ARG: set MAC duplex failed because of invalid argument + * - ESP_FAIL: set MAC duplex failed because some other error occurred + * + */ + esp_err_t (*set_duplex)(esp_eth_mac_t *mac, eth_duplex_t duplex); + + /** + * @brief Set link status of MAC + * + * @param[in] mac: Ethernet MAC instance + * @param[in] link: Link status + * + * @return + * - ESP_OK: set link status successfully + * - ESP_ERR_INVALID_ARG: set link status failed because of invalid argument + * - ESP_FAIL: set link status failed because some other error occurred + * + */ + esp_err_t (*set_link)(esp_eth_mac_t *mac, eth_link_t link); + + /** + * @brief Set promiscuous of MAC + * + * @param[in] mac: Ethernet MAC instance + * @param[in] enable: set true to enable promiscuous mode; set false to disable promiscuous mode + * + * @return + * - ESP_OK: set promiscuous mode successfully + * - ESP_FAIL: set promiscuous mode failed because some error occurred + * + */ + esp_err_t (*set_promiscuous)(esp_eth_mac_t *mac, bool enable); + + /** + * @brief Free memory of Ethernet MAC + * + * @param[in] mac: Ethernet MAC instance + * + * @return + * - ESP_OK: free Ethernet MAC instance successfully + * - ESP_FAIL: free Ethernet MAC instance failed because some error occurred + * + */ + esp_err_t (*del)(esp_eth_mac_t *mac); +}; + +/** +* @brief Configuration of Ethernet MAC object +* +*/ +typedef struct { + uint32_t sw_reset_timeout_ms; /*!< Software reset timeout value (Unit: ms) */ + uint32_t rx_task_stack_size; /*!< Stack size of the receive task */ + uint32_t rx_task_prio; /*!< Priority of the receive task */ + uint32_t queue_len; /*!< Length of the transaction queue */ +#if CONFIG_ETH_USE_SPI_ETHERNET + spi_device_handle_t spi_hdl; /*!< Handle of spi device */ +#endif + +} eth_mac_config_t; + +/** + * @brief Default configuration for Ethernet MAC object + * + */ +#define ETH_MAC_DEFAULT_CONFIG() \ + { \ + .sw_reset_timeout_ms = 100, \ + .rx_task_stack_size = 4096, \ + .rx_task_prio = 15, \ + .queue_len = 100, \ + } + +#if CONFIG_ETH_USE_ESP32_EMAC +/** +* @brief Create ESP32 Ethernet MAC instance +* +* @param config: Ethernet MAC configuration +* +* @return +* - instance: create MAC instance successfully +* - NULL: create MAC instance failed because some error occurred +*/ +esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config); +#endif + +#if CONFIG_ETH_SPI_ETHERNET_DM9051 +/** +* @brief Create DM9051 Ethernet MAC instance +* +* @param config: Ethernet MAC configuration +* +* @return +* - instance: create MAC instance successfully +* - NULL: create MAC instance failed because some error occurred +*/ +esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_mac_config_t *config); +#endif +#ifdef __cplusplus +} +#endif diff --git a/components/esp_eth/include/esp_eth_phy.h b/components/esp_eth/include/esp_eth_phy.h new file mode 100644 index 0000000000..b30fdad5dd --- /dev/null +++ b/components/esp_eth/include/esp_eth_phy.h @@ -0,0 +1,239 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "esp_eth_com.h" +#include "sdkconfig.h" + +/** +* @brief Ethernet PHY +* +*/ +typedef struct esp_eth_phy_s esp_eth_phy_t; + +/** +* @brief Ethernet PHY +* +*/ +struct esp_eth_phy_s { + /** + * @brief Set mediator for PHY + * + * @param[in] phy: Ethernet PHY instance + * @param[in] mediator: mediator of Ethernet driver + * + * @return + * - ESP_OK: set mediator for Ethernet PHY instance successfully + * - ESP_ERR_INVALID_ARG: set mediator for Ethernet PHY instance failed because of some invalid arguments + * + */ + esp_err_t (*set_mediator)(esp_eth_phy_t *phy, esp_eth_mediator_t *mediator); + + /** + * @brief Reset Ethernet PHY + * + * @param[in] phy: Ethernet PHY instance + * + * @return + * - ESP_OK: reset Ethernet PHY successfully + * - ESP_FAIL: reset Ethernet PHY failed because some error occurred + * + */ + esp_err_t (*reset)(esp_eth_phy_t *phy); + + /** + * @brief Initialize Ethernet PHY + * + * @param[in] phy: Ethernet PHY instance + * + * @return + * - ESP_OK: initialize Ethernet PHY successfully + * - ESP_FAIL: initialize Ethernet PHY failed because some error occurred + * + */ + esp_err_t (*init)(esp_eth_phy_t *phy); + + /** + * @brief Deinitialize Ethernet PHY + * + * @param[in] phyL Ethernet PHY instance + * + * @return + * - ESP_OK: deinitialize Ethernet PHY successfully + * - ESP_FAIL: deinitialize Ethernet PHY failed because some error occurred + * + */ + esp_err_t (*deinit)(esp_eth_phy_t *phy); + + /** + * @brief Start auto negotiation + * + * @param[in] phy: Ethernet PHY instance + * + * @return + * - ESP_OK: restart auto negotiation successfully + * - ESP_FAIL: restart auto negotiation failed because some error occurred + * + */ + esp_err_t (*negotiate)(esp_eth_phy_t *phy); + + /** + * @brief Get Ethernet PHY link status + * + * @param[in] phy: Ethernet PHY instance + * + * @return + * - ESP_OK: get Ethernet PHY link status successfully + * - ESP_FAIL: get Ethernet PHY link status failed because some error occurred + * + */ + esp_err_t (*get_link)(esp_eth_phy_t *phy); + + /** + * @brief Power control of Ethernet PHY + * + * @param[in] phy: Ethernet PHY instance + * @param[in] enable: set true to power on Ethernet PHY; ser false to power off Ethernet PHY + * + * @return + * - ESP_OK: control Ethernet PHY power successfully + * - ESP_FAIL: control Ethernet PHY power failed because some error occurred + * + */ + esp_err_t (*pwrctl)(esp_eth_phy_t *phy, bool enable); + + /** + * @brief Set PHY chip address + * + * @param[in] phy: Ethernet PHY instance + * @param[in] addr: PHY chip address + * + * @return + * - ESP_OK: set Ethernet PHY address successfully + * - ESP_FAIL: set Ethernet PHY address failed because some error occurred + * + */ + esp_err_t (*set_addr)(esp_eth_phy_t *phy, uint32_t addr); + + /** + * @brief Get PHY chip address + * + * @param[in] phy: Ethernet PHY instance + * @param[out] addr: PHY chip address + * + * @return + * - ESP_OK: get Ethernet PHY address successfully + * - ESP_ERR_INVALID_ARG: get Ethernet PHY address failed because of invalid argument + * + */ + esp_err_t (*get_addr)(esp_eth_phy_t *phy, uint32_t *addr); + + /** + * @brief Free memory of Ethernet PHY instance + * + * @param[in] phy: Ethernet PHY instance + * + * @return + * - ESP_OK: free PHY instance successfully + * - ESP_FAIL: free PHY instance failed because some error occurred + * + */ + esp_err_t (*del)(esp_eth_phy_t *phy); +}; + +/** +* @brief Ethernet PHY configuration +* +*/ +typedef struct { + uint32_t phy_addr; /*!< PHY address */ + uint32_t reset_timeout_ms; /*!< Reset timeout value (Unit: ms) */ + uint32_t autonego_timeout_ms; /*!< Auto-negotiation timeout value (Unit: ms) */ +} eth_phy_config_t; + +/** + * @brief Default configuration for Ethernet PHY object + * + */ +#define ETH_PHY_DEFAULT_CONFIG() \ + { \ + .phy_addr = 1, \ + .reset_timeout_ms = 100, \ + .autonego_timeout_ms = 4000 \ + } + +/** +* @brief Create a PHY instance of IP101 +* +* @param[in] config: configuration of PHY +* +* @return +* - instance: create PHY instance successfully +* - NULL: create PHY instance failed because some error occurred +*/ +esp_eth_phy_t *esp_eth_phy_new_ip101(const eth_phy_config_t *config); + +/** +* @brief Create a PHY instance of RTL8201 +* +* @param[in] config: configuration of PHY +* +* @return +* - instance: create PHY instance successfully +* - NULL: create PHY instance failed because some error occurred +*/ +esp_eth_phy_t *esp_eth_phy_new_rtl8201(const eth_phy_config_t *config); + +/** +* @brief Create a PHY instance of LAN8720 +* +* @param[in] config: configuration of PHY +* +* @return +* - instance: create PHY instance successfully +* - NULL: create PHY instance failed because some error occurred +*/ +esp_eth_phy_t *esp_eth_phy_new_lan8720(const eth_phy_config_t *config); + +/** +* @brief Create a PHY instance of DP83848 +* +* @param[in] config: configuration of PHY +* +* @return +* - instance: create PHY instance successfully +* - NULL: create PHY instance failed because some error occurred +*/ +esp_eth_phy_t *esp_eth_phy_new_dp83848(const eth_phy_config_t *config); + +#if CONFIG_ETH_SPI_ETHERNET_DM9051 +/** +* @brief Create a PHY instance of DM9051 +* +* @param[in] config: configuration of PHY +* +* @return +* - instance: create PHY instance successfully +* - NULL: create PHY instance failed because some error occurred +*/ +esp_eth_phy_t *esp_eth_phy_new_dm9051(const eth_phy_config_t *config); +#endif +#ifdef __cplusplus +} +#endif diff --git a/components/esp_eth/include/eth_phy_regs_struct.h b/components/esp_eth/include/eth_phy_regs_struct.h new file mode 100644 index 0000000000..023ccf2a6b --- /dev/null +++ b/components/esp_eth/include/eth_phy_regs_struct.h @@ -0,0 +1,163 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/******************Basic PHY Registers*******************/ + +/** + * @brief BMCR(Basic Mode Control Register) + * + */ +typedef union { + struct { + uint32_t reserved : 7; /*!< Reserved */ + uint32_t collision_test : 1; /*!< Collision test */ + uint32_t duplex_mode : 1; /*!< Duplex mode:Full Duplex(1) and Half Duplex(0) */ + uint32_t restart_auto_nego : 1; /*!< Restart auto-negotiation */ + uint32_t isolate : 1; /*!< Isolate the PHY from MII except the SMI interface */ + uint32_t power_down : 1; /*!< Power off PHY except SMI interface */ + uint32_t en_auto_nego : 1; /*!< Enable auto negotiation */ + uint32_t speed_select : 1; /*!< Select speed: 100Mbps(1) and 10Mbps(0) */ + uint32_t en_loopback : 1; /*!< Enables transmit data to be routed to the receive path */ + uint32_t reset : 1; /*!< Reset PHY registers. This bit is self-clearing. */ + }; + uint32_t val; +} bmcr_reg_t; +#define ETH_PHY_BMCR_REG_ADDR (0x00) + +/** + * @brief BMSR(Basic Mode Status Register) + * + */ +typedef union { + struct { + uint32_t ext_capability : 1; /*!< Extended register capability */ + uint32_t jabber_detect : 1; /*!< Jabber condition detected */ + uint32_t link_status : 1; /*!< Link status */ + uint32_t auto_nego_ability : 1; /*!< Auto negotiation ability */ + uint32_t remote_fault : 1; /*!< Remote fault detected */ + uint32_t auto_nego_complete : 1; /*!< Auto negotiation completed */ + uint32_t mf_preamble_suppress : 1; /*!< Preamble suppression capability for management frame */ + uint32_t reserved : 1; /*!< Reserved */ + uint32_t ext_status : 1; /*!< Extended Status */ + uint32_t base100_t2_hdx : 1; /*!< 100Base-T2 Half Duplex capability */ + uint32_t base100_t2_fdx : 1; /*!< 100Base-T2 Full Duplex capability */ + uint32_t base10_t_hdx : 1; /*!< 10Base-T Half Duplex capability */ + uint32_t base10_t_fdx : 1; /*!< 10Base-T Full Duplex capability */ + uint32_t base100_tx_hdx : 1; /*!< 100Base-Tx Half Duplex capability */ + uint32_t base100_tx_fdx : 1; /*!< 100Base-Tx Full Duplex capability */ + uint32_t based100_t4 : 1; /*!< 100Base-T4 capability */ + }; + uint32_t val; +} bmsr_reg_t; +#define ETH_PHY_BMSR_REG_ADDR (0x01) + +/** + * @brief PHYIDR1(PHY Identifier Register 1) + * + */ +typedef union { + struct { + uint32_t oui_msb : 16; /*!< Organizationally Unique Identifier(OUI) most significant bits */ + }; + uint32_t val; +} phyidr1_reg_t; +#define ETH_PHY_IDR1_REG_ADDR (0x02) + +/** + * @brief PHYIDR2(PHY Identifier Register 2) + * + */ +typedef union { + struct { + uint32_t model_revision : 4; /*!< Model revision number */ + uint32_t vendor_model : 6; /*!< Vendor model number */ + uint32_t oui_lsb : 6; /*!< Organizationally Unique Identifier(OUI) least significant bits */ + }; + uint32_t val; +} phyidr2_reg_t; +#define ETH_PHY_IDR2_REG_ADDR (0x03) + +/** + * @brief ANAR(Auto-Negotiation Advertisement Register) + * + */ +typedef union { + struct { + uint32_t protocol_select : 5; /*!< Binary encoded selector supported by this PHY */ + uint32_t base10_t : 1; /*!< 10Base-T support */ + uint32_t base10_t_fd : 1; /*!< 10Base-T full duplex support */ + uint32_t base100_tx : 1; /*!< 100Base-TX support */ + uint32_t base100_tx_fd : 1; /*!< 100Base-TX full duplex support */ + uint32_t base100_t4 : 1; /*!< 100Base-T4 support */ + uint32_t symmetric_pause : 1; /*!< Symmetric pause support for full duplex links */ + uint32_t asymmetric_pause : 1; /*!< Asymmetric pause support for full duplex links */ + uint32_t reserved1 : 1; /*!< Reserved */ + uint32_t remote_fault : 1; /*!< Advertise remote fault detection capability */ + uint32_t acknowledge : 1; /*!< Link partner ability data reception acknowledged */ + uint32_t next_page : 1; /*!< Next page indication, if set, next page transfer is desired */ + }; + uint32_t val; +} anar_reg_t; +#define ETH_PHY_ANAR_REG_ADDR (0x04) + +/** + * @brief ANLPAR(Auto-Negotiation Link Partner Ability Register) + * + */ +typedef union { + struct { + uint32_t protocol_select : 5; /*!< Link Partner’s binary encoded node selector */ + uint32_t base10_t : 1; /*!< 10Base-T support */ + uint32_t base10_t_fd : 1; /*!< 10Base-T full duplex support */ + uint32_t base100_tx : 1; /*!< 100Base-TX support */ + uint32_t base100_tx_fd : 1; /*!< 100Base-TX full duplex support */ + uint32_t base100_t4 : 1; /*!< 100Base-T4 support */ + uint32_t symmetric_pause : 1; /*!< Symmetric pause supported by Link Partner */ + uint32_t asymmetric_pause : 1; /*!< Asymmetric pause supported by Link Partner */ + uint32_t reserved : 1; /*!< Reserved */ + uint32_t remote_fault : 1; /*!< Link partner is indicating a remote fault */ + uint32_t acknowledge : 1; /*!< Acknowledges from link partner */ + uint32_t next_page : 1; /*!< Next page indication */ + }; + uint32_t val; +} anlpar_reg_t; +#define ETH_PHY_ANLPAR_REG_ADDR (0x05) + +/** + * @brief ANER(Auto-Negotiate Expansion Register) + * + */ +typedef union { + struct { + uint32_t link_partner_auto_nego_able : 1; /*!< Link partner auto-negotiation ability */ + uint32_t link_page_received : 1; /*!< Link code word page has received */ + uint32_t next_page_able : 1; /*!< Next page ablility */ + uint32_t link_partner_next_page_able : 1; /*!< Link partner next page ability */ + uint32_t parallel_detection_fault : 1; /*!< Parallel detection fault */ + uint32_t reserved : 11; /*!< Reserved */ + }; + uint32_t val; +} aner_reg_t; +#define ETH_PHY_ANER_REG_ADDR (0x06) + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_eth/linker.lf b/components/esp_eth/linker.lf new file mode 100644 index 0000000000..64969708d9 --- /dev/null +++ b/components/esp_eth/linker.lf @@ -0,0 +1,12 @@ +[mapping:esp_eth] +archive: libesp_eth.a +entries: + if ETH_USE_ESP32_EMAC = y: + esp_eth_mac_esp32:emac_hal_tx_complete_cb (noflash_text) + esp_eth_mac_esp32:emac_hal_tx_unavail_cb (noflash_text) + esp_eth_mac_esp32:emac_hal_rx_complete_cb (noflash_text) + esp_eth_mac_esp32:emac_hal_rx_early_cb (noflash_text) + esp_eth_mac_esp32:emac_hal_rx_unavail_cb (noflash_text) + esp_eth_mac_esp32:emac_esp32_isr_handler (noflash_text) + if ETH_SPI_ETHERNET_DM9051 = y: + esp_eth_mac_dm9051:dm9051_isr_handler (noflash_text) diff --git a/components/esp_eth/src/esp_eth.c b/components/esp_eth/src/esp_eth.c new file mode 100644 index 0000000000..adef9096e3 --- /dev/null +++ b/components/esp_eth/src/esp_eth.c @@ -0,0 +1,284 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include +#include "esp_log.h" +#include "esp_eth.h" +#include "esp_event.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/timers.h" + +static const char *TAG = "esp_eth"; +#define ETH_CHECK(a, str, goto_tag, ret_value, ...) \ + do \ + { \ + if (!(a)) \ + { \ + ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ + ret = ret_value; \ + goto goto_tag; \ + } \ + } while (0) + +ESP_EVENT_DEFINE_BASE(ETH_EVENT); + +/** + * @brief The Ethernet driver mainly consists of PHY, MAC and + * the mediator who will handle the request/response from/to MAC, PHY and Users. + * Ethernet driver adopts an OS timer to check the link status periodically. + * This structure preserves some important Ethernet attributes (e.g. speed, duplex, link). + * Function stack_input is the channel which set by user, it will deliver all received packets. + * If stack_input is set to NULL, then all received packets will be passed to tcp/ip stack. + * on_lowlevel_init_done and on_lowlevel_deinit_done are callbacks set by user. + * In the callback, user can do any low level operations (e.g. enable/disable crystal clock). + */ +typedef struct { + esp_eth_mediator_t mediator; + esp_eth_phy_t *phy; + esp_eth_mac_t *mac; + TimerHandle_t check_link_timer; + eth_speed_t speed; + eth_duplex_t duplex; + eth_link_t link; + esp_err_t (*stack_input)(esp_eth_handle_t eth_handle, uint8_t *buffer, uint32_t length); + esp_err_t (*on_lowlevel_init_done)(esp_eth_handle_t eth_handle); + esp_err_t (*on_lowlevel_deinit_done)(esp_eth_handle_t eth_handle); +} esp_eth_driver_t; + +////////////////////////////////Mediator Functions//////////////////////////////////////////// +// Following functions are owned by mediator, which will get invoked by MAC or PHY. +// Mediator functions need to find the right actor (MAC, PHY or user) to perform the operation. +// So in the head of mediator function, we have to get the esp_eth_driver_t pointer. +// With this pointer, we could deliver the task to the real actor (MAC, PHY or user). +// This might sound excessive, but is helpful to separate the PHY with MAC (they can not contact with each other directly). +// For more details, please refer to WiKi. https://en.wikipedia.org/wiki/Mediator_pattern +////////////////////////////////////////////////////////////////////////////////////////////// + +static esp_err_t eth_phy_reg_read(esp_eth_mediator_t *eth, uint32_t phy_addr, uint32_t phy_reg, uint32_t *reg_value) +{ + esp_eth_driver_t *eth_driver = __containerof(eth, esp_eth_driver_t, mediator); + esp_eth_mac_t *mac = eth_driver->mac; + return mac->read_phy_reg(mac, phy_addr, phy_reg, reg_value); +} + +static esp_err_t eth_phy_reg_write(esp_eth_mediator_t *eth, uint32_t phy_addr, uint32_t phy_reg, uint32_t reg_value) +{ + esp_eth_driver_t *eth_driver = __containerof(eth, esp_eth_driver_t, mediator); + esp_eth_mac_t *mac = eth_driver->mac; + return mac->write_phy_reg(mac, phy_addr, phy_reg, reg_value); +} + +static esp_err_t eth_stack_input(esp_eth_mediator_t *eth, uint8_t *buffer, uint32_t length) +{ + esp_eth_driver_t *eth_driver = __containerof(eth, esp_eth_driver_t, mediator); + if (!eth_driver->stack_input) { + return tcpip_adapter_eth_input(buffer, length, NULL); + } else { + return eth_driver->stack_input((esp_eth_handle_t)eth_driver, buffer, length); + } +} + +static esp_err_t eth_on_state_changed(esp_eth_mediator_t *eth, esp_eth_state_t state, void *args) +{ + esp_err_t ret = ESP_OK; + esp_eth_driver_t *eth_driver = __containerof(eth, esp_eth_driver_t, mediator); + esp_eth_mac_t *mac = eth_driver->mac; + switch (state) { + case ETH_STATE_LLINIT: { + if (eth_driver->on_lowlevel_init_done) { + ETH_CHECK(eth_driver->on_lowlevel_init_done(eth_driver) == ESP_OK, "extra lowlevel init failed", err, ESP_FAIL); + } + break; + } + case ETH_STATE_DEINIT: { + if (eth_driver->on_lowlevel_deinit_done) { + ETH_CHECK(eth_driver->on_lowlevel_deinit_done(eth_driver) == ESP_OK, "extra lowlevel deinit failed", err, ESP_FAIL); + } + break; + } + case ETH_STATE_LINK: { + eth_link_t link = (eth_link_t)args; + ETH_CHECK(mac->set_link(mac, link) == ESP_OK, "ethernet mac set link failed", err, ESP_FAIL); + eth_driver->link = link; + if (link == ETH_LINK_UP) { + ETH_CHECK(esp_event_post(ETH_EVENT, ETHERNET_EVENT_CONNECTED, ð_driver, sizeof(eth_driver), 0) == ESP_OK, + "send ETHERNET_EVENT_CONNECTED event failed", err, ESP_FAIL); + } else if (link == ETH_LINK_DOWN) { + ETH_CHECK(esp_event_post(ETH_EVENT, ETHERNET_EVENT_DISCONNECTED, ð_driver, sizeof(eth_driver), 0) == ESP_OK, + "send ETHERNET_EVENT_DISCONNECTED event failed", err, ESP_FAIL); + } + break; + } + case ETH_STATE_SPEED: { + eth_speed_t speed = (eth_speed_t)args; + ETH_CHECK(mac->set_speed(mac, speed) == ESP_OK, "ethernet mac set speed failed", err, ESP_FAIL); + eth_driver->speed = speed; + break; + } + case ETH_STATE_DUPLEX: { + eth_duplex_t duplex = (eth_duplex_t)args; + ETH_CHECK(mac->set_duplex(mac, duplex) == ESP_OK, "ethernet mac set duplex failed", err, ESP_FAIL); + eth_driver->duplex = duplex; + break; + } + default: + ETH_CHECK(false, "unknown ethernet state: %d", err, ESP_ERR_INVALID_ARG, state); + break; + } + return ESP_OK; +err: + return ret; +} + +static void eth_check_link_timer_cb(TimerHandle_t xTimer) +{ + esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)pvTimerGetTimerID(xTimer); + esp_eth_phy_t *phy = eth_driver->phy; + phy->get_link(phy); +} + +////////////////////////////////User face APIs//////////////////////////////////////////////// +// User has to pass the handle of Ethernet driver to each API. +// Different Ethernet driver instance is identified with a unique handle. +// It's helpful for us to support multiple Ethernet port on ESP32. +////////////////////////////////////////////////////////////////////////////////////////////// + +esp_err_t esp_eth_driver_install(const esp_eth_config_t *config, esp_eth_handle_t *out_hdl) +{ + esp_err_t ret = ESP_OK; + ETH_CHECK(config, "eth config can't be null", err, ESP_ERR_INVALID_ARG); + ETH_CHECK(out_hdl, "eth handle can't be null", err, ESP_ERR_INVALID_ARG); + esp_eth_mac_t *mac = config->mac; + esp_eth_phy_t *phy = config->phy; + ETH_CHECK(mac && phy, "can't set eth->mac or eth->phy to null", err, ESP_ERR_INVALID_ARG); + esp_eth_driver_t *eth_driver = calloc(1, sizeof(esp_eth_driver_t)); + ETH_CHECK(eth_driver, "request memory for eth_driver failed", err, ESP_ERR_NO_MEM); + eth_driver->mac = mac; + eth_driver->phy = phy; + eth_driver->link = ETH_LINK_DOWN; + eth_driver->duplex = ETH_DUPLEX_HALF; + eth_driver->speed = ETH_SPEED_10M; + eth_driver->stack_input = config->stack_input; + eth_driver->on_lowlevel_init_done = config->on_lowlevel_init_done; + eth_driver->on_lowlevel_deinit_done = config->on_lowlevel_deinit_done; + eth_driver->mediator.phy_reg_read = eth_phy_reg_read; + eth_driver->mediator.phy_reg_write = eth_phy_reg_write; + eth_driver->mediator.stack_input = eth_stack_input; + eth_driver->mediator.on_state_changed = eth_on_state_changed; + ETH_CHECK(mac->set_mediator(mac, ð_driver->mediator) == ESP_OK, "set mediator for mac failed", err_mediator, ESP_FAIL); + ETH_CHECK(phy->set_mediator(phy, ð_driver->mediator) == ESP_OK, "set mediator for phy failed", err_mediator, ESP_FAIL); + ETH_CHECK(mac->init(mac) == ESP_OK, "init mac failed", err_init_mac, ESP_FAIL); + ETH_CHECK(phy->init(phy) == ESP_OK, "init phy failed", err_init_phy, ESP_FAIL); + eth_driver->check_link_timer = xTimerCreate("eth_link_timer", pdMS_TO_TICKS(config->check_link_period_ms), pdTRUE, + eth_driver, eth_check_link_timer_cb); + ETH_CHECK(eth_driver->check_link_timer, "create eth_link_timer failed", err_create_timer, ESP_FAIL); + ETH_CHECK(xTimerStart(eth_driver->check_link_timer, 0) == pdPASS, "start eth_link_timer failed", err_start_timer, ESP_FAIL); + ETH_CHECK(esp_event_post(ETH_EVENT, ETHERNET_EVENT_START, ð_driver, sizeof(eth_driver), 0) == ESP_OK, + "send ETHERNET_EVENT_START event failed", err_event, ESP_FAIL); + *out_hdl = (esp_eth_handle_t)eth_driver; + return ESP_OK; +err_event: + xTimerStop(eth_driver->check_link_timer, 0); +err_start_timer: + xTimerDelete(eth_driver->check_link_timer, 0); +err_create_timer: + phy->deinit(phy); +err_init_phy: + mac->deinit(mac); +err_init_mac: +err_mediator: + free(eth_driver); +err: + return ret; +} + +esp_err_t esp_eth_driver_uninstall(esp_eth_handle_t hdl) +{ + esp_err_t ret = ESP_OK; + esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl; + ETH_CHECK(eth_driver, "ethernet driver handle can't be null", err, ESP_ERR_INVALID_ARG); + esp_eth_mac_t *mac = eth_driver->mac; + esp_eth_phy_t *phy = eth_driver->phy; + ETH_CHECK(xTimerDelete(eth_driver->check_link_timer, 0) == pdPASS, "delete eth_link_timer failed", err, ESP_FAIL); + ETH_CHECK(esp_event_post(ETH_EVENT, ETHERNET_EVENT_STOP, ð_driver, sizeof(eth_driver), 0) == ESP_OK, + "send ETHERNET_EVENT_STOP event failed", err, ESP_FAIL); + ETH_CHECK(phy->deinit(phy) == ESP_OK, "deinit phy failed", err, ESP_FAIL); + ETH_CHECK(mac->deinit(mac) == ESP_OK, "deinit mac failed", err, ESP_FAIL); + free(eth_driver); + return ESP_OK; +err: + return ret; +} + +esp_err_t esp_eth_transmit(esp_eth_handle_t hdl, uint8_t *buf, uint32_t length) +{ + esp_err_t ret = ESP_OK; + esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl; + ETH_CHECK(eth_driver, "ethernet driver handle can't be null", err, ESP_ERR_INVALID_ARG); + esp_eth_mac_t *mac = eth_driver->mac; + return mac->transmit(mac, buf, length); +err: + return ret; +} + +esp_err_t esp_eth_receive(esp_eth_handle_t hdl, uint8_t *buf, uint32_t *length) +{ + esp_err_t ret = ESP_OK; + esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl; + ETH_CHECK(eth_driver, "ethernet driver handle can't be null", err, ESP_ERR_INVALID_ARG); + esp_eth_mac_t *mac = eth_driver->mac; + return mac->receive(mac, buf, length); +err: + return ret; +} + +esp_err_t esp_eth_ioctl(esp_eth_handle_t hdl, esp_eth_io_cmd_t cmd, void *data) +{ + esp_err_t ret = ESP_OK; + esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl; + ETH_CHECK(eth_driver, "ethernet driver handle can't be null", err, ESP_ERR_INVALID_ARG); + esp_eth_mac_t *mac = eth_driver->mac; + esp_eth_phy_t *phy = eth_driver->phy; + switch (cmd) { + case ETH_CMD_S_MAC_ADDR: + ETH_CHECK(data, "can't set mac addr to null", err, ESP_ERR_INVALID_ARG); + ETH_CHECK(mac->set_addr(mac, (uint8_t *)data) == ESP_OK, "set mac address failed", err, ESP_FAIL); + break; + case ETH_CMD_G_MAC_ADDR: + ETH_CHECK(data, "no mem to store mac addr", err, ESP_ERR_INVALID_ARG); + ETH_CHECK(mac->get_addr(mac, (uint8_t *)data) == ESP_OK, "get mac address failed", err, ESP_FAIL); + break; + case ETH_CMD_S_PHY_ADDR: + ETH_CHECK(data, "can't set phy addr to null", err, ESP_ERR_INVALID_ARG); + ETH_CHECK(phy->set_addr(phy, (uint32_t)data) == ESP_OK, "set phy address failed", err, ESP_FAIL); + break; + case ETH_CMD_G_PHY_ADDR: + ETH_CHECK(data, "no mem to store phy addr", err, ESP_ERR_INVALID_ARG); + ETH_CHECK(phy->get_addr(phy, (uint32_t *)data) == ESP_OK, "get phy address failed", err, ESP_FAIL); + break; + case ETH_CMD_G_SPEED: + ETH_CHECK(data, "no mem to store speed value", err, ESP_ERR_INVALID_ARG); + *(eth_speed_t *)data = eth_driver->speed; + break; + case ETH_CMD_S_PROMISCUOUS: + ETH_CHECK(mac->set_promiscuous(mac, (bool)data) == ESP_OK, "set promiscuous mode failed", err, ESP_FAIL); + break; + default: + ETH_CHECK(false, "unknown io command: %d", err, ESP_ERR_INVALID_ARG, cmd); + break; + } + return ESP_OK; +err: + return ret; +} diff --git a/components/esp_eth/src/esp_eth_mac_dm9051.c b/components/esp_eth/src/esp_eth_mac_dm9051.c new file mode 100644 index 0000000000..b76c5a4fd5 --- /dev/null +++ b/components/esp_eth/src/esp_eth_mac_dm9051.c @@ -0,0 +1,852 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include +#include +#include +#include "driver/gpio.h" +#include "driver/spi_master.h" +#include "esp_log.h" +#include "esp_eth.h" +#include "esp_system.h" +#include "esp_intr_alloc.h" +#include "esp_heap_caps.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "sdkconfig.h" + +static const char *TAG = "emac_dm9051"; +#define MAC_CHECK(a, str, goto_tag, ret_value, ...) \ + do \ + { \ + if (!(a)) \ + { \ + ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ + ret = ret_value; \ + goto goto_tag; \ + } \ + } while (0) + +#define RX_QUEUE_WAIT_MS (100) +#define DM9051_SPI_LOCK_TIMEOUT_MS (50) +#define DM9051_PHY_OPERATION_TIMEOUT_US (1000) + +/** + * @brief Registers in DM9051 + * + */ +#define DM9051_NCR (0x00) // Network Control Register +#define DM9051_NSR (0x01) // Network Status Register +#define DM9051_TCR (0x02) // Tx Control Register +#define DM9051_TSR1 (0x03) // Tx Status Register I +#define DM9051_TSR2 (0x04) // Tx Status Register II +#define DM9051_RCR (0x05) // Rx Control Register +#define DM9051_RSR (0x06) // Rx Status Register +#define DM9051_ROCR (0x07) // Receive Overflow Counter Register +#define DM9051_BPTR (0x08) // Back Pressure Threshold Register +#define DM9051_FCTR (0x09) // Flow Control Threshold Register +#define DM9051_FCR (0x0A) // Rx/Tx Flow Control Register +#define DM9051_EPCR (0x0B) // EEPROM & PHY Control Register +#define DM9051_EPAR (0x0C) // EEPROM & PHY Address Register +#define DM9051_EPDRL (0x0D) // EEPROM & PHY Data Register Low +#define DM9051_EPDRH (0x0E) // EEPROM & PHY Data Register High +#define DM9051_WCR (0x0F) // Wake Up Control Register +#define DM9051_PAR (0x10) // Physical Address Register +#define DM9051_MAR (0x16) // Multicast Address Hash Table Register +#define DM9051_GPCR (0x1E) // General Purpose Control Register +#define DM9051_GPR (0x1F) // General Purpose Register +#define DM9051_TRPAL (0x22) // Tx Memory Read Pointer Address Low Byte +#define DM9051_TRPAH (0x23) // Tx Memory Read Pointer Address High Byte +#define DM9051_RWPAL (0x24) // Rx Memory Read Pointer Address Low Byte +#define DM9051_RWPAH (0x25) // Rx Memory Read Pointer Address High Byte +#define DM9051_VIDL (0x28) // Vendor ID Low Byte +#define DM9051_VIDH (0x29) // Vendor ID High Byte +#define DM9051_PIDL (0x2A) // Product ID Low Byte +#define DM9051_PIDH (0x2B) // Product ID High Byte +#define DM9051_CHIPR (0x2C) // CHIP Revision +#define DM9051_TCR2 (0x2D) // Transmit Control Register 2 +#define DM9051_ATCR (0x30) // Auto-Transmit Control Register +#define DM9051_TCSCR (0x31) // Transmit Check Sum Control Register +#define DM9051_RCSCSR (0x32) // Receive Check Sum Control Status Register +#define DM9051_SBCR (0x38) // SPI Bus Control Register +#define DM9051_INTCR (0x39) // INT Pin Control Register +#define DM9051_PPCSR (0x3D) // Pause Packet Control Status Register +#define DM9051_EEE_IN (0x3E) // IEEE 802.3az Enter Counter Register +#define DM9051_EEE_OUT (0x3F) // IEEE 802.3az Leave Counter Register +#define DM9051_ALNCR (0x4A) // SPI Byte Align Error Counter Register +#define DM9051_RLENCR (0x52) // Rx Packet Length Control Register +#define DM9051_BCASTCR (0x53) // RX Broadcast Control Register +#define DM9051_INTCKCR (0x54) // INT Pin Clock Output Control Register +#define DM9051_MPTRCR (0x55) // Memory Pointer Control Register +#define DM9051_MLEDCR (0x57) // More LED Control Register +#define DM9051_MEMSCR (0x59) // Memory Control Register +#define DM9051_TMEMR (0x5A) // Transmit Memory Size Register +#define DM9051_MBSR (0x5D) // Memory BIST Status Register +#define DM9051_MRCMDX (0x70) // Memory Data Pre-Fetch Read Command Without Address Increment Register +#define DM9051_MRCMDX1 (0x71) // Memory Read Command Without Pre-Fetch and Without Address Increment Register +#define DM9051_MRCMD (0x72) // Memory Data Read Command With Address Increment Register +#define DM9051_SDR_DLY (0x73) // SPI Data Read Delay Counter Register +#define DM9051_MRRL (0x74) // Memory Data Read Address Register Low Byte +#define DM9051_MRRH (0x75) // Memory Data Read Address Register High Byte +#define DM9051_MWCMDX (0x76) // Memory Data Write Command Without Address Increment Register +#define DM9051_MWCMD (0x78) // Memory Data Write Command With Address Increment Register +#define DM9051_MWRL (0x7A) // Memory Data Write Address Register Low Byte +#define DM9051_MWRH (0x7B) // Memory Data Write Address Register High Byte +#define DM9051_TXPLL (0x7C) // TX Packet Length Low Byte Register +#define DM9051_TXPLH (0x7D) // TX Packet Length High Byte Register +#define DM9051_ISR (0x7E) // Interrupt Status Register +#define DM9051_IMR (0x7F) // Interrupt Mask Register + +/** + * @brief status and flag of DM9051 specific registers + * + */ +#define DM9051_SPI_RD (0) // Burst Read Command +#define DM9051_SPI_WR (1) // Burst Write Command + +#define NCR_WAKEEN (1 << 6) // Enable Wakeup Function +#define NCR_FDX (1 << 3) // Duplex Mode of the Internal PHY +#define NCR_RST (1 << 0) // Software Reset and Auto-Clear after 10us + +#define NSR_SPEED (1 << 7) // Speed of Internal PHY +#define NSR_LINKST (1 << 6) // Link Status of Internal PHY +#define NSR_WAKEST (1 << 5) // Wakeup Event Status +#define NSR_TX2END (1 << 3) // TX Packet Index II Complete Status +#define NSR_TX1END (1 << 2) // TX Packet Index I Complete Status +#define NSR_RXOV (1 << 1) // RX Memory Overflow Status +#define NSR_RXRDY (1 << 0) // RX Packet Ready + +#define TCR_TXREQ (1 << 0) // TX Request. Auto-Clear after Sending Completely + +#define RCR_WTDIS (1 << 6) // Watchdog Timer Disable +#define RCR_DIS_LONG (1 << 5) // Discard Long Packet +#define RCR_DIS_CRC (1 << 4) // Discard CRC Error Packet +#define RCR_ALL (1 << 3) // Receive All Multicast +#define RCR_RUNT (1 << 2) // Receive Runt Packet +#define RCR_PRMSC (1 << 1) // Promiscuous Mode +#define RCR_RXEN (1 << 0) // RX Enable + +#define RSR_RF (1 << 7) // Runt Frame +#define RSR_MF (1 << 6) // Multicast Frame +#define RSR_LCS (1 << 5) // Late Collision Seen +#define RSR_RWTO (1 << 4) // Receive Watchdog Time-Out +#define RSR_PLE (1 << 3) // Physical Layer Error +#define RSR_AE (1 << 2) // Alignment Error +#define RSR_CE (1 << 1) // CRC Error +#define RSR_FOE (1 << 0) // RX Memory Overflow Error + +#define FCR_FLOW_ENABLE (0x39) // Enable Flow Control + +#define EPCR_REEP (1 << 5) // Reload EEPROM +#define EPCR_WEP (1 << 4) // Write EEPROM Enable +#define EPCR_EPOS (1 << 3) // EEPROM or PHY Operation Select +#define EPCR_ERPRR (1 << 2) // EEPROM Read or PHY Register Read Command +#define EPCR_ERPRW (1 << 1) // EEPROM Write or PHY Register Write Command +#define EPCR_ERRE (1 << 0) // EEPROM Access Status or PHY Access Status + +#define TCR2_RLCP (1 << 6) // Retry Late Collision Packet + +#define ATCR_AUTO_TX (1 << 7) // Auto-Transmit Control + +#define TCSCR_UDPCSE (1 << 2) // UDP CheckSum Generation +#define TCSCR_TCPCSE (1 << 1) // TCP CheckSum Generation +#define TCSCR_IPCSE (1 << 0) // IPv4 CheckSum Generation + +#define MPTRCR_RST_TX (1 << 1) // Reset TX Memory Pointer +#define MPTRCR_RST_RX (1 << 0) // Reset RX Memory Pointer + +#define ISR_LNKCHGS (1 << 5) // Link Status Change +#define ISR_ROO (1 << 3) // Receive Overflow Counter Overflow +#define ISR_ROS (1 << 2) // Receive Overflow +#define ISR_PT (1 << 1) // Packet Transmitted +#define ISR_PR (1 << 0) // Packet Received +#define ISR_CLR_STATUS (ISR_LNKCHGS | ISR_ROO | ISR_ROS | ISR_PT | ISR_PR) + +#define IMR_PAR (1 << 7) // Pointer Auto-Return Mode +#define IMR_LNKCHGI (1 << 5) // Enable Link Status Change Interrupt +#define IMR_ROOI (1 << 3) // Enable Receive Overflow Counter Overflow Interrupt +#define IMR_ROI (1 << 2) // Enable Receive Overflow Interrupt +#define IMR_PTI (1 << 1) // Enable Packet Transmitted Interrupt +#define IMR_PRI (1 << 0) // Enable Packet Received Interrupt +#define IMR_ALL (IMR_PAR | IMR_LNKCHGI | IMR_ROOI | IMR_ROI | IMR_PTI | IMR_PRI) + +typedef struct { + uint8_t flag; + uint8_t status; + uint8_t length_low; + uint8_t length_high; +} dm9051_rx_header_t; + +typedef struct { + esp_eth_mac_t parent; + esp_eth_mediator_t *eth; + spi_device_handle_t spi_hdl; + SemaphoreHandle_t spi_lock; + TaskHandle_t rx_task_hdl; + uint32_t sw_reset_timeout_ms; + uint8_t addr[6]; + bool packets_remain; +} emac_dm9051_t; + +static inline bool dm9051_lock(emac_dm9051_t *emac) +{ + return xSemaphoreTake(emac->spi_lock, DM9051_SPI_LOCK_TIMEOUT_MS) == pdTRUE; +} + +static inline bool dm9051_unlock(emac_dm9051_t *emac) +{ + return xSemaphoreGive(emac->spi_lock) == pdTRUE; +} + +/** + * @brief write value to dm9051 internal register + */ +static esp_err_t dm9051_register_write(emac_dm9051_t *emac, uint8_t reg_addr, uint8_t value) +{ + esp_err_t ret = ESP_OK; + spi_transaction_t trans = { + .cmd = DM9051_SPI_WR, + .addr = reg_addr, + .length = 8, + .flags = SPI_TRANS_USE_TXDATA + }; + trans.tx_data[0] = value; + if (dm9051_lock(emac)) { + if (spi_device_polling_transmit(emac->spi_hdl, &trans) != ESP_OK) { + ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__); + ret = ESP_FAIL; + } + dm9051_unlock(emac); + } else { + ret = ESP_ERR_TIMEOUT; + } + return ret; +} + +/** + * @brief read value from dm9051 internal register + */ +static esp_err_t dm9051_register_read(emac_dm9051_t *emac, uint8_t reg_addr, uint8_t *value) +{ + esp_err_t ret = ESP_OK; + spi_transaction_t trans = { + .cmd = DM9051_SPI_RD, + .addr = reg_addr, + .length = 8, + .flags = SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA + }; + if (dm9051_lock(emac)) { + if (spi_device_polling_transmit(emac->spi_hdl, &trans) != ESP_OK) { + ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__); + ret = ESP_FAIL; + } else { + *value = trans.rx_data[0]; + } + dm9051_unlock(emac); + } else { + ret = ESP_ERR_TIMEOUT; + } + return ret; +} + +/** + * @brief write buffer to dm9051 internal memory + */ +static esp_err_t dm9051_memory_write(emac_dm9051_t *emac, uint8_t *buffer, uint32_t len) +{ + esp_err_t ret = ESP_OK; + spi_transaction_t trans = { + .cmd = DM9051_SPI_WR, + .addr = DM9051_MWCMD, + .length = len * 8, + .tx_buffer = buffer + }; + if (dm9051_lock(emac)) { + if (spi_device_polling_transmit(emac->spi_hdl, &trans) != ESP_OK) { + ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__); + ret = ESP_FAIL; + } + dm9051_unlock(emac); + } else { + ret = ESP_ERR_TIMEOUT; + } + return ret; +} + +/** + * @brief read buffer from dm9051 internal memory + */ +static esp_err_t dm9051_memory_read(emac_dm9051_t *emac, uint8_t *buffer, uint32_t len) +{ + esp_err_t ret = ESP_OK; + spi_transaction_t trans = { + .cmd = DM9051_SPI_RD, + .addr = DM9051_MRCMD, + .length = len * 8, + .rx_buffer = buffer + }; + if (dm9051_lock(emac)) { + if (spi_device_polling_transmit(emac->spi_hdl, &trans) != ESP_OK) { + ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__); + ret = ESP_FAIL; + } + dm9051_unlock(emac); + } else { + ret = ESP_ERR_TIMEOUT; + } + return ret; +} + +/** + * @brief read mac address from internal registers + */ +static esp_err_t dm9051_get_mac_addr(emac_dm9051_t *emac) +{ + esp_err_t ret = ESP_OK; + for (int i = 0; i < 6; i++) { + MAC_CHECK(dm9051_register_read(emac, DM9051_PAR + i, &emac->addr[i]) == ESP_OK, "read PAR failed", err, ESP_FAIL); + } + return ESP_OK; +err: + return ret; +} + +/** + * @brief set new mac address to internal registers + */ +static esp_err_t dm9051_set_mac_addr(emac_dm9051_t *emac) +{ + esp_err_t ret = ESP_OK; + for (int i = 0; i < 6; i++) { + MAC_CHECK(dm9051_register_write(emac, DM9051_PAR + i, emac->addr[i]) == ESP_OK, "write PAR failed", err, ESP_FAIL); + } + return ESP_OK; +err: + return ret; +} + +/** + * @brief clear multicast hash table + */ +static esp_err_t dm9051_clear_multicast_table(emac_dm9051_t *emac) +{ + esp_err_t ret = ESP_OK; + /* rx broadcast packet control by bit7 of MAC register 1DH */ + MAC_CHECK(dm9051_register_write(emac, DM9051_BCASTCR, 0x00) == ESP_OK, "write BCASTCR failed", err, ESP_FAIL); + for (int i = 0; i < 7; i++) { + MAC_CHECK(dm9051_register_write(emac, DM9051_MAR + i, 0x00) == ESP_OK, "write MAR failed", err, ESP_FAIL); + } + /* enable receive broadcast paclets */ + MAC_CHECK(dm9051_register_write(emac, DM9051_MAR + 7, 0x80) == ESP_OK, "write MAR failed", err, ESP_FAIL); + return ESP_OK; +err: + return ret; +} + +/** + * @brief software reset dm9051 internal register + */ +static esp_err_t dm9051_reset(emac_dm9051_t *emac) +{ + esp_err_t ret = ESP_OK; + /* power on phy */ + MAC_CHECK(dm9051_register_write(emac, DM9051_GPR, 0x00) == ESP_OK, "write GPR failed", err, ESP_FAIL); + /* mac and phy register won't be accesable within at least 1ms */ + vTaskDelay(pdMS_TO_TICKS(10)); + /* software reset */ + uint8_t ncr = NCR_RST; + MAC_CHECK(dm9051_register_write(emac, DM9051_NCR, ncr) == ESP_OK, "write NCR failed", err, ESP_FAIL); + uint32_t to = 0; + for (to = 0; to < emac->sw_reset_timeout_ms / 10; to++) { + MAC_CHECK(dm9051_register_read(emac, DM9051_NCR, &ncr) == ESP_OK, "read NCR failed", err, ESP_FAIL); + if (!(ncr & NCR_RST)) { + break; + } + vTaskDelay(pdMS_TO_TICKS(10)); + } + MAC_CHECK(to < emac->sw_reset_timeout_ms / 10, "reset timeout", err, ESP_ERR_TIMEOUT); + return ESP_OK; +err: + return ret; +} + +/** + * @brief verify dm9051 chip ID + */ +static esp_err_t dm9051_verify_id(emac_dm9051_t *emac) +{ + esp_err_t ret = ESP_OK; + uint8_t id[2]; + MAC_CHECK(dm9051_register_read(emac, DM9051_VIDL, &id[0]) == ESP_OK, "read VIDL failed", err, ESP_FAIL); + MAC_CHECK(dm9051_register_read(emac, DM9051_VIDH, &id[1]) == ESP_OK, "read VIDH failed", err, ESP_FAIL); + MAC_CHECK(0x0A46 == *(uint16_t *)id, "wrong Vendor ID", err, ESP_ERR_INVALID_VERSION); + MAC_CHECK(dm9051_register_read(emac, DM9051_PIDL, &id[0]) == ESP_OK, "read PIDL failed", err, ESP_FAIL); + MAC_CHECK(dm9051_register_read(emac, DM9051_PIDH, &id[1]) == ESP_OK, "read PIDH failed", err, ESP_FAIL); + MAC_CHECK(0x9051 == *(uint16_t *)id, "wrong Product ID", err, ESP_ERR_INVALID_VERSION); + return ESP_OK; +err: + return ret; +} + +/** + * @brief default setup for dm9051 internal registers + */ +static esp_err_t dm9051_setup_default(emac_dm9051_t *emac) +{ + esp_err_t ret = ESP_OK; + /* disable wakeup */ + MAC_CHECK(dm9051_register_write(emac, DM9051_NCR, 0x00) == ESP_OK, "write NCR failed", err, ESP_FAIL); + MAC_CHECK(dm9051_register_write(emac, DM9051_WCR, 0x00) == ESP_OK, "write WCR failed", err, ESP_FAIL); + /* stop transmitting, enable appending pad, crc for packets */ + MAC_CHECK(dm9051_register_write(emac, DM9051_TCR, 0x00) == ESP_OK, "write TCR failed", err, ESP_FAIL); + /* stop receiving, no promiscuous mode, no runt packet(size < 64bytes), not all multicast packets*/ + /* discard long packet(size > 1522bytes) and crc error packet, enable watchdog */ + MAC_CHECK(dm9051_register_write(emac, DM9051_RCR, RCR_DIS_LONG | RCR_DIS_CRC) == ESP_OK, "write RCR failed", err, ESP_FAIL); + /* send jam pattern (duration time = 1.15ms) when rx free space < 3k bytes */ + MAC_CHECK(dm9051_register_write(emac, DM9051_BPTR, 0x3F) == ESP_OK, "write BPTR failed", err, ESP_FAIL); + /* flow control: high water threshold = 3k bytes, low water threshold = 8k bytes */ + MAC_CHECK(dm9051_register_write(emac, DM9051_FCTR, 0x38) == ESP_OK, "write FCTR failed", err, ESP_FAIL); + /* enable flow control */ + MAC_CHECK(dm9051_register_write(emac, DM9051_FCR, FCR_FLOW_ENABLE) == ESP_OK, "write FCR failed", err, ESP_FAIL); + /* retry late collision packet, at most two transmit command can be issued before transmit complete */ + MAC_CHECK(dm9051_register_write(emac, DM9051_TCR2, TCR2_RLCP) == ESP_OK, "write TCR2 failed", err, ESP_FAIL); + /* enable auto transmit */ + MAC_CHECK(dm9051_register_write(emac, DM9051_ATCR, ATCR_AUTO_TX) == ESP_OK, "write ATCR failed", err, ESP_FAIL); + /* generate checksum for UDP, TCP and IPv4 packets */ + MAC_CHECK(dm9051_register_write(emac, DM9051_TCSCR, TCSCR_IPCSE | TCSCR_TCPCSE | TCSCR_UDPCSE) == ESP_OK, + "write TCSCR failed", err, ESP_FAIL); + /* disable check sum for receive packets */ + MAC_CHECK(dm9051_register_write(emac, DM9051_RCSCSR, 0x00) == ESP_OK, "write RCSCSR failed", err, ESP_FAIL); + /* interrupt pin config: push-pull output, active high */ + MAC_CHECK(dm9051_register_write(emac, DM9051_INTCR, 0x00) == ESP_OK, "write INTCR failed", err, ESP_FAIL); + MAC_CHECK(dm9051_register_write(emac, DM9051_INTCKCR, 0x00) == ESP_OK, "write INTCKCR failed", err, ESP_FAIL); + /* no length limitation for rx packets */ + MAC_CHECK(dm9051_register_write(emac, DM9051_RLENCR, 0x00) == ESP_OK, "write RLENCR failed", err, ESP_FAIL); + /* 3K-byte for TX and 13K-byte for RX */ + MAC_CHECK(dm9051_register_write(emac, DM9051_MEMSCR, 0x00) == ESP_OK, "write MEMSCR failed", err, ESP_FAIL); + /* reset tx and rx memory pointer */ + MAC_CHECK(dm9051_register_write(emac, DM9051_MPTRCR, MPTRCR_RST_RX | MPTRCR_RST_TX) == ESP_OK, + "write MPTRCR failed", err, ESP_FAIL); + /* clear network status: wakeup event, tx complete */ + MAC_CHECK(dm9051_register_write(emac, DM9051_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END) == ESP_OK, "write NSR failed", err, ESP_FAIL); + /* clear interrupt status */ + MAC_CHECK(dm9051_register_write(emac, DM9051_ISR, ISR_CLR_STATUS) == ESP_OK, "write ISR failed", err, ESP_FAIL); + return ESP_OK; +err: + return ret; +} + +/** + * @brief start dm9051: enable interrupt and start receive + */ +static esp_err_t dm9051_start(emac_dm9051_t *emac) +{ + esp_err_t ret = ESP_OK; + /* enable interrupt */ + MAC_CHECK(dm9051_register_write(emac, DM9051_IMR, IMR_ALL) == ESP_OK, "write IMR failed", err, ESP_FAIL); + /* enable rx */ + uint8_t rcr = 0; + MAC_CHECK(dm9051_register_read(emac, DM9051_RCR, &rcr) == ESP_OK, "read RCR failed", err, ESP_FAIL); + rcr |= RCR_RXEN; + MAC_CHECK(dm9051_register_write(emac, DM9051_RCR, rcr) == ESP_OK, "write RCR failed", err, ESP_FAIL); + return ESP_OK; +err: + return ret; +} + +/** + * @brief stop dm9051: disable interrupt and stop receive + */ +static esp_err_t dm9051_stop(emac_dm9051_t *emac) +{ + esp_err_t ret = ESP_OK; + /* disable interrupt */ + MAC_CHECK(dm9051_register_write(emac, DM9051_IMR, 0x00) == ESP_OK, "write IMR failed", err, ESP_FAIL); + /* disable rx */ + uint8_t rcr = 0; + MAC_CHECK(dm9051_register_read(emac, DM9051_RCR, &rcr) == ESP_OK, "read RCR failed", err, ESP_FAIL); + rcr &= ~RCR_RXEN; + MAC_CHECK(dm9051_register_write(emac, DM9051_RCR, rcr) == ESP_OK, "write RCR failed", err, ESP_FAIL); + return ESP_OK; +err: + return ret; +} + +static void dm9051_isr_handler(void *arg) +{ + emac_dm9051_t *emac = (emac_dm9051_t *)arg; + BaseType_t high_task_wakeup = pdFALSE; + /* notify dm9051 task */ + vTaskNotifyGiveFromISR(emac->rx_task_hdl, &high_task_wakeup); + if (high_task_wakeup != pdFALSE) { + portYIELD_FROM_ISR(); + } +} + +static void emac_dm9051_task(void *arg) +{ + emac_dm9051_t *emac = (emac_dm9051_t *)arg; + uint8_t status = 0; + uint8_t *buffer = NULL; + uint32_t length = 0; + while (1) { + if (ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(RX_QUEUE_WAIT_MS))) { + /* clear interrupt status */ + dm9051_register_read(emac, DM9051_ISR, &status); + dm9051_register_write(emac, DM9051_ISR, status); + /* packet received */ + if (status & ISR_PR) { + do { + buffer = (uint8_t *)heap_caps_malloc(ETH_MAX_PACKET_SIZE, MALLOC_CAP_DMA); + if (emac->parent.receive(&emac->parent, buffer, &length) == ESP_OK) { + /* pass the buffer to stack (e.g. TCP/IP layer) */ + emac->eth->stack_input(emac->eth, buffer, length); + } else { + free(buffer); + } + } while (emac->packets_remain); + } + } + } + vTaskDelete(NULL); +} + +static esp_err_t emac_dm9051_set_mediator(esp_eth_mac_t *mac, esp_eth_mediator_t *eth) +{ + esp_err_t ret = ESP_OK; + MAC_CHECK(eth, "can't set mac's mediator to null", err, ESP_ERR_INVALID_ARG); + emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent); + emac->eth = eth; + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_dm9051_write_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr, uint32_t phy_reg, uint32_t reg_value) +{ + esp_err_t ret = ESP_OK; + emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent); + /* check if phy access is in progress */ + uint8_t epcr = 0; + MAC_CHECK(dm9051_register_read(emac, DM9051_EPCR, &epcr) == ESP_OK, "read EPCR failed", err, ESP_FAIL); + MAC_CHECK(!(epcr & EPCR_ERRE), "phy is busy", err, ESP_ERR_INVALID_STATE); + MAC_CHECK(dm9051_register_write(emac, DM9051_EPAR, (uint8_t)(((phy_addr << 6) & 0xFF) | phy_reg)) == ESP_OK, + "write EPAR failed", err, ESP_FAIL); + MAC_CHECK(dm9051_register_write(emac, DM9051_EPDRL, (uint8_t)(reg_value & 0xFF)) == ESP_OK, + "write EPDRL failed", err, ESP_FAIL); + MAC_CHECK(dm9051_register_write(emac, DM9051_EPDRH, (uint8_t)((reg_value >> 8) & 0xFF)) == ESP_OK, + "write EPDRH failed", err, ESP_FAIL); + /* select PHY and select write operation */ + MAC_CHECK(dm9051_register_write(emac, DM9051_EPCR, EPCR_EPOS | EPCR_ERPRW) == ESP_OK, "write EPCR failed", err, ESP_FAIL); + /* polling the busy flag */ + uint32_t to = 0; + do { + ets_delay_us(100); + MAC_CHECK(dm9051_register_read(emac, DM9051_EPCR, &epcr) == ESP_OK, "read EPCR failed", err, ESP_FAIL); + to += 100; + } while ((epcr & EPCR_ERRE) && to < DM9051_PHY_OPERATION_TIMEOUT_US); + MAC_CHECK(!(epcr & EPCR_ERRE), "phy is busy", err, ESP_ERR_TIMEOUT); + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_dm9051_read_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr, uint32_t phy_reg, uint32_t *reg_value) +{ + esp_err_t ret = ESP_OK; + MAC_CHECK(reg_value, "can't set reg_value to null", err, ESP_ERR_INVALID_ARG); + emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent); + /* check if phy access is in progress */ + uint8_t epcr = 0; + MAC_CHECK(dm9051_register_read(emac, DM9051_EPCR, &epcr) == ESP_OK, "read EPCR failed", err, ESP_FAIL); + MAC_CHECK(!(epcr & 0x01), "phy is busy", err, ESP_ERR_INVALID_STATE); + MAC_CHECK(dm9051_register_write(emac, DM9051_EPAR, (uint8_t)(((phy_addr << 6) & 0xFF) | phy_reg)) == ESP_OK, + "write EPAR failed", err, ESP_FAIL); + /* Select PHY and select read operation */ + MAC_CHECK(dm9051_register_write(emac, DM9051_EPCR, 0x0C) == ESP_OK, "write EPCR failed", err, ESP_FAIL); + /* polling the busy flag */ + uint32_t to = 0; + do { + ets_delay_us(100); + MAC_CHECK(dm9051_register_read(emac, DM9051_EPCR, &epcr) == ESP_OK, "read EPCR failed", err, ESP_FAIL); + to += 100; + } while ((epcr & EPCR_ERRE) && to < DM9051_PHY_OPERATION_TIMEOUT_US); + MAC_CHECK(!(epcr & EPCR_ERRE), "phy is busy", err, ESP_ERR_TIMEOUT); + uint8_t value_h = 0; + uint8_t value_l = 0; + MAC_CHECK(dm9051_register_read(emac, DM9051_EPDRH, &value_h) == ESP_OK, "read EPDRH failed", err, ESP_FAIL); + MAC_CHECK(dm9051_register_read(emac, DM9051_EPDRL, &value_l) == ESP_OK, "read EPDRL failed", err, ESP_FAIL); + *reg_value = (value_h << 8) | value_l; + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_dm9051_set_addr(esp_eth_mac_t *mac, uint8_t *addr) +{ + esp_err_t ret = ESP_OK; + MAC_CHECK(addr, "can't set mac addr to null", err, ESP_ERR_INVALID_ARG); + emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent); + memcpy(emac->addr, addr, 6); + MAC_CHECK(dm9051_set_mac_addr(emac) == ESP_OK, "set mac address failed", err, ESP_FAIL); + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_dm9051_get_addr(esp_eth_mac_t *mac, uint8_t *addr) +{ + esp_err_t ret = ESP_OK; + MAC_CHECK(addr, "can't set mac addr to null", err, ESP_ERR_INVALID_ARG); + emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent); + memcpy(addr, emac->addr, 6); + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_dm9051_set_link(esp_eth_mac_t *mac, eth_link_t link) +{ + esp_err_t ret = ESP_OK; + emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent); + uint8_t nsr = 0; + MAC_CHECK(dm9051_register_read(emac, DM9051_NSR, &nsr) == ESP_OK, "read NSR failed", err, ESP_FAIL); + switch (link) { + case ETH_LINK_UP: + MAC_CHECK(nsr & NSR_LINKST, "phy is not link up", err, ESP_ERR_INVALID_STATE); + MAC_CHECK(dm9051_start(emac) == ESP_OK, "dm9051 start failed", err, ESP_FAIL); + break; + case ETH_LINK_DOWN: + MAC_CHECK(!(nsr & NSR_LINKST), "phy is not link down", err, ESP_ERR_INVALID_STATE); + MAC_CHECK(dm9051_stop(emac) == ESP_OK, "dm9051 stop failed", err, ESP_FAIL); + break; + default: + MAC_CHECK(false, "unknown link status", err, ESP_ERR_INVALID_ARG); + break; + } + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_dm9051_set_speed(esp_eth_mac_t *mac, eth_speed_t speed) +{ + esp_err_t ret = ESP_OK; + emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent); + uint8_t nsr = 0; + MAC_CHECK(dm9051_register_read(emac, DM9051_NSR, &nsr) == ESP_OK, "read NSR failed", err, ESP_FAIL); + switch (speed) { + case ETH_SPEED_10M: + MAC_CHECK(nsr & NSR_SPEED, "phy speed is not at 10Mbps", err, ESP_ERR_INVALID_STATE); + break; + case ETH_SPEED_100M: + MAC_CHECK(!(nsr & NSR_SPEED), "phy speed is not at 100Mbps", err, ESP_ERR_INVALID_STATE); + break; + default: + MAC_CHECK(false, "unknown speed", err, ESP_ERR_INVALID_ARG); + break; + } + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_dm9051_set_duplex(esp_eth_mac_t *mac, eth_duplex_t duplex) +{ + esp_err_t ret = ESP_OK; + emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent); + uint8_t ncr = 0; + MAC_CHECK(dm9051_register_read(emac, DM9051_NCR, &ncr) == ESP_OK, "read NCR failed", err, ESP_FAIL); + switch (duplex) { + case ETH_DUPLEX_HALF: + MAC_CHECK(!(ncr & NCR_FDX), "phy is not at half duplex", err, ESP_ERR_INVALID_STATE); + break; + case ETH_DUPLEX_FULL: + MAC_CHECK(ncr & NCR_FDX, "phy is not at full duplex", err, ESP_ERR_INVALID_STATE); + break; + default: + MAC_CHECK(false, "unknown duplex", err, ESP_ERR_INVALID_ARG); + break; + } + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_dm9051_set_promiscuous(esp_eth_mac_t *mac, bool enable) +{ + esp_err_t ret = ESP_OK; + emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent); + uint8_t rcr = 0; + MAC_CHECK(dm9051_register_read(emac, DM9051_EPDRL, &rcr) == ESP_OK, "read RCR failed", err, ESP_FAIL); + if (enable) { + rcr |= RCR_PRMSC; + } else { + rcr &= ~RCR_PRMSC; + } + MAC_CHECK(dm9051_register_write(emac, DM9051_RCR, rcr) == ESP_OK, "write RCR failed", err, ESP_FAIL); + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_dm9051_transmit(esp_eth_mac_t *mac, uint8_t *buf, uint32_t length) +{ + esp_err_t ret = ESP_OK; + emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent); + MAC_CHECK(buf, "can't set buf to null", err, ESP_ERR_INVALID_ARG); + MAC_CHECK(length, "buf length can't be zero", err, ESP_ERR_INVALID_ARG); + /* Check if last transmit complete */ + uint8_t tcr = 0; + MAC_CHECK(dm9051_register_read(emac, DM9051_TCR, &tcr) == ESP_OK, "read TCR failed", err, ESP_FAIL); + MAC_CHECK(!(tcr & TCR_TXREQ), "last transmit still in progress", err, ESP_ERR_INVALID_STATE); + /* set tx length */ + MAC_CHECK(dm9051_register_write(emac, DM9051_TXPLL, length & 0xFF) == ESP_OK, "write TXPLL failed", err, ESP_FAIL); + MAC_CHECK(dm9051_register_write(emac, DM9051_TXPLH, (length >> 8) & 0xFF) == ESP_OK, "write TXPLH failed", err, ESP_FAIL); + /* copy data to tx memory */ + MAC_CHECK(dm9051_memory_write(emac, buf, length) == ESP_OK, "write memory failed", err, ESP_FAIL); + /* issue tx polling command */ + tcr |= TCR_TXREQ; + MAC_CHECK(dm9051_register_write(emac, DM9051_TCR, tcr) == ESP_OK, "write TCR failed", err, ESP_FAIL); + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_dm9051_receive(esp_eth_mac_t *mac, uint8_t *buf, uint32_t *length) +{ + esp_err_t ret = ESP_OK; + emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent); + MAC_CHECK(buf && length, "can't set buf and length to null", err, ESP_ERR_INVALID_ARG); + uint8_t rxbyte = 0; + uint16_t rx_len = 0; + __attribute__((aligned(4))) dm9051_rx_header_t header; // SPI driver needs the rx buffer 4 byte align + emac->packets_remain = false; + /* dummy read, get the most updated data */ + MAC_CHECK(dm9051_register_read(emac, DM9051_MRCMDX, &rxbyte) == ESP_OK, "read MRCMDX failed", err, ESP_FAIL); + MAC_CHECK(dm9051_register_read(emac, DM9051_MRCMDX, &rxbyte) == ESP_OK, "read MRCMDX failed", err, ESP_FAIL); + /* rxbyte must be 0xFF, 0 or 1 */ + if (rxbyte > 1) { + MAC_CHECK(dm9051_stop(emac) == ESP_OK, "stop dm9051 failed", err, ESP_FAIL); + /* reset rx fifo pointer */ + MAC_CHECK(dm9051_register_write(emac, DM9051_MPTRCR, MPTRCR_RST_RX) == ESP_OK, "write MPTRCR failed", err, ESP_FAIL); + ets_delay_us(10); + MAC_CHECK(dm9051_start(emac) == ESP_OK, "start dm9051 failed", err, ESP_FAIL); + MAC_CHECK(false, "reset rx fifo pointer", err, ESP_FAIL); + } else if (rxbyte) { + MAC_CHECK(dm9051_memory_read(emac, (uint8_t *)&header, sizeof(header)) == ESP_OK, "read rx header failed", err, ESP_FAIL); + rx_len = header.length_low + (header.length_high << 8); + MAC_CHECK(dm9051_memory_read(emac, buf, rx_len) == ESP_OK, "read rx data failed", err, ESP_FAIL); + MAC_CHECK(!(header.status & 0xBF), "receive status error: %xH", err, ESP_FAIL, header.status); + *length = rx_len - 4; // substract the CRC length (4Bytes) + /* dummy read, get the most updated data */ + MAC_CHECK(dm9051_register_read(emac, DM9051_MRCMDX, &rxbyte) == ESP_OK, "read MRCMDX failed", err, ESP_FAIL); + MAC_CHECK(dm9051_register_read(emac, DM9051_MRCMDX, &rxbyte) == ESP_OK, "read MRCMDX failed", err, ESP_FAIL); + emac->packets_remain = rxbyte > 0; + } + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_dm9051_init(esp_eth_mac_t *mac) +{ + esp_err_t ret = ESP_OK; + emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent); + esp_eth_mediator_t *eth = emac->eth; + /* init gpio used by spi-ethernet interrupt */ + gpio_pad_select_gpio(CONFIG_ETH_DM9051_INT_GPIO); + gpio_set_direction(CONFIG_ETH_DM9051_INT_GPIO, GPIO_MODE_INPUT); + gpio_set_pull_mode(CONFIG_ETH_DM9051_INT_GPIO, GPIO_PULLDOWN_ONLY); + gpio_set_intr_type(CONFIG_ETH_DM9051_INT_GPIO, GPIO_INTR_POSEDGE); + gpio_intr_enable(CONFIG_ETH_DM9051_INT_GPIO); + gpio_isr_handler_add(CONFIG_ETH_DM9051_INT_GPIO, dm9051_isr_handler, emac); + MAC_CHECK(eth->on_state_changed(eth, ETH_STATE_LLINIT, NULL) == ESP_OK, "lowlevel init failed", err, ESP_FAIL); + /* reset dm9051 */ + MAC_CHECK(dm9051_reset(emac) == ESP_OK, "reset dm9051 failed", err, ESP_FAIL); + /* verify chip id */ + MAC_CHECK(dm9051_verify_id(emac) == ESP_OK, "vefiry chip ID failed", err, ESP_FAIL); + /* default setup of internal registers */ + MAC_CHECK(dm9051_setup_default(emac) == ESP_OK, "dm9051 default setup failed", err, ESP_FAIL); + /* clear multicast hash table */ + MAC_CHECK(dm9051_clear_multicast_table(emac) == ESP_OK, "clear multicast table failed", err, ESP_FAIL); + /* get emac address from eeprom */ + MAC_CHECK(dm9051_get_mac_addr(emac) == ESP_OK, "fetch ethernet mac address failed", err, ESP_FAIL); + return ESP_OK; +err: + gpio_isr_handler_remove(CONFIG_ETH_DM9051_INT_GPIO); + gpio_reset_pin(CONFIG_ETH_DM9051_INT_GPIO); + eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL); + return ret; +} + +static esp_err_t emac_dm9051_deinit(esp_eth_mac_t *mac) +{ + emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent); + esp_eth_mediator_t *eth = emac->eth; + dm9051_stop(emac); + gpio_isr_handler_remove(CONFIG_ETH_DM9051_INT_GPIO); + gpio_reset_pin(CONFIG_ETH_DM9051_INT_GPIO); + eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL); + return ESP_OK; +} + +static esp_err_t emac_dm9051_del(esp_eth_mac_t *mac) +{ + emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent); + vTaskDelete(emac->rx_task_hdl); + vSemaphoreDelete(emac->spi_lock); + free(emac); + return ESP_OK; +} + +esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_mac_config_t *config) +{ + esp_eth_mac_t *ret = NULL; + MAC_CHECK(config, "can't set mac config to null", err, NULL); + MAC_CHECK(config->spi_hdl, "can't set spi handle to null", err, NULL); + emac_dm9051_t *emac = calloc(1, sizeof(emac_dm9051_t)); + MAC_CHECK(emac, "calloc emac failed", err, NULL); + /* bind methods and attributes */ + emac->sw_reset_timeout_ms = config->sw_reset_timeout_ms; + emac->spi_hdl = config->spi_hdl; + emac->parent.set_mediator = emac_dm9051_set_mediator; + emac->parent.init = emac_dm9051_init; + emac->parent.deinit = emac_dm9051_deinit; + emac->parent.del = emac_dm9051_del; + emac->parent.write_phy_reg = emac_dm9051_write_phy_reg; + emac->parent.read_phy_reg = emac_dm9051_read_phy_reg; + emac->parent.set_addr = emac_dm9051_set_addr; + emac->parent.get_addr = emac_dm9051_get_addr; + emac->parent.set_speed = emac_dm9051_set_speed; + emac->parent.set_duplex = emac_dm9051_set_duplex; + emac->parent.set_link = emac_dm9051_set_link; + emac->parent.set_promiscuous = emac_dm9051_set_promiscuous; + emac->parent.transmit = emac_dm9051_transmit; + emac->parent.receive = emac_dm9051_receive; + /* create mutex */ + emac->spi_lock = xSemaphoreCreateMutex(); + MAC_CHECK(emac->spi_lock, "create lock failed", err_lock, NULL); + /* create dm9051 task */ + BaseType_t xReturned = xTaskCreate(emac_dm9051_task, "dm9051_tsk", config->rx_task_stack_size, emac, + config->rx_task_prio, &emac->rx_task_hdl); + MAC_CHECK(xReturned == pdPASS, "create dm9051 task failed", err_tsk, NULL); + return &(emac->parent); +err_tsk: + vSemaphoreDelete(emac->spi_lock); +err_lock: + free(emac); +err: + return ret; +} diff --git a/components/esp_eth/src/esp_eth_mac_esp32.c b/components/esp_eth/src/esp_eth_mac_esp32.c new file mode 100644 index 0000000000..cea8868a3b --- /dev/null +++ b/components/esp_eth/src/esp_eth_mac_esp32.c @@ -0,0 +1,468 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include +#include +#include +#include "driver/periph_ctrl.h" +#include "driver/gpio.h" +#include "esp_log.h" +#include "esp_eth.h" +#include "esp_system.h" +#include "esp_heap_caps.h" +#include "esp_intr_alloc.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "hal/emac.h" +#include "soc/soc.h" +#include "sdkconfig.h" + +static const char *TAG = "emac_esp32"; +#define MAC_CHECK(a, str, goto_tag, ret_value, ...) \ + do \ + { \ + if (!(a)) \ + { \ + ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ + ret = ret_value; \ + goto goto_tag; \ + } \ + } while (0) + +#define RX_QUEUE_WAIT_MS (20) +#define PHY_OPERATION_TIMEOUT_US (1000) + +typedef struct { + esp_eth_mac_t parent; + esp_eth_mediator_t *eth; + emac_hal_context_t hal; + intr_handle_t intr_hdl; + SemaphoreHandle_t rx_counting_sem; + TaskHandle_t rx_task_hdl; + uint32_t sw_reset_timeout_ms; + uint32_t frames_remain; + uint8_t addr[6]; + uint8_t *rx_buf[CONFIG_ETH_DMA_RX_BUFFER_NUM]; + uint8_t *tx_buf[CONFIG_ETH_DMA_TX_BUFFER_NUM]; + bool isr_need_yield; +} emac_esp32_t; + +static esp_err_t emac_esp32_set_mediator(esp_eth_mac_t *mac, esp_eth_mediator_t *eth) +{ + esp_err_t ret = ESP_OK; + MAC_CHECK(eth, "can't set mac's mediator to null", err, ESP_ERR_INVALID_ARG); + emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); + emac->eth = eth; + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_esp32_write_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr, uint32_t phy_reg, uint32_t reg_value) +{ + esp_err_t ret = ESP_OK; + emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); + MAC_CHECK(!emac_hal_is_mii_busy(&emac->hal), "phy is busy", err, ESP_ERR_INVALID_STATE); + emac_hal_set_phy_data(&emac->hal, reg_value); + emac_hal_set_phy_cmd(&emac->hal, phy_addr, phy_reg, true); + /* polling the busy flag */ + uint32_t to = 0; + bool busy = true; + do { + ets_delay_us(100); + busy = emac_hal_is_mii_busy(&emac->hal); + to += 100; + } while (busy && to < PHY_OPERATION_TIMEOUT_US); + MAC_CHECK(!busy, "phy is busy", err, ESP_ERR_TIMEOUT); + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_esp32_read_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr, uint32_t phy_reg, uint32_t *reg_value) +{ + esp_err_t ret = ESP_OK; + MAC_CHECK(reg_value, "can't set reg_value to null", err, ESP_ERR_INVALID_ARG); + emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); + MAC_CHECK(!emac_hal_is_mii_busy(&emac->hal), "phy is busy", err, ESP_ERR_INVALID_STATE); + emac_hal_set_phy_cmd(&emac->hal, phy_addr, phy_reg, false); + /* polling the busy flag */ + uint32_t to = 0; + bool busy = true; + do { + ets_delay_us(100); + busy = emac_hal_is_mii_busy(&emac->hal); + to += 100; + } while (busy && to < PHY_OPERATION_TIMEOUT_US); + MAC_CHECK(!busy, "phy is busy", err, ESP_ERR_TIMEOUT); + /* Store value */ + *reg_value = emac_hal_get_phy_data(&emac->hal); + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_esp32_set_addr(esp_eth_mac_t *mac, uint8_t *addr) +{ + esp_err_t ret = ESP_OK; + MAC_CHECK(addr, "can't set mac addr to null", err, ESP_ERR_INVALID_ARG); + emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); + memcpy(emac->addr, addr, 6); + emac_hal_set_address(&emac->hal, emac->addr); + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_esp32_get_addr(esp_eth_mac_t *mac, uint8_t *addr) +{ + esp_err_t ret = ESP_OK; + MAC_CHECK(addr, "can't set mac addr to null", err, ESP_ERR_INVALID_ARG); + emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); + memcpy(addr, emac->addr, 6); + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_esp32_set_link(esp_eth_mac_t *mac, eth_link_t link) +{ + esp_err_t ret = ESP_OK; + emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); + switch (link) { + case ETH_LINK_UP: + MAC_CHECK(esp_intr_enable(emac->intr_hdl) == ESP_OK, "enable interrupt failed", err, ESP_FAIL); + emac_hal_start(&emac->hal); + break; + case ETH_LINK_DOWN: + MAC_CHECK(esp_intr_disable(emac->intr_hdl) == ESP_OK, "disable interrupt failed", err, ESP_FAIL); + emac_hal_stop(&emac->hal); + break; + default: + MAC_CHECK(false, "unknown link status", err, ESP_ERR_INVALID_ARG); + break; + } + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_esp32_set_speed(esp_eth_mac_t *mac, eth_speed_t speed) +{ + esp_err_t ret = ESP_OK; + emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); + switch (speed) { + case ETH_SPEED_10M: + emac_hal_set_speed(&emac->hal, EMAC_SPEED_10M); + break; + case ETH_SPEED_100M: + emac_hal_set_speed(&emac->hal, EMAC_SPEED_100M); + break; + default: + MAC_CHECK(false, "unknown speed", err, ESP_ERR_INVALID_ARG); + break; + } + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_esp32_set_duplex(esp_eth_mac_t *mac, eth_duplex_t duplex) +{ + esp_err_t ret = ESP_OK; + emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); + switch (duplex) { + case ETH_DUPLEX_HALF: + emac_hal_set_duplex(&emac->hal, EMAC_DUPLEX_HALF); + break; + case ETH_DUPLEX_FULL: + emac_hal_set_duplex(&emac->hal, EMAC_DUPLEX_FULL); + break; + default: + MAC_CHECK(false, "unknown duplex", err, ESP_ERR_INVALID_ARG); + break; + } + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_esp32_set_promiscuous(esp_eth_mac_t *mac, bool enable) +{ + emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); + emac_hal_set_promiscuous(&emac->hal, enable); + return ESP_OK; +} + +static esp_err_t emac_esp32_transmit(esp_eth_mac_t *mac, uint8_t *buf, uint32_t length) +{ + esp_err_t ret = ESP_OK; + emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); + MAC_CHECK(buf, "can't set buf to null", err, ESP_ERR_INVALID_ARG); + MAC_CHECK(length, "buf length can't be zero", err, ESP_ERR_INVALID_ARG); + /* Check if the descriptor is owned by the Ethernet DMA (when 1) or CPU (when 0) */ + MAC_CHECK(emac_hal_get_tx_desc_owner(&emac->hal) == EMAC_DMADESC_OWNER_CPU, + "CPU doesn't own the Tx Descriptor", err, ESP_ERR_INVALID_STATE); + emac_hal_transmit_frame(&emac->hal, buf, length); + return ESP_OK; +err: + return ret; +} + +static esp_err_t emac_esp32_receive(esp_eth_mac_t *mac, uint8_t *buf, uint32_t *length) +{ + esp_err_t ret = ESP_OK; + emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); + MAC_CHECK(buf && length, "can't set buf and length to null", err, ESP_ERR_INVALID_ARG); + *length = emac_hal_receive_frame(&emac->hal, buf, &emac->frames_remain); + return ESP_OK; +err: + return ret; +} + +static void emac_esp32_rx_task(void *arg) +{ + emac_esp32_t *emac = (emac_esp32_t *)arg; + uint8_t *buffer = NULL; + uint32_t length = 0; + while (1) { + if (xSemaphoreTake(emac->rx_counting_sem, pdMS_TO_TICKS(RX_QUEUE_WAIT_MS)) == pdTRUE) { + buffer = (uint8_t *)malloc(ETH_MAX_PACKET_SIZE); + if (emac_esp32_receive(&emac->parent, buffer, &length) == ESP_OK) { + /* pass the buffer to stack (e.g. TCP/IP layer) */ + emac->eth->stack_input(emac->eth, buffer, length); + } else { + free(buffer); + } + } + /* there might be some frames left in DMA buffer */ + else if (emac->frames_remain) { + xSemaphoreGive(emac->rx_counting_sem); + } + } + vTaskDelete(NULL); +} + +static void emac_esp32_init_smi_gpio(void) +{ + /* Setup SMI MDC GPIO */ + gpio_set_direction(CONFIG_ETH_SMI_MDC_GPIO, GPIO_MODE_OUTPUT); + gpio_matrix_out(CONFIG_ETH_SMI_MDC_GPIO, EMAC_MDC_O_IDX, false, false); + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[CONFIG_ETH_SMI_MDC_GPIO], PIN_FUNC_GPIO); + /* Setup SMI MDIO GPIO */ + gpio_set_direction(CONFIG_ETH_SMI_MDIO_GPIO, GPIO_MODE_INPUT_OUTPUT); + gpio_matrix_out(CONFIG_ETH_SMI_MDIO_GPIO, EMAC_MDO_O_IDX, false, false); + gpio_matrix_in(CONFIG_ETH_SMI_MDIO_GPIO, EMAC_MDI_I_IDX, false); + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[CONFIG_ETH_SMI_MDIO_GPIO], PIN_FUNC_GPIO); +} + +static esp_err_t emac_esp32_init(esp_eth_mac_t *mac) +{ + esp_err_t ret = ESP_OK; + emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); + esp_eth_mediator_t *eth = emac->eth; + /* enable peripheral clock */ + periph_module_enable(PERIPH_EMAC_MODULE); + /* enable clock, config gpio, etc */ + emac_hal_lowlevel_init(&emac->hal); + /* init gpio used by gpio */ + emac_esp32_init_smi_gpio(); +#if CONFIG_ETH_PHY_USE_RST + gpio_pad_select_gpio(CONFIG_ETH_PHY_RST_GPIO); + gpio_set_direction(CONFIG_ETH_PHY_RST_GPIO, GPIO_MODE_OUTPUT); + gpio_set_level(CONFIG_ETH_PHY_RST_GPIO, 1); +#endif + MAC_CHECK(eth->on_state_changed(eth, ETH_STATE_LLINIT, NULL) == ESP_OK, "lowlevel init failed", err, ESP_FAIL); + /* software reset */ + emac_hal_reset(&emac->hal); + uint32_t to = 0; + for (to = 0; to < emac->sw_reset_timeout_ms / 10; to++) { + if (emac_hal_is_reset_done(&emac->hal)) { + break; + } + vTaskDelay(pdMS_TO_TICKS(10)); + } + MAC_CHECK(to < emac->sw_reset_timeout_ms / 10, "reset timeout", err, ESP_ERR_TIMEOUT); + /* set smi clock */ + emac_hal_set_csr_clock_range(&emac->hal); + /* reset descriptor chain */ + emac_hal_reset_desc_chain(&emac->hal); + /* init mac registers by default */ + emac_hal_init_mac_default(&emac->hal); + /* init dma registers by default */ + emac_hal_init_dma_default(&emac->hal); + /* get emac address from efuse */ + MAC_CHECK(esp_read_mac(emac->addr, ESP_MAC_ETH) == ESP_OK, "fetch ethernet mac address failed", err, ESP_FAIL); + /* set MAC address to emac register */ + emac_hal_set_address(&emac->hal, emac->addr); + return ESP_OK; +err: + eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL); + periph_module_disable(PERIPH_EMAC_MODULE); + return ret; +} + +static esp_err_t emac_esp32_deinit(esp_eth_mac_t *mac) +{ + emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); + esp_eth_mediator_t *eth = emac->eth; +#if CONFIG_ETH_PHY_USE_RST + gpio_set_level(CONFIG_ETH_PHY_RST_GPIO, 0); +#endif + emac_hal_stop(&emac->hal); + eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL); + periph_module_disable(PERIPH_EMAC_MODULE); + return ESP_OK; +} + +static esp_err_t emac_esp32_del(esp_eth_mac_t *mac) +{ + emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); + esp_intr_free(emac->intr_hdl); + vTaskDelete(emac->rx_task_hdl); + vSemaphoreDelete(emac->rx_counting_sem); + int i = 0; + for (i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) { + free(emac->hal.rx_buf[i]); + } + for (i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) { + free(emac->hal.tx_buf[i]); + } + free(emac->hal.descriptors); + free(emac); + return ESP_OK; +} + +void emac_esp32_isr_handler(void *args) +{ + emac_hal_context_t *hal = (emac_hal_context_t *)args; + emac_esp32_t *emac = __containerof(hal, emac_esp32_t, hal); + emac_hal_isr(args); + if (emac->isr_need_yield) { + emac->isr_need_yield = false; + portYIELD_FROM_ISR(); + } +} + +esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config) +{ + esp_eth_mac_t *ret = NULL; + MAC_CHECK(config, "can't set mac config to null", err, NULL); + emac_esp32_t *emac = calloc(1, sizeof(emac_esp32_t)); + MAC_CHECK(emac, "calloc emac failed", err, NULL); + /* alloc memory for ethernet dma descriptor */ + uint32_t desc_size = CONFIG_ETH_DMA_RX_BUFFER_NUM * sizeof(eth_dma_rx_descriptor_t) + + CONFIG_ETH_DMA_TX_BUFFER_NUM * sizeof(eth_dma_tx_descriptor_t); + void *descriptors = heap_caps_calloc(1, desc_size, MALLOC_CAP_DMA); + MAC_CHECK(descriptors, "calloc descriptors failed", err_desc, NULL); + int i = 0; + /* alloc memory for ethernet dma buffer */ + for (i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) { + emac->rx_buf[i] = heap_caps_calloc(1, CONFIG_ETH_DMA_BUFFER_SIZE, MALLOC_CAP_DMA); + if (!(emac->rx_buf[i])) { + break; + } + } + if (i != CONFIG_ETH_DMA_RX_BUFFER_NUM) { + for (--i; i >= 0; i--) { + free(emac->rx_buf[i]); + } + goto err_buffer; + } + for (i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) { + emac->tx_buf[i] = heap_caps_calloc(1, CONFIG_ETH_DMA_BUFFER_SIZE, MALLOC_CAP_DMA); + if (!(emac->tx_buf[i])) { + break; + } + } + if (i != CONFIG_ETH_DMA_TX_BUFFER_NUM) { + for (--i; i >= 0; i--) { + free(emac->tx_buf[i]); + } + for (i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) { + free(emac->rx_buf[i]); + } + goto err_buffer; + } + /* initialize hal layer driver */ + emac_hal_init(&emac->hal, descriptors, emac->rx_buf, emac->tx_buf); + emac->sw_reset_timeout_ms = config->sw_reset_timeout_ms; + emac->parent.set_mediator = emac_esp32_set_mediator; + emac->parent.init = emac_esp32_init; + emac->parent.deinit = emac_esp32_deinit; + emac->parent.del = emac_esp32_del; + emac->parent.write_phy_reg = emac_esp32_write_phy_reg; + emac->parent.read_phy_reg = emac_esp32_read_phy_reg; + emac->parent.set_addr = emac_esp32_set_addr; + emac->parent.get_addr = emac_esp32_get_addr; + emac->parent.set_speed = emac_esp32_set_speed; + emac->parent.set_duplex = emac_esp32_set_duplex; + emac->parent.set_link = emac_esp32_set_link; + emac->parent.set_promiscuous = emac_esp32_set_promiscuous; + emac->parent.transmit = emac_esp32_transmit; + emac->parent.receive = emac_esp32_receive; + /* Interrupt configuration */ + MAC_CHECK(esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, ESP_INTR_FLAG_IRAM, emac_esp32_isr_handler, + &emac->hal, &(emac->intr_hdl)) == ESP_OK, + "alloc emac interrupt failed", err_intr, NULL); + /* create counting semaphore */ + emac->rx_counting_sem = xSemaphoreCreateCounting(config->queue_len, 0); + MAC_CHECK(emac->rx_counting_sem, "create semaphore failed", err_sem, NULL); + /* create rx task */ + BaseType_t xReturned = xTaskCreate(emac_esp32_rx_task, "emac_rx", config->rx_task_stack_size, emac, + config->rx_task_prio, &emac->rx_task_hdl); + MAC_CHECK(xReturned == pdPASS, "create emac_rx task failed", err_task, NULL); + return &(emac->parent); +err_task: + vSemaphoreDelete(emac->rx_counting_sem); +err_sem: + esp_intr_free(emac->intr_hdl); +err_intr: + for (int i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) { + free(emac->tx_buf[i]); + } + for (int i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) { + free(emac->rx_buf[i]); + } +err_buffer: + free(descriptors); +err_desc: + free(emac); +err: + return ret; +} + +void emac_hal_rx_complete_cb(void *arg) +{ + emac_hal_context_t *hal = (emac_hal_context_t *)arg; + emac_esp32_t *emac = __containerof(hal, emac_esp32_t, hal); + BaseType_t high_task_wakeup; + /* send message to rx thread */ + xSemaphoreGiveFromISR(emac->rx_counting_sem, &high_task_wakeup); + if (high_task_wakeup == pdTRUE) { + emac->isr_need_yield = true; + } +} + +void emac_hal_rx_unavail_cb(void *arg) +{ + emac_hal_context_t *hal = (emac_hal_context_t *)arg; + emac_esp32_t *emac = __containerof(hal, emac_esp32_t, hal); + BaseType_t high_task_wakeup; + /* send message to rx thread */ + xSemaphoreGiveFromISR(emac->rx_counting_sem, &high_task_wakeup); + if (high_task_wakeup == pdTRUE) { + emac->isr_need_yield = true; + } +} diff --git a/components/esp_eth/src/esp_eth_phy_dm9051.c b/components/esp_eth/src/esp_eth_phy_dm9051.c new file mode 100644 index 0000000000..cb658c181d --- /dev/null +++ b/components/esp_eth/src/esp_eth_phy_dm9051.c @@ -0,0 +1,302 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include +#include +#include +#include "esp_log.h" +#include "esp_eth.h" +#include "eth_phy_regs_struct.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +static const char *TAG = "dm9051"; +#define PHY_CHECK(a, str, goto_tag, ...) \ + do \ + { \ + if (!(a)) \ + { \ + ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ + goto goto_tag; \ + } \ + } while (0) + +/***************Vendor Specific Register***************/ + +/** + * @brief DSCR(DAVICOM Specified Configuration Register) + * + */ +typedef union { + struct { + uint32_t reserved1 : 1; /* Reserved */ + uint32_t sleep : 1; /* Set 1 to enable PHY into sleep mode */ + uint32_t mfpsc : 1; /* MII frame preamble suppression control bit */ + uint32_t smrst : 1; /* Set 1 to reset all state machines of PHY */ + uint32_t rpdctr_en : 1; /* Set 1 to enable automatic reduced power down */ + uint32_t reserved2 : 2; /* Reserved */ + uint32_t flink100 : 1; /* Force Good Link in 100Mbps */ + uint32_t reserved3 : 2; /* Reserved */ + uint32_t tx_fx : 1; /* 100BASE-TX or FX Mode Control */ + uint32_t reserved4 : 1; /* Reserved */ + uint32_t bp_adpok : 1; /* BYPASS ADPOK */ + uint32_t bp_align : 1; /* Bypass Symbol Alignment Function */ + uint32_t bp_scr : 1; /* Bypass Scrambler/Descrambler Function */ + uint32_t bp_4b5b : 1; /* Bypass 4B5B Encoding and 5B4B Decoding */ + }; + uint32_t val; +} dscr_reg_t; +#define ETH_PHY_DSCR_REG_ADDR (0x10) + +/** + * @brief DSCSR(DAVICOM Specified Configuration and Status Register) + * + */ +typedef union { + struct { + uint32_t anmb : 4; /* Auto-Negotiation Monitor Bits */ + uint32_t phy_addr : 5; /* PHY Address */ + uint32_t reserved : 3; /* Reserved */ + uint32_t hdx10 : 1; /* 10M Half-Duplex Operation Mode */ + uint32_t fdx10 : 1; /* 10M Full-Duplex Operation Mode */ + uint32_t hdx100 : 1; /* 100M Half-Duplex Operation Mode */ + uint32_t fdx100 : 1; /* 100M Full-Duplex Operation Mode */ + }; + uint32_t val; +} dscsr_reg_t; +#define ETH_PHY_DSCSR_REG_ADDR (0x11) + +typedef struct { + esp_eth_phy_t parent; + esp_eth_mediator_t *eth; + const char *name; + uint32_t addr; + uint32_t reset_timeout_ms; + uint32_t autonego_timeout_ms; + eth_link_t link_status; +} phy_dm9051_t; + +static esp_err_t dm9051_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth) +{ + PHY_CHECK(eth, "can't set mediator for dm9051 to null", err); + phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); + dm9051->eth = eth; + return ESP_OK; +err: + return ESP_ERR_INVALID_ARG; +} + +static esp_err_t dm9051_get_link(esp_eth_phy_t *phy) +{ + phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); + esp_eth_mediator_t *eth = dm9051->eth; + bmsr_reg_t bmsr; + + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); + eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; + if (dm9051->link_status != link) { + if (link == ETH_LINK_UP) { + phy->negotiate(phy); + } else { + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err); + dm9051->link_status = link; + } + } + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t dm9051_reset(esp_eth_phy_t *phy) +{ + phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); + esp_eth_mediator_t *eth = dm9051->eth; + dscr_reg_t dscr; + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, &(dscr.val)) == ESP_OK, "read DSCR failed", err); + dscr.smrst = 1; + PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, dscr.val) == ESP_OK, "write DSCR failed", err); + bmcr_reg_t bmcr = {.reset = 1}; + PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); + /* Wait for reset complete */ + uint32_t to = 0; + for (to = 0; to < dm9051->reset_timeout_ms / 10; to++) { + vTaskDelay(pdMS_TO_TICKS(10)); + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, &(dscr.val)) == ESP_OK, "read DSCR failed", err); + if (!bmcr.reset && !dscr.smrst) { + break; + } + } + PHY_CHECK(to < dm9051->reset_timeout_ms / 10, "PHY reset timeout", err); + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t dm9051_negotiate(esp_eth_phy_t *phy) +{ + phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); + esp_eth_mediator_t *eth = dm9051->eth; + /* Start auto negotiation */ + bmcr_reg_t bmcr = { + .speed_select = 1, /* 100Mbps */ + .duplex_mode = 1, /* Full Duplex */ + .en_auto_nego = 1, /* Auto Negotiation */ + .restart_auto_nego = 1 /* Restart Auto Negotiation */ + }; + PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); + /* Wait for auto negotiation complete */ + bmsr_reg_t bmsr; + dscsr_reg_t dscsr; + uint32_t to = 0; + for (to = 0; to < dm9051->autonego_timeout_ms / 10; to++) { + vTaskDelay(pdMS_TO_TICKS(10)); + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCSR_REG_ADDR, &(dscsr.val)) == ESP_OK, "read DSCSR failed", err); + if (bmsr.auto_nego_complete && dscsr.anmb & 0x08) { + break; + } + } + if (to >= dm9051->autonego_timeout_ms / 10) { + ESP_LOGW(TAG, "Ethernet PHY auto negotiation timeout"); + } + /* Updata information about link, speed, duplex */ + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCSR_REG_ADDR, &(dscsr.val)) == ESP_OK, "read DSCSR failed", err); + eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; + eth_speed_t speed = ETH_SPEED_10M; + eth_duplex_t duplex = ETH_DUPLEX_HALF; + if (dscsr.fdx100 || dscsr.hdx100) { + speed = ETH_SPEED_100M; + } else { + speed = ETH_SPEED_10M; + } + if (dscsr.fdx100 || dscsr.fdx10) { + duplex = ETH_DUPLEX_FULL; + } else { + duplex = ETH_DUPLEX_HALF; + } + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, "send speed event failed", err); + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, "send duplex event failed", err); + if (dm9051->link_status != link) { + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err); + dm9051->link_status = link; + } + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t dm9051_pwrctl(esp_eth_phy_t *phy, bool enable) +{ + phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); + esp_eth_mediator_t *eth = dm9051->eth; + bmcr_reg_t bmcr; + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + if (!enable) { + /* Enable IEEE Power Down Mode */ + bmcr.power_down = 1; + } else { + /* Disable IEEE Power Down Mode */ + bmcr.power_down = 0; + } + PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + if (!enable) { + PHY_CHECK(bmcr.power_down == 1, "power down failed", err); + } else { + PHY_CHECK(bmcr.power_down == 0, "power up failed", err); + } + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t dm9051_set_addr(esp_eth_phy_t *phy, uint32_t addr) +{ + phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); + dm9051->addr = addr; + return ESP_OK; +} + +static esp_err_t dm9051_get_addr(esp_eth_phy_t *phy, uint32_t *addr) +{ + PHY_CHECK(addr, "get phy address failed", err); + phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); + *addr = dm9051->addr; + return ESP_OK; +err: + return ESP_ERR_INVALID_ARG; +} + +static esp_err_t dm9051_del(esp_eth_phy_t *phy) +{ + phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); + free(dm9051); + return ESP_OK; +} + +static esp_err_t dm9051_init(esp_eth_phy_t *phy) +{ + phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); + esp_eth_mediator_t *eth = dm9051->eth; + /* Power on Ethernet PHY */ + PHY_CHECK(dm9051_pwrctl(phy, true) == ESP_OK, "power on Ethernet PHY failed", err); + /* Reset Ethernet PHY */ + PHY_CHECK(dm9051_reset(phy) == ESP_OK, "reset Ethernet PHY failed", err); + /* Check PHY ID */ + phyidr1_reg_t id1; + phyidr2_reg_t id2; + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, "read ID1 failed", err); + PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, "read ID2 failed", err); + PHY_CHECK(id1.oui_msb == 0x0181 && id2.oui_lsb == 0x2E && id2.vendor_model == 0x0A, "wrong PHY chip ID", err); + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t dm9051_deinit(esp_eth_phy_t *phy) +{ + /* Power off Ethernet PHY */ + PHY_CHECK(dm9051_pwrctl(phy, false) == ESP_OK, "power off Ethernet PHY failed", err); + return ESP_OK; +err: + return ESP_FAIL; +} + +esp_eth_phy_t *esp_eth_phy_new_dm9051(const eth_phy_config_t *config) +{ + PHY_CHECK(config, "can't set phy config to null", err); + PHY_CHECK(config->phy_addr == 1, "dm9051's phy address can only set to 1", err); + phy_dm9051_t *dm9051 = calloc(1, sizeof(phy_dm9051_t)); + PHY_CHECK(dm9051, "calloc dm9051 object failed", err); + dm9051->name = "dm9051"; + dm9051->addr = config->phy_addr; + dm9051->reset_timeout_ms = config->reset_timeout_ms; + dm9051->link_status = ETH_LINK_DOWN; + dm9051->autonego_timeout_ms = config->autonego_timeout_ms; + dm9051->parent.reset = dm9051_reset; + dm9051->parent.init = dm9051_init; + dm9051->parent.deinit = dm9051_deinit; + dm9051->parent.set_mediator = dm9051_set_mediator; + dm9051->parent.negotiate = dm9051_negotiate; + dm9051->parent.get_link = dm9051_get_link; + dm9051->parent.pwrctl = dm9051_pwrctl; + dm9051->parent.get_addr = dm9051_get_addr; + dm9051->parent.set_addr = dm9051_set_addr; + dm9051->parent.del = dm9051_del; + + return &(dm9051->parent); +err: + return NULL; +} diff --git a/components/esp_eth/src/esp_eth_phy_dp83848.c b/components/esp_eth/src/esp_eth_phy_dp83848.c new file mode 100644 index 0000000000..ac76f7a99c --- /dev/null +++ b/components/esp_eth/src/esp_eth_phy_dp83848.c @@ -0,0 +1,303 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include +#include +#include +#include "esp_log.h" +#include "esp_eth.h" +#include "eth_phy_regs_struct.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +static const char *TAG = "dp83848"; +#define PHY_CHECK(a, str, goto_tag, ...) \ + do \ + { \ + if (!(a)) \ + { \ + ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ + goto goto_tag; \ + } \ + } while (0) + +/***************Vendor Specific Register***************/ + +/** + * @brief PHYSTS(PHY Status Register) + * + */ +typedef union { + struct { + uint32_t link_status : 1; /* Link Status */ + uint32_t speed_status : 1; /* Link Status */ + uint32_t duplex_status : 1; /* Duplex Status */ + uint32_t loopback_status : 1; /* MII Loopback */ + uint32_t auto_nego_complete : 1; /* Auto-Negotiation Complete */ + uint32_t jabber_detect : 1; /* Jabber Detect */ + uint32_t remote_fault : 1; /* Remote Fault */ + uint32_t mii_interrupt : 1; /* MII Interrupt Pending */ + uint32_t page_received : 1; /* Link Code Word Page Received */ + uint32_t descrambler_lock : 1; /* Descrambler Lock */ + uint32_t signal_detect : 1; /* Signal Detect */ + uint32_t false_carrier_sense_latch : 1; /* False Carrier Sense Latch */ + uint32_t polarity_status : 1; /* Polarity Status */ + uint32_t receive_error_latch : 1; /* Receive Error Latch */ + uint32_t mdix_mode : 1; /* MDI-X mode reported by auto-negotiation */ + uint32_t reserved : 1; /* Reserved */ + }; + uint32_t val; +} physts_reg_t; +#define ETH_PHY_STS_REG_ADDR (0x10) + +/** + * @brief PHYCR(PHY Control Register) + * + */ +typedef union { + struct { + uint32_t phy_addr : 5; /* PHY Address */ + uint32_t led_cfg : 2; /* LED Configuration Modes */ + uint32_t bypass_led_stretching : 1; /* Bypass LED Stretching */ + uint32_t bist_start : 1; /* BIST Start */ + uint32_t bist_status : 1; /* BIST Test Status */ + uint32_t psr_15 : 1; /* BIST Sequence select */ + uint32_t bist_force_error : 1; /* BIST Force Error */ + uint32_t pause_trans_negotiate : 1; /* Pause Transmit Negotiated Status */ + uint32_t pause_receive_negotiat : 1; /* Pause Receive Negotiated Status */ + uint32_t force_mdix : 1; /* Force MDIX */ + uint32_t en_auto_mdix : 1; /* Auto-MDIX Enable */ + }; + uint32_t val; +} phycr_reg_t; +#define ETH_PHY_CR_REG_ADDR (0x19) + +typedef struct { + esp_eth_phy_t parent; + esp_eth_mediator_t *eth; + const char *name; + uint32_t addr; + uint32_t reset_timeout_ms; + uint32_t autonego_timeout_ms; + eth_link_t link_status; +} phy_dp83848_t; + +static esp_err_t dp83848_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth) +{ + PHY_CHECK(eth, "can't set mediator for dp83848 to null", err); + phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent); + dp83848->eth = eth; + return ESP_OK; +err: + return ESP_ERR_INVALID_ARG; +} + +static esp_err_t dp83848_get_link(esp_eth_phy_t *phy) +{ + phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent); + esp_eth_mediator_t *eth = dp83848->eth; + bmsr_reg_t bmsr; + + PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); + eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; + if (dp83848->link_status != link) { + if (link == ETH_LINK_UP) { + phy->negotiate(phy); + } else { + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err); + dp83848->link_status = link; + } + } + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t dp83848_reset(esp_eth_phy_t *phy) +{ + phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent); + esp_eth_mediator_t *eth = dp83848->eth; + bmcr_reg_t bmcr = {.reset = 1}; + PHY_CHECK(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); + /* Wait for reset complete */ + uint32_t to = 0; + for (to = 0; to < dp83848->reset_timeout_ms / 10; to++) { + vTaskDelay(pdMS_TO_TICKS(10)); + PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + if (!bmcr.reset) { + break; + } + } + PHY_CHECK(to < dp83848->reset_timeout_ms / 10, "PHY reset timeout", err); + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t dp83848_negotiate(esp_eth_phy_t *phy) +{ + phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent); + esp_eth_mediator_t *eth = dp83848->eth; + /* Start auto negotiation */ + bmcr_reg_t bmcr = { + .speed_select = 1, /* 100Mbps */ + .duplex_mode = 1, /* Full Duplex */ + .en_auto_nego = 1, /* Auto Negotiation */ + .restart_auto_nego = 1 /* Restart Auto Negotiation */ + }; + PHY_CHECK(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); + /* Wait for auto negotiation complete */ + bmsr_reg_t bmsr; + physts_reg_t physts; + uint32_t to = 0; + for (to = 0; to < dp83848->autonego_timeout_ms / 10; to++) { + vTaskDelay(pdMS_TO_TICKS(10)); + PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_STS_REG_ADDR, &(physts.val)) == ESP_OK, "read PHYSTS failed", err); + if (bmsr.auto_nego_complete && physts.auto_nego_complete) { + break; + } + } + /* Auto negotiation failed, maybe no network cable plugged in, so output a warning */ + if (to >= dp83848->autonego_timeout_ms / 10) { + ESP_LOGW(TAG, "Ethernet PHY auto negotiation timeout"); + } + /* Updata information about link, speed, duplex */ + PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_STS_REG_ADDR, &(physts.val)) == ESP_OK, "read PHYSTS failed", err); + eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; + eth_speed_t speed = ETH_SPEED_10M; + eth_duplex_t duplex = ETH_DUPLEX_HALF; + if (physts.speed_status) { + speed = ETH_SPEED_10M; + } else { + speed = ETH_SPEED_100M; + } + if (physts.duplex_status) { + duplex = ETH_DUPLEX_FULL; + } else { + duplex = ETH_DUPLEX_HALF; + } + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, "send speed event failed", err); + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, "send duplex event failed", err); + if (dp83848->link_status != link) { + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err); + dp83848->link_status = link; + } + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t dp83848_pwrctl(esp_eth_phy_t *phy, bool enable) +{ + phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent); + esp_eth_mediator_t *eth = dp83848->eth; + bmcr_reg_t bmcr; + PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + if (!enable) { + /* Enable IEEE Power Down Mode */ + bmcr.power_down = 1; + } else { + /* Disable IEEE Power Down Mode */ + bmcr.power_down = 0; + } + PHY_CHECK(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + if (!enable) { + PHY_CHECK(bmcr.power_down == 1, "power down failed", err); + } else { + PHY_CHECK(bmcr.power_down == 0, "power up failed", err); + } + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t dp83848_set_addr(esp_eth_phy_t *phy, uint32_t addr) +{ + phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent); + dp83848->addr = addr; + return ESP_OK; +} + +static esp_err_t dp83848_get_addr(esp_eth_phy_t *phy, uint32_t *addr) +{ + PHY_CHECK(addr, "get phy address failed", err); + phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent); + *addr = dp83848->addr; + return ESP_OK; +err: + return ESP_ERR_INVALID_ARG; +} + +static esp_err_t dp83848_del(esp_eth_phy_t *phy) +{ + phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent); + free(dp83848); + return ESP_OK; +} + +static esp_err_t dp83848_init(esp_eth_phy_t *phy) +{ + phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent); + esp_eth_mediator_t *eth = dp83848->eth; + /* Power on Ethernet PHY */ + PHY_CHECK(dp83848_pwrctl(phy, true) == ESP_OK, "power on Ethernet PHY failed", err); + /* Reset Ethernet PHY */ + PHY_CHECK(dp83848_reset(phy) == ESP_OK, "reset Ethernet PHY failed", err); + /* Check PHY ID */ + phyidr1_reg_t id1; + phyidr2_reg_t id2; + PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, "read ID1 failed", err); + PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, "read ID2 failed", err); + PHY_CHECK(id1.oui_msb == 0x2000 && id2.oui_lsb == 0x17 && id2.vendor_model == 0x09, "wrong PHY chip ID", err); + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t dp83848_deinit(esp_eth_phy_t *phy) +{ + /* Power off Ethernet PHY */ + PHY_CHECK(dp83848_pwrctl(phy, false) == ESP_OK, "power off Ethernet PHY failed", err); + return ESP_OK; +err: + return ESP_FAIL; +} + +esp_eth_phy_t *esp_eth_phy_new_dp83848(const eth_phy_config_t *config) +{ + PHY_CHECK(config, "can't set phy config to null", err); + phy_dp83848_t *dp83848 = calloc(1, sizeof(phy_dp83848_t)); + PHY_CHECK(dp83848, "calloc dp83848 object failed", err); + dp83848->name = "dp83848"; + dp83848->addr = config->phy_addr; + dp83848->reset_timeout_ms = config->reset_timeout_ms; + dp83848->link_status = ETH_LINK_DOWN; + dp83848->autonego_timeout_ms = config->autonego_timeout_ms; + dp83848->parent.reset = dp83848_reset; + dp83848->parent.init = dp83848_init; + dp83848->parent.deinit = dp83848_deinit; + dp83848->parent.set_mediator = dp83848_set_mediator; + dp83848->parent.negotiate = dp83848_negotiate; + dp83848->parent.get_link = dp83848_get_link; + dp83848->parent.pwrctl = dp83848_pwrctl; + dp83848->parent.get_addr = dp83848_get_addr; + dp83848->parent.set_addr = dp83848_set_addr; + dp83848->parent.del = dp83848_del; + + return &(dp83848->parent); +err: + return NULL; +} diff --git a/components/esp_eth/src/esp_eth_phy_ip101.c b/components/esp_eth/src/esp_eth_phy_ip101.c new file mode 100644 index 0000000000..e5dfd55557 --- /dev/null +++ b/components/esp_eth/src/esp_eth_phy_ip101.c @@ -0,0 +1,345 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include +#include +#include +#include "esp_log.h" +#include "esp_eth.h" +#include "eth_phy_regs_struct.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +static const char *TAG = "ip101"; +#define PHY_CHECK(a, str, goto_tag, ...) \ + do \ + { \ + if (!(a)) \ + { \ + ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ + goto goto_tag; \ + } \ + } while (0) + +/***************Vendor Specific Register***************/ + +/** + * @brief PCR(Page Control Register) + * + */ +typedef union { + struct { + uint32_t register_page_select : 5; /* Select register page, default is 16 */ + uint32_t reserved : 11; /* Reserved */ + }; + uint32_t val; +} pcr_reg_t; +#define ETH_PHY_PCR_REG_ADDR (0x14) + +/** + * @brief ISR(Interrupt Status Register), Page 16 + * + */ +typedef union { + struct { + uint32_t link_changed : 1; /* Flag to indicate link status change interrupt */ + uint32_t duplex_changed : 1; /* Flag to indicate duplex change interrupt */ + uint32_t speed_changed : 1; /* Flag to indicate speed change interrupt */ + uint32_t intr_status : 1; /* Flag to indicate interrupt status */ + uint32_t reserved1 : 4; /* Reserved */ + uint32_t link_mask : 1; /* Mask link change interrupt */ + uint32_t duplex_mask : 1; /* Mask duplex change interrupt */ + uint32_t speed_mask : 1; /* Mask speed change interrupt */ + uint32_t all_mask : 1; /* Mask all interrupt */ + uint32_t reserved2 : 3; /* Reserved */ + uint32_t use_intr_pin : 1; /* Set high to use INTR and INTR_32 as an interrupt pin */ + }; + uint32_t val; +} isr_reg_t; +#define ETH_PHY_ISR_REG_ADDR (0x11) + +/** + * @brief PHY MDI/MDIX Control and Specific Status Register, Page 16 + * + */ +typedef union { + struct { + uint32_t op_mode : 3; /* Operation Mode Idicator */ + uint32_t force_mdix : 1; /* Force the MDIX channel to be selected */ + uint32_t reserved1 : 4; /* Reserved */ + uint32_t link_up : 1; /* Indicate the link status is OK or FAIL */ + uint32_t reserved2 : 7; /* Reserved */ + }; + uint32_t val; +} cssr_reg_t; +#define ETH_PHY_CSSR_REG_ADDR (0x1E) + +/** + * @brief PSCR(PHY Specific Control Register), Page 1 + * + */ +typedef union { + struct { + uint32_t reserved1 : 7; /* Reserved */ + uint32_t force_link_100 : 1; /* Force Link 100 */ + uint32_t force_link_10 : 1; /* Force Link 10 */ + uint32_t reserved2 : 7; /* Reserved */ + }; + uint32_t val; +} pscr_reg_t; +#define ETH_PHY_PSCR_REG_ADDR (0x11) + +typedef struct { + esp_eth_phy_t parent; + esp_eth_mediator_t *eth; + const char *name; + uint32_t addr; + uint32_t reset_timeout_ms; + uint32_t autonego_timeout_ms; + eth_link_t link_status; +} phy_ip101_t; + +static esp_err_t ip101_page_select(phy_ip101_t *ip101, uint32_t page) +{ + esp_eth_mediator_t *eth = ip101->eth; + pcr_reg_t pcr = { + .register_page_select = page + }; + PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_PCR_REG_ADDR, pcr.val) == ESP_OK, "write PCR failed", err); + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t ip101_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth) +{ + PHY_CHECK(eth, "can't set mediator for ip101 to null", err); + phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent); + ip101->eth = eth; + return ESP_OK; +err: + return ESP_ERR_INVALID_ARG; +} + +static esp_err_t ip101_get_link(esp_eth_phy_t *phy) +{ + phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent); + esp_eth_mediator_t *eth = ip101->eth; + bmsr_reg_t bmsr; + + PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); + eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; + if (ip101->link_status != link) { + if (link == ETH_LINK_UP) { + phy->negotiate(phy); + } else { + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err); + ip101->link_status = link; + } + } + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t ip101_reset(esp_eth_phy_t *phy) +{ + phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent); + esp_eth_mediator_t *eth = ip101->eth; + bmcr_reg_t bmcr = {.reset = 1}; + PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); + /* wait for reset complete */ + uint32_t to = 0; + for (to = 0; to < ip101->reset_timeout_ms / 10; to++) { + vTaskDelay(pdMS_TO_TICKS(10)); + PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + if (!bmcr.reset) { + break; + } + } + PHY_CHECK(to < ip101->reset_timeout_ms / 10, "PHY reset timeout", err); + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t ip101_negotiate(esp_eth_phy_t *phy) +{ + phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent); + esp_eth_mediator_t *eth = ip101->eth; + /* Start auto negotiation */ + bmcr_reg_t bmcr = { + .speed_select = 1, /* 100Mbps */ + .duplex_mode = 1, /* Full Duplex */ + .en_auto_nego = 1, /* Auto Negotiation */ + .restart_auto_nego = 1 /* Restart Auto Negotiation */ + }; + PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); + /* Wait for auto negotiation complete */ + bmsr_reg_t bmsr; + uint32_t to = 0; + for (to = 0; to < ip101->autonego_timeout_ms / 10; to++) { + vTaskDelay(pdMS_TO_TICKS(10)); + PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); + if (bmsr.auto_nego_complete) { + break; + } + } + /* Auto negotiation failed, maybe no network cable plugged in, so output a warning */ + if (to >= ip101->autonego_timeout_ms / 10) { + ESP_LOGW(TAG, "Ethernet PHY auto negotiation timeout"); + } + PHY_CHECK(ip101_page_select(ip101, 16) == ESP_OK, "select page failed", err); + /* Updata information about link, speed, duplex */ + cssr_reg_t cssr; + PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_CSSR_REG_ADDR, &(cssr.val)) == ESP_OK, "read CSSR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); + eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; + eth_speed_t speed = ETH_SPEED_10M; + eth_duplex_t duplex = ETH_DUPLEX_HALF; + switch (cssr.op_mode) { + case 0: //Link off + link = ETH_LINK_DOWN; + break; + case 1: //10M Half + speed = ETH_SPEED_10M; + duplex = ETH_DUPLEX_HALF; + break; + case 2: //100M Half + speed = ETH_SPEED_100M; + duplex = ETH_DUPLEX_HALF; + break; + case 5: //10M Full + speed = ETH_SPEED_10M; + duplex = ETH_DUPLEX_FULL; + break; + case 6: //100M Full + speed = ETH_SPEED_100M; + duplex = ETH_DUPLEX_FULL; + break; + default: + break; + } + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, "send speed event failed", err); + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, "send duplex event failed", err); + if (ip101->link_status != link) { + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err); + ip101->link_status = link; + } + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t ip101_pwrctl(esp_eth_phy_t *phy, bool enable) +{ + phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent); + esp_eth_mediator_t *eth = ip101->eth; + bmcr_reg_t bmcr; + PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + if (!enable) { + /* Enable IEEE Power Down Mode */ + bmcr.power_down = 1; + } else { + /* Disable IEEE Power Down Mode */ + bmcr.power_down = 0; + } + PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + if (!enable) { + PHY_CHECK(bmcr.power_down == 1, "power down failed", err); + } else { + PHY_CHECK(bmcr.power_down == 0, "power up failed", err); + } + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t ip101_set_addr(esp_eth_phy_t *phy, uint32_t addr) +{ + phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent); + ip101->addr = addr; + return ESP_OK; +} + +static esp_err_t ip101_get_addr(esp_eth_phy_t *phy, uint32_t *addr) +{ + PHY_CHECK(addr, "get phy address failed", err); + phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent); + *addr = ip101->addr; + return ESP_OK; +err: + return ESP_ERR_INVALID_ARG; +} + +static esp_err_t ip101_del(esp_eth_phy_t *phy) +{ + phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent); + free(ip101); + return ESP_OK; +} + +static esp_err_t ip101_init(esp_eth_phy_t *phy) +{ + phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent); + esp_eth_mediator_t *eth = ip101->eth; + /* Power on Ethernet PHY */ + PHY_CHECK(ip101_pwrctl(phy, true) == ESP_OK, "power on Ethernet PHY failed", err); + /* Reset Ethernet PHY */ + PHY_CHECK(ip101_reset(phy) == ESP_OK, "reset Ethernet PHY failed", err); + /* Check PHY ID */ + phyidr1_reg_t id1; + phyidr2_reg_t id2; + PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, "read ID1 failed", err); + PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, "read ID2 failed", err); + PHY_CHECK(id1.oui_msb == 0x243 && id2.oui_lsb == 0x3 && id2.vendor_model == 0x5, "wrong PHY chip ID", err); + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t ip101_deinit(esp_eth_phy_t *phy) +{ + /* Power off Ethernet PHY */ + PHY_CHECK(ip101_pwrctl(phy, false) == ESP_OK, "power off Ethernet PHY failed", err); + return ESP_OK; +err: + return ESP_FAIL; +} + +esp_eth_phy_t *esp_eth_phy_new_ip101(const eth_phy_config_t *config) +{ + PHY_CHECK(config, "can't set phy config to null", err); + phy_ip101_t *ip101 = calloc(1, sizeof(phy_ip101_t)); + PHY_CHECK(ip101, "calloc ip101 object failed", err); + ip101->name = "ip101"; + ip101->addr = config->phy_addr; + ip101->reset_timeout_ms = config->reset_timeout_ms; + ip101->link_status = ETH_LINK_DOWN; + ip101->autonego_timeout_ms = config->autonego_timeout_ms; + ip101->parent.reset = ip101_reset; + ip101->parent.init = ip101_init; + ip101->parent.deinit = ip101_deinit; + ip101->parent.set_mediator = ip101_set_mediator; + ip101->parent.negotiate = ip101_negotiate; + ip101->parent.get_link = ip101_get_link; + ip101->parent.pwrctl = ip101_pwrctl; + ip101->parent.get_addr = ip101_get_addr; + ip101->parent.set_addr = ip101_set_addr; + ip101->parent.del = ip101_del; + + return &(ip101->parent); +err: + return NULL; +} diff --git a/components/esp_eth/src/esp_eth_phy_lan8720.c b/components/esp_eth/src/esp_eth_phy_lan8720.c new file mode 100644 index 0000000000..8cbcd11298 --- /dev/null +++ b/components/esp_eth/src/esp_eth_phy_lan8720.c @@ -0,0 +1,385 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include +#include +#include +#include "esp_log.h" +#include "esp_eth.h" +#include "eth_phy_regs_struct.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +static const char *TAG = "lan8720"; +#define PHY_CHECK(a, str, goto_tag, ...) \ + do \ + { \ + if (!(a)) \ + { \ + ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ + goto goto_tag; \ + } \ + } while (0) + +/***************Vendor Specific Register***************/ + +/** + * @brief MCSR(Mode Control Status Register) + * + */ +typedef union { + struct { + uint32_t reserved1 : 1; /* Reserved */ + uint32_t energy_is_on : 1; /* Energy is On */ + uint32_t reserved2 : 4; /* Reserved */ + uint32_t en_alternate_interrupt : 1; /* Enable Alternate Interrupt Mode */ + uint32_t reserved3 : 2; /* Reserved */ + uint32_t en_far_loopback : 1; /* Enable Far Loopback Mode */ + uint32_t reserved4 : 3; /* Reserved */ + uint32_t en_energy_detect_powerdown : 1; /* Enable Energy Detect Power Down */ + uint32_t reserved5 : 2; /* Reserved */ + }; + uint32_t val; +} mcsr_reg_t; +#define ETH_PHY_MCSR_REG_ADDR (0x11) + +/** + * @brief SMR(Special Modes Register) + * + */ +typedef union { + struct { + uint32_t phy_addr : 5; /* PHY Address */ + uint32_t mode : 3; /* Transceiver Mode of Operation */ + uint32_t reserved : 8; /* Reserved */ + }; + uint32_t val; +} smr_reg_t; +#define ETH_PHY_SMR_REG_ADDR (0x12) + +/** + * @brief SECR(Symbol Error Counter Register) + * + */ +typedef union { + struct { + uint32_t symbol_err_count : 16; /* Symbol Error Counter */ + }; + uint32_t val; +} secr_reg_t; +#define EHT_PHY_SECR_REG_ADDR (0x1A) + +/** + * @brief CSIR(Control Status Indications Register) + * + */ +typedef union { + struct { + uint32_t reserved1 : 4; /* Reserved */ + uint32_t base10_t_polarity : 1; /* Polarity State of 10Base-T */ + uint32_t reserved2 : 6; /* Reserved */ + uint32_t dis_sqe : 1; /* Disable SQE test(Heartbeat) */ + uint32_t reserved3 : 1; /* Reserved */ + uint32_t select_channel : 1; /* Manual channel select:MDI(0) or MDIX(1) */ + uint32_t reserved4 : 1; /* Reserved */ + uint32_t auto_mdix_ctrl : 1; /* Auto-MDIX Control: EN(0) or DE(1) */ + }; + uint32_t val; +} scsir_reg_t; +#define ETH_PHY_CSIR_REG_ADDR (0x1B) + +/** + * @brief ISR(Interrupt Source Register) + * + */ +typedef union { + struct { + uint32_t reserved1 : 1; /* Reserved */ + uint32_t auto_nego_page_received : 1; /* Auto-Negotiation Page Received */ + uint32_t parallel_detect_falut : 1; /* Parallel Detection Fault */ + uint32_t auto_nego_lp_acknowledge : 1; /* Auto-Negotiation LP Acknowledge */ + uint32_t link_down : 1; /* Link Down */ + uint32_t remote_fault_detect : 1; /* Remote Fault Detect */ + uint32_t auto_nego_complete : 1; /* Auto-Negotiation Complete */ + uint32_t energy_on_generate : 1; /* ENERYON generated */ + uint32_t reserved2 : 8; /* Reserved */ + }; + uint32_t val; +} isfr_reg_t; +#define ETH_PHY_ISR_REG_ADDR (0x1D) + +/** + * @brief IMR(Interrupt Mask Register) + * + */ +typedef union { + struct { + uint32_t reserved1 : 1; /* Reserved */ + uint32_t auto_nego_page_received : 1; /* Auto-Negotiation Page Received */ + uint32_t parallel_detect_falut : 1; /* Parallel Detection Fault */ + uint32_t auto_nego_lp_acknowledge : 1; /* Auto-Negotiation LP Acknowledge */ + uint32_t link_down : 1; /* Link Down */ + uint32_t remote_fault_detect : 1; /* Remote Fault Detect */ + uint32_t auto_nego_complete : 1; /* Auto-Negotiation Complete */ + uint32_t energy_on_generate : 1; /* ENERYON generated */ + uint32_t reserved2 : 8; /* Reserved */ + }; + uint32_t val; +} imr_reg_t; +#define ETH_PHY_IMR_REG_ADDR (0x1E) + +/** + * @brief PSCSR(PHY Special Control Status Register) + * + */ +typedef union { + struct { + uint32_t reserved1 : 2; /* Reserved */ + uint32_t speed_indication : 3; /* Speed Indication */ + uint32_t reserved2 : 7; /* Reserved */ + uint32_t auto_nego_done : 1; /* Auto Negotiation Done */ + uint32_t reserved3 : 3; /* Reserved */ + }; + uint32_t val; +} pscsr_reg_t; +#define ETH_PHY_PSCSR_REG_ADDR (0x1F) + +typedef struct { + esp_eth_phy_t parent; + esp_eth_mediator_t *eth; + const char *name; + uint32_t addr; + uint32_t reset_timeout_ms; + uint32_t autonego_timeout_ms; + eth_link_t link_status; +} phy_lan8720_t; + +static esp_err_t lan8720_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth) +{ + PHY_CHECK(eth, "can't set mediator for lan8720 to null", err); + phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent); + lan8720->eth = eth; + return ESP_OK; +err: + return ESP_ERR_INVALID_ARG; +} + +static esp_err_t lan8720_get_link(esp_eth_phy_t *phy) +{ + phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent); + esp_eth_mediator_t *eth = lan8720->eth; + bmsr_reg_t bmsr; + + PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); + eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; + if (lan8720->link_status != link) { + if (link == ETH_LINK_UP) { + phy->negotiate(phy); + } else { + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err); + lan8720->link_status = link; + } + } + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t lan8720_reset(esp_eth_phy_t *phy) +{ + phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent); + esp_eth_mediator_t *eth = lan8720->eth; + bmcr_reg_t bmcr = {.reset = 1}; + PHY_CHECK(eth->phy_reg_write(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); + /* wait for reset complete */ + uint32_t to = 0; + for (to = 0; to < lan8720->reset_timeout_ms / 10; to++) { + vTaskDelay(pdMS_TO_TICKS(10)); + PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + if (!bmcr.reset) { + break; + } + } + PHY_CHECK(to < lan8720->reset_timeout_ms / 10, "PHY reset timeout", err); + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t lan8720_negotiate(esp_eth_phy_t *phy) +{ + phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent); + esp_eth_mediator_t *eth = lan8720->eth; + /* Start auto negotiation */ + bmcr_reg_t bmcr = { + .speed_select = 1, /* 100Mbps */ + .duplex_mode = 1, /* Full Duplex */ + .en_auto_nego = 1, /* Auto Negotiation */ + .restart_auto_nego = 1 /* Restart Auto Negotiation */ + }; + PHY_CHECK(eth->phy_reg_write(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); + /* Wait for auto negotiation complete */ + bmsr_reg_t bmsr; + pscsr_reg_t pscsr; + int32_t to = 0; + for (to = 0; to < lan8720->autonego_timeout_ms / 10; to++) { + vTaskDelay(pdMS_TO_TICKS(10)); + PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_PSCSR_REG_ADDR, &(pscsr.val)) == ESP_OK, "read PSCSR failed", err); + if (bmsr.auto_nego_complete && pscsr.auto_nego_done) { + break; + } + } + /* Auto negotiation failed, maybe no network cable plugged in, so output a warning */ + if (to >= lan8720->autonego_timeout_ms / 10) { + ESP_LOGW(TAG, "Ethernet PHY auto negotiation timeout"); + } + /* Updata information about link, speed, duplex */ + PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_PSCSR_REG_ADDR, &(pscsr.val)) == ESP_OK, "read PSCSR failed", err); + eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; + eth_speed_t speed = ETH_SPEED_10M; + eth_duplex_t duplex = ETH_DUPLEX_HALF; + switch (pscsr.speed_indication) { + case 1: //10Base-T half-duplex + speed = ETH_SPEED_10M; + duplex = ETH_DUPLEX_HALF; + break; + case 2: //100Base-TX half-duplex + speed = ETH_SPEED_100M; + duplex = ETH_DUPLEX_HALF; + break; + case 5: //10Base-T full-duplex + speed = ETH_SPEED_10M; + duplex = ETH_DUPLEX_FULL; + break; + case 6: //100Base-TX full-duplex + speed = ETH_SPEED_100M; + duplex = ETH_DUPLEX_FULL; + break; + default: + break; + } + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, "send speed event failed", err); + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, "send duplex event failed", err); + if (lan8720->link_status != link) { + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err); + lan8720->link_status = link; + } + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t lan8720_pwrctl(esp_eth_phy_t *phy, bool enable) +{ + phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent); + esp_eth_mediator_t *eth = lan8720->eth; + bmcr_reg_t bmcr; + PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + if (!enable) { + /* General Power Down Mode */ + bmcr.power_down = 1; + } else { + /* Normal operation Mode */ + bmcr.power_down = 0; + } + PHY_CHECK(eth->phy_reg_write(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + if (!enable) { + PHY_CHECK(bmcr.power_down == 1, "power down failed", err); + } else { + PHY_CHECK(bmcr.power_down == 0, "power up failed", err); + } + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t lan8720_set_addr(esp_eth_phy_t *phy, uint32_t addr) +{ + phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent); + lan8720->addr = addr; + return ESP_OK; +} + +static esp_err_t lan8720_get_addr(esp_eth_phy_t *phy, uint32_t *addr) +{ + PHY_CHECK(addr, "get phy address failed", err); + phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent); + *addr = lan8720->addr; + return ESP_OK; +err: + return ESP_ERR_INVALID_ARG; +} + +static esp_err_t lan8720_del(esp_eth_phy_t *phy) +{ + phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent); + free(lan8720); + return ESP_OK; +} + +static esp_err_t lan8720_init(esp_eth_phy_t *phy) +{ + phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent); + esp_eth_mediator_t *eth = lan8720->eth; + /* Power on Ethernet PHY */ + PHY_CHECK(lan8720_pwrctl(phy, true) == ESP_OK, "power on Ethernet PHY failed", err); + /* Reset Ethernet PHY */ + PHY_CHECK(lan8720_reset(phy) == ESP_OK, "reset Ethernet PHY failed", err); + /* Check PHY ID */ + phyidr1_reg_t id1; + phyidr2_reg_t id2; + PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, "read ID1 failed", err); + PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, "read ID2 failed", err); + PHY_CHECK(id1.oui_msb == 0x7 && id2.oui_lsb == 0x30 && id2.vendor_model == 0xF, "wrong PHY chip ID", err); + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t lan8720_deinit(esp_eth_phy_t *phy) +{ + /* Power off Ethernet PHY */ + PHY_CHECK(lan8720_pwrctl(phy, false) == ESP_OK, "power off Ethernet PHY failed", err); + return ESP_OK; +err: + return ESP_FAIL; +} + +esp_eth_phy_t *esp_eth_phy_new_lan8720(const eth_phy_config_t *config) +{ + PHY_CHECK(config, "can't set phy config to null", err); + phy_lan8720_t *lan8720 = calloc(1, sizeof(phy_lan8720_t)); + PHY_CHECK(lan8720, "calloc lan8720 object failed", err); + lan8720->name = "lan8720"; + lan8720->addr = config->phy_addr; + lan8720->reset_timeout_ms = config->reset_timeout_ms; + lan8720->link_status = ETH_LINK_DOWN; + lan8720->autonego_timeout_ms = config->autonego_timeout_ms; + lan8720->parent.reset = lan8720_reset; + lan8720->parent.init = lan8720_init; + lan8720->parent.deinit = lan8720_deinit; + lan8720->parent.set_mediator = lan8720_set_mediator; + lan8720->parent.negotiate = lan8720_negotiate; + lan8720->parent.get_link = lan8720_get_link; + lan8720->parent.pwrctl = lan8720_pwrctl; + lan8720->parent.get_addr = lan8720_get_addr; + lan8720->parent.set_addr = lan8720_set_addr; + lan8720->parent.del = lan8720_del; + + return &(lan8720->parent); +err: + return NULL; +} diff --git a/components/esp_eth/src/esp_eth_phy_rtl8201.c b/components/esp_eth/src/esp_eth_phy_rtl8201.c new file mode 100644 index 0000000000..b927ed5c9c --- /dev/null +++ b/components/esp_eth/src/esp_eth_phy_rtl8201.c @@ -0,0 +1,292 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include "esp_log.h" +#include "esp_eth.h" +#include "eth_phy_regs_struct.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +static const char *TAG = "rtl8201"; +#define PHY_CHECK(a, str, goto_tag, ...) \ + do \ + { \ + if (!(a)) \ + { \ + ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ + goto goto_tag; \ + } \ + } while (0) + +/***************Vendor Specific Register***************/ + +/** + * @brief PSMR(Power Saving Mode Register) + * + */ +typedef union { + struct { + uint16_t reserved : 15; /* Reserved */ + uint16_t en_pwr_save : 1; /* Enable power saving mode */ + }; + uint16_t val; +} psmr_reg_t; +#define ETH_PHY_PSMR_REG_ADDR (0x18) + +/** + * @brief PSR(Page Select Register) + * + */ +typedef union { + struct { + uint16_t page_select : 8; /* Select register page, default is 0 */ + uint16_t reserved : 8; /* Reserved */ + }; + uint16_t val; +} psr_reg_t; +#define ETH_PHY_PSR_REG_ADDR (0x1F) + +typedef struct { + esp_eth_phy_t parent; + esp_eth_mediator_t *eth; + const char *name; + uint32_t addr; + uint32_t reset_timeout_ms; + uint32_t autonego_timeout_ms; + eth_link_t link_status; +} phy_rtl8201_t; + +static esp_err_t rtl8201_page_select(phy_rtl8201_t *rtl8201, uint32_t page) +{ + esp_eth_mediator_t *eth = rtl8201->eth; + psr_reg_t psr = { + .page_select = page + }; + PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_PSR_REG_ADDR, psr.val) == ESP_OK, "write PSR failed", err); + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t rtl8201_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth) +{ + PHY_CHECK(eth, "can't set mediator for rtl8201 to null", err); + phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent); + rtl8201->eth = eth; + return ESP_OK; +err: + return ESP_ERR_INVALID_ARG; +} + +static esp_err_t rtl8201_get_link(esp_eth_phy_t *phy) +{ + phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent); + esp_eth_mediator_t *eth = rtl8201->eth; + bmsr_reg_t bmsr; + + PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); + eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; + if (rtl8201->link_status != link) { + if (link == ETH_LINK_UP) { + phy->negotiate(phy); + } else { + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err); + rtl8201->link_status = link; + } + } + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t rtl8201_reset(esp_eth_phy_t *phy) +{ + phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent); + esp_eth_mediator_t *eth = rtl8201->eth; + bmcr_reg_t bmcr = {.reset = 1}; + PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); + /* Wait for reset complete */ + uint32_t to = 0; + for (to = 0; to < rtl8201->reset_timeout_ms / 10; to++) { + vTaskDelay(pdMS_TO_TICKS(10)); + PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + if (!bmcr.reset) { + break; + } + } + PHY_CHECK(to < rtl8201->reset_timeout_ms / 10, "PHY reset timeout", err); + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t rtl8201_negotiate(esp_eth_phy_t *phy) +{ + phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent); + esp_eth_mediator_t *eth = rtl8201->eth; + /* Start auto negotiation */ + bmcr_reg_t bmcr = { + .speed_select = 1, /* 100Mbps */ + .duplex_mode = 1, /* Full Duplex */ + .en_auto_nego = 1, /* Auto Negotiation */ + .restart_auto_nego = 1 /* Restart Auto Negotiation */ + }; + PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); + /* Wait for auto negotiation complete */ + bmsr_reg_t bmsr; + uint32_t to = 0; + for (to = 0; to < rtl8201->autonego_timeout_ms / 10; to++) { + vTaskDelay(pdMS_TO_TICKS(10)); + PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); + if (bmsr.auto_nego_complete) { + break; + } + } + /* Auto negotiation failed, maybe no network cable plugged in, so output a warning */ + if (to >= rtl8201->autonego_timeout_ms / 10) { + ESP_LOGW(TAG, "Ethernet PHY auto negotiation timeout"); + } + PHY_CHECK(rtl8201_page_select(rtl8201, 0) == ESP_OK, "select page failed", err); + /* Updata information about link, speed, duplex */ + PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err); + eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; + eth_speed_t speed = ETH_SPEED_10M; + eth_duplex_t duplex = ETH_DUPLEX_HALF; + if (bmcr.speed_select) { + speed = ETH_SPEED_100M; + } else { + speed = ETH_SPEED_10M; + } + if (bmcr.duplex_mode) { + duplex = ETH_DUPLEX_FULL; + } else { + duplex = ETH_DUPLEX_HALF; + } + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, "send speed event failed", err); + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, "send duplex event failed", err); + if (rtl8201->link_status != link) { + PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err); + rtl8201->link_status = link; + } + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t rtl8201_pwrctl(esp_eth_phy_t *phy, bool enable) +{ + phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent); + esp_eth_mediator_t *eth = rtl8201->eth; + bmcr_reg_t bmcr; + PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + if (!enable) { + /* Enable IEEE Power Down Mode */ + bmcr.power_down = 1; + } else { + /* Disable IEEE Power Down Mode */ + bmcr.power_down = 0; + } + PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err); + PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err); + if (!enable) { + PHY_CHECK(bmcr.power_down == 1, "power down failed", err); + } else { + PHY_CHECK(bmcr.power_down == 0, "power up failed", err); + } + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t rtl8201_set_addr(esp_eth_phy_t *phy, uint32_t addr) +{ + phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent); + rtl8201->addr = addr; + return ESP_OK; +} + +static esp_err_t rtl8201_get_addr(esp_eth_phy_t *phy, uint32_t *addr) +{ + PHY_CHECK(addr, "get phy address failed", err); + phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent); + *addr = rtl8201->addr; + return ESP_OK; +err: + return ESP_ERR_INVALID_ARG; +} + +static esp_err_t rtl8201_del(esp_eth_phy_t *phy) +{ + phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent); + free(rtl8201); + return ESP_OK; +} + +static esp_err_t rtl8201_init(esp_eth_phy_t *phy) +{ + phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent); + esp_eth_mediator_t *eth = rtl8201->eth; + /* Power on Ethernet PHY */ + PHY_CHECK(rtl8201_pwrctl(phy, true) == ESP_OK, "power on Ethernet PHY failed", err); + /* Reset Ethernet PHY */ + PHY_CHECK(rtl8201_reset(phy) == ESP_OK, "reset Ethernet PHY failed", err); + /* Check PHY ID */ + phyidr1_reg_t id1; + phyidr2_reg_t id2; + PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, "read ID1 failed", err); + PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, "read ID2 failed", err); + PHY_CHECK(id1.oui_msb == 0x1C && id2.oui_lsb == 0x32 && id2.vendor_model == 0x1, "wrong PHY chip ID", err); + return ESP_OK; +err: + return ESP_FAIL; +} + +static esp_err_t rtl8201_deinit(esp_eth_phy_t *phy) +{ + /* Power off Ethernet PHY */ + PHY_CHECK(rtl8201_pwrctl(phy, false) == ESP_OK, "power off Ethernet PHY failed", err); + return ESP_OK; +err: + return ESP_FAIL; +} + +esp_eth_phy_t *esp_eth_phy_new_rtl8201(const eth_phy_config_t *config) +{ + PHY_CHECK(config, "can't set phy config to null", err); + phy_rtl8201_t *rtl8201 = calloc(1, sizeof(phy_rtl8201_t)); + PHY_CHECK(rtl8201, "calloc rtl8201 object failed", err); + rtl8201->name = "rtl8201"; + rtl8201->addr = config->phy_addr; + rtl8201->reset_timeout_ms = config->reset_timeout_ms; + rtl8201->link_status = ETH_LINK_DOWN; + rtl8201->autonego_timeout_ms = config->autonego_timeout_ms; + rtl8201->parent.reset = rtl8201_reset; + rtl8201->parent.init = rtl8201_init; + rtl8201->parent.deinit = rtl8201_deinit; + rtl8201->parent.set_mediator = rtl8201_set_mediator; + rtl8201->parent.negotiate = rtl8201_negotiate; + rtl8201->parent.get_link = rtl8201_get_link; + rtl8201->parent.pwrctl = rtl8201_pwrctl; + rtl8201->parent.get_addr = rtl8201_get_addr; + rtl8201->parent.set_addr = rtl8201_set_addr; + rtl8201->parent.del = rtl8201_del; + + return &(rtl8201->parent); +err: + return NULL; +} diff --git a/components/esp_eth/test/CMakeLists.txt b/components/esp_eth/test/CMakeLists.txt new file mode 100644 index 0000000000..c4041b1feb --- /dev/null +++ b/components/esp_eth/test/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + PRIV_REQUIRES "unity" "test_utils" "esp_eth") diff --git a/components/ethernet/test/component.mk b/components/esp_eth/test/component.mk similarity index 82% rename from components/ethernet/test/component.mk rename to components/esp_eth/test/component.mk index 5dd172bdb7..8b9586c0b3 100644 --- a/components/ethernet/test/component.mk +++ b/components/esp_eth/test/component.mk @@ -2,4 +2,6 @@ #Component Makefile # +COMPONENT_SRCDIRS := . + COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive diff --git a/components/esp_eth/test/test_emac.c b/components/esp_eth/test/test_emac.c new file mode 100644 index 0000000000..2ebe98b023 --- /dev/null +++ b/components/esp_eth/test/test_emac.c @@ -0,0 +1,137 @@ +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "tcpip_adapter.h" +#include "esp_event.h" +#include "unity.h" +#include "test_utils.h" +#include "esp_eth.h" +#include "esp_log.h" +#include "sdkconfig.h" + +static const char *TAG = "esp_eth_test"; +/** Event handler for Ethernet events */ +static void eth_event_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + switch (event_id) { + case ETHERNET_EVENT_CONNECTED: + ESP_LOGI(TAG, "Ethernet Link Up"); + break; + case ETHERNET_EVENT_DISCONNECTED: + ESP_LOGI(TAG, "Ethernet Link Down"); + break; + case ETHERNET_EVENT_START: + ESP_LOGI(TAG, "Ethernet Started"); + break; + case ETHERNET_EVENT_STOP: + ESP_LOGI(TAG, "Ethernet Stopped"); + break; + default: + break; + } +} + +/** Event handler for IP_EVENT_ETH_GOT_IP */ +static void got_ip_event_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data; + const tcpip_adapter_ip_info_t *ip_info = &event->ip_info; + + ESP_LOGI(TAG, "Ethernet Got IP Address"); + ESP_LOGI(TAG, "~~~~~~~~~~~"); + ESP_LOGI(TAG, "ETHIP:" IPSTR, IP2STR(&ip_info->ip)); + ESP_LOGI(TAG, "ETHMASK:" IPSTR, IP2STR(&ip_info->netmask)); + ESP_LOGI(TAG, "ETHGW:" IPSTR, IP2STR(&ip_info->gw)); + ESP_LOGI(TAG, "~~~~~~~~~~~"); +} + +TEST_CASE("esp32 emac io test", "[ethernet][ignore]") +{ + TEST_ESP_OK(esp_event_loop_create_default()); + eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); + esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config); + eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); + esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config); + esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); + esp_eth_handle_t eth_handle = NULL; + TEST_ESP_OK(esp_eth_driver_install(&config, ð_handle)); + vTaskDelay(pdMS_TO_TICKS(1000)); + /* get MAC address */ + uint8_t mac_addr[6]; + memset(mac_addr, 0, sizeof(mac_addr)); + TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr)); + TEST_ASSERT(mac_addr[0] != 0); + /* get PHY address */ + int phy_addr = -1; + TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_PHY_ADDR, &phy_addr)); + TEST_ASSERT(phy_addr >= 0 && phy_addr <= 31); + TEST_ESP_OK(esp_eth_driver_uninstall(eth_handle)); + TEST_ESP_OK(phy->del(phy)); + TEST_ESP_OK(mac->del(mac)); + TEST_ESP_OK(esp_event_loop_delete_default()); +} + +TEST_CASE("ethernet tcpip_adapter", "[ethernet][ignore]") +{ + test_case_uses_tcpip(); + TEST_ESP_OK(esp_event_loop_create_default()); + TEST_ESP_OK(tcpip_adapter_set_default_eth_handlers()); + TEST_ESP_OK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, NULL)); + TEST_ESP_OK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL)); + eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); + esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config); + eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); + esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config); + esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); + esp_eth_handle_t eth_handle = NULL; + TEST_ESP_OK(esp_eth_driver_install(&config, ð_handle)); + vTaskDelay(portMAX_DELAY); +} + +#if CONFIG_ETH_USE_SPI_ETHERNET +TEST_CASE("dm9051 io test", "[ethernet][ignore]") +{ + spi_device_handle_t spi_handle = NULL; + spi_bus_config_t buscfg = { + .miso_io_num = 25, + .mosi_io_num = 23, + .sclk_io_num = 19, + .quadwp_io_num = -1, + .quadhd_io_num = -1, + }; + TEST_ESP_OK(spi_bus_initialize(HSPI_HOST, &buscfg, 1)); + spi_device_interface_config_t devcfg = { + .command_bits = 1, + .address_bits = 7, + .mode = 0, + .clock_speed_hz = 20 * 1000 * 1000, + .spics_io_num = 22, + .queue_size = 20 + }; + TEST_ESP_OK(spi_bus_add_device(HSPI_HOST, &devcfg, &spi_handle)); + gpio_install_isr_service(0); + tcpip_adapter_init(); + TEST_ESP_OK(esp_event_loop_create_default()); + TEST_ESP_OK(tcpip_adapter_set_default_eth_handlers()); + TEST_ESP_OK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, NULL)); + TEST_ESP_OK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL)); + eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); + mac_config.spi_hdl = spi_handle; + esp_eth_mac_t *mac = esp_eth_mac_new_dm9051(&mac_config); + eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); + esp_eth_phy_t *phy = esp_eth_phy_new_dm9051(&phy_config); + esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy); + esp_eth_handle_t eth_handle = NULL; + TEST_ESP_OK(esp_eth_driver_install(&config, ð_handle)); + vTaskDelay(pdMS_TO_TICKS(portMAX_DELAY)); + TEST_ESP_OK(esp_eth_driver_uninstall(eth_handle)); + TEST_ESP_OK(phy->del(phy)); + TEST_ESP_OK(mac->del(mac)); + TEST_ESP_OK(esp_event_loop_delete_default()); + TEST_ESP_OK(spi_bus_remove_device(spi_handle)); + TEST_ESP_OK(spi_bus_free(HSPI_HOST)); +} +#endif diff --git a/components/esp_event/CMakeLists.txt b/components/esp_event/CMakeLists.txt index 834ecea54d..da463ff1fc 100644 --- a/components/esp_event/CMakeLists.txt +++ b/components/esp_event/CMakeLists.txt @@ -1,20 +1,19 @@ -set(COMPONENT_SRCS "default_event_loop.c" - "esp_event.c" - "esp_event_private.c" - "event_loop_legacy.c" - "event_send.c") - -set(COMPONENT_ADD_INCLUDEDIRS "include") -set(COMPONENT_PRIV_INCLUDEDIRS "private_include") - -set(COMPONENT_REQUIRES log tcpip_adapter) if(IDF_TARGET STREQUAL "esp32") - set(COMPONENT_PRIV_REQUIRES ethernet) + set(priv_requires esp_eth) +else() + set(priv_requires) endif() -set(COMPONENT_ADD_LDFRAGMENTS linker.lf) - -register_component() +idf_component_register(SRCS "default_event_loop.c" + "esp_event.c" + "esp_event_private.c" + "event_loop_legacy.c" + "event_send.c" + INCLUDE_DIRS "include" + PRIV_INCLUDE_DIRS "private_include" + REQUIRES log tcpip_adapter + PRIV_REQUIRES ${priv_requires} + LDFRAGMENTS linker.lf) if(GCC_NOT_5_2_0 AND CONFIG_ESP_EVENT_LOOP_PROFILING) # uses C11 atomic feature diff --git a/components/esp_event/component.mk b/components/esp_event/component.mk index c59eccc41a..828cb6abac 100644 --- a/components/esp_event/component.mk +++ b/components/esp_event/component.mk @@ -4,6 +4,7 @@ COMPONENT_ADD_INCLUDEDIRS := include COMPONENT_PRIV_INCLUDEDIRS := private_include COMPONENT_SRCDIRS := . +COMPONENT_ADD_LDFRAGMENTS := linker.lf ifdef CONFIG_ESP_EVENT_LOOP_PROFILING PROFILING_ENABLED := 1 diff --git a/components/esp_event/default_event_loop.c b/components/esp_event/default_event_loop.c index 9cad688876..01418c72a5 100644 --- a/components/esp_event/default_event_loop.c +++ b/components/esp_event/default_event_loop.c @@ -14,6 +14,7 @@ #include "esp_event.h" #include "esp_event_internal.h" +#include "esp_task.h" /* ------------------------- Static Variables ------------------------------- */ @@ -100,7 +101,7 @@ esp_err_t esp_event_loop_delete_default() } esp_err_t err; - + err = esp_event_loop_delete(s_default_loop); if (err != ESP_OK) { diff --git a/components/esp_event/esp_event.c b/components/esp_event/esp_event.c index b51a74cb50..99a3cf70bb 100644 --- a/components/esp_event/esp_event.c +++ b/components/esp_event/esp_event.c @@ -212,7 +212,7 @@ static esp_err_t base_node_add_handler(esp_event_base_node_t* base_node, int32_t id_node = (esp_event_id_node_t*) calloc(1, sizeof(*id_node)); if (!id_node) { - ESP_LOGI(TAG, "alloc for new id node failed"); + ESP_LOGE(TAG, "alloc for new id node failed"); return ESP_ERR_NO_MEM; } @@ -229,6 +229,8 @@ static esp_err_t base_node_add_handler(esp_event_base_node_t* base_node, int32_t else { SLIST_INSERT_AFTER(last_id_node, id_node, next); } + } else { + free(id_node); } return err; @@ -280,6 +282,8 @@ static esp_err_t loop_node_add_handler(esp_event_loop_node_t* loop_node, esp_eve else { SLIST_INSERT_AFTER(last_base_node, base_node, next); } + } else { + free(base_node); } return err; @@ -414,7 +418,7 @@ esp_err_t esp_event_loop_create(const esp_event_loop_args_t* event_loop_args, es loop = calloc(1, sizeof(*loop)); if (loop == NULL) { ESP_LOGE(TAG, "alloc for event loop failed"); - goto on_err; + return err; } loop->queue = xQueueCreate(event_loop_args->queue_size , sizeof(esp_event_post_instance_t)); @@ -692,6 +696,8 @@ esp_err_t esp_event_handler_register_with(esp_event_loop_handle_t event_loop, es else { SLIST_INSERT_AFTER(last_loop_node, loop_node, next); } + } else { + free(loop_node); } } else { diff --git a/components/esp_event/event_send.c b/components/esp_event/event_send.c index 4472bb4743..2c31ee0f6c 100644 --- a/components/esp_event/event_send.c +++ b/components/esp_event/event_send.c @@ -20,7 +20,6 @@ esp_err_t esp_event_send_noop(system_event_t *event); extern esp_err_t esp_event_send_legacy(system_event_t *event) __attribute__((weak, alias("esp_event_send_noop"))); extern esp_err_t esp_event_send_to_default_loop(system_event_t *event) __attribute((weak, alias("esp_event_send_noop"))); -extern esp_err_t esp_event_mesh_hook(system_event_t* event) __attribute__((weak, alias("esp_event_send_noop"))); esp_err_t esp_event_send_noop(system_event_t *event) @@ -42,11 +41,5 @@ esp_err_t esp_event_send(system_event_t *event) return err; } - // send the event to mesh hook - err = esp_event_mesh_hook(event); - if (err != ESP_OK) { - return err; - } - return ESP_OK; } diff --git a/components/esp_event/event_send_compat.inc b/components/esp_event/event_send_compat.inc index 701103b0b3..c14630fa2b 100644 --- a/components/esp_event/event_send_compat.inc +++ b/components/esp_event/event_send_compat.inc @@ -82,6 +82,7 @@ esp_err_t esp_event_send_to_default_loop(system_event_t *event) HANDLE_SYS_EVENT(WIFI, STA_WPS_ER_TIMEOUT); HANDLE_SYS_EVENT_ARG(WIFI, STA_WPS_ER_FAILED, sta_er_fail_reason); HANDLE_SYS_EVENT_ARG(WIFI, STA_WPS_ER_PIN, sta_er_pin); + HANDLE_SYS_EVENT(WIFI, STA_WPS_ER_PBC_OVERLAP); /* AP events */ HANDLE_SYS_EVENT(WIFI, AP_START); @@ -235,6 +236,10 @@ static void esp_system_event_debug(const system_event_t* event) ESP_LOGD(TAG, "SYSTEM_EVENT_STA_WPS_ER_PIN"); break; } + case SYSTEM_EVENT_STA_WPS_ER_PBC_OVERLAP: { + ESP_LOGD(TAG, "SYSTEM_EVENT_STA_WPS_ER_PBC_OVERLAP"); + break; + } case SYSTEM_EVENT_AP_START: { ESP_LOGD(TAG, "SYSTEM_EVENT_AP_START"); break; diff --git a/components/esp_event/include/esp_event_legacy.h b/components/esp_event/include/esp_event_legacy.h index 7748f69a0d..44e95546a1 100644 --- a/components/esp_event/include/esp_event_legacy.h +++ b/components/esp_event/include/esp_event_legacy.h @@ -40,6 +40,7 @@ typedef enum { SYSTEM_EVENT_STA_WPS_ER_FAILED, /*!< ESP32 station wps fails in enrollee mode */ SYSTEM_EVENT_STA_WPS_ER_TIMEOUT, /*!< ESP32 station wps timeout in enrollee mode */ SYSTEM_EVENT_STA_WPS_ER_PIN, /*!< ESP32 station wps pin code in enrollee mode */ + SYSTEM_EVENT_STA_WPS_ER_PBC_OVERLAP, /*!< ESP32 station wps overlap in enrollee mode */ SYSTEM_EVENT_AP_START, /*!< ESP32 soft-AP start */ SYSTEM_EVENT_AP_STOP, /*!< ESP32 soft-AP stop */ SYSTEM_EVENT_AP_STACONNECTED, /*!< a station connected to ESP32 soft-AP */ diff --git a/components/esp_event/test/CMakeLists.txt b/components/esp_event/test/CMakeLists.txt index 287a2ba928..8264f10dda 100644 --- a/components/esp_event/test/CMakeLists.txt +++ b/components/esp_event/test/CMakeLists.txt @@ -1,5 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_PRIV_INCLUDEDIRS "../private_include" ".") -set(COMPONENT_PRIV_REQUIRES unity test_utils esp_event driver) - -register_component() \ No newline at end of file +idf_component_register(SRC_DIRS "." + PRIV_INCLUDE_DIRS "../private_include" "." + REQUIRES unity test_utils esp_event driver) diff --git a/components/esp_gdbstub/xtensa/gdbstub_xtensa.c b/components/esp_gdbstub/xtensa/gdbstub_xtensa.c index edae3226f8..853b1ba085 100644 --- a/components/esp_gdbstub/xtensa/gdbstub_xtensa.c +++ b/components/esp_gdbstub/xtensa/gdbstub_xtensa.c @@ -18,7 +18,6 @@ #include "soc/cpu.h" #include "soc/soc_memory_layout.h" #include "sdkconfig.h" -#include "esp_debug_helpers.h" #if !XCHAL_HAVE_WINDOWED #warning "gdbstub_xtensa: revisit the implementation for Call0 ABI" diff --git a/components/esp_http_client/CMakeLists.txt b/components/esp_http_client/CMakeLists.txt index 2bea7ce022..327e90778a 100644 --- a/components/esp_http_client/CMakeLists.txt +++ b/components/esp_http_client/CMakeLists.txt @@ -1,11 +1,8 @@ -set(COMPONENT_SRCS "esp_http_client.c" - "lib/http_auth.c" - "lib/http_header.c" - "lib/http_utils.c") -set(COMPONENT_ADD_INCLUDEDIRS "include") -set(COMPONENT_PRIV_INCLUDEDIRS "lib/include") - -set(COMPONENT_REQUIRES "nghttp") -set(COMPONENT_PRIV_REQUIRES "mbedtls" "lwip" "esp-tls" "tcp_transport") - -register_component() +idf_component_register(SRCS "esp_http_client.c" + "lib/http_auth.c" + "lib/http_header.c" + "lib/http_utils.c" + INCLUDE_DIRS "include" + PRIV_INCLUDE_DIRS "lib/include" + REQUIRES nghttp + PRIV_REQUIRES mbedtls lwip esp-tls tcp_transport) diff --git a/components/esp_http_client/esp_http_client.c b/components/esp_http_client/esp_http_client.c index baab149f8a..76f6eec016 100644 --- a/components/esp_http_client/esp_http_client.c +++ b/components/esp_http_client/esp_http_client.c @@ -110,7 +110,8 @@ struct esp_http_client { esp_http_state_t state; http_event_handle_cb event_handler; int timeout_ms; - int buffer_size; + int buffer_size_rx; + int buffer_size_tx; bool disable_auto_redirect; esp_http_client_event_t event; int data_written_index; @@ -312,11 +313,16 @@ static esp_err_t _set_config(esp_http_client_handle_t client, const esp_http_cli client->timeout_ms = config->timeout_ms; client->max_redirection_count = config->max_redirection_count; client->user_data = config->user_data; - client->buffer_size = config->buffer_size; + client->buffer_size_rx = config->buffer_size; + client->buffer_size_tx = config->buffer_size_tx; client->disable_auto_redirect = config->disable_auto_redirect; if (config->buffer_size == 0) { - client->buffer_size = DEFAULT_HTTP_BUF_SIZE; + client->buffer_size_rx = DEFAULT_HTTP_BUF_SIZE; + } + + if (config->buffer_size_tx == 0) { + client->buffer_size_tx = DEFAULT_HTTP_BUF_SIZE; } if (client->max_redirection_count == 0) { @@ -506,6 +512,10 @@ esp_http_client_handle_t esp_http_client_init(const esp_http_client_config_t *co if (config->client_key_pem) { esp_transport_ssl_set_client_key_data(ssl, config->client_key_pem, strlen(config->client_key_pem)); } + + if (config->skip_cert_common_name_check) { + esp_transport_ssl_skip_common_name_check(ssl); + } #endif if (_set_config(client, config) != ESP_OK) { @@ -513,8 +523,8 @@ esp_http_client_handle_t esp_http_client_init(const esp_http_client_config_t *co goto error; } _success = ( - (client->request->buffer->data = malloc(client->buffer_size)) && - (client->response->buffer->data = malloc(client->buffer_size)) + (client->request->buffer->data = malloc(client->buffer_size_tx)) && + (client->response->buffer->data = malloc(client->buffer_size_rx)) ); if (!_success) { @@ -758,7 +768,7 @@ static int esp_http_client_get_data(esp_http_client_handle_t client) ESP_LOGD(TAG, "data_process=%d, content_length=%d", client->response->data_process, client->response->content_length); - int rlen = esp_transport_read(client->transport, res_buffer->data, client->buffer_size, client->timeout_ms); + int rlen = esp_transport_read(client->transport, res_buffer->data, client->buffer_size_rx, client->timeout_ms); if (rlen >= 0) { http_parser_execute(client->parser, client->parser_settings, res_buffer->data, rlen); } @@ -793,8 +803,8 @@ int esp_http_client_read(esp_http_client_handle_t client, char *buffer, int len) break; } int byte_to_read = need_read; - if (byte_to_read > client->buffer_size) { - byte_to_read = client->buffer_size; + if (byte_to_read > client->buffer_size_rx) { + byte_to_read = client->buffer_size_rx; } rlen = esp_transport_read(client->transport, res_buffer->data, byte_to_read, client->timeout_ms); ESP_LOGD(TAG, "need_read=%d, byte_to_read=%d, rlen=%d, ridx=%d", need_read, byte_to_read, rlen, ridx); @@ -911,7 +921,7 @@ int esp_http_client_fetch_headers(esp_http_client_handle_t client) client->response->status_code = -1; while (client->state < HTTP_STATE_RES_COMPLETE_HEADER) { - buffer->len = esp_transport_read(client->transport, buffer->data, client->buffer_size, client->timeout_ms); + buffer->len = esp_transport_read(client->transport, buffer->data, client->buffer_size_rx, client->timeout_ms); if (buffer->len <= 0) { return ESP_FAIL; } @@ -989,26 +999,26 @@ static int http_client_prepare_first_line(esp_http_client_handle_t client, int w const char *method = HTTP_METHOD_MAPPING[client->connection_info.method]; int first_line_len = snprintf(client->request->buffer->data, - client->buffer_size, "%s %s", + client->buffer_size_tx, "%s %s", method, client->connection_info.path); - if (first_line_len >= client->buffer_size) { + if (first_line_len >= client->buffer_size_tx) { ESP_LOGE(TAG, "Out of buffer"); return -1; } if (client->connection_info.query) { first_line_len += snprintf(client->request->buffer->data + first_line_len, - client->buffer_size - first_line_len, "?%s", client->connection_info.query); - if (first_line_len >= client->buffer_size) { + client->buffer_size_tx - first_line_len, "?%s", client->connection_info.query); + if (first_line_len >= client->buffer_size_tx) { ESP_LOGE(TAG, "Out of buffer"); return -1; } } first_line_len += snprintf(client->request->buffer->data + first_line_len, - client->buffer_size - first_line_len, " %s\r\n", DEFAULT_HTTP_PROTOCOL); - if (first_line_len >= client->buffer_size) { + client->buffer_size_tx - first_line_len, " %s\r\n", DEFAULT_HTTP_PROTOCOL); + if (first_line_len >= client->buffer_size_tx) { ESP_LOGE(TAG, "Out of buffer"); return -1; } @@ -1043,7 +1053,7 @@ static esp_err_t esp_http_client_request_send(esp_http_client_handle_t client, i } } - int wlen = client->buffer_size - first_line_len; + int wlen = client->buffer_size_tx - first_line_len; while ((client->header_index = http_header_generate_string(client->request->headers, client->header_index, client->request->buffer->data + first_line_len, &wlen))) { if (wlen <= 0) { break; @@ -1067,7 +1077,7 @@ static esp_err_t esp_http_client_request_send(esp_http_client_handle_t client, i client->data_write_left -= wret; client->data_written_index += wret; } - wlen = client->buffer_size; + wlen = client->buffer_size_tx; } client->data_written_index = 0; @@ -1141,7 +1151,7 @@ int esp_http_client_write(esp_http_client_handle_t client, const char *buffer, i esp_err_t esp_http_client_close(esp_http_client_handle_t client) { if (client->state >= HTTP_STATE_INIT) { - http_dispatch_event(client, HTTP_EVENT_DISCONNECTED, NULL, 0); + http_dispatch_event(client, HTTP_EVENT_DISCONNECTED, esp_transport_get_error_handle(client->transport), 0); client->state = HTTP_STATE_INIT; return esp_transport_close(client->transport); } @@ -1247,4 +1257,4 @@ void esp_http_client_add_auth(esp_http_client_handle_t client) client->connection_info.auth_type = HTTP_AUTH_TYPE_NONE; ESP_LOGW(TAG, "This request requires authentication, but does not provide header information for that"); } -} \ No newline at end of file +} diff --git a/components/esp_http_client/include/esp_http_client.h b/components/esp_http_client/include/esp_http_client.h index d236921770..cc97cc0690 100644 --- a/components/esp_http_client/include/esp_http_client.h +++ b/components/esp_http_client/include/esp_http_client.h @@ -116,10 +116,12 @@ typedef struct { int max_redirection_count; /*!< Max redirection number, using default value if zero*/ http_event_handle_cb event_handler; /*!< HTTP Event Handle */ esp_http_client_transport_t transport_type; /*!< HTTP transport type, see `esp_http_client_transport_t` */ - int buffer_size; /*!< HTTP buffer size (both send and receive) */ + int buffer_size; /*!< HTTP receive buffer size */ + int buffer_size_tx; /*!< HTTP transmit buffer size */ void *user_data; /*!< HTTP user_data context */ bool is_async; /*!< Set asynchronous mode, only supported with HTTPS for now */ bool use_global_ca_store; /*!< Use a global ca_store for all the connections in which this bool is set. */ + bool skip_cert_common_name_check; /*!< Skip any validation of server certificate CN field */ } esp_http_client_config_t; /** @@ -426,7 +428,7 @@ esp_http_client_transport_t esp_http_client_get_transport_type(esp_http_client_h * * @param[in] client The esp_http_client handle * - * @return + * @return * - ESP_OK * - ESP_FAIL */ diff --git a/components/esp_http_client/lib/include/http_utils.h b/components/esp_http_client/lib/include/http_utils.h index d57840228f..14c3b10c4e 100644 --- a/components/esp_http_client/lib/include/http_utils.h +++ b/components/esp_http_client/lib/include/http_utils.h @@ -16,7 +16,7 @@ #ifndef _HTTP_UTILS_H_ #define _HTTP_UTILS_H_ #include -#include "esp_transport_utils.h" + /** * @brief Assign new_str to *str pointer, and realloc *str if it not NULL * @@ -80,7 +80,9 @@ char *http_utils_join_string(const char *first_str, int len_first, const char *s int http_utils_str_starts_with(const char *str, const char *start); -#define HTTP_MEM_CHECK(TAG, a, action) ESP_TRANSPORT_MEM_CHECK(TAG, a, action) - +#define HTTP_MEM_CHECK(TAG, a, action) if (!(a)) { \ + ESP_LOGE(TAG,"%s:%d (%s): %s", __FILE__, __LINE__, __FUNCTION__, "Memory exhausted"); \ + action; \ + } #endif diff --git a/components/esp_http_client/test/CMakeLists.txt b/components/esp_http_client/test/CMakeLists.txt index 6b99d7546a..70fc98dcad 100644 --- a/components/esp_http_client/test/CMakeLists.txt +++ b/components/esp_http_client/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity test_utils esp_http_client) - -register_component() +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity test_utils esp_http_client) \ No newline at end of file diff --git a/components/esp_http_server/CMakeLists.txt b/components/esp_http_server/CMakeLists.txt index 700a0b9cb1..744e6b207f 100644 --- a/components/esp_http_server/CMakeLists.txt +++ b/components/esp_http_server/CMakeLists.txt @@ -1,13 +1,10 @@ -set(COMPONENT_ADD_INCLUDEDIRS include) -set(COMPONENT_PRIV_INCLUDEDIRS src/port/esp32 src/util) -set(COMPONENT_SRCS "src/httpd_main.c" - "src/httpd_parse.c" - "src/httpd_sess.c" - "src/httpd_txrx.c" - "src/httpd_uri.c" - "src/util/ctrl_sock.c") - -set(COMPONENT_REQUIRES nghttp) # for http_parser.h -set(COMPONENT_PRIV_REQUIRES lwip) - -register_component() +idf_component_register(SRCS "src/httpd_main.c" + "src/httpd_parse.c" + "src/httpd_sess.c" + "src/httpd_txrx.c" + "src/httpd_uri.c" + "src/util/ctrl_sock.c" + INCLUDE_DIRS "include" + PRIV_INCLUDE_DIRS "src/port/esp32" "src/util" + REQUIRES nghttp # for http_parser.h + PRIV_REQUIRES lwip) diff --git a/components/esp_http_server/src/httpd_txrx.c b/components/esp_http_server/src/httpd_txrx.c index ab96550c81..8f81ae2b1e 100644 --- a/components/esp_http_server/src/httpd_txrx.c +++ b/components/esp_http_server/src/httpd_txrx.c @@ -553,16 +553,9 @@ int httpd_req_to_sockfd(httpd_req_t *r) static int httpd_sock_err(const char *ctx, int sockfd) { int errval; - int sock_err; - size_t sock_err_len = sizeof(sock_err); + ESP_LOGW(TAG, LOG_FMT("error in %s : %d"), ctx, errno); - if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &sock_err, &sock_err_len) < 0) { - ESP_LOGE(TAG, LOG_FMT("error calling getsockopt : %d"), errno); - return HTTPD_SOCK_ERR_FAIL; - } - ESP_LOGW(TAG, LOG_FMT("error in %s : %d"), ctx, sock_err); - - switch(sock_err) { + switch(errno) { case EAGAIN: case EINTR: errval = HTTPD_SOCK_ERR_TIMEOUT; diff --git a/components/esp_http_server/test/CMakeLists.txt b/components/esp_http_server/test/CMakeLists.txt index de20de38f5..e2ceeb2986 100644 --- a/components/esp_http_server/test/CMakeLists.txt +++ b/components/esp_http_server/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity test_utils esp_http_server) - -register_component() +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity test_utils esp_http_server) \ No newline at end of file diff --git a/components/esp_https_ota/CMakeLists.txt b/components/esp_https_ota/CMakeLists.txt index 6ef0a5c9e0..8608666fde 100644 --- a/components/esp_https_ota/CMakeLists.txt +++ b/components/esp_https_ota/CMakeLists.txt @@ -1,7 +1,4 @@ -set(COMPONENT_ADD_INCLUDEDIRS include) -set(COMPONENT_SRCS "src/esp_https_ota.c") - -set(COMPONENT_REQUIRES esp_http_client) -set(COMPONENT_PRIV_REQUIRES log app_update) - -register_component() +idf_component_register(SRCS "src/esp_https_ota.c" + INCLUDE_DIRS "include" + REQUIRES esp_http_client + PRIV_REQUIRES log app_update) diff --git a/components/esp_https_ota/include/esp_https_ota.h b/components/esp_https_ota/include/esp_https_ota.h index a9d7f140db..0c8fd06934 100644 --- a/components/esp_https_ota/include/esp_https_ota.h +++ b/components/esp_https_ota/include/esp_https_ota.h @@ -70,6 +70,7 @@ esp_err_t esp_https_ota(const esp_http_client_config_t *config); * completion of OTA operation or on failure in subsequent operations. * This API supports URL redirection, but if CA cert of URLs differ then it * should be appended to `cert_pem` member of `http_config`, which is a part of `ota_config`. + * In case of error, this API explicitly sets `handle` to NULL. * * @param[in] ota_config pointer to esp_https_ota_config_t structure * @param[out] handle pointer to an allocated data of type `esp_https_ota_handle_t` diff --git a/components/esp_https_ota/src/esp_https_ota.c b/components/esp_https_ota/src/esp_https_ota.c index 515f03d706..baba0bbaa4 100644 --- a/components/esp_https_ota/src/esp_https_ota.c +++ b/components/esp_https_ota/src/esp_https_ota.c @@ -126,14 +126,19 @@ static esp_err_t _ota_write(esp_https_ota_t *https_ota_handle, const void *buffe esp_err_t esp_https_ota_begin(esp_https_ota_config_t *ota_config, esp_https_ota_handle_t *handle) { esp_err_t err; + if (handle == NULL || ota_config == NULL || ota_config->http_config == NULL) { ESP_LOGE(TAG, "esp_https_ota_begin: Invalid argument"); + if (handle) { + *handle = NULL; + } return ESP_ERR_INVALID_ARG; } #if !CONFIG_OTA_ALLOW_HTTP if (!ota_config->http_config->cert_pem) { ESP_LOGE(TAG, "Server certificate not found in esp_http_client config"); + *handle = NULL; return ESP_ERR_INVALID_ARG; } #endif @@ -141,6 +146,7 @@ esp_err_t esp_https_ota_begin(esp_https_ota_config_t *ota_config, esp_https_ota_ esp_https_ota_t *https_ota_handle = calloc(1, sizeof(esp_https_ota_t)); if (!https_ota_handle) { ESP_LOGE(TAG, "Couldn't allocate memory to upgrade data buffer"); + *handle = NULL; return ESP_ERR_NO_MEM; } @@ -188,6 +194,7 @@ http_cleanup: _http_cleanup(https_ota_handle->http_client); failure: free(https_ota_handle); + *handle = NULL; return err; } @@ -286,9 +293,12 @@ esp_err_t esp_https_ota_finish(esp_https_ota_handle_t https_ota_handle) err = esp_ota_end(handle->update_handle); /* falls through */ case ESP_HTTPS_OTA_BEGIN: - free(handle->ota_upgrade_buf); - _http_cleanup(handle->http_client); - free(handle); + if (handle->ota_upgrade_buf) { + free(handle->ota_upgrade_buf); + } + if (handle->http_client) { + _http_cleanup(handle->http_client); + } break; default: ESP_LOGE(TAG, "Invalid ESP HTTPS OTA State"); @@ -301,6 +311,7 @@ esp_err_t esp_https_ota_finish(esp_https_ota_handle_t https_ota_handle) ESP_LOGE(TAG, "esp_ota_set_boot_partition failed! err=0x%d", err); } } + free(handle); return err; } @@ -341,7 +352,6 @@ esp_err_t esp_https_ota(const esp_http_client_config_t *config) } esp_err_t ota_finish_err = esp_https_ota_finish(https_ota_handle); - free(https_ota_handle); if (err != ESP_OK) { /* If there was an error in esp_https_ota_perform(), then it is given more precedence than error in esp_https_ota_finish() diff --git a/components/esp_https_server/CMakeLists.txt b/components/esp_https_server/CMakeLists.txt index dfdaa11ecc..0eb83865b5 100644 --- a/components/esp_https_server/CMakeLists.txt +++ b/components/esp_https_server/CMakeLists.txt @@ -1,7 +1,10 @@ -set(COMPONENT_ADD_INCLUDEDIRS include) -set(COMPONENT_SRCS "src/https_server.c") +if (CONFIG_ESP_HTTPS_SERVER_ENABLE) + set(src "src/https_server.c") + set(inc "include") +endif() -set(COMPONENT_REQUIRES esp_http_server openssl) -set(COMPONENT_PRIV_REQUIRES lwip) +idf_component_register(SRCS ${src} + INCLUDE_DIRS ${inc} + REQUIRES esp_http_server esp-tls + PRIV_REQUIRES lwip) -register_component() diff --git a/components/esp_https_server/Kconfig b/components/esp_https_server/Kconfig new file mode 100644 index 0000000000..e4085539bb --- /dev/null +++ b/components/esp_https_server/Kconfig @@ -0,0 +1,9 @@ +menu "ESP HTTPS server" + + config ESP_HTTPS_SERVER_ENABLE + bool "Enable ESP_HTTPS_SERVER component" + select ESP_TLS_SERVER + help + Enable ESP HTTPS server component + +endmenu diff --git a/components/esp_https_server/component.mk b/components/esp_https_server/component.mk index be1bffc586..c90f6ee255 100644 --- a/components/esp_https_server/component.mk +++ b/components/esp_https_server/component.mk @@ -1,2 +1,6 @@ +ifdef CONFIG_ESP_HTTPS_SERVER_ENABLE COMPONENT_SRCDIRS := src COMPONENT_ADD_INCLUDEDIRS := include +else +COMPONENT_CONFIG_ONLY := 1 +endif diff --git a/components/esp_https_server/src/https_server.c b/components/esp_https_server/src/https_server.c index 4a0d21792f..f012ffec8e 100644 --- a/components/esp_https_server/src/https_server.c +++ b/components/esp_https_server/src/https_server.c @@ -14,9 +14,9 @@ #include #include "esp_https_server.h" -#include "openssl/ssl.h" #include "esp_log.h" #include "sdkconfig.h" +#include "esp_tls.h" const static char *TAG = "esp_https_server"; @@ -28,8 +28,7 @@ const static char *TAG = "esp_https_server"; static void httpd_ssl_close(void *ctx) { assert(ctx != NULL); - SSL_shutdown(ctx); - SSL_free(ctx); + esp_tls_server_session_delete(ctx); ESP_LOGD(TAG, "Secure socket closed"); } @@ -42,9 +41,9 @@ static void httpd_ssl_close(void *ctx) */ static int httpd_ssl_pending(httpd_handle_t server, int sockfd) { - SSL *ssl = httpd_sess_get_transport_ctx(server, sockfd); - assert(ssl != NULL); - return SSL_pending(ssl); + esp_tls_t *tls = httpd_sess_get_transport_ctx(server, sockfd); + assert(tls != NULL); + return esp_tls_get_bytes_avail(tls); } /** @@ -59,9 +58,9 @@ static int httpd_ssl_pending(httpd_handle_t server, int sockfd) */ static int httpd_ssl_recv(httpd_handle_t server, int sockfd, char *buf, size_t buf_len, int flags) { - SSL *ssl = httpd_sess_get_transport_ctx(server, sockfd); - assert(ssl != NULL); - return SSL_read(ssl, buf, buf_len); + esp_tls_t *tls = httpd_sess_get_transport_ctx(server, sockfd); + assert(tls != NULL); + return esp_tls_conn_read(tls, buf, buf_len); } /** @@ -76,9 +75,9 @@ static int httpd_ssl_recv(httpd_handle_t server, int sockfd, char *buf, size_t b */ static int httpd_ssl_send(httpd_handle_t server, int sockfd, const char *buf, size_t buf_len, int flags) { - SSL *ssl = httpd_sess_get_transport_ctx(server, sockfd); - assert(ssl != NULL); - return SSL_write(ssl, buf, buf_len); + esp_tls_t *tls = httpd_sess_get_transport_ctx(server, sockfd); + assert(tls != NULL); + return esp_tls_conn_write(tls, buf, buf_len); } /** @@ -94,28 +93,22 @@ static esp_err_t httpd_ssl_open(httpd_handle_t server, int sockfd) assert(server != NULL); // Retrieve the SSL context from the global context field (set in config) - SSL_CTX *global_ctx = httpd_get_global_transport_ctx(server); + esp_tls_cfg_server_t *global_ctx = httpd_get_global_transport_ctx(server); assert(global_ctx != NULL); - SSL *ssl = SSL_new(global_ctx); - if (NULL == ssl) { - ESP_LOGE(TAG, "SSL_new ret NULL (out of memory)"); + esp_tls_t *tls = (esp_tls_t *)calloc(1, sizeof(esp_tls_t)); + if (!tls) { return ESP_ERR_NO_MEM; } - - if (1 != SSL_set_fd(ssl, sockfd)) { - ESP_LOGE(TAG, "fail to set SSL fd"); - goto teardown; - } - - ESP_LOGD(TAG, "SSL accept"); - if (1 != SSL_accept(ssl)) { - ESP_LOGW(TAG, "fail to SSL_accept - handshake error"); - goto teardown; + ESP_LOGI(TAG, "performing session handshake"); + int ret = esp_tls_server_session_create(global_ctx, sockfd, tls); + if (ret != 0) { + ESP_LOGE(TAG, "esp_tls_create_server_session failed"); + goto fail; } // Store the SSL session into the context field of the HTTPD session object - httpd_sess_set_transport_ctx(server, sockfd, ssl, httpd_ssl_close); + httpd_sess_set_transport_ctx(server, sockfd, tls, httpd_ssl_close); // Set rx/tx/pending override functions httpd_sess_set_send_override(server, sockfd, httpd_ssl_send); @@ -127,9 +120,8 @@ static esp_err_t httpd_ssl_open(httpd_handle_t server, int sockfd) ESP_LOGD(TAG, "Secure socket open"); return ESP_OK; - -teardown: - SSL_free(ssl); +fail: + esp_tls_server_session_delete(tls); return ESP_FAIL; } @@ -141,38 +133,41 @@ teardown: static void free_secure_context(void *ctx) { assert(ctx != NULL); - + esp_tls_cfg_server_t *cfg = (esp_tls_cfg_server_t *)ctx; ESP_LOGI(TAG, "Server shuts down, releasing SSL context"); - SSL_CTX_free(ctx); + if (cfg->servercert_pem_buf) { + free((void *)cfg->servercert_pem_buf); + } + if (cfg->serverkey_pem_buf) { + free((void *)cfg->serverkey_pem_buf); + } + free(cfg); } -/** -* Create and perform basic init of a SSL_CTX, or return NULL on failure -* -* @return ctx or null -*/ -static SSL_CTX *create_secure_context(const struct httpd_ssl_config *config) +static esp_tls_cfg_server_t *create_secure_context(const struct httpd_ssl_config *config) { - SSL_CTX *ctx = NULL; - - ESP_LOGD(TAG, "SSL server context create"); - ctx = SSL_CTX_new(TLS_server_method()); - if (NULL != ctx) { - //region SSL ctx alloc'd - ESP_LOGD(TAG, "SSL ctx set own cert"); - if (SSL_CTX_use_certificate_ASN1(ctx, config->cacert_len, config->cacert_pem) - && SSL_CTX_use_PrivateKey_ASN1(0, ctx, config->prvtkey_pem, (long) config->prvtkey_len)) { - return ctx; - } - else { - ESP_LOGE(TAG, "Failed to set certificate"); - SSL_CTX_free(ctx); - ctx = NULL; - } - } else { - ESP_LOGE(TAG, "Failed to create SSL context"); + esp_tls_cfg_server_t *cfg = (esp_tls_cfg_server_t *)calloc(1, sizeof(esp_tls_cfg_server_t)); + if (!cfg) { + return NULL; } - return NULL; + cfg->servercert_pem_buf = (unsigned char *)malloc(config->cacert_len); + if (!cfg->servercert_pem_buf) { + free(cfg); + return NULL; + } + memcpy((char *)cfg->servercert_pem_buf, config->cacert_pem, config->cacert_len); + cfg->servercert_pem_bytes = config->cacert_len; + + cfg->serverkey_pem_buf = (unsigned char *)malloc(config->prvtkey_len); + if (!cfg->serverkey_pem_buf) { + free((void *)cfg->servercert_pem_buf); + free(cfg); + return NULL; + } + memcpy((char *)cfg->serverkey_pem_buf, config->prvtkey_pem, config->prvtkey_len); + cfg->serverkey_pem_bytes = config->prvtkey_len; + + return cfg; } /** Start the server */ @@ -184,15 +179,16 @@ esp_err_t httpd_ssl_start(httpd_handle_t *pHandle, struct httpd_ssl_config *conf ESP_LOGI(TAG, "Starting server"); if (HTTPD_SSL_TRANSPORT_SECURE == config->transport_mode) { - SSL_CTX *ctx = create_secure_context(config); - if (!ctx) { - return ESP_FAIL; + + esp_tls_cfg_server_t *esp_tls_cfg = create_secure_context(config); + if (!esp_tls_cfg) { + return -1; } ESP_LOGD(TAG, "SSL context ready"); // set SSL specific config - config->httpd.global_transport_ctx = ctx; + config->httpd.global_transport_ctx = esp_tls_cfg; config->httpd.global_transport_ctx_free_fn = free_secure_context; config->httpd.open_fn = httpd_ssl_open; // the open function configures the created SSL sessions diff --git a/components/esp_local_ctrl/CMakeLists.txt b/components/esp_local_ctrl/CMakeLists.txt new file mode 100644 index 0000000000..562ed91911 --- /dev/null +++ b/components/esp_local_ctrl/CMakeLists.txt @@ -0,0 +1,23 @@ +set(include_dirs include) +set(priv_include_dirs proto-c src ../protocomm/proto-c) +set(srcs "src/esp_local_ctrl.c" + "src/esp_local_ctrl_handler.c" + "proto-c/esp_local_ctrl.pb-c.c") + +if(CONFIG_ESP_HTTPS_SERVER_ENABLE) + list(APPEND srcs + "src/esp_local_ctrl_transport_httpd.c") +endif() + +if(CONFIG_BT_ENABLED) + if(CONFIG_BT_BLUEDROID_ENABLED) + list(APPEND srcs + "src/esp_local_ctrl_transport_ble.c") + endif() +endif() + +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS "${include_dirs}" + PRIV_INCLUDE_DIRS "${priv_include_dirs}" + REQUIRES protocomm esp_https_server + PRIV_REQUIRES protobuf-c mdns) diff --git a/components/esp_local_ctrl/component.mk b/components/esp_local_ctrl/component.mk new file mode 100644 index 0000000000..c7d18301d4 --- /dev/null +++ b/components/esp_local_ctrl/component.mk @@ -0,0 +1,11 @@ +COMPONENT_SRCDIRS := src proto-c +COMPONENT_ADD_INCLUDEDIRS := include +COMPONENT_PRIV_INCLUDEDIRS := src proto-c ../protocomm/proto-c/ + +ifndef CONFIG_BT_BLUEDROID_ENABLED + COMPONENT_OBJEXCLUDE += src/esp_local_ctrl_transport_ble.o +endif + +ifndef CONFIG_ESP_HTTPS_SERVER_ENABLE + COMPONENT_OBJEXCLUDE += src/esp_local_ctrl_transport_httpd.o +endif diff --git a/components/esp_local_ctrl/include/esp_local_ctrl.h b/components/esp_local_ctrl/include/esp_local_ctrl.h new file mode 100644 index 0000000000..53d062b104 --- /dev/null +++ b/components/esp_local_ctrl/include/esp_local_ctrl.h @@ -0,0 +1,339 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** + * @brief Property description data structure, which is to be populated + * and passed to the `esp_local_ctrl_add_property()` function + * + * Once a property is added, its structure is available for read-only access + * inside `get_prop_values()` and `set_prop_values()` handlers. + */ +typedef struct esp_local_ctrl_prop { + /** + * Unique name of property + */ + char *name; + + /** + * Type of property. This may be set to application defined enums + */ + uint32_t type; + + /** + * Size of the property value, which: + * - if zero, the property can have values of variable size + * - if non-zero, the property can have values of fixed size only, + * therefore, checks are performed internally by esp_local_ctrl + * when setting the value of such a property + */ + size_t size; + + /** + * Flags set for this property. This could be a bit field. + * A flag may indicate property behavior, e.g. read-only / constant + */ + uint32_t flags; + + /** + * Pointer to some context data relevant for this property. This will + * be available for use inside the `get_prop_values` and `set_prop_values` + * handlers as a part of this property structure. When set, this is valid + * throughout the lifetime of a property, till either the property is + * removed or the esp_local_ctrl service is stopped. + */ + void *ctx; + + /** + * Function used by esp_local_ctrl to internally free the property + * context when `esp_local_ctrl_remove_property()` or + * `esp_local_ctrl_stop()` is called. + */ + void (*ctx_free_fn)(void *ctx); +} esp_local_ctrl_prop_t; + +/** + * @brief Property value data structure. This gets passed to the + * `get_prop_values()` and `set_prop_values()` handlers for + * the purpose of retrieving or setting the present value + * of a property. + */ +typedef struct esp_local_ctrl_prop_val { + /** + * Pointer to memory holding property value + */ + void *data; + + /** + * Size of property value + */ + size_t size; + + /** + * This may be set by the application in `get_prop_values()` handler + * to tell `esp_local_ctrl` to call this function on the data pointer + * above, for freeing its resources after sending the `get_prop_values` + * response. + */ + void (*free_fn)(void *data); +} esp_local_ctrl_prop_val_t; + +/** + * @brief Handlers for receiving and responding to local + * control commands for getting and setting properties. + */ +typedef struct esp_local_ctrl_handlers { + /** + * @brief Handler function to be implemented for retrieving current + * values of properties + * + * @note If any of the properties have fixed sizes, the size field of + * corresponding element in `prop_values` need to be set + * + * @param[in] props_count Total elements in the props array + * @param[in] props Array of properties, the current values for which + * have been requested by the client + * @param[out] prop_values Array of empty property values, the elements of + * which need to be populated with the current values + * of those properties specified by props argument + * @param[in] usr_ctx This provides value of the `usr_ctx` field of + * `esp_local_ctrl_handlers_t` structure + * + * @return Returning different error codes will convey the corresponding + * protocol level errors to the client : + * - ESP_OK : Success + * - ESP_ERR_INVALID_ARG : InvalidArgument + * - ESP_ERR_INVALID_STATE : InvalidProto + * - All other error codes : InternalError + */ + esp_err_t (*get_prop_values)(size_t props_count, + const esp_local_ctrl_prop_t props[], + esp_local_ctrl_prop_val_t prop_values[], + void *usr_ctx); + + /** + * @brief Handler function to be implemented for changing values of properties + * + * @note If any of the properties have variable sizes, the size field + * of the corresponding element in `prop_values` must be checked + * explicitly before making any assumptions on the size. + * + * @param[in] props_count Total elements in the props array + * @param[in] props Array of properties, the values for which the + * client requests to change + * @param[in] prop_values Array of property values, the elements of which + * need to be used for updating those properties + * specified by props argument + * @param[in] usr_ctx This provides value of the `usr_ctx` field of + * `esp_local_ctrl_handlers_t` structure + * + * @return Returning different error codes will convey the corresponding + * protocol level errors to the client : + * - ESP_OK : Success + * - ESP_ERR_INVALID_ARG : InvalidArgument + * - ESP_ERR_INVALID_STATE : InvalidProto + * - All other error codes : InternalError + */ + esp_err_t (*set_prop_values)(size_t props_count, + const esp_local_ctrl_prop_t props[], + const esp_local_ctrl_prop_val_t prop_values[], + void *usr_ctx); + + /** + * Context pointer to be passed to above handler functions upon invocation. + * This is different from the property level context, as this is valid + * throughout the lifetime of the `esp_local_ctrl` service, and freed only + * when the service is stopped. + */ + void *usr_ctx; + + /** + * Pointer to function which will be internally invoked on `usr_ctx` for + * freeing the context resources when `esp_local_ctrl_stop()` is called. + */ + void (*usr_ctx_free_fn)(void *usr_ctx); +} esp_local_ctrl_handlers_t; + +/** + * @brief Transport mode (BLE / HTTPD) over which the service will be provided + * + * This is forward declaration of a private structure, implemented internally + * by `esp_local_ctrl`. + */ +typedef struct esp_local_ctrl_transport esp_local_ctrl_transport_t; + +/** + * @brief Function for obtaining BLE transport mode + */ +const esp_local_ctrl_transport_t *esp_local_ctrl_get_transport_ble(); + +/** + * @brief Function for obtaining HTTPD transport mode + */ +const esp_local_ctrl_transport_t *esp_local_ctrl_get_transport_httpd(); + +#define ESP_LOCAL_CTRL_TRANSPORT_BLE esp_local_ctrl_get_transport_ble() +#define ESP_LOCAL_CTRL_TRANSPORT_HTTPD esp_local_ctrl_get_transport_httpd() + +/** + * @brief Configuration for transport mode BLE + * + * This is a forward declaration for `protocomm_ble_config_t`. + * To use this, application must set CONFIG_BT_BLUEDROID_ENABLED + * and include `protocomm_ble.h`. + */ +typedef struct protocomm_ble_config esp_local_ctrl_transport_config_ble_t; + +/** + * @brief Configuration for transport mode HTTPD + * + * This is a forward declaration for `httpd_ssl_config_t`. + * To use this, application must set CONFIG_ESP_HTTPS_SERVER_ENABLE + * and include `esp_https_server.h` + */ +typedef struct httpd_ssl_config esp_local_ctrl_transport_config_httpd_t; + +/** + * @brief Transport mode (BLE / HTTPD) configuration + */ +typedef union { + /** + * This is same as `protocomm_ble_config_t`. See `protocomm_ble.h` for + * available configuration parameters. + */ + esp_local_ctrl_transport_config_ble_t *ble; + + /** + * This is same as `httpd_ssl_config_t`. See `esp_https_server.h` for + * available configuration parameters. + */ + esp_local_ctrl_transport_config_httpd_t *httpd; +} esp_local_ctrl_transport_config_t; + +/** + * @brief Configuration structure to pass to `esp_local_ctrl_start()` + */ +typedef struct esp_local_ctrl_config { + /** + * Transport layer over which service will be provided + */ + const esp_local_ctrl_transport_t *transport; + + /** + * Transport layer over which service will be provided + */ + esp_local_ctrl_transport_config_t transport_config; + + /** + * Register handlers for responding to get/set requests on properties + */ + esp_local_ctrl_handlers_t handlers; + + /** + * This limits the number of properties that are available at a time + */ + size_t max_properties; +} esp_local_ctrl_config_t; + +/** + * @brief Start local control service + * + * @param[in] config Pointer to configuration structure + * + * @return + * - ESP_OK : Success + * - ESP_FAIL : Failure + */ +esp_err_t esp_local_ctrl_start(const esp_local_ctrl_config_t *config); + +/** + * @brief Stop local control service + */ +esp_err_t esp_local_ctrl_stop(void); + +/** + * @brief Add a new property + * + * This adds a new property and allocates internal resources for it. + * The total number of properties that could be added is limited by + * configuration option `max_properties` + * + * @param[in] prop Property description structure + * + * @return + * - ESP_OK : Success + * - ESP_FAIL : Failure + */ +esp_err_t esp_local_ctrl_add_property(const esp_local_ctrl_prop_t *prop); + +/** + * @brief Remove a property + * + * This finds a property by name, and releases the internal resources + * which are associated with it. + * + * @param[in] name Name of the property to remove + * + * @return + * - ESP_OK : Success + * - ESP_ERR_NOT_FOUND : Failure + */ +esp_err_t esp_local_ctrl_remove_property(const char *name); + +/** + * @brief Get property description structure by name + * + * This API may be used to get a property's context structure + * `esp_local_ctrl_prop_t` when its name is known + * + * @param[in] name Name of the property to find + * + * @return + * - Pointer to property + * - NULL if not found + */ +const esp_local_ctrl_prop_t *esp_local_ctrl_get_property(const char *name); + +/** + * @brief Register protocomm handler for a custom endpoint + * + * This API can be called by the application to register a protocomm handler + * for an endpoint after the local control service has started. + * + * @note In case of BLE transport the names and uuids of all custom + * endpoints must be provided beforehand as a part of the `protocomm_ble_config_t` + * structure set in `esp_local_ctrl_config_t`, and passed to `esp_local_ctrl_start()`. + * + * @param[in] ep_name Name of the endpoint + * @param[in] handler Endpoint handler function + * @param[in] user_ctx User data + * + * @return + * - ESP_OK : Success + * - ESP_FAIL : Failure + */ +esp_err_t esp_local_ctrl_set_handler(const char *ep_name, + protocomm_req_handler_t handler, + void *user_ctx); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_local_ctrl/proto-c/esp_local_ctrl.pb-c.c b/components/esp_local_ctrl/proto-c/esp_local_ctrl.pb-c.c new file mode 100644 index 0000000000..a6dd76eb2e --- /dev/null +++ b/components/esp_local_ctrl/proto-c/esp_local_ctrl.pb-c.c @@ -0,0 +1,942 @@ +/* Generated by the protocol buffer compiler. DO NOT EDIT! */ +/* Generated from: esp_local_ctrl.proto */ + +/* Do not generate deprecated warnings for self */ +#ifndef PROTOBUF_C__NO_DEPRECATED +#define PROTOBUF_C__NO_DEPRECATED +#endif + +#include "esp_local_ctrl.pb-c.h" +void cmd_get_property_count__init + (CmdGetPropertyCount *message) +{ + static const CmdGetPropertyCount init_value = CMD_GET_PROPERTY_COUNT__INIT; + *message = init_value; +} +size_t cmd_get_property_count__get_packed_size + (const CmdGetPropertyCount *message) +{ + assert(message->base.descriptor == &cmd_get_property_count__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t cmd_get_property_count__pack + (const CmdGetPropertyCount *message, + uint8_t *out) +{ + assert(message->base.descriptor == &cmd_get_property_count__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t cmd_get_property_count__pack_to_buffer + (const CmdGetPropertyCount *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &cmd_get_property_count__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +CmdGetPropertyCount * + cmd_get_property_count__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (CmdGetPropertyCount *) + protobuf_c_message_unpack (&cmd_get_property_count__descriptor, + allocator, len, data); +} +void cmd_get_property_count__free_unpacked + (CmdGetPropertyCount *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &cmd_get_property_count__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void resp_get_property_count__init + (RespGetPropertyCount *message) +{ + static const RespGetPropertyCount init_value = RESP_GET_PROPERTY_COUNT__INIT; + *message = init_value; +} +size_t resp_get_property_count__get_packed_size + (const RespGetPropertyCount *message) +{ + assert(message->base.descriptor == &resp_get_property_count__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t resp_get_property_count__pack + (const RespGetPropertyCount *message, + uint8_t *out) +{ + assert(message->base.descriptor == &resp_get_property_count__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t resp_get_property_count__pack_to_buffer + (const RespGetPropertyCount *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &resp_get_property_count__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +RespGetPropertyCount * + resp_get_property_count__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (RespGetPropertyCount *) + protobuf_c_message_unpack (&resp_get_property_count__descriptor, + allocator, len, data); +} +void resp_get_property_count__free_unpacked + (RespGetPropertyCount *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &resp_get_property_count__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void property_info__init + (PropertyInfo *message) +{ + static const PropertyInfo init_value = PROPERTY_INFO__INIT; + *message = init_value; +} +size_t property_info__get_packed_size + (const PropertyInfo *message) +{ + assert(message->base.descriptor == &property_info__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t property_info__pack + (const PropertyInfo *message, + uint8_t *out) +{ + assert(message->base.descriptor == &property_info__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t property_info__pack_to_buffer + (const PropertyInfo *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &property_info__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +PropertyInfo * + property_info__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (PropertyInfo *) + protobuf_c_message_unpack (&property_info__descriptor, + allocator, len, data); +} +void property_info__free_unpacked + (PropertyInfo *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &property_info__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void cmd_get_property_values__init + (CmdGetPropertyValues *message) +{ + static const CmdGetPropertyValues init_value = CMD_GET_PROPERTY_VALUES__INIT; + *message = init_value; +} +size_t cmd_get_property_values__get_packed_size + (const CmdGetPropertyValues *message) +{ + assert(message->base.descriptor == &cmd_get_property_values__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t cmd_get_property_values__pack + (const CmdGetPropertyValues *message, + uint8_t *out) +{ + assert(message->base.descriptor == &cmd_get_property_values__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t cmd_get_property_values__pack_to_buffer + (const CmdGetPropertyValues *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &cmd_get_property_values__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +CmdGetPropertyValues * + cmd_get_property_values__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (CmdGetPropertyValues *) + protobuf_c_message_unpack (&cmd_get_property_values__descriptor, + allocator, len, data); +} +void cmd_get_property_values__free_unpacked + (CmdGetPropertyValues *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &cmd_get_property_values__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void resp_get_property_values__init + (RespGetPropertyValues *message) +{ + static const RespGetPropertyValues init_value = RESP_GET_PROPERTY_VALUES__INIT; + *message = init_value; +} +size_t resp_get_property_values__get_packed_size + (const RespGetPropertyValues *message) +{ + assert(message->base.descriptor == &resp_get_property_values__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t resp_get_property_values__pack + (const RespGetPropertyValues *message, + uint8_t *out) +{ + assert(message->base.descriptor == &resp_get_property_values__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t resp_get_property_values__pack_to_buffer + (const RespGetPropertyValues *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &resp_get_property_values__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +RespGetPropertyValues * + resp_get_property_values__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (RespGetPropertyValues *) + protobuf_c_message_unpack (&resp_get_property_values__descriptor, + allocator, len, data); +} +void resp_get_property_values__free_unpacked + (RespGetPropertyValues *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &resp_get_property_values__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void property_value__init + (PropertyValue *message) +{ + static const PropertyValue init_value = PROPERTY_VALUE__INIT; + *message = init_value; +} +size_t property_value__get_packed_size + (const PropertyValue *message) +{ + assert(message->base.descriptor == &property_value__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t property_value__pack + (const PropertyValue *message, + uint8_t *out) +{ + assert(message->base.descriptor == &property_value__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t property_value__pack_to_buffer + (const PropertyValue *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &property_value__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +PropertyValue * + property_value__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (PropertyValue *) + protobuf_c_message_unpack (&property_value__descriptor, + allocator, len, data); +} +void property_value__free_unpacked + (PropertyValue *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &property_value__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void cmd_set_property_values__init + (CmdSetPropertyValues *message) +{ + static const CmdSetPropertyValues init_value = CMD_SET_PROPERTY_VALUES__INIT; + *message = init_value; +} +size_t cmd_set_property_values__get_packed_size + (const CmdSetPropertyValues *message) +{ + assert(message->base.descriptor == &cmd_set_property_values__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t cmd_set_property_values__pack + (const CmdSetPropertyValues *message, + uint8_t *out) +{ + assert(message->base.descriptor == &cmd_set_property_values__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t cmd_set_property_values__pack_to_buffer + (const CmdSetPropertyValues *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &cmd_set_property_values__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +CmdSetPropertyValues * + cmd_set_property_values__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (CmdSetPropertyValues *) + protobuf_c_message_unpack (&cmd_set_property_values__descriptor, + allocator, len, data); +} +void cmd_set_property_values__free_unpacked + (CmdSetPropertyValues *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &cmd_set_property_values__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void resp_set_property_values__init + (RespSetPropertyValues *message) +{ + static const RespSetPropertyValues init_value = RESP_SET_PROPERTY_VALUES__INIT; + *message = init_value; +} +size_t resp_set_property_values__get_packed_size + (const RespSetPropertyValues *message) +{ + assert(message->base.descriptor == &resp_set_property_values__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t resp_set_property_values__pack + (const RespSetPropertyValues *message, + uint8_t *out) +{ + assert(message->base.descriptor == &resp_set_property_values__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t resp_set_property_values__pack_to_buffer + (const RespSetPropertyValues *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &resp_set_property_values__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +RespSetPropertyValues * + resp_set_property_values__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (RespSetPropertyValues *) + protobuf_c_message_unpack (&resp_set_property_values__descriptor, + allocator, len, data); +} +void resp_set_property_values__free_unpacked + (RespSetPropertyValues *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &resp_set_property_values__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void local_ctrl_message__init + (LocalCtrlMessage *message) +{ + static const LocalCtrlMessage init_value = LOCAL_CTRL_MESSAGE__INIT; + *message = init_value; +} +size_t local_ctrl_message__get_packed_size + (const LocalCtrlMessage *message) +{ + assert(message->base.descriptor == &local_ctrl_message__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t local_ctrl_message__pack + (const LocalCtrlMessage *message, + uint8_t *out) +{ + assert(message->base.descriptor == &local_ctrl_message__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t local_ctrl_message__pack_to_buffer + (const LocalCtrlMessage *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &local_ctrl_message__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +LocalCtrlMessage * + local_ctrl_message__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (LocalCtrlMessage *) + protobuf_c_message_unpack (&local_ctrl_message__descriptor, + allocator, len, data); +} +void local_ctrl_message__free_unpacked + (LocalCtrlMessage *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &local_ctrl_message__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +#define cmd_get_property_count__field_descriptors NULL +#define cmd_get_property_count__field_indices_by_name NULL +#define cmd_get_property_count__number_ranges NULL +const ProtobufCMessageDescriptor cmd_get_property_count__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "CmdGetPropertyCount", + "CmdGetPropertyCount", + "CmdGetPropertyCount", + "", + sizeof(CmdGetPropertyCount), + 0, + cmd_get_property_count__field_descriptors, + cmd_get_property_count__field_indices_by_name, + 0, cmd_get_property_count__number_ranges, + (ProtobufCMessageInit) cmd_get_property_count__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor resp_get_property_count__field_descriptors[2] = +{ + { + "status", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_ENUM, + 0, /* quantifier_offset */ + offsetof(RespGetPropertyCount, status), + &status__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "count", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(RespGetPropertyCount, count), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned resp_get_property_count__field_indices_by_name[] = { + 1, /* field[1] = count */ + 0, /* field[0] = status */ +}; +static const ProtobufCIntRange resp_get_property_count__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 2 } +}; +const ProtobufCMessageDescriptor resp_get_property_count__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "RespGetPropertyCount", + "RespGetPropertyCount", + "RespGetPropertyCount", + "", + sizeof(RespGetPropertyCount), + 2, + resp_get_property_count__field_descriptors, + resp_get_property_count__field_indices_by_name, + 1, resp_get_property_count__number_ranges, + (ProtobufCMessageInit) resp_get_property_count__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor property_info__field_descriptors[5] = +{ + { + "status", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_ENUM, + 0, /* quantifier_offset */ + offsetof(PropertyInfo, status), + &status__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "name", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(PropertyInfo, name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "type", + 3, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(PropertyInfo, type), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "flags", + 4, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(PropertyInfo, flags), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "value", + 5, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_BYTES, + 0, /* quantifier_offset */ + offsetof(PropertyInfo, value), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned property_info__field_indices_by_name[] = { + 3, /* field[3] = flags */ + 1, /* field[1] = name */ + 0, /* field[0] = status */ + 2, /* field[2] = type */ + 4, /* field[4] = value */ +}; +static const ProtobufCIntRange property_info__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 5 } +}; +const ProtobufCMessageDescriptor property_info__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "PropertyInfo", + "PropertyInfo", + "PropertyInfo", + "", + sizeof(PropertyInfo), + 5, + property_info__field_descriptors, + property_info__field_indices_by_name, + 1, property_info__number_ranges, + (ProtobufCMessageInit) property_info__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor cmd_get_property_values__field_descriptors[1] = +{ + { + "indices", + 1, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_UINT32, + offsetof(CmdGetPropertyValues, n_indices), + offsetof(CmdGetPropertyValues, indices), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned cmd_get_property_values__field_indices_by_name[] = { + 0, /* field[0] = indices */ +}; +static const ProtobufCIntRange cmd_get_property_values__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 1 } +}; +const ProtobufCMessageDescriptor cmd_get_property_values__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "CmdGetPropertyValues", + "CmdGetPropertyValues", + "CmdGetPropertyValues", + "", + sizeof(CmdGetPropertyValues), + 1, + cmd_get_property_values__field_descriptors, + cmd_get_property_values__field_indices_by_name, + 1, cmd_get_property_values__number_ranges, + (ProtobufCMessageInit) cmd_get_property_values__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor resp_get_property_values__field_descriptors[2] = +{ + { + "status", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_ENUM, + 0, /* quantifier_offset */ + offsetof(RespGetPropertyValues, status), + &status__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "props", + 2, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(RespGetPropertyValues, n_props), + offsetof(RespGetPropertyValues, props), + &property_info__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned resp_get_property_values__field_indices_by_name[] = { + 1, /* field[1] = props */ + 0, /* field[0] = status */ +}; +static const ProtobufCIntRange resp_get_property_values__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 2 } +}; +const ProtobufCMessageDescriptor resp_get_property_values__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "RespGetPropertyValues", + "RespGetPropertyValues", + "RespGetPropertyValues", + "", + sizeof(RespGetPropertyValues), + 2, + resp_get_property_values__field_descriptors, + resp_get_property_values__field_indices_by_name, + 1, resp_get_property_values__number_ranges, + (ProtobufCMessageInit) resp_get_property_values__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor property_value__field_descriptors[2] = +{ + { + "index", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(PropertyValue, index), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "value", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_BYTES, + 0, /* quantifier_offset */ + offsetof(PropertyValue, value), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned property_value__field_indices_by_name[] = { + 0, /* field[0] = index */ + 1, /* field[1] = value */ +}; +static const ProtobufCIntRange property_value__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 2 } +}; +const ProtobufCMessageDescriptor property_value__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "PropertyValue", + "PropertyValue", + "PropertyValue", + "", + sizeof(PropertyValue), + 2, + property_value__field_descriptors, + property_value__field_indices_by_name, + 1, property_value__number_ranges, + (ProtobufCMessageInit) property_value__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor cmd_set_property_values__field_descriptors[1] = +{ + { + "props", + 1, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(CmdSetPropertyValues, n_props), + offsetof(CmdSetPropertyValues, props), + &property_value__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned cmd_set_property_values__field_indices_by_name[] = { + 0, /* field[0] = props */ +}; +static const ProtobufCIntRange cmd_set_property_values__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 1 } +}; +const ProtobufCMessageDescriptor cmd_set_property_values__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "CmdSetPropertyValues", + "CmdSetPropertyValues", + "CmdSetPropertyValues", + "", + sizeof(CmdSetPropertyValues), + 1, + cmd_set_property_values__field_descriptors, + cmd_set_property_values__field_indices_by_name, + 1, cmd_set_property_values__number_ranges, + (ProtobufCMessageInit) cmd_set_property_values__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor resp_set_property_values__field_descriptors[1] = +{ + { + "status", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_ENUM, + 0, /* quantifier_offset */ + offsetof(RespSetPropertyValues, status), + &status__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned resp_set_property_values__field_indices_by_name[] = { + 0, /* field[0] = status */ +}; +static const ProtobufCIntRange resp_set_property_values__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 1 } +}; +const ProtobufCMessageDescriptor resp_set_property_values__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "RespSetPropertyValues", + "RespSetPropertyValues", + "RespSetPropertyValues", + "", + sizeof(RespSetPropertyValues), + 1, + resp_set_property_values__field_descriptors, + resp_set_property_values__field_indices_by_name, + 1, resp_set_property_values__number_ranges, + (ProtobufCMessageInit) resp_set_property_values__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor local_ctrl_message__field_descriptors[7] = +{ + { + "msg", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_ENUM, + 0, /* quantifier_offset */ + offsetof(LocalCtrlMessage, msg), + &local_ctrl_msg_type__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "cmd_get_prop_count", + 10, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(LocalCtrlMessage, payload_case), + offsetof(LocalCtrlMessage, cmd_get_prop_count), + &cmd_get_property_count__descriptor, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "resp_get_prop_count", + 11, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(LocalCtrlMessage, payload_case), + offsetof(LocalCtrlMessage, resp_get_prop_count), + &resp_get_property_count__descriptor, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "cmd_get_prop_vals", + 12, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(LocalCtrlMessage, payload_case), + offsetof(LocalCtrlMessage, cmd_get_prop_vals), + &cmd_get_property_values__descriptor, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "resp_get_prop_vals", + 13, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(LocalCtrlMessage, payload_case), + offsetof(LocalCtrlMessage, resp_get_prop_vals), + &resp_get_property_values__descriptor, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "cmd_set_prop_vals", + 14, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(LocalCtrlMessage, payload_case), + offsetof(LocalCtrlMessage, cmd_set_prop_vals), + &cmd_set_property_values__descriptor, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "resp_set_prop_vals", + 15, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(LocalCtrlMessage, payload_case), + offsetof(LocalCtrlMessage, resp_set_prop_vals), + &resp_set_property_values__descriptor, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned local_ctrl_message__field_indices_by_name[] = { + 1, /* field[1] = cmd_get_prop_count */ + 3, /* field[3] = cmd_get_prop_vals */ + 5, /* field[5] = cmd_set_prop_vals */ + 0, /* field[0] = msg */ + 2, /* field[2] = resp_get_prop_count */ + 4, /* field[4] = resp_get_prop_vals */ + 6, /* field[6] = resp_set_prop_vals */ +}; +static const ProtobufCIntRange local_ctrl_message__number_ranges[2 + 1] = +{ + { 1, 0 }, + { 10, 1 }, + { 0, 7 } +}; +const ProtobufCMessageDescriptor local_ctrl_message__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "LocalCtrlMessage", + "LocalCtrlMessage", + "LocalCtrlMessage", + "", + sizeof(LocalCtrlMessage), + 7, + local_ctrl_message__field_descriptors, + local_ctrl_message__field_indices_by_name, + 2, local_ctrl_message__number_ranges, + (ProtobufCMessageInit) local_ctrl_message__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCEnumValue local_ctrl_msg_type__enum_values_by_number[6] = +{ + { "TypeCmdGetPropertyCount", "LOCAL_CTRL_MSG_TYPE__TypeCmdGetPropertyCount", 0 }, + { "TypeRespGetPropertyCount", "LOCAL_CTRL_MSG_TYPE__TypeRespGetPropertyCount", 1 }, + { "TypeCmdGetPropertyValues", "LOCAL_CTRL_MSG_TYPE__TypeCmdGetPropertyValues", 4 }, + { "TypeRespGetPropertyValues", "LOCAL_CTRL_MSG_TYPE__TypeRespGetPropertyValues", 5 }, + { "TypeCmdSetPropertyValues", "LOCAL_CTRL_MSG_TYPE__TypeCmdSetPropertyValues", 6 }, + { "TypeRespSetPropertyValues", "LOCAL_CTRL_MSG_TYPE__TypeRespSetPropertyValues", 7 }, +}; +static const ProtobufCIntRange local_ctrl_msg_type__value_ranges[] = { +{0, 0},{4, 2},{0, 6} +}; +static const ProtobufCEnumValueIndex local_ctrl_msg_type__enum_values_by_name[6] = +{ + { "TypeCmdGetPropertyCount", 0 }, + { "TypeCmdGetPropertyValues", 2 }, + { "TypeCmdSetPropertyValues", 4 }, + { "TypeRespGetPropertyCount", 1 }, + { "TypeRespGetPropertyValues", 3 }, + { "TypeRespSetPropertyValues", 5 }, +}; +const ProtobufCEnumDescriptor local_ctrl_msg_type__descriptor = +{ + PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC, + "LocalCtrlMsgType", + "LocalCtrlMsgType", + "LocalCtrlMsgType", + "", + 6, + local_ctrl_msg_type__enum_values_by_number, + 6, + local_ctrl_msg_type__enum_values_by_name, + 2, + local_ctrl_msg_type__value_ranges, + NULL,NULL,NULL,NULL /* reserved[1234] */ +}; diff --git a/components/esp_local_ctrl/proto-c/esp_local_ctrl.pb-c.h b/components/esp_local_ctrl/proto-c/esp_local_ctrl.pb-c.h new file mode 100644 index 0000000000..1a1723ec48 --- /dev/null +++ b/components/esp_local_ctrl/proto-c/esp_local_ctrl.pb-c.h @@ -0,0 +1,383 @@ +/* Generated by the protocol buffer compiler. DO NOT EDIT! */ +/* Generated from: esp_local_ctrl.proto */ + +#ifndef PROTOBUF_C_esp_5flocal_5fctrl_2eproto__INCLUDED +#define PROTOBUF_C_esp_5flocal_5fctrl_2eproto__INCLUDED + +#include + +PROTOBUF_C__BEGIN_DECLS + +#if PROTOBUF_C_VERSION_NUMBER < 1003000 +# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers. +#elif 1003001 < PROTOBUF_C_MIN_COMPILER_VERSION +# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c. +#endif + +#include "constants.pb-c.h" + +typedef struct _CmdGetPropertyCount CmdGetPropertyCount; +typedef struct _RespGetPropertyCount RespGetPropertyCount; +typedef struct _PropertyInfo PropertyInfo; +typedef struct _CmdGetPropertyValues CmdGetPropertyValues; +typedef struct _RespGetPropertyValues RespGetPropertyValues; +typedef struct _PropertyValue PropertyValue; +typedef struct _CmdSetPropertyValues CmdSetPropertyValues; +typedef struct _RespSetPropertyValues RespSetPropertyValues; +typedef struct _LocalCtrlMessage LocalCtrlMessage; + + +/* --- enums --- */ + +typedef enum _LocalCtrlMsgType { + LOCAL_CTRL_MSG_TYPE__TypeCmdGetPropertyCount = 0, + LOCAL_CTRL_MSG_TYPE__TypeRespGetPropertyCount = 1, + LOCAL_CTRL_MSG_TYPE__TypeCmdGetPropertyValues = 4, + LOCAL_CTRL_MSG_TYPE__TypeRespGetPropertyValues = 5, + LOCAL_CTRL_MSG_TYPE__TypeCmdSetPropertyValues = 6, + LOCAL_CTRL_MSG_TYPE__TypeRespSetPropertyValues = 7 + PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(LOCAL_CTRL_MSG_TYPE) +} LocalCtrlMsgType; + +/* --- messages --- */ + +struct _CmdGetPropertyCount +{ + ProtobufCMessage base; +}; +#define CMD_GET_PROPERTY_COUNT__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&cmd_get_property_count__descriptor) \ + } + + +struct _RespGetPropertyCount +{ + ProtobufCMessage base; + Status status; + uint32_t count; +}; +#define RESP_GET_PROPERTY_COUNT__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&resp_get_property_count__descriptor) \ + , STATUS__Success, 0 } + + +struct _PropertyInfo +{ + ProtobufCMessage base; + Status status; + char *name; + uint32_t type; + uint32_t flags; + ProtobufCBinaryData value; +}; +#define PROPERTY_INFO__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&property_info__descriptor) \ + , STATUS__Success, (char *)protobuf_c_empty_string, 0, 0, {0,NULL} } + + +struct _CmdGetPropertyValues +{ + ProtobufCMessage base; + size_t n_indices; + uint32_t *indices; +}; +#define CMD_GET_PROPERTY_VALUES__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&cmd_get_property_values__descriptor) \ + , 0,NULL } + + +struct _RespGetPropertyValues +{ + ProtobufCMessage base; + Status status; + size_t n_props; + PropertyInfo **props; +}; +#define RESP_GET_PROPERTY_VALUES__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&resp_get_property_values__descriptor) \ + , STATUS__Success, 0,NULL } + + +struct _PropertyValue +{ + ProtobufCMessage base; + uint32_t index; + ProtobufCBinaryData value; +}; +#define PROPERTY_VALUE__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&property_value__descriptor) \ + , 0, {0,NULL} } + + +struct _CmdSetPropertyValues +{ + ProtobufCMessage base; + size_t n_props; + PropertyValue **props; +}; +#define CMD_SET_PROPERTY_VALUES__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&cmd_set_property_values__descriptor) \ + , 0,NULL } + + +struct _RespSetPropertyValues +{ + ProtobufCMessage base; + Status status; +}; +#define RESP_SET_PROPERTY_VALUES__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&resp_set_property_values__descriptor) \ + , STATUS__Success } + + +typedef enum { + LOCAL_CTRL_MESSAGE__PAYLOAD__NOT_SET = 0, + LOCAL_CTRL_MESSAGE__PAYLOAD_CMD_GET_PROP_COUNT = 10, + LOCAL_CTRL_MESSAGE__PAYLOAD_RESP_GET_PROP_COUNT = 11, + LOCAL_CTRL_MESSAGE__PAYLOAD_CMD_GET_PROP_VALS = 12, + LOCAL_CTRL_MESSAGE__PAYLOAD_RESP_GET_PROP_VALS = 13, + LOCAL_CTRL_MESSAGE__PAYLOAD_CMD_SET_PROP_VALS = 14, + LOCAL_CTRL_MESSAGE__PAYLOAD_RESP_SET_PROP_VALS = 15 + PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(LOCAL_CTRL_MESSAGE__PAYLOAD) +} LocalCtrlMessage__PayloadCase; + +struct _LocalCtrlMessage +{ + ProtobufCMessage base; + LocalCtrlMsgType msg; + LocalCtrlMessage__PayloadCase payload_case; + union { + CmdGetPropertyCount *cmd_get_prop_count; + RespGetPropertyCount *resp_get_prop_count; + CmdGetPropertyValues *cmd_get_prop_vals; + RespGetPropertyValues *resp_get_prop_vals; + CmdSetPropertyValues *cmd_set_prop_vals; + RespSetPropertyValues *resp_set_prop_vals; + }; +}; +#define LOCAL_CTRL_MESSAGE__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&local_ctrl_message__descriptor) \ + , LOCAL_CTRL_MSG_TYPE__TypeCmdGetPropertyCount, LOCAL_CTRL_MESSAGE__PAYLOAD__NOT_SET, {0} } + + +/* CmdGetPropertyCount methods */ +void cmd_get_property_count__init + (CmdGetPropertyCount *message); +size_t cmd_get_property_count__get_packed_size + (const CmdGetPropertyCount *message); +size_t cmd_get_property_count__pack + (const CmdGetPropertyCount *message, + uint8_t *out); +size_t cmd_get_property_count__pack_to_buffer + (const CmdGetPropertyCount *message, + ProtobufCBuffer *buffer); +CmdGetPropertyCount * + cmd_get_property_count__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void cmd_get_property_count__free_unpacked + (CmdGetPropertyCount *message, + ProtobufCAllocator *allocator); +/* RespGetPropertyCount methods */ +void resp_get_property_count__init + (RespGetPropertyCount *message); +size_t resp_get_property_count__get_packed_size + (const RespGetPropertyCount *message); +size_t resp_get_property_count__pack + (const RespGetPropertyCount *message, + uint8_t *out); +size_t resp_get_property_count__pack_to_buffer + (const RespGetPropertyCount *message, + ProtobufCBuffer *buffer); +RespGetPropertyCount * + resp_get_property_count__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void resp_get_property_count__free_unpacked + (RespGetPropertyCount *message, + ProtobufCAllocator *allocator); +/* PropertyInfo methods */ +void property_info__init + (PropertyInfo *message); +size_t property_info__get_packed_size + (const PropertyInfo *message); +size_t property_info__pack + (const PropertyInfo *message, + uint8_t *out); +size_t property_info__pack_to_buffer + (const PropertyInfo *message, + ProtobufCBuffer *buffer); +PropertyInfo * + property_info__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void property_info__free_unpacked + (PropertyInfo *message, + ProtobufCAllocator *allocator); +/* CmdGetPropertyValues methods */ +void cmd_get_property_values__init + (CmdGetPropertyValues *message); +size_t cmd_get_property_values__get_packed_size + (const CmdGetPropertyValues *message); +size_t cmd_get_property_values__pack + (const CmdGetPropertyValues *message, + uint8_t *out); +size_t cmd_get_property_values__pack_to_buffer + (const CmdGetPropertyValues *message, + ProtobufCBuffer *buffer); +CmdGetPropertyValues * + cmd_get_property_values__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void cmd_get_property_values__free_unpacked + (CmdGetPropertyValues *message, + ProtobufCAllocator *allocator); +/* RespGetPropertyValues methods */ +void resp_get_property_values__init + (RespGetPropertyValues *message); +size_t resp_get_property_values__get_packed_size + (const RespGetPropertyValues *message); +size_t resp_get_property_values__pack + (const RespGetPropertyValues *message, + uint8_t *out); +size_t resp_get_property_values__pack_to_buffer + (const RespGetPropertyValues *message, + ProtobufCBuffer *buffer); +RespGetPropertyValues * + resp_get_property_values__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void resp_get_property_values__free_unpacked + (RespGetPropertyValues *message, + ProtobufCAllocator *allocator); +/* PropertyValue methods */ +void property_value__init + (PropertyValue *message); +size_t property_value__get_packed_size + (const PropertyValue *message); +size_t property_value__pack + (const PropertyValue *message, + uint8_t *out); +size_t property_value__pack_to_buffer + (const PropertyValue *message, + ProtobufCBuffer *buffer); +PropertyValue * + property_value__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void property_value__free_unpacked + (PropertyValue *message, + ProtobufCAllocator *allocator); +/* CmdSetPropertyValues methods */ +void cmd_set_property_values__init + (CmdSetPropertyValues *message); +size_t cmd_set_property_values__get_packed_size + (const CmdSetPropertyValues *message); +size_t cmd_set_property_values__pack + (const CmdSetPropertyValues *message, + uint8_t *out); +size_t cmd_set_property_values__pack_to_buffer + (const CmdSetPropertyValues *message, + ProtobufCBuffer *buffer); +CmdSetPropertyValues * + cmd_set_property_values__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void cmd_set_property_values__free_unpacked + (CmdSetPropertyValues *message, + ProtobufCAllocator *allocator); +/* RespSetPropertyValues methods */ +void resp_set_property_values__init + (RespSetPropertyValues *message); +size_t resp_set_property_values__get_packed_size + (const RespSetPropertyValues *message); +size_t resp_set_property_values__pack + (const RespSetPropertyValues *message, + uint8_t *out); +size_t resp_set_property_values__pack_to_buffer + (const RespSetPropertyValues *message, + ProtobufCBuffer *buffer); +RespSetPropertyValues * + resp_set_property_values__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void resp_set_property_values__free_unpacked + (RespSetPropertyValues *message, + ProtobufCAllocator *allocator); +/* LocalCtrlMessage methods */ +void local_ctrl_message__init + (LocalCtrlMessage *message); +size_t local_ctrl_message__get_packed_size + (const LocalCtrlMessage *message); +size_t local_ctrl_message__pack + (const LocalCtrlMessage *message, + uint8_t *out); +size_t local_ctrl_message__pack_to_buffer + (const LocalCtrlMessage *message, + ProtobufCBuffer *buffer); +LocalCtrlMessage * + local_ctrl_message__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void local_ctrl_message__free_unpacked + (LocalCtrlMessage *message, + ProtobufCAllocator *allocator); +/* --- per-message closures --- */ + +typedef void (*CmdGetPropertyCount_Closure) + (const CmdGetPropertyCount *message, + void *closure_data); +typedef void (*RespGetPropertyCount_Closure) + (const RespGetPropertyCount *message, + void *closure_data); +typedef void (*PropertyInfo_Closure) + (const PropertyInfo *message, + void *closure_data); +typedef void (*CmdGetPropertyValues_Closure) + (const CmdGetPropertyValues *message, + void *closure_data); +typedef void (*RespGetPropertyValues_Closure) + (const RespGetPropertyValues *message, + void *closure_data); +typedef void (*PropertyValue_Closure) + (const PropertyValue *message, + void *closure_data); +typedef void (*CmdSetPropertyValues_Closure) + (const CmdSetPropertyValues *message, + void *closure_data); +typedef void (*RespSetPropertyValues_Closure) + (const RespSetPropertyValues *message, + void *closure_data); +typedef void (*LocalCtrlMessage_Closure) + (const LocalCtrlMessage *message, + void *closure_data); + +/* --- services --- */ + + +/* --- descriptors --- */ + +extern const ProtobufCEnumDescriptor local_ctrl_msg_type__descriptor; +extern const ProtobufCMessageDescriptor cmd_get_property_count__descriptor; +extern const ProtobufCMessageDescriptor resp_get_property_count__descriptor; +extern const ProtobufCMessageDescriptor property_info__descriptor; +extern const ProtobufCMessageDescriptor cmd_get_property_values__descriptor; +extern const ProtobufCMessageDescriptor resp_get_property_values__descriptor; +extern const ProtobufCMessageDescriptor property_value__descriptor; +extern const ProtobufCMessageDescriptor cmd_set_property_values__descriptor; +extern const ProtobufCMessageDescriptor resp_set_property_values__descriptor; +extern const ProtobufCMessageDescriptor local_ctrl_message__descriptor; + +PROTOBUF_C__END_DECLS + + +#endif /* PROTOBUF_C_esp_5flocal_5fctrl_2eproto__INCLUDED */ diff --git a/components/esp_local_ctrl/proto/CMakeLists.txt b/components/esp_local_ctrl/proto/CMakeLists.txt new file mode 100644 index 0000000000..3bcc8e87df --- /dev/null +++ b/components/esp_local_ctrl/proto/CMakeLists.txt @@ -0,0 +1,27 @@ +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 "esp_local_ctrl.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/esp_local_ctrl/proto/README.md b/components/esp_local_ctrl/proto/README.md new file mode 100644 index 0000000000..cdb4e2ce2a --- /dev/null +++ b/components/esp_local_ctrl/proto/README.md @@ -0,0 +1,25 @@ +# Protobuf files for defining ESP Local Control message structures + +The proto files under this directory are used by esp_local_ctrl for defining protobuf messages which are sent and received over protocomm transport layer. These proto files cannot be used directly and have to be compiled into C and Python files. The generated C files are used by esp_local_ctrl itself to create, delete and manipulate transaction packets. The generated Python files can be used by python based applications for implementing client side interface to esp_local_ctrl service running on a device. + +Note : These proto files are not automatically compiled during the build process. + +# Compilation + +Compilation requires protoc (Protobuf Compiler) and protoc-c (Protobuf C Compiler) installed. Since the generated files are to remain the same, as long as the proto files are not modified, therefore the generated files are already available under `components/esp_local_ctrl/proto-c` and `components/esp_local_ctrl/python` directories, and thus running `cmake` / `make` (and installing the Protobuf compilers) is optional. + +If using `cmake` follow the below steps. If using `make`, jump to Step 2 directly. + +## Step 1 (Only for cmake) + +When using cmake, first create a build directory and call cmake from inside: + +``` +mkdir build +cd build +cmake .. +``` + +## Step 2 + +Simply run `make` to generate the respective C and Python files. The newly created files will overwrite those under `components/esp_local_ctrl/proto-c` and `components/esp_local_ctrl/python` diff --git a/components/esp_local_ctrl/proto/esp_local_ctrl.proto b/components/esp_local_ctrl/proto/esp_local_ctrl.proto new file mode 100644 index 0000000000..1d91b56c2d --- /dev/null +++ b/components/esp_local_ctrl/proto/esp_local_ctrl.proto @@ -0,0 +1,62 @@ +syntax = "proto3"; + +import "constants.proto"; + +message CmdGetPropertyCount { +} + +message RespGetPropertyCount { + Status status = 1; + uint32 count = 2; +} + +message PropertyInfo { + Status status = 1; + string name = 2; + uint32 type = 3; + uint32 flags = 4; + bytes value = 5; +} + +message CmdGetPropertyValues { + repeated uint32 indices = 1; +} + +message RespGetPropertyValues { + Status status = 1; + repeated PropertyInfo props = 2; +} + +message PropertyValue { + uint32 index = 1; + bytes value = 2; +} + +message CmdSetPropertyValues { + repeated PropertyValue props = 1; +} + +message RespSetPropertyValues { + Status status = 1; +} + +enum LocalCtrlMsgType { + TypeCmdGetPropertyCount = 0; + TypeRespGetPropertyCount = 1; + TypeCmdGetPropertyValues = 4; + TypeRespGetPropertyValues = 5; + TypeCmdSetPropertyValues = 6; + TypeRespSetPropertyValues = 7; +} + +message LocalCtrlMessage { + LocalCtrlMsgType msg = 1; + oneof payload { + CmdGetPropertyCount cmd_get_prop_count = 10; + RespGetPropertyCount resp_get_prop_count = 11; + CmdGetPropertyValues cmd_get_prop_vals = 12; + RespGetPropertyValues resp_get_prop_vals = 13; + CmdSetPropertyValues cmd_set_prop_vals = 14; + RespSetPropertyValues resp_set_prop_vals = 15; + } +} diff --git a/components/esp_local_ctrl/proto/makefile b/components/esp_local_ctrl/proto/makefile new file mode 100644 index 0000000000..585e42267b --- /dev/null +++ b/components/esp_local_ctrl/proto/makefile @@ -0,0 +1,7 @@ +all: c_proto python_proto + +c_proto: *.proto + @protoc-c --c_out=../proto-c/ -I . -I ../../protocomm/proto/ *.proto + +python_proto: *.proto + @protoc --python_out=../python/ -I . -I ../../protocomm/proto/ *.proto diff --git a/components/esp_local_ctrl/python/esp_local_ctrl_pb2.py b/components/esp_local_ctrl/python/esp_local_ctrl_pb2.py new file mode 100644 index 0000000000..39f081f230 --- /dev/null +++ b/components/esp_local_ctrl/python/esp_local_ctrl_pb2.py @@ -0,0 +1,549 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: esp_local_ctrl.proto + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf.internal import enum_type_wrapper +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +import constants_pb2 as constants__pb2 + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='esp_local_ctrl.proto', + package='', + syntax='proto3', + serialized_options=None, + serialized_pb=_b('\n\x14\x65sp_local_ctrl.proto\x1a\x0f\x63onstants.proto\"\x15\n\x13\x43mdGetPropertyCount\">\n\x14RespGetPropertyCount\x12\x17\n\x06status\x18\x01 \x01(\x0e\x32\x07.Status\x12\r\n\x05\x63ount\x18\x02 \x01(\r\"a\n\x0cPropertyInfo\x12\x17\n\x06status\x18\x01 \x01(\x0e\x32\x07.Status\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0c\n\x04type\x18\x03 \x01(\r\x12\r\n\x05\x66lags\x18\x04 \x01(\r\x12\r\n\x05value\x18\x05 \x01(\x0c\"\'\n\x14\x43mdGetPropertyValues\x12\x0f\n\x07indices\x18\x01 \x03(\r\"N\n\x15RespGetPropertyValues\x12\x17\n\x06status\x18\x01 \x01(\x0e\x32\x07.Status\x12\x1c\n\x05props\x18\x02 \x03(\x0b\x32\r.PropertyInfo\"-\n\rPropertyValue\x12\r\n\x05index\x18\x01 \x01(\r\x12\r\n\x05value\x18\x02 \x01(\x0c\"5\n\x14\x43mdSetPropertyValues\x12\x1d\n\x05props\x18\x01 \x03(\x0b\x32\x0e.PropertyValue\"0\n\x15RespSetPropertyValues\x12\x17\n\x06status\x18\x01 \x01(\x0e\x32\x07.Status\"\xfb\x02\n\x10LocalCtrlMessage\x12\x1e\n\x03msg\x18\x01 \x01(\x0e\x32\x11.LocalCtrlMsgType\x12\x32\n\x12\x63md_get_prop_count\x18\n \x01(\x0b\x32\x14.CmdGetPropertyCountH\x00\x12\x34\n\x13resp_get_prop_count\x18\x0b \x01(\x0b\x32\x15.RespGetPropertyCountH\x00\x12\x32\n\x11\x63md_get_prop_vals\x18\x0c \x01(\x0b\x32\x15.CmdGetPropertyValuesH\x00\x12\x34\n\x12resp_get_prop_vals\x18\r \x01(\x0b\x32\x16.RespGetPropertyValuesH\x00\x12\x32\n\x11\x63md_set_prop_vals\x18\x0e \x01(\x0b\x32\x15.CmdSetPropertyValuesH\x00\x12\x34\n\x12resp_set_prop_vals\x18\x0f \x01(\x0b\x32\x16.RespSetPropertyValuesH\x00\x42\t\n\x07payload*\xc7\x01\n\x10LocalCtrlMsgType\x12\x1b\n\x17TypeCmdGetPropertyCount\x10\x00\x12\x1c\n\x18TypeRespGetPropertyCount\x10\x01\x12\x1c\n\x18TypeCmdGetPropertyValues\x10\x04\x12\x1d\n\x19TypeRespGetPropertyValues\x10\x05\x12\x1c\n\x18TypeCmdSetPropertyValues\x10\x06\x12\x1d\n\x19TypeRespSetPropertyValues\x10\x07\x62\x06proto3') + , + dependencies=[constants__pb2.DESCRIPTOR,]) + +_LOCALCTRLMSGTYPE = _descriptor.EnumDescriptor( + name='LocalCtrlMsgType', + full_name='LocalCtrlMsgType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='TypeCmdGetPropertyCount', index=0, number=0, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='TypeRespGetPropertyCount', index=1, number=1, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='TypeCmdGetPropertyValues', index=2, number=4, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='TypeRespGetPropertyValues', index=3, number=5, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='TypeCmdSetPropertyValues', index=4, number=6, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='TypeRespSetPropertyValues', index=5, number=7, + serialized_options=None, + type=None), + ], + containing_type=None, + serialized_options=None, + serialized_start=883, + serialized_end=1082, +) +_sym_db.RegisterEnumDescriptor(_LOCALCTRLMSGTYPE) + +LocalCtrlMsgType = enum_type_wrapper.EnumTypeWrapper(_LOCALCTRLMSGTYPE) +TypeCmdGetPropertyCount = 0 +TypeRespGetPropertyCount = 1 +TypeCmdGetPropertyValues = 4 +TypeRespGetPropertyValues = 5 +TypeCmdSetPropertyValues = 6 +TypeRespSetPropertyValues = 7 + + + +_CMDGETPROPERTYCOUNT = _descriptor.Descriptor( + name='CmdGetPropertyCount', + full_name='CmdGetPropertyCount', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=41, + serialized_end=62, +) + + +_RESPGETPROPERTYCOUNT = _descriptor.Descriptor( + name='RespGetPropertyCount', + full_name='RespGetPropertyCount', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='status', full_name='RespGetPropertyCount.status', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='count', full_name='RespGetPropertyCount.count', index=1, + number=2, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=64, + serialized_end=126, +) + + +_PROPERTYINFO = _descriptor.Descriptor( + name='PropertyInfo', + full_name='PropertyInfo', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='status', full_name='PropertyInfo.status', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='name', full_name='PropertyInfo.name', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='type', full_name='PropertyInfo.type', index=2, + number=3, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='flags', full_name='PropertyInfo.flags', index=3, + number=4, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='value', full_name='PropertyInfo.value', index=4, + number=5, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=128, + serialized_end=225, +) + + +_CMDGETPROPERTYVALUES = _descriptor.Descriptor( + name='CmdGetPropertyValues', + full_name='CmdGetPropertyValues', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='indices', full_name='CmdGetPropertyValues.indices', index=0, + number=1, type=13, cpp_type=3, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=227, + serialized_end=266, +) + + +_RESPGETPROPERTYVALUES = _descriptor.Descriptor( + name='RespGetPropertyValues', + full_name='RespGetPropertyValues', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='status', full_name='RespGetPropertyValues.status', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='props', full_name='RespGetPropertyValues.props', index=1, + number=2, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=268, + serialized_end=346, +) + + +_PROPERTYVALUE = _descriptor.Descriptor( + name='PropertyValue', + full_name='PropertyValue', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='index', full_name='PropertyValue.index', index=0, + number=1, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='value', full_name='PropertyValue.value', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=_b(""), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=348, + serialized_end=393, +) + + +_CMDSETPROPERTYVALUES = _descriptor.Descriptor( + name='CmdSetPropertyValues', + full_name='CmdSetPropertyValues', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='props', full_name='CmdSetPropertyValues.props', index=0, + number=1, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=395, + serialized_end=448, +) + + +_RESPSETPROPERTYVALUES = _descriptor.Descriptor( + name='RespSetPropertyValues', + full_name='RespSetPropertyValues', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='status', full_name='RespSetPropertyValues.status', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=450, + serialized_end=498, +) + + +_LOCALCTRLMESSAGE = _descriptor.Descriptor( + name='LocalCtrlMessage', + full_name='LocalCtrlMessage', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='msg', full_name='LocalCtrlMessage.msg', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='cmd_get_prop_count', full_name='LocalCtrlMessage.cmd_get_prop_count', index=1, + number=10, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='resp_get_prop_count', full_name='LocalCtrlMessage.resp_get_prop_count', index=2, + number=11, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='cmd_get_prop_vals', full_name='LocalCtrlMessage.cmd_get_prop_vals', index=3, + number=12, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='resp_get_prop_vals', full_name='LocalCtrlMessage.resp_get_prop_vals', index=4, + number=13, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='cmd_set_prop_vals', full_name='LocalCtrlMessage.cmd_set_prop_vals', index=5, + number=14, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='resp_set_prop_vals', full_name='LocalCtrlMessage.resp_set_prop_vals', index=6, + number=15, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='payload', full_name='LocalCtrlMessage.payload', + index=0, containing_type=None, fields=[]), + ], + serialized_start=501, + serialized_end=880, +) + +_RESPGETPROPERTYCOUNT.fields_by_name['status'].enum_type = constants__pb2._STATUS +_PROPERTYINFO.fields_by_name['status'].enum_type = constants__pb2._STATUS +_RESPGETPROPERTYVALUES.fields_by_name['status'].enum_type = constants__pb2._STATUS +_RESPGETPROPERTYVALUES.fields_by_name['props'].message_type = _PROPERTYINFO +_CMDSETPROPERTYVALUES.fields_by_name['props'].message_type = _PROPERTYVALUE +_RESPSETPROPERTYVALUES.fields_by_name['status'].enum_type = constants__pb2._STATUS +_LOCALCTRLMESSAGE.fields_by_name['msg'].enum_type = _LOCALCTRLMSGTYPE +_LOCALCTRLMESSAGE.fields_by_name['cmd_get_prop_count'].message_type = _CMDGETPROPERTYCOUNT +_LOCALCTRLMESSAGE.fields_by_name['resp_get_prop_count'].message_type = _RESPGETPROPERTYCOUNT +_LOCALCTRLMESSAGE.fields_by_name['cmd_get_prop_vals'].message_type = _CMDGETPROPERTYVALUES +_LOCALCTRLMESSAGE.fields_by_name['resp_get_prop_vals'].message_type = _RESPGETPROPERTYVALUES +_LOCALCTRLMESSAGE.fields_by_name['cmd_set_prop_vals'].message_type = _CMDSETPROPERTYVALUES +_LOCALCTRLMESSAGE.fields_by_name['resp_set_prop_vals'].message_type = _RESPSETPROPERTYVALUES +_LOCALCTRLMESSAGE.oneofs_by_name['payload'].fields.append( + _LOCALCTRLMESSAGE.fields_by_name['cmd_get_prop_count']) +_LOCALCTRLMESSAGE.fields_by_name['cmd_get_prop_count'].containing_oneof = _LOCALCTRLMESSAGE.oneofs_by_name['payload'] +_LOCALCTRLMESSAGE.oneofs_by_name['payload'].fields.append( + _LOCALCTRLMESSAGE.fields_by_name['resp_get_prop_count']) +_LOCALCTRLMESSAGE.fields_by_name['resp_get_prop_count'].containing_oneof = _LOCALCTRLMESSAGE.oneofs_by_name['payload'] +_LOCALCTRLMESSAGE.oneofs_by_name['payload'].fields.append( + _LOCALCTRLMESSAGE.fields_by_name['cmd_get_prop_vals']) +_LOCALCTRLMESSAGE.fields_by_name['cmd_get_prop_vals'].containing_oneof = _LOCALCTRLMESSAGE.oneofs_by_name['payload'] +_LOCALCTRLMESSAGE.oneofs_by_name['payload'].fields.append( + _LOCALCTRLMESSAGE.fields_by_name['resp_get_prop_vals']) +_LOCALCTRLMESSAGE.fields_by_name['resp_get_prop_vals'].containing_oneof = _LOCALCTRLMESSAGE.oneofs_by_name['payload'] +_LOCALCTRLMESSAGE.oneofs_by_name['payload'].fields.append( + _LOCALCTRLMESSAGE.fields_by_name['cmd_set_prop_vals']) +_LOCALCTRLMESSAGE.fields_by_name['cmd_set_prop_vals'].containing_oneof = _LOCALCTRLMESSAGE.oneofs_by_name['payload'] +_LOCALCTRLMESSAGE.oneofs_by_name['payload'].fields.append( + _LOCALCTRLMESSAGE.fields_by_name['resp_set_prop_vals']) +_LOCALCTRLMESSAGE.fields_by_name['resp_set_prop_vals'].containing_oneof = _LOCALCTRLMESSAGE.oneofs_by_name['payload'] +DESCRIPTOR.message_types_by_name['CmdGetPropertyCount'] = _CMDGETPROPERTYCOUNT +DESCRIPTOR.message_types_by_name['RespGetPropertyCount'] = _RESPGETPROPERTYCOUNT +DESCRIPTOR.message_types_by_name['PropertyInfo'] = _PROPERTYINFO +DESCRIPTOR.message_types_by_name['CmdGetPropertyValues'] = _CMDGETPROPERTYVALUES +DESCRIPTOR.message_types_by_name['RespGetPropertyValues'] = _RESPGETPROPERTYVALUES +DESCRIPTOR.message_types_by_name['PropertyValue'] = _PROPERTYVALUE +DESCRIPTOR.message_types_by_name['CmdSetPropertyValues'] = _CMDSETPROPERTYVALUES +DESCRIPTOR.message_types_by_name['RespSetPropertyValues'] = _RESPSETPROPERTYVALUES +DESCRIPTOR.message_types_by_name['LocalCtrlMessage'] = _LOCALCTRLMESSAGE +DESCRIPTOR.enum_types_by_name['LocalCtrlMsgType'] = _LOCALCTRLMSGTYPE +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +CmdGetPropertyCount = _reflection.GeneratedProtocolMessageType('CmdGetPropertyCount', (_message.Message,), dict( + DESCRIPTOR = _CMDGETPROPERTYCOUNT, + __module__ = 'esp_local_ctrl_pb2' + # @@protoc_insertion_point(class_scope:CmdGetPropertyCount) + )) +_sym_db.RegisterMessage(CmdGetPropertyCount) + +RespGetPropertyCount = _reflection.GeneratedProtocolMessageType('RespGetPropertyCount', (_message.Message,), dict( + DESCRIPTOR = _RESPGETPROPERTYCOUNT, + __module__ = 'esp_local_ctrl_pb2' + # @@protoc_insertion_point(class_scope:RespGetPropertyCount) + )) +_sym_db.RegisterMessage(RespGetPropertyCount) + +PropertyInfo = _reflection.GeneratedProtocolMessageType('PropertyInfo', (_message.Message,), dict( + DESCRIPTOR = _PROPERTYINFO, + __module__ = 'esp_local_ctrl_pb2' + # @@protoc_insertion_point(class_scope:PropertyInfo) + )) +_sym_db.RegisterMessage(PropertyInfo) + +CmdGetPropertyValues = _reflection.GeneratedProtocolMessageType('CmdGetPropertyValues', (_message.Message,), dict( + DESCRIPTOR = _CMDGETPROPERTYVALUES, + __module__ = 'esp_local_ctrl_pb2' + # @@protoc_insertion_point(class_scope:CmdGetPropertyValues) + )) +_sym_db.RegisterMessage(CmdGetPropertyValues) + +RespGetPropertyValues = _reflection.GeneratedProtocolMessageType('RespGetPropertyValues', (_message.Message,), dict( + DESCRIPTOR = _RESPGETPROPERTYVALUES, + __module__ = 'esp_local_ctrl_pb2' + # @@protoc_insertion_point(class_scope:RespGetPropertyValues) + )) +_sym_db.RegisterMessage(RespGetPropertyValues) + +PropertyValue = _reflection.GeneratedProtocolMessageType('PropertyValue', (_message.Message,), dict( + DESCRIPTOR = _PROPERTYVALUE, + __module__ = 'esp_local_ctrl_pb2' + # @@protoc_insertion_point(class_scope:PropertyValue) + )) +_sym_db.RegisterMessage(PropertyValue) + +CmdSetPropertyValues = _reflection.GeneratedProtocolMessageType('CmdSetPropertyValues', (_message.Message,), dict( + DESCRIPTOR = _CMDSETPROPERTYVALUES, + __module__ = 'esp_local_ctrl_pb2' + # @@protoc_insertion_point(class_scope:CmdSetPropertyValues) + )) +_sym_db.RegisterMessage(CmdSetPropertyValues) + +RespSetPropertyValues = _reflection.GeneratedProtocolMessageType('RespSetPropertyValues', (_message.Message,), dict( + DESCRIPTOR = _RESPSETPROPERTYVALUES, + __module__ = 'esp_local_ctrl_pb2' + # @@protoc_insertion_point(class_scope:RespSetPropertyValues) + )) +_sym_db.RegisterMessage(RespSetPropertyValues) + +LocalCtrlMessage = _reflection.GeneratedProtocolMessageType('LocalCtrlMessage', (_message.Message,), dict( + DESCRIPTOR = _LOCALCTRLMESSAGE, + __module__ = 'esp_local_ctrl_pb2' + # @@protoc_insertion_point(class_scope:LocalCtrlMessage) + )) +_sym_db.RegisterMessage(LocalCtrlMessage) + + +# @@protoc_insertion_point(module_scope) diff --git a/components/esp_local_ctrl/src/esp_local_ctrl.c b/components/esp_local_ctrl/src/esp_local_ctrl.c new file mode 100644 index 0000000000..1eead4d7c1 --- /dev/null +++ b/components/esp_local_ctrl/src/esp_local_ctrl.c @@ -0,0 +1,417 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include + +#include +#include + +#include +#include "esp_local_ctrl_priv.h" +#include "esp_local_ctrl.pb-c.h" + +#define ESP_LOCAL_CTRL_VERSION "v1.0" + +struct inst_ctx { + protocomm_t *pc; + esp_local_ctrl_config_t config; + esp_local_ctrl_prop_t **props; + size_t props_count; +}; + +struct inst_ctx *local_ctrl_inst_ctx; + +static const char *TAG = "esp_local_ctrl"; + +esp_err_t esp_local_ctrl_start(const esp_local_ctrl_config_t *config) +{ + esp_err_t ret; + + if (!config) { + ESP_LOGE(TAG, "NULL configuration provided"); + return ESP_ERR_INVALID_ARG; + } + + if (!config->transport) { + ESP_LOGE(TAG, "No transport provided"); + return ESP_ERR_INVALID_ARG; + } + + if (config->max_properties == 0) { + ESP_LOGE(TAG, "max_properties must be greater than 0"); + return ESP_ERR_INVALID_ARG; + } + + if (!config->handlers.get_prop_values || + !config->handlers.set_prop_values) { + ESP_LOGE(TAG, "Handlers cannot be null"); + return ESP_ERR_INVALID_ARG; + } + + if (local_ctrl_inst_ctx) { + ESP_LOGW(TAG, "Service already active"); + return ESP_ERR_INVALID_STATE; + } + + local_ctrl_inst_ctx = calloc(1, sizeof(struct inst_ctx)); + if (!local_ctrl_inst_ctx) { + ESP_LOGE(TAG, "Failed to allocate memory for instance"); + return ESP_ERR_NO_MEM; + } + memcpy(&local_ctrl_inst_ctx->config, config, sizeof(local_ctrl_inst_ctx->config)); + + local_ctrl_inst_ctx->props = calloc(local_ctrl_inst_ctx->config.max_properties, + sizeof(esp_local_ctrl_prop_t *)); + if (!local_ctrl_inst_ctx->props) { + ESP_LOGE(TAG, "Failed to allocate memory for properties"); + free(local_ctrl_inst_ctx); + local_ctrl_inst_ctx = NULL; + return ESP_ERR_NO_MEM; + } + + /* Since the config structure will be different for different transport modes, each transport may + * implement a `copy_config()` function, which accepts a configuration structure as input and + * creates a copy of that, which can be kept in the context structure of the `esp_local_ctrl` instance. + * This copy can be later be freed using `free_config()` */ + if (config->transport->copy_config) { + ret = config->transport->copy_config(&local_ctrl_inst_ctx->config.transport_config, + &config->transport_config); + if (ret != ESP_OK) { + esp_local_ctrl_stop(); + return ret; + } + } + + /* For a selected transport mode, endpoints may need to be declared prior to starting the + * `esp_local_ctrl` service, e.g. in case of BLE. By declaration it means that the transport layer + * allocates some resources for an endpoint, and later, after service has started, a handler + * is assigned for that endpoint */ + if (config->transport->declare_ep) { + /* UUIDs are 16bit unique IDs for each endpoint. This may or may not be relevant for + * a chosen transport. We reserve all values from FF50 to FFFF for the internal endpoints. + * The remaining endpoints can be used by the application for its own custom endpoints */ + uint16_t start_uuid = 0xFF50; + ret = config->transport->declare_ep(&local_ctrl_inst_ctx->config.transport_config, + "esp_local_ctrl/version", start_uuid++); + if (ret != ESP_OK) { + esp_local_ctrl_stop(); + return ret; + } + ret = config->transport->declare_ep(&local_ctrl_inst_ctx->config.transport_config, + "esp_local_ctrl/session", start_uuid++); + if (ret != ESP_OK) { + esp_local_ctrl_stop(); + return ret; + } + ret = config->transport->declare_ep(&local_ctrl_inst_ctx->config.transport_config, + "esp_local_ctrl/control", start_uuid++); + if (ret != ESP_OK) { + esp_local_ctrl_stop(); + return ret; + } + } + + local_ctrl_inst_ctx->pc = protocomm_new(); + if (!local_ctrl_inst_ctx->pc) { + ESP_LOGE(TAG, "Failed to create new protocomm instance"); + esp_local_ctrl_stop(); + return ESP_FAIL; + } + + if (config->transport->start_service) { + ret = config->transport->start_service(local_ctrl_inst_ctx->pc, + &local_ctrl_inst_ctx->config.transport_config); + if (ret != ESP_OK) { + esp_local_ctrl_stop(); + return ret; + } + } + + ret = protocomm_set_version(local_ctrl_inst_ctx->pc, "esp_local_ctrl/version", + ESP_LOCAL_CTRL_VERSION); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to set version endpoint"); + esp_local_ctrl_stop(); + return ret; + } + + ret = protocomm_set_security(local_ctrl_inst_ctx->pc, "esp_local_ctrl/session", + &protocomm_security0, NULL); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to set session endpoint"); + esp_local_ctrl_stop(); + return ret; + } + + ret = protocomm_add_endpoint(local_ctrl_inst_ctx->pc, "esp_local_ctrl/control", + esp_local_ctrl_data_handler, NULL); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to set control endpoint"); + esp_local_ctrl_stop(); + return ret; + } + return ESP_OK; +} + +esp_err_t esp_local_ctrl_stop(void) +{ + if (local_ctrl_inst_ctx) { + if (local_ctrl_inst_ctx->config.transport->free_config) { + local_ctrl_inst_ctx->config.transport->free_config(&local_ctrl_inst_ctx->config.transport_config); + } + if (local_ctrl_inst_ctx->pc) { + if (local_ctrl_inst_ctx->config.transport->stop_service) { + local_ctrl_inst_ctx->config.transport->stop_service(local_ctrl_inst_ctx->pc); + } + protocomm_delete(local_ctrl_inst_ctx->pc); + } + if (local_ctrl_inst_ctx->config.handlers.usr_ctx_free_fn) { + local_ctrl_inst_ctx->config.handlers.usr_ctx_free_fn( + local_ctrl_inst_ctx->config.handlers.usr_ctx); + } + + /* Iterate through all properties one by one and free them */ + for (uint32_t i = 0; i < local_ctrl_inst_ctx->config.max_properties; i++) { + if (local_ctrl_inst_ctx->props[i] == NULL) { + continue; + } + /* Release memory allocated for property data */ + free(local_ctrl_inst_ctx->props[i]->name); + if (local_ctrl_inst_ctx->props[i]->ctx_free_fn) { + local_ctrl_inst_ctx->props[i]->ctx_free_fn(local_ctrl_inst_ctx->props[i]->ctx); + } + free(local_ctrl_inst_ctx->props[i]); + } + free(local_ctrl_inst_ctx->props); + free(local_ctrl_inst_ctx); + local_ctrl_inst_ctx = NULL; + } + return ESP_OK; +} + +static int esp_local_ctrl_get_property_index(const char *name) +{ + if (!local_ctrl_inst_ctx || !name) { + return -1; + } + + /* Iterate through all properties one by one + * and find the one with matching name */ + for (uint32_t i = 0; i < local_ctrl_inst_ctx->props_count; i++) { + if (strcmp(local_ctrl_inst_ctx->props[i]->name, name) == 0) { + return i; + } + } + return -1; +} + +esp_err_t esp_local_ctrl_add_property(const esp_local_ctrl_prop_t *prop) +{ + if (!local_ctrl_inst_ctx) { + ESP_LOGE(TAG, "Service not running"); + return ESP_ERR_INVALID_STATE; + } + if (!prop || !prop->name) { + return ESP_ERR_INVALID_ARG; + } + if (esp_local_ctrl_get_property_index(prop->name) >= 0) { + ESP_LOGE(TAG, "Property with name %s exists", prop->name); + return ESP_ERR_INVALID_STATE; + } + + if (local_ctrl_inst_ctx->config.max_properties + == local_ctrl_inst_ctx->props_count) { + ESP_LOGE(TAG, "Max properties limit reached. Cannot add property %s", prop->name); + return ESP_ERR_NO_MEM; + } + + uint32_t i = local_ctrl_inst_ctx->props_count; + local_ctrl_inst_ctx->props[i] = calloc(1, sizeof(esp_local_ctrl_prop_t)); + if (!local_ctrl_inst_ctx->props[i]) { + ESP_LOGE(TAG, "Failed to allocate memory for new property %s", prop->name); + return ESP_ERR_NO_MEM; + } + local_ctrl_inst_ctx->props[i]->name = strdup(prop->name); + if (!local_ctrl_inst_ctx->props[i]->name) { + ESP_LOGE(TAG, "Failed to allocate memory for property data %s", prop->name); + free(local_ctrl_inst_ctx->props[i]); + local_ctrl_inst_ctx->props[i] = NULL; + return ESP_ERR_NO_MEM; + } + local_ctrl_inst_ctx->props[i]->type = prop->type; + local_ctrl_inst_ctx->props[i]->size = prop->size; + local_ctrl_inst_ctx->props[i]->flags = prop->flags; + local_ctrl_inst_ctx->props[i]->ctx = prop->ctx; + local_ctrl_inst_ctx->props[i]->ctx_free_fn = prop->ctx_free_fn; + local_ctrl_inst_ctx->props_count++; + return ESP_OK; +} + + +esp_err_t esp_local_ctrl_remove_property(const char *name) +{ + int idx = esp_local_ctrl_get_property_index(name); + if (idx < 0) { + ESP_LOGE(TAG, "Property %s not found", name); + return ESP_ERR_NOT_FOUND; + } + + /* Release memory allocated for property data */ + if (local_ctrl_inst_ctx->props[idx]->ctx_free_fn) { + local_ctrl_inst_ctx->props[idx]->ctx_free_fn( + local_ctrl_inst_ctx->props[idx]->ctx); + } + free(local_ctrl_inst_ctx->props[idx]->name); + free(local_ctrl_inst_ctx->props[idx]); + local_ctrl_inst_ctx->props[idx++] = NULL; + + /* Move the following properties forward, so that there is + * no empty space between two properties */ + for (uint32_t i = idx; i < local_ctrl_inst_ctx->props_count; i++) { + if (local_ctrl_inst_ctx->props[i] == NULL) { + break; + } + local_ctrl_inst_ctx->props[i-1] = local_ctrl_inst_ctx->props[i]; + } + local_ctrl_inst_ctx->props_count--; + return ESP_OK; +} + +const esp_local_ctrl_prop_t *esp_local_ctrl_get_property(const char *name) +{ + int idx = esp_local_ctrl_get_property_index(name); + if (idx < 0) { + ESP_LOGE(TAG, "Property %s not found", name); + return NULL; + } + + return local_ctrl_inst_ctx->props[idx]; +} + +esp_err_t esp_local_ctrl_get_prop_count(size_t *count) +{ + if (!local_ctrl_inst_ctx) { + ESP_LOGE(TAG, "Service not running"); + return ESP_ERR_INVALID_STATE; + } + if (!count) { + return ESP_ERR_INVALID_ARG; + } + *count = local_ctrl_inst_ctx->props_count; + return ESP_OK; +} + +esp_err_t esp_local_ctrl_get_prop_values(size_t total_indices, uint32_t *indices, + esp_local_ctrl_prop_t *props, + esp_local_ctrl_prop_val_t *values) +{ + if (!local_ctrl_inst_ctx) { + ESP_LOGE(TAG, "Service not running"); + return ESP_ERR_INVALID_STATE; + } + if (!indices || !props || !values) { + return ESP_ERR_INVALID_ARG; + } + + /* Convert indices to names */ + for (size_t i = 0; i < total_indices; i++) { + if (indices[i] >= local_ctrl_inst_ctx->props_count) { + ESP_LOGE(TAG, "Invalid property index %d", indices[i]); + return ESP_ERR_INVALID_ARG; + } + props[i].name = local_ctrl_inst_ctx->props[indices[i]]->name; + props[i].type = local_ctrl_inst_ctx->props[indices[i]]->type; + props[i].flags = local_ctrl_inst_ctx->props[indices[i]]->flags; + props[i].size = local_ctrl_inst_ctx->props[indices[i]]->size; + props[i].ctx = local_ctrl_inst_ctx->props[indices[i]]->ctx; + } + + esp_local_ctrl_handlers_t *h = &local_ctrl_inst_ctx->config.handlers; + esp_err_t ret = h->get_prop_values(total_indices, props, values, h->usr_ctx); + + /* Properties with fixed sizes need to be checked */ + for (size_t i = 0; i < total_indices; i++) { + if (local_ctrl_inst_ctx->props[indices[i]]->size != 0) { + values[i].size = local_ctrl_inst_ctx->props[indices[i]]->size; + } + } + return ret; +} + +esp_err_t esp_local_ctrl_set_prop_values(size_t total_indices, uint32_t *indices, + const esp_local_ctrl_prop_val_t *values) +{ + if (!local_ctrl_inst_ctx) { + ESP_LOGE(TAG, "Service not running"); + return ESP_ERR_INVALID_STATE; + } + if (!indices || !values) { + return ESP_ERR_INVALID_ARG; + } + + esp_local_ctrl_prop_t *props = calloc(total_indices, + sizeof(esp_local_ctrl_prop_t)); + if (!props) { + ESP_LOGE(TAG, "Unable to allocate memory for properties array"); + return ESP_ERR_NO_MEM; + } + for (size_t i = 0; i < total_indices; i++) { + if (indices[i] >= local_ctrl_inst_ctx->props_count) { + ESP_LOGE(TAG, "Invalid property index %d", indices[i]); + free(props); + return ESP_ERR_INVALID_ARG; + } + + /* Properties with fixed sizes need to be checked */ + if ((local_ctrl_inst_ctx->props[indices[i]]->size != values[i].size) && + (local_ctrl_inst_ctx->props[indices[i]]->size != 0)) { + ESP_LOGE(TAG, "Invalid property size %d. Expected %d", + values[i].size, local_ctrl_inst_ctx->props[indices[i]]->size); + free(props); + return ESP_ERR_INVALID_ARG; + } + + props[i].name = local_ctrl_inst_ctx->props[indices[i]]->name; + props[i].type = local_ctrl_inst_ctx->props[indices[i]]->type; + props[i].flags = local_ctrl_inst_ctx->props[indices[i]]->flags; + props[i].size = local_ctrl_inst_ctx->props[indices[i]]->size; + props[i].ctx = local_ctrl_inst_ctx->props[indices[i]]->ctx; + } + + esp_local_ctrl_handlers_t *h = &local_ctrl_inst_ctx->config.handlers; + esp_err_t ret = h->set_prop_values(total_indices, props, values, h->usr_ctx); + + free(props); + return ret; +} + +esp_err_t esp_local_ctrl_set_handler(const char *ep_name, + protocomm_req_handler_t handler, + void *priv_data) +{ + esp_err_t ret = ESP_ERR_INVALID_STATE; + + if (local_ctrl_inst_ctx) { + ret = protocomm_add_endpoint(local_ctrl_inst_ctx->pc, ep_name, + handler, priv_data); + } + + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to register endpoint handler"); + } + return ret; +} diff --git a/components/esp_local_ctrl/src/esp_local_ctrl_handler.c b/components/esp_local_ctrl/src/esp_local_ctrl_handler.c new file mode 100644 index 0000000000..23a92abd6c --- /dev/null +++ b/components/esp_local_ctrl/src/esp_local_ctrl_handler.c @@ -0,0 +1,298 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include + +#include "esp_local_ctrl.h" +#include "esp_local_ctrl_priv.h" +#include "esp_local_ctrl.pb-c.h" + +#define SAFE_ALLOCATION(type, var) \ + type *var = (type *) malloc(sizeof(type)); \ + if (!var) { \ + ESP_LOGE(TAG, "Error allocating memory"); \ + return ESP_ERR_NO_MEM; \ + } + +static const char* TAG = "esp_local_ctrl_handler"; + +typedef struct esp_local_ctrl_cmd { + int cmd_num; + esp_err_t (*command_handler)(LocalCtrlMessage *req, + LocalCtrlMessage *resp, void **ctx); +} esp_local_ctrl_cmd_t; + +static esp_err_t cmd_get_prop_count_handler(LocalCtrlMessage *req, + LocalCtrlMessage *resp, void **ctx); + +static esp_err_t cmd_get_prop_vals_handler(LocalCtrlMessage *req, + LocalCtrlMessage *resp, void **ctx); + +static esp_err_t cmd_set_prop_vals_handler(LocalCtrlMessage *req, + LocalCtrlMessage *resp, void **ctx); + +static esp_local_ctrl_cmd_t cmd_table[] = { + { + .cmd_num = LOCAL_CTRL_MSG_TYPE__TypeCmdGetPropertyCount, + .command_handler = cmd_get_prop_count_handler + }, + { + .cmd_num = LOCAL_CTRL_MSG_TYPE__TypeCmdGetPropertyValues, + .command_handler = cmd_get_prop_vals_handler + }, + { + .cmd_num = LOCAL_CTRL_MSG_TYPE__TypeCmdSetPropertyValues, + .command_handler = cmd_set_prop_vals_handler + } +}; + +static uint16_t err_to_status(esp_err_t err) +{ + uint16_t status; + switch (err) { + case ESP_OK: + status = STATUS__Success; + break; + case ESP_ERR_INVALID_ARG: + status = STATUS__InvalidArgument; + break; + case ESP_ERR_INVALID_STATE: + status = STATUS__InvalidProto; + break; + default: + status = STATUS__InternalError; + } + return status; +} + +static esp_err_t cmd_get_prop_count_handler(LocalCtrlMessage *req, + LocalCtrlMessage *resp, void **ctx) +{ + SAFE_ALLOCATION(RespGetPropertyCount, resp_payload); + resp_get_property_count__init(resp_payload); + + size_t prop_count = 0; + resp_payload->status = err_to_status(esp_local_ctrl_get_prop_count(&prop_count)); + resp_payload->count = prop_count; + resp->payload_case = LOCAL_CTRL_MESSAGE__PAYLOAD_RESP_GET_PROP_COUNT; + resp->resp_get_prop_count = resp_payload; + ESP_LOGD(TAG, "Got properties count %d", prop_count); + return ESP_OK; +} + +typedef void (*prop_val_free_fn_t)(void *val); + +static esp_err_t cmd_get_prop_vals_handler(LocalCtrlMessage *req, + LocalCtrlMessage *resp, void **ctx) +{ + SAFE_ALLOCATION(RespGetPropertyValues, resp_payload); + resp_get_property_values__init(resp_payload); + + esp_local_ctrl_prop_val_t *vals = calloc(req->cmd_get_prop_vals->n_indices, + sizeof(esp_local_ctrl_prop_val_t)); + esp_local_ctrl_prop_t *descs = calloc(req->cmd_get_prop_vals->n_indices, + sizeof(esp_local_ctrl_prop_t)); + prop_val_free_fn_t *free_fns = calloc(req->cmd_get_prop_vals->n_indices, + sizeof(prop_val_free_fn_t)); + resp_payload->props = calloc(req->cmd_get_prop_vals->n_indices, + sizeof(PropertyInfo *)); + if (!vals || !descs || !free_fns || !resp_payload->props) { + ESP_LOGE(TAG, "Failed to allocate memory for getting values"); + free(vals); + free(descs); + free(free_fns); + free(resp_payload->props); + free(resp_payload); + return ESP_ERR_NO_MEM; + } + + esp_err_t ret = esp_local_ctrl_get_prop_values(req->cmd_get_prop_vals->n_indices, + req->cmd_get_prop_vals->indices, + descs, vals); + resp_payload->status = err_to_status(ret); + if (ret == ESP_OK) { + resp_payload->n_props = 0; + for (size_t i = 0; i < req->cmd_get_prop_vals->n_indices; i++) { + resp_payload->props[i] = malloc(sizeof(PropertyInfo)); + if (!resp_payload->props[i]) { + resp_payload->status = STATUS__InternalError; + break; + } + resp_payload->n_props++; + property_info__init(resp_payload->props[i]); + resp_payload->props[i]->name = descs[i].name; + resp_payload->props[i]->type = descs[i].type; + resp_payload->props[i]->flags = descs[i].flags; + resp_payload->props[i]->value.data = vals[i].data; + resp_payload->props[i]->value.len = vals[i].size; + free_fns[i] = vals[i].free_fn; + } + } + resp->payload_case = LOCAL_CTRL_MESSAGE__PAYLOAD_RESP_GET_PROP_VALS; + resp->resp_get_prop_vals = resp_payload; + (*ctx) = (void *)free_fns; + free(vals); + free(descs); + + /* Unless it's a fatal error, always return ESP_OK, otherwise + * the underlying connection will be closed by protocomm */ + return ESP_OK; +} + +static esp_err_t cmd_set_prop_vals_handler(LocalCtrlMessage *req, + LocalCtrlMessage *resp, void **ctx) +{ + SAFE_ALLOCATION(RespSetPropertyValues, resp_payload); + resp_set_property_values__init(resp_payload); + + uint32_t *idxs = calloc(req->cmd_set_prop_vals->n_props, sizeof(uint32_t)); + esp_local_ctrl_prop_val_t *vals = calloc(req->cmd_set_prop_vals->n_props, + sizeof(esp_local_ctrl_prop_val_t)); + if (!idxs || !vals) { + ESP_LOGE(TAG, "Failed to allocate memory for setting values"); + free(idxs); + free(vals); + return ESP_ERR_NO_MEM; + } + for (size_t i = 0; i < req->cmd_set_prop_vals->n_props; i++) { + idxs[i] = req->cmd_set_prop_vals->props[i]->index; + vals[i].data = req->cmd_set_prop_vals->props[i]->value.data; + vals[i].size = req->cmd_set_prop_vals->props[i]->value.len; + } + + esp_err_t ret = esp_local_ctrl_set_prop_values(req->cmd_set_prop_vals->n_props, + idxs, vals); + resp_payload->status = err_to_status(ret); + resp->payload_case = LOCAL_CTRL_MESSAGE__PAYLOAD_RESP_SET_PROP_VALS; + resp->resp_set_prop_vals = resp_payload; + free(idxs); + free(vals); + + /* Unless it's a fatal error, always return ESP_OK, otherwise + * the underlying connection will be closed by protocomm */ + return ESP_OK; +} + +static int lookup_cmd_handler(int cmd_id) +{ + int i; + + for (i = 0; i < sizeof(cmd_table)/sizeof(esp_local_ctrl_cmd_t); i++) { + if (cmd_table[i].cmd_num == cmd_id) { + return i; + } + } + + return -1; +} + +static void esp_local_ctrl_command_cleanup(LocalCtrlMessage *resp, void **ctx) +{ + if (!resp) { + return; + } + + switch (resp->msg) { + case LOCAL_CTRL_MSG_TYPE__TypeRespGetPropertyCount: + free(resp->resp_get_prop_count); + break; + case LOCAL_CTRL_MSG_TYPE__TypeRespGetPropertyValues: { + if (resp->resp_get_prop_vals) { + prop_val_free_fn_t *free_fns = (prop_val_free_fn_t *)(*ctx); + for (size_t i = 0; i < resp->resp_get_prop_vals->n_props; i++) { + if (free_fns[i]) { + free_fns[i](resp->resp_get_prop_vals->props[i]->value.data); + } + free(resp->resp_get_prop_vals->props[i]); + } + free(free_fns); + free(resp->resp_get_prop_vals->props); + free(resp->resp_get_prop_vals); + } + } + break; + case LOCAL_CTRL_MSG_TYPE__TypeRespSetPropertyValues: + free(resp->resp_set_prop_vals); + break; + default: + ESP_LOGE(TAG, "Unsupported response type in cleanup_handler"); + } + return; +} + +static esp_err_t esp_local_ctrl_command_dispatcher(LocalCtrlMessage *req, + LocalCtrlMessage *resp, + void **ctx) +{ + int cmd_index = lookup_cmd_handler(req->msg); + if (cmd_index < 0) { + ESP_LOGE(TAG, "Invalid command handler lookup"); + return ESP_ERR_INVALID_ARG; + } + + esp_err_t ret = cmd_table[cmd_index].command_handler(req, resp, ctx); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Error executing command handler"); + return ret; + } + + return ESP_OK; +} + +esp_err_t esp_local_ctrl_data_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen, + uint8_t **outbuf, ssize_t *outlen, void *priv_data) +{ + void *temp_ctx = NULL; + LocalCtrlMessage *req = local_ctrl_message__unpack(NULL, inlen, inbuf); + if (!req) { + ESP_LOGE(TAG, "Unable to unpack payload data"); + return ESP_ERR_INVALID_ARG; + } + + LocalCtrlMessage resp; + local_ctrl_message__init(&resp); + resp.msg = req->msg + 1; /* Response is request + 1 */ + + esp_err_t ret = esp_local_ctrl_command_dispatcher(req, &resp, &temp_ctx); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "command dispatcher failed"); + esp_local_ctrl_command_cleanup(&resp, &temp_ctx); + local_ctrl_message__free_unpacked(req, NULL); + return ESP_FAIL; + } + + local_ctrl_message__free_unpacked(req, NULL); + + *outlen = local_ctrl_message__get_packed_size(&resp); + if (*outlen <= 0) { + ESP_LOGE(TAG, "Invalid encoding for response"); + esp_local_ctrl_command_cleanup(&resp, &temp_ctx); + return ESP_FAIL; + } + + *outbuf = (uint8_t *) malloc(*outlen); + if (!*outbuf) { + ESP_LOGE(TAG, "System out of memory"); + esp_local_ctrl_command_cleanup(&resp, &temp_ctx); + return ESP_ERR_NO_MEM; + } + + local_ctrl_message__pack(&resp, *outbuf); + esp_local_ctrl_command_cleanup(&resp, &temp_ctx); + ESP_LOG_BUFFER_HEX_LEVEL(TAG, *outbuf, *outlen, ESP_LOG_DEBUG); + return ESP_OK; +} diff --git a/components/esp_local_ctrl/src/esp_local_ctrl_priv.h b/components/esp_local_ctrl/src/esp_local_ctrl_priv.h new file mode 100644 index 0000000000..9241054e35 --- /dev/null +++ b/components/esp_local_ctrl/src/esp_local_ctrl_priv.h @@ -0,0 +1,153 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/** + * @brief `esp_local_ctrl` transport specific structure + * + * Every supported transport layer should have the following functions + * implemented for starting, stopping and configuring a protocomm service + */ +struct esp_local_ctrl_transport { + /** + * Handler for starting a protocomm service as per specified configuration + */ + esp_err_t (*start_service) (protocomm_t *pc, + const esp_local_ctrl_transport_config_t *config); + + /** + * Handler for stopping a protocomm service + */ + void (*stop_service) (protocomm_t *pc); + + /** + * Handler for creating a copy of the transport specific configuration + */ + esp_err_t (*copy_config) (esp_local_ctrl_transport_config_t *dest_config, + const esp_local_ctrl_transport_config_t *src_config); + + /** + * Handler for allocating resources corresponding to a protocomm endpoint. + * Usually when adding a new endpoint `protocomm_endpoint_add()` API is used, + * but the transport layer may need to perform resource allocation for + * each endpoint, prior to starting the protocomm instance. This handler + * is useful in that case, as it is called before `start_service()`. + */ + esp_err_t (*declare_ep) (esp_local_ctrl_transport_config_t *config, + const char *ep_name, uint16_t ep_uuid); + + /** + * Handler for freeing a transport specific configuration + */ + void (*free_config) (esp_local_ctrl_transport_config_t *config); +}; + +/** + * @brief Protocomm handler for `esp_local_ctrl` + * + * This is the handler which is responsible for processing incoming requests + * over a protocomm channel, then invokes one of the following functions + * depending upon the request type: + * - `esp_local_ctrl_get_prop_count()` + * - `esp_local_ctrl_get_prop_values()` + * -` esp_local_ctrl_set_prop_values()` + * The output of the above functions are used to form the response messages + * corresponding to request types. The formed response messages are packed and + * sent back via the protocomm channel. + * + * @param[in] session_id A number to identify an ongoing session between + * device and client + * @param[in] inbuf Buffer which holds serialized / packed request data + * @param[in] inlen Length of input buffer + * @param[out] outbuf Buffer which holds serialized / packed response data + * @param[out] outlen Length of output buffer + * @param[in] priv_data Private data associated with `esp_local_ctrl` endpoint + * + * @return + * - ESP_OK : Success + * - ESP_FAIL : Failure + */ +esp_err_t esp_local_ctrl_data_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen, + uint8_t **outbuf, ssize_t *outlen, void *priv_data); + +/** + * @brief Use this for obtaining total number of properties registered + * with `esp_local_ctrl` service + * + * @param[out] count Pointer to variable where the result is to be stored + * + * @return + * - ESP_OK : Success + * - ESP_FAIL : Failure + */ +esp_err_t esp_local_ctrl_get_prop_count(size_t *count); + +/** + * @brief Get descriptions and values of multiple properties at the same time. + * The properties are requested by indices. This internally calls the + * `get_prop_values` handler specified in the `esp_local_ctrl_handlers_t` + * structure. Since `get_prop_values` accepts property structure, the + * indices are first converted to the corresponding `esp_local_ctrl_prop_t` + * internally. + * + * @param[in] total_indices The number of elements in the `indices` array argument + * @param[in] indices An array of indices, that specify which properties to get + * @param[out] props A pre-allocated array of empty property structures, elements of + * which are to be populated with names, types and flags of those + * properties which correspond to the provided indices + * @param[out] values A pre-allocated array of empty value structures, elements of + * which are to be populated with values and sizes of those + * properties which correspond to the provided indices + * + * @return + * - ESP_OK : Success + * - ESP_FAIL : Failure + */ +esp_err_t esp_local_ctrl_get_prop_values(size_t total_indices, uint32_t *indices, + esp_local_ctrl_prop_t *props, + esp_local_ctrl_prop_val_t *values); + +/** + * @brief Set values of multiple properties at the same time. The properties to + * set are specified by indices. This internally calls the `set_prop_values` + * handler specified in the `esp_local_ctrl_handlers_t` structure. Since + * `set_prop_values` accepts property structures, the indices are first + * converted to the corresponding `esp_local_ctrl_prop_t` internally. + * + * @param[in] total_indices The number of elements in the `indices` array argument + * @param[in] indices An array of indices, that specify which properties to set + * @param[in] values A array of values. Every value should have the correct + * size, if it is for setting a fixed size property, else + * error will be generated and none of the properties will + * be set to any of the given values + * + * @return + * - ESP_OK : Success + * - ESP_FAIL : Failure + */ +esp_err_t esp_local_ctrl_set_prop_values(size_t total_indices, uint32_t *indices, + const esp_local_ctrl_prop_val_t *values); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_local_ctrl/src/esp_local_ctrl_transport_ble.c b/components/esp_local_ctrl/src/esp_local_ctrl_transport_ble.c new file mode 100644 index 0000000000..248b410899 --- /dev/null +++ b/components/esp_local_ctrl/src/esp_local_ctrl_transport_ble.c @@ -0,0 +1,140 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include + +#include +#include + +#include "esp_local_ctrl_priv.h" + +#define LOCAL_CTRL_VERSION "v1.0" + +static const char *TAG = "esp_local_ctrl_transport_ble"; + +static esp_err_t start_ble_transport(protocomm_t *pc, const esp_local_ctrl_transport_config_t *config) +{ + if (!config || !config->ble) { + ESP_LOGE(TAG, "NULL configuration provided"); + return ESP_ERR_INVALID_ARG; + } + return protocomm_ble_start(pc, config->ble); +} + +static void stop_ble_transport(protocomm_t *pc) +{ + protocomm_ble_stop(pc); +} + +static esp_err_t copy_ble_config(esp_local_ctrl_transport_config_t *dest_config, const esp_local_ctrl_transport_config_t *src_config) +{ + if (!dest_config || !src_config || !src_config->ble) { + ESP_LOGE(TAG, "NULL arguments provided"); + return ESP_ERR_INVALID_ARG; + } + + dest_config->ble = calloc(1, sizeof(protocomm_ble_config_t)); + if (!dest_config->ble) { + ESP_LOGE(TAG, "Failed to allocate memory for BLE transport config"); + return ESP_ERR_NO_MEM; + } + + /* Copy BLE device name */ + memcpy(dest_config->ble->device_name, + src_config->ble->device_name, + sizeof(src_config->ble->device_name)); + + /* Copy Service UUID */ + memcpy(dest_config->ble->service_uuid, + src_config->ble->service_uuid, + sizeof(src_config->ble->service_uuid)); + + dest_config->ble->nu_lookup_count = 0; + if (src_config->ble->nu_lookup_count) { + /* Copy any provided name-uuid lookup table */ + dest_config->ble->nu_lookup = calloc(src_config->ble->nu_lookup_count, + sizeof(protocomm_ble_name_uuid_t)); + if (!dest_config->ble->nu_lookup) { + ESP_LOGE(TAG, "Failed to allocate memory for BLE characteristic names"); + free(dest_config->ble); + return ESP_ERR_NO_MEM; + } + for (uint16_t i = 0; i < src_config->ble->nu_lookup_count; i++) { + dest_config->ble->nu_lookup[i].uuid = src_config->ble->nu_lookup[i].uuid; + if (!src_config->ble->nu_lookup[i].name) { + ESP_LOGE(TAG, "Endpoint name cannot be null"); + return ESP_ERR_INVALID_ARG; + } + dest_config->ble->nu_lookup[i].name = strdup(src_config->ble->nu_lookup[i].name); + if (!dest_config->ble->nu_lookup[i].name) { + ESP_LOGE(TAG, "Failed to allocate memory for endpoint name"); + return ESP_ERR_NO_MEM; + } + dest_config->ble->nu_lookup_count++; + } + } + return ESP_OK; +} + +static esp_err_t declare_endpoint(esp_local_ctrl_transport_config_t *config, const char *ep_name, uint16_t ep_uuid) +{ + if (!config || !config->ble) { + ESP_LOGE(TAG, "NULL configuration provided"); + return ESP_ERR_INVALID_ARG; + } + + protocomm_ble_name_uuid_t *nu_lookup = realloc(config->ble->nu_lookup, + (config->ble->nu_lookup_count + 1) + * sizeof(protocomm_ble_name_uuid_t)); + if (!nu_lookup) { + ESP_LOGE(TAG, "Failed to allocate memory for new endpoint entry"); + return ESP_ERR_NO_MEM; + } + config->ble->nu_lookup = nu_lookup; + nu_lookup[config->ble->nu_lookup_count].uuid = ep_uuid; + nu_lookup[config->ble->nu_lookup_count].name = strdup(ep_name); + if (!nu_lookup[config->ble->nu_lookup_count].name) { + ESP_LOGE(TAG, "Failed to allocate memory for new endpoint name"); + return ESP_ERR_NO_MEM; + } + config->ble->nu_lookup_count++; + return ESP_OK; +} + +static void free_config(esp_local_ctrl_transport_config_t *config) +{ + if (config && config->ble) { + for (unsigned int i = 0; i < config->ble->nu_lookup_count; i++) { + free((void*) config->ble->nu_lookup[i].name); + } + free(config->ble->nu_lookup); + free(config->ble); + config->ble = NULL; + } +} + +const esp_local_ctrl_transport_t *esp_local_ctrl_get_transport_ble(void) +{ + static const esp_local_ctrl_transport_t tp = { + .start_service = start_ble_transport, + .stop_service = stop_ble_transport, + .copy_config = copy_ble_config, + .declare_ep = declare_endpoint, + .free_config = free_config + }; + return &tp; +}; diff --git a/components/esp_local_ctrl/src/esp_local_ctrl_transport_httpd.c b/components/esp_local_ctrl/src/esp_local_ctrl_transport_httpd.c new file mode 100644 index 0000000000..2089c3dbf5 --- /dev/null +++ b/components/esp_local_ctrl/src/esp_local_ctrl_transport_httpd.c @@ -0,0 +1,128 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "esp_local_ctrl_priv.h" + +#define LOCAL_CTRL_VERSION "v1.0" + +static const char *TAG = "esp_local_ctrl_transport_httpd"; + +static httpd_handle_t server_handle = NULL; + +static esp_err_t start_httpd_transport(protocomm_t *pc, const esp_local_ctrl_transport_config_t *config) +{ + if (!config || !config->httpd) { + ESP_LOGE(TAG, "NULL configuration provided"); + return ESP_ERR_INVALID_ARG; + } + + /* Extract configured port */ + uint16_t port = ( + config->httpd->transport_mode == HTTPD_SSL_TRANSPORT_SECURE ? + config->httpd->port_secure : + config->httpd->port_insecure + ); + + esp_err_t err = mdns_service_add("Local Control Service", "_esp_local_ctrl", + "_tcp", port, NULL, 0); + if (err != ESP_OK) { + /* mDNS is not mandatory for provisioning to work, + * so print warning and return without failure */ + ESP_LOGW(TAG, "Error adding mDNS service! Check if mDNS is running"); + } else { + /* Information to identify the roles of the various + * protocomm endpoint URIs provided by the service */ + err |= mdns_service_txt_item_set("_esp_local_ctrl", "_tcp", + "version_endpoint", "/esp_local_ctrl/version"); + err |= mdns_service_txt_item_set("_esp_local_ctrl", "_tcp", + "session_endpoint", "/esp_local_ctrl/session"); + err |= mdns_service_txt_item_set("_esp_local_ctrl", "_tcp", + "control_endpoint", "/esp_local_ctrl/control"); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Error adding mDNS service text item"); + } + } + + err = httpd_ssl_start(&server_handle, config->httpd); + if (ESP_OK != err) { + ESP_LOGE(TAG, "Error starting HTTPS service!"); + mdns_service_remove("_esp_local_ctrl", "_tcp"); + return err; + } + + protocomm_httpd_config_t pc_conf = { + .ext_handle_provided = true, + .data = { + .handle = &server_handle + } + }; + + return protocomm_httpd_start(pc, &pc_conf); +} + +static void stop_httpd_transport(protocomm_t *pc) +{ + mdns_service_remove("_esp_local_ctrl", "_tcp"); + protocomm_httpd_stop(pc); + httpd_ssl_stop(server_handle); + server_handle = NULL; +} + +static esp_err_t copy_httpd_config(esp_local_ctrl_transport_config_t *dest_config, const esp_local_ctrl_transport_config_t *src_config) +{ + if (!dest_config || !src_config || !src_config->httpd) { + ESP_LOGE(TAG, "NULL configuration provided"); + return ESP_ERR_INVALID_ARG; + } + + dest_config->httpd = calloc(1, sizeof(httpd_ssl_config_t)); + if (!dest_config->httpd) { + ESP_LOGE(TAG, "Failed to allocate memory for HTTPD transport config"); + return ESP_ERR_NO_MEM; + } + memcpy(dest_config->httpd, + src_config->httpd, + sizeof(httpd_ssl_config_t)); + return ESP_OK; +} + +static void free_config(esp_local_ctrl_transport_config_t *config) +{ + if (config && config->httpd) { + free(config->httpd); + config->httpd = NULL; + } +} + +const esp_local_ctrl_transport_t *esp_local_ctrl_get_transport_httpd(void) +{ + static const esp_local_ctrl_transport_t tp = { + .start_service = start_httpd_transport, + .stop_service = stop_httpd_transport, + .copy_config = copy_httpd_config, + .declare_ep = NULL, + .free_config = free_config + }; + return &tp; +}; diff --git a/components/esp_ringbuf/CMakeLists.txt b/components/esp_ringbuf/CMakeLists.txt index bba1dfd6d8..4c4b114af9 100644 --- a/components/esp_ringbuf/CMakeLists.txt +++ b/components/esp_ringbuf/CMakeLists.txt @@ -1,7 +1,3 @@ -set(COMPONENT_ADD_INCLUDEDIRS "include") -set(COMPONENT_SRCS "ringbuf.c") -set(COMPONENT_ADD_LDFRAGMENTS linker.lf) - -set(COMPONENT_REQUIRES) - -register_component() +idf_component_register(SRCS "ringbuf.c" + INCLUDE_DIRS "include" + LDFRAGMENTS linker.lf) diff --git a/components/esp_ringbuf/include/freertos/ringbuf.h b/components/esp_ringbuf/include/freertos/ringbuf.h index de8a369095..338fa3eae2 100644 --- a/components/esp_ringbuf/include/freertos/ringbuf.h +++ b/components/esp_ringbuf/include/freertos/ringbuf.h @@ -1,9 +1,9 @@ -// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at - +// // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software @@ -16,7 +16,7 @@ #define FREERTOS_RINGBUF_H #ifndef INC_FREERTOS_H - #error "include FreeRTOS.h" must appear in source files before "include ringbuf.h" + #error "include FreeRTOS.h" must appear in source files before "include ringbuf.h" #endif #ifdef __cplusplus @@ -33,27 +33,52 @@ extern "C" { typedef void * RingbufHandle_t; typedef enum { - /** - * No-split buffers will only store an item in contiguous memory and will - * never split an item. Each item requires an 8 byte overhead for a header - * and will always internally occupy a 32-bit aligned size of space. - */ - RINGBUF_TYPE_NOSPLIT = 0, - /** - * Allow-split buffers will split an item into two parts if necessary in - * order to store it. Each item requires an 8 byte overhead for a header, - * splitting incurs an extra header. Each item will always internally occupy - * a 32-bit aligned size of space. - */ - RINGBUF_TYPE_ALLOWSPLIT, - /** - * Byte buffers store data as a sequence of bytes and do not maintain separate - * items, therefore byte buffers have no overhead. All data is stored as a - * sequence of byte and any number of bytes can be sent or retrieved each - * time. - */ - RINGBUF_TYPE_BYTEBUF -} ringbuf_type_t; + /** + * No-split buffers will only store an item in contiguous memory and will + * never split an item. Each item requires an 8 byte overhead for a header + * and will always internally occupy a 32-bit aligned size of space. + */ + RINGBUF_TYPE_NOSPLIT = 0, + /** + * Allow-split buffers will split an item into two parts if necessary in + * order to store it. Each item requires an 8 byte overhead for a header, + * splitting incurs an extra header. Each item will always internally occupy + * a 32-bit aligned size of space. + */ + RINGBUF_TYPE_ALLOWSPLIT, + /** + * Byte buffers store data as a sequence of bytes and do not maintain separate + * items, therefore byte buffers have no overhead. All data is stored as a + * sequence of byte and any number of bytes can be sent or retrieved each + * time. + */ + RINGBUF_TYPE_BYTEBUF, + RINGBUF_TYPE_MAX, +} RingbufferType_t; + +/** + * @brief Struct that is equivalent in size to the ring buffer's data structure + * + * The contents of this struct are not meant to be used directly. This + * structure is meant to be used when creating a statically allocated ring + * buffer where this struct is of the exact size required to store a ring + * buffer's control data structure. + * + * @note The CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION option must be enabled for + * this structure to be available. + */ +#if ( configSUPPORT_STATIC_ALLOCATION == 1) +typedef struct xSTATIC_RINGBUFFER { + /** @cond */ //Doxygen command to hide this structure from API Reference + size_t xDummy1[2]; + UBaseType_t uxDummy2; + BaseType_t xDummy3; + void *pvDummy4[11]; + StaticSemaphore_t xDummy5[2]; + portMUX_TYPE muxDummy; + /** @endcond */ +} StaticRingbuffer_t; +#endif /** * @brief Create a ring buffer @@ -66,7 +91,7 @@ typedef enum { * * @return A handle to the created ring buffer, or NULL in case of error. */ -RingbufHandle_t xRingbufferCreate(size_t xBufferSize, ringbuf_type_t xBufferType); +RingbufHandle_t xRingbufferCreate(size_t xBufferSize, RingbufferType_t xBufferType); /** * @brief Create a ring buffer of type RINGBUF_TYPE_NOSPLIT for a fixed item_size @@ -81,11 +106,36 @@ RingbufHandle_t xRingbufferCreate(size_t xBufferSize, ringbuf_type_t xBufferType */ RingbufHandle_t xRingbufferCreateNoSplit(size_t xItemSize, size_t xItemNum); + +/** + * @brief Create a ring buffer but manually provide the required memory + * + * @param[in] xBufferSize Size of the buffer in bytes. + * @param[in] xBufferType Type of ring buffer, see documentation + * @param[in] pucRingbufferStorage Pointer to the ring buffer's storage area. + * Storage area must of the same size as specified by xBufferSize + * @param[in] pxStaticRingbuffer Pointed to a struct of type StaticRingbuffer_t + * which will be used to hold the ring buffer's data structure + * + * @note The CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION option must be enabled + * for this to be available + * + * @note xBufferSize of no-split/allow-split buffers MUST be 32-bit aligned. + * + * @return A handle to the created ring buffer + */ +#if ( configSUPPORT_STATIC_ALLOCATION == 1) +RingbufHandle_t xRingbufferCreateStatic(size_t xBufferSize, + RingbufferType_t xBufferType, + uint8_t *pucRingbufferStorage, + StaticRingbuffer_t *pxStaticRingbuffer); +#endif + /** * @brief Insert an item into the ring buffer * * Attempt to insert an item into the ring buffer. This function will block until - * enough free space is available or until it timesout. + * enough free space is available or until it times out. * * @param[in] xRingbuffer Ring buffer to insert the item into * @param[in] pvItem Pointer to data to insert. NULL is allowed if xItemSize is 0. @@ -101,7 +151,10 @@ RingbufHandle_t xRingbufferCreateNoSplit(size_t xItemSize, size_t xItemNum); * - pdTRUE if succeeded * - pdFALSE on time-out or when the data is larger than the maximum permissible size of the buffer */ -BaseType_t xRingbufferSend(RingbufHandle_t xRingbuffer, const void *pvItem, size_t xItemSize, TickType_t xTicksToWait); +BaseType_t xRingbufferSend(RingbufHandle_t xRingbuffer, + const void *pvItem, + size_t xItemSize, + TickType_t xTicksToWait); /** * @brief Insert an item into the ring buffer in an ISR @@ -123,13 +176,60 @@ BaseType_t xRingbufferSend(RingbufHandle_t xRingbuffer, const void *pvItem, size * - pdTRUE if succeeded * - pdFALSE when the ring buffer does not have space. */ -BaseType_t xRingbufferSendFromISR(RingbufHandle_t xRingbuffer, const void *pvItem, size_t xItemSize, BaseType_t *pxHigherPriorityTaskWoken); +BaseType_t xRingbufferSendFromISR(RingbufHandle_t xRingbuffer, + const void *pvItem, + size_t xItemSize, + BaseType_t *pxHigherPriorityTaskWoken); + +/** + * @brief Acquire memory from the ring buffer to be written to by an external + * source and to be sent later. + * + * Attempt to allocate buffer for an item to be sent into the ring buffer. This + * function will block until enough free space is available or until it + * timesout. + * + * The item, as well as the following items ``SendAcquire`` or ``Send`` after it, + * will not be able to be read from the ring buffer until this item is actually + * sent into the ring buffer. + * + * @param[in] xRingbuffer Ring buffer to allocate the memory + * @param[out] ppvItem Double pointer to memory acquired (set to NULL if no memory were retrieved) + * @param[in] xItemSize Size of item to acquire. + * @param[in] xTicksToWait Ticks to wait for room in the ring buffer. + * + * @note Only applicable for no-split ring buffers now, the actual size of + * memory that the item will occupy will be rounded up to the nearest 32-bit + * aligned size. This is done to ensure all items are always stored in 32-bit + * aligned fashion. + * + * @return + * - pdTRUE if succeeded + * - pdFALSE on time-out or when the data is larger than the maximum permissible size of the buffer + */ +BaseType_t xRingbufferSendAcquire(RingbufHandle_t xRingbuffer, void **ppvItem, size_t xItemSize, TickType_t xTicksToWait); + +/** + * @brief Actually send an item into the ring buffer allocated before by + * ``xRingbufferSendAcquire``. + * + * @param[in] xRingbuffer Ring buffer to insert the item into + * @param[in] pvItem Pointer to item in allocated memory to insert. + * + * @note Only applicable for no-split ring buffers. Only call for items + * allocated by ``xRingbufferSendAcquire``. + * + * @return + * - pdTRUE if succeeded + * - pdFALSE if fail for some reason. + */ +BaseType_t xRingbufferSendComplete(RingbufHandle_t xRingbuffer, void *pvItem); /** * @brief Retrieve an item from the ring buffer * * Attempt to retrieve an item from the ring buffer. This function will block - * until an item is available or until it timesout. + * until an item is available or until it times out. * * @param[in] xRingbuffer Ring buffer to retrieve the item from * @param[out] pxItemSize Pointer to a variable to which the size of the retrieved item will be written. @@ -168,7 +268,7 @@ void *xRingbufferReceiveFromISR(RingbufHandle_t xRingbuffer, size_t *pxItemSize) * Attempt to retrieve a split item from an allow-split ring buffer. If the item * is not split, only a single item is retried. If the item is split, both parts * will be retrieved. This function will block until an item is available or - * until it timesout. + * until it times out. * * @param[in] xRingbuffer Ring buffer to retrieve the item from * @param[out] ppvHeadItem Double pointer to first part (set to NULL if no items were retrieved) @@ -184,7 +284,12 @@ void *xRingbufferReceiveFromISR(RingbufHandle_t xRingbuffer, size_t *pxItemSize) * - pdTRUE if an item (split or unsplit) was retrieved * - pdFALSE when no item was retrieved */ -BaseType_t xRingbufferReceiveSplit(RingbufHandle_t xRingbuffer, void **ppvHeadItem, void **ppvTailItem, size_t *pxHeadItemSize, size_t *pxTailItemSize, TickType_t xTicksToWait); +BaseType_t xRingbufferReceiveSplit(RingbufHandle_t xRingbuffer, + void **ppvHeadItem, + void **ppvTailItem, + size_t *pxHeadItemSize, + size_t *pxTailItemSize, + TickType_t xTicksToWait); /** * @brief Retrieve a split item from an allow-split ring buffer in an ISR @@ -207,14 +312,18 @@ BaseType_t xRingbufferReceiveSplit(RingbufHandle_t xRingbuffer, void **ppvHeadIt * - pdTRUE if an item (split or unsplit) was retrieved * - pdFALSE when no item was retrieved */ -BaseType_t xRingbufferReceiveSplitFromISR(RingbufHandle_t xRingbuffer, void **ppvHeadItem, void **ppvTailItem, size_t *pxHeadItemSize, size_t *pxTailItemSize); +BaseType_t xRingbufferReceiveSplitFromISR(RingbufHandle_t xRingbuffer, + void **ppvHeadItem, + void **ppvTailItem, + size_t *pxHeadItemSize, + size_t *pxTailItemSize); /** * @brief Retrieve bytes from a byte buffer, specifying the maximum amount of bytes to retrieve * * Attempt to retrieve data from a byte buffer whilst specifying a maximum number * of bytes to retrieve. This function will block until there is data available - * for retrieval or until it timesout. + * for retrieval or until it times out. * * @param[in] xRingbuffer Ring buffer to retrieve the item from * @param[out] pxItemSize Pointer to a variable to which the size of the retrieved item will be written. @@ -230,7 +339,10 @@ BaseType_t xRingbufferReceiveSplitFromISR(RingbufHandle_t xRingbuffer, void **pp * the length of the item. * - NULL on timeout, *pxItemSize is untouched in that case. */ -void *xRingbufferReceiveUpTo(RingbufHandle_t xRingbuffer, size_t *pxItemSize, TickType_t xTicksToWait, size_t xMaxSize); +void *xRingbufferReceiveUpTo(RingbufHandle_t xRingbuffer, + size_t *pxItemSize, + TickType_t xTicksToWait, + size_t xMaxSize); /** * @brief Retrieve bytes from a byte buffer, specifying the maximum amount of @@ -281,6 +393,10 @@ void vRingbufferReturnItemFromISR(RingbufHandle_t xRingbuffer, void *pvItem, Bas * @brief Delete a ring buffer * * @param[in] xRingbuffer Ring buffer to delete + * + * @note This function will not deallocate any memory if the ring buffer was + * created using xRingbufferCreateStatic(). Deallocation must be done + * manually be the user. */ void vRingbufferDelete(RingbufHandle_t xRingbuffer); @@ -292,6 +408,12 @@ void vRingbufferDelete(RingbufHandle_t xRingbuffer); * * @param[in] xRingbuffer Ring buffer to query * + * @note The max item size for a no-split buffer is limited to + * ((buffer_size/2)-header_size). This limit is imposed so that an item + * of max item size can always be sent to the an empty no-split buffer + * regardless of the internal positions of the buffer's read/write/free + * pointers. + * * @return Maximum size, in bytes, of an item that can be placed in a ring buffer. */ size_t xRingbufferGetMaxItemSize(RingbufHandle_t xRingbuffer); @@ -307,6 +429,10 @@ size_t xRingbufferGetMaxItemSize(RingbufHandle_t xRingbuffer); * the same ring buffer, it is the application's responsibility to * ensure atomic access to this API and the subsequent Send * + * @note An empty no-split buffer has a max current free size for an item + * that is limited to ((buffer_size/2)-header_size). See API reference + * for xRingbufferGetMaxItemSize(). + * * @param[in] xRingbuffer Ring buffer to query * * @return Current free size, in bytes, available for an entry @@ -371,9 +497,15 @@ BaseType_t xRingbufferRemoveFromQueueSetRead(RingbufHandle_t xRingbuffer, QueueS * @param[out] uxFree Pointer use to store free pointer position * @param[out] uxRead Pointer use to store read pointer position * @param[out] uxWrite Pointer use to store write pointer position + * @param[out] uxAcquire Pointer use to store acquire pointer position * @param[out] uxItemsWaiting Pointer use to store number of items (bytes for byte buffer) waiting to be retrieved */ -void vRingbufferGetInfo(RingbufHandle_t xRingbuffer, UBaseType_t *uxFree, UBaseType_t *uxRead, UBaseType_t *uxWrite, UBaseType_t *uxItemsWaiting); +void vRingbufferGetInfo(RingbufHandle_t xRingbuffer, + UBaseType_t *uxFree, + UBaseType_t *uxRead, + UBaseType_t *uxWrite, + UBaseType_t *uxAcquire, + UBaseType_t *uxItemsWaiting); /** * @brief Debugging function to print the internal pointers in the ring buffer @@ -382,30 +514,9 @@ void vRingbufferGetInfo(RingbufHandle_t xRingbuffer, UBaseType_t *uxFree, UBaseT */ void xRingbufferPrintInfo(RingbufHandle_t xRingbuffer); -/* -------------------------------- Deprecated Functions --------------------------- */ +/* ------------------------------- Deprecated ------------------------------- */ -/** @cond */ //Doxygen command to hide deprecated function from API Reference -/* - * Deprecated as function is not thread safe and does not check if an item is - * actually available for retrieval. Use xRingbufferReceiveSplit() instead for - * thread safe method of retrieve a split item. - */ -bool xRingbufferIsNextItemWrapped(RingbufHandle_t xRingbuffer) __attribute__((deprecated)); - -/* - * Deprecated as queue sets are not meant to be used for writing to buffers. Adding - * the ring buffer write semaphore to a queue set will break queue set usage rules, - * as every read of a semaphore must be preceded by a call to xQueueSelectFromSet(). - * QueueSetWrite no longer supported. - */ -BaseType_t xRingbufferAddToQueueSetWrite(RingbufHandle_t xRingbuffer, QueueSetHandle_t xQueueSet) __attribute__((deprecated)); - -/* - * Deprecated as queue sets are not meant to be used for writing to buffers. - * QueueSetWrite no longer supported. - */ -BaseType_t xRingbufferRemoveFromQueueSetWrite(RingbufHandle_t xRingbuffer, QueueSetHandle_t xQueueSet) __attribute__((deprecated)); -/** @endcond */ +typedef RingbufferType_t ringbuf_type_t __attribute__((deprecated)); #ifdef __cplusplus } diff --git a/components/esp_ringbuf/ringbuf.c b/components/esp_ringbuf/ringbuf.c index 558b61c6d8..33a1a5de88 100644 --- a/components/esp_ringbuf/ringbuf.c +++ b/components/esp_ringbuf/ringbuf.c @@ -1,9 +1,9 @@ -// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at - +// // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software @@ -21,17 +21,28 @@ //32-bit alignment macros #define rbALIGN_SIZE( xSize ) ( ( xSize + portBYTE_ALIGNMENT_MASK ) & ~portBYTE_ALIGNMENT_MASK ) -#define rbCHECK_ALIGNED( pvPtr ) ( ( ( UBaseType_t ) pvPtr & portBYTE_ALIGNMENT_MASK ) == 0 ) +#define rbCHECK_ALIGNED( pvPtr ) ( ( ( UBaseType_t ) ( pvPtr ) & portBYTE_ALIGNMENT_MASK ) == 0 ) //Ring buffer flags #define rbALLOW_SPLIT_FLAG ( ( UBaseType_t ) 1 ) //The ring buffer allows items to be split #define rbBYTE_BUFFER_FLAG ( ( UBaseType_t ) 2 ) //The ring buffer is a byte buffer #define rbBUFFER_FULL_FLAG ( ( UBaseType_t ) 4 ) //The ring buffer is currently full (write pointer == free pointer) +#define rbBUFFER_STATIC_FLAG ( ( UBaseType_t ) 8 ) //The ring buffer is statically allocated //Item flags #define rbITEM_FREE_FLAG ( ( UBaseType_t ) 1 ) //Item has been retrieved and returned by application, free to overwrite #define rbITEM_DUMMY_DATA_FLAG ( ( UBaseType_t ) 2 ) //Data from here to end of the ring buffer is dummy data. Restart reading at start of head of the buffer #define rbITEM_SPLIT_FLAG ( ( UBaseType_t ) 4 ) //Valid for RINGBUF_TYPE_ALLOWSPLIT, indicating that rest of the data is wrapped around +#define rbITEM_WRITTEN_FLAG ( ( UBaseType_t ) 8 ) //Item has been written to by the application, thus it is free to be read + +//Static allocation related +#if ( configSUPPORT_STATIC_ALLOCATION == 1 ) +#define rbGET_TX_SEM_HANDLE( pxRingbuffer ) ( (SemaphoreHandle_t) &(pxRingbuffer->xTransSemStatic) ) +#define rbGET_RX_SEM_HANDLE( pxRingbuffer ) ( (SemaphoreHandle_t) &(pxRingbuffer->xRecvSemStatic) ) +#else +#define rbGET_TX_SEM_HANDLE( pxRingbuffer ) ( pxRingbuffer->xTransSemHandle ) +#define rbGET_RX_SEM_HANDLE( pxRingbuffer ) ( pxRingbuffer->xRecvSemHandle ) +#endif typedef struct { //This size of this structure must be 32-bit aligned @@ -40,7 +51,7 @@ typedef struct { } ItemHeader_t; #define rbHEADER_SIZE sizeof(ItemHeader_t) -typedef struct Ringbuffer_t Ringbuffer_t; +typedef struct RingbufferDefinition Ringbuffer_t; typedef BaseType_t (*CheckItemFitsFunction_t)(Ringbuffer_t *pxRingbuffer, size_t xItemSize); typedef void (*CopyItemFunction_t)(Ringbuffer_t *pxRingbuffer, const uint8_t *pcItem, size_t xItemSize); typedef BaseType_t (*CheckItemAvailFunction_t) (Ringbuffer_t *pxRingbuffer); @@ -48,10 +59,10 @@ typedef void *(*GetItemFunction_t)(Ringbuffer_t *pxRingbuffer, BaseType_t *pxIsS typedef void (*ReturnItemFunction_t)(Ringbuffer_t *pxRingbuffer, uint8_t *pvItem); typedef size_t (*GetCurMaxSizeFunction_t)(Ringbuffer_t *pxRingbuffer); -struct Ringbuffer_t { +typedef struct RingbufferDefinition { size_t xSize; //Size of the data storage - UBaseType_t uxRingbufferFlags; //Flags to indicate the type and status of ring buffer size_t xMaxItemSize; //Maximum item size + UBaseType_t uxRingbufferFlags; //Flags to indicate the type and status of ring buffer CheckItemFitsFunction_t xCheckItemFits; //Function to check if item can currently fit in ring buffer CopyItemFunction_t vCopyItem; //Function to copy item to ring buffer @@ -59,6 +70,7 @@ struct Ringbuffer_t { ReturnItemFunction_t vReturnItem; //Function to return item to ring buffer GetCurMaxSizeFunction_t xGetCurMaxSize; //Function to get current free size + uint8_t *pucAcquire; //Acquire Pointer. Points to where the next item should be acquired. uint8_t *pucWrite; //Write Pointer. Points to where the next item should be written uint8_t *pucRead; //Read Pointer. Points to where the next item should be read from uint8_t *pucFree; //Free Pointer. Points to the last item that has yet to be returned to the ring buffer @@ -66,11 +78,37 @@ struct Ringbuffer_t { uint8_t *pucTail; //Pointer to the end of the ring buffer storage area BaseType_t xItemsWaiting; //Number of items/bytes(for byte buffers) currently in ring buffer that have not yet been read - SemaphoreHandle_t xFreeSpaceSemaphore; //Binary semaphore, wakes up writing threads when more free space becomes available or when another thread times out attempting to write - SemaphoreHandle_t xItemsBufferedSemaphore; //Binary semaphore, indicates there are new packets in the circular buffer. See remark. + /* + * TransSem: Binary semaphore used to indicate to a blocked transmitting tasks + * that more free space has become available or that the block has + * timed out. + * + * RecvSem: Binary semaphore used to indicate to a blocked receiving task that + * new data/item has been written to the ring buffer. + * + * Note - When static allocation is enabled, the two semaphores are always + * statically stored in the ring buffer's control structure + * regardless of whether the ring buffer is allocated dynamically or + * statically. When static allocation is disabled, the two semaphores + * are allocated dynamically and their handles stored instead, thus + * making the ring buffer's control structure slightly smaller when + * static allocation is disabled. + */ +#if ( configSUPPORT_STATIC_ALLOCATION == 1 ) + StaticSemaphore_t xTransSemStatic; + StaticSemaphore_t xRecvSemStatic; +#else + SemaphoreHandle_t xTransSemHandle; + SemaphoreHandle_t xRecvSemHandle; +#endif portMUX_TYPE mux; //Spinlock required for SMP -}; +} Ringbuffer_t; +#if ( configSUPPORT_STATIC_ALLOCATION == 1 ) +#if __GNUC_PREREQ(4, 6) +_Static_assert(sizeof(StaticRingbuffer_t) == sizeof(Ringbuffer_t), "StaticRingbuffer_t != Ringbuffer_t"); +#endif +#endif /* Remark: A counting semaphore for items_buffered_sem would be more logical, but counting semaphores in FreeRTOS need a maximum count, and allocate more memory the larger the maximum count is. Here, we @@ -78,13 +116,20 @@ would need to set the maximum to the maximum amount of times a null-byte unit fi which is quite high and so would waste a fair amount of memory. */ -/* ------------------------------------------------ Static Declarations ------------------------------------------ */ +/* --------------------------- Static Declarations -------------------------- */ /* * WARNING: All of the following static functions (except generic functions) * ARE NOT THREAD SAFE. Therefore they should only be called within a critical * section (using spin locks) */ + +//Initialize a ring buffer after space has been allocated for it +static void prvInitializeNewRingbuffer(size_t xBufferSize, + RingbufferType_t xBufferType, + Ringbuffer_t *pxNewRingbuffer, + uint8_t *pucRingbufferStorage); + //Calculate current amount of free space (in bytes) in the ring buffer static size_t prvGetFreeSize(Ringbuffer_t *pxRingbuffer); @@ -107,10 +152,16 @@ static void prvCopyItemAllowSplit(Ringbuffer_t *pxRingbuffer, const uint8_t *puc static void prvCopyItemByteBuf(Ringbuffer_t *pxRingbuffer, const uint8_t *pucItem, size_t xItemSize); //Retrieve item from no-split/allow-split ring buffer. *pxIsSplit is set to pdTRUE if the retrieved item is split -static void *prvGetItemDefault(Ringbuffer_t *pxRingbuffer, BaseType_t *pxIsSplit, size_t xUnusedParam, size_t *pxItemSize); +static void *prvGetItemDefault(Ringbuffer_t *pxRingbuffer, + BaseType_t *pxIsSplit, + size_t xUnusedParam, + size_t *pxItemSize); //Retrieve data from byte buffer. If xMaxSize is 0, all continuous data is retrieved -static void *prvGetItemByteBuf(Ringbuffer_t *pxRingbuffer, BaseType_t *pxUnusedParam ,size_t xMaxSize, size_t *pxItemSize); +static void *prvGetItemByteBuf(Ringbuffer_t *pxRingbuffer, + BaseType_t *pxUnusedParam, + size_t xMaxSize, + size_t *pxItemSize); //Return an item to a split/no-split ring buffer static void prvReturnItemDefault(Ringbuffer_t *pxRingbuffer, uint8_t *pucItem); @@ -133,12 +184,74 @@ static size_t prvGetCurMaxSizeByteBuf(Ringbuffer_t *pxRingbuffer); * a split item will be retrieved. xMaxSize will only take effect if called on * byte buffers. */ -static BaseType_t prvReceiveGeneric(Ringbuffer_t *pxRingbuffer, void **pvItem1, void **pvItem2, size_t *xItemSize1, size_t *xItemSize2, size_t xMaxSize, TickType_t xTicksToWait); +static BaseType_t prvReceiveGeneric(Ringbuffer_t *pxRingbuffer, + void **pvItem1, + void **pvItem2, + size_t *xItemSize1, + size_t *xItemSize2, + size_t xMaxSize, + TickType_t xTicksToWait); //Generic function used to retrieve an item/data from ring buffers in an ISR -static BaseType_t prvReceiveGenericFromISR(Ringbuffer_t *pxRingbuffer, void **pvItem1, void **pvItem2, size_t *xItemSize1, size_t *xItemSize2, size_t xMaxSize); +static BaseType_t prvReceiveGenericFromISR(Ringbuffer_t *pxRingbuffer, + void **pvItem1, + void **pvItem2, + size_t *xItemSize1, + size_t *xItemSize2, + size_t xMaxSize); -/* ------------------------------------------------ Static Definitions ------------------------------------------- */ +/* --------------------------- Static Definitions --------------------------- */ + +static void prvInitializeNewRingbuffer(size_t xBufferSize, + RingbufferType_t xBufferType, + Ringbuffer_t *pxNewRingbuffer, + uint8_t *pucRingbufferStorage) +{ + //Initialize values + pxNewRingbuffer->xSize = xBufferSize; + pxNewRingbuffer->pucHead = pucRingbufferStorage; + pxNewRingbuffer->pucTail = pucRingbufferStorage + xBufferSize; + pxNewRingbuffer->pucFree = pucRingbufferStorage; + pxNewRingbuffer->pucRead = pucRingbufferStorage; + pxNewRingbuffer->pucWrite = pucRingbufferStorage; + pxNewRingbuffer->pucAcquire = pucRingbufferStorage; + pxNewRingbuffer->xItemsWaiting = 0; + pxNewRingbuffer->uxRingbufferFlags = 0; + + //Initialize type dependent values and function pointers + if (xBufferType == RINGBUF_TYPE_NOSPLIT) { + pxNewRingbuffer->xCheckItemFits = prvCheckItemFitsDefault; + pxNewRingbuffer->vCopyItem = prvCopyItemNoSplit; + pxNewRingbuffer->pvGetItem = prvGetItemDefault; + pxNewRingbuffer->vReturnItem = prvReturnItemDefault; + /* + * Worst case scenario is when the read/write/acquire/free pointers are all + * pointing to the halfway point of the buffer. + */ + pxNewRingbuffer->xMaxItemSize = rbALIGN_SIZE(pxNewRingbuffer->xSize / 2) - rbHEADER_SIZE; + pxNewRingbuffer->xGetCurMaxSize = prvGetCurMaxSizeNoSplit; + } else if (xBufferType == RINGBUF_TYPE_ALLOWSPLIT) { + pxNewRingbuffer->uxRingbufferFlags |= rbALLOW_SPLIT_FLAG; + pxNewRingbuffer->xCheckItemFits = prvCheckItemFitsDefault; + pxNewRingbuffer->vCopyItem = prvCopyItemAllowSplit; + pxNewRingbuffer->pvGetItem = prvGetItemDefault; + pxNewRingbuffer->vReturnItem = prvReturnItemDefault; + //Worst case an item is split into two, incurring two headers of overhead + pxNewRingbuffer->xMaxItemSize = pxNewRingbuffer->xSize - (sizeof(ItemHeader_t) * 2); + pxNewRingbuffer->xGetCurMaxSize = prvGetCurMaxSizeAllowSplit; + } else { //Byte Buffer + pxNewRingbuffer->uxRingbufferFlags |= rbBYTE_BUFFER_FLAG; + pxNewRingbuffer->xCheckItemFits = prvCheckItemFitsByteBuffer; + pxNewRingbuffer->vCopyItem = prvCopyItemByteBuf; + pxNewRingbuffer->pvGetItem = prvGetItemByteBuf; + pxNewRingbuffer->vReturnItem = prvReturnItemByteBuf; + //Byte buffers do not incur any overhead + pxNewRingbuffer->xMaxItemSize = pxNewRingbuffer->xSize; + pxNewRingbuffer->xGetCurMaxSize = prvGetCurMaxSizeByteBuf; + } + xSemaphoreGive(rbGET_TX_SEM_HANDLE(pxNewRingbuffer)); + vPortCPUInitializeMutex(&pxNewRingbuffer->mux); +} static size_t prvGetFreeSize(Ringbuffer_t *pxRingbuffer) { @@ -146,7 +259,7 @@ static size_t prvGetFreeSize(Ringbuffer_t *pxRingbuffer) if (pxRingbuffer->uxRingbufferFlags & rbBUFFER_FULL_FLAG) { xReturn = 0; } else { - BaseType_t xFreeSize = pxRingbuffer->pucFree - pxRingbuffer->pucWrite; + BaseType_t xFreeSize = pxRingbuffer->pucFree - pxRingbuffer->pucAcquire; //Check if xFreeSize has underflowed if (xFreeSize <= 0) { xFreeSize += pxRingbuffer->xSize; @@ -160,26 +273,26 @@ static size_t prvGetFreeSize(Ringbuffer_t *pxRingbuffer) static BaseType_t prvCheckItemFitsDefault( Ringbuffer_t *pxRingbuffer, size_t xItemSize) { //Check arguments and buffer state - configASSERT(rbCHECK_ALIGNED(pxRingbuffer->pucWrite)); //pucWrite is always aligned in no-split ring buffers - configASSERT(pxRingbuffer->pucWrite >= pxRingbuffer->pucHead && pxRingbuffer->pucWrite < pxRingbuffer->pucTail); //Check write pointer is within bounds + configASSERT(rbCHECK_ALIGNED(pxRingbuffer->pucAcquire)); //pucAcquire is always aligned in no-split/allow-split ring buffers + configASSERT(pxRingbuffer->pucAcquire >= pxRingbuffer->pucHead && pxRingbuffer->pucAcquire < pxRingbuffer->pucTail); //Check write pointer is within bounds size_t xTotalItemSize = rbALIGN_SIZE(xItemSize) + rbHEADER_SIZE; //Rounded up aligned item size with header - if (pxRingbuffer->pucWrite == pxRingbuffer->pucFree) { + if (pxRingbuffer->pucAcquire == pxRingbuffer->pucFree) { //Buffer is either complete empty or completely full return (pxRingbuffer->uxRingbufferFlags & rbBUFFER_FULL_FLAG) ? pdFALSE : pdTRUE; } - if (pxRingbuffer->pucFree > pxRingbuffer->pucWrite) { + if (pxRingbuffer->pucFree > pxRingbuffer->pucAcquire) { //Free space does not wrap around - return (xTotalItemSize <= pxRingbuffer->pucFree - pxRingbuffer->pucWrite) ? pdTRUE : pdFALSE; + return (xTotalItemSize <= pxRingbuffer->pucFree - pxRingbuffer->pucAcquire) ? pdTRUE : pdFALSE; } //Free space wraps around - if (xTotalItemSize <= pxRingbuffer->pucTail - pxRingbuffer->pucWrite) { + if (xTotalItemSize <= pxRingbuffer->pucTail - pxRingbuffer->pucAcquire) { return pdTRUE; //Item fits without wrapping around } //Check if item fits by wrapping if (pxRingbuffer->uxRingbufferFlags & rbALLOW_SPLIT_FLAG) { //Allow split wrapping incurs an extra header - return (xTotalItemSize + rbHEADER_SIZE <= pxRingbuffer->xSize - (pxRingbuffer->pucWrite - pxRingbuffer->pucFree)) ? pdTRUE : pdFALSE; + return (xTotalItemSize + rbHEADER_SIZE <= pxRingbuffer->xSize - (pxRingbuffer->pucAcquire - pxRingbuffer->pucFree)) ? pdTRUE : pdFALSE; } else { return (xTotalItemSize <= pxRingbuffer->pucFree - pxRingbuffer->pucHead) ? pdTRUE : pdFALSE; } @@ -188,76 +301,130 @@ static BaseType_t prvCheckItemFitsDefault( Ringbuffer_t *pxRingbuffer, size_t xI static BaseType_t prvCheckItemFitsByteBuffer( Ringbuffer_t *pxRingbuffer, size_t xItemSize) { //Check arguments and buffer state - configASSERT(pxRingbuffer->pucWrite >= pxRingbuffer->pucHead && pxRingbuffer->pucWrite < pxRingbuffer->pucTail); //Check write pointer is within bounds + configASSERT(pxRingbuffer->pucAcquire >= pxRingbuffer->pucHead && pxRingbuffer->pucAcquire < pxRingbuffer->pucTail); //Check acquire pointer is within bounds - if (pxRingbuffer->pucWrite == pxRingbuffer->pucFree) { + if (pxRingbuffer->pucAcquire == pxRingbuffer->pucFree) { //Buffer is either complete empty or completely full return (pxRingbuffer->uxRingbufferFlags & rbBUFFER_FULL_FLAG) ? pdFALSE : pdTRUE; } - if (pxRingbuffer->pucFree > pxRingbuffer->pucWrite) { + if (pxRingbuffer->pucFree > pxRingbuffer->pucAcquire) { //Free space does not wrap around - return (xItemSize <= pxRingbuffer->pucFree - pxRingbuffer->pucWrite) ? pdTRUE : pdFALSE; + return (xItemSize <= pxRingbuffer->pucFree - pxRingbuffer->pucAcquire) ? pdTRUE : pdFALSE; } //Free space wraps around - return (xItemSize <= pxRingbuffer->xSize - (pxRingbuffer->pucWrite - pxRingbuffer->pucFree)) ? pdTRUE : pdFALSE; + return (xItemSize <= pxRingbuffer->xSize - (pxRingbuffer->pucAcquire - pxRingbuffer->pucFree)) ? pdTRUE : pdFALSE; } -static void prvCopyItemNoSplit(Ringbuffer_t *pxRingbuffer, const uint8_t *pucItem, size_t xItemSize) +static uint8_t* prvAcquireItemNoSplit(Ringbuffer_t *pxRingbuffer, size_t xItemSize) { //Check arguments and buffer state size_t xAlignedItemSize = rbALIGN_SIZE(xItemSize); //Rounded up aligned item size - size_t xRemLen = pxRingbuffer->pucTail - pxRingbuffer->pucWrite; //Length from pucWrite until end of buffer - configASSERT(rbCHECK_ALIGNED(pxRingbuffer->pucWrite)); //pucWrite is always aligned in no-split ring buffers - configASSERT(pxRingbuffer->pucWrite >= pxRingbuffer->pucHead && pxRingbuffer->pucWrite < pxRingbuffer->pucTail); //Check write pointer is within bounds + size_t xRemLen = pxRingbuffer->pucTail - pxRingbuffer->pucAcquire; //Length from pucAcquire until end of buffer + configASSERT(rbCHECK_ALIGNED(pxRingbuffer->pucAcquire)); //pucAcquire is always aligned in no-split ring buffers + configASSERT(pxRingbuffer->pucAcquire >= pxRingbuffer->pucHead && pxRingbuffer->pucAcquire < pxRingbuffer->pucTail); //Check write pointer is within bounds configASSERT(xRemLen >= rbHEADER_SIZE); //Remaining length must be able to at least fit an item header //If remaining length can't fit item, set as dummy data and wrap around if (xRemLen < xAlignedItemSize + rbHEADER_SIZE) { - ItemHeader_t *pxDummy = (ItemHeader_t *)pxRingbuffer->pucWrite; + ItemHeader_t *pxDummy = (ItemHeader_t *)pxRingbuffer->pucAcquire; pxDummy->uxItemFlags = rbITEM_DUMMY_DATA_FLAG; //Set remaining length as dummy data pxDummy->xItemLen = 0; //Dummy data should have no length - pxRingbuffer->pucWrite = pxRingbuffer->pucHead; //Reset write pointer to wrap around + pxRingbuffer->pucAcquire = pxRingbuffer->pucHead; //Reset acquire pointer to wrap around } //Item should be guaranteed to fit at this point. Set item header and copy data - ItemHeader_t *pxHeader = (ItemHeader_t *)pxRingbuffer->pucWrite; + ItemHeader_t *pxHeader = (ItemHeader_t *)pxRingbuffer->pucAcquire; pxHeader->xItemLen = xItemSize; pxHeader->uxItemFlags = 0; - pxRingbuffer->pucWrite += rbHEADER_SIZE; //Advance pucWrite past header - memcpy(pxRingbuffer->pucWrite, pucItem, xItemSize); - pxRingbuffer->xItemsWaiting++; - pxRingbuffer->pucWrite += xAlignedItemSize; //Advance pucWrite past item to next aligned address + //hold the buffer address without touching pucWrite + uint8_t* item_address = pxRingbuffer->pucAcquire + rbHEADER_SIZE; + pxRingbuffer->pucAcquire += rbHEADER_SIZE + xAlignedItemSize; //Advance pucAcquire past header and the item to next aligned address + + //After the allocation, add some padding after the buffer and correct the flags //If current remaining length can't fit a header, wrap around write pointer - if (pxRingbuffer->pucTail - pxRingbuffer->pucWrite < rbHEADER_SIZE) { - pxRingbuffer->pucWrite = pxRingbuffer->pucHead; //Wrap around pucWrite + if (pxRingbuffer->pucTail - pxRingbuffer->pucAcquire < rbHEADER_SIZE) { + pxRingbuffer->pucAcquire = pxRingbuffer->pucHead; //Wrap around pucAcquire } //Check if buffer is full - if (pxRingbuffer->pucWrite == pxRingbuffer->pucFree) { + if (pxRingbuffer->pucAcquire == pxRingbuffer->pucFree) { //Mark the buffer as full to distinguish with an empty buffer pxRingbuffer->uxRingbufferFlags |= rbBUFFER_FULL_FLAG; } + return item_address; +} + +static void prvSendItemDoneNoSplit(Ringbuffer_t *pxRingbuffer, uint8_t* pucItem) +{ + //Check arguments and buffer state + configASSERT(rbCHECK_ALIGNED(pucItem)); + configASSERT(pucItem >= pxRingbuffer->pucHead); + configASSERT(pucItem <= pxRingbuffer->pucTail); //Inclusive of pucTail in the case of zero length item at the very end + + //Get and check header of the item + ItemHeader_t *pxCurHeader = (ItemHeader_t *)(pucItem - rbHEADER_SIZE); + configASSERT(pxCurHeader->xItemLen <= pxRingbuffer->xMaxItemSize); + configASSERT((pxCurHeader->uxItemFlags & rbITEM_DUMMY_DATA_FLAG) == 0); //Dummy items should never have been written + configASSERT((pxCurHeader->uxItemFlags & rbITEM_WRITTEN_FLAG) == 0); //Indicates item has already been written before + pxCurHeader->uxItemFlags &= ~rbITEM_SPLIT_FLAG; //Clear wrap flag if set (not strictly necessary) + pxCurHeader->uxItemFlags |= rbITEM_WRITTEN_FLAG; //Mark as written + + pxRingbuffer->xItemsWaiting++; + + /* + * Items might not be written in the order they were acquired. Move the + * write pointer up to the next item that has not been marked as written (by + * written flag) or up till the acquire pointer. When advancing the write + * pointer, items that have already been written or items with dummy data + * should be skipped over + */ + pxCurHeader = (ItemHeader_t *)pxRingbuffer->pucWrite; + //Skip over Items that have already been written or are dummy items + while (((pxCurHeader->uxItemFlags & rbITEM_WRITTEN_FLAG) || (pxCurHeader->uxItemFlags & rbITEM_DUMMY_DATA_FLAG)) && pxRingbuffer->pucWrite != pxRingbuffer->pucAcquire) { + if (pxCurHeader->uxItemFlags & rbITEM_DUMMY_DATA_FLAG) { + pxCurHeader->uxItemFlags |= rbITEM_WRITTEN_FLAG; //Mark as freed (not strictly necessary but adds redundancy) + pxRingbuffer->pucWrite = pxRingbuffer->pucHead; //Wrap around due to dummy data + } else { + //Item with data that has already been written, advance write pointer past this item + size_t xAlignedItemSize = rbALIGN_SIZE(pxCurHeader->xItemLen); + pxRingbuffer->pucWrite += xAlignedItemSize + rbHEADER_SIZE; + //Redundancy check to ensure write pointer has not overshot buffer bounds + configASSERT(pxRingbuffer->pucWrite <= pxRingbuffer->pucHead + pxRingbuffer->xSize); + } + //Check if pucAcquire requires wrap around + if ((pxRingbuffer->pucTail - pxRingbuffer->pucWrite) < rbHEADER_SIZE) { + pxRingbuffer->pucWrite = pxRingbuffer->pucHead; + } + pxCurHeader = (ItemHeader_t *)pxRingbuffer->pucWrite; //Update header to point to item + } +} + +static void prvCopyItemNoSplit(Ringbuffer_t *pxRingbuffer, const uint8_t *pucItem, size_t xItemSize) +{ + uint8_t* item_addr = prvAcquireItemNoSplit(pxRingbuffer, xItemSize); + memcpy(item_addr, pucItem, xItemSize); + prvSendItemDoneNoSplit(pxRingbuffer, item_addr); } static void prvCopyItemAllowSplit(Ringbuffer_t *pxRingbuffer, const uint8_t *pucItem, size_t xItemSize) { //Check arguments and buffer state size_t xAlignedItemSize = rbALIGN_SIZE(xItemSize); //Rounded up aligned item size - size_t xRemLen = pxRingbuffer->pucTail - pxRingbuffer->pucWrite; //Length from pucWrite until end of buffer - configASSERT(rbCHECK_ALIGNED(pxRingbuffer->pucWrite)); //pucWrite is always aligned in split ring buffers - configASSERT(pxRingbuffer->pucWrite >= pxRingbuffer->pucHead && pxRingbuffer->pucWrite < pxRingbuffer->pucTail); //Check write pointer is within bounds + size_t xRemLen = pxRingbuffer->pucTail - pxRingbuffer->pucAcquire; //Length from pucAcquire until end of buffer + configASSERT(rbCHECK_ALIGNED(pxRingbuffer->pucAcquire)); //pucAcquire is always aligned in split ring buffers + configASSERT(pxRingbuffer->pucAcquire >= pxRingbuffer->pucHead && pxRingbuffer->pucAcquire < pxRingbuffer->pucTail); //Check write pointer is within bounds configASSERT(xRemLen >= rbHEADER_SIZE); //Remaining length must be able to at least fit an item header //Split item if necessary if (xRemLen < xAlignedItemSize + rbHEADER_SIZE) { //Write first part of the item - ItemHeader_t *pxFirstHeader = (ItemHeader_t *)pxRingbuffer->pucWrite; + ItemHeader_t *pxFirstHeader = (ItemHeader_t *)pxRingbuffer->pucAcquire; pxFirstHeader->uxItemFlags = 0; pxFirstHeader->xItemLen = xRemLen - rbHEADER_SIZE; //Fill remaining length with first part - pxRingbuffer->pucWrite += rbHEADER_SIZE; //Advance pucWrite past header + pxRingbuffer->pucAcquire += rbHEADER_SIZE; //Advance pucAcquire past header xRemLen -= rbHEADER_SIZE; if (xRemLen > 0) { - memcpy(pxRingbuffer->pucWrite, pucItem, xRemLen); + memcpy(pxRingbuffer->pucAcquire, pucItem, xRemLen); pxRingbuffer->xItemsWaiting++; //Update item arguments to account for data already copied pucItem += xRemLen; @@ -268,57 +435,63 @@ static void prvCopyItemAllowSplit(Ringbuffer_t *pxRingbuffer, const uint8_t *puc //Remaining length was only large enough to fit header pxFirstHeader->uxItemFlags |= rbITEM_DUMMY_DATA_FLAG; //Item will completely be stored in 2nd part } - pxRingbuffer->pucWrite = pxRingbuffer->pucHead; //Reset write pointer to start of buffer + pxRingbuffer->pucAcquire = pxRingbuffer->pucHead; //Reset acquire pointer to start of buffer } //Item (whole or second part) should be guaranteed to fit at this point - ItemHeader_t *pxSecondHeader = (ItemHeader_t *)pxRingbuffer->pucWrite; + ItemHeader_t *pxSecondHeader = (ItemHeader_t *)pxRingbuffer->pucAcquire; pxSecondHeader->xItemLen = xItemSize; pxSecondHeader->uxItemFlags = 0; - pxRingbuffer->pucWrite += rbHEADER_SIZE; //Advance write pointer past header - memcpy(pxRingbuffer->pucWrite, pucItem, xItemSize); + pxRingbuffer->pucAcquire += rbHEADER_SIZE; //Advance acquire pointer past header + memcpy(pxRingbuffer->pucAcquire, pucItem, xItemSize); pxRingbuffer->xItemsWaiting++; - pxRingbuffer->pucWrite += xAlignedItemSize; //Advance pucWrite past item to next aligned address + pxRingbuffer->pucAcquire += xAlignedItemSize; //Advance pucAcquire past item to next aligned address //If current remaining length can't fit a header, wrap around write pointer - if (pxRingbuffer->pucTail - pxRingbuffer->pucWrite < rbHEADER_SIZE) { - pxRingbuffer->pucWrite = pxRingbuffer->pucHead; //Wrap around pucWrite + if (pxRingbuffer->pucTail - pxRingbuffer->pucAcquire < rbHEADER_SIZE) { + pxRingbuffer->pucAcquire = pxRingbuffer->pucHead; //Wrap around pucAcquire } //Check if buffer is full - if (pxRingbuffer->pucWrite == pxRingbuffer->pucFree) { + if (pxRingbuffer->pucAcquire == pxRingbuffer->pucFree) { //Mark the buffer as full to distinguish with an empty buffer pxRingbuffer->uxRingbufferFlags |= rbBUFFER_FULL_FLAG; } + + //currently the Split mode is not supported, pucWrite tracks the pucAcquire + pxRingbuffer->pucWrite = pxRingbuffer->pucAcquire; } static void prvCopyItemByteBuf(Ringbuffer_t *pxRingbuffer, const uint8_t *pucItem, size_t xItemSize) { //Check arguments and buffer state - configASSERT(pxRingbuffer->pucWrite >= pxRingbuffer->pucHead && pxRingbuffer->pucWrite < pxRingbuffer->pucTail); //Check write pointer is within bounds + configASSERT(pxRingbuffer->pucAcquire >= pxRingbuffer->pucHead && pxRingbuffer->pucAcquire < pxRingbuffer->pucTail); //Check acquire pointer is within bounds - size_t xRemLen = pxRingbuffer->pucTail - pxRingbuffer->pucWrite; //Length from pucWrite until end of buffer + size_t xRemLen = pxRingbuffer->pucTail - pxRingbuffer->pucAcquire; //Length from pucAcquire until end of buffer if (xRemLen < xItemSize) { //Copy as much as possible into remaining length - memcpy(pxRingbuffer->pucWrite, pucItem, xRemLen); + memcpy(pxRingbuffer->pucAcquire, pucItem, xRemLen); pxRingbuffer->xItemsWaiting += xRemLen; //Update item arguments to account for data already written pucItem += xRemLen; xItemSize -= xRemLen; - pxRingbuffer->pucWrite = pxRingbuffer->pucHead; //Reset write pointer to start of buffer + pxRingbuffer->pucAcquire = pxRingbuffer->pucHead; //Reset acquire pointer to start of buffer } //Copy all or remaining portion of the item - memcpy(pxRingbuffer->pucWrite, pucItem, xItemSize); + memcpy(pxRingbuffer->pucAcquire, pucItem, xItemSize); pxRingbuffer->xItemsWaiting += xItemSize; - pxRingbuffer->pucWrite += xItemSize; + pxRingbuffer->pucAcquire += xItemSize; - //Wrap around pucWrite if it reaches the end - if (pxRingbuffer->pucWrite == pxRingbuffer->pucTail) { - pxRingbuffer->pucWrite = pxRingbuffer->pucHead; + //Wrap around pucAcquire if it reaches the end + if (pxRingbuffer->pucAcquire == pxRingbuffer->pucTail) { + pxRingbuffer->pucAcquire = pxRingbuffer->pucHead; } //Check if buffer is full - if (pxRingbuffer->pucWrite == pxRingbuffer->pucFree) { + if (pxRingbuffer->pucAcquire == pxRingbuffer->pucFree) { pxRingbuffer->uxRingbufferFlags |= rbBUFFER_FULL_FLAG; //Mark the buffer as full to avoid confusion with an empty buffer } + + //Currently, acquiring memory is not supported in byte mode. pucWrite tracks the pucAcquire. + pxRingbuffer->pucWrite = pxRingbuffer->pucAcquire; } static BaseType_t prvCheckItemAvail(Ringbuffer_t *pxRingbuffer) @@ -333,7 +506,10 @@ static BaseType_t prvCheckItemAvail(Ringbuffer_t *pxRingbuffer) } } -static void *prvGetItemDefault(Ringbuffer_t *pxRingbuffer, BaseType_t *pxIsSplit, size_t xUnusedParam, size_t *pxItemSize) +static void *prvGetItemDefault(Ringbuffer_t *pxRingbuffer, + BaseType_t *pxIsSplit, + size_t xUnusedParam, + size_t *pxItemSize) { //Check arguments and buffer state ItemHeader_t *pxHeader = (ItemHeader_t *)pxRingbuffer->pucRead; @@ -371,7 +547,10 @@ static void *prvGetItemDefault(Ringbuffer_t *pxRingbuffer, BaseType_t *pxIsSplit return (void *)pcReturn; } -static void *prvGetItemByteBuf(Ringbuffer_t *pxRingbuffer, BaseType_t *pxUnusedParam ,size_t xMaxSize, size_t *pxItemSize) +static void *prvGetItemByteBuf(Ringbuffer_t *pxRingbuffer, + BaseType_t *pxUnusedParam, + size_t xMaxSize, + size_t *pxItemSize) { //Check arguments and buffer state configASSERT((pxRingbuffer->xItemsWaiting > 0) && ((pxRingbuffer->pucRead != pxRingbuffer->pucWrite) || (pxRingbuffer->uxRingbufferFlags & rbBUFFER_FULL_FLAG))); //Check there are items to be read @@ -452,9 +631,9 @@ static void prvReturnItemDefault(Ringbuffer_t *pxRingbuffer, uint8_t *pucItem) //Check if the buffer full flag should be reset if (pxRingbuffer->uxRingbufferFlags & rbBUFFER_FULL_FLAG) { - if (pxRingbuffer->pucFree != pxRingbuffer->pucWrite) { + if (pxRingbuffer->pucFree != pxRingbuffer->pucAcquire) { pxRingbuffer->uxRingbufferFlags &= ~rbBUFFER_FULL_FLAG; - } else if (pxRingbuffer->pucFree == pxRingbuffer->pucWrite && pxRingbuffer->pucFree == pxRingbuffer->pucRead) { + } else if (pxRingbuffer->pucFree == pxRingbuffer->pucAcquire && pxRingbuffer->pucFree == pxRingbuffer->pucRead) { //Special case where a full buffer is completely freed in one go pxRingbuffer->uxRingbufferFlags &= ~rbBUFFER_FULL_FLAG; } @@ -481,13 +660,13 @@ static size_t prvGetCurMaxSizeNoSplit(Ringbuffer_t *pxRingbuffer) if (pxRingbuffer->uxRingbufferFlags & rbBUFFER_FULL_FLAG) { return 0; } - if (pxRingbuffer->pucWrite < pxRingbuffer->pucFree) { - //Free space is contiguous between pucWrite and pucFree - xFreeSize = pxRingbuffer->pucFree - pxRingbuffer->pucWrite; + if (pxRingbuffer->pucAcquire < pxRingbuffer->pucFree) { + //Free space is contiguous between pucAcquire and pucFree + xFreeSize = pxRingbuffer->pucFree - pxRingbuffer->pucAcquire; } else { //Free space wraps around (or overlapped at pucHead), select largest //contiguous free space as no-split items require contiguous space - size_t xSize1 = pxRingbuffer->pucTail - pxRingbuffer->pucWrite; + size_t xSize1 = pxRingbuffer->pucTail - pxRingbuffer->pucAcquire; size_t xSize2 = pxRingbuffer->pucFree - pxRingbuffer->pucHead; xFreeSize = (xSize1 > xSize2) ? xSize1 : xSize2; } @@ -511,16 +690,16 @@ static size_t prvGetCurMaxSizeAllowSplit(Ringbuffer_t *pxRingbuffer) if (pxRingbuffer->uxRingbufferFlags & rbBUFFER_FULL_FLAG) { return 0; } - if (pxRingbuffer->pucWrite == pxRingbuffer->pucHead && pxRingbuffer->pucFree == pxRingbuffer->pucHead) { - //Check for special case where pucWrite and pucFree are both at pucHead + if (pxRingbuffer->pucAcquire == pxRingbuffer->pucHead && pxRingbuffer->pucFree == pxRingbuffer->pucHead) { + //Check for special case where pucAcquire and pucFree are both at pucHead xFreeSize = pxRingbuffer->xSize - rbHEADER_SIZE; - } else if (pxRingbuffer->pucWrite < pxRingbuffer->pucFree) { - //Free space is contiguous between pucWrite and pucFree, requires single header - xFreeSize = (pxRingbuffer->pucFree - pxRingbuffer->pucWrite) - rbHEADER_SIZE; + } else if (pxRingbuffer->pucAcquire < pxRingbuffer->pucFree) { + //Free space is contiguous between pucAcquire and pucFree, requires single header + xFreeSize = (pxRingbuffer->pucFree - pxRingbuffer->pucAcquire) - rbHEADER_SIZE; } else { //Free space wraps around, requires two headers xFreeSize = (pxRingbuffer->pucFree - pxRingbuffer->pucHead) + - (pxRingbuffer->pucTail - pxRingbuffer->pucWrite) - + (pxRingbuffer->pucTail - pxRingbuffer->pucAcquire) - (rbHEADER_SIZE * 2); } @@ -543,16 +722,22 @@ static size_t prvGetCurMaxSizeByteBuf(Ringbuffer_t *pxRingbuffer) /* * Return whatever space is available depending on relative positions of the free - * pointer and write pointer. There is no overhead of headers in this mode + * pointer and Acquire pointer. There is no overhead of headers in this mode */ - xFreeSize = pxRingbuffer->pucFree - pxRingbuffer->pucWrite; + xFreeSize = pxRingbuffer->pucFree - pxRingbuffer->pucAcquire; if (xFreeSize <= 0) { xFreeSize += pxRingbuffer->xSize; } return xFreeSize; } -static BaseType_t prvReceiveGeneric(Ringbuffer_t *pxRingbuffer, void **pvItem1, void **pvItem2, size_t *xItemSize1, size_t *xItemSize2, size_t xMaxSize, TickType_t xTicksToWait) +static BaseType_t prvReceiveGeneric(Ringbuffer_t *pxRingbuffer, + void **pvItem1, + void **pvItem2, + size_t *xItemSize1, + size_t *xItemSize2, + size_t xMaxSize, + TickType_t xTicksToWait) { BaseType_t xReturn = pdFALSE; BaseType_t xReturnSemaphore = pdFALSE; @@ -560,7 +745,7 @@ static BaseType_t prvReceiveGeneric(Ringbuffer_t *pxRingbuffer, void **pvItem1, TickType_t xTicksRemaining = xTicksToWait; while (xTicksRemaining <= xTicksToWait) { //xTicksToWait will underflow once xTaskGetTickCount() > ticks_end //Block until more free space becomes available or timeout - if (xSemaphoreTake(pxRingbuffer->xItemsBufferedSemaphore, xTicksRemaining) != pdTRUE) { + if (xSemaphoreTake(rbGET_RX_SEM_HANDLE(pxRingbuffer), xTicksRemaining) != pdTRUE) { xReturn = pdFALSE; //Timed out attempting to get semaphore break; } @@ -606,12 +791,17 @@ static BaseType_t prvReceiveGeneric(Ringbuffer_t *pxRingbuffer, void **pvItem1, } if (xReturnSemaphore == pdTRUE) { - xSemaphoreGive(pxRingbuffer->xItemsBufferedSemaphore); //Give semaphore back so other tasks can retrieve + xSemaphoreGive(rbGET_RX_SEM_HANDLE(pxRingbuffer)); //Give semaphore back so other tasks can retrieve } return xReturn; } -static BaseType_t prvReceiveGenericFromISR(Ringbuffer_t *pxRingbuffer, void **pvItem1, void **pvItem2, size_t *xItemSize1, size_t *xItemSize2, size_t xMaxSize) +static BaseType_t prvReceiveGenericFromISR(Ringbuffer_t *pxRingbuffer, + void **pvItem1, + void **pvItem2, + size_t *xItemSize1, + size_t *xItemSize2, + size_t xMaxSize) { BaseType_t xReturn = pdFALSE; BaseType_t xReturnSemaphore = pdFALSE; @@ -644,95 +834,54 @@ static BaseType_t prvReceiveGenericFromISR(Ringbuffer_t *pxRingbuffer, void **pv portEXIT_CRITICAL_ISR(&pxRingbuffer->mux); if (xReturnSemaphore == pdTRUE) { - xSemaphoreGiveFromISR(pxRingbuffer->xItemsBufferedSemaphore, NULL); //Give semaphore back so other tasks can retrieve + xSemaphoreGiveFromISR(rbGET_RX_SEM_HANDLE(pxRingbuffer), NULL); //Give semaphore back so other tasks can retrieve } return xReturn; } -/* ------------------------------------------------- Public Definitions -------------------------------------------- */ +/* --------------------------- Public Definitions --------------------------- */ -RingbufHandle_t xRingbufferCreate(size_t xBufferSize, ringbuf_type_t xBufferType) +RingbufHandle_t xRingbufferCreate(size_t xBufferSize, RingbufferType_t xBufferType) { + configASSERT(xBufferSize > 0); + configASSERT(xBufferType < RINGBUF_TYPE_MAX); + //Allocate memory - Ringbuffer_t *pxRingbuffer = calloc(1, sizeof(Ringbuffer_t)); - if (pxRingbuffer == NULL) { - goto err; - } if (xBufferType != RINGBUF_TYPE_BYTEBUF) { xBufferSize = rbALIGN_SIZE(xBufferSize); //xBufferSize is rounded up for no-split/allow-split buffers } - pxRingbuffer->pucHead = malloc(xBufferSize); - if (pxRingbuffer->pucHead == NULL) { + Ringbuffer_t *pxNewRingbuffer = calloc(1, sizeof(Ringbuffer_t)); + uint8_t *pucRingbufferStorage = malloc(xBufferSize); + if (pxNewRingbuffer == NULL || pucRingbufferStorage == NULL) { goto err; } - //Initialize values - pxRingbuffer->xSize = xBufferSize; - pxRingbuffer->pucTail = pxRingbuffer->pucHead + xBufferSize; - pxRingbuffer->pucFree = pxRingbuffer->pucHead; - pxRingbuffer->pucRead = pxRingbuffer->pucHead; - pxRingbuffer->pucWrite = pxRingbuffer->pucHead; - pxRingbuffer->xItemsWaiting = 0; - pxRingbuffer->xFreeSpaceSemaphore = xSemaphoreCreateBinary(); - pxRingbuffer->xItemsBufferedSemaphore = xSemaphoreCreateBinary(); - pxRingbuffer->uxRingbufferFlags = 0; - - //Initialize type dependent values and function pointers - if (xBufferType == RINGBUF_TYPE_NOSPLIT) { - pxRingbuffer->xCheckItemFits = prvCheckItemFitsDefault; - pxRingbuffer->vCopyItem = prvCopyItemNoSplit; - pxRingbuffer->pvGetItem = prvGetItemDefault; - pxRingbuffer->vReturnItem = prvReturnItemDefault; - /* - * Buffer lengths are always aligned. No-split buffer (read/write/free) - * pointers are also always aligned. Therefore worse case scenario is - * the write pointer is at the most aligned halfway point. - */ - pxRingbuffer->xMaxItemSize = rbALIGN_SIZE(pxRingbuffer->xSize / 2) - rbHEADER_SIZE; - pxRingbuffer->xGetCurMaxSize = prvGetCurMaxSizeNoSplit; - } else if (xBufferType == RINGBUF_TYPE_ALLOWSPLIT) { - pxRingbuffer->uxRingbufferFlags |= rbALLOW_SPLIT_FLAG; - pxRingbuffer->xCheckItemFits = prvCheckItemFitsDefault; - pxRingbuffer->vCopyItem = prvCopyItemAllowSplit; - pxRingbuffer->pvGetItem = prvGetItemDefault; - pxRingbuffer->vReturnItem = prvReturnItemDefault; - //Worst case an item is split into two, incurring two headers of overhead - pxRingbuffer->xMaxItemSize = pxRingbuffer->xSize - (sizeof(ItemHeader_t) * 2); - pxRingbuffer->xGetCurMaxSize = prvGetCurMaxSizeAllowSplit; - } else if (xBufferType == RINGBUF_TYPE_BYTEBUF) { - pxRingbuffer->uxRingbufferFlags |= rbBYTE_BUFFER_FLAG; - pxRingbuffer->xCheckItemFits = prvCheckItemFitsByteBuffer; - pxRingbuffer->vCopyItem = prvCopyItemByteBuf; - pxRingbuffer->pvGetItem = prvGetItemByteBuf; - pxRingbuffer->vReturnItem = prvReturnItemByteBuf; - //Byte buffers do not incur any overhead - pxRingbuffer->xMaxItemSize = pxRingbuffer->xSize; - pxRingbuffer->xGetCurMaxSize = prvGetCurMaxSizeByteBuf; - } else { - //Unsupported type - configASSERT(0); - } - - if (pxRingbuffer->xFreeSpaceSemaphore == NULL || pxRingbuffer->xItemsBufferedSemaphore == NULL) { + //Initialize Semaphores +#if ( configSUPPORT_STATIC_ALLOCATION == 1) + //We don't use the handles for static semaphores, and xSemaphoreCreateBinaryStatic will never fail thus no need to check static case + xSemaphoreCreateBinaryStatic(&(pxNewRingbuffer->xTransSemStatic)); + xSemaphoreCreateBinaryStatic(&(pxNewRingbuffer->xRecvSemStatic)); +#else + pxNewRingbuffer->xTransSemHandle = xSemaphoreCreateBinary(); + pxNewRingbuffer->xRecvSemHandle = xSemaphoreCreateBinary(); + if (pxNewRingbuffer->xTransSemHandle == NULL || pxNewRingbuffer->xRecvSemHandle == NULL) { + if (pxNewRingbuffer->xTransSemHandle != NULL) { + vSemaphoreDelete(pxNewRingbuffer->xTransSemHandle); + } + if (pxNewRingbuffer->xRecvSemHandle != NULL) { + vSemaphoreDelete(pxNewRingbuffer->xRecvSemHandle); + } goto err; } - xSemaphoreGive(pxRingbuffer->xFreeSpaceSemaphore); - vPortCPUInitializeMutex(&pxRingbuffer->mux); +#endif - return (RingbufHandle_t)pxRingbuffer; + prvInitializeNewRingbuffer(xBufferSize, xBufferType, pxNewRingbuffer, pucRingbufferStorage); + return (RingbufHandle_t)pxNewRingbuffer; err: - //Some error has happened. Free/destroy all allocated things and return NULL. - if (pxRingbuffer) { - free(pxRingbuffer->pucHead); - if (pxRingbuffer->xFreeSpaceSemaphore) { - vSemaphoreDelete(pxRingbuffer->xFreeSpaceSemaphore); - } - if (pxRingbuffer->xItemsBufferedSemaphore) { - vSemaphoreDelete(pxRingbuffer->xItemsBufferedSemaphore); - } - } - free(pxRingbuffer); + //An error has occurred, Free memory and return NULL + free(pxNewRingbuffer); + free(pucRingbufferStorage); return NULL; } @@ -741,7 +890,109 @@ RingbufHandle_t xRingbufferCreateNoSplit(size_t xItemSize, size_t xItemNum) return xRingbufferCreate((rbALIGN_SIZE(xItemSize) + rbHEADER_SIZE) * xItemNum, RINGBUF_TYPE_NOSPLIT); } -BaseType_t xRingbufferSend(RingbufHandle_t xRingbuffer, const void *pvItem, size_t xItemSize, TickType_t xTicksToWait) +#if ( configSUPPORT_STATIC_ALLOCATION == 1 ) +RingbufHandle_t xRingbufferCreateStatic(size_t xBufferSize, + RingbufferType_t xBufferType, + uint8_t *pucRingbufferStorage, + StaticRingbuffer_t *pxStaticRingbuffer) +{ + //Check arguments + configASSERT(xBufferSize > 0); + configASSERT(xBufferType < RINGBUF_TYPE_MAX); + configASSERT(pucRingbufferStorage != NULL && pxStaticRingbuffer != NULL); + if (xBufferType != RINGBUF_TYPE_BYTEBUF) { + //No-split/allow-split buffer sizes must be 32-bit aligned + configASSERT(rbCHECK_ALIGNED(xBufferSize)); + } + + Ringbuffer_t *pxNewRingbuffer = (Ringbuffer_t *)pxStaticRingbuffer; + xSemaphoreCreateBinaryStatic(&(pxNewRingbuffer->xTransSemStatic)); + xSemaphoreCreateBinaryStatic(&(pxNewRingbuffer->xRecvSemStatic)); + prvInitializeNewRingbuffer(xBufferSize, xBufferType, pxNewRingbuffer, pucRingbufferStorage); + pxNewRingbuffer->uxRingbufferFlags |= rbBUFFER_STATIC_FLAG; + return (RingbufHandle_t)pxNewRingbuffer; +} +#endif + +BaseType_t xRingbufferSendAcquire(RingbufHandle_t xRingbuffer, void **ppvItem, size_t xItemSize, TickType_t xTicksToWait) +{ + //Check arguments + Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; + configASSERT(pxRingbuffer); + configASSERT(ppvItem != NULL || xItemSize == 0); + //currently only supported in NoSplit buffers + configASSERT((pxRingbuffer->uxRingbufferFlags & (rbBYTE_BUFFER_FLAG | rbALLOW_SPLIT_FLAG)) == 0); + + *ppvItem = NULL; + if (xItemSize > pxRingbuffer->xMaxItemSize) { + return pdFALSE; //Data will never ever fit in the queue. + } + if ((pxRingbuffer->uxRingbufferFlags & rbBYTE_BUFFER_FLAG) && xItemSize == 0) { + return pdTRUE; //Sending 0 bytes to byte buffer has no effect + } + + //Attempt to send an item + BaseType_t xReturn = pdFALSE; + BaseType_t xReturnSemaphore = pdFALSE; + TickType_t xTicksEnd = xTaskGetTickCount() + xTicksToWait; + TickType_t xTicksRemaining = xTicksToWait; + while (xTicksRemaining <= xTicksToWait) { //xTicksToWait will underflow once xTaskGetTickCount() > ticks_end + //Block until more free space becomes available or timeout + if (xSemaphoreTake(rbGET_TX_SEM_HANDLE(pxRingbuffer), xTicksRemaining) != pdTRUE) { + xReturn = pdFALSE; + break; + } + + //Semaphore obtained, check if item can fit + portENTER_CRITICAL(&pxRingbuffer->mux); + if(pxRingbuffer->xCheckItemFits(pxRingbuffer, xItemSize) == pdTRUE) { + //Item will fit, copy item + *ppvItem = prvAcquireItemNoSplit(pxRingbuffer, xItemSize); + xReturn = pdTRUE; + //Check if the free semaphore should be returned to allow other tasks to send + if (prvGetFreeSize(pxRingbuffer) > 0) { + xReturnSemaphore = pdTRUE; + } + portEXIT_CRITICAL(&pxRingbuffer->mux); + break; + } + //Item doesn't fit, adjust ticks and take the semaphore again + if (xTicksToWait != portMAX_DELAY) { + xTicksRemaining = xTicksEnd - xTaskGetTickCount(); + } + portEXIT_CRITICAL(&pxRingbuffer->mux); + /* + * Gap between critical section and re-acquiring of the semaphore. If + * semaphore is given now, priority inversion might occur (see docs) + */ + } + + if (xReturnSemaphore == pdTRUE) { + xSemaphoreGive(rbGET_TX_SEM_HANDLE(pxRingbuffer)); //Give back semaphore so other tasks can acquire + } + return xReturn; +} + +BaseType_t xRingbufferSendComplete(RingbufHandle_t xRingbuffer, void *pvItem) +{ + //Check arguments + Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; + configASSERT(pxRingbuffer); + configASSERT(pvItem != NULL); + configASSERT((pxRingbuffer->uxRingbufferFlags & (rbBYTE_BUFFER_FLAG | rbALLOW_SPLIT_FLAG)) == 0); + + portENTER_CRITICAL(&pxRingbuffer->mux); + prvSendItemDoneNoSplit(pxRingbuffer, pvItem); + portEXIT_CRITICAL(&pxRingbuffer->mux); + + xSemaphoreGive(rbGET_RX_SEM_HANDLE(pxRingbuffer)); + return pdTRUE; +} + +BaseType_t xRingbufferSend(RingbufHandle_t xRingbuffer, + const void *pvItem, + size_t xItemSize, + TickType_t xTicksToWait) { //Check arguments Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; @@ -761,7 +1012,7 @@ BaseType_t xRingbufferSend(RingbufHandle_t xRingbuffer, const void *pvItem, size TickType_t xTicksRemaining = xTicksToWait; while (xTicksRemaining <= xTicksToWait) { //xTicksToWait will underflow once xTaskGetTickCount() > ticks_end //Block until more free space becomes available or timeout - if (xSemaphoreTake(pxRingbuffer->xFreeSpaceSemaphore, xTicksRemaining) != pdTRUE) { + if (xSemaphoreTake(rbGET_TX_SEM_HANDLE(pxRingbuffer), xTicksRemaining) != pdTRUE) { xReturn = pdFALSE; break; } @@ -791,15 +1042,18 @@ BaseType_t xRingbufferSend(RingbufHandle_t xRingbuffer, const void *pvItem, size if (xReturn == pdTRUE) { //Indicate item was successfully sent - xSemaphoreGive(pxRingbuffer->xItemsBufferedSemaphore); + xSemaphoreGive(rbGET_RX_SEM_HANDLE(pxRingbuffer)); } if (xReturnSemaphore == pdTRUE) { - xSemaphoreGive(pxRingbuffer->xFreeSpaceSemaphore); //Give back semaphore so other tasks can send + xSemaphoreGive(rbGET_TX_SEM_HANDLE(pxRingbuffer)); //Give back semaphore so other tasks can send } return xReturn; } -BaseType_t xRingbufferSendFromISR(RingbufHandle_t xRingbuffer, const void *pvItem, size_t xItemSize, BaseType_t *pxHigherPriorityTaskWoken) +BaseType_t xRingbufferSendFromISR(RingbufHandle_t xRingbuffer, + const void *pvItem, + size_t xItemSize, + BaseType_t *pxHigherPriorityTaskWoken) { //Check arguments Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; @@ -830,10 +1084,10 @@ BaseType_t xRingbufferSendFromISR(RingbufHandle_t xRingbuffer, const void *pvIte if (xReturn == pdTRUE) { //Indicate item was successfully sent - xSemaphoreGiveFromISR(pxRingbuffer->xItemsBufferedSemaphore, pxHigherPriorityTaskWoken); + xSemaphoreGiveFromISR(rbGET_RX_SEM_HANDLE(pxRingbuffer), pxHigherPriorityTaskWoken); } if (xReturnSemaphore == pdTRUE) { - xSemaphoreGiveFromISR(pxRingbuffer->xFreeSpaceSemaphore, pxHigherPriorityTaskWoken); //Give back semaphore so other tasks can send + xSemaphoreGiveFromISR(rbGET_TX_SEM_HANDLE(pxRingbuffer), pxHigherPriorityTaskWoken); //Give back semaphore so other tasks can send } return xReturn; } @@ -876,7 +1130,12 @@ void *xRingbufferReceiveFromISR(RingbufHandle_t xRingbuffer, size_t *pxItemSize) } } -BaseType_t xRingbufferReceiveSplit(RingbufHandle_t xRingbuffer, void **ppvHeadItem, void **ppvTailItem, size_t *pxHeadItemSize, size_t *pxTailItemSize, TickType_t xTicksToWait) +BaseType_t xRingbufferReceiveSplit(RingbufHandle_t xRingbuffer, + void **ppvHeadItem, + void **ppvTailItem, + size_t *pxHeadItemSize, + size_t *pxTailItemSize, + TickType_t xTicksToWait) { //Check arguments Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; @@ -911,7 +1170,11 @@ BaseType_t xRingbufferReceiveSplit(RingbufHandle_t xRingbuffer, void **ppvHeadIt } } -BaseType_t xRingbufferReceiveSplitFromISR(RingbufHandle_t xRingbuffer, void **ppvHeadItem, void **ppvTailItem, size_t *pxHeadItemSize, size_t *pxTailItemSize) +BaseType_t xRingbufferReceiveSplitFromISR(RingbufHandle_t xRingbuffer, + void **ppvHeadItem, + void **ppvTailItem, + size_t *pxHeadItemSize, + size_t *pxTailItemSize) { //Check arguments Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; @@ -945,7 +1208,10 @@ BaseType_t xRingbufferReceiveSplitFromISR(RingbufHandle_t xRingbuffer, void **pp } } -void *xRingbufferReceiveUpTo(RingbufHandle_t xRingbuffer, size_t *pxItemSize, TickType_t xTicksToWait, size_t xMaxSize) +void *xRingbufferReceiveUpTo(RingbufHandle_t xRingbuffer, + size_t *pxItemSize, + TickType_t xTicksToWait, + size_t xMaxSize) { //Check arguments Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; @@ -1000,7 +1266,7 @@ void vRingbufferReturnItem(RingbufHandle_t xRingbuffer, void *pvItem) portENTER_CRITICAL(&pxRingbuffer->mux); pxRingbuffer->vReturnItem(pxRingbuffer, (uint8_t *)pvItem); portEXIT_CRITICAL(&pxRingbuffer->mux); - xSemaphoreGive(pxRingbuffer->xFreeSpaceSemaphore); + xSemaphoreGive(rbGET_TX_SEM_HANDLE(pxRingbuffer)); } void vRingbufferReturnItemFromISR(RingbufHandle_t xRingbuffer, void *pvItem, BaseType_t *pxHigherPriorityTaskWoken) @@ -1012,7 +1278,7 @@ void vRingbufferReturnItemFromISR(RingbufHandle_t xRingbuffer, void *pvItem, Bas portENTER_CRITICAL_ISR(&pxRingbuffer->mux); pxRingbuffer->vReturnItem(pxRingbuffer, (uint8_t *)pvItem); portEXIT_CRITICAL_ISR(&pxRingbuffer->mux); - xSemaphoreGiveFromISR(pxRingbuffer->xFreeSpaceSemaphore, pxHigherPriorityTaskWoken); + xSemaphoreGiveFromISR(rbGET_TX_SEM_HANDLE(pxRingbuffer), pxHigherPriorityTaskWoken); } void vRingbufferDelete(RingbufHandle_t xRingbuffer) @@ -1020,15 +1286,16 @@ void vRingbufferDelete(RingbufHandle_t xRingbuffer) Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; configASSERT(pxRingbuffer); - if (pxRingbuffer) { - free(pxRingbuffer->pucHead); - if (pxRingbuffer->xFreeSpaceSemaphore) { - vSemaphoreDelete(pxRingbuffer->xFreeSpaceSemaphore); - } - if (pxRingbuffer->xItemsBufferedSemaphore) { - vSemaphoreDelete(pxRingbuffer->xItemsBufferedSemaphore); - } + vSemaphoreDelete(rbGET_TX_SEM_HANDLE(pxRingbuffer)); + vSemaphoreDelete(rbGET_RX_SEM_HANDLE(pxRingbuffer)); + +#if ( configSUPPORT_STATIC_ALLOCATION == 1 ) + if (pxRingbuffer->uxRingbufferFlags & rbBUFFER_STATIC_FLAG) { + //Ring buffer was statically allocated, no need to free + return; } +#endif + free(pxRingbuffer->pucHead); free(pxRingbuffer); } @@ -1059,11 +1326,11 @@ BaseType_t xRingbufferAddToQueueSetRead(RingbufHandle_t xRingbuffer, QueueSetHan BaseType_t xReturn; portENTER_CRITICAL(&pxRingbuffer->mux); //Cannot add semaphore to queue set if semaphore is not empty. Temporarily hold semaphore - BaseType_t xHoldSemaphore = xSemaphoreTake(pxRingbuffer->xItemsBufferedSemaphore, 0); - xReturn = xQueueAddToSet(pxRingbuffer->xItemsBufferedSemaphore, xQueueSet); + BaseType_t xHoldSemaphore = xSemaphoreTake(rbGET_RX_SEM_HANDLE(pxRingbuffer), 0); + xReturn = xQueueAddToSet(rbGET_RX_SEM_HANDLE(pxRingbuffer), xQueueSet); if (xHoldSemaphore == pdTRUE) { //Return semaphore if temporarily held - configASSERT(xSemaphoreGive(pxRingbuffer->xItemsBufferedSemaphore) == pdTRUE); + configASSERT(xSemaphoreGive(rbGET_RX_SEM_HANDLE(pxRingbuffer)) == pdTRUE); } portEXIT_CRITICAL(&pxRingbuffer->mux); return xReturn; @@ -1074,7 +1341,7 @@ BaseType_t xRingbufferCanRead(RingbufHandle_t xRingbuffer, QueueSetMemberHandle_ //Check if the selected queue set member is the ring buffer's read semaphore Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; configASSERT(pxRingbuffer); - return (pxRingbuffer->xItemsBufferedSemaphore == xMember) ? pdTRUE : pdFALSE; + return (rbGET_RX_SEM_HANDLE(pxRingbuffer) == xMember) ? pdTRUE : pdFALSE; } BaseType_t xRingbufferRemoveFromQueueSetRead(RingbufHandle_t xRingbuffer, QueueSetHandle_t xQueueSet) @@ -1085,17 +1352,22 @@ BaseType_t xRingbufferRemoveFromQueueSetRead(RingbufHandle_t xRingbuffer, QueueS BaseType_t xReturn; portENTER_CRITICAL(&pxRingbuffer->mux); //Cannot remove semaphore from queue set if semaphore is not empty. Temporarily hold semaphore - BaseType_t xHoldSemaphore = xSemaphoreTake(pxRingbuffer->xItemsBufferedSemaphore, 0); - xReturn = xQueueRemoveFromSet(pxRingbuffer->xItemsBufferedSemaphore, xQueueSet); + BaseType_t xHoldSemaphore = xSemaphoreTake(rbGET_RX_SEM_HANDLE(pxRingbuffer), 0); + xReturn = xQueueRemoveFromSet(rbGET_RX_SEM_HANDLE(pxRingbuffer), xQueueSet); if (xHoldSemaphore == pdTRUE) { //Return semaphore if temporarily held - configASSERT(xSemaphoreGive(pxRingbuffer->xItemsBufferedSemaphore) == pdTRUE); + configASSERT(xSemaphoreGive(rbGET_RX_SEM_HANDLE(pxRingbuffer)) == pdTRUE); } portEXIT_CRITICAL(&pxRingbuffer->mux); return xReturn; } -void vRingbufferGetInfo(RingbufHandle_t xRingbuffer, UBaseType_t *uxFree, UBaseType_t *uxRead, UBaseType_t *uxWrite, UBaseType_t *uxItemsWaiting) +void vRingbufferGetInfo(RingbufHandle_t xRingbuffer, + UBaseType_t *uxFree, + UBaseType_t *uxRead, + UBaseType_t *uxWrite, + UBaseType_t *uxAcquire, + UBaseType_t *uxItemsWaiting) { Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; configASSERT(pxRingbuffer); @@ -1110,6 +1382,9 @@ void vRingbufferGetInfo(RingbufHandle_t xRingbuffer, UBaseType_t *uxFree, UBaseT if (uxWrite != NULL) { *uxWrite = (UBaseType_t)(pxRingbuffer->pucWrite - pxRingbuffer->pucHead); } + if (uxAcquire != NULL) { + *uxAcquire = (UBaseType_t)(pxRingbuffer->pucAcquire - pxRingbuffer->pucHead); + } if (uxItemsWaiting != NULL) { *uxItemsWaiting = (UBaseType_t)(pxRingbuffer->xItemsWaiting); } @@ -1120,65 +1395,11 @@ void xRingbufferPrintInfo(RingbufHandle_t xRingbuffer) { Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; configASSERT(pxRingbuffer); - printf("Rb size:%d\tfree: %d\trptr: %d\tfreeptr: %d\twptr: %d\n", + printf("Rb size:%d\tfree: %d\trptr: %d\tfreeptr: %d\twptr: %d, aptr: %d\n", pxRingbuffer->xSize, prvGetFreeSize(pxRingbuffer), pxRingbuffer->pucRead - pxRingbuffer->pucHead, pxRingbuffer->pucFree - pxRingbuffer->pucHead, - pxRingbuffer->pucWrite - pxRingbuffer->pucHead); -} - -/* --------------------------------- Deprecated Functions ------------------------------ */ -//Todo: Remove the following deprecated functions in next release - -bool xRingbufferIsNextItemWrapped(RingbufHandle_t xRingbuffer) -{ - //This function is deprecated, use xRingbufferReceiveSplit() instead - Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; - configASSERT(pxRingbuffer); - bool is_wrapped; - - portENTER_CRITICAL(&pxRingbuffer->mux); - ItemHeader_t *xHeader = (ItemHeader_t *)pxRingbuffer->pucRead; - is_wrapped = xHeader->uxItemFlags & rbITEM_SPLIT_FLAG; - portEXIT_CRITICAL(&pxRingbuffer->mux); - return is_wrapped; -} - -BaseType_t xRingbufferAddToQueueSetWrite(RingbufHandle_t xRingbuffer, QueueSetHandle_t xQueueSet) -{ - //This function is deprecated. QueueSetWrite no longer supported - Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; - configASSERT(pxRingbuffer); - - BaseType_t xReturn; - portENTER_CRITICAL(&pxRingbuffer->mux); - //Cannot add semaphore to queue set if semaphore is not empty. Temporary hold semaphore - BaseType_t xHoldSemaphore = xSemaphoreTake(pxRingbuffer->xFreeSpaceSemaphore, 0); - xReturn = xQueueAddToSet(pxRingbuffer->xFreeSpaceSemaphore, xQueueSet); - if (xHoldSemaphore == pdTRUE) { - //Return semaphore is temporarily held - configASSERT(xSemaphoreGive(pxRingbuffer->xFreeSpaceSemaphore) == pdTRUE); - } - portEXIT_CRITICAL(&pxRingbuffer->mux); - return xReturn; -} - -BaseType_t xRingbufferRemoveFromQueueSetWrite(RingbufHandle_t xRingbuffer, QueueSetHandle_t xQueueSet) -{ - //This function is deprecated. QueueSetWrite no longer supported - Ringbuffer_t *pxRingbuffer = (Ringbuffer_t *)xRingbuffer; - configASSERT(pxRingbuffer); - - BaseType_t xReturn; - portENTER_CRITICAL(&pxRingbuffer->mux); - //Cannot remove semaphore from queue set if semaphore is not empty. Temporary hold semaphore - BaseType_t xHoldSemaphore = xSemaphoreTake(pxRingbuffer->xFreeSpaceSemaphore, 0); - xReturn = xQueueRemoveFromSet(pxRingbuffer->xFreeSpaceSemaphore, xQueueSet); - if (xHoldSemaphore == pdTRUE) { - //Return semaphore is temporarily held - configASSERT(xSemaphoreGive(pxRingbuffer->xFreeSpaceSemaphore) == pdTRUE); - } - portEXIT_CRITICAL(&pxRingbuffer->mux); - return xReturn; + pxRingbuffer->pucWrite - pxRingbuffer->pucHead, + pxRingbuffer->pucAcquire - pxRingbuffer->pucHead); } diff --git a/components/esp_ringbuf/test/CMakeLists.txt b/components/esp_ringbuf/test/CMakeLists.txt index 236536c476..b531a14504 100644 --- a/components/esp_ringbuf/test/CMakeLists.txt +++ b/components/esp_ringbuf/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity test_utils) - -register_component() +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity test_utils) \ No newline at end of file diff --git a/components/esp_ringbuf/test/test_ringbuf.c b/components/esp_ringbuf/test/test_ringbuf.c index 4acf63ba84..376b119a78 100644 --- a/components/esp_ringbuf/test/test_ringbuf.c +++ b/components/esp_ringbuf/test/test_ringbuf.c @@ -6,6 +6,7 @@ #include "freertos/semphr.h" #include "freertos/ringbuf.h" #include "driver/timer.h" +#include "esp_heap_caps.h" #include "esp_spi_flash.h" #include "unity.h" #include "test_utils.h" @@ -165,7 +166,7 @@ static void receive_check_and_return_item_byte_buffer(RingbufHandle_t handle, co * 4) Receive and check the wrapped item */ -TEST_CASE("Test ring buffer No-Split", "[freertos]") +TEST_CASE("Test ring buffer No-Split", "[esp_ringbuf]") { //Create buffer RingbufHandle_t buffer_handle = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_NOSPLIT); @@ -184,19 +185,19 @@ TEST_CASE("Test ring buffer No-Split", "[freertos]") //Write pointer should be near the end, test wrap around uint32_t write_pos_before, write_pos_after; - vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_before, NULL); + vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_before, NULL, NULL); //Send large item that causes wrap around send_item_and_check(buffer_handle, large_item, LARGE_ITEM_SIZE, TIMEOUT_TICKS, false); //Receive wrapped item receive_check_and_return_item_no_split(buffer_handle, large_item, LARGE_ITEM_SIZE, TIMEOUT_TICKS, false); - vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_after, NULL); + vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_after, NULL, NULL); TEST_ASSERT_MESSAGE(write_pos_after < write_pos_before, "Failed to wrap around"); //Cleanup vRingbufferDelete(buffer_handle); } -TEST_CASE("Test ring buffer Allow-Split", "[freertos]") +TEST_CASE("Test ring buffer Allow-Split", "[esp_ringbuf]") { //Create buffer RingbufHandle_t buffer_handle = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_ALLOWSPLIT); @@ -215,19 +216,19 @@ TEST_CASE("Test ring buffer Allow-Split", "[freertos]") //Write pointer should be near the end, test wrap around uint32_t write_pos_before, write_pos_after; - vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_before, NULL); + vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_before, NULL, NULL); //Send large item that causes wrap around send_item_and_check(buffer_handle, large_item, LARGE_ITEM_SIZE, TIMEOUT_TICKS, false); //Receive wrapped item receive_check_and_return_item_allow_split(buffer_handle, large_item, LARGE_ITEM_SIZE, TIMEOUT_TICKS, false); - vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_after, NULL); + vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_after, NULL, NULL); TEST_ASSERT_MESSAGE(write_pos_after < write_pos_before, "Failed to wrap around"); //Cleanup vRingbufferDelete(buffer_handle); } -TEST_CASE("Test ring buffer Byte Buffer", "[freertos]") +TEST_CASE("Test ring buffer Byte Buffer", "[esp_ringbuf]") { //Create buffer RingbufHandle_t buffer_handle = xRingbufferCreate(BUFFER_SIZE, RINGBUF_TYPE_BYTEBUF); @@ -246,12 +247,12 @@ TEST_CASE("Test ring buffer Byte Buffer", "[freertos]") //Write pointer should be near the end, test wrap around uint32_t write_pos_before, write_pos_after; - vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_before, NULL); + vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_before, NULL, NULL); //Send large item that causes wrap around send_item_and_check(buffer_handle, large_item, LARGE_ITEM_SIZE, TIMEOUT_TICKS, false); //Receive wrapped item receive_check_and_return_item_byte_buffer(buffer_handle, large_item, LARGE_ITEM_SIZE, TIMEOUT_TICKS, false); - vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_after, NULL); + vRingbufferGetInfo(buffer_handle, NULL, NULL, &write_pos_after, NULL, NULL); TEST_ASSERT_MESSAGE(write_pos_after < write_pos_before, "Failed to wrap around"); //Cleanup @@ -304,7 +305,7 @@ static void queue_set_receiving_task(void *queue_set_handle) vTaskDelete(NULL); } -TEST_CASE("Test ring buffer with queue sets", "[freertos]") +TEST_CASE("Test ring buffer with queue sets", "[esp_ringbuf]") { QueueSetHandle_t queue_set = xQueueCreateSet(NO_OF_RB_TYPES); done_sem = xSemaphoreCreateBinary(); @@ -421,7 +422,7 @@ static void cleanup_timer() esp_intr_free(ringbuffer_isr_handle); } -TEST_CASE("Test ring buffer ISR", "[freertos]") +TEST_CASE("Test ring buffer ISR", "[esp_ringbuf]") { for (int i = 0; i < NO_OF_RB_TYPES; i++) { buffer_handles[i] = xRingbufferCreate(BUFFER_SIZE, i); @@ -461,11 +462,12 @@ static const char continuous_data[] = {"A_very_long_string_that_will_be_split_in "be_increased_over_multiple_iterations_in_this" "_test"}; #define CONT_DATA_LEN sizeof(continuous_data) -#define CONT_DATA_TEST_BUFF_LEN (CONT_DATA_LEN/2) //This will guarantee that the buffer must do a wrap around at some point +//32-bit aligned size that guarantees a wrap around at some point +#define CONT_DATA_TEST_BUFF_LEN (((CONT_DATA_LEN/2) + 0x03) & ~0x3) typedef struct { RingbufHandle_t buffer; - ringbuf_type_t type; + RingbufferType_t type; } task_args_t; static SemaphoreHandle_t tasks_done; @@ -494,7 +496,7 @@ static void send_to_buffer(RingbufHandle_t buffer, size_t max_item_size) } } -static void read_from_buffer(RingbufHandle_t buffer, ringbuf_type_t buf_type, size_t max_rec_size) +static void read_from_buffer(RingbufHandle_t buffer, RingbufferType_t buf_type, size_t max_rec_size) { for (int iter = 0; iter < SMP_TEST_ITERATIONS; iter++) { size_t bytes_rec = 0; //Number of data bytes received in this iteration @@ -568,20 +570,33 @@ static void rec_task(void *args) vTaskDelete(NULL); } -TEST_CASE("Test ring buffer SMP", "[freertos]") +static void setup() { - ets_printf("size of buf %d\n", CONT_DATA_LEN); + ets_printf("Size of test data: %d\n", CONT_DATA_LEN); tx_done = xSemaphoreCreateBinary(); //Semaphore to indicate send is done for a particular iteration rx_done = xSemaphoreCreateBinary(); //Semaphore to indicate receive is done for a particular iteration - tasks_done = xSemaphoreCreateBinary(); //Semaphore used to to indicate send and receive tasks completed running + tasks_done = xSemaphoreCreateBinary(); //Semaphore used to to indicate send and receive tasks completed running srand(SRAND_SEED); //Seed RNG +} +static void cleanup() +{ + //Cleanup + vSemaphoreDelete(tx_done); + vSemaphoreDelete(rx_done); + vSemaphoreDelete(tasks_done); +} + +TEST_CASE("Test ring buffer SMP", "[esp_ringbuf]") +{ + setup(); //Iterate through buffer types (No split, split, then byte buff) - for (ringbuf_type_t buf_type = 0; buf_type <= RINGBUF_TYPE_BYTEBUF; buf_type++) { + for (RingbufferType_t buf_type = 0; buf_type < RINGBUF_TYPE_MAX; buf_type++) { //Create buffer task_args_t task_args; task_args.buffer = xRingbufferCreate(CONT_DATA_TEST_BUFF_LEN, buf_type); //Create buffer of selected type task_args.type = buf_type; + TEST_ASSERT_MESSAGE(task_args.buffer != NULL, "Failed to create ring buffer"); for (int prior_mod = -1; prior_mod < 2; prior_mod++) { //Test different relative priorities //Test every permutation of core affinity @@ -600,13 +615,60 @@ TEST_CASE("Test ring buffer SMP", "[freertos]") vRingbufferDelete(task_args.buffer); vTaskDelay(10); } - - //Cleanup - vSemaphoreDelete(tx_done); - vSemaphoreDelete(rx_done); - vSemaphoreDelete(tasks_done); + cleanup(); } +#if ( configSUPPORT_STATIC_ALLOCATION == 1 ) +TEST_CASE("Test static ring buffer SMP", "[esp_ringbuf]") +{ + setup(); + //Iterate through buffer types (No split, split, then byte buff) + for (RingbufferType_t buf_type = 0; buf_type < RINGBUF_TYPE_MAX; buf_type++) { + StaticRingbuffer_t *buffer_struct; + uint8_t *buffer_storage; + //Allocate memory and create semaphores +#if CONFIG_SPIRAM_USE_CAPS_ALLOC //When SPIRAM can only be allocated using heap_caps_malloc() + buffer_struct = (StaticRingbuffer_t *)heap_caps_malloc(sizeof(StaticRingbuffer_t), MALLOC_CAP_SPIRAM); + buffer_storage = (uint8_t *)heap_caps_malloc(sizeof(uint8_t)*CONT_DATA_TEST_BUFF_LEN, MALLOC_CAP_SPIRAM); +#else //Case where SPIRAM is disabled or when SPIRAM is allocatable through malloc() + buffer_struct = (StaticRingbuffer_t *)malloc(sizeof(StaticRingbuffer_t)); + buffer_storage = (uint8_t *)malloc(sizeof(uint8_t)*CONT_DATA_TEST_BUFF_LEN); +#endif + TEST_ASSERT(buffer_struct != NULL && buffer_storage != NULL); + + //Create buffer + task_args_t task_args; + task_args.buffer = xRingbufferCreateStatic(CONT_DATA_TEST_BUFF_LEN, buf_type, buffer_storage, buffer_struct); //Create buffer of selected type + task_args.type = buf_type; + TEST_ASSERT_MESSAGE(task_args.buffer != NULL, "Failed to create ring buffer"); + + for (int prior_mod = -1; prior_mod < 2; prior_mod++) { //Test different relative priorities + //Test every permutation of core affinity + for (int send_core = 0; send_core < portNUM_PROCESSORS; send_core++) { + for (int rec_core = 0; rec_core < portNUM_PROCESSORS; rec_core ++) { + ets_printf("Type: %d, PM: %d, SC: %d, RC: %d\n", buf_type, prior_mod, send_core, rec_core); + xTaskCreatePinnedToCore(send_task, "send tsk", 2048, (void *)&task_args, 10 + prior_mod, NULL, send_core); + xTaskCreatePinnedToCore(rec_task, "rec tsk", 2048, (void *)&task_args, 10, NULL, rec_core); + xSemaphoreTake(tasks_done, portMAX_DELAY); + vTaskDelay(5); //Allow idle to clean up + } + } + } + + //Delete ring buffer + vRingbufferDelete(task_args.buffer); + + //Deallocate memory + free(buffer_storage); + free(buffer_struct); + vTaskDelay(10); + } + cleanup(); +} +#endif + +/* -------------------------- Test ring buffer IRAM ------------------------- */ + static IRAM_ATTR __attribute__((noinline)) bool iram_ringbuf_test() { bool result = true; @@ -621,7 +683,7 @@ static IRAM_ATTR __attribute__((noinline)) bool iram_ringbuf_test() return result; } -TEST_CASE("Test ringbuffer functions work with flash cache disabled", "[freertos]") +TEST_CASE("Test ringbuffer functions work with flash cache disabled", "[esp_ringbuf]") { TEST_ASSERT( iram_ringbuf_test() ); } diff --git a/components/esp_rom/CMakeLists.txt b/components/esp_rom/CMakeLists.txt index 74077a3f1a..39f08ceb0a 100644 --- a/components/esp_rom/CMakeLists.txt +++ b/components/esp_rom/CMakeLists.txt @@ -2,23 +2,21 @@ idf_build_get_property(target IDF_TARGET) if(BOOTLOADER_BUILD) # For bootloader, all we need is headers - set(COMPONENT_ADD_INCLUDEDIRS "include") - set(COMPONENT_REQUIRES ${IDF_COMPONENTS}) - set(COMPONENT_SRCS) - register_component() - set(scripts "${target}/ld/${target}.rom.ld" - "${target}/ld/${target}.rom.newlib-funcs.ld" - "${target}/ld/${target}.rom.libgcc.ld") + idf_component_register(INCLUDE_DIRS include) + set(scripts + "${target}/ld/${target}.rom.ld" + "${target}/ld/${target}.rom.newlib-funcs.ld" + "${target}/ld/${target}.rom.libgcc.ld" + ) if (target STREQUAL "esp32s2beta") list(APPEND scripts "esp32s2beta/ld/esp32s2beta.rom.spiflash.ld") endif() - target_linker_script(${COMPONENT_LIB} "${scripts}") + + target_linker_script(${COMPONENT_LIB} INTERFACE "${scripts}") else() # Regular app build - set(COMPONENT_SRCS "esp_rom.c") - set(COMPONENT_ADD_INCLUDEDIRS "include") - - register_component() + idf_component_register(SRCS "esp_rom.c" + INCLUDE_DIRS include) set(scripts "${target}/ld/${target}.rom.ld" @@ -29,19 +27,19 @@ else() list(APPEND scripts "${target}/ld/${target}.rom.syscalls.ld") if(NOT CONFIG_SPIRAM_CACHE_WORKAROUND) - target_linker_script(${COMPONENT_LIB} "esp32/ld/esp32.rom.newlib-funcs.ld") + list(APPEND scripts "esp32/ld/esp32.rom.newlib-funcs.ld") endif() if(CONFIG_NEWLIB_NANO_FORMAT) - target_linker_script(${COMPONENT_LIB} "esp32/ld/esp32.rom.newlib-nano.ld") + list(APPEND scripts "esp32/ld/esp32.rom.newlib-nano.ld") endif() if(NOT GCC_NOT_5_2_0) - target_linker_script(${COMPONENT_LIB} "esp32/ld/esp32.rom.newlib-locale.ld") + list(APPEND scripts "esp32/ld/esp32.rom.newlib-locale.ld") endif() if(NOT CONFIG_SPI_FLASH_ROM_DRIVER_PATCH) - target_linker_script(${COMPONENT_LIB} "esp32/ld/esp32.rom.spiflash.ld") + list(APPEND scripts "esp32/ld/esp32.rom.spiflash.ld") endif() elseif(target STREQUAL "esp32s2beta") @@ -53,6 +51,6 @@ else() "esp32s2beta/ld/esp32s2beta.rom.spiflash.ld") endif() - target_linker_script(${COMPONENT_LIB} "${scripts}") + target_linker_script(${COMPONENT_LIB} INTERFACE "${scripts}") endif() diff --git a/components/esp_rom/include/esp32/rom/spi_flash.h b/components/esp_rom/include/esp32/rom/spi_flash.h index ea25146d71..b78a6130aa 100644 --- a/components/esp_rom/include/esp32/rom/spi_flash.h +++ b/components/esp_rom/include/esp32/rom/spi_flash.h @@ -90,7 +90,8 @@ extern "C" { #define SPI0_R_QIO_DUMMY_CYCLELEN 3 #define SPI0_R_QIO_ADDR_BITSLEN 31 #define SPI0_R_FAST_DUMMY_CYCLELEN 7 -#define SPI0_R_DIO_DUMMY_CYCLELEN 3 +#define SPI0_R_DIO_DUMMY_CYCLELEN 1 +#define SPI0_R_DIO_ADDR_BITSLEN 27 #define SPI0_R_FAST_ADDR_BITSLEN 23 #define SPI0_R_SIO_ADDR_BITSLEN 23 @@ -113,13 +114,18 @@ extern "C" { #define ESP_ROM_SPIFLASH_BUFF_BYTE_READ_BITS 0x3f //SPI status register -#define ESP_ROM_SPIFLASH_BUSY_FLAG BIT0 -#define ESP_ROM_SPIFLASH_WRENABLE_FLAG BIT1 -#define ESP_ROM_SPIFLASH_BP0 BIT2 -#define ESP_ROM_SPIFLASH_BP1 BIT3 -#define ESP_ROM_SPIFLASH_BP2 BIT4 -#define ESP_ROM_SPIFLASH_WR_PROTECT (ESP_ROM_SPIFLASH_BP0|ESP_ROM_SPIFLASH_BP1|ESP_ROM_SPIFLASH_BP2) -#define ESP_ROM_SPIFLASH_QE BIT9 +#define ESP_ROM_SPIFLASH_BUSY_FLAG BIT0 +#define ESP_ROM_SPIFLASH_WRENABLE_FLAG BIT1 +#define ESP_ROM_SPIFLASH_BP0 BIT2 +#define ESP_ROM_SPIFLASH_BP1 BIT3 +#define ESP_ROM_SPIFLASH_BP2 BIT4 +#define ESP_ROM_SPIFLASH_WR_PROTECT (ESP_ROM_SPIFLASH_BP0|ESP_ROM_SPIFLASH_BP1|ESP_ROM_SPIFLASH_BP2) +#define ESP_ROM_SPIFLASH_QE BIT9 + +//Extra dummy for flash read +#define ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_20M 0 +#define ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_40M 1 +#define ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_80M 2 #define FLASH_ID_GD25LQ32C 0xC86016 diff --git a/components/esp_websocket_client/CMakeLists.txt b/components/esp_websocket_client/CMakeLists.txt new file mode 100644 index 0000000000..f366a278d3 --- /dev/null +++ b/components/esp_websocket_client/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "esp_websocket_client.c" + INCLUDE_DIRS "include" + REQUIRES lwip esp-tls tcp_transport nghttp) diff --git a/components/esp_websocket_client/component.mk b/components/esp_websocket_client/component.mk new file mode 100644 index 0000000000..e69de29bb2 diff --git a/components/esp_websocket_client/esp_websocket_client.c b/components/esp_websocket_client/esp_websocket_client.c new file mode 100644 index 0000000000..a066c288c9 --- /dev/null +++ b/components/esp_websocket_client/esp_websocket_client.c @@ -0,0 +1,592 @@ +// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "esp_websocket_client.h" +#include "esp_transport.h" +#include "esp_transport_tcp.h" +#include "esp_transport_ssl.h" +#include "esp_transport_ws.h" +/* using uri parser */ +#include "http_parser.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "freertos/queue.h" +#include "freertos/event_groups.h" +#include "esp_log.h" +#include "esp_timer.h" + +static const char *TAG = "WEBSOCKET_CLIENT"; + +#define WEBSOCKET_TCP_DEFAULT_PORT (80) +#define WEBSOCKET_SSL_DEFAULT_PORT (443) +#define WEBSOCKET_BUFFER_SIZE_BYTE (1024) +#define WEBSOCKET_RECONNECT_TIMEOUT_MS (10*1000) +#define WEBSOCKET_TASK_PRIORITY (5) +#define WEBSOCKET_TASK_STACK (4*1024) +#define WEBSOCKET_NETWORK_TIMEOUT_MS (10*1000) +#define WEBSOCKET_PING_TIMEOUT_MS (10*1000) +#define WEBSOCKET_EVENT_QUEUE_SIZE (1) +#define WEBSOCKET_SEND_EVENT_TIMEOUT_MS (1000/portTICK_RATE_MS) + +#define ESP_WS_CLIENT_MEM_CHECK(TAG, a, action) if (!(a)) { \ + ESP_LOGE(TAG,"%s:%d (%s): %s", __FILE__, __LINE__, __FUNCTION__, "Memory exhausted"); \ + action; \ + } + +const static int STOPPED_BIT = BIT0; + +ESP_EVENT_DEFINE_BASE(WEBSOCKET_EVENTS); + +typedef struct { + int task_stack; + int task_prio; + char *uri; + char *host; + char *path; + char *scheme; + char *username; + char *password; + int port; + bool auto_reconnect; + void *user_context; + int network_timeout_ms; +} websocket_config_storage_t; + +typedef enum { + WEBSOCKET_STATE_ERROR = -1, + WEBSOCKET_STATE_UNKNOW = 0, + WEBSOCKET_STATE_INIT, + WEBSOCKET_STATE_CONNECTED, + WEBSOCKET_STATE_WAIT_TIMEOUT, +} websocket_client_state_t; + +struct esp_websocket_client { + esp_event_loop_handle_t event_handle; + esp_transport_list_handle_t transport_list; + esp_transport_handle_t transport; + websocket_config_storage_t *config; + websocket_client_state_t state; + uint64_t keepalive_tick_ms; + uint64_t reconnect_tick_ms; + uint64_t ping_tick_ms; + int wait_timeout_ms; + int auto_reconnect; + bool run; + EventGroupHandle_t status_bits; + xSemaphoreHandle lock; + char *rx_buffer; + char *tx_buffer; + int buffer_size; +}; + +static uint64_t _tick_get_ms() +{ + return esp_timer_get_time()/1000; +} + +static esp_err_t esp_websocket_client_dispatch_event(esp_websocket_client_handle_t client, + esp_websocket_event_id_t event, + const char *data, + int data_len) +{ + esp_err_t err; + esp_websocket_event_data_t event_data; + event_data.data_ptr = data; + event_data.data_len = data_len; + + if ((err = esp_event_post_to(client->event_handle, + WEBSOCKET_EVENTS, event, + &event_data, + sizeof(esp_websocket_event_data_t), + WEBSOCKET_SEND_EVENT_TIMEOUT_MS)) != ESP_OK) { + return err; + } + return esp_event_loop_run(client->event_handle, WEBSOCKET_SEND_EVENT_TIMEOUT_MS); +} + +static esp_err_t esp_websocket_client_abort_connection(esp_websocket_client_handle_t client) +{ + esp_transport_close(client->transport); + client->wait_timeout_ms = WEBSOCKET_RECONNECT_TIMEOUT_MS; + client->reconnect_tick_ms = _tick_get_ms(); + client->state = WEBSOCKET_STATE_WAIT_TIMEOUT; + ESP_LOGI(TAG, "Reconnect after %d ms", client->wait_timeout_ms); + esp_websocket_client_dispatch_event(client, WEBSOCKET_EVENT_DISCONNECTED, NULL, 0); + return ESP_OK; +} + +static esp_err_t esp_websocket_client_set_config(esp_websocket_client_handle_t client, const esp_websocket_client_config_t *config) +{ + websocket_config_storage_t *cfg = client->config; + cfg->task_prio = config->task_prio; + if (cfg->task_prio <= 0) { + cfg->task_prio = WEBSOCKET_TASK_PRIORITY; + } + + cfg->task_stack = config->task_stack; + if (cfg->task_stack == 0) { + cfg->task_stack = WEBSOCKET_TASK_STACK; + } + + if (config->host) { + cfg->host = strdup(config->host); + ESP_WS_CLIENT_MEM_CHECK(TAG, cfg->host, return ESP_ERR_NO_MEM); + } + + if (config->port) { + cfg->port = config->port; + } + + if (config->username) { + free(cfg->username); + cfg->username = strdup(config->username); + ESP_WS_CLIENT_MEM_CHECK(TAG, cfg->username, return ESP_ERR_NO_MEM); + } + + if (config->password) { + free(cfg->password); + cfg->password = strdup(config->password); + ESP_WS_CLIENT_MEM_CHECK(TAG, cfg->password, return ESP_ERR_NO_MEM); + } + + if (config->uri) { + free(cfg->uri); + cfg->uri = strdup(config->uri); + ESP_WS_CLIENT_MEM_CHECK(TAG, cfg->uri, return ESP_ERR_NO_MEM); + } + if (config->path) { + free(cfg->path); + cfg->path = strdup(config->path); + ESP_WS_CLIENT_MEM_CHECK(TAG, cfg->path, return ESP_ERR_NO_MEM); + } + + cfg->network_timeout_ms = WEBSOCKET_NETWORK_TIMEOUT_MS; + cfg->user_context = config->user_context; + cfg->auto_reconnect = true; + if (config->disable_auto_reconnect) { + cfg->auto_reconnect = false; + } + + + return ESP_OK; +} + +static esp_err_t esp_websocket_client_destroy_config(esp_websocket_client_handle_t client) +{ + if (client == NULL) { + return ESP_ERR_INVALID_ARG; + } + websocket_config_storage_t *cfg = client->config; + if (client->config == NULL) { + return ESP_ERR_INVALID_ARG; + } + free(cfg->host); + free(cfg->uri); + free(cfg->path); + free(cfg->scheme); + free(cfg->username); + free(cfg->password); + memset(cfg, 0, sizeof(websocket_config_storage_t)); + free(client->config); + client->config = NULL; + return ESP_OK; +} + +esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_client_config_t *config) +{ + esp_websocket_client_handle_t client = calloc(1, sizeof(struct esp_websocket_client)); + ESP_WS_CLIENT_MEM_CHECK(TAG, client, return NULL); + + esp_event_loop_args_t event_args = { + .queue_size = WEBSOCKET_EVENT_QUEUE_SIZE, + .task_name = NULL // no task will be created + }; + + if (esp_event_loop_create(&event_args, &client->event_handle) != ESP_OK) { + ESP_LOGE(TAG, "Error create event handler for websocket client"); + free(client); + return NULL; + } + + client->lock = xSemaphoreCreateMutex(); + ESP_WS_CLIENT_MEM_CHECK(TAG, client->lock, goto _websocket_init_fail); + + client->transport_list = esp_transport_list_init(); + ESP_WS_CLIENT_MEM_CHECK(TAG, client->transport_list, goto _websocket_init_fail); + + esp_transport_handle_t tcp = esp_transport_tcp_init(); + ESP_WS_CLIENT_MEM_CHECK(TAG, tcp, goto _websocket_init_fail); + + esp_transport_set_default_port(tcp, WEBSOCKET_TCP_DEFAULT_PORT); + esp_transport_list_add(client->transport_list, tcp, "_tcp"); // need to save to transport list, for cleanup + + + esp_transport_handle_t ws = esp_transport_ws_init(tcp); + ESP_WS_CLIENT_MEM_CHECK(TAG, ws, goto _websocket_init_fail); + + esp_transport_set_default_port(ws, WEBSOCKET_TCP_DEFAULT_PORT); + esp_transport_list_add(client->transport_list, ws, "ws"); + if (config->transport == WEBSOCKET_TRANSPORT_OVER_TCP) { + asprintf(&client->config->scheme, "ws"); + ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->scheme, goto _websocket_init_fail); + } + + esp_transport_handle_t ssl = esp_transport_ssl_init(); + ESP_WS_CLIENT_MEM_CHECK(TAG, ssl, goto _websocket_init_fail); + + esp_transport_set_default_port(ssl, WEBSOCKET_SSL_DEFAULT_PORT); + if (config->cert_pem) { + esp_transport_ssl_set_cert_data(ssl, config->cert_pem, strlen(config->cert_pem)); + } + esp_transport_list_add(client->transport_list, ssl, "_ssl"); // need to save to transport list, for cleanup + + esp_transport_handle_t wss = esp_transport_ws_init(ssl); + ESP_WS_CLIENT_MEM_CHECK(TAG, wss, goto _websocket_init_fail); + + esp_transport_set_default_port(wss, WEBSOCKET_SSL_DEFAULT_PORT); + + esp_transport_list_add(client->transport_list, wss, "wss"); + if (config->transport == WEBSOCKET_TRANSPORT_OVER_TCP) { + asprintf(&client->config->scheme, "wss"); + ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->scheme, goto _websocket_init_fail); + } + + client->config = calloc(1, sizeof(websocket_config_storage_t)); + ESP_WS_CLIENT_MEM_CHECK(TAG, client->config, goto _websocket_init_fail); + + if (config->uri) { + if (esp_websocket_client_set_uri(client, config->uri) != ESP_OK) { + ESP_LOGE(TAG, "Invalid uri"); + goto _websocket_init_fail; + } + } + + if (esp_websocket_client_set_config(client, config) != ESP_OK) { + ESP_LOGE(TAG, "Failed to set the configuration"); + goto _websocket_init_fail; + } + + if (client->config->scheme == NULL) { + asprintf(&client->config->scheme, "ws"); + ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->scheme, goto _websocket_init_fail); + } + + client->keepalive_tick_ms = _tick_get_ms(); + client->reconnect_tick_ms = _tick_get_ms(); + client->ping_tick_ms = _tick_get_ms(); + + int buffer_size = config->buffer_size; + if (buffer_size <= 0) { + buffer_size = WEBSOCKET_BUFFER_SIZE_BYTE; + } + client->rx_buffer = malloc(buffer_size); + ESP_WS_CLIENT_MEM_CHECK(TAG, client->rx_buffer, { + goto _websocket_init_fail; + }); + client->tx_buffer = malloc(buffer_size); + ESP_WS_CLIENT_MEM_CHECK(TAG, client->tx_buffer, { + goto _websocket_init_fail; + }); + client->status_bits = xEventGroupCreate(); + ESP_WS_CLIENT_MEM_CHECK(TAG, client->status_bits, { + goto _websocket_init_fail; + }); + + client->buffer_size = buffer_size; + return client; + +_websocket_init_fail: + esp_websocket_client_destroy(client); + return NULL; +} + +esp_err_t esp_websocket_client_destroy(esp_websocket_client_handle_t client) +{ + if (client == NULL) { + return ESP_ERR_INVALID_ARG; + } + if (client->run) { + esp_websocket_client_stop(client); + } + if (client->event_handle) { + esp_event_loop_delete(client->event_handle); + } + esp_websocket_client_destroy_config(client); + esp_transport_list_destroy(client->transport_list); + vQueueDelete(client->lock); + free(client->tx_buffer); + free(client->rx_buffer); + if (client->status_bits) { + vEventGroupDelete(client->status_bits); + } + free(client); + client = NULL; + return ESP_OK; +} + +esp_err_t esp_websocket_client_set_uri(esp_websocket_client_handle_t client, const char *uri) +{ + if (client == NULL || uri == NULL) { + return ESP_ERR_INVALID_ARG; + } + struct http_parser_url puri; + http_parser_url_init(&puri); + int parser_status = http_parser_parse_url(uri, strlen(uri), 0, &puri); + if (parser_status != 0) { + ESP_LOGE(TAG, "Error parse uri = %s", uri); + return ESP_FAIL; + } + if (puri.field_data[UF_SCHEMA].len) { + free(client->config->scheme); + asprintf(&client->config->scheme, "%.*s", puri.field_data[UF_SCHEMA].len, uri + puri.field_data[UF_SCHEMA].off); + ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->scheme, return ESP_ERR_NO_MEM); + } + + if (puri.field_data[UF_HOST].len) { + free(client->config->host); + asprintf(&client->config->host, "%.*s", puri.field_data[UF_HOST].len, uri + puri.field_data[UF_HOST].off); + ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->host, return ESP_ERR_NO_MEM); + } + + + if (puri.field_data[UF_PATH].len) { + free(client->config->path); + asprintf(&client->config->path, "%.*s", puri.field_data[UF_PATH].len, uri + puri.field_data[UF_PATH].off); + ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->path, return ESP_ERR_NO_MEM); + + esp_transport_handle_t trans = esp_transport_list_get_transport(client->transport_list, "ws"); + if (trans) { + esp_transport_ws_set_path(trans, client->config->path); + } + trans = esp_transport_list_get_transport(client->transport_list, "wss"); + if (trans) { + esp_transport_ws_set_path(trans, client->config->path); + } + } + if (puri.field_data[UF_PORT].off) { + client->config->port = strtol((const char*)(uri + puri.field_data[UF_PORT].off), NULL, 10); + } + + if (puri.field_data[UF_USERINFO].len) { + char *user_info = NULL; + asprintf(&user_info, "%.*s", puri.field_data[UF_USERINFO].len, uri + puri.field_data[UF_USERINFO].off); + if (user_info) { + char *pass = strchr(user_info, ':'); + if (pass) { + pass[0] = 0; //terminal username + pass ++; + free(client->config->password); + client->config->password = strdup(pass); + ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->password, return ESP_ERR_NO_MEM); + } + free(client->config->username); + client->config->username = strdup(user_info); + ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->username, return ESP_ERR_NO_MEM); + free(user_info); + } else { + return ESP_ERR_NO_MEM; + } + } + return ESP_OK; +} + +static void esp_websocket_client_task(void *pv) +{ + int rlen; + esp_websocket_client_handle_t client = (esp_websocket_client_handle_t) pv; + client->run = true; + + //get transport by scheme + client->transport = esp_transport_list_get_transport(client->transport_list, client->config->scheme); + + if (client->transport == NULL) { + ESP_LOGE(TAG, "There are no transports valid, stop websocket client"); + client->run = false; + } + //default port + if (client->config->port == 0) { + client->config->port = esp_transport_get_default_port(client->transport); + } + + client->state = WEBSOCKET_STATE_INIT; + xEventGroupClearBits(client->status_bits, STOPPED_BIT); + int read_select; + while (client->run) { + switch ((int)client->state) { + case WEBSOCKET_STATE_INIT: + if (client->transport == NULL) { + ESP_LOGE(TAG, "There are no transport"); + client->run = false; + break; + } + + if (esp_transport_connect(client->transport, + client->config->host, + client->config->port, + client->config->network_timeout_ms) < 0) { + ESP_LOGE(TAG, "Error transport connect"); + esp_websocket_client_abort_connection(client); + break; + } + ESP_LOGD(TAG, "Transport connected to %s://%s:%d", client->config->scheme, client->config->host, client->config->port); + + client->state = WEBSOCKET_STATE_CONNECTED; + esp_websocket_client_dispatch_event(client, WEBSOCKET_EVENT_CONNECTED, NULL, 0); + + break; + case WEBSOCKET_STATE_CONNECTED: + read_select = esp_transport_poll_read(client->transport, 1000); //Poll every 1000ms + if (read_select < 0) { + ESP_LOGE(TAG, "Network error, errorno"); + esp_websocket_client_abort_connection(client); + break; + } + if (_tick_get_ms() - client->ping_tick_ms > WEBSOCKET_PING_TIMEOUT_MS) { + client->ping_tick_ms = _tick_get_ms(); + // Send PING + esp_transport_write(client->transport, NULL, 0, client->config->network_timeout_ms); + } + if (read_select == 0) { + ESP_LOGD(TAG, "Timeout..."); + continue; + } + client->ping_tick_ms = _tick_get_ms(); + + rlen = esp_transport_read(client->transport, client->rx_buffer, client->buffer_size, client->config->network_timeout_ms); + if (rlen < 0) { + ESP_LOGE(TAG, "Error read data"); + esp_websocket_client_abort_connection(client); + break; + } + if (rlen > 0) { + esp_websocket_client_dispatch_event(client, WEBSOCKET_EVENT_DATA, client->rx_buffer, rlen); + } + break; + case WEBSOCKET_STATE_WAIT_TIMEOUT: + + if (!client->config->auto_reconnect) { + client->run = false; + break; + } + if (_tick_get_ms() - client->reconnect_tick_ms > client->wait_timeout_ms) { + client->state = WEBSOCKET_STATE_INIT; + client->reconnect_tick_ms = _tick_get_ms(); + ESP_LOGD(TAG, "Reconnecting..."); + } + vTaskDelay(client->wait_timeout_ms / 2 / portTICK_RATE_MS); + break; + } + } + + esp_transport_close(client->transport); + xEventGroupSetBits(client->status_bits, STOPPED_BIT); + client->state = WEBSOCKET_STATE_UNKNOW; + vTaskDelete(NULL); +} + +esp_err_t esp_websocket_client_start(esp_websocket_client_handle_t client) +{ + if (client == NULL) { + return ESP_ERR_INVALID_ARG; + } + if (client->state >= WEBSOCKET_STATE_INIT) { + ESP_LOGE(TAG, "The client has started"); + return ESP_FAIL; + } + if (xTaskCreate(esp_websocket_client_task, "websocket_task", client->config->task_stack, client, client->config->task_prio, NULL) != pdTRUE) { + ESP_LOGE(TAG, "Error create websocket task"); + return ESP_FAIL; + } + xEventGroupClearBits(client->status_bits, STOPPED_BIT); + return ESP_OK; +} + +esp_err_t esp_websocket_client_stop(esp_websocket_client_handle_t client) +{ + if (client == NULL) { + return ESP_ERR_INVALID_ARG; + } + if (!client->run) { + ESP_LOGW(TAG, "Client was not started"); + return ESP_FAIL; + } + client->run = false; + xEventGroupWaitBits(client->status_bits, STOPPED_BIT, false, true, portMAX_DELAY); + client->state = WEBSOCKET_STATE_UNKNOW; + return ESP_OK; +} + +int esp_websocket_client_send(esp_websocket_client_handle_t client, const char *data, int len, TickType_t timeout) +{ + int need_write = len; + int wlen = 0, widx = 0; + + if (client == NULL || data == NULL || len <= 0) { + ESP_LOGE(TAG, "Invalid arguments"); + return ESP_FAIL; + } + + if (!esp_websocket_client_is_connected(client)) { + ESP_LOGE(TAG, "Websocket client is not connected"); + return ESP_FAIL; + } + + if (client->transport == NULL) { + ESP_LOGE(TAG, "Invalid transport"); + return ESP_FAIL; + } + + if (xSemaphoreTake(client->lock, timeout) != pdPASS) { + return ESP_FAIL; + } + + while (widx < len) { + if (need_write > client->buffer_size) { + need_write = client->buffer_size; + } + memcpy(client->tx_buffer, data + widx, need_write); + wlen = esp_transport_write(client->transport, + (char *)client->tx_buffer, + need_write, + client->config->network_timeout_ms); + if (wlen <= 0) { + xSemaphoreGive(client->lock); + return wlen; + } + widx += wlen; + need_write = len - widx; + } + xSemaphoreGive(client->lock); + return widx; +} + +bool esp_websocket_client_is_connected(esp_websocket_client_handle_t client) +{ + if (client == NULL) { + return false; + } + return client->state == WEBSOCKET_STATE_CONNECTED; +} + +esp_err_t esp_websocket_register_events(esp_websocket_client_handle_t client, + esp_websocket_event_id_t event, + esp_event_handler_t event_handler, + void* event_handler_arg) { + if (client == NULL) { + return ESP_ERR_INVALID_ARG; + } + return esp_event_handler_register_with(client->event_handle, WEBSOCKET_EVENTS, event, event_handler, event_handler_arg); +} diff --git a/components/esp_websocket_client/include/esp_websocket_client.h b/components/esp_websocket_client/include/esp_websocket_client.h new file mode 100644 index 0000000000..898fab5ae0 --- /dev/null +++ b/components/esp_websocket_client/include/esp_websocket_client.h @@ -0,0 +1,195 @@ +// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef _ESP_WEBSOCKET_CLIENT_H_ +#define _ESP_WEBSOCKET_CLIENT_H_ + + +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "esp_err.h" +#include "esp_event.h" +#include "esp_event_loop.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct esp_websocket_client* esp_websocket_client_handle_t; + +ESP_EVENT_DECLARE_BASE(WEBSOCKET_EVENTS); // declaration of the task events family + +/** + * @brief Websocket Client events id + */ +typedef enum { + WEBSOCKET_EVENT_ANY = -1, + WEBSOCKET_EVENT_ERROR = 0, /*!< This event occurs when there are any errors during execution */ + WEBSOCKET_EVENT_CONNECTED, /*!< Once the Websocket has been connected to the server, no data exchange has been performed */ + WEBSOCKET_EVENT_DISCONNECTED, /*!< The connection has been disconnected */ + WEBSOCKET_EVENT_DATA, /*!< When receiving data from the server, possibly multiple portions of the packet */ + WEBSOCKET_EVENT_MAX +} esp_websocket_event_id_t; + +/** + * @brief Websocket event data + */ +typedef struct { + const char *data_ptr; /*!< Data pointer */ + int data_len; /*!< Data length */ +} esp_websocket_event_data_t; + +/** + * @brief Websocket Client transport + */ +typedef enum { + WEBSOCKET_TRANSPORT_UNKNOWN = 0x0, /*!< Transport unknown */ + WEBSOCKET_TRANSPORT_OVER_TCP, /*!< Transport over tcp */ + WEBSOCKET_TRANSPORT_OVER_SSL, /*!< Transport over ssl */ +} esp_websocket_transport_t; + +/** + * @brief Websocket Client events data + */ +typedef struct { + esp_websocket_event_id_t event_id; /*!< event_id, to know the cause of the event */ + esp_websocket_client_handle_t client; /*!< esp_websocket_client_handle_t context */ + void *user_context;/*!< user_data context, from esp_websocket_client_config_t user_data */ + char *data; /*!< data of the event */ + int data_len; /*!< length of data */ +} esp_websocket_event_t; + +typedef esp_websocket_event_t* esp_websocket_event_handle_t; +typedef esp_err_t (* websocket_event_callback_t)(esp_websocket_event_handle_t event); + +/** + * @brief Websocket client setup configuration + */ +typedef struct { + const char *uri; /*!< Websocket URI, the information on the URI can be overrides the other fields below, if any */ + const char *host; /*!< Domain or IP as string */ + int port; /*!< Port to connect, default depend on esp_websocket_transport_t (80 or 443) */ + const char *username; /*!< Using for Http authentication - Not supported for now */ + const char *password; /*!< Using for Http authentication - Not supported for now */ + const char *path; /*!< HTTP Path, if not set, default is `/` */ + bool disable_auto_reconnect; /*!< Disable the automatic reconnect function when disconnected */ + void *user_context; /*!< HTTP user data context */ + int task_prio; /*!< Websocket task priority */ + int task_stack; /*!< Websocket task stack */ + int buffer_size; /*!< Websocket buffer size */ + const char *cert_pem; /*!< SSL Certification, PEM format as string, if the client requires to verify server */ + esp_websocket_transport_t transport; /*!< Websocket transport type, see `esp_websocket_transport_t */ +} esp_websocket_client_config_t; + +/** + * @brief Start a Websocket session + * This function must be the first function to call, + * and it returns a esp_websocket_client_handle_t that you must use as input to other functions in the interface. + * This call MUST have a corresponding call to esp_websocket_client_destroy when the operation is complete. + * + * @param[in] config The configuration + * + * @return + * - `esp_websocket_client_handle_t` + * - NULL if any errors + */ +esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_client_config_t *config); + +/** + * @brief Set URL for client, when performing this behavior, the options in the URL will replace the old ones + * Must stop the WebSocket client before set URI if the client has been connected + * + * @param[in] client The client + * @param[in] uri The uri + * + * @return esp_err_t + */ +esp_err_t esp_websocket_client_set_uri(esp_websocket_client_handle_t client, const char *uri); + +/** + * @brief Open the WebSocket connection + * + * @param[in] client The client + * + * @return esp_err_t + */ +esp_err_t esp_websocket_client_start(esp_websocket_client_handle_t client); + +/** + * @brief Close the WebSocket connection + * + * @param[in] client The client + * + * @return esp_err_t + */ +esp_err_t esp_websocket_client_stop(esp_websocket_client_handle_t client); + +/** + * @brief Destroy the WebSocket connection and free all resources. + * This function must be the last function to call for an session. + * It is the opposite of the esp_websocket_client_init function and must be called with the same handle as input that a esp_websocket_client_init call returned. + * This might close all connections this handle has used. + * + * @param[in] client The client + * + * @return esp_err_t + */ +esp_err_t esp_websocket_client_destroy(esp_websocket_client_handle_t client); + +/** + * @brief Write data to the WebSocket connection + * + * @param[in] client The client + * @param[in] data The data + * @param[in] len The length + * @param[in] timeout Write data timeout + * + * @return + * - Number of data was sent + * - (-1) if any errors + */ +int esp_websocket_client_send(esp_websocket_client_handle_t client, const char *data, int len, TickType_t timeout); + +/** + * @brief Check the WebSocket connection status + * + * @param[in] client The client handle + * + * @return + * - true + * - false + */ +bool esp_websocket_client_is_connected(esp_websocket_client_handle_t client); + +/** + * @brief Register the Websocket Events + * + * @param client The client handle + * @param event The event id + * @param event_handler The callback function + * @param event_handler_arg User context + * @return esp_err_t + */ +esp_err_t esp_websocket_register_events(esp_websocket_client_handle_t client, + esp_websocket_event_id_t event, + esp_event_handler_t event_handler, + void* event_handler_arg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/esp_wifi/CMakeLists.txt b/components/esp_wifi/CMakeLists.txt index 70f9b78279..c1a9c9896c 100644 --- a/components/esp_wifi/CMakeLists.txt +++ b/components/esp_wifi/CMakeLists.txt @@ -1,33 +1,30 @@ idf_build_get_property(idf_target IDF_TARGET) -idf_build_get_property(build_dir BUILD_DIR) -set(COMPONENT_SRCS - "src/coexist.c" - "src/fast_crypto_ops.c" - "src/lib_printf.c" - "src/mesh_event.c" - "src/phy_init.c" - "src/restore.c" - "src/wifi_init.c") -set(COMPONENT_ADD_INCLUDEDIRS "include" "${idf_target}/include") -set(COMPONENT_PRIV_INCLUDEDIRS) -set(COMPONENT_REQUIRES wpa_supplicant smartconfig_ack) -set(COMPONENT_PRIV_REQUIRES "nvs_flash") - -set(link_binary_libs 1) -if (CONFIG_ESP32_NO_BLOBS OR CONFIG_ESP32S2_NO_BLOBS) +if(CONFIG_ESP32_NO_BLOBS OR CONFIG_ESP32S2_NO_BLOBS) set(link_binary_libs 0) + set(ldfragments) +else() + set(link_binary_libs 1) + set(ldfragments "linker.lf") endif() -if(link_binary_libs) - set(COMPONENT_ADD_LDFRAGMENTS "linker.lf") -endif() +idf_component_register(SRCS "src/coexist.c" + "src/crypto_ops.c" + "src/lib_printf.c" + "src/mesh_event.c" + "src/phy_init.c" + "src/restore.c" + "src/smartconfig.c" + "src/wifi_init.c" + INCLUDE_DIRS "include" "${idf_target}/include" + PRIV_REQUIRES wpa_supplicant nvs_flash smartconfig_ack + LDFRAGMENTS "${ldfragments}") -register_component() +idf_build_get_property(build_dir BUILD_DIR) target_link_libraries(${COMPONENT_LIB} PUBLIC "-L ${CMAKE_CURRENT_SOURCE_DIR}/lib_${idf_target}") if(link_binary_libs) - set(blobs coexist core espnow mesh net80211 phy pp rtc smartconfig wpa2 wpa wps) + set(blobs coexist core espnow mesh net80211 phy pp rtc smartconfig) foreach(blob ${blobs}) add_library(${blob} STATIC IMPORTED) set_property(TARGET ${blob} PROPERTY IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/lib_${idf_target}/lib${blob}.a) @@ -50,17 +47,18 @@ if(CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION) # To get the phy_init_data.bin file, compile phy_init_data.h as a C file and then objcopy # the object file to a raw binary + idf_build_get_property(config_dir CONFIG_DIR) add_custom_command( OUTPUT ${phy_init_data_bin} DEPENDS ${CMAKE_CURRENT_LIST_DIR}/${idf_target}/include/phy_init_data.h COMMAND ${CMAKE_C_COMPILER} -x c -c - -I ${esp_common_dir}/include -I ${CMAKE_CURRENT_LIST_DIR}/include -I ${build_dir}/config + -I ${esp_common_dir}/include -I ${CMAKE_CURRENT_LIST_DIR}/include -I ${config_dir} -o phy_init_data.obj ${CMAKE_CURRENT_LIST_DIR}/${idf_target}/include/phy_init_data.h COMMAND ${CMAKE_OBJCOPY} -O binary phy_init_data.obj ${phy_init_data_bin} ) add_custom_target(phy_init_data ALL DEPENDS ${phy_init_data_bin}) - add_dependencies(app phy_init_data) + add_dependencies(flash phy_init_data) esptool_py_flash_project_args(phy ${phy_partition_offset} ${phy_init_data_bin} FLASH_IN_PROJECT) endif() diff --git a/components/esp_wifi/Kconfig b/components/esp_wifi/Kconfig index eff3f7c1fa..1677a96d1d 100644 --- a/components/esp_wifi/Kconfig +++ b/components/esp_wifi/Kconfig @@ -355,7 +355,7 @@ menu PHY config ESP32_PHY_MAX_WIFI_TX_POWER int "Max WiFi TX power (dBm)" - range 0 20 + range 10 20 default 20 help Set maximum transmit power for WiFi radio. Actual transmit power for high diff --git a/components/esp_wifi/component.mk b/components/esp_wifi/component.mk index 866a1fdd11..aa196fd4ff 100644 --- a/components/esp_wifi/component.mk +++ b/components/esp_wifi/component.mk @@ -6,7 +6,7 @@ COMPONENT_ADD_INCLUDEDIRS := include $(IDF_TARGET)/include COMPONENT_SRCDIRS := src ifndef CONFIG_ESP32_NO_BLOBS - LIBS := core rtc net80211 pp wpa smartconfig coexist wps wpa2 espnow phy mesh + LIBS := core rtc net80211 pp smartconfig coexist espnow phy mesh COMPONENT_ADD_LDFLAGS += -L$(COMPONENT_PATH)/lib_$(IDF_TARGET) \ $(addprefix -l,$(LIBS)) diff --git a/components/esp_wifi/esp32/include/phy_init_data.h b/components/esp_wifi/esp32/include/phy_init_data.h index c44307505c..2cb12a7378 100644 --- a/components/esp_wifi/esp32/include/phy_init_data.h +++ b/components/esp_wifi/esp32/include/phy_init_data.h @@ -77,12 +77,12 @@ static const esp_phy_init_data_t phy_init_data= { { 0x18, 0x18, 0x18, - LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 78), - LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 72), - LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 66), - LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 60), - LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 56), - LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 52), + LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 40, 78), + LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 40, 72), + LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 40, 66), + LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 40, 60), + LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 40, 56), + LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 40, 52), 0, 1, 1, diff --git a/components/esp_wifi/include/esp_mesh.h b/components/esp_wifi/include/esp_mesh.h index a532117567..0666b182e0 100644 --- a/components/esp_wifi/include/esp_mesh.h +++ b/components/esp_wifi/include/esp_mesh.h @@ -174,8 +174,6 @@ typedef enum { MESH_EVENT_ROOT_ADDRESS, /**< the root address is obtained. It is posted by mesh stack automatically. */ MESH_EVENT_ROOT_SWITCH_REQ, /**< root switch request sent from a new voted root candidate */ MESH_EVENT_ROOT_SWITCH_ACK, /**< root switch acknowledgment responds the above request sent from current root */ - MESH_EVENT_ROOT_GOT_IP, /**< the root obtains the IP address. It is posted by LwIP stack automatically */ - MESH_EVENT_ROOT_LOST_IP, /**< the root loses the IP address. It is posted by LwIP stack automatically */ MESH_EVENT_ROOT_ASKED_YIELD, /**< the root is asked yield by a more powerful existing root. If self organized is disabled and this device is specified to be a root by users, users should set a new parent for this device. if self organized is enabled, this device will find a new parent @@ -195,6 +193,9 @@ typedef enum { MESH_EVENT_MAX, } mesh_event_id_t; +/** @brief ESP-MESH event base declaration */ +ESP_EVENT_DECLARE_BASE(MESH_EVENT); + /** * @brief Device type */ @@ -427,21 +428,6 @@ typedef union { mesh_event_router_switch_t router_switch; /**< new router information */ } mesh_event_info_t; -/** - * @brief Mesh event - */ -typedef struct { - mesh_event_id_t id; /**< mesh event id */ - mesh_event_info_t info; /**< mesh event info */ -} mesh_event_t; - -/** - * @brief Mesh event callback handler prototype definition - * - * @param event mesh_event_t - */ -typedef void (*mesh_event_cb_t)(mesh_event_t event); - /** * @brief Mesh option */ @@ -492,7 +478,6 @@ typedef struct { uint8_t channel; /**< channel, the mesh network on */ bool allow_channel_switch; /**< if this value is set, when "fail" (mesh_attempts_t) times is reached, device will change to a full channel scan for a network that could join. The default value is false. */ - mesh_event_cb_t event_cb; /**< mesh event callback */ mesh_addr_t mesh_id; /**< mesh network identification */ mesh_router_t router; /**< router configuration */ mesh_ap_cfg_t mesh_ap; /**< mesh softAP configuration */ @@ -543,9 +528,6 @@ typedef struct { /* mesh IE crypto callback function */ extern const mesh_crypto_funcs_t g_wifi_default_mesh_crypto_funcs; -/* mesh event callback handler */ -extern mesh_event_cb_t g_mesh_event_cb; - #define MESH_INIT_CONFIG_DEFAULT() { \ .crypto_funcs = &g_wifi_default_mesh_crypto_funcs, \ } @@ -1303,16 +1285,6 @@ esp_err_t esp_mesh_set_root_healing_delay(int delay_ms); */ int esp_mesh_get_root_healing_delay(void); -/** - * @brief Set mesh event callback - * - * @param[in] event_cb mesh event call back - * - * @return - * - ESP_OK - */ -esp_err_t esp_mesh_set_event_cb(const mesh_event_cb_t event_cb); - /** * @brief Enable network Fixed Root Setting * - Enabling fixed root disables automatic election of the root node via voting. @@ -1479,6 +1451,13 @@ esp_err_t esp_mesh_switch_channel(const uint8_t *new_bssid, int csa_newchan, int */ esp_err_t esp_mesh_get_router_bssid(uint8_t *router_bssid); +/** + * @brief Get the TSF time + * + * @return the TSF time + */ +int64_t esp_mesh_get_tsf_time(void); + #ifdef __cplusplus } #endif diff --git a/components/esp_wifi/include/esp_private/esp_wifi_private.h b/components/esp_wifi/include/esp_private/esp_wifi_private.h new file mode 100644 index 0000000000..80828aa886 --- /dev/null +++ b/components/esp_wifi/include/esp_private/esp_wifi_private.h @@ -0,0 +1,25 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef _ESP_WIFI_PRIVATE_H +#define _ESP_WIFI_PRIVATE_H + +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "sys/queue.h" +#include "sdkconfig.h" +#include "esp_wifi_crypto_types.h" +#include "esp_private/wifi_os_adapter.h" + + +#endif /* _ESP_WIFI_PRIVATE_H */ diff --git a/components/esp_wifi/include/esp_private/esp_wifi_types_private.h b/components/esp_wifi/include/esp_private/esp_wifi_types_private.h new file mode 100644 index 0000000000..3a1eebac61 --- /dev/null +++ b/components/esp_wifi/include/esp_private/esp_wifi_types_private.h @@ -0,0 +1,25 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef _ESP_WIFI_TYPES_PRIVATE_H +#define _ESP_WIFI_TYPES_PRIVATE_H + +#include +#include +#include "sys/queue.h" +#include "esp_err.h" +#include "esp_interface.h" +#include "esp_event_base.h" + +#endif diff --git a/components/esp_wifi/include/esp_private/wifi.h b/components/esp_wifi/include/esp_private/wifi.h index c8fbe90ed0..8671d1705a 100644 --- a/components/esp_wifi/include/esp_private/wifi.h +++ b/components/esp_wifi/include/esp_private/wifi.h @@ -36,6 +36,8 @@ #include "esp_wifi_types.h" #include "esp_event.h" #include "esp_wifi.h" +#include "esp_smartconfig.h" +#include "wifi_types.h" #ifdef __cplusplus extern "C" { @@ -181,6 +183,34 @@ esp_err_t esp_wifi_internal_set_sta_ip(void); */ esp_err_t esp_wifi_internal_set_fix_rate(wifi_interface_t ifx, bool en, wifi_phy_rate_t rate); +/** + * @brief Start SmartConfig, config ESP device to connect AP. You need to broadcast information by phone APP. + * Device sniffer special packets from the air that containing SSID and password of target AP. + * + * @attention 1. This API can be called in station or softAP-station mode. + * @attention 2. Can not call esp_smartconfig_start twice before it finish, please call + * esp_smartconfig_stop first. + * + * @param config pointer to smartconfig start configure structure + * + * @return + * - ESP_OK: succeed + * - others: fail + */ +esp_err_t esp_smartconfig_internal_start(const smartconfig_start_config_t *config); + +/** + * @brief Stop SmartConfig, free the buffer taken by esp_smartconfig_start. + * + * @attention Whether connect to AP succeed or not, this API should be called to free + * memory taken by smartconfig_start. + * + * @return + * - ESP_OK: succeed + * - others: fail + */ +esp_err_t esp_smartconfig_internal_stop(void); + /** * @brief Check the MD5 values of the OS adapter header files in IDF and WiFi library * @@ -204,15 +234,26 @@ esp_err_t esp_wifi_internal_osi_funcs_md5_check(const char *md5); esp_err_t esp_wifi_internal_crypto_funcs_md5_check(const char *md5); /** - * @brief Check the git commit id of WiFi library + * @brief Check the MD5 values of the esp_wifi_types.h in IDF and WiFi library * - * @attention 1. It is used for internal CI WiFi library check + * @attention 1. It is used for internal CI version check * * @return * - ESP_OK : succeed - * - ESP_FAIL : fail + * - ESP_WIFI_INVALID_ARG : MD5 check fail */ -esp_err_t esp_wifi_internal_git_commit_id_check(void); +esp_err_t esp_wifi_internal_wifi_type_md5_check(const char *md5); + +/** + * @brief Check the MD5 values of the esp_wifi.h in IDF and WiFi library + * + * @attention 1. It is used for internal CI version check + * + * @return + * - ESP_OK : succeed + * - ESP_WIFI_INVALID_ARG : MD5 check fail + */ +esp_err_t esp_wifi_internal_esp_wifi_md5_check(const char *md5); /** * @brief Allocate a chunk of memory for WiFi driver diff --git a/components/esp_wifi/include/esp_private/wifi_os_adapter.h b/components/esp_wifi/include/esp_private/wifi_os_adapter.h index d339ce0789..30f0b94cba 100644 --- a/components/esp_wifi/include/esp_private/wifi_os_adapter.h +++ b/components/esp_wifi/include/esp_private/wifi_os_adapter.h @@ -21,7 +21,7 @@ extern "C" { #endif -#define ESP_WIFI_OS_ADAPTER_VERSION 0x00000002 +#define ESP_WIFI_OS_ADAPTER_VERSION 0x00000003 #define ESP_WIFI_OS_ADAPTER_MAGIC 0xDEADBEAF #define OSI_FUNCS_TIME_BLOCKING 0xffffffff @@ -72,6 +72,7 @@ typedef struct { int32_t (* _task_get_max_priority)(void); void *(* _malloc)(uint32_t size); void (* _free)(void *p); + int32_t (* _event_post)(const char* event_base, int32_t event_id, void* event_data, size_t event_data_size, uint32_t ticks_to_wait); uint32_t (* _get_free_heap_size)(void); uint32_t (* _rand)(void); void (* _dport_access_stall_other_cpu_start_wrap)(void); @@ -121,8 +122,6 @@ typedef struct { int32_t (* _modem_sleep_exit)(uint32_t module); int32_t (* _modem_sleep_register)(uint32_t module); int32_t (* _modem_sleep_deregister)(uint32_t module); - void (* _sc_ack_send)(void *param); - void (* _sc_ack_send_stop)(void); uint32_t (* _coex_status_get)(void); int32_t (* _coex_wifi_request)(uint32_t event, uint32_t latency, uint32_t duration); int32_t (* _coex_wifi_release)(uint32_t event); diff --git a/components/esp_wifi/include/esp_private/wifi_types.h b/components/esp_wifi/include/esp_private/wifi_types.h new file mode 100644 index 0000000000..4542492c8f --- /dev/null +++ b/components/esp_wifi/include/esp_private/wifi_types.h @@ -0,0 +1,54 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef _WIFI_TYPES_H +#define _WIFI_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief WiFi ioctl command type + * + */ +typedef enum { + WIFI_IOCTL_SET_STA_HT2040_COEX = 1, /**< Set the configuration of STA's HT2040 coexist management */ + WIFI_IOCTL_GET_STA_HT2040_COEX, /**< Get the configuration of STA's HT2040 coexist management */ + WIFI_IOCTL_MAX, +} wifi_ioctl_cmd_t; + +/** + * @brief Configuration for STA's HT2040 coexist management + * + */ +typedef struct { + int enable; /**< Indicate whether STA's HT2040 coexist management is enabled or not */ +} wifi_ht2040_coex_t; + +/** + * @brief Configuration for WiFi ioctl + * + */ +typedef struct { + union { + wifi_ht2040_coex_t ht2040_coex; /**< Configuration of STA's HT2040 coexist management */ + } data; /**< Configuration of ioctl command */ +} wifi_ioctl_config_t; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/esp_wifi/include/esp_smartconfig.h b/components/esp_wifi/include/esp_smartconfig.h index 34cf8667ab..bd5c545e58 100644 --- a/components/esp_wifi/include/esp_smartconfig.h +++ b/components/esp_wifi/include/esp_smartconfig.h @@ -18,37 +18,48 @@ #include #include #include "esp_err.h" +#include "esp_event_base.h" #ifdef __cplusplus extern "C" { #endif -typedef enum { - SC_STATUS_WAIT = 0, /**< Waiting to start connect */ - SC_STATUS_FIND_CHANNEL, /**< Finding target channel */ - SC_STATUS_GETTING_SSID_PSWD, /**< Getting SSID and password of target AP */ - SC_STATUS_LINK, /**< Connecting to target AP */ - SC_STATUS_LINK_OVER, /**< Connected to AP successfully */ -} smartconfig_status_t; - typedef enum { SC_TYPE_ESPTOUCH = 0, /**< protocol: ESPTouch */ SC_TYPE_AIRKISS, /**< protocol: AirKiss */ SC_TYPE_ESPTOUCH_AIRKISS, /**< protocol: ESPTouch and AirKiss */ } smartconfig_type_t; -/** - * @brief The callback of SmartConfig, executed when smart-config status changed. - * - * @param status Status of SmartConfig: - * - SC_STATUS_GETTING_SSID_PSWD : pdata is a pointer of smartconfig_type_t, means config type. - * - SC_STATUS_LINK : pdata is a pointer to wifi_config_t. - * - SC_STATUS_LINK_OVER : pdata is a pointer of phone's IP address(4 bytes) if pdata unequal NULL. - * - otherwise : parameter void *pdata is NULL. - * @param pdata According to the different status have different values. - * - */ -typedef void (*sc_callback_t)(smartconfig_status_t status, void *pdata); +/** Smartconfig event declarations */ +typedef enum { + SC_EVENT_SCAN_DONE, /*!< ESP32 station smartconfig has finished to scan for APs */ + SC_EVENT_FOUND_CHANNEL, /*!< ESP32 station smartconfig has found the channel of the target AP */ + SC_EVENT_GOT_SSID_PSWD, /*!< ESP32 station smartconfig got the SSID and password */ + SC_EVENT_SEND_ACK_DONE, /*!< ESP32 station smartconfig has sent ACK to cellphone */ +} smartconfig_event_t; + +/** @brief smartconfig event base declaration */ +ESP_EVENT_DECLARE_BASE(SC_EVENT); + +/** Argument structure for SC_EVENT_GOT_SSID_PSWD event */ +typedef struct { + uint8_t ssid[32]; /**< SSID of the AP. Null terminated string. */ + uint8_t password[64]; /**< Password of the AP. Null terminated string. */ + bool bssid_set; /**< whether set MAC address of target AP or not. */ + uint8_t bssid[6]; /**< MAC address of target AP. */ + smartconfig_type_t type; /**< Type of smartconfig(ESPTouch or AirKiss). */ + uint8_t token; /**< Token from cellphone which is used to send ACK to cellphone. */ + uint8_t cellphone_ip[4]; /**< IP address of cellphone. */ +} smartconfig_event_got_ssid_pswd_t; + +/** Configure structure for esp_smartconfig_start */ +typedef struct { + bool enable_log; /**< Enable smartconfig logs. */ +} smartconfig_start_config_t; + +#define SMARTCONFIG_START_CONFIG_DEFAULT() { \ + .enable_log = false \ +}; /** * @brief Get the version of SmartConfig. @@ -66,14 +77,13 @@ const char *esp_smartconfig_get_version(void); * @attention 2. Can not call esp_smartconfig_start twice before it finish, please call * esp_smartconfig_stop first. * - * @param cb SmartConfig callback function. - * @param ... log 1: UART output logs; 0: UART only outputs the result. + * @param config pointer to smartconfig start configure structure * * @return * - ESP_OK: succeed * - others: fail */ -esp_err_t esp_smartconfig_start(sc_callback_t cb, ...); +esp_err_t esp_smartconfig_start(const smartconfig_start_config_t *config); /** * @brief Stop SmartConfig, free the buffer taken by esp_smartconfig_start. diff --git a/components/esp_wifi/include/esp_wifi.h b/components/esp_wifi/include/esp_wifi.h index 05265257a0..57014b8d9a 100644 --- a/components/esp_wifi/include/esp_wifi.h +++ b/components/esp_wifi/include/esp_wifi.h @@ -59,15 +59,10 @@ #include #include -#include "freertos/FreeRTOS.h" -#include "freertos/queue.h" -#include "sys/queue.h" -#include "sdkconfig.h" #include "esp_err.h" #include "esp_wifi_types.h" -#include "esp_wifi_crypto_types.h" #include "esp_event.h" -#include "esp_private/wifi_os_adapter.h" +#include "esp_private/esp_wifi_private.h" #ifdef __cplusplus extern "C" { @@ -89,6 +84,10 @@ extern "C" { #define ESP_ERR_WIFI_WOULD_BLOCK (ESP_ERR_WIFI_BASE + 14) /*!< The caller would block */ #define ESP_ERR_WIFI_NOT_CONNECT (ESP_ERR_WIFI_BASE + 15) /*!< Station still in disconnect status */ +#define ESP_ERR_WIFI_POST (ESP_ERR_WIFI_BASE + 18) /*!< Failed to post the event to WiFi task */ +#define ESP_ERR_WIFI_INIT_STATE (ESP_ERR_WIFI_BASE + 19) /*!< Invalod WiFi state when init/deinit is called */ +#define ESP_ERR_WIFI_STOP_STATE (ESP_ERR_WIFI_BASE + 20) /*!< Returned when WiFi is stopping */ + /** * @brief WiFi stack configuration parameters passed to esp_wifi_init call. */ @@ -581,7 +580,7 @@ esp_err_t esp_wifi_get_channel(uint8_t *primary, wifi_second_chan_t *second); * and the country info of the AP to which the station is connected is {.cc="JP", .schan=1, .nchan=14} * then the country info that will be used is {.cc="JP", .schan=1, .nchan=14}. If the station disconnected * from the AP the country info is set back back to the country info of the station automatically, - * {.cc="USA", .schan=1, .nchan=11} in the example. + * {.cc="US", .schan=1, .nchan=11} in the example. * @attention 3. When the country policy is WIFI_COUNTRY_POLICY_MANUAL, always use the configured country info. * @attention 4. When the country info is changed because of configuration or because the station connects to a different * external AP, the country IE in probe response/beacon of the soft-AP is changed also. @@ -840,6 +839,16 @@ esp_err_t esp_wifi_set_auto_connect(bool en) __attribute__ ((deprecated)); */ esp_err_t esp_wifi_get_auto_connect(bool *en) __attribute__ ((deprecated)); +/** + * @brief Function signature for received Vendor-Specific Information Element callback. + * @param ctx Context argument, as passed to esp_wifi_set_vendor_ie_cb() when registering callback. + * @param type Information element type, based on frame type received. + * @param sa Source 802.11 address. + * @param vnd_ie Pointer to the vendor specific element data received. + * @param rssi Received signal strength indication. + */ +typedef void (*esp_vendor_ie_cb_t) (void *ctx, wifi_vendor_ie_type_t type, const uint8_t sa[6], const vendor_ie_data_t *vnd_ie, int rssi); + /** * @brief Set 802.11 Vendor-Specific Information Element * @@ -858,16 +867,6 @@ esp_err_t esp_wifi_get_auto_connect(bool *en) __attribute__ ((deprecated)); */ esp_err_t esp_wifi_set_vendor_ie(bool enable, wifi_vendor_ie_type_t type, wifi_vendor_ie_id_t idx, const void *vnd_ie); -/** - * @brief Function signature for received Vendor-Specific Information Element callback. - * @param ctx Context argument, as passed to esp_wifi_set_vendor_ie_cb() when registering callback. - * @param type Information element type, based on frame type received. - * @param sa Source 802.11 address. - * @param vnd_ie Pointer to the vendor specific element data received. - * @param rssi Received signal strength indication. - */ -typedef void (*esp_vendor_ie_cb_t) (void *ctx, wifi_vendor_ie_type_t type, const uint8_t sa[6], const vendor_ie_data_t *vnd_ie, int rssi); - /** * @brief Register Vendor-Specific Information Element monitoring callback. * @@ -881,60 +880,22 @@ typedef void (*esp_vendor_ie_cb_t) (void *ctx, wifi_vendor_ie_type_t type, const esp_err_t esp_wifi_set_vendor_ie_cb(esp_vendor_ie_cb_t cb, void *ctx); /** - * @brief Set maximum WiFi transmiting power + * @brief Set maximum WiFi transmitting power * - * @attention WiFi transmiting power is divided to six levels in phy init data. - * Level0 represents highest transmiting power and level5 represents lowest - * transmiting power. Packets of different rates are transmitted in - * different powers according to the configuration in phy init data. - * This API only sets maximum WiFi transmiting power. If this API is called, - * the transmiting power of every packet will be less than or equal to the - * value set by this API. If this API is not called, the value of maximum - * transmitting power set in phy_init_data.bin or menuconfig (depend on - * whether to use phy init data in partition or not) will be used. Default - * value is level0. Values passed in power are mapped to transmit power - * levels as follows: - * - [78, 127]: level0 - * - [76, 77]: level1 - * - [74, 75]: level2 - * - [68, 73]: level3 - * - [60, 67]: level4 - * - [52, 59]: level5 - * - [44, 51]: level5 - 2dBm - * - [34, 43]: level5 - 4.5dBm - * - [28, 33]: level5 - 6dBm - * - [20, 27]: level5 - 8dBm - * - [8, 19]: level5 - 11dBm - * - [-128, 7]: level5 - 14dBm - * - * @param power Maximum WiFi transmiting power. + * @param power Maximum WiFi transmitting power, unit is 0.25dBm, range is [40, 82] corresponding to 10dBm - 20.5dBm here. * * @return * - ESP_OK: succeed * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init * - ESP_ERR_WIFI_NOT_START: WiFi is not started by esp_wifi_start + * - ESP_ERR_WIFI_NOT_ARG: invalid argument */ esp_err_t esp_wifi_set_max_tx_power(int8_t power); /** * @brief Get maximum WiFi transmiting power * - * @attention This API gets maximum WiFi transmiting power. Values got - * from power are mapped to transmit power levels as follows: - * - 78: 19.5dBm - * - 76: 19dBm - * - 74: 18.5dBm - * - 68: 17dBm - * - 60: 15dBm - * - 52: 13dBm - * - 44: 11dBm - * - 34: 8.5dBm - * - 28: 7dBm - * - 20: 5dBm - * - 8: 2dBm - * - -4: -1dBm - * - * @param power Maximum WiFi transmiting power. + * @param power Maximum WiFi transmitting power, unit is 0.25dBm. * * @return * - ESP_OK: succeed diff --git a/components/esp_wifi/include/esp_wifi_crypto_types.h b/components/esp_wifi/include/esp_wifi_crypto_types.h index e1e2a51a13..df2388259b 100644 --- a/components/esp_wifi/include/esp_wifi_crypto_types.h +++ b/components/esp_wifi/include/esp_wifi_crypto_types.h @@ -62,43 +62,6 @@ typedef struct crypto_hash esp_crypto_hash_t; */ typedef struct crypto_cipher esp_crypto_cipher_t; -/** - * @brief The crypto callback function used in wpa enterprise hash operation when connect. - * Initialize a esp_crypto_hash_t structure. - * - * @param alg Hash algorithm. - * @param key Key for keyed hash (e.g., HMAC) or %NULL if not needed. - * @param key_len Length of the key in bytes - * - */ -typedef esp_crypto_hash_t * (*esp_crypto_hash_init_t)(esp_crypto_hash_alg_t alg, const unsigned char *key, int key_len); - -/** - * @brief The crypto callback function used in wpa enterprise hash operation when connect. - * Add data to hash calculation. - * - * @param ctz Context pointer from esp_crypto_hash_init_t function. - * @param data Data buffer to add. - * @param len Length of the buffer. - * - */ -typedef void (*esp_crypto_hash_update_t)(esp_crypto_hash_t *ctx, const unsigned char *data, int len); - -/** - * @brief The crypto callback function used in wpa enterprise hash operation when connect. - * Complete hash calculation. - * - * @param ctz Context pointer from esp_crypto_hash_init_t function. - * @param hash Buffer for hash value or %NULL if caller is just freeing the hash - * context. - * @param 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) - * - */ -typedef int (*esp_crypto_hash_finish_t)(esp_crypto_hash_t *ctx, unsigned char *hash, int *len); - /** * @brief The AES callback function when do WPS connect. * @@ -142,64 +105,6 @@ typedef int (*esp_aes_wrap_t)(const unsigned char *kek, int n, const unsigned ch */ typedef int (*esp_aes_unwrap_t)(const unsigned char *kek, int n, const unsigned char *cipher, unsigned char *plain); -/** - * @brief The crypto callback function used in wpa enterprise cipher operation when connect. - * Initialize a esp_crypto_cipher_t structure. - * - * @param alg cipher algorithm. - * @param iv Initialization vector for block ciphers or %NULL for stream ciphers. - * @param key Cipher key - * @param key_len Length of key in bytes - * - */ -typedef esp_crypto_cipher_t * (*esp_crypto_cipher_init_t)(esp_crypto_cipher_alg_t alg, const unsigned char *iv, const unsigned char *key, int key_len); - -/** - * @brief The crypto callback function used in wpa enterprise cipher operation when connect. - * Cipher encrypt. - * - * @param ctx Context pointer from esp_crypto_cipher_init_t callback function. - * @param plain Plaintext to cipher. - * @param crypt Resulting ciphertext. - * @param len Length of the plaintext. - * - */ -typedef int (*esp_crypto_cipher_encrypt_t)(esp_crypto_cipher_t *ctx, - const unsigned char *plain, unsigned char *crypt, int len); -/** - * @brief The crypto callback function used in wpa enterprise cipher operation when connect. - * Cipher decrypt. - * - * @param ctx Context pointer from esp_crypto_cipher_init_t callback function. - * @param crypt Ciphertext to decrypt. - * @param plain Resulting plaintext. - * @param len Length of the cipher text. - * - */ -typedef int (*esp_crypto_cipher_decrypt_t)(esp_crypto_cipher_t *ctx, - const unsigned char *crypt, unsigned char *plain, int len); -/** - * @brief The crypto callback function used in wpa enterprise cipher operation when connect. - * Free cipher context. - * - * @param ctx Context pointer from esp_crypto_cipher_init_t callback function. - * - */ -typedef void (*esp_crypto_cipher_deinit_t)(esp_crypto_cipher_t *ctx); - -/** - * @brief The SHA256 callback function when do WPS connect. - * - * @param key Key for HMAC operations. - * @param key_len Length of the key in bytes. - * @param data Pointers to the data area. - * @param data_len Length of the data area. - * @param mac Buffer for the hash (20 bytes). - * - */ -typedef void (*esp_hmac_sha256_t)(const unsigned char *key, int key_len, const unsigned char *data, - int data_len, unsigned char *mac); - /** * @brief The SHA256 callback function when do WPS connect. * @@ -229,37 +134,6 @@ typedef void (*esp_hmac_sha256_vector_t)(const unsigned char *key, int key_len, typedef void (*esp_sha256_prf_t)(const unsigned char *key, int key_len, const char *label, const unsigned char *data, int data_len, unsigned char *buf, int buf_len); -/** - * @brief The SHA256 callback function when do WPS connect. - * - * @param num_elem Number of elements in the data vector. - * @param addr Pointers to the data areas. - * @param len Lengths of the data blocks. - * @paramac Buffer for the hash. - * - */ -typedef int (*esp_sha256_vector_t)(int num_elem, const unsigned char *addr[], const int *len, - unsigned char *mac); - -/** - * @brief The bignum calculate callback function used when do connect. - * In WPS process, it used to calculate public key and private key. - * - * @param base Base integer (big endian byte array). - * @param base_len Length of base integer in bytes. - * @param power Power integer (big endian byte array). - * @param power_len Length of power integer in bytes. - * @param modulus Modulus integer (big endian byte array). - * @param modulus_len Length of modulus integer in bytes. - * @param result Buffer for the result. - * @param result_len Result length (max buffer size on input, real len on output). - * - */ -typedef int (*esp_crypto_mod_exp_t)(const unsigned char *base, int base_len, - const unsigned char *power, int power_len, - const unsigned char *modulus, int modulus_len, - unsigned char *result, unsigned int *result_len); - /** * @brief HMAC-MD5 over data buffer (RFC 2104)' * @@ -441,258 +315,6 @@ typedef void * (*esp_aes_decrypt_init_t)(const unsigned char *key, unsigned int */ typedef void (*esp_aes_decrypt_deinit_t)(void *ctx); -/** - * @brief Initialize TLS library - * - * @conf: Configuration data for TLS library - * Returns: Context data to be used as tls_ctx in calls to other functions, - * or %NULL on failure. - * - * Called once during program startup and once for each RSN pre-authentication - * session. In other words, there can be two concurrent TLS contexts. If global - * library initialization is needed (i.e., one that is shared between both - * authentication types), the TLS library wrapper should maintain a reference - * counter and do global initialization only when moving from 0 to 1 reference. - */ -typedef void * (*esp_tls_init_t)(void); - -/** - * @brief Deinitialize TLS library - * - * @tls_ctx: TLS context data from tls_init() - * - * Called once during program shutdown and once for each RSN pre-authentication - * session. If global library deinitialization is needed (i.e., one that is - * shared between both authentication types), the TLS library wrapper should - * maintain a reference counter and do global deinitialization only when moving - * from 1 to 0 references. - */ -typedef void (*esp_tls_deinit_t)(void *tls_ctx); - -/** - * @brief Add certificate and private key for connect - - * @sm: eap state machine - * - * Returns: 0 for success, -1 state machine didn't exist, -2 short of certificate or key - */ -typedef int (*esp_eap_peer_blob_init_t)(void *sm); - -/** - * @brief delete the certificate and private - * - * @sm: eap state machine - * - */ -typedef void (*esp_eap_peer_blob_deinit_t)(void *sm); - -/** - * @brief Initialize the eap state machine - * - * @sm: eap state machine - * @private_key_passwd: the start address of private_key_passwd - * @private_key_passwd_len: length of private_key_password - * - * Returns: 0 is success, -1 state machine didn't exist, -2 short of parameters - * - */ -typedef int (*esp_eap_peer_config_init_t)(void *sm, unsigned char *private_key_passwd,int private_key_passwd_len); - -/** - * @brief Deinit the eap state machine - * - * @sm: eap state machine - * - */ -typedef void (*esp_eap_peer_config_deinit_t)(void *sm); - -/** - * @brief Register the eap method - * - * Note: ESP32 only support PEAP/TTLS/TLS three eap methods now. - * - */ -typedef int (*esp_eap_peer_register_methods_t)(void); - -/** - * @brief remove the eap method - * - * Note: ESP32 only support PEAP/TTLS/TLS three eap methods now. - * - */ -typedef void (*esp_eap_peer_unregister_methods_t)(void); - -/** - * @brief remove the eap method before build new connect - * - * @sm: eap state machine - * @txt: not used now - */ -typedef void (*esp_eap_deinit_prev_method_t)(void *sm, const char *txt); - -/** - * @brief Get EAP method based on type number - * - * @vendor: EAP Vendor-Id (0 = IETF) - * @method: EAP type number - * Returns: Pointer to EAP method or %NULL if not found - */ -typedef const void * (*esp_eap_peer_get_eap_method_t)(int vendor, int method); - -/** - * @brief Abort EAP authentication - * - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * - * Release system resources that have been allocated for the authentication - * session without fully deinitializing the EAP state machine. - */ -typedef void (*esp_eap_sm_abort_t)(void *sm); - -/** - * @brief Build EAP-NAK for the current network - * - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @type: EAP type of the fail reason - * @id: EAP identifier for the packet - * - * This function allocates and builds a nak packet for the - * current network. The caller is responsible for freeing the returned data. - */ -typedef void * (*esp_eap_sm_build_nak_t)(void *sm, int type, unsigned char id); - -/** - * @brief Build EAP-Identity/Response for the current network - * - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @id: EAP identifier for the packet - * @encrypted: Whether the packet is for encrypted tunnel (EAP phase 2) - * Returns: Pointer to the allocated EAP-Identity/Response packet or %NULL on - * failure - * - * This function allocates and builds an EAP-Identity/Response packet for the - * current network. The caller is responsible for freeing the returned data. - */ -typedef void * (*esp_eap_sm_build_identity_resp_t)(void *sm, unsigned char id, int encrypted); - -/** - * @brief 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. - */ -typedef void * (*esp_eap_msg_alloc_t)(int vendor, int type, unsigned int payload_len, - unsigned char code, unsigned char identifier); - -/** - * @brief get the enrollee mac address - * @mac_addr: instore the mac address of enrollee - * @uuid: Universally Unique Identifer of the enrollee - * - */ -typedef void (*esp_uuid_gen_mac_addr_t)(const unsigned char *mac_addr, unsigned char *uuid); - -/** - * @brief free the message after finish DH - * - */ -typedef void (*esp_dh5_free_t)(void *ctx); - -/** - * @brief Build WPS IE for (Re)Association Request - * - * @req_type: Value for Request Type attribute - * Returns: WPS IE or %NULL on failure - * - * The caller is responsible for freeing the buffer. - */ -typedef void * (*esp_wps_build_assoc_req_ie_t)(int req_type); - -/** - * @brief Build WPS IE for (Re)Association Response - * - * Returns: WPS IE or %NULL on failure - * - * The caller is responsible for freeing the buffer. - */ -typedef void * (*esp_wps_build_assoc_resp_ie_t)(void); - -/** - * @brief Build WPS IE for Probe Request - * - * @pw_id: Password ID (DEV_PW_PUSHBUTTON for active PBC and DEV_PW_DEFAULT for - * most other use cases) - * @dev: Device attributes - * @uuid: Own UUID - * @req_type: Value for Request Type attribute - * @num_req_dev_types: Number of requested device types - * @req_dev_types: Requested device types (8 * num_req_dev_types octets) or - * %NULL if none - * Returns: WPS IE or %NULL on failure - * - * The caller is responsible for freeing the buffer. - */ -typedef void * (*esp_wps_build_probe_req_ie_t)(uint16_t pw_id, void *dev, const unsigned char *uuid, - int req_type, unsigned int num_req_dev_types, const unsigned char *req_dev_types); - -/** - * @brief build public key for exchange in M1 - * - * - */ -typedef int (*esp_wps_build_public_key_t)(void *wps, void *msg, int mode); - - -/** - * @brief get the wps information in exchange password - * - * - */ -typedef void * (*esp_wps_enrollee_get_msg_t)(void *wps, void *op_code); - -/** - * @brief deal with the wps information in exchange password - * - * - */ -typedef int (*esp_wps_enrollee_process_msg_t)(void *wps, int op_code, const void *msg); - -/** - * @brief Generate a random PIN - * - * Returns: Eight digit PIN (i.e., including the checksum digit) - */ -typedef unsigned int (*esp_wps_generate_pin_t)(void); - -/** - * @brief Check whether WPS IE indicates active PIN - * - * @msg: WPS IE contents from Beacon or Probe Response frame - * Returns: 1 if PIN Registrar is active, 0 if not - */ -typedef int (*esp_wps_is_selected_pin_registrar_t)(const void *msg, unsigned char *bssid); - -/** - * @brief Check whether WPS IE indicates active PBC - * - * @msg: WPS IE contents from Beacon or Probe Response frame - * Returns: 1 if PBC Registrar is active, 0 if not - */ -typedef int (*esp_wps_is_selected_pbc_registrar_t)(const void *msg, unsigned char *bssid); - - - /** * @brief The crypto callback function structure used when do station security connect. * The structure can be set as software crypto or the crypto optimized by ESP32 @@ -722,67 +344,6 @@ typedef struct { esp_aes_decrypt_deinit_t aes_decrypt_deinit; }wpa_crypto_funcs_t; -/** - * @brief The crypto callback function structure used when do WPS process. The - * structure can be set as software crypto or the crypto optimized by ESP32 - * hardware. - */ -typedef struct{ - uint32_t size; - uint32_t version; - esp_aes_128_encrypt_t aes_128_encrypt; /**< function used to process message when do WPS */ - esp_aes_128_decrypt_t aes_128_decrypt; /**< function used to process message when do WPS */ - esp_crypto_mod_exp_t crypto_mod_exp; /**< function used to calculate public key and private key */ - esp_hmac_sha256_t hmac_sha256; /**< function used to get attribute */ - esp_hmac_sha256_vector_t hmac_sha256_vector; /**< function used to process message when do WPS */ - esp_sha256_vector_t sha256_vector; /**< function used to process message when do WPS */ - esp_uuid_gen_mac_addr_t uuid_gen_mac_addr; - esp_dh5_free_t dh5_free; - esp_wps_build_assoc_req_ie_t wps_build_assoc_req_ie; - esp_wps_build_assoc_resp_ie_t wps_build_assoc_resp_ie; - esp_wps_build_probe_req_ie_t wps_build_probe_req_ie; - esp_wps_build_public_key_t wps_build_public_key; - esp_wps_enrollee_get_msg_t wps_enrollee_get_msg; - esp_wps_enrollee_process_msg_t wps_enrollee_process_msg; - esp_wps_generate_pin_t wps_generate_pin; - esp_wps_is_selected_pin_registrar_t wps_is_selected_pin_registrar; - esp_wps_is_selected_pbc_registrar_t wps_is_selected_pbc_registrar; - esp_eap_msg_alloc_t eap_msg_alloc; -}wps_crypto_funcs_t; - -/** - * @brief The crypto callback function structure used when do WPA enterprise connect. - * The structure can be set as software crypto or the crypto optimized by ESP32 - * hardware. - */ -typedef struct { - uint32_t size; - uint32_t version; - esp_crypto_hash_init_t crypto_hash_init; /**< function used to initialize a crypto_hash structure when use TLSV1 */ - esp_crypto_hash_update_t crypto_hash_update; /**< function used to calculate hash data when use TLSV1 */ - esp_crypto_hash_finish_t crypto_hash_finish; /**< function used to finish the hash calculate when use TLSV1 */ - esp_crypto_cipher_init_t crypto_cipher_init; /**< function used to initialize a crypt_cipher structure when use TLSV1 */ - esp_crypto_cipher_encrypt_t crypto_cipher_encrypt; /**< function used to encrypt cipher when use TLSV1 */ - esp_crypto_cipher_decrypt_t crypto_cipher_decrypt; /**< function used to decrypt cipher when use TLSV1 */ - esp_crypto_cipher_deinit_t crypto_cipher_deinit; /**< function used to free context when use TLSV1 */ - esp_crypto_mod_exp_t crypto_mod_exp; /**< function used to do key exchange when use TLSV1 */ - esp_sha256_vector_t sha256_vector; /**< function used to do X.509v3 certificate parsing and processing */ - esp_tls_init_t tls_init; - esp_tls_deinit_t tls_deinit; - esp_eap_peer_blob_init_t eap_peer_blob_init; - esp_eap_peer_blob_deinit_t eap_peer_blob_deinit; - esp_eap_peer_config_init_t eap_peer_config_init; - esp_eap_peer_config_deinit_t eap_peer_config_deinit; - esp_eap_peer_register_methods_t eap_peer_register_methods; - esp_eap_peer_unregister_methods_t eap_peer_unregister_methods; - esp_eap_deinit_prev_method_t eap_deinit_prev_method; - esp_eap_peer_get_eap_method_t eap_peer_get_eap_method; - esp_eap_sm_abort_t eap_sm_abort; - esp_eap_sm_build_nak_t eap_sm_build_nak; - esp_eap_sm_build_identity_resp_t eap_sm_build_identity_resp; - esp_eap_msg_alloc_t eap_msg_alloc; -} wpa2_crypto_funcs_t; - /** * @brief The crypto callback function structure used in mesh vendor IE encryption. The * structure can be set as software crypto or the crypto optimized by ESP32 diff --git a/components/esp_wifi/include/esp_wifi_types.h b/components/esp_wifi/include/esp_wifi_types.h index 714b88bc6c..5e8bb7fc9b 100644 --- a/components/esp_wifi/include/esp_wifi_types.h +++ b/components/esp_wifi/include/esp_wifi_types.h @@ -16,12 +16,7 @@ #ifndef __ESP_WIFI_TYPES_H__ #define __ESP_WIFI_TYPES_H__ -#include -#include -#include "sys/queue.h" -#include "esp_err.h" -#include "esp_interface.h" -#include "esp_event_base.h" +#include "esp_private/esp_wifi_types_private.h" #ifdef __cplusplus extern "C" { @@ -50,7 +45,7 @@ typedef struct { char cc[3]; /**< country code string */ uint8_t schan; /**< start channel */ uint8_t nchan; /**< total channel number */ - int8_t max_tx_power; /**< maximum tx power */ + int8_t max_tx_power; /**< This field is used for getting WiFi maximum transmitting power, call esp_wifi_set_max_tx_power to set the maximum transmitting power. */ wifi_country_policy_t policy; /**< country policy */ } wifi_country_t; @@ -230,7 +225,7 @@ typedef struct { uint8_t channel; /**< channel of target AP. Set to 1~13 to scan starting from the specified channel before connecting to AP. If the channel of AP is unknown, set it to 0.*/ uint16_t listen_interval; /**< Listen interval for ESP32 station to receive beacon when WIFI_PS_MAX_MODEM is set. Units: AP beacon intervals. Defaults to 3 if set to 0. */ wifi_sort_method_t sort_method; /**< sort the connect AP in the list by rssi or security mode */ - wifi_scan_threshold_t threshold; /**< When scan_method is set, only APs which have an auth mode that is more secure than the selected auth mode and a signal stronger than the minimum RSSI will be used. */ + wifi_scan_threshold_t threshold; /**< When sort_method is set, only APs which have an auth mode that is more secure than the selected auth mode and a signal stronger than the minimum RSSI will be used. */ } wifi_sta_config_t; /** @brief Configuration data for ESP32 AP or STA. @@ -516,6 +511,7 @@ typedef enum { WIFI_EVENT_STA_WPS_ER_FAILED, /**< ESP32 station wps fails in enrollee mode */ WIFI_EVENT_STA_WPS_ER_TIMEOUT, /**< ESP32 station wps timeout in enrollee mode */ WIFI_EVENT_STA_WPS_ER_PIN, /**< ESP32 station wps pin code in enrollee mode */ + WIFI_EVENT_STA_WPS_ER_PBC_OVERLAP, /**< ESP32 station wps overlap in enrollee mode */ WIFI_EVENT_AP_START, /**< ESP32 soft-AP start */ WIFI_EVENT_AP_STOP, /**< ESP32 soft-AP stop */ @@ -590,34 +586,6 @@ typedef struct { uint8_t mac[6]; /**< MAC address of the station which send probe request */ } wifi_event_ap_probe_req_rx_t; -/** - * @brief WiFi ioctl command type - * - */ -typedef enum { - WIFI_IOCTL_SET_STA_HT2040_COEX = 1, /**< Set the configuration of STA's HT2040 coexist management */ - WIFI_IOCTL_GET_STA_HT2040_COEX, /**< Get the configuration of STA's HT2040 coexist management */ - WIFI_IOCTL_MAX, -} wifi_ioctl_cmd_t; - -/** - * @brief Configuration for STA's HT2040 coexist management - * - */ -typedef struct { - int enable; /**< Indicate whether STA's HT2040 coexist management is enabled or not */ -} wifi_ht2040_coex_t; - -/** - * @brief Configuration for WiFi ioctl - * - */ -typedef struct { - union { - wifi_ht2040_coex_t ht2040_coex; /**< Configuration of STA's HT2040 coexist management */ - } data; /**< Configuration of ioctl command */ -} wifi_ioctl_config_t; - #ifdef __cplusplus } #endif diff --git a/components/esp_wifi/lib_esp32 b/components/esp_wifi/lib_esp32 index b8b96f985a..57e1fd11f2 160000 --- a/components/esp_wifi/lib_esp32 +++ b/components/esp_wifi/lib_esp32 @@ -1 +1 @@ -Subproject commit b8b96f985aee155682a2907c6c0f3b693bb43785 +Subproject commit 57e1fd11f2f2e17c39ce9612e5fd87d687bcf133 diff --git a/components/esp_wifi/src/crypto_ops.c b/components/esp_wifi/src/crypto_ops.c new file mode 100644 index 0000000000..fdef5ca57e --- /dev/null +++ b/components/esp_wifi/src/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 "crypto/aes_wrap.h" +#include "crypto/sha256.h" +#include "crypto/crypto.h" +#include "crypto/md5.h" +#include "crypto/sha1.h" +#include "crypto/aes.h" +#include "crypto/dh_group5.h" +#include "esp_wifi_crypto_types.h" +/* + * 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/esp_wifi/src/mesh_event.c b/components/esp_wifi/src/mesh_event.c index f0b90ae422..52c6cf56f6 100644 --- a/components/esp_wifi/src/mesh_event.c +++ b/components/esp_wifi/src/mesh_event.c @@ -14,24 +14,10 @@ #include #include "esp_event.h" -#include "esp_mesh.h" -/* mesh event callback handler */ -mesh_event_cb_t g_mesh_event_cb = NULL; +ESP_EVENT_DEFINE_BASE(MESH_EVENT); -esp_err_t esp_event_mesh_hook(system_event_t *event) +esp_err_t esp_mesh_send_event_internal(int32_t event_id, void* event_data, size_t event_data_size) { - if (event->event_id == SYSTEM_EVENT_STA_GOT_IP || event->event_id == SYSTEM_EVENT_STA_LOST_IP) { - if (g_mesh_event_cb) { - mesh_event_t mevent; - if (event->event_id == SYSTEM_EVENT_STA_GOT_IP) { - mevent.id = MESH_EVENT_ROOT_GOT_IP; - memcpy(&mevent.info.got_ip, &event->event_info.got_ip, sizeof(system_event_sta_got_ip_t)); - } else { - mevent.id = MESH_EVENT_ROOT_LOST_IP; - } - g_mesh_event_cb(mevent); - } - } - return ESP_OK; + return esp_event_post(MESH_EVENT, event_id, event_data, event_data_size, 0); } diff --git a/components/esp_wifi/src/smartconfig.c b/components/esp_wifi/src/smartconfig.c new file mode 100644 index 0000000000..a4138c89bb --- /dev/null +++ b/components/esp_wifi/src/smartconfig.c @@ -0,0 +1,77 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include "esp_log.h" +#include "esp_event_base.h" +#include "esp_private/wifi.h" +#include "esp_smartconfig.h" +#include "smartconfig_ack.h" + +/* Smartconfig events definitions */ +ESP_EVENT_DEFINE_BASE(SC_EVENT); + +static const char *TAG = "smartconfig"; + +static void handler_got_ssid_passwd(void *arg, esp_event_base_t base, int32_t event_id, void *data) +{ + smartconfig_event_got_ssid_pswd_t *evt = (smartconfig_event_got_ssid_pswd_t *)data; + uint8_t ssid[33] = { 0 }; + uint8_t password[65] = { 0 }; + uint8_t cellphone_ip[4]; + esp_err_t err = ESP_OK; + + memcpy(ssid, evt->ssid, sizeof(evt->ssid)); + memcpy(password, evt->password, sizeof(evt->password)); + memcpy(cellphone_ip, evt->cellphone_ip, sizeof(evt->cellphone_ip)); + + ESP_LOGD(TAG, "SSID:%s", ssid); + ESP_LOGD(TAG, "PASSWORD:%s", password); + ESP_LOGD(TAG, "Phone ip: %d.%d.%d.%d\n", cellphone_ip[0], cellphone_ip[1], cellphone_ip[2], cellphone_ip[3]); + + err = sc_send_ack_start(evt->type, evt->token, evt->cellphone_ip); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Send smartconfig ACK error: %d", err); + } +} + +esp_err_t esp_smartconfig_start(const smartconfig_start_config_t *config) +{ + esp_err_t err = ESP_OK; + + err = esp_event_handler_register(SC_EVENT, SC_EVENT_GOT_SSID_PSWD, handler_got_ssid_passwd, NULL); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Register smartconfig default event handler fail!"); + return err; + } + + err = esp_smartconfig_internal_start(config); + if (err != ESP_OK) { + esp_event_handler_unregister(SC_EVENT, SC_EVENT_GOT_SSID_PSWD, handler_got_ssid_passwd); + } + return err; +} + +esp_err_t esp_smartconfig_stop(void) +{ + esp_err_t err = ESP_OK; + + err = esp_smartconfig_internal_stop(); + if (err == ESP_OK) { + sc_send_ack_stop(); + esp_event_handler_unregister(SC_EVENT, SC_EVENT_GOT_SSID_PSWD, handler_got_ssid_passwd); + } + return err; +} \ No newline at end of file diff --git a/components/esp_wifi/src/wifi_init.c b/components/esp_wifi/src/wifi_init.c index a4b4d00531..d34de7b68c 100644 --- a/components/esp_wifi/src/wifi_init.c +++ b/components/esp_wifi/src/wifi_init.c @@ -18,6 +18,15 @@ #include "esp_private/wifi.h" #include "esp_pm.h" #include "soc/rtc.h" +#include "esp_wpa.h" + +#if (CONFIG_ESP32_WIFI_RX_BA_WIN > CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM) +#error "WiFi configuration check: WARNING, WIFI_RX_BA_WIN should not be larger than WIFI_DYNAMIC_RX_BUFFER_NUM!" +#endif + +#if (CONFIG_ESP32_WIFI_RX_BA_WIN > (CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM << 1)) +#error "WiFi configuration check: WARNING, WIFI_RX_BA_WIN should not be larger than double of the WIFI_STATIC_RX_BUFFER_NUM!" +#endif ESP_EVENT_DEFINE_BASE(WIFI_EVENT); @@ -110,6 +119,17 @@ esp_err_t esp_wifi_init(const wifi_init_config_t *config) #if CONFIG_IDF_TARGET_ESP32 s_wifi_mac_time_update_cb = esp_wifi_internal_update_mac_time; #endif + + result = esp_supplicant_init(); + if (result != ESP_OK) { + ESP_LOGE(TAG, "Failed to init supplicant (0x%x)", result); + esp_err_t deinit_ret = esp_wifi_deinit(); + if (deinit_ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to deinit Wi-Fi (0x%x)", deinit_ret); + } + + return result; + } } return result; diff --git a/components/esp_wifi/test/CMakeLists.txt b/components/esp_wifi/test/CMakeLists.txt index 6f9211dcc6..e7cf4b12c8 100644 --- a/components/esp_wifi/test/CMakeLists.txt +++ b/components/esp_wifi/test/CMakeLists.txt @@ -1,9 +1,6 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ". ${CMAKE_CURRENT_BINARY_DIR}") - -set(COMPONENT_REQUIRES unity test_utils nvs_flash ulp esp_common) - -register_component() +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." "${CMAKE_CURRENT_BINARY_DIR}" + REQUIRES unity test_utils nvs_flash ulp esp_common) idf_component_get_property(esp_wifi_dir esp_wifi COMPONENT_DIR) @@ -19,6 +16,16 @@ string(SUBSTRING "${WIFI_CRYPTO_MD5}" 0 7 WIFI_CRYPTO_MD5) file(MD5 ${esp_wifi_dir}/include/esp_coexist_adapter.h COEX_ADAPTER_MD5) string(SUBSTRING "${COEX_ADAPTER_MD5}" 0 7 COEX_ADAPTER_MD5) +# Calculate MD5 value of header file esp_wifi_types.h +file(MD5 ${esp_wifi_dir}/include/esp_wifi_types.h WIFI_TYPE_MD5) +string(SUBSTRING "${WIFI_TYPE_MD5}" 0 7 WIFI_TYPE_MD5) + +# Calculate MD5 value of header file esp_wifi.h +file(MD5 ${esp_wifi_dir}/include/esp_wifi.h WIFI_ESP_WIFI_MD5) +string(SUBSTRING "${WIFI_ESP_WIFI_MD5}" 0 7 WIFI_ESP_WIFI_MD5) + add_definitions(-DWIFI_OS_ADAPTER_MD5=\"${WIFI_OS_ADAPTER_MD5}\") add_definitions(-DWIFI_CRYPTO_MD5=\"${WIFI_CRYPTO_MD5}\") add_definitions(-DCOEX_ADAPTER_MD5=\"${COEX_ADAPTER_MD5}\") +add_definitions(-DWIFI_TYPE_MD5=\"${WIFI_TYPE_MD5}\") +add_definitions(-DWIFI_ESP_WIFI_MD5=\"${WIFI_ESP_WIFI_MD5}\") diff --git a/components/esp_wifi/test/component.mk b/components/esp_wifi/test/component.mk index 88f939f810..7dbb988dd0 100644 --- a/components/esp_wifi/test/component.mk +++ b/components/esp_wifi/test/component.mk @@ -17,3 +17,11 @@ CFLAGS+=-DWIFI_CRYPTO_MD5=$(WIFI_CRYPTO_MD5_VAL) # Calculate MD5 value of header file esp_coexist_adapter.h COEX_ADAPTER_MD5_VAL=\"$(shell md5sum $(IDF_PATH)/components/esp_wifi/include/esp_coexist_adapter.h | cut -c 1-7)\" CFLAGS+=-DCOEX_ADAPTER_MD5=$(COEX_ADAPTER_MD5_VAL) + +# Calculate MD5 value of header file esp_wifi_types.h +WIFI_TYPE_MD5_VAL=\"$(shell md5sum $(IDF_PATH)/components/esp_wifi/include/esp_wifi_types.h | cut -c 1-7)\" +CFLAGS+=-DWIFI_TYPE_MD5=$(WIFI_TYPE_MD5_VAL) + +# Calculate MD5 value of header file esp_wifi.h +WIFI_ESP_WIFI_MD5_VAL=\"$(shell md5sum $(IDF_PATH)/components/esp_wifi/include/esp_wifi.h | cut -c 1-7)\" +CFLAGS+=-DWIFI_ESP_WIFI_MD5=$(WIFI_ESP_WIFI_MD5_VAL) diff --git a/components/esp_wifi/test/test_header_files_md5.c b/components/esp_wifi/test/test_header_files_md5.c index cccf7028a6..eb431051ac 100644 --- a/components/esp_wifi/test/test_header_files_md5.c +++ b/components/esp_wifi/test/test_header_files_md5.c @@ -12,17 +12,17 @@ TEST_CASE("wifi os adapter MD5","[wifi]") { const char *test_wifi_os_funcs_md5 = WIFI_OS_ADAPTER_MD5; - ESP_LOGI(TAG, "test wifi os adapter MD5..."); + ESP_LOGI(TAG, "test esp_wifi_os_adapter.h MD5..."); TEST_ESP_OK(esp_wifi_internal_osi_funcs_md5_check(test_wifi_os_funcs_md5)); ESP_LOGI(TAG, "test passed..."); } TEST_CASE("wifi crypto types MD5","[wifi]") -{ +{ const char *test_wifi_crypto_funcs_md5 = WIFI_CRYPTO_MD5; - ESP_LOGI(TAG, "test wifi crypto adapter MD5..."); + ESP_LOGI(TAG, "test esp_wifi_crypto_types.h MD5..."); TEST_ESP_OK(esp_wifi_internal_crypto_funcs_md5_check(test_wifi_crypto_funcs_md5)); ESP_LOGI(TAG, "test passed..."); @@ -32,8 +32,28 @@ TEST_CASE("coexist adapter MD5","[coex]") { const char *test_coex_adapter_funcs_md5 = COEX_ADAPTER_MD5; - ESP_LOGI(TAG, "test coexist adapter MD5..."); + ESP_LOGI(TAG, "test esp_coexist_adapter.h MD5..."); TEST_ESP_OK(esp_coex_adapter_funcs_md5_check(test_coex_adapter_funcs_md5)); ESP_LOGI(TAG, "test passed..."); } + +TEST_CASE("wifi type MD5","[wifi]") +{ + const char *test_wifi_type_md5 = WIFI_TYPE_MD5; + + ESP_LOGI(TAG, "test esp_wifi_types.h MD5..."); + TEST_ESP_OK(esp_wifi_internal_wifi_type_md5_check(test_wifi_type_md5)); + + ESP_LOGI(TAG, "test passed..."); +} + +TEST_CASE("esp wifi MD5","[wifi]") +{ + const char *test_esp_wifi_md5 = WIFI_ESP_WIFI_MD5; + + ESP_LOGI(TAG, "test esp_wifi.h MD5..."); + TEST_ESP_OK(esp_wifi_internal_esp_wifi_md5_check(test_esp_wifi_md5)); + + ESP_LOGI(TAG, "test passed..."); +} diff --git a/components/esp_wifi/test/test_wifi_lib_git_commit.c b/components/esp_wifi/test/test_wifi_lib_git_commit.c deleted file mode 100644 index f8e6f3940d..0000000000 --- a/components/esp_wifi/test/test_wifi_lib_git_commit.c +++ /dev/null @@ -1,12 +0,0 @@ -/* - Tests for the Wi-Fi -*/ -#include "unity.h" -#include "esp_log.h" -#include "esp_private/wifi.h" - -TEST_CASE("wifi lib git commit id","[wifi]") -{ - TEST_ESP_OK( esp_wifi_internal_git_commit_id_check() ); -} - diff --git a/components/espcoredump/CMakeLists.txt b/components/espcoredump/CMakeLists.txt index 8ef4c1ce70..aa3b32eeac 100644 --- a/components/espcoredump/CMakeLists.txt +++ b/components/espcoredump/CMakeLists.txt @@ -1,10 +1,8 @@ -set(COMPONENT_PRIV_INCLUDEDIRS "include_core_dump") -set(COMPONENT_ADD_INCLUDEDIRS "include") -set(COMPONENT_PRIV_REQUIRES spi_flash soc) -set(COMPONENT_ADD_LDFRAGMENTS linker.lf) -set(COMPONENT_SRCS "src/core_dump_common.c" - "src/core_dump_flash.c" - "src/core_dump_port.c" - "src/core_dump_uart.c") - -register_component() +idf_component_register(SRCS "src/core_dump_common.c" + "src/core_dump_flash.c" + "src/core_dump_port.c" + "src/core_dump_uart.c" + INCLUDE_DIRS "include" + PRIV_INCLUDE_DIRS "include_core_dump" + LDFRAGMENTS linker.lf + PRIV_REQUIRES spi_flash soc) diff --git a/components/espcoredump/src/core_dump_port.c b/components/espcoredump/src/core_dump_port.c index 3e3414a4cc..2ac1b6482b 100644 --- a/components/espcoredump/src/core_dump_port.c +++ b/components/espcoredump/src/core_dump_port.c @@ -13,7 +13,7 @@ // limitations under the License. #include #include -#include "esp_debug_helpers.h" +#include "soc/soc_memory_layout.h" #include "esp_core_dump_priv.h" const static DRAM_ATTR char TAG[] __attribute__((unused)) = "esp_core_dump_port"; diff --git a/components/espcoredump/test/CMakeLists.txt b/components/espcoredump/test/CMakeLists.txt index 6704c238b9..c000ba4e57 100644 --- a/components/espcoredump/test/CMakeLists.txt +++ b/components/espcoredump/test/CMakeLists.txt @@ -1,8 +1,7 @@ if(TESTS_ALL EQUAL 1) message("not linking coredump test from CI.") else() - set(COMPONENT_SRCDIRS ".") - set(COMPONENT_ADD_INCLUDEDIRS ".") - set(COMPONENT_REQUIRES unity nvs_flash) - register_component() + idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity nvs_flash) endif() \ No newline at end of file diff --git a/components/esptool_py/CMakeLists.txt b/components/esptool_py/CMakeLists.txt index 09764ccf05..d30210531f 100644 --- a/components/esptool_py/CMakeLists.txt +++ b/components/esptool_py/CMakeLists.txt @@ -1,39 +1,81 @@ -set(COMPONENT_PRIV_REQUIRES bootloader) -register_component() +idf_component_register(REQUIRES bootloader) -string(REPLACE ";" " " ESPTOOLPY_FLASH_PROJECT_OPTIONS "${ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS}") -set(ESPTOOLPY_FLASH_PROJECT_OPTIONS - "${ESPTOOLPY_FLASH_PROJECT_OPTIONS}" - ) +if(NOT BOOTLOADER_BUILD) + string(REPLACE ";" " " ESPTOOLPY_FLASH_PROJECT_OPTIONS "${ESPTOOLPY_FLASH_OPTIONS}") + set(ESPTOOLPY_FLASH_PROJECT_OPTIONS + "${ESPTOOLPY_FLASH_PROJECT_OPTIONS}" + ) -if(CONFIG_SECURE_BOOT_ENABLED) - set(ESPTOOLPY_FLASH_PROJECT_OPTIONS "") + if(CONFIG_SECURE_BOOT_ENABLED) + set(ESPTOOLPY_FLASH_PROJECT_OPTIONS "") + endif() + + # FLASH_PROJECT_ARGS, FLASH_PROJECT_ARGS_JSON, FLASH_PROJECT_ARGS_ENTRY_JSON + # are used in the flasher args input files (flash_project_args.in, flasher_args.json.in) + idf_component_get_property(FLASH_PROJECT_ARGS ${COMPONENT_NAME} + FLASH_PROJECT_ARGS GENERATOR_EXPRESSION) + idf_component_get_property(FLASH_PROJECT_ARGS_JSON ${COMPONENT_NAME} + FLASH_PROJECT_ARGS_JSON GENERATOR_EXPRESSION) + idf_component_get_property(FLASH_PROJECT_ARGS_ENTRY_JSON ${COMPONENT_NAME} + FLASH_PROJECT_ARGS_ENTRY_JSON GENERATOR_EXPRESSION) + + # Generate the flash project args and the flasher args json file using the accumulated values + # from esptool_py_flash_project_args calls. The file is first configured using configure_file() for all variable values, + # and then generated using file(GENERATE... for generator expressions. + configure_file(${COMPONENT_DIR}/flash_project_args.in + ${CMAKE_CURRENT_BINARY_DIR}/flash_project_args.in) + + file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/flash_project_args.in2 + INPUT ${CMAKE_CURRENT_BINARY_DIR}/flash_project_args.in) + file(GENERATE OUTPUT ${CMAKE_BINARY_DIR}/flash_project_args + INPUT ${CMAKE_CURRENT_BINARY_DIR}/flash_project_args.in2) + + if(CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT) + configure_file(${COMPONENT_DIR}/flash_encrypted_project_args.in + ${CMAKE_CURRENT_BINARY_DIR}/flash_encrypted_project_args.in) + + file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/flash_encrypted_project_args.in2 + INPUT ${CMAKE_CURRENT_BINARY_DIR}/flash_encrypted_project_args.in) + file(GENERATE OUTPUT ${CMAKE_BINARY_DIR}/flash_encrypted_project_args + INPUT ${CMAKE_CURRENT_BINARY_DIR}/flash_encrypted_project_args.in2) + endif() + + configure_file(${COMPONENT_DIR}/flasher_args.json.in + ${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in) + + file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in2 + INPUT ${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in) + file(GENERATE OUTPUT ${CMAKE_BINARY_DIR}/flasher_args.json + INPUT ${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in2) + + set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES + "${CMAKE_CURRENT_BINARY_DIR}/flash_project_args.in" + "${CMAKE_CURRENT_BINARY_DIR}/flash_project_args.in2" + "${CMAKE_BINARY_DIR}/flash_project_args" + "${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in" + "${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in2" + "${CMAKE_BINARY_DIR}/flasher_args.json") + + idf_build_get_property(build_dir BUILD_DIR) + partition_table_get_partition_info(app_partition_offset "--partition-boot-default" "offset") + esptool_py_flash_project_args(app ${app_partition_offset} ${build_dir}/${PROJECT_BIN} FLASH_IN_PROJECT) + + if(CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT) + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/flash_encrypted_app_args.in "--encrypt ${app_partition_offset} ${PROJECT_BIN}") + esptool_py_flash_project_args(encrypted_app ${app_partition_offset} ${build_dir}/${PROJECT_BIN} + FLASH_FILE_TEMPLATE ${CMAKE_CURRENT_BINARY_DIR}/flash_encrypted_app_args.in) + endif() + + add_dependencies(flash partition_table) + + # If anti-rollback option is set then factory partition should not be in Partition Table. + # In this case, should be used the partition table with two ota app without the factory. + partition_table_get_partition_info(factory_offset "--partition-type app --partition-subtype factory" "offset") + if(CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK AND factory_offset) + fail_at_build_time(check_table_contents + "ERROR: Anti-rollback option is enabled. Partition table should consist of two ota app without factory partition.") + add_dependencies(app check_table_contents) + endif() endif() -# Generate the flash project args and the flasher args json file using the accumulated values -# from esptool_py_flash_project_args calls. The file is first configured using configure_file() for all variable values, -# and then generated using file(GENERATE... for generator expressions. -configure_file(${COMPONENT_DIR}/flash_project_args.in - ${CMAKE_CURRENT_BINARY_DIR}/flash_project_args.in) - -file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/flash_project_args.in2 - INPUT ${CMAKE_CURRENT_BINARY_DIR}/flash_project_args.in) -file(GENERATE OUTPUT ${CMAKE_BINARY_DIR}/flash_project_args - INPUT ${CMAKE_CURRENT_BINARY_DIR}/flash_project_args.in2) - -configure_file(${COMPONENT_DIR}/flasher_args.json.in - ${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in) - -file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in2 - INPUT ${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in) -file(GENERATE OUTPUT ${CMAKE_BINARY_DIR}/flasher_args.json - INPUT ${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in2) - -set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES - "${CMAKE_CURRENT_BINARY_DIR}/flash_project_args.in" - "${CMAKE_CURRENT_BINARY_DIR}/flash_project_args.in2" - "${CMAKE_BINARY_DIR}/flash_project_args" - "${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in" - "${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json.in2" - "${CMAKE_BINARY_DIR}/flasher_args.json") diff --git a/components/esptool_py/Kconfig.projbuild b/components/esptool_py/Kconfig.projbuild index 95919bd007..e11f9c7d50 100644 --- a/components/esptool_py/Kconfig.projbuild +++ b/components/esptool_py/Kconfig.projbuild @@ -135,8 +135,9 @@ menu "Serial flasher config" bool "Detect flash size when flashing bootloader" default y help - If this option is set, 'make flash' targets will automatically detect - the flash size and update the bootloader image when flashing. + If this option is set, flashing the project will automatically detect + the flash size of the target chip and update the bootloader image + before it is flashed. choice ESPTOOLPY_BEFORE prompt "Before flashing" @@ -181,11 +182,11 @@ menu "Serial flasher config" default "no_reset" if ESPTOOLPY_AFTER_NORESET choice ESPTOOLPY_MONITOR_BAUD - prompt "'make monitor' baud rate" + prompt "'idf.py monitor' baud rate" default ESPTOOLPY_MONITOR_BAUD_115200B help - Baud rate to use when running 'make monitor' to view serial output - from a running chip. + Baud rate to use when running 'idf.py monitor' or 'make monitor' + to view serial output from a running chip. Can override by setting the MONITORBAUD environment variable. diff --git a/components/esptool_py/Makefile.projbuild b/components/esptool_py/Makefile.projbuild index c8aee775e3..8292c06ecd 100644 --- a/components/esptool_py/Makefile.projbuild +++ b/components/esptool_py/Makefile.projbuild @@ -45,6 +45,10 @@ endif ESPTOOLPY_WRITE_FLASH=$(ESPTOOLPY_SERIAL) write_flash $(if $(CONFIG_ESPTOOLPY_COMPRESSED),-z,-u) $(ESPTOOL_WRITE_FLASH_OPTIONS) +ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT +ESPTOOLPY_WRITE_FLASH_ENCRYPT=$(ESPTOOLPY_SERIAL) write_flash --encrypt $(if $(CONFIG_ESPTOOLPY_COMPRESSED),-z,-u) $(ESPTOOL_WRITE_FLASH_OPTIONS) +endif + ESPTOOL_ALL_FLASH_ARGS += $(APP_OFFSET) $(APP_BIN) ifdef CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES @@ -62,6 +66,19 @@ APP_BIN_UNSIGNED ?= $(APP_BIN) $(APP_BIN_UNSIGNED): $(APP_ELF) $(ESPTOOLPY_SRC) | check_python_dependencies $(ESPTOOLPY) elf2image $(ESPTOOL_FLASH_OPTIONS) $(ESPTOOL_ELF2IMAGE_OPTIONS) -o $@ $< +ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT +encrypted-flash: all_binaries $(ESPTOOLPY_SRC) $(call prereq_if_explicit,erase_flash) partition_table_get_info | check_python_dependencies + @echo "Flashing binaries to serial port $(ESPPORT) (app at offset $(APP_OFFSET))..." +ifdef CONFIG_SECURE_BOOT_ENABLED + @echo "(Secure boot enabled, so bootloader not flashed automatically. See 'make bootloader' output)" +endif + $(ESPTOOLPY_WRITE_FLASH_ENCRYPT) $(ESPTOOL_ALL_FLASH_ARGS) +else +encrypted-flash: + @echo "The command is supported only in FLASH ENCRYPTION DEVELOPMENT MODE" + @exit 1 +endif + flash: all_binaries $(ESPTOOLPY_SRC) $(call prereq_if_explicit,erase_flash) partition_table_get_info | check_python_dependencies @echo "Flashing binaries to serial port $(ESPPORT) (app at offset $(APP_OFFSET))..." ifdef CONFIG_SECURE_BOOT_ENABLED @@ -73,6 +90,16 @@ app-flash: $(APP_BIN) $(ESPTOOLPY_SRC) $(call prereq_if_explicit,erase_flash) pa @echo "Flashing app to serial port $(ESPPORT), offset $(APP_OFFSET)..." $(ESPTOOLPY_WRITE_FLASH) $(APP_OFFSET) $(APP_BIN) +ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT +encrypted-app-flash: $(APP_BIN) $(ESPTOOLPY_SRC) $(call prereq_if_explicit,erase_flash) partition_table_get_info | check_python_dependencies + @echo "Flashing encrypted app binary to serial port $(ESPPORT) (app at offset $(APP_OFFSET))..." + $(ESPTOOLPY_WRITE_FLASH_ENCRYPT) $(APP_OFFSET) $(APP_BIN) +else +encrypted-app-flash: + @echo "The command is supported only in FLASH ENCRYPTION DEVELOPMENT MODE" + @exit 1 +endif + # Submodules normally added in component.mk, but can be added # at the project level as long as qualified path COMPONENT_SUBMODULES += $(COMPONENT_PATH)/esptool diff --git a/components/esptool_py/flash_encrypted_project_args.in b/components/esptool_py/flash_encrypted_project_args.in new file mode 100644 index 0000000000..db16bc6cdf --- /dev/null +++ b/components/esptool_py/flash_encrypted_project_args.in @@ -0,0 +1,3 @@ +--encrypt ${ESPTOOLPY_FLASH_PROJECT_OPTIONS} +$, +> diff --git a/components/esptool_py/flash_project_args.in b/components/esptool_py/flash_project_args.in index 640626af17..b6e3f8f9ee 100644 --- a/components/esptool_py/flash_project_args.in +++ b/components/esptool_py/flash_project_args.in @@ -1,3 +1,3 @@ ${ESPTOOLPY_FLASH_PROJECT_OPTIONS} -$, +$ \ No newline at end of file diff --git a/components/esptool_py/flasher_args.json.in b/components/esptool_py/flasher_args.json.in index aa3aad2ccb..ca8693cc75 100644 --- a/components/esptool_py/flasher_args.json.in +++ b/components/esptool_py/flasher_args.json.in @@ -8,10 +8,10 @@ "flash_freq": "${ESPFLASHFREQ}" }, "flash_files" : { - $,, + $ }, - $,, + $, "extra_esptool_args" : { "after" : "${ESPTOOLPY_AFTER}", diff --git a/components/esptool_py/project_include.cmake b/components/esptool_py/project_include.cmake index dd3659dd59..3c0181cf4d 100644 --- a/components/esptool_py/project_include.cmake +++ b/components/esptool_py/project_include.cmake @@ -31,7 +31,7 @@ else() set(ESPTOOLPY_COMPRESSED_OPT -u) endif() -set(ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS +set(ESPTOOLPY_FLASH_OPTIONS --flash_mode ${ESPFLASHMODE} --flash_freq ${ESPFLASHFREQ} --flash_size ${ESPFLASHSIZE} @@ -40,19 +40,18 @@ set(ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS # String for printing flash command string(REPLACE ";" " " ESPTOOLPY_WRITE_FLASH_STR "${ESPTOOLPY} --port (PORT) --baud (BAUD) --before ${ESPTOOLPY_BEFORE} --after ${ESPTOOLPY_AFTER} " - "write_flash ${ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS} ${ESPTOOLPY_EXTRA_FLASH_OPTIONS} ${ESPTOOLPY_COMPRESSED_OPT}") - -if(CONFIG_SECURE_BOOT_ENABLED AND - NOT CONFIG_SECURE_BOOT_ALLOW_SHORT_APP_PARTITION AND - NOT BOOTLOADER_BUILD) - set(ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS - ${ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS} --secure-pad) -endif() + "write_flash ${ESPTOOLPY_FLASH_OPTIONS} ${ESPTOOLPY_EXTRA_FLASH_OPTIONS} ${ESPTOOLPY_COMPRESSED_OPT}") if(NOT BOOTLOADER_BUILD) # set(ESPTOOLPY_ELF2IMAGE_OPTIONS --elf-sha256-offset 0xb0) endif() +if(CONFIG_SECURE_BOOT_ENABLED AND + NOT CONFIG_SECURE_BOOT_ALLOW_SHORT_APP_PARTITION + AND NOT BOOTLOADER_BUILD) + set(ESPTOOLPY_ELF2IMAGE_OPTIONS ${ESPTOOLPY_ELF2IMAGE_OPTIONS} --secure-pad) +endif() + if(CONFIG_ESPTOOLPY_FLASHSIZE_DETECT) # Set ESPFLASHSIZE to 'detect' *after* elf2image options are generated, # as elf2image can't have 'detect' as an option... @@ -75,46 +74,54 @@ set(PROJECT_BIN "${elf_name}.bin") # # Add 'app.bin' target - generates with elf2image # -add_custom_command(OUTPUT "${build_dir}/.app_hash" - COMMAND ${ESPTOOLPY} elf2image ${ESPTOOLPY_ELF2IMAGE_FLASH_OPTIONS} ${ESPTOOLPY_ELF2IMAGE_OPTIONS} +add_custom_command(OUTPUT "${build_dir}/.bin_timestamp" + COMMAND ${ESPTOOLPY} elf2image ${ESPTOOLPY_FLASH_OPTIONS} ${ESPTOOLPY_ELF2IMAGE_OPTIONS} -o "${build_dir}/${unsigned_project_binary}" "${elf}" - COMMAND ${CMAKE_COMMAND} -E md5sum "${build_dir}/${unsigned_project_binary}" > "${build_dir}/.app_hash" + COMMAND ${CMAKE_COMMAND} -E echo "Generated ${build_dir}/${unsigned_project_binary}" + COMMAND ${CMAKE_COMMAND} -E md5sum "${build_dir}/${unsigned_project_binary}" > "${build_dir}/.bin_timestamp" DEPENDS ${elf} VERBATIM WORKING_DIRECTORY ${build_dir} + COMMENT "Generating binary image from built executable" ) -add_custom_target(gen_project_binary DEPENDS "${build_dir}/.app_hash") +add_custom_target(gen_project_binary DEPENDS "${build_dir}/.bin_timestamp") -if(NOT BOOTLOADER_BUILD AND - CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) +set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES + "${build_dir}/${unsigned_project_binary}" + ) - # for locally signed secure boot image, add a signing step to get from unsigned app to signed app - add_custom_command(OUTPUT "${build_dir}/.signed_app_hash" - COMMAND ${ESPSECUREPY} sign_data --keyfile ${secure_boot_signing_key} - -o "${build_dir}/${PROJECT_BIN}" "${build_dir}/${unsigned_project_binary}" - COMMAND ${CMAKE_COMMAND} -E md5sum "${build_dir}/${PROJECT_BIN}" > "${build_dir}/.signed_app_hash" - DEPENDS "${build_dir}/.app_hash" - VERBATIM - ) - add_custom_target(gen_signed_project_binary DEPENDS "${build_dir}/.signed_app_hash") - add_dependencies(gen_project_binary gen_signed_project_binary) -endif() +add_custom_target(app ALL DEPENDS gen_project_binary) -if(NOT BOOTLOADER_BUILD) - add_custom_target(app ALL DEPENDS gen_project_binary) -else() - add_custom_target(bootloader ALL DEPENDS gen_project_binary) -endif() +if(NOT BOOTLOADER_BUILD AND CONFIG_SECURE_SIGNED_APPS) + if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) + # for locally signed secure boot image, add a signing step to get from unsigned app to signed app + add_custom_command(OUTPUT "${build_dir}/.signed_bin_timestamp" + COMMAND ${ESPSECUREPY} sign_data --keyfile ${secure_boot_signing_key} + -o "${build_dir}/${PROJECT_BIN}" "${build_dir}/${unsigned_project_binary}" + COMMAND ${CMAKE_COMMAND} -E echo "Generated signed binary image ${build_dir}/${PROJECT_BIN}" + "from ${build_dir}/${unsigned_project_binary}" + COMMAND ${CMAKE_COMMAND} -E md5sum "${build_dir}/${PROJECT_BIN}" > "${build_dir}/.signed_bin_timestamp" + DEPENDS "${build_dir}/.bin_timestamp" + VERBATIM + COMMENT "Generating signed binary image" + ) + add_custom_target(gen_signed_project_binary DEPENDS "${build_dir}/.signed_bin_timestamp") + add_dependencies(gen_project_binary gen_signed_project_binary) -if(NOT BOOTLOADER_BUILD AND - CONFIG_SECURE_BOOT_ENABLED AND - NOT CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) - add_custom_command(TARGET app POST_BUILD - COMMAND ${CMAKE_COMMAND} -E echo - "App built but not signed. Sign app before flashing" - COMMAND ${CMAKE_COMMAND} -E echo - "\t${ESPSECUREPY} sign_data --keyfile KEYFILE ${build_dir}/${elf_bin}" - VERBATIM) + set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES + "${build_dir}/${PROJECT_BIN}" + ) + else() + string(REPLACE ";" " " espsecurepy "${ESPSECUREPY}") + add_custom_command(TARGET app POST_BUILD + COMMAND ${CMAKE_COMMAND} -E echo + "App built but not signed. Sign app before flashing" + COMMAND ${CMAKE_COMMAND} -E echo + "\t${espsecurepy} sign_data --keyfile KEYFILE ${build_dir}/${PROJECT_BIN}" + VERBATIM) + endif() endif() # @@ -136,59 +143,67 @@ endfunction() esptool_py_custom_target(flash project "app;partition_table;bootloader") esptool_py_custom_target(app-flash app "app") -esptool_py_custom_target(bootloader-flash bootloader "bootloader") -add_custom_target(flash_project_args_target) +if(CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT) + esptool_py_custom_target(encrypted-flash encrypted_project "app;partition_table;bootloader") + esptool_py_custom_target(encrypted-app-flash encrypted_app "app") +endif() # esptool_py_flash_project_args # -# Add file to the flasher args list, to be flashed at a particular offset +# Add file to the flasher args list, to be flashed at a particular offset. +# +# When a template FLASH_FILE_TEMPLATE is given, the variables OFFSET and IMAGE +# hold the value of arguments offset and image, respectively. function(esptool_py_flash_project_args entry offset image) set(options FLASH_IN_PROJECT) # flash the image when flashing the project set(single_value FLASH_FILE_TEMPLATE) # template file to use to be able to # flash the image individually using esptool cmake_parse_arguments(_ "${options}" "${single_value}" "" "${ARGN}") - idf_build_get_property(build_dir BUILD_DIR) - get_property(flash_project_entries TARGET flash_project_args_target PROPERTY FLASH_PROJECT_ENTRIES) - if(${entry} IN_LIST flash_project_entries) message(FATAL_ERROR "entry '${entry}' has already been added to flash project entries") endif() - list(APPEND flash_project_entries "${entry}") - set_property(TARGET flash_project_args_target PROPERTY FLASH_PROJECT_ENTRIES "${flash_project_entries}") + idf_component_set_property(esptool_py FLASH_PROJECT_ENTRIES "${entry}" APPEND) - file(RELATIVE_PATH image ${CMAKE_BINARY_DIR} ${image}) + idf_build_get_property(build_dir BUILD_DIR) + file(RELATIVE_PATH image ${build_dir} ${image}) # Generate the standalone flash file to flash the image individually using esptool set(entry_flash_args ${build_dir}/flash_${entry}_args) if(NOT __FLASH_FILE_TEMPLATE) file(GENERATE OUTPUT ${entry_flash_args} CONTENT "${offset} ${image}") else() - get_filename_component(template "${__FLASH_FILE_TEMPLATE}" ABSOLUTE) - file(GENERATE OUTPUT ${entry_flash_args} INPUT ${template}) + set(OFFSET ${offset}) + set(IMAGE ${image}) + + get_filename_component(template_in "${__FLASH_FILE_TEMPLATE}" ABSOLUTE) + get_filename_component(template_name "${template_in}" NAME) + set(template_partial "${CMAKE_CURRENT_BINARY_DIR}/${template_name}.in2") + + configure_file("${template_in}" "${template_partial}") + file(GENERATE OUTPUT ${entry_flash_args} INPUT "${template_partial}") + set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + APPEND PROPERTY + ADDITIONAL_MAKE_CLEAN_FILES "${template_partial}") + unset(OFFSET) + unset(IMAGE) endif() set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${entry_flash_args}) # Generate standalone entries in the flasher args json file - get_property(flash_project_args_entry_json TARGET - flash_project_args_target PROPERTY FLASH_PROJECT_ARGS_ENTRY_JSON) - list(APPEND flash_project_args_entry_json - "\"${entry}\" : { \"offset\" : \"${offset}\", \"file\" : \"${image}\" }") - set_property(TARGET flash_project_args_target - PROPERTY FLASH_PROJECT_ARGS_ENTRY_JSON "${flash_project_args_entry_json}") + idf_component_set_property(esptool_py FLASH_PROJECT_ARGS_ENTRY_JSON + "\"${entry}\" : { \"offset\" : \"${offset}\", \"file\" : \"${image}\" }" APPEND) # Generate entries in the flasher args json file if(__FLASH_IN_PROJECT) - get_property(flash_project_args TARGET flash_project_args_target PROPERTY FLASH_PROJECT_ARGS) - list(APPEND flash_project_args "${offset} ${image}") - set_property(TARGET flash_project_args_target PROPERTY FLASH_PROJECT_ARGS "${flash_project_args}") + idf_component_set_property(esptool_py FLASH_PROJECT_ARGS + "${offset} ${image}" APPEND) - get_property(flash_project_args_json TARGET flash_project_args_target PROPERTY FLASH_PROJECT_ARGS_JSON) - list(APPEND flash_project_args_json "\"${offset}\" : \"${image}\"") - set_property(TARGET flash_project_args_target PROPERTY FLASH_PROJECT_ARGS_JSON "${flash_project_args_json}") + idf_component_set_property(esptool_py FLASH_PROJECT_ARGS_JSON + "\"${offset}\" : \"${image}\"" APPEND) endif() endfunction() diff --git a/components/ethernet/CMakeLists.txt b/components/ethernet/CMakeLists.txt deleted file mode 100644 index 8fb148cfe6..0000000000 --- a/components/ethernet/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -if(IDF_TARGET STREQUAL "esp32") - set(COMPONENT_SRCS "emac_dev.c" - "emac_main.c" - "eth_phy/phy_common.c" - "eth_phy/phy_lan8720.c" - "eth_phy/phy_tlk110.c" - "eth_phy/phy_ip101.c") - set(COMPONENT_ADD_INCLUDEDIRS "include") - - set(COMPONENT_REQUIRES) - set(COMPONENT_PRIV_REQUIRES tcpip_adapter esp_event soc) - - register_component() -endif() diff --git a/components/ethernet/Kconfig b/components/ethernet/Kconfig deleted file mode 100644 index 02dcfa4ec3..0000000000 --- a/components/ethernet/Kconfig +++ /dev/null @@ -1,56 +0,0 @@ -menu Ethernet - depends on IDF_TARGET_ESP32 - - config ETH_DMA_RX_BUF_NUM - int "Number of DMA RX buffers" - range 3 20 - default 10 - help - Number of DMA receive buffers. Each buffer is 1600 bytes. - These buffers are allocated dynamically. - More buffers will increase throughput. - If flow ctrl is enabled, make sure this number is larger than 9. - - config ETH_DMA_TX_BUF_NUM - int "Number of DMA TX buffers" - range 3 20 - default 10 - help - Number of DMA transmit buffers. Each buffer is 1600 bytes. - These buffers are allocated dynamically. - More buffers will increase throughput. - - config ETH_EMAC_L2_TO_L3_RX_BUF_MODE - bool "Enable received buffers be copied to Layer3 from Layer2" - default y - help - If this option is selected, a copy of each received buffer will be allocated from the heap - before passing it to the IP Layer (L3). - Which means, the total amount of received buffers is limited by the heap size. - - If this option is not selected, IP layer only uses the pointers to the DMA buffers owned by Ethernet MAC. - When Ethernet MAC doesn't have any available buffers left, it will drop the incoming packets. - - config ETH_CHECK_LINK_STATUS_PERIOD_MS - int "Period (ms) of checking Ethernet linkup status" - range 1000 5000 - default 2000 - help - The emac driver uses an internal timer to check the Ethernet linkup status. - Here you should choose a valid interval time. - - config ETH_EMAC_TASK_PRIORITY - int "EMAC_TASK_PRIORITY" - default 20 - range 3 22 - help - Priority of Ethernet MAC task. - - config ETH_EMAC_TASK_STACK_SIZE - int "Stack Size of EMAC Task" - default 3072 - range 2000 8000 - help - Stack Size of Ethernet MAC task. - -endmenu diff --git a/components/ethernet/component.mk b/components/ethernet/component.mk deleted file mode 100644 index 73bfbab96f..0000000000 --- a/components/ethernet/component.mk +++ /dev/null @@ -1,9 +0,0 @@ -# -# Component Makefile -# - -ifdef CONFIG_IDF_TARGET_ESP32 - COMPONENT_SRCDIRS := . eth_phy -else - COMPONENT_CONFIG_ONLY := 1 -endif diff --git a/components/ethernet/emac_common.h b/components/ethernet/emac_common.h deleted file mode 100644 index e60de6186e..0000000000 --- a/components/ethernet/emac_common.h +++ /dev/null @@ -1,125 +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 _EMAC_COMMON_H_ -#define _EMAC_COMMON_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "esp_eth.h" -#include "emac_dev.h" - -typedef uint32_t emac_sig_t; -typedef uint32_t emac_par_t; - -typedef struct { - emac_sig_t sig; - emac_par_t par; -} emac_event_t; - -enum emac_runtime_status { - EMAC_RUNTIME_NOT_INIT = 0, - EMAC_RUNTIME_INIT, - EMAC_RUNTIME_START, - EMAC_RUNTIME_STOP, -}; - -enum { - SIG_EMAC_RX_UNAVAIL, - SIG_EMAC_TX_DONE, - SIG_EMAC_RX_DONE, - SIG_EMAC_START, - SIG_EMAC_STOP, - SIG_EMAC_CHECK_LINK, - SIG_EMAC_MAX -}; - -struct emac_config_data { - eth_phy_base_t phy_addr; - eth_mode_t mac_mode; - eth_clock_mode_t clock_mode; - struct dma_extended_desc *dma_etx; - uint32_t cur_tx; - uint32_t dirty_tx; - int32_t cnt_tx; - struct dma_extended_desc *dma_erx; - uint32_t cur_rx; - uint32_t dirty_rx; - int32_t cnt_rx; - uint32_t rx_need_poll; - bool phy_link_up; - enum emac_runtime_status emac_status; - uint8_t macaddr[6]; - eth_phy_func phy_init; - eth_tcpip_input_func emac_tcpip_input; - eth_gpio_config_func emac_gpio_config; - eth_phy_check_link_func emac_phy_check_link; - eth_phy_check_init_func emac_phy_check_init; - eth_phy_get_speed_mode_func emac_phy_get_speed_mode; - eth_phy_get_duplex_mode_func emac_phy_get_duplex_mode; - bool emac_flow_ctrl_enable; - bool emac_flow_ctrl_partner_support; - eth_phy_get_partner_pause_enable_func emac_phy_get_partner_pause_enable; - eth_phy_power_enable_func emac_phy_power_enable; - uint32_t reset_timeout_ms; - bool promiscuous_enable; -}; - -enum emac_post_type { - EMAC_POST_ASYNC, - EMAC_POST_SYNC, -}; - -struct emac_post_cmd { - void *cmd; - enum emac_post_type post_type; -}; - -struct emac_tx_cmd { - uint8_t *buf; - uint16_t size; - int8_t err; -}; - -struct emac_open_cmd { - int8_t err; -}; - -struct emac_close_cmd { - int8_t err; -}; - -#define DMA_RX_BUF_NUM CONFIG_ETH_DMA_RX_BUF_NUM -#define DMA_TX_BUF_NUM CONFIG_ETH_DMA_TX_BUF_NUM -#define EMAC_TASK_PRIORITY CONFIG_ETH_EMAC_TASK_PRIORITY -#define EMAC_TASK_STACK_SIZE CONFIG_ETH_EMAC_TASK_STACK_SIZE - -#define DMA_RX_BUF_SIZE 1600 -#define DMA_TX_BUF_SIZE 1600 - -#define FLOW_CONTROL_HIGH_WATERMARK 3 -#define FLOW_CONTROL_LOW_WATERMARK 6 - -#define PHY_LINK_CHECK_NUM 5 - -#define EMAC_CMD_OK 0 -#define EMAC_CMD_FAIL -1 - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/components/ethernet/emac_desc.h b/components/ethernet/emac_desc.h deleted file mode 100644 index f004b6f411..0000000000 --- a/components/ethernet/emac_desc.h +++ /dev/null @@ -1,204 +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 _EMAC_DESC_H_ -#define _EMAC_DESC_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "soc/soc.h" - -#define REG_EMAC_DESC_BASE 0 -#define EMAC_DESC_TDES0_REG (REG_EMAC_DESC_BASE + 0x0000) -#define EMAC_DESC_TX_OWN (BIT(31)) -#define EMAC_DESC_TX_OWN_S 31 -#define EMAC_DESC_INT_COMPL (BIT(30)) -#define EMAC_DESC_INT_COMPL_S 30 -#define EMAC_DESC_LAST_SEGMENT (BIT(29)) -#define EMAC_DESC_LAST_SEGMENT_S 29 -#define EMAC_DESC_FIRST_SEGMENT (BIT(28)) -#define EMAC_DESC_FIRST_SEGMENT_S 28 -#define EMAC_DESC_DIS_CRC (BIT(27)) -#define EMAC_DESC_DIS_CRC_S 27 -#define EMAC_DESC_DIS_PAD (BIT(26)) -#define EMAC_DESC_DIS_PAD_S 26 -#define EMAC_DESC_TX_TS_EN (BIT(25)) -#define EMAC_DESC_TX_TS_EN_S 25 -#define EMAC_DESC_CRC_REPLACE_CTRL (BIT(24)) -#define EMAC_DESC_CRC_REPLACE_CTRL_S 24 -#define EMAC_DESC_CHECKSUM_INSERT_CTRL 0x00000003 -#define EMAC_DESC_CHECKSUM_INSERT_CTRL_S 22 -#define EMAC_DESC_TX_END_OF_RING (BIT(21)) -#define EMAC_DESC_TX_END_OF_RING_S 21 -#define EMAC_DESC_SECOND_ADDR_CHAIN (BIT(20)) -#define EMAC_DESC_SECOND_ADDR_CHAIN_S 20 -#define EMAC_DESC_VLAN_INSERT_CTRL 0x00000003 -#define EMAC_DESC_VLAN_INSERT_CTRL_S 18 -#define EMAC_DESC_TX_TS_STATUS (BIT(17)) -#define EMAC_DESC_TX_TS_STATUS_S 17 -#define EMAC_DESC_TX_IP_HEAD_ERR (BIT(16)) -#define EMAC_DESC_TX_IP_HEAD_ERR_S 16 -#define EMAC_DESC_ERR_SUMMARY (BIT(15)) -#define EMAC_DESC_ERR_SUMMARY_S 15 -#define EMAC_DESC_JABBER_TO (BIT(14)) -#define EMAC_DESC_JABBER_TO_S 14 -#define EMAC_DESC_FRAME_FLUSH (BIT(13)) -#define EMAC_DESC_FRAME_FLUSH_S 13 -#define EMAC_DESC_TX_IP_PAYLAD_ERR (BIT(12)) -#define EMAC_DESC_TX_IP_PAYLAD_ERR_S 12 -#define EMAC_DESC_LOSS_OF_CARRIER (BIT(11)) -#define EMAC_DESC_LOSS_OF_CARRIER_S 11 -#define EMAC_DESC_NO_CARRIER (BIT(10)) -#define EMAC_DESC_NO_CARRIER_S 10 -#define EMAC_DESC_LATE_COLLISION_T (BIT(9)) -#define EMAC_DESC_LATE_COLLISION_T_S 9 -#define EMAC_DESC_EXCESSIVE_COLLISION (BIT(8)) -#define EMAC_DESC_EXCESSIVE_COLLISION_S 8 -#define EMAC_DESC_VLAN_FRAME (BIT(7)) -#define EMAC_DESC_VLAN_FRAME_S 7 -#define EMAC_DESC_COLLISION_COUNT 0x0000000F -#define EMAC_DESC_COLLISION_COUNT_S 3 -#define EMAC_DESC_EXCESSIVE_DEFERRAL (BIT(2)) -#define EMAC_DESC_EXCESSIVE_DEFERRAL_S 2 -#define EMAC_DESC_UNDERFLOW_ERR (BIT(1)) -#define EMAC_DESC_UNDERFLOW_ERR_S 1 -#define EMAC_DESC_DEFFER_BIT (BIT(0)) -#define EMAC_DESC_DEFFER_BIT_S 0 - -#define EMAC_DESC_TDES1_REG (REG_EMAC_DESC_BASE + 0x0004) -#define EMAC_DESC_SA_INSERT_CRTL 0x00000007 -#define EMAC_DESC_SA_INSERT_CRTL_S 29 -#define EMAC_DESC_TX_BUFFER1_SIZE 0x00001FFF -#define EMAC_DESC_TX_BUFFER1_SIZE_S 0 - -#define EMAC_DESC_TDES2_REG (REG_EMAC_DESC_BASE + 0x0008) -#define EMAC_DESC_TX_BUFFER1_ADDR_PTR 0xFFFFFFFF -#define EMAC_DESC_TX_BUFFER1_ADDR_PTR_S 0 - -#define EMAC_DESC_TDES3_REG (REG_EMAC_DESC_BASE + 0x000C) -#define EMAC_DESC_TX_NEXT_DESC_ADDR 0xFFFFFFFF -#define EMAC_DESC_TX_NEXT_DESC_ADDR_S 0 - -#define EMAC_DESC_TDES4_REG (REG_EMAC_DESC_BASE + 0x0010) - -#define EMAC_DESC_TDES5_REG (REG_EMAC_DESC_BASE + 0x0014) - -#define EMAC_DESC_TDES6_REG (REG_EMAC_DESC_BASE + 0x0018) -#define EMAC_DESC_TX_FRAME_TS_LOW 0xFFFFFFFF -#define EMAC_DESC_TX_FRAME_TS_LOW_S 0 - -#define EMAC_DESC_TDES7_REG (REG_EMAC_DESC_BASE + 0x001C) -#define EMAC_DESC_TX_FRAME_TS_HIGH 0xFFFFFFFF -#define EMAC_DESC_TX_FRAME_TS_HIGH_S 0 - -#define EMAC_DESC_RDES0_REG (REG_EMAC_DESC_BASE + 0x0000) -#define EMAC_DESC_RX_OWN (BIT(31)) -#define EMAC_DESC_RX_OWN_S 31 -#define EMAC_DESC_DEST_ADDR_FILTER_FAIL (BIT(30)) -#define EMAC_DESC_DEST_ADDR_FILTER_FAIL_S 30 -#define EMAC_DESC_FRAME_LENGTH 0x00003FFF -#define EMAC_DESC_FRAME_LENGTH_S 16 -#define EMAC_DESC_ERROR_SUMMARY (BIT(15)) -#define EMAC_DESC_ERROR_SUMMARY_S 15 -#define EMAC_DESC_DESC_ERR (BIT(14)) -#define EMAC_DESC_DESC_ERR_S 14 -#define EMAC_DESC_SOURCE_ADDR_FILTER_FAIL (BIT(13)) -#define EMAC_DESC_SOURCE_ADDR_FILTER_FAIL_S 13 -#define EMAC_DESC_LENGTH_ERR (BIT(12)) -#define EMAC_DESC_LENGTH_ERR_S 12 -#define EMAC_DESC_OVERFLOW_ERR (BIT(11)) -#define EMAC_DESC_OVERFLOW_ERR_S 11 -#define EMAC_DESC_VLAN_TAG (BIT(10)) -#define EMAC_DESC_VLAN_TAG_S 10 -#define EMAC_DESC_FRIST_DESC (BIT(9)) -#define EMAC_DESC_FRIST_DESC_S 9 -#define EMAC_DESC_LAST_DESC (BIT(8)) -#define EMAC_DESC_LAST_DESC_S 8 -#define EMAC_DESC_TS_AV_IP_CHK_ERR (BIT(7)) -#define EMAC_DESC_TS_AV_IP_CHK_ERR_S 7 -#define EMAC_DESC_LATE_COLLISION (BIT(6)) -#define EMAC_DESC_LATE_COLLISION_S 6 -#define EMAC_DESC_FRAME_TYPE (BIT(5)) -#define EMAC_DESC_FRAME_TYPE_S 5 -#define EMAC_DESC_RX_WDT_TO (BIT(4)) -#define EMAC_DESC_RX_WDT_TO_S 4 -#define EMAC_DESC_RX_ERR (BIT(3)) -#define EMAC_DESC_RX_ERR_S 3 -#define EMAC_DESC_DRIBBLE_BIT_ERR (BIT(2)) -#define EMAC_DESC_DRIBBLE_BIT_ERR_S 2 -#define EMAC_DESC_CRC_ERR (BIT(1)) -#define EMAC_DESC_CRC_ERR_S 1 -#define EMAC_DESC_EXT_STATUS_AVAIL (BIT(0)) -#define EMAC_DESC_EXT_STATUS_AVAIL_S 0 - -#define EMAC_DESC_RDES1_REG (REG_EMAC_DESC_BASE + 0x0004) -#define EMAC_DESC_DIS_INT_ON_COMPLET (BIT(31)) -#define EMAC_DESC_DIS_INT_ON_COMPLET_S 31 -#define EMAC_DESC_RX_END_OF_RING (BIT(15)) -#define EMAC_DESC_RX_END_OF_RING_S 15 -#define EMAC_DESC_RX_SECOND_ADDR_CHAIN (BIT(14)) -#define EMAC_DESC_RX_SECOND_ADDR_CHAIN_S 14 -#define EMAC_DESC_RX_BUFFER1_SIZE 0x00001FFF -#define EMAC_DESC_RX_BUFFER1_SIZE_S 0 - -#define EMAC_DESC_RDES2_REG (REG_EMAC_DESC_BASE + 0x0008) -#define EMAC_DESC_RX_BUFFER1_ADDR_PTR 0xFFFFFFFF -#define EMAC_DESC_RX_BUFFER1_ADDR_PTR_S 0 - -#define EMAC_DESC_RDES3_REG (REG_EMAC_DESC_BASE + 0x000c) -#define EMAC_DESC_RX_NEXT_DESC_ADDR 0xFFFFFFFF -#define EMAC_DESC_RX_NEXT_DESC_ADDR_S 0 - -#define EMAC_DESC_RDES4_REG (REG_EMAC_DESC_BASE + 0x0010) -#define EMAC_DESC_VLAN_TAG_PRIOR_VALUE 0x00000007 -#define EMAC_DESC_VLAN_TAG_PRIOR_VALUE_S 18 -#define EMAC_DESC_TS_DROP (BIT(14)) -#define EMAC_DESC_TS_DROP_S 14 -#define EMAC_DESC_PTP_VERSION (BIT(13)) -#define EMAC_DESC_PTP_VERSION_S 13 -#define EMAC_DESC_PTP_FRAME_TYPE (BIT(12)) -#define EMAC_DESC_PTP_FRAME_TYPE_S 12 -#define EMAC_DESC_MESSAGE_TYPE 0x0000000F -#define EMAC_DESC_MESSAGE_TYPE_S 8 -#define EMAC_DESC_IPV6_PACK_RECEIVE (BIT(7)) -#define EMAC_DESC_IPV6_PACK_RECEIVE_S 7 -#define EMAC_DESC_IPV4_PACK_RECEIVE (BIT(6)) -#define EMAC_DESC_IPV4_PACK_RECEIVE_S 6 -#define EMAC_DESC_IP_CHECKSUM_BYPASS (BIT(5)) -#define EMAC_DESC_IP_CHECKSUM_BYPASS_S 5 -#define EMAC_DESC_RX_IP_PAYLAD_ERR (BIT(4)) -#define EMAC_DESC_RX_IP_PAYLAD_ERR_S 4 -#define EMAC_DESC_RX_IP_HEAD_ERR (BIT(3)) -#define EMAC_DESC_RX_IP_HEAD_ERR_S 3 -#define EMAC_DESC_IP_PAYLOAD_TYPE 0x00000007 -#define EMAC_DESC_IP_PAYLOAD_TYPE_S 0 - -#define EMAC_DESC_RDES5_REG (REG_EMAC_DESC_BASE + 0x0014) - -#define EMAC_DESC_RDES6_REG (REG_EMAC_DESC_BASE + 0x0018) -#define EMAC_DESC_RX_FRAME_TS_LOW 0xFFFFFFFF -#define EMAC_DESC_RX_FRAME_TS_LOW_S 0 - -#define EMAC_DESC_RDES7_REG (REG_EMAC_DESC_BASE + 0x001C) -#define EMAC_DESC_RX_FRAME_TS_HIGH 0xFFFFFFFF -#define EMAC_DESC_RX_FRAME_TS_HIGH_S 0 - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/components/ethernet/emac_dev.c b/components/ethernet/emac_dev.c deleted file mode 100644 index 51b6f918d7..0000000000 --- a/components/ethernet/emac_dev.c +++ /dev/null @@ -1,107 +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 "esp32/rom/ets_sys.h" -#include "esp32/rom/gpio.h" - -#include "soc/dport_reg.h" -#include "soc/rtc_periph.h" -#include "soc/gpio_periph.h" - -#include "esp_log.h" -#include "driver/gpio.h" -#include "sdkconfig.h" - -#include "emac_common.h" - -void emac_enable_flowctrl(void) -{ - REG_SET_BIT(EMAC_GMACFC_REG, EMAC_TFCE); - REG_SET_BIT(EMAC_GMACFC_REG, EMAC_RFCE); - REG_CLR_BIT(EMAC_GMACFC_REG, EMAC_DZPQ); - REG_SET_FIELD(EMAC_GMACFC_REG, EMAC_PAUSE_TIME, 0x1648); - REG_SET_FIELD(EMAC_GMACFC_REG, EMAC_PLT, 0x1); -} - -void emac_disable_flowctrl(void) -{ - REG_CLR_BIT(EMAC_GMACFC_REG, EMAC_TFCE); - REG_CLR_BIT(EMAC_GMACFC_REG, EMAC_RFCE); - REG_CLR_BIT(EMAC_GMACFC_REG, EMAC_DZPQ); - REG_SET_FIELD(EMAC_GMACFC_REG, EMAC_PAUSE_TIME, 0); - REG_SET_FIELD(EMAC_GMACFC_REG, EMAC_PLT, 0); -} - -void emac_enable_dma_tx(void) -{ - REG_SET_BIT(EMAC_DMAOPERATION_MODE_REG, EMAC_START_STOP_TRANSMISSION_COMMAND); -} - -void emac_enable_dma_rx(void) -{ - REG_SET_BIT(EMAC_DMAOPERATION_MODE_REG, EMAC_START_STOP_RX); -} - -void emac_disable_dma_tx(void) -{ - REG_CLR_BIT(EMAC_DMAOPERATION_MODE_REG, EMAC_START_STOP_TRANSMISSION_COMMAND); -} - -void emac_disable_dma_rx(void) -{ - REG_CLR_BIT(EMAC_DMAOPERATION_MODE_REG, EMAC_START_STOP_RX); -} - -void emac_enable_clk(bool enable) -{ - if (enable == true) { - DPORT_REG_SET_BIT(EMAC_CLK_EN_REG, EMAC_CLK_EN); - } else { - DPORT_REG_CLR_BIT(EMAC_CLK_EN_REG, EMAC_CLK_EN); - } -} - -void emac_dma_init(void) -{ - REG_SET_BIT(EMAC_DMAOPERATION_MODE_REG, EMAC_FWD_UNDER_GF); - REG_SET_BIT(EMAC_DMAOPERATION_MODE_REG, EMAC_OPT_SECOND_FRAME); - REG_SET_FIELD(EMAC_DMABUSMODE_REG, EMAC_PROG_BURST_LEN, 4); -} - -void emac_mac_enable_txrx(void) -{ - REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_EMACRX); - REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_EMACTX); -} - -void emac_mac_init(void) -{ - REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_EMACDUPLEX); - REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_EMACMII); - REG_CLR_BIT(EMAC_GMACCONFIG_REG, EMAC_EMACFESPEED); - REG_SET_BIT(EMAC_GMACFF_REG, EMAC_PAM); -} - -void emac_enable_promiscuous(void) -{ - REG_SET_BIT(EMAC_GMACFF_REG, EMAC_PMODE); -} - -void emac_disable_promiscuous(void) -{ - REG_CLR_BIT(EMAC_GMACFF_REG, EMAC_PMODE); -} diff --git a/components/ethernet/emac_dev.h b/components/ethernet/emac_dev.h deleted file mode 100644 index 1c44f43660..0000000000 --- a/components/ethernet/emac_dev.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 _EMAC_DEV_H_ -#define _EMAC_DEV_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "esp_types.h" -#include "soc/emac_periph.h" - -#define EMAC_INTR_ENABLE_BIT (EMAC_DMAIN_TIE | EMAC_DMAIN_RIE | EMAC_DMAIN_RBUE | EMAC_DMAIN_NISE) - -struct dma_desc { - uint32_t desc0; - uint32_t desc1; - uint32_t desc2; - uint32_t desc3; -}; - -typedef struct dma_extended_desc { - struct dma_desc basic; - uint32_t desc4; - uint32_t desc5; - uint32_t desc6; - uint32_t desc7; -} dma_extended_desc_t; - -void emac_enable_clk(bool enable); -esp_err_t emac_reset(void); -void emac_set_gpio_pin_rmii(void); -void emac_set_gpio_pin_mii(void); -uint32_t emac_read_mac_version(void); -void emac_dma_init(void); -void emac_mac_init(void); -void emac_enable_dma_tx(void); -void emac_enable_dma_rx(void); -void emac_disable_dma_tx(void); -void emac_disable_dma_rx(void); -void emac_enable_flowctrl(void); -void emac_disable_flowctrl(void); -void emac_mac_enable_txrx(void); -void emac_enable_promiscuous(void); -void emac_disable_promiscuous(void); - -static inline uint32_t emac_read_tx_cur_reg(void) -{ - return REG_READ(EMAC_DMATXCURRDESC_REG); -} - -static inline uint32_t emac_read_rx_cur_reg(void) -{ - return REG_READ(EMAC_DMARXCURRDESC_REG); -} - -static inline void emac_poll_tx_cmd(void) -{ - //write any to wake up dma - REG_WRITE(EMAC_DMATXPOLLDEMAND_REG, 1); -} - -static inline void emac_poll_rx_cmd(void) -{ - //write any to wake up dma - REG_WRITE(EMAC_DMARXPOLLDEMAND_REG, 1); -} - -static inline void emac_disable_rx_intr(void) -{ - REG_CLR_BIT(EMAC_DMAIN_EN_REG, EMAC_DMAIN_RIE); -} - -static inline void emac_enable_rx_intr(void) -{ - REG_SET_BIT(EMAC_DMAIN_EN_REG, EMAC_DMAIN_RIE); -} - -static inline void emac_disable_rx_unavail_intr(void) -{ - REG_CLR_BIT(EMAC_DMAIN_EN_REG, EMAC_DMAIN_RBUE); -} - -static inline void emac_enable_rx_unavail_intr(void) -{ - REG_SET_BIT(EMAC_DMAIN_EN_REG, EMAC_DMAIN_RBUE); -} - -static inline void IRAM_ATTR emac_send_pause_frame_enable(void) -{ - REG_SET_BIT(EMAC_EX_PHYINF_CONF_REG, EMAC_EX_SBD_FLOWCTRL); -} - -static inline void emac_send_pause_zero_frame_enable(void) -{ - REG_CLR_BIT(EMAC_EX_PHYINF_CONF_REG, EMAC_EX_SBD_FLOWCTRL); -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/components/ethernet/emac_main.c b/components/ethernet/emac_main.c deleted file mode 100644 index 48e26a302a..0000000000 --- a/components/ethernet/emac_main.c +++ /dev/null @@ -1,1250 +0,0 @@ -// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include - -#include "esp32/rom/ets_sys.h" -#include "esp32/rom/gpio.h" -#include "soc/dport_reg.h" -#include "soc/rtc.h" -#include "soc/rtc_periph.h" -#include "soc/gpio_periph.h" -#include "soc/dport_reg.h" -#include "soc/soc.h" - -#include "tcpip_adapter.h" -#include "sdkconfig.h" - -#include "esp_task_wdt.h" -#include "esp_event.h" -#include "esp_system.h" -#include "esp_err.h" -#include "esp_log.h" -#include "esp_eth.h" -#include "esp_intr_alloc.h" -#include "esp_pm.h" -#include "esp32/spiram.h" - -#include "driver/periph_ctrl.h" - -#include "emac_common.h" -#include "emac_desc.h" - -#include "freertos/xtensa_api.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/queue.h" -#include "freertos/semphr.h" -#include "freertos/timers.h" - -#include "lwip/err.h" - -#define EMAC_EVT_QNUM 200 -#define EMAC_SIG_MAX 50 - -static struct emac_config_data emac_config; - -static dma_extended_desc_t *emac_dma_rx_chain_buf; -static dma_extended_desc_t *emac_dma_tx_chain_buf; -static uint8_t *emac_dma_rx_buf[DMA_RX_BUF_NUM]; -static uint8_t *emac_dma_tx_buf[DMA_TX_BUF_NUM]; - -static SemaphoreHandle_t emac_g_sem = NULL; -static portMUX_TYPE g_emac_mux = portMUX_INITIALIZER_UNLOCKED; -static xTaskHandle emac_task_hdl = NULL; -static xQueueHandle emac_xqueue = NULL; -static uint8_t emac_sig_cnt[EMAC_SIG_MAX] = {0}; -static TimerHandle_t emac_timer = NULL; -static SemaphoreHandle_t emac_rx_xMutex = NULL; -static SemaphoreHandle_t emac_tx_xMutex = NULL; -static intr_handle_t eth_intr_handle = NULL; -static const char *TAG = "emac"; -static bool pause_send = false; -#ifdef CONFIG_PM_ENABLE -static esp_pm_lock_handle_t s_pm_lock; -#endif -ESP_EVENT_DEFINE_BASE(ETH_EVENT); - -static esp_err_t emac_ioctl(emac_sig_t sig, emac_par_t par); -esp_err_t emac_post(emac_sig_t sig, emac_par_t par); - -static void emac_macaddr_init(void) -{ - esp_read_mac(&(emac_config.macaddr[0]), ESP_MAC_ETH); -} - -void esp_eth_get_mac(uint8_t mac[6]) -{ - memcpy(mac, &(emac_config.macaddr[0]), 6); -} - -esp_err_t esp_eth_set_mac(const uint8_t mac[6]) -{ - if (!(mac[0] & 0x01)) { - memcpy(&(emac_config.macaddr[0]), mac, 6); - return ESP_OK; - } else { - return ESP_ERR_INVALID_MAC; - } -} - -eth_speed_mode_t esp_eth_get_speed(void) -{ - return emac_config.emac_phy_get_speed_mode(); -} - -static void emac_setup_tx_desc(dma_extended_desc_t *tx_desc, uint32_t size) -{ - tx_desc->basic.desc1 = size & 0xfff; - tx_desc->basic.desc0 = EMAC_DESC_TX_OWN | EMAC_DESC_INT_COMPL | EMAC_DESC_LAST_SEGMENT | - EMAC_DESC_FIRST_SEGMENT | EMAC_DESC_SECOND_ADDR_CHAIN; -} - -static void emac_clean_tx_desc(dma_extended_desc_t *tx_desc) -{ - tx_desc->basic.desc1 = 0; - tx_desc->basic.desc0 = 0; -} - -static void emac_clean_rx_desc(dma_extended_desc_t *rx_desc, uint32_t buf_ptr) -{ - if (buf_ptr != 0) { - rx_desc->basic.desc2 = buf_ptr; - } - rx_desc->basic.desc1 = EMAC_DESC_RX_SECOND_ADDR_CHAIN | DMA_RX_BUF_SIZE; - rx_desc->basic.desc0 = EMAC_DESC_RX_OWN; -} - -static void emac_set_tx_base_reg(void) -{ - REG_WRITE(EMAC_DMATXBASEADDR_REG, (uint32_t)(emac_config.dma_etx)); -} - -static void emac_set_rx_base_reg(void) -{ - REG_WRITE(EMAC_DMARXBASEADDR_REG, (uint32_t)(emac_config.dma_erx)); -} - -/* -* dirty_rx indicates the hardware has been fed with data packets and is the -* first node software needs to handle; -* -* cur_rx indicates the completion of software handling and is the last node -* hardware could use; -* -* cnt_rx is to count the numbers of packets handled by software, passed to -* protocol stack and not been freed. -* -* (1) Initializing the Linked List. Connect the numerable nodes to a circular -* linked list, appoint one of the nodes as the head node, mark* the dirty_rx -* and cur_rx into the node, and mount the node on the hardware base address. -* Initialize cnt_rx into 0. -* -* (2) When hardware receives packets, nodes of linked lists will be fed with -* data packets from the base address by turns, marks the node -* of linked lists as “HARDWARE UNUSABLE” and reports interrupts. -* -* (3) When the software receives the interrupts, it will handle the linked -* lists by turns from dirty_rx, send data packets to protocol -* stack. dirty_rx will deviate backwards by turns and cnt_rx will by turns ++. -* -* (4) After the protocol stack handles all the data and calls the free function, -* it will deviate backwards by turns from cur_rx, mark the * node of linked -* lists as “HARDWARE USABLE” and cnt_rx will by turns --. -* -* (5) Cycle from Step 2 to Step 4 without break and build up circular linked -* list handling. -*/ -static void emac_reset_dma_chain(void) -{ - emac_config.cnt_tx = 0; - emac_config.cur_tx = 0; - emac_config.dirty_tx = 0; - - emac_config.cnt_rx = 0; - emac_config.cur_rx = 0; - emac_config.dirty_rx = 0; -} - -static void emac_init_dma_chain(void) -{ - int i; - uint32_t dma_phy; - dma_extended_desc_t *p = NULL; - - //init tx chain - emac_config.dma_etx = emac_dma_tx_chain_buf; - emac_config.cnt_tx = 0; - emac_config.cur_tx = 0; - emac_config.dirty_tx = 0; - - dma_phy = (uint32_t)(emac_config.dma_etx); - p = emac_config.dma_etx; - - for (i = 0; i < (DMA_TX_BUF_NUM - 1); i++) { - dma_phy += sizeof(dma_extended_desc_t); - emac_clean_tx_desc(p); - p->basic.desc2 = (uint32_t)(emac_dma_tx_buf[i]); - p->basic.desc3 = dma_phy; - p++; - } - emac_clean_tx_desc(p); - p->basic.desc2 = (uint32_t)(emac_dma_tx_buf[i]); - p->basic.desc3 = (uint32_t)(emac_config.dma_etx); - - //init rx chain - emac_config.dma_erx = emac_dma_rx_chain_buf; - emac_config.cnt_rx = 0; - emac_config.cur_rx = 0; - emac_config.dirty_rx = 0; - - dma_phy = (uint32_t)(emac_config.dma_erx); - p = emac_config.dma_erx; - - for (i = 0; i < (DMA_RX_BUF_NUM - 1); i++) { - dma_phy += sizeof(dma_extended_desc_t); - emac_clean_rx_desc(p, (uint32_t)(emac_dma_rx_buf[i])); - p->basic.desc3 = dma_phy; - p++; - } - - emac_clean_rx_desc(p, (uint32_t)(emac_dma_rx_buf[i])); - p->basic.desc3 = (uint32_t)(emac_config.dma_erx); -} - -void esp_eth_smi_write(uint32_t reg_num, uint16_t value) -{ - uint32_t phy_num = emac_config.phy_addr; - - while (REG_GET_BIT(EMAC_GMIIADDR_REG, EMAC_MIIBUSY) == 1) { - } - - REG_WRITE(EMAC_MIIDATA_REG, value); - REG_WRITE(EMAC_GMIIADDR_REG, 0x3 | ((reg_num & 0x1f) << 6) | ((phy_num & 0x1f) << 11) | ((0x3) << 2)); - - while (REG_GET_BIT(EMAC_GMIIADDR_REG, EMAC_MIIBUSY) == 1) { - } -} - -uint16_t esp_eth_smi_read(uint32_t reg_num) -{ - uint32_t phy_num = emac_config.phy_addr; - uint16_t value = 0; - - while (REG_GET_BIT(EMAC_GMIIADDR_REG, EMAC_MIIBUSY) == 1) { - } - - REG_WRITE(EMAC_GMIIADDR_REG, 0x1 | ((reg_num & 0x1f) << 6) | ((phy_num & 0x1f) << 11) | (0x3 << 2)); - while (REG_GET_BIT(EMAC_GMIIADDR_REG, EMAC_MIIBUSY) == 1) { - } - value = (REG_READ(EMAC_MIIDATA_REG) & 0xffff); - - return value; -} - -esp_err_t esp_eth_smi_wait_value(uint32_t reg_num, uint16_t value, uint16_t value_mask, int timeout_ms) -{ - unsigned start = xTaskGetTickCount(); - unsigned timeout_ticks = (timeout_ms + portTICK_PERIOD_MS - 1) / portTICK_PERIOD_MS; - uint16_t current_value = 0; - - while (timeout_ticks == 0 || (xTaskGetTickCount() - start < timeout_ticks)) { - current_value = esp_eth_smi_read(reg_num); - if ((current_value & value_mask) == (value & value_mask)) { - return ESP_OK; - } - vTaskDelay(1); - } - ESP_LOGE(TAG, "Timed out waiting for PHY register 0x%x to have value 0x%04x(mask 0x%04x). Current value 0x%04x", - reg_num, value, value_mask, current_value); - return ESP_ERR_TIMEOUT; -} - -esp_err_t emac_reset(void) -{ - REG_SET_BIT(EMAC_DMABUSMODE_REG, EMAC_SW_RST); - if (emac_config.reset_timeout_ms) { - int start = xTaskGetTickCount(); - uint32_t timeout_ticks = (emac_config.reset_timeout_ms + portTICK_PERIOD_MS - 1) / portTICK_PERIOD_MS; - while (timeout_ticks == 0 || (xTaskGetTickCount() - start < timeout_ticks)) { - if (REG_GET_BIT(EMAC_DMABUSMODE_REG, EMAC_SW_RST) != EMAC_SW_RST) { - goto reset_ok; - } - vTaskDelay(1); - } - ESP_LOGE(TAG, "Reset EMAC Timeout"); - return ESP_ERR_TIMEOUT; - } - /* infinite wait loop */ - else { - while (REG_GET_BIT(EMAC_DMABUSMODE_REG, EMAC_SW_RST) == EMAC_SW_RST) { - //nothing to do ,if stop here,maybe emac have not clk input. - ESP_LOGI(TAG, "emac resetting ...."); - } - } -reset_ok: - ESP_LOGI(TAG, "emac reset done"); - return ESP_OK; -} - -static void emac_set_user_config_data(eth_config_t *config) -{ - emac_config.phy_addr = config->phy_addr; - emac_config.mac_mode = config->mac_mode; - emac_config.clock_mode = config->clock_mode; - emac_config.phy_init = config->phy_init; - emac_config.emac_tcpip_input = config->tcpip_input; - emac_config.emac_gpio_config = config->gpio_config; - emac_config.emac_phy_check_link = config->phy_check_link; - emac_config.emac_phy_check_init = config->phy_check_init; - emac_config.emac_phy_get_speed_mode = config->phy_get_speed_mode; - emac_config.emac_phy_get_duplex_mode = config->phy_get_duplex_mode; - emac_config.reset_timeout_ms = config->reset_timeout_ms; -#if DMA_RX_BUF_NUM > 9 - emac_config.emac_flow_ctrl_enable = config->flow_ctrl_enable; -#else - if (config->flow_ctrl_enable == true) { - ESP_LOGE(TAG, "Can only configure flow_ctrl_enable==true if DMA_RX_BUF_NUM in menuconfig is >9. Disabling flow control."); - } - emac_config.emac_flow_ctrl_enable = false; -#endif - emac_config.emac_phy_get_partner_pause_enable = config->phy_get_partner_pause_enable; - emac_config.emac_phy_power_enable = config->phy_power_enable; - emac_config.promiscuous_enable = config->promiscuous_enable; -} - -static void emac_enable_intr() -{ - REG_WRITE(EMAC_DMAIN_EN_REG, EMAC_INTR_ENABLE_BIT); -} - -static void emac_disable_intr() -{ - REG_WRITE(EMAC_DMAIN_EN_REG, 0); -} - -static esp_err_t emac_verify_args(void) -{ - esp_err_t ret = ESP_OK; - - if (emac_config.phy_addr > PHY31) { - ESP_LOGE(TAG, "phy addr err"); - ret = ESP_FAIL; - } - - if (emac_config.mac_mode != ETH_MODE_RMII) { - ESP_LOGE(TAG, "mac mode err, currently only support for RMII"); - ret = ESP_FAIL; - } - - if (emac_config.clock_mode > ETH_CLOCK_GPIO17_OUT) { - ESP_LOGE(TAG, "emac clock mode err"); - ret = ESP_FAIL; - } - - if (emac_config.phy_init == NULL) { - ESP_LOGE(TAG, "phy_init func is null"); - ret = ESP_FAIL; - } - - if (emac_config.emac_tcpip_input == NULL) { - ESP_LOGE(TAG, "tcpip_input func is null"); - ret = ESP_FAIL; - } - - if (emac_config.emac_gpio_config == NULL) { - ESP_LOGE(TAG, "gpio config func is null"); - ret = ESP_FAIL; - } - - if (emac_config.emac_phy_check_link == NULL) { - ESP_LOGE(TAG, "phy check link func is null"); - ret = ESP_FAIL; - } - - if (emac_config.emac_phy_check_init == NULL) { - ESP_LOGE(TAG, "phy check init func is null"); - ret = ESP_FAIL; - } - - if (emac_config.emac_phy_get_speed_mode == NULL) { - ESP_LOGE(TAG, "phy get speed mode func is null"); - ret = ESP_FAIL; - } - - if (emac_config.emac_phy_get_duplex_mode == NULL) { - ESP_LOGE(TAG, "phy get duplex mode func is null"); - ret = ESP_FAIL; - } - - if (emac_config.emac_flow_ctrl_enable && !emac_config.emac_phy_get_partner_pause_enable) { - ESP_LOGE(TAG, "phy get partner pause enable func is null"); - ret = ESP_FAIL; - } - - if (emac_config.emac_phy_power_enable == NULL) { - ESP_LOGE(TAG, "phy power enable func is null"); - ret = ESP_FAIL; - } - - return ret; -} - -static void emac_process_tx(void) -{ - uint32_t cur_tx_desc = emac_read_tx_cur_reg(); - - if (emac_config.emac_status == EMAC_RUNTIME_STOP) { - return; - } - - xSemaphoreTakeRecursive(emac_tx_xMutex, portMAX_DELAY); - - while (((uint32_t) & (emac_config.dma_etx[emac_config.dirty_tx])) != cur_tx_desc) { - emac_clean_tx_desc(&(emac_config.dma_etx[emac_config.dirty_tx])); - emac_config.dirty_tx = (emac_config.dirty_tx + 1) % DMA_TX_BUF_NUM; - emac_config.cnt_tx--; - - if (emac_config.cnt_tx < 0) { - ESP_LOGE(TAG, "emac tx chain err"); - } - cur_tx_desc = emac_read_tx_cur_reg(); - } - - xSemaphoreGiveRecursive(emac_tx_xMutex); -} - -void esp_eth_free_rx_buf(void *buf) -{ - xSemaphoreTakeRecursive(emac_rx_xMutex, portMAX_DELAY); - - emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.cur_rx]), (uint32_t)buf); - emac_config.cur_rx = (emac_config.cur_rx + 1) % DMA_RX_BUF_NUM; - emac_config.cnt_rx--; - if (emac_config.cnt_rx < 0) { - ESP_LOGE(TAG, "emac rx buf err"); - } - emac_poll_rx_cmd(); - - xSemaphoreGiveRecursive(emac_rx_xMutex); - - if (emac_config.emac_flow_ctrl_partner_support) { - portENTER_CRITICAL(&g_emac_mux); - if (pause_send && emac_config.cnt_rx < FLOW_CONTROL_LOW_WATERMARK) { - emac_send_pause_zero_frame_enable(); - pause_send = false; - } - portEXIT_CRITICAL(&g_emac_mux); - } -} - -static uint32_t IRAM_ATTR emac_get_rxbuf_count_in_intr(void) -{ - uint32_t cnt = 0; - uint32_t cur_rx_desc = emac_read_rx_cur_reg(); - dma_extended_desc_t *cur_desc = (dma_extended_desc_t *)cur_rx_desc; - - while (cur_desc->basic.desc0 == EMAC_DESC_RX_OWN && cnt < DMA_RX_BUF_NUM) { - cnt++; - cur_desc = (dma_extended_desc_t *)cur_desc->basic.desc3; - } - return cnt; -} - -#if CONFIG_ETH_EMAC_L2_TO_L3_RX_BUF_MODE -static void emac_process_rx(void) -{ - if (emac_config.emac_status == EMAC_RUNTIME_STOP) { - return; - } - uint32_t cur_rx_desc = emac_read_rx_cur_reg(); - - while (((uint32_t) & (emac_config.dma_erx[emac_config.dirty_rx])) != cur_rx_desc) { - //copy data to lwip - emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2), - (((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & - EMAC_DESC_FRAME_LENGTH), NULL); - - emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.dirty_rx]), (emac_config.dma_erx[emac_config.dirty_rx].basic.desc2)); - emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM; - - cur_rx_desc = emac_read_rx_cur_reg(); - } - - emac_enable_rx_intr(); -} - -static void emac_process_rx_unavail(void) -{ - if (emac_config.emac_status == EMAC_RUNTIME_STOP) { - return; - } - - uint32_t dirty_cnt = 0; - while (dirty_cnt < DMA_RX_BUF_NUM) { - if (emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 & EMAC_DESC_RX_OWN) { - break; - } - dirty_cnt++; - //copy data to lwip - emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2), - (((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & - EMAC_DESC_FRAME_LENGTH), NULL); - - emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.dirty_rx]), (emac_config.dma_erx[emac_config.dirty_rx].basic.desc2)); - emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM; - } - emac_enable_rx_intr(); - emac_enable_rx_unavail_intr(); - emac_poll_rx_cmd(); -} - -#else -static void emac_process_rx_unavail(void) -{ - if (emac_config.emac_status == EMAC_RUNTIME_STOP) { - return; - } - - xSemaphoreTakeRecursive(emac_rx_xMutex, portMAX_DELAY); - - while (emac_config.cnt_rx < DMA_RX_BUF_NUM) { - if (emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 & EMAC_DESC_RX_OWN) { - break; - } - emac_config.cnt_rx++; - if (emac_config.cnt_rx > DMA_RX_BUF_NUM) { - ESP_LOGE(TAG, "emac rx buf full"); - } - uint32_t tmp_dirty = emac_config.dirty_rx; - emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM; - - //copy data to lwip - emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[tmp_dirty].basic.desc2), - (((emac_config.dma_erx[tmp_dirty].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & - EMAC_DESC_FRAME_LENGTH), NULL); - } - emac_enable_rx_intr(); - emac_enable_rx_unavail_intr(); - xSemaphoreGiveRecursive(emac_rx_xMutex); -} - -static void emac_process_rx(void) -{ - if (emac_config.emac_status == EMAC_RUNTIME_STOP) { - return; - } - - uint32_t cur_rx_desc = emac_read_rx_cur_reg(); - - xSemaphoreTakeRecursive(emac_rx_xMutex, portMAX_DELAY); - - if ((((uint32_t) & (emac_config.dma_erx[emac_config.dirty_rx])) != cur_rx_desc)) { - while ((((uint32_t) & (emac_config.dma_erx[emac_config.dirty_rx])) != cur_rx_desc) && - emac_config.cnt_rx < DMA_RX_BUF_NUM) { - emac_config.cnt_rx++; - if (emac_config.cnt_rx > DMA_RX_BUF_NUM) { - ESP_LOGE(TAG, "emac rx buf full"); - } - uint32_t tmp_dirty = emac_config.dirty_rx; - emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM; - - //copy data to lwip - emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[tmp_dirty].basic.desc2), - (((emac_config.dma_erx[tmp_dirty].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & - EMAC_DESC_FRAME_LENGTH), NULL); - - cur_rx_desc = emac_read_rx_cur_reg(); - } - } else { - if (emac_config.cnt_rx < DMA_RX_BUF_NUM) { - if (!(emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 & EMAC_DESC_RX_OWN)) { - while (emac_config.cnt_rx < DMA_RX_BUF_NUM) { - if (emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 & EMAC_DESC_RX_OWN) { - break; - } - emac_config.cnt_rx++; - if (emac_config.cnt_rx > DMA_RX_BUF_NUM) { - ESP_LOGE(TAG, "emac rx buf full"); - } - uint32_t tmp_dirty = emac_config.dirty_rx; - emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM; - - //copy data to lwip - emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[tmp_dirty].basic.desc2), - (((emac_config.dma_erx[tmp_dirty].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & - EMAC_DESC_FRAME_LENGTH), NULL); - } - } - } - } - emac_enable_rx_intr(); - xSemaphoreGiveRecursive(emac_rx_xMutex); -} -#endif - -//TODO other events need to do something -static void IRAM_ATTR emac_process_intr(void *arg) -{ - uint32_t event; - event = REG_READ(EMAC_DMASTATUS_REG); - - //clr intrs - REG_WRITE(EMAC_DMASTATUS_REG, event); - - if (event & EMAC_RECV_INT) { - emac_disable_rx_intr(); - if (emac_config.emac_flow_ctrl_partner_support) { - if (emac_get_rxbuf_count_in_intr() < FLOW_CONTROL_HIGH_WATERMARK && !pause_send) { - pause_send = true; - emac_send_pause_frame_enable(); - } - } - emac_post(SIG_EMAC_RX_DONE, 0); - } - - if (event & EMAC_RECV_BUF_UNAVAIL) { - emac_disable_rx_unavail_intr(); - emac_post(SIG_EMAC_RX_UNAVAIL, 0); - } - - if (event & EMAC_TRANS_INT) { - emac_post(SIG_EMAC_TX_DONE, 0); - } -} - -static void emac_set_macaddr_reg(void) -{ - REG_SET_FIELD(EMAC_ADDR0HIGH_REG, EMAC_ADDRESS0_HI, (emac_config.macaddr[5] << 8) | (emac_config.macaddr[4])); - REG_WRITE(EMAC_ADDR0LOW_REG, (emac_config.macaddr[3] << 24) | (emac_config.macaddr[2] << 16) | - (emac_config.macaddr[1] << 8) | (emac_config.macaddr[0])); -} - -static void emac_check_phy_init(void) -{ - emac_config.emac_phy_check_init(); - if (emac_config.emac_phy_get_duplex_mode() == ETH_MODE_FULLDUPLEX) { - REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_EMACDUPLEX); - } else { - REG_CLR_BIT(EMAC_GMACCONFIG_REG, EMAC_EMACDUPLEX); - } - if (emac_config.emac_phy_get_speed_mode() == ETH_SPEED_MODE_100M) { - REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_EMACFESPEED); - } else { - REG_CLR_BIT(EMAC_GMACCONFIG_REG, EMAC_EMACFESPEED); - } -#if CONFIG_ETH_EMAC_L2_TO_L3_RX_BUF_MODE - emac_disable_flowctrl(); - emac_config.emac_flow_ctrl_partner_support = false; -#else - if (emac_config.emac_flow_ctrl_enable) { - if (emac_config.emac_phy_get_partner_pause_enable() && - emac_config.emac_phy_get_duplex_mode() == ETH_MODE_FULLDUPLEX) { - emac_enable_flowctrl(); - emac_config.emac_flow_ctrl_partner_support = true; - } else { - emac_disable_flowctrl(); - emac_config.emac_flow_ctrl_partner_support = false; - } - } else { - emac_disable_flowctrl(); - emac_config.emac_flow_ctrl_partner_support = false; - } -#endif - emac_mac_enable_txrx(); -} -static void emac_process_link_updown(bool link_status) -{ - system_event_t evt; - uint8_t i = 0; - - emac_config.phy_link_up = link_status; - - if (link_status) { - emac_check_phy_init(); - ESP_LOGD(TAG, "eth link_up"); - emac_enable_dma_tx(); - emac_enable_dma_rx(); - for (i = 0; i < PHY_LINK_CHECK_NUM; i++) { - emac_check_phy_init(); - } - - evt.event_id = SYSTEM_EVENT_ETH_CONNECTED; - } else { - ESP_LOGD(TAG, "eth link_down"); - emac_disable_dma_tx(); - emac_disable_dma_rx(); - evt.event_id = SYSTEM_EVENT_ETH_DISCONNECTED; - } - - esp_event_send(&evt); -} - -static void emac_hw_init(void) -{ - //init chain - emac_init_dma_chain(); - - //get hw features TODO - - //ipc TODO -} - -esp_err_t esp_eth_tx(uint8_t *buf, uint16_t size) -{ - esp_err_t ret = ESP_OK; - - if (emac_config.emac_status != EMAC_RUNTIME_START) { - ESP_LOGE(TAG, "tx netif is not ready, emac_status=%d", emac_config.emac_status); - ret = ESP_ERR_INVALID_STATE; - return ret; - } - - xSemaphoreTakeRecursive(emac_tx_xMutex, portMAX_DELAY); - if (emac_config.cnt_tx == DMA_TX_BUF_NUM - 1) { - ESP_LOGD(TAG, "tx buf full"); - ret = ESP_ERR_NO_MEM; - goto _exit; - } - - memcpy((void *)(emac_config.dma_etx[emac_config.cur_tx].basic.desc2), buf, size); - - emac_setup_tx_desc(&(emac_config.dma_etx[emac_config.cur_tx]), size); - - emac_config.cnt_tx++; - emac_config.cur_tx = (emac_config.cur_tx + 1) % DMA_TX_BUF_NUM; - - emac_poll_tx_cmd(); - -_exit: - - xSemaphoreGiveRecursive(emac_tx_xMutex); - return ret; -} - -static void emac_init_default_data(void) -{ - memset((void *)&emac_config, 0, sizeof(struct emac_config_data)); -} - -void emac_process_link_check(void) -{ - if (emac_config.emac_status != EMAC_RUNTIME_START) { - return; - } - - if (emac_config.emac_phy_check_link()) { - if (!emac_config.phy_link_up) { - emac_process_link_updown(true); - } - } else { - if (emac_config.phy_link_up) { - emac_process_link_updown(false); - } - } -} - -void emac_link_check_func(void *pv_parameters) -{ - emac_post(SIG_EMAC_CHECK_LINK, 0); -} - -static bool emac_link_check_timer_init(void) -{ - emac_timer = xTimerCreate("emac_timer", - (CONFIG_ETH_CHECK_LINK_STATUS_PERIOD_MS / portTICK_PERIOD_MS), - pdTRUE, - NULL, - emac_link_check_func); - if (emac_timer == NULL) { - return false; - } else { - return true; - } -} - -static bool emac_link_check_timer_start(void) -{ - if (xTimerStart(emac_timer, portMAX_DELAY) != pdPASS) { - return false; - } else { - return true; - } -} - -static bool emac_link_check_timer_stop(void) -{ - if (xTimerStop(emac_timer, portMAX_DELAY) != pdPASS) { - return false; - } else { - return true; - } -} - -static bool emac_link_check_timer_delete(void) -{ - xTimerDelete(emac_timer, portMAX_DELAY); - emac_timer = NULL; - return true; -} - -static void emac_start(void *param) -{ - struct emac_post_cmd *post_cmd = (struct emac_post_cmd *)param; - struct emac_open_cmd *cmd = (struct emac_open_cmd *)(post_cmd->cmd); - - ESP_LOGD(TAG, "emac start"); - cmd->err = EMAC_CMD_OK; - - if (emac_reset() != ESP_OK) { - return; - } - emac_reset_dma_chain(); - emac_dma_init(); - - emac_set_macaddr_reg(); - - emac_set_tx_base_reg(); - emac_set_rx_base_reg(); - - emac_mac_init(); - - /* check if enable promiscuous mode */ - if(emac_config.promiscuous_enable){ - emac_enable_promiscuous(); - }else{ - emac_disable_promiscuous(); - } - - emac_enable_intr(); - - emac_config.emac_status = EMAC_RUNTIME_START; - - system_event_t evt; - evt.event_id = SYSTEM_EVENT_ETH_START; - esp_event_send(&evt); - - //set a timer to check link up status - if (emac_link_check_timer_init()) { - if (!emac_link_check_timer_start()) { - cmd->err = EMAC_CMD_FAIL; - emac_link_check_timer_delete(); - } - } else { - cmd->err = EMAC_CMD_FAIL; - } - - if (post_cmd->post_type == EMAC_POST_SYNC) { - xSemaphoreGive(emac_g_sem); - } - - ESP_LOGD(TAG, "emac start success"); -} - -esp_err_t esp_eth_enable(void) -{ - struct emac_post_cmd post_cmd; - struct emac_open_cmd open_cmd; - - post_cmd.cmd = (void *)(&open_cmd); - open_cmd.err = EMAC_CMD_OK; - - if (emac_config.emac_status == EMAC_RUNTIME_START) { - open_cmd.err = EMAC_CMD_OK; - return open_cmd.err; - } - -#ifdef CONFIG_PM_ENABLE - esp_err_t err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "ethernet", &s_pm_lock); - if (err != ESP_OK) { - return err; - } - esp_pm_lock_acquire(s_pm_lock); -#endif //CONFIG_PM_ENABLE - - emac_enable_clk(true); - /* init phy device */ - if (emac_config.phy_init() != ESP_OK) { - ESP_LOGE(TAG, "Initialise PHY device Timeout"); - return ESP_FAIL; - } - - if (emac_config.emac_status != EMAC_RUNTIME_NOT_INIT) { - if (emac_ioctl(SIG_EMAC_START, (emac_par_t)(&post_cmd))) { - open_cmd.err = EMAC_CMD_FAIL; - goto cleanup; - } - } else { - open_cmd.err = EMAC_CMD_FAIL; - goto cleanup; - } - return EMAC_CMD_OK; - -cleanup: -#ifdef CONFIG_PM_ENABLE - esp_pm_lock_release(s_pm_lock); - esp_pm_lock_delete(s_pm_lock); - s_pm_lock = NULL; -#endif //CONFIG_PM_ENABLE - return open_cmd.err; -} - -static void emac_stop(void *param) -{ - struct emac_post_cmd *post_cmd = (struct emac_post_cmd *)param; - ESP_LOGD(TAG, "emac stop"); - - emac_link_check_timer_stop(); - emac_link_check_timer_delete(); - - emac_process_link_updown(false); - - emac_disable_intr(); - emac_enable_clk(false); - - emac_config.emac_status = EMAC_RUNTIME_STOP; - system_event_t evt; - evt.event_id = SYSTEM_EVENT_ETH_STOP; - esp_event_send(&evt); - - if (post_cmd->post_type == EMAC_POST_SYNC) { - xSemaphoreGive(emac_g_sem); - } - - ESP_LOGD(TAG, "emac stop success"); -} - -esp_err_t esp_eth_disable(void) -{ - struct emac_post_cmd post_cmd; - struct emac_close_cmd close_cmd; - - post_cmd.cmd = (void *)(&close_cmd); - close_cmd.err = EMAC_CMD_OK; - - if (emac_config.emac_status == EMAC_RUNTIME_STOP) { - close_cmd.err = EMAC_CMD_OK; - return close_cmd.err; - } - -#ifdef CONFIG_PM_ENABLE - esp_pm_lock_release(s_pm_lock); - esp_pm_lock_delete(s_pm_lock); - s_pm_lock = NULL; -#endif // CONFIG_PM_ENABLE - - if (emac_config.emac_status == EMAC_RUNTIME_START) { - if (emac_ioctl(SIG_EMAC_STOP, (emac_par_t)(&post_cmd)) != 0) { - close_cmd.err = EMAC_CMD_FAIL; - } - } else { - close_cmd.err = EMAC_CMD_FAIL; - } - return close_cmd.err; -} - -static esp_err_t emac_ioctl(emac_sig_t sig, emac_par_t par) -{ - esp_err_t ret = ESP_OK; - struct emac_post_cmd *post_cmd = (struct emac_post_cmd *)par; - xTaskHandle task_hdl = xTaskGetCurrentTaskHandle(); - - if (emac_task_hdl != task_hdl) { - post_cmd->post_type = EMAC_POST_SYNC; - if (emac_post(sig, par) != ESP_OK) { - ret = ESP_FAIL; - return ret; - }; - - if (xSemaphoreTake(emac_g_sem, portMAX_DELAY) == pdTRUE) { - return ret; - } - } else { - post_cmd->post_type = EMAC_POST_ASYNC; - switch (sig) { - case SIG_EMAC_RX_DONE: - emac_process_rx(); - break; - case SIG_EMAC_TX_DONE: - emac_process_tx(); - break; - case SIG_EMAC_START: - emac_start((void *)par); - break; - case SIG_EMAC_STOP: - emac_stop((void *)par); - break; - default: - ESP_LOGE(TAG, "unexpect sig %d", sig); - break; - } - } - - return ret; -} - -void emac_task(void *pv) -{ - emac_event_t e; - - for (;;) { - if (xQueueReceive(emac_xqueue, &e, portMAX_DELAY) == pdTRUE) { - portENTER_CRITICAL(&g_emac_mux); - emac_sig_cnt[e.sig]--; - portEXIT_CRITICAL(&g_emac_mux); - switch (e.sig) { - case SIG_EMAC_RX_DONE: - emac_process_rx(); - break; - case SIG_EMAC_RX_UNAVAIL: - emac_process_rx_unavail(); - break; - case SIG_EMAC_TX_DONE: - emac_process_tx(); - break; - case SIG_EMAC_START: - emac_start((void *)e.par); - break; - case SIG_EMAC_STOP: - emac_stop((void *)e.par); - break; - case SIG_EMAC_CHECK_LINK: - emac_process_link_check(); - break; - default: - ESP_LOGE(TAG, "unexpect sig %d", e.sig); - break; - } - } - } -} - -esp_err_t IRAM_ATTR emac_post(emac_sig_t sig, emac_par_t par) -{ - if (sig <= SIG_EMAC_RX_DONE) { - if (emac_sig_cnt[sig]) { - return ESP_OK; - } else { - emac_sig_cnt[sig]++; - emac_event_t evt; - signed portBASE_TYPE ret; - evt.sig = sig; - evt.par = par; - portBASE_TYPE tmp; - - ret = xQueueSendFromISR(emac_xqueue, &evt, &tmp); - - if (tmp != pdFALSE) { - portYIELD_FROM_ISR(); - } - - if (ret != pdPASS) { - return ESP_FAIL; - } - } - } else { - portENTER_CRITICAL(&g_emac_mux); - emac_sig_cnt[sig]++; - portEXIT_CRITICAL(&g_emac_mux); - emac_event_t evt; - evt.sig = sig; - evt.par = par; - - if (xQueueSend(emac_xqueue, &evt, 10 / portTICK_PERIOD_MS) != pdTRUE) { - return ESP_FAIL; - } - } - - return ESP_OK; -} - -esp_err_t esp_eth_init(eth_config_t *config) -{ - tcpip_adapter_set_default_eth_handlers(); - return esp_eth_init_internal(config); -} - -esp_err_t esp_eth_init_internal(eth_config_t *config) -{ - int i = 0; - esp_err_t ret = ESP_OK; - if (emac_config.emac_status != EMAC_RUNTIME_NOT_INIT) { - goto _initialised; - } - - /* dynamically alloc memory for ethernet dma */ - emac_dma_rx_chain_buf = (dma_extended_desc_t *)heap_caps_malloc(sizeof(dma_extended_desc_t) * DMA_RX_BUF_NUM, MALLOC_CAP_DMA); - emac_dma_tx_chain_buf = (dma_extended_desc_t *)heap_caps_malloc(sizeof(dma_extended_desc_t) * DMA_TX_BUF_NUM, MALLOC_CAP_DMA); - for (i = 0; i < DMA_RX_BUF_NUM; i++) { - emac_dma_rx_buf[i] = (uint8_t *)heap_caps_malloc(DMA_RX_BUF_SIZE, MALLOC_CAP_DMA); - } - for (i = 0; i < DMA_TX_BUF_NUM; i++) { - emac_dma_tx_buf[i] = (uint8_t *)heap_caps_malloc(DMA_TX_BUF_SIZE, MALLOC_CAP_DMA); - } - - emac_init_default_data(); - - if (config) { - emac_set_user_config_data(config); - } - - ret = emac_verify_args(); - - if (ret != ESP_OK) { - goto _verify_err; - } - - emac_config.emac_phy_power_enable(true); - - //before set emac reg must enable clk - periph_module_enable(PERIPH_EMAC_MODULE); - - if (emac_config.clock_mode != ETH_CLOCK_GPIO0_IN) { -#if CONFIG_SPIRAM - if (esp_spiram_is_initialized()) { - ESP_LOGE(TAG, "GPIO16 and GPIO17 has been occupied by PSRAM, Only ETH_CLOCK_GPIO_IN is supported!"); - ret = ESP_FAIL; - goto _verify_err; - } else { - ESP_LOGW(TAG, "GPIO16/17 is used for clock of EMAC, Please Make Sure you're not using PSRAM."); - } -#endif - // 50 MHz = 40MHz * (6 + 4) / (2 * (2 + 2) = 400MHz / 8 - rtc_clk_apll_enable(1, 0, 0, 6, 2); - REG_SET_FIELD(EMAC_EX_CLKOUT_CONF_REG, EMAC_EX_CLK_OUT_H_DIV_NUM, 0); - REG_SET_FIELD(EMAC_EX_CLKOUT_CONF_REG, EMAC_EX_CLK_OUT_DIV_NUM, 0); - - if (emac_config.clock_mode == ETH_CLOCK_GPIO0_OUT) { - PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1); - REG_WRITE(PIN_CTRL, 6); - ESP_LOGD(TAG, "EMAC 50MHz clock output on GPIO0"); - } else if (emac_config.clock_mode == ETH_CLOCK_GPIO16_OUT) { - PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO16_U, FUNC_GPIO16_EMAC_CLK_OUT); - ESP_LOGD(TAG, "EMAC 50MHz clock output on GPIO16"); - } else if (emac_config.clock_mode == ETH_CLOCK_GPIO17_OUT) { - PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO17_U, FUNC_GPIO17_EMAC_CLK_OUT_180); - ESP_LOGD(TAG, "EMAC 50MHz inverted clock output on GPIO17"); - } - } - - emac_enable_clk(true); - REG_SET_FIELD(EMAC_EX_PHYINF_CONF_REG, EMAC_EX_PHY_INTF_SEL, EMAC_EX_PHY_INTF_RMII); - emac_dma_init(); - - if (emac_config.clock_mode == ETH_CLOCK_GPIO0_IN) { - // external clock on GPIO0 - REG_SET_BIT(EMAC_EX_CLK_CTRL_REG, EMAC_EX_EXT_OSC_EN); - REG_CLR_BIT(EMAC_EX_CLK_CTRL_REG, EMAC_EX_INT_OSC_EN); - REG_SET_BIT(EMAC_EX_OSCCLK_CONF_REG, EMAC_EX_OSC_CLK_SEL); - ESP_LOGD(TAG, "External clock input 50MHz on GPIO0"); - if (emac_config.mac_mode == ETH_MODE_MII) { - REG_SET_BIT(EMAC_EX_CLK_CTRL_REG, EMAC_EX_MII_CLK_RX_EN); - REG_SET_BIT(EMAC_EX_CLK_CTRL_REG, EMAC_EX_MII_CLK_TX_EN); - } - } else { - // internal clock by APLL - REG_CLR_BIT(EMAC_EX_CLK_CTRL_REG, EMAC_EX_EXT_OSC_EN); - REG_SET_BIT(EMAC_EX_CLK_CTRL_REG, EMAC_EX_INT_OSC_EN); - REG_CLR_BIT(EMAC_EX_OSCCLK_CONF_REG, EMAC_EX_OSC_CLK_SEL); - } - - emac_config.emac_gpio_config(); - - emac_hw_init(); - emac_macaddr_init(); - - //watchdog TODO - - //init task for emac - emac_g_sem = xSemaphoreCreateBinary(); - emac_rx_xMutex = xSemaphoreCreateRecursiveMutex(); - emac_tx_xMutex = xSemaphoreCreateRecursiveMutex(); - emac_xqueue = xQueueCreate(EMAC_EVT_QNUM, sizeof(emac_event_t)); - xTaskCreate(emac_task, - "emacT", - EMAC_TASK_STACK_SIZE, - NULL, - EMAC_TASK_PRIORITY, - &emac_task_hdl); - - esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, 0, emac_process_intr, NULL, ð_intr_handle); - - emac_config.emac_status = EMAC_RUNTIME_INIT; - - return ESP_OK; - -_verify_err: - free(emac_dma_rx_chain_buf); - free(emac_dma_tx_chain_buf); - emac_dma_rx_chain_buf = NULL; - emac_dma_tx_chain_buf = NULL; - for (i = 0; i < DMA_RX_BUF_NUM; i++) { - free(emac_dma_rx_buf[i]); - emac_dma_rx_buf[i] = NULL; - } - for (i = 0; i < DMA_TX_BUF_NUM; i++) { - free(emac_dma_tx_buf[i]); - emac_dma_tx_buf[i] = NULL; - } -_initialised: - return ret; -} - -esp_err_t esp_eth_deinit(void) -{ - esp_err_t ret = ESP_OK; - int i = 0; - - if (emac_config.emac_status == EMAC_RUNTIME_NOT_INIT) { - goto _exit; - } - if (emac_config.emac_status == EMAC_RUNTIME_START) { - esp_eth_disable(); - } - if (!emac_task_hdl) { - ret = ESP_ERR_INVALID_STATE; - goto _exit; - } - - vTaskDelete(emac_task_hdl); - emac_task_hdl = NULL; - - vQueueDelete(emac_xqueue); - vSemaphoreDelete(emac_tx_xMutex); - vSemaphoreDelete(emac_rx_xMutex); - vSemaphoreDelete(emac_g_sem); - emac_reset_dma_chain(); - emac_config.emac_phy_power_enable(false); - periph_module_disable(PERIPH_EMAC_MODULE); - emac_config.emac_status = EMAC_RUNTIME_NOT_INIT; - - /* free memory that dynamically allocted */ - free(emac_dma_rx_chain_buf); - free(emac_dma_tx_chain_buf); - emac_dma_rx_chain_buf = NULL; - emac_dma_tx_chain_buf = NULL; - for (i = 0; i < DMA_RX_BUF_NUM; i++) { - free(emac_dma_rx_buf[i]); - emac_dma_rx_buf[i] = NULL; - } - for (i = 0; i < DMA_TX_BUF_NUM; i++) { - free(emac_dma_tx_buf[i]); - emac_dma_tx_buf[i] = NULL; - } - esp_intr_free(eth_intr_handle); -_exit: - return ret; -} diff --git a/components/ethernet/eth_phy/phy_common.c b/components/ethernet/eth_phy/phy_common.c deleted file mode 100644 index 936930236d..0000000000 --- a/components/ethernet/eth_phy/phy_common.c +++ /dev/null @@ -1,80 +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 "eth_phy/phy.h" -#include "eth_phy/phy_reg.h" -#include "driver/gpio.h" -#include "esp_log.h" - -static const char *TAG = "phy_common"; - -void phy_rmii_configure_data_interface_pins(void) -{ - // CRS_DRV to GPIO27 - PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO27_U, FUNC_GPIO27_EMAC_RX_DV); - // TXD0 to GPIO19 - PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO19_U, FUNC_GPIO19_EMAC_TXD0); - // TX_EN to GPIO21 - PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO21_U, FUNC_GPIO21_EMAC_TX_EN); - // TXD1 to GPIO22 - PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO22_U, FUNC_GPIO22_EMAC_TXD1); - // RXD0 to GPIO25 - gpio_set_direction(25, GPIO_MODE_INPUT); - // RXD1 to GPIO26 - gpio_set_direction(26, GPIO_MODE_INPUT); - // RMII CLK to GPIO0 - gpio_set_direction(0, GPIO_MODE_INPUT); -} - -void phy_rmii_smi_configure_pins(uint8_t mdc_gpio, uint8_t mdio_gpio) -{ - // setup SMI MDC pin - gpio_set_direction(mdc_gpio, GPIO_MODE_OUTPUT); - gpio_matrix_out(mdc_gpio, EMAC_MDC_O_IDX, 0, 0); - PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[mdc_gpio], PIN_FUNC_GPIO); - // setup SMI MDIO pin - gpio_set_direction(mdio_gpio, GPIO_MODE_INPUT_OUTPUT); - gpio_matrix_out(mdio_gpio, EMAC_MDO_O_IDX, 0, 0); - gpio_matrix_in(mdio_gpio, EMAC_MDI_I_IDX, 0); - PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[mdio_gpio], PIN_FUNC_GPIO); -} - -void phy_mii_enable_flow_ctrl(void) -{ - uint32_t data = esp_eth_smi_read(MII_AUTO_NEG_ADVERTISEMENT_REG); - data |= MII_ASM_DIR | MII_PAUSE; - esp_eth_smi_write(MII_AUTO_NEG_ADVERTISEMENT_REG, data); -} - -bool phy_mii_check_link_status(void) -{ - if ((esp_eth_smi_read(MII_BASIC_MODE_STATUS_REG) & MII_LINK_STATUS)) { - ESP_LOGD(TAG, "phy_mii_check_link_status(UP)"); - return true; - } else { - ESP_LOGD(TAG, "phy_mii_check_link_status(DOWN)"); - return false; - } -} - -bool phy_mii_get_partner_pause_enable(void) -{ - if ((esp_eth_smi_read(MII_PHY_LINK_PARTNER_ABILITY_REG) & MII_PARTNER_PAUSE)) { - ESP_LOGD(TAG, "phy_mii_get_partner_pause_enable(TRUE)"); - return true; - } else { - ESP_LOGD(TAG, "phy_mii_get_partner_pause_enable(FALSE)"); - return false; - } -} diff --git a/components/ethernet/eth_phy/phy_ip101.c b/components/ethernet/eth_phy/phy_ip101.c deleted file mode 100644 index 69b5c2daf8..0000000000 --- a/components/ethernet/eth_phy/phy_ip101.c +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#include "esp_log.h" -#include "esp_eth.h" -#include "eth_phy/phy_reg.h" -#include "eth_phy/phy_ip101.h" - -#define IP101_PHY_ID1 0x243 -#define IP101_PHY_ID2 0xc54 -#define IP101_PHY_ID2_MASK 0xFFF0 - -#define PHY_STATUS_REG (0x1e) -#define DUPLEX_STATUS BIT(2) -#define SPEED_STATUS BIT(1) - -static const char *TAG = "ip101"; - -void phy_ip101_check_phy_init(void) -{ - phy_ip101_dump_registers(); - esp_eth_smi_wait_set(MII_BASIC_MODE_STATUS_REG, MII_AUTO_NEGOTIATION_COMPLETE, 0); -} - -eth_speed_mode_t phy_ip101_get_speed_mode(void) -{ - if ((esp_eth_smi_read(PHY_STATUS_REG) & SPEED_STATUS) == SPEED_STATUS) { - ESP_LOGD(TAG, "phy_ip101_get_speed_mode(100)"); - return ETH_SPEED_MODE_100M; - } else { - ESP_LOGD(TAG, "phy_ip101_get_speed_mode(10)"); - return ETH_SPEED_MODE_10M; - } -} - -eth_duplex_mode_t phy_ip101_get_duplex_mode(void) -{ - if ((esp_eth_smi_read(PHY_STATUS_REG) & DUPLEX_STATUS) == DUPLEX_STATUS) { - ESP_LOGD(TAG, "phy_ip101_get_duplex_mode(FULL)"); - return ETH_MODE_FULLDUPLEX; - } else { - ESP_LOGD(TAG, "phy_ip101_get_duplex_mode(HALF)"); - return ETH_MODE_HALFDUPLEX; - } -} - -void phy_ip101_power_enable(bool enable) -{ - if (enable) { - uint32_t data = esp_eth_smi_read(MII_BASIC_MODE_CONTROL_REG); - data |= MII_AUTO_NEGOTIATION_ENABLE | MII_RESTART_AUTO_NEGOTIATION; - esp_eth_smi_write(MII_BASIC_MODE_CONTROL_REG, data); - // TODO: only do this if config.flow_ctrl_enable == true - phy_mii_enable_flow_ctrl(); - } -} - -esp_err_t phy_ip101_init(void) -{ - esp_err_t res1, res2; - ESP_LOGD(TAG, "phy_ip101_init()"); - phy_ip101_dump_registers(); - - esp_eth_smi_write(MII_BASIC_MODE_CONTROL_REG, MII_SOFTWARE_RESET); - - do { - // Call esp_eth_smi_wait_value() with a timeout so it prints an error periodically - res1 = esp_eth_smi_wait_value(MII_PHY_IDENTIFIER_1_REG, IP101_PHY_ID1, UINT16_MAX, 1000); - res2 = esp_eth_smi_wait_value(MII_PHY_IDENTIFIER_2_REG, IP101_PHY_ID2, IP101_PHY_ID2_MASK, 1000); - } while (res1 != ESP_OK || res2 != ESP_OK); - - uint32_t data = esp_eth_smi_read(MII_BASIC_MODE_CONTROL_REG); - data |= MII_AUTO_NEGOTIATION_ENABLE | MII_RESTART_AUTO_NEGOTIATION; - esp_eth_smi_write(MII_BASIC_MODE_CONTROL_REG, data); - - ets_delay_us(300); - // TODO: only do this if config.flow_ctrl_enable == true - phy_mii_enable_flow_ctrl(); - if (res1 == ESP_OK && res2 == ESP_OK) { - return ESP_OK; - } else { - return ESP_ERR_TIMEOUT; - } -} - -const eth_config_t phy_ip101_default_ethernet_config = { - .phy_addr = 0x1, - .mac_mode = ETH_MODE_RMII, - .clock_mode = ETH_CLOCK_GPIO0_OUT, - .flow_ctrl_enable = true, - .phy_init = phy_ip101_init, - .phy_check_init = phy_ip101_check_phy_init, - .phy_check_link = phy_mii_check_link_status, - .phy_get_speed_mode = phy_ip101_get_speed_mode, - .phy_get_duplex_mode = phy_ip101_get_duplex_mode, - .phy_get_partner_pause_enable = phy_mii_get_partner_pause_enable, - .phy_power_enable = phy_ip101_power_enable, - .reset_timeout_ms = 1000, - .promiscuous_enable = false, -}; - -void phy_ip101_dump_registers() -{ - ESP_LOGD(TAG, "IP101 Registers:"); - ESP_LOGD(TAG, "BCR 0x%04x", esp_eth_smi_read(0x0)); - ESP_LOGD(TAG, "BSR 0x%04x", esp_eth_smi_read(0x1)); - ESP_LOGD(TAG, "PHY1 0x%04x", esp_eth_smi_read(0x2)); - ESP_LOGD(TAG, "PHY2 0x%04x", esp_eth_smi_read(0x3)); - ESP_LOGD(TAG, "ANAR 0x%04x", esp_eth_smi_read(0x4)); - ESP_LOGD(TAG, "ANLPAR 0x%04x", esp_eth_smi_read(0x5)); - ESP_LOGD(TAG, "ANER 0x%04x", esp_eth_smi_read(0x6)); - ESP_LOGD(TAG, "PSCR 0x%04x", esp_eth_smi_read(0x16)); - ESP_LOGD(TAG, "ISR 0x%04x", esp_eth_smi_read(0x17)); - ESP_LOGD(TAG, "ICR 0x%04x", esp_eth_smi_read(0x18)); - ESP_LOGD(TAG, "CSSR 0x%04x", esp_eth_smi_read(0x30)); -} diff --git a/components/ethernet/eth_phy/phy_lan8720.c b/components/ethernet/eth_phy/phy_lan8720.c deleted file mode 100644 index 666b82868e..0000000000 --- a/components/ethernet/eth_phy/phy_lan8720.c +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#include "esp_log.h" -#include "esp_eth.h" -#include "eth_phy/phy_reg.h" -#include "eth_phy/phy_lan8720.h" - -#define LAN8720_PHY_ID1 0x0007 -#define LAN8720_PHY_ID2 0xc0f0 -#define LAN8720_PHY_ID2_MASK 0xFFF0 - -/* LAN8720-specific registers */ -#define PHY_SPECIAL_CONTROL_STATUS_REG (0x1f) -#define AUTO_NEGOTIATION_DONE BIT(12) -#define DUPLEX_INDICATION_FULL BIT(4) -#define SPEED_INDICATION_100T BIT(3) -#define SPEED_INDICATION_10T BIT(2) -#define SPEED_DUPLEX_INDICATION_10T_HALF 0x04 -#define SPEED_DUPLEX_INDICATION_10T_FULL 0x14 -#define SPEED_DUPLEX_INDICATION_100T_HALF 0x08 -#define SPEED_DUPLEX_INDICATION_100T_FULL 0x18 - -static const char *TAG = "lan8720"; - -void phy_lan8720_check_phy_init(void) -{ - phy_lan8720_dump_registers(); - - esp_eth_smi_wait_set(MII_BASIC_MODE_STATUS_REG, MII_AUTO_NEGOTIATION_COMPLETE, 0); - esp_eth_smi_wait_set(PHY_SPECIAL_CONTROL_STATUS_REG, AUTO_NEGOTIATION_DONE, 0); -} - -eth_speed_mode_t phy_lan8720_get_speed_mode(void) -{ - if (esp_eth_smi_read(PHY_SPECIAL_CONTROL_STATUS_REG) & SPEED_INDICATION_100T) { - ESP_LOGD(TAG, "phy_lan8720_get_speed_mode(100)"); - return ETH_SPEED_MODE_100M; - } else { - ESP_LOGD(TAG, "phy_lan8720_get_speed_mode(10)"); - return ETH_SPEED_MODE_10M; - } -} - -eth_duplex_mode_t phy_lan8720_get_duplex_mode(void) -{ - if (esp_eth_smi_read(PHY_SPECIAL_CONTROL_STATUS_REG) & DUPLEX_INDICATION_FULL) { - ESP_LOGD(TAG, "phy_lan8720_get_duplex_mode(FULL)"); - return ETH_MODE_FULLDUPLEX; - } else { - ESP_LOGD(TAG, "phy_lan8720_get_duplex_mode(HALF)"); - return ETH_MODE_HALFDUPLEX; - } -} - -void phy_lan8720_power_enable(bool enable) -{ - if (enable) { - uint32_t data = esp_eth_smi_read(MII_BASIC_MODE_CONTROL_REG); - data |= MII_AUTO_NEGOTIATION_ENABLE | MII_RESTART_AUTO_NEGOTIATION; - esp_eth_smi_write(MII_BASIC_MODE_CONTROL_REG, data); - // TODO: only enable if config.flow_ctrl_enable == true - phy_mii_enable_flow_ctrl(); - } -} - -esp_err_t phy_lan8720_init(void) -{ - ESP_LOGD(TAG, "phy_lan8720_init()"); - phy_lan8720_dump_registers(); - - esp_eth_smi_write(MII_BASIC_MODE_CONTROL_REG, MII_SOFTWARE_RESET); - - esp_err_t res1, res2; - // Call esp_eth_smi_wait_value() with a timeout so it prints an error periodically - res1 = esp_eth_smi_wait_value(MII_PHY_IDENTIFIER_1_REG, LAN8720_PHY_ID1, UINT16_MAX, 1000); - res2 = esp_eth_smi_wait_value(MII_PHY_IDENTIFIER_2_REG, LAN8720_PHY_ID2, LAN8720_PHY_ID2_MASK, 1000); - - uint32_t data = esp_eth_smi_read(MII_BASIC_MODE_CONTROL_REG); - data |= MII_AUTO_NEGOTIATION_ENABLE | MII_RESTART_AUTO_NEGOTIATION; - esp_eth_smi_write(MII_BASIC_MODE_CONTROL_REG, data); - - ets_delay_us(300); - - // TODO: only enable if config.flow_ctrl_enable == true - phy_mii_enable_flow_ctrl(); - - if (res1 == ESP_OK && res2 == ESP_OK) { - return ESP_OK; - } else { - return ESP_ERR_TIMEOUT; - } -} - -const eth_config_t phy_lan8720_default_ethernet_config = { - .phy_addr = 0, - .mac_mode = ETH_MODE_RMII, - .clock_mode = ETH_CLOCK_GPIO0_IN, - .flow_ctrl_enable = true, - .phy_init = phy_lan8720_init, - .phy_check_init = phy_lan8720_check_phy_init, - .phy_power_enable = phy_lan8720_power_enable, - .phy_check_link = phy_mii_check_link_status, - .phy_get_speed_mode = phy_lan8720_get_speed_mode, - .phy_get_duplex_mode = phy_lan8720_get_duplex_mode, - .phy_get_partner_pause_enable = phy_mii_get_partner_pause_enable, - .reset_timeout_ms = 1000, - .promiscuous_enable = false, -}; - -void phy_lan8720_dump_registers() -{ - ESP_LOGD(TAG, "LAN8720 Registers:"); - ESP_LOGD(TAG, "BCR 0x%04x", esp_eth_smi_read(0x0)); - ESP_LOGD(TAG, "BSR 0x%04x", esp_eth_smi_read(0x1)); - ESP_LOGD(TAG, "PHY1 0x%04x", esp_eth_smi_read(0x2)); - ESP_LOGD(TAG, "PHY2 0x%04x", esp_eth_smi_read(0x3)); - ESP_LOGD(TAG, "ANAR 0x%04x", esp_eth_smi_read(0x4)); - ESP_LOGD(TAG, "ANLPAR 0x%04x", esp_eth_smi_read(0x5)); - ESP_LOGD(TAG, "ANER 0x%04x", esp_eth_smi_read(0x6)); - ESP_LOGD(TAG, "MCSR 0x%04x", esp_eth_smi_read(0x17)); - ESP_LOGD(TAG, "SM 0x%04x", esp_eth_smi_read(0x18)); - ESP_LOGD(TAG, "SECR 0x%04x", esp_eth_smi_read(0x26)); - ESP_LOGD(TAG, "CSIR 0x%04x", esp_eth_smi_read(0x27)); - ESP_LOGD(TAG, "ISR 0x%04x", esp_eth_smi_read(0x29)); - ESP_LOGD(TAG, "IMR 0x%04x", esp_eth_smi_read(0x30)); - ESP_LOGD(TAG, "PSCSR 0x%04x", esp_eth_smi_read(0x31)); -} diff --git a/components/ethernet/eth_phy/phy_tlk110.c b/components/ethernet/eth_phy/phy_tlk110.c deleted file mode 100644 index 8e8fd2bfd8..0000000000 --- a/components/ethernet/eth_phy/phy_tlk110.c +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#include "esp_log.h" -#include "esp_eth.h" -#include "eth_phy/phy_reg.h" -#include "eth_phy/phy_tlk110.h" - -#define TLK110_PHY_ID1 0x2000 -#define TLK110_PHY_ID2 0xa210 -#define TLK110_PHY_ID2_MASK 0xFFF0 - -/* TLK110-specific registers */ -#define SW_STRAP_CONTROL_REG (0x9) -#define SW_STRAP_CONFIG_DONE BIT(15) -#define AUTO_MDIX_ENABLE BIT(14) -#define AUTO_NEGOTIATION_ENABLE BIT(13) -#define AN_1 BIT(12) -#define AN_0 BIT(11) -#define LED_CFG BIT(10) -#define RMII_ENHANCED_MODE BIT(9) - -#define DEFAULT_STRAP_CONFIG (AUTO_MDIX_ENABLE | AUTO_NEGOTIATION_ENABLE | AN_1 | AN_0 | LED_CFG) - -#define PHY_STATUS_REG (0x10) -#define AUTO_NEGOTIATION_STATUS BIT(4) -#define DUPLEX_STATUS BIT(2) -#define SPEED_STATUS BIT(1) - -#define CABLE_DIAGNOSTIC_CONTROL_REG (0x1e) -#define DIAGNOSTIC_DONE BIT(1) - -#define PHY_RESET_CONTROL_REG (0x1f) -#define SOFTWARE_RESET BIT(15) - -static const char *TAG = "tlk110"; - -void phy_tlk110_check_phy_init(void) -{ - phy_tlk110_dump_registers(); - - esp_eth_smi_wait_set(MII_BASIC_MODE_STATUS_REG, MII_AUTO_NEGOTIATION_COMPLETE, 0); - esp_eth_smi_wait_set(PHY_STATUS_REG, AUTO_NEGOTIATION_STATUS, 0); - esp_eth_smi_wait_set(CABLE_DIAGNOSTIC_CONTROL_REG, DIAGNOSTIC_DONE, 0); -} - -eth_speed_mode_t phy_tlk110_get_speed_mode(void) -{ - if ((esp_eth_smi_read(PHY_STATUS_REG) & SPEED_STATUS) != SPEED_STATUS) { - ESP_LOGD(TAG, "phy_tlk110_get_speed_mode(100)"); - return ETH_SPEED_MODE_100M; - } else { - ESP_LOGD(TAG, "phy_tlk110_get_speed_mode(10)"); - return ETH_SPEED_MODE_10M; - } -} - -eth_duplex_mode_t phy_tlk110_get_duplex_mode(void) -{ - if ((esp_eth_smi_read(PHY_STATUS_REG) & DUPLEX_STATUS) == DUPLEX_STATUS) { - ESP_LOGD(TAG, "phy_tlk110_get_duplex_mode(FULL)"); - return ETH_MODE_FULLDUPLEX; - } else { - ESP_LOGD(TAG, "phy_tlk110_get_duplex_mode(HALF)"); - return ETH_MODE_HALFDUPLEX; - } -} - -void phy_tlk110_power_enable(bool enable) -{ - if (enable) { - esp_eth_smi_write(SW_STRAP_CONTROL_REG, DEFAULT_STRAP_CONFIG | SW_STRAP_CONFIG_DONE); - - // TODO: only do this if config.flow_ctrl_enable == true - phy_mii_enable_flow_ctrl(); - } -} - -esp_err_t phy_tlk110_init(void) -{ - ESP_LOGD(TAG, "phy_tlk110_init()"); - phy_tlk110_dump_registers(); - - esp_eth_smi_write(PHY_RESET_CONTROL_REG, SOFTWARE_RESET); - - esp_err_t res1, res2; - // Call esp_eth_smi_wait_value() with a timeout so it prints an error periodically - res1 = esp_eth_smi_wait_value(MII_PHY_IDENTIFIER_1_REG, TLK110_PHY_ID1, UINT16_MAX, 1000); - res2 = esp_eth_smi_wait_value(MII_PHY_IDENTIFIER_2_REG, TLK110_PHY_ID2, TLK110_PHY_ID2_MASK, 1000); - - esp_eth_smi_write(SW_STRAP_CONTROL_REG, - DEFAULT_STRAP_CONFIG | SW_STRAP_CONFIG_DONE); - - ets_delay_us(300); - - // TODO: only do this if config.flow_ctrl_enable == true - phy_mii_enable_flow_ctrl(); - - if (res1 == ESP_OK && res2 == ESP_OK) { - return ESP_OK; - } else { - return ESP_ERR_TIMEOUT; - } -} - -const eth_config_t phy_tlk110_default_ethernet_config = { - .phy_addr = 0x1, - .mac_mode = ETH_MODE_RMII, - .clock_mode = ETH_CLOCK_GPIO0_IN, - .flow_ctrl_enable = true, - .phy_init = phy_tlk110_init, - .phy_check_init = phy_tlk110_check_phy_init, - .phy_check_link = phy_mii_check_link_status, - .phy_get_speed_mode = phy_tlk110_get_speed_mode, - .phy_get_duplex_mode = phy_tlk110_get_duplex_mode, - .phy_get_partner_pause_enable = phy_mii_get_partner_pause_enable, - .phy_power_enable = phy_tlk110_power_enable, - .reset_timeout_ms = 1000, - .promiscuous_enable = false, -}; - -void phy_tlk110_dump_registers() -{ - ESP_LOGD(TAG, "TLK110 Registers:"); - ESP_LOGD(TAG, "BMCR 0x%04x", esp_eth_smi_read(0x0)); - ESP_LOGD(TAG, "BMSR 0x%04x", esp_eth_smi_read(0x1)); - ESP_LOGD(TAG, "PHYIDR1 0x%04x", esp_eth_smi_read(0x2)); - ESP_LOGD(TAG, "PHYIDR2 0x%04x", esp_eth_smi_read(0x3)); - ESP_LOGD(TAG, "ANAR 0x%04x", esp_eth_smi_read(0x4)); - ESP_LOGD(TAG, "ANLPAR 0x%04x", esp_eth_smi_read(0x5)); - ESP_LOGD(TAG, "ANER 0x%04x", esp_eth_smi_read(0x6)); - ESP_LOGD(TAG, "ANNPTR 0x%04x", esp_eth_smi_read(0x7)); - ESP_LOGD(TAG, "ANLNPTR 0x%04x", esp_eth_smi_read(0x8)); - ESP_LOGD(TAG, "SWSCR1 0x%04x", esp_eth_smi_read(0x9)); - ESP_LOGD(TAG, "SWSCR2 0x%04x", esp_eth_smi_read(0xa)); - ESP_LOGD(TAG, "SWSCR3 0x%04x", esp_eth_smi_read(0xb)); - ESP_LOGD(TAG, "REGCR 0x%04x", esp_eth_smi_read(0xd)); - ESP_LOGD(TAG, "ADDAR 0x%04x", esp_eth_smi_read(0xe)); - ESP_LOGD(TAG, "PHYSTS 0x%04x", esp_eth_smi_read(0x10)); - ESP_LOGD(TAG, "PHYSCR 0x%04x", esp_eth_smi_read(0x11)); - ESP_LOGD(TAG, "MISR1 0x%04x", esp_eth_smi_read(0x12)); - ESP_LOGD(TAG, "MISR2 0x%04x", esp_eth_smi_read(0x13)); - ESP_LOGD(TAG, "FCSCR 0x%04x", esp_eth_smi_read(0x14)); - ESP_LOGD(TAG, "RECR 0x%04x", esp_eth_smi_read(0x15)); - ESP_LOGD(TAG, "BISCR 0x%04x", esp_eth_smi_read(0x16)); - ESP_LOGD(TAG, "RBR 0x%04x", esp_eth_smi_read(0x17)); - ESP_LOGD(TAG, "LEDCR 0x%04x", esp_eth_smi_read(0x18)); - ESP_LOGD(TAG, "PHYCR 0x%04x", esp_eth_smi_read(0x19)); - ESP_LOGD(TAG, "10BTSCR 0x%04x", esp_eth_smi_read(0x1a)); - ESP_LOGD(TAG, "BICSR1 0x%04x", esp_eth_smi_read(0x1b)); - ESP_LOGD(TAG, "BICSR2 0x%04x", esp_eth_smi_read(0x1c)); - ESP_LOGD(TAG, "CDCR 0x%04x", esp_eth_smi_read(0x1e)); - ESP_LOGD(TAG, "TRXCPSR 0x%04x", esp_eth_smi_read(0x42)); - ESP_LOGD(TAG, "PWRBOCR 0x%04x", esp_eth_smi_read(0xae)); - ESP_LOGD(TAG, "VRCR 0x%04x", esp_eth_smi_read(0xD0)); - ESP_LOGD(TAG, "ALCDRR1 0x%04x", esp_eth_smi_read(0x155)); - ESP_LOGD(TAG, "CDSCR1 0x%04x", esp_eth_smi_read(0x170)); - ESP_LOGD(TAG, "CDSCR2 0x%04x", esp_eth_smi_read(0x171)); -} diff --git a/components/ethernet/include/esp_eth.h b/components/ethernet/include/esp_eth.h deleted file mode 100644 index de9a07863f..0000000000 --- a/components/ethernet/include/esp_eth.h +++ /dev/null @@ -1,322 +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 __ESP_ETH_H__ -#define __ESP_ETH_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include "esp_event_base.h" -#include "esp_types.h" -#include "esp_err.h" - -/** - * @brief Ethernet interface mode - * - */ -typedef enum { - ETH_MODE_RMII = 0, /*!< RMII mode */ - ETH_MODE_MII, /*!< MII mode */ -} eth_mode_t; - -/** - * @brief Ethernet clock mode - * - */ -typedef enum { - ETH_CLOCK_GPIO0_IN = 0, /*!< RMII clock input to GPIO0 */ - ETH_CLOCK_GPIO0_OUT = 1, /*!< RMII clock output from GPIO0 */ - ETH_CLOCK_GPIO16_OUT = 2, /*!< RMII clock output from GPIO16 */ - ETH_CLOCK_GPIO17_OUT = 3 /*!< RMII clock output from GPIO17 */ -} eth_clock_mode_t; - -/** - * @brief Ethernet Speed - * - */ -typedef enum { - ETH_SPEED_MODE_10M = 0, /*!< Ethernet speed: 10Mbps */ - ETH_SPEED_MODE_100M, /*!< Ethernet speed: 100Mbps */ -} eth_speed_mode_t; - -/** - * @brief Ethernet Duplex - * - */ -typedef enum { - ETH_MODE_HALFDUPLEX = 0, /*!< Ethernet half duplex */ - ETH_MODE_FULLDUPLEX, /*!< Ethernet full duplex */ -} eth_duplex_mode_t; - -/** - * @brief Ethernet PHY address - * - */ -typedef enum { - PHY0 = 0, /*!< PHY address 0 */ - PHY1, /*!< PHY address 1 */ - PHY2, /*!< PHY address 2 */ - PHY3, /*!< PHY address 3 */ - PHY4, /*!< PHY address 4 */ - PHY5, /*!< PHY address 5 */ - PHY6, /*!< PHY address 6 */ - PHY7, /*!< PHY address 7 */ - PHY8, /*!< PHY address 8 */ - PHY9, /*!< PHY address 9 */ - PHY10, /*!< PHY address 10 */ - PHY11, /*!< PHY address 11 */ - PHY12, /*!< PHY address 12 */ - PHY13, /*!< PHY address 13 */ - PHY14, /*!< PHY address 14 */ - PHY15, /*!< PHY address 15 */ - PHY16, /*!< PHY address 16 */ - PHY17, /*!< PHY address 17 */ - PHY18, /*!< PHY address 18 */ - PHY19, /*!< PHY address 19 */ - PHY20, /*!< PHY address 20 */ - PHY21, /*!< PHY address 21 */ - PHY22, /*!< PHY address 22 */ - PHY23, /*!< PHY address 23 */ - PHY24, /*!< PHY address 24 */ - PHY25, /*!< PHY address 25 */ - PHY26, /*!< PHY address 26 */ - PHY27, /*!< PHY address 27 */ - PHY28, /*!< PHY address 28 */ - PHY29, /*!< PHY address 29 */ - PHY30, /*!< PHY address 30 */ - PHY31 /*!< PHY address 31 */ -} eth_phy_base_t; - -typedef bool (*eth_phy_check_link_func)(void); -typedef void (*eth_phy_check_init_func)(void); -typedef eth_speed_mode_t (*eth_phy_get_speed_mode_func)(void); -typedef eth_duplex_mode_t (*eth_phy_get_duplex_mode_func)(void); -typedef esp_err_t (*eth_phy_func)(void); -typedef esp_err_t (*eth_tcpip_input_func)(void *buffer, uint16_t len, void *eb); -typedef void (*eth_gpio_config_func)(void); -typedef bool (*eth_phy_get_partner_pause_enable_func)(void); -typedef void (*eth_phy_power_enable_func)(bool enable); - -/** - * @brief ethernet configuration - * - */ -typedef struct { - eth_phy_base_t phy_addr; /*!< PHY address (0~31) */ - eth_mode_t mac_mode; /*!< MAC mode: only support RMII now */ - eth_clock_mode_t clock_mode; /*!< external/internal clock mode selection */ - eth_tcpip_input_func tcpip_input; /*!< tcpip input func */ - eth_phy_func phy_init; /*!< phy init func */ - eth_phy_check_link_func phy_check_link; /*!< phy check link func */ - eth_phy_check_init_func phy_check_init; /*!< phy check init func */ - eth_phy_get_speed_mode_func phy_get_speed_mode; /*!< phy check init func */ - eth_phy_get_duplex_mode_func phy_get_duplex_mode; /*!< phy check init func */ - eth_gpio_config_func gpio_config; /*!< gpio config func */ - bool flow_ctrl_enable; /*!< flag of flow ctrl enable */ - eth_phy_get_partner_pause_enable_func phy_get_partner_pause_enable; /*!< get partner pause enable */ - eth_phy_power_enable_func phy_power_enable; /*!< enable or disable phy power */ - uint32_t reset_timeout_ms; /*!< timeout value for reset emac */ - bool promiscuous_enable; /*!< set true to enable promiscuous mode */ -} eth_config_t; - -/** Ethernet event declarations */ -typedef enum { - ETHERNET_EVENT_START, /**< ESP32 ethernet start */ - ETHERNET_EVENT_STOP, /**< ESP32 ethernet stop */ - ETHERNET_EVENT_CONNECTED, /**< ESP32 ethernet phy link up */ - ETHERNET_EVENT_DISCONNECTED, /**< ESP32 ethernet phy link down */ -} eth_event_t; - -/** @brief Ethernet event base declaration */ -ESP_EVENT_DECLARE_BASE(ETH_EVENT); - -/** - * @brief Init ethernet mac - * - * @note config can not be NULL, and phy chip must be suitable to phy init func. - * - * @param[in] config mac init data. - * - * @return - * - ESP_OK - * - ESP_FAIL - */ -esp_err_t esp_eth_init(eth_config_t *config); - -/** - * @brief Deinit ethernet mac - * - * @return - * - ESP_OK - * - ESP_FAIL - * - ESP_ERR_INVALID_STATE - */ -esp_err_t esp_eth_deinit(void); - -/** - * @brief Init Ethernet mac driver only - * - * For the most part, you need not call this function directly. It gets called - * from esp_eth_init(). - * - * This function may be called, if you only need to initialize the Ethernet - * driver without having to use the network stack on top. - * - * @note config can not be NULL, and phy chip must be suitable to phy init func. - * @param[in] config mac init data. - * - * @return - * - ESP_OK - * - ESP_FAIL - */ -esp_err_t esp_eth_init_internal(eth_config_t *config); - -/** - * @brief Send packet from tcp/ip to mac - * - * @note buf can not be NULL, size must be less than 1580 - * - * @param[in] buf: start address of packet data. - * - * @param[in] size: size (byte) of packet data. - * - * @return - * - ESP_OK - * - ESP_FAIL - */ -esp_err_t esp_eth_tx(uint8_t *buf, uint16_t size); - -/** - * @brief Enable ethernet interface - * - * @note Should be called after esp_eth_init - * - * @return - * - ESP_OK - * - ESP_FAIL - */ -esp_err_t esp_eth_enable(void); - -/** - * @brief Disable ethernet interface - * - * @note Should be called after esp_eth_init - * - * @return - * - ESP_OK - * - ESP_FAIL - */ -esp_err_t esp_eth_disable(void); - -/** - * @brief Get mac addr - * - * @note mac addr must be a valid unicast address - * - * @param[out] mac: start address of mac address. - */ -void esp_eth_get_mac(uint8_t mac[6]); - -/** - * @brief Write PHY reg with SMI interface. - * - * @note PHY base addr must be right. - * - * @param[in] reg_num: PHY reg num. - * - * @param[in] value: value which is written to PHY reg. - */ -void esp_eth_smi_write(uint32_t reg_num, uint16_t value); - -/** - * @brief Read PHY reg with SMI interface. - * - * @note PHY base addr must be right. - * - * @param[in] reg_num: PHY reg num. - * - * @return value that is read from PHY reg - */ -uint16_t esp_eth_smi_read(uint32_t reg_num); - -/** - * @brief Continuously read a PHY register over SMI interface, wait until the register has the desired value. - * - * @note PHY base address must be right. - * - * @param reg_num: PHY register number - * @param value: Value to wait for (masked with value_mask) - * @param value_mask: Mask of bits to match in the register. - * @param timeout_ms: Timeout to wait for this value (milliseconds). 0 means never timeout. - * - * @return ESP_OK if desired value matches, ESP_ERR_TIMEOUT if timed out. - */ -esp_err_t esp_eth_smi_wait_value(uint32_t reg_num, uint16_t value, uint16_t value_mask, int timeout_ms); - -/** - * @brief Continuously read a PHY register over SMI interface, wait until the register has all bits in a mask set. - * - * @note PHY base address must be right. - * - * @param reg_num: PHY register number - * @param value_mask: Value mask to wait for (all bits in this mask must be set) - * @param timeout_ms: Timeout to wait for this value (milliseconds). 0 means never timeout. - * - * @return ESP_OK if desired value matches, ESP_ERR_TIMEOUT if timed out. - */ -static inline esp_err_t esp_eth_smi_wait_set(uint32_t reg_num, uint16_t value_mask, int timeout_ms) -{ - return esp_eth_smi_wait_value(reg_num, value_mask, value_mask, timeout_ms); -} - -/** - * @brief Free emac rx buf. - * - * @note buf can not be null, and it is tcpip input buf. - * - * @param[in] buf: start address of received packet data. - * - */ -void esp_eth_free_rx_buf(void *buf); - -/** - * @brief Set mac of ethernet interface. - * - * @note user can call this function after emac_init, and the new mac address will be enabled after emac_enable. - * - * @param[in] mac: the Mac address. - * - * @return - * - ESP_OK: succeed - * - ESP_ERR_INVALID_MAC: invalid mac address - */ -esp_err_t esp_eth_set_mac(const uint8_t mac[6]); - -/** - * @brief Get Ethernet link speed - * - * @return eth_speed_mode_t ETH_SPEED_MODE_10M when link speed is 10Mbps - * ETH_SPEED_MODE_100M when link speed is 100Mbps - */ -eth_speed_mode_t esp_eth_get_speed(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/components/ethernet/include/eth_phy/phy.h b/components/ethernet/include/eth_phy/phy.h deleted file mode 100644 index d38e9819d6..0000000000 --- a/components/ethernet/include/eth_phy/phy.h +++ /dev/null @@ -1,76 +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. - -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#include "esp_eth.h" - -/** - * @brief Common PHY-management functions. - * - * @note These are not enough to drive any particular Ethernet PHY. - * They provide a common configuration structure and management functions. - * - */ - -/** - * @brief Configure fixed pins for RMII data interface. - * - * @note This configures GPIOs 0, 19, 22, 25, 26, 27 for use with RMII data interface. - * These pins cannot be changed, and must be wired to ethernet functions. - * This is not sufficient to fully configure the Ethernet PHY. - * MDIO configuration interface pins (such as SMI MDC, MDO, MDI) must also be configured correctly in the GPIO matrix. - * - */ -void phy_rmii_configure_data_interface_pins(void); - -/** - * @brief Configure variable pins for SMI ethernet functions. - * - * @param mdc_gpio MDC GPIO Pin number - * @param mdio_gpio MDIO GPIO Pin number - * - * @note Calling this function along with mii_configure_default_pins() will fully configure the GPIOs for the ethernet PHY. - */ -void phy_rmii_smi_configure_pins(uint8_t mdc_gpio, uint8_t mdio_gpio); - -/** - * @brief Enable flow control in standard PHY MII register. - * - */ -void phy_mii_enable_flow_ctrl(void); - -/** - * @brief Check Ethernet link status via MII interface - * - * @return true Link is on - * @return false Link is off - */ -bool phy_mii_check_link_status(void); - -/** - * @brief Check pause frame ability of partner via MII interface - * - * @return true Partner is able to process pause frame - * @return false Partner can not process pause frame - */ -bool phy_mii_get_partner_pause_enable(void); - -#ifdef __cplusplus -} -#endif diff --git a/components/ethernet/include/eth_phy/phy_ip101.h b/components/ethernet/include/eth_phy/phy_ip101.h deleted file mode 100644 index d18ef2d096..0000000000 --- a/components/ethernet/include/eth_phy/phy_ip101.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#include "phy.h" - -/** - * @brief Dump IP101 PHY SMI configuration registers - * - */ -void phy_ip101_dump_registers(); - -/** - * @brief Default IP101 phy_check_init function - * - */ -void phy_ip101_check_phy_init(void); - -/** - * @brief Default IP101 phy_get_speed_mode function - * - * @return eth_speed_mode_t Ethernet speed mode - */ -eth_speed_mode_t phy_ip101_get_speed_mode(void); - -/** - * @brief Default IP101 phy_get_duplex_mode function - * - * @return eth_duplex_mode_t Ethernet duplex mode - */ -eth_duplex_mode_t phy_ip101_get_duplex_mode(void); - -/** - * @brief Default IP101 phy_power_enable function - * - */ -void phy_ip101_power_enable(bool); - -/** - * @brief Default IP101 phy_init function - * - * @return esp_err_t - * - ESP_OK on success - * - ESP_FAIL on error - */ -esp_err_t phy_ip101_init(void); - -/** - * @brief Default IP101 PHY configuration - * - * @note This configuration is not suitable for use as-is, - * it will need to be modified for your particular PHY hardware setup. - * - */ -extern const eth_config_t phy_ip101_default_ethernet_config; - -#ifdef __cplusplus -} -#endif diff --git a/components/ethernet/include/eth_phy/phy_lan8720.h b/components/ethernet/include/eth_phy/phy_lan8720.h deleted file mode 100644 index 1448f36556..0000000000 --- a/components/ethernet/include/eth_phy/phy_lan8720.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#include "phy.h" - -/** - * @brief Dump LAN8720 PHY SMI configuration registers - * - */ -void phy_lan8720_dump_registers(); - -/** - * @brief Default LAN8720 phy_check_init function - * - */ -void phy_lan8720_check_phy_init(void); - -/** - * @brief Default LAN8720 phy_get_speed_mode function - * - * @return eth_speed_mode_t Ethernet speed mode - */ -eth_speed_mode_t phy_lan8720_get_speed_mode(void); - -/** - * @brief Default LAN8720 phy_get_duplex_mode function - * - * @return eth_duplex_mode_t Ethernet duplex mode - */ -eth_duplex_mode_t phy_lan8720_get_duplex_mode(void); - -/** - * @brief Default LAN8720 phy_power_enable function - * - */ -void phy_lan8720_power_enable(bool); - -/** - * @brief Default LAN8720 phy_init function - * - * @return esp_err_t - * - ESP_OK on success - * - ESP_FAIL on error - */ -esp_err_t phy_lan8720_init(void); - -/** - * @brief Default LAN8720 PHY configuration - * - * @note This configuration is not suitable for use as-is, - * it will need to be modified for your particular PHY hardware setup. - * - */ -extern const eth_config_t phy_lan8720_default_ethernet_config; - -#ifdef __cplusplus -} -#endif diff --git a/components/ethernet/include/eth_phy/phy_reg.h b/components/ethernet/include/eth_phy/phy_reg.h deleted file mode 100644 index b7aad89106..0000000000 --- a/components/ethernet/include/eth_phy/phy_reg.h +++ /dev/null @@ -1,56 +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. - -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/** - * @brief This header contains register/bit masks for the standard PHY MII registers that should be supported by all PHY models. - * - */ - -#define MII_BASIC_MODE_CONTROL_REG (0x0) -#define MII_SOFTWARE_RESET BIT(15) -#define MII_SPEED_SELECT BIT(13) -#define MII_AUTO_NEGOTIATION_ENABLE BIT(12) -#define MII_POWER_DOWN BIT(11) -#define MII_RESTART_AUTO_NEGOTIATION BIT(9) -#define MII_DUPLEX_MODE BIT(8) - -#define MII_BASIC_MODE_STATUS_REG (0x1) -#define MII_AUTO_NEGOTIATION_COMPLETE BIT(5) -#define MII_LINK_STATUS BIT(2) - -#define MII_PHY_IDENTIFIER_1_REG (0x2) -#define MII_PHY_IDENTIFIER_2_REG (0x3) - -#define MII_AUTO_NEGOTIATION_ADVERTISEMENT_REG (0x4) -#define MII_ASM_DIR BIT(11) -#define MII_PAUSE BIT(10) - -#define MII_PHY_LINK_PARTNER_ABILITY_REG (0x5) -#define MII_PARTNER_ASM_DIR BIT(11) -#define MII_PARTNER_PAUSE BIT(10) - -/******************************legacy*******************************/ -#define MII_AUTO_NEG_ADVERTISEMENT_REG MII_AUTO_NEGOTIATION_ADVERTISEMENT_REG - -#ifdef __cplusplus -} -#endif diff --git a/components/ethernet/include/eth_phy/phy_tlk110.h b/components/ethernet/include/eth_phy/phy_tlk110.h deleted file mode 100644 index 077f13cece..0000000000 --- a/components/ethernet/include/eth_phy/phy_tlk110.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#include "phy.h" - -/** - * @brief Dump TLK110 PHY SMI configuration registers - * - */ -void phy_tlk110_dump_registers(); - -/** - * @brief Default TLK110 phy_check_init function - * - */ -void phy_tlk110_check_phy_init(void); - -/** - * @brief Default TLK110 phy_get_speed_mode function - * - * @return eth_speed_mode_t Ethernet speed mode - */ -eth_speed_mode_t phy_tlk110_get_speed_mode(void); - -/** - * @brief Default TLK110 phy_get_duplex_mode function - * - * @return eth_duplex_mode_t Ethernet duplex mode - */ -eth_duplex_mode_t phy_tlk110_get_duplex_mode(void); - -/** - * @brief Default TLK110 phy_power_enable function - * - */ -void phy_tlk110_power_enable(bool); - -/** - * @brief Default TLK110 phy_init function - * - * @return esp_err_t - * - ESP_OK on success - * - ESP_FAIL on error - */ -esp_err_t phy_tlk110_init(void); - -/** - * @brief Default TLK110 PHY configuration - * - * @note This configuration is not suitable for use as-is, - * it will need to be modified for your particular PHY hardware setup. - * - */ -extern const eth_config_t phy_tlk110_default_ethernet_config; - -#ifdef __cplusplus -} -#endif diff --git a/components/ethernet/sdkconfig.rename b/components/ethernet/sdkconfig.rename deleted file mode 100644 index d70ede3150..0000000000 --- a/components/ethernet/sdkconfig.rename +++ /dev/null @@ -1,9 +0,0 @@ -# sdkconfig replacement configurations for deprecated options formatted as -# CONFIG_DEPRECATED_OPTION CONFIG_NEW_OPTION - -CONFIG_DMA_RX_BUF_NUM CONFIG_ETH_DMA_RX_BUF_NUM -CONFIG_DMA_TX_BUF_NUM CONFIG_ETH_DMA_TX_BUF_NUM -CONFIG_EMAC_L2_TO_L3_RX_BUF_MODE CONFIG_ETH_EMAC_L2_TO_L3_RX_BUF_MODE -CONFIG_EMAC_CHECK_LINK_PERIOD_MS CONFIG_ETH_CHECK_LINK_STATUS_PERIOD_MS -CONFIG_EMAC_TASK_PRIORITY CONFIG_ETH_EMAC_TASK_PRIORITY -CONFIG_EMAC_TASK_STACK_SIZE CONFIG_ETH_EMAC_TASK_STACK_SIZE diff --git a/components/ethernet/test/CMakeLists.txt b/components/ethernet/test/CMakeLists.txt deleted file mode 100644 index d5d44577ae..0000000000 --- a/components/ethernet/test/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") -set(COMPONENT_REQUIRES unity ethernet) - -register_component() \ No newline at end of file diff --git a/components/ethernet/test/test_emac_deinit.c b/components/ethernet/test/test_emac_deinit.c deleted file mode 100644 index 0468a474be..0000000000 --- a/components/ethernet/test/test_emac_deinit.c +++ /dev/null @@ -1,133 +0,0 @@ -/** - * @brief This test has just run in the ESP32_Ethernet_V3 board, which featured - * in PoE submodule and TLK110 PHY. The 50MHz clock used by MAC and PHY is - * supplied by external oscillator through GPIO0. - * - * @file test_emac_deinit.c - * @author morris - * @date 2018-08-24 - */ -#include -#include - -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/event_groups.h" -#include "esp_system.h" -#include "esp_err.h" -#include "esp_event_loop.h" -#include "esp_event.h" -#include "esp_log.h" -#include "esp_eth.h" -#include "unity.h" - -#include "esp32/rom/gpio.h" - -#include "tcpip_adapter.h" -#include "driver/gpio.h" -#include "driver/periph_ctrl.h" - -#include "eth_phy/phy_tlk110.h" - -#define DEFAULT_ETHERNET_PHY_CONFIG phy_tlk110_default_ethernet_config - -static const char *TAG = "eth_test_deinit"; - -#define PIN_PHY_POWER 17 -#define PIN_SMI_MDC 23 -#define PIN_SMI_MDIO 18 -#define CONFIG_PHY_ADDRESS 31 -#define CONFIG_PHY_CLOCK_MODE 0 - -static EventGroupHandle_t eth_event_group = NULL; -static const int GOTIP_BIT = BIT0; - -static void phy_device_power_enable_via_gpio(bool enable) -{ - if (!enable) { - DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable(false); - } - - gpio_pad_select_gpio(PIN_PHY_POWER); - gpio_set_direction(PIN_PHY_POWER, GPIO_MODE_OUTPUT); - if (enable == true) { - gpio_set_level(PIN_PHY_POWER, 1); - ESP_LOGI(TAG, "power on ethernet phy"); - } else { - gpio_set_level(PIN_PHY_POWER, 0); - ESP_LOGI(TAG, "power off ethernet phy"); - } - - vTaskDelay(1); // Allow the power up/down to take effect, min 300us - - if (enable) { - /* operates the default phy-specific power on function */ - DEFAULT_ETHERNET_PHY_CONFIG.phy_power_enable(true); - } -} - -static void eth_gpio_config_rmii(void) -{ - phy_rmii_configure_data_interface_pins(); - phy_rmii_smi_configure_pins(PIN_SMI_MDC, PIN_SMI_MDIO); -} - -static esp_err_t eth_event_handler(void *ctx, system_event_t *event) -{ - tcpip_adapter_ip_info_t ip; - - switch (event->event_id) { - case SYSTEM_EVENT_ETH_CONNECTED: - ESP_LOGI(TAG, "Ethernet Link Up"); - break; - case SYSTEM_EVENT_ETH_DISCONNECTED: - ESP_LOGI(TAG, "Ethernet Link Down"); - break; - case SYSTEM_EVENT_ETH_START: - ESP_LOGI(TAG, "Ethernet Started"); - break; - case SYSTEM_EVENT_ETH_GOT_IP: - memset(&ip, 0, sizeof(tcpip_adapter_ip_info_t)); - ESP_ERROR_CHECK(tcpip_adapter_get_ip_info(ESP_IF_ETH, &ip)); - ESP_LOGI(TAG, "Ethernet Got IP Addr"); - ESP_LOGI(TAG, "~~~~~~~~~~~"); - ESP_LOGI(TAG, "ETHIP:" IPSTR, IP2STR(&ip.ip)); - ESP_LOGI(TAG, "ETHMASK:" IPSTR, IP2STR(&ip.netmask)); - ESP_LOGI(TAG, "ETHGW:" IPSTR, IP2STR(&ip.gw)); - ESP_LOGI(TAG, "~~~~~~~~~~~"); - xEventGroupSetBits(eth_event_group, GOTIP_BIT); - break; - case SYSTEM_EVENT_ETH_STOP: - ESP_LOGI(TAG, "Ethernet Stopped"); - break; - default: - break; - } - return ESP_OK; -} - -TEST_CASE("start event loop", "[ethernet][ignore]") -{ - eth_event_group = xEventGroupCreate(); - tcpip_adapter_init(); - ESP_ERROR_CHECK(esp_event_loop_init(eth_event_handler, NULL)); -} - -TEST_CASE("test emac deinit", "[ethernet][ignore]") -{ - eth_config_t config = DEFAULT_ETHERNET_PHY_CONFIG; - config.phy_addr = CONFIG_PHY_ADDRESS; - config.gpio_config = eth_gpio_config_rmii; - config.tcpip_input = tcpip_adapter_eth_input; - config.clock_mode = CONFIG_PHY_CLOCK_MODE; - config.phy_power_enable = phy_device_power_enable_via_gpio; - - ESP_ERROR_CHECK(esp_eth_init(&config)); - ESP_ERROR_CHECK(esp_eth_enable()); - - xEventGroupWaitBits(eth_event_group, GOTIP_BIT, true, true, portMAX_DELAY); - vTaskDelay(15000 / portTICK_RATE_MS); - - ESP_ERROR_CHECK(esp_eth_disable()); - ESP_ERROR_CHECK(esp_eth_deinit()); -} diff --git a/components/expat/CMakeLists.txt b/components/expat/CMakeLists.txt index 596aee917c..a6c5882c79 100644 --- a/components/expat/CMakeLists.txt +++ b/components/expat/CMakeLists.txt @@ -1,11 +1,10 @@ -set(COMPONENT_ADD_INCLUDEDIRS expat/expat/lib port/include) -set(COMPONENT_SRCS "expat/expat/lib/loadlibrary.c" - "expat/expat/lib/xmlparse.c" - "expat/expat/lib/xmlrole.c" - "expat/expat/lib/xmltok.c" - "expat/expat/lib/xmltok_impl.c" - "expat/expat/lib/xmltok_ns.c") -register_component() +idf_component_register(SRCS "expat/expat/lib/loadlibrary.c" + "expat/expat/lib/xmlparse.c" + "expat/expat/lib/xmlrole.c" + "expat/expat/lib/xmltok.c" + "expat/expat/lib/xmltok_impl.c" + "expat/expat/lib/xmltok_ns.c" + INCLUDE_DIRS expat/expat/lib port/include) target_compile_definitions(${COMPONENT_LIB} PRIVATE HAVE_EXPAT_CONFIG_H) target_compile_definitions(${COMPONENT_LIB} PRIVATE HAVE_GETRANDOM) diff --git a/components/expat/test/CMakeLists.txt b/components/expat/test/CMakeLists.txt index be2a822177..28d0afb413 100644 --- a/components/expat/test/CMakeLists.txt +++ b/components/expat/test/CMakeLists.txt @@ -1,5 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") -set(COMPONENT_REQUIRES unity expat) - -register_component() +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity expat) \ No newline at end of file diff --git a/components/fatfs/CMakeLists.txt b/components/fatfs/CMakeLists.txt index 4df07d30b9..2cd91bf005 100644 --- a/components/fatfs/CMakeLists.txt +++ b/components/fatfs/CMakeLists.txt @@ -1,15 +1,12 @@ -set(COMPONENT_SRCS "src/diskio.c" - "src/diskio_rawflash.c" - "src/diskio_sdmmc.c" - "src/diskio_wl.c" - "src/ff.c" - "src/ffsystem.c" - "src/ffunicode.c" - "src/vfs_fat.c" - "src/vfs_fat_sdmmc.c" - "src/vfs_fat_spiflash.c") -set(COMPONENT_ADD_INCLUDEDIRS src) - -set(COMPONENT_REQUIRES wear_levelling sdmmc) - -register_component() +idf_component_register(SRCS "diskio/diskio.c" + "diskio/diskio_rawflash.c" + "diskio/diskio_sdmmc.c" + "diskio/diskio_wl.c" + "src/ff.c" + "port/freertos/ffsystem.c" + "src/ffunicode.c" + "vfs/vfs_fat.c" + "vfs/vfs_fat_sdmmc.c" + "vfs/vfs_fat_spiflash.c" + INCLUDE_DIRS diskio vfs src + REQUIRES wear_levelling sdmmc) diff --git a/components/fatfs/component.mk b/components/fatfs/component.mk index 591e080c62..bf33270c13 100644 --- a/components/fatfs/component.mk +++ b/components/fatfs/component.mk @@ -1,2 +1,3 @@ -COMPONENT_ADD_INCLUDEDIRS := src -COMPONENT_SRCDIRS := src/option src +COMPONENT_ADD_INCLUDEDIRS := diskio vfs src +COMPONENT_SRCDIRS := diskio vfs port/freertos src +COMPONENT_OBJEXCLUDE := src/diskio.o src/ffsystem.o diff --git a/components/fatfs/diskio/diskio.c b/components/fatfs/diskio/diskio.c new file mode 100644 index 0000000000..c8075166d6 --- /dev/null +++ b/components/fatfs/diskio/diskio.c @@ -0,0 +1,93 @@ +/*-----------------------------------------------------------------------*/ +/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2016 */ +/* ESP-IDF port Copyright 2016 Espressif Systems (Shanghai) PTE LTD */ +/*-----------------------------------------------------------------------*/ +/* If a working storage control module is available, it should be */ +/* attached to the FatFs via a glue function rather than modifying it. */ +/* This is an example of glue functions to attach various exsisting */ +/* storage control modules to the FatFs module with a defined API. */ +/*-----------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include "diskio_impl.h" +#include "ffconf.h" +#include "ff.h" + +static ff_diskio_impl_t * s_impls[FF_VOLUMES] = { NULL }; + +#if FF_MULTI_PARTITION /* Multiple partition configuration */ +PARTITION VolToPart[] = { + {0, 0}, /* Logical drive 0 ==> Physical drive 0, auto detection */ + {1, 0} /* Logical drive 1 ==> Physical drive 1, auto detection */ +}; +#endif + +esp_err_t ff_diskio_get_drive(BYTE* out_pdrv) +{ + BYTE i; + for(i=0; iinit(pdrv); +} +DSTATUS ff_disk_status (BYTE pdrv) +{ + return s_impls[pdrv]->status(pdrv); +} +DRESULT ff_disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count) +{ + return s_impls[pdrv]->read(pdrv, buff, sector, count); +} +DRESULT ff_disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) +{ + return s_impls[pdrv]->write(pdrv, buff, sector, count); +} +DRESULT ff_disk_ioctl (BYTE pdrv, BYTE cmd, void* buff) +{ + return s_impls[pdrv]->ioctl(pdrv, cmd, buff); +} + +DWORD get_fattime(void) +{ + time_t t = time(NULL); + struct tm tmr; + localtime_r(&t, &tmr); + int year = tmr.tm_year < 80 ? 0 : tmr.tm_year - 80; + return ((DWORD)(year) << 25) + | ((DWORD)(tmr.tm_mon + 1) << 21) + | ((DWORD)tmr.tm_mday << 16) + | (WORD)(tmr.tm_hour << 11) + | (WORD)(tmr.tm_min << 5) + | (WORD)(tmr.tm_sec >> 1); +} diff --git a/components/fatfs/diskio/diskio_impl.h b/components/fatfs/diskio/diskio_impl.h new file mode 100644 index 0000000000..76c246dd8c --- /dev/null +++ b/components/fatfs/diskio/diskio_impl.h @@ -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. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +typedef unsigned int UINT; +typedef unsigned char BYTE; +typedef uint32_t DWORD; + +#include "diskio.h" +#include "esp_err.h" + +/** + * Structure of pointers to disk IO driver functions. + * + * See FatFs documentation for details about these functions + */ +typedef struct { + DSTATUS (*init) (unsigned char pdrv); /*!< disk initialization function */ + DSTATUS (*status) (unsigned char pdrv); /*!< disk status check function */ + DRESULT (*read) (unsigned char pdrv, unsigned char* buff, uint32_t sector, unsigned count); /*!< sector read function */ + DRESULT (*write) (unsigned char pdrv, const unsigned char* buff, uint32_t sector, unsigned count); /*!< sector write function */ + DRESULT (*ioctl) (unsigned char pdrv, unsigned char cmd, void* buff); /*!< function to get info about disk and do some misc operations */ +} ff_diskio_impl_t; + +/** + * Register or unregister diskio driver for given drive number. + * + * When FATFS library calls one of disk_xxx functions for driver number pdrv, + * corresponding function in discio_impl for given pdrv will be called. + * + * @param pdrv drive number + * @param discio_impl pointer to ff_diskio_impl_t structure with diskio functions + * or NULL to unregister and free previously registered drive + */ +void ff_diskio_register(BYTE pdrv, const ff_diskio_impl_t* discio_impl); + +#define ff_diskio_unregister(pdrv_) ff_diskio_register(pdrv_, NULL) + + +/** + * Get next available drive number + * + * @param out_pdrv pointer to the byte to set if successful + * + * @return ESP_OK on success + * ESP_ERR_NOT_FOUND if all drives are attached + */ +esp_err_t ff_diskio_get_drive(BYTE* out_pdrv); + + +#ifdef __cplusplus +} +#endif + diff --git a/components/fatfs/src/diskio_rawflash.c b/components/fatfs/diskio/diskio_rawflash.c similarity index 99% rename from components/fatfs/src/diskio_rawflash.c rename to components/fatfs/diskio/diskio_rawflash.c index bc3b204b50..363bd9b328 100644 --- a/components/fatfs/src/diskio_rawflash.c +++ b/components/fatfs/diskio/diskio_rawflash.c @@ -13,7 +13,7 @@ // limitations under the License. #include -#include "diskio.h" +#include "diskio_impl.h" #include "ffconf.h" #include "ff.h" #include "esp_log.h" diff --git a/components/fatfs/src/diskio_rawflash.h b/components/fatfs/diskio/diskio_rawflash.h similarity index 84% rename from components/fatfs/src/diskio_rawflash.h rename to components/fatfs/diskio/diskio_rawflash.h index a7b61a4708..73ff15f881 100644 --- a/components/fatfs/src/diskio_rawflash.h +++ b/components/fatfs/diskio/diskio_rawflash.h @@ -19,7 +19,6 @@ extern "C" { #endif -#include "integer.h" #include "esp_partition.h" /** @@ -28,8 +27,8 @@ extern "C" { * @param pdrv drive number * @param part_handle pointer to raw flash partition. */ -esp_err_t ff_diskio_register_raw_partition(BYTE pdrv, const esp_partition_t* part_handle); -BYTE ff_diskio_get_pdrv_raw(const esp_partition_t* part_handle); +esp_err_t ff_diskio_register_raw_partition(unsigned char pdrv, const esp_partition_t* part_handle); +unsigned char ff_diskio_get_pdrv_raw(const esp_partition_t* part_handle); #ifdef __cplusplus } diff --git a/components/fatfs/src/diskio_sdmmc.c b/components/fatfs/diskio/diskio_sdmmc.c similarity index 98% rename from components/fatfs/src/diskio_sdmmc.c rename to components/fatfs/diskio/diskio_sdmmc.c index 168b29a978..115bd59e72 100644 --- a/components/fatfs/src/diskio_sdmmc.c +++ b/components/fatfs/diskio/diskio_sdmmc.c @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "diskio.h" +#include "diskio_impl.h" #include "ffconf.h" #include "ff.h" #include "sdmmc_cmd.h" diff --git a/components/fatfs/diskio/diskio_sdmmc.h b/components/fatfs/diskio/diskio_sdmmc.h new file mode 100644 index 0000000000..d7a50221bd --- /dev/null +++ b/components/fatfs/diskio/diskio_sdmmc.h @@ -0,0 +1,35 @@ +// Copyright 2017-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "sdmmc_cmd.h" +#include "driver/sdmmc_host.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Register SD/MMC diskio driver + * + * @param pdrv drive number + * @param card pointer to sdmmc_card_t structure describing a card; card should be initialized before calling f_mount. + */ +void ff_diskio_register_sdmmc(unsigned char pdrv, sdmmc_card_t* card); + +#ifdef __cplusplus +} +#endif + diff --git a/components/fatfs/src/diskio_wl.c b/components/fatfs/diskio/diskio_wl.c similarity index 99% rename from components/fatfs/src/diskio_wl.c rename to components/fatfs/diskio/diskio_wl.c index 40547906f0..2a17f5ba08 100644 --- a/components/fatfs/src/diskio_wl.c +++ b/components/fatfs/diskio/diskio_wl.c @@ -13,7 +13,7 @@ // limitations under the License. #include -#include "diskio.h" +#include "diskio_impl.h" #include "ffconf.h" #include "ff.h" #include "esp_log.h" diff --git a/components/fatfs/src/diskio_wl.h b/components/fatfs/diskio/diskio_wl.h similarity index 86% rename from components/fatfs/src/diskio_wl.h rename to components/fatfs/diskio/diskio_wl.h index 9abff7ae06..af3f147973 100644 --- a/components/fatfs/src/diskio_wl.h +++ b/components/fatfs/diskio/diskio_wl.h @@ -19,7 +19,6 @@ extern "C" { #endif -#include "integer.h" #include "wear_levelling.h" @@ -29,8 +28,8 @@ extern "C" { * @param pdrv drive number * @param flash_handle handle of the wear levelling partition. */ -esp_err_t ff_diskio_register_wl_partition(BYTE pdrv, wl_handle_t flash_handle); -BYTE ff_diskio_get_pdrv_wl(wl_handle_t flash_handle); +esp_err_t ff_diskio_register_wl_partition(unsigned char pdrv, wl_handle_t flash_handle); +unsigned char ff_diskio_get_pdrv_wl(wl_handle_t flash_handle); void ff_diskio_clear_pdrv_wl(wl_handle_t flash_handle); #ifdef __cplusplus diff --git a/components/fatfs/port/freertos/ffsystem.c b/components/fatfs/port/freertos/ffsystem.c new file mode 100644 index 0000000000..45a894de52 --- /dev/null +++ b/components/fatfs/port/freertos/ffsystem.c @@ -0,0 +1,108 @@ +/*------------------------------------------------------------------------*/ +/* Sample Code of OS Dependent Functions for FatFs */ +/* (C)ChaN, 2017 */ +/*------------------------------------------------------------------------*/ + + +#include +#include +#include "ff.h" +#include "sdkconfig.h" +#ifdef CONFIG_FATFS_ALLOC_EXTRAM_FIRST +#include "esp_heap_caps.h" +#endif + +void* ff_memalloc ( /* Returns pointer to the allocated memory block (null on not enough core) */ + unsigned msize /* Number of bytes to allocate */ +) +{ +#ifdef CONFIG_FATFS_ALLOC_EXTRAM_FIRST + return heap_caps_malloc_prefer(size, 2, MALLOC_CAP_DEFAULT | MALLOC_CAP_SPIRAM, + MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL); +#else + return malloc(msize); +#endif +} + + +/*------------------------------------------------------------------------*/ +/* Free a memory block */ +/*------------------------------------------------------------------------*/ + +void ff_memfree ( + void* mblock /* Pointer to the memory block to free (nothing to do for null) */ +) +{ + free(mblock); /* Free the memory block with POSIX API */ +} + + + + +#if FF_FS_REENTRANT /* Mutal exclusion */ + +/*------------------------------------------------------------------------*/ +/* Create a Synchronization Object */ +/*------------------------------------------------------------------------*/ +/* This function is called in f_mount() function to create a new +/ synchronization object for the volume, such as semaphore and mutex. +/ When a 0 is returned, the f_mount() function fails with FR_INT_ERR. +*/ + + +int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */ + BYTE vol, /* Corresponding volume (logical drive number) */ + FF_SYNC_t *sobj /* Pointer to return the created sync object */ +) +{ + *sobj = xSemaphoreCreateMutex(); + return (*sobj != NULL) ? 1 : 0; +} + + +/*------------------------------------------------------------------------*/ +/* Delete a Synchronization Object */ +/*------------------------------------------------------------------------*/ +/* This function is called in f_mount() function to delete a synchronization +/ object that created with ff_cre_syncobj() function. When a 0 is returned, +/ the f_mount() function fails with FR_INT_ERR. +*/ + +int ff_del_syncobj ( /* 1:Function succeeded, 0:Could not delete due to an error */ + FF_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */ +) +{ + vSemaphoreDelete(sobj); + return 1; +} + + +/*------------------------------------------------------------------------*/ +/* Request Grant to Access the Volume */ +/*------------------------------------------------------------------------*/ +/* This function is called on entering file functions to lock the volume. +/ When a 0 is returned, the file function fails with FR_TIMEOUT. +*/ + +int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */ + FF_SYNC_t sobj /* Sync object to wait */ +) +{ + return (xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE) ? 1 : 0; +} + + +/*------------------------------------------------------------------------*/ +/* Release Grant to Access the Volume */ +/*------------------------------------------------------------------------*/ +/* This function is called on leaving file functions to unlock the volume. +*/ + +void ff_rel_grant ( + FF_SYNC_t sobj /* Sync object to be signaled */ +) +{ + xSemaphoreGive(sobj); +} + +#endif // FF_FS_REENTRANT diff --git a/components/fatfs/port/linux/ffsystem.c b/components/fatfs/port/linux/ffsystem.c new file mode 100644 index 0000000000..5013c8b126 --- /dev/null +++ b/components/fatfs/port/linux/ffsystem.c @@ -0,0 +1,46 @@ +/*------------------------------------------------------------------------*/ +/* OS Dependent Functions for FatFs */ +/* (C)ChaN, 2018 */ +/*------------------------------------------------------------------------*/ + + +#include "ff.h" +#include + +/* This is the implementation for host-side testing on Linux. + * Host-side tests are single threaded, so lock functionality isn't needed. + */ + +void* ff_memalloc(UINT msize) +{ + return malloc(msize); +} + +void ff_memfree(void* mblock) +{ + free(mblock); +} + +/* 1:Function succeeded, 0:Could not create the sync object */ +int ff_cre_syncobj(BYTE vol, FF_SYNC_t* sobj) +{ + *sobj = NULL; + return 1; +} + +/* 1:Function succeeded, 0:Could not delete due to an error */ +int ff_del_syncobj(FF_SYNC_t sobj) +{ + return 1; +} + +/* 1:Function succeeded, 0:Could not acquire lock */ +int ff_req_grant (FF_SYNC_t sobj) +{ + return 1; +} + +void ff_rel_grant (FF_SYNC_t sobj) +{ +} + diff --git a/components/fatfs/src/00history.txt b/components/fatfs/src/00history.txt index 6789ab07f3..db12a9e1b1 100644 --- a/components/fatfs/src/00history.txt +++ b/components/fatfs/src/00history.txt @@ -312,3 +312,19 @@ R0.13a (October 14, 2017) Fixed f_setlabel() rejects some valid characters for exFAT volume. (appeared at R0.12) + +R0.13b (April 07, 2018) + + Added support for UTF-32 encoding on the API. (FF_LFN_UNICODE = 3) + Added support for Unix style volume ID. (FF_STR_VOLUME_ID = 2) + Fixed accesing any object on the exFAT root directory beyond the cluster boundary can fail. (appeared at R0.12c) + Fixed f_setlabel() does not reject some invalid characters. (appeared at R0.09b) + + + +R0.13c (October 14, 2018) + Supported stdint.h for C99 and later. (integer.h was included in ff.h) + Fixed reading a directory gets infinite loop when the last directory entry is not empty. (appeared at R0.12) + Fixed creating a sub-directory in the fragmented sub-directory on the exFAT volume collapses FAT chain of the parent directory. (appeared at R0.12) + Fixed f_getcwd() cause output buffer overrun when the buffer has a valid drive number. (appeared at R0.13b) + diff --git a/components/fatfs/src/00readme.txt b/components/fatfs/src/00readme.txt index 6eff7fce9f..dcccbdbebc 100644 --- a/components/fatfs/src/00readme.txt +++ b/components/fatfs/src/00readme.txt @@ -1,4 +1,4 @@ -FatFs Module Source Files R0.13a +FatFs Module Source Files R0.13c FILES @@ -10,7 +10,6 @@ FILES ff.h Common include file for FatFs and application module. diskio.h Common include file for FatFs and disk I/O module. diskio.c An example of glue function to attach existing disk I/O module to FatFs. - integer.h Integer type definitions for FatFs. ffunicode.c Optional Unicode utility functions. ffsystem.c An example of optional O/S related functions. diff --git a/components/fatfs/src/diskio.c b/components/fatfs/src/diskio.c index 1bc78ea979..08ffcc8600 100644 --- a/components/fatfs/src/diskio.c +++ b/components/fatfs/src/diskio.c @@ -1,6 +1,5 @@ /*-----------------------------------------------------------------------*/ /* Low level disk I/O module skeleton for FatFs (C)ChaN, 2016 */ -/* ESP-IDF port Copyright 2016 Espressif Systems (Shanghai) PTE LTD */ /*-----------------------------------------------------------------------*/ /* If a working storage control module is available, it should be */ /* attached to the FatFs via a glue function rather than modifying it. */ @@ -8,85 +7,223 @@ /* storage control modules to the FatFs module with a defined API. */ /*-----------------------------------------------------------------------*/ -#include -#include -#include -#include "diskio.h" /* FatFs lower layer API */ -#include "ffconf.h" -#include "ff.h" +#include "ff.h" /* Obtains integer types */ +#include "diskio.h" /* Declarations of disk functions */ -static ff_diskio_impl_t * s_impls[FF_VOLUMES] = { NULL }; +/* Definitions of physical drive number for each drive */ +#define DEV_RAM 0 /* Example: Map Ramdisk to physical drive 0 */ +#define DEV_MMC 1 /* Example: Map MMC/SD card to physical drive 1 */ +#define DEV_USB 2 /* Example: Map USB MSD to physical drive 2 */ + + +/*-----------------------------------------------------------------------*/ +/* Get Drive Status */ +/*-----------------------------------------------------------------------*/ + +DSTATUS disk_status ( + BYTE pdrv /* Physical drive nmuber to identify the drive */ +) +{ + DSTATUS stat; + int result; + + switch (pdrv) { + case DEV_RAM : + result = RAM_disk_status(); + + // translate the reslut code here + + return stat; + + case DEV_MMC : + result = MMC_disk_status(); + + // translate the reslut code here + + return stat; + + case DEV_USB : + result = USB_disk_status(); + + // translate the reslut code here + + return stat; + } + return STA_NOINIT; +} + + + +/*-----------------------------------------------------------------------*/ +/* Inidialize a Drive */ +/*-----------------------------------------------------------------------*/ + +DSTATUS disk_initialize ( + BYTE pdrv /* Physical drive nmuber to identify the drive */ +) +{ + DSTATUS stat; + int result; + + switch (pdrv) { + case DEV_RAM : + result = RAM_disk_initialize(); + + // translate the reslut code here + + return stat; + + case DEV_MMC : + result = MMC_disk_initialize(); + + // translate the reslut code here + + return stat; + + case DEV_USB : + result = USB_disk_initialize(); + + // translate the reslut code here + + return stat; + } + return STA_NOINIT; +} + + + +/*-----------------------------------------------------------------------*/ +/* Read Sector(s) */ +/*-----------------------------------------------------------------------*/ + +DRESULT disk_read ( + BYTE pdrv, /* Physical drive nmuber to identify the drive */ + BYTE *buff, /* Data buffer to store read data */ + DWORD sector, /* Start sector in LBA */ + UINT count /* Number of sectors to read */ +) +{ + DRESULT res; + int result; + + switch (pdrv) { + case DEV_RAM : + // translate the arguments here + + result = RAM_disk_read(buff, sector, count); + + // translate the reslut code here + + return res; + + case DEV_MMC : + // translate the arguments here + + result = MMC_disk_read(buff, sector, count); + + // translate the reslut code here + + return res; + + case DEV_USB : + // translate the arguments here + + result = USB_disk_read(buff, sector, count); + + // translate the reslut code here + + return res; + } + + return RES_PARERR; +} + + + +/*-----------------------------------------------------------------------*/ +/* Write Sector(s) */ +/*-----------------------------------------------------------------------*/ + +#if FF_FS_READONLY == 0 + +DRESULT disk_write ( + BYTE pdrv, /* Physical drive nmuber to identify the drive */ + const BYTE *buff, /* Data to be written */ + DWORD sector, /* Start sector in LBA */ + UINT count /* Number of sectors to write */ +) +{ + DRESULT res; + int result; + + switch (pdrv) { + case DEV_RAM : + // translate the arguments here + + result = RAM_disk_write(buff, sector, count); + + // translate the reslut code here + + return res; + + case DEV_MMC : + // translate the arguments here + + result = MMC_disk_write(buff, sector, count); + + // translate the reslut code here + + return res; + + case DEV_USB : + // translate the arguments here + + result = USB_disk_write(buff, sector, count); + + // translate the reslut code here + + return res; + } + + return RES_PARERR; +} -#if FF_MULTI_PARTITION /* Multiple partition configuration */ -PARTITION VolToPart[] = { - {0, 0}, /* Logical drive 0 ==> Physical drive 0, auto detection */ - {1, 0} /* Logical drive 1 ==> Physical drive 1, auto detection */ -}; #endif -esp_err_t ff_diskio_get_drive(BYTE* out_pdrv) + +/*-----------------------------------------------------------------------*/ +/* Miscellaneous Functions */ +/*-----------------------------------------------------------------------*/ + +DRESULT disk_ioctl ( + BYTE pdrv, /* Physical drive nmuber (0..) */ + BYTE cmd, /* Control code */ + void *buff /* Buffer to send/receive control data */ +) { - BYTE i; - for(i=0; iinit(pdrv); -} -DSTATUS ff_disk_status (BYTE pdrv) -{ - return s_impls[pdrv]->status(pdrv); -} -DRESULT ff_disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count) -{ - return s_impls[pdrv]->read(pdrv, buff, sector, count); -} -DRESULT ff_disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) -{ - return s_impls[pdrv]->write(pdrv, buff, sector, count); -} -DRESULT ff_disk_ioctl (BYTE pdrv, BYTE cmd, void* buff) -{ - return s_impls[pdrv]->ioctl(pdrv, cmd, buff); -} - -DWORD get_fattime(void) -{ - time_t t = time(NULL); - struct tm tmr; - localtime_r(&t, &tmr); - int year = tmr.tm_year < 80 ? 0 : tmr.tm_year - 80; - return ((DWORD)(year) << 25) - | ((DWORD)(tmr.tm_mon + 1) << 21) - | ((DWORD)tmr.tm_mday << 16) - | (WORD)(tmr.tm_hour << 11) - | (WORD)(tmr.tm_min << 5) - | (WORD)(tmr.tm_sec >> 1); -} diff --git a/components/fatfs/src/diskio.h b/components/fatfs/src/diskio.h index 572f03dce0..31776b8b61 100644 --- a/components/fatfs/src/diskio.h +++ b/components/fatfs/src/diskio.h @@ -9,10 +9,6 @@ extern "C" { #endif -#include "integer.h" -#include "sdmmc_cmd.h" -#include "driver/sdmmc_host.h" - /* Status of Disk Functions */ typedef BYTE DSTATUS; @@ -30,64 +26,12 @@ typedef enum { /* Prototypes for disk control functions */ -/* Redefine names of disk IO functions to prevent name collisions */ -#define disk_initialize ff_disk_initialize -#define disk_status ff_disk_status -#define disk_read ff_disk_read -#define disk_write ff_disk_write -#define disk_ioctl ff_disk_ioctl - - DSTATUS disk_initialize (BYTE pdrv); DSTATUS disk_status (BYTE pdrv); DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count); DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count); DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); -/** - * Structure of pointers to disk IO driver functions. - * - * See FatFs documentation for details about these functions - */ -typedef struct { - DSTATUS (*init) (BYTE pdrv); /*!< disk initialization function */ - DSTATUS (*status) (BYTE pdrv); /*!< disk status check function */ - DRESULT (*read) (BYTE pdrv, BYTE* buff, DWORD sector, UINT count); /*!< sector read function */ - DRESULT (*write) (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count); /*!< sector write function */ - DRESULT (*ioctl) (BYTE pdrv, BYTE cmd, void* buff); /*!< function to get info about disk and do some misc operations */ -} ff_diskio_impl_t; - -/** - * Register or unregister diskio driver for given drive number. - * - * When FATFS library calls one of disk_xxx functions for driver number pdrv, - * corresponding function in discio_impl for given pdrv will be called. - * - * @param pdrv drive number - * @param discio_impl pointer to ff_diskio_impl_t structure with diskio functions - * or NULL to unregister and free previously registered drive - */ -void ff_diskio_register(BYTE pdrv, const ff_diskio_impl_t* discio_impl); - -#define ff_diskio_unregister(pdrv_) ff_diskio_register(pdrv_, NULL) - -/** - * Register SD/MMC diskio driver - * - * @param pdrv drive number - * @param card pointer to sdmmc_card_t structure describing a card; card should be initialized before calling f_mount. - */ -void ff_diskio_register_sdmmc(BYTE pdrv, sdmmc_card_t* card); - -/** - * Get next available drive number - * - * @param out_pdrv pointer to the byte to set if successful - * - * @return ESP_OK on success - * ESP_ERR_NOT_FOUND if all drives are attached - */ -esp_err_t ff_diskio_get_drive(BYTE* out_pdrv); /* Disk Status Bits (DSTATUS) */ @@ -99,11 +43,11 @@ esp_err_t ff_diskio_get_drive(BYTE* out_pdrv); /* Command code for disk_ioctrl fucntion */ /* Generic command (Used by FatFs) */ -#define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */ -#define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */ -#define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */ -#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */ -#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */ +#define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */ +#define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */ +#define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */ +#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */ +#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */ /* Generic command (Not used by FatFs) */ #define CTRL_POWER 5 /* Get/Set power status */ diff --git a/components/fatfs/src/ff.c b/components/fatfs/src/ff.c index 5ebdf49191..d9833c72e1 100644 --- a/components/fatfs/src/ff.c +++ b/components/fatfs/src/ff.c @@ -1,8 +1,8 @@ /*----------------------------------------------------------------------------/ -/ FatFs - Generic FAT Filesystem Module R0.13a / +/ FatFs - Generic FAT Filesystem Module R0.13c / /-----------------------------------------------------------------------------/ / -/ Copyright (C) 2017, ChaN, all right reserved. +/ Copyright (C) 2018, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided @@ -29,11 +29,20 @@ ---------------------------------------------------------------------------*/ -#if FF_DEFINED != 89352 /* Revision ID */ +#if FF_DEFINED != 86604 /* Revision ID */ #error Wrong include file (ff.h). #endif +/* Limits and boundaries */ +#define MAX_DIR 0x200000 /* Max size of FAT directory */ +#define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory */ +#define MAX_FAT12 0xFF5 /* Max FAT12 clusters (differs from specs, but right for real DOS/Windows behavior) */ +#define MAX_FAT16 0xFFF5 /* Max FAT16 clusters (differs from specs, but right for real DOS/Windows behavior) */ +#define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */ +#define MAX_EXFAT 0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */ + + /* Character code support macros */ #define IsUpper(c) ((c) >= 'A' && (c) <= 'Z') #define IsLower(c) ((c) >= 'a' && (c) <= 'z') @@ -43,18 +52,18 @@ #define IsSurrogateL(c) ((c) >= 0xDC00 && (c) <= 0xDFFF) -/* Additional file attribute bits for internal use */ -#define AM_VOL 0x08 /* Volume label */ -#define AM_LFN 0x0F /* LFN entry */ -#define AM_MASK 0x3F /* Mask of defined bits */ - - /* Additional file access control and file status flags for internal use */ #define FA_SEEKEND 0x20 /* Seek to end of the file on file open */ #define FA_MODIFIED 0x40 /* File has been modified */ #define FA_DIRTY 0x80 /* FIL.buf[] needs to be written-back */ +/* Additional file attribute bits for internal use */ +#define AM_VOL 0x08 /* Volume label */ +#define AM_LFN 0x0F /* LFN entry */ +#define AM_MASK 0x3F /* Mask of defined bits */ + + /* Name status flags in fn[11] */ #define NSFLAG 11 /* Index of the name status byte */ #define NS_LOSS 0x01 /* Out of 8.3 format */ @@ -67,13 +76,13 @@ #define NS_NONAME 0x80 /* Not followed */ -/* Limits and boundaries */ -#define MAX_DIR 0x200000 /* Max size of FAT directory */ -#define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory */ -#define MAX_FAT12 0xFF5 /* Max FAT12 clusters (differs from specs, but right for real DOS/Windows behavior) */ -#define MAX_FAT16 0xFFF5 /* Max FAT16 clusters (differs from specs, but right for real DOS/Windows behavior) */ -#define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */ -#define MAX_EXFAT 0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */ +/* exFAT directory entry types */ +#define ET_BITMAP 0x81 /* Allocation bitmap */ +#define ET_UPCASE 0x82 /* Up-case table */ +#define ET_VLABEL 0x83 /* Volume label */ +#define ET_FILEDIR 0x85 /* File and directory */ +#define ET_STREAM 0xC0 /* Stream extension */ +#define ET_FILENAME 0xC1 /* Name extension */ /* FatFs refers the FAT structure as simple byte array instead of structure member @@ -426,10 +435,10 @@ typedef struct { #if FF_VOLUMES < 1 || FF_VOLUMES > 10 #error Wrong FF_VOLUMES setting #endif -static FATFS *FatFs[FF_VOLUMES]; /* Pointer to the filesystem objects (logical drives) */ -static WORD Fsid; /* File system mount ID */ +static FATFS* FatFs[FF_VOLUMES]; /* Pointer to the filesystem objects (logical drives) */ +static WORD Fsid; /* Filesystem mount ID */ -#if FF_FS_RPATH != 0 && FF_VOLUMES >= 2 +#if FF_FS_RPATH != 0 static BYTE CurrVol; /* Current drive */ #endif @@ -437,6 +446,11 @@ static BYTE CurrVol; /* Current drive */ static FILESEM Files[FF_FS_LOCK]; /* Open object lock semaphores */ #endif +#if FF_STR_VOLUME_ID +#ifdef FF_VOLUME_STRS +static const char* const VolumeStr[FF_VOLUMES] = {FF_VOLUME_STRS}; /* Pre-defined volume ID */ +#endif +#endif /*--------------------------------*/ @@ -456,10 +470,10 @@ static FILESEM Files[FF_FS_LOCK]; /* Open object lock semaphores */ #if FF_MAX_LFN < 12 || FF_MAX_LFN > 255 #error Wrong setting of FF_MAX_LFN #endif -#if FF_LFN_BUF < 12 || FF_SFN_BUF < 12 || FF_LFN_BUF < FF_SFN_BUF +#if FF_LFN_BUF < FF_SFN_BUF || FF_SFN_BUF < 12 #error Wrong setting of FF_LFN_BUF or FF_SFN_BUF #endif -#if FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 2 +#if FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3 #error Wrong setting of FF_LFN_UNICODE #endif static const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* FAT: Offset of LFN characters in the directory entry */ @@ -498,7 +512,7 @@ static WCHAR LfnBuf[FF_MAX_LFN + 1]; /* LFN working buffer */ #define FREE_NAMBUF() ff_memfree(lfn) #endif #define LEAVE_MKFS(res) { if (!work) ff_memfree(buf); return res; } -#define MAX_MALLOC 0x8000 +#define MAX_MALLOC 0x8000 /* Must be >=FF_MAX_SS */ #else #error Wrong setting of FF_USE_LFN @@ -516,6 +530,7 @@ static WCHAR LfnBuf[FF_MAX_LFN + 1]; /* LFN working buffer */ #define CODEPAGE CodePage static WORD CodePage; /* Current code page */ static const BYTE *ExCvt, *DbcTbl; /* Pointer to current SBCS up-case table and DBCS code range table below */ + static const BYTE Ct437[] = TBL_CT437; static const BYTE Ct720[] = TBL_CT720; static const BYTE Ct737[] = TBL_CT737; @@ -562,8 +577,7 @@ static const BYTE DbcTbl[] = MKCVTBL(TBL_DC, FF_CODE_PAGE); /* Load/Store multi-byte word in the FAT structure */ /*-----------------------------------------------------------------------*/ -static -WORD ld_word (const BYTE* ptr) /* Load a 2-byte little-endian word */ +static WORD ld_word (const BYTE* ptr) /* Load a 2-byte little-endian word */ { WORD rv; @@ -572,8 +586,7 @@ WORD ld_word (const BYTE* ptr) /* Load a 2-byte little-endian word */ return rv; } -static -DWORD ld_dword (const BYTE* ptr) /* Load a 4-byte little-endian word */ +static DWORD ld_dword (const BYTE* ptr) /* Load a 4-byte little-endian word */ { DWORD rv; @@ -585,8 +598,7 @@ DWORD ld_dword (const BYTE* ptr) /* Load a 4-byte little-endian word */ } #if FF_FS_EXFAT -static -QWORD ld_qword (const BYTE* ptr) /* Load an 8-byte little-endian word */ +static QWORD ld_qword (const BYTE* ptr) /* Load an 8-byte little-endian word */ { QWORD rv; @@ -603,15 +615,13 @@ QWORD ld_qword (const BYTE* ptr) /* Load an 8-byte little-endian word */ #endif #if !FF_FS_READONLY -static -void st_word (BYTE* ptr, WORD val) /* Store a 2-byte word in little-endian */ +static void st_word (BYTE* ptr, WORD val) /* Store a 2-byte word in little-endian */ { *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; } -static -void st_dword (BYTE* ptr, DWORD val) /* Store a 4-byte word in little-endian */ +static void st_dword (BYTE* ptr, DWORD val) /* Store a 4-byte word in little-endian */ { *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; @@ -620,8 +630,7 @@ void st_dword (BYTE* ptr, DWORD val) /* Store a 4-byte word in little-endian */ } #if FF_FS_EXFAT -static -void st_qword (BYTE* ptr, QWORD val) /* Store an 8-byte word in little-endian */ +static void st_qword (BYTE* ptr, QWORD val) /* Store an 8-byte word in little-endian */ { *ptr++ = (BYTE)val; val >>= 8; *ptr++ = (BYTE)val; val >>= 8; @@ -642,8 +651,7 @@ void st_qword (BYTE* ptr, QWORD val) /* Store an 8-byte word in little-endian */ /*-----------------------------------------------------------------------*/ /* Copy memory to memory */ -static -void mem_cpy (void* dst, const void* src, UINT cnt) +static void mem_cpy (void* dst, const void* src, UINT cnt) { BYTE *d = (BYTE*)dst; const BYTE *s = (const BYTE*)src; @@ -657,8 +665,7 @@ void mem_cpy (void* dst, const void* src, UINT cnt) /* Fill memory block */ -static -void mem_set (void* dst, int val, UINT cnt) +static void mem_set (void* dst, int val, UINT cnt) { BYTE *d = (BYTE*)dst; @@ -669,8 +676,7 @@ void mem_set (void* dst, int val, UINT cnt) /* Compare memory block */ -static -int mem_cmp (const void* dst, const void* src, UINT cnt) /* ZR:same, NZ:different */ +static int mem_cmp (const void* dst, const void* src, UINT cnt) /* ZR:same, NZ:different */ { const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)src; int r = 0; @@ -684,8 +690,7 @@ int mem_cmp (const void* dst, const void* src, UINT cnt) /* ZR:same, NZ:differen /* Check if chr is contained in the string */ -static -int chk_chr (const char* str, int chr) /* NZ:contained, ZR:not contained */ +static int chk_chr (const char* str, int chr) /* NZ:contained, ZR:not contained */ { while (*str && *str != chr) str++; return *str; @@ -693,8 +698,7 @@ int chk_chr (const char* str, int chr) /* NZ:contained, ZR:not contained */ /* Test if the character is DBC 1st byte */ -static -int dbc_1st (BYTE c) +static int dbc_1st (BYTE c) { #if FF_CODE_PAGE == 0 /* Variable code page */ if (DbcTbl && c >= DbcTbl[0]) { @@ -714,8 +718,7 @@ int dbc_1st (BYTE c) /* Test if the character is DBC 2nd byte */ -static -int dbc_2nd (BYTE c) +static int dbc_2nd (BYTE c) { #if FF_CODE_PAGE == 0 /* Variable code page */ if (DbcTbl && c >= DbcTbl[4]) { @@ -739,9 +742,8 @@ int dbc_2nd (BYTE c) #if FF_USE_LFN /* Get a character from TCHAR string in defined API encodeing */ -static -DWORD tchar2uni ( /* Returns character in UTF-16 encoding (>=0x10000 on double encoding unit, 0xFFFFFFFF on decode error) */ - const TCHAR** str /* Pointer to pointer to TCHAR string in configured encoding */ +static DWORD tchar2uni ( /* Returns character in UTF-16 encoding (>=0x10000 on double encoding unit, 0xFFFFFFFF on decode error) */ + const TCHAR** str /* Pointer to pointer to TCHAR string in configured encoding */ ) { DWORD uc; @@ -750,7 +752,7 @@ DWORD tchar2uni ( /* Returns character in UTF-16 encoding (>=0x10000 on double #if FF_LFN_UNICODE == 1 /* UTF-16 input */ WCHAR wc; - uc = *p++; + uc = *p++; /* Get a unit */ if (IsSurrogate(uc)) { /* Surrogate? */ wc = *p++; /* Get low surrogate */ if (!IsSurrogateH(uc) || !IsSurrogateL(wc)) return 0xFFFFFFFF; /* Wrong surrogate? */ @@ -761,7 +763,7 @@ DWORD tchar2uni ( /* Returns character in UTF-16 encoding (>=0x10000 on double BYTE b; int nf; - uc = (BYTE)*p++; /* Get a byte */ + uc = (BYTE)*p++; /* Get a unit */ if (uc & 0x80) { /* Multiple byte code? */ if ((uc & 0xE0) == 0xC0) { /* 2-byte sequence? */ uc &= 0x1F; nf = 1; @@ -782,9 +784,14 @@ DWORD tchar2uni ( /* Returns character in UTF-16 encoding (>=0x10000 on double uc = uc << 6 | (b & 0x3F); } while (--nf != 0); if (uc < 0x80 || IsSurrogate(uc) || uc >= 0x110000) return 0xFFFFFFFF; /* Wrong code? */ - if (uc >= 0x10000) uc = 0xD800DC00 | ((uc - 0x10000) << 6 & 0x3FF0000) | (uc & 0x3FF); /* Make a surrogate pair if needed */ + if (uc >= 0x010000) uc = 0xD800DC00 | ((uc - 0x10000) << 6 & 0x3FF0000) | (uc & 0x3FF); /* Make a surrogate pair if needed */ } +#elif FF_LFN_UNICODE == 3 /* UTF-32 input */ + uc = (TCHAR)*p++; /* Get a unit */ + if (uc >= 0x110000) return 0xFFFFFFFF; /* Wrong code? */ + if (uc >= 0x010000) uc = 0xD800DC00 | ((uc - 0x10000) << 6 & 0x3FF0000) | (uc & 0x3FF); /* Make a surrogate pair if needed */ + #else /* ANSI/OEM input */ BYTE b; WCHAR wc; @@ -808,8 +815,7 @@ DWORD tchar2uni ( /* Returns character in UTF-16 encoding (>=0x10000 on double /* Output a TCHAR string in defined API encoding */ -static -BYTE put_utf ( /* Returns number of encoding units written (0:buffer overflow or wrong encoding) */ +static BYTE put_utf ( /* Returns number of encoding units written (0:buffer overflow or wrong encoding) */ DWORD chr, /* UTF-16 encoded character (Double encoding unit char if >=0x10000) */ TCHAR* buf, /* Output buffer */ UINT szb /* Size of the buffer */ @@ -863,6 +869,19 @@ BYTE put_utf ( /* Returns number of encoding units written (0:buffer overflow or *buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F)); return 4; +#elif FF_LFN_UNICODE == 3 /* UTF-32 output */ + DWORD hc; + + if (szb < 1) return 0; /* Buffer overflow? */ + if (chr >= 0x10000) { /* Out of BMP? */ + hc = ((chr & 0xFFFF0000) - 0xD8000000) >> 6; /* Get high 10 bits */ + chr = (chr & 0xFFFF) - 0xDC00; /* Get low 10 bits */ + if (hc >= 0x100000 || chr >= 0x400) return 0; /* Wrong surrogate? */ + chr = (hc | chr) + 0x10000; + } + *buf++ = (TCHAR)chr; + return 1; + #else /* ANSI/OEM output */ WCHAR wc; @@ -885,8 +904,7 @@ BYTE put_utf ( /* Returns number of encoding units written (0:buffer overflow or /*-----------------------------------------------------------------------*/ /* Request/Release grant to access the volume */ /*-----------------------------------------------------------------------*/ -static -int lock_fs ( /* 1:Ok, 0:timeout */ +static int lock_fs ( /* 1:Ok, 0:timeout */ FATFS* fs /* Filesystem object */ ) { @@ -894,8 +912,7 @@ int lock_fs ( /* 1:Ok, 0:timeout */ } -static -void unlock_fs ( +static void unlock_fs ( FATFS* fs, /* Filesystem object */ FRESULT res /* Result code to be returned */ ) @@ -914,8 +931,7 @@ void unlock_fs ( /* File lock control functions */ /*-----------------------------------------------------------------------*/ -static -FRESULT chk_lock ( /* Check if the file can be accessed */ +static FRESULT chk_lock ( /* Check if the file can be accessed */ FF_DIR* dp, /* Directory object pointing the file to be checked */ int acc /* Desired access type (0:Read mode open, 1:Write mode open, 2:Delete or rename) */ ) @@ -942,8 +958,7 @@ FRESULT chk_lock ( /* Check if the file can be accessed */ } -static -int enq_lock (void) /* Check if an entry is available for a new object */ +static int enq_lock (void) /* Check if an entry is available for a new object */ { UINT i; @@ -952,8 +967,7 @@ int enq_lock (void) /* Check if an entry is available for a new object */ } -static -UINT inc_lock ( /* Increment object open counter and returns its index (0:Internal error) */ +static UINT inc_lock ( /* Increment object open counter and returns its index (0:Internal error) */ FF_DIR* dp, /* Directory object pointing the file to register or increment */ int acc /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */ ) @@ -984,8 +998,7 @@ UINT inc_lock ( /* Increment object open counter and returns its index (0:Intern } -static -FRESULT dec_lock ( /* Decrement object open counter */ +static FRESULT dec_lock ( /* Decrement object open counter */ UINT i /* Semaphore index (1..) */ ) { @@ -1007,8 +1020,7 @@ FRESULT dec_lock ( /* Decrement object open counter */ } -static -void clear_lock ( /* Clear lock entries of the volume */ +static void clear_lock ( /* Clear lock entries of the volume */ FATFS *fs ) { @@ -1027,8 +1039,7 @@ void clear_lock ( /* Clear lock entries of the volume */ /* Move/Flush disk access window in the filesystem object */ /*-----------------------------------------------------------------------*/ #if !FF_FS_READONLY -static -FRESULT sync_window ( /* Returns FR_OK or FR_DISK_ERR */ +static FRESULT sync_window ( /* Returns FR_OK or FR_DISK_ERR */ FATFS* fs /* Filesystem object */ ) { @@ -1050,8 +1061,7 @@ FRESULT sync_window ( /* Returns FR_OK or FR_DISK_ERR */ #endif -static -FRESULT move_window ( /* Returns FR_OK or FR_DISK_ERR */ +static FRESULT move_window ( /* Returns FR_OK or FR_DISK_ERR */ FATFS* fs, /* Filesystem object */ DWORD sector /* Sector number to make appearance in the fs->win[] */ ) @@ -1082,8 +1092,7 @@ FRESULT move_window ( /* Returns FR_OK or FR_DISK_ERR */ /* Synchronize filesystem and data on the storage */ /*-----------------------------------------------------------------------*/ -static -FRESULT sync_fs ( /* Returns FR_OK or FR_DISK_ERR */ +static FRESULT sync_fs ( /* Returns FR_OK or FR_DISK_ERR */ FATFS* fs /* Filesystem object */ ) { @@ -1094,7 +1103,7 @@ FRESULT sync_fs ( /* Returns FR_OK or FR_DISK_ERR */ if (res == FR_OK) { if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { /* FAT32: Update FSInfo sector if needed */ /* Create FSInfo structure */ - mem_set(fs->win, 0, SS(fs)); + mem_set(fs->win, 0, sizeof fs->win); st_word(fs->win + BS_55AA, 0xAA55); st_dword(fs->win + FSI_LeadSig, 0x41615252); st_dword(fs->win + FSI_StrucSig, 0x61417272); @@ -1120,8 +1129,7 @@ FRESULT sync_fs ( /* Returns FR_OK or FR_DISK_ERR */ /* Get physical sector number from cluster number */ /*-----------------------------------------------------------------------*/ -static -DWORD clst2sect ( /* !=0:Sector number, 0:Failed (invalid cluster#) */ +static DWORD clst2sect ( /* !=0:Sector number, 0:Failed (invalid cluster#) */ FATFS* fs, /* Filesystem object */ DWORD clst /* Cluster# to be converted */ ) @@ -1138,8 +1146,7 @@ DWORD clst2sect ( /* !=0:Sector number, 0:Failed (invalid cluster#) */ /* FAT access - Read value of a FAT entry */ /*-----------------------------------------------------------------------*/ -static -DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Cluster status */ +static DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Cluster status */ FFOBJID* obj, /* Corresponding object */ DWORD clst /* Cluster number to get the value */ ) @@ -1176,7 +1183,7 @@ DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Clust break; #if FF_FS_EXFAT case FS_EXFAT : - if (obj->objsize != 0) { + if ((obj->objsize != 0 && obj->sclust != 0) || obj->stat == 0) { /* Object except root dir must have valid data length */ DWORD cofs = clst - obj->sclust; /* Offset from start cluster */ DWORD clen = (DWORD)((obj->objsize - 1) / SS(fs)) / fs->csize; /* Number of clusters - 1 */ @@ -1216,8 +1223,7 @@ DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Clust /* FAT access - Change value of a FAT entry */ /*-----------------------------------------------------------------------*/ -static -FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ +static FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ FATFS* fs, /* Corresponding filesystem object */ DWORD clst, /* FAT index number (cluster number) to be changed */ DWORD val /* New value to be set to the entry */ @@ -1282,8 +1288,7 @@ FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ /* Find a contiguous free cluster block */ /*--------------------------------------*/ -static -DWORD find_bitmap ( /* 0:Not found, 2..:Cluster block found, 0xFFFFFFFF:Disk error */ +static DWORD find_bitmap ( /* 0:Not found, 2..:Cluster block found, 0xFFFFFFFF:Disk error */ FATFS* fs, /* Filesystem object */ DWORD clst, /* Cluster number to scan from */ DWORD ncl /* Number of contiguous clusters to find (1..) */ @@ -1298,7 +1303,7 @@ DWORD find_bitmap ( /* 0:Not found, 2..:Cluster block found, 0xFFFFFFFF:Disk err if (clst >= fs->n_fatent - 2) clst = 0; scl = val = clst; ctr = 0; for (;;) { - if (move_window(fs, fs->database + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF; /* (assuming bitmap is located top of the cluster heap) */ + if (move_window(fs, fs->bitbase + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF; i = val / 8 % SS(fs); bm = 1 << (val % 8); do { do { @@ -1323,8 +1328,7 @@ DWORD find_bitmap ( /* 0:Not found, 2..:Cluster block found, 0xFFFFFFFF:Disk err /* Set/Clear a block of allocation bitmap */ /*----------------------------------------*/ -static -FRESULT change_bitmap ( +static FRESULT change_bitmap ( FATFS* fs, /* Filesystem object */ DWORD clst, /* Cluster number to change from */ DWORD ncl, /* Number of clusters to be changed */ @@ -1337,9 +1341,9 @@ FRESULT change_bitmap ( clst -= 2; /* The first bit corresponds to cluster #2 */ - sect = fs->database + clst / 8 / SS(fs); /* Sector address (assuming bitmap is located top of the cluster heap) */ - i = clst / 8 % SS(fs); /* Byte offset in the sector */ - bm = 1 << (clst % 8); /* Bit mask in the byte */ + sect = fs->bitbase + clst / 8 / SS(fs); /* Sector address */ + i = clst / 8 % SS(fs); /* Byte offset in the sector */ + bm = 1 << (clst % 8); /* Bit mask in the byte */ for (;;) { if (move_window(fs, sect++) != FR_OK) return FR_DISK_ERR; do { @@ -1360,8 +1364,7 @@ FRESULT change_bitmap ( /* Fill the first fragment of the FAT chain */ /*---------------------------------------------*/ -static -FRESULT fill_first_frag ( +static FRESULT fill_first_frag ( FFOBJID* obj /* Pointer to the corresponding object */ ) { @@ -1384,8 +1387,7 @@ FRESULT fill_first_frag ( /* Fill the last fragment of the FAT chain */ /*---------------------------------------------*/ -static -FRESULT fill_last_frag ( +static FRESULT fill_last_frag ( FFOBJID* obj, /* Pointer to the corresponding object */ DWORD lcl, /* Last cluster of the fragment */ DWORD term /* Value to set the last FAT entry */ @@ -1410,11 +1412,11 @@ FRESULT fill_last_frag ( /*-----------------------------------------------------------------------*/ /* FAT handling - Remove a cluster chain */ /*-----------------------------------------------------------------------*/ -static -FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ + +static FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ FFOBJID* obj, /* Corresponding object */ DWORD clst, /* Cluster to remove a chain from */ - DWORD pclst /* Previous cluster of clst (0:entire chain) */ + DWORD pclst /* Previous cluster of clst (0 if entire chain) */ ) { FRESULT res = FR_OK; @@ -1505,8 +1507,8 @@ FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ /*-----------------------------------------------------------------------*/ /* FAT handling - Stretch a chain or Create a new chain */ /*-----------------------------------------------------------------------*/ -static -DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */ + +static DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */ FFOBJID* obj, /* Corresponding object */ DWORD clst /* Cluster# to stretch, 0:Create a new chain */ ) @@ -1609,8 +1611,7 @@ DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk err /* FAT handling - Convert offset into cluster with link map table */ /*-----------------------------------------------------------------------*/ -static -DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ +static DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ FIL* fp, /* Pointer to the file object */ FSIZE_t ofs /* File offset to be converted to cluster# */ ) @@ -1640,25 +1641,24 @@ DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ /*-----------------------------------------------------------------------*/ #if !FF_FS_READONLY -static -FRESULT dir_clear ( /* Returns FR_OK or FR_DISK_ERR */ +static FRESULT dir_clear ( /* Returns FR_OK or FR_DISK_ERR */ FATFS *fs, /* Filesystem object */ DWORD clst /* Directory table to clear */ ) { DWORD sect; UINT n, szb; - BYTE *ibuf = NULL; + BYTE *ibuf; if (sync_window(fs) != FR_OK) return FR_DISK_ERR; /* Flush disk access window */ sect = clst2sect(fs, clst); /* Top of the cluster */ fs->winsect = sect; /* Set window to top of the cluster */ - mem_set(fs->win, 0, SS(fs)); /* Clear window buffer */ + mem_set(fs->win, 0, sizeof fs->win); /* Clear window buffer */ #if FF_USE_LFN == 3 /* Quick table clear by using multi-secter write */ /* Allocate a temporary buffer */ - for (szb = ((DWORD)fs->csize * SS(fs) >= MAX_MALLOC) ? MAX_MALLOC : fs->csize * SS(fs); szb > SS(fs) && !(ibuf = ff_memalloc(szb)); szb /= 2) ; - if (szb > SS(fs) && ibuf != NULL) { /* Buffer allocated? */ + for (szb = ((DWORD)fs->csize * SS(fs) >= MAX_MALLOC) ? MAX_MALLOC : fs->csize * SS(fs), ibuf = 0; szb > SS(fs) && (ibuf = ff_memalloc(szb)) == 0; szb /= 2) ; + if (szb > SS(fs)) { /* Buffer allocated? */ mem_set(ibuf, 0, szb); szb /= SS(fs); /* Bytes -> Sectors */ for (n = 0; n < fs->csize && disk_write(fs->pdrv, ibuf, sect + n, szb) == RES_OK; n += szb) ; /* Fill the cluster with 0 */ @@ -1666,7 +1666,7 @@ FRESULT dir_clear ( /* Returns FR_OK or FR_DISK_ERR */ } else #endif { - ibuf = fs->win; szb = 1; /* Use window buffer (single-sector writes may take a time) */ + ibuf = fs->win; szb = 1; /* Use window buffer (many single-sector writes may take a time) */ for (n = 0; n < fs->csize && disk_write(fs->pdrv, ibuf, sect + n, szb) == RES_OK; n += szb) ; /* Fill the cluster with 0 */ } return (n == fs->csize) ? FR_OK : FR_DISK_ERR; @@ -1680,8 +1680,7 @@ FRESULT dir_clear ( /* Returns FR_OK or FR_DISK_ERR */ /* Directory handling - Set directory index */ /*-----------------------------------------------------------------------*/ -static -FRESULT dir_sdi ( /* FR_OK(0):succeeded, !=0:error */ +static FRESULT dir_sdi ( /* FR_OK(0):succeeded, !=0:error */ FF_DIR* dp, /* Pointer to directory object */ DWORD ofs /* Offset of directory table */ ) @@ -1729,10 +1728,9 @@ FRESULT dir_sdi ( /* FR_OK(0):succeeded, !=0:error */ /* Directory handling - Move directory table index next */ /*-----------------------------------------------------------------------*/ -static -FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Could not stretch */ - FF_DIR* dp, /* Pointer to the directory object */ - int stretch /* 0: Do not stretch table, 1: Stretch table if needed */ +static FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Could not stretch */ + FF_DIR* dp, /* Pointer to the directory object */ + int stretch /* 0: Do not stretch table, 1: Stretch table if needed */ ) { DWORD ofs, clst; @@ -1740,7 +1738,8 @@ FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Cou ofs = dp->dptr + SZDIRE; /* Next entry */ - if (dp->sect == 0 || ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR)) return FR_NO_FILE; /* Report EOT when offset has reached max value */ + if (ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR)) dp->sect = 0; /* Disable it if the offset reached the max value */ + if (dp->sect == 0) return FR_NO_FILE; /* Report EOT if it has been disabled */ if (ofs % SS(fs) == 0) { /* Sector changed? */ dp->sect++; /* Next sector */ @@ -1790,10 +1789,9 @@ FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Cou /* Directory handling - Reserve a block of directory entries */ /*-----------------------------------------------------------------------*/ -static -FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */ - FF_DIR* dp, /* Pointer to the directory object */ - UINT nent /* Number of contiguous entries to allocate */ +static FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */ + FF_DIR* dp, /* Pointer to the directory object */ + UINT nent /* Number of contiguous entries to allocate */ ) { FRESULT res; @@ -1833,10 +1831,9 @@ FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */ /* FAT: Directory handling - Load/Store start cluster number */ /*-----------------------------------------------------------------------*/ -static -DWORD ld_clust ( /* Returns the top cluster value of the SFN entry */ - FATFS* fs, /* Pointer to the fs object */ - const BYTE* dir /* Pointer to the key entry */ +static DWORD ld_clust ( /* Returns the top cluster value of the SFN entry */ + FATFS* fs, /* Pointer to the fs object */ + const BYTE* dir /* Pointer to the key entry */ ) { DWORD cl; @@ -1851,8 +1848,7 @@ DWORD ld_clust ( /* Returns the top cluster value of the SFN entry */ #if !FF_FS_READONLY -static -void st_clust ( +static void st_clust ( FATFS* fs, /* Pointer to the fs object */ BYTE* dir, /* Pointer to the key entry */ DWORD cl /* Value to be set */ @@ -1871,8 +1867,8 @@ void st_clust ( /*--------------------------------------------------------*/ /* FAT-LFN: Compare a part of file name with an LFN entry */ /*--------------------------------------------------------*/ -static -int cmp_lfn ( /* 1:matched, 0:not matched */ + +static int cmp_lfn ( /* 1:matched, 0:not matched */ const WCHAR* lfnbuf, /* Pointer to the LFN working buffer to be compared */ BYTE* dir /* Pointer to the directory entry containing the part of LFN */ ) @@ -1888,7 +1884,7 @@ int cmp_lfn ( /* 1:matched, 0:not matched */ for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ if (wc != 0) { - if (i >= FF_MAX_LFN || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */ + if (i >= FF_MAX_LFN + 1 || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */ return 0; /* Not matched */ } wc = uc; @@ -1907,8 +1903,8 @@ int cmp_lfn ( /* 1:matched, 0:not matched */ /*-----------------------------------------------------*/ /* FAT-LFN: Pick a part of file name from an LFN entry */ /*-----------------------------------------------------*/ -static -int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */ + +static int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */ WCHAR* lfnbuf, /* Pointer to the LFN working buffer */ BYTE* dir /* Pointer to the LFN entry */ ) @@ -1924,15 +1920,15 @@ int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */ for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ if (wc != 0) { - if (i >= FF_MAX_LFN) return 0; /* Buffer overflow? */ + if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */ lfnbuf[i++] = wc = uc; /* Store it */ } else { if (uc != 0xFFFF) return 0; /* Check filler */ } } - if (dir[LDIR_Ord] & LLEF) { /* Put terminator if it is the last LFN part */ - if (i >= FF_MAX_LFN) return 0; /* Buffer overflow? */ + if (dir[LDIR_Ord] & LLEF && wc != 0) { /* Put terminator if it is the last LFN part and not terminated */ + if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */ lfnbuf[i] = 0; } @@ -1945,8 +1941,8 @@ int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */ /*-----------------------------------------*/ /* FAT-LFN: Create an entry of LFN entries */ /*-----------------------------------------*/ -static -void put_lfn ( + +static void put_lfn ( const WCHAR* lfn, /* Pointer to the LFN */ BYTE* dir, /* Pointer to the LFN entry to be created */ BYTE ord, /* LFN order (1-20) */ @@ -1983,8 +1979,7 @@ void put_lfn ( /* FAT-LFN: Create a Numbered SFN */ /*-----------------------------------------------------------------------*/ -static -void gen_numname ( +static void gen_numname ( BYTE* dst, /* Pointer to the buffer to store numbered SFN */ const BYTE* src, /* Pointer to SFN */ const WCHAR* lfn, /* Pointer to LFN */ @@ -2001,7 +1996,7 @@ void gen_numname ( if (seq > 5) { /* In case of many collisions, generate a hash number instead of sequential number */ sr = seq; - while (*lfn) { /* Create a CRC */ + while (*lfn) { /* Create a CRC as hash value */ wc = *lfn++; for (i = 0; i < 16; i++) { sr = (sr << 1) + (wc & 1); @@ -2042,8 +2037,7 @@ void gen_numname ( /* FAT-LFN: Calculate checksum of an SFN entry */ /*-----------------------------------------------------------------------*/ -static -BYTE sum_sfn ( +static BYTE sum_sfn ( const BYTE* dir /* Pointer to the SFN entry */ ) { @@ -2065,8 +2059,7 @@ BYTE sum_sfn ( /* exFAT: Checksum */ /*-----------------------------------------------------------------------*/ -static -WORD xdir_sum ( /* Get checksum of the directoly entry block */ +static WORD xdir_sum ( /* Get checksum of the directoly entry block */ const BYTE* dir /* Directory entry block to be calculated */ ) { @@ -2074,9 +2067,9 @@ WORD xdir_sum ( /* Get checksum of the directoly entry block */ WORD sum; - szblk = (dir[XDIR_NumSec] + 1) * SZDIRE; + szblk = (dir[XDIR_NumSec] + 1) * SZDIRE; /* Number of bytes of the entry block */ for (i = sum = 0; i < szblk; i++) { - if (i == XDIR_SetSum) { /* Skip sum field */ + if (i == XDIR_SetSum) { /* Skip 2-byte sum field */ i++; } else { sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + dir[i]; @@ -2087,8 +2080,7 @@ WORD xdir_sum ( /* Get checksum of the directoly entry block */ -static -WORD xname_sum ( /* Get check sum (to be used as hash) of the name */ +static WORD xname_sum ( /* Get check sum (to be used as hash) of the file name */ const WCHAR* name /* File name to be calculated */ ) { @@ -2097,7 +2089,7 @@ WORD xname_sum ( /* Get check sum (to be used as hash) of the name */ while ((chr = *name++) != 0) { - chr = (WCHAR)ff_wtoupper(chr); /* File name needs to be upper-case converted */ + chr = (WCHAR)ff_wtoupper(chr); /* File name needs to be up-case converted */ sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr & 0xFF); sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr >> 8); } @@ -2106,10 +2098,9 @@ WORD xname_sum ( /* Get check sum (to be used as hash) of the name */ #if !FF_FS_READONLY && FF_USE_MKFS -static -DWORD xsum32 ( - BYTE dat, /* Byte to be calculated */ - DWORD sum /* Previous sum */ +static DWORD xsum32 ( /* Returns 32-bit checksum */ + BYTE dat, /* Byte to be calculated (byte-by-byte processing) */ + DWORD sum /* Previous sum value */ ) { sum = ((sum & 1) ? 0x80000000 : 0) + (sum >> 1) + dat; @@ -2123,8 +2114,7 @@ DWORD xsum32 ( /* exFAT: Get object information from a directory block */ /*------------------------------------------------------*/ -static -void get_xfileinfo ( +static void get_xfileinfo ( BYTE* dirb, /* Pointer to the direcotry entry block 85+C0+C1s */ FILINFO* fno /* Buffer to store the extracted file information */ ) @@ -2134,7 +2124,7 @@ void get_xfileinfo ( /* Get file name from the entry block */ si = SZDIRE * 2; /* 1st C1 entry */ - nc = hs = di = 0; + nc = 0; hs = 0; di = 0; while (nc < dirb[XDIR_NumName]) { if (si >= MAXDIRB(FF_MAX_LFN)) { di = 0; break; } /* Truncated directory block? */ if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ @@ -2142,7 +2132,7 @@ void get_xfileinfo ( if (hs == 0 && IsSurrogate(wc)) { /* Is it a surrogate? */ hs = wc; continue; /* Get low surrogate */ } - wc = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di); /* Store it in UTF-16 or UTF-8 encoding */ + wc = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di); /* Store it in API encoding */ if (wc == 0) { di = 0; break; } /* Buffer overflow or wrong encoding? */ di += wc; hs = 0; @@ -2150,7 +2140,7 @@ void get_xfileinfo ( if (hs != 0) di = 0; /* Broken surrogate pair? */ if (di == 0) fno->fname[di++] = '?'; /* Inaccessible object name? */ fno->fname[di] = 0; /* Terminate the name */ - fno->altname[0] = 0; /* exFAT does not have SFN */ + fno->altname[0] = 0; /* exFAT does not support SFN */ fno->fattrib = dirb[XDIR_Attr]; /* Attribute */ fno->fsize = (fno->fattrib & AM_DIR) ? 0 : ld_qword(dirb + XDIR_FileSize); /* Size */ @@ -2165,9 +2155,8 @@ void get_xfileinfo ( /* exFAT: Get a directry entry block */ /*-----------------------------------*/ -static -FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ - FF_DIR* dp /* Reading direcotry object pointing top of the entry block to load */ +static FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ + FF_DIR* dp /* Reading direcotry object pointing top of the entry block to load */ ) { FRESULT res; @@ -2175,33 +2164,33 @@ FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory direcotry entry block 85+C0+C1s */ - /* Load 85 entry */ + /* Load file-directory entry */ res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; - if (dp->dir[XDIR_Type] != 0x85) return FR_INT_ERR; /* Invalid order */ + if (dp->dir[XDIR_Type] != ET_FILEDIR) return FR_INT_ERR; /* Invalid order */ mem_cpy(dirb + 0 * SZDIRE, dp->dir, SZDIRE); sz_ent = (dirb[XDIR_NumSec] + 1) * SZDIRE; if (sz_ent < 3 * SZDIRE || sz_ent > 19 * SZDIRE) return FR_INT_ERR; - /* Load C0 entry */ + /* Load stream-extension entry */ res = dir_next(dp, 0); if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */ if (res != FR_OK) return res; res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; - if (dp->dir[XDIR_Type] != 0xC0) return FR_INT_ERR; /* Invalid order */ + if (dp->dir[XDIR_Type] != ET_STREAM) return FR_INT_ERR; /* Invalid order */ mem_cpy(dirb + 1 * SZDIRE, dp->dir, SZDIRE); if (MAXDIRB(dirb[XDIR_NumName]) > sz_ent) return FR_INT_ERR; - /* Load C1 entries */ - i = 2 * SZDIRE; /* C1 offset to load */ + /* Load file-name entries */ + i = 2 * SZDIRE; /* Name offset to load */ do { res = dir_next(dp, 0); if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */ if (res != FR_OK) return res; res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; - if (dp->dir[XDIR_Type] != 0xC1) return FR_INT_ERR; /* Invalid order */ + if (dp->dir[XDIR_Type] != ET_FILENAME) return FR_INT_ERR; /* Invalid order */ if (i < MAXDIRB(FF_MAX_LFN)) mem_cpy(dirb + i, dp->dir, SZDIRE); } while ((i += SZDIRE) < sz_ent); @@ -2217,8 +2206,7 @@ FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ /* exFAT: Initialize object allocation info with loaded entry block */ /*------------------------------------------------------------------*/ -static -void init_alloc_info ( +static void init_alloc_info ( FATFS* fs, /* Filesystem object */ FFOBJID* obj /* Object allocation information to be initialized */ ) @@ -2235,8 +2223,8 @@ void init_alloc_info ( /*------------------------------------------------*/ /* exFAT: Load the object's directory entry block */ /*------------------------------------------------*/ -static -FRESULT load_obj_xdir ( + +static FRESULT load_obj_xdir ( FF_DIR* dp, /* Blank directory object to be used to access containing direcotry */ const FFOBJID* obj /* Object with its containing directory information */ ) @@ -2264,8 +2252,8 @@ FRESULT load_obj_xdir ( /*----------------------------------------*/ /* exFAT: Store the directory entry block */ /*----------------------------------------*/ -static -FRESULT store_xdir ( + +static FRESULT store_xdir ( FF_DIR* dp /* Pointer to the direcotry object */ ) { @@ -2297,8 +2285,7 @@ FRESULT store_xdir ( /* exFAT: Create a new directory enrty block */ /*-------------------------------------------*/ -static -void create_xdir ( +static void create_xdir ( BYTE* dirb, /* Pointer to the direcotry entry block buffer */ const WCHAR* lfn /* Pointer to the object name */ ) @@ -2308,16 +2295,16 @@ void create_xdir ( WCHAR wc; - /* Create 85,C0 entry */ + /* Create file-directory and stream-extension entry */ mem_set(dirb, 0, 2 * SZDIRE); - dirb[0 * SZDIRE + XDIR_Type] = 0x85; /* 85 entry */ - dirb[1 * SZDIRE + XDIR_Type] = 0xC0; /* C0 entry */ + dirb[0 * SZDIRE + XDIR_Type] = ET_FILEDIR; + dirb[1 * SZDIRE + XDIR_Type] = ET_STREAM; - /* Create C1 entries */ - i = SZDIRE * 2; /* Top of C1 entries */ + /* Create file-name entries */ + i = SZDIRE * 2; /* Top of file_name entries */ nlen = nc1 = 0; wc = 1; do { - dirb[i++] = 0xC1; dirb[i++] = 0; /* Entry type C1 */ + dirb[i++] = ET_FILENAME; dirb[i++] = 0; do { /* Fill name field */ if (wc != 0 && (wc = lfn[nlen]) != 0) nlen++; /* Get a character if exist */ st_word(dirb + i, wc); /* Store it */ @@ -2341,18 +2328,17 @@ void create_xdir ( /* Read an object from the directory */ /*-----------------------------------------------------------------------*/ -#define dir_read_file(dp) dir_read(dp, 0) -#define dir_read_label(dp) dir_read(dp, 1) +#define DIR_READ_FILE(dp) dir_read(dp, 0) +#define DIR_READ_LABEL(dp) dir_read(dp, 1) -static -FRESULT dir_read ( +static FRESULT dir_read ( FF_DIR* dp, /* Pointer to the directory object */ int vol /* Filtered by 0:file/directory or 1:volume label */ ) { FRESULT res = FR_NO_FILE; FATFS *fs = dp->obj.fs; - BYTE a, c; + BYTE attr, b; #if FF_USE_LFN BYTE ord = 0xFF, sum = 0xFF; #endif @@ -2360,16 +2346,16 @@ FRESULT dir_read ( while (dp->sect) { res = move_window(fs, dp->sect); if (res != FR_OK) break; - c = dp->dir[DIR_Name]; /* Test for the entry type */ - if (c == 0) { + b = dp->dir[DIR_Name]; /* Test for the entry type */ + if (b == 0) { res = FR_NO_FILE; break; /* Reached to end of the directory */ } #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ if (FF_USE_LABEL && vol) { - if (c == 0x83) break; /* Volume label entry? */ + if (b == ET_VLABEL) break; /* Volume label entry? */ } else { - if (c == 0x85) { /* Start of the file entry block? */ + if (b == ET_FILEDIR) { /* Start of the file entry block? */ dp->blk_ofs = dp->dptr; /* Get location of the block */ res = load_xdir(dp); /* Load the entry block */ if (res == FR_OK) { @@ -2381,19 +2367,19 @@ FRESULT dir_read ( } else #endif { /* On the FAT/FAT32 volume */ - dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */ + dp->obj.attr = attr = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */ #if FF_USE_LFN /* LFN configuration */ - if (c == DDEM || c == '.' || (int)((a & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ + if (b == DDEM || b == '.' || (int)((attr & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ ord = 0xFF; } else { - if (a == AM_LFN) { /* An LFN entry is found */ - if (c & LLEF) { /* Is it start of an LFN sequence? */ + if (attr == AM_LFN) { /* An LFN entry is found */ + if (b & LLEF) { /* Is it start of an LFN sequence? */ sum = dp->dir[LDIR_Chksum]; - c &= (BYTE)~LLEF; ord = c; + b &= (BYTE)~LLEF; ord = b; dp->blk_ofs = dp->dptr; } /* Check LFN validity and capture it */ - ord = (c == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; + ord = (b == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; } else { /* An SFN entry is found */ if (ord != 0 || sum != sum_sfn(dp->dir)) { /* Is there a valid LFN? */ dp->blk_ofs = 0xFFFFFFFF; /* It has no LFN. */ @@ -2402,7 +2388,7 @@ FRESULT dir_read ( } } #else /* Non LFN configuration */ - if (c != DDEM && c != '.' && a != AM_LFN && (int)((a & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */ + if (b != DDEM && b != '.' && attr != AM_LFN && (int)((attr & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */ break; } #endif @@ -2423,9 +2409,8 @@ FRESULT dir_read ( /* Directory handling - Find an object in the directory */ /*-----------------------------------------------------------------------*/ -static -FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ - FF_DIR* dp /* Pointer to the directory object with the file name */ +static FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ + FF_DIR* dp /* Pointer to the directory object with the file name */ ) { FRESULT res; @@ -2443,7 +2428,7 @@ FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ UINT di, ni; WORD hash = xname_sum(fs->lfnbuf); /* Hash value of the name to find */ - while ((res = dir_read_file(dp)) == FR_OK) { /* Read an item */ + while ((res = DIR_READ_FILE(dp)) == FR_OK) { /* Read an item */ #if FF_MAX_LFN < 255 if (fs->dirbuf[XDIR_NumName] > FF_MAX_LFN) continue; /* Skip comparison if inaccessible object name */ #endif @@ -2505,9 +2490,8 @@ FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ /* Register an object to the directory */ /*-----------------------------------------------------------------------*/ -static -FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many SFN collision, FR_DISK_ERR:disk error */ - FF_DIR* dp /* Target directory with object name to be created */ +static FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many SFN collision, FR_DISK_ERR:disk error */ + FF_DIR* dp /* Target directory with object name to be created */ ) { FRESULT res; @@ -2523,17 +2507,17 @@ FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many S #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ nent = (nlen + 14) / 15 + 2; /* Number of entries to allocate (85+C0+C1s) */ - res = dir_alloc(dp, nent); /* Allocate entries */ + res = dir_alloc(dp, nent); /* Allocate directory entries */ if (res != FR_OK) return res; dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set the allocated entry block offset */ - if (dp->obj.stat & 4) { /* Has the directory been stretched? */ + if (dp->obj.stat & 4) { /* Has the directory been stretched by new allocation? */ dp->obj.stat &= ~4; res = fill_first_frag(&dp->obj); /* Fill the first fragment on the FAT if needed */ if (res != FR_OK) return res; res = fill_last_frag(&dp->obj, dp->clust, 0xFFFFFFFF); /* Fill the last fragment on the FAT if needed */ if (res != FR_OK) return res; - if (dp->obj.sclust != 0) { /* Is it a sub directory? */ + if (dp->obj.sclust != 0) { /* Is it a sub-directory? */ FF_DIR dj; res = load_obj_xdir(&dj, &dp->obj); /* Load the object status */ @@ -2612,9 +2596,8 @@ FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many S /* Remove an object from the directory */ /*-----------------------------------------------------------------------*/ -static -FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */ - FF_DIR* dp /* Directory object pointing the entry to be removed */ +static FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */ + FF_DIR* dp /* Directory object pointing the entry to be removed */ ) { FRESULT res; @@ -2659,14 +2642,14 @@ FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */ /* Get file information from directory entry */ /*-----------------------------------------------------------------------*/ -static -void get_fileinfo ( - FF_DIR* dp, /* Pointer to the directory object */ - FILINFO* fno /* Pointer to the file information to be filled */ +static void get_fileinfo ( + FF_DIR* dp, /* Pointer to the directory object */ + FILINFO* fno /* Pointer to the file information to be filled */ ) { UINT si, di; #if FF_USE_LFN + BYTE lcf; WCHAR wc, hs; FATFS *fs = dp->obj.fs; #else @@ -2714,7 +2697,7 @@ void get_fileinfo ( } wc = ff_oem2uni(wc, CODEPAGE); /* ANSI/OEM -> Unicode */ if (wc == 0) { di = 0; break; } /* Wrong char in the current code page? */ - wc = put_utf(wc, &fno->altname[di], FF_SFN_BUF - di); /* Store it in UTF-16 or UTF-8 */ + wc = put_utf(wc, &fno->altname[di], FF_SFN_BUF - di); /* Store it in Unicode */ if (wc == 0) { di = 0; break; } /* Buffer overflow? */ di += wc; #else /* ANSI/OEM output */ @@ -2727,9 +2710,10 @@ void get_fileinfo ( if (di == 0) { /* If LFN and SFN both are invalid, this object is inaccesible */ fno->fname[di++] = '?'; } else { - for (si = di = 0; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */ + for (si = di = 0, lcf = NS_BODY; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */ wc = (WCHAR)fno->altname[si]; - if (IsUpper(wc) && (dp->dir[DIR_NTres] & ((si >= 9) ? NS_EXT : NS_BODY))) wc += 0x20; + if (wc == '.') lcf = NS_EXT; + if (IsUpper(wc) && (dp->dir[DIR_NTres] & lcf)) wc += 0x20; fno->fname[di] = (TCHAR)wc; } } @@ -2764,9 +2748,8 @@ void get_fileinfo ( /* Pattern matching */ /*-----------------------------------------------------------------------*/ -static -DWORD get_achar ( /* Get a character and advances ptr */ - const TCHAR** ptr /* Pointer to pointer to the ANSI/OEM or Unicode string */ +static DWORD get_achar ( /* Get a character and advances ptr */ + const TCHAR** ptr /* Pointer to pointer to the ANSI/OEM or Unicode string */ ) { DWORD chr; @@ -2796,8 +2779,7 @@ DWORD get_achar ( /* Get a character and advances ptr */ } -static -int pattern_matching ( /* 0:not matched, 1:matched */ +static int pattern_matching ( /* 0:not matched, 1:matched */ const TCHAR* pat, /* Matching pattern */ const TCHAR* nam, /* String to be tested */ int skip, /* Number of pre-skip chars (number of ?s) */ @@ -2844,10 +2826,9 @@ int pattern_matching ( /* 0:not matched, 1:matched */ /* Pick a top segment and create the object name in directory form */ /*-----------------------------------------------------------------------*/ -static -FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */ - FF_DIR* dp, /* Pointer to the directory object */ - const TCHAR** path /* Pointer to pointer to the segment in the path string */ +static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */ + FF_DIR* dp, /* Pointer to the directory object */ + const TCHAR** path /* Pointer to pointer to the segment in the path string */ ) { #if FF_USE_LFN /* LFN configuration */ @@ -3042,10 +3023,9 @@ FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */ /* Follow a file path */ /*-----------------------------------------------------------------------*/ -static -FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ - FF_DIR* dp, /* Directory object to return last directory and found object */ - const TCHAR* path /* Full-path string to find a file or directory */ +static FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ + FF_DIR* dp, /* Directory object to return last directory and found object */ + const TCHAR* path /* Full-path string to find a file or directory */ ) { FRESULT res; @@ -3130,58 +3110,71 @@ FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ /* Get logical drive number from path name */ /*-----------------------------------------------------------------------*/ -static -int get_ldnumber ( /* Returns logical drive number (-1:invalid drive) */ - const TCHAR** path /* Pointer to pointer to the path name */ +static int get_ldnumber ( /* Returns logical drive number (-1:invalid drive number or null pointer) */ + const TCHAR** path /* Pointer to pointer to the path name */ ) { const TCHAR *tp, *tt; - UINT i; - int vol = -1; -#if FF_STR_VOLUME_ID /* Find string drive id */ - static const char* const volid[] = {FF_VOLUME_STRS}; + TCHAR tc; + int i, vol = -1; +#if FF_STR_VOLUME_ID /* Find string volume ID */ const char *sp; char c; - TCHAR tc; #endif + tt = tp = *path; + if (!tp) return vol; /* Invalid path name? */ + do tc = *tt++; while ((UINT)tc >= (FF_USE_LFN ? ' ' : '!') && tc != ':'); /* Find a colon in the path */ - if (*path != 0) { /* If the pointer is not a null */ - for (tt = *path; (UINT)*tt >= (FF_USE_LFN ? ' ' : '!') && *tt != ':'; tt++) ; /* Find a colon in the path */ - if (*tt == ':') { /* If a colon is exist in the path name */ - tp = *path; - i = *tp++; - if (IsDigit(i) && tp == tt) { /* Is there a numeric drive id + colon? */ - if ((i -= '0') < FF_VOLUMES) { /* If drive id is found, get the value and strip it */ - vol = (int)i; - *path = ++tt; - } - } -#if FF_STR_VOLUME_ID - else { /* No numeric drive number, find string drive id */ - i = 0; tt++; - do { - sp = volid[i]; tp = *path; - do { /* Compare a string drive id with path name */ - c = *sp++; tc = *tp++; - if (IsLower(tc)) tc -= 0x20; - } while (c && (TCHAR)c == tc); - } while ((c || tp != tt) && ++i < FF_VOLUMES); /* Repeat for each id until pattern match */ - if (i < FF_VOLUMES) { /* If a drive id is found, get the value and strip it */ - vol = (int)i; - *path = tt; - } - } -#endif - } else { /* No volume id and use default drive */ -#if FF_FS_RPATH != 0 && FF_VOLUMES >= 2 - vol = CurrVol; /* Current drive */ -#else - vol = 0; /* Drive 0 */ + if (tc == ':') { /* DOS/Windows style volume ID? */ + i = FF_VOLUMES; + if (IsDigit(*tp) && tp + 2 == tt) { /* Is there a numeric volume ID + colon? */ + i = (int)*tp - '0'; /* Get the LD number */ + } +#if FF_STR_VOLUME_ID == 1 /* Arbitrary string is enabled */ + else { + i = 0; + do { + sp = VolumeStr[i]; tp = *path; /* This string volume ID and path name */ + do { /* Compare the volume ID with path name */ + c = *sp++; tc = *tp++; + if (IsLower(c)) c -= 0x20; + if (IsLower(tc)) tc -= 0x20; + } while (c && (TCHAR)c == tc); + } while ((c || tp != tt) && ++i < FF_VOLUMES); /* Repeat for each id until pattern match */ + } #endif + if (i < FF_VOLUMES) { /* If a volume ID is found, get the drive number and strip it */ + vol = i; /* Drive number */ + *path = tt; /* Snip the drive prefix off */ + } + return vol; + } +#if FF_STR_VOLUME_ID == 2 /* Unix style volume ID is enabled */ + if (*tp == '/') { + i = 0; + do { + sp = VolumeStr[i]; tp = *path; /* This string volume ID and path name */ + do { /* Compare the volume ID with path name */ + c = *sp++; tc = *(++tp); + if (IsLower(c)) c -= 0x20; + if (IsLower(tc)) tc -= 0x20; + } while (c && (TCHAR)c == tc); + } while ((c || (tc != '/' && (UINT)tc >= (FF_USE_LFN ? ' ' : '!'))) && ++i < FF_VOLUMES); /* Repeat for each ID until pattern match */ + if (i < FF_VOLUMES) { /* If a volume ID is found, get the drive number and strip it */ + vol = i; /* Drive number */ + *path = tp; /* Snip the drive prefix off */ + return vol; } } - return vol; +#endif + /* No drive prefix is found */ +#if FF_FS_RPATH != 0 + vol = CurrVol; /* Default drive is current drive */ +#else + vol = 0; /* Default drive is 0 */ +#endif + return vol; /* Return the default drive */ } @@ -3191,16 +3184,15 @@ int get_ldnumber ( /* Returns logical drive number (-1:invalid drive) */ /* Load a sector and check if it is an FAT VBR */ /*-----------------------------------------------------------------------*/ -static -BYTE check_fs ( /* 0:FAT, 1:exFAT, 2:Valid BS but not FAT, 3:Not a BS, 4:Disk error */ - FATFS* fs, /* Filesystem object */ - DWORD sect /* Sector# (lba) to load and check if it is an FAT-VBR or not */ +static BYTE check_fs ( /* 0:FAT, 1:exFAT, 2:Valid BS but not FAT, 3:Not a BS, 4:Disk error */ + FATFS* fs, /* Filesystem object */ + DWORD sect /* Sector# (lba) to load and check if it is an FAT-VBR or not */ ) { fs->wflag = 0; fs->winsect = 0xFFFFFFFF; /* Invaidate window */ if (move_window(fs, sect) != FR_OK) return 4; /* Load boot record */ - if (ld_word(fs->win + BS_55AA) != 0xAA55) return 3; /* Check boot record signature (always placed here even if the sector size is >512) */ + if (ld_word(fs->win + BS_55AA) != 0xAA55) return 3; /* Check boot record signature (always here regardless of the sector size) */ #if FF_FS_EXFAT if (!mem_cmp(fs->win + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11)) return 1; /* Check if exFAT VBR */ @@ -3219,11 +3211,10 @@ BYTE check_fs ( /* 0:FAT, 1:exFAT, 2:Valid BS but not FAT, 3:Not a BS, 4:Disk er /* Determine logical drive number and mount the volume if needed */ /*-----------------------------------------------------------------------*/ -static -FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ - const TCHAR** path, /* Pointer to pointer to the path name (drive number) */ - FATFS** rfs, /* Pointer to pointer to the found filesystem object */ - BYTE mode /* !=0: Check write protection for write access */ +static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */ + const TCHAR** path, /* Pointer to pointer to the path name (drive number) */ + FATFS** rfs, /* Pointer to pointer to the found filesystem object */ + BYTE mode /* !=0: Check write protection for write access */ ) { BYTE fmt, *pt; @@ -3276,7 +3267,7 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ if (SS(fs) > FF_MAX_SS || SS(fs) < FF_MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR; #endif - /* Find an FAT partition on the drive. Supports only generic partitioning rules, FDISK and SFD. */ + /* Find an FAT partition on the drive. Supports only generic partitioning rules, FDISK (MBR) and SFD (w/o partition). */ bsect = 0; fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT-VBR as SFD */ if (fmt == 2 || (fmt < 2 && LD2PT(vol) != 0)) { /* Not an FAT-VBR or forced partition number */ @@ -3299,6 +3290,7 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ #if FF_FS_EXFAT if (fmt == 1) { QWORD maxlba; + DWORD so, cv, bcl; for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && fs->win[i] == 0; i++) ; /* Check zero filler */ if (i < BPB_ZeroedEx + 53) return FR_NO_FILESYSTEM; @@ -3331,12 +3323,27 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */ fs->dirbase = ld_dword(fs->win + BPB_RootClusEx); - /* Check if bitmap location is in assumption (at the first cluster) */ - if (move_window(fs, clst2sect(fs, fs->dirbase)) != FR_OK) return FR_DISK_ERR; - for (i = 0; i < SS(fs); i += SZDIRE) { - if (fs->win[i] == 0x81 && ld_dword(fs->win + i + 20) == 2) break; /* 81 entry with cluster #2? */ + /* Get bitmap location and check if it is contiguous (implementation assumption) */ + so = i = 0; + for (;;) { /* Find the bitmap entry in the root directory (in only first cluster) */ + if (i == 0) { + if (so >= fs->csize) return FR_NO_FILESYSTEM; /* Not found? */ + if (move_window(fs, clst2sect(fs, fs->dirbase) + so) != FR_OK) return FR_DISK_ERR; + so++; + } + if (fs->win[i] == ET_BITMAP) break; /* Is it a bitmap entry? */ + i = (i + SZDIRE) % SS(fs); /* Next entry */ } - if (i == SS(fs)) return FR_NO_FILESYSTEM; + bcl = ld_dword(fs->win + i + 20); /* Bitmap cluster */ + if (bcl < 2 || bcl >= fs->n_fatent) return FR_NO_FILESYSTEM; + fs->bitbase = fs->database + fs->csize * (bcl - 2); /* Bitmap sector */ + for (;;) { /* Check if bitmap is contiguous */ + if (move_window(fs, fs->fatbase + bcl / (SS(fs) / 4)) != FR_OK) return FR_DISK_ERR; + cv = ld_dword(fs->win + bcl % (SS(fs) / 4) * 4); + if (cv == 0xFFFFFFFF) break; /* Last link? */ + if (cv != ++bcl) return FR_NO_FILESYSTEM; /* Fragmented? */ + } + #if !FF_FS_READONLY fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ #endif @@ -3367,7 +3374,7 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ if (nrsv == 0) return FR_NO_FILESYSTEM; /* (Must not be 0) */ /* Determine the FAT sub type */ - sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE); /* RSV + FAT + DIR */ + sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE); /* RSV + FAT + FF_DIR */ if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ if (nclst == 0) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ @@ -3445,10 +3452,9 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ /* Check if the file/directory object is valid or not */ /*-----------------------------------------------------------------------*/ -static -FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ - FFOBJID* obj, /* Pointer to the FFOBJID, the 1st member in the FIL/DIR object, to check validity */ - FATFS** rfs /* Pointer to pointer to the owner filesystem object to return */ +static FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ + FFOBJID* obj, /* Pointer to the FFOBJID, the 1st member in the FIL/FF_DIR object, to check validity */ + FATFS** rfs /* Pointer to pointer to the owner filesystem object to return */ ) { FRESULT res = FR_INVALID_OBJECT; @@ -3556,7 +3562,7 @@ FRESULT f_open ( if (!fp) return FR_INVALID_OBJECT; - /* Get logical drive */ + /* Get logical drive number */ mode &= FF_FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_CREATE_NEW | FA_OPEN_ALWAYS | FA_OPEN_APPEND; res = find_volume(&path, &fs, mode); if (res == FR_OK) { @@ -3587,7 +3593,7 @@ FRESULT f_open ( mode |= FA_CREATE_ALWAYS; /* File is created */ } else { /* Any object with the same name is already existing */ - if (dj.obj.attr & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or DIR) */ + if (dj.obj.attr & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or FF_DIR) */ res = FR_DENIED; } else { if (mode & FA_CREATE_NEW) res = FR_EXIST; /* Cannot create as new file */ @@ -3687,7 +3693,7 @@ FRESULT f_open ( fp->fptr = 0; /* Set file pointer top of the file */ #if !FF_FS_READONLY #if !FF_FS_TINY - mem_set(fp->buf, 0, FF_MAX_SS); /* Clear sector buffer */ + mem_set(fp->buf, 0, sizeof fp->buf); /* Clear sector buffer */ #endif if ((mode & FA_SEEKEND) && fp->obj.objsize > 0) { /* Seek to end of file if FA_OPEN_APPEND is specified */ fp->fptr = fp->obj.objsize; /* Offset to seek */ @@ -3750,7 +3756,7 @@ FRESULT f_read ( remain = fp->obj.objsize - fp->fptr; if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ - for ( ; btr; /* Repeat until all data read */ + for ( ; btr; /* Repeat until btr bytes read */ btr -= rcnt, *br += rcnt, rbuff += rcnt, fp->fptr += rcnt) { if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* Sector offset in the cluster */ @@ -4066,9 +4072,8 @@ FRESULT f_close ( /* Change Current Directory or Current Drive, Get Current Directory */ /*-----------------------------------------------------------------------*/ -#if FF_VOLUMES >= 2 FRESULT f_chdrive ( - const TCHAR* path /* Drive number */ + const TCHAR* path /* Drive number to set */ ) { int vol; @@ -4077,23 +4082,26 @@ FRESULT f_chdrive ( /* Get logical drive number */ vol = get_ldnumber(&path); if (vol < 0) return FR_INVALID_DRIVE; - CurrVol = (BYTE)vol; /* Set it as current volume */ return FR_OK; } -#endif + FRESULT f_chdir ( const TCHAR* path /* Pointer to the directory path */ ) { +#if FF_STR_VOLUME_ID == 2 + UINT i; +#endif FRESULT res; FF_DIR dj; FATFS *fs; DEF_NAMBUF + /* Get logical drive */ res = find_volume(&path, &fs, 0); if (res == FR_OK) { @@ -4101,8 +4109,8 @@ FRESULT f_chdir ( INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the path */ if (res == FR_OK) { /* Follow completed */ - if (dj.fn[NSFLAG] & NS_NONAME) { - fs->cdir = dj.obj.sclust; /* It is the start directory itself */ + if (dj.fn[NSFLAG] & NS_NONAME) { /* Is it the start directory itself? */ + fs->cdir = dj.obj.sclust; #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { fs->cdc_scl = dj.obj.c_scl; @@ -4130,6 +4138,12 @@ FRESULT f_chdir ( } FREE_NAMBUF(); if (res == FR_NO_FILE) res = FR_NO_PATH; +#if FF_STR_VOLUME_ID == 2 /* Also current drive is changed at Unix style volume ID */ + if (res == FR_OK) { + for (i = FF_VOLUMES - 1; i && fs != FatFs[i]; i--) ; /* Set current drive */ + CurrVol = (BYTE)i; + } +#endif } LEAVE_FF(fs, res); @@ -4139,7 +4153,7 @@ FRESULT f_chdir ( #if FF_FS_RPATH >= 2 FRESULT f_getcwd ( TCHAR* buff, /* Pointer to the directory path */ - UINT len /* Size of path */ + UINT len /* Size of buff in unit of TCHAR */ ) { FRESULT res; @@ -4147,17 +4161,25 @@ FRESULT f_getcwd ( FATFS *fs; UINT i, n; DWORD ccl; - TCHAR *tp; + TCHAR *tp = buff; +#if FF_VOLUMES >= 2 + UINT vl; +#if FF_STR_VOLUME_ID + const char *vp; +#endif +#endif FILINFO fno; DEF_NAMBUF - *buff = 0; /* Get logical drive */ + buff[0] = 0; /* Set null string to get current volume */ res = find_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */ if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); + + /* Follow parent directories and create the path */ i = len; /* Bottom of buffer (directory stack base) */ if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* (Cannot do getcwd on exFAT and returns root path) */ dj.obj.sclust = fs->cdir; /* Start to follow upper directory from current directory */ @@ -4170,7 +4192,7 @@ FRESULT f_getcwd ( res = dir_sdi(&dj, 0); if (res != FR_OK) break; do { /* Find the entry links to the child directory */ - res = dir_read_file(&dj); + res = DIR_READ_FILE(&dj); if (res != FR_OK) break; if (ccl == ld_clust(fs, dj.dir)) break; /* Found the entry */ res = dir_next(&dj, 0); @@ -4178,32 +4200,44 @@ FRESULT f_getcwd ( if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */ if (res != FR_OK) break; get_fileinfo(&dj, &fno); /* Get the directory name and push it to the buffer */ - for (n = 0; fno.fname[n]; n++) ; - if (i < n + 3) { + for (n = 0; fno.fname[n]; n++) ; /* Name length */ + if (i < n + 1) { /* Insufficient space to store the path name? */ res = FR_NOT_ENOUGH_CORE; break; } - while (n) buff[--i] = fno.fname[--n]; + while (n) buff[--i] = fno.fname[--n]; /* Stack the name */ buff[--i] = '/'; } } - tp = buff; if (res == FR_OK) { -#if FF_VOLUMES >= 2 - *tp++ = '0' + CurrVol; /* Put drive number */ - *tp++ = ':'; + if (i == len) buff[--i] = '/'; /* Is it the root-directory? */ +#if FF_VOLUMES >= 2 /* Put drive prefix */ + vl = 0; +#if FF_STR_VOLUME_ID >= 1 /* String volume ID */ + for (n = 0, vp = (const char*)VolumeStr[CurrVol]; vp[n]; n++) ; + if (i >= n + 2) { + if (FF_STR_VOLUME_ID == 2) *tp++ = (TCHAR)'/'; + for (vl = 0; vl < n; *tp++ = (TCHAR)vp[vl], vl++) ; + if (FF_STR_VOLUME_ID == 1) *tp++ = (TCHAR)':'; + vl++; + } +#else /* Numeric volume ID */ + if (i >= 3) { + *tp++ = (TCHAR)'0' + CurrVol; + *tp++ = (TCHAR)':'; + vl = 2; + } #endif - if (i == len) { /* Root-directory */ - *tp++ = '/'; - } else { /* Sub-directroy */ - do /* Add stacked path str */ - *tp++ = buff[i++]; - while (i < len); + if (vl == 0) res = FR_NOT_ENOUGH_CORE; +#endif + /* Add current directory path */ + if (res == FR_OK) { + do *tp++ = buff[i++]; while (i < len); /* Copy stacked path string */ } } - *tp = 0; FREE_NAMBUF(); } + *tp = 0; LEAVE_FF(fs, res); } @@ -4490,7 +4524,7 @@ FRESULT f_readdir ( res = dir_sdi(dp, 0); /* Rewind the directory object */ } else { INIT_NAMBUF(fs); - res = dir_read_file(dp); /* Read an item */ + res = DIR_READ_FILE(dp); /* Read an item */ if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory */ if (res == FR_OK) { /* A valid entry is found */ get_fileinfo(dp, fno); /* Get the object information */ @@ -4635,7 +4669,7 @@ FRESULT f_getfree ( UINT b; clst = fs->n_fatent - 2; /* Number of clusters */ - sect = fs->database; /* Assuming bitmap starts at cluster 2 */ + sect = fs->bitbase; /* Bitmap sector */ i = 0; /* Offset in the sector */ do { /* Counts numbuer of bits with zero in the bitmap */ if (i == 0) { @@ -4694,6 +4728,7 @@ FRESULT f_truncate ( FATFS *fs; DWORD ncl; + res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ @@ -4797,7 +4832,7 @@ FRESULT f_unlink ( #endif res = dir_sdi(&sdj, 0); if (res == FR_OK) { - res = dir_read_file(&sdj); /* Test if the directory is empty */ + res = DIR_READ_FILE(&sdj); /* Test if the directory is empty */ if (res == FR_OK) res = FR_DENIED; /* Not empty? */ if (res == FR_NO_FILE) res = FR_OK; /* Empty? */ } @@ -4835,73 +4870,69 @@ FRESULT f_mkdir ( { FRESULT res; FF_DIR dj; + FFOBJID sobj; FATFS *fs; - BYTE *dir; DWORD dcl, pcl, tm; DEF_NAMBUF - /* Get logical drive */ - res = find_volume(&path, &fs, FA_WRITE); + res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive */ if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ - if (res == FR_OK) res = FR_EXIST; /* Any object with same name is already existing */ - if (FF_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) { + if (res == FR_OK) res = FR_EXIST; /* Name collision? */ + if (FF_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) { /* Invalid name? */ res = FR_INVALID_NAME; } - if (res == FR_NO_FILE) { /* Can create a new directory */ - dcl = create_chain(&dj.obj, 0); /* Allocate a cluster for the new directory table */ - dj.obj.objsize = (DWORD)fs->csize * SS(fs); + if (res == FR_NO_FILE) { /* It is clear to create a new directory */ + sobj.fs = fs; /* New object id to create a new chain */ + dcl = create_chain(&sobj, 0); /* Allocate a cluster for the new directory */ res = FR_OK; - if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster */ - if (dcl == 1) res = FR_INT_ERR; - if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; - if (res == FR_OK) res = sync_window(fs); /* Flush FAT */ + if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster? */ + if (dcl == 1) res = FR_INT_ERR; /* Any insanity? */ + if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; /* Disk error? */ tm = GET_FATTIME(); - if (res == FR_OK) { /* Initialize the new directory table */ - res = dir_clear(fs, dcl); /* Clean up the new table */ - if (res == FR_OK && (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT)) { /* Create dot entries (FAT only) */ - dir = fs->win; - mem_set(dir + DIR_Name, ' ', 11); /* Create "." entry */ - dir[DIR_Name] = '.'; - dir[DIR_Attr] = AM_DIR; - st_dword(dir + DIR_ModTime, tm); - st_clust(fs, dir, dcl); - mem_cpy(dir + SZDIRE, dir, SZDIRE); /* Create ".." entry */ - dir[SZDIRE + 1] = '.'; pcl = dj.obj.sclust; - st_clust(fs, dir + SZDIRE, pcl); - fs->wflag = 1; - } - } if (res == FR_OK) { - res = dir_register(&dj); /* Register the object to the directoy */ + res = dir_clear(fs, dcl); /* Clean up the new table */ + if (res == FR_OK) { + if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* Create dot entries (FAT only) */ + mem_set(fs->win + DIR_Name, ' ', 11); /* Create "." entry */ + fs->win[DIR_Name] = '.'; + fs->win[DIR_Attr] = AM_DIR; + st_dword(fs->win + DIR_ModTime, tm); + st_clust(fs, fs->win, dcl); + mem_cpy(fs->win + SZDIRE, fs->win, SZDIRE); /* Create ".." entry */ + fs->win[SZDIRE + 1] = '.'; pcl = dj.obj.sclust; + st_clust(fs, fs->win + SZDIRE, pcl); + fs->wflag = 1; + } + res = dir_register(&dj); /* Register the object to the parent directoy */ + } } if (res == FR_OK) { #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* Initialize directory entry block */ st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Created time */ st_dword(fs->dirbuf + XDIR_FstClus, dcl); /* Table start cluster */ - st_dword(fs->dirbuf + XDIR_FileSize, (DWORD)dj.obj.objsize); /* File size needs to be valid */ - st_dword(fs->dirbuf + XDIR_ValidFileSize, (DWORD)dj.obj.objsize); + st_dword(fs->dirbuf + XDIR_FileSize, (DWORD)fs->csize * SS(fs)); /* File size needs to be valid */ + st_dword(fs->dirbuf + XDIR_ValidFileSize, (DWORD)fs->csize * SS(fs)); fs->dirbuf[XDIR_GenFlags] = 3; /* Initialize the object flag */ fs->dirbuf[XDIR_Attr] = AM_DIR; /* Attribute */ res = store_xdir(&dj); } else #endif { - dir = dj.dir; - st_dword(dir + DIR_ModTime, tm); /* Created time */ - st_clust(fs, dir, dcl); /* Table start cluster */ - dir[DIR_Attr] = AM_DIR; /* Attribute */ + st_dword(dj.dir + DIR_ModTime, tm); /* Created time */ + st_clust(fs, dj.dir, dcl); /* Table start cluster */ + dj.dir[DIR_Attr] = AM_DIR; /* Attribute */ fs->wflag = 1; } if (res == FR_OK) { res = sync_fs(fs); } } else { - remove_chain(&dj.obj, dcl, 0); /* Could not register, remove cluster chain */ + remove_chain(&sobj, dcl, 0); /* Could not register, remove the allocated cluster */ } } FREE_NAMBUF(); @@ -5141,7 +5172,7 @@ FRESULT f_getlabel ( dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */ res = dir_sdi(&dj, 0); if (res == FR_OK) { - res = dir_read_label(&dj); /* Find a volume label entry */ + res = DIR_READ_LABEL(&dj); /* Find a volume label entry */ if (res == FR_OK) { #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { @@ -5167,8 +5198,8 @@ FRESULT f_getlabel ( wc = dj.dir[si++]; #if FF_USE_LFN && FF_LFN_UNICODE >= 1 /* Unicode output */ if (dbc_1st((BYTE)wc) && si < 11) wc = wc << 8 | dj.dir[si++]; /* Is it a DBC? */ - wc = ff_oem2uni(wc, CODEPAGE); - if (wc != 0) wc = put_utf(wc, &label[di], 4); + wc = ff_oem2uni(wc, CODEPAGE); /* Convert it into Unicode */ + if (wc != 0) wc = put_utf(wc, &label[di], 4); /* Put it in Unicode */ if (wc == 0) { di = 0; break; } di += wc; #else /* ANSI/OEM output */ @@ -5226,7 +5257,7 @@ FRESULT f_setlabel ( BYTE dirvn[22]; UINT di; WCHAR wc; - static const char badchr[] = "+.,;=[]\"*:<>\?|\x7F"; /* [0..] for FAT, [7..] for exFAT */ + static const char badchr[] = "+.,;=[]/\\\"*:<>\?|\x7F"; /* [0..] for FAT, [7..] for exFAT */ #if FF_USE_LFN DWORD dc; #endif @@ -5239,7 +5270,7 @@ FRESULT f_setlabel ( if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ mem_set(dirvn, 0, 22); di = 0; - while (*label) { /* Create volume label in directory form */ + while ((UINT)*label >= ' ') { /* Create volume label */ dc = tchar2uni(&label); /* Get a Unicode character */ if (dc >= 0x10000) { if (dc == 0xFFFFFFFF || di >= 10) { /* Wrong surrogate or buffer overflow */ @@ -5258,7 +5289,7 @@ FRESULT f_setlabel ( { /* On the FAT/FAT32 volume */ mem_set(dirvn, ' ', 11); di = 0; - while (*label) { /* Create volume label in directory form */ + while ((UINT)*label >= ' ') { /* Create volume label */ #if FF_USE_LFN dc = tchar2uni(&label); wc = (dc < 0x10000) ? ff_uni2oem(ff_wtoupper(dc), CODEPAGE) : 0; @@ -5286,7 +5317,7 @@ FRESULT f_setlabel ( dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */ res = dir_sdi(&dj, 0); if (res == FR_OK) { - res = dir_read_label(&dj); /* Get volume label entry */ + res = DIR_READ_LABEL(&dj); /* Get volume label entry */ if (res == FR_OK) { if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { dj.dir[XDIR_NumLabel] = (BYTE)di; /* Change the volume label */ @@ -5308,7 +5339,7 @@ FRESULT f_setlabel ( if (res == FR_OK) { mem_set(dj.dir, 0, SZDIRE); /* Clean the entry */ if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { - dj.dir[XDIR_Type] = 0x83; /* Create 83 entry */ + dj.dir[XDIR_Type] = ET_VLABEL; /* Create volume label entry */ dj.dir[XDIR_NumLabel] = (BYTE)di; mem_cpy(dj.dir + XDIR_Label, dirvn, 22); } else { @@ -5546,7 +5577,7 @@ FRESULT f_mkfs ( /* Get working buffer */ #if FF_USE_LFN == 3 if (!work) { /* Use heap memory for working buffer */ - for (szb_buf = MAX_MALLOC, buf = 0; szb_buf >= ss && !(buf = ff_memalloc(szb_buf)); szb_buf /= 2) ; + for (szb_buf = MAX_MALLOC, buf = 0; szb_buf >= ss && (buf = ff_memalloc(szb_buf)) == 0; szb_buf /= 2) ; sz_buf = szb_buf / ss; /* Size of working buffer (sector) */ } else #endif @@ -5613,7 +5644,7 @@ FRESULT f_mkfs ( b_fat = b_vol + 32; /* FAT start at offset 32 */ sz_fat = ((sz_vol / au + 2) * 4 + ss - 1) / ss; /* Number of FAT sectors */ b_data = (b_fat + sz_fat + sz_blk - 1) & ~(sz_blk - 1); /* Align data area to the erase block boundary */ - if (b_data >= sz_vol / 2) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */ + if (b_data - b_vol >= sz_vol / 2) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */ n_clst = (sz_vol - (b_data - b_vol)) / au; /* Number of clusters */ if (n_clst <16) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too few clusters? */ if (n_clst > MAX_EXFAT) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters? */ @@ -5624,7 +5655,7 @@ FRESULT f_mkfs ( /* Create a compressed up-case table */ sect = b_data + au * tbl[0]; /* Table start sector */ sum = 0; /* Table checksum to be stored in the 82 entry */ - st = si = i = j = szb_case = 0; + st = 0; si = 0; i = 0; j = 0; szb_case = 0; do { switch (st) { case 0: @@ -5644,7 +5675,7 @@ FRESULT f_mkfs ( break; default: - ch = (WCHAR)j; si += j; /* Number of chars to skip */ + ch = (WCHAR)j; si += (WCHAR)j; /* Number of chars to skip */ st = 0; } sum = xsum32(buf[i + 0] = (BYTE)ch, sum); /* Put it into the write buffer */ @@ -5694,14 +5725,14 @@ FRESULT f_mkfs ( /* Initialize the root directory */ mem_set(buf, 0, szb_buf); - buf[SZDIRE * 0 + 0] = 0x83; /* 83 entry (volume label) */ - buf[SZDIRE * 1 + 0] = 0x81; /* 81 entry (allocation bitmap) */ - st_dword(buf + SZDIRE * 1 + 20, 2); - st_dword(buf + SZDIRE * 1 + 24, szb_bit); - buf[SZDIRE * 2 + 0] = 0x82; /* 82 entry (up-case table) */ - st_dword(buf + SZDIRE * 2 + 4, sum); - st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]); - st_dword(buf + SZDIRE * 2 + 24, szb_case); + buf[SZDIRE * 0 + 0] = ET_VLABEL; /* Volume label entry */ + buf[SZDIRE * 1 + 0] = ET_BITMAP; /* Bitmap entry */ + st_dword(buf + SZDIRE * 1 + 20, 2); /* cluster */ + st_dword(buf + SZDIRE * 1 + 24, szb_bit); /* size */ + buf[SZDIRE * 2 + 0] = ET_UPCASE; /* Up-case table entry */ + st_dword(buf + SZDIRE * 2 + 4, sum); /* sum */ + st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]); /* cluster */ + st_dword(buf + SZDIRE * 2 + 24, szb_case); /* size */ sect = b_data + au * (tbl[0] + tbl[1]); nsect = au; /* Start of the root directory and number of sectors */ do { /* Fill root directory sectors */ n = (nsect > sz_buf) ? sz_buf : nsect; @@ -5991,8 +6022,7 @@ FRESULT f_fdisk ( if (!buf) return FR_NOT_ENOUGH_CORE; /* Determine the CHS without any consideration of the drive geometry */ - for (n = 16; n < 256 && sz_disk / n / cluster_size > 1024; n *= 2) - { + for (n = 16; n < 256 && sz_disk / n / cluster_size > 1024; n *= 2) { ; } if (n == 256) n--; @@ -6027,7 +6057,7 @@ FRESULT f_fdisk ( p[3] = (BYTE)b_cyl; /* Start cylinder */ p[4] = 0x07; /* System type (temporary setting) */ p[5] = e_hd; /* End head */ - p[6] = (BYTE)(((e_cyl >> 2) & 0xC0) | 63); /* End sector */ + p[6] = (BYTE)(((e_cyl >> 2) & 0xC0) | cluster_size); /* End sector */ p[7] = (BYTE)e_cyl; /* End cylinder */ st_dword(p + 8, s_part); /* Start sector in LBA */ st_dword(p + 12, sz_part); /* Number of sectors */ @@ -6064,68 +6094,22 @@ TCHAR* f_gets ( { int nc = 0; TCHAR *p = buff; - BYTE s[2]; + BYTE s[4]; UINT rc; - WCHAR wc; -#if FF_USE_LFN && ((FF_LFN_UNICODE == 1 && FF_STRF_ENCODE == 3) || (FF_LFN_UNICODE == 2 && FF_STRF_ENCODE != 3)) DWORD dc; +#if FF_USE_LFN && FF_LFN_UNICODE && FF_STRF_ENCODE <= 2 + WCHAR wc; #endif -#if FF_USE_LFN && FF_LFN_UNICODE == 1 && FF_STRF_ENCODE == 3 +#if FF_USE_LFN && FF_LFN_UNICODE && FF_STRF_ENCODE == 3 UINT ct; #endif -#if FF_USE_LFN && FF_LFN_UNICODE == 1 /* UTF-16 output */ -#if FF_STRF_ENCODE == 0 /* Read a character in ANSI/OEM */ - while (nc < len - 1) { - f_read(fp, s, 1, &rc); - if (rc != 1) break; - wc = s[0]; - if (dbc_1st((BYTE)wc)) { - f_read(fp, s, 1, &rc); - if (rc != 1 || !dbc_2nd(s[0])) continue; - wc = wc << 8 | s[0]; - } - wc = ff_oem2uni(wc, CODEPAGE); - if (wc == 0) continue; -#elif FF_STRF_ENCODE == 1 || FF_STRF_ENCODE == 2 /* Read a character in UTF-16LE/BE */ - while (nc < len - 1) { - f_read(fp, s, 2, &rc); - if (rc != 2) break; - wc = (FF_STRF_ENCODE == 1) ? s[1] << 8 | s[0] : s[0] << 8 | s[1]; -#elif FF_STRF_ENCODE == 3 /* Read a character in UTF-8 */ - while (nc < len - 2) { - f_read(fp, s, 1, &rc); - if (rc != 1) break; - dc = s[0]; - if (dc >= 0x80) { - ct = 0; - if ((dc & 0xE0) == 0xC0) { dc &= 0x1F; ct = 1; } - if ((dc & 0xF0) == 0xE0) { dc &= 0x0F; ct = 2; } - if ((dc & 0xF8) == 0xF0) { dc &= 0x07; ct = 3; } - if (ct == 0) continue; - do { - f_read(fp, s, 1, &rc); - if (rc != 1 || (s[0] & 0xC0) != 0x80) break; - dc = dc << 6 | (s[0] & 0x3F); - } while (--ct); - if (ct || dc < 0x80 || dc >= 0x110000) continue; - } - if (dc >= 0x10000) { - wc = (WCHAR)(0xD800 | ((dc >> 10) - 0x40)); - *p++ = wc; nc++; - wc = (WCHAR)(0xDC00 | (dc & 0x3FF)); - } else { - wc = (WCHAR)dc; - } -#endif - /* Output it in UTF-16 encoding */ - if (FF_USE_STRFUNC == 2 && wc == '\r') continue; - *p++ = wc; nc++; - if (wc == '\n') break; - } - -#elif FF_USE_LFN && FF_LFN_UNICODE == 2 && FF_STRF_ENCODE != 3 /* UTF-8 output */ - while (nc < len - 4) { +#if FF_USE_LFN && FF_LFN_UNICODE /* With code conversion (Unicode API) */ + /* Make a room for the character and terminator */ + if (FF_LFN_UNICODE == 1) len -= (FF_STRF_ENCODE == 0) ? 1 : 2; + if (FF_LFN_UNICODE == 2) len -= (FF_STRF_ENCODE == 0) ? 3 : 4; + if (FF_LFN_UNICODE == 3) len -= 1; + while (nc < len) { #if FF_STRF_ENCODE == 0 /* Read a character in ANSI/OEM */ f_read(fp, s, 1, &rc); if (rc != 1) break; @@ -6137,26 +6121,53 @@ TCHAR* f_gets ( } dc = ff_oem2uni(wc, CODEPAGE); if (dc == 0) continue; -#else /* Read a character in UTF-16LE/BE */ +#elif FF_STRF_ENCODE == 1 || FF_STRF_ENCODE == 2 /* Read a character in UTF-16LE/BE */ f_read(fp, s, 2, &rc); if (rc != 2) break; - dc = (FF_STRF_ENCODE == 1) ? s[1] << 8 | s[0] : s[0] << 8 | s[1]; - if (IsSurrogate(dc)) { + dc = (FF_STRF_ENCODE == 1) ? ld_word(s) : s[0] << 8 | s[1]; + if (IsSurrogateL(dc)) continue; + if (IsSurrogateH(dc)) { f_read(fp, s, 2, &rc); if (rc != 2) break; - wc = (FF_STRF_ENCODE == 1) ? s[1] << 8 | s[0] : s[0] << 8 | s[1]; - if (!IsSurrogateH(dc) || !IsSurrogateL(wc)) continue; + wc = (FF_STRF_ENCODE == 1) ? ld_word(s) : s[0] << 8 | s[1]; + if (!IsSurrogateL(wc)) continue; dc = ((dc & 0x3FF) + 0x40) << 10 | (wc & 0x3FF); } +#else /* Read a character in UTF-8 */ + f_read(fp, s, 1, &rc); + if (rc != 1) break; + dc = s[0]; + if (dc >= 0x80) { /* Multi-byte character? */ + ct = 0; + if ((dc & 0xE0) == 0xC0) { dc &= 0x1F; ct = 1; } /* 2-byte? */ + if ((dc & 0xF0) == 0xE0) { dc &= 0x0F; ct = 2; } /* 3-byte? */ + if ((dc & 0xF8) == 0xF0) { dc &= 0x07; ct = 3; } /* 4-byte? */ + if (ct == 0) continue; + f_read(fp, s, ct, &rc); /* Get trailing bytes */ + if (rc != ct) break; + rc = 0; + do { /* Merge trailing bytes */ + if ((s[rc] & 0xC0) != 0x80) break; + dc = dc << 6 | (s[rc] & 0x3F); + } while (++rc < ct); + if (rc != ct || dc < 0x80 || IsSurrogate(dc) || dc >= 0x110000) continue; /* Wrong encoding? */ + } #endif - /* Output it in UTF-8 encoding */ - if (FF_USE_STRFUNC == 2 && dc == '\r') continue; + if (FF_USE_STRFUNC == 2 && dc == '\r') continue; /* Strip \r off if needed */ +#if FF_LFN_UNICODE == 1 || FF_LFN_UNICODE == 3 /* Output it in UTF-16/32 encoding */ + if (FF_LFN_UNICODE == 1 && dc >= 0x10000) { /* Out of BMP at UTF-16? */ + *p++ = (TCHAR)(0xD800 | ((dc >> 10) - 0x40)); nc++; /* Make and output high surrogate */ + dc = 0xDC00 | (dc & 0x3FF); /* Make low surrogate */ + } + *p++ = (TCHAR)dc; nc++; + if (dc == '\n') break; /* End of line? */ +#elif FF_LFN_UNICODE == 2 /* Output it in UTF-8 encoding */ if (dc < 0x80) { /* 1-byte */ *p++ = (TCHAR)dc; nc++; - if (dc == '\n') break; + if (dc == '\n') break; /* End of line? */ } else { - if (dc < 0x800) { /* 2-byte */ + if (dc < 0x800) { /* 2-byte */ *p++ = (TCHAR)(0xC0 | (dc >> 6 & 0x1F)); *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); nc += 2; @@ -6175,21 +6186,23 @@ TCHAR* f_gets ( } } } +#endif } -#else /* Byte-by-byte without any conversion (ANSI/OEM API or UTF-8 to UTF-8) */ - while (nc < len - 1) { +#else /* Byte-by-byte without any conversion (ANSI/OEM API) */ + len -= 1; /* Make a room for the terminator */ + while (nc < len) { f_read(fp, s, 1, &rc); if (rc != 1) break; - wc = s[0]; - if (FF_USE_STRFUNC == 2 && wc == '\r') continue; - *p++ = (TCHAR)wc; nc++; - if (wc == '\n') break; + dc = s[0]; + if (FF_USE_STRFUNC == 2 && dc == '\r') continue; + *p++ = (TCHAR)dc; nc++; + if (dc == '\n') break; } #endif - *p = 0; - return nc ? buff : 0; /* When no data read (EOF or error), return with error. */ + *p = 0; /* Terminate the string */ + return nc ? buff : 0; /* When no data read due to EOF or error, return with error. */ } @@ -6214,20 +6227,19 @@ typedef struct { /* Putchar output buffer and work area */ } putbuff; -static -void putc_bfd ( /* Buffered write with code conversion */ +static void putc_bfd ( /* Buffered write with code conversion */ putbuff* pb, TCHAR c ) { UINT n; int i, nc; -#if FF_USE_LFN && (FF_LFN_UNICODE == 1 || (FF_LFN_UNICODE == 2 && (FF_STRF_ENCODE != 3))) +#if FF_USE_LFN && FF_LFN_UNICODE WCHAR hs, wc; -#endif -#if FF_USE_LFN && FF_LFN_UNICODE == 2 && FF_STRF_ENCODE != 3 +#if FF_LFN_UNICODE == 2 DWORD dc; TCHAR *tp; +#endif #endif if (FF_USE_STRFUNC == 2 && c == '\n') { /* LF -> CRLF conversion */ @@ -6236,45 +6248,21 @@ void putc_bfd ( /* Buffered write with code conversion */ i = pb->idx; /* Write index of pb->buf[] */ if (i < 0) return; - nc = pb->nchr; /* Write unit count */ + nc = pb->nchr; /* Write unit counter */ -#if FF_USE_LFN && FF_LFN_UNICODE >= 1 -#if FF_USE_LFN && FF_LFN_UNICODE == 1 /* UTF-16 input */ +#if FF_USE_LFN && FF_LFN_UNICODE +#if FF_LFN_UNICODE == 1 /* UTF-16 input */ if (IsSurrogateH(c)) { pb->hs = c; return; } - wc = c; hs = pb->hs; pb->hs = 0; + hs = pb->hs; pb->hs = 0; if (hs != 0) { - if (!IsSurrogateL(wc)) hs = 0; + if (!IsSurrogateL(c)) hs = 0; } else { - if (IsSurrogateL(wc)) return; + if (IsSurrogateL(c)) return; } -#if FF_STRF_ENCODE == 3 /* Write it in UTF-8 */ - if (hs != 0) { /* 4-byte */ - nc += 4; - hs = (hs & 0x3FF) + 0x40; - pb->buf[i++] = (BYTE)(0xF0 | hs >> 8); - pb->buf[i++] = (BYTE)(0x80 | (hs >> 2 & 0x3F)); - pb->buf[i++] = (BYTE)(0x80 | (hs & 3) << 4 | (wc >> 6 & 0x0F)); - pb->buf[i++] = (BYTE)(0x80 | (wc & 0x3F)); - } else { - if (wc < 0x80) { /* 1-byte */ - nc++; - pb->buf[i++] = (BYTE)wc; - } else { - if (wc < 0x800) { /* 2-byte */ - nc += 2; - pb->buf[i++] = (BYTE)(0xC0 | wc >> 6); - } else { /* 3-byte */ - nc += 3; - pb->buf[i++] = (BYTE)(0xE0 | wc >> 12); - pb->buf[i++] = (BYTE)(0x80 | (wc >> 6 & 0x3F)); - } - pb->buf[i++] = (BYTE)(0x80 | (wc & 0x3F)); - } - } -#endif -#else /* UTF-8 input */ + wc = c; +#elif FF_LFN_UNICODE == 2 /* UTF-8 input */ for (;;) { if (pb->ct == 0) { /* Out of multi-byte sequence? */ pb->bs[pb->wi = 0] = (BYTE)c; /* Save 1st byte */ @@ -6283,36 +6271,40 @@ void putc_bfd ( /* Buffered write with code conversion */ if (((BYTE)c & 0xF0) == 0xE0) pb->ct = 2; /* 3-byte? */ if (((BYTE)c & 0xF1) == 0xF0) pb->ct = 3; /* 4-byte? */ return; - } else { /* In the multi-byte sequence */ + } else { /* In the multi-byte sequence */ if (((BYTE)c & 0xC0) != 0x80) { /* Broken sequence? */ pb->ct = 0; continue; } pb->bs[++pb->wi] = (BYTE)c; /* Save the trailing byte */ - if (--pb->ct == 0) break; /* End of sequence? */ + if (--pb->ct == 0) break; /* End of multi-byte sequence? */ return; } } -#if FF_STRF_ENCODE == 3 /* Write it in UTF-8 */ - pb->buf[i++] = pb->bs[0]; nc++; - if (pb->bs[0] >= 0xC0) { - pb->buf[i++] = pb->bs[1]; nc++; - } - if (pb->bs[0] >= 0xE0) { - pb->buf[i++] = pb->bs[2]; nc++; - } - if (pb->bs[0] >= 0xF0) { - pb->buf[i++] = pb->bs[3]; nc++; - } -#else /* Write it in UTF-16 or ANSI/OEM */ tp = (TCHAR*)pb->bs; dc = tchar2uni(&tp); /* UTF-8 ==> UTF-16 */ if (dc == 0xFFFFFFFF) return; wc = (WCHAR)dc; hs = (WCHAR)(dc >> 16); +#elif FF_LFN_UNICODE == 3 /* UTF-32 input */ + if (IsSurrogate(c) || c >= 0x110000) return; + if (c >= 0x10000) { + hs = (WCHAR)(0xD800 | ((c >> 10) - 0x40)); /* Make high surrogate */ + wc = 0xDC00 | (c & 0x3FF); /* Make low surrogate */ + } else { + hs = 0; + wc = (WCHAR)c; + } #endif -#endif -#if FF_USE_LFN && FF_LFN_UNICODE >= 1 && FF_STRF_ENCODE != 3 -#if FF_STRF_ENCODE == 2 /* Write a character in UTF-16BE */ + +#if FF_STRF_ENCODE == 1 /* Write a character in UTF-16LE */ + if (hs != 0) { + st_word(&pb->buf[i], hs); + i += 2; + nc++; + } + st_word(&pb->buf[i], wc); + i += 2; +#elif FF_STRF_ENCODE == 2 /* Write a character in UTF-16BE */ if (hs != 0) { pb->buf[i++] = (BYTE)(hs >> 8); pb->buf[i++] = (BYTE)hs; @@ -6320,30 +6312,41 @@ void putc_bfd ( /* Buffered write with code conversion */ } pb->buf[i++] = (BYTE)(wc >> 8); pb->buf[i++] = (BYTE)wc; - nc++; -#elif FF_STRF_ENCODE == 1 /* Write a character in UTF-16LE */ - if (hs != 0) { - pb->buf[i++] = (BYTE)hs; - pb->buf[i++] = (BYTE)(hs >> 8); - nc++; +#elif FF_STRF_ENCODE == 3 /* Write it in UTF-8 */ + if (hs != 0) { /* 4-byte */ + nc += 3; + hs = (hs & 0x3FF) + 0x40; + pb->buf[i++] = (BYTE)(0xF0 | hs >> 8); + pb->buf[i++] = (BYTE)(0x80 | (hs >> 2 & 0x3F)); + pb->buf[i++] = (BYTE)(0x80 | (hs & 3) << 4 | (wc >> 6 & 0x0F)); + pb->buf[i++] = (BYTE)(0x80 | (wc & 0x3F)); + } else { + if (wc < 0x80) { /* 1-byte */ + pb->buf[i++] = (BYTE)wc; + } else { + if (wc < 0x800) { /* 2-byte */ + nc += 1; + pb->buf[i++] = (BYTE)(0xC0 | wc >> 6); + } else { /* 3-byte */ + nc += 2; + pb->buf[i++] = (BYTE)(0xE0 | wc >> 12); + pb->buf[i++] = (BYTE)(0x80 | (wc >> 6 & 0x3F)); + } + pb->buf[i++] = (BYTE)(0x80 | (wc & 0x3F)); + } } - pb->buf[i++] = (BYTE)wc; - pb->buf[i++] = (BYTE)(wc >> 8); - nc++; -#else /* Write a character in ANSI/OEM */ +#else /* Write it in ANSI/OEM */ if (hs != 0) return; wc = ff_uni2oem(wc, CODEPAGE); /* UTF-16 ==> ANSI/OEM */ - if (wc == 0) return;; + if (wc == 0) return; if (wc >= 0x100) { pb->buf[i++] = (BYTE)(wc >> 8); nc++; } - pb->buf[i++] = (BYTE)wc; nc++; -#endif + pb->buf[i++] = (BYTE)wc; #endif -#else /* ANSI/OEM input */ +#else /* ANSI/OEM input (without re-encode) */ pb->buf[i++] = (BYTE)c; - nc++; #endif if (i >= (int)(sizeof pb->buf) - 4) { /* Write buffered characters to the file */ @@ -6351,12 +6354,11 @@ void putc_bfd ( /* Buffered write with code conversion */ i = (n == (UINT)i) ? 0 : -1; } pb->idx = i; - pb->nchr = nc; + pb->nchr = nc + 1; } -static -int putc_flush ( /* Flush left characters in the buffer */ +static int putc_flush ( /* Flush left characters in the buffer */ putbuff* pb ) { @@ -6369,8 +6371,7 @@ int putc_flush ( /* Flush left characters in the buffer */ } -static -void putc_init ( /* Initialize write buffer */ +static void putc_init ( /* Initialize write buffer */ putbuff* pb, FIL* fp ) @@ -6544,7 +6545,7 @@ FRESULT f_setcp ( ) { static const WORD validcp[] = { 437, 720, 737, 771, 775, 850, 852, 857, 860, 861, 862, 863, 864, 865, 866, 869, 932, 936, 949, 950, 0}; - static const BYTE *const tables[] = {Ct437, Ct720, Ct737, Ct771, Ct775, Ct850, Ct852, Ct857, Ct860, Ct861, Ct862, Ct863, Ct864, Ct865, Ct866, Ct869, Dc932, Dc936, Dc949, Dc950, 0}; + static const BYTE* const tables[] = {Ct437, Ct720, Ct737, Ct771, Ct775, Ct850, Ct852, Ct857, Ct860, Ct861, Ct862, Ct863, Ct864, Ct865, Ct866, Ct869, Dc932, Dc936, Dc949, Dc950, 0}; UINT i; diff --git a/components/fatfs/src/ff.h b/components/fatfs/src/ff.h index 55c1329827..d8ebeb833f 100644 --- a/components/fatfs/src/ff.h +++ b/components/fatfs/src/ff.h @@ -1,8 +1,8 @@ /*----------------------------------------------------------------------------/ -/ FatFs - Generic FAT Filesystem module R0.13a / +/ FatFs - Generic FAT Filesystem module R0.13c / /-----------------------------------------------------------------------------/ / -/ Copyright (C) 2017, ChaN, all right reserved. +/ Copyright (C) 2018, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided @@ -20,21 +20,41 @@ #ifndef FF_DEFINED -#define FF_DEFINED 89352 /* Revision ID */ +#define FF_DEFINED 86604 /* Revision ID */ #ifdef __cplusplus extern "C" { #endif -#include "integer.h" /* Basic integer types */ #include "ffconf.h" /* FatFs configuration options */ #if FF_DEFINED != FFCONF_DEF #error Wrong configuration file (ffconf.h). #endif -#ifdef FF_DEFINE_DIR -#define FF_DIR DIR + +/* Integer types used for FatFs API */ + +#if defined(_WIN32) /* Main development platform */ +#define FF_INTDEF 2 +#include +typedef unsigned __int64 QWORD; +#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus) /* C99 or later */ +#define FF_INTDEF 2 +#include +typedef unsigned int UINT; /* int must be 16-bit or 32-bit */ +typedef unsigned char BYTE; /* char must be 8-bit */ +typedef uint16_t WORD; /* 16-bit unsigned integer */ +typedef uint16_t WCHAR; /* 16-bit unsigned integer */ +typedef uint32_t DWORD; /* 32-bit unsigned integer */ +typedef uint64_t QWORD; /* 64-bit unsigned integer */ +#else /* Earlier than C99 */ +#define FF_INTDEF 1 +typedef unsigned int UINT; /* int must be 16-bit or 32-bit */ +typedef unsigned char BYTE; /* char must be 8-bit */ +typedef unsigned short WORD; /* 16-bit unsigned integer */ +typedef unsigned short WCHAR; /* 16-bit unsigned integer */ +typedef unsigned long DWORD; /* 32-bit unsigned integer */ #endif @@ -48,6 +68,12 @@ typedef struct { extern PARTITION VolToPart[]; /* Volume - Partition resolution table */ #endif +#if FF_STR_VOLUME_ID +#ifndef FF_VOLUME_STRS +extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */ +#endif +#endif + /* Type of path name strings on FatFs API */ @@ -63,7 +89,11 @@ typedef WCHAR TCHAR; typedef char TCHAR; #define _T(x) u8 ## x #define _TEXT(x) u8 ## x -#elif FF_USE_LFN && (FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 2) +#elif FF_USE_LFN && FF_LFN_UNICODE == 3 /* Unicode in UTF-32 encoding */ +typedef DWORD TCHAR; +#define _T(x) U ## x +#define _TEXT(x) U ## x +#elif FF_USE_LFN && (FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3) #error Wrong FF_LFN_UNICODE setting #else /* ANSI/OEM code in SBCS/DBCS */ typedef char TCHAR; @@ -78,6 +108,9 @@ typedef char TCHAR; /* Type of file size variables */ #if FF_FS_EXFAT +#if FF_INTDEF != 2 +#error exFAT feature wants C99 or later +#endif typedef QWORD FSIZE_t; #else typedef DWORD FSIZE_t; @@ -88,8 +121,8 @@ typedef DWORD FSIZE_t; /* Filesystem object structure (FATFS) */ typedef struct { - BYTE fs_type; /* Filesystem type (0:N/A) */ - BYTE pdrv; /* Physical drive number */ + BYTE fs_type; /* Filesystem type (0:not mounted) */ + BYTE pdrv; /* Associated physical drive */ BYTE n_fats; /* Number of FATs (1 or 2) */ BYTE wflag; /* win[] flag (b0:dirty) */ BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ @@ -126,6 +159,9 @@ typedef struct { DWORD fatbase; /* FAT base sector */ DWORD dirbase; /* Root directory base sector/cluster */ DWORD database; /* Data base sector */ +#if FF_FS_EXFAT + DWORD bitbase; /* Allocation bitmap base sector */ +#endif DWORD winsect; /* Current sector appearing in the win[] */ BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ } FATFS; @@ -138,7 +174,7 @@ typedef struct { FATFS* fs; /* Pointer to the hosting volume of this object */ WORD id; /* Hosting volume mount ID */ BYTE attr; /* Object attribute */ - BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:flagmented in this session, b2:sub-directory stretched) */ + BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */ DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */ FSIZE_t objsize; /* Object size (valid when sclust != 0) */ #if FF_FS_EXFAT @@ -269,7 +305,7 @@ FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get numbe FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */ FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ -FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */ +FRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous block to the file */ FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */ FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */ diff --git a/components/fatfs/src/ffconf.h b/components/fatfs/src/ffconf.h index 9513b51608..79792beef2 100644 --- a/components/fatfs/src/ffconf.h +++ b/components/fatfs/src/ffconf.h @@ -1,10 +1,10 @@ -#include #include "sdkconfig.h" + /*---------------------------------------------------------------------------/ -/ FatFs - Configuration file +/ FatFs Functional Configurations /---------------------------------------------------------------------------*/ -#define FFCONF_DEF 89352 /* Revision ID */ +#define FFCONF_DEF 86604 /* Revision ID */ /*---------------------------------------------------------------------------/ / Function Configurations @@ -141,6 +141,7 @@ / 0: ANSI/OEM in current CP (TCHAR = char) / 1: Unicode in UTF-16 (TCHAR = WCHAR) / 2: Unicode in UTF-8 (TCHAR = char) +/ 3: Unicode in UTF-32 (TCHAR = DWORD) / / Also behavior of string I/O functions will be affected by this option. / When LFN is not enabled, this option has no effect. */ @@ -186,11 +187,16 @@ #define FF_STR_VOLUME_ID 0 #define FF_VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3" -/* FF_STR_VOLUME_ID switches string support for volume ID. -/ When FF_STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive -/ number in the path name. FF_VOLUME_STRS defines the drive ID strings for each -/ logical drives. Number of items must be equal to FF_VOLUMES. Valid characters for -/ the drive ID strings are: A-Z and 0-9. */ +/* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings. +/ When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive +/ number in the path name. FF_VOLUME_STRS defines the volume ID strings for each +/ logical drives. Number of items must not be less than FF_VOLUMES. Valid +/ characters for the volume ID strings are A-Z, a-z and 0-9, however, they are +/ compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is +/ not defined, a user defined volume string table needs to be defined as: +/ +/ const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",... +*/ #define FF_MULTI_PARTITION 1 @@ -248,17 +254,17 @@ #define FF_FS_EXFAT 0 /* This option switches support for exFAT filesystem. (0:Disable or 1:Enable) -/ When enable exFAT, also LFN needs to be enabled. +/ To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1) / Note that enabling exFAT discards ANSI C (C89) compatibility. */ #define FF_FS_NORTC 0 #define FF_NORTC_MON 1 #define FF_NORTC_MDAY 1 -#define FF_NORTC_YEAR 2017 +#define FF_NORTC_YEAR 2018 /* The option FF_FS_NORTC switches timestamp functiton. If the system does not have / any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable -/ the timestamp function. All objects modified by FatFs will have a fixed timestamp +/ the timestamp function. Every object modified by FatFs will have a fixed timestamp / defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time. / To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be / added to the project to read current time form real-time clock. FF_NORTC_MON, @@ -298,14 +304,22 @@ / SemaphoreHandle_t and etc. A header file for O/S definitions needs to be / included somewhere in the scope of ff.h. */ +#include #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" /* Some memory allocation functions are declared here in addition to ff.h, so that they can be used also by external code when LFN feature is disabled. */ -void* ff_memalloc (UINT msize); -void* ff_memcalloc (UINT num, UINT size); +void* ff_memalloc (unsigned msize); +void ff_memfree(void*); /*--- End of configuration options ---*/ + +/* Redefine names of disk IO functions to prevent name collisions */ +#define disk_initialize ff_disk_initialize +#define disk_status ff_disk_status +#define disk_read ff_disk_read +#define disk_write ff_disk_write +#define disk_ioctl ff_disk_ioctl diff --git a/components/fatfs/src/ffsystem.c b/components/fatfs/src/ffsystem.c index ac02365180..b88ce15555 100644 --- a/components/fatfs/src/ffsystem.c +++ b/components/fatfs/src/ffsystem.c @@ -1,47 +1,23 @@ /*------------------------------------------------------------------------*/ /* Sample Code of OS Dependent Functions for FatFs */ -/* (C)ChaN, 2017 */ +/* (C)ChaN, 2018 */ /*------------------------------------------------------------------------*/ -#include #include "ff.h" -#include "sdkconfig.h" -#ifdef CONFIG_FATFS_ALLOC_EXTRAM_FIRST -#include "esp_heap_caps.h" -#endif +#if FF_USE_LFN == 3 /* Dynamic memory allocation */ /*------------------------------------------------------------------------*/ /* Allocate a memory block */ /*------------------------------------------------------------------------*/ -void* ff_memalloc ( /* Returns pointer to the allocated memory block (null on not enough core) */ +void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */ UINT msize /* Number of bytes to allocate */ ) { -#ifdef CONFIG_FATFS_ALLOC_EXTRAM_FIRST - return heap_caps_malloc_prefer(size, 2, MALLOC_CAP_DEFAULT | MALLOC_CAP_SPIRAM, - MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL); -#else - return malloc(msize); -#endif -} - -/*------------------------------------------------------------------------*/ -/* Allocate and zero out memory block */ -/*------------------------------------------------------------------------*/ - - -void* ff_memcalloc (UINT num, UINT size) -{ -#ifdef CONFIG_FATFS_ALLOC_EXTRAM_FIRST - return heap_caps_calloc_prefer(num, size, 2, MALLOC_CAP_DEFAULT | MALLOC_CAP_SPIRAM, - MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL); -#else - return calloc(num, size); -#endif + return malloc(msize); /* Allocate a new memory block with POSIX API */ } @@ -50,12 +26,13 @@ void* ff_memcalloc (UINT num, UINT size) /*------------------------------------------------------------------------*/ void ff_memfree ( - void* mblock /* Pointer to the memory block to free (nothing to do for null) */ + void* mblock /* Pointer to the memory block to free (nothing to do if null) */ ) { free(mblock); /* Free the memory block with POSIX API */ } +#endif @@ -69,14 +46,35 @@ void ff_memfree ( / When a 0 is returned, the f_mount() function fails with FR_INT_ERR. */ +//const osMutexDef_t Mutex[FF_VOLUMES]; /* Table of CMSIS-RTOS mutex */ + int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */ BYTE vol, /* Corresponding volume (logical drive number) */ - FF_SYNC_t *sobj /* Pointer to return the created sync object */ + FF_SYNC_t* sobj /* Pointer to return the created sync object */ ) { - *sobj = xSemaphoreCreateMutex(); - return (*sobj != NULL) ? 1 : 0; + /* Win32 */ + *sobj = CreateMutex(NULL, FALSE, NULL); + return (int)(*sobj != INVALID_HANDLE_VALUE); + + /* uITRON */ +// T_CSEM csem = {TA_TPRI,1,1}; +// *sobj = acre_sem(&csem); +// return (int)(*sobj > 0); + + /* uC/OS-II */ +// OS_ERR err; +// *sobj = OSMutexCreate(0, &err); +// return (int)(err == OS_NO_ERR); + + /* FreeRTOS */ +// *sobj = xSemaphoreCreateMutex(); +// return (int)(*sobj != NULL); + + /* CMSIS-RTOS */ +// *sobj = osMutexCreate(&Mutex[vol]); +// return (int)(*sobj != NULL); } @@ -92,8 +90,23 @@ int ff_del_syncobj ( /* 1:Function succeeded, 0:Could not delete due to an error FF_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */ ) { - vSemaphoreDelete(sobj); - return 1; + /* Win32 */ + return (int)CloseHandle(sobj); + + /* uITRON */ +// return (int)(del_sem(sobj) == E_OK); + + /* uC/OS-II */ +// OS_ERR err; +// OSMutexDel(sobj, OS_DEL_ALWAYS, &err); +// return (int)(err == OS_NO_ERR); + + /* FreeRTOS */ +// vSemaphoreDelete(sobj); +// return 1; + + /* CMSIS-RTOS */ +// return (int)(osMutexDelete(sobj) == osOK); } @@ -108,7 +121,22 @@ int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a gran FF_SYNC_t sobj /* Sync object to wait */ ) { - return (xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE) ? 1 : 0; + /* Win32 */ + return (int)(WaitForSingleObject(sobj, FF_FS_TIMEOUT) == WAIT_OBJECT_0); + + /* uITRON */ +// return (int)(wai_sem(sobj) == E_OK); + + /* uC/OS-II */ +// OS_ERR err; +// OSMutexPend(sobj, FF_FS_TIMEOUT, &err)); +// return (int)(err == OS_NO_ERR); + + /* FreeRTOS */ +// return (int)(xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE); + + /* CMSIS-RTOS */ +// return (int)(osMutexWait(sobj, FF_FS_TIMEOUT) == osOK); } @@ -122,7 +150,21 @@ void ff_rel_grant ( FF_SYNC_t sobj /* Sync object to be signaled */ ) { - xSemaphoreGive(sobj); + /* Win32 */ + ReleaseMutex(sobj); + + /* uITRON */ +// sig_sem(sobj); + + /* uC/OS-II */ +// OSMutexPost(sobj); + + /* FreeRTOS */ +// xSemaphoreGive(sobj); + + /* CMSIS-RTOS */ +// osMutexRelease(sobj); } #endif + diff --git a/components/fatfs/src/ffunicode.c b/components/fatfs/src/ffunicode.c index 901affe56a..349901b1f3 100644 --- a/components/fatfs/src/ffunicode.c +++ b/components/fatfs/src/ffunicode.c @@ -1,5 +1,5 @@ /*------------------------------------------------------------------------*/ -/* Unicode handling functions for FatFs R0.13a */ +/* Unicode handling functions for FatFs R0.13c */ /*------------------------------------------------------------------------*/ /* This module will occupy a huge memory in the .const section when the / / FatFs is configured for LFN with DBCS. If the system has any Unicode / @@ -7,7 +7,7 @@ / that function to avoid silly memory consumption. / /-------------------------------------------------------------------------*/ /* -/ Copyright (C) 2017, ChaN, all right reserved. +/ Copyright (C) 2018, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided @@ -25,9 +25,9 @@ #include "ff.h" -#if FF_USE_LFN /* This module is blanked when non-LFN configuration */ +#if FF_USE_LFN /* This module will be blanked at non-LFN configuration */ -#if FF_DEFINED != 89352 /* Revision ID */ +#if FF_DEFINED != 86604 /* Revision ID */ #error Wrong include file (ff.h). #endif @@ -40,8 +40,7 @@ /*------------------------------------------------------------------------*/ #if FF_CODE_PAGE == 932 || FF_CODE_PAGE == 0 /* Japanese */ -static -const WCHAR uni2oem932[] = { /* Unicode --> Shift_JIS pairs */ +static const WCHAR uni2oem932[] = { /* Unicode --> Shift_JIS pairs */ 0x00A7, 0x8198, 0x00A8, 0x814E, 0x00B0, 0x818B, 0x00B1, 0x817D, 0x00B4, 0x814C, 0x00B6, 0x81F7, 0x00D7, 0x817E, 0x00F7, 0x8180, 0x0391, 0x839F, 0x0392, 0x83A0, 0x0393, 0x83A1, 0x0394, 0x83A2, 0x0395, 0x83A3, 0x0396, 0x83A4, 0x0397, 0x83A5, 0x0398, 0x83A6, 0x0399, 0x83A7, 0x039A, 0x83A8, 0x039B, 0x83A9, 0x039C, 0x83AA, 0x039D, 0x83AB, 0x039E, 0x83AC, 0x039F, 0x83AD, 0x03A0, 0x83AE, @@ -968,8 +967,7 @@ const WCHAR uni2oem932[] = { /* Unicode --> Shift_JIS pairs */ 0xFFE1, 0x8192, 0xFFE2, 0x81CA, 0xFFE3, 0x8150, 0xFFE4, 0xFA55, 0xFFE5, 0x818F, 0, 0 }; -static -const WCHAR oem2uni932[] = { /* Shift_JIS --> Unicode pairs */ +static const WCHAR oem2uni932[] = { /* Shift_JIS --> Unicode pairs */ 0x00A1, 0xFF61, 0x00A2, 0xFF62, 0x00A3, 0xFF63, 0x00A4, 0xFF64, 0x00A5, 0xFF65, 0x00A6, 0xFF66, 0x00A7, 0xFF67, 0x00A8, 0xFF68, 0x00A9, 0xFF69, 0x00AA, 0xFF6A, 0x00AB, 0xFF6B, 0x00AC, 0xFF6C, 0x00AD, 0xFF6D, 0x00AE, 0xFF6E, 0x00AF, 0xFF6F, 0x00B0, 0xFF70, 0x00B1, 0xFF71, 0x00B2, 0xFF72, 0x00B3, 0xFF73, 0x00B4, 0xFF74, 0x00B5, 0xFF75, 0x00B6, 0xFF76, 0x00B7, 0xFF77, 0x00B8, 0xFF78, @@ -1898,8 +1896,7 @@ const WCHAR oem2uni932[] = { /* Shift_JIS --> Unicode pairs */ #endif #if FF_CODE_PAGE == 936 || FF_CODE_PAGE == 0 /* Simplified Chinese */ -static -const WCHAR uni2oem936[] = { /* Unicode --> GBK pairs */ +static const WCHAR uni2oem936[] = { /* Unicode --> GBK pairs */ 0x00A4, 0xA1E8, 0x00A7, 0xA1EC, 0x00A8, 0xA1A7, 0x00B0, 0xA1E3, 0x00B1, 0xA1C0, 0x00B7, 0xA1A4, 0x00D7, 0xA1C1, 0x00E0, 0xA8A4, 0x00E1, 0xA8A2, 0x00E8, 0xA8A8, 0x00E9, 0xA8A6, 0x00EA, 0xA8BA, 0x00EC, 0xA8AC, 0x00ED, 0xA8AA, 0x00F2, 0xA8B0, 0x00F3, 0xA8AE, 0x00F7, 0xA1C2, 0x00F9, 0xA8B4, 0x00FA, 0xA8B2, 0x00FC, 0xA8B9, 0x0101, 0xA8A1, 0x0113, 0xA8A5, 0x011B, 0xA8A7, 0x012B, 0xA8A9, @@ -4627,8 +4624,7 @@ const WCHAR uni2oem936[] = { /* Unicode --> GBK pairs */ 0, 0 }; -static -const WCHAR oem2uni936[] = { /* GBK --> Unicode pairs */ +static const WCHAR oem2uni936[] = { /* GBK --> Unicode pairs */ 0x0080, 0x20AC, 0x8140, 0x4E02, 0x8141, 0x4E04, 0x8142, 0x4E05, 0x8143, 0x4E06, 0x8144, 0x4E0F, 0x8145, 0x4E12, 0x8146, 0x4E17, 0x8147, 0x4E1F, 0x8148, 0x4E20, 0x8149, 0x4E21, 0x814A, 0x4E23, 0x814B, 0x4E26, 0x814C, 0x4E29, 0x814D, 0x4E2E, 0x814E, 0x4E2F, 0x814F, 0x4E31, 0x8150, 0x4E33, 0x8151, 0x4E35, 0x8152, 0x4E37, 0x8153, 0x4E3C, 0x8154, 0x4E40, 0x8155, 0x4E41, 0x8156, 0x4E42, @@ -7358,8 +7354,7 @@ const WCHAR oem2uni936[] = { /* GBK --> Unicode pairs */ #endif #if FF_CODE_PAGE == 949 || FF_CODE_PAGE == 0 /* Korean */ -static -const WCHAR uni2oem949[] = { /* Unicode --> Korean pairs */ +static const WCHAR uni2oem949[] = { /* Unicode --> Korean pairs */ 0x00A1, 0xA2AE, 0x00A4, 0xA2B4, 0x00A7, 0xA1D7, 0x00A8, 0xA1A7, 0x00AA, 0xA8A3, 0x00AD, 0xA1A9, 0x00AE, 0xA2E7, 0x00B0, 0xA1C6, 0x00B1, 0xA1BE, 0x00B2, 0xA9F7, 0x00B3, 0xA9F8, 0x00B4, 0xA2A5, 0x00B6, 0xA2D2, 0x00B7, 0xA1A4, 0x00B8, 0xA2AC, 0x00B9, 0xA9F6, 0x00BA, 0xA8AC, 0x00BC, 0xA8F9, 0x00BD, 0xA8F6, 0x00BE, 0xA8FA, 0x00BF, 0xA2AF, 0x00C6, 0xA8A1, 0x00D0, 0xA8A2, 0x00D7, 0xA1BF, @@ -9494,8 +9489,7 @@ const WCHAR uni2oem949[] = { /* Unicode --> Korean pairs */ 0, 0 }; -static -const WCHAR oem2uni949[] = { /* Korean --> Unicode pairs */ +static const WCHAR oem2uni949[] = { /* Korean --> Unicode pairs */ 0x8141, 0xAC02, 0x8142, 0xAC03, 0x8143, 0xAC05, 0x8144, 0xAC06, 0x8145, 0xAC0B, 0x8146, 0xAC0C, 0x8147, 0xAC0D, 0x8148, 0xAC0E, 0x8149, 0xAC0F, 0x814A, 0xAC18, 0x814B, 0xAC1E, 0x814C, 0xAC1F, 0x814D, 0xAC21, 0x814E, 0xAC22, 0x814F, 0xAC23, 0x8150, 0xAC25, 0x8151, 0xAC26, 0x8152, 0xAC27, 0x8153, 0xAC28, 0x8154, 0xAC29, 0x8155, 0xAC2A, 0x8156, 0xAC2B, 0x8157, 0xAC2E, 0x8158, 0xAC32, @@ -11632,8 +11626,7 @@ const WCHAR oem2uni949[] = { /* Korean --> Unicode pairs */ #endif #if FF_CODE_PAGE == 950 || FF_CODE_PAGE == 0 /* Traditional Chinese */ -static -const WCHAR uni2oem950[] = { /* Unicode --> Big5 pairs */ +static const WCHAR uni2oem950[] = { /* Unicode --> Big5 pairs */ 0x00A7, 0xA1B1, 0x00AF, 0xA1C2, 0x00B0, 0xA258, 0x00B1, 0xA1D3, 0x00B7, 0xA150, 0x00D7, 0xA1D1, 0x00F7, 0xA1D2, 0x02C7, 0xA3BE, 0x02C9, 0xA3BC, 0x02CA, 0xA3BD, 0x02CB, 0xA3BF, 0x02CD, 0xA1C5, 0x02D9, 0xA3BB, 0x0391, 0xA344, 0x0392, 0xA345, 0x0393, 0xA346, 0x0394, 0xA347, 0x0395, 0xA348, 0x0396, 0xA349, 0x0397, 0xA34A, 0x0398, 0xA34B, 0x0399, 0xA34C, 0x039A, 0xA34D, 0x039B, 0xA34E, @@ -13324,8 +13317,7 @@ const WCHAR uni2oem950[] = { /* Unicode --> Big5 pairs */ 0xFF5C, 0xA155, 0xFF5D, 0xA162, 0xFF5E, 0xA1E3, 0xFFE0, 0xA246, 0xFFE1, 0xA247, 0xFFE3, 0xA1C3, 0xFFE5, 0xA244, 0, 0 }; -static -const WCHAR oem2uni950[] = { /* Big5 --> Unicode pairs */ +static const WCHAR oem2uni950[] = { /* Big5 --> Unicode pairs */ 0xA140, 0x3000, 0xA141, 0xFF0C, 0xA142, 0x3001, 0xA143, 0x3002, 0xA144, 0xFF0E, 0xA145, 0x2027, 0xA146, 0xFF1B, 0xA147, 0xFF1A, 0xA148, 0xFF1F, 0xA149, 0xFF01, 0xA14A, 0xFE30, 0xA14B, 0x2026, 0xA14C, 0x2025, 0xA14D, 0xFE50, 0xA14E, 0xFE51, 0xA14F, 0xFE52, 0xA150, 0x00B7, 0xA151, 0xFE54, 0xA152, 0xFE55, 0xA153, 0xFE56, 0xA154, 0xFE57, 0xA155, 0xFF5C, 0xA156, 0x2013, 0xA157, 0xFE31, @@ -15018,8 +15010,7 @@ const WCHAR oem2uni950[] = { /* Big5 --> Unicode pairs */ #endif #if FF_CODE_PAGE == 437 || FF_CODE_PAGE == 0 -static -const WCHAR uc437[] = { /* CP437(U.S.) to Unicode conversion table */ +static const WCHAR uc437[] = { /* CP437(U.S.) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, @@ -15031,8 +15022,7 @@ const WCHAR uc437[] = { /* CP437(U.S.) to Unicode conversion table */ }; #endif #if FF_CODE_PAGE == 720 || FF_CODE_PAGE == 0 -static -const WCHAR uc720[] = { /* CP720(Arabic) to Unicode conversion table */ +static const WCHAR uc720[] = { /* CP720(Arabic) to Unicode conversion table */ 0x0000, 0x0000, 0x00E9, 0x00E2, 0x0000, 0x00E0, 0x0000, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0651, 0x0652, 0x00F4, 0x00A4, 0x0640, 0x00FB, 0x00F9, 0x0621, 0x0622, 0x0623, 0x0624, 0x00A3, 0x0625, 0x0626, 0x0627, 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x00AB, 0x00BB, @@ -15044,8 +15034,7 @@ const WCHAR uc720[] = { /* CP720(Arabic) to Unicode conversion table */ }; #endif #if FF_CODE_PAGE == 737 || FF_CODE_PAGE == 0 -static -const WCHAR uc737[] = { /* CP737(Greek) to Unicode conversion table */ +static const WCHAR uc737[] = { /* CP737(Greek) to Unicode conversion table */ 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0, 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, @@ -15057,8 +15046,7 @@ const WCHAR uc737[] = { /* CP737(Greek) to Unicode conversion table */ }; #endif #if FF_CODE_PAGE == 771 || FF_CODE_PAGE == 0 -static -const WCHAR uc771[] = { /* CP771(KBL) to Unicode conversion table */ +static const WCHAR uc771[] = { /* CP771(KBL) to Unicode conversion table */ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, @@ -15070,8 +15058,7 @@ const WCHAR uc771[] = { /* CP771(KBL) to Unicode conversion table */ }; #endif #if FF_CODE_PAGE == 775 || FF_CODE_PAGE == 0 -static -const WCHAR uc775[] = { /* CP775(Baltic) to Unicode conversion table */ +static const WCHAR uc775[] = { /* CP775(Baltic) to Unicode conversion table */ 0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107, 0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4, 0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6, 0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB, @@ -15083,8 +15070,7 @@ const WCHAR uc775[] = { /* CP775(Baltic) to Unicode conversion table */ }; #endif #if FF_CODE_PAGE == 850 || FF_CODE_PAGE == 0 -static -const WCHAR uc850[] = { /* CP850(Latin 1) to Unicode conversion table */ +static const WCHAR uc850[] = { /* CP850(Latin 1) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, @@ -15096,8 +15082,7 @@ const WCHAR uc850[] = { /* CP850(Latin 1) to Unicode conversion table */ }; #endif #if FF_CODE_PAGE == 852 || FF_CODE_PAGE == 0 -static -const WCHAR uc852[] = { /* CP852(Latin 2) to Unicode conversion table */ +static const WCHAR uc852[] = { /* CP852(Latin 2) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7, 0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106, 0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E, 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB, @@ -15109,8 +15094,7 @@ const WCHAR uc852[] = { /* CP852(Latin 2) to Unicode conversion table */ }; #endif #if FF_CODE_PAGE == 855 || FF_CODE_PAGE == 0 -static -const WCHAR uc855[] = { /* CP855(Cyrillic) to Unicode conversion table */ +static const WCHAR uc855[] = { /* CP855(Cyrillic) to Unicode conversion table */ 0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408, 0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C, 0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A, 0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414, 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB, @@ -15122,8 +15106,7 @@ const WCHAR uc855[] = { /* CP855(Cyrillic) to Unicode conversion table */ }; #endif #if FF_CODE_PAGE == 857 || FF_CODE_PAGE == 0 -static -const WCHAR uc857[] = { /* CP857(Turkish) to Unicode conversion table */ +static const WCHAR uc857[] = { /* CP857(Turkish) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, @@ -15135,8 +15118,7 @@ const WCHAR uc857[] = { /* CP857(Turkish) to Unicode conversion table */ }; #endif #if FF_CODE_PAGE == 860 || FF_CODE_PAGE == 0 -static -const WCHAR uc860[] = { /* CP860(Portuguese) to Unicode conversion table */ +static const WCHAR uc860[] = { /* CP860(Portuguese) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E3, 0x00E0, 0x00C1, 0x00E7, 0x00EA, 0x00CA, 0x00E8, 0x00CD, 0x00D4, 0x00EC, 0x00C3, 0x00C2, 0x00C9, 0x00C0, 0x00C8, 0x00F4, 0x00F5, 0x00F2, 0x00DA, 0x00F9, 0x00CC, 0x00D5, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x20A7, 0x00D3, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00D2, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, @@ -15148,8 +15130,7 @@ const WCHAR uc860[] = { /* CP860(Portuguese) to Unicode conversion table */ }; #endif #if FF_CODE_PAGE == 861 || FF_CODE_PAGE == 0 -static -const WCHAR uc861[] = { /* CP861(Icelandic) to Unicode conversion table */ +static const WCHAR uc861[] = { /* CP861(Icelandic) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00D0, 0x00F0, 0x00DE, 0x00C4, 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00FE, 0x00FB, 0x00DD, 0x00FD, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00C1, 0x00CD, 0x00D3, 0x00DA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, @@ -15161,8 +15142,7 @@ const WCHAR uc861[] = { /* CP861(Icelandic) to Unicode conversion table */ }; #endif #if FF_CODE_PAGE == 862 || FF_CODE_PAGE == 0 -static -const WCHAR uc862[] = { /* CP862(Hebrew) to Unicode conversion table */ +static const WCHAR uc862[] = { /* CP862(Hebrew) to Unicode conversion table */ 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, @@ -15174,8 +15154,7 @@ const WCHAR uc862[] = { /* CP862(Hebrew) to Unicode conversion table */ }; #endif #if FF_CODE_PAGE == 863 || FF_CODE_PAGE == 0 -static -const WCHAR uc863[] = { /* CP863(Canadian French) to Unicode conversion table */ +static const WCHAR uc863[] = { /* CP863(Canadian French) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00C2, 0x00E0, 0x00B6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x2017, 0x00C0, 0x00C9, 0x00C8, 0x00CA, 0x00F4, 0x00CB, 0x00CF, 0x00FB, 0x00F9, 0x00A4, 0x00D4, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x00DB, 0x0192, 0x00A6, 0x00B4, 0x00F3, 0x00FA, 0x00A8, 0x00BB, 0x00B3, 0x00AF, 0x00CE, 0x3210, 0x00AC, 0x00BD, 0x00BC, 0x00BE, 0x00AB, 0x00BB, @@ -15187,8 +15166,7 @@ const WCHAR uc863[] = { /* CP863(Canadian French) to Unicode conversion table * }; #endif #if FF_CODE_PAGE == 864 || FF_CODE_PAGE == 0 -static -const WCHAR uc864[] = { /* CP864(Arabic) to Unicode conversion table */ +static const WCHAR uc864[] = { /* CP864(Arabic) to Unicode conversion table */ 0x00B0, 0x00B7, 0x2219, 0x221A, 0x2592, 0x2500, 0x2502, 0x253C, 0x2524, 0x252C, 0x251C, 0x2534, 0x2510, 0x250C, 0x2514, 0x2518, 0x03B2, 0x221E, 0x03C6, 0x00B1, 0x00BD, 0x00BC, 0x2248, 0x00AB, 0x00BB, 0xFEF7, 0xFEF8, 0x0000, 0x0000, 0xFEFB, 0xFEFC, 0x0000, 0x00A0, 0x00AD, 0xFE82, 0x00A3, 0x00A4, 0xFE84, 0x0000, 0x20AC, 0xFE8E, 0xFE8F, 0xFE95, 0xFE99, 0x060C, 0xFE9D, 0xFEA1, 0xFEA5, @@ -15200,8 +15178,7 @@ const WCHAR uc864[] = { /* CP864(Arabic) to Unicode conversion table */ }; #endif #if FF_CODE_PAGE == 865 || FF_CODE_PAGE == 0 -static -const WCHAR uc865[] = { /* CP865(Nordic) to Unicode conversion table */ +static const WCHAR uc865[] = { /* CP865(Nordic) to Unicode conversion table */ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, 0x00C5, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00A4, @@ -15213,8 +15190,7 @@ const WCHAR uc865[] = { /* CP865(Nordic) to Unicode conversion table */ }; #endif #if FF_CODE_PAGE == 866 || FF_CODE_PAGE == 0 -static -const WCHAR uc866[] = { /* CP866(Russian) to Unicode conversion table */ +static const WCHAR uc866[] = { /* CP866(Russian) to Unicode conversion table */ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, @@ -15226,8 +15202,7 @@ const WCHAR uc866[] = { /* CP866(Russian) to Unicode conversion table */ }; #endif #if FF_CODE_PAGE == 869 || FF_CODE_PAGE == 0 -static -const WCHAR uc869[] = { /* CP869(Greek 2) to Unicode conversion table */ +static const WCHAR uc869[] = { /* CP869(Greek 2) to Unicode conversion table */ 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x0386, 0x00B7, 0x00B7, 0x00AC, 0x00A6, 0x2018, 0x2019, 0x0388, 0x2015, 0x0389, 0x038A, 0x03AA, 0x038C, 0x00B7, 0x00B7, 0x038E, 0x03AB, 0x00A9, 0x038F, 0x00B2, 0x00B3, 0x03AC, 0x00A3, 0x03AD, 0x03AE, 0x03AF, 0x03CA, 0x0390, 0x03CC, 0x03CD, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x00BD, 0x0398, 0x0399, 0x00AB, 0x00BB, @@ -15261,7 +15236,7 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ c = (WCHAR)uni; } else { /* Non-ASCII */ - if (uni < 0x10000 && cp == FF_CODE_PAGE) { /* Is it a valid code? */ + if (uni < 0x10000 && cp == FF_CODE_PAGE) { /* Is it in BMP and valid code page? */ for (c = 0; c < 0x80 && uni != p[c]; c++) ; c = (c + 0x80) & 0xFF; } @@ -15308,30 +15283,28 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ { const WCHAR *p; WCHAR c = 0, uc; - UINT i, n, li, hi; + UINT i = 0, n, li, hi; if (uni < 0x80) { /* ASCII? */ c = (WCHAR)uni; } else { /* Non-ASCII */ - if (uni < 0x10000) { /* Is it in BMP? */ - if (cp == FF_CODE_PAGE) { /* Is it a valid code? */ - uc = (WCHAR)uni; - p = CVTBL(uni2oem, FF_CODE_PAGE); - hi = sizeof CVTBL(uni2oem, FF_CODE_PAGE) / 4 - 1; - li = 0; - for (n = 16; n; n--) { - i = li + (hi - li) / 2; - if (uc == p[i * 2]) break; - if (uc > p[i * 2]) { - li = i; - } else { - hi = i; - } + if (uni < 0x10000 && cp == FF_CODE_PAGE) { /* Is it in BMP and valid code page? */ + uc = (WCHAR)uni; + p = CVTBL(uni2oem, FF_CODE_PAGE); + hi = sizeof CVTBL(uni2oem, FF_CODE_PAGE) / 4 - 1; + li = 0; + for (n = 16; n; n--) { + i = li + (hi - li) / 2; + if (uc == p[i * 2]) break; + if (uc > p[i * 2]) { + li = i; + } else { + hi = i; } - if (n != 0) c = p[i * 2 + 1]; } + if (n != 0) c = p[i * 2 + 1]; } } @@ -15346,14 +15319,14 @@ WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */ { const WCHAR *p; WCHAR c = 0; - UINT i, n, li, hi; + UINT i = 0, n, li, hi; if (oem < 0x80) { /* ASCII? */ c = oem; } else { /* Extended char */ - if (cp == FF_CODE_PAGE) { /* Is it a valid code page? */ + if (cp == FF_CODE_PAGE) { /* Is it valid code page? */ p = CVTBL(oem2uni, FF_CODE_PAGE); hi = sizeof CVTBL(oem2uni, FF_CODE_PAGE) / 4 - 1; li = 0; @@ -15383,7 +15356,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */ #if FF_CODE_PAGE == 0 static const WORD cp_code[] = { 437, 720, 737, 771, 775, 850, 852, 855, 857, 860, 861, 862, 863, 864, 865, 866, 869, 0}; -static const WCHAR *const cp_table[] = {uc437, uc720, uc737, uc771, uc775, uc850, uc852, uc855, uc857, uc860, uc861, uc862, uc863, uc864, uc865, uc866, uc869, 0}; +static const WCHAR* const cp_table[] = {uc437, uc720, uc737, uc771, uc775, uc850, uc852, uc855, uc857, uc860, uc861, uc862, uc863, uc864, uc865, uc866, uc869, 0}; WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ @@ -15404,20 +15377,20 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ uc = (WCHAR)uni; p = 0; if (cp < 900) { /* SBCS */ - for (i = 0; cp_code[i] != 0 && cp_code[i] != cp; i++) ; /* Get table */ + for (i = 0; cp_code[i] != 0 && cp_code[i] != cp; i++) ; /* Get conversion table */ p = cp_table[i]; - if (p) { /* Is it a valid CP ? */ + if (p) { /* Is it valid code page ? */ for (c = 0; c < 0x80 && uc != p[c]; c++) ; /* Find OEM code in the table */ c = (c + 0x80) & 0xFF; } } else { /* DBCS */ - switch (cp) { + switch (cp) { /* Get conversion table */ case 932 : p = uni2oem932; hi = sizeof uni2oem932 / 4 - 1; break; case 936 : p = uni2oem936; hi = sizeof uni2oem936 / 4 - 1; break; case 949 : p = uni2oem949; hi = sizeof uni2oem949 / 4 - 1; break; case 950 : p = uni2oem950; hi = sizeof uni2oem950 / 4 - 1; break; } - if (p) { /* Is it a valid code page? */ + if (p) { /* Is it valid code page? */ li = 0; for (n = 16; n; n--) { /* Find OEM code */ i = li + (hi - li) / 2; @@ -15496,50 +15469,90 @@ DWORD ff_wtoupper ( /* Returns up-converted code point */ DWORD uni /* Unicode code point to be up-converted */ ) { - /* Compressed upper conversion table */ - static const WORD cvt1[] = { /* U+0000 - U+0FFF */ + const WORD *p; + WORD uc, bc, nc, cmd; + static const WORD cvt1[] = { /* Compressed up conversion table for U+0000 - U+0FFF */ /* Basic Latin */ 0x0061,0x031A, /* Latin-1 Supplement */ - 0x00E0,0x0317, 0x00F8,0x0307, 0x00FF,0x0001,0x0178, + 0x00E0,0x0317, + 0x00F8,0x0307, + 0x00FF,0x0001,0x0178, /* Latin Extended-A */ - 0x0100,0x0130, 0x0132,0x0106, 0x0139,0x0110, 0x014A,0x012E, 0x0179,0x0106, + 0x0100,0x0130, + 0x0132,0x0106, + 0x0139,0x0110, + 0x014A,0x012E, + 0x0179,0x0106, /* Latin Extended-B */ 0x0180,0x004D,0x0243,0x0181,0x0182,0x0182,0x0184,0x0184,0x0186,0x0187,0x0187,0x0189,0x018A,0x018B,0x018B,0x018D,0x018E,0x018F,0x0190,0x0191,0x0191,0x0193,0x0194,0x01F6,0x0196,0x0197,0x0198,0x0198,0x023D,0x019B,0x019C,0x019D,0x0220,0x019F,0x01A0,0x01A0,0x01A2,0x01A2,0x01A4,0x01A4,0x01A6,0x01A7,0x01A7,0x01A9,0x01AA,0x01AB,0x01AC,0x01AC,0x01AE,0x01AF,0x01AF,0x01B1,0x01B2,0x01B3,0x01B3,0x01B5,0x01B5,0x01B7,0x01B8,0x01B8,0x01BA,0x01BB,0x01BC,0x01BC,0x01BE,0x01F7,0x01C0,0x01C1,0x01C2,0x01C3,0x01C4,0x01C5,0x01C4,0x01C7,0x01C8,0x01C7,0x01CA,0x01CB,0x01CA, - 0x01CD,0x0110, 0x01DD,0x0001,0x018E, 0x01DE,0x0112, 0x01F3,0x0003,0x01F1,0x01F4,0x01F4, 0x01F8,0x0128, - 0x0222,0x0112, 0x023A,0x0009,0x2C65,0x023B,0x023B,0x023D,0x2C66,0x023F,0x0240,0x0241,0x0241, 0x0246,0x010A, + 0x01CD,0x0110, + 0x01DD,0x0001,0x018E, + 0x01DE,0x0112, + 0x01F3,0x0003,0x01F1,0x01F4,0x01F4, + 0x01F8,0x0128, + 0x0222,0x0112, + 0x023A,0x0009,0x2C65,0x023B,0x023B,0x023D,0x2C66,0x023F,0x0240,0x0241,0x0241, + 0x0246,0x010A, /* IPA Extensions */ 0x0253,0x0040,0x0181,0x0186,0x0255,0x0189,0x018A,0x0258,0x018F,0x025A,0x0190,0x025C,0x025D,0x025E,0x025F,0x0193,0x0261,0x0262,0x0194,0x0264,0x0265,0x0266,0x0267,0x0197,0x0196,0x026A,0x2C62,0x026C,0x026D,0x026E,0x019C,0x0270,0x0271,0x019D,0x0273,0x0274,0x019F,0x0276,0x0277,0x0278,0x0279,0x027A,0x027B,0x027C,0x2C64,0x027E,0x027F,0x01A6,0x0281,0x0282,0x01A9,0x0284,0x0285,0x0286,0x0287,0x01AE,0x0244,0x01B1,0x01B2,0x0245,0x028D,0x028E,0x028F,0x0290,0x0291,0x01B7, /* Greek, Coptic */ - 0x037B,0x0003,0x03FD,0x03FE,0x03FF, 0x03AC,0x0004,0x0386,0x0388,0x0389,0x038A, 0x03B1,0x0311, - 0x03C2,0x0002,0x03A3,0x03A3, 0x03C4,0x0308, 0x03CC,0x0003,0x038C,0x038E,0x038F, 0x03D8,0x0118, + 0x037B,0x0003,0x03FD,0x03FE,0x03FF, + 0x03AC,0x0004,0x0386,0x0388,0x0389,0x038A, + 0x03B1,0x0311, + 0x03C2,0x0002,0x03A3,0x03A3, + 0x03C4,0x0308, + 0x03CC,0x0003,0x038C,0x038E,0x038F, + 0x03D8,0x0118, 0x03F2,0x000A,0x03F9,0x03F3,0x03F4,0x03F5,0x03F6,0x03F7,0x03F7,0x03F9,0x03FA,0x03FA, /* Cyrillic */ - 0x0430,0x0320, 0x0450,0x0710, 0x0460,0x0122, 0x048A,0x0136, 0x04C1,0x010E, 0x04CF,0x0001,0x04C0, 0x04D0,0x0144, + 0x0430,0x0320, + 0x0450,0x0710, + 0x0460,0x0122, + 0x048A,0x0136, + 0x04C1,0x010E, + 0x04CF,0x0001,0x04C0, + 0x04D0,0x0144, /* Armenian */ 0x0561,0x0426, - 0x0000 + 0x0000 /* EOT */ }; - static const WORD cvt2[] = { /* U+1000 - U+FFFF */ + static const WORD cvt2[] = { /* Compressed up conversion table for U+1000 - U+FFFF */ /* Phonetic Extensions */ 0x1D7D,0x0001,0x2C63, /* Latin Extended Additional */ - 0x1E00,0x0196, 0x1EA0,0x015A, + 0x1E00,0x0196, + 0x1EA0,0x015A, /* Greek Extended */ - 0x1F00,0x0608, 0x1F10,0x0606, 0x1F20,0x0608, 0x1F30,0x0608, 0x1F40,0x0606, - 0x1F51,0x0007,0x1F59,0x1F52,0x1F5B,0x1F54,0x1F5D,0x1F56,0x1F5F, 0x1F60,0x0608, + 0x1F00,0x0608, + 0x1F10,0x0606, + 0x1F20,0x0608, + 0x1F30,0x0608, + 0x1F40,0x0606, + 0x1F51,0x0007,0x1F59,0x1F52,0x1F5B,0x1F54,0x1F5D,0x1F56,0x1F5F, + 0x1F60,0x0608, 0x1F70,0x000E,0x1FBA,0x1FBB,0x1FC8,0x1FC9,0x1FCA,0x1FCB,0x1FDA,0x1FDB,0x1FF8,0x1FF9,0x1FEA,0x1FEB,0x1FFA,0x1FFB, - 0x1F80,0x0608, 0x1F90,0x0608, 0x1FA0,0x0608, 0x1FB0,0x0004,0x1FB8,0x1FB9,0x1FB2,0x1FBC, - 0x1FCC,0x0001,0x1FC3, 0x1FD0,0x0602, 0x1FE0,0x0602, 0x1FE5,0x0001,0x1FEC, 0x1FF3,0x0001,0x1FFC, + 0x1F80,0x0608, + 0x1F90,0x0608, + 0x1FA0,0x0608, + 0x1FB0,0x0004,0x1FB8,0x1FB9,0x1FB2,0x1FBC, + 0x1FCC,0x0001,0x1FC3, + 0x1FD0,0x0602, + 0x1FE0,0x0602, + 0x1FE5,0x0001,0x1FEC, + 0x1FF3,0x0001,0x1FFC, /* Letterlike Symbols */ 0x214E,0x0001,0x2132, /* Number forms */ - 0x2170,0x0210, 0x2184,0x0001,0x2183, + 0x2170,0x0210, + 0x2184,0x0001,0x2183, /* Enclosed Alphanumerics */ - 0x24D0,0x051A, 0x2C30,0x042F, + 0x24D0,0x051A, + 0x2C30,0x042F, /* Latin Extended-C */ - 0x2C60,0x0102, 0x2C67,0x0106, 0x2C75,0x0102, + 0x2C60,0x0102, + 0x2C67,0x0106, 0x2C75,0x0102, /* Coptic */ 0x2C80,0x0164, /* Georgian Supplement */ @@ -15547,18 +15560,16 @@ DWORD ff_wtoupper ( /* Returns up-converted code point */ /* Full-width */ 0xFF41,0x031A, - 0x0000 + 0x0000 /* EOT */ }; - const WORD *p; - WORD uc, bc, nc, cmd; if (uni < 0x10000) { /* Is it in BMP? */ uc = (WORD)uni; p = uc < 0x1000 ? cvt1 : cvt2; for (;;) { - bc = *p++; /* Get block base */ - if (!bc || uc < bc) break; + bc = *p++; /* Get the block base */ + if (bc == 0 || uc < bc) break; /* Not matched? */ nc = *p++; cmd = nc >> 8; nc &= 0xFF; /* Get processing command and block size */ if (uc < bc + nc) { /* In the block? */ switch (cmd) { @@ -15574,7 +15585,7 @@ DWORD ff_wtoupper ( /* Returns up-converted code point */ } break; } - if (!cmd) p += nc; + if (cmd == 0) p += nc; /* Skip table if needed */ } uni = uc; } diff --git a/components/fatfs/src/integer.h b/components/fatfs/src/integer.h deleted file mode 100644 index 4fcf5c443f..0000000000 --- a/components/fatfs/src/integer.h +++ /dev/null @@ -1,38 +0,0 @@ -/*-------------------------------------------*/ -/* Integer type definitions for FatFs module */ -/*-------------------------------------------*/ - -#ifndef FF_INTEGER -#define FF_INTEGER - -#ifdef _WIN32 /* FatFs development platform */ - -#include -#include -typedef unsigned __int64 QWORD; - - -#else /* Embedded platform */ - -/* These types MUST be 16-bit or 32-bit */ -typedef int INT; -typedef unsigned int UINT; - -/* This type MUST be 8-bit */ -typedef unsigned char BYTE; - -/* These types MUST be 16-bit */ -typedef short SHORT; -typedef unsigned short WORD; -typedef unsigned short WCHAR; - -/* These types MUST be 32-bit */ -typedef long LONG; -typedef unsigned long DWORD; - -/* This type MUST be 64-bit (Remove this for ANSI C (C89) compatibility) */ -typedef unsigned long long QWORD; - -#endif - -#endif diff --git a/components/fatfs/test/CMakeLists.txt b/components/fatfs/test/CMakeLists.txt index 5e0431c469..2796e95eb4 100644 --- a/components/fatfs/test/CMakeLists.txt +++ b/components/fatfs/test/CMakeLists.txt @@ -1,8 +1,4 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity test_utils vfs fatfs) - -set(COMPONENT_EMBED_TXTFILES fatfs.img) - -register_component() \ No newline at end of file +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity test_utils vfs fatfs + EMBED_TXTFILES fatfs.img) \ No newline at end of file diff --git a/components/fatfs/test/test_fatfs_common.c b/components/fatfs/test/test_fatfs_common.c index 77e53707c5..09e2938268 100644 --- a/components/fatfs/test/test_fatfs_common.c +++ b/components/fatfs/test/test_fatfs_common.c @@ -16,8 +16,10 @@ #include #include #include +#include #include #include +#include #include #include #include "unity.h" @@ -98,6 +100,88 @@ void test_fatfs_read_file_utf_8(const char* filename) TEST_ASSERT_EQUAL(0, fclose(f)); } +void test_fatfs_pread_file(const char* filename) +{ + char buf[32] = { 0 }; + const int fd = open(filename, O_RDONLY); + TEST_ASSERT_NOT_EQUAL(-1, fd); + + int r = pread(fd, buf, sizeof(buf), 0); // it is a regular read() with offset==0 + TEST_ASSERT_EQUAL(0, strcmp(fatfs_test_hello_str, buf)); + TEST_ASSERT_EQUAL(strlen(fatfs_test_hello_str), r); + + memset(buf, 0, sizeof(buf)); + r = pread(fd, buf, sizeof(buf), 1); // offset==1 + TEST_ASSERT_EQUAL(0, strcmp(fatfs_test_hello_str + 1, buf)); + TEST_ASSERT_EQUAL(strlen(fatfs_test_hello_str) - 1, r); + + memset(buf, 0, sizeof(buf)); + r = pread(fd, buf, sizeof(buf), 5); // offset==5 + TEST_ASSERT_EQUAL(0, strcmp(fatfs_test_hello_str + 5, buf)); + TEST_ASSERT_EQUAL(strlen(fatfs_test_hello_str) - 5, r); + + // regular read() should work now because pread() should not affect the current position in file + + memset(buf, 0, sizeof(buf)); + r = read(fd, buf, sizeof(buf)); // note that this is read() and not pread() + TEST_ASSERT_EQUAL(0, strcmp(fatfs_test_hello_str, buf)); + TEST_ASSERT_EQUAL(strlen(fatfs_test_hello_str), r); + + memset(buf, 0, sizeof(buf)); + r = pread(fd, buf, sizeof(buf), 10); // offset==10 + TEST_ASSERT_EQUAL(0, strcmp(fatfs_test_hello_str + 10, buf)); + TEST_ASSERT_EQUAL(strlen(fatfs_test_hello_str) - 10, r); + + memset(buf, 0, sizeof(buf)); + r = pread(fd, buf, sizeof(buf), strlen(fatfs_test_hello_str) + 1); // offset to EOF + TEST_ASSERT_EQUAL(0, r); + + TEST_ASSERT_EQUAL(0, close(fd)); +} + +static void test_pwrite(const char *filename, off_t offset, const char *msg) +{ + const int fd = open(filename, O_WRONLY); + TEST_ASSERT_NOT_EQUAL(-1, fd); + + const off_t current_pos = lseek(fd, 0, SEEK_END); // O_APPEND is not the same - jumps to the end only before write() + + const int r = pwrite(fd, msg, strlen(msg), offset); + TEST_ASSERT_EQUAL(strlen(msg), r); + + TEST_ASSERT_EQUAL(current_pos, lseek(fd, 0, SEEK_CUR)); // pwrite should not move the pointer + + TEST_ASSERT_EQUAL(0, close(fd)); +} + +static void test_file_content(const char *filename, const char *msg) +{ + char buf[32] = { 0 }; + const int fd = open(filename, O_RDONLY); + TEST_ASSERT_NOT_EQUAL(-1, fd); + + int r = read(fd, buf, sizeof(buf)); + TEST_ASSERT_NOT_EQUAL(-1, r); + TEST_ASSERT_EQUAL(0, strcmp(msg, buf)); + + TEST_ASSERT_EQUAL(0, close(fd)); +} + +void test_fatfs_pwrite_file(const char *filename) +{ + int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC); + TEST_ASSERT_NOT_EQUAL(-1, fd); + TEST_ASSERT_EQUAL(0, close(fd)); + + test_pwrite(filename, 0, "Hello"); + test_file_content(filename, "Hello"); + + test_pwrite(filename, strlen("Hello"), ", world!"); + test_file_content(filename, "Hello, world!"); + test_pwrite(filename, strlen("Hello, "), "Dolly"); + test_file_content(filename, "Hello, Dolly!"); +} + void test_fatfs_open_max_files(const char* filename_prefix, size_t files_count) { FILE** files = calloc(files_count, sizeof(FILE*)); diff --git a/components/fatfs/test/test_fatfs_common.h b/components/fatfs/test/test_fatfs_common.h index ba330b6b6b..0a792434b1 100644 --- a/components/fatfs/test/test_fatfs_common.h +++ b/components/fatfs/test/test_fatfs_common.h @@ -41,6 +41,10 @@ void test_fatfs_read_file(const char* filename); void test_fatfs_read_file_utf_8(const char* filename); +void test_fatfs_pread_file(const char* filename); + +void test_fatfs_pwrite_file(const char* filename); + void test_fatfs_open_max_files(const char* filename_prefix, size_t files_count); void test_fatfs_lseek(const char* filename); diff --git a/components/fatfs/test/test_fatfs_rawflash.c b/components/fatfs/test/test_fatfs_rawflash.c index 5e60bb2965..66412451a3 100644 --- a/components/fatfs/test/test_fatfs_rawflash.c +++ b/components/fatfs/test/test_fatfs_rawflash.c @@ -43,9 +43,18 @@ static void test_setup(size_t max_files) TEST_ASSERT(part->size == (fatfs_end - fatfs_start - 1)); - esp_partition_erase_range(part, 0, part->size); - for (int i = 0; i < part->size; i+= SPI_FLASH_SEC_SIZE) { - ESP_ERROR_CHECK( esp_partition_write(part, i, fatfs_start + i, SPI_FLASH_SEC_SIZE) ); + spi_flash_mmap_handle_t mmap_handle; + const void* mmap_ptr; + TEST_ESP_OK(esp_partition_mmap(part, 0, part->size, SPI_FLASH_MMAP_DATA, &mmap_ptr, &mmap_handle)); + bool content_valid = memcmp(fatfs_start, mmap_ptr, part->size) == 0; + spi_flash_munmap(mmap_handle); + + if (!content_valid) { + printf("Copying fatfs.img into test partition...\n"); + esp_partition_erase_range(part, 0, part->size); + for (int i = 0; i < part->size; i+= SPI_FLASH_SEC_SIZE) { + ESP_ERROR_CHECK( esp_partition_write(part, i, fatfs_start + i, SPI_FLASH_SEC_SIZE) ); + } } TEST_ESP_OK(esp_vfs_fat_rawflash_mount("/spiflash", "flash_test", &mount_config)); @@ -319,12 +328,8 @@ TEST_CASE("(raw) multiple tasks can use same volume", "[fatfs]") test_teardown(); } -TEST_CASE("(raw) write/read speed test", "[fatfs][timeout=60]") +TEST_CASE("(raw) read speed test", "[fatfs][timeout=60]") { - /* Erase partition before running the test to get consistent results */ - const esp_partition_t* part = get_test_data_partition(); - esp_partition_erase_range(part, 0, part->size); - test_setup(5); const size_t buf_size = 16 * 1024; diff --git a/components/fatfs/test/test_fatfs_sdmmc.c b/components/fatfs/test/test_fatfs_sdmmc.c index e1a6cfb3bd..50e1eb5a08 100644 --- a/components/fatfs/test/test_fatfs_sdmmc.c +++ b/components/fatfs/test/test_fatfs_sdmmc.c @@ -28,7 +28,6 @@ #include "driver/sdmmc_host.h" #include "driver/sdmmc_defs.h" #include "sdmmc_cmd.h" -#include "diskio.h" #include "ff.h" #include "test_fatfs_common.h" @@ -87,6 +86,20 @@ TEST_CASE("(SD) can read file", "[fatfs][test_env=UT_T1_SDMODE]") test_teardown(); } +TEST_CASE("(SD) can read file with pread()", "[fatfs][test_env=UT_T1_SDMODE]") +{ + test_setup(); + test_fatfs_create_file_with_text(test_filename, fatfs_test_hello_str); + test_fatfs_pread_file(test_filename); + test_teardown(); +} + +TEST_CASE("(SD) pwrite() works well", "[fatfs][test_env=UT_T1_SDMODE]") +{ + test_setup(); + test_fatfs_pwrite_file(test_filename); + test_teardown(); +} TEST_CASE("(SD) overwrite and append file", "[fatfs][sd][test_env=UT_T1_SDMODE]") { diff --git a/components/fatfs/test/test_fatfs_spiflash.c b/components/fatfs/test/test_fatfs_spiflash.c index 6c33559395..f848c31ca8 100644 --- a/components/fatfs/test/test_fatfs_spiflash.c +++ b/components/fatfs/test/test_fatfs_spiflash.c @@ -70,6 +70,21 @@ TEST_CASE("(WL) can read file", "[fatfs][wear_levelling]") test_teardown(); } +TEST_CASE("(WL) can read file with pread", "[fatfs][wear_levelling]") +{ + test_setup(); + test_fatfs_create_file_with_text("/spiflash/hello.txt", fatfs_test_hello_str); + test_fatfs_pread_file("/spiflash/hello.txt"); + test_teardown(); +} + +TEST_CASE("(WL) pwrite() works well", "[fatfs][wear_levelling]") +{ + test_setup(); + test_fatfs_pwrite_file("/spiflash/hello.txt"); + test_teardown(); +} + TEST_CASE("(WL) can open maximum number of files", "[fatfs][wear_levelling]") { size_t max_files = FOPEN_MAX - 3; /* account for stdin, stdout, stderr */ diff --git a/components/fatfs/test_fatfs_host/Makefile.files b/components/fatfs/test_fatfs_host/Makefile.files index d668d5d9b1..ab77bc40c0 100644 --- a/components/fatfs/test_fatfs_host/Makefile.files +++ b/components/fatfs/test_fatfs_host/Makefile.files @@ -1,35 +1,38 @@ SOURCE_FILES := \ $(addprefix ../src/, \ - diskio.c \ - ff.c \ - ffsystem.c \ - ffunicode.c \ - diskio_wl.c \ - ) + ff.c \ + ffunicode.c \ + ) \ + $(addprefix ../diskio/,\ + diskio.c \ + diskio_wl.c \ + ) \ + ../port/linux/ffsystem.c INCLUDE_DIRS := \ . \ + ../diskio \ ../src \ $(addprefix ../../spi_flash/sim/stubs/, \ - app_update/include \ - driver/include \ - esp32/include \ - freertos/include \ - log/include \ - newlib/include \ - sdmmc/include \ - vfs/include \ + app_update/include \ + driver/include \ + esp32/include \ + freertos/include \ + log/include \ + newlib/include \ + sdmmc/include \ + vfs/include \ ) \ $(addprefix ../../../components/, \ - esp_rom/include \ - xtensa/include \ - xtensa/esp32/include \ - soc/esp32/include \ - soc/include \ - esp32/include \ - esp_common/include \ - bootloader_support/include \ - app_update/include \ - spi_flash/include \ - wear_levelling/include \ + esp_rom/include \ + xtensa/include \ + xtensa/esp32/include \ + soc/esp32/include \ + soc/include \ + esp32/include \ + esp_common/include \ + bootloader_support/include \ + app_update/include \ + spi_flash/include \ + wear_levelling/include \ ) diff --git a/components/fatfs/test_fatfs_host/partition_table.csv b/components/fatfs/test_fatfs_host/partition_table.csv index cb7fccd87b..9b4dbd1ba5 100644 --- a/components/fatfs/test_fatfs_host/partition_table.csv +++ b/components/fatfs/test_fatfs_host/partition_table.csv @@ -1,5 +1,5 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 1M, diff --git a/components/fatfs/test_fatfs_host/sdkconfig/sdkconfig.h b/components/fatfs/test_fatfs_host/sdkconfig/sdkconfig.h index 93886fff51..1c08df4ae4 100644 --- a/components/fatfs/test_fatfs_host/sdkconfig/sdkconfig.h +++ b/components/fatfs/test_fatfs_host/sdkconfig/sdkconfig.h @@ -4,3 +4,5 @@ #define CONFIG_LOG_DEFAULT_LEVEL 3 #define CONFIG_PARTITION_TABLE_OFFSET 0x8000 #define CONFIG_ESPTOOLPY_FLASHSIZE "8MB" +//currently use the legacy implementation, since the stubs for new HAL are not done yet +#define CONFIG_SPI_FLASH_USE_LEGACY_IMPL diff --git a/components/fatfs/test_fatfs_host/test_fatfs.cpp b/components/fatfs/test_fatfs_host/test_fatfs.cpp index 98a4d40c7a..fcbbe55945 100644 --- a/components/fatfs/test_fatfs_host/test_fatfs.cpp +++ b/components/fatfs/test_fatfs_host/test_fatfs.cpp @@ -4,7 +4,7 @@ #include "ff.h" #include "esp_partition.h" #include "wear_levelling.h" -#include "diskio.h" +#include "diskio_impl.h" #include "diskio_wl.h" #include "catch.hpp" diff --git a/components/fatfs/src/esp_vfs_fat.h b/components/fatfs/vfs/esp_vfs_fat.h similarity index 100% rename from components/fatfs/src/esp_vfs_fat.h rename to components/fatfs/vfs/esp_vfs_fat.h diff --git a/components/fatfs/src/vfs_fat.c b/components/fatfs/vfs/vfs_fat.c similarity index 89% rename from components/fatfs/src/vfs_fat.c rename to components/fatfs/vfs/vfs_fat.c index ea74c82ee6..511be8c56e 100644 --- a/components/fatfs/src/vfs_fat.c +++ b/components/fatfs/vfs/vfs_fat.c @@ -22,7 +22,7 @@ #include "esp_vfs.h" #include "esp_log.h" #include "ff.h" -#include "diskio.h" +#include "diskio_impl.h" typedef struct { char fat_drive[8]; /* FAT drive name */ @@ -68,6 +68,8 @@ static const char* TAG = "vfs_fat"; static ssize_t vfs_fat_write(void* p, int fd, const void * data, size_t size); static off_t vfs_fat_lseek(void* p, int fd, off_t size, int mode); static ssize_t vfs_fat_read(void* ctx, int fd, void * dst, size_t size); +static ssize_t vfs_fat_pread(void *ctx, int fd, void *dst, size_t size, off_t offset); +static ssize_t vfs_fat_pwrite(void *ctx, int fd, const void *src, size_t size, off_t offset); static int vfs_fat_open(void* ctx, const char * path, int flags, int mode); static int vfs_fat_close(void* ctx, int fd); static int vfs_fat_fstat(void* ctx, int fd, struct stat * st); @@ -129,6 +131,8 @@ esp_err_t esp_vfs_fat_register(const char* base_path, const char* fat_drive, siz .write_p = &vfs_fat_write, .lseek_p = &vfs_fat_lseek, .read_p = &vfs_fat_read, + .pread_p = &vfs_fat_pread, + .pwrite_p = &vfs_fat_pwrite, .open_p = &vfs_fat_open, .close_p = &vfs_fat_close, .fstat_p = &vfs_fat_fstat, @@ -150,15 +154,17 @@ esp_err_t esp_vfs_fat_register(const char* base_path, const char* fat_drive, siz .utime_p = &vfs_fat_utime, }; size_t ctx_size = sizeof(vfs_fat_ctx_t) + max_files * sizeof(FIL); - vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ff_memcalloc(1, ctx_size); + vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ff_memalloc(ctx_size); if (fat_ctx == NULL) { return ESP_ERR_NO_MEM; } + memset(fat_ctx, 0, ctx_size); fat_ctx->o_append = ff_memalloc(max_files * sizeof(bool)); if (fat_ctx->o_append == NULL) { free(fat_ctx); return ESP_ERR_NO_MEM; } + memset(fat_ctx->o_append, 0, max_files * sizeof(bool)); fat_ctx->max_files = max_files; strlcpy(fat_ctx->fat_drive, fat_drive, sizeof(fat_ctx->fat_drive) - 1); strlcpy(fat_ctx->base_path, base_path, sizeof(fat_ctx->base_path) - 1); @@ -371,6 +377,84 @@ static ssize_t vfs_fat_read(void* ctx, int fd, void * dst, size_t size) return read; } +static ssize_t vfs_fat_pread(void *ctx, int fd, void *dst, size_t size, off_t offset) +{ + ssize_t ret = -1; + vfs_fat_ctx_t *fat_ctx = (vfs_fat_ctx_t *) ctx; + _lock_acquire(&fat_ctx->lock); + FIL *file = &fat_ctx->files[fd]; + const off_t prev_pos = f_tell(file); + + FRESULT f_res = f_lseek(file, offset); + if (f_res != FR_OK) { + ESP_LOGD(TAG, "%s: fresult=%d", __func__, f_res); + errno = fresult_to_errno(f_res); + goto pread_release; + } + + unsigned read = 0; + f_res = f_read(file, dst, size, &read); + if (f_res == FR_OK) { + ret = read; + } else { + ESP_LOGD(TAG, "%s: fresult=%d", __func__, f_res); + errno = fresult_to_errno(f_res); + // No return yet - need to restore previous position + } + + f_res = f_lseek(file, prev_pos); + if (f_res != FR_OK) { + ESP_LOGD(TAG, "%s: fresult=%d", __func__, f_res); + if (ret >= 0) { + errno = fresult_to_errno(f_res); + } // else f_read failed so errno shouldn't be overwritten + ret = -1; // in case the read was successful but the seek wasn't + } + +pread_release: + _lock_release(&fat_ctx->lock); + return ret; +} + +static ssize_t vfs_fat_pwrite(void *ctx, int fd, const void *src, size_t size, off_t offset) +{ + ssize_t ret = -1; + vfs_fat_ctx_t *fat_ctx = (vfs_fat_ctx_t *) ctx; + _lock_acquire(&fat_ctx->lock); + FIL *file = &fat_ctx->files[fd]; + const off_t prev_pos = f_tell(file); + + FRESULT f_res = f_lseek(file, offset); + if (f_res != FR_OK) { + ESP_LOGD(TAG, "%s: fresult=%d", __func__, f_res); + errno = fresult_to_errno(f_res); + goto pwrite_release; + } + + unsigned wr = 0; + f_res = f_write(file, src, size, &wr); + if (f_res == FR_OK) { + ret = wr; + } else { + ESP_LOGD(TAG, "%s: fresult=%d", __func__, f_res); + errno = fresult_to_errno(f_res); + // No return yet - need to restore previous position + } + + f_res = f_lseek(file, prev_pos); + if (f_res != FR_OK) { + ESP_LOGD(TAG, "%s: fresult=%d", __func__, f_res); + if (ret >= 0) { + errno = fresult_to_errno(f_res); + } // else f_write failed so errno shouldn't be overwritten + ret = -1; // in case the write was successful but the seek wasn't + } + +pwrite_release: + _lock_release(&fat_ctx->lock); + return ret; +} + static int vfs_fat_fsync(void* ctx, int fd) { vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx; @@ -512,8 +596,8 @@ static int vfs_fat_link(void* ctx, const char* n1, const char* n2) prepend_drive_to_path(fat_ctx, &n1, &n2); const size_t copy_buf_size = fat_ctx->fs.csize; FRESULT res; - FIL* pf1 = ff_memcalloc(1, sizeof(FIL)); - FIL* pf2 = ff_memcalloc(1, sizeof(FIL)); + FIL* pf1 = (FIL*) ff_memalloc(sizeof(FIL)); + FIL* pf2 = (FIL*) ff_memalloc(sizeof(FIL)); void* buf = ff_memalloc(copy_buf_size); if (buf == NULL || pf1 == NULL || pf2 == NULL) { _lock_release(&fat_ctx->lock); @@ -524,6 +608,8 @@ static int vfs_fat_link(void* ctx, const char* n1, const char* n2) errno = ENOMEM; return -1; } + memset(pf1, 0, sizeof(*pf1)); + memset(pf2, 0, sizeof(*pf2)); res = f_open(pf1, n1, FA_READ | FA_OPEN_EXISTING); if (res != FR_OK) { _lock_release(&fat_ctx->lock); @@ -591,12 +677,14 @@ static DIR* vfs_fat_opendir(void* ctx, const char* name) vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx; _lock_acquire(&fat_ctx->lock); prepend_drive_to_path(fat_ctx, &name, NULL); - vfs_fat_dir_t* fat_dir = ff_memcalloc(1, sizeof(vfs_fat_dir_t)); + vfs_fat_dir_t* fat_dir = ff_memalloc(sizeof(vfs_fat_dir_t)); if (!fat_dir) { _lock_release(&fat_ctx->lock); errno = ENOMEM; return NULL; } + memset(fat_dir, 0, sizeof(*fat_dir)); + FRESULT res = f_opendir(&fat_dir->ffdir, name); _lock_release(&fat_ctx->lock); if (res != FR_OK) { @@ -766,7 +854,7 @@ static int vfs_fat_truncate(void* ctx, const char *path, off_t length) _lock_acquire(&fat_ctx->lock); prepend_drive_to_path(fat_ctx, &path, NULL); - file = (FIL*) ff_memcalloc(1, sizeof(FIL)); + file = (FIL*) ff_memalloc(sizeof(FIL)); if (file == NULL) { _lock_release(&fat_ctx->lock); ESP_LOGD(TAG, "truncate alloc failed"); @@ -774,6 +862,7 @@ static int vfs_fat_truncate(void* ctx, const char *path, off_t length) ret = -1; goto out; } + memset(file, 0, sizeof(*file)); res = f_open(file, path, FA_WRITE); diff --git a/components/fatfs/src/vfs_fat_internal.h b/components/fatfs/vfs/vfs_fat_internal.h similarity index 100% rename from components/fatfs/src/vfs_fat_internal.h rename to components/fatfs/vfs/vfs_fat_internal.h diff --git a/components/fatfs/src/vfs_fat_sdmmc.c b/components/fatfs/vfs/vfs_fat_sdmmc.c similarity index 99% rename from components/fatfs/src/vfs_fat_sdmmc.c rename to components/fatfs/vfs/vfs_fat_sdmmc.c index b667aa19fe..97928f7d02 100644 --- a/components/fatfs/src/vfs_fat_sdmmc.c +++ b/components/fatfs/vfs/vfs_fat_sdmmc.c @@ -21,7 +21,8 @@ #include "driver/sdmmc_host.h" #include "driver/sdspi_host.h" #include "sdmmc_cmd.h" -#include "diskio.h" +#include "diskio_impl.h" +#include "diskio_sdmmc.h" static const char* TAG = "vfs_fat_sdmmc"; static sdmmc_card_t* s_card = NULL; diff --git a/components/fatfs/src/vfs_fat_spiflash.c b/components/fatfs/vfs/vfs_fat_spiflash.c similarity index 99% rename from components/fatfs/src/vfs_fat_spiflash.c rename to components/fatfs/vfs/vfs_fat_spiflash.c index 9fbe953815..afd46453b0 100644 --- a/components/fatfs/src/vfs_fat_spiflash.c +++ b/components/fatfs/vfs/vfs_fat_spiflash.c @@ -18,7 +18,7 @@ #include "esp_vfs.h" #include "esp_vfs_fat.h" #include "vfs_fat_internal.h" -#include "diskio.h" +#include "diskio_impl.h" #include "diskio_rawflash.h" diff --git a/components/freemodbus/CMakeLists.txt b/components/freemodbus/CMakeLists.txt index 4b57c16619..97112a53be 100644 --- a/components/freemodbus/CMakeLists.txt +++ b/components/freemodbus/CMakeLists.txt @@ -1,41 +1,44 @@ # The following five lines of boilerplate have to be in your project's # CMakeLists in this exact order for cmake to work correctly -set(COMPONENT_SRCS "common/esp_modbus_master.c" - "common/esp_modbus_slave.c" - "modbus/mb.c" - "modbus/mb_m.c" - "modbus/ascii/mbascii.c" - "modbus/rtu/mbrtu_m.c" - "modbus/rtu/mbrtu.c" - "modbus/rtu/mbcrc.c" - "modbus/tcp/mbtcp.c" - "port/port.c" - "port/portevent.c" - "port/portevent_m.c" - "port/portother.c" - "port/portother_m.c" - "port/portserial.c" - "port/portserial_m.c" - "port/porttimer.c" - "port/porttimer_m.c" - "modbus/functions/mbfunccoils.c" - "modbus/functions/mbfunccoils_m.c" - "modbus/functions/mbfuncdiag.c" - "modbus/functions/mbfuncdisc.c" - "modbus/functions/mbfuncdisc_m.c" - "modbus/functions/mbfuncholding.c" - "modbus/functions/mbfuncholding_m.c" - "modbus/functions/mbfuncinput.c" - "modbus/functions/mbfuncinput_m.c" - "modbus/functions/mbfuncother.c" - "modbus/functions/mbutils.c" - "serial_slave/modbus_controller/mbc_serial_slave.c" - "serial_master/modbus_controller/mbc_serial_master.c") -set(COMPONENT_ADD_INCLUDEDIRS common/include) -set(COMPONENT_PRIV_INCLUDEDIRS common port modbus modbus/ascii modbus/functions +set(srcs + "common/esp_modbus_master.c" + "common/esp_modbus_slave.c" + "modbus/mb.c" + "modbus/mb_m.c" + "modbus/ascii/mbascii.c" + "modbus/rtu/mbrtu_m.c" + "modbus/rtu/mbrtu.c" + "modbus/rtu/mbcrc.c" + "modbus/tcp/mbtcp.c" + "port/port.c" + "port/portevent.c" + "port/portevent_m.c" + "port/portother.c" + "port/portother_m.c" + "port/portserial.c" + "port/portserial_m.c" + "port/porttimer.c" + "port/porttimer_m.c" + "modbus/functions/mbfunccoils.c" + "modbus/functions/mbfunccoils_m.c" + "modbus/functions/mbfuncdiag.c" + "modbus/functions/mbfuncdisc.c" + "modbus/functions/mbfuncdisc_m.c" + "modbus/functions/mbfuncholding.c" + "modbus/functions/mbfuncholding_m.c" + "modbus/functions/mbfuncinput.c" + "modbus/functions/mbfuncinput_m.c" + "modbus/functions/mbfuncother.c" + "modbus/functions/mbutils.c" + "serial_slave/modbus_controller/mbc_serial_slave.c" + "serial_master/modbus_controller/mbc_serial_master.c") +set(include_dirs common/include) +set(priv_include_dirs common port modbus modbus/ascii modbus/functions modbus/rtu modbus/tcp modbus/include) -list(APPEND COMPONENT_PRIV_INCLUDEDIRS serial_slave/port serial_slave/modbus_controller +list(APPEND priv_include_dirs serial_slave/port serial_slave/modbus_controller serial_master/port serial_master/modbus_controller) -set(COMPONENT_REQUIRES "driver") -register_component() +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS "${include_dirs}" + PRIV_INCLUDE_DIRS "${priv_include_dirs}" + REQUIRES driver) diff --git a/components/freemodbus/common/include/esp_modbus_common.h b/components/freemodbus/common/include/esp_modbus_common.h index 34810cf366..cd171c7557 100644 --- a/components/freemodbus/common/include/esp_modbus_common.h +++ b/components/freemodbus/common/include/esp_modbus_common.h @@ -22,10 +22,10 @@ #define MB_CONTROLLER_PRIORITY (CONFIG_FMB_SERIAL_TASK_PRIO - 1) // priority of MB controller task // Default port defines -#define MB_DEVICE_ADDRESS (1) // Default slave device address in Modbus -#define MB_DEVICE_SPEED (115200) // Default Modbus speed for now hard defined +#define MB_DEVICE_ADDRESS (1) // Default slave device address in Modbus +#define MB_DEVICE_SPEED (115200) // Default Modbus speed for now hard defined #define MB_UART_PORT (UART_NUM_MAX - 1) // Default UART port number -#define MB_PAR_INFO_TOUT (10) // Timeout for get parameter info +#define MB_PAR_INFO_TOUT (10) // Timeout for get parameter info #define MB_PARITY_NONE (UART_PARITY_DISABLE) // The Macros below handle the endianness while transfer N byte data into buffer diff --git a/components/freertos/CMakeLists.txt b/components/freertos/CMakeLists.txt index dec3387415..ee6b560392 100644 --- a/components/freertos/CMakeLists.txt +++ b/components/freertos/CMakeLists.txt @@ -1,31 +1,31 @@ -set(COMPONENT_ADD_INCLUDEDIRS include) -set(COMPONENT_PRIV_INCLUDEDIRS include/freertos .) -set(COMPONENT_SRCS "croutine.c" - "event_groups.c" - "FreeRTOS-openocd.c" - "list.c" - "port.c" - "portasm.S" - "queue.c" - "tasks.c" - "timers.c" - "xtensa_context.S" - "xtensa_init.c" - "xtensa_intr.c" - "xtensa_intr_asm.S" - "xtensa_overlay_os_hook.c" - "xtensa_vector_defaults.S" - "xtensa_vectors.S") +set(srcs + "croutine.c" + "event_groups.c" + "FreeRTOS-openocd.c" + "list.c" + "port.c" + "portasm.S" + "queue.c" + "tasks.c" + "timers.c" + "xtensa_context.S" + "xtensa_init.c" + "xtensa_intr.c" + "xtensa_intr_asm.S" + "xtensa_overlay_os_hook.c" + "xtensa_vector_defaults.S" + "xtensa_vectors.S") # app_trace is required by FreeRTOS headers only when CONFIG_SYSVIEW_ENABLE=y, # but requirements can't depend on config options, so always require it. -set(COMPONENT_REQUIRES app_trace) -set(COMPONENT_PRIV_REQUIRES esp_common soc) -set(COMPONENT_ADD_LDFRAGMENTS linker.lf) +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS include + PRIV_INCLUDE_DIRS include/freertos . + LDFRAGMENTS linker.lf + REQUIRES app_trace + PRIV_REQUIRES soc) -register_component() - -target_link_libraries(${COMPONENT_LIB} "-Wl,--undefined=uxTopUsedPriority") +target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--undefined=uxTopUsedPriority") set_source_files_properties( tasks.c diff --git a/components/freertos/tasks.c b/components/freertos/tasks.c index f8d2f1ed2d..9eaa5578df 100644 --- a/components/freertos/tasks.c +++ b/components/freertos/tasks.c @@ -77,7 +77,6 @@ all the API functions to use the MPU wrappers. That should only be done when task.h is included from an application file. */ #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE #include "esp_newlib.h" -#include "esp_debug_helpers.h" /* FreeRTOS includes. */ #include "FreeRTOS.h" diff --git a/components/freertos/test/CMakeLists.txt b/components/freertos/test/CMakeLists.txt index 66a8c82315..b531a14504 100644 --- a/components/freertos/test/CMakeLists.txt +++ b/components/freertos/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity test_utils) - -register_component() \ No newline at end of file +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity test_utils) \ No newline at end of file diff --git a/components/heap/CMakeLists.txt b/components/heap/CMakeLists.txt index f27665d5fe..0bacaf74f9 100644 --- a/components/heap/CMakeLists.txt +++ b/components/heap/CMakeLists.txt @@ -1,23 +1,24 @@ -set(COMPONENT_SRCS "heap_caps.c" - "heap_caps_init.c" - "multi_heap.c") +set(srcs + "heap_caps.c" + "heap_caps_init.c" + "multi_heap.c") if(NOT CONFIG_HEAP_POISONING_DISABLED) - list(APPEND COMPONENT_SRCS "multi_heap_poisoning.c") + list(APPEND srcs "multi_heap_poisoning.c") endif() if(CONFIG_HEAP_TASK_TRACKING) - list(APPEND COMPONENT_SRCS "heap_task_info.c") + list(APPEND srcs "heap_task_info.c") endif() if(CONFIG_HEAP_TRACING_STANDALONE) - list(APPEND COMPONENT_SRCS "heap_trace_standalone.c") + list(APPEND srcs "heap_trace_standalone.c") endif() -set(COMPONENT_ADD_INCLUDEDIRS "include") -set(COMPONENT_ADD_LDFRAGMENTS linker.lf) -set(COMPONENT_PRIV_REQUIRES soc) -register_component() +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS include + LDFRAGMENTS linker.lf + PRIV_REQUIRES soc) if(CONFIG_HEAP_TRACING) set(WRAP_FUNCTIONS @@ -32,7 +33,7 @@ if(CONFIG_HEAP_TRACING) heap_caps_realloc_default) foreach(wrap ${WRAP_FUNCTIONS}) - target_link_libraries(${COMPONENT_LIB} "-Wl,--wrap=${wrap}") + target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=${wrap}") endforeach() endif() diff --git a/components/heap/test/CMakeLists.txt b/components/heap/test/CMakeLists.txt index aed6c9743e..b70637f263 100644 --- a/components/heap/test/CMakeLists.txt +++ b/components/heap/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity test_utils heap) - -register_component() \ No newline at end of file +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity test_utils heap) \ No newline at end of file diff --git a/components/heap/test/test_malloc.c b/components/heap/test/test_malloc.c index 1ed67ce50c..e2916e2bc3 100644 --- a/components/heap/test/test_malloc.c +++ b/components/heap/test/test_malloc.c @@ -14,7 +14,6 @@ #include "unity.h" #include "esp_heap_caps.h" -#include "esp_debug_helpers.h" #include "sdkconfig.h" diff --git a/components/idf_test/CMakeLists.txt b/components/idf_test/CMakeLists.txt index e307838a8b..eafb7ac220 100644 --- a/components/idf_test/CMakeLists.txt +++ b/components/idf_test/CMakeLists.txt @@ -1,2 +1 @@ -set(COMPONENT_ADD_INCLUDEDIRS "include") -register_component() +idf_component_register(INCLUDE_DIRS include) diff --git a/components/idf_test/include/idf_performance.h b/components/idf_test/include/idf_performance.h index 6cdb288236..137c1b74b3 100644 --- a/components/idf_test/include/idf_performance.h +++ b/components/idf_test/include/idf_performance.h @@ -15,9 +15,9 @@ #define IDF_PERFORMANCE_MAX_VFS_OPEN_WRITE_CLOSE_TIME 20000 #define IDF_PERFORMANCE_MAX_VFS_OPEN_WRITE_CLOSE_TIME_PSRAM 25000 // throughput performance by iperf -#define IDF_PERFORMANCE_MIN_TCP_RX_THROUGHPUT 50 +#define IDF_PERFORMANCE_MIN_TCP_RX_THROUGHPUT 45 #define IDF_PERFORMANCE_MIN_TCP_TX_THROUGHPUT 40 -#define IDF_PERFORMANCE_MIN_UDP_RX_THROUGHPUT 80 +#define IDF_PERFORMANCE_MIN_UDP_RX_THROUGHPUT 64 #define IDF_PERFORMANCE_MIN_UDP_TX_THROUGHPUT 50 // events dispatched per second by event loop library #define IDF_PERFORMANCE_MIN_EVENT_DISPATCH 25000 diff --git a/components/idf_test/integration_test/CIConfigs/nvs_compatible_test.yml b/components/idf_test/integration_test/CIConfigs/nvs_compatible_test_.yml similarity index 100% rename from components/idf_test/integration_test/CIConfigs/nvs_compatible_test.yml rename to components/idf_test/integration_test/CIConfigs/nvs_compatible_test_.yml diff --git a/components/idf_test/integration_test/INIT_COND_SSC.yml b/components/idf_test/integration_test/INIT_COND_SSC.yml index 61c86b28ea..746fa9e83d 100644 --- a/components/idf_test/integration_test/INIT_COND_SSC.yml +++ b/components/idf_test/integration_test/INIT_COND_SSC.yml @@ -14,6 +14,13 @@ - - SSC SSC1 op -W -a start - - R SSC1 C +MODE +.dut_init_espnow: &dut_init_espnow + LIST_MERGE: + - - SSC SSC[1,2] espnow -D + - - 'R SSC[1,2] C +ESPNOW:' + - - SSC SSC[1,2] espnow -I + - - 'R SSC[1,2] C +ESPNOW:' + initial condition: - tag: APM1 <<: *SSC_INIT_COND @@ -290,6 +297,61 @@ initial condition: - - R SSC1 C +MODE:OK - - SSC SSC1 op -W -a stop - - R SSC1 C +MODE:OK +- tag: APM2_MDNS + <<: *SSC_INIT_COND + initial condition detail: (SSC) DUT set to SoftAP mode, PC Wi-Fi NIC connected with SoftAP, restart MDNS + check cmd set: + - '' + - - SSC SSC1 op -Q + - - R SSC1 C +CURMODE:2 + - - SSC SSC1 ap -Q + - - R SSC1 RE "\+APCONFIG:%%s,%%s,7,\d+,\d+,4,"%%(,) + - - SSC SSC1 ap -L + - - R SSC1 RE "\+LSTA:.+,%%s"%%() + - - SSC SSC1 dhcp -Q -o 2 + - - R SSC1 C +DHCP:AP,STARTED + - - SSC SSC1 mac -Q -o 2 + - - R SSC1 P + - - SSC SSC1 mdns -T + - - R SSC1 C +MDNS:OK + - - SSC SSC1 mdns -I + - - R SSC1 C +MDNS:OK + restore cmd set: + - '' + - - SSC SSC1 op -S -o 2 + - - R SSC1 C +MODE:OK + - - SSC SSC1 mac -S -o 2 -m + - - R SSC1 C +MAC:AP,OK + - - SSC SSC1 dhcp -S -o 2 + - - R SSC1 C +DHCP + - - SSC SSC1 ap -S -s -p -t -n 7 + - - R SSC1 C +SAP:OK + - - WIFI CONN + + - - R PC_COM NC ERROR C +WIFICONN:OK + - - SSC SSC1 mdns -T + - - R SSC1 C +MDNS:OK + - - SSC SSC1 mdns -I + - - R SSC1 C +MDNS:OK + force restore cmd set: + - '' + - - SSC SSC1 reboot + - - R SSC1 C !!!ready!!! + - - SSC SSC1 op -S -o 2 + - - R SSC1 C +MODE:OK + - - SSC SSC1 mac -S -o 2 -m + - - R SSC1 C +MAC:AP,OK + - - SSC SSC1 dhcp -S -o 2 + - - R SSC1 C +DHCP + - - SSC SSC1 ap -S -s -p -t -n 7 + - - R SSC1 C +SAP:OK + - - WIFI CONN + + - - R PC_COM NC ERROR C +WIFICONN:OK + - - SSC SSC1 mdns -T + - - R SSC1 C +MDNS:OK + - - SSC SSC1 mdns -I + - - R SSC1 C +MDNS:OK - tag: BLE_CONN2 <<: *SSC_INIT_COND initial condition detail: (SSC) enable BLE one 2 DUTs, GATT service 0xA000 started on DUT2, DUT1 connected with DUT2 @@ -316,21 +378,21 @@ initial condition: - - 'R SSC[1-2] C +GATTS:' - - SSC SSC[1-2] gattc -U -z all - - R SSC[1-2] C +GATTC:OK + - - SSC SSC2 gatts -S -z load -p 0xA0 + - - R SSC2 C +GATTS:StartService,OK,A000 - - SSC SSC[1-2] bleadv -D -z stop - - - R SSC[1-2] C +BLEADV:OK + - - R SSC[1-2] C +BLEADV:Stop - - SSC SSC[1-2] ble -S -z public - - R SSC[1-2] C +BLE:OK - - SSC SSC2 bleadv -L -c 0 -t 3 - - R SSC2 C +BLEADV:SetAdv,OK - - SSC SSC2 bleadv -D -z start - - - R SSC2 C +BLEADV:OK - - - SSC SSC2 gatts -S -z load -p 0xA0 - - - R SSC2 C +GATTS:StartService,OK,A000 + - - R SSC2 C +BLEADV:Start,OK - - SSC SSC1 gattc -F -r - - R SSC1 C +GATTC:OK - - SSC SSC1 bleconn -C -p 0x10 -a - - - R SSC1 C +BLE:GattcConnect,OK - - P SSC2 C +BLE:GattsConnect + - - R SSC1 C +BLECONN:GapConnect,OK + - P SSC2 C +BLECONN:GapConnect,OK force restore cmd set: - '' - - SSC SSC[1-2] reboot @@ -348,21 +410,21 @@ initial condition: - - 'R SSC[1-2] C +GATTS:' - - SSC SSC[1-2] gattc -U -z all - - R SSC[1-2] C +GATTC:OK + - - SSC SSC2 gatts -S -z load -p 0xA0 + - - R SSC2 C +GATTS:StartService,OK,A000 - - SSC SSC[1-2] bleadv -D -z stop - - - R SSC[1-2] C +BLEADV:OK + - - R SSC[1-2] C +BLEADV:Stop - - SSC SSC[1-2] ble -S -z public - - R SSC[1-2] C +BLE:OK - - SSC SSC2 bleadv -L -c 0 -t 3 - - R SSC2 C +BLEADV:SetAdv,OK - - SSC SSC2 bleadv -D -z start - - - R SSC2 C +BLEADV:OK - - - SSC SSC2 gatts -S -z load -p 0xA0 - - - R SSC2 C +GATTS:StartService,OK,A000 + - - R SSC2 C +BLEADV:Start,OK - - SSC SSC1 gattc -F -r - - R SSC1 C +GATTC:OK - - SSC SSC1 bleconn -C -p 0x10 -a - - - R SSC1 C +BLE:GattcConnect,OK - - P SSC2 C +BLE:GattsConnect + - - R SSC1 C +BLECONN:GapConnect,OK + - P SSC2 C +BLECONN:GapConnect,OK restore post cmd set: - '' - - SSC SSC1 ram @@ -393,21 +455,21 @@ initial condition: - - 'R SSC[1-2] C +GATTS:' - - SSC SSC[1-2] gattc -U -z all - - R SSC[1-2] C +GATTC:OK + - - SSC SSC2 gatts -S -z load -p 0xA2 + - - R SSC2 C +GATTS:StartService,OK,A002 - - SSC SSC[1-2] bleadv -D -z stop - - - R SSC[1-2] C +BLEADV:OK + - - R SSC[1-2] C +BLEADV:Stop - - SSC SSC[1-2] ble -S -z public - - R SSC[1-2] C +BLE:OK - - SSC SSC2 bleadv -L -c 0 -t 3 - - R SSC2 C +BLEADV:SetAdv,OK - - SSC SSC2 bleadv -D -z start - - R SSC2 C +BLEADV:OK - - - SSC SSC2 gatts -S -z load -p 0xA2 - - - R SSC2 C +GATTS:StartService,OK,A002 - - SSC SSC1 gattc -F -r - - R SSC1 C +GATTC:OK - - SSC SSC1 bleconn -C -p 0x10 -a - - - R SSC1 C +BLE:GattcConnect,OK - - P SSC2 C +BLE:GattsConnect + - - R SSC1 C +BLECONN:GapConnect,OK + - P SSC2 C +BLECONN:GapConnect,OK force restore cmd set: - '' - - SSC SSC[1-2] reboot @@ -425,21 +487,21 @@ initial condition: - - 'R SSC[1-2] C +GATTS:' - - SSC SSC[1-2] gattc -U -z all - - R SSC[1-2] C +GATTC:OK + - - SSC SSC2 gatts -S -z load -p 0xA2 + - - R SSC2 C +GATTS:StartService,OK,A002 - - SSC SSC[1-2] bleadv -D -z stop - - - R SSC[1-2] C +BLEADV:OK + - - R SSC[1-2] C +BLEADV:Stop - - SSC SSC[1-2] ble -S -z public - - R SSC[1-2] C +BLE:OK - - SSC SSC2 bleadv -L -c 0 -t 3 - - R SSC2 C +BLEADV:SetAdv,OK - - SSC SSC2 bleadv -D -z start - - R SSC2 C +BLEADV:OK - - - SSC SSC2 gatts -S -z load -p 0xA2 - - - R SSC2 C +GATTS:StartService,OK,A002 - - SSC SSC1 gattc -F -r - - R SSC1 C +GATTC:OK - - SSC SSC1 bleconn -C -p 0x10 -a - - - R SSC1 C +BLE:GattcConnect,OK - - P SSC2 C +BLE:GattsConnect + - - R SSC1 C +BLECONN:GapConnect,OK + - P SSC2 C +BLECONN:GapConnect,OK restore post cmd set: - '' - - SSC SSC1 ram @@ -470,23 +532,21 @@ initial condition: - - 'R SSC[1-2] C +GATTS:' - - SSC SSC[1-2] gattc -U -z all - - R SSC[1-2] C +GATTC:OK + - - SSC SSC[1-2] gatts -S -z load -p 0xA2 + - - R SSC[1-2] C +GATTS:StartService,OK,A002 - - SSC SSC[1-2] bleadv -D -z stop - - - R SSC[1-2] C +BLEADV:OK + - - R SSC[1-2] C +BLEADV:Stop - - SSC SSC[1-2] ble -S -z public - - R SSC[1-2] C +BLE:OK - - SSC SSC2 bleadv -L -c 0 -t 3 - - R SSC2 C +BLEADV:SetAdv,OK - - SSC SSC2 bleadv -D -z start - - - R SSC2 C +BLEADV:OK - - - SSC SSC[1-2] gatts -S -z load -p 0xA2 - - - R SSC[1-2] C +GATTS:StartService,OK,A002 + - - R SSC2 C +BLEADV - - SSC SSC[1-2] gattc -F -r - - R SSC[1-2] C +GATTC:OK - - SSC SSC1 bleconn -C -p 0x10 -a - - - R SSC1 C +BLE:GattcConnect,OK - - P SSC2 C +BLE:GattsConnect - - - SSC SSC2 bleconn -C -p 0x10 -a - - - R SSC2 C +BLE:GattcOpen,OK + - - R SSC1 C +BLECONN:GapConnect,OK + - P SSC2 C +BLECONN:GapConnect,OK force restore cmd set: - '' - - SSC SSC[1-2] reboot @@ -504,23 +564,21 @@ initial condition: - - 'R SSC[1-2] C +GATTS:' - - SSC SSC[1-2] gattc -U -z all - - R SSC[1-2] C +GATTC:OK + - - SSC SSC[1-2] gatts -S -z load -p 0xA2 + - - R SSC[1-2] C +GATTS:StartService,OK,A002 - - SSC SSC[1-2] bleadv -D -z stop - - - R SSC[1-2] C +BLEADV:OK + - - R SSC[1-2] C +BLEADV:Stop - - SSC SSC[1-2] ble -S -z public - - R SSC[1-2] C +BLE:OK - - SSC SSC2 bleadv -L -c 0 -t 3 - - R SSC2 C +BLEADV:SetAdv,OK - - SSC SSC2 bleadv -D -z start - - - R SSC2 C +BLEADV:OK - - - SSC SSC[1-2] gatts -S -z load -p 0xA2 - - - R SSC[1-2] C +GATTS:StartService,OK,A002 + - - R SSC2 C +BLEADV:Start,OK - - SSC SSC[1-2] gattc -F -r - - R SSC[1-2] C +GATTC:OK - - SSC SSC1 bleconn -C -p 0x10 -a - - - R SSC1 C +BLE:GattcConnect,OK - - P SSC2 C +BLE:GattsConnect - - - SSC SSC2 bleconn -C -p 0x10 -a - - - R SSC2 C +BLE:GattcOpen,OK + - - R SSC1 C +BLECONN:GapConnect,OK + - P SSC2 C +BLECONN:GapConnect,OK restore post cmd set: - '' - - SSC SSC1 ram @@ -549,21 +607,21 @@ initial condition: - - 'R SSC[1-5] C +GATTS:' - - SSC SSC[1-5] gattc -U -z all - - R SSC[1-5] C +GATTC:OK + - - SSC SSC[2-5] gatts -S -z load -p 0xA2 + - - P SSC[2-5] C +GATTS:StartService,OK,A002 - - SSC SSC[1-5] bleadv -D -z stop - - - R SSC[1-5] C +BLEADV:OK + - - R SSC[1-5] C +BLEADV:Stop - - SSC SSC[1-5] ble -S -z public - - R SSC[1-5] C +BLE:OK - - SSC SSC[2-5] bleadv -D -z start - - P SSC[2-5] C +BLEADV:Start,OK - - - SSC SSC[2-5] gatts -S -z load -p 0xA2 - - - P SSC[2-5] C +GATTS:StartService,OK,A002 - - SSC SSC1 gattc -F -r - - R SSC1 C +GATTC:OK - - LOOP 4 1 "[2,3,4,5]" "[2,3,4,5]" "[2,3,4,5]" - '' - - SSC SSC1 bleconn -C -p 0x10 -a - - - R SSC1 RE "\+BLE:GattcConnect,OK,0010,%%s"%%() - - P SSC{%d} C +BLE:GattsConnect + - - R SSC1 RE "\+BLECONN:GapConnect,OK,0010,%%s"%%() + - P SSC{%d} C +BLECONN:GapConnect,OK restore cmd set: - '' # do wifi disconnect, to prevent wifi reconnect cause bad BLE performance @@ -583,21 +641,21 @@ initial condition: - - 'R SSC[1-5] C +GATTS:' - - SSC SSC[1-5] gattc -U -z all - - R SSC[1-5] C +GATTC:OK + - - SSC SSC[2-5] gatts -S -z load -p 0xA2 + - - P SSC[2-5] C +GATTS:StartService,OK,A002 - - SSC SSC[1-5] bleadv -D -z stop - - - R SSC[1-5] C +BLEADV:OK + - - R SSC[1-5] C +BLEADV:Stop - - SSC SSC[1-5] ble -S -z public - - R SSC[1-5] C +BLE:OK - - SSC SSC[2-5] bleadv -D -z start - - P SSC[2-5] C +BLEADV:Start,OK - - - SSC SSC[2-5] gatts -S -z load -p 0xA2 - - - P SSC[2-5] C +GATTS:StartService,OK,A002 - - SSC SSC1 gattc -F -r - - R SSC1 C +GATTC:OK - - LOOP 4 1 "[2,3,4,5]" "[2,3,4,5]" "[2,3,4,5]" - '' - - SSC SSC1 bleconn -C -p 0x10 -a - - - R SSC1 RE "\+BLE:GattcConnect,OK,0010,%%s"%%() - - P SSC{%d} C +BLE:GattsConnect + - - R SSC1 RE "\+BLECONN:GapConnect,OK,0010,%%s"%%() + - P SSC{%d} C +BLECONN:GapConnect,OK, restore post cmd set: - '' - - SSC SSC1 ram @@ -628,12 +686,12 @@ initial condition: - - 'R SSC[1-5] C +GATTS:' - - SSC SSC[1-5] gattc -U -z all - - R SSC[1-5] C +GATTC:OK - - - SSC SSC[1-5] bleadv -D -z stop - - - R SSC[1-5] C +BLEADV:OK - - SSC SSC[1-5] ble -S -z public - - R SSC[1-5] C +BLE:OK - - SSC SSC1 gatts -S -z load -p 0xA2 - - R SSC1 C +GATTS:StartService,OK,A002 + - - SSC SSC[1-5] bleadv -D -z stop + - - R SSC[1-5] C +BLEADV:Stop - - LOOP 4 3 "[2,3,4,5]" "[2,3,4,5]" - '' - - SSC SSC1 bleadv -D -z start @@ -641,8 +699,8 @@ initial condition: - - SSC SSC[2-5] gattc -F -r - - R SSC[2-5] C +GATTC:OK - - SSC SSC{%d} bleconn -C -p 0x10 -a - - - R SSC{%d} RE "\+BLE:GattcConnect,OK,0010,%%s"%%() - - P SSC1 C +BLE:GattsConnect + - - R SSC{%d} RE "\+BLECONN:GapConnect,OK,0010,%%s"%%() + - P SSC1 C +BLECONN:GapConnect,OK force restore cmd set: - '' - - SSC SSC[1-5] reboot @@ -661,20 +719,22 @@ initial condition: - - SSC SSC[1-5] gattc -U -z all - - R SSC[1-5] C +GATTC:OK - - SSC SSC[1-5] bleadv -D -z stop - - - R SSC[1-5] C +BLEADV:OK + - - R SSC[1-5] C +BLEADV:Stop - - SSC SSC[1-5] ble -S -z public - - R SSC[1-5] C +BLE:OK - - SSC SSC1 gatts -S -z load -p 0xA2 - - R SSC1 C +GATTS:StartService,OK,A002 - - SSC SSC[2-5] gattc -F -r - - R SSC[2-5] C +GATTC:OK - - - LOOP 4 2 "[2,3,4,5]" "[2,3,4,5]" + - - LOOP 4 3 "[2,3,4,5]" "[2,3,4,5]" - '' - - SSC SSC1 bleadv -D -z start - - P SSC1 C +BLEADV:Start,OK + - - SSC SSC[2-5] gattc -F -r + - - R SSC[2-5] C +GATTC:OK - - SSC SSC{%d} bleconn -C -p 0x10 -a - - - R SSC{%d} RE "\+BLE:GattcConnect,OK,0010,%%s"%%() - - P SSC1 C +BLE:GattsConnect + - - R SSC{%d} RE "\+BLECONN:GapConnect,OK,0010,%%s"%%() + - P SSC1 C +BLECONN:GapConnect,OK restore post cmd set: - '' - - SSC SSC1 ram @@ -706,7 +766,7 @@ initial condition: - - SSC SSC[1-5] gattc -U -z all - - R SSC[1-5] C +GATTC:OK - - SSC SSC[1-5] bleadv -D -z stop - - - R SSC[1-5] C +BLEADV:OK + - - R SSC[1-5] C +BLEADV:Stop - - SSC SSC[1-5] ble -S -z public - - R SSC[1-5] C +BLE:OK - - SSC SSC[1-3] gatts -S -z load -p 0xA2 @@ -716,15 +776,15 @@ initial condition: - - SSC SSC1 bleadv -D -z start - - P SSC1 C +BLEADV:Start,OK - - SSC SSC{%d} bleconn -C -p 0x10 -a - - - R SSC{%d} RE "\+BLE:GattcConnect,OK,0010,%%s"%%() - - P SSC1 C +BLE:GattsConnect + - - R SSC{%d} RE "\+BLECONN:GapConnect,OK,0010,%%s"%%() + - P SSC1 C +BLECONN:GapConnect,OK - - SSC SSC[2-3] bleadv -D -z start - - P SSC[2-3] C +BLEADV:Start,OK - - LOOP 2 1 "[2,3]" "[2,3]" "[2,3]" - '' - - SSC SSC1 bleconn -C -p 0x10 -a - - - R SSC1 RE "\+BLE:GattcConnect,OK,0010,%%s"%%() - - P SSC{%d} C +BLE:GattsConnect + - - R SSC1 RE "\+BLECONN:GapConnect,OK,0010,%%s"%%() + - P SSC{%d} C +BLECONN:GapConnect,OK, force restore cmd set: - '' - - SSC SSC[1-5] reboot @@ -743,7 +803,7 @@ initial condition: - - SSC SSC[1-5] gattc -U -z all - - R SSC[1-5] C +GATTC:OK - - SSC SSC[1-5] bleadv -D -z stop - - - R SSC[1-5] C +BLEADV:OK + - - R SSC[1-5] C +BLEADV:Stop - - SSC SSC[1-5] ble -S -z public - - R SSC[1-5] C +BLE:OK - - SSC SSC[1-3] gatts -S -z load -p 0xA2 @@ -753,15 +813,15 @@ initial condition: - - SSC SSC1 bleadv -D -z start - - P SSC1 C +BLEADV:Start,OK - - SSC SSC{%d} bleconn -C -p 0x10 -a - - - R SSC{%d} RE "\+BLE:GattcConnect,OK,0010,%%s"%%() - - P SSC1 C +BLE:GattsConnect + - - R SSC{%d} RE "\+BLECONN:GapConnect,OK,0010,%%s"%%() + - P SSC1 C +BLECONN:GapConnect,OK, - - SSC SSC[2-3] bleadv -D -z start - - P SSC[2-3] C +BLEADV:Start,OK - - LOOP 2 1 "[2,3]" "[2,3]" "[2,3]" - '' - - SSC SSC1 bleconn -C -p 0x10 -a - - - R SSC1 RE "\+BLE:GattcConnect,OK,0010,%%s"%%() - - P SSC{%d} C +BLE:GattsConnect + - - R SSC1 RE "\+BLECONN:GapConnect,OK,0010,%%s"%%() + - P SSC{%d} C +BLECONN:GapConnect,OK restore post cmd set: - '' - - SSC SSC1 ram @@ -793,15 +853,15 @@ initial condition: - - SSC SSC[1-2] gattc -U -z all - - R SSC[1-2] C +GATTC:OK - - SSC SSC[1-2] bleadv -D -z stop - - - R SSC[1-2] C +BLEADV:OK + - - R SSC[1-2] C +BLEADV:Stop + - - SSC SSC2 gatts -S -z load -p 0xA2 + - - R SSC2 C +GATTS:StartService,OK,A002 - - SSC SSC[1-2] ble -S -z public - - R SSC[1-2] C +BLE:OK - - SSC SSC2 bleadv -L -c 0 -t 3 - - R SSC2 C +BLEADV:SetAdv,OK - - SSC SSC2 bleadv -D -z start - - - R SSC2 C +BLEADV:OK - - - SSC SSC2 gatts -S -z load -p 0xA0 - - - R SSC2 C +GATTS:StartService,OK,A000 + - - R SSC2 C +BLEADV:Start,OK - - SSC SSC2 blesmp -S -z AuthReqMode -v 0x01 - - P SSC2 C +BLESMP:OK - - SSC SSC2 blesmp -S -z IOCAP -v 0x03 @@ -809,11 +869,9 @@ initial condition: - - SSC SSC2 blesmp -S -z RspKey -v 0x03 - - P SSC2 C +BLESMP:OK - - SSC SSC1 bleconn -C -p 0x10 -a - - - P SSC1 C +BLE:GattcConnect,OK - - P SSC2 C +BLE:GattsConnect + - - P SSC1 C +BLECONN:GapConnect,OK + - P SSC2 C +BLECONN:GapConnect,OK - - SSC SSC2 blesmp -E -r -z Enc - - - P SSC1 C +BLESMP:SecReq - - - SSC SSC1 blesmp -R -a 1 -r - - P SSC[1-2] C +BLESMP:AuthComplete,Success,0 - - SSC SSC1 gattc -F -r - - R SSC1 C +GATTC:OK @@ -835,15 +893,15 @@ initial condition: - - SSC SSC[1-2] gattc -U -z all - - R SSC[1-2] C +GATTC:OK - - SSC SSC[1-2] bleadv -D -z stop - - - R SSC[1-2] C +BLEADV:OK + - - R SSC[1-2] C +BLEADV:Stop + - - SSC SSC2 gatts -S -z load -p 0xA2 + - - R SSC2 C +GATTS:StartService,OK,A002 - - SSC SSC[1-2] ble -S -z public - - R SSC[1-2] C +BLE:OK - - SSC SSC2 bleadv -L -c 0 -t 3 - - R SSC2 C +BLEADV:SetAdv,OK - - SSC SSC2 bleadv -D -z start - - - R SSC2 C +BLEADV:OK - - - SSC SSC2 gatts -S -z load -p 0xA0 - - - R SSC2 C +GATTS:StartService,OK,A000 + - - R SSC2 C +BLEADV:Start,OK - - SSC SSC2 blesmp -S -z AuthReqMode -v 0x01 - - P SSC2 C +BLESMP:OK - - SSC SSC2 blesmp -S -z IOCAP -v 0x03 @@ -851,11 +909,9 @@ initial condition: - - SSC SSC2 blesmp -S -z RspKey -v 0x03 - - P SSC2 C +BLESMP:OK - - SSC SSC1 bleconn -C -p 0x10 -a - - - P SSC1 C +BLE:GattcConnect,OK - - P SSC2 C +BLE:GattsConnect + - - P SSC1 C +BLECONN:GapConnect,OK + - P SSC2 C +BLECONN:GapConnect,OK - - SSC SSC2 blesmp -E -r -z Enc - - - P SSC1 C +BLESMP:SecReq - - - SSC SSC1 blesmp -R -a 1 -r - - P SSC[1-2] C +BLESMP:AuthComplete,Success,0 - - SSC SSC1 gattc -F -r - - R SSC1 C +GATTC:OK @@ -1017,17 +1073,16 @@ initial condition: - - 'R SSC[1-2] C +GATTS:' - - SSC SSC[1-2] gattc -U -z all - - R SSC[1-2] C +GATTC:OK + - - SSC SSC[1-2] bleadv -D -z stop + - - R SSC[1-2] C +BLEADV:Stop - - SSC SSC2 gatts -S -z load -p 0xA0 - - R SSC2 C +GATTS:StartService,OK,A000 - - - SSC SSC[1-2] bleadv -D -z stop - - - R SSC[1-2] C +BLEADV:OK - - SSC SSC[1-2] ble -S -z public - - R SSC[1-2] C +BLE:OK - - SSC SSC2 bleadv -L -c 0 -t 3 - - R SSC2 C +BLEADV:SetAdv,OK - - SSC SSC2 bleadv -D -z start - - - R SSC2 C +BLEADV:OK - + - - R SSC2 C +BLEADV:Start,OK - - SSC SSC1 ram - - R SSC1 A :(\d+) - tag: BLE_INIT3 @@ -1066,13 +1121,13 @@ initial condition: - - SSC SSC2 gatts -S -z load -p 0xA2 - - R SSC2 C +GATTS:StartService,OK,A002 - - SSC SSC[1-2] bleadv -D -z stop - - - R SSC[1-2] C +BLEADV:OK + - - R SSC[1-2] C +BLEADV:Stop - - SSC SSC[1-2] ble -S -z public - - R SSC[1-2] C +BLE:OK - - SSC SSC2 bleadv -L -c 0 -t 3 - - R SSC2 C +BLEADV:SetAdv,OK - - SSC SSC2 bleadv -D -z start - - - R SSC2 C +BLEADV:OK + - - R SSC2 C +BLEADV:Start,OK - - SSC SSC1 ram - - R SSC1 A :(\d+) - tag: BLE_INIT5 @@ -1111,10 +1166,10 @@ initial condition: - - 'R SSC[1-5] C +GATTS:' - - SSC SSC[1-2] gattc -U -z all - - R SSC[1-2] C +GATTC:OK - - - "SSC SSC[2-5] gatts -S -z load -p 0xA0" - - ["P SSC[2-5] C +GATTS:StartService,OK,A000"] + - - "SSC SSC[2-5] gatts -S -z load -p 0xA2" + - ["P SSC[2-5] C +GATTS:StartService,OK,A002"] - - SSC SSC[1-5] bleadv -D -z stop - - - R SSC[1-5] C +BLEADV:OK + - - R SSC[1-5] C +BLEADV:Stop - - SSC SSC[1-5] ble -S -z public - - R SSC[1-5] C +BLE:OK - - SSC SSC1 gattc -F -r @@ -1147,7 +1202,7 @@ initial condition: - - SSC SSC[1-2] gattc -U -z all - - R SSC[1-2] C +GATTC:OK - - SSC SSC[1-2] bleadv -D -z stop - - - R SSC[1-2] C +BLEADV:OK + - - R SSC[1-2] C +BLEADV:Stop - - SSC SSC[1-2] ble -S -z public - - R SSC[1-2] C +BLE:OK - - SSC SSC2 gatts -S -z load -p 0xA2 @@ -1155,7 +1210,7 @@ initial condition: - - SSC SSC2 bleadv -L -c 0 -t 3 - - R SSC2 C +BLEADV:SetAdv,OK - - SSC SSC2 bleadv -D -z start - - - R SSC2 C +BLEADV:OK + - - R SSC2 C +BLEADV:Start,OK - - SSC SSC[1-2] blesmp -L -c [1,0] - - R SSC[1-2] C +BLESMP:OK - - SSC SSC1 gattc -F -r @@ -1178,7 +1233,7 @@ initial condition: - - SSC SSC[1-2] gattc -U -z all - - R SSC[1-2] C +GATTC:OK - - SSC SSC[1-2] bleadv -D -z stop - - - R SSC[1-2] C +BLEADV:OK + - - R SSC[1-2] C +BLEADV:Stop - - SSC SSC[1-2] ble -S -z public - - R SSC[1-2] C +BLE:OK - - SSC SSC2 gatts -S -z load -p 0xA2 @@ -1186,7 +1241,7 @@ initial condition: - - SSC SSC2 bleadv -L -c 0 -t 3 - - R SSC2 C +BLEADV:SetAdv,OK - - SSC SSC2 bleadv -D -z start - - - R SSC2 C +BLEADV:OK + - - R SSC2 C +BLEADV:Start,OK - - SSC SSC[1-2] blesmp -L -c [1,0] - - R SSC[1-2] C +BLESMP:OK - - SSC SSC1 gattc -F -r @@ -1219,15 +1274,15 @@ initial condition: - - SSC SSC[1-5] gattc -U -z all - - R SSC[1-5] C +GATTC:OK - - SSC SSC[1-5] bleadv -D -z stop - - - R SSC[1-5] C +BLEADV:OK + - - R SSC[1-5] C +BLEADV:Stop - - SSC SSC[1-5] ble -S -z public - - R SSC[1-5] C +BLE:OK - - - SSC SSC[2-5] gatts -S -z load -p 0xA0 - - - R SSC[2-5] C +GATTS:StartService,OK,A000 + - - SSC SSC[2-5] gatts -S -z load -p 0xA2 + - - R SSC[2-5] C +GATTS:StartService,OK,A002 - - SSC SSC[2-5] bleadv -L -c 0 -t 3 - - R SSC[2-5] C +BLEADV:SetAdv,OK - - SSC SSC[2-5] bleadv -D -z start - - - R SSC[2-5] C +BLEADV:OK + - - R SSC[2-5] C +BLEADV:Start,OK - - SSC SSC[1-5] blesmp -L -c [1,0] - - R SSC[1-5] C +BLESMP:OK - - SSC SSC1 gattc -F -r @@ -1247,15 +1302,15 @@ initial condition: - - SSC SSC[1-5] gattc -U -z all - - R SSC[1-5] C +GATTC:OK - - SSC SSC[1-5] bleadv -D -z stop - - - R SSC[1-5] C +BLEADV:OK + - - R SSC[1-5] C +BLEADV:Stop - - SSC SSC[1-5] ble -S -z public - - R SSC[1-5] C +BLE:OK - - - SSC SSC[2-5] gatts -S -z load -p 0xA0 - - - R SSC[2-5] C +GATTS:StartService,OK,A000 + - - SSC SSC[2-5] gatts -S -z load -p 0xA2 + - - R SSC[2-5] C +GATTS:StartService,OK,A002 - - SSC SSC[2-5] bleadv -L -c 0 -t 3 - - R SSC[2-5] C +BLEADV:SetAdv,OK - - SSC SSC[2-5] bleadv -D -z start - - - R SSC[2-5] C +BLEADV:OK + - - R SSC[2-5] C +BLEADV:Start,OK - - SSC SSC1 blesmp -L -c 1 - - R SSC1 C +BLESMP:OK - - SSC SSC[2-5] blesmp -L -c 0 @@ -1267,14 +1322,99 @@ initial condition: - - R SSC1 C +GATTC:OK - - SSC SSC1 ram - - R SSC1 A :(\d+) -- tag: NOW1 +- tag: NOW_STAM1 + <<: *SSC_INIT_COND + initial condition detail: (SSC) DUT in sta mode and espnow is de-initialized + check cmd set: + - '' + - - SSC SSC1 op -Q + - - R SSC1 C +CURMODE:1 + - - SSC SSC1 sta -D + - - 'R SSC1 C +QAP:' + - - SSC SSC1 dhcp -Q -o 1 + - - R SSC1 C +DHCP:STA,STARTED + - - SSC SSC1 mac -Q -o 1 + - - R SSC1 P + - - SSC SSC1 espnow -D + - - 'R SSC1 C +ESPNOW:' + restore cmd set: + - '' + - - SSC SSC1 op -S -o 1 + - - R SSC1 C +MODE:OK + - - SSC SSC1 sta -D + - - 'R SSC1 C +QAP:' + - - SSC SSC1 dhcp -S -o 1 + - - R SSC1 C +DHCP + - - SSC SSC1 mac -S -o 1 -m + - - R SSC1 C +MAC:STA,OK + - - SSC SSC1 espnow -D + - - 'R SSC1 C +ESPNOW:' + force restore cmd set: + - '' + - - SSC SSC1 reboot + - - R SSC1 C !!!ready!!! + - - SSC SSC1 op -S -o 1 + - - R SSC1 C +MODE:OK + - - SSC SSC1 sta -D + - - 'R SSC1 C +QAP:' + - - SSC SSC1 dhcp -S -o 1 + - - R SSC1 C +DHCP + - - SSC SSC1 mac -S -o 1 -m + - - R SSC1 C +MAC:STA,OK + - - SSC SSC1 espnow -D + - - 'R SSC1 C +ESPNOW:' +- tag: NOW_STAM2 + <<: *SSC_INIT_COND + initial condition detail: (SSC) DUT in sta mode, join AP and espnow is de-initialized + check cmd set: + - '' + - - SSC SSC1 op -Q + - - R SSC1 C +CURMODE:1 + - - SSC SSC1 sta -Q + - - R SSC1 RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC1 dhcp -Q -o 1 + - - R SSC1 C +DHCP:STA,STARTED + - - SSC SSC1 mac -Q -o 1 + - - R SSC1 P + - - SSC SSC1 espnow -D + - - 'R SSC1 C +ESPNOW:' + restore cmd set: + - '' + - - SSC SSC1 op -S -o 1 + - - R SSC1 C +MODE:OK + - - SSC SSC1 dhcp -S -o 1 + - - R SSC1 C +DHCP + - - SSC SSC1 mac -S -o 1 -m + - - R SSC1 C +MAC:STA,OK + - - SSC SSC1 sta -C -s -p + - - R SSC1 RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC1 espnow -D + - - 'R SSC1 C +ESPNOW:' + force restore cmd set: + - '' + - - SSC SSC1 reboot + - - R SSC1 C !!!ready!!! + - - SSC SSC1 op -S -o 1 + - - R SSC1 C +MODE:OK + - - SSC SSC1 dhcp -S -o 1 + - - R SSC1 C +DHCP + - - SSC SSC1 mac -S -o 1 -m + - - R SSC1 C +MAC:STA,OK + - - SSC SSC1 sta -C -s -p + - - R SSC1 RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC1 espnow -D + - - 'R SSC1 C +ESPNOW:' +- tag: NOW_APM1 <<: *SSC_INIT_COND initial condition detail: (SSC) DUT1 in AP mode and espnow is de-initialized check cmd set: - '' - - *dut1_start_wifi - - SSC SSC1 op -Q - - R SSC1 C +CURMODE:2 + - - SSC SSC1 ap -Q + - - R SSC1 RE "\+APCONFIG:%%s,%%s,8,\d+,\d+,4,"%%(,) + - - SSC SSC1 dhcp -Q -o 2 + - - R SSC1 C +DHCP:AP,STARTED - - SSC SSC1 mac -Q -o 2 - - R SSC1 P - - SSC SSC1 espnow -D @@ -1283,79 +1423,284 @@ initial condition: - '' - - SSC SSC1 op -S -o 2 - - R SSC1 C +MODE:OK - - - SSC SSC1 mac -S -m -o 2 + - - SSC SSC1 dhcp -S -o 2 + - - R SSC1 C +DHCP + - - SSC SSC1 mac -S -o 2 -m - - R SSC1 C +MAC:AP,OK + - - SSC SSC1 ap -S -s -p -t -n 8 + - - R SSC1 C +SAP:OK - - SSC SSC1 espnow -D - - 'R SSC1 C +ESPNOW:' force restore cmd set: - '' - - - SSC SSC[1-] reboot - - - R SSC[1-] C !!!ready!!! + - - SSC SSC1 reboot + - - R SSC1 C !!!ready!!! - - SSC SSC1 op -S -o 2 - - R SSC1 C +MODE:OK - - - SSC SSC1 mac -S -m -o 2 + - - SSC SSC1 dhcp -S -o 2 + - - R SSC1 C +DHCP + - - SSC SSC1 mac -S -o 2 -m - - R SSC1 C +MAC:AP,OK + - - SSC SSC1 ap -S -s -p -t -n 8 + - - R SSC1 C +SAP:OK - - SSC SSC1 espnow -D - - 'R SSC1 C +ESPNOW:' - restore post cmd set: - - '' - - - SSC SSC1 ram - - - R SSC1 A :(\d+) -- tag: NOW2 +- tag: NOW_T2_STAM1 <<: *SSC_INIT_COND - initial condition detail: (SSC) multiple () DUTs in AP mode, espnow is initialized - with self role slave + initial condition detail: (SSC) two DUTs in sta mode, set same channel and espnow is de-initialized check cmd set: - '' - - *dut1_start_wifi - - - SSC SSC[1-] op -Q - - - R SSC[1-] C +CURMODE:2 - - - SSC SSC[1-] mac -Q -o 3 - - - R SSC[1-] P ]_ap_mac> P ]_mac> - - - SSC SSC[1-] espnow -D - - - 'R SSC[1-] C +ESPNOW:' - - - SSC SSC[1-] espnow -I - - - R SSC[1-] C +ESPNOW:OK - - - SSC SSC[1-] espnow -R -t Set -r 2 - - - R SSC[1-] C +ESPNOW:OK + - - SSC SSC[1,2] op -Q + - - R SSC[1,2] C +CURMODE:1 + - - SSC SSC[1,2] sta -D + - - 'R SSC[1,2] C +QAP:' + - - SSC SSC[1,2] channel -G + - - R SSC[1,2] C +CHANNEL:5 + - - SSC SSC[1,2] dhcp -Q -o 1 + - - R SSC[1,2] C +DHCP:STA,STARTED + - - SSC SSC[1,2] mac -Q -o 1 + - - R SSC[1,2] P + - *dut_init_espnow restore cmd set: - '' - - - SSC SSC[1-] op -S -o 3 - - - R SSC[1-] C +MODE:OK - - - SSC SSC[1-] mac -S -m ]_ap_mac> -o 2 - - - R SSC[1-] C +MAC:AP,OK - - - SSC SSC[1-] mac -S -m ]_mac> -o 1 - - - R SSC[1-] C +MAC:STA,OK - - - SSC SSC[1-] op -S -o 2 - - - R SSC[1-] C +MODE:OK - - - SSC SSC[1-] espnow -D - - - 'R SSC[1-] C +ESPNOW:' - - - SSC SSC[1-] espnow -I - - - R SSC[1-] C +ESPNOW:OK - - - SSC SSC[1-] espnow -R -t Set -r 2 - - - R SSC[1-] C +ESPNOW:OK + - - SSC SSC[1,2] op -S -o 1 + - - R SSC[1,2] C +MODE:OK + - - SSC SSC[1,2] sta -D + - - 'R SSC[1,2] C +QAP:' + - - SSC SSC[1,2] channel -S -c 5 + - - R SSC[1,2] C +CHANNEL:OK + - - SSC SSC[1,2] dhcp -S -o 1 + - - R SSC[1,2] C +DHCP + - - SSC SSC[1,2] mac -S -o 1 -m + - - R SSC[1,2] C +MAC:STA,OK + - *dut_init_espnow force restore cmd set: - '' - - - SSC SSC[1-] reboot - - - R SSC[1-] C !!!ready!!! - - - SSC SSC[1-] op -S -o 3 - - - R SSC[1-] C +MODE:OK - - - SSC SSC[1-] mac -S -m ]_ap_mac> -o 2 - - - R SSC[1-] C +MAC:AP,OK - - - SSC SSC[1-] mac -S -m ]_mac> -o 1 - - - R SSC[1-] C +MAC:STA,OK - - - SSC SSC[1-] op -S -o 2 - - - R SSC[1-] C +MODE:OK - - - SSC SSC[1-] espnow -D - - - 'R SSC[1-] C +ESPNOW:' - - - SSC SSC[1-] espnow -I - - - R SSC[1-] C +ESPNOW:OK - - - SSC SSC[1-] espnow -R -t Set -r 2 - - - R SSC[1-] C +ESPNOW:OK - restore post cmd set: + - - SSC SSC[1,2] reboot + - - R SSC[1,2] C !!!ready!!! + - - SSC SSC[1,2] op -S -o 1 + - - R SSC[1,2] C +MODE:OK + - - SSC SSC[1,2] sta -D + - - 'R SSC[1,2] C +QAP:' + - - SSC SSC[1,2] channel -S -c 5 + - - R SSC[1,2] C +CHANNEL:OK + - - SSC SSC[1,2] dhcp -S -o 1 + - - R SSC[1,2] C +DHCP + - - SSC SSC[1,2] mac -S -o 1 -m + - - R SSC[1,2] C +MAC:STA,OK + - *dut_init_espnow +- tag: NOW_T2_STAM2 + <<: *SSC_INIT_COND + initial condition detail: (SSC) one DUT in sta mode, one DUT in softap mode, station joins softap and espnow is de-initialized + check cmd set: - '' - - - SSC SSC1 ram - - - R SSC1 A :(\d+) + - - SSC SSC1 op -Q + - - R SSC1 C +CURMODE:1 + - - SSC SSC2 op -Q + - - R SSC2 C +CURMODE:2 + - - SSC SSC2 ap -Q + - - R SSC2 RE "\+APCONFIG:%%s,%%s,8,\d+,\d+,4,"%%(,) + - - SSC SSC1 sta -Q + - - R SSC1 RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC1 dhcp -Q -o 1 + - - R SSC1 C +DHCP:STA,STARTED + - - SSC SSC2 dhcp -Q -o 2 + - - R SSC2 C +DHCP:AP,STARTED + - - SSC SSC1 mac -Q -o 1 + - - R SSC1 P + - - SSC SSC2 mac -Q -o 2 + - - R SSC2 P + - *dut_init_espnow + restore cmd set: + - '' + - - SSC SSC1 op -S -o 1 + - - R SSC1 C +MODE:OK + - - SSC SSC2 op -S -o 2 + - - R SSC2 C +MODE:OK + - - SSC SSC[1,2] dhcp -S -o [1,2] + - - R SSC[1,2] C +DHCP + - - SSC SSC1 mac -S -o 1 -m + - - R SSC1 C +MAC:STA,OK + - - SSC SSC2 mac -S -o 2 -m + - - R SSC2 C +MAC:AP,OK + - - SSC SSC2 ap -S -s -p -t -n 8 + - - R SSC2 C +SAP:OK + - - SSC SSC1 sta -C -s -p + - - R SSC1 RE "\+JAP:CONNECTED,%%s"%%() + - *dut_init_espnow + force restore cmd set: + - '' + - - SSC SSC[1-2] reboot + - - R SSC[1-2] C !!!ready!!! + - - SSC SSC[1-2] op -S -o [1,2] + - - R SSC[1-2] C +MODE:OK + - - SSC SSC[1,2] dhcp -S -o [1,2] + - - R SSC[1,2] C +DHCP + - - SSC SSC1 mac -S -o 1 -m + - - R SSC1 C +MAC:STA,OK + - - SSC SSC2 mac -S -o 2 -m + - - R SSC2 C +MAC:AP,OK + - - SSC SSC2 ap -S -s -p -t -n 8 + - - R SSC2 C +SAP:OK + - - SSC SSC1 sta -C -s -p + - - R SSC1 RE "\+JAP:CONNECTED,%%s"%%() + - *dut_init_espnow +- tag: NOW_T2_APM1 + <<: *SSC_INIT_COND + initial condition detail: (SSC) 2 DUTs in softap mode, set same channel and espnow is de-initialized + check cmd set: + - '' + - - SSC SSC[1,2] op -Q + - - R SSC[1,2] C +CURMODE:2 + - - SSC SSC[1,2] ap -Q + - - R SSC[1,2] RE "\+APCONFIG:%%s,%%s,2,\d+,\d+,4,"%%(,) + - - SSC SSC[1,2] dhcp -Q -o 2 + - - R SSC[1,2] C +DHCP:AP,STARTED + - - SSC SSC[1,2] mac -Q -o 2 + - - R SSC[1,2] P + - *dut_init_espnow + restore cmd set: + - '' + - - SSC SSC[1,2] op -S -o 2 + - - R SSC[1,2] C +MODE:OK + - - SSC SSC[1,2] dhcp -S -o 2 + - - R SSC[1,2] C +DHCP + - - SSC SSC[1,2] mac -S -o 2 -m + - - R SSC[1,2] C +MAC:AP,OK + - - SSC SSC[1,2] ap -S -s -p -t -n 2 + - - R SSC[1,2] C +SAP:OK + - *dut_init_espnow + force restore cmd set: + - '' + - - SSC SSC[1,2] reboot + - - R SSC[1,2] C !!!ready!!! + - - SSC SSC[1,2] op -S -o 2 + - - R SSC[1,2] C +MODE:OK + - - SSC SSC[1,2] dhcp -S -o 2 + - - R SSC[1,2] C +DHCP + - - SSC SSC[1,2] mac -S -o 2 -m + - - R SSC[1,2] C +MAC:AP,OK + - - SSC SSC[1,2] ap -S -s -p -t -n 2 + - - R SSC[1,2] C +SAP:OK + - *dut_init_espnow +- tag: NOW_T2_STAAP1 + <<: *SSC_INIT_COND + initial condition detail: (SSC) two DUTs in sta + ap mode, set same channel and espnow is de-initialized + check cmd set: + - '' + - - SSC SSC[1,2] op -Q + - - R SSC[1,2] C +CURMODE:3 + - - SSC SSC[1,2] sta -D + - - 'R SSC[1,2] C +QAP:' + - - SSC SSC[1,2] ap -Q + - - R SSC[1,2] RE "\+APCONFIG:%%s,%%s,8,\d+,\d+,4,"%%(,) + - - SSC SSC[1,2] dhcp -Q -o 1 + - - R SSC[1,2] C +DHCP:STA,STARTED + - - SSC SSC[1,2] dhcp -Q -o 2 + - - R SSC[1,2] C +DHCP:AP,STARTED + - - SSC SSC[1,2] mac -Q -o 1 + - - R SSC[1,2] P + - - SSC SSC[1,2] mac -Q -o 2 + - - R SSC[1,2] P + - *dut_init_espnow + restore cmd set: + - '' + - - SSC SSC[1,2] op -S -o 3 + - - R SSC[1,2] C +MODE:OK + - - SSC SSC[1,2] sta -D + - - 'R SSC[1,2] C +QAP:' + - - SSC SSC[1,2] dhcp -S -o 1 + - - R SSC[1,2] C +DHCP + - - SSC SSC[1,2] dhcp -S -o 2 + - - R SSC[1,2] C +DHCP + - - SSC SSC[1,2] mac -S -o 1 -m + - - R SSC[1,2] C +MAC:STA,OK + - - SSC SSC[1,2] mac -S -o 2 -m + - - R SSC[1,2] C +MAC:AP,OK + - - SSC SSC[1,2] ap -S -s -p -t -n 8 + - - R SSC[1,2] C +SAP:OK + - *dut_init_espnow + force restore cmd set: + - '' + - - SSC SSC[1,2] reboot + - - R SSC[1,2] C !!!ready!!! + - - SSC SSC[1,2] op -S -o 3 + - - R SSC[1,2] C +MODE:OK + - - SSC SSC[1,2] sta -D + - - 'R SSC[1,2] C +QAP:' + - - SSC SSC[1,2] dhcp -S -o 1 + - - R SSC[1,2] C +DHCP + - - SSC SSC[1,2] dhcp -S -o 2 + - - R SSC[1,2] C +DHCP + - - SSC SSC[1,2] mac -S -o 1 -m + - - R SSC[1,2] C +MAC:STA,OK + - - SSC SSC[1,2] mac -S -o 2 -m + - - R SSC[1,2] C +MAC:AP,OK + - - SSC SSC[1,2] ap -S -s -p -t -n 8 + - - R SSC[1,2] C +SAP:OK + - *dut_init_espnow +- tag: NOW_T2_STAAP2 + <<: *SSC_INIT_COND + initial condition detail: (SSC) one DUT in softap mode, one DUT in sta + softap mode, station join softap and espnow is de-initialized + check cmd set: + - '' + - - SSC SSC[1,2] op -Q + - - R SSC[1,2] C +CURMODE:3 + - - SSC SSC2 ap -Q + - - R SSC2 RE "\+APCONFIG:%%s,%%s,8,\d+,\d+,4,"%%(,) + - - SSC SSC1 sta -Q + - - R SSC1 RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC1 dhcp -Q -o 1 + - - R SSC1 C +DHCP:STA,STARTED + - - SSC SSC2 dhcp -Q -o 2 + - - R SSC2 C +DHCP:AP,STARTED + - - SSC SSC1 mac -Q -o 1 + - - R SSC1 P + - - SSC SSC2 mac -Q -o 2 + - - R SSC2 P + - - SSC SSC2 sta -D + - - 'R SSC2 C +QAP:' + - *dut_init_espnow + restore cmd set: + - '' + - - SSC SSC[1,2] op -S -o 3 + - - R SSC[1,2] C +MODE:OK + - - SSC SSC1 dhcp -S -o 1 + - - R SSC1 C +DHCP + - - SSC SSC2 dhcp -S -o 2 + - - R SSC2 C +DHCP + - - SSC SSC1 mac -S -o 1 -m + - - R SSC1 C +MAC:STA,OK + - - SSC SSC2 mac -S -o 2 -m + - - R SSC2 C +MAC:AP,OK + - - SSC SSC2 ap -S -s -p -t -n 8 + - - R SSC2 C +SAP:OK + - - SSC SSC1 sta -C -s -p + - - R SSC1 RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC2 sta -D + - - 'R SSC2 C +QAP:' + - *dut_init_espnow + force restore cmd set: + - '' + - - SSC SSC[1,2] reboot + - - R SSC[1,2] C !!!ready!!! + - - SSC SSC[1,2] op -S -o 3 + - - R SSC[1,2] C +MODE:OK + - - SSC SSC1 dhcp -S -o 1 + - - R SSC1 C +DHCP + - - SSC SSC2 dhcp -S -o 2 + - - R SSC2 C +DHCP + - - SSC SSC1 mac -S -o 1 -m + - - R SSC1 C +MAC:STA,OK + - - SSC SSC2 mac -S -o 2 -m + - - R SSC2 C +MAC:AP,OK + - - SSC SSC2 ap -S -s -p -t -n 8 + - - R SSC2 C +SAP:OK + - - SSC SSC1 sta -C -s -p + - - R SSC1 RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC2 sta -D + - - 'R SSC2 C +QAP:' + - *dut_init_espnow - tag: None <<: *SSC_INIT_COND initial condition detail: (SSC) do nothing @@ -1630,6 +1975,53 @@ initial condition: - - R SSC1 C +MAC:STA,OK - - SSC SSC1 sta -C -s -p - - R SSC1 RE "\+JAP:CONNECTED,%%s"%%() +- tag: STAM2_MDNS + <<: *SSC_INIT_COND + initial condition detail: (SSC) DUT set to STA mode, connected with AP, restart MDNS + check cmd set: + - '' + - - SSC SSC1 op -Q + - - R SSC1 C +CURMODE:1 + - - SSC SSC1 sta -Q + - - R SSC1 RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC1 dhcp -Q -o 1 + - - R SSC1 C +DHCP:STA,STARTED + - - SSC SSC1 mac -Q -o 1 + - - R SSC1 P + - - SSC SSC1 mdns -T + - - R SSC1 C +MDNS:OK + - - SSC SSC1 mdns -I + - - R SSC1 C +MDNS:OK + restore cmd set: + - '' + - - SSC SSC1 op -S -o 1 + - - R SSC1 C +MODE:OK + - - SSC SSC1 dhcp -S -o 1 + - - R SSC1 C +DHCP + - - SSC SSC1 mac -S -o 1 -m + - - R SSC1 C +MAC:STA,OK + - - SSC SSC1 sta -C -s -p + - - R SSC1 RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC1 mdns -T + - - R SSC1 C +MDNS:OK + - - SSC SSC1 mdns -I + - - R SSC1 C +MDNS:OK + force restore cmd set: + - '' + - - SSC SSC1 reboot + - - R SSC1 C !!!ready!!! + - - SSC SSC1 op -S -o 1 + - - R SSC1 C +MODE:OK + - - SSC SSC1 dhcp -S -o 1 + - - R SSC1 C +DHCP + - - SSC SSC1 mac -S -o 1 -m + - - R SSC1 C +MAC:STA,OK + - - SSC SSC1 sta -C -s -p + - - R SSC1 RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC1 mdns -T + - - R SSC1 C +MDNS:OK + - - SSC SSC1 mdns -I + - - R SSC1 C +MDNS:OK - tag: STAO1 <<: *SSC_INIT_COND initial condition detail: (SSC) DUT set to STA mode, disconnected from AP, enable DHCP client @@ -1919,6 +2311,246 @@ initial condition: - - R SSC1 C +MAC:AP,OK - - SSC SSC2 mac -S -o 1 -m - - R SSC2 C +MAC:STA,OK +- tag: T2_3 + <<: *SSC_INIT_COND + initial condition detail: (SSC) DUT1 set to STA+SoftAP mode, DUT2 set to STA+SoftAP mode + check cmd set: + - '' + - - SSC SSC1 op -Q + - - R SSC1 C +CURMODE:2 + - - SSC SSC2 op -Q + - - R SSC2 C +CURMODE:3 + - - SSC SSC2 sta -D + - - 'R SSC2 C +QAP:' + - - SSC SSC2 soc -T + - - R SSC2 C +CLOSEALL + - - SSC SSC1 dhcp -Q -o 2 + - - R SSC1 C +DHCP:AP,STARTED + - - SSC SSC2 dhcp -Q -o 1 + - - R SSC2 C +DHCP:STA,STARTED + - - SSC SSC1 mac -Q -o 2 + - - R SSC1 P + - - SSC SSC2 mac -Q -o 1 + - - R SSC2 P + restore cmd set: + - '' + - - SSC SSC1 op -S -o 2 + - - R SSC1 C +MODE:OK + - - SSC SSC2 op -S -o 3 + - - R SSC2 C +MODE:OK + - - SSC SSC2 sta -D + - - 'R SSC2 C +QAP:' + - - SSC SSC2 soc -T + - - R SSC2 C +CLOSEALL + - - SSC SSC1 dhcp -S -o 2 + - - R SSC1 C +DHCP + - - SSC SSC2 dhcp -S -o 1 + - - R SSC2 C +DHCP + - - SSC SSC1 mac -S -o 2 -m + - - R SSC1 C +MAC:AP,OK + - - SSC SSC2 mac -S -o 1 -m + - - R SSC2 C +MAC:STA,OK + force restore cmd set: + - '' + - - SSC SSC1 reboot + - - R SSC1 C !!!ready!!! + - - SSC SSC2 reboot + - - R SSC2 C !!!ready!!! + - - SSC SSC1 op -S -o 2 + - - R SSC1 C +MODE:OK + - - SSC SSC2 op -S -o 3 + - - R SSC2 C +MODE:OK + - - SSC SSC2 sta -D + - - 'R SSC2 C +QAP:' + - - SSC SSC2 soc -T + - - R SSC2 C +CLOSEALL + - - SSC SSC1 dhcp -S -o 2 + - - R SSC1 C +DHCP + - - SSC SSC2 dhcp -S -o 1 + - - R SSC2 C +DHCP + - - SSC SSC1 mac -S -o 2 -m + - - R SSC1 C +MAC:AP,OK + - - SSC SSC2 mac -S -o 1 -m + - - R SSC2 C +MAC:STA,OK +- tag: T2_MDNS + <<: *SSC_INIT_COND + initial condition detail: (SSC) Both DUT set to STA mode, connected with AP, restart MDNS + check cmd set: + - '' + - - SSC SSC[1-2] op -Q + - - R SSC[1-2] C+CURMODE:1 + - - SSC SSC[1-2] sta -Q + - - R SSC[1-2] RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC[1-2] dhcp -Q -o 1 + - - R SSC[1-2] C +DHCP:STA,STARTED + - - SSC SSC1 mac -Q -o 1 + - - R SSC1 P + - - SSC SSC2 mac -Q -o 1 + - - R SSC2 P + - - SSC SSC[1-2] mdns -T + - - R SSC[1-2] C +MDNS:OK + - - SSC SSC[1-2] mdns -I + - - R SSC[1-2] C +MDNS:OK + restore cmd set: + - '' + - - SSC SSC[1-2] op -S -o [1,1] + - - R SSC[1-2] C +MODE:OK + - - SSC SSC[1-2] dhcp -S -o 1 + - - R SSC[1-2] C +DHCP + - - SSC SSC1 mac -S -o 1 -m + - - R SSC1 C +MAC:STA,OK + - - SSC SSC2 mac -S -o 1 -m + - - R SSC2 C +MAC:STA,OK + - - SSC SSC[1-2] sta -C -s -p + - - R SSC[1-2] RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC[1-2] mdns -T + - - R SSC[1-2] C +MDNS:OK + - - SSC SSC[1-2] mdns -I + - - R SSC[1-2] C +MDNS:OK + force restore cmd set: + - '' + - - SSC SSC[1-2] reboot + - - R SSC[1-2] C !!!ready!!! + - - SSC SSC[1-2] op -S -o 1 + - - R SSC[1-2] C +MODE:OK + - - SSC SSC[1-2] dhcp -S -o 1 + - - R SSC[1-2] C +DHCP + - - SSC SSC1 mac -S -o 1 -m + - - R SSC1 C +MAC:STA,OK + - - SSC SSC2 mac -S -o 1 -m + - - R SSC2 C +MAC:STA,OK + - - SSC SSC[1-2] sta -C -s -p + - - R SSC[1-2] RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC[1-2] mdns -T + - - R SSC[1-2] C +MDNS:OK + - - SSC SSC[1-2] mdns -I + - - R SSC[1-2] C +MDNS:OK +- tag: T2_MDNS_MODE1 + <<: *SSC_INIT_COND + initial condition detail: (SSC) DUT1 set to STA mode, DUT2 set to SoftAP mode, DUT1 connected with DUT2, restart MDNS + check cmd set: + - '' + - - SSC SSC1 op -Q + - - R SSC1 C+CURMODE:1 + - - SSC SSC2 op -Q + - - R SSC2 C+CURMODE:2 + - - SSC SSC1 sta -Q + - - R SSC1 RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC2 ap -Q + - - R SSC2 RE "\+APCONFIG:%%s,%%s,7,\d+,\d+,4,"%%(,) + - - SSC SSC1 dhcp -Q -o 1 + - - R SSC1 C +DHCP:STA,STARTED + - - SSC SSC2 dhcp -Q -o 2 + - - R SSC2 C +DHCP:AP,STARTED + - - SSC SSC1 mac -Q -o 1 + - - R SSC1 P + - - SSC SSC2 mac -Q -o 2 + - - R SSC2 P + - - SSC SSC[1-2] mdns -T + - - R SSC[1-2] C +MDNS:OK + - - SSC SSC[1-2] mdns -I + - - R SSC[1-2] C +MDNS:OK + restore cmd set: + - '' + - - SSC SSC[1-2] op -S -o [1,2] + - - R SSC[1-2] C +MODE:OK + - - SSC SSC[1-2] dhcp -S -o [1,2] + - - R SSC[1-2] C +DHCP + - - SSC SSC1 mac -S -o 1 -m + - - R SSC1 C +MAC:STA,OK + - - SSC SSC2 mac -S -o 2 -m + - - R SSC2 C +MAC:AP,OK + - - SSC SSC2 ap -S -s -p -t -n 7 + - - R SSC2 C +SAP:OK + - - SSC SSC1 sta -C -s -p + - - R SSC1 RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC[1-2] mdns -T + - - R SSC[1-2] C +MDNS:OK + - - SSC SSC[1-2] mdns -I + - - R SSC[1-2] C +MDNS:OK + force restore cmd set: + - '' + - - SSC SSC[1-2] reboot + - - R SSC[1-2] C !!!ready!!! + - - SSC SSC[1-2] op -S -o [1,2] + - - R SSC[1-2] C +MODE:OK + - - SSC SSC[1-2] dhcp -S -o [1,2] + - - R SSC[1-2] C +DHCP + - - SSC SSC1 mac -S -o 1 -m + - - R SSC1 C +MAC:STA,OK + - - SSC SSC2 mac -S -o 2 -m + - - R SSC2 C +MAC:AP,OK + - - SSC SSC2 ap -S -s -p -t -n 7 + - - R SSC2 C +SAP:OK + - - SSC SSC1 sta -C -s -p + - - R SSC1 RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC[1-2] mdns -T + - - R SSC[1-2] C +MDNS:OK + - - SSC SSC[1-2] mdns -I + - - R SSC[1-2] C +MDNS:OK +- tag: T2_MDNS_MODE2 + <<: *SSC_INIT_COND + initial condition detail: (SSC) DUT1 set to SoftAP mode, DUT2 set to STA mode, DUT1 connected with DUT2, restart MDNS + check cmd set: + - '' + - - SSC SSC1 op -Q + - - R SSC1 C+CURMODE:2 + - - SSC SSC2 op -Q + - - R SSC2 C+CURMODE:1 + - - SSC SSC1 ap -Q + - - R SSC1 RE "\+APCONFIG:%%s,%%s,7,\d+,\d+,4,"%%(,) + - - SSC SSC2 sta -Q + - - R SSC2 RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC1 dhcp -Q -o 2 + - - R SSC1 C +DHCP:AP,STARTED + - - SSC SSC2 dhcp -Q -o 1 + - - R SSC2 C +DHCP:STA,STARTED + - - SSC SSC1 mac -Q -o 2 + - - R SSC1 P + - - SSC SSC2 mac -Q -o 1 + - - R SSC2 P + - - SSC SSC[1-2] mdns -T + - - R SSC[1-2] C +MDNS:OK + - - SSC SSC[1-2] mdns -I + - - R SSC[1-2] C +MDNS:OK + restore cmd set: + - '' + - - SSC SSC[1-2] op -S -o [2,1] + - - R SSC[1-2] C +MODE:OK + - - SSC SSC[1-2] dhcp -S -o [2,1] + - - R SSC[1-2] C +DHCP + - - SSC SSC1 mac -S -o 2 -m + - - R SSC1 C +MAC:AP,OK + - - SSC SSC2 mac -S -o 1 -m + - - R SSC2 C +MAC:STA,OK + - - SSC SSC1 ap -S -s -p -t -n 7 + - - R SSC1 C +SAP:OK + - - SSC SSC2 sta -C -s -p + - - R SSC2 RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC[1-2] mdns -T + - - R SSC[1-2] C +MDNS:OK + - - SSC SSC[1-2] mdns -I + - - R SSC[1-2] C +MDNS:OK + force restore cmd set: + - '' + - - SSC SSC[1-2] reboot + - - R SSC[1-2] C !!!ready!!! + - - SSC SSC[1-2] op -S -o [2,1] + - - R SSC[1-2] C +MODE:OK + - - SSC SSC[1-2] dhcp -S -o [2,1] + - - R SSC[1-2] C +DHCP + - - SSC SSC1 mac -S -o 2 -m + - - R SSC1 C +MAC:AP,OK + - - SSC SSC2 mac -S -o 1 -m + - - R SSC2 C +MAC:STA,OK + - - SSC SSC1 ap -S -s -p -t -n 7 + - - R SSC1 C +SAP:OK + - - SSC SSC2 sta -C -s -p + - - R SSC2 RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC[1-2] mdns -T + - - R SSC[1-2] C +MDNS:OK + - - SSC SSC[1-2] mdns -I + - - R SSC[1-2] C +MDNS:OK - tag: T3_1 <<: *SSC_INIT_COND initial condition detail: (SSC) DUT1 set to STA+SoftAP mode, DUT2 and DUT3 set to STA mode @@ -1970,6 +2602,376 @@ initial condition: - - R SSC2 C +MAC:STA,OK - - SSC SSC3 mac -S -o 1 -m - - R SSC3 C +MAC:STA,OK +- tag: T3_2 + <<: *SSC_INIT_COND + initial condition detail: (SSC) DUT1 set to SoftAP mode, DUT2 as STA mode + check cmd set: + - '' + - - SSC SSC1 op -Q + - - R SSC1 C +CURMODE:2 + - - SSC SSC2 op -Q + - - R SSC2 C +CURMODE:1 + - - SSC SSC3 op -Q + - - R SSC3 C +CURMODE:2 + - - SSC SSC2 sta -D + - - 'R SSC2 C +QAP:' + - - SSC SSC2 soc -T + - - '' + - - SSC SSC1 dhcp -Q -o 2 + - - R SSC1 C +DHCP:AP,STARTED + - - SSC SSC2 dhcp -Q -o 1 + - - R SSC2 C +DHCP:STA,STARTED + - - SSC SSC3 dhcp -Q -o 2 + - - R SSC3 C +DHCP:AP,STARTED + - - SSC SSC1 mac -Q -o 2 + - - R SSC1 P + - - SSC SSC2 mac -Q -o 1 + - - R SSC2 P + - - SSC SSC3 mac -Q -o 2 + - - R SSC3 P + restore cmd set: + - '' + - - SSC SSC[1-3] op -S -o [2,1,2] + - - R SSC[1-3] C +MODE:OK + - - SSC SSC2 sta -D + - - 'R SSC2 C +QAP:' + - - SSC SSC2 soc -T + - - '' + - - SSC SSC[1-3] dhcp -S -o [2,1,2] + - - R SSC[1-3] C +DHCP + - - SSC SSC1 mac -S -o 2 -m + - - R SSC1 C +MAC:AP,OK + - - SSC SSC2 mac -S -o 1 -m + - - R SSC2 C +MAC:STA,OK + - - SSC SSC3 mac -S -o 2 -m + - - R SSC3 C +MAC:AP,OK + force restore cmd set: + - '' + - - SSC SSC[1-3] reboot + - - R SSC[1-3] C !!!ready!!! + - - SSC SSC[1-3] op -S -o [2,1,2] + - - R SSC[1-3] C +MODE:OK + - - SSC SSC2 sta -D + - - 'R SSC2 C +QAP:' + - - SSC SSC2 soc -T + - - '' + - - SSC SSC[1-3] dhcp -S -o [2,1,2] + - - R SSC[1-3] C +DHCP + - - SSC SSC1 mac -S -o 2 -m + - - R SSC1 C +MAC:AP,OK + - - SSC SSC2 mac -S -o 1 -m + - - R SSC2 C +MAC:STA,OK + - - SSC SSC3 mac -S -o 2 -m + - - R SSC3 C +MAC:AP,OK +- tag: T3_3 + <<: *SSC_INIT_COND + initial condition detail: (SSC) DUT1 set to SoftAp mode, DUT2-3 set to STA mode + check cmd set: + - '' + - - SSC SSC[1,2,3] op -Q + - - R SSC[1,2,3] C +CURMODE:[2,1,1] + - - SSC SSC[2,3] sta -D + - - 'R SSC[2,3] C +QAP:' + restore cmd set: + - '' + - - SSC SSC[1,2,3] op -S -o [2,1,1] + - - R SSC[1,2,3] C +MODE:OK + - - SSC SSC[2,3] sta -D + - - 'R SSC[2,3] C +QAP:' + force restore cmd set: + - '' + - - SSC SSC[1,2,3] reboot + - - R SSC[1,2,3] C !!!ready!!! + - - SSC SSC[1,2,3] op -S -o [2,1,1] + - - R SSC[1,2,3] C +MODE:OK + - - SSC SSC[2,3] sta -D + - - 'R SSC[2,3] C +QAP:' +- tag: T3_MDNS + <<: *SSC_INIT_COND + initial condition detail: (SSC) All 3 DUTs set to STA mode, connected with AP, restart MDNS + check cmd set: + - '' + - - SSC SSC[1-3] op -Q + - - R SSC[1-3] C +CURMODE:1 + - - SSC SSC[1-3] sta -Q + - - R SSC[1-3] RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC[1-3] dhcp -Q -o 1 + - - R SSC[1-3] C +DHCP:STA,STARTED + - - SSC SSC1 mac -Q -o 1 + - - R SSC1 P + - - SSC SSC2 mac -Q -o 1 + - - R SSC2 P + - - SSC SSC3 mac -Q -o 1 + - - R SSC3 P + - - SSC SSC[1-3] mdns -T + - - R SSC[1-3] C +MDNS:OK + - - SSC SSC[1-3] mdns -I + - - R SSC[1-3] C +MDNS:OK + restore cmd set: + - '' + - - SSC SSC[1-3] op -S -o 1 + - - R SSC[1-3] C +MODE:OK + - - SSC SSC[1-3] dhcp -S -o 1 + - - R SSC[1-3] C +DHCP + - - SSC SSC1 mac -S -o 1 -m + - - R SSC1 C +MAC:STA,OK + - - SSC SSC2 mac -S -o 1 -m + - - R SSC2 C +MAC:STA,OK + - - SSC SSC3 mac -S -o 1 -m + - - R SSC3 C +MAC:STA,OK + - - SSC SSC[1-3] sta -C -s -p + - - R SSC[1-3] RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC[1-3] mdns -T + - - R SSC[1-3] C +MDNS:OK + - - SSC SSC[1-3] mdns -I + - - R SSC[1-3] C +MDNS:OK + force restore cmd set: + - '' + - - SSC SSC[1-3] reboot + - - R SSC[1-3] C !!!ready!!! + - - SSC SSC[1-3] op -S -o 1 + - - R SSC[1-3] C +MODE:OK + - - SSC SSC[1-3] dhcp -S -o 1 + - - R SSC[1-3] C +DHCP + - - SSC SSC1 mac -S -o 1 -m + - - R SSC1 C +MAC:STA,OK + - - SSC SSC2 mac -S -o 1 -m + - - R SSC2 C +MAC:STA,OK + - - SSC SSC3 mac -S -o 1 -m + - - R SSC3 C +MAC:STA,OK + - - SSC SSC[1-3] sta -C -s -p + - - R SSC[1-3] RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC[1-3] mdns -T + - - R SSC[1-3] C +MDNS:OK + - - SSC SSC[1-3] mdns -I + - - R SSC[1-3] C +MDNS:OK +- tag: T3_MDNS_MODE1 + <<: *SSC_INIT_COND + initial condition detail: (SSC) DUT1 and DUT2 set to STA mode, DUT3 set to SoftAP mode, DUT1 and DUT2 connected with DUT3, restart MDNS on all DUTs + check cmd set: + - '' + - - SSC SSC[1-2] op -Q + - - R SSC[1-2] C +CURMODE:1 + - - SSC SSC3 op -Q + - - R SSC3 C +CURMODE:2 + - - SSC SSC[1-2] sta -Q + - - R SSC[1-2] RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC3 ap -Q + - - R SSC3 RE "\+APCONFIG:%%s,%%s,7,\d+,\d+,4,"%%(,) + - - SSC SSC[1-2] dhcp -Q -o 1 + - - R SSC[1-2] C +DHCP:STA,STARTED + - - SSC SSC3 dhcp -Q -o 2 + - - R SSC3 C +DHCP:AP,STARTED + - - SSC SSC1 mac -Q -o 1 + - - R SSC1 P + - - SSC SSC2 mac -Q -o 1 + - - R SSC2 P + - - SSC SSC3 mac -Q -o 2 + - - R SSC3 P + - - SSC SSC[1-3] mdns -T + - - R SSC[1-3] C +MDNS:OK + - - SSC SSC[1-3] mdns -I + - - R SSC[1-3] C +MDNS:OK + restore cmd set: + - '' + - - SSC SSC[1-3] op -S -o [1,1,2] + - - R SSC[1-3] C +MODE:OK + - - SSC SSC[1-3] dhcp -S -o [1,1,2] + - - R SSC[1-3] C +DHCP + - - SSC SSC1 mac -S -o 1 -m + - - R SSC1 C +MAC:STA,OK + - - SSC SSC2 mac -S -o 1 -m + - - R SSC2 C +MAC:STA,OK + - - SSC SSC3 mac -S -o 2 -m + - - R SSC3 C +MAC:AP,OK + - - SSC SSC3 ap -S -s -p -t -n 7 + - - R SSC3 C +SAP:OK + - - SSC SSC[1-2] sta -C -s -p + - - R SSC[1-2] RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC[1-3] mdns -T + - - R SSC[1-3] C +MDNS:OK + - - SSC SSC[1-3] mdns -I + - - R SSC[1-3] C +MDNS:OK + force restore cmd set: + - '' + - - SSC SSC[1-3] reboot + - - R SSC[1-3] C !!!ready!!! + - - SSC SSC[1-3] op -S -o [1,1,2] + - - R SSC[1-3] C +MODE:OK + - - SSC SSC[1-3] dhcp -S -o [1,1,2] + - - R SSC[1-3] C +DHCP + - - SSC SSC1 mac -S -o 1 -m + - - R SSC1 C +MAC:STA,OK + - - SSC SSC2 mac -S -o 1 -m + - - R SSC2 C +MAC:STA,OK + - - SSC SSC3 mac -S -o 2 -m + - - R SSC3 C +MAC:AP,OK + - - SSC SSC3 ap -S -s -p -t -n 7 + - - R SSC3 C +SAP:OK + - - SSC SSC[1-2] sta -C -s -p + - - R SSC[1-2] RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC[1-3] mdns -T + - - R SSC[1-3] C +MDNS:OK + - - SSC SSC[1-3] mdns -I + - - R SSC[1-3] C +MDNS:OK +- tag: T3_MDNS_MODE2 + <<: *SSC_INIT_COND + initial condition detail: (SSC) DUT1 and DUT3 set to STA mode, DUT2 set to SoftAP mode, DUT1 and DUT3 connected with DUT2, restart MDNS on all DUTs + check cmd set: + - '' + - - SSC SSC1 op -Q + - - R SSC1 C +CURMODE:1 + - - SSC SSC2 op -Q + - - R SSC2 C +CURMODE:2 + - - SSC SSC3 op -Q + - - R SSC3 C +CURMODE:1 + - - SSC SSC1 sta -Q + - - R SSC1 RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC2 ap -Q + - - R SSC2 RE "\+APCONFIG:%%s,%%s,7,\d+,\d+,4,"%%(,) + - - SSC SSC3 sta -Q + - - R SSC3 RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC1 dhcp -Q -o 1 + - - R SSC1 C +DHCP:STA,STARTED + - - SSC SSC2 dhcp -Q -o 2 + - - R SSC2 C +DHCP:AP,STARTED + - - SSC SSC3 dhcp -Q -o 1 + - - R SSC3 C +DHCP:STA,STARTED + - - SSC SSC1 mac -Q -o 1 + - - R SSC1 P + - - SSC SSC2 mac -Q -o 2 + - - R SSC2 P + - - SSC SSC3 mac -Q -o 1 + - - R SSC3 P + - - SSC SSC[1-3] mdns -T + - - R SSC[1-3] C +MDNS:OK + - - SSC SSC[1-3] mdns -I + - - R SSC[1-3] C +MDNS:OK + restore cmd set: + - '' + - - SSC SSC[1-3] op -S -o [1,2,1] + - - R SSC[1-3] C +MODE:OK + - - SSC SSC[1-3] dhcp -S -o [1,2,1] + - - R SSC[1-3] C +DHCP + - - SSC SSC1 mac -S -o 1 -m + - - R SSC1 C +MAC:STA,OK + - - SSC SSC2 mac -S -o 2 -m + - - R SSC2 C +MAC:AP,OK + - - SSC SSC3 mac -S -o 1 -m + - - R SSC3 C +MAC:STA,OK + - - SSC SSC2 ap -S -s -p -t -n 7 + - - R SSC2 C +SAP:OK + - - SSC SSC1 sta -C -s -p + - - R SSC1 RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC3 sta -C -s -p + - - R SSC3 RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC[1-3] mdns -T + - - R SSC[1-3] C +MDNS:OK + - - SSC SSC[1-3] mdns -I + - - R SSC[1-3] C +MDNS:OK + force restore cmd set: + - '' + - - SSC SSC[1-3] reboot + - - R SSC[1-3] C !!!ready!!! + - - SSC SSC[1-3] op -S -o [1,2,1] + - - R SSC[1-3] C +MODE:OK + - - SSC SSC[1-3] dhcp -S -o [1,2,1] + - - R SSC[1-3] C +DHCP + - - SSC SSC1 mac -S -o 1 -m + - - R SSC1 C +MAC:STA,OK + - - SSC SSC2 mac -S -o 2 -m + - - R SSC2 C +MAC:AP,OK + - - SSC SSC3 mac -S -o 1 -m + - - R SSC3 C +MAC:STA,OK + - - SSC SSC2 ap -S -s -p -t -n 7 + - - R SSC2 C +SAP:OK + - - SSC SSC1 sta -C -s -p + - - R SSC1 RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC3 sta -C -s -p + - - R SSC3 RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC[1-3] mdns -T + - - R SSC[1-3] C +MDNS:OK + - - SSC SSC[1-3] mdns -I + - - R SSC[1-3] C +MDNS:OK +- tag: T3_MDNS_MODE3 + <<: *SSC_INIT_COND + initial condition detail: softap + sta + sta mode, sta join softap, DHCP on, mdns stop + check cmd set: + - '' + - - SSC SSC1 op -Q + - - R SSC1 C +CURMODE:2 + - - SSC SSC2 op -Q + - - R SSC2 C +CURMODE:1 + - - SSC SSC3 op -Q + - - R SSC3 C +CURMODE:1 + - - SSC SSC1 ap -Q + - - R SSC1 RE "\+APCONFIG:%%s,%%s,7,\d+,\d+,4,"%%(,) + - - SSC SSC2 sta -Q + - - R SSC2 RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC3 sta -Q + - - R SSC3 RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC1 dhcp -Q -o 2 + - - R SSC1 C +DHCP:AP,STARTED + - - SSC SSC2 dhcp -Q -o 1 + - - R SSC2 C +DHCP:STA,STARTED + - - SSC SSC3 dhcp -Q -o 1 + - - R SSC3 C +DHCP:STA,STARTED + - - SSC SSC1 mac -Q -o 2 + - - R SSC1 P + - - SSC SSC2 mac -Q -o 1 + - - R SSC2 P + - - SSC SSC3 mac -Q -o 1 + - - R SSC3 P + - - SSC SSC[1-3] mdns -T + - - R SSC[1-3] C +MDNS:OK + - - SSC SSC[1-3] mdns -I + - - R SSC[1-3] C +MDNS:OK + restore cmd set: + - '' + - - SSC SSC[1-3] op -S -o [2,1,1] + - - R SSC[1-3] C +MODE:OK + - - SSC SSC[1-3] dhcp -S -o [2,1,1] + - - R SSC[1-3] C +DHCP + - - SSC SSC1 mac -S -o 2 -m + - - R SSC1 C +MAC:AP,OK + - - SSC SSC2 mac -S -o 1 -m + - - R SSC2 C +MAC:STA,OK + - - SSC SSC3 mac -S -o 1 -m + - - R SSC3 C +MAC:STA,OK + - - SSC SSC1 ap -S -s -p -t -n 7 + - - R SSC1 C +SAP:OK + - - SSC SSC2 sta -C -s -p + - - R SSC2 RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC3 sta -C -s -p + - - R SSC3 RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC[1-3] mdns -T + - - R SSC[1-3] C +MDNS:OK + - - SSC SSC[1-3] mdns -I + - - R SSC[1-3] C +MDNS:OK + force restore cmd set: + - '' + - - SSC SSC[1-3] reboot + - - R SSC[1-3] C !!!ready!!! + - - SSC SSC[1-3] op -S -o [2,1,1] + - - R SSC[1-3] C +MODE:OK + - - SSC SSC[1-3] dhcp -S -o [2,1,1] + - - R SSC[1-3] C +DHCP + - - SSC SSC1 mac -S -o 2 -m + - - R SSC1 C +MAC:AP,OK + - - SSC SSC2 mac -S -o 1 -m + - - R SSC2 C +MAC:STA,OK + - - SSC SSC3 mac -S -o 1 -m + - - R SSC3 C +MAC:STA,OK + - - SSC SSC1 ap -S -s -p -t -n 7 + - - R SSC1 C +SAP:OK + - - SSC SSC2 sta -C -s -p + - - R SSC2 RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC3 sta -C -s -p + - - R SSC3 RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC[1-3] mdns -T + - - R SSC[1-3] C +MDNS:OK + - - SSC SSC[1-3] mdns -I + - - R SSC[1-3] C +MDNS:OK - tag: T3_PHY1 <<: *SSC_INIT_COND initial condition detail: (SSC) DUT1-2 set to STA+SoftAP mode, DUT3 set to STA mode. All interface of DUT2-3 set to 11n ht40. Set DUT1-2 SoftAP config. @@ -2131,54 +3133,8 @@ initial condition: - - SSC SSC[1-2] gattc -U -z all - - R SSC[1-2] C +GATTC:OK - - SSC SSC[1-2] bleadv -D -z stop - - - R SSC[1-2] C +BLEADV:OK + - - R SSC[1-2] C +BLEADV:Stop - - SSC SSC[1-2] ble -S -z public - - R SSC[1-2] C +BLE:OK - - SSC SSC1 ram - - R SSC1 A :(\d+) -- tag: T3_2 - <<: *SSC_INIT_COND - initial condition detail: (SSC) DUT set to STA+SoftAP mode, DUT2 set to SoftAP mode, DUT3 set to STA mode - check cmd set: - - '' - - - SSC SSC[1,2,3] op -Q - - - R SSC[1,2,3] C +CURMODE:[3,2,1] - - - SSC SSC3 sta -D - - - 'R SSC3 C +QAP:' - restore cmd set: - - '' - - - SSC SSC[1,2,3] op -S -o [3,2,1] - - - R SSC[1,2,3] C +MODE:OK - - - SSC SSC3 sta -D - - - 'R SSC3 C +QAP:' - force restore cmd set: - - '' - - - SSC SSC[1,2,3] reboot - - - R SSC[1,2,3] C !!!ready!!! - - - SSC SSC[1,2,3] op -S -o [3,2,1] - - - R SSC[1,2,3] C +MODE:OK - - - SSC SSC3 sta -D - - - 'R SSC3 C +QAP:' -- tag: T3_3 - <<: *SSC_INIT_COND - initial condition detail: (SSC) DUT1 set to SoftAp mode, DUT2-3 set to STA mode - check cmd set: - - '' - - - SSC SSC[1,2,3] op -Q - - - R SSC[1,2,3] C +CURMODE:[2,1,1] - - - SSC SSC[2,3] sta -D - - - 'R SSC[2,3] C +QAP:' - restore cmd set: - - '' - - - SSC SSC[1,2,3] op -S -o [2,1,1] - - - R SSC[1,2,3] C +MODE:OK - - - SSC SSC[2,3] sta -D - - - 'R SSC[2,3] C +QAP:' - force restore cmd set: - - '' - - - SSC SSC[1,2,3] reboot - - - R SSC[1,2,3] C !!!ready!!! - - - SSC SSC[1,2,3] op -S -o [2,1,1] - - - R SSC[1,2,3] C +MODE:OK - - - SSC SSC[2,3] sta -D - - - 'R SSC[2,3] C +QAP:' diff --git a/components/idf_test/integration_test/KnownIssues b/components/idf_test/integration_test/KnownIssues index f61c722ae1..818c27cba4 100644 --- a/components/idf_test/integration_test/KnownIssues +++ b/components/idf_test/integration_test/KnownIssues @@ -12,19 +12,6 @@ ESP32.WIFI_SCAN_0303 ESP32.WIFI_SCAN_0303_01 ESP32.WIFI_CONN_0302 ESP32.WIFI_CONN_0302_01 -ESP32.WIFI_CONN_0101 -ESP32.WIFI_CONN_0101_01 -ESP32.WIFI_CONN_0102 -ESP32.WIFI_CONN_0103 -ESP32.WIFI_CONN_0103_01 -ESP32.WIFI_SCAN_0101 -ESP32.WIFI_SCAN_0101_01 -ESP32.WIFI_SCAN_0102 -ESP32.WIFI_SCAN_0102_01 -ESP32.WIFI_SCAN_0103 -ESP32.WIFI_SCAN_0103_01 -ESP32.WIFI_SCAN_0104 -ESP32.WIFI_SCAN_0104_01 ESP32.WIFI_MODE_0102 ESP32.WIFI_MODE_0103 ESP32.WIFI_ADDR_0102 diff --git a/components/idf_test/integration_test/TC_IT_BLUEDROID_GAP.yml b/components/idf_test/integration_test/TC_IT_BLUEDROID_GAP.yml new file mode 100644 index 0000000000..8a378df626 --- /dev/null +++ b/components/idf_test/integration_test/TC_IT_BLUEDROID_GAP.yml @@ -0,0 +1,1213 @@ +.GAP_CASE: &GAP_CASE + SDK: ESP32_IDF + Test App: SSC_BLE + auto test: 'Yes' + category: Function + test point 1: basic function + initial condition: BLE_INIT2 + test environment: SSC_T2_5 + execution time: 0 + module: BLUEDROID + sub module: GAP + version: v1 (2016-12-31) + CI ready: 'Yes' + level: Integration + allow fail: '' + +.set_default_ble_name: &set_default_ble_name + LIST_MERGE: + - - "SSC SSC1 ble -S -z name -n " + - ["R SSC1 C +BLE:OK"] + +.open_capture_nic: &open_capture_nic + LIST_MERGE: + - - "NIC BLENIC START bt+capture" + - ['R PC_COM C +NIC_START:OK'] + +.dut1_stop_adv: &dut1_stop_adv + LIST_MERGE: + - - "SSC SSC1 bleadv -D -z stop" + - ["R SSC1 C +BLEADV:"] + +.dut1_start_adv: &dut1_start_adv + LIST_MERGE: + - - "SSC SSC1 bleadv -D -z start" + - ["R SSC1 C +BLEADV:Start,OK"] + +.dut1_connect_to_dut2: &dut1_connect_to_dut2 + LIST_MERGE: + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect,OK'] + +.set_default_adv_data: &set_default_adv_data + LIST_MERGE: + - - "SSC SSC1 bleadv -D -z stop" + - ["R SSC1 C +BLEADV:"] + - - "SSC SSC1 bleadv -L -c 0 -t 3" + - ["R SSC1 C +BLEADV:SetAdv,OK C +BLEADV:SetScanRes,OK"] + - - "SSC SSC1 bleadv -D -z start" + - ["R SSC1 C +BLEADV:Start,OK"] + +.dut2_stop_adv: &dut2_stop_adv + LIST_MERGE: + - - "SSC SSC2 bleadv -D -z stop" + - ["R SSC2 C +BLEADV:"] + +test cases: +- ID: BLUEDROID_GAP_01003 + <<: *GAP_CASE + test point 2: BLE GAP param device name test + summary: ble set long device name for BLUEDROID + steps: | + 1. DUT1 set 32 byte device name A + 2. stop advertising + 3. config scan response and start advertising + 4. DUT2 do active scan + 5. DUT1 set 33 bytes device name + 6. stop advertising + 7. config scan response and start advertising + 8. DUT2 do active scan + expected result: | + 1. succeed + 2. succeed + 3. succeed + 4. DUT1 mac in scan result (device name is too long) + 5. failed + 6. succeed + 7. succeed + 8. DUT1 mac in scan result (device name is too long) + cmd set: + - "" + - - "SSC SSC1 ble -S -z name -n " + - ["R SSC1 C +BLE:OK"] + - *set_default_adv_data + - *dut2_stop_adv + - - "SSC SSC2 blescan -D -z start -t 3 -c 0 -s 1" + - ["R SSC2 P C Complete"] + - - "SSC SSC1 ble -S -z name -n 123456789012345678901234567890123" + - ["R SSC1 C +BLE:ERROR"] + - *set_default_adv_data + - - "SSC SSC2 blescan -D -z start -t 3 -c 0 -s 1" + - ["R SSC2 P C Complete"] +- ID: BLUEDROID_GAP_03003 + <<: *GAP_CASE + test point 2: BLE GAP set advertise param + summary: ble set adv parameter own address type for BLUEDROID + steps: | + 1. DUT1 stop advertise + 2. DUT1 start adv with own address type public + 3. PC do active scan and capture advertising report + 4. repeat step 1-3 with own address type random, rpa_public, rpa_random + 5. repeat step 1-3 with channel map not valid + expected result: | + 1. succeed + 2. succeed + 3. get ADV_IND with DUT1 BT MAC + 4. get ADV_IND with DUT1 BT MAC + 5. can not get ADV_IND with DUT1 BT MAC + initial condition: BLE_INIT1 + test environment: SSC_T1_3 + cmd set: + - "" + - *set_default_ble_name + - - "SSC SSC1 bleadv -L -c 0 -t 3 -n 1" + - ["R SSC1 C +BLEADV:SetAdv,OK"] + - *open_capture_nic + - - LOOP 4 3 "[0,2,1,3]" "['PDU','PDU','NPDU','NPDU']" + - *dut1_stop_adv + - - "SSC SSC1 bleadv -D -z start -t 0 -o {%d}" + - ["R SSC1 C +BLEADV:OK"] + - - "HCITOOL 2 -i lescan" + - - 'P PC_COM C +HCITOOL:OK' + - 'P BLENIC {%s} (HCIEvent.le_sub_event_code="LEAdvReport")(HCIEvent.event_type_0="ADV_IND")(HCIEvent.data_0.NameComplete=)(HCIEvent.address_0=)' +- ID: BLUEDROID_GAP_03006 + <<: *GAP_CASE + test point 2: BLE GAP set advertise param + summary: ble set paramters for SCAN_IND for BLUEDROID + steps: | + 1. DUT1 stop advertise + 2. DUT1 set incorrect adv interval for SCAN_IND + 3. PC do active scan and capture advertising report + 4. repeat step 1-3 with correct adv interval + expected result: | + 1. succeed + 2. succeed + 3. can not get SCAN_IND with DUT1 BT MAC + 4. get SCAN_IND with DUT1 BT MAC + initial condition: BLE_INIT1 + test environment: SSC_T1_3 + cmd set: + - "" + - *set_default_ble_name + - - "SSC SSC1 bleadv -L -c 0 -t 3" + - ["R SSC1 C +BLEADV:SetAdv,OK"] + - *open_capture_nic + - *dut1_stop_adv + - - LOOP 2 2 "['0x20-0x40','0xA0-0xB0']" "['PDU','PDU']" + - [""] + - - "SSC SSC1 bleadv -D -z start -t 2 -i {%s}" + - ["R SSC1 C +BLEADV:OK"] + - - "HCITOOL 2 -i lescan" + - - 'P PC_COM C +HCITOOL:OK' + - 'P BLENIC {%s} (HCIEvent.le_sub_event_code="LEAdvReport")(HCIEvent.event_type_0="SCAN_IND")(HCIEvent.address_0=)' +- ID: BLUEDROID_GAP_03007 + <<: *GAP_CASE + test point 2: BLE GAP set advertise param + summary: ble set paramters for NONCONN_IND for BLUEDROID + steps: | + 1. DUT1 stop advertise + 2. DUT1 set incorrect adv interval for NONCONN_IND + 3. PC do active scan and capture advertising report + 4. repeat step 1-3 with correct adv interval + expected result: | + 1. succeed + 2. succeed + 3. can not get SCAN_IND with DUT1 BT MAC + 4. get SCAN_IND with DUT1 BT MAC + initial condition: BLE_INIT1 + test environment: SSC_T1_3 + cmd set: + - "" + - *set_default_ble_name + - - "SSC SSC1 bleadv -L -c 0 -t 3" + - ["R SSC1 C +BLEADV:SetAdv,OK"] + - *open_capture_nic + - *dut1_stop_adv + - - LOOP 2 2 "['0x20-0x40','0xA0-0xB0']" "['PDU','PDU']" + - [""] + - - "SSC SSC1 bleadv -D -z start -t 3 -i {%s}" + - ["R SSC1 C +BLEADV:OK"] + - - "HCITOOL 2 -i lescan" + - - 'P PC_COM C +HCITOOL:OK' + - 'P BLENIC {%s} (HCIEvent.le_sub_event_code="LEAdvReport")(HCIEvent.event_type_0="NONCONN_IND")(HCIEvent.address_0=)' +- ID: BLUEDROID_GAP_06001 + <<: *GAP_CASE + test point 2: BLE GAP connect / disconnect + summary: ble connect as "client" and "server" for BLUEDROID + allow fail: 1/2 + steps: | + 1. DUT1 connect to DUT2 as "client" + 2. DUT1 disconnected with DUT2 + 3. DUT1 start gatt server app + 4. DUT1 connect to DUT2 as "server" + expected result: | + 1. succeed + 2. succeed + 3. succeed + 4. succeed + cmd set: + - "" + - *dut1_connect_to_dut2 + - - "SSC SSC1 bleconn -D -p 0x10" + - ['R SSC1 C +BLE:CLOSE,OK'] + - - "SSC SSC1 gatts -S -z load -p 0xA0" + - ['R SSC1 C +GATTS:LoadProfile,OK'] + - - "SSC SSC2 bleadv -D -z start" + - ['R SSC2 C +BLEADV:OK'] + - - "SSC SSC1 bleconn -C -p 0xA0 -a -z server" + - ['R SSC1 C +BLECONN:GapConnect'] +- ID: BLUEDROID_GAP_06002 + <<: *GAP_CASE + test point 2: BLE GAP connect / disconnect + summary: ble disconnect as "client" and "server" for BLUEDROID + steps: | + 1. DUT1 connect to DUT2 as "client" + 2. DUT1 disconnected with DUT2 as "client" + 3. DUT1 start gatt server app + 4. DUT1 connect to DUT2 as client + 5. DUT1 disconnect with DUT2 as "server" + expected result: | + 1. succeed + 2. succeed + 3. succeed + 4. succeed + 5. succeed + cmd set: + - "" + - *dut1_connect_to_dut2 + - - "SSC SSC1 bleconn -D -p 0x10" + - ['R SSC1 C +BLE:CLOSE,OK'] + - - "SSC SSC2 bleadv -D -z start" + - ['R SSC2 C +BLEADV:OK'] + - - "SSC SSC1 gatts -S -z load -p 0xA0" + - ['R SSC1 C +GATTS:LoadProfile,OK'] + - *dut1_connect_to_dut2 + - - "SSC SSC1 bleconn -D -p 0x10" + - ['R SSC1 C +BLE:CLOSE,OK'] +- ID: BLUEDROID_GAP_06003 + <<: *GAP_CASE + allow fail: 1/2 + test point 2: BLE GAP connect / disconnect + summary: ble connect/disconnect to same connection multiple times for BLUEDROID + steps: | + 1. DUT1 connect to DUT2 as "client" + 2. DUT1 start gatt server app + 3. DUT1 connect to DUT2 as "client" again + 4. DUT1 connect to DUT2 as "server" + 5. DUT1 disconnected with DUT2 as "client" + 6. DUT1 disconnected with DUT2 as "server" + expected result: | + 1. succeed + 2. succeed + 3. succeed + 4. succeed + 5. succeed + 6. succeed + cmd set: + - "" + - *dut1_connect_to_dut2 + - - "SSC SSC1 gatts -S -z load -p 0xA0" + - ['R SSC1 C +GATTS:LoadProfile,OK'] + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ['R SSC1 C +BLE:GattcOpen,OK'] + - - "SSC SSC1 bleconn -C -p 0xA0 -a -z server" + - ['R SSC1 C +BLE:GattsOpen,OK,00A0'] + - - "SSC SSC1 bleconn -D -p 0x10" + - ['R SSC1 C +BLE:CLOSE,OK'] + - - "SSC SSC1 bleconn -D -p 0xA0 -z server" + - ['R SSC1 C +BLE:GattsClose,OK'] +- ID: BLUEDROID_GAP_06004 + <<: *GAP_CASE + test point 2: BLE GAP connect / disconnect + summary: ble connect to invalid address for BLUEDROID + allow fail: 2/3 + steps: | + 1. DUT1 connect to invalid address + 2. DUT1 connect to DUT2 + expected result: | + 1. failed + 2. succeed + cmd set: + - "" + - - "SSC SSC1 bleconn -C -p 0x10 -a 24:0a:c4:04:26:50" + - ['R SSC1 C +BLECONN:OK'] + - - DELAY 30 + - ['R SSC1 C +BLE:GattcOpen,ERROR'] + - *dut1_connect_to_dut2 +- ID: BLUEDROID_GAP_06005 + <<: *GAP_CASE + test point 2: BLE GAP connect / disconnect + summary: ble connect/disconnect event to active app for BLUEDROID + steps: | + 1. DUT1 create gatts app + 2. DUT1 connect to DUT2 as "client" + 3. DUT1 do disconnect as "server" + expected result: | + 1. succeed + 2. succeed, DUT1 and DUT2 gatts get connect event + 3. DUT1 and DUT2 gatts get disconnect event + cmd set: + - "" + - - "SSC SSC1 gatts -S -z load -p 0xA0" + - ['R SSC1 C +GATTS:LoadProfile,OK'] + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ['P SSC1 C +BLECONN:GapConnect', 'P SSC2 C +BLECONN:GapConnect'] + - - "SSC SSC1 bleconn -D -p 0xA0 -z server" + - ['P SSC1 C +BLE:GattsClose'] +- ID: BLUEDROID_GAP_07001 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update connect parameters by master for BLUEDROID + steps: | + 1. update connect parameters by master + expected result: | + 1. succeed + initial condition: BLE_CONN2 + cmd set: + - "BLEFunction/ConnParamUpdate" + - - dut = ["SSC1"] + - [''] + - - interval=["32-64"] + - [''] + - - latency=["0"] + - [''] + - - supervision_timeout=["32"] + - [''] + - - expect_result=["OK"] + - [''] +- ID: BLUEDROID_GAP_07002 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update connect parameters by slave for BLUEDROID + steps: | + 1. update connect parameters by slave + expected result: | + 1. succeed + initial condition: BLE_CONN2 + cmd set: + - "BLEFunction/ConnParamUpdate" + - - dut = ["SSC2"] + - [''] + - - interval=["32-64"] + - [''] + - - latency=["0"] + - [''] + - - supervision_timeout=["32"] + - [''] + - - expect_result=["OK"] + - [''] +- ID: BLUEDROID_GAP_07003 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update invalid connect parameters(timeout<(1+latency)*2*MAX_interval*1.25) for BLUEDROID + steps: | + 1. update invalid connect parameters(timeout<(1+latency)*2*MAX_interval*1.25) + expected result: | + 1. fail + initial condition: BLE_CONN2 + cmd set: + - "BLEFunction/ConnParamUpdate" + - - dut = ["SSC1"] + - [''] + - - interval=["7-90"] + - [''] + - - latency=["1"] + - [''] + - - supervision_timeout=["41"] + - [''] + - - expect_result=["ERROR"] + - [''] +- ID: BLUEDROID_GAP_07004 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update connnect parameters and interval within allowed range for BLUEDROID + steps: | + 1. DUT1 update connection parametres and interval is 6-128 + 2. DUT1 update connection parametres and interval is 33-3200 + expected result: | + 1. succeed + 2. succeed + initial condition: BLE_CONN2 + cmd set: + - "BLEFunction/ConnParamUpdate" + - - dut = ["SSC1","SSC1"] + - [''] + - - interval=["6-128","33-3200"] + - [''] + - - latency=["0","0"] + - [''] + - - supervision_timeout=["50","1000"] + - [''] + - - expect_result=["OK","OK"] + - [''] +- ID: BLUEDROID_GAP_07005 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update connect parameters interval and interval out of allowed range for BLUEDROID + steps: | + 1. DUT1 update invalid interval and interval is 16-3201 + 2. DUT1 update invalid interval and interval is 5-64 + expected result: | + 1. fail + 2. fail + initial condition: BLE_CONN2 + cmd set: + - "BLEFunction/ConnParamUpdate" + - - dut = ["SSC1","SSC1"] + - [''] + - - interval=["16-3201","5-64"] + - [''] + - - latency=["0","0"] + - [''] + - - supervision_timeout=["32","32"] + - [''] + - - expect_result=["ERROR","ERROR"] + - [''] +- ID: BLUEDROID_GAP_07006 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update connect parameters latency and latency within allowed range and timeout<(1+latency)*2*MAX_interval*1.25 for BLUEDROID + steps: | + 1. DUT1 update connect parameters latency and latency within allowed range and timeout<(1+latency)*2*MAX_interval*1.25 + expected result: | + 1. fail + initial condition: BLE_CONN2 + cmd set: + - "BLEFunction/ConnParamUpdate" + - - dut = ["SSC1"] + - [''] + - - interval=["32-64"] + - [''] + - - latency=["8"] + - [''] + - - supervision_timeout=["32"] + - [''] + - - expect_result=["ERROR"] + - [''] +- ID: BLUEDROID_GAP_07007 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update connect parameters latency and latency = 501 + steps: | + 1. DUT1 uupdate connect parameters latency and latency = 501 + expected result: | + 1. fail + initial condition: BLE_CONN2 + cmd set: + - "BLEFunction/ConnParamUpdate" + - - dut = ["SSC1"] + - [''] + - - interval=["6-8"] + - [''] + - - latency=["501"] + - [''] + - - supervision_timeout=["1003"] + - [''] + - - expect_result=["ERROR"] + - [''] +- ID: BLUEDROID_GAP_07008 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update connect parameters latency and latency = 500 for BLUEDROID + steps: | + 1. DUT1 update connect parameters latency and latency = 500 + expected result: | + 1. succeed + initial condition: BLE_CONN2 + cmd set: + - "BLEFunction/ConnParamUpdate" + - - dut = ["SSC1"] + - [''] + - - interval=["6-8"] + - [''] + - - latency=["500"] + - [''] + - - supervision_timeout=["1003"] + - [''] + - - expect_result=["OK"] + - [''] +- ID: BLUEDROID_GAP_07009 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update connect parameters timeout and timeout within allowed range and timeout<(1+latency)*2*MAX_interval*1.25 for BLUEDROID + steps: | + 1. DUT1 update connect parameters timeout and timeout within allowed range and timeout<(1+latency)*2*MAX_interval*1.25 + expected result: | + 1. fail + initial condition: BLE_CONN2 + cmd set: + - "BLEFunction/ConnParamUpdate" + - - dut = ["SSC1"] + - [''] + - - interval=["32-64"] + - [''] + - - latency=["0"] + - [''] + - - supervision_timeout=["12"] + - [''] + - - expect_result=["ERROR"] + - [''] +- ID: BLUEDROID_GAP_07010 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update connect parameters timeout and timeout = 9 for BLUEDROID + steps: | + 1. DUT1 update connect parameters timeout and timeout = 9 + expected result: | + 1. fail + initial condition: BLE_CONN2 + cmd set: + - "BLEFunction/ConnParamUpdate" + - - dut = ["SSC1"] + - [''] + - - interval=["8-10"] + - [''] + - - latency=["0"] + - [''] + - - supervision_timeout=["9"] + - [''] + - - expect_result=["ERROR"] + - [''] +- ID: BLUEDROID_GAP_07011 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update connect parameters timeout and timeout within allowed range for BLUEDROID + steps: | + 1. DUT1 update timeout = 10 + 2. DUT1 update timeout = 3200 + expected result: | + 1. succeed + 2. succeed + initial condition: BLE_CONN2 + cmd set: + - "BLEFunction/ConnParamUpdate" + - - dut = ["SSC1","SSC1"] + - [''] + - - interval=["8-10","8-10"] + - [''] + - - latency=["0","0"] + - [''] + - - supervision_timeout=["10","3200"] + - [''] + - - expect_result=["OK","OK"] + - [''] +- ID: BLUEDROID_GAP_07012 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update connect parameters timeout and timeout = 3201 for BLUEDROID + steps: | + 1. DUT1 update timeout = 3201 + expected result: | + 1. fail + initial condition: BLE_CONN2 + cmd set: + - "BLEFunction/ConnParamUpdate" + - - dut = ["SSC1"] + - [''] + - - interval=["8-10"] + - [''] + - - latency=["0"] + - [''] + - - supervision_timeout=["3201"] + - [''] + - - expect_result=["ERROR"] + - [''] +- ID: BLUEDROID_GAP_07013 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update invalid connect parameters before configure connect param event back for BLUEDROID + steps: | + 1. DUT1 update valid interval + 2. DUT1 update valid interval + expected result: | + 1. + 2. succeed + initial condition: BLE_CONN2 + cmd set: + - "" + - - "SSC SSC1 bleconn -S -z ConnParam -a " + - [''] + - - "SSC SSC1 bleconn -S -z ConnParam -a -t 0x40" + - ['R SSC1 C pending'] +- ID: BLUEDROID_GAP_07014 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update invalid connect param and unpdate valid connect params by master for BLUEDROID + steps: | + 1. DUT1 update invalid connect parameters + 2. DUT2 update valid connect + expected result: | + 1. fail + 2. succeed + initial condition: BLE_CONN2 + cmd set: + - "BLEFunction/ConnParamUpdate" + - - dut = ["SSC1","SSC1"] + - [''] + - - interval=["32-64","32-64"] + - [''] + - - latency=["9","0"] + - [''] + - - supervision_timeout=["32","32"] + - [''] + - - expect_result=["ERROR","OK"] + - [''] +- ID: BLUEDROID_GAP_07015 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update valid connect parameters twice for BLUEDROID + allow fail: 1/2 + steps: | + 1. DUT1 update valid connect parameters + 2. DUT1 update valid connect parameters + expected result: | + 1. succeed + 2. succeed + initial condition: BLE_CONN2 + cmd set: + - "BLEFunction/ConnParamUpdate" + - - dut = ["SSC1","SSC1"] + - [''] + - - interval=["7-80","10-100"] + - [''] + - - latency=["1","0"] + - [''] + - - supervision_timeout=["41","30"] + - [''] + - - expect_result=["OK","OK"] + - [''] +- ID: BLUEDROID_GAP_07016 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update valid connect parameters(timeout<(1+latency)*2*MAX_interval*1.25) by slave for BLUEDROID + steps: | + 1. DUT2 update valid connect parameters(timeout<(1+latency)*2*MAX_interval*1.25) by slave + expected result: | + 1. fail + initial condition: BLE_CONN2 + cmd set: + - "BLEFunction/ConnParamUpdate" + - - dut = ["SSC2"] + - [''] + - - interval=["7-90"] + - [''] + - - latency=["1"] + - [''] + - - supervision_timeout=["41"] + - [''] + - - expect_result=["ERROR"] + - [''] +- ID: BLUEDROID_GAP_07017 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update connnect parameters interval within allowed range by slave for BLUEDROID + steps: | + 1. DUT2 update interval 6-128 + 2. DUT2 update interval 21-3200 + expected result: | + 1. succeed + 2. succeed + initial condition: BLE_CONN2 + cmd set: + - "BLEFunction/ConnParamUpdate" + - - dut = ["SSC2","SSC2"] + - [''] + - - interval=["6-128","21-3200"] + - [''] + - - latency=["0","0"] + - [''] + - - supervision_timeout=["50","1000"] + - [''] + - - expect_result=["OK","OK"] + - [''] +- ID: BLUEDROID_GAP_07018 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update connnect parameters interval out of allowed range by slave for BLUEDROID + steps: | + 1. DUT2 update invalid interval 10-3201 + 2. DUT2 update invalid interval 5-64 + expected result: | + 1. fail + 2. fail + initial condition: BLE_CONN2 + cmd set: + - "BLEFunction/ConnParamUpdate" + - - dut = ["SSC2","SSC2"] + - [''] + - - interval=["10-3201","5-64"] + - [''] + - - latency=["0","0"] + - [''] + - - supervision_timeout=["32","32"] + - [''] + - - expect_result=["ERROR","ERROR"] + - [''] +- ID: BLUEDROID_GAP_07019 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update connnect parameters and latency within allowed range and timeout<(1+latency)*2*MAX_interval*1.25 by slave for BLUEDROID + steps: | + 1. DUT2 update connnect parameters and latency within allowed range and timeout<(1+latency)*2*MAX_interval*1.25 by slave + expected result: | + 1. fail + initial condition: BLE_CONN2 + cmd set: + - "BLEFunction/ConnParamUpdate" + - - dut = ["SSC2"] + - [''] + - - interval=["32-64"] + - [''] + - - latency=["8"] + - [''] + - - supervision_timeout=["32"] + - [''] + - - expect_result=["ERROR"] + - [''] +- ID: BLUEDROID_GAP_07020 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update connect parameters latency and latency out of allowed range by slave for BLUEDROID + steps: | + 1. DUT2 update invalid latency = 501 + expected result: | + 1. fail + initial condition: BLE_CONN2 + cmd set: + - "BLEFunction/ConnParamUpdate" + - - dut = ["SSC2"] + - [''] + - - interval=["6-8"] + - [''] + - - latency=["501"] + - [''] + - - supervision_timeout=["1003"] + - [''] + - - expect_result=["ERROR"] + - [''] +- ID: BLUEDROID_GAP_07021 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update valid connect parameters and latency = 500 by slave for BLUEDROID + steps: | + 1. DUT2 update latency = 500 + expected result: | + 1. success + initial condition: BLE_CONN2 + cmd set: + - "BLEFunction/ConnParamUpdate" + - - dut = ["SSC2"] + - [''] + - - interval=["6-8"] + - [''] + - - latency=["500"] + - [''] + - - supervision_timeout=["1003"] + - [''] + - - expect_result=["OK"] + - [''] +- ID: BLUEDROID_GAP_07022 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update connect parameters timeout and timeout = 9 by slave for BLUEDROID + steps: | + 1. DUT2 update connect parameters timeout and timeout = 9 + expected result: | + 1. fail + initial condition: BLE_CONN2 + cmd set: + - "BLEFunction/ConnParamUpdate" + - - dut = ["SSC2"] + - [''] + - - interval=["8-10"] + - [''] + - - latency=["0"] + - [''] + - - supervision_timeout=["9"] + - [''] + - - expect_result=["ERROR"] + - [''] +- ID: BLUEDROID_GAP_07023 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update connect parameters timeout and timeout = 10 by slave for BLUEDROID + steps: | + 1. DUT2 update connect parameters timeout and timeout = 10 by slave + expected result: | + 1. fail + initial condition: BLE_CONN2 + cmd set: + - "BLEFunction/ConnParamUpdate" + - - dut = ["SSC2"] + - [''] + - - interval=["8-10"] + - [''] + - - latency=["0"] + - [''] + - - supervision_timeout=["10"] + - [''] + - - expect_result=["OK"] + - [''] +- ID: BLUEDROID_GAP_07024 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update connect parameters timeout and timeout = 3200 by slave for BLUEDROID + steps: | + 1. DUT2 update connect parameters timeout and timeout = 3200 by slave + expected result: | + 1. fail + initial condition: BLE_CONN2 + cmd set: + - "BLEFunction/ConnParamUpdate" + - - dut = ["SSC2"] + - [''] + - - interval=["8-10"] + - [''] + - - latency=["0"] + - [''] + - - supervision_timeout=["3200"] + - [''] + - - expect_result=["OK"] + - [''] +- ID: BLUEDROID_GAP_07025 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update connect parameters timeout and timeout = 3201 by slave for BLUEDROID + steps: | + 1. DUT2 update connect parameters timeout and timeout = 3201 by slave + expected result: | + 1. fail + initial condition: BLE_CONN2 + cmd set: + - "BLEFunction/ConnParamUpdate" + - - dut = ["SSC2"] + - [''] + - - interval=["8-10"] + - [''] + - - latency=["0"] + - [''] + - - supervision_timeout=["3201"] + - [''] + - - expect_result=["ERROR"] + - [''] +- ID: BLUEDROID_GAP_07026 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update invalid connect parameters before configure connect param event back by slave for BLUEDROID + steps: | + 1. DUT2 update valid interval + 2. DUT2 update valid interval + expected result: | + 1. + 2. pending + initial condition: BLE_CONN2 + cmd set: + - "" + - - "SSC SSC2 bleconn -S -z ConnParam -a " + - [''] + - - "SSC SSC2 bleconn -S -z ConnParam -a -t 0x40" + - ['R SSC2 C pending'] +- ID: BLUEDROID_GAP_07027 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update invalid connect param and update valid connect params by slave for BLUEDROID + steps: | + 1. DUT2 update invalid connect + 2. DUT2 update valid connect + expected result: | + 1. fail + 2. succeed + initial condition: BLE_CONN2 + cmd set: + - "BLEFunction/ConnParamUpdate" + - - dut = ["SSC2","SSC2"] + - [''] + - - interval=["32-64","32-64"] + - [''] + - - latency=["0","0"] + - [''] + - - supervision_timeout=["9","21"] + - [''] + - - expect_result=["ERROR","OK"] + - [''] +- ID: BLUEDROID_GAP_07028 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update valid connect parameters twice by slave for BLUEDROID + allow fail: 1/2 + steps: | + 1. DUT2 update valid interval + 2. DUT2 update valid interval + expected result: | + 1. succeed + 2. succeed + initial condition: BLE_CONN2 + cmd set: + - "BLEFunction/ConnParamUpdate" + - - dut = ["SSC2","SSC2"] + - [''] + - - interval=["7-80","10-100"] + - [''] + - - latency=["1","0"] + - [''] + - - supervision_timeout=["41","30"] + - [''] + - - expect_result=["OK","OK"] + - [''] +- ID: BLUEDROID_GAP_07029 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update invalid connect param by master and update valid connect params by slave for BLUEDROID + steps: | + 1. DUT1 update invalid connect + 2. DUT2 update valid connect + expected result: | + 1. fail + 2. succeed + initial condition: BLE_CONN2 + cmd set: + - "BLEFunction/ConnParamUpdate" + - - dut = ["SSC1","SSC2"] + - [''] + - - interval=["32-64","32-64"] + - [''] + - - latency=["9","0"] + - [''] + - - supervision_timeout=["32","32"] + - [''] + - - expect_result=["ERROR","OK"] + - [''] +- ID: BLUEDROID_GAP_07030 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update valid connect param by master and update valid connect params by slave for BLUEDROID + steps: | + 1. DUT1 update valid interval + 2. DUT2 update valid interval + expected result: | + 1. succeed + 2. succeed + initial condition: BLE_CONN2 + cmd set: + - "BLEFunction/ConnParamUpdate" + - - dut = ["SSC1","SSC2"] + - [''] + - - interval=["7-80","10-100"] + - [''] + - - latency=["1","0"] + - [''] + - - supervision_timeout=["41","30"] + - [''] + - - expect_result=["OK","OK"] + - [''] +- ID: BLUEDROID_GAP_07031 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update invalid connect param by slave and update valid connect params by master for BLUEDROID + steps: | + 1. DUT1 update invalid connect + 2. DUT2 update valid connect + expected result: | + 1. fail + 2. success + initial condition: BLE_CONN2 + cmd set: + - "BLEFunction/ConnParamUpdate" + - - dut = ["SSC2","SSC1"] + - [''] + - - interval=["32-64","32-64"] + - [''] + - - latency=["9","0"] + - [''] + - - supervision_timeout=["32","32"] + - [''] + - - expect_result=["ERROR","OK"] + - [''] +- ID: BLUEDROID_GAP_07032 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update valid connect param by slave and update valid connect params by master for BLUEDROID + allow fail: 1/2 + steps: | + 1. DUT2 update valid interval + 2. DUT1 update valid interval + expected result: | + 1. succeed + 2. succeed + initial condition: BLE_CONN2 + cmd set: + - "BLEFunction/ConnParamUpdate" + - - dut = ["SSC2","SSC1"] + - [''] + - - interval=["7-80","10-100"] + - [''] + - - latency=["1","0"] + - [''] + - - supervision_timeout=["41","30"] + - [''] + - - expect_result=["OK","OK"] + - [''] +- ID: BLUEDROID_GAP_07033 + <<: *GAP_CASE + test point 2: BLE GAP update connect parameters + summary: update connect parameters by master after pairing for BLUEDROID + steps: | + 1. DUT1 update connection parameters + expected result: | + 1. succeed + initial condition: BLE_CONN_SMP + cmd set: + - "BLEFunction/ConnParamUpdate" + - - dut = ["SSC1"] + - [''] + - - interval=["32-64"] + - [''] + - - latency=["0"] + - [''] + - - supervision_timeout=["32"] + - [''] + - - expect_result=["OK"] + - [''] +- ID: BLUEDROID_GAP_09001 + <<: *GAP_CASE + test point 2: BLE GAP processing scan data + summary: process scan data txp, manufacturer data, interval range, appearence, flag + steps: | + 1. DUT1 set raw adv data tx power, manufacturer data, interval range, apperaence, flag + 2. DUT1 start adv + 3. DUT2 do active scan with extended scan data + expected result: | + 1. succeed + 2. succeed + 3. scan with the correct adv data + cmd set: + - "" + - *dut1_stop_adv + - - "SSC SSC1 bleadv -R -t 1 -r 0x020AEB06FF1112131415051220004000021901020106" + - ["R SSC1 C +BLEADV:OK"] + - *dut1_start_adv + - *dut2_stop_adv + - - "SSC SSC2 blescan -D -z start -t 1 -e 1 -c 0 -d 1" + - - 'P SSC2 RE "\+BTSCANEXT:%%s,man,0x1112131415"%%()' + - 'P SSC2 RE "\+BTSCANEXT:%%s,txp,0xEB"%%()' + - 'P SSC2 RE "\+BTSCANEXT:%%s,intrange,0x20004000"%%()' + - 'P SSC2 RE "\+BTSCANEXT:%%s,app,0x01"%%()' + - 'P SSC2 RE "\+BTSCANEXT:%%s,flag,0x06"%%()' + - 'R SSC2 C Complete' +- ID: BLUEDROID_GAP_09004 + <<: *GAP_CASE + test point 2: BLE GAP processing scan data + summary: process combined adv data and scan response data + steps: | + 1. DUT1 set raw adv data manufacturer data + 2. DUT1 set scan response data tx power, interval range, apperaence, flag + 2. DUT1 start adv + 3. DUT2 do active scan with extended scan data 19 + expected result: | + 1. succeed + 2. succeed + 3. scan with the correct adv data + cmd set: + - "" + - *dut1_stop_adv + - - "SSC SSC1 bleadv -R -t 1 -r 0x15FF1011121314151617181910111213141516171819" + - ["R SSC1 C +BLEADV:OK"] + - - "SSC SSC1 bleadv -R -t 2 -r 0x020AEB051220004000021901020106" + - ["R SSC1 C +BLEADV:OK"] + - *dut1_start_adv + - *dut2_stop_adv + - - "SSC SSC2 blescan -D -z start -t 1 -e 1 -d 1" + - - 'P SSC2 RE "\+BTSCANEXT:%%s,man,0x1011121314151617181910111213141516171819"%%()' + - 'P SSC2 RE "\+BTSCANEXT:%%s,txp,0xEB"%%()' + - 'P SSC2 RE "\+BTSCANEXT:%%s,intrange,0x20004000"%%()' + - 'P SSC2 RE "\+BTSCANEXT:%%s,app,0x01"%%()' + - 'P SSC2 RE "\+BTSCANEXT:%%s,flag,0x06"%%()' + - 'R SSC2 C Complete' +- ID: BLUEDROID_GAP_09007 + <<: *GAP_CASE + test point 2: BLE GAP processing scan data + summary: proccess scan data included adv interval + steps: | + 1. DUT1 stop advertise and set short device name + 2. DUT1 set max interval 0x40 min interval 0x20 for adv data and scan response + 3. DUT1 start advertising + 4. DUT2 start scan and processing scan data + 5. DUT1 stop advertising + 6. DUT1 set max interval 0x400 min interval 0x200 for adv data and scan response + 7. DUT1 start advertising + 8. DUT2 start scan and processing scan data + expected result: | + 1. succeed + 2. succeed + 3. succeed + 4. scan with the correct adv data + 5. succeed + 6. succeed + 7. succeed + 8. scan with the correct adv data + cmd set: + - "" + - *dut1_stop_adv + - *set_default_ble_name + - - "SSC SSC1 bleadv -L -c 0 -i 0x20-0x40 -t 3" + - ["R SSC1 C +BLEADV:SetAdv,OK"] + - *dut1_start_adv + - - "SSC SSC2 blescan -D -z start -t 1 -e 1 -c 0 -d 1" + - - 'P SSC2 RE "\+BTSCANEXT:%%s,intrange,0x20004000"%%()' + - 'R SSC2 C Complete' + - *dut1_stop_adv + - - "SSC SSC1 bleadv -L -c 0 -i 0x200-0x400 -t 3" + - ["R SSC1 C +BLEADV:SetAdv,OK"] + - *dut1_start_adv + - - "SSC SSC2 blescan -D -z start -t 1 -e 1 -c 0 -d 1" + - - 'P SSC2 RE "\+BTSCANEXT:%%s,intrange,0x00020004"%%()' + - 'R SSC2 C Complete' +- ID: BLUEDROID_GAP_13001 + <<: *GAP_CASE + test point 2: BLE GAP param packet data length test + summary: gattc set packet data length at valid length (27-251) for BLUEDROID + steps: | + 1. DUT1 connect DUT2 + 2. DUT1 set packet data length + expected result: | + 1. succeed + 2. succeed + cmd set: + - "" + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ['R SSC1 C +BLECONN:GapConnect,OK', 'R SSC2 C +BLECONN:GapConnect'] + - - LOOP 3 1 "[27,200,251]" "[27,200,251]" + - - "SSC SSC1 ble -S -z pktLen -a -l {%d}" + - ["R SSC1 C +BLECONN:UpdatePktLen,OK,{%d}"] +- ID: BLUEDROID_GAP_13002 + <<: *GAP_CASE + test point 2: BLE GAP param packet data length test + summary: gattc set packet data length at invalid length for BLUEDROID + steps: | + 1. DUT1 connect DUT2 + 2. DUT1 set packet data length + expected result: | + 1. succeed + 2. succeed + cmd set: + - "" + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ['R SSC1 C +BLECONN:GapConnect,OK', 'R SSC2 C +BLECONN:GapConnect'] + - - LOOP 2 1 "[26,252]" "[27,251]" + - - "SSC SSC1 ble -S -z pktLen -a -l {%d}" + - ["R SSC1 C +BLECONN:UpdatePktLen,OK,{%d}"] +- ID: BLUEDROID_GAP_13003 + <<: *GAP_CASE + test point 2: BLE GAP param packet data length test + summary: gatts set packet data length at valid length (27-251) for BLUEDROID + steps: | + 1. DUT1 connect DUT2 + 2. DUT1 set packet data length + expected result: | + 1. succeed + 2. succeed + cmd set: + - "" + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ['R SSC1 C +BLECONN:GapConnect,OK', 'R SSC2 C +BLECONN:GapConnect'] + - - LOOP 3 1 "[27,200,251]" "[27,200,251]" + - - "SSC SSC2 ble -S -z pktLen -a -l {%d}" + - ["R SSC2 C +BLECONN:UpdatePktLen,OK,{%d}"] +- ID: BLUEDROID_GAP_13004 + <<: *GAP_CASE + test point 2: BLE GAP param packet data length test + summary: gatts set packet data length at invalid length for BLUEDROID + steps: | + 1. DUT1 connect DUT2 + 2. DUT1 set packet data length + expected result: | + 1. succeed + 2. succeed + cmd set: + - "" + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ['R SSC1 C +BLECONN:GapConnect,OK', 'R SSC2 C +BLECONN:GapConnect'] + - - LOOP 2 1 "[26,252]" "[27,251]" + - - "SSC SSC2 ble -S -z pktLen -a -l {%d}" + - ["R SSC2 C +BLECONN:UpdatePktLen,OK,{%d}"] +- ID: BLUEDROID_GAP_40001 + <<: *GAP_CASE + auto test: 'No' + test point 2: test if BLE work after switch off some sub modules + summary: GAP only test for BLUEDROID + steps: | + 1. download GAP only SSC bin on both DUT + 2. DUT1 set ascii device name + 3. stop advertising + 4. config scan response and start advertising + 5. DUT2 do active scan + expected result: | + 1. succeed + 2. succeed + 3. succeed + 4. succeed + 5. device name in scan result + initial condition: None + version: v1 (2017-05-19) + cmd set: + - "" + - - "SSC SSC[1-2] reboot" + - ['R SSC[1-2] C !!!ready!!!'] + - - "SSC SSC[1-2] ble -R" + - ["R SSC[1-2] C +BLE:OK"] + - *set_default_ble_name + - *set_default_adv_data + - *dut2_stop_adv + - - "SSC SSC2 blescan -D -z start -t 3 -c 0" + - ["R SSC2 P "] + diff --git a/components/idf_test/integration_test/TC_IT_BLUEDROID_GATT.yml b/components/idf_test/integration_test/TC_IT_BLUEDROID_GATT.yml new file mode 100644 index 0000000000..8e7e75d146 --- /dev/null +++ b/components/idf_test/integration_test/TC_IT_BLUEDROID_GATT.yml @@ -0,0 +1,1209 @@ +.GATT_CASE: &GATT_CASE + SDK: ESP32_IDF + Test App: SSC_BLE + auto test: 'Yes' + category: Function + test point 1: basic function + initial condition: BLE_CONN2 + test environment: SSC_T2_5 + execution time: 0 + module: BLUEDROID + sub module: GATT + version: v1 (2016-12-31) + CI ready: 'Yes' + level: Integration + allow fail: '' + +.primary_service_discovery: &primary_service_discovery + LIST_MERGE: + - - "SSC SSC1 gattc -D -z primaryService -p 0x10 -r " + - ["R SSC1 C +GATTC:Discover,OK"] + +.included_service_connection: &included_primary_service_connection + LIST_MERGE: + - - "SSC SSC2 gatts -S -z load -p 0xA1" + - ["R SSC2 C +GATTS:CreateService,OK,A001"] + - - "SSC SSC2 gatts -S -z include -p 0xA1 -i 0xA0" + - ["R SSC2 C +GATTS:AddIncludedService,OK"] + - - "SSC SSC2 gatts -S -z add -p 0xA1" + - ["R SSC2 C +GATTS:StartService,OK,A001"] + - - SSC SSC1 gattc -F -r + - ['R SSC1 C +GATTC:OK'] + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ["R SSC1 C +BLECONN:GapConnect,OK,0010", "R SSC2 C +BLECONN:GapConnect"] + +.included_second_service_connection: &included_second_service_connection + LIST_MERGE: + - - "SSC SSC2 gatts -S -z load -p 0xA4" + - ["R SSC2 C +GATTS:StartService,OK,A004"] + - - "SSC SSC2 gatts -S -z load -p 0xA1" + - ["R SSC2 C +GATTS:CreateService,OK,A001"] + - - "SSC SSC1 gatts -S -z add -p 0xA1" + - ["R SSC1 C +GATTS:StartService,OK,A001"] + - - "SSC SSC2 gatts -S -z include -p 0xA1 -i 0xA4" + - ["R SSC2 C +GATTS:AddIncludedService,OK"] + - - SSC SSC1 gattc -F -r + - ['R SSC1 C +GATTC:OK'] + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ["R SSC1 C +BLECONN:GapConnect,OK,0010", "R SSC2 C +BLECONN:GapConnect"] + +.table_include_table_service: &table_include_table_service + LIST_MERGE: + - - "SSC SSC2 gatts -S -z load -p 0xA5 -i 0xA2" + - ["R SSC2 C +GATTS:StartService,OK,A005"] + - - SSC SSC1 gattc -F -r + - ['R SSC1 C +GATTC:OK'] + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ["R SSC1 C +BLECONN:GapConnect,OK,0010", "R SSC2 C +BLECONN:GapConnect"] + +.table_include_service: &table_include_service + LIST_MERGE: + - - "SSC SSC2 gatts -S -z load -p 0xA5 -i 0xA0" + - ["R SSC2 C +GATTS:StartService,OK,A005"] + - - SSC SSC1 gattc -F -r + - ['R SSC1 C +GATTC:OK'] + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ["R SSC1 C +BLECONN:GapConnect,OK,0010", "R SSC2 C +BLECONN:GapConnect"] + +.register_notify_c107: ®ister_notify_c107 + LIST_MERGE: + - - "SSC SSC1 gattc -N -z register -s 0xA000 -c 0xC107 -p 0x10 -r " + - ["R SSC1 C +GATTC:RegNotify,OK,0010,A000,C107"] + +.register_indicate_c108: ®ister_indicate_c108 + LIST_MERGE: + - - "SSC SSC1 gattc -N -z register -s 0xA000 -c 0xC108 -p 0x10 -r " + - ["R SSC1 C +GATTC:RegNotify,OK,0010,A000,C108"] + +.stop_adv: &stop_adv + LIST_MERGE: + - - "SSC SSC2 bleadv -D -z stop" + - ["R SSC2 C +BLEADV:Stop"] + +test cases: +- ID: BLUEDROID_GATT_01001 + <<: *GATT_CASE + test point 2: BLE GATT server create service + summary: create service, add char and descriptor and start service for BLUEDOID + steps: | + 1. create preset service 0xA000 + expected result: | + 1. succeed + initial condition: BLE_INIT1 + test environment: SSC_T1_4 + cmd set: + - "" + - - "SSC SSC1 gatts -S -z load -p 0xA0" + - ["R SSC1 C +GATTS:StartService,OK,A000"] +- ID: BLUEDROID_GATT_01002 + <<: *GATT_CASE + test point 2: BLE GATT server create service + summary: create service and include another service for BLUEDROID + steps: | + 1. create preset service 0xA000 + 2. create preset service 0xA001 + expected result: | + 1. succeed + 2. succeed + initial condition: BLE_INIT1 + test environment: SSC_T1_4 + cmd set: + - "" + - - "SSC SSC1 gatts -S -z load -p 0xA0" + - ["R SSC1 C +GATTS:StartService,OK,A000"] + - - "SSC SSC1 gatts -S -z load -p 0xA1" + - ["R SSC1 C +GATTS:CreateService,OK,A001"] + - - "SSC SSC1 gatts -S -z add -p 0xA1" + - ["R SSC1 C +GATTS:StartService,OK,A001"] +- ID: BLUEDROID_GATT_20001 + <<: *GATT_CASE + test point 2: BLE GATT client service / char discovery + summary: GATT client discover manual primary service for BLUEDOID + steps: | + 1. DUT2 create preset service 0xA000 + 2. DUT2 create preset service 0xA001 + 3. DUT1 connect to DUT2 + 4. DUT1 do primary service discovery + expected result: | + 1. succeed + 2. succeed + 3. succeed + 4. found service 0xA000 and 0xA001 + initial condition: BLE_INIT2 + cmd set: + - "" + - *included_primary_service_connection + - - "SSC SSC1 gattc -D -z primaryService -p 0x10" + - ["R SSC1 C +GATTC:DiscoverService,A000 C +GATTC:DiscoverService,A001"] + - - SSC SSC1 gattc -F -r + - ['R SSC1 C +GATTC:OK'] +- ID: BLUEDROID_GATT_20002 + <<: *GATT_CASE + test point 2: BLE GATT client service / char discovery + summary: GATT client get manual included service for BLUEDOID + steps: | + 1. DUT2 create preset service 0xA000 + 2. DUT2 create preset service 0xA001 + 3. DUT1 connect to DUT2 + 4. DUT1 do primary service discovery + 5. DUT1 get included service 0xA000 from service 0xA001 + expected result: | + 1. succeed + 2. succeed + 3. succeed + 4. succeed + 5. get included service 0xA000 from service 0xA001 + initial condition: BLE_INIT2 + cmd set: + - "" + - *included_primary_service_connection + - - "SSC SSC1 gattc -D -z primaryService -p 0x10" + - ["R SSC1 C +GATTC:DiscoverService,A000 A :GATTC:DiscoverService,A001,(\\d+-\\d+)"] + - - "SSC SSC1 gattc -D -z includedService -p 0x10 -s 0xA001 -i 0xA000 -q -k 1" + - ["R SSC1 C +GATTC:IncludedService,0010,A001,A000"] + - - SSC SSC1 gattc -F -r + - ['R SSC1 C +GATTC:OK'] +- ID: BLUEDROID_GATT_20003 + <<: *GATT_CASE + test point 2: BLE GATT client service / char discovery + summary: GATT client discover table primary service (table service include table service) for BLUEDROID + steps: | + 1. DUT2 create preset service 0xA002 + 2. DUT2 create preset service 0xA005 + 3. DUT1 connect to DUT2 + 4. DUT1 do primary service discovery + expected result: | + 1. succeed + 2. succeed + 3. succeed + 4. found service 0xA002 and 0xA005 + initial condition: BLE_INIT3 + cmd set: + - "" + - *table_include_table_service + - - "SSC SSC1 gattc -D -z primaryService -p 0x10" + - ["R SSC1 C +GATTC:DiscoverService,A002 C +GATTC:DiscoverService,A005"] +- ID: BLUEDROID_GATT_20004 + <<: *GATT_CASE + test point 2: BLE GATT client service / char discovery + summary: GATT client get table included service for BLUEDROID + steps: | + 1. DUT2 create preset service 0xA002 + 2. DUT2 create preset service 0xA005 + 3. DUT1 connect to DUT2 + 4. DUT1 do primary service discovery + 5. DUT1 get included service 0xA002 from service 0xA005 + expected result: | + 1. succeed + 2. succeed + 3. succeed + 4. succeed + 5. get included service 0xA002 from service 0xA005 + initial condition: BLE_INIT3 + cmd set: + - "" + - *table_include_table_service + - - "SSC SSC1 gattc -D -z primaryService -p 0x10" + - ["R SSC1 C +GATTC:DiscoverService,A002 A :GATTC:DiscoverService,A005,(\\d+-\\d+)"] + - - "SSC SSC1 gattc -D -z includedService -p 0x10 -s 0xA005 -i 0xA002 -q -k 1" + - ["R SSC1 C +GATTC:IncludedService,0010,A005,A002"] +- ID: BLUEDROID_GATT_20005 + <<: *GATT_CASE + test point 2: BLE GATT client service / char discovery + summary: GATT client discover table primary service (table service include manual service) for BLUEDROID + steps: | + 1. DUT2 create preset service 0xA000 + 2. DUT2 create preset service 0xA005 + 3. DUT1 connect to DUT2 + 4. DUT1 do primary service discovery + expected result: | + 1. succeed + 2. succeed + 3. succeed + 4. found service 0xA000 and 0xA005 + initial condition: BLE_INIT2 + cmd set: + - "" + - *table_include_service + - - "SSC SSC1 gattc -D -z primaryService -p 0x10" + - ["R SSC1 C +GATTC:DiscoverService,A000 C +GATTC:DiscoverService,A005"] +- ID: BLUEDROID_GATT_20006 + <<: *GATT_CASE + test point 2: BLE GATT client service / char discovery + summary: GATT client get table included manual service for BLUEDROID + steps: | + 1. DUT2 create preset service 0xA000 + 2. DUT2 create preset service 0xA005 + 3. DUT1 connect to DUT2 + 4. DUT1 do primary service discovery + 5. DUT1 get included service 0xA000 from service 0xA005 + expected result: | + 1. succeed + 2. succeed + 3. succeed + 4. succeed + 5. get included service 0xA000 from service 0xA005 + initial condition: BLE_INIT2 + cmd set: + - "" + - *table_include_service + - - "SSC SSC1 gattc -D -z primaryService -p 0x10" + - ["R SSC1 C +GATTC:DiscoverService,A000 A :GATTC:DiscoverService,A005,(\\d+-\\d+)"] + - - "SSC SSC1 gattc -D -z includedService -p 0x10 -s 0xA005 -i 0xA000 -q -k 1" + - ["R SSC1 C +GATTC:IncludedService,0010,A005,A000"] +- ID: BLUEDROID_GATT_21001 + <<: *GATT_CASE + test point 2: BLE GATT client read char and descriptor + summary: GATT client read short char for BLUEDROID + steps: | + 1. DUT1 do discover + 2. GATT client read 1 byte short char + expected result: | + 1. succeed + 2. read succeed + cmd set: + - "" + - *primary_service_discovery + - - "SSC SSC1 gattc -R -z char -s 0xA000 -c 0xC100 -p 0x10" + - ["R SSC1 C +GATTC:ReadOnce,0010,A000,C100,1", "R SSC1 C +GATTC:Read,OK,0010,A000,C100"] +- ID: BLUEDROID_GATT_21002 + <<: *GATT_CASE + test point 2: BLE GATT client read char and descriptor + summary: GATT client read long char for BLUEDROID + steps: | + 1. DUT1 do service discovery + 2. DUT1 GATT client read 256 bytes long char + expected result: | + 1. succeed + 2. read succeed + cmd set: + - "" + - *primary_service_discovery + - - "SSC SSC1 gattc -R -z char -s 0xA000 -c 0xC101 -p 0x10" + - ["R SSC1 C +GATTC:ReadOnce,0010,A000,C101,256", "R SSC1 C +GATTC:Read,OK,0010,A000,C101"] +- ID: BLUEDROID_GATT_21003 + <<: *GATT_CASE + test point 2: BLE GATT client read char and descriptor + summary: GATT client read short descriptor for BLUEDROID + steps: | + 1. DUT1 do service discovery + 2. GATT client read short descriptor + expected result: | + 1. succeed + 2. read succeed + cmd set: + - "" + - *primary_service_discovery + - - "SSC SSC1 gattc -R -z descriptor -s 0xA000 -c 0xC107 -d 0x2902 -p 0x10" + - ["R SSC1 C +GATTC:ReadOnce,0010,A000,C107,2902,2", "R SSC1 C +GATTC:ReadDescriptor,OK,0010,A000,C107,2902"] +- ID: BLUEDROID_GATT_21004 + <<: *GATT_CASE + test point 2: BLE GATT client read char and descriptor + summary: GATT client read long descriptor for BLUEDROID + steps: | + 1. DUT1 do service discovery + 2. GATT client read long descriptor + expected result: | + 1. succeed + 2. read succeed + cmd set: + - "" + - *primary_service_discovery + - - "SSC SSC1 gattc -R -z descriptor -s 0xA000 -c 0xC100 -d 0x2901 -p 0x10" + - ["R SSC1 C +GATTC:ReadOnce,0010,A000,C100,2901,2", "R SSC1 C +GATTC:ReadDescriptor,OK,0010,A000,C100,2901"] +- ID: BLUEDROID_GATT_21005 + <<: *GATT_CASE + test point 2: BLE GATT client read char and descriptor + summary: GATT client read short char of an included service for BLUEDROID + steps: | + 1. DUT2 create preset service 0xA000 + 2. DUT2 create preset service 0xA001 + 3. DUT1 connect to DUT2 + 4. DUT1 do discover + 5. GATT client read 1 byte short char + expected result: | + 1. succeed + 2. succeed + 3. succeed + 4. succeed + 5. succeed + initial condition: BLE_INIT2 + cmd set: + - "" + - - "SSC SSC2 gatts -S -z load -p 0xA1" + - ["R SSC2 C +GATTS:CreateService,OK,A001"] + - - SSC SSC1 gattc -F -r + - ['R SSC1 C +GATTC:OK'] + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ["R SSC1 C +BLECONN:GapConnect,OK,0010", "R SSC2 C +BLECONN:GapConnect"] + - *primary_service_discovery + - - "SSC SSC1 gattc -R -z char -s 0xA000 -c 0xC100 -p 0x10" + - ["R SSC1 C +GATTC:ReadOnce,0010,A000,C100,1", "R SSC1 C +GATTC:Read,OK,0010,A000,C100"] +- ID: BLUEDROID_GATT_21006 + <<: *GATT_CASE + test point 2: BLE GATT client read char and descriptor + summary: GATT client read short descriptor or an included service for BLUEDROID + allow fail: 1/2 + steps: | + 1. DUT2 create preset service 0xA000 + 2. DUT2 create preset service 0xA001 + 3. DUT1 connect to DUT2 + 4. DUT1 do discover + 5. GATT client read 1 byte short descriptor + expected result: | + 1. succeed + 2. succeed + 3. succeed + 4. succeed + 5. succeed + initial condition: BLE_INIT2 + cmd set: + - "" + - - "SSC SSC2 gatts -S -z load -p 0xA1" + - ["R SSC2 C +GATTS:CreateService,OK,A001"] + - - SSC SSC1 gattc -F -r + - ['R SSC1 C +GATTC:OK'] + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ["R SSC1 C +BLECONN:GapConnect,OK,0010", "R SSC2 C +BLECONN:GapConnect"] + - *primary_service_discovery + - - "SSC SSC1 gattc -R -z descriptor -s 0xA000 -c 0xC107 -d 0x2902 -p 0x10" + - ["R SSC1 C +GATTC:ReadOnce,0010,A000,C107,2902,2", "R SSC1 C +GATTC:ReadDescriptor,OK,0010,A000,C107,2902"] +- ID: BLUEDROID_GATT_22001 + <<: *GATT_CASE + test point 2: BLE GATT client write char and descriptor + summary: GATT client write with response to a short char with response for BLUEDROID + steps: | + 1. DUT1 do service discovery + 2. GATT client write with response to short char with response + expected result: | + 1. succeed + 2. write succeed + cmd set: + - "" + - *primary_service_discovery + - - "SSC SSC1 gattc -W -z char -s 0xA000 -c 0xC102 -p 0x10 -v 0x01" + - ["R SSC1 C +GATTC:WriteOnce,0010,A000,C102", "R SSC1 C +GATTC:Write,OK,0010,A000,C102"] +- ID: BLUEDROID_GATT_22002 + <<: *GATT_CASE + test point 2: BLE GATT client write char and descriptor + summary: GATT client write without response to a short char without response for BLUEDROID + steps: | + 1. DUT1 do service discovery + 2. GATT client write without response to short char without response + expected result: | + 1. succeed + 2. write succeed + cmd set: + - "" + - *primary_service_discovery + - - "SSC SSC1 gattc -W -z char -s 0xA000 -c 0xC103 -p 0x10 -v 0x01 -w 1" + - - "P SSC1 C +GATTC:WriteOnce,0010,A000,C103" + - "P SSC2 C +GATTS:Write,OK,A000,C103" + - "P SSC1 C +GATTC:Write,OK,0010,A000,C103" +- ID: BLUEDROID_GATT_22003 + <<: *GATT_CASE + test point 2: BLE GATT client write char and descriptor + summary: GATT client prepare write and do execute for BLUEDROID + steps: | + 1. DUT1 do service discovery + 2. GATT client prepare write and do execute + expected result: | + 1. succeed + 2. write succeed + cmd set: + - "" + - *primary_service_discovery + - - "SSC SSC1 gattc -W -z longChar -s 0xA000 -c 0xC110 -p 0x10 -l 256" + - ["P SSC1 C +GATTC:Write,OK,0010,A000,C110"] +- ID: BLUEDROID_GATT_22004 + <<: *GATT_CASE + test point 2: BLE GATT client write char and descriptor + summary: GATT client prepare write and do cancel for BLUEDROID + steps: | + 1. DUT1 do service discovery + 2. GATT client prepare write and do cancel + expected result: | + 1. succeed + 2. write succeed + cmd set: + - "" + - *primary_service_discovery + - - "SSC SSC1 gattc -W -z longChar -s 0xA000 -c 0xC110 -p 0x10 -l 256 -e 0" + - ["P SSC1 C +GATTC:Write,OK,0010,A000,C110"] + - - "SSC SSC1 gattc -W -z char -s 0xA000 -c 0xC110 -p 0x10 -l 256 -e 0" + - ["P SSC1 C +GATTC:Write,OK,0010,A000,C110"] +- ID: BLUEDROID_GATT_22005 + <<: *GATT_CASE + test point 2: BLE GATT client write char and descriptor + summary: GATT client write to a short descriptor for BLUEDROID + steps: | + 1. DUT1 do service discovery + 2. GATT client write to short descriptor + expected result: | + 1. succeed + 2. write succeed + cmd set: + - "" + - *primary_service_discovery + - - "SSC SSC1 gattc -W -z descriptor -s 0xA000 -c 0xC107 -d 0x2902 -p 0x10 -v 0x0100" + - ["R SSC1 C +GATTC:WriteOnce,0010,A000,C107,2902", "R SSC1 C +GATTC:WriteDescriptor,OK,0010,A000,C107,2902"] +- ID: BLUEDROID_GATT_22006 + <<: *GATT_CASE + test point 2: BLE GATT client write char and descriptor + summary: GATT client write to long descriptor and execute for BLUEDROID + steps: | + 1. DUT1 do service discovery + 2. GATT client write to long descriptor and execute + expected result: | + 1. succeed + 2. write succeed + cmd set: + - "" + - *primary_service_discovery + - - "SSC SSC1 gattc -W -z longDescriptor -s 0xA000 -c 0xC100 -d 0x2901 -p 0x10 -l 256" + - ["P SSC1 C +GATTC:WriteDescriptor,OK,0010,A000,C100,2901"] +- ID: BLUEDROID_GATT_22007 + <<: *GATT_CASE + test point 2: BLE GATT client write char and descriptor + summary: GATT client write to long descriptor using write API for BLUEDROID + steps: | + 1. DUT1 do service discovery + 2. GATT client write to long descriptor and execute + expected result: | + 1. succeed + 2. write succeed + cmd set: + - "" + - *primary_service_discovery + - - "SSC SSC1 gattc -W -z descriptor -s 0xA000 -c 0xC100 -d 0x2901 -p 0x10 -l 256" + - ["P SSC1 C +GATTC:WriteDescriptor,OK,0010,A000,C100,2901"] +- ID: BLUEDROID_GATT_22008 + <<: *GATT_CASE + test point 2: BLE GATT client write char and descriptor + summary: GATT client write to an included char for BLUEDROID + allow fail: 1/2 + steps: | + 1. DUT2 create preset service 0xA000 + 2. DUT2 create preset service 0xA001 + 3. DUT1 connect to DUT2 + 4. DUT1 do discover + 5. GATT client write with response to short char with response + expected result: | + 1. succeed + 2. succeed + 3. succeed + 4. succeed + 5. succeed + initial condition: BLE_INIT2 + cmd set: + - "" + - - "SSC SSC2 gatts -S -z load -p 0xA1" + - ["R SSC2 C +GATTS:CreateService,OK,A001"] + - - SSC SSC1 gattc -F -r + - ['R SSC1 C +GATTC:OK'] + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ["R SSC1 C +BLECONN:GapConnect,OK,0010", "R SSC2 C +BLECONN:GapConnect"] + - *primary_service_discovery + - - "SSC SSC1 gattc -W -z char -s 0xA000 -c 0xC102 -p 0x10 -v 0x01" + - ["R SSC1 C +GATTC:WriteOnce,0010,A000,C102", "R SSC1 C +GATTC:Write,OK,0010,A000,C102"] +- ID: BLUEDROID_GATT_22009 + <<: *GATT_CASE + test point 2: BLE GATT client write char and descriptor + summary: GATT client write to an included descriptor for BLUEDROID + steps: | + 1. DUT2 create preset service 0xA000 + 2. DUT2 create preset service 0xA001 + 3. DUT1 connect to DUT2 + 4. DUT1 do discover + 5. GATT client write to short descriptor + expected result: | + 1. succeed + 2. succeed + 3. succeed + 4. succeed + 5. succeed + initial condition: BLE_INIT2 + cmd set: + - "" + - - "SSC SSC2 gatts -S -z load -p 0xA1" + - ["R SSC2 C +GATTS:CreateService,OK,A001"] + - - SSC SSC1 gattc -F -r + - ['R SSC1 C +GATTC:OK'] + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ["R SSC1 C +BLECONN:GapConnect,OK,0010", "R SSC2 C +BLECONN:GapConnect"] + - *primary_service_discovery + - - "SSC SSC1 gattc -W -z descriptor -s 0xA000 -c 0xC107 -d 0x2902 -p 0x10 -v 0x0100" + - ["R SSC1 C +GATTC:WriteOnce,0010,A000,C107,2902", "R SSC1 C +GATTC:WriteDescriptor,OK,0010,A000,C107,2902"] +- ID: BLUEDROID_GATT_23001 + <<: *GATT_CASE + test point 2: BLE GATT client receive notify and indication + summary: GATT client register/unregister notify for BLUEDROID + steps: | + 1. DUT1 do service discovery + 2. DUT1 register notify on notification char + 3. DUT1 register notify on indication char + expected result: | + 1. succeed + 2. succeed + 3. succeed + cmd set: + - "" + - *primary_service_discovery + - *register_notify_c107 + - *register_indicate_c108 + - - "SSC SSC1 gattc -N -z unregister -s 0xA000 -c 0xC107 -p 0x10 -r " + - ["R SSC1 C +GATTC:UnRegNotify,OK,0010,A000,C107"] + - - "SSC SSC1 gattc -N -z unregister -s 0xA000 -c 0xC108 -p 0x10 -r " + - ["R SSC1 C +GATTC:UnRegNotify,OK,0010,A000,C108"] +- ID: BLUEDROID_GATT_23002 + <<: *GATT_CASE + test point 2: BLE GATT client receive notify and indication + summary: GATT client receive notify for BLUEDROID + steps: | + 1. DUT1 do service discovery + 2. DUT1 register notify on notification char and write to CCC + 3. DUT2 do notify + expected result: | + 1. succeed + 2. succeed + 3. DUT1 recv notify + cmd set: + - "" + - *primary_service_discovery + - *register_notify_c107 + - - "SSC SSC1 gattc -W -z descriptor -s 0xA000 -c 0xC107 -d 0x2902 -p 0x10 -v 0x0100" + - ["R SSC1 C +GATTC:WriteOnce,0010,A000,C107,2902", "R SSC1 C +GATTC:WriteDescriptor,OK,0010,A000,C107,2902"] + - - "SSC SSC2 gatts -N -c 0xC107 -p 0xA0 -v 0x01 -r " + - ["R SSC1 C +GATTC:Notification,0010,A000,C107,1"] +- ID: BLUEDROID_GATT_23003 + <<: *GATT_CASE + test point 2: BLE GATT client receive notify and indication + summary: GATT client receive indication for BLUEDROID + steps: | + 1. DUT1 do service discovery + 2. DUT1 register notify on inidcation char and write to CCC + 3. DUT2 do indication + expected result: | + 1. succeed + 2. succeed + 3. DUT1 recv indication + cmd set: + - "" + - *primary_service_discovery + - *register_indicate_c108 + - - "SSC SSC1 gattc -W -z descriptor -s 0xA000 -c 0xC108 -d 0x2902 -p 0x10 -v 0x0002" + - ["R SSC1 C +GATTC:WriteOnce,0010,A000,C108,2902", "R SSC1 C +GATTC:WriteDescriptor,OK,0010,A000,C108,2902"] + - - "SSC SSC2 gatts -I -c 0xC108 -p 0xA0 -v 0x01 -r " + - ["R SSC1 C +GATTC:Indication,0010,A000,C108,1"] +- ID: BLUEDROID_GATT_23004 + <<: *GATT_CASE + test point 2: BLE GATT client receive notify and indication + summary: GATT client can't receive notification/indication without write to CCC (manual service) for BLUEDROID + steps: | + 1. DUT1 do service discovery + 2. DUT1 register notify on notify and inidcation char + 3. DUT2 do notify and indication + expected result: | + 1. succeed + 2. succeed + 3. DUT1 can recv notify and indication (this is aganist Spec, but a reasonable behavior in bluedroid) + cmd set: + - "" + - *primary_service_discovery + - *register_notify_c107 + - *register_indicate_c108 + - - "SSC SSC1 gattc -W -z descriptor -s 0xA000 -c 0xC107 -d 0x2902 -p 0x10 -v 0x0000" + - ["R SSC1 C +GATTC:WriteOnce,0010,A000,C107,2902", "R SSC1 C +GATTC:WriteDescriptor,OK,0010,A000,C107,2902"] + - - "SSC SSC2 gatts -N -c 0xC107 -p 0xA0 -v 0x01 -r " + - ["P SSC1 C +GATTC:Notification,0010,A000,C107,1"] + - - "SSC SSC2 gatts -I -c 0xC108 -p 0xA0 -v 0x01 -r " + - ["P SSC1 C +GATTC:Indication,0010,A000,C108,1"] +- ID: BLUEDROID_GATT_24001 + <<: *GATT_CASE + test point 2: BLE GATT client do invalid read + summary: GATT client read to a char without read property for BLUEDROID + steps: | + 1. DUT1 do service discovery + 2. DUT1 read to a char without read property + expected result: | + 1. succeed + 2. failed + cmd set: + - "" + - *primary_service_discovery + - - "SSC SSC1 gattc -R -z char -s 0xA000 -c 0xC103 -p 0x10" + - ["P SSC1 C +GATTC:Read,ERROR"] +- ID: BLUEDROID_GATT_24002 + <<: *GATT_CASE + test point 2: BLE GATT client do invalid read + summary: GATT client read to a descriptor without read property for BLUEDROID + steps: | + 1. DUT1 do service discovery + 2. DUT1 read to a descriptor without read property + expected result: | + 1. succeed + 2. failed + cmd set: + - "" + - *primary_service_discovery + - - "SSC SSC1 gattc -R -z descriptor -s 0xA000 -c 0xC102 -d 0x2901 -p 0x10" + - ["P SSC1 C +GATTC:Read,ERROR"] +- ID: BLUEDROID_GATT_25001 + <<: *GATT_CASE + test point 2: BLE GATT client do invalid write + summary: GATT client write with response to a char without write property for BLUEDROID + steps: | + 1. DUT1 do service discovery + 2. DUT1 write with response to a char without write property + expected result: | + 1. succeed + 2. failed + cmd set: + - "" + - *primary_service_discovery + - - "SSC SSC1 gattc -W -z char -s 0xA000 -c 0xC100 -p 0x10 -l 1" + - ["R SSC1 C +GATTC:Write,ERROR"] +- ID: BLUEDROID_GATT_25002 + <<: *GATT_CASE + test point 1: basic function + test point 2: BLE GATT client do invalid write + summary: GATT client write without response to a char without write property for BLUEDROID + steps: | + 1. DUT1 do service discovery + 2. DUT1 write without response to a char without write property + expected result: | + 1. succeed + 2. succeed (write without response always succeed) + cmd set: + - "" + - *primary_service_discovery + - - "SSC SSC1 gattc -W -z char -s 0xA000 -c 0xC100 -p 0x10 -l 1 -w 1" + - ["R SSC1 C +GATTC:Write,OK"] +- ID: BLUEDROID_GATT_25003 + <<: *GATT_CASE + test point 2: BLE GATT client do invalid write + summary: GATT client write to a descriptor without write property for BLUEDROID + steps: | + 1. DUT1 do service discovery + 2. DUT1 write to a descriptor without write property + expected result: | + 1. succeed + 2. failed + cmd set: + - "" + - *primary_service_discovery + - - "SSC SSC1 gattc -W -z descriptor -s 0xA000 -c 0xC101 -d 0x2901 -p 0x10 -l 1" + - ["R SSC1 C +GATTC:Write,ERROR"] +- ID: BLUEDROID_GATT_25004 + <<: *GATT_CASE + test point 2: BLE GATT client do invalid write + summary: GATT client prepare write to a char without write property for BLUEDROID + steps: | + 1. DUT1 do service discovery + 2. DUT1 prepare write to a char without write property + expected result: | + 1. succeed + 2. failed + cmd set: + - "" + - *primary_service_discovery + - - "SSC SSC1 gattc -W -z longChar -s 0xA000 -c 0xC100 -p 0x10 -l 256" + - ["R SSC1 C +GATTC:Write,ERROR"] +- ID: BLUEDROID_GATT_25005 + <<: *GATT_CASE + test point 2: BLE GATT client do invalid write + summary: GATT client prepare write to a descriptor without write property for BLUEDROID + steps: | + 1. DUT1 do service discovery + 2. DUT1 prepare write to a descriptor without write property + expected result: | + 1. succeed + 2. failed + cmd set: + - "" + - *primary_service_discovery + - - "SSC SSC1 gattc -W -z longDescriptor -s 0xA000 -c 0xC101 -d 0x2901 -p 0x10 -l 256" + - ["R SSC1 C +GATTC:Write,ERROR"] +- ID: BLUEDROID_GATT_25006 + <<: *GATT_CASE + test point 2: BLE GATT client do invalid write + summary: GATT client write with response to a char not send response for BLUEDROID + steps: | + 1. DUT1 do service discovery + 2. DUT1 write with response to a char not send response + expected result: | + 1. succeed + 2. failed + cmd set: + - "" + - *primary_service_discovery + - - "SSC SSC1 gattc -W -z char -s 0xA000 -c 0xC103 -p 0x10 -v 0x01" + - ["R SSC1 C +GATTC:Write,ERROR"] +- ID: BLUEDROID_GATT_25007 + <<: *GATT_CASE + test point 2: BLE GATT client do invalid write + summary: GATT client write without response to a char will send response for BLUEDROID + steps: | + 1. DUT1 do service discovery + 2. DUT1 write without response to a char will send response + expected result: | + 1. succeed + 2. succeed (write without response always succeed) + cmd set: + - "" + - *primary_service_discovery + - - "SSC SSC1 gattc -W -z char -s 0xA000 -c 0xC102 -p 0x10 -v 0x01 -w 1" + - ["P SSC1 C +GATTC:WriteOnce"] +- ID: BLUEDROID_GATT_25013 + <<: *GATT_CASE + test point 2: BLE GATT client do invalid write + summary: GATT client write with response to a char created by table not send response + steps: | + 1. DUT1 do service discovery + 2. DUT1 write with response to auto reply char created by table not send response + 3. DUT1 write with response to app reply char created by table not send response + expected result: | + 1. succeed + 2. succeed(BLE Spec do not define the behavior of this case. IDF implementation will return success when GATTC write with response and recv response from remote side) + 3. failed + initial condition: BLE_CONN3 + cmd set: + - "" + - *primary_service_discovery + - - "SSC SSC1 gattc -W -z char -s 0xA002 -c 0xC303 -p 0x10 -v 0x01 -r " + - ["R SSC1 C +GATTC:Write,OK,0010,A002,C303"] + - - "SSC SSC1 gattc -W -z char -s 0xA002 -c 0xC313 -p 0x10 -v 0x01 -r " + - ["R SSC1 C +GATTC:Write,ERROR"] +- ID: BLUEDROID_GATT_26001 + <<: *GATT_CASE + test point 2: BLE GATT client set mtu + summary: GATT client config different mtu size for BLUEDOID + steps: | + 1. set mtu size 22 + 2. set mtu size 23 + 3. set mtu size 517 + 4. set mtu size 518 + expected result: | + 1. failed + 2. succeed + 3. succeed + 4. failed + cmd set: + - "" + - - "SSC SSC1 bleconn -D -z all" + - ["P SSC1 C +BLECONN:GapDisconnect,OK", "P SSC2 C +BLECONN:GapDisconnect,OK"] + - - "SSC SSC1 gattc -S -m 22 " + - ["R SSC1 C +GATTC:ERROR"] + - - "SSC SSC1 gattc -S -m 23" + - ["R SSC1 C +GATTC:OK"] + - - "SSC SSC1 gattc -S -m 517" + - ["R SSC1 C +GATTC:OK"] + - - "SSC SSC1 gattc -S -m 518" + - ["R SSC1 C +GATTC:ERROR"] +- ID: BLUEDROID_GATT_26002 + <<: *GATT_CASE + test point 2: BLE GATT server set mtu + summary: GATT server config different mtu size for BLUEDOID + steps: | + 1. set mtu size 22 + 2. set mtu size 23 + 3. set mtu size 517 + 4. set mtu size 518 + expected result: | + 1. failed + 2. succeed + 3. succeed + 4. failed + cmd set: + - "" + - - "SSC SSC1 bleconn -D -z all" + - ["P SSC1 C +BLECONN:GapDisconnect,OK", "P SSC2 C +BLECONN:GapDisconnect,OK"] + - - "SSC SSC2 gatts -C -m 22" + - ["R SSC2 C +GATTS:ERROR"] + - - "SSC SSC2 gatts -C -m 23" + - ["R SSC2 C +GATTS:OK"] + - - "SSC SSC2 gatts -C -m 517" + - ["R SSC2 C +GATTS:OK"] + - - "SSC SSC2 gatts -C -m 518" + - ["R SSC2 C +GATTS:ERROR"] +- ID: BLUEDROID_GATT_26004 + <<: *GATT_CASE + test point 2: BLE GATT client config mtu + summary: GATT read write on mtu size 261 + allow fail: 1/2 + steps: | + 1. config mtu size 261 + 2. do read + 3. do write + expected result: | + 1. succeed + 2. succeed + 3. succeed + cmd set: + - "" + - - "SSC SSC1 bleconn -D -p 0x10" + - ["P SSC1 C +BLECONN:GapDisconnect,OK", "P SSC2 C +BLECONN:GapDisconnect,OK"] + - - "SSC SSC1 gattc -S -m 261" + - ["R SSC1 C +GATTC:OK"] + - - "SSC SSC2 gatts -C -m 261" + - ["R SSC2 C +GATTS:OK"] + - - "SSC SSC2 bleadv -D -z start" + - ['R SSC2 C +BLEADV:OK'] + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ['R SSC1 C +BLECONN:GapConnect,OK', 'R SSC2 C +BLECONN:GapConnect'] + - - "SSC SSC1 gattc -C" + - ["R SSC1 C +GATTC:OK","P SSC[1-2] C ConfigMTU,OK,261"] + - *primary_service_discovery + - - "SSC SSC1 gattc -R -z char -p 0x10 -s 0xA000 -c 0xC101" + - ["R SSC1 C +GATTC:ReadOnce,0010,A000,C101,256"] + - - "SSC SSC1 gattc -W -z char -p 0x10 -s 0xA000 -c 0xC109 -l 256" + - ["R SSC1 C +GATTC:WriteOnce,0010,A000,C109"] + - - "SSC SSC1 gattc -W -z longChar -p 0x10 -s 0xA000 -c 0xC110 -l 512" + - ["R SSC1 C +GATTC:Write,OK,0010,A000,C110", "P SSC2 C +GATTS:ReliableWrite,OK"] +- ID: BLUEDROID_GATT_26005 + <<: *GATT_CASE + test point 2: BLE GATT client config mtu + summary: GATT read write on mtu size 517 for BLUEDOID + allow fail: 1/2 + steps: | + 1. config mtu size 517 + 2. do read + 3. do write + expected result: | + 1. succeed + 2. succeed + 3. succeed + cmd set: + - "" + - - "SSC SSC1 bleconn -D -z all" + - ["P SSC1 C +BLECONN:GapDisconnect,OK", "P SSC2 C +BLECONN:GapDisconnect,OK"] + - - "SSC SSC1 gattc -S -m 517" + - ["R SSC1 C +GATTC:OK"] + - - "SSC SSC2 gatts -C -m 517" + - ["R SSC2 C +GATTS:OK"] + - - "SSC SSC2 bleadv -D -z start" + - ['R SSC2 C +BLEADV:OK'] + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ['R SSC1 C +BLECONN:GapConnect,OK', 'R SSC2 C +BLECONN:GapConnect,OK'] + - - "SSC SSC1 gattc -C -r " + - ["P SSC1 C +GATTC:OK", "P SSC[1-2] C ConfigMTU,OK,517"] + - *primary_service_discovery + - - "SSC SSC1 gattc -R -z char -p 0x10 -s 0xA000 -c 0xC101" + - ["R SSC1 C +GATTC:ReadOnce,0010,A000,C101,256"] + - - "SSC SSC1 gattc -W -z char -p 0x10 -s 0xA000 -c 0xC109 -l 256" + - ["R SSC1 C +GATTC:WriteOnce,0010,A000,C109"] + - - "SSC SSC1 gattc -W -z char -p 0x10 -s 0xA000 -c 0xC109 -l 512" + - ["R SSC1 C +GATTC:WriteOnce,0010,A000,C109"] +- ID: BLUEDROID_GATT_27001 + <<: *GATT_CASE + test point 2: BLE GATT read multiple + summary: GATT client read 2 char and 11 char of same service for BLUEDROID + steps: | + 1. DUT1 do discover + 2. GATT client read 2 char + 3. GATT client read 11 char + expected result: | + 1. succeed + 2. succeed + 3. succeed + cmd set: + - "" + - *primary_service_discovery + - - "SSC SSC1 gattc -R -z multiple -u #0xC100##0xC101# -s 0xA000 -r " + - ['R SSC1 C +GATTC:ReadOnce,22', 'R SSC1 C +GATTC:ReadMultiple,OK'] + - - "SSC SSC1 gattc -R -z multiple -u #0xC100##0xC101##0xC107##0xC108##0xC109##0xC110##0xC100##0xC101##0xC107##0xC108##0xC109# -s 0xA000" + - ['R SSC1 C +GATTC:Read,ERROR'] +- ID: BLUEDROID_GATT_27002 + <<: *GATT_CASE + test point 2: BLE GATT read multiple + summary: GATT client read char and descriptor for BLUEDROID + steps: | + 1. DUT1 do discover + 2. GATT client read all char and descriptor + expected result: | + 1. succeed + 2. succeed + cmd set: + - "" + - *primary_service_discovery + - - "SSC SSC1 gattc -R -z multiple -u 0xA00xC100#0xA00xC101#0xA00xC1000x29010xA00xC1070x2902 -r " + - ['R SSC1 C +GATTC:ReadOnce', 'R SSC1 C +GATTC:ReadMultiple,OK'] +- ID: BLUEDROID_GATT_27003 + <<: *GATT_CASE + test point 2: BLE GATT read multiple + summary: GATT client read char and descriptor of table create service for BLUEDROID + steps: | + 1. DUT1 do discover + 2. GATT client read all char and descriptor + expected result: | + 1. succeed + 2. succeed + cmd set: + - "" + - - "SSC SSC2 gatts -S -z load -p 0xA2" + - ['R SSC2 C +GATTS:StartService,OK,A002'] + - *primary_service_discovery + - - "SSC SSC1 gattc -R -z multiple -u 0xA20xC300#0xA20xC301#0xA20xC310#0xA20xC311# -r " + - ['R SSC1 C +GATTC:ReadOnce', 'R SSC1 C +GATTC:ReadMultiple,OK'] +- ID: BLUEDROID_GATT_27004 + <<: *GATT_CASE + test point 2: BLE GATT read multiple + summary: GATT client read char and descriptor of included service and table service for BLUEDROID + initial condition: BLE_INIT2 + steps: | + 1. DUT2 load service included service and table service + 2. DUT1 search service + 3. GATT client read all char and descriptor of different services + expected result: | + 1. succeed + 2. succeed + 3. succeed + cmd set: + - "" + - - "SSC SSC2 gatts -S -z load -p 0xA2" + - ['R SSC2 C +GATTS:StartService,OK,A002'] + - *included_primary_service_connection + - *primary_service_discovery + - - "SSC SSC1 gattc -R -z multiple -u 0xA10xC200#0xA00xC100#0xA00xC101#0xA20xC300#0xA20xC301#" + - ['R SSC1 C +GATTC:ReadOnce', 'R SSC1 C +GATTC:ReadMultiple,OK'] +- ID: BLUEDROID_GATT_30004 + <<: *GATT_CASE + test point 2: BLE GATT multi connection service discovery test + summary: do primary service discovery when master and slave both create GATTC and GATTS for BLUEDOID + steps: | + 1. DUT1 do primary service discovery for DUT2 + 2. DUT2 do primary service discovery for DUT1 + expected result: | + 1. succeed + 2. succeed + initial condition: BLE_CONN4 + cmd set: + - "" + - - "SSC SSC2 bleconn -C -p 0x10 -a " + - ["R SSC2 C +BLE:GattcOpen,OK"] + - - "SSC SSC1 gattc -D -z primaryService -p 0x10 -r " + - ["R SSC1 C +GATTC:Discover,OK"] + - - "SSC SSC2 gattc -D -z primaryService -p 0x10 -r " + - ["R SSC2 C +GATTC:Discover,OK"] +- ID: BLUEDROID_GATT_31004 + <<: *GATT_CASE + test point 2: BLE GATT multi connection read test + summary: do read when master and slave both create GATTC and GATTS for BLUEDOID + steps: | + 1. DUT1 do primary service discovery for DUT2 + 2. DUT2 do primary service discovery for DUT1 + 3. DUT1 do read on DUT2 + 4. DUT2 do read on DUT1 + expected result: | + 1. succeed + 2. succeed + 3. succeed + 4. succeed + initial condition: BLE_CONN4 + cmd set: + - "" + - - "SSC SSC2 bleconn -C -p 0x10 -a " + - ["R SSC2 C +BLE:GattcOpen,OK"] + - - "SSC SSC[1-2] gattc -D -z primaryService -p 0x10 -r " + - ["R SSC[1-2] C +GATTC:Discover,OK"] + - - "SSC SSC[1-2] gattc -R -z char -s 0xA002 -c 0xC300 -p 0x10 -r " + - ["R SSC[1-2] C +GATTC:ReadOnce,0010,A002,C300,1"] + - - "SSC SSC[1-2] gattc -R -z char -s 0xA002 -c 0xC301 -p 0x10 -r " + - ["R SSC[1-2] C +GATTC:ReadOnce,0010,A002,C301,256"] +- ID: BLUEDROID_GATT_32004 + <<: *GATT_CASE + test point 2: BLE GATT multi connection write test + summary: do write when master and slave both create GATTC and GATTS for BLUEDOID + steps: | + 1. DUT1 do primary service discovery for DUT2 + 2. DUT2 do primary service discovery for DUT1 + 3. DUT1 do write on DUT2 + 4. DUT2 do write on DUT1 + expected result: | + 1. succeed + 2. succeed + 3. succeed + 4. succeed + initial condition: BLE_CONN4 + cmd set: + - "" + - - "SSC SSC2 bleconn -C -p 0x10 -a " + - ["R SSC2 C +BLE:GattcOpen,OK"] + - - "SSC SSC[1-2] gattc -D -z primaryService -p 0x10 -r " + - ["R SSC[1-2] C +GATTC:Discover,OK"] + - - "SSC SSC[1-2] -W -z char -s 0xA002 -c 0xC302 -l 1 -p 0x10 -r " + - ["R SSC[1-2] C +GATTC:Write,OK,0010,A002,C302"] + - - "SSC SSC[1-2] -W -z char -s 0xA002 -c 0xC304 -l 256 -p 0x10 -r " + - ["R SSC[1-2] C +GATTC:Write,OK,0010,A002,C304"] +- ID: BLUEDROID_GATT_33004 + <<: *GATT_CASE + test point 2: BLE GATT multi connection notify test + summary: do notify when master and slave both create GATTC and GATTS for BLUEDOID + steps: | + 1. DUT1 do primary service discovery for DUT2 + 2. DUT2 do primary service discovery for DUT1 + 3. DUT[1-2] do register notify + 4. DUT1 and DUT2 send notify to each other + expected result: | + 1. succeed + 2. succeed + 3. succeed + 4. receive notification + initial condition: BLE_CONN4 + cmd set: + - "" + - - "SSC SSC2 bleconn -C -p 0x10 -a " + - ["R SSC2 C +BLE:GattcOpen,OK"] + - - "SSC SSC[1-2] gattc -D -z primaryService -p 0x10 -r " + - ["R SSC[1-2] C +GATTC:Discover,OK"] + - - "SSC SSC[1-2] gattc -N -z register -s 0xA002 -c 0xC305 -p 0x10 -r " + - ["R SSC[1-2] C +GATTC:RegNotify,OK,0010,A002,C305"] + - - "SSC SSC[1-2] gatts -N -c 0xC305 -l 1 -p 0xA2 -r " + - ['P SSC[1,2] RE "\+GATTC:Notification,0010,A002,C305,1,%%s"%%()'] +- ID: BLUEDROID_GATT_34004 + <<: *GATT_CASE + test point 2: BLE GATT multi connection indicate test + summary: do indicate when master and slave both create GATTC and GATTS for BLUEDOID + steps: | + 1. DUT1 do primary service discovery for DUT2 + 2. DUT2 do primary service discovery for DUT1 + 3. DUT[1-2] do register indication + 4. DUT1 and DUT2 send notify to each other + expected result: | + 1. succeed + 2. succeed + 3. succeed + 4. receive indication + initial condition: BLE_CONN4 + cmd set: + - "" + - - "SSC SSC2 bleconn -C -p 0x10 -a " + - ["R SSC2 C +BLE:GattcOpen,OK"] + - - "SSC SSC[1-2] gattc -D -z primaryService -p 0x10 -r " + - ["R SSC[1-2] C +GATTC:Discover,OK"] + - - "SSC SSC[1-2] gattc -N -z register -s 0xA002 -c 0xC306 -p 0x10 -r " + - ["R SSC[1-2] C +GATTC:RegNotify,OK,0010,A002,C306"] + - - "SSC SSC[1-2] gatts -I -c 0xC306 -l 1 -p 0xA2 -r " + - ['P SSC[1,2] RE "\+GATTC:Indication,0010,A002,C306,1,%%s"%%()'] +- ID: BLUEDROID_GATT_40001 + <<: *GATT_CASE + auto test: 'No' + test point 2: test if BLE work after switch off some sub modules + summary: GATTC only and GATTS only test for BLUEDROID + steps: | + 1. download GATTC only bin to DUT1 and GATTS only bin to DUT2 + 2. DUT2 start adv, enable service 0xA000, DUT1 connect to DUT2 + 3. DUT1 connect to DUT2 + 4. DUT1 do primary service discovery + 5. DUT1 do read + 6. DUT1 do read descriptor + 7. DUT1 do write + 8. DUT1 do write descriptor + 9. DUT1 register for notify and indication + 10. DUT2 do notify + 11. DUT2 do indicate + expected result: | + 1. succeed + 2. succeed + 3. succeed + 4. succeed + 5. succeed + 6. succeed + 7. succeed + 8. succeed + 9. succeed + 10. succeed + 11. succeed + initial condition: None + execution time: 5 + CI ready: 'No' + cmd set: + - "" + - - SSC SSC[1-2] reboot + - ['R SSC[1-2] C !!!ready!!!'] + - - SSC SSC[1-2] ble -R + - ['R SSC[1-2] C +BLE:OK'] + - - SSC SSC2 bleadv -D -z start + - ['R SSC2 C +BLEADV:OK'] + - - SSC SSC2 gatts -S -z load -p 0xA0 + - ['R SSC2 C +GATTS:StartService,OK,A000'] + - - SSC SSC1 bleconn -C -p 0x10 -a + - ['R SSC1 C +BLECONN:GapConnect,OK', 'R SSC2 C +BLECONN:GapConnect'] + - *primary_service_discovery + - - "SSC SSC1 gattc -R -z char -s 0xA000 -c 0xC100 -p 0x10" + - ["R SSC1 C +GATTC:ReadOnce,0010,A000,C100,1", "R SSC1 C +GATTC:Read,OK,0010,A000,C100"] + - - "SSC SSC1 gattc -W -z char -s 0xA000 -c 0xC102 -p 0x10 -v 0x01" + - ["R SSC1 C +GATTC:WriteOnce,0010,A000,C102", "R SSC1 C +GATTC:Write,OK,0010,A000,C102"] + - - "SSC SSC1 gattc -R -z descriptor -s 0xA000 -c 0xC100 -d 0x2901 -p 0x10" + - ["R SSC1 C +GATTC:ReadOnce,0010,A000,C100,2901,256", "R SSC1 C +GATTC:ReadDescriptor,OK,0010,A000,C100,2901"] + - - "SSC SSC1 gattc -W -z descriptor -s 0xA000 -c 0xC107 -d 0x2902 -p 0x10 -v 0x0100" + - ["R SSC1 C +GATTC:WriteOnce,0010,A000,C107,2902", "R SSC1 C +GATTC:WriteDescriptor,OK,0010,A000,C107,2902"] + - *register_notify_c107 + - *register_indicate_c108 + - - "SSC SSC1 gattc -W -z descriptor -s 0xA000 -c 0xC107 -d 0x2902 -p 0x10 -v 0x0300 -n 1" + - ["R SSC1 C +GATTC:WriteOnce,0010,A000,C107,2902", "R SSC1 C +GATTC:WriteDescriptor,OK,0010,A000,C107,2902"] + - - "SSC SSC2 gatts -N -c 0xC107 -p 0xA0 -v 0x01" + - ["P SSC2 C +GATTS:Done,Notify,A000,C107", "P SSC1 C +GATTC:Notification,0010,A000,C107,1"] + - - "SSC SSC2 gatts -I -c 0xC108 -p 0xA0 -v 0x01" + - ["P SSC2 C +GATTS:Done,Indicate,A000,C108", "P SSC1 C +GATTC:Indication,0010,A000,C108,1"] +- ID: BLUEDROID_GATT_40002 + <<: *GATT_CASE + auto test: 'No' + test point 2: test if BLE work after switch off some sub modules + summary: GATTC_SMP only and GATTS_SMP only test for BLUEDROID + steps: | + 1. download GATTC_SMP bin to DUT1 and GATTS_SMP bin to DUT2 + 2. DUT2 start adv, start service 0xA000, DUT1 connect to DUT2 + 3. DUT1 connect to DUT2 + 4. DUT1 do primary service discovery + 5. DUT1 do read + 6. DUT1 do read descriptor + 7. DUT1 do write + 8. DUT1 do write descriptor + 9. DUT1 register for notify and indication + 10. DUT2 do notify + 11. DUT2 do indicate + expected result: | + 1. succeed + 2. succeed + 3. succeed + 4. succeed + 5. succeed + 6. succeed + 7. succeed + 8. succeed + 9. succeed + 10. succeed + 11. succeed + initial condition: None + execution time: 5 + CI ready: 'No' + cmd set: + - "" + - - SSC SSC[1-2] reboot + - ['R SSC[1-2] C !!!ready!!!'] + - - SSC SSC[1-2] ble -R + - ['R SSC[1-2] C +BLE:OK'] + - - SSC SSC2 bleadv -D -z start + - ['R SSC2 C +BLEADV:OK'] + - - SSC SSC2 gatts -S -z load -p 0xA0 + - ['R SSC2 C +GATTS:StartService,OK,A000'] + - - SSC SSC1 bleconn -C -p 0x10 -a + - ['R SSC1 C +BLECONN:GapConnect,OK', 'R SSC2 C +BLECONN:GapConnect'] + - *primary_service_discovery + - - "SSC SSC1 gattc -R -z char -s 0xA000 -c 0xC100 -p 0x10" + - ["R SSC1 C +GATTC:ReadOnce,0010,A000,C100,1", "R SSC1 C +GATTC:Read,OK,0010,A000,C100"] + - - "SSC SSC1 gattc -W -z char -s 0xA000 -c 0xC102 -p 0x10 -v 0x01" + - ["R SSC1 C +GATTC:WriteOnce,0010,A000,C102", "R SSC1 C +GATTC:Write,OK,0010,A000,C102"] + - - "SSC SSC1 gattc -R -z descriptor -s 0xA000 -c 0xC100 -d 0x2901 -p 0x10" + - ["R SSC1 C +GATTC:ReadOnce,0010,A000,C100,2901,256", "R SSC1 C +GATTC:ReadDescriptor,OK,0010,A000,C100,2901"] + - - "SSC SSC1 gattc -W -z descriptor -s 0xA000 -c 0xC107 -d 0x2902 -p 0x10 -v 0x0100" + - ["R SSC1 C +GATTC:WriteOnce,0010,A000,C107,2902", "R SSC1 C +GATTC:WriteDescriptor,OK,0010,A000,C107,2902"] + - *register_notify_c107 + - *register_indicate_c108 + - - "SSC SSC1 gattc -W -z descriptor -s 0xA000 -c 0xC107 -d 0x2902 -p 0x10 -v 0x0300 -n 1" + - ["R SSC1 C +GATTC:WriteOnce,0010,A000,C107,2902", "R SSC1 C +GATTC:WriteDescriptor,OK,0010,A000,C107,2902"] + - - "SSC SSC2 gatts -N -c 0xC107 -p 0xA0 -v 0x01" + - ["P SSC2 C +GATTS:Done,Notify,A000,C107", "P SSC1 C +GATTC:Notification,0010,A000,C107,1"] + - - "SSC SSC2 gatts -I -c 0xC108 -p 0xA0 -v 0x01" + - ["P SSC2 C +GATTS:Done,Indicate,A000,C108", "P SSC1 C +GATTC:Indication,0010,A000,C108,1"] \ No newline at end of file diff --git a/components/idf_test/integration_test/TC_IT_BLUEDROID_SMP.yml b/components/idf_test/integration_test/TC_IT_BLUEDROID_SMP.yml new file mode 100644 index 0000000000..2bca97e2d9 --- /dev/null +++ b/components/idf_test/integration_test/TC_IT_BLUEDROID_SMP.yml @@ -0,0 +1,606 @@ +.SMP_CASE: &SMP_CASE + SDK: ESP32_IDF + Test App: SSC_BLE + auto test: 'Yes' + category: Function + test point 1: basic function + initial condition: BLE_INIT_SMP + test environment: SSC_T2_5 + execution time: 0 + module: BLUEDROID + sub module: SMP + version: v1 (2017-05-26) + CI ready: 'Yes' + level: Integration + allow fail: '' + +.just_work_pair: &just_work_pair + LIST_MERGE: + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect,OK'] + - - "SSC SSC2 blesmp -E -r -z Enc" + - ['P SSC[1-2] C +BLESMP:AuthComplete,Success,0'] + +.slave_passkey_entry_pair: &slave_passkey_entry_pair + LIST_MERGE: + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect,OK'] + - - "SSC SSC2 blesmp -E -r -z Enc" + - ['P SSC2 C +BLESMP:PassKeyReq', 'P SSC1 A :BLESMP:PassKeyNotify,(\d+)'] + - - "SSC SSC2 blesmp -K -r -a 1 -k " + - ['P SSC[1-2] C +BLESMP:AuthComplete,Success,0'] + +.master_passkey_entry_pair: &master_passkey_entry_pair + LIST_MERGE: + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect,OK'] + - - "SSC SSC2 blesmp -E -r -z Enc" + - ['P SSC1 C +BLESMP:PassKeyReq', 'P SSC2 A :BLESMP:PassKeyNotify,(\d+)'] + - - "SSC SSC1 blesmp -K -r -a 1 -k " + - ['P SSC[1-2] C +BLESMP:AuthComplete,Success,0'] + +.both_side_passkey_entry_pair: &both_side_passkey_entry_pair + LIST_MERGE: + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect,OK'] + - - "SSC SSC2 blesmp -E -r -z Enc" + - ['P SSC[1,2] C +BLESMP:PassKeyReq'] + - - "SSC SSC[1,2] blesmp -K -r -a 1 -k 123456" + - ['P SSC[1-2] C +BLESMP:AuthComplete,Success,0'] + +.numberic_comparision_pair: &numberic_comparision_pair + LIST_MERGE: + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect,OK'] + - - "SSC SSC2 blesmp -E -r -z Enc" + - ['R SSC2 A :BLESMP:NCReq,(\d+)', 'R SSC1 C NCReq P '] + - - "SSC SSC[1-2] blesmp -C -r -a 1" + - ['P SSC[1-2] C +BLESMP:AuthComplete,Success,0'] + +.check_connection: &check_connection + LIST_MERGE: + - - "SSC SSC1 gattc -D -z primaryService -p 0x10 -r " + - ["R SSC1 C +GATTC:Discover,OK"] + +.disconnect: &disconnect + LIST_MERGE: + - - "SSC SSC1 bleconn -D -z all" + - ['P SSC1 C +BLECONN:GapDisconnect,OK', 'P SSC2 C +BLECONN:GapDisconnect,OK'] + - - "SSC SSC2 bleadv -D -z start" + - ['P SSC2 C +BLEADV:OK'] + +.connect: &connect + LIST_MERGE: + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect,OK'] + +.config_just_work: &config_just_work + LIST_MERGE: + - - "SSC SSC[1-2] blesmp -S -z AuthReqMode -v 0x00" + - ['P SSC[1-2] C +BLESMP:OK'] + - - "SSC SSC[1-2] blesmp -S -z IOCAP -v 0x04" + - ['P SSC[1-2] C +BLESMP:OK'] + +.config_master_passkey_entry: &config_master_passkey_entry + LIST_MERGE: + - - "SSC SSC[1-2] blesmp -S -z AuthReqMode -v 0x0C" + - ['P SSC[1-2] C +BLESMP:OK'] + - - "SSC SSC1 blesmp -S -z IOCAP -v 0x02" + - ['P SSC1 C +BLESMP:OK'] + - - "SSC SSC2 blesmp -S -z IOCAP -v 0x04" + - ['P SSC2 C +BLESMP:OK'] + +.config_slave_passkey_entry: &config_slave_passkey_entry + LIST_MERGE: + - - "SSC SSC[1-2] blesmp -S -z AuthReqMode -v 0x04" + - ['P SSC[1-2] C +BLESMP:OK'] + - - "SSC SSC[1-2] blesmp -S -z IOCAP -v 0x04" + - ['P SSC[1-2] C +BLESMP:OK'] + +.config_both_side_passkey_entry: &config_both_side_passkey_entry + LIST_MERGE: + - - "SSC SSC[1-2] blesmp -S -z AuthReqMode -v 0x04" + - ['P SSC[1-2] C +BLESMP:OK'] + - - "SSC SSC[1-2] blesmp -S -z IOCAP -v 0x02" + - ['P SSC[1-2] C +BLESMP:OK'] + +.config_numberic_comparision: &config_numberic_comparision + LIST_MERGE: + - - "SSC SSC[1-2] blesmp -S -z AuthReqMode -v 0x0C" + - ['P SSC[1-2] C +BLESMP:OK'] + - - "SSC SSC[1-2] blesmp -S -z IOCAP -v 0x04" + - ['P SSC[1-2] C +BLESMP:OK'] + +.config_bond_device: &config_bond_device + LIST_MERGE: + - - "SSC SSC2 blesmp -S -z AuthReqMode -v 0x01" + - ['P SSC2 C +BLESMP:OK'] + - - "SSC SSC2 blesmp -S -z IOCAP -v 0x03" + - ['P SSC2 C +BLESMP:OK'] + +test cases: +- ID: BLUEDROID_SMP_04001 + <<: *SMP_CASE + test point 2: BLE SMP key test + summary: BLE SMP set key size less than required for BLUEDROID + allow fail: 1/2 + steps: | + 1. set key size 7 + 2. set key size 6 + 3. do just work pair + expected result: | + 1. succeed + 2. LTK size is 7 + 3. succeed + cmd set: + - "" + - *config_numberic_comparision + - - "SSC SSC1 blesmp -S -z KeySize -v 0x07" + - ['P SSC1 C +BLESMP:OK'] + - - "SSC SSC1 blesmp -S -z KeySize -v 0x06" + - ['P SSC1 C +BLESMP:OK'] + - *connect + - - "SSC SSC2 blesmp -E -r -z Enc" + - ['R SSC2 A :BLESMP:NCReq,(\d+)', 'R SSC1 C NCReq P '] + - - "SSC SSC[1-2] blesmp -C -r -a 1" + - ['P SSC[1-2] C +BLESMP:Key,LocalLTK,16 C +BLESMP:AuthComplete,Success,0'] +- ID: BLUEDROID_SMP_04002 + <<: *SMP_CASE + test point 2: BLE SMP key test + summary: BLE SMP set key size greater than required for BLUEDROID + allow fail: 1/2 + steps: | + 1. set key size 16 + 2. set key size 17 + 3. do just work pair + expected result: | + 1. succeed + 2. LTK size is 17 + 3. succeed + cmd set: + - "" + - *config_numberic_comparision + - - "SSC SSC1 blesmp -S -z KeySize -v 0x10" + - ['P SSC1 C +BLESMP:OK'] + - - "SSC SSC1 blesmp -S -z KeySize -v 0x11" + - ['P SSC1 C +BLESMP:OK'] + - *connect + - - "SSC SSC2 blesmp -E -r -z Enc" + - ['R SSC2 A :BLESMP:NCReq,(\d+)', 'R SSC1 C NCReq P '] + - - "SSC SSC[1-2] blesmp -C -r -a 1" + - ['P SSC[1-2] C +BLESMP:Key,LocalLTK,16 C +BLESMP:AuthComplete,Success,0'] +- ID: BLUEDROID_SMP_05001 + <<: *SMP_CASE + test point 2: BLE SMP unsuccessful pair reply test + summary: BLE SMP unsuccessful passkey entry test for BLUEDROID + steps: | + 1. enter passkey entry phase + 2. entry incorrect passkey and accept + 3. enter passkey entry phase + 4. entry correct passkey and reject + 5. enter passkey entry phase + 6. send numberic comparision accept + 7. enter passkey entry phase + 8. send numberic comparision reject + expected result: | + 1. succeed + 2. pair failed + 3. succeed + 4. pair failed + 5. succeed + 6. pair failed + 7. succeed + 8. pair failed + cmd set: + - "" + - *config_slave_passkey_entry + - - LOOP 2 5 "[1,0]" "['000001','']" + - "" + - *connect + - - "SSC SSC2 blesmp -E -r -z Enc" + - ['P SSC2 C +BLESMP:PassKeyReq', 'P SSC1 A :BLESMP:PassKeyNotify,(\d+)'] + - - "SSC SSC2 blesmp -K -r -a {%d} -k {%s}" + - ['P SSC[1-2] C +BLESMP:AuthComplete,Fail'] + - *disconnect + - - LOOP 2 5 "[1,0]" + - "" + - *connect + - - "SSC SSC2 blesmp -E -r -z Enc" + - ['P SSC2 C +BLESMP:PassKeyReq', 'P SSC1 A :BLESMP:PassKeyNotify,(\d+)'] + - - "SSC SSC[1-2] blesmp -C -r -a {%d}" + - ['P SSC[1-2] C +BLESMP:AuthComplete,Fail'] + - *disconnect +- ID: BLUEDROID_SMP_05002 + <<: *SMP_CASE + test point 2: BLE SMP unsuccessful pair reply test + summary: BLE SMP unsuccessful numberic comparision test for BLUEDROID + steps: | + 1. enter numberic comparision phase + 2. entry passkey and accept + 3. enter numberic comparision phase + 4. send numberic comparision reject + expected result: | + 1. succeed + 2. pair failed + 3. succeed + 4. pair failed + cmd set: + - "" + - *config_numberic_comparision + - - LOOP 2 6 "[1,0]" + - "" + - *connect + - - "SSC SSC2 blesmp -E -r -z Enc" + - ['R SSC2 A :BLESMP:NCReq,(\d+)', 'R SSC1 C NCReq P '] + - - "SSC SSC2 blesmp -K -r -a {%d} -k 000001" + - [] + - - DELAY 10 + - ['P SSC[1-2] C +BLESMP:AuthComplete,Fail'] + - *disconnect + - - LOOP 2 5 "[1,0]" "[0,1]" + - "" + - *connect + - - "SSC SSC2 blesmp -E -r -z Enc" + - ['R SSC2 A :BLESMP:NCReq,(\d+)', 'R SSC1 C NCReq P '] + - - "SSC SSC[1,2] blesmp -C -r -a [{%d},{%d}]" + - ['P SSC[1-2] C +BLESMP:AuthComplete,Fail'] + - *disconnect +- ID: BLUEDROID_SMP_06001 + <<: *SMP_CASE + test environment: SSC_T1_4 + initial condition: BLE_DEINIT1 + test point 2: BLE SMP use API in abnormal state + summary: BLE SMP use API when BLE not initialized, not enabled or not registered callback for BLUEDROID + steps: | + 1. set security parameter + 2. send security response + 3. send passkey reply + 4. send confirm reply + 5. init BLE + 6. set security parameter + 7. send security response + 8. send passkey reply + 9. send confirm reply + 10. init BLE + 11. set security parameter + 12. send security response + 13. send passkey reply + 14. send confirm reply + expected result: | + 1. failed + 2. failed + 3. failed + 4. failed + 5. succeed + 6. failed + 7. failed + 8. failed + 9. failed + 10. succeed + 11. failed + 12. failed + 13. failed + 14. failed + cmd set: + - "" + - - "SSC SSC1 blesmp -S -z AuthReqMode -v 0x0C" + - ['P SSC1 C +BLESMP:ERROR'] + - - "SSC SSC1 blesmp -R -a 1 -r " + - ['P SSC1 C +BLESMP:ERROR'] + - - "SSC SSC1 blesmp -K -r -a 1 -k 123456" + - ['P SSC1 C +BLESMP:ERROR'] + - - "SSC SSC1 blesmp -C -r -a 1" + - ['P SSC1 C +BLESMP:ERROR'] + - - SSC SSC1 bt -D -z init + - ['R SSC1 C +BT:'] + - - "SSC SSC1 blesmp -S -z AuthReqMode -v 0x0C" + - ['P SSC1 C +BLESMP'] + - - "SSC SSC1 blesmp -R -a 1 -r " + - ['P SSC1 C +BLESMP'] + - - "SSC SSC1 blesmp -K -r -a 1 -k 123456" + - ['P SSC1 C +BLESMP'] + - - "SSC SSC1 blesmp -C -r -a 1" + - ['P SSC1 C +BLESMP'] + - - SSC SSC1 bt -D -z enable + - ['R SSC1 C +BT:'] + - - "SSC SSC1 blesmp -S -z AuthReqMode -v 0x0C" + - ['P SSC1 C +BLESMP'] + - - "SSC SSC1 blesmp -R -a 1 -r " + - ['P SSC1 C +BLESMP'] + - - "SSC SSC1 blesmp -K -r -a 1 -k 123456" + - ['P SSC1 C +BLESMP'] + - - "SSC SSC1 blesmp -C -r -a 1" + - ['P SSC1 C +BLESMP'] +- ID: BLUEDROID_SMP_07002 + <<: *SMP_CASE + test point 2: BLE SMP no bond test and repairing + summary: BLE SMP just work pairing and reboot for BLUEDROID + steps: | + 1. DUT1 and DUT2 SMP with just work pair + 2. DUT1 reboot + 3. DUT1 connect to DUT2 + 4. DUT2 send auth request + expected result: | + 1. succeed + 2. succeed + 3. succeed + 4. failed + cmd set: + - "" + - *config_just_work + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect,OK'] + - - "SSC SSC1 blesmp -E -r -z Enc" + - ['P SSC[1-2] C +BLESMP:AuthComplete,Success,0'] + - - "SSC SSC1 reboot" + - ['P SSC2 C +BLECONN:GapDisconnect,OK'] + - - "SSC SSC1 ble -R" + - ['R SSC1 C +BLE:'] + - - "SSC SSC2 bleadv -D -z start" + - ['R SSC2 C +BLEADV:OK'] + - *slave_passkey_entry_pair +- ID: BLUEDROID_SMP_07005 + <<: *SMP_CASE + test point 2: BLE SMP no bond test and repairing + summary: BLE SMP initiator with master passkey entry and reconnect for BLUEDROID + steps: | + 1. DUT1 and DUT2 SMP with master passkey entry + 2. DUT1 disconnect + 3. DUT1 connect to DUT2 + 4. DUT2 send auth request + expected result: | + 1. succeed + 2. succeed + 3. connect succeed + 4. succeed + cmd set: + - "" + - *config_master_passkey_entry + - *master_passkey_entry_pair + - *disconnect + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect'] + - - "SSC SSC2 blesmp -E -r -z Enc" + - ['P SSC[1-2] C +BLESMP:AuthComplete,Success,0'] +- ID: BLUEDROID_SMP_07006 + <<: *SMP_CASE + test point 2: BLE SMP no bond test and repairing + summary: BLE SMP initiator with master passkey entry and reboot for BLUEDROID + steps: | + 1. DUT1 and DUT2 SMP bond with lagecy pairing + 2. DUT1 reboot + 3. DUT1 connect to DUT2 + 4. DUT2 send auth requst + expected result: | + 1. succeed + 2. succeed + 3. connect succeed + 4. fail + cmd set: + - "" + - *config_master_passkey_entry + - *master_passkey_entry_pair + - - "SSC SSC1 reboot" + - ['P SSC2 C +BLECONN:GapDisconnect,OK'] + - - "SSC SSC1 ble -R" + - ['R SSC1 C +BLE:'] + - - "SSC SSC2 bleadv -D -z start" + - ['R SSC2 C +BLEADV:OK'] + - *numberic_comparision_pair +- ID: BLUEDROID_SMP_07007 + <<: *SMP_CASE + test point 2: BLE SMP no bond test and repairing + summary: BLE SMP initiator numberic comparision and reconnect for BLUEDROID + steps: | + 1. DUT1 and DUT2 SMP with numberic comparision + 2. DUT1 disconnect + 3. DUT1 connect to DUT2 + 4. DUT2 send auth requst + expected result: | + 1. succeed + 2. succeed + 3. connect succeed + 4. succeed + cmd set: + - "" + - *config_numberic_comparision + - *numberic_comparision_pair + - *disconnect + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect'] + - - "SSC SSC2 blesmp -E -r -z Enc" + - ['P SSC[1-2] C +BLESMP:AuthComplete,Success,0'] +- ID: BLUEDROID_SMP_07008 + <<: *SMP_CASE + test point 2: BLE SMP no bond test and repairing + summary: BLE SMP initiator numberic comparision and reboot for BLUEDROID + steps: | + 1. DUT1 and DUT2 SMP with numberic comparision + 2. DUT1 disconnect + 3. DUT1 and DUT2 reboot + 4. DUT2 send auth requst + expected result: | + 1. succeed + 2. succeed + 3. connect succeed + 4. failed + cmd set: + - "" + - *config_numberic_comparision + - *numberic_comparision_pair + - - "SSC SSC1 reboot" + - ['P SSC2 C +BLECONN:GapDisconnect,OK'] + - - "SSC SSC1 ble -R" + - ['R SSC1 C +BLE:'] + - - "SSC SSC2 bleadv -D -z start" + - ['R SSC2 C +BLEADV:OK'] + - *numberic_comparision_pair +- ID: BLUEDROID_SMP_08001 + <<: *SMP_CASE + test point 2: BLE SMP bond item management test + summary: BLE SMP get bond list and number without bond device for BLUEDROID + steps: | + 1. DUT1 get bond list + 2. DUT1 get bond number + expected result: | + 1. succeed + 2. succeed + cmd set: + - "" + - - "SSC SSC1 blesmp -B -z getlist -n 1" + - ['P SSC1 C +BLESMP:GetBondList,OK,0'] + - - "SSC SSC1 blesmp -B -z getnum" + - ['P SSC1 C +BLESMP:GetBondNum,0'] +- ID: BLUEDROID_SMP_08002 + <<: *SMP_CASE + test point 2: BLE SMP bond item management test + summary: BLE SMP remove bond after connected + steps: | + 1. DUT2 set AuthReqMode and RspKey + 2. pairing + 3. remove bond + expected result: | + 1. Succeed + 2. Succeed + 3. Succeed + cmd set: + - "" + - *config_bond_device + - - "SSC SSC2 bleadv -D -z start" + - ['R SSC2 C +BLEADV:Start,OK'] + - *connect + - - "SSC SSC2 blesmp -E -r -z Enc" + - ['P SSC1 C +BLESMP:AuthComplete,Success,0','P SSC2 C +BLESMP:AuthComplete,Success,0'] + - - "SSC SSC1 blesmp -B -z getnum" + - ['P SSC1 C +BLESMP:GetBondNum,1'] + - - "SSC SSC1 blesmp -B -z remove -r " + - ['P SSC1 RE "\+BLESMP:RemoveBond,Success,%%s"%%()'] +- ID: BLUEDROID_SMP_08003 + <<: *SMP_CASE + test point 2: BLE SMP bond item management test + summary: BLE SMP get bond list and number when pairing and after reboot for BLUEDROID + steps: | + 1. all slaves set AuthReqMode and RspKey + 2. do pairing + 3. master and slave get bond list and num + 4. reboot + 5. master and slave get bond list and num + 6. slave remove bond device + expected result: | + 1. Succeed + 2. Succeed + 3. Succeed + 4. succeed + 5. succeed + 6. succeed + test environment: SSC_T5_1 + initial condition: BLE_INIT_SMP5 + allow fail: 3/5 + cmd set: + - "" + - - "SSC SSC[2-5] blesmp -S -z AuthReqMode -v 0x01" + - ['P SSC[2-5] C +BLESMP:OK'] + - - "SSC SSC[2-5] blesmp -S -z IOCAP -v 0x03" + - ['P SSC[2-5] C +BLESMP:OK'] + - - "SSC SSC[2-5] blesmp -S -z RspKey -v 0x03" + - ['P SSC[2-5] C +BLESMP:OK'] + - - LOOP 4 4 "[2,3,4,5]" "[2,3,4,5]" "[2,3,4,5]" "[2,3,4,5]" "[2,3,4,5]" "[2,3,4,5]" "[2,3,4,5]" + - "" + - - "SSC SSC{%d} bleadv -D -z start" + - ['R SSC{%d} C +BLEADV:Start,OK'] + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC{%d} C +BLECONN:GapConnect'] + - - "SSC SSC{%d} blesmp -E -r -z Enc" + - ['P SSC1 C +BLESMP:SecReq'] + - - "SSC SSC1 blesmp -R -a 1 -r " + - ['P SSC1 C +BLESMP:AuthComplete,Success,0','P SSC{%d} C +BLESMP:AuthComplete,Success,0'] + - - "SSC SSC1 blesmp -B -z getlist -n 4" + - ['P SSC1 C +BLESMP:GetBondList,OK,4'] + - - "SSC SSC1 blesmp -B -z getnum" + - ['P SSC1 C +BLESMP:GetBondNum,4'] + - - "SSC SSC2 blesmp -B -z getnum" + - ['P SSC2 C +BLESMP:GetBondNum,1'] + - - "SSC SSC[1-2] reboot" + - ['R SSC[1-2] C !!!ready!!!'] + - - "SSC SSC[1-2] ble -R" + - ["R SSC[1-2] C +BLE:OK"] + - - "SSC SSC1 blesmp -B -z getnum" + - ['P SSC1 C +BLESMP:GetBondNum,4'] + - - "SSC SSC2 blesmp -B -z getnum" + - ['P SSC2 C +BLESMP:GetBondNum,1'] + - - "SSC SSC2 blesmp -B -z remove -r " + - ['P SSC2 RE "\+BLESMP:RemoveBond,Success,%%s"%%()'] +- ID: BLUEDROID_SMP_08004 + <<: *SMP_CASE + test point 2: BLE SMP bond item management test + summary: BLE SMP remove bond which not bond for BLUEDROID + steps: | + 1. DUT1 remove bond + expected result: | + 1. failed + cmd set: + - "" + - - "SSC SSC1 blesmp -B -z remove -r " + - ['P SSC1 C +BLESMP:RemoveBond,Fail'] +- ID: BLUEDROID_SMP_08005 + <<: *SMP_CASE + test point 2: BLE SMP remove bond + summary: BLE SMP bond 15/16 devices and get list + steps: | + 1. DUT2 set AuthReqMode and RspKey + 2. DUT2 set static random address + 3. DUT1 and DUT2 do pairing + 4. loop step 2 and step3 16 times + 5. get bond list and bond num + 6. DUT2 set static random address + 7. DUT1 and DUT2 do pairing + 8. get bond list and bond num + expected result: | + 1. Succeed + 2. Succeed + 3. Succeed + 4. succeed + 5. succeed + 6. succeed + 7. succeed + 8. succeed + cmd set: + - "" + - - "SSC SSC[1-2] blesmp -S -z AuthReqMode -v 0x01" + - ['P SSC[1-2] C +BLESMP:OK'] + - - "SSC SSC[1-2] blesmp -S -z IOCAP -v 0x03" + - ['P SSC[1-2] C +BLESMP:OK'] + - - "SSC SSC[1-2] blesmp -S -z RspKey -v 0x03" + - ['P SSC[1-2] C +BLESMP:OK'] + - - LOOP 15 7 "range(0,15)" "range(0,15)" "range(0,15)" + - "" + - - "SSC SSC2 bleadv -D -z stop" + - ['R SSC2 C +BLEADV:Stop,OK'] + - - "SSC SSC2 ble -S -z randAddr -a c0:9b:0e:36:6d:7{%x} -r 1" + - ["R SSC2 C +BLECONN:SetRandAddr,OK"] + - - "SSC SSC2 bleadv -D -z start -o 1" + - ['R SSC2 C +BLEADV:Start,OK'] + - - "SSC SSC1 bleconn -C -p 0x10 -a c0:9b:0e:36:6d:7{%x} -r 1" + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect'] + - - "SSC SSC2 blesmp -E -r -z Enc" + - ['P SSC1 C +BLESMP:SecReq'] + - - "SSC SSC1 blesmp -R -a 1 -r c0:9b:0e:36:6d:7{%x}" + - ['P SSC1 C +BLESMP:AuthComplete,Success,0','P SSC2 C +BLESMP:AuthComplete,Success,0'] + - - "SSC SSC1 bleconn -D -z all" + - ['P SSC1 C +BLE:CLOSE', 'P SSC2 C +BLECONN:GapDisconnect,OK'] + - - "SSC SSC1 blesmp -B -z getlist -n 16" + - ['P SSC1 C +BLESMP:GetBondList,OK,15'] + - - "SSC SSC2 ble -S -z randAddr -a c1:0a:d3:25:7a:cf -r 1" + - ["R SSC2 C +BLECONN:SetRandAddr,OK"] + - - "SSC SSC2 bleadv -D -z stop" + - ['R SSC2 C +BLEADV:Stop,OK'] + - - "SSC SSC2 bleadv -D -z start -o 1" + - ['R SSC2 C +BLEADV:Start,OK'] + - - "SSC SSC1 bleconn -C -p 0x10 -a c1:0a:d3:25:7a:cf -r 1" + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect'] + - - "SSC SSC2 blesmp -E -r -z Enc" + - ['P SSC1 C +BLESMP:SecReq'] + - - "SSC SSC1 blesmp -R -a 1 -r c1:0a:d3:25:7a:cf" + - ['P SSC1 C +BLESMP:AuthComplete,Success,0','P SSC2 C +BLESMP:AuthComplete,Success,0'] + - - "SSC SSC1 blesmp -B -z getlist -n 16" + - ['P SSC1 C +BLESMP:GetBondList,OK,15'] diff --git a/components/idf_test/integration_test/TC_IT_BTSTK_GAP.yml b/components/idf_test/integration_test/TC_IT_BTSTK_GAP.yml index 32477c963b..544bc53fd3 100644 --- a/components/idf_test/integration_test/TC_IT_BTSTK_GAP.yml +++ b/components/idf_test/integration_test/TC_IT_BTSTK_GAP.yml @@ -4,7 +4,7 @@ auto test: 'Yes' category: Function test point 1: basic function - initial condition: BLE_INIT2 + initial condition: BLE_INIT3 test environment: SSC_T2_5 execution time: 0 module: BT Stack @@ -17,12 +17,12 @@ .dut1_stop_adv: &dut1_stop_adv LIST_MERGE: - - "SSC SSC1 bleadv -D -z stop" - - ["R SSC1 C +BLEADV:Stop,OK"] + - ["R SSC1 C +BLEADV:"] .dut2_stop_adv: &dut2_stop_adv LIST_MERGE: - - "SSC SSC2 bleadv -D -z stop" - - ["R SSC2 C +BLEADV:Stop,OK"] + - ["R SSC2 C +BLEADV:"] .dut1_start_adv: &dut1_start_adv LIST_MERGE: @@ -37,7 +37,7 @@ .set_default_adv_data: &set_default_adv_data LIST_MERGE: - - "SSC SSC1 bleadv -D -z stop" - - ["R SSC1 C +BLEADV:Stop,OK"] + - ["R SSC1 C +BLEADV:"] - - "SSC SSC1 bleadv -L -c 0 -t 3" - ["R SSC1 C +BLEADV:SetAdv,OK C +BLEADV:SetScanRes,OK"] - - "SSC SSC1 bleadv -D -z start" @@ -51,7 +51,7 @@ .dut1_connect_to_dut2: &dut1_connect_to_dut2 LIST_MERGE: - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ['R SSC1 C +BLE:GattcConnect,OK', 'R SSC2 C +BLE:GattsConnect'] + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect,OK'] test cases: - ID: BTSTK_GAP_01001 @@ -71,11 +71,14 @@ test cases: cmd set: - "" - *set_default_ble_name - - *set_default_adv_data + - - "SSC SSC1 bleadv -D -z stop" + - ["R SSC1 C +BLEADV:"] + - - "SSC SSC1 bleadv -L -c 0 -t 3 -n 1" + - ["R SSC1 C +BLEADV:SetAdv,OK C +BLEADV:SetScanRes,OK"] + - - "SSC SSC1 bleadv -D -z start" + - ["R SSC1 C +BLEADV:Start,OK"] - *dut2_stop_adv - - - "SSC SSC2 blescan -L -c 0" - - ["R SSC2 C +BLESCAN:SetScanParam,OK"] - - - "SSC SSC2 blescan -D -z start -t 3" + - - "SSC SSC2 blescan -D -z start -t 3 -c 0" - ["R SSC2 P "] - ID: BTSTK_GAP_01002 <<: *GAP_CASE @@ -95,51 +98,15 @@ test cases: - "" - - "SSC SSC1 ble -S -z name -n " - ["R SSC1 C +BLE:OK"] - - *set_default_adv_data + - - "SSC SSC1 bleadv -D -z stop" + - ["R SSC1 C +BLEADV:"] + - - "SSC SSC1 bleadv -L -c 0 -t 3 -n 1" + - ["R SSC1 C +BLEADV:SetAdv,OK C +BLEADV:SetScanRes,OK"] + - - "SSC SSC1 bleadv -D -z start" + - ["R SSC1 C +BLEADV:Start,OK"] - *dut2_stop_adv - - - "SSC SSC2 blescan -L -c 0" - - ["R SSC2 C +BLESCAN:SetScanParam,OK"] - - - "SSC SSC2 blescan -D -z start -t 3" + - - "SSC SSC2 blescan -D -z start -t 3 -c 0" - ["R SSC2 P "] -- ID: BTSTK_GAP_01003 - <<: *GAP_CASE - test point 2: BLE GAP param device name test - summary: ble set long device name - steps: | - 1. DUT1 set 32 byte device name A - 2. stop advertising - 3. config scan response and start advertising - 4. DUT2 do active scan - 5. DUT1 set 33 bytes device name - 6. stop advertising - 7. config scan response and start advertising - 8. DUT2 do active scan - expected result: | - 1. succeed - 2. succeed - 3. succeed - 4. DUT1 mac in scan result (device name is too long) - 5. failed - 6. succeed - 7. succeed - 8. DUT1 mac in scan result (device name is too long) - cmd set: - - "" - - - "SSC SSC1 ble -S -z name -n " - - ["R SSC1 C +BLE:OK"] - - *set_default_adv_data - - *dut2_stop_adv - - - "SSC SSC2 blescan -L -c 0 -s 1" - - ["R SSC2 C +BLESCAN:SetScanParam,OK"] - - - "SSC SSC2 blescan -D -z start -t 3" - - ["R SSC2 P C Complete"] - - - "SSC SSC1 ble -S -z name -n 123456789012345678901234567890123" - - ["R SSC1 C +BLE:ERROR"] - - *set_default_adv_data - - - "SSC SSC2 blescan -L -c 0 -s 1" - - ["R SSC2 C +BLESCAN:SetScanParam,OK"] - - - "SSC SSC2 blescan -D -z start -t 3" - - ["R SSC2 P C Complete"] - ID: BTSTK_GAP_02001 <<: *GAP_CASE test point 2: BLE GAP config advertising data @@ -190,30 +157,27 @@ test cases: test point 2: BLE GAP config advertising data summary: ble set advertising data / scan response include Tx power steps: | - 1. DUT1 stop advertise and set short device name - 2. DUT1 set include Tx power for adv data and scan response - 3. DUT1 start advertising - 4. PC do active scan and capture advertising report - 5. DUT1 stop advertising - 6. DUT1 set not include Tx power for adv data and scan response - 7. DUT1 start advertising - 8. PC do active scan and capture advertising report + 1. DUT1 set include Tx power for adv data and scan response + 2. DUT1 start advertising + 3. PC do active scan and capture advertising report + 4. DUT1 stop advertising + 5. DUT1 set not include Tx power for adv data and scan response + 6. DUT1 start advertising + 7. PC do active scan and capture advertising report expected result: | 1. succeed 2. succeed - 3. succeed - 4. get Tx power in ADV_IND and SCAN_RSP + 3. get Tx power in ADV_IND and SCAN_RSP + 4. succeed 5. succeed 6. succeed - 7. succeed - 8. do not have Tx power in ADV_IND and SCAN_RSP + 7. do not have Tx power in ADV_IND and SCAN_RSP initial condition: BLE_INIT1 test environment: SSC_T1_3 version: v2 (2016-03-01) cmd set: - "" - *dut1_stop_adv - - *set_default_ble_name - - "SSC SSC1 bleadv -L -c 0 -x 1 -t 3" - ["R SSC1 C +BLEADV:SetAdv,OK"] - *dut1_start_adv @@ -230,57 +194,12 @@ test cases: - - 'P PC_COM C +HCITOOL:OK' - 'P BLENIC PDU (HCIEvent.le_sub_event_code="LEAdvReport")(HCIEvent.event_type_0="ADV_IND")(HCIEvent.address_0=)(!HCIEvent.data_0.TxPower)' - 'P BLENIC PDU (HCIEvent.le_sub_event_code="LEAdvReport")(HCIEvent.event_type_0="SCAN_RSP")(HCIEvent.address_0=)(!HCIEvent.data_0.TxPower)' -- ID: BTSTK_GAP_02003 - <<: *GAP_CASE - test point 2: BLE GAP config advertising data - summary: ble set advertising data / scan response adv interval - steps: | - 1. DUT1 stop advertise and set short device name - 2. DUT1 set max interval 0x40 min interval 0x20 for adv data and scan response - 3. DUT1 start advertising - 4. PC do active scan and capture advertising report - 5. DUT1 stop advertising - 6. DUT1 set max interval 0x400 min interval 0x200 for adv data and scan response - 7. DUT1 start advertising - 8. PC do active scan and capture advertising report - expected result: | - 1. succeed - 2. succeed - 3. succeed - 4. get interval 0x40 0x20 in ADV_IND and SCAN_RSP - 5. succeed - 6. succeed - 7. succeed - 8. get interval 0x400 0x200 in ADV_IND and SCAN_RSP - initial condition: BLE_INIT1 - test environment: SSC_T1_3 - version: v2 (2016-03-01) - cmd set: - - "" - - *dut1_stop_adv - - *set_default_ble_name - - - "SSC SSC1 bleadv -L -c 0 -i 0x20-0x40 -t 3" - - ["R SSC1 C +BLEADV:SetAdv,OK"] - - *dut1_start_adv - - *open_capture_nic - - - "HCITOOL 2 -i lescan" - - - 'P PC_COM C +HCITOOL:OK' - - 'P BLENIC PDU (HCIEvent.le_sub_event_code="LEAdvReport")(HCIEvent.event_type_0="ADV_IND")(HCIEvent.address_0=)(HCIEvent.data_0.SlaveConnIntervalRange="0x0020-0x0040")' - - 'P BLENIC PDU (HCIEvent.le_sub_event_code="LEAdvReport")(HCIEvent.event_type_0="SCAN_RSP")(HCIEvent.address_0=)(HCIEvent.data_0.SlaveConnIntervalRange="0x0020-0x0040")' - - *dut1_stop_adv - - - "SSC SSC1 bleadv -L -c 0 -i 0x200-0x400 -t 3" - - ["R SSC1 C +BLEADV:SetAdv,OK"] - - *dut1_start_adv - - - "HCITOOL 2 -i lescan" - - - 'P PC_COM C +HCITOOL:OK' - - 'P BLENIC PDU (HCIEvent.le_sub_event_code="LEAdvReport")(HCIEvent.event_type_0="ADV_IND")(HCIEvent.address_0=)(HCIEvent.data_0.SlaveConnIntervalRange="0x0200-0x0400")' - - 'P BLENIC PDU (HCIEvent.le_sub_event_code="LEAdvReport")(HCIEvent.event_type_0="SCAN_RSP")(HCIEvent.address_0=)(HCIEvent.data_0.SlaveConnIntervalRange="0x0200-0x0400")' - ID: BTSTK_GAP_02004 <<: *GAP_CASE test point 2: BLE GAP config advertising data summary: ble set advertising data / scan response appearance steps: | - 1. DUT1 stop advertise and set short device name + 1. DUT1 stop advertise 2. DUT1 set appearance to 0 for adv data and scan response 3. DUT1 start advertising 4. PC do active scan and capture advertising report @@ -303,7 +222,6 @@ test cases: cmd set: - "" - *dut1_stop_adv - - *set_default_ble_name - - "SSC SSC1 bleadv -L -c 0 -a 0 -t 3" - ["R SSC1 C +BLEADV:SetAdv,OK"] - *dut1_start_adv @@ -325,7 +243,7 @@ test cases: test point 2: BLE GAP config advertising data summary: ble set advertising data / scan response manufacturer data steps: | - 1. DUT1 stop advertise and set short device name + 1. DUT1 stop advertise 2. DUT1 set manufacturer to 0x12345678 for adv data and scan response 3. DUT1 start advertising 4. PC do active scan and capture advertising report @@ -340,7 +258,6 @@ test cases: cmd set: - "" - *dut1_stop_adv - - *set_default_ble_name - - "SSC SSC1 bleadv -L -c 0 -m 0x12345678 -t 3" - ["R SSC1 C +BLEADV:SetAdv,OK"] - *dut1_start_adv @@ -354,11 +271,11 @@ test cases: test point 2: BLE GAP config advertising data summary: ble set advertising data / scan response manufacturer length not equal to real lenght steps: | - 1. DUT1 stop advertise and set short device name + 1. DUT1 stop advertise 2. DUT1 set manufacturer 0x12345678 and length 3 for adv data and scan response 3. DUT1 start advertising 4. PC do active scan and capture advertising report - 5. DUT1 stop advertise and set short device name + 5. DUT1 stop advertise 6. DUT1 set manufacturer 0x12345678 and length 10 for adv data and scan response 7. DUT1 start advertising 8. PC do active scan and capture advertising report @@ -377,7 +294,6 @@ test cases: cmd set: - "" - *dut1_stop_adv - - *set_default_ble_name - - "SSC SSC1 bleadv -L -c 0 -m 0x12345678 -t 3 -l 3" - ["R SSC1 C +BLEADV:SetAdv,OK"] - *dut1_start_adv @@ -387,7 +303,6 @@ test cases: - 'P BLENIC PDU (HCIEvent.le_sub_event_code="LEAdvReport")(HCIEvent.event_type_0="ADV_IND")(HCIEvent.address_0=)(HCIEvent.data_0.ManufacturerSpecificData="0x12345678")' - 'P BLENIC PDU (HCIEvent.le_sub_event_code="LEAdvReport")(HCIEvent.event_type_0="SCAN_RSP")(HCIEvent.address_0=)(HCIEvent.data_0.ManufacturerSpecificData="0x12345678")' - *dut1_stop_adv - - *set_default_ble_name - - "SSC SSC1 bleadv -L -c 0 -m 0x12345678 -t 3 -l 10" - ["R SSC1 C +BLEADV:SetAdv,OK"] - *dut1_start_adv @@ -416,8 +331,7 @@ test cases: cmd set: - "" - *dut1_stop_adv - - *set_default_ble_name - - - "SSC SSC1 bleadv -L -c 0 -n 0 -d 0x1234123456 -t 3" + - - "SSC SSC1 bleadv -L -c 0 -n 0 -d 0x1234123456 -t 3 -p -f 0 -x 0" - ["R SSC1 C +BLEADV:SetAdv,OK"] - *dut1_start_adv - *open_capture_nic @@ -453,8 +367,7 @@ test cases: cmd set: - "" - *dut1_stop_adv - - *set_default_ble_name - - - "SSC SSC1 bleadv -L -c 0 -n 0 -d 0x1234123456 -t 3 -l 3" + - - "SSC SSC1 bleadv -L -c 0 -d 0x1234123456 -t 3 -l 3" - ["R SSC1 C +BLEADV:SetAdv,OK"] - *dut1_start_adv - *open_capture_nic @@ -463,8 +376,7 @@ test cases: - 'P BLENIC PDU (HCIEvent.le_sub_event_code="LEAdvReport")(HCIEvent.event_type_0="ADV_IND")(HCIEvent.address_0=)(HCIEvent.data_0.ServiceData16BitUUID="1234123456")' - 'P BLENIC PDU (HCIEvent.le_sub_event_code="LEAdvReport")(HCIEvent.event_type_0="SCAN_RSP")(HCIEvent.address_0=)(HCIEvent.data_0.ServiceData16BitUUID="1234123456")' - *dut1_stop_adv - - *set_default_ble_name - - - "SSC SSC1 bleadv -L -c 0 -n 0 -d 0x1234123456 -t 3 -l 10" + - - "SSC SSC1 bleadv -L -c 0 -d 0x1234123456 -t 3 -l 10" - ["R SSC1 C +BLEADV:SetAdv,OK"] - *dut1_start_adv - *open_capture_nic @@ -553,7 +465,7 @@ test cases: test point 2: BLE GAP set advertise param summary: ble set adv parameter adv_type steps: | - 1. DUT1 stop advertise and set short device name + 1. DUT1 stop advertise 2. DUT1 start adv with adv_type ADV_IND 3. PC do active scan and capture advertising report 4. repeat step 1-3 with adv_type ADV_TYPE_DIRECT_IND_HIGH @@ -572,9 +484,8 @@ test cases: test environment: SSC_T1_3 cmd set: - "" - - *set_default_ble_name - - "SSC SSC1 bleadv -L -c 0 -t 3" - - ["R SSC1 C +BLEADV:SetAdv,OK"] + - ["R SSC1 C +BLEADV:SetAdv,OK C +BLEADV:SetScanRes,OK"] - *open_capture_nic - *dut1_stop_adv - - "SSC SSC1 bleadv -D -z start -t 0" @@ -582,11 +493,13 @@ test cases: - - "HCITOOL 2 -i lescan" - - 'P PC_COM C +HCITOOL:OK' - 'P BLENIC PDU (HCIEvent.le_sub_event_code="LEAdvReport")(HCIEvent.event_type_0="ADV_IND")(HCIEvent.address_0=)' + - *dut1_stop_adv - - "SSC SSC1 bleadv -D -z start -t 1 -y 0 -b " - ["R SSC1 C +BLEADV:OK"] - - "HCITOOL 2 -i lescan" - - 'P PC_COM C +HCITOOL:OK' - 'P BLENIC PDU (HCIEvent.le_sub_event_code="LEAdvReport")(HCIEvent.event_type_0="ADV_DIRECT_IND")(HCIEvent.address_0=)' + - *dut1_stop_adv - - "SSC SSC1 bleadv -L -c 0 -i 0x00B0-0x0200 -t 3" - ["R SSC1 C +BLEADV:OK"] - - "SSC SSC1 bleadv -D -z start -t 2 -i 0x00B0-0x0200" @@ -594,6 +507,7 @@ test cases: - - "HCITOOL 2 -i lescan" - - 'P PC_COM C +HCITOOL:OK' - 'P BLENIC PDU (HCIEvent.le_sub_event_code="LEAdvReport")(HCIEvent.event_type_0="ADV_SCAN_IND")(HCIEvent.address_0=)' + - *dut1_stop_adv - - "SSC SSC1 bleadv -D -z start -t 3 -i 0x00B0-0x0200" - ["R SSC1 C +BLEADV:OK"] - - "HCITOOL 2 -i lescan" @@ -628,9 +542,8 @@ test cases: allow fail: 1/2 cmd set: - "" - - *set_default_ble_name - - "SSC SSC1 bleadv -L -c 0 -t 3" - - ["R SSC1 C +BLEADV:SetAdv,OK"] + - ["R SSC1 C +BLEADV:SetAdv,OK C +BLEADV:SetScanRes,OK"] - *open_capture_nic - - LOOP 7 3 "[1,2,3,4,5,6,7]" "['PDU','PDU','PDU','PDU','PDU','PDU','PDU']" - *dut1_stop_adv @@ -641,37 +554,6 @@ test cases: - 'P BLENIC {%s} (HCIEvent.le_sub_event_code="LEAdvReport")(HCIEvent.event_type_0="ADV_IND")(HCIEvent.address_0=)' - - "SSC SSC1 bleadv -D -z start -t 0 -h 8" - ["R SSC1 C +BLEADV:Start,ERROR"] -- ID: BTSTK_GAP_03003 - <<: *GAP_CASE - test point 2: BLE GAP set advertise param - summary: ble set adv parameter own address type - steps: | - 1. DUT1 stop advertise - 2. DUT1 start adv with own address type public - 3. PC do active scan and capture advertising report - 4. repeat step 1-3 with own address type random, rpa_public, rpa_random - 5. repeat step 1-3 with channel map not valid - expected result: | - 1. succeed - 2. succeed - 3. get ADV_IND with DUT1 BT MAC - 4. get ADV_IND with DUT1 BT MAC - 5. can not get ADV_IND with DUT1 BT MAC - initial condition: BLE_INIT1 - test environment: SSC_T1_3 - cmd set: - - "" - - *set_default_ble_name - - - "SSC SSC1 bleadv -L -c 0 -t 3" - - ["R SSC1 C +BLEADV:SetAdv,OK"] - - *open_capture_nic - - - LOOP 4 3 "[0,2,1,3]" "['PDU','PDU','NPDU','NPDU']" - - *dut1_stop_adv - - - "SSC SSC1 bleadv -D -z start -t 0 -o {%d}" - - ["R SSC1 C +BLEADV:OK"] - - - "HCITOOL 2 -i lescan" - - - 'P PC_COM C +HCITOOL:OK' - - 'P BLENIC {%s} (HCIEvent.le_sub_event_code="LEAdvReport")(HCIEvent.event_type_0="ADV_IND")(HCIEvent.data_0.NameComplete=)(HCIEvent.address_0=)' - ID: BTSTK_GAP_03004 <<: *GAP_CASE test point 2: BLE GAP set advertise param @@ -691,9 +573,8 @@ test cases: allow fail: 2/3 cmd set: - "" - - *set_default_ble_name - - "SSC SSC1 bleadv -L -c 0 -t 3" - - ["R SSC1 C +BLEADV:SetAdv,OK"] + - ["R SSC1 C +BLEADV:SetAdv,OK C +BLEADV:SetScanRes,OK"] - *open_capture_nic - *dut1_stop_adv - - LOOP 2 2 "[0,1]" "['=','!=']" @@ -720,72 +601,13 @@ test cases: 4. calculate adv intervals, within the interval range in adv param initial condition: BLE_INIT1 test environment: SSC_T1_3 + CI ready: 'No' cmd set: - "BLEFunction/AdvInterval" - - interval_list = ["0x0020-0x0020", "0x0040-0x0040", "0x0060-0x0060"] - [''] - - deviation = 0.3 - [''] -- ID: BTSTK_GAP_03006 - <<: *GAP_CASE - test point 2: BLE GAP set advertise param - summary: ble set paramters for SCAN_IND - steps: | - 1. DUT1 stop advertise - 2. DUT1 set incorrect adv interval for SCAN_IND - 3. PC do active scan and capture advertising report - 4. repeat step 1-3 with correct adv interval - expected result: | - 1. succeed - 2. succeed - 3. can not get SCAN_IND with DUT1 BT MAC - 4. get SCAN_IND with DUT1 BT MAC - initial condition: BLE_INIT1 - test environment: SSC_T1_3 - cmd set: - - "" - - *set_default_ble_name - - - "SSC SSC1 bleadv -L -c 0 -t 3" - - ["R SSC1 C +BLEADV:SetAdv,OK"] - - *open_capture_nic - - *dut1_stop_adv - - - LOOP 2 2 "['0x20-0x40','0xA0-0xB0']" "['PDU','PDU']" - - [""] - - - "SSC SSC1 bleadv -D -z start -t 2 -i {%s}" - - ["R SSC1 C +BLEADV:OK"] - - - "HCITOOL 2 -i lescan" - - - 'P PC_COM C +HCITOOL:OK' - - 'P BLENIC {%s} (HCIEvent.le_sub_event_code="LEAdvReport")(HCIEvent.event_type_0="SCAN_IND")(HCIEvent.address_0=)' -- ID: BTSTK_GAP_03007 - <<: *GAP_CASE - test point 2: BLE GAP set advertise param - summary: ble set paramters for NONCONN_IND - steps: | - 1. DUT1 stop advertise - 2. DUT1 set incorrect adv interval for NONCONN_IND - 3. PC do active scan and capture advertising report - 4. repeat step 1-3 with correct adv interval - expected result: | - 1. succeed - 2. succeed - 3. can not get SCAN_IND with DUT1 BT MAC - 4. get SCAN_IND with DUT1 BT MAC - initial condition: BLE_INIT1 - test environment: SSC_T1_3 - cmd set: - - "" - - *set_default_ble_name - - - "SSC SSC1 bleadv -L -c 0 -t 3" - - ["R SSC1 C +BLEADV:SetAdv,OK"] - - *open_capture_nic - - *dut1_stop_adv - - - LOOP 2 2 "['0x20-0x40','0xA0-0xB0']" "['PDU','PDU']" - - [""] - - - "SSC SSC1 bleadv -D -z start -t 3 -i {%s}" - - ["R SSC1 C +BLEADV:OK"] - - - "HCITOOL 2 -i lescan" - - - 'P PC_COM C +HCITOOL:OK' - - 'P BLENIC {%s} (HCIEvent.le_sub_event_code="LEAdvReport")(HCIEvent.event_type_0="NONCONN_IND")(HCIEvent.address_0=)' - ID: BTSTK_GAP_03008 <<: *GAP_CASE test point 2: BLE GAP set advertise param @@ -801,6 +623,8 @@ test cases: 3. succeed cmd set: - "" + - - "SSC SSC1 bleadv -L -c 0 -t 3 -n 1" + - ["R SSC1 C +BLEADV:SetAdv,OK C +BLEADV:SetScanRes,OK"] - - "SSC SSC2 bleadv -D -z stop" - ["R SSC2 C +BLEADV:Stop,OK"] - - "SSC SSC2 ble -S -z privacy -p 1" @@ -808,7 +632,7 @@ test cases: - - "SSC SSC2 bleadv -D -z start -t 0 -o 2" - ["R SSC2 C +BLEADV:OK"] - - "SSC SSC1 blescan -D -z start" - - ["R SSC1 NP C Complete"] + - ["R SSC1 NP C InquiryComplete"] - ID: BTSTK_GAP_03009 <<: *GAP_CASE test point 2: BLE GAP set advertise param @@ -832,30 +656,34 @@ test cases: 7. succeed cmd set: - "" + - - "SSC SSC2 ble -S -z name -n " + - ["R SSC2 C +BLE:OK"] - - "SSC SSC2 blesmp -S -z AuthReqMode -v 0x01" - ['P SSC2 C +BLESMP:OK'] - - "SSC SSC2 blesmp -S -z IOCAP -v 0x03" - ['P SSC2 C +BLESMP:OK'] - - - "SSC SSC2 blesmp -S -z RspKey -v 0x03" - - ['P SSC2 C +BLESMP:OK'] + - - "SSC SSC[1-2] blesmp -S -z RspKey -v 0x02" + - ['P SSC[1-2] C +BLESMP:OK'] + - - "SSC SSC[1-2] blesmp -S -z InitKey -v 0x02" + - ['P SSC[1-2] C +BLESMP:OK'] + - - "SSC SSC2 bleadv -L -c 0 -n 1" + - ["R SSC2 C +BLEADV:SetAdv,OK"] - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ['P SSC1 C +BLE:GattcConnect,OK', 'P SSC2 C +BLE:GattsConnect'] + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect,OK'] - - "SSC SSC2 blesmp -E -r -z Enc" - - ['P SSC1 C +BLESMP:SecReq'] - - - "SSC SSC1 blesmp -R -a 1 -r " - ['P SSC[1-2] C +BLESMP:AuthComplete,Success,0'] - - "SSC SSC1 bleconn -D -z all" - - ['P SSC1 C +BLE:GattcDisconnect,OK', 'P SSC2 C +BLE:GattsDisconnect,OK'] + - ['P SSC1 C +BLECONN:GapDisconnect,OK', 'P SSC2 C +BLECONN:GapDisconnect,OK'] - - "SSC SSC2 ble -S -z privacy -p 1" - ["R SSC2 C +BLECONN:SetResAddr,Success"] - - "SSC SSC2 bleadv -D -z stop" - - ["R SSC2 C +BLEADV:OK"] + - ["R SSC2 C +BLEADV:"] - - "SSC SSC2 bleadv -D -z start -o 2" - ["R SSC2 C +BLEADV:OK"] - - "SSC SSC1 blescan -D -z start" - ["R SSC1 P C Complete"] - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ["R SSC1 C +BLE:GattcConnect,OK", "R SSC2 C +BLE:GattsConnect"] + - ["R SSC1 C +BLECONN:GapConnect,OK", "R SSC2 C +BLECONN:GapConnect,OK"] - ID: BTSTK_GAP_03010 <<: *GAP_CASE CI ready: "No" # can't restore to use public address after set to use private address @@ -874,8 +702,13 @@ test cases: - "" - - "SSC SSC2 bleadv -D -z stop" - ["R SSC2 C +BLEADV:Stop,OK"] + - *set_default_ble_name + - - "SSC SSC2 ble -S -z randAddr -a -r 1" + - ["R SSC2 C +BLECONN:SetRandAddr,OK"] - - "SSC SSC2 ble -S -z privacy -p 1" - ["R SSC2 C +BLECONN:SetResAddr,Success"] + - - "SSC SSC2 bleadv -L -c 0 -n 1" + - ["R SSC2 C +BLEADV:SetAdv,OK"] - - "SSC SSC2 bleadv -D -z start -t 0 -o 3" - ["R SSC2 C +BLEADV:OK"] - - "SSC SSC1 blescan -D -z start" @@ -908,30 +741,30 @@ test cases: 9. succeed cmd set: - "" - - - "SSC SSC2 blesmp -S -z AuthReqMode -v 0x01" - - ['P SSC2 C +BLESMP:OK'] - - - "SSC SSC2 blesmp -S -z IOCAP -v 0x03" - - ['P SSC2 C +BLESMP:OK'] - - - "SSC SSC2 blesmp -S -z RspKey -v 0x03" - - ['P SSC2 C +BLESMP:OK'] + - - "SSC SSC[1-2] blesmp -S -z AuthReqMode -v 0x01" + - ['P SSC[1-2] C +BLESMP:OK'] + - - "SSC SSC[1-2] blesmp -S -z IOCAP -v 0x02" + - ['P SSC[1-2] C +BLESMP:OK'] + - - "SSC SSC[1-2] blesmp -S -z RspKey -v 0x02" + - ['P SSC[1-2] C +BLESMP:OK'] - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ['P SSC1 C +BLE:GattcConnect,OK', 'P SSC2 C +BLE:GattsConnect'] + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect,OK'] - - "SSC SSC2 blesmp -E -r -z Enc" - - ['P SSC1 C +BLESMP:SecReq'] - - - "SSC SSC1 blesmp -R -a 1 -r " - ['P SSC[1-2] C +BLESMP:AuthComplete,Success,0'] - - "SSC SSC1 bleconn -D -z all" - - ['P SSC1 C +BLE:GattcDisconnect,OK', 'P SSC2 C +BLE:GattsDisconnect,OK'] + - ['P SSC1 C +BLECONN:GapDisconnect,OK', 'P SSC2 C +BLECONN:GapDisconnect,OK'] + - - "SSC SSC2 ble -S -z randAddr -a -r 1" + - ["R SSC2 C +BLECONN:SetRandAddr,OK"] - - "SSC SSC2 ble -S -z privacy -p 1" - ["R SSC2 C +BLECONN:SetResAddr,Success"] - - "SSC SSC2 bleadv -D -z stop" - - ["R SSC2 C +BLEADV:OK"] + - ["R SSC2 C +BLEADV:"] - - "SSC SSC2 bleadv -D -z start -o 3" - ["R SSC2 C +BLEADV:OK"] - - "SSC SSC1 blescan -D -z start" - ["R SSC1 P C Complete"] - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ["R SSC1 C +BLE:GattcConnect,OK", "R SSC2 C +BLE:GattsConnect"] + - ["R SSC1 C +BLECONN:GapConnect,OK", "R SSC2 C +BLECONN:GapConnect,OK"] - ID: BTSTK_GAP_03012 <<: *GAP_CASE test point 2: BLE GAP set advertise param @@ -946,7 +779,7 @@ test cases: cmd set: - "" - - "SSC SSC1 bleadv -D -z stop" - - ["R SSC1 C +BLEADV:Stop,OK"] + - ["R SSC1 C +BLEADV:"] - - "SSC SSC1 bleadv -D -z start -b -y 2" - ["R SSC1 C +BLEADV:Start,ERROR"] - - "SSC SSC1 bleadv -D -z start -b -y 3" @@ -976,16 +809,12 @@ test cases: - ["R SSC1 C +BLEADV:SetScanRes,OK"] - *dut1_start_adv - *dut2_stop_adv - - - "SSC SSC2 blescan -L -c 0 -s 0" - - ["R SSC2 C +BLESCAN:SetScanParam,OK"] - - - "SSC SSC2 blescan -D -z start -t 3 -e 2" + - - "SSC SSC2 blescan -D -z start -t 3 -e 2 -c 0 -s 0" - - 'P SSC2 RE "\+BTSCANEXT:%%s,man,0x1011121314151617181910111213141516171819"%%()' - 'R SSC2 NRE "\+BTSCANEXT:%%s,txp,0xEB"%%() C Complete' - - "SSC SSC2 blescan -D -z stop" - ['R SSC2 C +BLESCAN'] - - - "SSC SSC2 blescan -L -c 0 -s 1" - - ["R SSC2 C +BLESCAN:SetScanParam,OK"] - - - "SSC SSC2 blescan -D -z start -t 3 -e 1" + - - "SSC SSC2 blescan -D -z start -t 3 -e 1 -c 0 -s 1" - - 'P SSC2 RE "\+BTSCANEXT:%%s,man,0x1011121314151617181910111213141516171819"%%()' - 'P SSC2 RE "\+BTSCANEXT:%%s,txp,0xEB"%%()' - 'R SSC2 C Complete' @@ -1005,20 +834,25 @@ test cases: 4. error cmd set: - "" - - *set_default_ble_name - *dut1_stop_adv - - "SSC SSC1 bleadv -L -c 0 -t 3" - ["R SSC1 C +BLEADV:SetScanRes,OK"] - *dut1_start_adv - *dut2_stop_adv - - - LOOP 4 2 "[0,1,2,3]" - - [''] - - - "SSC SSC2 blescan -L -c 0 -s 1 -o {%d}" - - ["R SSC2 C +BLESCAN:SetScanParam,OK"] - - - "SSC SSC2 blescan -D -z start -t 1" + - - "SSC SSC2 blescan -D -z start -t 1 -c 0 -s 1 -o 0" + - ['R SSC2 P C Complete'] + - - "SSC SSC2 ble -S -z privacy -p 1" + - ["R SSC2 C +BLECONN:SetResAddr,Success"] + - - "SSC SSC2 blescan -D -z start -t 1 -c 0 -s 1 -o 2" + - ['R SSC2 P C Complete'] + - - "SSC SSC2 ble -S -z randAddr -a -r 1" + - ["R SSC2 C +BLECONN:SetRandAddr,OK"] + - - "SSC SSC2 blescan -D -z start -t 1 -c 0 -s 1 -o 1" + - ['R SSC2 P C Complete'] + - - "SSC SSC2 ble -S -z privacy -p 1" + - ["R SSC2 C +BLECONN:SetResAddr,Success"] + - - "SSC SSC2 blescan -D -z start -t 1 -c 0 -s 1 -o 3" - ['R SSC2 P C Complete'] - - - "SSC SSC2 blescan -L -c 0 -o 4" - - ["R SSC2 C +BLESCAN:SetScanParam,ERROR"] - ID: BTSTK_GAP_04003 <<: *GAP_CASE test point 2: BLE GAP set scan param @@ -1035,17 +869,19 @@ test cases: 4. error cmd set: - "" - - - "SSC SSC2 bleadv -D -z start" - - ["R SSC2 C +BLEADV:OK"] - *dut1_stop_adv - - - "SSC SSC1 blescan -L -c 0 -s 1 -i 0x0004 -w 0x0003" - - ["R SSC1 C +BLESCAN:SetScanParam,OK"] - - - "SSC SSC1 blescan -L -c 0 -s 1 -i 0x4000 -w 0x4000" - - ["R SSC1 C +BLESCAN:SetScanParam,OK"] - - - "SSC SSC1 blescan -L -c 0 -s 1 -i 0x0003 -w 0x0003" - - ["R SSC1 C +BLESCAN:SetScanParam,ERROR"] - - - "SSC SSC1 blescan -L -c 0 -s 1 -i 0x4001 -w 0x4001" - - ["R SSC1 C +BLESCAN:SetScanParam,ERROR"] + - - "SSC SSC1 blescan -D -z start -c 0 -s 1 -i 0x0004 -w 0x0004" + - ["R SSC1 C +BLESCAN:Start,OK"] + - - "SSC SSC1 blescan -D -z stop" + - ["R SSC1 C +BLESCAN:Stop,OK"] + - - "SSC SSC1 blescan -D -z start -c 0 -s 1 -i 0x4000 -w 0x4000" + - ["R SSC1 C +BLESCAN:Start,OK"] + - - "SSC SSC1 blescan -D -z stop" + - ["R SSC1 C +BLESCAN:Stop,OK"] + - - "SSC SSC1 blescan -D -z start -c 0 -s 1 -i 0x0003 -w 0x0003" + - ["R SSC1 C +BLESCAN:Start,ERROR"] + - - "SSC SSC1 blescan -D -z start -c 0 -s 1 -i 0x4001 -w 0x4001" + - ["R SSC1 C +BLESCAN:Start,ERROR"] - ID: BTSTK_GAP_04004 <<: *GAP_CASE test point 2: BLE GAP set scan param @@ -1064,14 +900,18 @@ test cases: test environment: SSC_T1_4 cmd set: - "" - - - "SSC SSC1 blescan -L -c 0 -w 0x0004 -i 0x004" - - ["R SSC1 C +BLESCAN:SetScanParam,OK"] - - - "SSC SSC1 blescan -L -c 0 -w 0x4000 -i 0x4000" - - ["R SSC1 C +BLESCAN:SetScanParam,OK"] - - - "SSC SSC1 blescan -L -c 0 -w 0x0003 -i 0x0003" - - ["R SSC1 C +BLESCAN:SetScanParam,ERROR"] - - - "SSC SSC1 blescan -L -c 0 -w 0x4001 -i 0x4001" - - ["R SSC1 C +BLESCAN:SetScanParam,ERROR"] + - - "SSC SSC1 blescan -D -z start -c 0 -w 0x0004 -i 0x0004" + - ["R SSC1 C +BLESCAN:Start,OK"] + - - "SSC SSC1 blescan -D -z stop" + - ["R SSC1 C +BLESCAN:Stop,OK"] + - - "SSC SSC1 blescan -D -z start -c 0 -w 0x4000 -i 0x4000" + - ["R SSC1 C +BLESCAN:Start,OK"] + - - "SSC SSC1 blescan -D -z stop" + - ["R SSC1 C +BLESCAN:Stop,OK"] + - - "SSC SSC1 blescan -D -z start -c 0 -w 0x0003 -i 0x0003" + - ["R SSC1 C +BLESCAN:Start,ERROR"] + - - "SSC SSC1 blescan -D -z start -c 0 -w 0x4001 - 0x4001" + - ["R SSC1 C +BLESCAN:Start,ERROR"] - ID: BTSTK_GAP_05001 <<: *GAP_CASE test point 2: BLE GAP start stop adv / scan @@ -1090,20 +930,16 @@ test cases: 4. succeed 5. succeed 6. DUT1 in scan result - initial condition: BLE_INIT2 cmd set: - "" - *dut1_stop_adv - *dut1_stop_adv - - - "SSC SSC2 blescan -L -c 0" - - ["R SSC2 C +BLESCAN:SetScanParam,OK"] - - - "SSC SSC2 blescan -D -z start -t 1" + - - "SSC SSC2 blescan -D -z start -t 1 -c 0" - ["R SSC2 NP C Complete"] - *dut1_start_adv - - *dut1_start_adv - - - "SSC SSC2 blescan -L -c 0" - - ["R SSC2 C +BLESCAN:SetScanParam,OK"] - - - "SSC SSC2 blescan -D -z start -t 1" + - - "SSC SSC1 bleadv -D -z start" + - ["R SSC1 C +BLEADV:Start"] + - - "SSC SSC2 blescan -D -z start -t 1 -c 0" - ["R SSC2 P C Complete"] - ID: BTSTK_GAP_05002 <<: *GAP_CASE @@ -1121,864 +957,22 @@ test cases: test environment: SSC_T1_4 cmd set: - "" - - - "SSC SSC1 blescan -L -c 0" - - ["R SSC1 C +BLESCAN:SetScanParam,OK"] - - - "SSC SSC1 blescan -D -z start -t 3" + - - "SSC SSC1 blescan -D -z start -t 3 -c 0" - ["R SSC1 C +BLESCAN:OK"] - - "SSC SSC1 blescan -D -z stop" - ["R SSC1 C +BLESCAN:Stop,OK"] - - "SSC SSC1 blescan -D -z stop" - ["R SSC1 C +BLESCAN:Stop,ERROR"] -- ID: BTSTK_GAP_06001 - <<: *GAP_CASE - test point 2: BLE GAP connect / disconnect - summary: ble connect as "client" and "server" - allow fail: 1/2 - steps: | - 1. DUT1 connect to DUT2 as "client" - 2. DUT1 disconnected with DUT2 - 3. DUT1 start gatt server app - 4. DUT1 connect to DUT2 as "server" - expected result: | - 1. succeed - 2. succeed - 3. succeed - 4. succeed - cmd set: - - "" - - *dut1_connect_to_dut2 - - - "SSC SSC1 bleconn -D -p 0x10" - - ['R SSC1 C +BLE:CLOSE,OK'] - - - "SSC SSC1 gatts -S -z load -p 0xA0" - - ['R SSC1 C +GATTS:LoadProfile,OK'] - - - "SSC SSC2 bleadv -D -z start" - - ['R SSC2 C +BLEADV:OK'] - - - "SSC SSC1 bleconn -C -p 0xA0 -a -z server" - - ['R SSC1 C +BLE:GattsConnect'] -- ID: BTSTK_GAP_06002 - <<: *GAP_CASE - test point 2: BLE GAP connect / disconnect - summary: ble disconnect as "client" and "server" - steps: | - 1. DUT1 connect to DUT2 as "client" - 2. DUT1 disconnected with DUT2 as "client" - 3. DUT1 start gatt server app - 4. DUT1 connect to DUT2 as client - 5. DUT1 disconnect with DUT2 as "server" - expected result: | - 1. succeed - 2. succeed - 3. succeed - 4. succeed - 5. succeed - cmd set: - - "" - - *dut1_connect_to_dut2 - - - "SSC SSC1 bleconn -D -p 0x10" - - ['R SSC1 C +BLE:CLOSE,OK'] - - - "SSC SSC2 bleadv -D -z start" - - ['R SSC2 C +BLEADV:OK'] - - - "SSC SSC1 gatts -S -z load -p 0xA0" - - ['R SSC1 C +GATTS:LoadProfile,OK'] - - *dut1_connect_to_dut2 - - - "SSC SSC1 bleconn -D -p 0x10" - - ['R SSC1 C +BLE:CLOSE,OK'] -- ID: BTSTK_GAP_06003 - <<: *GAP_CASE - allow fail: 1/2 - test point 2: BLE GAP connect / disconnect - summary: ble connect/disconnect to same connection multiple times - steps: | - 1. DUT1 connect to DUT2 as "client" - 2. DUT1 start gatt server app - 3. DUT1 connect to DUT2 as "client" again - 4. DUT1 connect to DUT2 as "server" - 5. DUT1 disconnected with DUT2 as "client" - 6. DUT1 disconnected with DUT2 as "server" - expected result: | - 1. succeed - 2. succeed - 3. succeed - 4. succeed - 5. succeed - 6. succeed - cmd set: - - "" - - *dut1_connect_to_dut2 - - - "SSC SSC1 gatts -S -z load -p 0xA0" - - ['R SSC1 C +GATTS:LoadProfile,OK'] - - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ['R SSC1 C +BLE:GattcOpen,OK'] - - - "SSC SSC1 bleconn -C -p 0xA0 -a -z server" - - ['R SSC1 C +BLE:GattsOpen,OK,00A0'] - - - "SSC SSC1 bleconn -D -p 0x10" - - ['R SSC1 C +BLE:CLOSE,OK'] - - - "SSC SSC1 bleconn -D -p 0xA0 -z server" - - ['R SSC1 C +BLE:GattsClose,OK'] -- ID: BTSTK_GAP_06004 - <<: *GAP_CASE - test point 2: BLE GAP connect / disconnect - summary: ble connect to invalid address - allow fail: 2/3 - steps: | - 1. DUT1 connect to invalid address - 2. DUT1 connect to DUT2 - expected result: | - 1. failed - 2. succeed - cmd set: - - "" - - - "SSC SSC1 bleconn -C -p 0x10 -a 24:0a:c4:04:26:50" - - ['R SSC1 C +BLECONN:OK'] - - - DELAY 30 - - ['R SSC1 C +BLE:GattcOpen,ERROR'] - - *dut1_connect_to_dut2 -- ID: BTSTK_GAP_06005 - <<: *GAP_CASE - test point 2: BLE GAP connect / disconnect - summary: ble connect/disconnect event to active app - steps: | - 1. DUT1 create gatts app - 2. DUT1 connect to DUT2 as "client" - 3. DUT1 do disconnect as "server" - expected result: | - 1. succeed - 2. succeed, DUT1 and DUT2 gatts get connect event - 3. DUT1 and DUT2 gatts get disconnect event - cmd set: - - "" - - - "SSC SSC1 gatts -S -z load -p 0xA0" - - ['R SSC1 C +GATTS:LoadProfile,OK'] - - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ['P SSC1 C +BLE:GattcConnect C +BLE:GattsConnect', 'P SSC2 C +BLE:GattsConnect'] - - - "SSC SSC1 bleconn -D -p 0xA0 -z server" - - ['P SSC1 C +BLE:GattsClose'] -- ID: BTSTK_GAP_07001 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update connect parameters by master - steps: | - 1. update connect parameters by master - expected result: | - 1. succeed - initial condition: BLE_CONN2 - cmd set: - - "BLEFunction/ConnParamUpdate" - - - dut = ["SSC1"] - - [''] - - - interval=["32-64"] - - [''] - - - latency=["0"] - - [''] - - - supervision_timeout=["32"] - - [''] - - - expect_result=["OK"] - - [''] -- ID: BTSTK_GAP_07002 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update connect parameters by slave - steps: | - 1. update connect parameters by slave - expected result: | - 1. succeed - initial condition: BLE_CONN2 - cmd set: - - "BLEFunction/ConnParamUpdate" - - - dut = ["SSC2"] - - [''] - - - interval=["32-64"] - - [''] - - - latency=["0"] - - [''] - - - supervision_timeout=["32"] - - [''] - - - expect_result=["OK"] - - [''] -- ID: BTSTK_GAP_07003 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update invalid connect parameters(timeout<(1+latency)*2*MAX_interval*1.25) - steps: | - 1. update invalid connect parameters(timeout<(1+latency)*2*MAX_interval*1.25) - expected result: | - 1. fail - initial condition: BLE_CONN2 - cmd set: - - "BLEFunction/ConnParamUpdate" - - - dut = ["SSC1"] - - [''] - - - interval=["7-90"] - - [''] - - - latency=["1"] - - [''] - - - supervision_timeout=["41"] - - [''] - - - expect_result=["ERROR"] - - [''] -- ID: BTSTK_GAP_07004 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update connnect parameters and interval within allowed range - steps: | - 1. DUT1 update connection parametres and interval is 6-128 - 2. DUT1 update connection parametres and interval is 33-3200 - expected result: | - 1. succeed - 2. succeed - initial condition: BLE_CONN2 - cmd set: - - "BLEFunction/ConnParamUpdate" - - - dut = ["SSC1","SSC1"] - - [''] - - - interval=["6-128","33-3200"] - - [''] - - - latency=["0","0"] - - [''] - - - supervision_timeout=["50","1000"] - - [''] - - - expect_result=["OK","OK"] - - [''] -- ID: BTSTK_GAP_07005 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update connect parameters interval and interval out of allowed range - steps: | - 1. DUT1 update invalid interval and interval is 16-3201 - 2. DUT1 update invalid interval and interval is 5-64 - expected result: | - 1. fail - 2. fail - initial condition: BLE_CONN2 - cmd set: - - "BLEFunction/ConnParamUpdate" - - - dut = ["SSC1","SSC1"] - - [''] - - - interval=["16-3201","5-64"] - - [''] - - - latency=["0","0"] - - [''] - - - supervision_timeout=["32","32"] - - [''] - - - expect_result=["ERROR","ERROR"] - - [''] -- ID: BTSTK_GAP_07006 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update connect parameters latency and latency within allowed range and timeout<(1+latency)*2*MAX_interval*1.25 - steps: | - 1. DUT1 update connect parameters latency and latency within allowed range and timeout<(1+latency)*2*MAX_interval*1.25 - expected result: | - 1. fail - initial condition: BLE_CONN2 - cmd set: - - "BLEFunction/ConnParamUpdate" - - - dut = ["SSC1"] - - [''] - - - interval=["32-64"] - - [''] - - - latency=["8"] - - [''] - - - supervision_timeout=["32"] - - [''] - - - expect_result=["ERROR"] - - [''] -- ID: BTSTK_GAP_07007 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update connect parameters latency and latency = 501 - steps: | - 1. DUT1 uupdate connect parameters latency and latency = 501 - expected result: | - 1. fail - initial condition: BLE_CONN2 - cmd set: - - "BLEFunction/ConnParamUpdate" - - - dut = ["SSC1"] - - [''] - - - interval=["6-8"] - - [''] - - - latency=["501"] - - [''] - - - supervision_timeout=["1003"] - - [''] - - - expect_result=["ERROR"] - - [''] -- ID: BTSTK_GAP_07008 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update connect parameters latency and latency = 500 - steps: | - 1. DUT1 update connect parameters latency and latency = 500 - expected result: | - 1. succeed - initial condition: BLE_CONN2 - cmd set: - - "BLEFunction/ConnParamUpdate" - - - dut = ["SSC1"] - - [''] - - - interval=["6-8"] - - [''] - - - latency=["500"] - - [''] - - - supervision_timeout=["1003"] - - [''] - - - expect_result=["OK"] - - [''] -- ID: BTSTK_GAP_07009 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update connect parameters timeout and timeout within allowed range and timeout<(1+latency)*2*MAX_interval*1.25 - steps: | - 1. DUT1 update connect parameters timeout and timeout within allowed range and timeout<(1+latency)*2*MAX_interval*1.25 - expected result: | - 1. fail - initial condition: BLE_CONN2 - cmd set: - - "BLEFunction/ConnParamUpdate" - - - dut = ["SSC1"] - - [''] - - - interval=["32-64"] - - [''] - - - latency=["0"] - - [''] - - - supervision_timeout=["12"] - - [''] - - - expect_result=["ERROR"] - - [''] -- ID: BTSTK_GAP_07010 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update connect parameters timeout and timeout = 9 - steps: | - 1. DUT1 update connect parameters timeout and timeout = 9 - expected result: | - 1. fail - initial condition: BLE_CONN2 - cmd set: - - "BLEFunction/ConnParamUpdate" - - - dut = ["SSC1"] - - [''] - - - interval=["8-10"] - - [''] - - - latency=["0"] - - [''] - - - supervision_timeout=["9"] - - [''] - - - expect_result=["ERROR"] - - [''] -- ID: BTSTK_GAP_07011 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update connect parameters timeout and timeout within allowed range - steps: | - 1. DUT1 update timeout = 10 - 2. DUT1 update timeout = 3200 - expected result: | - 1. succeed - 2. succeed - initial condition: BLE_CONN2 - cmd set: - - "BLEFunction/ConnParamUpdate" - - - dut = ["SSC1","SSC1"] - - [''] - - - interval=["8-10","8-10"] - - [''] - - - latency=["0","0"] - - [''] - - - supervision_timeout=["10","3200"] - - [''] - - - expect_result=["OK","OK"] - - [''] -- ID: BTSTK_GAP_07012 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update connect parameters timeout and timeout = 3201 - steps: | - 1. DUT1 update timeout = 3201 - expected result: | - 1. fail - initial condition: BLE_CONN2 - cmd set: - - "BLEFunction/ConnParamUpdate" - - - dut = ["SSC1"] - - [''] - - - interval=["8-10"] - - [''] - - - latency=["0"] - - [''] - - - supervision_timeout=["3201"] - - [''] - - - expect_result=["ERROR"] - - [''] -- ID: BTSTK_GAP_07013 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update invalid connect parameters before configure connect param event back - steps: | - 1. DUT1 update valid interval - 2. DUT1 update valid interval - expected result: | - 1. - 2. succeed - initial condition: BLE_CONN2 - cmd set: - - "" - - - "SSC SSC1 bleconn -S -z ConnParam -a " - - [''] - - - "SSC SSC1 bleconn -S -z ConnParam -a -t 0x40" - - ['R SSC1 C pending'] -- ID: BTSTK_GAP_07014 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update invalid connect param and unpdate valid connect params by master - steps: | - 1. DUT1 update invalid connect parameters - 2. DUT2 update valid connect - expected result: | - 1. fail - 2. succeed - initial condition: BLE_CONN2 - cmd set: - - "BLEFunction/ConnParamUpdate" - - - dut = ["SSC1","SSC1"] - - [''] - - - interval=["32-64","32-64"] - - [''] - - - latency=["9","0"] - - [''] - - - supervision_timeout=["32","32"] - - [''] - - - expect_result=["ERROR","OK"] - - [''] -- ID: BTSTK_GAP_07015 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update valid connect parameters twice - allow fail: 1/2 - steps: | - 1. DUT1 update valid connect parameters - 2. DUT1 update valid connect parameters - expected result: | - 1. succeed - 2. succeed - initial condition: BLE_CONN2 - cmd set: - - "BLEFunction/ConnParamUpdate" - - - dut = ["SSC1","SSC1"] - - [''] - - - interval=["7-80","10-100"] - - [''] - - - latency=["1","0"] - - [''] - - - supervision_timeout=["41","30"] - - [''] - - - expect_result=["OK","OK"] - - [''] -- ID: BTSTK_GAP_07016 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update valid connect parameters(timeout<(1+latency)*2*MAX_interval*1.25) by slave - steps: | - 1. DUT2 update valid connect parameters(timeout<(1+latency)*2*MAX_interval*1.25) by slave - expected result: | - 1. fail - initial condition: BLE_CONN2 - cmd set: - - "BLEFunction/ConnParamUpdate" - - - dut = ["SSC2"] - - [''] - - - interval=["7-90"] - - [''] - - - latency=["1"] - - [''] - - - supervision_timeout=["41"] - - [''] - - - expect_result=["ERROR"] - - [''] -- ID: BTSTK_GAP_07017 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update connnect parameters interval within allowed range by slave - steps: | - 1. DUT2 update interval 6-128 - 2. DUT2 update interval 21-3200 - expected result: | - 1. succeed - 2. succeed - initial condition: BLE_CONN2 - cmd set: - - "BLEFunction/ConnParamUpdate" - - - dut = ["SSC2","SSC2"] - - [''] - - - interval=["6-128","21-3200"] - - [''] - - - latency=["0","0"] - - [''] - - - supervision_timeout=["50","1000"] - - [''] - - - expect_result=["OK","OK"] - - [''] -- ID: BTSTK_GAP_07018 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update connnect parameters interval out of allowed range by slave - steps: | - 1. DUT2 update invalid interval 10-3201 - 2. DUT2 update invalid interval 5-64 - expected result: | - 1. fail - 2. fail - initial condition: BLE_CONN2 - cmd set: - - "BLEFunction/ConnParamUpdate" - - - dut = ["SSC2","SSC2"] - - [''] - - - interval=["10-3201","5-64"] - - [''] - - - latency=["0","0"] - - [''] - - - supervision_timeout=["32","32"] - - [''] - - - expect_result=["ERROR","ERROR"] - - [''] -- ID: BTSTK_GAP_07019 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update connnect parameters and latency within allowed range and timeout<(1+latency)*2*MAX_interval*1.25 by slave - steps: | - 1. DUT2 update connnect parameters and latency within allowed range and timeout<(1+latency)*2*MAX_interval*1.25 by slave - expected result: | - 1. fail - initial condition: BLE_CONN2 - cmd set: - - "BLEFunction/ConnParamUpdate" - - - dut = ["SSC2"] - - [''] - - - interval=["32-64"] - - [''] - - - latency=["8"] - - [''] - - - supervision_timeout=["32"] - - [''] - - - expect_result=["ERROR"] - - [''] -- ID: BTSTK_GAP_07020 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update connect parameters latency and latency out of allowed range by slave - steps: | - 1. DUT2 update invalid latency = 501 - expected result: | - 1. fail - initial condition: BLE_CONN2 - cmd set: - - "BLEFunction/ConnParamUpdate" - - - dut = ["SSC2"] - - [''] - - - interval=["6-8"] - - [''] - - - latency=["501"] - - [''] - - - supervision_timeout=["1003"] - - [''] - - - expect_result=["ERROR"] - - [''] -- ID: BTSTK_GAP_07021 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update valid connect parameters and latency = 500 by slave - steps: | - 1. DUT2 update latency = 500 - expected result: | - 1. success - initial condition: BLE_CONN2 - cmd set: - - "BLEFunction/ConnParamUpdate" - - - dut = ["SSC2"] - - [''] - - - interval=["6-8"] - - [''] - - - latency=["500"] - - [''] - - - supervision_timeout=["1003"] - - [''] - - - expect_result=["OK"] - - [''] -- ID: BTSTK_GAP_07022 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update connect parameters timeout and timeout = 9 by slave - steps: | - 1. DUT2 update connect parameters timeout and timeout = 9 - expected result: | - 1. fail - initial condition: BLE_CONN2 - cmd set: - - "BLEFunction/ConnParamUpdate" - - - dut = ["SSC2"] - - [''] - - - interval=["8-10"] - - [''] - - - latency=["0"] - - [''] - - - supervision_timeout=["9"] - - [''] - - - expect_result=["ERROR"] - - [''] -- ID: BTSTK_GAP_07023 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update connect parameters timeout and timeout = 10 by slave - steps: | - 1. DUT2 update connect parameters timeout and timeout = 10 by slave - expected result: | - 1. fail - initial condition: BLE_CONN2 - cmd set: - - "BLEFunction/ConnParamUpdate" - - - dut = ["SSC2"] - - [''] - - - interval=["8-10"] - - [''] - - - latency=["0"] - - [''] - - - supervision_timeout=["10"] - - [''] - - - expect_result=["OK"] - - [''] -- ID: BTSTK_GAP_07024 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update connect parameters timeout and timeout = 3200 by slave - steps: | - 1. DUT2 update connect parameters timeout and timeout = 3200 by slave - expected result: | - 1. fail - initial condition: BLE_CONN2 - cmd set: - - "BLEFunction/ConnParamUpdate" - - - dut = ["SSC2"] - - [''] - - - interval=["8-10"] - - [''] - - - latency=["0"] - - [''] - - - supervision_timeout=["3200"] - - [''] - - - expect_result=["OK"] - - [''] -- ID: BTSTK_GAP_07025 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update connect parameters timeout and timeout = 3201 by slave - steps: | - 1. DUT2 update connect parameters timeout and timeout = 3201 by slave - expected result: | - 1. fail - initial condition: BLE_CONN2 - cmd set: - - "BLEFunction/ConnParamUpdate" - - - dut = ["SSC2"] - - [''] - - - interval=["8-10"] - - [''] - - - latency=["0"] - - [''] - - - supervision_timeout=["3201"] - - [''] - - - expect_result=["ERROR"] - - [''] -- ID: BTSTK_GAP_07026 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update invalid connect parameters before configure connect param event back by slave - steps: | - 1. DUT2 update valid interval - 2. DUT2 update valid interval - expected result: | - 1. - 2. pending - initial condition: BLE_CONN2 - cmd set: - - "" - - - "SSC SSC2 bleconn -S -z ConnParam -a " - - [''] - - - "SSC SSC2 bleconn -S -z ConnParam -a -t 0x40" - - ['R SSC2 C pending'] -- ID: BTSTK_GAP_07027 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update invalid connect param and update valid connect params by slave - steps: | - 1. DUT2 update invalid connect - 2. DUT2 update valid connect - expected result: | - 1. fail - 2. succeed - initial condition: BLE_CONN2 - cmd set: - - "BLEFunction/ConnParamUpdate" - - - dut = ["SSC2","SSC2"] - - [''] - - - interval=["32-64","32-64"] - - [''] - - - latency=["0","0"] - - [''] - - - supervision_timeout=["9","21"] - - [''] - - - expect_result=["ERROR","OK"] - - [''] -- ID: BTSTK_GAP_07028 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update valid connect parameters twice by slave - allow fail: 1/2 - steps: | - 1. DUT2 update valid interval - 2. DUT2 update valid interval - expected result: | - 1. succeed - 2. succeed - initial condition: BLE_CONN2 - cmd set: - - "BLEFunction/ConnParamUpdate" - - - dut = ["SSC2","SSC2"] - - [''] - - - interval=["7-80","10-100"] - - [''] - - - latency=["1","0"] - - [''] - - - supervision_timeout=["41","30"] - - [''] - - - expect_result=["OK","OK"] - - [''] -- ID: BTSTK_GAP_07029 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update invalid connect param by master and update valid connect params by slave - steps: | - 1. DUT1 update invalid connect - 2. DUT2 update valid connect - expected result: | - 1. fail - 2. succeed - initial condition: BLE_CONN2 - cmd set: - - "BLEFunction/ConnParamUpdate" - - - dut = ["SSC1","SSC2"] - - [''] - - - interval=["32-64","32-64"] - - [''] - - - latency=["9","0"] - - [''] - - - supervision_timeout=["32","32"] - - [''] - - - expect_result=["ERROR","OK"] - - [''] -- ID: BTSTK_GAP_07030 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update valid connect param by master and update valid connect params by slave - steps: | - 1. DUT1 update valid interval - 2. DUT2 update valid interval - expected result: | - 1. succeed - 2. succeed - initial condition: BLE_CONN2 - cmd set: - - "BLEFunction/ConnParamUpdate" - - - dut = ["SSC1","SSC2"] - - [''] - - - interval=["7-80","10-100"] - - [''] - - - latency=["1","0"] - - [''] - - - supervision_timeout=["41","30"] - - [''] - - - expect_result=["OK","OK"] - - [''] -- ID: BTSTK_GAP_07031 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update invalid connect param by slave and update valid connect params by master - steps: | - 1. DUT1 update invalid connect - 2. DUT2 update valid connect - expected result: | - 1. fail - 2. success - initial condition: BLE_CONN2 - cmd set: - - "BLEFunction/ConnParamUpdate" - - - dut = ["SSC2","SSC1"] - - [''] - - - interval=["32-64","32-64"] - - [''] - - - latency=["9","0"] - - [''] - - - supervision_timeout=["32","32"] - - [''] - - - expect_result=["ERROR","OK"] - - [''] -- ID: BTSTK_GAP_07032 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update valid connect param by slave and update valid connect params by master - allow fail: 1/2 - steps: | - 1. DUT2 update valid interval - 2. DUT1 update valid interval - expected result: | - 1. succeed - 2. succeed - initial condition: BLE_CONN2 - cmd set: - - "BLEFunction/ConnParamUpdate" - - - dut = ["SSC2","SSC1"] - - [''] - - - interval=["7-80","10-100"] - - [''] - - - latency=["1","0"] - - [''] - - - supervision_timeout=["41","30"] - - [''] - - - expect_result=["OK","OK"] - - [''] -- ID: BTSTK_GAP_07033 - <<: *GAP_CASE - test point 2: BLE GAP update connect parameters - summary: update connect parameters by master after pairing - steps: | - 1. DUT1 update connection parameters - expected result: | - 1. succeed - initial condition: BLE_CONN_SMP - cmd set: - - "BLEFunction/ConnParamUpdate" - - - dut = ["SSC1"] - - [''] - - - interval=["32-64"] - - [''] - - - latency=["0"] - - [''] - - - supervision_timeout=["32"] - - [''] - - - expect_result=["OK"] - - [''] - ID: BTSTK_GAP_08001 <<: *GAP_CASE test point 2: BLE GAP operation without init/enable BT or register callback summary: do adv, scan, set name when BT is deinit steps: | 1. DUT1 do adv - 2. DUT1 do scan - 3. DUT1 do set name + 2. DUT1 do set name expected result: | 1. fail 2. fail - 3. fail initial condition: BLE_DEINIT1 test environment: SSC_T1_4 cmd set: @@ -1987,10 +981,6 @@ test cases: - ["R SSC1 C +BLEADV"] - - "SSC SSC1 bleadv -D -z start" - ["R SSC1 C +BLEADV"] - - - "SSC SSC1 blescan -L -c 0" - - ["R SSC1 C +BLESCAN"] - - - "SSC SSC1 blescan -D -z start" - - ["R SSC1 C +BLESCAN"] - - "SSC SSC1 ble -S -z name -n abcde" - ["R SSC1 C +BLE"] - ID: BTSTK_GAP_08002 @@ -2000,13 +990,11 @@ test cases: steps: | 1. DUT1 do init 2. DUT1 do adv - 3. DUT1 do scan - 4. DUT2 do set name + 3. DUT2 do set name expected result: | 1. succeed 2. fail 3. fail - 4. fail initial condition: BLE_DEINIT1 test environment: SSC_T1_4 cmd set: @@ -2017,10 +1005,6 @@ test cases: - ["R SSC1 C +BLEADV"] - - "SSC SSC1 bleadv -D -z start" - ["R SSC1 C +BLEADV"] - - - "SSC SSC1 blescan -L -c 0" - - ["R SSC1 C +BLESCAN"] - - - "SSC SSC1 blescan -D -z start" - - ["R SSC1 C +BLESCAN"] - - "SSC SSC1 ble -S -z name -n abcde" - ["R SSC1 C +BLE"] - ID: BTSTK_GAP_08003 @@ -2030,13 +1014,11 @@ test cases: steps: | 1. DUT1 do init and enable 2. DUT1 do adv - 3. DUT1 do scan - 4. DUT2 do set name + 3. DUT2 do set name expected result: | 1. succeed 2. fail 3. fail - 4. fail initial condition: BLE_DEINIT1 test environment: SSC_T1_4 cmd set: @@ -2047,40 +1029,8 @@ test cases: - ["R SSC1 C +BLEADV"] - - "SSC SSC1 bleadv -D -z start" - ["R SSC1 C +BLEADV"] - - - "SSC SSC1 blescan -L -c 0" - - ["R SSC1 C +BLESCAN"] - - - "SSC SSC1 blescan -D -z start" - - ["R SSC1 C +BLESCAN"] - - "SSC SSC1 ble -S -z name -n abcde" - ["R SSC1 C +BLE"] -- ID: BTSTK_GAP_09001 - <<: *GAP_CASE - test point 2: BLE GAP processing scan data - summary: process scan data txp, manufacturer data, interval range, appearence, flag - steps: | - 1. DUT1 set raw adv data tx power, manufacturer data, interval range, apperaence, flag - 2. DUT1 start adv - 3. DUT2 do active scan with extended scan data 19 - expected result: | - 1. succeed - 2. succeed - 3. scan with the correct adv data - cmd set: - - "" - - - "SSC SSC2 blescan -L -c 0 -d 1" - - ["R SSC2 C +BLESCAN:SetScanParam,OK"] - - *dut1_stop_adv - - - "SSC SSC1 bleadv -R -t 1 -r 0x020AEB06FF1112131415051220004000021901020106" - - ["R SSC1 C +BLEADV:OK"] - - *dut1_start_adv - - *dut2_stop_adv - - - "SSC SSC2 blescan -D -z start -t 1 -e 1" - - - 'P SSC2 RE "\+BTSCANEXT:%%s,man,0x1112131415"%%()' - - 'P SSC2 RE "\+BTSCANEXT:%%s,txp,0xEB"%%()' - - 'P SSC2 RE "\+BTSCANEXT:%%s,intrange,0x20004000"%%()' - - 'P SSC2 RE "\+BTSCANEXT:%%s,app,0x01"%%()' - - 'P SSC2 RE "\+BTSCANEXT:%%s,flag,0x06"%%()' - - 'R SSC2 C Complete' - ID: BTSTK_GAP_09002 <<: *GAP_CASE test point 2: BLE GAP processing scan data @@ -2097,18 +1047,17 @@ test cases: 4. scan with the correct adv data cmd set: - "" - - *dut1_stop_adv - *dut2_stop_adv - - - "SSC SSC2 blescan -L -c 0 -d 1" - - ["R SSC2 C +BLESCAN:SetScanParam,OK"] - - - LOOP 4 3 "['0302ABCD','0303ABCD','0504ABCDABCD','0505ABCDABCD',]" "['insrv16,0xABCD','srv16,0xABCD','insrv32,0xABCDABCD','srv32,0xABCDABCD']" + - - LOOP 4 4 "['0302ABCD','0303ABCD','0504ABCDABCD','0505ABCDABCD',]" "['insrv16,0xABCD','srv16,0xABCD','insrv32,0xABCDABCD','srv32,0xABCDABCD']" + - *dut1_stop_adv - - "SSC SSC1 bleadv -R -t 1 -r 0x{%s}" - ["R SSC1 C +BLEADV:OK"] - *dut1_start_adv - - - "SSC SSC2 blescan -D -z start -t 1 -e 1" + - - "SSC SSC2 blescan -D -z start -t 1 -e 1 -c 0 -d 1" - - 'P SSC2 RE "\+BTSCANEXT:%%s,{%s}"%%()' - 'R SSC2 C Complete' - - - LOOP 2 3 "['1106ABCDABCDABCDABCDABCDABCDABCDABCD','1107ABCDABCDABCDABCDABCDABCDABCDABCD']" "['insrv128,0xABCDABCDABCDABCDABCDABCDABCDABCD','srv128,0xABCDABCDABCDABCDABCDABCDABCDABCD']" + - - LOOP 2 4 "['1106ABCDABCDABCDABCDABCDABCDABCDABCD','1107ABCDABCDABCDABCDABCDABCDABCDABCD']" "['insrv128,0xABCDABCDABCDABCDABCDABCDABCDABCD','srv128,0xABCDABCDABCDABCDABCDABCDABCDABCD']" + - *dut1_stop_adv - - "SSC SSC1 bleadv -R -t 1 -r 0x{%s}" - ["R SSC1 C +BLEADV:OK"] - *dut1_start_adv @@ -2131,47 +1080,14 @@ test cases: 4. scan with the correct adv data cmd set: - "" - - *dut1_stop_adv - *dut2_stop_adv - - - "SSC SSC2 blescan -L -c 0 -d 1" - - ["R SSC2 C +BLESCAN:SetScanParam,OK"] - - - LOOP 3 3 "['0416ABCDEF','0620ABCDABCDEF','1221ABCDABCDABCDABCDABCDABCDABCDABCDEF',]" "['srvdata,0xABCDEF','srvdata32,0xABCDABCDEF','srvdata128,0xABCDABCDABCDABCDABCDABCDABCDABCDEF']" + - - LOOP 3 4 "['0416ABCDEF','0620ABCDABCDEF','1221ABCDABCDABCDABCDABCDABCDABCDABCDEF',]" "['srvdata16,0xABCDEF','srvdata32,0xABCDABCDEF','srvdata128,0xABCDABCDABCDABCDABCDABCDABCDABCDEF']" - - "SSC SSC1 bleadv -R -t 1 -r 0x{%s}" - ["R SSC1 C +BLEADV:OK"] - - *dut1_start_adv - - - "SSC SSC2 blescan -D -z start -t 1 -e 1" - - - 'P SSC2 RE "\+BTSCANEXT:%%s,{%s}"%%()' - - 'R SSC2 C Complete' -- ID: BTSTK_GAP_09004 - <<: *GAP_CASE - test point 2: BLE GAP processing scan data - summary: process combined adv data and scan response data - steps: | - 1. DUT1 set raw adv data manufacturer data - 2. DUT1 set scan response data tx power, interval range, apperaence, flag - 2. DUT1 start adv - 3. DUT2 do active scan with extended scan data 19 - expected result: | - 1. succeed - 2. succeed - 3. scan with the correct adv data - cmd set: - - "" - *dut1_stop_adv - - - "SSC SSC2 blescan -L -c 0 -d 1" - - ["R SSC2 C +BLESCAN:SetScanParam,OK"] - - - "SSC SSC1 bleadv -R -t 1 -r 0x15FF1011121314151617181910111213141516171819" - - ["R SSC1 C +BLEADV:OK"] - - - "SSC SSC1 bleadv -R -t 2 -r 0x020AEB051220004000021901020106" - - ["R SSC1 C +BLEADV:OK"] - *dut1_start_adv - - *dut2_stop_adv - - - "SSC SSC2 blescan -D -z start -t 1 -e 1" - - - 'P SSC2 RE "\+BTSCANEXT:%%s,man,0x1011121314151617181910111213141516171819"%%()' - - 'P SSC2 RE "\+BTSCANEXT:%%s,txp,0xEB"%%()' - - 'P SSC2 RE "\+BTSCANEXT:%%s,intrange,0x20004000"%%()' - - 'P SSC2 RE "\+BTSCANEXT:%%s,app,0x01"%%()' - - 'P SSC2 RE "\+BTSCANEXT:%%s,flag,0x06"%%()' + - - "SSC SSC2 blescan -D -z start -t 1 -e 1 -c 0 -d 1" + - - 'P SSC2 RE "\+BTSCANEXT:%%s,{%s}"%%()' - 'R SSC2 C Complete' - ID: BTSTK_GAP_09005 <<: *GAP_CASE @@ -2198,21 +1114,19 @@ test cases: cmd set: - "" - *dut1_stop_adv - - - "SSC SSC2 blescan -L -c 0 -d 1" - - ["R SSC2 C +BLESCAN:SetScanParam,OK"] - - "SSC SSC1 ble -S -z name -n abcde" - ["R SSC1 C +BLE"] - - "SSC SSC1 bleadv -L -c 0 -n 1 -t 3" - ["R SSC1 C +BLEADV:SetAdv,OK"] - *dut1_start_adv - - - "SSC SSC2 blescan -D -z start -t 1 -e 1" + - - "SSC SSC2 blescan -D -z start -t 1 -e 1 -c 0 -d 1" - - 'P SSC2 RE "\+BTSCAN:INQ,%%s,abcde"%%()' - 'R SSC2 C Complete' - *dut1_stop_adv - - "SSC SSC1 bleadv -L -c 0 -n 0 -t 3" - ["R SSC1 C +BLEADV:SetAdv,OK"] - *dut1_start_adv - - - "SSC SSC2 blescan -D -z start -t 1 -e 1" + - - "SSC SSC2 blescan -D -z start -t 1 -e 1 -c 0 -d 1" - - 'P SSC2 RE "\+BTSCAN:INQ,%%s,NULL"%%()' - 'R SSC2 C Complete' - ID: BTSTK_GAP_09006 @@ -2240,63 +1154,19 @@ test cases: cmd set: - "" - *dut1_stop_adv - - - "SSC SSC2 blescan -L -c 0 -d 1" - - ["R SSC2 C +BLESCAN:SetScanParam,OK"] - - *set_default_ble_name - - "SSC SSC1 bleadv -L -c 0 -x 1 -t 3" - ["R SSC1 C +BLEADV:SetAdv,OK"] - *dut1_start_adv - - - "SSC SSC2 blescan -D -z start -t 1 -e 1" + - - "SSC SSC2 blescan -D -z start -t 1 -e 1 -c 0 -d 1" - - 'P SSC2 RE "\+BTSCANEXT:%%s,txp,0x03"%%()' - 'R SSC2 C Complete' - *dut1_stop_adv - - "SSC SSC1 bleadv -L -c 0 -x 0 -t 3" - ["R SSC1 C +BLEADV:SetAdv,OK"] - *dut1_start_adv - - - "SSC SSC2 blescan -D -z start -t 1 -e 1" + - - "SSC SSC2 blescan -D -z start -t 1 -e 1 -c 0 -d 1" - - 'R SSC2 NRE "\+BTSCANEXT:%%s,txp,0x03"%%()' - 'R SSC2 C Complete' -- ID: BTSTK_GAP_09007 - <<: *GAP_CASE - test point 2: BLE GAP processing scan data - summary: proccess scan data included adv interval - steps: | - 1. DUT1 stop advertise and set short device name - 2. DUT1 set max interval 0x40 min interval 0x20 for adv data and scan response - 3. DUT1 start advertising - 4. DUT2 start scan and processing scan data - 5. DUT1 stop advertising - 6. DUT1 set max interval 0x400 min interval 0x200 for adv data and scan response - 7. DUT1 start advertising - 8. DUT2 start scan and processing scan data - expected result: | - 1. succeed - 2. succeed - 3. succeed - 4. scan with the correct adv data - 5. succeed - 6. succeed - 7. succeed - 8. scan with the correct adv data - cmd set: - - "" - - *dut1_stop_adv - - - "SSC SSC2 blescan -L -c 0 -d 1" - - ["R SSC2 C +BLESCAN:SetScanParam,OK"] - - *set_default_ble_name - - - "SSC SSC1 bleadv -L -c 0 -i 0x20-0x40 -t 3" - - ["R SSC1 C +BLEADV:SetAdv,OK"] - - *dut1_start_adv - - - "SSC SSC2 blescan -D -z start -t 1 -e 1" - - - 'P SSC2 RE "\+BTSCANEXT:%%s,intrange,0x20004000"%%()' - - 'R SSC2 C Complete' - - *dut1_stop_adv - - - "SSC SSC1 bleadv -L -c 0 -i 0x200-0x400 -t 3" - - ["R SSC1 C +BLEADV:SetAdv,OK"] - - *dut1_start_adv - - - "SSC SSC2 blescan -D -z start -t 1 -e 1" - - - 'P SSC2 RE "\+BTSCANEXT:%%s,intrange,0x00020004"%%()' - - 'R SSC2 C Complete' - ID: BTSTK_GAP_09008 <<: *GAP_CASE test point 2: BLE GAP processing scan data @@ -2322,20 +1192,17 @@ test cases: cmd set: - "" - *dut1_stop_adv - - - "SSC SSC2 blescan -L -c 0 -d 1" - - ["R SSC2 C +BLESCAN:SetScanParam,OK"] - - *set_default_ble_name - - "SSC SSC1 bleadv -L -c 0 -a 0 -t 3" - - ["R SSC1 C +BLEADV:SetAdv,OK"] + - ["R SSC1 C +BLEADV:SetAdv,OK C +BLEADV:SetScanRes,OK"] - *dut1_start_adv - - - "SSC SSC2 blescan -D -z start -t 1 -e 1" + - - "SSC SSC2 blescan -D -z start -t 1 -e 1 -c 0 -d 1" - - 'P SSC2 NRE "\+BTSCANEXT:%%s,app,0x0100"%%()' - 'R SSC2 C Complete' - *dut1_stop_adv - - "SSC SSC1 bleadv -L -c 0 -a 1 -t 3" - ["R SSC1 C +BLEADV:SetAdv,OK"] - *dut1_start_adv - - - "SSC SSC2 blescan -D -z start -t 1 -e 1" + - - "SSC SSC2 blescan -D -z start -t 1 -e 1 -c 0 -d 1" - - 'P SSC2 RE "\+BTSCANEXT:%%s,app,0x0100"%%()' - 'R SSC2 C Complete' - ID: BTSTK_GAP_09009 @@ -2355,13 +1222,10 @@ test cases: cmd set: - "" - *dut1_stop_adv - - - "SSC SSC2 blescan -L -c 0 -d 1" - - ["R SSC2 C +BLESCAN:SetScanParam,OK"] - - *set_default_ble_name - - "SSC SSC1 bleadv -L -c 0 -m 0x12345678 -t 3" - ["R SSC1 C +BLEADV:SetAdv,OK"] - *dut1_start_adv - - - "SSC SSC2 blescan -D -z start -t 1 -e 1" + - - "SSC SSC2 blescan -D -z start -t 1 -e 1 -c 0 -d 1" - - 'P SSC2 RE "\+BTSCANEXT:%%s,man,0x12345678"%%()' - 'R SSC2 C Complete' - ID: BTSTK_GAP_09010 @@ -2381,14 +1245,11 @@ test cases: cmd set: - "" - *dut1_stop_adv - - - "SSC SSC2 blescan -L -c 0 -d 1" - - ["R SSC2 C +BLESCAN:SetScanParam,OK"] - - *set_default_ble_name - - "SSC SSC1 bleadv -L -c 0 -n 0 -d 0x1234123456 -t 3" - ["R SSC1 C +BLEADV:SetAdv,OK"] - *dut1_start_adv - - - "SSC SSC2 blescan -D -z start -t 1 -e 1" - - - 'P SSC2 RE "\+BTSCANEXT:%%s,srvdata,0x1234123456"%%()' + - - "SSC SSC2 blescan -D -z start -t 1 -e 1 -c 0 -d 1" + - - 'P SSC2 RE "\+BTSCANEXT:%%s,srvdata16,0x1234123456"%%()' - 'R SSC2 C Complete' - ID: BTSTK_GAP_09011 <<: *GAP_CASE @@ -2407,12 +1268,10 @@ test cases: cmd set: - "" - *dut1_stop_adv - - - "SSC SSC2 blescan -L -c 0 -d 1" - - ["R SSC2 C +BLESCAN:SetScanParam,OK"] - - "SSC SSC1 bleadv -L -c 0 -n 0 -x 0 -i 0x00-0x00 -s ABCD,ABCDDCBA,12349B5F8000008000100000ABCD0000 -t 3" - ["R SSC1 C +BLEADV:SetAdv,OK"] - *dut1_start_adv - - - "SSC SSC2 blescan -D -z start -t 1 -e 1" + - - "SSC SSC2 blescan -D -z start -t 1 -e 1 -c 0 -d 1" - - 'P SSC2 RE "\+BTSCANEXT:%%s,srv16,0xABCD"%%()' - 'P SSC2 RE "\+BTSCANEXT:%%s,srv32,0xABCDDCBA"%%()' - 'P SSC2 RE "\+BTSCANEXT:%%s,srv128,0x12349B5F8000008000100000ABCD0000"%%()' @@ -2438,7 +1297,7 @@ test cases: - ["R SSC1 C +BLEADV:SetAdv,OK"] - - "SSC SSC1 bleadv -D -z start" - ["R SSC1 C +BLEADV:Start,OK"] - - - "SSC SSC2 blescan -D -z start" + - - "SSC SSC2 blescan -D -z start -c 0" - - 'P SSC2 RE "\+BTSCAN:INQ,%%s"%%()' - 'R SSC2 C Complete' - ID: BTSTK_GAP_09013 @@ -2504,20 +1363,18 @@ test cases: cmd set: - "" - *dut1_stop_adv - - *set_default_ble_name - - "SSC SSC1 bleadv -L -c 0 -n 0 -d 0x1234123456 -t 3 -l 4" - ["R SSC1 C +BLEADV:SetAdv,OK"] - *dut1_start_adv - - "SSC SSC2 blescan -D -z start -t 1 -e 1" - - - 'P SSC2 RE "\+BTSCANEXT:%%s,srvdata,0x1234123456"%%()' + - - 'P SSC2 RE "\+BTSCANEXT:%%s,srvdata16,0x1234123456"%%()' - 'R SSC2 C Complete' - *dut1_stop_adv - - *set_default_ble_name - - "SSC SSC1 bleadv -L -c 0 -n 0 -d 0x1234123456 -t 3 -l 10" - ["R SSC1 C +BLEADV:SetAdv,OK"] - *dut1_start_adv - - "SSC SSC2 blescan -D -z start -t 1 -e 1" - - - 'P SSC2 RE "\+BTSCANEXT:%%s,srvdata,0x1234123456"%%()' + - - 'P SSC2 RE "\+BTSCANEXT:%%s,srvdata16,0x1234123456"%%()' - 'R SSC2 C Complete' - ID: BTSTK_GAP_09015 <<: *GAP_CASE @@ -2575,18 +1432,19 @@ test cases: 3. succeed initial condition: BLE_INIT5 test environment: SSC_T5_1 + allow fail: 3/5 cmd set: - "" - - "SSC SSC[2-4] bleadv -D -z start" - ["P SSC[2-4] C +BLEADV:Start,OK"] - - - LOOP 3 1 "[0,1,2]" "[2,3,4]" + - - LOOP 3 1 "[0,1,2]" "[2,3,4]" "[2,3,4]" - "" - - "SSC SSC1 bleconn -C -p 0x1{%d} -a " - - ['R SSC1 C +BLE:GattcOpen,OK'] - - - LOOP 3 1 "[2,1,0]" "[4,3,2]" + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC{%d} C +BLECONN:GapConnect,OK'] + - - LOOP 3 1 "[2,1,0]" "[4,3,2]" "[4,3,2]" - "" - - - "SSC SSC1 bleconn -D -z client -p 0x1{%d}" - - ['P SSC1 C +BLE:GattcDisconnect,OK', 'P SSC{%d} C +BLE:GattsDisconnect,OK'] + - - "SSC SSC1 bleconn -D -z client -p 0x1{%d} -a " + - ['P SSC1 C +BLECONN:GapDisconnect,OK', 'P SSC{%d} C +BLECONN:GapDisconnect,OK'] - ID: BTSTK_GAP_10002 <<: *GAP_CASE test point 2: BLE GAP master multi connection test @@ -2601,6 +1459,7 @@ test cases: 3. succeed initial condition: BLE_INIT5 test environment: SSC_T5_1 + allow fail: 3/5 cmd set: - "" - - "SSC SSC[2-4] bleadv -D -z start" @@ -2608,11 +1467,11 @@ test cases: - - LOOP 3 1 "[0,1,2]" "[2,3,4]" "[2,3,4]" - "" - - "SSC SSC1 bleconn -C -p 0x1{%d} -a " - - ['R SSC1 C +BLE:GattcConnect,OK', 'R SSC{%d} C +BLE:GattsConnect'] + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC{%d} C +BLECONN:GapConnect,OK'] - - LOOP 3 1 "[2,3,4]" "[2,3,4]" - "" - - - "SSC SSC{%d} bleconn -D -z server -p 0xA0" - - ['P SSC1 C +BLE:GattcDisconnect,OK,001[0-2]', 'P SSC{%d} C +BLE:GattsDisconnect,OK'] + - - "SSC SSC{%d} bleconn -D -z server -p 0xA0 -r " + - ['P SSC1 C +BLECONN:GapDisconnect,OK,001[0-2]', 'P SSC{%d} C +BLECONN:GapDisconnect,OK'] - ID: BTSTK_GAP_10003 <<: *GAP_CASE test point 2: BLE GAP master multi connection test @@ -2627,6 +1486,7 @@ test cases: 3. succeed initial condition: BLE_INIT5 test environment: SSC_T5_1 + allow fail: 3/5 cmd set: - "" - - "SSC SSC[2-5] bleadv -D -z start" @@ -2634,11 +1494,11 @@ test cases: - - LOOP 4 1 "[2,3,4,5]" "[2,3,4,5]" - "" - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ['R SSC1 C +BLE:GattcConnect,OK', 'R SSC{%d} C +BLE:GattsConnect'] + - ['R SSC1 C +BLECONN:GapConnect,OK', 'R SSC{%d} C +BLECONN:GapConnect,OK'] - - LOOP 4 1 "[2,3,4,5]" "[2,3,4,5]" - "" - - "SSC SSC1 bleconn -D -z client -p 0x10 -a " - - ['P SSC1 C +BLE:GattcDisconnect,OK', 'P SSC{%d} C +BLE:GattsDisconnect,OK'] + - ['P SSC1 C +BLECONN:GapDisconnect,OK', 'P SSC{%d} C +BLECONN:GapDisconnect,OK'] - ID: BTSTK_GAP_10004 <<: *GAP_CASE test point 2: BLE GAP master multi connection test @@ -2653,6 +1513,7 @@ test cases: 3. succeed initial condition: BLE_INIT5 test environment: SSC_T5_1 + allow fail: 3/5 cmd set: - "" - - "SSC SSC[2-5] bleadv -D -z start" @@ -2660,11 +1521,11 @@ test cases: - - LOOP 4 1 "[2,3,4,5]" "[2,3,4,5]" - "" - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ['R SSC1 C +BLE:GattcConnect,OK', 'R SSC{%d} C +BLE:GattsConnect'] - - - LOOP 4 1 "[2,3,4,5]" "[2,3,4,5]" "[2,3,4,5]" + - ['R SSC1 C +BLECONN:GapConnect,OK', 'R SSC{%d} C +BLECONN:GapConnect,OK'] + - - LOOP 4 1 "[2,3,4,5]" "[2,3,4,5]" - "" - - - "SSC SSC{%d} bleconn -D -z server -p 0xA0" - - ['P SSC1 RE "BLE:GattcDisconnect,OK,0010,%%s"%%()', 'P SSC{%d} C +BLE:GattsDisconnect'] + - - "SSC SSC{%d} bleconn -D -z server -p 0xA2 -a " + - ['P SSC1 C +BLECONN:GapDisconnect,OK', 'P SSC{%d} C +BLECONN:GapDisconnect,OK'] - ID: BTSTK_GAP_11001 <<: *GAP_CASE test point 2: BLE GAP slave multi connection test @@ -2679,19 +1540,21 @@ test cases: 3. succeed initial condition: BLE_INIT5 test environment: SSC_T5_1 + allow fail: 3/5 cmd set: - "" - - - "SSC SSC1 gatts -S -z load -p 0xA0" - - ['R SSC1 C +GATTS:StartService,OK,A000'] + - *dut1_stop_adv + - - "SSC SSC1 gatts -S -z load -p 0xA2" + - ['R SSC1 C +GATTS:StartService,OK,A002'] - - LOOP 4 2 "[2,3,4,5]" "[2,3,4,5]" - "" - - "SSC SSC1 bleadv -D -z start" - ["P SSC1 C +BLEADV:Start,OK"] - - "SSC SSC{%d} bleconn -C -p 0x10 -a " - - ['R SSC{%d} C +BLE:GattcConnect,OK,0010', 'R SSC1 C +BLE:GattsConnect'] + - ['R SSC{%d} C +BLECONN:GapConnect,OK,0010', 'R SSC1 C +BLECONN:GapConnect,OK'] - - LOOP 4 1 "[2,3,4,5]" "[2,3,4,5]" - - - "SSC SSC{%d} bleconn -D -z client -p 0x10" - - ['P SSC{%d} C +BLE:GattcDisconnect,OK', 'P SSC1 C +BLE:GattsDisconnect,OK'] + - - "SSC SSC{%d} bleconn -D -z client -p 0x10 -a " + - ['P SSC{%d} C +BLECONN:GapDisconnect,OK', 'P SSC1 C +BLECONN:GapDisconnect,OK'] - ID: BTSTK_GAP_11002 <<: *GAP_CASE test point 2: BLE GAP slave multi connection test @@ -2706,20 +1569,22 @@ test cases: 3. succeed initial condition: BLE_INIT5 test environment: SSC_T5_1 + allow fail: 3/5 cmd set: - "" - - - "SSC SSC1 gatts -S -z load -p 0xA0" - - ['R SSC1 C +GATTS:StartService,OK,A000'] + - *dut1_stop_adv + - - "SSC SSC1 gatts -S -z load -p 0xA2" + - ['R SSC1 C +GATTS:StartService,OK,A002'] - - LOOP 4 2 "[2,3,4,5]" "[2,3,4,5]" - "" - - "SSC SSC1 bleadv -D -z start" - ["P SSC1 C +BLEADV:Start,OK"] - - "SSC SSC{%d} bleconn -C -p 0x10 -a " - - ['R SSC{%d} C +BLE:GattcConnect,OK,0010', 'R SSC1 C +BLE:GattsConnect'] + - ['R SSC{%d} C +BLECONN:GapConnect,OK,0010', 'R SSC1 C +BLECONN:GapConnect,OK'] - - LOOP 4 1 "[2,3,4,5]" "[2,3,4,5]" - "" - - - "SSC SSC1 bleconn -D -z server -p 0xA0 -a " - - ['P SSC{%d} C +BLE:GattcDisconnect,OK', 'P SSC1 C +BLE:GattsDisconnect,OK'] + - - "SSC SSC1 bleconn -D -z server -p 0xA2 -a " + - ['P SSC{%d} C +BLECONN:GapDisconnect,OK', 'P SSC1 C +BLECONN:GapDisconnect,OK'] - ID: BTSTK_GAP_12001 <<: *GAP_CASE test point 2: BLE GAP multi connection as both master and slave role test @@ -2736,22 +1601,24 @@ test cases: 4. succeed initial condition: BLE_INIT5 test environment: SSC_T5_1 + allow fail: 3/5 cmd set: - "" - - - "SSC SSC1 gatts -S -z load -p 0xA0" - - ['R SSC1 C +GATTS:StartService,OK,A000'] + - *dut1_stop_adv + - - "SSC SSC1 gatts -S -z load -p 0xA2" + - ['R SSC1 C +GATTS:StartService,OK,A002'] - - LOOP 2 2 "[2,3]" "[2,3]" - "" - - "SSC SSC1 bleadv -D -z start" - ["P SSC1 C +BLEADV:Start,OK"] - - "SSC SSC{%d} bleconn -C -p 0x10 -a " - - ['R SSC{%d} C +BLE:GattcConnect,OK,0010', 'P SSC1 C +BLE:GattsConnect'] + - ['R SSC{%d} C +BLECONN:GapConnect,OK,0010', 'P SSC1 C +BLECONN:GapConnect,OK'] - - "SSC SSC[4-5] bleadv -D -z start" - ["P SSC[4-5] C +BLEADV:Start,OK"] - - LOOP 2 1 "[4,5]" "[4,5]" - "" - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ['P SSC1 C +BLE:GattcConnect,OK', 'P SSC{%d} C +BLE:GattsConnect'] + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC{%d} C +BLECONN:GapConnect,OK'] - - "SSC SSC1 bleconn -D -z all" - ["P SSC[2-5] C Disconnect"] - ID: BTSTK_GAP_12002 @@ -2770,93 +1637,115 @@ test cases: 4. succeed initial condition: BLE_INIT5 test environment: SSC_T5_1 + allow fail: 3/5 cmd set: - "" - - - "SSC SSC1 gatts -S -z load -p 0xA0" - - ['R SSC1 C +GATTS:StartService,OK,A000'] + - *dut1_stop_adv + - - "SSC SSC1 gatts -S -z load -p 0xA2" + - ['R SSC1 C +GATTS:StartService,OK,A002'] - - LOOP 2 2 "[2,3]" "[2,3]" - "" - - "SSC SSC1 bleadv -D -z start" - ["P SSC1 C +BLEADV:Start,OK"] - - "SSC SSC{%d} bleconn -C -p 0x10 -a " - - ['R SSC{%d} C +BLE:GattcConnect,OK,0010', 'R SSC1 C +BLE:GattsConnect'] + - ['R SSC{%d} C +BLECONN:GapConnect,OK,0010', 'R SSC1 C +BLECONN:GapConnect,OK'] - - "SSC SSC[4-5] bleadv -D -z start" - ["P SSC[4-5] C +BLEADV:Start,OK"] - - LOOP 2 1 "[4,5]" "[4,5]" - "" - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ['R SSC1 C +BLE:GattcConnect,OK', 'R SSC{%d} C +BLE:GattsConnect'] + - ['R SSC1 C +BLECONN:GapConnect,OK', 'R SSC{%d} C +BLECONN:GapConnect,OK'] - - LOOP 4 1 "[2,3,4,5]" - - "SSC SSC{%d} bleconn -D -z all" - ["P SSC1 C Disconnect"] -- ID: BTSTK_GAP_13001 +- ID: BTSTK_GAP_50001 <<: *GAP_CASE - test point 2: BLE GAP param packet data length test - summary: gattc set packet data length at valid length (27-251) + category: Performance + test point 1: performance + stress + test point 2: BLE GAP performance test + summary: BLE Connect and disconnect performance test steps: | - 1. DUT1 connect DUT2 - 2. DUT1 set packet data length + 1. DUT1 disconnect with DUT2 + 2. DUT2 start advertising + 3. DUT1 connect to DUT2 + 4. do service discovery + 5. loop step 1-4 + 6. check connection fail ratio and average conn time expected result: | 1. succeed 2. succeed + 3. succeed + 4. succeed + 5. succeed + 6. meet pass standard + initial condition: BLE_INIT2 + execution time: 6 + version: v1 (2017-05-19) + CI ready: 'No' cmd set: - - "" - - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ['R SSC1 C +BLE:GattcConnect,OK', 'R SSC2 C +BLE:GattsConnect'] - - - LOOP 3 1 "[27,200,251]" "[27,200,251]" - - - "SSC SSC1 ble -S -z pktLen -a -l {%d}" - - ["R SSC1 C +BLECONN:UpdatePktLen,OK,{%d}"] -- ID: BTSTK_GAP_13002 + - "BLEStress/BLEConnPerformance" + - - "test_time = 20" + - "" + - - "average_conn_time = 3" + - "" + - - "fail_ratio = 0.01" + - "" + - - "fail_timeout = 10" + - "" +- ID: BTSTK_GAP_50004 <<: *GAP_CASE - test point 2: BLE GAP param packet data length test - summary: gattc set packet data length at invalid length + category: Performance + test point 1: performance + stress + test point 2: BLE GAP performance test + summary: BLE Connect and disconnect correct performance test steps: | - 1. DUT1 connect DUT2 - 2. DUT1 set packet data length + 1. DUT1 disconnect with DUT2 + 2. DUT2 start advertising + 3. DUT1 connect to DUT2 + 4. loop step 1-4 1000 times + 5. reboot + 6. loop step 1-5 expected result: | 1. succeed 2. succeed + 3. succeed + 4. succeed + 5. succeed + 6. meet pass standard + initial condition: BLE_INIT2 + execution time: 6 + version: v1 (2017-05-19) + CI ready: 'No' cmd set: - - "" - - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ['R SSC1 C +BLE:GattcConnect,OK', 'R SSC2 C +BLE:GattsConnect'] - - - LOOP 2 1 "[26,252]" "[27,251]" - - - "SSC SSC1 ble -S -z pktLen -a -l {%d}" - - ["R SSC1 C +BLECONN:UpdatePktLen,OK,{%d}"] -- ID: BTSTK_GAP_13003 + - "BLEStress/BLEConnCorPerformance" + - - "test_time = 100" + - "" + - - "reboot_time = 1000" + - "" + - - "average_conn_time = 3" + - "" + - - "fail_ratio = 0.01" + - "" + - - "fail_timeout = 10" + - "" +- ID: BTSTK_GAP_51001 <<: *GAP_CASE - test point 2: BLE GAP param packet data length test - summary: gatts set packet data length at valid length (27-251) + category: Performance + test point 1: performance + stress + test point 2: BLE GAP performance test + summary: BLE adv and scan forever steps: | - 1. DUT1 connect DUT2 - 2. DUT1 set packet data length + 1. DUT1 do adv + 2. DUT2 do scan expected result: | 1. succeed 2. succeed + initial condition: BLE_INIT2 + execution time: 10 cmd set: - - "" - - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ['R SSC1 C +BLE:GattcConnect,OK', 'R SSC2 C +BLE:GattsConnect'] - - - LOOP 3 1 "[27,200,251]" "[27,200,251]" - - - "SSC SSC2 ble -S -z pktLen -a -l {%d}" - - ["R SSC2 C +BLECONN:UpdatePktLen,OK,{%d}"] -- ID: BTSTK_GAP_13004 - <<: *GAP_CASE - test point 2: BLE GAP param packet data length test - summary: gatts set packet data length at invalid length - steps: | - 1. DUT1 connect DUT2 - 2. DUT1 set packet data length - expected result: | - 1. succeed - 2. succeed - cmd set: - - "" - - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ['R SSC1 C +BLE:GattcConnect,OK', 'R SSC2 C +BLE:GattsConnect'] - - - LOOP 2 1 "[26,252]" "[27,251]" - - - "SSC SSC2 ble -S -z pktLen -a -l {%d}" - - ["R SSC2 C +BLECONN:UpdatePktLen,OK,{%d}"] + - "BLEStress/BLEAdvScanPerformance" + - - "test_time = 600" + - "" - ID: BTSTK_GAP_14001 <<: *GAP_CASE test point 2: BLE GAP set randAddr as random address @@ -2880,7 +1769,7 @@ test cases: - - "SSC SSC1 blescan -D -z start" - ['R SSC1 P C Complete'] - - "SSC SSC1 bleconn -C -p 0x10 -a -r 1" - - ["P SSC1 C +BLE:GattcConnect,OK", "P SSC2 C +BLE:GattsConnect"] + - ["P SSC1 C +BLECONN:GapConnect,OK", "P SSC2 C +BLECONN:GapConnect,OK"] - ID: BTSTK_GAP_14002 <<: *GAP_CASE test point 2: BLE GAP set as pablic address @@ -2954,19 +1843,13 @@ test cases: 2. succeed cmd set: - "" - - - "SSC SSC1 bleadv -D -z stop" - - ["R SSC1 C +BLEADV:OK"] - - "SSC SSC1 bleadv -L -c 0 -t 3" - ["R SSC1 C +BLEADV:SetAdv,OK C +BLEADV:SetScanRes,OK"] - - "SSC SSC1 ble -S -z privacy -p 1" - ["R SSC1 C +BLECONN:SetResAddr,Success"] - - - "SSC SSC1 bleadv -D -z start -o 1" + - - "SSC SSC1 bleadv -D -z start -o 2" - ["R SSC1 C +BLEADV:OK"] - - - "SSC SSC2 bleadv -D -z stop" - - ["R SSC2 C +BLEADV:OK"] - - - "SSC SSC2 blescan -L -c 0" - - ["R SSC2 C +BLESCAN:SetScanParam,OK"] - - - "SSC SSC2 blescan -D -z start -t 3" + - - "SSC SSC2 blescan -D -z start -t 3 -c 0" - ["R SSC2 NP C +BLESCAN:InquiryComplete"] - ID: BTSTK_GAP_14008 <<: *GAP_CASE @@ -2993,24 +1876,24 @@ test cases: - ['P SSC2 C +BLESMP:OK'] - - "SSC SSC2 blesmp -S -z IOCAP -v 0x03" - ['P SSC2 C +BLESMP:OK'] - - - "SSC SSC2 blesmp -S -z RspKey -v 0x03" - - ['P SSC2 C +BLESMP:OK'] + - - "SSC SSC[1-2] blesmp -S -z RspKey -v 0x02" + - ['P SSC[1-2] C +BLESMP:OK'] + - - "SSC SSC[1-2] blesmp -S -z InitKey -v 0x02" + - ['P SSC[1-2] C +BLESMP:OK'] - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ['P SSC1 C +BLE:GattcConnect,OK', 'P SSC2 C +BLE:GattsConnect'] + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect,OK'] - - "SSC SSC2 blesmp -E -r -z Enc" - - ['P SSC1 C +BLESMP:SecReq'] - - - "SSC SSC1 blesmp -R -a 1 -r " - ['P SSC[1-2] C +BLESMP:AuthComplete,Success,0'] - - "SSC SSC1 bleconn -D -z all" - - ['P SSC1 C +BLE:GattcDisconnect,OK', 'P SSC2 C +BLE:GattsDisconnect,OK'] + - ['P SSC1 C +BLECONN:GapDisconnect,OK', 'P SSC2 C +BLECONN:GapDisconnect,OK'] - - "SSC SSC2 ble -S -z privacy -p 1" - ["R SSC2 C +BLECONN:SetResAddr,Success"] - - - "SSC SSC2 bleadv -D -z start -o 1" + - - "SSC SSC2 bleadv -D -z start -o 2" - ["R SSC2 C +BLEADV:OK"] - - "SSC SSC1 blescan -D -z start -t 3" - ["R SSC1 P C InquiryComplete"] - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ["R SSC1 C +BLE:GattcConnect,OK", "R SSC2 C +BLE:GattsConnect"] + - ["R SSC1 C +BLECONN:GapConnect,OK", "R SSC2 C +BLECONN:GapConnect,OK"] - ID: BTSTK_GAP_14009 <<: *GAP_CASE test point 2: BLE set random address test @@ -3040,33 +1923,29 @@ test cases: - - "SSC SSC2 blesmp -S -z RspKey -v 0x03" - ['P SSC2 C +BLESMP:OK'] - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ['P SSC1 C +BLE:GattcConnect,OK', 'P SSC2 C +BLE:GattsConnect'] + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect,OK'] - - "SSC SSC2 blesmp -E -r -z Enc" - - ['P SSC1 C +BLESMP:SecReq'] - - - "SSC SSC1 blesmp -R -a 1 -r " - ['P SSC[1-2] C +BLESMP:AuthComplete,Success,0'] - - "SSC SSC[1-2] reboot" - ['R SSC[1-2] C !!!ready!!!'] - - "SSC SSC[1-2] ble -R" - ["R SSC[1-2] C +BLE:OK"] - - - "SSC SSC2 gatts -S -z load -p 0xA0" - - ['R SSC2 C +GATTS:LoadProfile,OK'] + - - "SSC SSC2 gatts -S -z load -p 0xA2" + - ['R SSC2 C +GATTS:StartService,OK,A002'] - - "SSC SSC2 ble -S -z privacy -p 1" - ["R SSC2 C +BLECONN:SetResAddr,Success"] - - "SSC SSC2 bleadv -D -z stop" - ["R SSC2 C +BLEADV:OK"] - - "SSC SSC2 bleadv -L -c 0 -t 3" - ["R SSC2 C +BLEADV:SetAdv,OK C +BLEADV:SetScanRes,OK"] - - - "SSC SSC2 bleadv -D -z start -o 1" + - - "SSC SSC2 bleadv -D -z start -o 2" - ["R SSC2 C +BLEADV:OK"] - - "SSC SSC1 blescan -D -z stop" - ["R SSC1 C +BLESCAN:OK"] - - - "SSC SSC1 blescan -L -c 0" - - ["R SSC1 C +BLESCAN:SetScanParam,OK"] - - - "SSC SSC1 blescan -D -z start -t 3" + - - "SSC SSC1 blescan -D -z start -t 3 -c 0" - ["R SSC1 P C InquiryComplete"] - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ["R SSC1 C +BLE:GattcConnect,OK", "R SSC2 C +BLE:GattsConnect"] + - ["R SSC1 C +BLECONN:GapConnect,OK", "R SSC2 C +BLECONN:GapConnect,OK"] - ID: BTSTK_GAP_15001 <<: *GAP_CASE test point 2: BLE GAP white list test @@ -3159,6 +2038,7 @@ test cases: test point 2: BLE low power test summary: test adv current and adv interval 32-32 category: Performance + auto test: 'No' steps: | 1. DUT2 start adv 2. test DUT2 current @@ -3174,6 +2054,7 @@ test cases: test point 2: BLE low power test summary: test scan current and scan window/interval 04 category: Performance + auto test: 'No' steps: | 1. DUT2 start scan 2. test DUT2 current @@ -3189,6 +2070,7 @@ test cases: test point 2: BLE low power test summary: test connect current and interval 6-6 category: Performance + auto test: 'No' steps: | 1. DUT1 connect to DUT2 2. test DUT2 current @@ -3199,124 +2081,3 @@ test cases: - "BLEFunction/BLELowPower" - - op_test = "do_connect" - "" -- ID: BTSTK_GAP_40001 - <<: *GAP_CASE - auto test: 'No' - test point 2: test if BLE work after switch off some sub modules - summary: GAP only test - steps: | - 1. download GAP only SSC bin on both DUT - 2. DUT1 set ascii device name - 3. stop advertising - 4. config scan response and start advertising - 5. DUT2 do active scan - expected result: | - 1. succeed - 2. succeed - 3. succeed - 4. succeed - 5. device name in scan result - initial condition: None - version: v1 (2017-05-19) - cmd set: - - "" - - - "SSC SSC[1-2] reboot" - - ['R SSC[1-2] C !!!ready!!!'] - - - "SSC SSC[1-2] ble -R" - - ["R SSC[1-2] C +BLE:OK"] - - *set_default_ble_name - - *set_default_adv_data - - *dut2_stop_adv - - - "SSC SSC2 blescan -L -c 0" - - ["R SSC2 C +BLESCAN:SetScanParam,OK"] - - - "SSC SSC2 blescan -D -z start -t 3" - - ["R SSC2 P "] -- ID: BTSTK_GAP_50001 - <<: *GAP_CASE - category: Performance - test point 1: performance + stress - test point 2: BLE GAP performance test - summary: BLE Connect and disconnect performance test - steps: | - 1. DUT1 disconnect with DUT2 - 2. DUT2 start advertising - 3. DUT1 connect to DUT2 - 4. do service discovery - 5. loop step 1-4 - 6. check connection fail ratio and average conn time - expected result: | - 1. succeed - 2. succeed - 3. succeed - 4. succeed - 5. succeed - 6. meet pass standard - initial condition: BLE_INIT2 - execution time: 6 - version: v1 (2017-05-19) - CI ready: 'No' - cmd set: - - "BLEStress/BLEConnPerformance" - - - "test_time = 420" - - "" - - - "average_conn_time = 3" - - "" - - - "fail_ratio = 0.01" - - "" - - - "fail_timeout = 10" - - "" -- ID: BTSTK_GAP_50004 - <<: *GAP_CASE - category: Performance - test point 1: performance + stress - test point 2: BLE GAP performance test - summary: BLE Connect and disconnect correct performance test - steps: | - 1. DUT1 disconnect with DUT2 - 2. DUT2 start advertising - 3. DUT1 connect to DUT2 - 4. loop step 1-4 1000 times - 5. reboot - 6. loop step 1-5 - expected result: | - 1. succeed - 2. succeed - 3. succeed - 4. succeed - 5. succeed - 6. meet pass standard - initial condition: BLE_INIT2 - execution time: 6 - version: v1 (2017-05-19) - CI ready: 'No' - cmd set: - - "BLEStress/BLEConnCorPerformance" - - - "test_time = 100" - - "" - - - "reboot_time = 1000" - - "" - - - "average_conn_time = 3" - - "" - - - "fail_ratio = 0.01" - - "" - - - "fail_timeout = 10" - - "" -- ID: BTSTK_GAP_51001 - <<: *GAP_CASE - Test App: SSC_BLE, SSC_PSRAM - category: Performance - test point 1: performance + stress - test point 2: BLE GAP performance test - summary: BLE adv and scan forever - steps: | - 1. DUT1 do adv - 2. DUT2 do scan - expected result: | - 1. succeed - 2. succeed - initial condition: BLE_INIT2 - execution time: 10 - cmd set: - - "BLEStress/BLEAdvScanPerformance" - - - "test_time = 600" - - "" diff --git a/components/idf_test/integration_test/TC_IT_BTSTK_GATT.yml b/components/idf_test/integration_test/TC_IT_BTSTK_GATT.yml index 4a746d866f..b4a824d7ba 100644 --- a/components/idf_test/integration_test/TC_IT_BTSTK_GATT.yml +++ b/components/idf_test/integration_test/TC_IT_BTSTK_GATT.yml @@ -4,7 +4,7 @@ auto test: 'Yes' category: Function test point 1: basic function - initial condition: BLE_CONN2 + initial condition: BLE_CONN3 test environment: SSC_T2_5 execution time: 0 module: BT Stack @@ -16,7 +16,7 @@ .primary_service_discovery: &primary_service_discovery LIST_MERGE: - - - "SSC SSC1 gattc -D -z primaryService -p 0x10" + - - "SSC SSC1 gattc -D -z primaryService -p 0x10 -r " - ["R SSC1 C +GATTC:Discover,OK"] .included_service_connection: &included_primary_service_connection @@ -30,7 +30,7 @@ - - SSC SSC1 gattc -F -r - ['R SSC1 C +GATTC:OK'] - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ["R SSC1 C +BLE:GattcConnect,OK,0010", "R SSC2 C +BLE:GattsConnect"] + - ["R SSC1 C +BLECONN:GapConnect,OK,0010", "R SSC2 C +BLECONN:GapConnect"] .included_second_service_connection: &included_second_service_connection LIST_MERGE: @@ -45,7 +45,7 @@ - - SSC SSC1 gattc -F -r - ['R SSC1 C +GATTC:OK'] - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ["R SSC1 C +BLE:GattcConnect,OK,0010", "R SSC2 C +BLE:GattsConnect"] + - ["R SSC1 C +BLECONN:GapConnect,OK,0010", "R SSC2 C +BLECONN:GapConnect"] .table_include_table_service: &table_include_table_service LIST_MERGE: @@ -54,7 +54,7 @@ - - SSC SSC1 gattc -F -r - ['R SSC1 C +GATTC:OK'] - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ["R SSC1 C +BLE:GattcConnect,OK,0010", "R SSC2 C +BLE:GattsConnect"] + - ["R SSC1 C +BLECONN:GapConnect,OK,0010", "R SSC2 C +BLECONN:GapConnect"] .table_include_service: &table_include_service LIST_MERGE: @@ -63,188 +63,24 @@ - - SSC SSC1 gattc -F -r - ['R SSC1 C +GATTC:OK'] - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ["R SSC1 C +BLE:GattcConnect,OK,0010", "R SSC2 C +BLE:GattsConnect"] + - ["R SSC1 C +BLECONN:GapConnect,OK,0010", "R SSC2 C +BLECONN:GapConnect"] .register_notify_c107: ®ister_notify_c107 LIST_MERGE: - - "SSC SSC1 gattc -N -z register -s 0xA000 -c 0xC107 -p 0x10 -r " - ["R SSC1 C +GATTC:RegNotify,OK,0010,A000,C107"] + .register_indicate_c108: ®ister_indicate_c108 LIST_MERGE: - - "SSC SSC1 gattc -N -z register -s 0xA000 -c 0xC108 -p 0x10 -r " - ["R SSC1 C +GATTC:RegNotify,OK,0010,A000,C108"] +.stop_adv: &stop_adv + LIST_MERGE: + - - "SSC SSC2 bleadv -D -z stop" + - ["R SSC2 C +BLEADV:Stop"] + test cases: -- ID: BTSTK_GATT_01001 - <<: *GATT_CASE - test point 2: BLE GATT server create service - summary: create service, add char and descriptor and start service - steps: | - 1. create preset service 0xA000 - expected result: | - 1. succeed - initial condition: BLE_INIT1 - test environment: SSC_T1_4 - cmd set: - - "" - - - "SSC SSC1 gatts -S -z load -p 0xA0" - - ["R SSC1 C +GATTS:StartService,OK,A000"] -- ID: BTSTK_GATT_01002 - <<: *GATT_CASE - test point 2: BLE GATT server create service - summary: create service and include another service - steps: | - 1. create preset service 0xA000 - 2. create preset service 0xA001 - expected result: | - 1. succeed - 2. succeed - initial condition: BLE_INIT1 - test environment: SSC_T1_4 - cmd set: - - "" - - - "SSC SSC1 gatts -S -z load -p 0xA0" - - ["R SSC1 C +GATTS:StartService,OK,A000"] - - - "SSC SSC1 gatts -S -z load -p 0xA1" - - ["R SSC1 C +GATTS:CreateService,OK,A001"] - - - "SSC SSC1 gatts -S -z add -p 0xA1" - - ["R SSC1 C +GATTS:StartService,OK,A001"] -- ID: BTSTK_GATT_20001 - <<: *GATT_CASE - test point 2: BLE GATT client service / char discovery - summary: GATT client discover manual primary service - steps: | - 1. DUT2 create preset service 0xA000 - 2. DUT2 create preset service 0xA001 - 3. DUT1 connect to DUT2 - 4. DUT1 do primary service discovery - expected result: | - 1. succeed - 2. succeed - 3. succeed - 4. found service 0xA000 and 0xA001 - initial condition: BLE_INIT2 - cmd set: - - "" - - *included_primary_service_connection - - - "SSC SSC1 gattc -D -z primaryService -p 0x10" - - ["R SSC1 C +GATTC:DiscoverService,A000 C +GATTC:DiscoverService,A001"] - - - SSC SSC1 gattc -F -r - - ['R SSC1 C +GATTC:OK'] -- ID: BTSTK_GATT_20002 - <<: *GATT_CASE - test point 2: BLE GATT client service / char discovery - summary: GATT client get manual included service - steps: | - 1. DUT2 create preset service 0xA000 - 2. DUT2 create preset service 0xA001 - 3. DUT1 connect to DUT2 - 4. DUT1 do primary service discovery - 5. DUT1 get included service 0xA000 from service 0xA001 - expected result: | - 1. succeed - 2. succeed - 3. succeed - 4. succeed - 5. get included service 0xA000 from service 0xA001 - initial condition: BLE_INIT2 - cmd set: - - "" - - *included_primary_service_connection - - - "SSC SSC1 gattc -D -z primaryService -p 0x10" - - ["R SSC1 C +GATTC:DiscoverService,A000 A :GATTC:DiscoverService,A001,(\\d+-\\d+)"] - - - "SSC SSC1 gattc -D -z includedService -p 0x10 -s 0xA001 -i 0xA000 -q -k 1" - - ["R SSC1 C +GATTC:IncludedService,0010,A001,A000"] - - - SSC SSC1 gattc -F -r - - ['R SSC1 C +GATTC:OK'] -- ID: BTSTK_GATT_20003 - <<: *GATT_CASE - test point 2: BLE GATT client service / char discovery - summary: GATT client discover table primary service (table service include table service) - steps: | - 1. DUT2 create preset service 0xA002 - 2. DUT2 create preset service 0xA005 - 3. DUT1 connect to DUT2 - 4. DUT1 do primary service discovery - expected result: | - 1. succeed - 2. succeed - 3. succeed - 4. found service 0xA002 and 0xA005 - initial condition: BLE_INIT3 - cmd set: - - "" - - *table_include_table_service - - - "SSC SSC1 gattc -D -z primaryService -p 0x10" - - ["R SSC1 C +GATTC:DiscoverService,A002 C +GATTC:DiscoverService,A005"] -- ID: BTSTK_GATT_20004 - <<: *GATT_CASE - test point 2: BLE GATT client service / char discovery - summary: GATT client get table included service - steps: | - 1. DUT2 create preset service 0xA002 - 2. DUT2 create preset service 0xA005 - 3. DUT1 connect to DUT2 - 4. DUT1 do primary service discovery - 5. DUT1 get included service 0xA002 from service 0xA005 - expected result: | - 1. succeed - 2. succeed - 3. succeed - 4. succeed - 5. get included service 0xA002 from service 0xA005 - initial condition: BLE_INIT3 - cmd set: - - "" - - *table_include_table_service - - - "SSC SSC1 gattc -D -z primaryService -p 0x10" - - ["R SSC1 C +GATTC:DiscoverService,A002 A :GATTC:DiscoverService,A005,(\\d+-\\d+)"] - - - "SSC SSC1 gattc -D -z includedService -p 0x10 -s 0xA005 -i 0xA002 -q -k 1" - - ["R SSC1 C +GATTC:IncludedService,0010,A005,A002"] -- ID: BTSTK_GATT_20005 - <<: *GATT_CASE - test point 2: BLE GATT client service / char discovery - summary: GATT client discover table primary service (table service include manual service) - steps: | - 1. DUT2 create preset service 0xA000 - 2. DUT2 create preset service 0xA005 - 3. DUT1 connect to DUT2 - 4. DUT1 do primary service discovery - expected result: | - 1. succeed - 2. succeed - 3. succeed - 4. found service 0xA000 and 0xA005 - initial condition: BLE_INIT2 - cmd set: - - "" - - *table_include_service - - - "SSC SSC1 gattc -D -z primaryService -p 0x10" - - ["R SSC1 C +GATTC:DiscoverService,A000 C +GATTC:DiscoverService,A005"] -- ID: BTSTK_GATT_20006 - <<: *GATT_CASE - test point 2: BLE GATT client service / char discovery - summary: GATT client get table included manual service - steps: | - 1. DUT2 create preset service 0xA000 - 2. DUT2 create preset service 0xA005 - 3. DUT1 connect to DUT2 - 4. DUT1 do primary service discovery - 5. DUT1 get included service 0xA000 from service 0xA005 - expected result: | - 1. succeed - 2. succeed - 3. succeed - 4. succeed - 5. get included service 0xA000 from service 0xA005 - initial condition: BLE_INIT2 - cmd set: - - "" - - *table_include_service - - - "SSC SSC1 gattc -D -z primaryService -p 0x10" - - ["R SSC1 C +GATTC:DiscoverService,A000 A :GATTC:DiscoverService,A005,(\\d+-\\d+)"] - - - "SSC SSC1 gattc -D -z includedService -p 0x10 -s 0xA005 -i 0xA000 -q -k 1" - - ["R SSC1 C +GATTC:IncludedService,0010,A005,A000"] - ID: BTSTK_GATT_60001 <<: *GATT_CASE test point 2: BLE GATT server get and set value @@ -256,11 +92,10 @@ test cases: expected result: | 1. succeed 2. failed - initial condition: BLE_INIT2 + initial condition: BLE_INIT3 cmd set: - "" - - - "SSC SSC2 gatts -S -z load -p 0xA2" - - ["R SSC2 C +GATTS:StartService,OK,A002"] + - *stop_adv - - "SSC SSC2 gatts -V -c 0xC300 -p 0xA2 -z set -l 3" - ["R SSC2 C +GATTS:SetAttrVal,ERROR"] - ID: BTSTK_GATT_60002 @@ -276,11 +111,10 @@ test cases: 1. succeed 2. succeed 3. succeed - initial condition: BLE_INIT2 + initial condition: BLE_INIT3 cmd set: - "" - - - "SSC SSC2 gatts -S -z load -p 0xA2" - - ["R SSC2 C +GATTS:StartService,OK,A002"] + - *stop_adv - - "SSC SSC2 gatts -V -c 0xC300 -p 0xA2 -z get" - ["R SSC2 C +GATTS:GetAttrValue,1,0x01"] - - "SSC SSC2 gatts -V -c 0xC301 -p 0xA2 -z get" @@ -305,11 +139,10 @@ test cases: 5. succeed 6. succeed 7. succeed - initial condition: BLE_INIT2 + initial condition: BLE_INIT3 cmd set: - "" - - - "SSC SSC2 gatts -S -z load -p 0xA2" - - ["R SSC2 C +GATTS:StartService,OK,A002"] + - *stop_adv - - "SSC SSC2 gatts -V -c 0xC300 -p 0xA2 -z set -v 0x02" - ["R SSC2 C +GATTS:SetAttrVal,OK"] - - "SSC SSC2 gatts -V -c 0xC300 -p 0xA2 -z get" @@ -334,11 +167,10 @@ test cases: 1. succeed 2. succeed 3. succeed - initial condition: BLE_INIT2 + initial condition: BLE_INIT3 cmd set: - "" - - - "SSC SSC2 gatts -S -z load -p 0xA2" - - ["R SSC2 C +GATTS:StartService,OK,A002"] + - *stop_adv - - "SSC SSC2 gatts -V -c 0xC301 -p 0xA2 -z set -v JKLJGFD*^" - ["R SSC2 C +GATTS:SetAttrVal,OK"] - - "SSC SSC2 gatts -V -c 0xC301 -p 0xA2 -z get" @@ -355,11 +187,10 @@ test cases: 1. succeed 2. succeed 3. succeed - initial condition: BLE_INIT2 + initial condition: BLE_INIT3 cmd set: - "" - - - "SSC SSC2 gatts -S -z load -p 0xA2" - - ["R SSC2 C +GATTS:StartService,OK,A002"] + - *stop_adv - - "SSC SSC2 gatts -V -c 0xC300 -p 0xA2 -z set -l 0" - ["R SSC2 C +GATTS:SetAttrVal,ERROR"] - - "SSC SSC2 gatts -V -c 0xC300 -p 0xA2 -z get" @@ -376,11 +207,10 @@ test cases: 1. succeed 2. succeed 3. succeed - initial condition: BLE_INIT2 + initial condition: BLE_INIT3 cmd set: - "" - - - "SSC SSC2 gatts -S -z load -p 0xA2" - - ["R SSC2 C +GATTS:StartService,OK,A002"] + - *stop_adv - - "SSC SSC2 gatts -V -c 0xC301 -p 0xA2 -z set -l 5" - ["R SSC2 C +GATTS:SetAttrVal,OK"] - - "SSC SSC2 gatts -V -c 0xC301 -p 0xA2 -z get" @@ -401,15 +231,14 @@ test cases: 3. succeed 4. succeed 5. succeed - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -W -z char -s 0xA002 -c 0xC302 -p 0x10 -v 0x01" + - - "SSC SSC1 gattc -W -z char -s 0xA002 -c 0xC302 -p 0x10 -v 0x01 -r " - ["R SSC1 C +GATTC:WriteOnce,0010,A002,C302", "R SSC1 C +GATTC:Write,OK,0010,A002,C302"] - - "SSC SSC2 gatts -V -c 0xC302 -p 0xA2 -z get" - ["R SSC2 C +GATTS:GetAttrValue,1,0x01"] - - - "SSC SSC1 gattc -W -z longChar -s 0xA002 -c 0xC304 -p 0x10 -l 256" + - - "SSC SSC1 gattc -W -z longChar -s 0xA002 -c 0xC304 -p 0x10 -l 256 -r " - ["P SSC1 C +GATTC:Write,OK,0010,A002,C304"] - - "SSC SSC2 gatts -V -c 0xC304 -p 0xA2 -z get" - ["R SSC2 C +GATTS:GetAttrValue,256"] @@ -431,21 +260,20 @@ test cases: 3. succeed 4. succeed 5. succeed - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - "SSC SSC2 gatts -V -c 0xC300 -p 0xA2 -z set -v 0x02" - ["R SSC2 C +GATTS:SetAttrVal,OK"] - - - "SSC SSC1 gattc -R -z char -s 0xA002 -c 0xC300 -p 0x10" + - - "SSC SSC1 gattc -R -z char -s 0xA002 -c 0xC300 -p 0x10 -r " - ["R SSC1 C +GATTC:ReadOnce,0010,A002,C300,1", "R SSC1 C +GATTC:Read,OK,0010,A002,C300"] - - "SSC SSC2 gatts -V -c 0xC301 -p 0xA2 -z set -v 0x02" - ["R SSC2 C +GATTS:SetAttrVal,OK"] - - - "SSC SSC1 gattc -R -z char -s 0xA002 -c 0xC301 -p 0x10" + - - "SSC SSC1 gattc -R -z char -s 0xA002 -c 0xC301 -p 0x10 -r " - ["R SSC1 C +GATTC:ReadOnce,0010,A002,C301,1", "R SSC1 C +GATTC:Read,OK,0010,A002,C301"] - - "SSC SSC2 gatts -V -c 0xC301 -p 0xA2 -z set -l 5" - ["R SSC2 C +GATTS:SetAttrVal,OK"] - - - "SSC SSC1 gattc -R -z char -s 0xA002 -c 0xC301 -p 0x10" + - - "SSC SSC1 gattc -R -z char -s 0xA002 -c 0xC301 -p 0x10 -r " - ["R SSC1 C +GATTC:ReadOnce,0010,A002,C301,5", "R SSC1 C +GATTC:Read,OK,0010,A002,C301"] - ID: BTSTK_GATT_60009 <<: *GATT_CASE @@ -457,11 +285,9 @@ test cases: expected result: | 1. succeed 2. failed - initial condition: BLE_INIT2 + initial condition: BLE_INIT3 cmd set: - "" - - - "SSC SSC2 gatts -S -z load -p 0xA2" - - ["R SSC2 C +GATTS:StartService,OK,A002"] - - "SSC SSC2 gatts -V -c 0xC300 -d 0x2901 -p 0xA2 -z set -l 3" - ["R SSC2 C +GATTS:SetAttrVal,ERROR"] - ID: BTSTK_GATT_60010 @@ -474,11 +300,9 @@ test cases: expected result: | 1. succeed 2. succeed - initial condition: BLE_INIT2 + initial condition: BLE_INIT3 cmd set: - "" - - - "SSC SSC2 gatts -S -z load -p 0xA2" - - ["R SSC2 C +GATTS:StartService,OK,A002"] - - "SSC SSC2 gatts -V -c 0xC300 -d 0x2901 -p 0xA2 -z get" - ["R SSC2 C +GATTS:GetAttrValue,1,0x00"] - ID: BTSTK_GATT_60011 @@ -501,11 +325,9 @@ test cases: 5. succeed 6. succeed 7. succeed - initial condition: BLE_INIT2 + initial condition: BLE_INIT3 cmd set: - "" - - - "SSC SSC2 gatts -S -z load -p 0xA2" - - ["R SSC2 C +GATTS:StartService,OK,A002"] - - "SSC SSC2 gatts -V -c 0xC300 -d 0x2901 -p 0xA2 -z set -v 0x02" - ["R SSC2 C +GATTS:SetAttrVal,OK"] - - "SSC SSC2 gatts -V -c 0xC300 -d 0x2901 -p 0xA2 -z get" @@ -530,11 +352,9 @@ test cases: 1. succeed 2. succeed 3. succeed - initial condition: BLE_INIT2 + initial condition: BLE_INIT3 cmd set: - "" - - - "SSC SSC2 gatts -S -z load -p 0xA2" - - ["R SSC2 C +GATTS:StartService,OK,A002"] - - "SSC SSC2 gatts -V -c 0xC301 -d 0x2901 -p 0xA2 -z set -v JKLJGFD*^" - ["R SSC2 C +GATTS:SetAttrVal,OK"] - - "SSC SSC2 gatts -V -c 0xC301 -d 0x2901 -p 0xA2 -z get" @@ -551,11 +371,9 @@ test cases: 1. succeed 2. succeed 3. succeed - initial condition: BLE_INIT2 + initial condition: BLE_INIT3 cmd set: - "" - - - "SSC SSC2 gatts -S -z load -p 0xA2" - - ["R SSC2 C +GATTS:StartService,OK,A002"] - - "SSC SSC2 gatts -V -c 0xC300 -d 0x2901 -p 0xA2 -z set -l 0" - ["R SSC2 C +GATTS:SetAttrVal,ERROR"] - - "SSC SSC2 gatts -V -c 0xC300 -d 0x2901 -p 0xA2 -z get" @@ -572,11 +390,9 @@ test cases: 1. succeed 2. succeed 3. succeed - initial condition: BLE_INIT2 + initial condition: BLE_INIT3 cmd set: - "" - - - "SSC SSC2 gatts -S -z load -p 0xA2" - - ["R SSC2 C +GATTS:StartService,OK,A002"] - - "SSC SSC2 gatts -V -c 0xC301 -d 0x2901 -p 0xA2 -z set -l 5" - ["R SSC2 C +GATTS:SetAttrVal,OK"] - - "SSC SSC2 gatts -V -c 0xC301 -d 0x2901 -p 0xA2 -z get" @@ -597,15 +413,14 @@ test cases: 3. succeed 4. succeed 5. succeed - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -W -z descriptor -s 0xA002 -c 0xC300 -d 0x2901 -p 0x10 -v 0x01" + - - "SSC SSC1 gattc -W -z descriptor -s 0xA002 -c 0xC300 -d 0x2901 -p 0x10 -v 0x01 -r " - ["R SSC1 C +GATTC:WriteOnce,0010,A002,C300,2901", "R SSC1 C +GATTC:WriteDescriptor,OK,0010,A002,C300,2901"] - - "SSC SSC2 gatts -V -c 0xC300 -d 0x2901 -p 0xA2 -z get" - ["R SSC2 C +GATTS:GetAttrValue,1,0x01"] - - - "SSC SSC1 gattc -W -z longDescriptor -s 0xA002 -c 0xC301 -d 0x2901 -p 0x10 -l 256" + - - "SSC SSC1 gattc -W -z longDescriptor -s 0xA002 -c 0xC301 -d 0x2901 -p 0x10 -l 256 -r " - ["P SSC1 C +GATTC:WriteDescriptor,OK,0010,A002,C301,2901"] - - "SSC SSC2 gatts -V -c 0xC301 -d 0x2901 -p 0xA2 -z get" - ["R SSC2 C +GATTS:GetAttrValue,256"] @@ -627,139 +442,21 @@ test cases: 3. succeed 4. succeed 5. succeed - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - "SSC SSC2 gatts -V -c 0xC300 -d 0x2901 -p 0xA2 -z set -v 0x02" - ["R SSC2 C +GATTS:SetAttrVal,OK"] - - - "SSC SSC1 gattc -R -z descriptor -s 0xA002 -c 0xC300 -d 0x2901 -p 0x10" + - - "SSC SSC1 gattc -R -z descriptor -s 0xA002 -c 0xC300 -d 0x2901 -p 0x10 -r " - ["R SSC1 C +GATTC:ReadOnce,0010,A002,C300,2901,1", "R SSC1 C +GATTC:ReadDescriptor,OK,0010,A002,C300,2901"] - - "SSC SSC2 gatts -V -c 0xC301 -d 0x2901 -p 0xA2 -z set -v 0x02" - ["R SSC2 C +GATTS:SetAttrVal,OK"] - - - "SSC SSC1 gattc -R -z descriptor -s 0xA002 -c 0xC301 -d 0x2901 -p 0x10" + - - "SSC SSC1 gattc -R -z descriptor -s 0xA002 -c 0xC301 -d 0x2901 -p 0x10 -r " - ["R SSC1 C +GATTC:ReadOnce,0010,A002,C301,2901,1", "R SSC1 C +GATTC:ReadDescriptor,OK,0010,A002,C301,2901"] - - "SSC SSC2 gatts -V -c 0xC301 -d 0x2901 -p 0xA2 -z set -l 5" - ["R SSC2 C +GATTS:SetAttrVal,OK"] - - - "SSC SSC1 gattc -R -z descriptor -s 0xA002 -c 0xC301 -d 0x2901 -p 0x10" + - - "SSC SSC1 gattc -R -z descriptor -s 0xA002 -c 0xC301 -d 0x2901 -p 0x10 -r " - ["R SSC1 C +GATTC:ReadOnce,0010,A002,C301,2901,5", "R SSC1 C +GATTC:ReadDescriptor,OK,0010,A002,C301,2901"] -- ID: BTSTK_GATT_21001 - <<: *GATT_CASE - test point 2: BLE GATT client read char and descriptor - summary: GATT client read short char - steps: | - 1. DUT1 do discover - 2. GATT client read 1 byte short char - expected result: | - 1. succeed - 2. read succeed - cmd set: - - "" - - *primary_service_discovery - - - "SSC SSC1 gattc -R -z char -s 0xA000 -c 0xC100 -p 0x10" - - ["R SSC1 C +GATTC:ReadOnce,0010,A000,C100,1", "R SSC1 C +GATTC:Read,OK,0010,A000,C100"] -- ID: BTSTK_GATT_21002 - <<: *GATT_CASE - test point 2: BLE GATT client read char and descriptor - summary: GATT client read long char - steps: | - 1. DUT1 do service discovery - 2. DUT1 GATT client read 256 bytes long char - expected result: | - 1. succeed - 2. read succeed - cmd set: - - "" - - *primary_service_discovery - - - "SSC SSC1 gattc -R -z char -s 0xA000 -c 0xC101 -p 0x10" - - ["R SSC1 C +GATTC:ReadOnce,0010,A000,C101,256", "R SSC1 C +GATTC:Read,OK,0010,A000,C101"] -- ID: BTSTK_GATT_21003 - <<: *GATT_CASE - test point 2: BLE GATT client read char and descriptor - summary: GATT client read short descriptor - steps: | - 1. DUT1 do service discovery - 2. GATT client read short descriptor - expected result: | - 1. succeed - 2. read succeed - cmd set: - - "" - - *primary_service_discovery - - - "SSC SSC1 gattc -R -z descriptor -s 0xA000 -c 0xC107 -d 0x2902 -p 0x10" - - ["R SSC1 C +GATTC:ReadOnce,0010,A000,C107,2902,2", "R SSC1 C +GATTC:ReadDescriptor,OK,0010,A000,C107,2902"] -- ID: BTSTK_GATT_21004 - <<: *GATT_CASE - test point 2: BLE GATT client read char and descriptor - summary: GATT client read long descriptor - steps: | - 1. DUT1 do service discovery - 2. GATT client read long descriptor - expected result: | - 1. succeed - 2. read succeed - cmd set: - - "" - - *primary_service_discovery - - - "SSC SSC1 gattc -R -z descriptor -s 0xA000 -c 0xC100 -d 0x2901 -p 0x10" - - ["R SSC1 C +GATTC:ReadOnce,0010,A000,C100,2901,2", "R SSC1 C +GATTC:ReadDescriptor,OK,0010,A000,C100,2901"] -- ID: BTSTK_GATT_21005 - <<: *GATT_CASE - test point 2: BLE GATT client read char and descriptor - summary: GATT client read short char of an included service - steps: | - 1. DUT2 create preset service 0xA000 - 2. DUT2 create preset service 0xA001 - 3. DUT1 connect to DUT2 - 4. DUT1 do discover - 5. GATT client read 1 byte short char - expected result: | - 1. succeed - 2. succeed - 3. succeed - 4. succeed - 5. succeed - initial condition: BLE_INIT2 - cmd set: - - "" - - - "SSC SSC2 gatts -S -z load -p 0xA1" - - ["R SSC2 C +GATTS:CreateService,OK,A001"] - - - SSC SSC1 gattc -F -r - - ['R SSC1 C +GATTC:OK'] - - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ["R SSC1 C +BLE:GattcConnect,OK,0010", "R SSC2 C +BLE:GattsConnect"] - - *primary_service_discovery - - - "SSC SSC1 gattc -R -z char -s 0xA000 -c 0xC100 -p 0x10" - - ["R SSC1 C +GATTC:ReadOnce,0010,A000,C100,1", "R SSC1 C +GATTC:Read,OK,0010,A000,C100"] -- ID: BTSTK_GATT_21006 - <<: *GATT_CASE - test point 2: BLE GATT client read char and descriptor - summary: GATT client read short descriptor or an included service - allow fail: 1/2 - steps: | - 1. DUT2 create preset service 0xA000 - 2. DUT2 create preset service 0xA001 - 3. DUT1 connect to DUT2 - 4. DUT1 do discover - 5. GATT client read 1 byte short descriptor - expected result: | - 1. succeed - 2. succeed - 3. succeed - 4. succeed - 5. succeed - initial condition: BLE_INIT2 - cmd set: - - "" - - - "SSC SSC2 gatts -S -z load -p 0xA1" - - ["R SSC2 C +GATTS:CreateService,OK,A001"] - - - SSC SSC1 gattc -F -r - - ['R SSC1 C +GATTC:OK'] - - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ["R SSC1 C +BLE:GattcConnect,OK,0010", "R SSC2 C +BLE:GattsConnect"] - - *primary_service_discovery - - - "SSC SSC1 gattc -R -z descriptor -s 0xA000 -c 0xC107 -d 0x2902 -p 0x10" - - ["R SSC1 C +GATTC:ReadOnce,0010,A000,C107,2902,2", "R SSC1 C +GATTC:ReadDescriptor,OK,0010,A000,C107,2902"] - ID: BTSTK_GATT_21007 <<: *GATT_CASE test point 2: BLE GATT client read char and descriptor @@ -774,7 +471,7 @@ test cases: cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -R -z char -s 0xA002 -c 0xC300 -p 0x10" + - - "SSC SSC1 gattc -R -z char -s 0xA002 -c 0xC300 -p 0x10 -r " - ["R SSC1 C +GATTC:ReadOnce,0010,A002,C300,1", "R SSC1 C +GATTC:Read,OK,0010,A002,C300"] - ID: BTSTK_GATT_21008 <<: *GATT_CASE @@ -786,12 +483,11 @@ test cases: expected result: | 1. succeed 2. succeed - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -R -z char -s 0xA002 -c 0xC301 -p 0x10" - - ["R SSC1 C +GATTC:ReadOnce,0010,A002,C301,256", "R SSC1 C +GATTC:Read,OK,0010,A002,C301"] + - - "SSC SSC1 gattc -R -z char -s 0xA002 -c 0xC301 -p 0x10 -r " + - ["P SSC1 C +GATTC:ReadOnce,0010,A002,C301,256", "P SSC1 C +GATTC:Read,OK,0010,A002,C301"] - ID: BTSTK_GATT_21009 <<: *GATT_CASE test point 2: BLE GATT client read char and descriptor @@ -802,12 +498,11 @@ test cases: expected result: | 1. succeed 2. succeed - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -R -z char -s 0xA002 -c 0xC310 -p 0x10" - - ["R SSC1 C +GATTC:ReadOnce,0010,A002,C310,1", "R SSC1 C +GATTC:Read,OK,0010,A002,C310"] + - - "SSC SSC1 gattc -R -z char -s 0xA002 -c 0xC310 -p 0x10 -r " + - ["P SSC1 C +GATTC:ReadOnce,0010,A002,C310,1", "P SSC1 C +GATTC:Read,OK,0010,A002,C310"] - ID: BTSTK_GATT_21010 <<: *GATT_CASE test point 2: BLE GATT client read char and descriptor @@ -818,12 +513,11 @@ test cases: expected result: | 1. succeed 2. succeed - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -R -z char -s 0xA002 -c 0xC311 -p 0x10" - - ["R SSC1 C +GATTC:ReadOnce,0010,A002,C311,256", "R SSC1 C +GATTC:Read,OK,0010,A002,C311"] + - - "SSC SSC1 gattc -R -z char -s 0xA002 -c 0xC311 -p 0x10 -r " + - ["P SSC1 C +GATTC:ReadOnce,0010,A002,C311,256", "P SSC1 C +GATTC:Read,OK,0010,A002,C311"] - ID: BTSTK_GATT_21011 <<: *GATT_CASE test point 2: BLE GATT client read char and descriptor @@ -834,12 +528,11 @@ test cases: expected result: | 1. succeed 2. succeed - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -R -z descriptor -s 0xA002 -c 0xC300 -d 0x2901 -p 0x10" - - ["R SSC1 C +GATTC:ReadOnce,0010,A002,C300,2901,1", "R SSC1 C +GATTC:ReadDescriptor,OK,0010,A002,C300,2901"] + - - "SSC SSC1 gattc -R -z descriptor -s 0xA002 -c 0xC300 -d 0x2901 -p 0x10 -r " + - ["P SSC1 C +GATTC:ReadOnce,0010,A002,C300,2901,1", "P SSC1 C +GATTC:ReadDescriptor,OK,0010,A002,C300,2901"] - ID: BTSTK_GATT_21012 <<: *GATT_CASE test point 2: BLE GATT client read char and descriptor @@ -850,12 +543,11 @@ test cases: expected result: | 1. succeed 2. succeed - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -R -z descriptor -s 0xA002 -c 0xC301 -d 0x2901 -p 0x10" - - ["R SSC1 C +GATTC:ReadOnce,0010,A002,C301,2901,256", "R SSC1 C +GATTC:ReadDescriptor,OK,0010,A002,C301,2901"] + - - "SSC SSC1 gattc -R -z descriptor -s 0xA002 -c 0xC301 -d 0x2901 -p 0x10 -r " + - ["P SSC1 C +GATTC:ReadOnce,0010,A002,C301,2901,256", "P SSC1 C +GATTC:ReadDescriptor,OK,0010,A002,C301,2901"] - ID: BTSTK_GATT_21013 <<: *GATT_CASE test point 2: BLE GATT client read char and descriptor @@ -866,12 +558,11 @@ test cases: expected result: | 1. succeed 2. succeed - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -R -z descriptor -s 0xA002 -c 0xC310 -d 0x2901 -p 0x10" - - ["R SSC1 C +GATTC:ReadOnce,0010,A002,C310,2901,1", "R SSC1 C +GATTC:ReadDescriptor,OK,0010,A002,C310,2901"] + - - "SSC SSC1 gattc -R -z descriptor -s 0xA002 -c 0xC310 -d 0x2901 -p 0x10 -r " + - ["P SSC1 C +GATTC:ReadOnce,0010,A002,C310,2901,1", "P SSC1 C +GATTC:ReadDescriptor,OK,0010,A002,C310,2901"] - ID: BTSTK_GATT_21014 <<: *GATT_CASE test point 2: BLE GATT client read char and descriptor @@ -882,178 +573,11 @@ test cases: expected result: | 1. succeed 2. succeed - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -R -z descriptor -s 0xA002 -c 0xC311 -d 0x2901 -p 0x10" - - ["R SSC1 C +GATTC:ReadOnce,0010,A002,C311,2901,256", "R SSC1 C +GATTC:ReadDescriptor,OK,0010,A002,C311,2901"] -- ID: BTSTK_GATT_22001 - <<: *GATT_CASE - test point 2: BLE GATT client write char and descriptor - summary: GATT client write with response to a short char with response - steps: | - 1. DUT1 do service discovery - 2. GATT client write with response to short char with response - expected result: | - 1. succeed - 2. write succeed - cmd set: - - "" - - *primary_service_discovery - - - "SSC SSC1 gattc -W -z char -s 0xA000 -c 0xC102 -p 0x10 -v 0x01" - - ["R SSC1 C +GATTC:WriteOnce,0010,A000,C102", "R SSC1 C +GATTC:Write,OK,0010,A000,C102"] -- ID: BTSTK_GATT_22002 - <<: *GATT_CASE - test point 2: BLE GATT client write char and descriptor - summary: GATT client write without response to a short char without response - steps: | - 1. DUT1 do service discovery - 2. GATT client write without response to short char without response - expected result: | - 1. succeed - 2. write succeed - cmd set: - - "" - - *primary_service_discovery - - - "SSC SSC1 gattc -W -z char -s 0xA000 -c 0xC103 -p 0x10 -v 0x01 -w 1" - - - "P SSC1 C +GATTC:WriteOnce,0010,A000,C103" - - "P SSC2 C +GATTS:Write,OK,A000,C103" - - "P SSC1 C +GATTC:Write,OK,0010,A000,C103" -- ID: BTSTK_GATT_22003 - <<: *GATT_CASE - test point 2: BLE GATT client write char and descriptor - summary: GATT client prepare write and do execute - steps: | - 1. DUT1 do service discovery - 2. GATT client prepare write and do execute - expected result: | - 1. succeed - 2. write succeed - cmd set: - - "" - - *primary_service_discovery - - - "SSC SSC1 gattc -W -z longChar -s 0xA000 -c 0xC110 -p 0x10 -l 256" - - ["P SSC1 C +GATTC:Write,OK,0010,A000,C110"] -- ID: BTSTK_GATT_22004 - <<: *GATT_CASE - test point 2: BLE GATT client write char and descriptor - summary: GATT client prepare write and do cancel - steps: | - 1. DUT1 do service discovery - 2. GATT client prepare write and do cancel - expected result: | - 1. succeed - 2. write succeed - cmd set: - - "" - - *primary_service_discovery - - - "SSC SSC1 gattc -W -z longChar -s 0xA000 -c 0xC110 -p 0x10 -l 256 -e 0" - - ["P SSC1 C +GATTC:Write,OK,0010,A000,C110"] - - - "SSC SSC1 gattc -W -z char -s 0xA000 -c 0xC110 -p 0x10 -l 256 -e 0" - - ["P SSC1 C +GATTC:Write,OK,0010,A000,C110"] -- ID: BTSTK_GATT_22005 - <<: *GATT_CASE - test point 2: BLE GATT client write char and descriptor - summary: GATT client write to a short descriptor - steps: | - 1. DUT1 do service discovery - 2. GATT client write to short descriptor - expected result: | - 1. succeed - 2. write succeed - cmd set: - - "" - - *primary_service_discovery - - - "SSC SSC1 gattc -W -z descriptor -s 0xA000 -c 0xC107 -d 0x2902 -p 0x10 -v 0x0100" - - ["R SSC1 C +GATTC:WriteOnce,0010,A000,C107,2902", "R SSC1 C +GATTC:WriteDescriptor,OK,0010,A000,C107,2902"] -- ID: BTSTK_GATT_22006 - <<: *GATT_CASE - test point 2: BLE GATT client write char and descriptor - summary: GATT client write to long descriptor and execute - steps: | - 1. DUT1 do service discovery - 2. GATT client write to long descriptor and execute - expected result: | - 1. succeed - 2. write succeed - cmd set: - - "" - - *primary_service_discovery - - - "SSC SSC1 gattc -W -z longDescriptor -s 0xA000 -c 0xC100 -d 0x2901 -p 0x10 -l 256" - - ["P SSC1 C +GATTC:WriteDescriptor,OK,0010,A000,C100,2901"] -- ID: BTSTK_GATT_22007 - <<: *GATT_CASE - test point 2: BLE GATT client write char and descriptor - summary: GATT client write to long descriptor using write API - steps: | - 1. DUT1 do service discovery - 2. GATT client write to long descriptor and execute - expected result: | - 1. succeed - 2. write succeed - cmd set: - - "" - - *primary_service_discovery - - - "SSC SSC1 gattc -W -z descriptor -s 0xA000 -c 0xC100 -d 0x2901 -p 0x10 -l 256" - - ["P SSC1 C +GATTC:WriteDescriptor,OK,0010,A000,C100,2901"] -- ID: BTSTK_GATT_22008 - <<: *GATT_CASE - test point 2: BLE GATT client write char and descriptor - summary: GATT client write to an included char - allow fail: 1/2 - steps: | - 1. DUT2 create preset service 0xA000 - 2. DUT2 create preset service 0xA001 - 3. DUT1 connect to DUT2 - 4. DUT1 do discover - 5. GATT client write with response to short char with response - expected result: | - 1. succeed - 2. succeed - 3. succeed - 4. succeed - 5. succeed - initial condition: BLE_INIT2 - cmd set: - - "" - - - "SSC SSC2 gatts -S -z load -p 0xA1" - - ["R SSC2 C +GATTS:CreateService,OK,A001"] - - - SSC SSC1 gattc -F -r - - ['R SSC1 C +GATTC:OK'] - - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ["R SSC1 C +BLE:GattcConnect,OK,0010", "R SSC2 C +BLE:GattsConnect"] - - *primary_service_discovery - - - "SSC SSC1 gattc -W -z char -s 0xA000 -c 0xC102 -p 0x10 -v 0x01" - - ["R SSC1 C +GATTC:WriteOnce,0010,A000,C102", "R SSC1 C +GATTC:Write,OK,0010,A000,C102"] -- ID: BTSTK_GATT_22009 - <<: *GATT_CASE - test point 2: BLE GATT client write char and descriptor - summary: GATT client write to an included descriptor - steps: | - 1. DUT2 create preset service 0xA000 - 2. DUT2 create preset service 0xA001 - 3. DUT1 connect to DUT2 - 4. DUT1 do discover - 5. GATT client write to short descriptor - expected result: | - 1. succeed - 2. succeed - 3. succeed - 4. succeed - 5. succeed - initial condition: BLE_INIT2 - cmd set: - - "" - - - "SSC SSC2 gatts -S -z load -p 0xA1" - - ["R SSC2 C +GATTS:CreateService,OK,A001"] - - - SSC SSC1 gattc -F -r - - ['R SSC1 C +GATTC:OK'] - - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ["R SSC1 C +BLE:GattcConnect,OK,0010", "R SSC2 C +BLE:GattsConnect"] - - *primary_service_discovery - - - "SSC SSC1 gattc -W -z descriptor -s 0xA000 -c 0xC107 -d 0x2902 -p 0x10 -v 0x0100" - - ["R SSC1 C +GATTC:WriteOnce,0010,A000,C107,2902", "R SSC1 C +GATTC:WriteDescriptor,OK,0010,A000,C107,2902"] + - - "SSC SSC1 gattc -R -z descriptor -s 0xA002 -c 0xC311 -d 0x2901 -p 0x10 -r " + - ["P SSC1 C +GATTC:ReadOnce,0010,A002,C311,2901,256", "P SSC1 C +GATTC:ReadDescriptor,OK,0010,A002,C311,2901"] - ID: BTSTK_GATT_22010 <<: *GATT_CASE test point 2: BLE GATT client write char and descriptor @@ -1065,12 +589,11 @@ test cases: expected result: | 1. succeed 2. write succeed - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -W -z char -s 0xA002 -c 0xC302 -p 0x10 -v 0x01" - - ["R SSC1 C +GATTC:WriteOnce,0010,A002,C302", "R SSC1 C +GATTC:Write,OK,0010,A002,C302"] + - - "SSC SSC1 gattc -W -z char -s 0xA002 -c 0xC302 -p 0x10 -r -v 0x01 -w 2" + - ["P SSC1 C +GATTC:WriteOnce,0010,A002,C302", "P SSC1 C +GATTC:Write,OK,0010,A002,C302"] - ID: BTSTK_GATT_22011 <<: *GATT_CASE test point 2: BLE GATT client write char and descriptor @@ -1081,11 +604,10 @@ test cases: expected result: | 1. succeed 2. write succeed - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -W -z char -s 0xA002 -c 0xC303 -p 0x10 -v 0x01 -w 1" + - - "SSC SSC1 gattc -W -z char -s 0xA002 -c 0xC303 -p 0x10 -v 0x01 -w 1 -r " - - "P SSC1 C +GATTC:WriteOnce,0010,A002,C303" - "P SSC2 C +GATTS:Write,OK,A002,C303" - "P SSC1 C +GATTC:Write,OK,0010,A002,C303" @@ -1099,11 +621,10 @@ test cases: expected result: | 1. succeed 2. write succeed - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -W -z longChar -s 0xA002 -c 0xC304 -p 0x10 -l 256" + - - "SSC SSC1 gattc -W -z longChar -s 0xA002 -c 0xC304 -p 0x10 -l 256 -r " - ["P SSC1 C +GATTC:Write,OK,0010,A002,C304"] - ID: BTSTK_GATT_22013 <<: *GATT_CASE @@ -1115,11 +636,10 @@ test cases: expected result: | 1. succeed 2. write succeed - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -W -z longChar -s 0xA002 -c 0xC304 -p 0x10 -l 256 -e 0" + - - "SSC SSC1 gattc -W -z longChar -s 0xA002 -c 0xC304 -p 0x10 -l 256 -e 0 -r " - ["P SSC1 C +GATTC:Write,OK,0010,A002,C304"] - ID: BTSTK_GATT_22014 <<: *GATT_CASE @@ -1131,11 +651,10 @@ test cases: expected result: | 1. succeed 2. write succeed - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -W -z descriptor -s 0xA002 -c 0xC300 -d 0x2901 -p 0x10 -v 0x01" + - - "SSC SSC1 gattc -W -z descriptor -s 0xA002 -c 0xC300 -d 0x2901 -p 0x10 -v 0x01 -r " - ["R SSC1 C +GATTC:WriteOnce,0010,A002,C300,2901", "R SSC1 C +GATTC:WriteDescriptor,OK,0010,A002,C300,2901"] - ID: BTSTK_GATT_22015 <<: *GATT_CASE @@ -1147,11 +666,10 @@ test cases: expected result: | 1. succeed 2. write succeed - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -W -z longDescriptor -s 0xA002 -c 0xC301 -d 0x2901 -p 0x10 -l 256" + - - "SSC SSC1 gattc -W -z longDescriptor -s 0xA002 -c 0xC301 -d 0x2901 -p 0x10 -l 256 -r " - ["P SSC1 C +GATTC:WriteDescriptor,OK,0010,A002,C301,2901"] - ID: BTSTK_GATT_22016 <<: *GATT_CASE @@ -1163,11 +681,10 @@ test cases: expected result: | 1. succeed 2. write succeed - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -W -z longDescriptor -s 0xA002 -c 0xC301 -d 0x2901 -p 0x10 -l 256 -e 0" + - - "SSC SSC1 gattc -W -z longDescriptor -s 0xA002 -c 0xC301 -d 0x2901 -p 0x10 -l 256 -e 0 -r " - ["P SSC1 C +GATTC:WriteDescriptor,OK,0010,A002,C301,2901"] - ID: BTSTK_GATT_22017 <<: *GATT_CASE @@ -1179,11 +696,10 @@ test cases: expected result: | 1. succeed 2. write succeed - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -W -z char -s 0xA002 -c 0xC312 -p 0x10 -v 0x01" + - - "SSC SSC1 gattc -W -z char -s 0xA002 -c 0xC312 -p 0x10 -v 0x01 -r " - ["R SSC1 C +GATTC:WriteOnce,0010,A002,C312", "R SSC1 C +GATTC:Write,OK,0010,A002,C312"] - ID: BTSTK_GATT_22018 <<: *GATT_CASE @@ -1195,11 +711,10 @@ test cases: expected result: | 1. succeed 2. write succeed - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -W -z char -s 0xA002 -c 0xC313 -p 0x10 -v 0x01 -w 1" + - - "SSC SSC1 gattc -W -z char -s 0xA002 -c 0xC313 -p 0x10 -v 0x01 -w 1 -r " - - "P SSC1 C +GATTC:WriteOnce,0010,A002,C313" - "P SSC2 C +GATTS:Write,OK,A002,C313" - "P SSC1 C +GATTC:Write,OK,0010,A002,C313" @@ -1213,11 +728,10 @@ test cases: expected result: | 1. succeed 2. write succeed - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -W -z longChar -s 0xA002 -c 0xC314 -p 0x10 -l 256" + - - "SSC SSC1 gattc -W -z longChar -s 0xA002 -c 0xC314 -p 0x10 -l 256 -r " - ["P SSC1 C +GATTC:Write,OK,0010,A002,C314"] - ID: BTSTK_GATT_22020 <<: *GATT_CASE @@ -1229,11 +743,10 @@ test cases: expected result: | 1. succeed 2. write succeed - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -W -z longChar -s 0xA002 -c 0xC314 -p 0x10 -l 256 -e 0" + - - "SSC SSC1 gattc -W -z longChar -s 0xA002 -c 0xC314 -p 0x10 -l 256 -e 0 -r " - ["P SSC1 C +GATTC:Write,OK,0010,A002,C314"] - ID: BTSTK_GATT_22021 <<: *GATT_CASE @@ -1245,11 +758,10 @@ test cases: expected result: | 1. succeed 2. write succeed - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -W -z descriptor -s 0xA002 -c 0xC310 -d 0x2901 -p 0x10 -v 0x01" + - - "SSC SSC1 gattc -W -z descriptor -s 0xA002 -c 0xC310 -d 0x2901 -p 0x10 -v 0x01 -r " - ["R SSC1 C +GATTC:WriteOnce,0010,A002,C310,2901", "R SSC1 C +GATTC:WriteDescriptor,OK,0010,A002,C310,2901"] - ID: BTSTK_GATT_22022 <<: *GATT_CASE @@ -1261,11 +773,10 @@ test cases: expected result: | 1. succeed 2. write succeed - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -W -z longDescriptor -s 0xA002 -c 0xC311 -d 0x2901 -p 0x10 -l 256" + - - "SSC SSC1 gattc -W -z longDescriptor -s 0xA002 -c 0xC311 -d 0x2901 -p 0x10 -l 256 -r " - ["P SSC1 C +GATTC:WriteDescriptor,OK,0010,A002,C311,2901"] - ID: BTSTK_GATT_22023 <<: *GATT_CASE @@ -1277,96 +788,11 @@ test cases: expected result: | 1. succeed 2. write succeed - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -W -z longDescriptor -s 0xA002 -c 0xC311 -d 0x2901 -p 0x10 -l 256 -e 0" + - - "SSC SSC1 gattc -W -z longDescriptor -s 0xA002 -c 0xC311 -d 0x2901 -p 0x10 -l 256 -e 0 -r " - ["P SSC1 C +GATTC:WriteDescriptor,OK,0010,A002,C311,2901"] -- ID: BTSTK_GATT_23001 - <<: *GATT_CASE - test point 2: BLE GATT client receive notify and indication - summary: GATT client register/unregister notify - steps: | - 1. DUT1 do service discovery - 2. DUT1 register notify on notification char - 3. DUT1 register notify on indication char - expected result: | - 1. succeed - 2. succeed - 3. succeed - cmd set: - - "" - - *primary_service_discovery - - *register_notify_c107 - - *register_indicate_c108 - - - "SSC SSC1 gattc -N -z unregister -s 0xA000 -c 0xC107 -p 0x10 -r " - - ["R SSC1 C +GATTC:UnRegNotify,OK,0010,A000,C107"] - - - "SSC SSC1 gattc -N -z unregister -s 0xA000 -c 0xC108 -p 0x10 -r " - - ["R SSC1 C +GATTC:UnRegNotify,OK,0010,A000,C108"] -- ID: BTSTK_GATT_23002 - <<: *GATT_CASE - test point 2: BLE GATT client receive notify and indication - summary: GATT client receive notify - steps: | - 1. DUT1 do service discovery - 2. DUT1 register notify on notification char and write to CCC - 3. DUT2 do notify - expected result: | - 1. succeed - 2. succeed - 3. DUT1 recv notify - cmd set: - - "" - - *primary_service_discovery - - *register_notify_c107 - - - "SSC SSC1 gattc -W -z descriptor -s 0xA000 -c 0xC107 -d 0x2902 -p 0x10 -v 0x0100" - - ["R SSC1 C +GATTC:WriteOnce,0010,A000,C107,2902", "R SSC1 C +GATTC:WriteDescriptor,OK,0010,A000,C107,2902"] - - - "SSC SSC2 gatts -N -c 0xC107 -p 0xA0 -v 0x01" - - ["R SSC1 C +GATTC:Notification,0010,A000,C107,1"] -- ID: BTSTK_GATT_23003 - <<: *GATT_CASE - test point 2: BLE GATT client receive notify and indication - summary: GATT client receive indication - steps: | - 1. DUT1 do service discovery - 2. DUT1 register notify on inidcation char and write to CCC - 3. DUT2 do indication - expected result: | - 1. succeed - 2. succeed - 3. DUT1 recv indication - cmd set: - - "" - - *primary_service_discovery - - *register_indicate_c108 - - - "SSC SSC1 gattc -W -z descriptor -s 0xA000 -c 0xC108 -d 0x2902 -p 0x10 -v 0x0002" - - ["R SSC1 C +GATTC:WriteOnce,0010,A000,C108,2902", "R SSC1 C +GATTC:WriteDescriptor,OK,0010,A000,C108,2902"] - - - "SSC SSC2 gatts -I -c 0xC108 -p 0xA0 -v 0x01" - - ["R SSC1 C +GATTC:Indication,0010,A000,C108,1"] -- ID: BTSTK_GATT_23004 - <<: *GATT_CASE - test point 2: BLE GATT client receive notify and indication - summary: GATT client can't receive notification/indication without write to CCC (manual service) - steps: | - 1. DUT1 do service discovery - 2. DUT1 register notify on notify and inidcation char - 3. DUT2 do notify and indication - expected result: | - 1. succeed - 2. succeed - 3. DUT1 can recv notify and indication (this is aganist Spec, but a reasonable behavior in bluedroid) - cmd set: - - "" - - *primary_service_discovery - - *register_notify_c107 - - *register_indicate_c108 - - - "SSC SSC1 gattc -W -z descriptor -s 0xA000 -c 0xC107 -d 0x2902 -p 0x10 -v 0x0000" - - ["R SSC1 C +GATTC:WriteOnce,0010,A000,C107,2902", "R SSC1 C +GATTC:WriteDescriptor,OK,0010,A000,C107,2902"] - - - "SSC SSC2 gatts -N -c 0xC107 -p 0xA0 -v 0x01" - - ["P SSC1 C +GATTC:Notification,0010,A000,C107,1"] - - - "SSC SSC2 gatts -I -c 0xC108 -p 0xA0 -v 0x01" - - ["P SSC1 C +GATTC:Indication,0010,A000,C108,1"] - ID: BTSTK_GATT_23005 <<: *GATT_CASE test point 2: BLE GATT client receive notify and indication @@ -1385,9 +811,9 @@ test cases: - *primary_service_discovery - - "SSC SSC1 gattc -N -z register -s 0xA002 -c 0xC305 -p 0x10 -r " - ["R SSC1 C +GATTC:RegNotify,OK,0010,A002,C305"] - - - "SSC SSC1 gattc -W -z descriptor -s 0xA002 -c 0xC305 -d 0x2902 -p 0x10 -v 0x0100" + - - "SSC SSC1 gattc -W -z descriptor -s 0xA002 -c 0xC305 -d 0x2902 -p 0x10 -v 0x0100 -r " - ["R SSC1 C +GATTC:WriteOnce,0010,A002,C305,2902", "R SSC1 C +GATTC:WriteDescriptor,OK,0010,A002,C305,2902"] - - - "SSC SSC2 gatts -N -c 0xC305 -p 0xA2 -v 0x01" + - - "SSC SSC2 gatts -N -c 0xC305 -p 0xA2 -v 0x01 -r " - ["R SSC1 C +GATTC:Notification,0010,A002,C305,1"] - ID: BTSTK_GATT_23006 <<: *GATT_CASE @@ -1401,15 +827,14 @@ test cases: 1. succeed 2. succeed 3. DUT1 recv indication - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - "SSC SSC1 gattc -N -z register -s 0xA002 -c 0xC306 -p 0x10 -r " - ["R SSC1 C +GATTC:RegNotify,OK,0010,A002,C306"] - - - "SSC SSC1 gattc -W -z descriptor -s 0xA002 -c 0xC306 -d 0x2902 -p 0x10 -v 0x0002" + - - "SSC SSC1 gattc -W -z descriptor -s 0xA002 -c 0xC306 -d 0x2902 -r -v 0x0002 -p 0x10" - ["R SSC1 C +GATTC:WriteOnce,0010,A002,C306,2902", "R SSC1 C +GATTC:WriteDescriptor,OK,0010,A002,C306,2902"] - - - "SSC SSC2 gatts -I -c 0xC306 -p 0xA2 -v 0x01" + - - "SSC SSC2 gatts -I -c 0xC306 -p 0xA2 -v 0x01 -r " - ["R SSC1 C +GATTC:Indication,0010,A002,C306,1"] - ID: BTSTK_GATT_23007 <<: *GATT_CASE @@ -1423,7 +848,6 @@ test cases: 1. succeed 2. succeed 3. DUT1 can recv notify and indication (this is aganist Spec, but a reasonable behavior in bluedroid) - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery @@ -1431,9 +855,9 @@ test cases: - ["R SSC1 C +GATTC:RegNotify,OK,0010,A002,C305"] - - "SSC SSC1 gattc -N -z register -s 0xA002 -c 0xC306 -p 0x10 -r " - ["R SSC1 C +GATTC:RegNotify,OK,0010,A002,C306"] - - - "SSC SSC2 gatts -N -c 0xC305 -p 0xA2 -v 0x01" + - - "SSC SSC2 gatts -N -c 0xC305 -p 0xA2 -v 0x01 -r " - ["P SSC1 C +GATTC:Notification,0010,A002,C305,1"] - - - "SSC SSC2 gatts -I -c 0xC306 -p 0xA2 -v 0x01" + - - "SSC SSC2 gatts -I -c 0xC306 -p 0xA2 -v 0x01 -r " - ["P SSC1 C +GATTC:Indication,0010,A002,C306,1"] - ID: BTSTK_GATT_23008 <<: *GATT_CASE @@ -1447,15 +871,14 @@ test cases: 1. succeed 2. succeed 3. DUT1 recv notify - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - "SSC SSC1 gattc -N -z register -s 0xA002 -c 0xC315 -p 0x10 -r " - ["R SSC1 C +GATTC:RegNotify,OK,0010,A002,C315"] - - - "SSC SSC1 gattc -W -z descriptor -s 0xA002 -c 0xC315 -d 0x2902 -p 0x10 -v 0x0100" + - - "SSC SSC1 gattc -W -z descriptor -s 0xA002 -c 0xC315 -d 0x2902 -p 0x10 -r -v 0x0100" - ["R SSC1 C +GATTC:WriteOnce,0010,A002,C315,2902", "R SSC1 C +GATTC:WriteDescriptor,OK,0010,A002,C315,2902"] - - - "SSC SSC2 gatts -N -c 0xC315 -p 0xA2 -v 0x01" + - - "SSC SSC2 gatts -N -c 0xC315 -p 0xA2 -v 0x01 -r " - ["R SSC1 C +GATTC:Notification,0010,A002,C315,1"] - ID: BTSTK_GATT_23009 <<: *GATT_CASE @@ -1469,15 +892,14 @@ test cases: 1. succeed 2. succeed 3. DUT1 recv indication - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - "SSC SSC1 gattc -N -z register -s 0xA002 -c 0xC316 -p 0x10 -r " - ["R SSC1 C +GATTC:RegNotify,OK,0010,A002,C316"] - - - "SSC SSC1 gattc -W -z descriptor -s 0xA002 -c 0xC316 -d 0x2902 -p 0x10 -v 0x0002" + - - "SSC SSC1 gattc -W -z descriptor -s 0xA002 -c 0xC316 -d 0x2902 -p 0x10 -r -v 0x0002" - ["R SSC1 C +GATTC:WriteOnce,0010,A002,C316,2902", "R SSC1 C +GATTC:WriteDescriptor,OK,0010,A002,C316,2902"] - - - "SSC SSC2 gatts -I -c 0xC316 -p 0xA2 -v 0x01" + - - "SSC SSC2 gatts -I -c 0xC316 -p 0xA2 -v 0x01 -r " - ["R SSC1 C +GATTC:Indication,0010,A002,C316,1"] - ID: BTSTK_GATT_23010 <<: *GATT_CASE @@ -1491,7 +913,6 @@ test cases: 1. succeed 2. succeed 3. DUT1 can recv notify and indication (this is aganist Spec, but a reasonable behavior in bluedroid) - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery @@ -1499,40 +920,10 @@ test cases: - ["R SSC1 C +GATTC:RegNotify,OK,0010,A002,C315"] - - "SSC SSC1 gattc -N -z register -s 0xA002 -c 0xC316 -p 0x10 -r " - ["R SSC1 C +GATTC:RegNotify,OK,0010,A002,C316"] - - - "SSC SSC2 gatts -N -c 0xC315 -p 0xA2 -v 0x01" + - - "SSC SSC2 gatts -N -c 0xC315 -p 0xA2 -v 0x01 -r " - ["P SSC1 C +GATTC:Notification,0010,A002,C315,1"] - - - "SSC SSC2 gatts -I -c 0xC316 -p 0xA2 -v 0x01" + - - "SSC SSC2 gatts -I -c 0xC316 -p 0xA2 -v 0x01 -r " - ["P SSC1 C +GATTC:Indication,0010,A002,C316,1"] -- ID: BTSTK_GATT_24001 - <<: *GATT_CASE - test point 2: BLE GATT client do invalid read - summary: GATT client read to a char without read property - steps: | - 1. DUT1 do service discovery - 2. DUT1 read to a char without read property - expected result: | - 1. succeed - 2. failed - cmd set: - - "" - - *primary_service_discovery - - - "SSC SSC1 gattc -R -z char -s 0xA000 -c 0xC103 -p 0x10" - - ["P SSC1 C +GATTC:Read,ERROR"] -- ID: BTSTK_GATT_24002 - <<: *GATT_CASE - test point 2: BLE GATT client do invalid read - summary: GATT client read to a descriptor without read property - steps: | - 1. DUT1 do service discovery - 2. DUT1 read to a descriptor without read property - expected result: | - 1. succeed - 2. failed - cmd set: - - "" - - *primary_service_discovery - - - "SSC SSC1 gattc -R -z descriptor -s 0xA000 -c 0xC102 -d 0x2901 -p 0x10" - - ["P SSC1 C +GATTC:Read,ERROR"] - ID: BTSTK_GATT_24003 <<: *GATT_CASE test point 2: BLE GATT client do invalid read @@ -1545,13 +936,12 @@ test cases: 1. succeed 2. failed 3. failed - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -R -z char -s 0xA002 -c 0xC302 -p 0x10" + - - "SSC SSC1 gattc -R -z char -s 0xA002 -c 0xC302 -p 0x10 -r " - ["P SSC1 C +GATTC:Read,ERROR"] - - - "SSC SSC1 gattc -R -z char -s 0xA002 -c 0xC312 -p 0x10" + - - "SSC SSC1 gattc -R -z char -s 0xA002 -c 0xC312 -p 0x10 -r " - ["P SSC1 C +GATTC:Read,ERROR"] - ID: BTSTK_GATT_24004 <<: *GATT_CASE @@ -1565,120 +955,13 @@ test cases: 1. succeed 2. failed 3. failed - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -R -z descriptor -s 0xA002 -c 0xC303 -d 0x2901 -p 0x10" + - - "SSC SSC1 gattc -R -z descriptor -s 0xA002 -c 0xC303 -d 0x2901 -p 0x10 -r " - ["P SSC1 C +GATTC:Read,ERROR"] - - - "SSC SSC1 gattc -R -z descriptor -s 0xA002 -c 0xC313 -d 0x2901 -p 0x10" + - - "SSC SSC1 gattc -R -z descriptor -s 0xA002 -c 0xC313 -d 0x2901 -p 0x10 -r " - ["P SSC1 C +GATTC:Read,ERROR"] -- ID: BTSTK_GATT_25001 - <<: *GATT_CASE - test point 2: BLE GATT client do invalid write - summary: GATT client write with response to a char without write property - steps: | - 1. DUT1 do service discovery - 2. DUT1 write with response to a char without write property - expected result: | - 1. succeed - 2. failed - cmd set: - - "" - - *primary_service_discovery - - - "SSC SSC1 gattc -W -z char -s 0xA000 -c 0xC100 -p 0x10 -l 1" - - ["R SSC1 C +GATTC:Write,ERROR"] -- ID: BTSTK_GATT_25002 - <<: *GATT_CASE - test point 1: basic function - test point 2: BLE GATT client do invalid write - summary: GATT client write without response to a char without write property - steps: | - 1. DUT1 do service discovery - 2. DUT1 write without response to a char without write property - expected result: | - 1. succeed - 2. succeed (write without response always succeed) - cmd set: - - "" - - *primary_service_discovery - - - "SSC SSC1 gattc -W -z char -s 0xA000 -c 0xC100 -p 0x10 -l 1 -w 1" - - ["R SSC1 C +GATTC:Write,OK"] -- ID: BTSTK_GATT_25003 - <<: *GATT_CASE - test point 2: BLE GATT client do invalid write - summary: GATT client write to a descriptor without write property - steps: | - 1. DUT1 do service discovery - 2. DUT1 write to a descriptor without write property - expected result: | - 1. succeed - 2. failed - cmd set: - - "" - - *primary_service_discovery - - - "SSC SSC1 gattc -W -z descriptor -s 0xA000 -c 0xC101 -d 0x2901 -p 0x10 -l 1" - - ["R SSC1 C +GATTC:Write,ERROR"] -- ID: BTSTK_GATT_25004 - <<: *GATT_CASE - test point 2: BLE GATT client do invalid write - summary: GATT client prepare write to a char without write property - steps: | - 1. DUT1 do service discovery - 2. DUT1 prepare write to a char without write property - expected result: | - 1. succeed - 2. failed - cmd set: - - "" - - *primary_service_discovery - - - "SSC SSC1 gattc -W -z longChar -s 0xA000 -c 0xC100 -p 0x10 -l 256" - - ["R SSC1 C +GATTC:Write,ERROR"] -- ID: BTSTK_GATT_25005 - <<: *GATT_CASE - test point 2: BLE GATT client do invalid write - summary: GATT client prepare write to a descriptor without write property - steps: | - 1. DUT1 do service discovery - 2. DUT1 prepare write to a descriptor without write property - expected result: | - 1. succeed - 2. failed - cmd set: - - "" - - *primary_service_discovery - - - "SSC SSC1 gattc -W -z longDescriptor -s 0xA000 -c 0xC101 -d 0x2901 -p 0x10 -l 256" - - ["R SSC1 C +GATTC:Write,ERROR"] -- ID: BTSTK_GATT_25006 - <<: *GATT_CASE - test point 2: BLE GATT client do invalid write - summary: GATT client write with response to a char not send response - steps: | - 1. DUT1 do service discovery - 2. DUT1 write with response to a char not send response - expected result: | - 1. succeed - 2. failed - cmd set: - - "" - - *primary_service_discovery - - - "SSC SSC1 gattc -W -z char -s 0xA000 -c 0xC103 -p 0x10 -v 0x01" - - ["R SSC1 C +GATTC:Write,ERROR"] -- ID: BTSTK_GATT_25007 - <<: *GATT_CASE - test point 2: BLE GATT client do invalid write - summary: GATT client write without response to a char will send response - steps: | - 1. DUT1 do service discovery - 2. DUT1 write without response to a char will send response - expected result: | - 1. succeed - 2. succeed (write without response always succeed) - cmd set: - - "" - - *primary_service_discovery - - - "SSC SSC1 gattc -W -z char -s 0xA000 -c 0xC102 -p 0x10 -v 0x01 -w 1" - - ["P SSC1 C +GATTC:WriteOnce"] - ID: BTSTK_GATT_25008 <<: *GATT_CASE test point 2: BLE GATT client do invalid write @@ -1691,13 +974,12 @@ test cases: 1. succeed 2. failed 3. failed - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -W -z char -s 0xA002 -c 0xC300 -p 0x10 -l 1" + - - "SSC SSC1 gattc -W -z char -s 0xA002 -c 0xC300 -p 0x10 -r -l 1" - ["R SSC1 C +GATTC:Write,ERROR"] - - - "SSC SSC1 gattc -W -z char -s 0xA002 -c 0xC310 -p 0x10 -l 1" + - - "SSC SSC1 gattc -W -z char -s 0xA002 -c 0xC310 -p 0x10 -r -l 1" - ["R SSC1 C +GATTC:Write,ERROR"] - ID: BTSTK_GATT_25009 <<: *GATT_CASE @@ -1711,13 +993,12 @@ test cases: 1. succeed 2. succeed (write without response always succeed) 3. succeed (write without response always succeed) - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -W -z char -s 0xA002 -c 0xC300 -p 0x10 -l 1 -w 1" + - - "SSC SSC1 gattc -W -z char -s 0xA002 -c 0xC300 -p 0x10 -r -l 1 -w 1" - ["R SSC1 C +GATTC:Write,OK"] - - - "SSC SSC1 gattc -W -z char -s 0xA002 -c 0xC300 -p 0x10 -l 1 -w 1" + - - "SSC SSC1 gattc -W -z char -s 0xA002 -c 0xC300 -p 0x10 -r -l 1 -w 1" - ["R SSC1 C +GATTC:Write,OK"] - ID: BTSTK_GATT_25010 <<: *GATT_CASE @@ -1731,13 +1012,12 @@ test cases: 1. succeed 2. failed 3. failed - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -W -z descriptor -s 0xA002 -c 0xC302 -d 0x2901 -p 0x10 -l 1" + - - "SSC SSC1 gattc -W -z descriptor -s 0xA002 -c 0xC302 -d 0x2901 -p 0x10 -r -l 1" - ["R SSC1 C +GATTC:Write,ERROR"] - - - "SSC SSC1 gattc -W -z descriptor -s 0xA002 -c 0xC312 -d 0x2901 -p 0x10 -l 1" + - - "SSC SSC1 gattc -W -z descriptor -s 0xA002 -c 0xC312 -d 0x2901 -p 0x10 -r -l 1" - ["R SSC1 C +GATTC:Write,ERROR"] - ID: BTSTK_GATT_25011 <<: *GATT_CASE @@ -1751,13 +1031,12 @@ test cases: 1. succeed 2. failed 3. failed - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -W -z longChar -s 0xA002 -c 0xC300 -p 0x10 -l 256" + - - "SSC SSC1 gattc -W -z longChar -s 0xA002 -c 0xC300 -p 0x10 -r -l 256" - ["R SSC1 C +GATTC:Write,ERROR"] - - - "SSC SSC1 gattc -W -z longChar -s 0xA002 -c 0xC310 -p 0x10 -l 256" + - - "SSC SSC1 gattc -W -z longChar -s 0xA002 -c 0xC310 -p 0x10 -r -l 256" - ["R SSC1 C +GATTC:Write,ERROR"] - ID: BTSTK_GATT_25012 <<: *GATT_CASE @@ -1771,33 +1050,12 @@ test cases: 1. succeed 2. failed 3. failed - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -W -z longDescriptor -s 0xA002 -c 0xC302 -d 0x2901 -p 0x10 -l 256" + - - "SSC SSC1 gattc -W -z longDescriptor -s 0xA002 -c 0xC302 -d 0x2901 -p 0x10 -r -l 256" - ["R SSC1 C +GATTC:Write,ERROR"] - - - "SSC SSC1 gattc -W -z longDescriptor -s 0xA002 -c 0xC312 -d 0x2901 -p 0x10 -l 256" - - ["R SSC1 C +GATTC:Write,ERROR"] -- ID: BTSTK_GATT_25013 - <<: *GATT_CASE - test point 2: BLE GATT client do invalid write - summary: GATT client write with response to a char created by table not send response - steps: | - 1. DUT1 do service discovery - 2. DUT1 write with response to auto reply char created by table not send response - 3. DUT1 write with response to app reply char created by table not send response - expected result: | - 1. succeed - 2. succeed(BLE Spec do not define the behavior of this case. IDF implementation will return success when GATTC write with response and recv response from remote side) - 3. failed - initial condition: BLE_CONN3 - cmd set: - - "" - - *primary_service_discovery - - - "SSC SSC1 gattc -W -z char -s 0xA002 -c 0xC303 -p 0x10 -v 0x01" - - ["R SSC1 C +GATTC:Write,OK,0010,A002,C303"] - - - "SSC SSC1 gattc -W -z char -s 0xA002 -c 0xC313 -p 0x10 -v 0x01" + - - "SSC SSC1 gattc -W -z longDescriptor -s 0xA002 -c 0xC312 -d 0x2901 -p 0x10 -r -l 256" - ["R SSC1 C +GATTC:Write,ERROR"] - ID: BTSTK_GATT_25014 <<: *GATT_CASE @@ -1811,45 +1069,13 @@ test cases: 1. succeed 2. succeed (write without response always succeed) 3. succeed (write without response always succeed) - initial condition: BLE_CONN3 cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -W -z char -s 0xA002 -c 0xC302 -p 0x10 -v 0x01 -w 1" + - - "SSC SSC1 gattc -W -z char -s 0xA002 -c 0xC302 -p 0x10 -r -v 0x01 -w 1" - ["R SSC1 C +GATTC:Write,OK"] - - - "SSC SSC1 gattc -W -z char -s 0xA002 -c 0xC302 -p 0x10 -v 0x01 -w 1" + - - "SSC SSC1 gattc -W -z char -s 0xA002 -c 0xC302 -p 0x10 -r -v 0x01 -w 1" - ["R SSC1 C +GATTC:Write,OK"] -- ID: BTSTK_GATT_25015 - <<: *GATT_CASE - test point 2: BLE GATT client do invalid write - summary: GATT client use write API write to a char won't reply prepare write event - steps: | - 1. DUT1 do service discovery - 2. DUT1 use write API write to a char reply NULL for prepare write event - expected result: | - 1. succeed - 2. failed - cmd set: - - "" - - *primary_service_discovery - - - "SSC SSC1 gattc -W -z char -p 0x10 -s 0xA000 -c 0xC109 -l 256" - - ["R SSC1 C +GATTC:Write,ERROR"] -- ID: BTSTK_GATT_25016 - <<: *GATT_CASE - test point 2: BLE GATT client do invalid write - summary: GATT client write long char value length longer than max length - initial condition: BLE_CONN3 - steps: | - 1. DUT1 do service discovery - 2. DUT1 write char value - expected result: | - 1. succeed - 2. failed - cmd set: - - "" - - *primary_service_discovery - - - "SSC SSC1 gattc -W -z longChar -s 0xA002 -c 0xC304 -p 0x10 -l 260" - - ["P SSC1 C +GATTC:Write,ERROR"] - ID: BTSTK_GATT_25017 <<: *GATT_CASE test point 2: BLE GATT client do invalid write @@ -1864,60 +1090,8 @@ test cases: cmd set: - "" - *primary_service_discovery - - - "SSC SSC1 gattc -W -z char -s 0xA002 -c 0xC302 -l 2" + - - "SSC SSC1 gattc -W -z char -s 0xA002 -c 0xC302 -l 2 -r " - ["P SSC1 C +GATTC:Write,ERROR"] -- ID: BTSTK_GATT_26001 - <<: *GATT_CASE - test point 2: BLE GATT client set mtu - summary: GATT client config different mtu size - steps: | - 1. set mtu size 22 - 2. set mtu size 23 - 3. set mtu size 517 - 4. set mtu size 518 - expected result: | - 1. failed - 2. succeed - 3. succeed - 4. failed - cmd set: - - "" - - - "SSC SSC1 bleconn -D -p 0x10" - - ["P SSC1 C +BLE:GattcDisconnect,OK", "P SSC2 C +BLE:GattsDisconnect,OK"] - - - "SSC SSC1 gattc -S -m 22 " - - ["R SSC1 C +GATTC:ERROR"] - - - "SSC SSC1 gattc -S -m 23" - - ["R SSC1 C +GATTC:OK"] - - - "SSC SSC1 gattc -S -m 517" - - ["R SSC1 C +GATTC:OK"] - - - "SSC SSC1 gattc -S -m 518" - - ["R SSC1 C +GATTC:ERROR"] -- ID: BTSTK_GATT_26002 - <<: *GATT_CASE - test point 2: BLE GATT server set mtu - summary: GATT server config different mtu size - steps: | - 1. set mtu size 22 - 2. set mtu size 23 - 3. set mtu size 517 - 4. set mtu size 518 - expected result: | - 1. failed - 2. succeed - 3. succeed - 4. failed - cmd set: - - "" - - - "SSC SSC1 bleconn -D -p 0x10" - - ["P SSC1 C +BLE:GattcDisconnect,OK", "P SSC2 C +BLE:GattsDisconnect,OK"] - - - "SSC SSC2 gatts -C -m 22" - - ["R SSC2 C +GATTS:ERROR"] - - - "SSC SSC2 gatts -C -m 23" - - ["R SSC2 C +GATTS:OK"] - - - "SSC SSC2 gatts -C -m 517" - - ["R SSC2 C +GATTS:OK"] - - - "SSC SSC2 gatts -C -m 518" - - ["R SSC2 C +GATTS:ERROR"] - ID: BTSTK_GATT_26003 <<: *GATT_CASE test point 2: BLE GATT config mtu @@ -1930,8 +1104,8 @@ test cases: 2. succeed cmd set: - "" - - - "SSC SSC1 bleconn -D -p 0x10" - - ["P SSC1 C +BLE:GattcDisconnect,OK", "P SSC2 C +BLE:GattsDisconnect,OK"] + - - "SSC SSC1 bleconn -D -z all" + - ["P SSC1 C +BLECONN:GapDisconnect,OK", "P SSC2 C +BLECONN:GapDisconnect,OK"] - - "SSC SSC1 gattc -S -m 365" - ["R SSC1 C +GATTC:OK"] - - "SSC SSC2 gatts -C -m 261" @@ -1939,149 +1113,9 @@ test cases: - - "SSC SSC2 bleadv -D -z start" - ['R SSC2 C +BLEADV:OK'] - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ['R SSC1 C +BLE:GattcConnect,OK', 'R SSC2 C +BLE:GattsConnect'] - - - "SSC SSC1 gattc -C" + - ['R SSC1 C +BLECONN:GapConnect,OK', 'R SSC2 C +BLECONN:GapConnect,OK'] + - - "SSC SSC1 gattc -C -r " - ["R SSC1 C +GATTC:OK","P SSC[1-2] C ConfigMTU,OK,261"] -- ID: BTSTK_GATT_26004 - <<: *GATT_CASE - test point 2: BLE GATT client config mtu - summary: GATT read write on mtu size 261 - allow fail: 1/2 - steps: | - 1. config mtu size 261 - 2. do read - 3. do write - expected result: | - 1. succeed - 2. succeed - 3. succeed - cmd set: - - "" - - - "SSC SSC1 bleconn -D -p 0x10" - - ["P SSC1 C +BLE:GattcDisconnect,OK", "P SSC2 C +BLE:GattsDisconnect,OK"] - - - "SSC SSC1 gattc -S -m 261" - - ["R SSC1 C +GATTC:OK"] - - - "SSC SSC2 gatts -C -m 261" - - ["R SSC2 C +GATTS:OK"] - - - "SSC SSC2 bleadv -D -z start" - - ['R SSC2 C +BLEADV:OK'] - - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ['R SSC1 C +BLE:GattcConnect,OK', 'R SSC2 C +BLE:GattsConnect'] - - - "SSC SSC1 gattc -C" - - ["R SSC1 C +GATTC:OK","P SSC[1-2] C ConfigMTU,OK,261"] - - *primary_service_discovery - - - "SSC SSC1 gattc -R -z char -p 0x10 -s 0xA000 -c 0xC101" - - ["R SSC1 C +GATTC:ReadOnce,0010,A000,C101,256"] - - - "SSC SSC1 gattc -W -z char -p 0x10 -s 0xA000 -c 0xC109 -l 256" - - ["R SSC1 C +GATTC:WriteOnce,0010,A000,C109"] - - - "SSC SSC1 gattc -W -z longChar -p 0x10 -s 0xA000 -c 0xC110 -l 512" - - ["R SSC1 C +GATTC:Write,OK,0010,A000,C110", "P SSC2 C +GATTS:ReliableWrite,OK"] -- ID: BTSTK_GATT_26005 - <<: *GATT_CASE - test point 2: BLE GATT client config mtu - summary: GATT read write on mtu size 517 - allow fail: 1/2 - steps: | - 1. config mtu size 517 - 2. do read - 3. do write - expected result: | - 1. succeed - 2. succeed - 3. succeed - cmd set: - - "" - - - "SSC SSC1 bleconn -D -p 0x10" - - ["P SSC1 C +BLE:GattcDisconnect,OK", "P SSC2 C +BLE:GattsDisconnect,OK"] - - - "SSC SSC1 gattc -S -m 517" - - ["R SSC1 C +GATTC:OK"] - - - "SSC SSC2 gatts -C -m 517" - - ["R SSC2 C +GATTS:OK"] - - - "SSC SSC2 bleadv -D -z start" - - ['R SSC2 C +BLEADV:OK'] - - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ['R SSC1 C +BLE:GattcConnect,OK', 'R SSC2 C +BLE:GattsConnect'] - - - "SSC SSC1 gattc -C" - - ["P SSC1 C +GATTC:OK", "P SSC[1-2] C ConfigMTU,OK,517"] - - *primary_service_discovery - - - "SSC SSC1 gattc -R -z char -p 0x10 -s 0xA000 -c 0xC101" - - ["R SSC1 C +GATTC:ReadOnce,0010,A000,C101,256"] - - - "SSC SSC1 gattc -W -z char -p 0x10 -s 0xA000 -c 0xC109 -l 256" - - ["R SSC1 C +GATTC:WriteOnce,0010,A000,C109"] - - - "SSC SSC1 gattc -W -z char -p 0x10 -s 0xA000 -c 0xC109 -l 512" - - ["R SSC1 C +GATTC:WriteOnce,0010,A000,C109"] -- ID: BTSTK_GATT_27001 - <<: *GATT_CASE - test point 2: BLE GATT read multiple - summary: GATT client read 2 char and 11 char of same service - steps: | - 1. DUT1 do discover - 2. GATT client read 2 char - 3. GATT client read 11 char - expected result: | - 1. succeed - 2. succeed - 3. succeed - cmd set: - - "" - - *primary_service_discovery - - - "SSC SSC1 gattc -R -z multiple -u #0xC100##0xC101# -s 0xA000" - - ['R SSC1 C +GATTC:ReadOnce,22', 'R SSC1 C +GATTC:ReadMultiple,OK'] - - - "SSC SSC1 gattc -R -z multiple -u #0xC100##0xC101##0xC107##0xC108##0xC109##0xC110##0xC100##0xC101##0xC107##0xC108##0xC109# -s 0xA000" - - ['R SSC1 C +GATTC:Read,ERROR'] -- ID: BTSTK_GATT_27002 - <<: *GATT_CASE - test point 2: BLE GATT read multiple - summary: GATT client read char and descriptor - steps: | - 1. DUT1 do discover - 2. GATT client read all char and descriptor - expected result: | - 1. succeed - 2. succeed - cmd set: - - "" - - *primary_service_discovery - - - "SSC SSC1 gattc -R -z multiple -u 0xA00xC100#0xA00xC101#0xA00xC1000x29010xA00xC1070x2902" - - ['R SSC1 C +GATTC:ReadOnce', 'R SSC1 C +GATTC:ReadMultiple,OK'] -- ID: BTSTK_GATT_27003 - <<: *GATT_CASE - test point 2: BLE GATT read multiple - summary: GATT client read char and descriptor of table create service - steps: | - 1. DUT1 do discover - 2. GATT client read all char and descriptor - expected result: | - 1. succeed - 2. succeed - cmd set: - - "" - - - "SSC SSC2 gatts -S -z load -p 0xA2" - - ['R SSC2 C +GATTS:StartService,OK,A002'] - - *primary_service_discovery - - - "SSC SSC1 gattc -R -z multiple -u 0xA20xC300#0xA20xC301#0xA20xC310#0xA20xC311#" - - ['R SSC1 C +GATTC:ReadOnce', 'R SSC1 C +GATTC:ReadMultiple,OK'] -- ID: BTSTK_GATT_27004 - <<: *GATT_CASE - test point 2: BLE GATT read multiple - summary: GATT client read char and descriptor of included service and table service - initial condition: BLE_INIT2 - steps: | - 1. DUT2 load service included service and table service - 2. DUT1 search service - 3. GATT client read all char and descriptor of different services - expected result: | - 1. succeed - 2. succeed - 3. succeed - cmd set: - - "" - - - "SSC SSC2 gatts -S -z load -p 0xA2" - - ['R SSC2 C +GATTS:StartService,OK,A002'] - - *included_primary_service_connection - - *primary_service_discovery - - - "SSC SSC1 gattc -R -z multiple -u 0xA10xC200#0xA00xC100#0xA00xC101#0xA20xC300#0xA20xC301#" - - ['R SSC1 C +GATTC:ReadOnce', 'R SSC1 C +GATTC:ReadMultiple,OK'] - ID: BTSTK_GATT_30001 <<: *GATT_CASE test point 2: BLE GATT multi connection service discovery test @@ -2092,6 +1126,7 @@ test cases: 1. succeed initial condition: BLE_CONN5 test environment: SSC_T5_1 + allow fail: 3/5 cmd set: - "" - - LOOP 4 1 "[2,3,4,5]" @@ -2108,6 +1143,7 @@ test cases: 1. succeed initial condition: BLE_CONN6 test environment: SSC_T5_1 + allow fail: 3/5 cmd set: - "" - - "SSC SSC[2-5] gattc -D -z primaryService -p 0x10 -r " @@ -2124,6 +1160,7 @@ test cases: 2. succeed initial condition: BLE_CONN7 test environment: SSC_T5_1 + allow fail: 3/5 cmd set: - "" - - LOOP 2 1 "[2,3]" @@ -2132,23 +1169,6 @@ test cases: - ["R SSC1 C +GATTC:Discover,OK"] - - "SSC SSC[4-5] gattc -D -z primaryService -p 0x10 -r " - ["R SSC[4-5] C +GATTC:Discover,OK"] -- ID: BTSTK_GATT_30004 - <<: *GATT_CASE - test point 2: BLE GATT multi connection service discovery test - summary: do primary service discovery when master and slave both create GATTC and GATTS - steps: | - 1. DUT1 do primary service discovery for DUT2 - 2. DUT2 do primary service discovery for DUT1 - expected result: | - 1. succeed - 2. succeed - initial condition: BLE_CONN4 - cmd set: - - "" - - - "SSC SSC1 gattc -D -z primaryService -p 0x10 -r " - - ["R SSC1 C +GATTC:Discover,OK"] - - - "SSC SSC2 gattc -D -z primaryService -p 0x10 -r " - - ["R SSC2 C +GATTC:Discover,OK"] - ID: BTSTK_GATT_31001 <<: *GATT_CASE test point 2: BLE GATT multi connection read test @@ -2163,6 +1183,7 @@ test cases: 3. succeed initial condition: BLE_CONN5 test environment: SSC_T5_1 + allow fail: 3/5 cmd set: - "" - - LOOP 4 3 "[2,3,4,5]" "[2,3,4,5]" "[2,3,4,5]" @@ -2183,6 +1204,7 @@ test cases: 1. succeed initial condition: BLE_CONN6 test environment: SSC_T5_1 + allow fail: 3/5 cmd set: - "" - - "SSC SSC[2-5] gattc -D -z primaryService -p 0x10 -r " @@ -2207,6 +1229,7 @@ test cases: 4. succeed initial condition: BLE_CONN7 test environment: SSC_T5_1 + allow fail: 3/5 cmd set: - "" - - LOOP 2 3 "[2,3]" "[2,3]" "[2,3]" @@ -2223,29 +1246,6 @@ test cases: - ["R SSC[4-5] C +GATTC:ReadOnce,0010,A002,C300,1"] - - "SSC SSC[4-5] gattc -R -z char -s 0xA002 -c 0xC301 -p 0x10 -r " - ["R SSC[4-5] C +GATTC:ReadOnce,0010,A002,C301,256"] -- ID: BTSTK_GATT_31004 - <<: *GATT_CASE - test point 2: BLE GATT multi connection read test - summary: do read when master and slave both create GATTC and GATTS - steps: | - 1. DUT1 do primary service discovery for DUT2 - 2. DUT2 do primary service discovery for DUT1 - 3. DUT1 do read on DUT2 - 4. DUT2 do read on DUT1 - expected result: | - 1. succeed - 2. succeed - 3. succeed - 4. succeed - initial condition: BLE_CONN4 - cmd set: - - "" - - - "SSC SSC[1-2] gattc -D -z primaryService -p 0x10 -r " - - ["R SSC[1-2] C +GATTC:Discover,OK"] - - - "SSC SSC[1-2] gattc -R -z char -s 0xA002 -c 0xC300 -p 0x10 -r " - - ["R SSC[1-2] C +GATTC:ReadOnce,0010,A002,C300,1"] - - - "SSC SSC[1-2] gattc -R -z char -s 0xA002 -c 0xC301 -p 0x10 -r " - - ["R SSC[1-2] C +GATTC:ReadOnce,0010,A002,C301,256"] - ID: BTSTK_GATT_32001 <<: *GATT_CASE test point 2: BLE GATT multi connection write test @@ -2260,6 +1260,7 @@ test cases: 3. succeed initial condition: BLE_CONN5 test environment: SSC_T5_1 + allow fail: 3/5 cmd set: - "" - - LOOP 4 3 "[2,3,4,5]" "[2,3,4,5]" "[2,3,4,5]" @@ -2280,6 +1281,7 @@ test cases: 1. succeed initial condition: BLE_CONN6 test environment: SSC_T5_1 + allow fail: 3/5 cmd set: - "" - - "SSC SSC[2-5] gattc -D -z primaryService -p 0x10 -r " @@ -2304,6 +1306,7 @@ test cases: 4. succeed initial condition: BLE_CONN7 test environment: SSC_T5_1 + allow fail: 3/5 cmd set: - "" - - LOOP 2 3 "[2,3]" "[2,3]" "[2,3]" @@ -2320,29 +1323,6 @@ test cases: - ["R SSC[4-5] C +GATTC:Write,OK,0010,A002,C302"] - - "SSC SSC[4-5] gattc -W -z char -s 0xA002 -c 0xC304 -l 256 -p 0x10 -r " - ["R SSC[4-5] C +GATTC:Write,OK,0010,A002,C304"] -- ID: BTSTK_GATT_32004 - <<: *GATT_CASE - test point 2: BLE GATT multi connection write test - summary: do write when master and slave both create GATTC and GATTS - steps: | - 1. DUT1 do primary service discovery for DUT2 - 2. DUT2 do primary service discovery for DUT1 - 3. DUT1 do write on DUT2 - 4. DUT2 do write on DUT1 - expected result: | - 1. succeed - 2. succeed - 3. succeed - 4. succeed - initial condition: BLE_CONN4 - cmd set: - - "" - - - "SSC SSC[1-2] gattc -D -z primaryService -p 0x10 -r " - - ["R SSC[1-2] C +GATTC:Discover,OK"] - - - "SSC SSC[1-2] -W -z char -s 0xA002 -c 0xC302 -l 1 -p 0x10 -r " - - ["R SSC[1-2] C +GATTC:Write,OK,0010,A002,C302"] - - - "SSC SSC[1-2] -W -z char -s 0xA002 -c 0xC304 -l 256 -p 0x10 -r " - - ["R SSC[1-2] C +GATTC:Write,OK,0010,A002,C304"] - ID: BTSTK_GATT_33001 <<: *GATT_CASE test point 2: BLE GATT multi connection notify test @@ -2357,16 +1337,17 @@ test cases: 3. DUT1 receive notification on DUT[2-5] initial condition: BLE_CONN5 test environment: SSC_T5_1 + allow fail: 3/5 cmd set: - "" - - - LOOP 4 2 "[2,3,4,5]" "[2,3,4,5]" + - - LOOP 4 3 "[2,3,4,5]" "[2,3,4,5]" "[2,3,4,5]" "[2,3,4,5]" - "" - - "SSC SSC1 gattc -D -z primaryService -p 0x10 -r " - ["R SSC1 C +GATTC:Discover,OK"] - - "SSC SSC1 gattc -N -z register -s 0xA002 -c 0xC305 -p 0x10 -r " - ["R SSC1 C +GATTC:RegNotify,OK,0010,A002,C305"] - - - "SSC SSC[2-5] gatts -N -c 0xC305 -l 1 -p 0xA2 -r " - - ['P SSC1 RE "\+GATTC:Notification,0010,A002,C305,1,%%s"%%()'] + - - "SSC SSC{%d} gatts -N -c 0xC305 -l 1 -p 0xA2 -r " + - ['P SSC1 RE "\+GATTC:Notification,0010,A002,C305,1,%%s"%%()'] - ID: BTSTK_GATT_33002 <<: *GATT_CASE test point 2: BLE GATT multi connection notify test @@ -2381,6 +1362,7 @@ test cases: 3. DUT[2-5] receive notification initial condition: BLE_CONN6 test environment: SSC_T5_1 + allow fail: 3/5 cmd set: - "" - - "SSC SSC[2-5] gattc -D -z primaryService -p 0x10 -r " @@ -2411,6 +1393,7 @@ test cases: 6. DUT[4-5] receive notify initial condition: BLE_CONN7 test environment: SSC_T5_1 + allow fail: 3/5 cmd set: - "" - - LOOP 2 2 "[2,3]" "[2,3]" @@ -2429,29 +1412,6 @@ test cases: - [''] - - "SSC SSC1 gatts -N -c 0xC305 -l 1 -p 0xA2 -r " - ['P SSC{%d} RE "\+GATTC:Notification,0010,A002,C305,1,%%s"%%()'] -- ID: BTSTK_GATT_33004 - <<: *GATT_CASE - test point 2: BLE GATT multi connection notify test - summary: do notify when master and slave both create GATTC and GATTS - steps: | - 1. DUT1 do primary service discovery for DUT2 - 2. DUT2 do primary service discovery for DUT1 - 3. DUT[1-2] do register notify - 4. DUT1 and DUT2 send notify to each other - expected result: | - 1. succeed - 2. succeed - 3. succeed - 4. receive notification - initial condition: BLE_CONN4 - cmd set: - - "" - - - "SSC SSC[1-2] gattc -D -z primaryService -p 0x10 -r " - - ["R SSC[1-2] C +GATTC:Discover,OK"] - - - "SSC SSC[1-2] gattc -N -z register -s 0xA002 -c 0xC305 -p 0x10 -r " - - ["R SSC[1-2] C +GATTC:RegNotify,OK,0010,A002,C305"] - - - "SSC SSC[1-2] gatts -N -c 0xC305 -l 1 -p 0xA2 -r " - - ['P SSC[1,2] RE "\+GATTC:Notification,0010,A002,C305,1,%%s"%%()'] - ID: BTSTK_GATT_34001 <<: *GATT_CASE test point 2: BLE GATT multi connection indicate test @@ -2466,6 +1426,7 @@ test cases: 3. DUT1 receive indication on DUT[2-5] initial condition: BLE_CONN5 test environment: SSC_T5_1 + allow fail: 3/5 cmd set: - "" - - LOOP 4 2 "[2,3,4,5]" "[2,3,4,5]" @@ -2490,6 +1451,7 @@ test cases: 3. DUT[2-5] receive indication initial condition: BLE_CONN6 test environment: SSC_T5_1 + allow fail: 3/5 cmd set: - "" - - "SSC SSC[2-5] gattc -D -z primaryService -p 0x10 -r " @@ -2520,6 +1482,7 @@ test cases: 6. DUT[4-5] receive indication initial condition: BLE_CONN7 test environment: SSC_T5_1 + allow fail: 3/5 cmd set: - "" - - LOOP 2 2 "[2,3]" "[2,3]" @@ -2538,151 +1501,6 @@ test cases: - [''] - - "SSC SSC1 gatts -I -c 0xC306 -l 1 -p 0xA2 -r " - ['P SSC{%d} RE "\+GATTC:Indication,0010,A002,C306,1,%%s"%%()'] -- ID: BTSTK_GATT_34004 - <<: *GATT_CASE - test point 2: BLE GATT multi connection indicate test - summary: do indicate when master and slave both create GATTC and GATTS - steps: | - 1. DUT1 do primary service discovery for DUT2 - 2. DUT2 do primary service discovery for DUT1 - 3. DUT[1-2] do register indication - 4. DUT1 and DUT2 send notify to each other - expected result: | - 1. succeed - 2. succeed - 3. succeed - 4. receive indication - initial condition: BLE_CONN4 - cmd set: - - "" - - - "SSC SSC[1-2] gattc -D -z primaryService -p 0x10 -r " - - ["R SSC[1-2] C +GATTC:Discover,OK"] - - - "SSC SSC[1-2] gattc -N -z register -s 0xA002 -c 0xC306 -p 0x10 -r " - - ["R SSC[1-2] C +GATTC:RegNotify,OK,0010,A002,C306"] - - - "SSC SSC[1-2] gatts -I -c 0xC306 -l 1 -p 0xA2 -r " - - ['P SSC[1,2] RE "\+GATTC:Indication,0010,A002,C306,1,%%s"%%()'] -- ID: BTSTK_GATT_40001 - <<: *GATT_CASE - auto test: 'No' - test point 2: test if BLE work after switch off some sub modules - summary: GATTC only and GATTS only test - steps: | - 1. download GATTC only bin to DUT1 and GATTS only bin to DUT2 - 2. DUT2 start adv, enable service 0xA000, DUT1 connect to DUT2 - 3. DUT1 connect to DUT2 - 4. DUT1 do primary service discovery - 5. DUT1 do read - 6. DUT1 do read descriptor - 7. DUT1 do write - 8. DUT1 do write descriptor - 9. DUT1 register for notify and indication - 10. DUT2 do notify - 11. DUT2 do indicate - expected result: | - 1. succeed - 2. succeed - 3. succeed - 4. succeed - 5. succeed - 6. succeed - 7. succeed - 8. succeed - 9. succeed - 10. succeed - 11. succeed - initial condition: None - execution time: 5 - CI ready: 'No' - cmd set: - - "" - - - SSC SSC[1-2] reboot - - ['R SSC[1-2] C !!!ready!!!'] - - - SSC SSC[1-2] ble -R - - ['R SSC[1-2] C +BLE:OK'] - - - SSC SSC2 bleadv -D -z start - - ['R SSC2 C +BLEADV:OK'] - - - SSC SSC2 gatts -S -z load -p 0xA0 - - ['R SSC2 C +GATTS:StartService,OK,A000'] - - - SSC SSC1 bleconn -C -p 0x10 -a - - ['R SSC1 C +BLE:GattcConnect,OK', 'R SSC2 C +BLE:GattsConnect'] - - *primary_service_discovery - - - "SSC SSC1 gattc -R -z char -s 0xA000 -c 0xC100 -p 0x10" - - ["R SSC1 C +GATTC:ReadOnce,0010,A000,C100,1", "R SSC1 C +GATTC:Read,OK,0010,A000,C100"] - - - "SSC SSC1 gattc -W -z char -s 0xA000 -c 0xC102 -p 0x10 -v 0x01" - - ["R SSC1 C +GATTC:WriteOnce,0010,A000,C102", "R SSC1 C +GATTC:Write,OK,0010,A000,C102"] - - - "SSC SSC1 gattc -R -z descriptor -s 0xA000 -c 0xC100 -d 0x2901 -p 0x10" - - ["R SSC1 C +GATTC:ReadOnce,0010,A000,C100,2901,256", "R SSC1 C +GATTC:ReadDescriptor,OK,0010,A000,C100,2901"] - - - "SSC SSC1 gattc -W -z descriptor -s 0xA000 -c 0xC107 -d 0x2902 -p 0x10 -v 0x0100" - - ["R SSC1 C +GATTC:WriteOnce,0010,A000,C107,2902", "R SSC1 C +GATTC:WriteDescriptor,OK,0010,A000,C107,2902"] - - *register_notify_c107 - - *register_indicate_c108 - - - "SSC SSC1 gattc -W -z descriptor -s 0xA000 -c 0xC107 -d 0x2902 -p 0x10 -v 0x0300 -n 1" - - ["R SSC1 C +GATTC:WriteOnce,0010,A000,C107,2902", "R SSC1 C +GATTC:WriteDescriptor,OK,0010,A000,C107,2902"] - - - "SSC SSC2 gatts -N -c 0xC107 -p 0xA0 -v 0x01" - - ["P SSC2 C +GATTS:Done,Notify,A000,C107", "P SSC1 C +GATTC:Notification,0010,A000,C107,1"] - - - "SSC SSC2 gatts -I -c 0xC108 -p 0xA0 -v 0x01" - - ["P SSC2 C +GATTS:Done,Indicate,A000,C108", "P SSC1 C +GATTC:Indication,0010,A000,C108,1"] -- ID: BTSTK_GATT_40002 - <<: *GATT_CASE - auto test: 'No' - test point 2: test if BLE work after switch off some sub modules - summary: GATTC_SMP only and GATTS_SMP only test - steps: | - 1. download GATTC_SMP bin to DUT1 and GATTS_SMP bin to DUT2 - 2. DUT2 start adv, start service 0xA000, DUT1 connect to DUT2 - 3. DUT1 connect to DUT2 - 4. DUT1 do primary service discovery - 5. DUT1 do read - 6. DUT1 do read descriptor - 7. DUT1 do write - 8. DUT1 do write descriptor - 9. DUT1 register for notify and indication - 10. DUT2 do notify - 11. DUT2 do indicate - expected result: | - 1. succeed - 2. succeed - 3. succeed - 4. succeed - 5. succeed - 6. succeed - 7. succeed - 8. succeed - 9. succeed - 10. succeed - 11. succeed - initial condition: None - execution time: 5 - CI ready: 'No' - cmd set: - - "" - - - SSC SSC[1-2] reboot - - ['R SSC[1-2] C !!!ready!!!'] - - - SSC SSC[1-2] ble -R - - ['R SSC[1-2] C +BLE:OK'] - - - SSC SSC2 bleadv -D -z start - - ['R SSC2 C +BLEADV:OK'] - - - SSC SSC2 gatts -S -z load -p 0xA0 - - ['R SSC2 C +GATTS:StartService,OK,A000'] - - - SSC SSC1 bleconn -C -p 0x10 -a - - ['R SSC1 C +BLE:GattcConnect,OK', 'R SSC2 C +BLE:GattsConnect'] - - *primary_service_discovery - - - "SSC SSC1 gattc -R -z char -s 0xA000 -c 0xC100 -p 0x10" - - ["R SSC1 C +GATTC:ReadOnce,0010,A000,C100,1", "R SSC1 C +GATTC:Read,OK,0010,A000,C100"] - - - "SSC SSC1 gattc -W -z char -s 0xA000 -c 0xC102 -p 0x10 -v 0x01" - - ["R SSC1 C +GATTC:WriteOnce,0010,A000,C102", "R SSC1 C +GATTC:Write,OK,0010,A000,C102"] - - - "SSC SSC1 gattc -R -z descriptor -s 0xA000 -c 0xC100 -d 0x2901 -p 0x10" - - ["R SSC1 C +GATTC:ReadOnce,0010,A000,C100,2901,256", "R SSC1 C +GATTC:ReadDescriptor,OK,0010,A000,C100,2901"] - - - "SSC SSC1 gattc -W -z descriptor -s 0xA000 -c 0xC107 -d 0x2902 -p 0x10 -v 0x0100" - - ["R SSC1 C +GATTC:WriteOnce,0010,A000,C107,2902", "R SSC1 C +GATTC:WriteDescriptor,OK,0010,A000,C107,2902"] - - *register_notify_c107 - - *register_indicate_c108 - - - "SSC SSC1 gattc -W -z descriptor -s 0xA000 -c 0xC107 -d 0x2902 -p 0x10 -v 0x0300 -n 1" - - ["R SSC1 C +GATTC:WriteOnce,0010,A000,C107,2902", "R SSC1 C +GATTC:WriteDescriptor,OK,0010,A000,C107,2902"] - - - "SSC SSC2 gatts -N -c 0xC107 -p 0xA0 -v 0x01" - - ["P SSC2 C +GATTS:Done,Notify,A000,C107", "P SSC1 C +GATTC:Notification,0010,A000,C107,1"] - - - "SSC SSC2 gatts -I -c 0xC108 -p 0xA0 -v 0x01" - - ["P SSC2 C +GATTS:Done,Indicate,A000,C108", "P SSC1 C +GATTC:Indication,0010,A000,C108,1"] - ID: BTSTK_GATT_50001 <<: *GATT_CASE category: Performance diff --git a/components/idf_test/integration_test/TC_IT_BTSTK_SMP.yml b/components/idf_test/integration_test/TC_IT_BTSTK_SMP.yml index a563f9bd59..bf81c2c83c 100644 --- a/components/idf_test/integration_test/TC_IT_BTSTK_SMP.yml +++ b/components/idf_test/integration_test/TC_IT_BTSTK_SMP.yml @@ -17,19 +17,15 @@ .just_work_pair: &just_work_pair LIST_MERGE: - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ['P SSC1 C +BLE:GattcConnect,OK', 'P SSC2 C +BLE:GattsConnect'] + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect,OK'] - - "SSC SSC2 blesmp -E -r -z Enc" - - ['P SSC1 C +BLESMP:SecReq'] - - - "SSC SSC1 blesmp -R -a 1 -r " - ['P SSC[1-2] C +BLESMP:AuthComplete,Success,0'] .slave_passkey_entry_pair: &slave_passkey_entry_pair LIST_MERGE: - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ['P SSC1 C +BLE:GattcConnect,OK', 'P SSC2 C +BLE:GattsConnect'] + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect,OK'] - - "SSC SSC2 blesmp -E -r -z Enc" - - ['P SSC1 C +BLESMP:SecReq'] - - - "SSC SSC1 blesmp -R -a 1 -r " - ['P SSC2 C +BLESMP:PassKeyReq', 'P SSC1 A :BLESMP:PassKeyNotify,(\d+)'] - - "SSC SSC2 blesmp -K -r -a 1 -k " - ['P SSC[1-2] C +BLESMP:AuthComplete,Success,0'] @@ -37,10 +33,8 @@ .master_passkey_entry_pair: &master_passkey_entry_pair LIST_MERGE: - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ['P SSC1 C +BLE:GattcConnect,OK', 'P SSC2 C +BLE:GattsConnect'] + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect,OK'] - - "SSC SSC2 blesmp -E -r -z Enc" - - ['P SSC1 C +BLESMP:SecReq'] - - - "SSC SSC1 blesmp -R -a 1 -r " - ['P SSC1 C +BLESMP:PassKeyReq', 'P SSC2 A :BLESMP:PassKeyNotify,(\d+)'] - - "SSC SSC1 blesmp -K -r -a 1 -k " - ['P SSC[1-2] C +BLESMP:AuthComplete,Success,0'] @@ -48,10 +42,8 @@ .both_side_passkey_entry_pair: &both_side_passkey_entry_pair LIST_MERGE: - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ['P SSC1 C +BLE:GattcConnect,OK', 'P SSC2 C +BLE:GattsConnect'] + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect,OK'] - - "SSC SSC2 blesmp -E -r -z Enc" - - ['P SSC1 C +BLESMP:SecReq'] - - - "SSC SSC1 blesmp -R -a 1 -r " - ['P SSC[1,2] C +BLESMP:PassKeyReq'] - - "SSC SSC[1,2] blesmp -K -r -a 1 -k 123456" - ['P SSC[1-2] C +BLESMP:AuthComplete,Success,0'] @@ -59,32 +51,28 @@ .numberic_comparision_pair: &numberic_comparision_pair LIST_MERGE: - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ['P SSC1 C +BLE:GattcConnect,OK', 'P SSC2 C +BLE:GattsConnect'] + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect,OK'] - - "SSC SSC2 blesmp -E -r -z Enc" - - ['P SSC1 C +BLESMP:SecReq'] - - - "SSC SSC1 blesmp -R -a 1 -r " - ['R SSC2 A :BLESMP:NCReq,(\d+)', 'R SSC1 C NCReq P '] - - "SSC SSC[1-2] blesmp -C -r -a 1" - ['P SSC[1-2] C +BLESMP:AuthComplete,Success,0'] .check_connection: &check_connection LIST_MERGE: - - - "SSC SSC1 gattc -D -z primaryService -p 0x10" - - ["R SSC1 C +GATTC:DiscoverService,A002"] + - - "SSC SSC1 gattc -D -z primaryService -p 0x10 -r " + - ["R SSC1 C +GATTC:Discover,OK"] .disconnect: &disconnect LIST_MERGE: - - "SSC SSC1 bleconn -D -z all" - - ['P SSC1 C +BLE:GattcDisconnect', 'P SSC2 C +BLE:GattsDisconnect'] + - ['P SSC1 C +BLECONN:GapDisconnect,OK', 'P SSC2 C +BLECONN:GapDisconnect,OK'] - - "SSC SSC2 bleadv -D -z start" - ['P SSC2 C +BLEADV:OK'] -.start_pair: &start_pair +.connect: &connect LIST_MERGE: - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ['P SSC1 C +BLE:GattcConnect,OK', 'P SSC2 C +BLE:GattsConnect'] - - - "SSC SSC2 blesmp -E -r -z Enc" - - ['P SSC1 C +BLESMP:SecReq'] + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect,OK'] .config_just_work: &config_just_work LIST_MERGE: @@ -1657,138 +1645,10 @@ test cases: - "" - *config_just_work - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ['P SSC1 C +BLE:GattcConnect,OK', 'P SSC2 C +BLE:GattsConnect'] + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect,OK'] - - "SSC SSC1 blesmp -E -r -z Enc" - - ['P SSC2 C +BLESMP:SecReq'] - - - "SSC SSC2 blesmp -R -a 1 -r " - ['P SSC[1-2] C +BLESMP:AuthComplete,Success,0'] - *check_connection -- ID: BTSTK_SMP_04001 - <<: *SMP_CASE - test point 2: BLE SMP key test - summary: BLE SMP set key size less than required - allow fail: 1/2 - steps: | - 1. set key size 7 - 2. set key size 6 - 3. do just work pair - expected result: | - 1. succeed - 2. LTK size is 7 - 3. succeed - cmd set: - - "" - - *config_numberic_comparision - - - "SSC SSC1 blesmp -S -z KeySize -v 0x07" - - ['P SSC1 C +BLESMP:OK'] - - - "SSC SSC1 blesmp -S -z KeySize -v 0x06" - - ['P SSC1 C +BLESMP:OK'] - - *start_pair - - - "SSC SSC1 blesmp -R -a 1 -r " - - ['R SSC2 A :BLESMP:NCReq,(\d+)', 'R SSC1 C NCReq P '] - - - "SSC SSC[1-2] blesmp -C -r -a 1" - - ['P SSC[1-2] C +BLESMP:Key,LocalLTK,16 C +BLESMP:AuthComplete,Success,0'] -- ID: BTSTK_SMP_04002 - <<: *SMP_CASE - test point 2: BLE SMP key test - summary: BLE SMP set key size greater than required - allow fail: 1/2 - steps: | - 1. set key size 16 - 2. set key size 17 - 3. do just work pair - expected result: | - 1. succeed - 2. LTK size is 17 - 3. succeed - cmd set: - - "" - - *config_numberic_comparision - - - "SSC SSC1 blesmp -S -z KeySize -v 0x10" - - ['P SSC1 C +BLESMP:OK'] - - - "SSC SSC1 blesmp -S -z KeySize -v 0x11" - - ['P SSC1 C +BLESMP:OK'] - - *start_pair - - - "SSC SSC1 blesmp -R -a 1 -r " - - ['R SSC2 A :BLESMP:NCReq,(\d+)', 'R SSC1 C NCReq P '] - - - "SSC SSC[1-2] blesmp -C -r -a 1" - - ['P SSC[1-2] C +BLESMP:Key,LocalLTK,16 C +BLESMP:AuthComplete,Success,0'] -- ID: BTSTK_SMP_05001 - <<: *SMP_CASE - test point 2: BLE SMP unsuccessful pair reply test - summary: BLE SMP unsuccessful passkey entry test - steps: | - 1. enter passkey entry phase - 2. entry incorrect passkey and accept - 3. enter passkey entry phase - 4. entry correct passkey and reject - 5. enter passkey entry phase - 6. send numberic comparision accept - 7. enter passkey entry phase - 8. send numberic comparision reject - expected result: | - 1. succeed - 2. pair failed - 3. succeed - 4. pair failed - 5. succeed - 6. pair failed - 7. succeed - 8. pair failed - cmd set: - - "" - - *config_slave_passkey_entry - - - LOOP 2 6 "[1,0]" "['000001','']" - - "" - - *start_pair - - - "SSC SSC1 blesmp -R -a 1 -r " - - ['P SSC2 C +BLESMP:PassKeyReq', 'P SSC1 A :BLESMP:PassKeyNotify,(\d+)'] - - - "SSC SSC2 blesmp -K -r -a {%d} -k {%s}" - - ['P SSC[1-2] C +BLESMP:AuthComplete,Fail'] - - *disconnect - - - LOOP 2 6 "[1,0]" - - "" - - *start_pair - - - "SSC SSC1 blesmp -R -a 1 -r " - - ['P SSC2 C +BLESMP:PassKeyReq', 'P SSC1 A :BLESMP:PassKeyNotify,(\d+)'] - - - "SSC SSC[1-2] blesmp -C -r -a {%d}" - - ['P SSC[1-2] C +BLESMP:AuthComplete,Fail'] - - *disconnect -- ID: BTSTK_SMP_05002 - <<: *SMP_CASE - test point 2: BLE SMP unsuccessful pair reply test - summary: BLE SMP unsuccessful numberic comparision test - steps: | - 1. enter numberic comparision phase - 2. entry passkey and accept - 3. enter numberic comparision phase - 4. send numberic comparision reject - expected result: | - 1. succeed - 2. pair failed - 3. succeed - 4. pair failed - cmd set: - - "" - - *config_numberic_comparision - - - LOOP 2 7 "[1,0]" - - "" - - *start_pair - - - "SSC SSC1 blesmp -R -a 1 -r " - - ['R SSC2 A :BLESMP:NCReq,(\d+)', 'R SSC1 C NCReq P '] - - - "SSC SSC2 blesmp -K -r -a {%d} -k 000001" - - [] - - - DELAY 10 - - ['P SSC[1-2] C +BLESMP:AuthComplete,Fail'] - - *disconnect - - - LOOP 2 6 "[1,0]" "[0,1]" - - "" - - *start_pair - - - "SSC SSC1 blesmp -R -a 1 -r " - - ['R SSC2 A :BLESMP:NCReq,(\d+)', 'R SSC1 C NCReq P '] - - - "SSC SSC[1,2] blesmp -C -r -a [{%d},{%d}]" - - ['P SSC[1-2] C +BLESMP:AuthComplete,Fail'] - - *disconnect - ID: BTSTK_SMP_05003 <<: *SMP_CASE test point 2: BLE SMP unsuccessful pair reply test @@ -1814,18 +1674,18 @@ test cases: cmd set: - "" - *config_both_side_passkey_entry - - - LOOP 2 6 "[1,0]" "['000002','000001']" + - - LOOP 2 5 "[1,0]" "['000002','000001']" - "" - - *start_pair - - - "SSC SSC1 blesmp -R -a 1 -r " + - *connect + - - "SSC SSC2 blesmp -E -r -z Enc" - ['R SSC[1,2] C +BLESMP:PassKeyReq'] - - "SSC SSC2 blesmp -K -r -a [1,{%d}] -k [000001,{%s}]" - ['P SSC[1-2] C +BLESMP:AuthComplete,Fail'] - *disconnect - - - LOOP 2 6 "[1,0]" "[0,1]" + - - LOOP 2 5 "[1,0]" "[0,1]" - "" - - *start_pair - - - "SSC SSC1 blesmp -R -a 1 -r " + - *connect + - - "SSC SSC2 blesmp -E -r -z Enc" - ['P SSC[1,2] C +BLESMP:PassKeyReq'] - - "SSC SSC[1,2] blesmp -C -r -a [{%d},{%d}]" - ['P SSC[1-2] C +BLESMP:AuthComplete,Fail'] @@ -1854,82 +1714,14 @@ test cases: 8. succeed cmd set: - "" - - *start_pair - - - "SSC SSC1 blesmp -R -a 0 -r " + - *connect + - - "SSC SSC2 blesmp -E -r -z Enc" - [""] - *disconnect - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ['P SSC1 C +BLE:GattcConnect,OK', 'P SSC2 C +BLE:GattsConnect'] + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect,OK'] - - "SSC SSC1 blesmp -E -r -z Enc" - - ['P SSC2 C +BLESMP:SecReq'] - - - "SSC SSC2 blesmp -R -a 0 -r " - [""] -- ID: BTSTK_SMP_06001 - <<: *SMP_CASE - test environment: SSC_T1_4 - initial condition: BLE_DEINIT1 - test point 2: BLE SMP use API in abnormal state - summary: BLE SMP use API when BLE not initialized, not enabled or not registered callback - steps: | - 1. set security parameter - 2. send security response - 3. send passkey reply - 4. send confirm reply - 5. init BLE - 6. set security parameter - 7. send security response - 8. send passkey reply - 9. send confirm reply - 10. init BLE - 11. set security parameter - 12. send security response - 13. send passkey reply - 14. send confirm reply - expected result: | - 1. failed - 2. failed - 3. failed - 4. failed - 5. succeed - 6. failed - 7. failed - 8. failed - 9. failed - 10. succeed - 11. failed - 12. failed - 13. failed - 14. failed - cmd set: - - "" - - - "SSC SSC1 blesmp -S -z AuthReqMode -v 0x0C" - - ['P SSC1 C +BLESMP:ERROR'] - - - "SSC SSC1 blesmp -R -a 1 -r " - - ['P SSC1 C +BLESMP:ERROR'] - - - "SSC SSC1 blesmp -K -r -a 1 -k 123456" - - ['P SSC1 C +BLESMP:ERROR'] - - - "SSC SSC1 blesmp -C -r -a 1" - - ['P SSC1 C +BLESMP:ERROR'] - - - SSC SSC1 bt -D -z init - - ['R SSC1 C +BT:'] - - - "SSC SSC1 blesmp -S -z AuthReqMode -v 0x0C" - - ['P SSC1 C +BLESMP'] - - - "SSC SSC1 blesmp -R -a 1 -r " - - ['P SSC1 C +BLESMP'] - - - "SSC SSC1 blesmp -K -r -a 1 -k 123456" - - ['P SSC1 C +BLESMP'] - - - "SSC SSC1 blesmp -C -r -a 1" - - ['P SSC1 C +BLESMP'] - - - SSC SSC1 bt -D -z enable - - ['R SSC1 C +BT:'] - - - "SSC SSC1 blesmp -S -z AuthReqMode -v 0x0C" - - ['P SSC1 C +BLESMP'] - - - "SSC SSC1 blesmp -R -a 1 -r " - - ['P SSC1 C +BLESMP'] - - - "SSC SSC1 blesmp -K -r -a 1 -k 123456" - - ['P SSC1 C +BLESMP'] - - - "SSC SSC1 blesmp -C -r -a 1" - - ['P SSC1 C +BLESMP'] - ID: BTSTK_SMP_06002 <<: *SMP_CASE test point 2: BLE SMP use API in abnormal state @@ -1945,12 +1737,9 @@ test cases: cmd set: - "" - *config_slave_passkey_entry - - *start_pair - - - "SSC SSC2 blesmp -K -r -a 1 -k " - - ['P SSC2 C +BLESMP'] - - - "SSC SSC2 blesmp -C -r -a 1" - - ['P SSC2 C +BLESMP'] - - - "SSC SSC1 blesmp -R -a 1 -r " + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect,OK'] + - - "SSC SSC2 blesmp -E -r -z Enc" - ['P SSC2 C +BLESMP:PassKeyReq', 'P SSC1 A :BLESMP:PassKeyNotify,(\d+)'] - - "SSC SSC2 blesmp -K -r -a 1 -k " - ['P SSC[1-2] C +BLESMP:AuthComplete,Success,0'] @@ -1969,11 +1758,10 @@ test cases: cmd set: - "" - *config_slave_passkey_entry - - *start_pair - - - "SSC SSC1 blesmp -R -a 1 -r " + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect,OK'] + - - "SSC SSC2 blesmp -E -r -z Enc" - ['P SSC2 C +BLESMP:PassKeyReq', 'P SSC1 A :BLESMP:PassKeyNotify,(\d+)'] - - - "SSC SSC1 blesmp -R -a 1 -r " - - ['P SSC1 C +BLESMP'] - - "SSC SSC2 blesmp -K -r -a 1 -k " - ['P SSC[1-2] C +BLESMP:AuthComplete,Success,0'] - ID: BTSTK_SMP_06004 @@ -1993,10 +1781,14 @@ test cases: cmd set: - "" - *config_slave_passkey_entry - - *start_pair + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect,OK'] + - - "SSC SSC2 blesmp -E -r -z Enc" + - ['P SSC1 C +BLESMP:SecReq'] - *disconnect - - *start_pair - - - "SSC SSC1 blesmp -R -a 1 -r " + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect,OK'] + - - "SSC SSC2 blesmp -E -r -z Enc" - ['P SSC2 C +BLESMP:PassKeyReq', 'P SSC1 A :BLESMP:PassKeyNotify,(\d+)'] - *disconnect - ID: BTSTK_SMP_06005 @@ -2016,16 +1808,20 @@ test cases: cmd set: - "" - *config_slave_passkey_entry - - *start_pair + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect,OK'] + - - "SSC SSC2 blesmp -E -r -z Enc" + - ['P SSC1 C +BLESMP:SecReq'] - - "SSC SSC2 bleconn -D -z all" - - ['P SSC2 C +BLE:GattsDisconnect', 'P SSC1 C +BLE:GattcDisconnect,OK'] + - ['P SSC2 C +BLECONN:GapDisconnect,OK', 'P SSC1 C +BLECONN:GapDisconnect,OK'] - - "SSC SSC2 bleadv -D -z start" - ['P SSC2 C +BLEADV:Start,OK'] - - *start_pair - - - "SSC SSC1 blesmp -R -a 1 -r " + - - "SSC SSC1 bleconn -C -p 0x10 -a " + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect,OK'] + - - "SSC SSC2 blesmp -E -r -z Enc" - ['P SSC2 C +BLESMP:PassKeyReq', 'P SSC1 A :BLESMP:PassKeyNotify,(\d+)'] - - "SSC SSC2 bleconn -D -z all" - - ['P SSC2 C +BLE:GattsDisconnect', 'P SSC1 C +BLE:GattcDisconnect,OK'] + - ['P SSC2 C +BLECONN:GapDisconnect,OK', 'P SSC1 C +BLECONN:GapDisconnect,OK'] - ID: BTSTK_SMP_07001 <<: *SMP_CASE test point 2: BLE SMP no bond test and repairing @@ -2044,48 +1840,14 @@ test cases: - "" - *config_just_work - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ['P SSC1 C +BLE:GattcConnect,OK', 'P SSC2 C +BLE:GattsConnect'] + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect,OK'] - - "SSC SSC1 blesmp -E -r -z Enc" - - ['P SSC2 C +BLESMP:SecReq'] - - - "SSC SSC2 blesmp -R -a 1 -r " - ['P SSC[1-2] C +BLESMP:AuthComplete,Success,0'] - *disconnect - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ['P SSC1 C +BLE:GattcConnect,OK', 'P SSC2 C +BLE:GattsConnect'] + - ['P SSC1 C +BLECONN:GapConnect,OK', 'P SSC2 C +BLECONN:GapConnect,OK'] - - "SSC SSC2 blesmp -E -r -z Enc" - - ["P SSC1 C +BLESMP:SecReq"] - - - "SSC SSC1 blesmp -R -a 1 -r " - ['P SSC[1-2] C +BLESMP:AuthComplete,Success'] -- ID: BTSTK_SMP_07002 - <<: *SMP_CASE - test point 2: BLE SMP no bond test and repairing - summary: BLE SMP just work pairing and reboot - steps: | - 1. DUT1 and DUT2 SMP with just work pair - 2. DUT1 reboot - 3. DUT1 connect to DUT2 - 4. DUT2 send auth request - expected result: | - 1. succeed - 2. succeed - 3. succeed - 4. failed - cmd set: - - "" - - *config_just_work - - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ['P SSC1 C +BLE:GattcConnect,OK', 'P SSC2 C +BLE:GattsConnect'] - - - "SSC SSC1 blesmp -E -r -z Enc" - - ['P SSC2 C +BLESMP:SecReq'] - - - "SSC SSC2 blesmp -R -a 1 -r " - - ['P SSC[1-2] C +BLESMP:AuthComplete,Success,0'] - - - "SSC SSC1 reboot" - - ['P SSC2 C +BLE:GattsDisconnect'] - - - "SSC SSC1 ble -R" - - ['R SSC1 C +BLE:'] - - - "SSC SSC2 bleadv -D -z start" - - ['R SSC2 C +BLEADV:OK'] - - *slave_passkey_entry_pair - ID: BTSTK_SMP_07003 <<: *SMP_CASE test point 2: BLE SMP no bond test and repairing @@ -2125,276 +1887,12 @@ test cases: - *config_slave_passkey_entry - *slave_passkey_entry_pair - - "SSC SSC1 reboot" - - ['P SSC2 C +BLE:GattsDisconnect'] + - ['P SSC2 C +BLECONN:GapDisconnect,OK'] - - "SSC SSC1 ble -R" - ['R SSC1 C +BLE:'] - - "SSC SSC2 bleadv -D -z start" - ['R SSC2 C +BLEADV:OK'] - *slave_passkey_entry_pair -- ID: BTSTK_SMP_07005 - <<: *SMP_CASE - test point 2: BLE SMP no bond test and repairing - summary: BLE SMP initiator with master passkey entry and reconnect - steps: | - 1. DUT1 and DUT2 SMP with master passkey entry - 2. DUT1 disconnect - 3. DUT1 connect to DUT2 - 4. DUT2 send auth request - expected result: | - 1. succeed - 2. succeed - 3. connect succeed - 4. succeed - cmd set: - - "" - - *config_master_passkey_entry - - *master_passkey_entry_pair - - *disconnect - - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ['P SSC1 C +BLE:GattcConnect,OK', 'P SSC2 C +BLE:GattsConnect'] - - - "SSC SSC2 blesmp -E -r -z Enc" - - ['P SSC[1-2] C +BLESMP:AuthComplete,Success,0'] -- ID: BTSTK_SMP_07006 - <<: *SMP_CASE - test point 2: BLE SMP no bond test and repairing - summary: BLE SMP initiator with master passkey entry and reboot - steps: | - 1. DUT1 and DUT2 SMP bond with lagecy pairing - 2. DUT1 reboot - 3. DUT1 connect to DUT2 - 4. DUT2 send auth requst - expected result: | - 1. succeed - 2. succeed - 3. connect succeed - 4. fail - cmd set: - - "" - - *config_master_passkey_entry - - *master_passkey_entry_pair - - - "SSC SSC1 reboot" - - ['P SSC2 C +BLE:GattsDisconnect'] - - - "SSC SSC1 ble -R" - - ['R SSC1 C +BLE:'] - - - "SSC SSC2 bleadv -D -z start" - - ['R SSC2 C +BLEADV:OK'] - - *numberic_comparision_pair -- ID: BTSTK_SMP_07007 - <<: *SMP_CASE - test point 2: BLE SMP no bond test and repairing - summary: BLE SMP initiator numberic comparision and reconnect - steps: | - 1. DUT1 and DUT2 SMP with numberic comparision - 2. DUT1 disconnect - 3. DUT1 connect to DUT2 - 4. DUT2 send auth requst - expected result: | - 1. succeed - 2. succeed - 3. connect succeed - 4. succeed - cmd set: - - "" - - *config_numberic_comparision - - *numberic_comparision_pair - - *disconnect - - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ['P SSC1 C +BLE:GattcConnect,OK', 'P SSC2 C +BLE:GattsConnect'] - - - "SSC SSC2 blesmp -E -r -z Enc" - - ['P SSC[1-2] C +BLESMP:AuthComplete,Success,0'] -- ID: BTSTK_SMP_07008 - <<: *SMP_CASE - test point 2: BLE SMP no bond test and repairing - summary: BLE SMP initiator numberic comparision and reboot - steps: | - 1. DUT1 and DUT2 SMP with numberic comparision - 2. DUT1 disconnect - 3. DUT1 and DUT2 reboot - 4. DUT2 send auth requst - expected result: | - 1. succeed - 2. succeed - 3. connect succeed - 4. failed - cmd set: - - "" - - *config_numberic_comparision - - *numberic_comparision_pair - - - "SSC SSC1 reboot" - - ['P SSC2 C +BLE:GattsDisconnect'] - - - "SSC SSC1 ble -R" - - ['R SSC1 C +BLE:'] - - - "SSC SSC2 bleadv -D -z start" - - ['R SSC2 C +BLEADV:OK'] - - *numberic_comparision_pair -- ID: BTSTK_SMP_08001 - <<: *SMP_CASE - test point 2: BLE SMP bond item management test - summary: BLE SMP get bond list and number without bond device - steps: | - 1. DUT1 get bond list - 2. DUT1 get bond number - expected result: | - 1. succeed - 2. succeed - cmd set: - - "" - - - "SSC SSC1 blesmp -B -z getlist -n 1" - - ['P SSC1 C +BLESMP:GetBondList,OK,0'] - - - "SSC SSC1 blesmp -B -z getnum" - - ['P SSC1 C +BLESMP:GetBondNum,0'] -- ID: BTSTK_SMP_08002 - <<: *SMP_CASE - test point 2: BLE SMP bond item management test - summary: BLE SMP remove bond after connected - steps: | - 1. DUT2 set AuthReqMode and RspKey - 2. pairing - 3. remove bond - expected result: | - 1. Succeed - 2. Succeed - 3. Succeed - cmd set: - - "" - - *config_bond_device - - - "SSC SSC2 bleadv -D -z start" - - ['R SSC2 C +BLEADV:Start,OK'] - - *start_pair - - - "SSC SSC1 blesmp -R -a 1 -r " - - ['P SSC1 C +BLESMP:AuthComplete,Success,0','P SSC2 C +BLESMP:AuthComplete,Success,0'] - - - "SSC SSC1 blesmp -B -z getnum" - - ['P SSC1 C +BLESMP:GetBondNum,1'] - - - "SSC SSC1 blesmp -B -z remove -r " - - ['P SSC1 RE "\+BLESMP:RemoveBond,Success,%%s"%%()'] -- ID: BTSTK_SMP_08003 - <<: *SMP_CASE - test point 2: BLE SMP bond item management test - summary: BLE SMP get bond list and number when pairing and after reboot - steps: | - 1. all slaves set AuthReqMode and RspKey - 2. do pairing - 3. master and slave get bond list and num - 4. reboot - 5. master and slave get bond list and num - 6. slave remove bond device - expected result: | - 1. Succeed - 2. Succeed - 3. Succeed - 4. succeed - 5. succeed - 6. succeed - test environment: SSC_T5_1 - initial condition: BLE_INIT_SMP5 - cmd set: - - "" - - - "SSC SSC[2-5] blesmp -S -z AuthReqMode -v 0x01" - - ['P SSC[2-5] C +BLESMP:OK'] - - - "SSC SSC[2-5] blesmp -S -z IOCAP -v 0x03" - - ['P SSC[2-5] C +BLESMP:OK'] - - - "SSC SSC[2-5] blesmp -S -z RspKey -v 0x03" - - ['P SSC[2-5] C +BLESMP:OK'] - - - LOOP 4 4 "[2,3,4,5]" "[2,3,4,5]" "[2,3,4,5]" "[2,3,4,5]" "[2,3,4,5]" "[2,3,4,5]" "[2,3,4,5]" - - "" - - - "SSC SSC{%d} bleadv -D -z start" - - ['R SSC{%d} C +BLEADV:Start,OK'] - - - "SSC SSC1 bleconn -C -p 0x10 -a " - - ['P SSC1 C +BLE:GattcConnect,OK', 'P SSC{%d} C +BLE:GattsConnect'] - - - "SSC SSC{%d} blesmp -E -r -z Enc" - - ['P SSC1 C +BLESMP:SecReq'] - - - "SSC SSC1 blesmp -R -a 1 -r " - - ['P SSC1 C +BLESMP:AuthComplete,Success,0','P SSC{%d} C +BLESMP:AuthComplete,Success,0'] - - - "SSC SSC1 blesmp -B -z getlist -n 4" - - ['P SSC1 C +BLESMP:GetBondList,OK,4'] - - - "SSC SSC1 blesmp -B -z getnum" - - ['P SSC1 C +BLESMP:GetBondNum,4'] - - - "SSC SSC2 blesmp -B -z getnum" - - ['P SSC2 C +BLESMP:GetBondNum,1'] - - - "SSC SSC[1-2] reboot" - - ['R SSC[1-2] C !!!ready!!!'] - - - "SSC SSC[1-2] ble -R" - - ["R SSC[1-2] C +BLE:OK"] - - - "SSC SSC1 blesmp -B -z getnum" - - ['P SSC1 C +BLESMP:GetBondNum,4'] - - - "SSC SSC2 blesmp -B -z getnum" - - ['P SSC2 C +BLESMP:GetBondNum,1'] - - - "SSC SSC2 blesmp -B -z remove -r " - - ['P SSC2 RE "\+BLESMP:RemoveBond,Success,%%s"%%()'] -- ID: BTSTK_SMP_08004 - <<: *SMP_CASE - test point 2: BLE SMP bond item management test - summary: BLE SMP remove bond which not bond - steps: | - 1. DUT1 remove bond - expected result: | - 1. failed - cmd set: - - "" - - - "SSC SSC1 blesmp -B -z remove -r " - - ['P SSC1 C +BLESMP:RemoveBond,Fail'] -- ID: BTSTK_SMP_08005 - <<: *SMP_CASE - test point 2: BLE SMP remove bond - summary: BLE SMP bond 15/16 devices and get list - steps: | - 1. DUT2 set AuthReqMode and RspKey - 2. DUT2 set static random address - 3. DUT1 and DUT2 do pairing - 4. loop step 2 and step3 16 times - 5. get bond list and bond num - 6. DUT2 set static random address - 7. DUT1 and DUT2 do pairing - 8. get bond list and bond num - expected result: | - 1. Succeed - 2. Succeed - 3. Succeed - 4. succeed - 5. succeed - 6. succeed - 7. succeed - 8. succeed - cmd set: - - "" - - - "SSC SSC[1-2] blesmp -S -z AuthReqMode -v 0x01" - - ['P SSC[1-2] C +BLESMP:OK'] - - - "SSC SSC[1-2] blesmp -S -z IOCAP -v 0x03" - - ['P SSC[1-2] C +BLESMP:OK'] - - - "SSC SSC[1-2] blesmp -S -z RspKey -v 0x03" - - ['P SSC[1-2] C +BLESMP:OK'] - - - LOOP 15 7 "range(0,15)" "range(0,15)" "range(0,15)" - - "" - - - "SSC SSC2 bleadv -D -z stop" - - ['R SSC2 C +BLEADV:Stop,OK'] - - - "SSC SSC2 ble -S -z randAddr -a c0:9b:0e:36:6d:7{%x} -r 1" - - ["R SSC2 C +BLECONN:SetRandAddr,OK"] - - - "SSC SSC2 bleadv -D -z start -o 1" - - ['R SSC2 C +BLEADV:Start,OK'] - - - "SSC SSC1 bleconn -C -p 0x10 -a c0:9b:0e:36:6d:7{%x} -r 1" - - ['P SSC1 C +BLE:GattcConnect,OK', 'P SSC2 C +BLE:GattsConnect'] - - - "SSC SSC2 blesmp -E -r -z Enc" - - ['P SSC1 C +BLESMP:SecReq'] - - - "SSC SSC1 blesmp -R -a 1 -r c0:9b:0e:36:6d:7{%x}" - - ['P SSC1 C +BLESMP:AuthComplete,Success,0','P SSC2 C +BLESMP:AuthComplete,Success,0'] - - - "SSC SSC1 bleconn -D -z all" - - ['P SSC1 C +BLE:CLOSE', 'P SSC2 C +BLE:GattsDisconnect'] - - - "SSC SSC1 blesmp -B -z getlist -n 16" - - ['P SSC1 C +BLESMP:GetBondList,OK,15'] - - - "SSC SSC2 ble -S -z randAddr -a c1:0a:d3:25:7a:cf -r 1" - - ["R SSC2 C +BLECONN:SetRandAddr,OK"] - - - "SSC SSC2 bleadv -D -z stop" - - ['R SSC2 C +BLEADV:Stop,OK'] - - - "SSC SSC2 bleadv -D -z start -o 1" - - ['R SSC2 C +BLEADV:Start,OK'] - - - "SSC SSC1 bleconn -C -p 0x10 -a c1:0a:d3:25:7a:cf -r 1" - - ['P SSC1 C +BLE:GattcConnect,OK', 'P SSC2 C +BLE:GattsConnect'] - - - "SSC SSC2 blesmp -E -r -z Enc" - - ['P SSC1 C +BLESMP:SecReq'] - - - "SSC SSC1 blesmp -R -a 1 -r c1:0a:d3:25:7a:cf" - - ['P SSC1 C +BLESMP:AuthComplete,Success,0','P SSC2 C +BLESMP:AuthComplete,Success,0'] - - - "SSC SSC1 blesmp -B -z getlist -n 16" - - ['P SSC1 C +BLESMP:GetBondList,OK,15'] - ID: BTSTK_SMP_50001 <<: *SMP_CASE category: Performance diff --git a/components/idf_test/integration_test/TC_IT_WIFI_CONN.yml b/components/idf_test/integration_test/TC_IT_WIFI_CONN.yml index f5cc01e929..7086310cdb 100644 --- a/components/idf_test/integration_test/TC_IT_WIFI_CONN.yml +++ b/components/idf_test/integration_test/TC_IT_WIFI_CONN.yml @@ -13,13 +13,13 @@ test cases: - '' - - SSC SSC1 ap -S -s -t 0 - - R SSC1 C +SAP:OK - - - SSC SSC2 sta -C -s -p + - - SSC SSC2 sta -C -s - - R SSC2 RE "\+JAP:CONNECTED,%%s"%%() - - SSC SSC1 ap -S -s -p -t 2 - - R SSC1 C +SAP:OK - - SSC SSC2 sta -C -s -p - - R SSC2 RE "\+JAP:CONNECTED,%%s"%%() - - - SSC SSC1 ap -S -s -p -t + - - SSC SSC1 ap -S -s -p -t 3 - - R SSC1 C +SAP:OK - - SSC SSC2 sta -C -s -p - - R SSC2 RE "\+JAP:CONNECTED,%%s"%%() @@ -29,6 +29,8 @@ test cases: - - R SSC2 RE "\+JAP:CONNECTED,%%s"%%() - - SSC SSC1 ap -S -s -p -t 1 - - R SSC1 C +SAP:OK + - - SSC SSC2 sta -D + - - R SSC2 C +QAP:OK - - SSC SSC2 sta -S - - R SSC2 RE "\+SCAN:%%s,.+,0,\d+"%%() C +SCANDONE - - SSC SSC1 ap -S -s -p -t 5 @@ -69,16 +71,18 @@ test cases: - '' - - SSC SSC1 ap -S -s -t 0 -n 1 - - R SSC1 C +SAP:OK - - - SSC SSC2 sta -C -s -p + - - SSC SSC2 sta -C -s - - R SSC2 RE "\+JAP:CONNECTED,%%s"%%() - - SSC SSC1 ap -S -s -t 0 -n 13 - - R SSC1 C +SAP:OK - - - SSC SSC2 sta -C -s -p + - - SSC SSC2 sta -C -s - - R SSC2 RE "\+JAP:CONNECTED,%%s"%%() - - SSC SSC1 ap -S -s -n 15 - - R SSC1 C +SAP:OK - - - SSC SSC2 sta -C -s -p + - - SSC SSC2 sta -C -s - - R SSC2 RE "\+JAP:CONNECTED,%%s"%%() + - - SSC SSC2 sta -D + - - R SSC2 C +QAP:OK - - SSC SSC2 sta -S - - R SSC2 RE "\+SCAN:%%s,.+,\d+,1"%%() execution time: 0.0 @@ -1040,43 +1044,6 @@ test cases: test point 1: basic function test point 2: beacon delay version: v1 (2016-8-15) -- CI ready: 'Yes' - ID: WIFI_CONN_1101 - SDK: ESP32_IDF - Test App: SSC - allow fail: '' - auto test: 'Yes' - category: Function - cmd set: - - '' - - - SSC SSC1 ram -Q - - - R SSC1 A :\+FREEHEAP:(\d+)\r\n - - - SSC SSC1 op -W -a start - - - R SSC1 C +MODE:OK - - - SSC SSC1 op -W -a stop - - - R SSC1 C +MODE:OK - - - SSC SSC1 ram -Q - - - R SSC1 P - execution time: 0 - expected result: | - 1. get current heap size - 2.OK - 3.OK - 4.heap size unchanged - initial condition: WIFISTO - level: Integration - module: WIFI MAC - steps: | - 1. check heap size - 2. wifi start - 3. wifi stop - 4. check heap size - sub module: WIFI Connect - summary: wifi start and stop, heap size unchanged - test environment: SSC_T1_4 - test point 1: basic function - test point 2: wifi start and stop, heap size unchanged - version: v1 (2016-12-31) - CI ready: 'Yes' ID: WIFI_CONN_1201 SDK: ESP32_IDF diff --git a/components/idf_test/unit_test/InitialConditionAll.yml b/components/idf_test/unit_test/InitialConditionAll.yml deleted file mode 100644 index 6e5d898e72..0000000000 --- a/components/idf_test/unit_test/InitialConditionAll.yml +++ /dev/null @@ -1,2955 +0,0 @@ -initial condition: -- check cmd set: - - '' - - - SSC SSC1 op -Q - - ['R SSC1 C +CURMODE:2'] - - - SSC SSC1 ap -Q - - ['R SSC1 RE "\+APCONFIG:%%s,%%s,\d+,\d+,\d+,4,"%%(,)'] - - - SSC SSC1 dhcp -Q -o 2 - - ['R SSC1 C +DHCP:AP,STARTED'] - - - SSC SSC1 mac -Q -o 2 - - [R SSC1 P ] - force restore cmd set: - - '' - - - SSC SSC1 reboot - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC1 ap -S -s -p -t - - ['R SSC1 C +SAP:OK'] - initial condition detail: AP mode, DHCP on, will autogen a TC with initial condition - APSTA1 - restore cmd set: - - '' - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC1 ap -S -s -p -t - - ['R SSC1 C +SAP:OK'] - restore post cmd set: - - '' - - - SSC SSC1 soc -T - - [R SSC1 C +CLOSEALL] - - - SSC SSC1 ram - - ['R SSC1 C +FREEHEAP:'] - script path: InitCondBase.py - start: 31.0 - tag: APM1 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 op -Q - - ['R SSC1 C +CURMODE:2'] - - - SSC SSC1 ap -Q - - ['R SSC1 RE "\+APCONFIG:%%s,%%s,\d+,\d+,\d+,4,"%%(,)'] - - - SSC SSC1 ap -L - - ['R SSC1 RE "\+LSTA:.+,%%s"%%()'] - - - SSC SSC1 dhcp -Q -o 2 - - ['R SSC1 C +DHCP:AP,STARTED'] - - - SSC SSC1 mac -Q -o 2 - - [R SSC1 P ] - force restore cmd set: - - '' - - - SSC SSC1 reboot - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC1 ap -S -s -p -t - - ['R SSC1 C +SAP:OK'] - - - WIFI CONN - - - ['R PC_COM NC ERROR C +WIFICONN:OK'] - initial condition detail: AP mode, PC join AP, DHCP on, will autogen a TC with initial - condition APSTA2 - restore cmd set: - - '' - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC1 ap -S -s -p -t - - ['R SSC1 C +SAP:OK'] - - - WIFI CONN - - - ['R PC_COM NC ERROR C +WIFICONN:OK'] - restore post cmd set: - - '' - - - SSC SSC1 soc -T - - [R SSC1 C +CLOSEALL] - - - SSC SSC1 ram - - ['R SSC1 C +FREEHEAP:'] - script path: InitCondBase.py - start: 38.0 - tag: APM2 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 op -Q - - ['R SSC1 C +CURMODE:2'] - - - SSC SSC1 ap -Q - - ['R SSC1 RE "\+APCONFIG:%%s,%%s,\d+,\d+,\d+,4,"%%(,)'] - - - SSC SSC1 dhcp -Q -o 2 - - ['R SSC1 C +DHCP:AP,STARTED'] - - - SSC SSC1 mac -Q -o 2 - - [R SSC1 P ] - force restore cmd set: - - '' - - - SSC SSC1 reboot - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC1 ap -S -s -p -t - - ['R SSC1 C +SAP:OK'] - initial condition detail: AP mode, will NOT autogen a TC with initial condition - APSTA1 - restore cmd set: - - '' - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC1 ap -S -s -p -t - - ['R SSC1 C +SAP:OK'] - restore post cmd set: - - '' - - - SSC SSC1 soc -T - - [R SSC1 C +CLOSEALL] - - - SSC SSC1 ram - - ['R SSC1 C +FREEHEAP:'] - script path: InitCondBase.py - start: 31.0 - tag: APO1 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 op -Q - - ['R SSC1 C +CURMODE:2'] - - - SSC SSC1 ap -Q - - ['R SSC1 RE "\+APCONFIG:%%s,%%s,\d+,\d+,\d+,4,"%%(,)'] - - - SSC SSC1 ap -L - - ['R SSC1 RE "\+LSTA:.+,%%s"%%()'] - - - SSC SSC1 dhcp -Q -o 2 - - ['R SSC1 C +DHCP:AP,STARTED'] - - - SSC SSC1 mac -Q -o 2 - - [R SSC1 P ] - force restore cmd set: - - '' - - - SSC SSC1 reboot - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC1 ap -S -s -p -t - - ['R SSC1 C +SAP:OK'] - - - WIFI CONN - - - ['R PC_COM NC ERROR C +WIFICONN:OK'] - initial condition detail: AP mode, will NOT autogen a TC with initial condition - APSTA2 - restore cmd set: - - '' - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC1 ap -S -s -p -t - - ['R SSC1 C +SAP:OK'] - - - WIFI CONN - - - ['R PC_COM NC ERROR C +WIFICONN:OK'] - restore post cmd set: - - '' - - - SSC SSC1 soc -T - - [R SSC1 C +CLOSEALL] - - - SSC SSC1 ram - - ['R SSC1 C +FREEHEAP:'] - script path: InitCondBase.py - start: 38.0 - tag: APO2 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 upgrade -Q -t 1 - - ['R SSC1 C BIN_ID,0'] - - - SSC SSC1 upgrade -Q -t 2 -b 0 - - ['R SSC1 C BIN_INFO,0'] - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - force restore cmd set: - - '' - - - SSC SSC1 upgrade -R -r 1 -s - - [R SSC1 NC ERROR C !!!ready!!!] - - - SSC SSC1 op -S -o 1 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 sta -C -s -p - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - - - SOC SOC1 ULISTEN - - [R SOC_COM L OK] - - - SOC SOC1 SETOPT REPLY BIN - - [R SOC_COM C OK] - - - SSC SSC1 upgrade -I -b 0 -f 0 - - ['P SSC1 C +UPGRADE:OK'] - - - SSC SSC1 upgrade -U -i -p -u - - ['P SSC1 C +UPGRADE:SUCCEED'] - - - SSC SSC1 upgrade -R -b 0 - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - initial condition detail: AP only mode, running BIN0 (located on flash id 0) - restore cmd set: - - '' - - - SSC SSC1 upgrade -Q -t 2 -b 0 - - ['R SSC1 C BIN_INFO,0'] - - - SSC SSC1 upgrade -R -b 0 - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - restore post cmd set: - - '' - - - SSC SSC1 upgrade -D - - ['R SSC1 C +UPGRADE:OK'] - - - SSC SSC1 ram - - ['R SSC1 A :(\d+)'] - script path: InitCondBase.py - start: 31.0 - tag: APOBIN0 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 op -Q - - ['R SSC1 C +CURMODE:3'] - - - SSC SSC1 ap -Q - - ['R SSC1 RE "\+APCONFIG:%%s,%%s,\d+,\d+,\d+,4,"%%(,)'] - - - SSC SSC1 dhcp -Q -o 2 - - ['R SSC1 C +DHCP:AP,STARTED'] - - - SSC SSC1 mac -Q -o 2 - - [R SSC1 P ] - force restore cmd set: - - '' - - - SSC SSC1 reboot - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 op -S -o 3 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC1 ap -S -s -p -t - - ['R SSC1 C +SAP:OK'] - initial condition detail: testing ap on sta + ap mode (autogen by APM1) - restore cmd set: - - '' - - - SSC SSC1 op -S -o 3 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC1 ap -S -s -p -t - - ['R SSC1 C +SAP:OK'] - restore post cmd set: - - '' - - - SSC SSC1 soc -T - - [R SSC1 C +CLOSEALL] - - - SSC SSC1 ram - - ['R SSC1 C +FREEHEAP:'] - script path: InitCondBase.py - start: 59.0 - tag: APSTA1 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 op -Q - - ['R SSC1 C +CURMODE:3'] - - - SSC SSC1 ap -Q - - ['R SSC1 RE "\+APCONFIG:%%s,%%s,\d+,\d+,\d+,4,"%%(,)'] - - - SSC SSC1 ap -L - - ['R SSC1 RE "\+LSTA:.+,%%s"%%()'] - - - SSC SSC1 dhcp -Q -o 2 - - ['R SSC1 C +DHCP:AP,STARTED'] - - - SSC SSC1 mac -Q -o 2 - - [R SSC1 P ] - force restore cmd set: - - '' - - - SSC SSC1 reboot - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 op -S -o 3 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC1 ap -S -s -p -t - - ['R SSC1 C +SAP:OK'] - - - WIFI CONN - - - ['R PC_COM NC ERROR C +WIFICONN:OK'] - initial condition detail: testing ap on sta + ap mode, PC join AP (autogen by APM2) - restore cmd set: - - '' - - - SSC SSC1 op -S -o 3 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC1 ap -S -s -p -t - - ['R SSC1 C +SAP:OK'] - - - WIFI CONN - - - ['R PC_COM NC ERROR C +WIFICONN:OK'] - restore post cmd set: - - '' - - - SSC SSC1 soc -T - - [R SSC1 C +CLOSEALL] - - - SSC SSC1 ram - - ['R SSC1 C +FREEHEAP:'] - script path: InitCondBase.py - start: 66.0 - tag: APSTA2 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 L +CWMODE_CUR:3'] - - - ATS AT1 AT+CWLIF - - [R AT1 P ] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - DELAY 5 - - [''] - - - ATC AT1 CWSAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - - - WIFI CONN - - - ['R PC_COM NC ERROR C +WIFICONN:OK'] - - - ATS AT1 AT+CWLIF - - [R AT1 P ] - initial condition detail: StationSoftAP mode - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATS AT1 AT+CWLIF - - [R AT1 P ] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 24.0 - tag: ATAP1 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 C +CWMODE_CUR:3 L OK'] - - - ATS AT1 AT+CWLIF - - [R AT1 P ] - - - ATS AT1 AT+CIPMUX? - - ['R AT1 L +CIPMUX:1'] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - DELAY 5 - - [''] - - - ATC AT1 CWSAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - - - WIFI CONN - - - ['R PC_COM NC ERROR C +WIFICONN:OK'] - - - ATS AT1 AT+CWLIF - - [R AT1 P ] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=1 - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - initial condition detail: StationSoftAP mode, PC join Target AP, multi link, use - dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=1 - - [R AT1 R *] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CWLIF - - [R AT1 P ] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 31.0 - tag: ATAP3 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 C +CWMODE_CUR:3 L OK'] - - - ATS AT1 AT+CWLIF - - [R AT1 P ] - - - ATS AT1 AT+CIPMUX? - - ['R AT1 L +CIPMUX:0'] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - DELAY 10 - - [''] - - - ATC AT1 CWSAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - - - WIFI CONN - - - ['R PC_COM NC ERROR C +WIFICONN:OK'] - - - ATS AT1 AT+CWLIF - - [R AT1 P ] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=0 - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - initial condition detail: StationSoftAP mode, PC join Target AP, single link, use - dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=0 - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - - - ATS AT1 AT+CWLIF - - [R AT1 P ] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 45.0 - tag: ATAP4 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT - - [R AT1 L OK] - - - ATS AT1 AT - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+RST - - [R AT1 L OK] - initial condition detail: StationSoftAP mode, both PC join Target AP, single link, - use dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 3.0 - tag: ATAP5 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT - - [R AT1 L OK] - - - ATS AT1 AT - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+RST - - [R AT1 L OK] - initial condition detail: StationSoftAP mode, both PC join Target AP, multi link, - use dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 3.0 - tag: ATAP6 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 L +CWMODE_CUR:2'] - - - ATS AT1 AT+CWDHCP_DEF=0,1 - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=2 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=0,1 - - [R AT1 R *] - initial condition detail: SoftAP mode, use dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=2 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=0,1 - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 59.0 - tag: ATAPO1 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 C +CWMODE_CUR:2 L OK'] - - - ATS AT1 AT+CWLIF - - [R AT1 P ] - - - ATS AT1 AT+CIPMUX? - - ['R AT1 L +CIPMUX:1'] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CWDHCP_DEF=0,1 - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=2 - - [R AT1 L OK] - - - ATC AT1 CWSAP_DEF - - [R AT1 L OK] - - - WIFI CONN - - - ['R PC_COM NC ERROR C +WIFICONN:OK'] - - - ATS AT1 AT+CWLIF - - [R AT1 P ] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=1 - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CWDHCP_DEF=0,1 - - [R AT1 R *] - initial condition detail: SoftAP mode, PC join Target AP, multi link, use dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=2 - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=1 - - [R AT1 R *] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CWLIF - - [R AT1 P ] - - - ATS AT1 AT+CWDHCP_DEF=0,1 - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 66.0 - tag: ATAPO3 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 C +CWMODE_CUR:2 L OK'] - - - ATS AT1 AT+CWLIF - - [R AT1 P ] - - - ATS AT1 AT+CIPMUX? - - ['R AT1 L +CIPMUX:0'] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - - - ATS AT1 AT+CWDHCP_DEF=0,1 - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=2 - - [R AT1 L OK] - - - ATC AT1 CWSAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=0,1 - - [R AT1 R *] - - - WIFI CONN - - - ['R PC_COM NC ERROR C +WIFICONN:OK'] - - - ATS AT1 AT+CWLIF - - [R AT1 P ] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=0 - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - initial condition detail: SoftAP mode, PC join Target AP, single link, use dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=2 - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=0 - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - - - ATS AT1 AT+CWLIF - - [R AT1 P ] - - - ATS AT1 AT+CWDHCP_DEF=0,1 - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 73.0 - tag: ATAPO4 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT - - [R AT1 L OK] - - - ATS AT1 AT - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+RST - - [R AT1 L OK] - initial condition detail: SoftAP mode, both PC join Target AP, single link, use - dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 3.0 - tag: ATAPO5 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT - - [R AT1 L OK] - - - ATS AT1 AT - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+RST - - [R AT1 L OK] - initial condition detail: SoftAP mode, both PC join Target AP, multi link, use dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 3.0 - tag: ATAPO6 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 L +CWMODE_CUR:3'] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - initial condition detail: StationSoftAP mode - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 87.0 - tag: ATAPSTA1 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 L +CWMODE_CUR:3'] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - initial condition detail: StationSoftAP mode, DHCP client on - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 87.0 - tag: ATAPSTA2 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 L +CWMODE_CUR:3'] - - - ATS AT1 AT+CWJAP_CUR? - - ['R AT1 C +CWJAP_CUR:', R AT1 P ] - - - ATS AT1 AT+CIPMUX? - - ['R AT1 L +CIPMUX:1'] - - - ATS AT1 AT+CWDHCP_CUR? - - ['R AT1 C DHCP:3'] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=1 - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - initial condition detail: StationSoftAP mode, connected to AP, multi link, use dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=1 - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 94.0 - tag: ATAPSTA3 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 L +CWMODE_CUR:3'] - - - ATS AT1 AT+CWJAP_CUR? - - ['R AT1 C +CWJAP_CUR:', R AT1 P ] - - - ATS AT1 AT+CIPMUX? - - ['R AT1 L +CIPMUX:0'] - - - ATS AT1 AT+CWDHCP_CUR? - - ['R AT1 C DHCP:3'] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=0 - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - initial condition detail: StationSoftAP mode, connected to AP, single link, use - dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=0 - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - - - ATS AT1 AT+CWDHCP_DEF=2,1 - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 101.0 - tag: ATAPSTA4 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 L +CWMODE_CUR:3'] - - - ATS AT1 AT+CWJAP_CUR? - - ['R AT1 C +CWJAP_CUR:', R AT1 P ] - - - ATS AT1 AT+CIPMUX? - - ['R AT1 L +CIPMUX:1'] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATC AT1 CIPSTA_DEF - - [R AT1 L OK] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=1 - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATC AT1 CIPSTA_DEF - - [R AT1 L OK] - initial condition detail: StationSoftAP mode, connected to AP, multi link, use static - ip - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=1 - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATC AT1 CIPSTA_DEF - - [R AT1 L OK] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 129.0 - tag: ATAPSTA5 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 L +CWMODE_CUR:3'] - - - ATS AT1 AT+CWJAP_CUR? - - ['R AT1 C +CWJAP_CUR:', R AT1 P ] - - - ATS AT1 AT+CIPMUX? - - ['R AT1 L +CIPMUX:0'] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - - - ATC AT1 CIPSTA_DEF - - [R AT1 L OK] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=0 - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATC AT1 CIPSTA_DEF - - [R AT1 L OK] - initial condition detail: StationSoftAP mode, connected to AP, single link, use - static ip - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=0 - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - - - ATC AT1 CIPSTA_DEF - - [R AT1 L OK] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 136.0 - tag: ATAPSTA6 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT - - [R AT1 L OK] - - - ATS AT1 AT+RESTORE - - [R AT1 L OK, R AT1 C ready] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT - - [R AT1 L OK] - - - ATS AT1 AT+RESTORE - - [R AT1 L OK, R AT1 C ready] - initial condition detail: 'first time usage. Use restore function. ' - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+RESTORE - - [R AT1 L OK, R AT1 C ready] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 143.0 - tag: ATFTU - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT - - [R AT1 L OK] - - - ATS AT1 AT - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+RST - - [R AT1 L OK] - initial condition detail: none - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 3.0 - tag: ATNone - test script: InitCondBase -- check cmd set: - - '' - - - DELAY 0.1 - - [dummy] - force restore cmd set: - - '' - - - DELAY 0.1 - - [dummy] - initial condition detail: none 2 - restore cmd set: - - '' - - - DELAY 0.1 - - [dummy] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 108.0 - tag: ATNone2 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 L +CWMODE_CUR:1'] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 L OK] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=1 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 L OK] - initial condition detail: same as STA1, but will not autogen STA+AP STA test case - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=1 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 L OK] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 10.0 - tag: ATOSTA1 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 L +CWMODE_CUR:1'] - - - ATS AT1 AT+CWJAP_CUR? - - ['R AT1 C +CWJAP_CUR:', R AT1 P ] - - - ATS AT1 AT+CIPMUX? - - ['R AT1 L +CIPMUX:0'] - - - ATS AT1 AT+CWDHCP_CUR? - - ['R AT1 C DHCP:3'] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=1 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 R *] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=0 - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - initial condition detail: same as STA4, but will not autogen STA+AP STA test case - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=1 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 R *] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=0 - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 17.0 - tag: ATOSTA4 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 C +CWMODE_CUR:3 C OK'] - - - ATS AT2 AT+CWMODE_CUR? - - ['R AT2 C +CWMODE_CUR:1 C OK'] - - - ATS AT1 AT+CWJAP_CUR? - - [R AT1 NC OK L ERROR] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATS AT2 AT+CWMODE_DEF=1 - - [R AT2 L OK] - - - ATS AT1 AT+CWQAP - - [R AT1 L OK] - initial condition detail: same as OT2_1, but will not autogen STA+AP STA test case - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATS AT2 AT+CWMODE_DEF=1 - - [R AT2 L OK] - - - ATS AT1 AT+CWQAP - - [R AT1 L OK] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 52.0 - tag: ATOT2_1 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 L +CWMODE_CUR:1'] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 L OK] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=1 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 L OK] - initial condition detail: station mode, use dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=1 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 L OK] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 10.0 - tag: ATSTA1 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 L +CWMODE_CUR:1'] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 L OK] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=1 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 L OK] - initial condition detail: station mode, DHCP client on, use dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=1 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 L OK] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 10.0 - tag: ATSTA2 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 L +CWMODE_CUR:1'] - - - ATS AT1 AT+CWJAP_CUR? - - ['R AT1 C +CWJAP_CUR:', R AT1 P ] - - - ATS AT1 AT+CIPMUX? - - ['R AT1 L +CIPMUX:1'] - - - ATS AT1 AT+CWDHCP_CUR? - - ['R AT1 C DHCP:3'] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=1 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 R *] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=1 - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - initial condition detail: station mode, connected to AP, multi link, use dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=1 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 R *] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=1 - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 38.0 - tag: ATSTA3 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 L +CWMODE_CUR:1'] - - - ATS AT1 AT+CWJAP_CUR? - - ['R AT1 C +CWJAP_CUR:', R AT1 P ] - - - ATS AT1 AT+CIPMUX? - - ['R AT1 L +CIPMUX:0'] - - - ATS AT1 AT+CWDHCP_CUR? - - ['R AT1 C DHCP:3'] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=1 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 R *] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=0 - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - initial condition detail: station mode, connected to AP, single link, use dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=1 - - [R AT1 L OK] - - - ATS AT1 AT+CWDHCP_DEF=1,1 - - [R AT1 R *] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=0 - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 17.0 - tag: ATSTA4 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 L +CWMODE_CUR:1'] - - - ATS AT1 AT+CWJAP_CUR? - - ['R AT1 C +CWJAP_CUR:', R AT1 P ] - - - ATS AT1 AT+CIPMUX? - - ['R AT1 L +CIPMUX:1'] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATC AT1 CIPSTA_DEF - - [R AT1 L OK] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=1 - - [R AT1 L OK] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=1 - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATC AT1 CIPSTA_DEF - - [R AT1 L OK] - initial condition detail: station mode, connected to AP, multi link, use static - ip - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=1 - - [R AT1 L OK] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=1 - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATC AT1 CIPSTA_DEF - - [R AT1 L OK] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 115.0 - tag: ATSTA5 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 L +CWMODE_CUR:1'] - - - ATS AT1 AT+CWJAP_CUR? - - ['R AT1 C +CWJAP_CUR:', R AT1 P ] - - - ATS AT1 AT+CIPMUX? - - ['R AT1 L +CIPMUX:0'] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - - - ATC AT1 CIPSTA_DEF - - [R AT1 L OK] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=1 - - [R AT1 L OK] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=0 - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATC AT1 CIPSTA_DEF - - [R AT1 L OK] - initial condition detail: station mode, connected to AP, single link, use static - ip - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=1 - - [R AT1 L OK] - - - ATC AT1 CWJAP_DEF - - [R AT1 L OK] - - - ATS AT1 AT+CIPSERVER=0 - - [R AT1 R *] - - - ATC AT1 CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMUX=0 - - [R AT1 L OK] - - - ATS AT1 AT+CIPCLOSE - - [R AT1 R *] - - - ATS AT1 AT+CIPMODE=0 - - [R AT1 R *] - - - ATC AT1 CIPSTA_DEF - - [R AT1 L OK] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 122.0 - tag: ATSTA6 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 C +CWMODE_CUR:3 C OK'] - - - ATS AT2 AT+CWMODE_CUR? - - ['R AT2 C +CWMODE_CUR:1 C OK'] - - - ATS AT1 AT+CWJAP_CUR? - - [R AT1 NC OK L ERROR] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATS AT2 AT+CWMODE_DEF=1 - - [R AT2 L OK] - - - ATS AT1 AT+CWQAP - - [R AT1 L OK] - initial condition detail: Target 1 in StationSoftAP mode, Target 2 in station mode, - use dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=3 - - [R AT1 L OK] - - - ATS AT2 AT+CWMODE_DEF=1 - - [R AT2 L OK] - - - ATS AT1 AT+CWQAP - - [R AT1 L OK] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 52.0 - tag: ATT2_1 - test script: InitCondBase -- check cmd set: - - '' - - - ATS AT1 AT+CWMODE_CUR? - - ['R AT1 C +CWMODE_CUR:2 C OK'] - - - ATS AT2 AT+CWMODE_CUR? - - ['R AT2 C +CWMODE_CUR:3 C OK'] - - - ATS AT1 AT+CWJAP_CUR? - - [R AT1 NC OK L ERROR] - force restore cmd set: - - '' - - - ATS AT1 AT+RST - - [R AT1 C ready] - - - ATS AT1 AT+CWMODE_DEF=2 - - [R AT1 L OK] - - - ATS AT2 AT+CWMODE_DEF=3 - - [R AT2 L OK] - initial condition detail: Target 1 in SoftAP mode, Target 2 in StationSoftAP mode, - use dhcp - restore cmd set: - - '' - - - ATSO AT1 +++ - - [''] - - - ATS AT1 AT - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - ATS AT1 AT+CWMODE_DEF=2 - - [R AT1 L OK] - - - ATS AT2 AT+CWMODE_DEF=3 - - [R AT2 L OK] - restore post cmd set: - - '' - - - ATS AT1 AT+CWSTOPSMART - - [R AT1 R *] - - - ATS AT1 AT+SAVETRANSLINK=0 - - [R AT1 R *] - - - AT+SYSRAM - - ['R AT1 A :(\d+)'] - script path: InitCondBase.py - start: 80.0 - tag: ATT2_2 - test script: InitCondBase -- check cmd set: - - '' - - - ASSERT - - [dummy] - force restore cmd set: - - '' - - - SSC SSC[1-] reboot - - ['P SSC[1-] C !!!ready!!!'] - - - SSC SSC[1-] mesh -E -o 0 - - ['P SSC[1-] C +MESH:DISABLED'] - - - SSC SSC[1-] op -S -o 1 - - ['P SSC[1-] C +MODE:OK'] - - - SSC SSC[1-] sta -D - - ['P SSC[1-] C +QAP:OK'] - initial condition detail: all mesh node disabled - restore cmd set: - - '' - - - SSC SSC[1-] mesh -E -o 0 - - ['P SSC[1-] C +MESH:DISABLED'] - - - SSC SSC[1-] op -S -o 1 - - ['P SSC[1-] C +MODE:OK'] - - - SSC SSC[1-] sta -D - - ['P SSC[1-] C +QAP:OK'] - restore post cmd set: - - '' - - - SSC SSC1 ram - - ['R SSC1 A :(\d+)'] - script path: InitCondBase.py - start: 31.0 - tag: DISABLED - test script: InitCondBase -- check cmd set: - - '' - - - ASSERT - - [dummy] - - - SSC SSC[1-] mesh -Q -t 4 - - ['R SSC[1-] T '] - - - MESHTREE - - ['R PC_COM RE "MESHTREE:%%s%20nodes"%%()'] - force restore cmd set: - - '' - - - SOC SOC1 LISTEN - - [R SOC_COM L OK] - - - SSC SSC[1-] mesh -E -o 0 - - ['P SSC[1-] C +MESH:DISABLED'] - - - SSC SSC[1-] mesh -I -g -a 4 -k -i - -p -h 5 - - ['P SSC[1-] C ENCRYPTION,OK C GROUP,OK C SERVER,OK C HOP,OK'] - - - SSC SSC[1-] mesh -A -s -k - - ['P SSC[1-] C +MESHINIT:AP,OK'] - - - SSC SSC1 mesh -E -o 1 -t 2 - - ['P SSC1 C +MESH:ENABLED'] - - - SOC SOC1 MACCEPT GSOC1 - - [R SOC_COM L OK] - - - SSC SSC[2-] mesh -E -o 1 -t 2 - - ['P SSC[2-] C +MESH:ENABLED'] - - - DELAY 60 - - [''] - - - SSC SSC[1-] mesh -C - - ['P SSC[1-] C +MESH:CONNECTED'] - - - SSC SSC[1-] mesh -Q -t 4 - - ['R SSC[1-] T '] - - - MESHTREE - - ['R PC_COM RE "MESHTREE:%%s%20nodes"%%()'] - - - SSC SSC[1-] mesh -O -t 1 -o 1 - - ['P SSC[1-] C +MESH:OK'] - initial condition detail: all mesh node enabled as ONLINE, mesh network established - restore cmd set: - - '' - - - SSC SSC[1-] reboot - - ['P SSC[1-] C !!!ready!!!'] - - - SOC SOC1 LISTEN - - [R SOC_COM L OK] - - - SSC SSC[1-] mesh -E -o 0 - - ['P SSC[1-] C +MESH:DISABLED'] - - - SSC SSC[1-] mesh -I -g -a 4 -k -i - -p -h 5 - - ['P SSC[1-] C ENCRYPTION,OK C GROUP,OK C SERVER,OK C HOP,OK'] - - - SSC SSC[1-] mesh -A -s -k - - ['P SSC[1-] C +MESHINIT:AP,OK'] - - - SSC SSC1 mesh -E -o 1 -t 2 - - ['P SSC1 C +MESH:ENABLED'] - - - SOC SOC1 MACCEPT GSOC1 - - [R SOC_COM L OK] - - - SSC SSC[2-] mesh -E -o 1 -t 2 - - ['P SSC[2-] C +MESH:ENABLED'] - - - DELAY 60 - - [''] - - - SSC SSC[1-] mesh -C - - ['P SSC[1-] C +MESH:CONNECTED'] - - - SSC SSC[1-] mesh -Q -t 4 - - ['R SSC[1-] T '] - - - MESHTREE - - ['R PC_COM RE "MESHTREE:%%s%20nodes"%%()'] - - - SSC SSC[1-] mesh -O -t 1 -o 1 - - ['P SSC[1-] C +MESH:OK'] - restore post cmd set: - - '' - - - SSC SSC1 ram - - ['R SSC1 A :(\d+)'] - script path: InitCondBase.py - start: 17.0 - tag: ENABLED_1 - test script: InitCondBase -- check cmd set: - - '' - - - ASSERT - - [dummy] - - - SSC SSC[1-] mesh -Q -t 4 - - ['R SSC[1-] T '] - - - MESHTREE - - ['R PC_COM RE "MESHTREE:%%s%20nodes"%%()'] - force restore cmd set: - - '' - - - SSC SSC[1-] reboot - - ['P SSC[1-] C !!!ready!!!'] - - - SSC SSC[1-] mesh -I -g -a 4 -k -i - -p -h 5 - - ['P SSC[1-] C ENCRYPTION,OK C GROUP,OK C SERVER,OK C HOP,OK'] - - - SSC SSC1 mesh -A -s -k - - ['P SSC1 C +MESHINIT:AP,OK'] - - - SSC SSC1 mesh -E -o 1 -t 1 - - ['P SSC1 C +MESH:ENABLED'] - - - SSC SSC[2-] mesh -E -o 1 -t 2 - - [''] - - - DELAY 60 - - ['P SSC[2-] C +MESH:ENABLED'] - - - SSC SSC[1-] mesh -C - - ['P SSC[1-] C +MESH:CONNECTED'] - - - SSC SSC[1-] mesh -Q -t 4 - - ['R SSC[1-] T '] - - - MESHTREE - - ['R PC_COM RE "MESHTREE:%%s%20nodes"%%()'] - initial condition detail: root as LOCAL, rest node as ONLINE, mesh network established - restore cmd set: - - '' - - - SSC SSC[1-] mesh -E -o 0 - - ['P SSC[1-] C +MESH:DISABLED'] - - - SSC SSC[1-] mesh -I -g -a 4 -k -i - -p -h 5 - - ['P SSC[1-] C ENCRYPTION,OK C GROUP,OK C SERVER,OK C HOP,OK'] - - - SSC SSC1 mesh -A -s -k - - ['P SSC1 C +MESHINIT:AP,OK'] - - - SSC SSC1 mesh -E -o 1 -t 1 - - ['P SSC1 C +MESH:ENABLED'] - - - SSC SSC[2-] mesh -E -o 1 -t 2 - - [''] - - - DELAY 60 - - ['P SSC[2-] C +MESH:ENABLED'] - - - SSC SSC[1-] mesh -C - - ['P SSC[1-] C +MESH:CONNECTED'] - - - SSC SSC[1-] mesh -Q -t 4 - - ['R SSC[1-] T '] - - - MESHTREE - - ['R PC_COM RE "MESHTREE:%%s%20nodes"%%()'] - restore post cmd set: - - '' - - - SSC SSC1 ram - - ['R SSC1 A :(\d+)'] - script path: InitCondBase.py - start: 24.0 - tag: ENABLED_2 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 op -Q - - ['R SSC1 C +CURMODE:2'] - - - SSC SSC1 mac -Q -o 2 - - [R SSC1 P ] - - - SSC SSC1 espnow -D - - ['R SSC1 C +ESPNOW:'] - force restore cmd set: - - '' - - - SSC SSC[1-] reboot - - ['R SSC[1-] C !!!ready!!!'] - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 mac -S -m -o 2 - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC1 espnow -D - - ['R SSC1 C +ESPNOW:'] - initial condition detail: one target in AP mode and espnow is de-initialized - restore cmd set: - - '' - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 mac -S -m -o 2 - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC1 espnow -D - - ['R SSC1 C +ESPNOW:'] - restore post cmd set: - - '' - - - SSC SSC1 ram - - ['R SSC1 A :(\d+)'] - script path: InitCondBase.py - start: 17.0 - tag: NOW1 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC[1-] op -Q - - ['R SSC[1-] C +CURMODE:2'] - - - SSC SSC[1-] mac -Q -o 3 - - ['R SSC[1-] P ]_ap_mac> P ]_mac>'] - - - SSC SSC[1-] espnow -D - - ['R SSC[1-] C +ESPNOW:'] - - - SSC SSC[1-] espnow -I - - ['R SSC[1-] C +ESPNOW:OK'] - - - SSC SSC[1-] espnow -R -t Set -r 2 - - ['R SSC[1-] C +ESPNOW:OK'] - force restore cmd set: - - '' - - - SSC SSC[1-] reboot - - ['R SSC[1-] C !!!ready!!!'] - - - SSC SSC[1-] op -S -o 3 - - ['R SSC[1-] C +MODE:OK'] - - - SSC SSC[1-] mac -S -m ]_ap_mac> -o 2 - - ['R SSC[1-] C +MAC:AP,OK'] - - - SSC SSC[1-] mac -S -m ]_mac> -o 1 - - ['R SSC[1-] C +MAC:STA,OK'] - - - SSC SSC[1-] op -S -o 2 - - ['R SSC[1-] C +MODE:OK'] - - - SSC SSC[1-] espnow -D - - ['R SSC[1-] C +ESPNOW:'] - - - SSC SSC[1-] espnow -I - - ['R SSC[1-] C +ESPNOW:OK'] - - - SSC SSC[1-] espnow -R -t Set -r 2 - - ['R SSC[1-] C +ESPNOW:OK'] - initial condition detail: multiple () targets in AP mode, espnow is initialized - with self role slave - restore cmd set: - - '' - - - SSC SSC[1-] op -S -o 3 - - ['R SSC[1-] C +MODE:OK'] - - - SSC SSC[1-] mac -S -m ]_ap_mac> -o 2 - - ['R SSC[1-] C +MAC:AP,OK'] - - - SSC SSC[1-] mac -S -m ]_mac> -o 1 - - ['R SSC[1-] C +MAC:STA,OK'] - - - SSC SSC[1-] op -S -o 2 - - ['R SSC[1-] C +MODE:OK'] - - - SSC SSC[1-] espnow -D - - ['R SSC[1-] C +ESPNOW:'] - - - SSC SSC[1-] espnow -I - - ['R SSC[1-] C +ESPNOW:OK'] - - - SSC SSC[1-] espnow -R -t Set -r 2 - - ['R SSC[1-] C +ESPNOW:OK'] - restore post cmd set: - - '' - - - SSC SSC1 ram - - ['R SSC1 A :(\d+)'] - script path: InitCondBase.py - start: 24.0 - tag: NOW2 - test script: InitCondBase -- check cmd set: - - '' - - - DELAY 0.1 - - [dummy] - force restore cmd set: - - '' - - - SSC SSC1 reboot - - [R SSC1 C !!!ready!!!] - initial condition detail: none - restore cmd set: - - '' - - - DELAY 0.1 - - [dummy] - restore post cmd set: - - '' - - - DELAY 0.1 - - [dummy] - script path: InitCondBase.py - start: 10.0 - tag: None - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 sp -D - - ['R SSC1 C +SP:OK'] - force restore cmd set: - - '' - - - SSC SSC1 sp -D - - ['R SSC1 C +SP:OK'] - initial condition detail: one target and simple is de-inited - restore cmd set: - - '' - - - SSC SSC1 sp -D - - ['R SSC1 C +SP:OK'] - restore post cmd set: - - '' - - - SSC SSC1 ram - - ['R SSC1 A :(\d+)'] - script path: InitCondBase.py - start: 31.0 - tag: PAIR1 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC[1,2] op -Q - - ['R SSC[1,2] C +MODE:[2,1]'] - - - SSC SSC[1,2] mac -Q -o 3 - - ['R SSC[1,2] P P '] - - - SSC SSC[1,2] sp -D - - ['R SSC[1,2] C +SP:OK'] - - - SSC SSC[1,2] sp -I - - ['R SSC[1,2] C +SP:OK'] - force restore cmd set: - - '' - - - SSC SSC[1,2] reboot - - ['R SSC[1,2] C !!!ready!!!'] - - - SSC SSC[1,2] op -S -o 3 - - ['R SSC[1,2] C +MODE:OK'] - - - SSC SSC[1,2] mac -S -m -o 2 - - ['R SSC[1,2] C +MAC:AP,OK'] - - - SSC SSC[1,2] mac -S -m -o 1 - - ['R SSC[1,2] C +MAC:STA,OK'] - - - SSC SSC[1,2] op -S -o [2,1] - - ['R SSC[1,2] C +MODE:OK'] - - - SSC SSC[1,2] sp -D - - ['R SSC[1,2] C +SP:OK'] - - - SSC SSC[1,2] sp -I - - ['R SSC[1,2] C +SP:OK'] - initial condition detail: target1 in AP mode, target2 in STA mode, two targets de-init - and init simple pair - restore cmd set: - - '' - - - SSC SSC[1,2] op -S -o 3 - - ['R SSC[1,2] C +MODE:OK'] - - - SSC SSC[1,2] mac -S -m -o 2 - - ['R SSC[1,2] C +MAC:AP,OK'] - - - SSC SSC[1,2] mac -S -m -o 1 - - ['R SSC[1,2] C +MAC:STA,OK'] - - - SSC SSC[1,2] op -S -o [2,1] - - ['R SSC[1,2] C +MODE:OK'] - - - SSC SSC[1,2] sp -D - - ['R SSC[1,2] C +SP:OK'] - - - SSC SSC[1,2] sp -I - - ['R SSC[1,2] C +SP:OK'] - restore post cmd set: - - '' - - - SSC SSC1 ram - - ['R SSC1 A :(\d+)'] - script path: InitCondBase.py - start: 38.0 - tag: PAIR2 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC[1,2] op -Q - - ['R SSC[1,2] C +MODE:[3,3]'] - - - SSC SSC[1,2] mac -Q -o 3 - - ['R SSC[1,2] P P '] - - - SSC SSC[1,2] sp -D - - ['R SSC[1,2] C +SP:OK'] - - - SSC SSC[1,2] sp -I - - ['R SSC[1,2] C +SP:OK'] - force restore cmd set: - - '' - - - SSC SSC[1,2] reboot - - ['R SSC[1,2] C !!!ready!!!'] - - - SSC SSC[1,2] op -S -o [3,3] - - ['R SSC[1,2] C +MODE:OK'] - - - SSC SSC[1,2] mac -S -m -o 2 - - ['R SSC[1,2] C +MAC:AP,OK'] - - - SSC SSC[1,2] mac -S -m -o 1 - - ['R SSC[1,2] C +MAC:STA,OK'] - - - SSC SSC[1,2] sp -D - - ['R SSC[1,2] C +SP:OK'] - - - SSC SSC[1,2] sp -I - - ['R SSC[1,2] C +SP:OK'] - initial condition detail: target1 and target2 in STA+AP mode, two targets de-init - and init simple pair - restore cmd set: - - '' - - - SSC SSC[1,2] op -S -o [3,3] - - ['R SSC[1,2] C +MODE:OK'] - - - SSC SSC[1,2] mac -S -m -o 2 - - ['R SSC[1,2] C +MAC:AP,OK'] - - - SSC SSC[1,2] mac -S -m -o 1 - - ['R SSC[1,2] C +MAC:STA,OK'] - - - SSC SSC[1,2] sp -D - - ['R SSC[1,2] C +SP:OK'] - - - SSC SSC[1,2] sp -I - - ['R SSC[1,2] C +SP:OK'] - restore post cmd set: - - '' - - - SSC SSC1 ram - - ['R SSC1 A :(\d+)'] - script path: InitCondBase.py - start: 45.0 - tag: PAIR3 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 op -Q - - ['R SSC1 C +CURMODE:3'] - - - SSC SSC1 sta -D - - ['R SSC1 C +QAP:'] - - - SSC SSC1 dhcp -Q -o 1 - - ['R SSC1 C +DHCP:STA,STARTED'] - - - SSC SSC1 mac -Q -o 1 - - [R SSC1 P ] - force restore cmd set: - - '' - - - SSC SSC1 reboot - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 op -S -o 3 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 sta -D - - ['R SSC1 C +QAP:'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 mac -S -o 1 -m - - ['R SSC1 C +MAC:STA,OK'] - initial condition detail: testing sta on sta + ap mode, quit AP (autogen by STAM1) - restore cmd set: - - '' - - - SSC SSC1 op -S -o 3 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 sta -D - - ['R SSC1 C +QAP:'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 mac -S -o 1 -m - - ['R SSC1 C +MAC:STA,OK'] - restore post cmd set: - - '' - - - SSC SSC1 soc -T - - [R SSC1 C +CLOSEALL] - - - SSC SSC1 ram - - ['R SSC1 C +FREEHEAP:'] - script path: InitCondBase.py - start: 45.0 - tag: STAAP1 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 op -Q - - ['R SSC1 C +CURMODE:3'] - - - SSC SSC1 sta -Q - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - - - SSC SSC1 dhcp -Q -o 1 - - ['R SSC1 C +DHCP:STA,STARTED'] - - - SSC SSC1 mac -Q -o 1 - - [R SSC1 P ] - force restore cmd set: - - '' - - - SSC SSC1 reboot - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 op -S -o 3 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 mac -S -o 1 -m - - ['R SSC1 C +MAC:STA,OK'] - - - SSC SSC1 sta -C -s -p - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - initial condition detail: testing sta on sta + ap mode, join AP, DHCP on (autogen - by STAM2) - restore cmd set: - - '' - - - SSC SSC1 op -S -o 3 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 mac -S -o 1 -m - - ['R SSC1 C +MAC:STA,OK'] - - - SSC SSC1 sta -C -s -p - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - restore post cmd set: - - '' - - - SSC SSC1 soc -T - - [R SSC1 C +CLOSEALL] - - - SSC SSC1 ram - - ['R SSC1 C +FREEHEAP:'] - script path: InitCondBase.py - start: 52.0 - tag: STAAP2 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 upgrade -Q -t 1 - - ['R SSC1 C BIN_ID,0'] - - - SSC SSC1 upgrade -Q -t 2 -b 0 - - ['R SSC1 C BIN_INFO,0'] - - - SSC SSC1 op -S -o 3 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 sta -C -s -p - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - force restore cmd set: - - '' - - - SSC SSC1 upgrade -R -r 1 -s - - [R SSC1 NC ERROR C !!!ready!!!] - - - SSC SSC1 op -S -o 3 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 sta -C -s -p - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - - - SOC SOC1 ULISTEN - - [R SOC_COM L OK] - - - SOC SOC1 SETOPT REPLY BIN - - [R SOC_COM C OK] - - - SSC SSC1 upgrade -I -b 0 -f 0 - - ['P SSC1 C +UPGRADE:OK'] - - - SSC SSC1 upgrade -U -i -p -u - - ['P SSC1 C +UPGRADE:SUCCEED'] - - - SSC SSC1 upgrade -R -b 0 - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 sta -C -s -p - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - initial condition detail: APSTA mode, connected to AP, running BIN0 (located on - flash id 0) - restore cmd set: - - '' - - - SSC SSC1 upgrade -Q -t 2 -b 0 - - ['R SSC1 C BIN_INFO,0'] - - - SSC SSC1 upgrade -R -b 0 - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 op -S -o 3 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 sta -C -s -p - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - restore post cmd set: - - '' - - - SSC SSC1 upgrade -D - - ['R SSC1 C +UPGRADE:OK'] - - - SSC SSC1 ram - - ['R SSC1 A :(\d+)'] - script path: InitCondBase.py - start: 24.0 - tag: STAAPBIN0 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 op -Q - - ['R SSC1 C +CURMODE:1'] - - - SSC SSC1 sta -D - - ['R SSC1 C +QAP:'] - - - SSC SSC1 dhcp -Q -o 1 - - ['R SSC1 C +DHCP:STA,STARTED'] - - - SSC SSC1 mac -Q -o 1 - - [R SSC1 P ] - force restore cmd set: - - '' - - - SSC SSC1 reboot - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 op -S -o 1 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 sta -D - - ['R SSC1 C +QAP:'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 mac -S -o 1 -m - - ['R SSC1 C +MAC:STA,OK'] - initial condition detail: sta mode, quit AP, DHCP on, will autogen a TC with initial - condition STAAP1 - restore cmd set: - - '' - - - SSC SSC1 op -S -o 1 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 sta -D - - ['R SSC1 C +QAP:'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 mac -S -o 1 -m - - ['R SSC1 C +MAC:STA,OK'] - restore post cmd set: - - '' - - - SSC SSC1 soc -T - - [R SSC1 C +CLOSEALL] - - - SSC SSC1 ram - - ['R SSC1 C +FREEHEAP:'] - script path: InitCondBase.py - start: 17.0 - tag: STAM1 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 op -Q - - ['R SSC1 C +CURMODE:1'] - - - SSC SSC1 sta -Q - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - - - SSC SSC1 dhcp -Q -o 1 - - ['R SSC1 C +DHCP:STA,STARTED'] - - - SSC SSC1 mac -Q -o 1 - - [R SSC1 P ] - force restore cmd set: - - '' - - - SSC SSC1 reboot - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 op -S -o 1 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 mac -S -o 1 -m - - ['R SSC1 C +MAC:STA,OK'] - - - SSC SSC1 sta -C -s -p - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - initial condition detail: sta mode, join AP, DHCP on, will autogen a TC with initial - condition STAAP2 - restore cmd set: - - '' - - - SSC SSC1 op -S -o 1 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 mac -S -o 1 -m - - ['R SSC1 C +MAC:STA,OK'] - - - SSC SSC1 sta -C -s -p - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - restore post cmd set: - - '' - - - SSC SSC1 soc -T - - [R SSC1 C +CLOSEALL] - - - SSC SSC1 ram - - ['R SSC1 C +FREEHEAP:'] - script path: InitCondBase.py - start: 24.0 - tag: STAM2 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 upgrade -Q -t 1 - - ['R SSC1 C BIN_ID,0'] - - - SSC SSC1 upgrade -Q -t 2 -b 0 - - ['R SSC1 C BIN_INFO,0'] - - - SSC SSC1 op -S -o 1 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 sta -C -s -p - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - force restore cmd set: - - '' - - - SSC SSC1 upgrade -R -r 1 -s - - [R SSC1 NC ERROR C !!!ready!!!] - - - SSC SSC1 op -S -o 1 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 sta -C -s -p - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - - - SOC SOC1 ULISTEN - - [R SOC_COM L OK] - - - SOC SOC1 SETOPT REPLY BIN - - [R SOC_COM C OK] - - - SSC SSC1 upgrade -I -b 0 -f 0 - - ['P SSC1 C +UPGRADE:OK'] - - - SSC SSC1 upgrade -U -i -p -u - - ['P SSC1 C +UPGRADE:SUCCEED'] - - - SSC SSC1 upgrade -R -b 0 - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 sta -C -s -p - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - initial condition detail: STA mode, connected to AP, running BIN0 (located on flash - id 0) - restore cmd set: - - '' - - - SSC SSC1 upgrade -Q -t 2 -b 0 - - ['R SSC1 C BIN_INFO,0'] - - - SSC SSC1 upgrade -R -b 0 - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 op -S -o 1 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 sta -C -s -p - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - restore post cmd set: - - '' - - - SSC SSC1 upgrade -D - - ['R SSC1 C +UPGRADE:OK'] - - - SSC SSC1 ram - - ['R SSC1 A :(\d+)'] - script path: InitCondBase.py - start: 17.0 - tag: STAMBIN0 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 op -Q - - ['R SSC1 C +CURMODE:1'] - - - SSC SSC1 sta -D - - ['R SSC1 C +QAP:'] - - - SSC SSC1 dhcp -Q -o 1 - - ['R SSC1 C +DHCP:STA,STARTED'] - - - SSC SSC1 mac -Q -o 1 - - [R SSC1 P ] - force restore cmd set: - - '' - - - SSC SSC1 reboot - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 op -S -o 1 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 sta -D - - ['R SSC1 C +QAP:'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 mac -S -o 1 -m - - ['R SSC1 C +MAC:STA,OK'] - initial condition detail: sta mode, quit AP, will NOT autogen a TC with initial - condition STAAP1 - restore cmd set: - - '' - - - SSC SSC1 op -S -o 1 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 sta -D - - ['R SSC1 C +QAP:'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 mac -S -o 1 -m - - ['R SSC1 C +MAC:STA,OK'] - restore post cmd set: - - '' - - - SSC SSC1 soc -T - - [R SSC1 C +CLOSEALL] - - - SSC SSC1 ram - - ['R SSC1 C +FREEHEAP:'] - script path: InitCondBase.py - start: 17.0 - tag: STAO1 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 op -Q - - ['R SSC1 C +CURMODE:1'] - - - SSC SSC1 sta -Q - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - - - SSC SSC1 dhcp -Q -o 1 - - ['R SSC1 C +DHCP:STA,STARTED'] - - - SSC SSC1 mac -Q -o 1 - - [R SSC1 P ] - force restore cmd set: - - '' - - - SSC SSC1 reboot - - [R SSC1 C !!!ready!!!] - - - SSC SSC1 op -S -o 1 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 mac -S -o 1 -m - - ['R SSC1 C +MAC:STA,OK'] - - - SSC SSC1 sta -C -s -p - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - initial condition detail: sta mode, join AP, DHCP on, will NOT autogen a TC with - initial condition STAAP2 - restore cmd set: - - '' - - - SSC SSC1 op -S -o 1 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC1 dhcp -S -o 1 - - [R SSC1 C +DHCP] - - - SSC SSC1 mac -S -o 1 -m - - ['R SSC1 C +MAC:STA,OK'] - - - SSC SSC1 sta -C -s -p - - ['R SSC1 RE "\+JAP:CONNECTED,%%s"%%()'] - restore post cmd set: - - '' - - - SSC SSC1 soc -T - - [R SSC1 C +CLOSEALL] - - - SSC SSC1 ram - - ['R SSC1 C +FREEHEAP:'] - script path: InitCondBase.py - start: 24.0 - tag: STAO2 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 op -Q - - ['R SSC1 C +CURMODE:2'] - - - SSC SSC2 op -Q - - ['R SSC2 C +CURMODE:1'] - - - SSC SSC2 sta -D - - ['R SSC2 C +QAP:'] - - - SSC SSC2 soc -T - - [''] - - - SSC SSC1 dhcp -Q -o 2 - - ['R SSC1 C +DHCP:AP,STARTED'] - - - SSC SSC2 dhcp -Q -o 1 - - ['R SSC2 C +DHCP:STA,STARTED'] - - - SSC SSC1 mac -Q -o 2 - - [R SSC1 P ] - - - SSC SSC2 mac -Q -o 1 - - [R SSC2 P ] - force restore cmd set: - - '' - - - SSC SSC1 reboot - - [R SSC1 C !!!ready!!!] - - - SSC SSC2 reboot - - [R SSC2 C !!!ready!!!] - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC2 op -S -o 1 - - ['R SSC2 C +MODE:OK'] - - - SSC SSC2 sta -D - - ['R SSC2 C +QAP:'] - - - SSC SSC2 soc -T - - [''] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC2 dhcp -S -o 1 - - [R SSC2 C +DHCP] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC2 mac -S -o 1 -m - - ['R SSC2 C +MAC:STA,OK'] - initial condition detail: same as T2_1 but will NOT autogen a TC with initial condition - T2_2 - restore cmd set: - - '' - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC2 op -S -o 1 - - ['R SSC2 C +MODE:OK'] - - - SSC SSC2 sta -D - - ['R SSC2 C +QAP:'] - - - SSC SSC2 soc -T - - [''] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC2 dhcp -S -o 1 - - [R SSC2 C +DHCP] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC2 mac -S -o 1 -m - - ['R SSC2 C +MAC:STA,OK'] - restore post cmd set: - - '' - - - SSC SSC1 soc -T - - [R SSC1 C +CLOSEALL] - - - SSC SSC1 ram - - ['R SSC1 C +FREEHEAP:'] - script path: InitCondBase.py - start: 73.0 - tag: T2O_1 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 op -Q - - ['R SSC1 C +CURMODE:2'] - - - SSC SSC2 op -Q - - ['R SSC2 C +CURMODE:1'] - - - SSC SSC2 sta -D - - ['R SSC2 C +QAP:'] - - - SSC SSC2 soc -T - - [''] - - - SSC SSC1 dhcp -Q -o 2 - - ['R SSC1 C +DHCP:AP,STARTED'] - - - SSC SSC2 dhcp -Q -o 1 - - ['R SSC2 C +DHCP:STA,STARTED'] - - - SSC SSC1 mac -Q -o 2 - - [R SSC1 P ] - - - SSC SSC2 mac -Q -o 1 - - [R SSC2 P ] - force restore cmd set: - - '' - - - SSC SSC1 reboot - - [R SSC1 C !!!ready!!!] - - - SSC SSC2 reboot - - [R SSC2 C !!!ready!!!] - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC2 op -S -o 1 - - ['R SSC2 C +MODE:OK'] - - - SSC SSC2 sta -D - - ['R SSC2 C +QAP:'] - - - SSC SSC2 soc -T - - [''] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC2 dhcp -S -o 1 - - [R SSC2 C +DHCP] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC2 mac -S -o 1 -m - - ['R SSC2 C +MAC:STA,OK'] - initial condition detail: target 1 as SoftAP, target 2 as STA, will autogen a TC - with initial condition T2_2 - restore cmd set: - - '' - - - SSC SSC1 op -S -o 2 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC2 op -S -o 1 - - ['R SSC2 C +MODE:OK'] - - - SSC SSC2 sta -D - - ['R SSC2 C +QAP:'] - - - SSC SSC2 soc -T - - [''] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC2 dhcp -S -o 1 - - [R SSC2 C +DHCP] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC2 mac -S -o 1 -m - - ['R SSC2 C +MAC:STA,OK'] - restore post cmd set: - - '' - - - SSC SSC1 soc -T - - [R SSC1 C +CLOSEALL] - - - SSC SSC1 ram - - ['R SSC1 C +FREEHEAP:'] - script path: InitCondBase.py - start: 73.0 - tag: T2_1 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC1 op -Q - - ['R SSC1 C +CURMODE:3'] - - - SSC SSC2 op -Q - - ['R SSC2 C +CURMODE:3'] - - - SSC SSC2 sta -D - - ['R SSC2 C +QAP:'] - - - SSC SSC2 soc -T - - [R SSC2 C +CLOSEALL] - - - SSC SSC1 dhcp -Q -o 2 - - ['R SSC1 C +DHCP:AP,STARTED'] - - - SSC SSC2 dhcp -Q -o 1 - - ['R SSC2 C +DHCP:STA,STARTED'] - - - SSC SSC1 mac -Q -o 2 - - [R SSC1 P ] - - - SSC SSC2 mac -Q -o 1 - - [R SSC2 P ] - force restore cmd set: - - '' - - - SSC SSC1 reboot - - [R SSC1 C !!!ready!!!] - - - SSC SSC2 reboot - - [R SSC2 C !!!ready!!!] - - - SSC SSC1 op -S -o 3 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC2 op -S -o 3 - - ['R SSC2 C +MODE:OK'] - - - SSC SSC2 sta -D - - ['R SSC2 C +QAP:'] - - - SSC SSC2 soc -T - - [R SSC2 C +CLOSEALL] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC2 dhcp -S -o 1 - - [R SSC2 C +DHCP] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC2 mac -S -o 1 -m - - ['R SSC2 C +MAC:STA,OK'] - initial condition detail: target 1 as AP+STA, target 2 as AP+STA (autogen) - restore cmd set: - - '' - - - SSC SSC1 op -S -o 3 - - ['R SSC1 C +MODE:OK'] - - - SSC SSC2 op -S -o 3 - - ['R SSC2 C +MODE:OK'] - - - SSC SSC2 sta -D - - ['R SSC2 C +QAP:'] - - - SSC SSC2 soc -T - - [R SSC2 C +CLOSEALL] - - - SSC SSC1 dhcp -S -o 2 - - [R SSC1 C +DHCP] - - - SSC SSC2 dhcp -S -o 1 - - [R SSC2 C +DHCP] - - - SSC SSC1 mac -S -o 2 -m - - ['R SSC1 C +MAC:AP,OK'] - - - SSC SSC2 mac -S -o 1 -m - - ['R SSC2 C +MAC:STA,OK'] - restore post cmd set: - - '' - - - SSC SSC1 soc -T - - [R SSC1 C +CLOSEALL] - - - SSC SSC1 ram - - ['R SSC1 C +FREEHEAP:'] - script path: InitCondBase.py - start: 80.0 - tag: T2_2 - test script: InitCondBase -- check cmd set: - - '' - - - SSC SSC[1-3] op -Q - - ['R SSC[1-3] C +CURMODE:3'] - - - SSC SSC[1-3] phy -Q -o 3 - - ['R SSC[1-3] C STA,n,40 C AP,n,40'] - force restore cmd set: - - '' - - - SSC SSC[1-3] reboot - - ['R SSC[1-3] C !!!ready!!!'] - - - SSC SSC[1-3] op -S -o 3 - - ['R SSC[1-3] C +MODE:OK'] - - - SSC SSC[1-3] phy -S -o 3 -m n -b 40 - - ['R SSC[1-3] C +PHY:OK'] - initial condition detail: '1. target 1 and target 2 set to AP+STA mode, target 3 - set to STA mode - - 2. all interface of target 2,3 set to 11n ht40 - - 3. config softAP of target 1 and target 2' - restore cmd set: - - '' - - - SSC SSC[1-3] op -S -o 3 - - ['R SSC[1-3] C +MODE:OK'] - - - SSC SSC[1-3] phy -S -o 3 -m n -b 40 - - ['R SSC[1-3] C +PHY:OK'] - restore post cmd set: - - '' - - - SSC SSC1 soc -T - - [R SSC1 C +CLOSEALL] - - - SSC SSC1 sta -R -r 1 - - [R SSC1 C OK] - - - SSC SSC1 ram - - ['R SSC1 A :(\d+)'] - script path: InitCondBase.py - start: 87.0 - tag: T3_PHY1 - test script: InitCondBase -- check cmd set: - - '' - - - FREBOOT UT1 - - ['R UT1 C Press%20ENTER%20to%20see%20the%20list%20of%20tests'] - force restore cmd set: - - '' - - - FREBOOT UT1 - - ['R UT1 C Press%20ENTER%20to%20see%20the%20list%20of%20tests'] - initial condition detail: At UT menu page - restore cmd set: - - '' - - - FREBOOT UT1 - - ['R UT1 C Press%20ENTER%20to%20see%20the%20list%20of%20tests'] - restore post cmd set: - - '' - - - DELAY 0.1 - - [''] - script path: InitCondBase.py - tag: UTINIT1 - test script: InitCondBase diff --git a/components/idf_test/unit_test/TestCaseScript/IDFUnitTest/__init__.py b/components/idf_test/unit_test/TestCaseScript/IDFUnitTest/__init__.py deleted file mode 100755 index 876a5d4023..0000000000 --- a/components/idf_test/unit_test/TestCaseScript/IDFUnitTest/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__all__ = ["UnitTest"] diff --git a/components/idf_test/unit_test/TestEnvAll.yml b/components/idf_test/unit_test/TestEnvAll.yml deleted file mode 100644 index a6054cf512..0000000000 --- a/components/idf_test/unit_test/TestEnvAll.yml +++ /dev/null @@ -1,292 +0,0 @@ -test environment: -- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_1, - test environment detail: 'PC has 2 wired NIC connected to AP. - - PC has 1 WiFi NIC. - - 1 AT target connect with PC by UART (AT and LOG port).', test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_2, - test environment detail: 'PC has 1 WiFi NIC. - - 1 AT target connect with PC by UART (AT and LOG port).', test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_3, - test environment detail: 'Able to access WAN after connect to AP. - - 1 AT target connect with PC by UART (AT and LOG port).', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_ADC, - test environment detail: 'PC has 1 wired NIC connected to AP. - - Analog input connect to AT1 TOUT. - - Multimeter connect to input, able to measure input voltage. - - 1 AT target connect with PC by UART (AT and LOG port).', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_APC1, - test environment detail: "PC has 1 wired NIC connected to AP.\nPC has 1 wired NIC\ - \ connected to APC (static IP within the same subnet with APC). \nAPC control\ - \ AP power supply. \nPC has 1 WiFi NIC. \n1 AT target connect with PC by UART\ - \ (AT and LOG port).", test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_APC2, - test environment detail: "Able to access WAN after connect to AP.\nPC has 1 wired\ - \ NIC connected to APC (static IP within the same subnet with APC). \nAPC control\ - \ AP power supply.\nPC has 1 WiFi NIC.\n1 AT target connect with PC by UART (AT\ - \ and LOG port).", test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_HighSpeedUART, - test environment detail: 'PC has 2 wired NIC connected to AP. - - PC has 1 WiFi NIC. - - 1 AT target connect with PC by high speed UART (AT and LOG port).', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: AT_T1_SmartConfigIOT, - test environment detail: '1 AT target connect with PC by UART (AT and LOG port). - - PC has 1 wired NIC connect to Common AP. - - Several AP are placed near AT target. - - Several smart phone installed test APK are placed near AT target.', test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 2.0, script path: EnvBase.py, tag: AT_T2_1, - test environment detail: 'PC has 1 wired NIC connected to AP. - - PC has 1 WiFi NIC. - - 2 AT target connect with PC by UART (AT and LOG port).', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 2.0, script path: EnvBase.py, tag: AT_T2_JAP, - test environment detail: "Several AP are placed near AT target.\nPC has 1 wired\ - \ NIC connected to APC (static IP within the same subnet with APC).\nAPC control\ - \ power supply for all APs. \n2 AT target connect with PC by UART (AT and LOG\ - \ port).", test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 2.0, script path: EnvBase.py, tag: AT_T2_Sleep, - test environment detail: 'AP support DTIM placed with AT target. - - 2 AT target connect with PC by UART (AT and LOG port). - - Multimeter connect with PC via GPIB. - - Series multimeter between GND and VCC of AT1. - - AT1''s light sleep wakeup pin and wakeup indication connect with AT2''s GPIO.', - test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 2.0, script path: EnvBase.py, tag: AT_T2_SmartConfig, - test environment detail: '2 AT target connect with PC by UART (AT and LOG port). - - PC has 1 WiFi NIC. - - One HT20 AP and One HT40 AP are placed near target.', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, UART ports: 'SSC1 - - SSC2', additional param list: '', basic param list: '', script path: EnvBase.py, - tag: IR_T2_1, test environment detail: '[TBD] 本测试为非自动测试, 红外能够做到数据收发吻合即可通过', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 2.0, script path: EnvBase.py, tag: NVS_T1_1, - test environment detail: '1 NVS target connect with PC by UART. - - 1 SSC target connect with PC by UART. - - SSC2 GPIO connect to NVS1 power control pin.', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, UART ports: SSC_1, additional param list: '', - basic param list: '', script path: EnvBase.py, tag: PWM_T1_1, test environment detail: "[TBD]\ - \ 1. PWM OS SDK 以及 Non-OS SDK的测试建议分开进行, 放在不同的文件夹, 防止文件命名混淆\n2. 分析CSV文件的Python脚本只能分析单个channel\ - \ \n3. 如果Init脚本打印\"Network Error\" 检查TCP Server是不是正常发送data", test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_1, - test environment detail: 'PC has 2 wired NIC connected to AP. - - PC has 1 WiFi NIC. - - 1 SSC target connect with PC by UART.', test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_2, - test environment detail: 'Able to access WAN after connect to AP. - - 1 SSC target connect with PC by UART.', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_8089, - test environment detail: 'PC has 1 wired NIC connected to AP. - - 1 8089 tablet able to run iperf test placed near SSC1. - - 1 SSC target connect with PC by UART.', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_ADC, - test environment detail: 'PC has 1 wired NIC connected to AP. - - Analog input connect to SSC1 TOUT. - - Multimeter connect to input, able to measure input voltage. - - 1 SSC target connect with PC by UART.', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_APC, - test environment detail: "PC has 1 wired NIC connected to AP.\nPC has 1 wired NIC\ - \ connected to APC (static IP within the same subnet with APC). \nAPC control\ - \ AP power supply. \nPC has 1 WiFi NIC. \n1 SSC target connect with PC by UART.", - test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_Enterprise, - test environment detail: "AP use WPA2-Etherprise is placed near SSC1. \n1 SSC target\ - \ connect with PC by UART.", test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_IOT1, - test environment detail: 'PC has 1 WiFi NIC. - - 1 SSC target connect with PC by UART. - - AP todo IOT test are placed near SSC1.', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 2.0, script path: EnvBase.py, tag: SSC_T1_InitData, - test environment detail: '2 SSC target connect with PC by UART. - - SSC1 use 40M crystal oscillator. - - SSC2 use normal 26M crystal oscillator. - - SSC2 GPIO connect to SSC1 power control pin.', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_ShieldBox, - test environment detail: 'refer to figure. - - All APs and APC should be set to the same IP subnet. - - PC wired NIC should set static IP address within the same subnet with AP. - - Must use onboard wired NIC.', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_Sleep1, - test environment detail: 'AP support DTIM placed with AT target. - - SSC target connect with Raspberry Pi by UART. - - Multimeter connect with Raspberry Pi via GPIB. - - Series multimeter between GND and VCC of SSC1. - - SSC1''s light sleep wakeup pin and wakeup indication connect with Raspberry Pi''s - GPIO. - - SSC1''s XPD connect with RSTB.', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_Sleep2, - test environment detail: 'AP support DTIM placed with AT target. - - SSC target connect with Raspberry Pi by UART. - - Multimeter connect with Raspberry Pi via GPIB. - - Series multimeter between GND and VCC of SSC1. - - SSC1''s RSTB pin connect with Raspberry Pi''s GPIO.', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_TempBox, - test environment detail: '1 SSC target connect with PC by UART. - - Put SSC target to temperature box.', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, UART ports: SSC_1, additional param list: '', - basic param list: '', script path: EnvBase.py, tag: SSC_T1_Timer, test environment detail: '[TBD] - 通过串口工具调节Timer, 将GPIO_13端口连接到逻辑分析仪', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_VDD33, - test environment detail: '1 SSC target connect with PC by UART. - - Multimeter connect to VDD33, able to measure voltage.', test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T1_WEP, - test environment detail: '1 SSC target connect with PC by UART. - - One WEP share key AP placed near SSC1.', test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 2.0, script path: EnvBase.py, tag: SSC_T2_1, - test environment detail: 'PC has 1 wired NIC connected to AP. - - PC has 1 WiFi NIC. - - 2 SSC target connect with PC by UART.', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 2.0, UART ports: 'SSC1 - - SSC2', additional param list: '', basic param list: '', script path: EnvBase.py, - tag: SSC_T2_GPIO1, test environment detail: '[TBD] 2个ESP_8266通过UART连到PC, ESP_8266的 - GPIO_6相连', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 2.0, UART ports: 'SSC1 - - SSC2', additional param list: '', basic param list: '', script path: EnvBase.py, - tag: SSC_T2_GPIO2, test environment detail: '[TBD] 1. 2个ESP_8266通过UART连到PC, ESP_8266的 - GPIO_15通过面包板相连 - - 2. 可借助面包板, 将GPIO_15, 以及中断函数被打开的8266板的GPIO_2 相连', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 2.0, UART ports: 'SSC1 - - SSC2', additional param list: '', basic param list: '', script path: EnvBase.py, - tag: SSC_T2_GPIO3, test environment detail: '[TBD] 2个ESP_8266通过UART连到PC, ESP_8266之间需要测试的Target_GPIO相连', - test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 2.0, script path: EnvBase.py, tag: SSC_T2_JAP, - test environment detail: 'PC has 1 wired NIC connected to APC. - - APC control the power supply of multiple APs. - - 2 SSC target connect with PC by UART.', test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 2.0, script path: EnvBase.py, tag: SSC_T2_PhyMode, - test environment detail: '2 SSC target connect with PC by UART. - - PC has one WiFi NIC support capture wlan packet using libpcap. - - Set 4 AP with phy mode 11b, 11g, 11n HT20, 11n HT40. - - Put 4 APs near SSC targets.', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 2.0, script path: EnvBase.py, tag: SSC_T2_ShieldBox, - test environment detail: '2 SSC target connect with PC by UART. - - Put them to Shield box.', test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 2.0, script path: EnvBase.py, tag: SSC_T2_SmartConfig, - test environment detail: '2 SSC target connect with PC by UART. - - PC has 1 WiFi NIC. - - One HT20 AP and One HT40 AP are placed near target.', test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 3.0, script path: EnvBase.py, tag: SSC_T3_PhyMode, - test environment detail: '3 SSC target connect with PC by UART. - - PC has one WiFi NIC support capture wlan packet using libpcap. - - Set 4 AP with (HT20, channel1), (HT20, channel2), (HT40, channel1), (HT40, channel2). - - Put 4 APs near SSC targets.', test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 5.0, script path: EnvBase.py, tag: SSC_T5_1, - test environment detail: 5 SSC target connect with PC by UART., test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 5.0, script path: EnvBase.py, tag: SSC_T5_IOT1, - test environment detail: '5 SSC targets connect with PC by UART. - - some Android smart phone are placed near SSC targets.', test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: SSC_T6_1, - test environment detail: 'PC has 1 wired NIC connected to AP. - - PC has 1 WiFi NIC. - - 6 SSC target connect with PC by UART.', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: TempSensor_T1_1, - test environment detail: 'Tempeture sensor target connect with PC by UART. - - AP support DTIM placed with AT target. - - Multimeter connect with PC via GPIB. - - Series multimeter between GND and VCC of TempSensor1. - - PC has 1 wired NIC connected to switch. - - APC, AP also connect with swtich. - - All devices connected with switch use the same IP subnet. - - APC control AP power supply.', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, UART ports: SSC_1, additional param list: '', - basic param list: '', script path: EnvBase.py, tag: UART_T1_1, test environment detail: '[TBD] - 将ESP_8266通过UART连到PC', test script: EnvBase} -- {PC OS: '', Special: Y, Target Count: 1.0, UART ports: 'SSC1 - - SSC2', additional param list: '', basic param list: '', script path: EnvBase.py, - tag: UART_T1_2, test environment detail: '[TBD] ESP_8266通过UART_0通过USB, UART_1 TXD - 通过 TTLcable 连到PC', test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: UT_T1_1, - test environment detail: Environment for running ESP32 unit tests, test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: UT_T1_SDMODE, - test environment detail: Environment for running sd card sd mode unit tests, test script: EnvBase} -- {PC OS: '', Special: N, Target Count: 1.0, script path: EnvBase.py, tag: UT_T1_SPIMODE, - test environment detail: Environment for running sd card spi mode unit tests, test script: EnvBase} -- {PC OS: linux, Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: WebServer_T1_1, - test environment detail: 'Web Server target connect with PC by UART. - - PC has 1 wired NIC connected to switch. - - APC, AP also connect with swtich. - - All devices connected with switch use same IP subnet. - - APC control AP power supply.', test script: EnvBase} -- {PC OS: linux, Special: Y, Target Count: 1.0, script path: EnvBase.py, tag: WebServer_T1_2, - test environment detail: 'Web Server target connect with PC by UART. - - 4 PC with WiFi NIC placed near WebServer1.', test script: EnvBase} diff --git a/components/jsmn/CMakeLists.txt b/components/jsmn/CMakeLists.txt index 562a2cadcb..0c7a0ab99e 100644 --- a/components/jsmn/CMakeLists.txt +++ b/components/jsmn/CMakeLists.txt @@ -1,3 +1,2 @@ -set(COMPONENT_SRCS "src/jsmn.c") -set(COMPONENT_ADD_INCLUDEDIRS "include") -register_component() +idf_component_register(SRCS "src/jsmn.c" + INCLUDE_DIRS "include") diff --git a/components/json/CMakeLists.txt b/components/json/CMakeLists.txt index 4a85a0b3d1..1ecadb3858 100644 --- a/components/json/CMakeLists.txt +++ b/components/json/CMakeLists.txt @@ -1,5 +1,4 @@ -set(COMPONENT_SRCS "cJSON/cJSON.c" - "cJSON/cJSON_Utils.c" - "cJSON/test.c") -set(COMPONENT_ADD_INCLUDEDIRS cJSON) -register_component() +idf_component_register(SRCS "cJSON/cJSON.c" + "cJSON/cJSON_Utils.c" + "cJSON/test.c" + INCLUDE_DIRS cJSON) diff --git a/components/libsodium/CMakeLists.txt b/components/libsodium/CMakeLists.txt index f0d5afc9da..103e296612 100644 --- a/components/libsodium/CMakeLists.txt +++ b/components/libsodium/CMakeLists.txt @@ -1,133 +1,137 @@ set(SRC libsodium/src/libsodium) # Derived from libsodium/src/libsodium/Makefile.am # (ignoring the !MINIMAL set) -set(COMPONENT_SRCS "${SRC}/crypto_aead/chacha20poly1305/sodium/aead_chacha20poly1305.c" - "${SRC}/crypto_aead/xchacha20poly1305/sodium/aead_xchacha20poly1305.c" - "${SRC}/crypto_auth/crypto_auth.c" - "${SRC}/crypto_auth/hmacsha256/auth_hmacsha256.c" - "${SRC}/crypto_auth/hmacsha512/auth_hmacsha512.c" - "${SRC}/crypto_auth/hmacsha512256/auth_hmacsha512256.c" - "${SRC}/crypto_box/crypto_box.c" - "${SRC}/crypto_box/crypto_box_easy.c" - "${SRC}/crypto_box/crypto_box_seal.c" - "${SRC}/crypto_box/curve25519xchacha20poly1305/box_curve25519xchacha20poly1305.c" - "${SRC}/crypto_box/curve25519xsalsa20poly1305/box_curve25519xsalsa20poly1305.c" - "${SRC}/crypto_core/curve25519/ref10/curve25519_ref10.c" - "${SRC}/crypto_core/hchacha20/core_hchacha20.c" - "${SRC}/crypto_core/hsalsa20/core_hsalsa20.c" - "${SRC}/crypto_core/hsalsa20/ref2/core_hsalsa20_ref2.c" - "${SRC}/crypto_core/salsa/ref/core_salsa_ref.c" - "${SRC}/crypto_generichash/crypto_generichash.c" - "${SRC}/crypto_generichash/blake2b/generichash_blake2.c" - "${SRC}/crypto_generichash/blake2b/ref/blake2b-compress-avx2.c" - "${SRC}/crypto_generichash/blake2b/ref/blake2b-compress-ref.c" - "${SRC}/crypto_generichash/blake2b/ref/blake2b-compress-sse41.c" - "${SRC}/crypto_generichash/blake2b/ref/blake2b-compress-ssse3.c" - "${SRC}/crypto_generichash/blake2b/ref/blake2b-ref.c" - "${SRC}/crypto_generichash/blake2b/ref/generichash_blake2b.c" - "${SRC}/crypto_hash/crypto_hash.c" - "${SRC}/crypto_hash/sha256/hash_sha256.c" - "${SRC}/crypto_hash/sha256/cp/hash_sha256_cp.c" - "${SRC}/crypto_hash/sha512/hash_sha512.c" - "${SRC}/crypto_hash/sha512/cp/hash_sha512_cp.c" - "${SRC}/crypto_kdf/crypto_kdf.c" - "${SRC}/crypto_kdf/blake2b/kdf_blake2b.c" - "${SRC}/crypto_kx/crypto_kx.c" - "${SRC}/crypto_onetimeauth/crypto_onetimeauth.c" - "${SRC}/crypto_onetimeauth/poly1305/onetimeauth_poly1305.c" - "${SRC}/crypto_onetimeauth/poly1305/donna/poly1305_donna.c" - "${SRC}/crypto_onetimeauth/poly1305/sse2/poly1305_sse2.c" - "${SRC}/crypto_pwhash/crypto_pwhash.c" - "${SRC}/crypto_pwhash/argon2/argon2-core.c" - "${SRC}/crypto_pwhash/argon2/argon2-encoding.c" - "${SRC}/crypto_pwhash/argon2/argon2-fill-block-ref.c" - "${SRC}/crypto_pwhash/argon2/argon2-fill-block-ssse3.c" - "${SRC}/crypto_pwhash/argon2/argon2.c" - "${SRC}/crypto_pwhash/argon2/blake2b-long.c" - "${SRC}/crypto_pwhash/argon2/pwhash_argon2i.c" - "${SRC}/crypto_pwhash/scryptsalsa208sha256/crypto_scrypt-common.c" - "${SRC}/crypto_pwhash/scryptsalsa208sha256/pbkdf2-sha256.c" - "${SRC}/crypto_pwhash/scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c" - "${SRC}/crypto_pwhash/scryptsalsa208sha256/scrypt_platform.c" - "${SRC}/crypto_pwhash/scryptsalsa208sha256/nosse/pwhash_scryptsalsa208sha256_nosse.c" - "${SRC}/crypto_pwhash/scryptsalsa208sha256/sse/pwhash_scryptsalsa208sha256_sse.c" - "${SRC}/crypto_scalarmult/crypto_scalarmult.c" - "${SRC}/crypto_scalarmult/curve25519/scalarmult_curve25519.c" - "${SRC}/crypto_scalarmult/curve25519/donna_c64/curve25519_donna_c64.c" - "${SRC}/crypto_scalarmult/curve25519/ref10/x25519_ref10.c" - "${SRC}/crypto_scalarmult/curve25519/sandy2x/consts.S" - "${SRC}/crypto_scalarmult/curve25519/sandy2x/curve25519_sandy2x.c" - "${SRC}/crypto_scalarmult/curve25519/sandy2x/fe51_invert.c" - "${SRC}/crypto_scalarmult/curve25519/sandy2x/fe51_mul.S" - "${SRC}/crypto_scalarmult/curve25519/sandy2x/fe51_nsquare.S" - "${SRC}/crypto_scalarmult/curve25519/sandy2x/fe51_pack.S" - "${SRC}/crypto_scalarmult/curve25519/sandy2x/fe_frombytes_sandy2x.c" - "${SRC}/crypto_scalarmult/curve25519/sandy2x/ladder.S" - "${SRC}/crypto_scalarmult/curve25519/sandy2x/ladder_base.S" - "${SRC}/crypto_scalarmult/curve25519/sandy2x/sandy2x.S" - "${SRC}/crypto_secretbox/crypto_secretbox.c" - "${SRC}/crypto_secretbox/crypto_secretbox_easy.c" - "${SRC}/crypto_secretbox/xchacha20poly1305/secretbox_xchacha20poly1305.c" - "${SRC}/crypto_secretbox/xsalsa20poly1305/secretbox_xsalsa20poly1305.c" - "${SRC}/crypto_shorthash/crypto_shorthash.c" - "${SRC}/crypto_shorthash/siphash24/shorthash_siphash24.c" - "${SRC}/crypto_shorthash/siphash24/shorthash_siphashx24.c" - "${SRC}/crypto_shorthash/siphash24/ref/shorthash_siphash24_ref.c" - "${SRC}/crypto_shorthash/siphash24/ref/shorthash_siphashx24_ref.c" - "${SRC}/crypto_sign/crypto_sign.c" - "${SRC}/crypto_sign/ed25519/sign_ed25519.c" - "${SRC}/crypto_sign/ed25519/ref10/keypair.c" - "${SRC}/crypto_sign/ed25519/ref10/obsolete.c" - "${SRC}/crypto_sign/ed25519/ref10/open.c" - "${SRC}/crypto_sign/ed25519/ref10/sign.c" - "${SRC}/crypto_stream/crypto_stream.c" - "${SRC}/crypto_stream/aes128ctr/stream_aes128ctr.c" - "${SRC}/crypto_stream/aes128ctr/nacl/afternm_aes128ctr.c" - "${SRC}/crypto_stream/aes128ctr/nacl/beforenm_aes128ctr.c" - "${SRC}/crypto_stream/aes128ctr/nacl/consts_aes128ctr.c" - "${SRC}/crypto_stream/aes128ctr/nacl/int128_aes128ctr.c" - "${SRC}/crypto_stream/aes128ctr/nacl/stream_aes128ctr_nacl.c" - "${SRC}/crypto_stream/aes128ctr/nacl/xor_afternm_aes128ctr.c" - "${SRC}/crypto_stream/chacha20/stream_chacha20.c" - "${SRC}/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-avx2.c" - "${SRC}/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-ssse3.c" - "${SRC}/crypto_stream/chacha20/ref/chacha20_ref.c" - "${SRC}/crypto_stream/salsa20/stream_salsa20.c" - "${SRC}/crypto_stream/salsa20/ref/salsa20_ref.c" - "${SRC}/crypto_stream/salsa20/xmm6/salsa20_xmm6-asm.S" - "${SRC}/crypto_stream/salsa20/xmm6/salsa20_xmm6.c" - "${SRC}/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-avx2.c" - "${SRC}/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-sse2.c" - "${SRC}/crypto_stream/salsa2012/stream_salsa2012.c" - "${SRC}/crypto_stream/salsa2012/ref/stream_salsa2012_ref.c" - "${SRC}/crypto_stream/salsa208/stream_salsa208.c" - "${SRC}/crypto_stream/salsa208/ref/stream_salsa208_ref.c" - "${SRC}/crypto_stream/xchacha20/stream_xchacha20.c" - "${SRC}/crypto_stream/xsalsa20/stream_xsalsa20.c" - "${SRC}/crypto_verify/sodium/verify.c" - "${SRC}/randombytes/randombytes.c" - "${SRC}/randombytes/nativeclient/randombytes_nativeclient.c" - "${SRC}/randombytes/salsa20/randombytes_salsa20_random.c" - "${SRC}/randombytes/sysrandom/randombytes_sysrandom.c" - "${SRC}/sodium/core.c" - "${SRC}/sodium/runtime.c" - "${SRC}/sodium/utils.c" - "${SRC}/sodium/version.c" - "port/randombytes_esp32.c") +set(srcs + "${SRC}/crypto_aead/chacha20poly1305/sodium/aead_chacha20poly1305.c" + "${SRC}/crypto_aead/xchacha20poly1305/sodium/aead_xchacha20poly1305.c" + "${SRC}/crypto_auth/crypto_auth.c" + "${SRC}/crypto_auth/hmacsha256/auth_hmacsha256.c" + "${SRC}/crypto_auth/hmacsha512/auth_hmacsha512.c" + "${SRC}/crypto_auth/hmacsha512256/auth_hmacsha512256.c" + "${SRC}/crypto_box/crypto_box.c" + "${SRC}/crypto_box/crypto_box_easy.c" + "${SRC}/crypto_box/crypto_box_seal.c" + "${SRC}/crypto_box/curve25519xchacha20poly1305/box_curve25519xchacha20poly1305.c" + "${SRC}/crypto_box/curve25519xsalsa20poly1305/box_curve25519xsalsa20poly1305.c" + "${SRC}/crypto_core/curve25519/ref10/curve25519_ref10.c" + "${SRC}/crypto_core/hchacha20/core_hchacha20.c" + "${SRC}/crypto_core/hsalsa20/core_hsalsa20.c" + "${SRC}/crypto_core/hsalsa20/ref2/core_hsalsa20_ref2.c" + "${SRC}/crypto_core/salsa/ref/core_salsa_ref.c" + "${SRC}/crypto_generichash/crypto_generichash.c" + "${SRC}/crypto_generichash/blake2b/generichash_blake2.c" + "${SRC}/crypto_generichash/blake2b/ref/blake2b-compress-avx2.c" + "${SRC}/crypto_generichash/blake2b/ref/blake2b-compress-ref.c" + "${SRC}/crypto_generichash/blake2b/ref/blake2b-compress-sse41.c" + "${SRC}/crypto_generichash/blake2b/ref/blake2b-compress-ssse3.c" + "${SRC}/crypto_generichash/blake2b/ref/blake2b-ref.c" + "${SRC}/crypto_generichash/blake2b/ref/generichash_blake2b.c" + "${SRC}/crypto_hash/crypto_hash.c" + "${SRC}/crypto_hash/sha256/hash_sha256.c" + "${SRC}/crypto_hash/sha256/cp/hash_sha256_cp.c" + "${SRC}/crypto_hash/sha512/hash_sha512.c" + "${SRC}/crypto_hash/sha512/cp/hash_sha512_cp.c" + "${SRC}/crypto_kdf/crypto_kdf.c" + "${SRC}/crypto_kdf/blake2b/kdf_blake2b.c" + "${SRC}/crypto_kx/crypto_kx.c" + "${SRC}/crypto_onetimeauth/crypto_onetimeauth.c" + "${SRC}/crypto_onetimeauth/poly1305/onetimeauth_poly1305.c" + "${SRC}/crypto_onetimeauth/poly1305/donna/poly1305_donna.c" + "${SRC}/crypto_onetimeauth/poly1305/sse2/poly1305_sse2.c" + "${SRC}/crypto_pwhash/crypto_pwhash.c" + "${SRC}/crypto_pwhash/argon2/argon2-core.c" + "${SRC}/crypto_pwhash/argon2/argon2-encoding.c" + "${SRC}/crypto_pwhash/argon2/argon2-fill-block-ref.c" + "${SRC}/crypto_pwhash/argon2/argon2-fill-block-ssse3.c" + "${SRC}/crypto_pwhash/argon2/argon2.c" + "${SRC}/crypto_pwhash/argon2/blake2b-long.c" + "${SRC}/crypto_pwhash/argon2/pwhash_argon2i.c" + "${SRC}/crypto_pwhash/scryptsalsa208sha256/crypto_scrypt-common.c" + "${SRC}/crypto_pwhash/scryptsalsa208sha256/pbkdf2-sha256.c" + "${SRC}/crypto_pwhash/scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c" + "${SRC}/crypto_pwhash/scryptsalsa208sha256/scrypt_platform.c" + "${SRC}/crypto_pwhash/scryptsalsa208sha256/nosse/pwhash_scryptsalsa208sha256_nosse.c" + "${SRC}/crypto_pwhash/scryptsalsa208sha256/sse/pwhash_scryptsalsa208sha256_sse.c" + "${SRC}/crypto_scalarmult/crypto_scalarmult.c" + "${SRC}/crypto_scalarmult/curve25519/scalarmult_curve25519.c" + "${SRC}/crypto_scalarmult/curve25519/donna_c64/curve25519_donna_c64.c" + "${SRC}/crypto_scalarmult/curve25519/ref10/x25519_ref10.c" + "${SRC}/crypto_scalarmult/curve25519/sandy2x/consts.S" + "${SRC}/crypto_scalarmult/curve25519/sandy2x/curve25519_sandy2x.c" + "${SRC}/crypto_scalarmult/curve25519/sandy2x/fe51_invert.c" + "${SRC}/crypto_scalarmult/curve25519/sandy2x/fe51_mul.S" + "${SRC}/crypto_scalarmult/curve25519/sandy2x/fe51_nsquare.S" + "${SRC}/crypto_scalarmult/curve25519/sandy2x/fe51_pack.S" + "${SRC}/crypto_scalarmult/curve25519/sandy2x/fe_frombytes_sandy2x.c" + "${SRC}/crypto_scalarmult/curve25519/sandy2x/ladder.S" + "${SRC}/crypto_scalarmult/curve25519/sandy2x/ladder_base.S" + "${SRC}/crypto_scalarmult/curve25519/sandy2x/sandy2x.S" + "${SRC}/crypto_secretbox/crypto_secretbox.c" + "${SRC}/crypto_secretbox/crypto_secretbox_easy.c" + "${SRC}/crypto_secretbox/xchacha20poly1305/secretbox_xchacha20poly1305.c" + "${SRC}/crypto_secretbox/xsalsa20poly1305/secretbox_xsalsa20poly1305.c" + "${SRC}/crypto_shorthash/crypto_shorthash.c" + "${SRC}/crypto_shorthash/siphash24/shorthash_siphash24.c" + "${SRC}/crypto_shorthash/siphash24/shorthash_siphashx24.c" + "${SRC}/crypto_shorthash/siphash24/ref/shorthash_siphash24_ref.c" + "${SRC}/crypto_shorthash/siphash24/ref/shorthash_siphashx24_ref.c" + "${SRC}/crypto_sign/crypto_sign.c" + "${SRC}/crypto_sign/ed25519/sign_ed25519.c" + "${SRC}/crypto_sign/ed25519/ref10/keypair.c" + "${SRC}/crypto_sign/ed25519/ref10/obsolete.c" + "${SRC}/crypto_sign/ed25519/ref10/open.c" + "${SRC}/crypto_sign/ed25519/ref10/sign.c" + "${SRC}/crypto_stream/crypto_stream.c" + "${SRC}/crypto_stream/aes128ctr/stream_aes128ctr.c" + "${SRC}/crypto_stream/aes128ctr/nacl/afternm_aes128ctr.c" + "${SRC}/crypto_stream/aes128ctr/nacl/beforenm_aes128ctr.c" + "${SRC}/crypto_stream/aes128ctr/nacl/consts_aes128ctr.c" + "${SRC}/crypto_stream/aes128ctr/nacl/int128_aes128ctr.c" + "${SRC}/crypto_stream/aes128ctr/nacl/stream_aes128ctr_nacl.c" + "${SRC}/crypto_stream/aes128ctr/nacl/xor_afternm_aes128ctr.c" + "${SRC}/crypto_stream/chacha20/stream_chacha20.c" + "${SRC}/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-avx2.c" + "${SRC}/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-ssse3.c" + "${SRC}/crypto_stream/chacha20/ref/chacha20_ref.c" + "${SRC}/crypto_stream/salsa20/stream_salsa20.c" + "${SRC}/crypto_stream/salsa20/ref/salsa20_ref.c" + "${SRC}/crypto_stream/salsa20/xmm6/salsa20_xmm6-asm.S" + "${SRC}/crypto_stream/salsa20/xmm6/salsa20_xmm6.c" + "${SRC}/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-avx2.c" + "${SRC}/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-sse2.c" + "${SRC}/crypto_stream/salsa2012/stream_salsa2012.c" + "${SRC}/crypto_stream/salsa2012/ref/stream_salsa2012_ref.c" + "${SRC}/crypto_stream/salsa208/stream_salsa208.c" + "${SRC}/crypto_stream/salsa208/ref/stream_salsa208_ref.c" + "${SRC}/crypto_stream/xchacha20/stream_xchacha20.c" + "${SRC}/crypto_stream/xsalsa20/stream_xsalsa20.c" + "${SRC}/crypto_verify/sodium/verify.c" + "${SRC}/randombytes/randombytes.c" + "${SRC}/randombytes/nativeclient/randombytes_nativeclient.c" + "${SRC}/randombytes/salsa20/randombytes_salsa20_random.c" + "${SRC}/randombytes/sysrandom/randombytes_sysrandom.c" + "${SRC}/sodium/core.c" + "${SRC}/sodium/runtime.c" + "${SRC}/sodium/utils.c" + "${SRC}/sodium/version.c" + "port/randombytes_esp32.c") if(CONFIG_LIBSODIUM_USE_MBEDTLS_SHA) - list(APPEND COMPONENT_SRCS "port/crypto_hash_mbedtls/crypto_hash_sha256_mbedtls.c" - "port/crypto_hash_mbedtls/crypto_hash_sha512_mbedtls.c") + list(APPEND srcs + "port/crypto_hash_mbedtls/crypto_hash_sha256_mbedtls.c" + "port/crypto_hash_mbedtls/crypto_hash_sha512_mbedtls.c") else() - list(APPEND COMPONENT_SRCS "${SRC}/crypto_hash/sha256/cp/hash_sha256_cp.c" - "${SRC}/crypto_hash/sha512/cp/hash_sha512_cp.c") + list(APPEND srcs + "${SRC}/crypto_hash/sha256/cp/hash_sha256_cp.c" + "${SRC}/crypto_hash/sha512/cp/hash_sha512_cp.c") endif() -set(COMPONENT_ADD_INCLUDEDIRS ${SRC}/include port_include) -set(COMPONENT_PRIV_INCLUDEDIRS ${SRC}/include/sodium port_include/sodium port) - -set(COMPONENT_REQUIRES mbedtls vfs) -register_component() +set(include_dirs ${SRC}/include port_include) +set(priv_include_dirs ${SRC}/include/sodium port_include/sodium port) +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS "${include_dirs}" + PRIV_INCLUDE_DIRS "${priv_include_dirs}" + REQUIRES mbedtls) target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIGURED diff --git a/components/libsodium/test/CMakeLists.txt b/components/libsodium/test/CMakeLists.txt index 76ac24d2fc..2e3a43bad6 100644 --- a/components/libsodium/test/CMakeLists.txt +++ b/components/libsodium/test/CMakeLists.txt @@ -2,11 +2,7 @@ if(TESTS_ALL EQUAL 1) message("not linking libsodium tests, use '-T libsodium' to test it") else() get_filename_component(LS_TESTDIR "${CMAKE_CURRENT_LIST_DIR}/../libsodium/test/default" ABSOLUTE) - - set(COMPONENT_ADD_INCLUDEDIRS "." "${LS_TESTDIR}/../quirks") - - set(COMPONENT_REQUIRES unity libsodium) - + set(TEST_CASES "chacha20;aead_chacha20poly1305;box;box2;ed25519_convert;sign;hash") foreach(test_case ${TEST_CASES}) @@ -14,9 +10,9 @@ else() list(APPEND TEST_CASES_FILES ${test_case_file}) endforeach() - set(COMPONENT_SRCS "${TEST_CASES_FILES};test_sodium.c") - - register_component() + idf_component_register(SRCS "${TEST_CASES_FILES}" "test_sodium.c" + INCLUDE_DIRS "." "${LS_TESTDIR}/../quirks" + REQUIRES unity libsodium) # The libsodium test suite is designed to be run each test case as an executable on a desktop computer and uses # filesytem to write & then compare contents of each file. diff --git a/components/log/CMakeLists.txt b/components/log/CMakeLists.txt index 505dc93186..4ca3c1a544 100644 --- a/components/log/CMakeLists.txt +++ b/components/log/CMakeLists.txt @@ -1,4 +1,3 @@ -set(COMPONENT_SRCS "log.c") -set(COMPONENT_ADD_INCLUDEDIRS "include") -set(COMPONENT_PRIV_REQUIRES soc) -register_component() +idf_component_register(SRCS "log.c" + INCLUDE_DIRS "include" + PRIV_REQUIRES soc) diff --git a/components/log/log.c b/components/log/log.c index 72c232c68b..c59469cc02 100644 --- a/components/log/log.c +++ b/components/log/log.c @@ -174,8 +174,10 @@ void esp_log_level_set(const char* tag, esp_log_level_t level) void clear_log_level_list() { - while( !SLIST_EMPTY(&s_log_tags)) { + uncached_tag_entry_t *it; + while((it = SLIST_FIRST(&s_log_tags)) != NULL) { SLIST_REMOVE_HEAD(&s_log_tags, entries ); + free(it); } s_log_cache_entry_count = 0; s_log_cache_max_generation = 0; diff --git a/components/lwip/CMakeLists.txt b/components/lwip/CMakeLists.txt index 7d401d06ce..db2dea2040 100644 --- a/components/lwip/CMakeLists.txt +++ b/components/lwip/CMakeLists.txt @@ -1,4 +1,4 @@ -set(COMPONENT_ADD_INCLUDEDIRS +set(include_dirs include/apps include/apps/sntp lwip/src/include @@ -6,132 +6,136 @@ set(COMPONENT_ADD_INCLUDEDIRS port/esp32/include/arch ) -set(COMPONENT_SRCS "apps/dhcpserver/dhcpserver.c" - "apps/ping/esp_ping.c" - "apps/ping/ping.c" - "apps/sntp/sntp.c" - "lwip/src/api/api_lib.c" - "lwip/src/api/api_msg.c" - "lwip/src/api/err.c" - "lwip/src/api/netbuf.c" - "lwip/src/api/netdb.c" - "lwip/src/api/netifapi.c" - "lwip/src/api/sockets.c" - "lwip/src/api/tcpip.c" - "lwip/src/apps/sntp/sntp.c" - "lwip/src/core/def.c" - "lwip/src/core/dns.c" - "lwip/src/core/inet_chksum.c" - "lwip/src/core/init.c" - "lwip/src/core/ip.c" - "lwip/src/core/mem.c" - "lwip/src/core/memp.c" - "lwip/src/core/netif.c" - "lwip/src/core/pbuf.c" - "lwip/src/core/raw.c" - "lwip/src/core/stats.c" - "lwip/src/core/sys.c" - "lwip/src/core/tcp.c" - "lwip/src/core/tcp_in.c" - "lwip/src/core/tcp_out.c" - "lwip/src/core/timeouts.c" - "lwip/src/core/udp.c" - "lwip/src/core/ipv4/autoip.c" - "lwip/src/core/ipv4/dhcp.c" - "lwip/src/core/ipv4/etharp.c" - "lwip/src/core/ipv4/icmp.c" - "lwip/src/core/ipv4/igmp.c" - "lwip/src/core/ipv4/ip4.c" - "lwip/src/core/ipv4/ip4_addr.c" - "lwip/src/core/ipv4/ip4_frag.c" - "lwip/src/core/ipv6/dhcp6.c" - "lwip/src/core/ipv6/ethip6.c" - "lwip/src/core/ipv6/icmp6.c" - "lwip/src/core/ipv6/inet6.c" - "lwip/src/core/ipv6/ip6.c" - "lwip/src/core/ipv6/ip6_addr.c" - "lwip/src/core/ipv6/ip6_frag.c" - "lwip/src/core/ipv6/mld6.c" - "lwip/src/core/ipv6/nd6.c" - "lwip/src/netif/ethernet.c" - "lwip/src/netif/ethernetif.c" - "lwip/src/netif/lowpan6.c" - "lwip/src/netif/slipif.c" - "lwip/src/netif/ppp/auth.c" - "lwip/src/netif/ppp/ccp.c" - "lwip/src/netif/ppp/chap-md5.c" - "lwip/src/netif/ppp/chap-new.c" - "lwip/src/netif/ppp/chap_ms.c" - "lwip/src/netif/ppp/demand.c" - "lwip/src/netif/ppp/eap.c" - "lwip/src/netif/ppp/ecp.c" - "lwip/src/netif/ppp/eui64.c" - "lwip/src/netif/ppp/fsm.c" - "lwip/src/netif/ppp/ipcp.c" - "lwip/src/netif/ppp/ipv6cp.c" - "lwip/src/netif/ppp/lcp.c" - "lwip/src/netif/ppp/magic.c" - "lwip/src/netif/ppp/mppe.c" - "lwip/src/netif/ppp/multilink.c" - "lwip/src/netif/ppp/ppp.c" - "lwip/src/netif/ppp/pppapi.c" - "lwip/src/netif/ppp/pppcrypt.c" - "lwip/src/netif/ppp/pppoe.c" - "lwip/src/netif/ppp/pppol2tp.c" - "lwip/src/netif/ppp/pppos.c" - "lwip/src/netif/ppp/upap.c" - "lwip/src/netif/ppp/utils.c" - "lwip/src/netif/ppp/vj.c" - "port/esp32/vfs_lwip.c" - "port/esp32/debug/lwip_debug.c" - "port/esp32/freertos/sys_arch.c" - "port/esp32/netif/dhcp_state.c" - "port/esp32/netif/nettestif.c" - "port/esp32/netif/wlanif.c") - -if(CONFIG_IDF_TARGET_ESP32) - list(APPEND COMPONENT_SRCS "port/esp32/netif/ethernetif.c") -endif() +set(srcs + "apps/dhcpserver/dhcpserver.c" + "apps/ping/esp_ping.c" + "apps/ping/ping.c" + "apps/sntp/sntp.c" + "lwip/src/api/api_lib.c" + "lwip/src/api/api_msg.c" + "lwip/src/api/err.c" + "lwip/src/api/netbuf.c" + "lwip/src/api/netdb.c" + "lwip/src/api/netifapi.c" + "lwip/src/api/sockets.c" + "lwip/src/api/tcpip.c" + "lwip/src/apps/sntp/sntp.c" + "lwip/src/core/def.c" + "lwip/src/core/dns.c" + "lwip/src/core/inet_chksum.c" + "lwip/src/core/init.c" + "lwip/src/core/ip.c" + "lwip/src/core/mem.c" + "lwip/src/core/memp.c" + "lwip/src/core/netif.c" + "lwip/src/core/pbuf.c" + "lwip/src/core/raw.c" + "lwip/src/core/stats.c" + "lwip/src/core/sys.c" + "lwip/src/core/tcp.c" + "lwip/src/core/tcp_in.c" + "lwip/src/core/tcp_out.c" + "lwip/src/core/timeouts.c" + "lwip/src/core/udp.c" + "lwip/src/core/ipv4/autoip.c" + "lwip/src/core/ipv4/dhcp.c" + "lwip/src/core/ipv4/etharp.c" + "lwip/src/core/ipv4/icmp.c" + "lwip/src/core/ipv4/igmp.c" + "lwip/src/core/ipv4/ip4.c" + "lwip/src/core/ipv4/ip4_addr.c" + "lwip/src/core/ipv4/ip4_frag.c" + "lwip/src/core/ipv6/dhcp6.c" + "lwip/src/core/ipv6/ethip6.c" + "lwip/src/core/ipv6/icmp6.c" + "lwip/src/core/ipv6/inet6.c" + "lwip/src/core/ipv6/ip6.c" + "lwip/src/core/ipv6/ip6_addr.c" + "lwip/src/core/ipv6/ip6_frag.c" + "lwip/src/core/ipv6/mld6.c" + "lwip/src/core/ipv6/nd6.c" + "lwip/src/netif/ethernet.c" + "lwip/src/netif/lowpan6.c" + "lwip/src/netif/slipif.c" + "lwip/src/netif/ppp/auth.c" + "lwip/src/netif/ppp/ccp.c" + "lwip/src/netif/ppp/chap-md5.c" + "lwip/src/netif/ppp/chap-new.c" + "lwip/src/netif/ppp/chap_ms.c" + "lwip/src/netif/ppp/demand.c" + "lwip/src/netif/ppp/eap.c" + "lwip/src/netif/ppp/ecp.c" + "lwip/src/netif/ppp/eui64.c" + "lwip/src/netif/ppp/fsm.c" + "lwip/src/netif/ppp/ipcp.c" + "lwip/src/netif/ppp/ipv6cp.c" + "lwip/src/netif/ppp/lcp.c" + "lwip/src/netif/ppp/magic.c" + "lwip/src/netif/ppp/mppe.c" + "lwip/src/netif/ppp/multilink.c" + "lwip/src/netif/ppp/ppp.c" + "lwip/src/netif/ppp/pppapi.c" + "lwip/src/netif/ppp/pppcrypt.c" + "lwip/src/netif/ppp/pppoe.c" + "lwip/src/netif/ppp/pppol2tp.c" + "lwip/src/netif/ppp/pppos.c" + "lwip/src/netif/ppp/upap.c" + "lwip/src/netif/ppp/utils.c" + "lwip/src/netif/ppp/vj.c" + "port/esp32/vfs_lwip.c" + "port/esp32/debug/lwip_debug.c" + "port/esp32/freertos/sys_arch.c" + "port/esp32/netif/dhcp_state.c" + "port/esp32/netif/nettestif.c" + "port/esp32/netif/wlanif.c") if(CONFIG_LWIP_PPP_SUPPORT) - list(APPEND COMPONENT_SRCS "lwip/src/netif/ppp/auth.c" - "lwip/src/netif/ppp/ccp.c" - "lwip/src/netif/ppp/chap-md5.c" - "lwip/src/netif/ppp/chap-new.c" - "lwip/src/netif/ppp/chap_ms.c" - "lwip/src/netif/ppp/demand.c" - "lwip/src/netif/ppp/eap.c" - "lwip/src/netif/ppp/ecp.c" - "lwip/src/netif/ppp/eui64.c" - "lwip/src/netif/ppp/fsm.c" - "lwip/src/netif/ppp/ipcp.c" - "lwip/src/netif/ppp/ipv6cp.c" - "lwip/src/netif/ppp/lcp.c" - "lwip/src/netif/ppp/magic.c" - "lwip/src/netif/ppp/mppe.c" - "lwip/src/netif/ppp/multilink.c" - "lwip/src/netif/ppp/ppp.c" - "lwip/src/netif/ppp/pppapi.c" - "lwip/src/netif/ppp/pppcrypt.c" - "lwip/src/netif/ppp/pppoe.c" - "lwip/src/netif/ppp/pppol2tp.c" - "lwip/src/netif/ppp/pppos.c" - "lwip/src/netif/ppp/upap.c" - "lwip/src/netif/ppp/utils.c" - "lwip/src/netif/ppp/vj.c" - "lwip/src/netif/ppp/polarssl/arc4.c" - "lwip/src/netif/ppp/polarssl/des.c" - "lwip/src/netif/ppp/polarssl/md4.c" - "lwip/src/netif/ppp/polarssl/md5.c" - "lwip/src/netif/ppp/polarssl/sha1.c") + list(APPEND srcs + "lwip/src/netif/ppp/auth.c" + "lwip/src/netif/ppp/ccp.c" + "lwip/src/netif/ppp/chap-md5.c" + "lwip/src/netif/ppp/chap-new.c" + "lwip/src/netif/ppp/chap_ms.c" + "lwip/src/netif/ppp/demand.c" + "lwip/src/netif/ppp/eap.c" + "lwip/src/netif/ppp/ecp.c" + "lwip/src/netif/ppp/eui64.c" + "lwip/src/netif/ppp/fsm.c" + "lwip/src/netif/ppp/ipcp.c" + "lwip/src/netif/ppp/ipv6cp.c" + "lwip/src/netif/ppp/lcp.c" + "lwip/src/netif/ppp/magic.c" + "lwip/src/netif/ppp/mppe.c" + "lwip/src/netif/ppp/multilink.c" + "lwip/src/netif/ppp/ppp.c" + "lwip/src/netif/ppp/pppapi.c" + "lwip/src/netif/ppp/pppcrypt.c" + "lwip/src/netif/ppp/pppoe.c" + "lwip/src/netif/ppp/pppol2tp.c" + "lwip/src/netif/ppp/pppos.c" + "lwip/src/netif/ppp/upap.c" + "lwip/src/netif/ppp/utils.c" + "lwip/src/netif/ppp/vj.c" + "lwip/src/netif/ppp/polarssl/arc4.c" + "lwip/src/netif/ppp/polarssl/des.c" + "lwip/src/netif/ppp/polarssl/md4.c" + "lwip/src/netif/ppp/polarssl/md5.c" + "lwip/src/netif/ppp/polarssl/sha1.c") endif() -set(COMPONENT_REQUIRES vfs esp_wifi ethernet) -set(COMPONENT_PRIV_REQUIRES tcpip_adapter nvs_flash) +# Ethernet support for ESP32 only +if (IDF_TARGET_ESP32) + set(priv_requires esp_eth) + list(APPEND srcs "port/esp32/netif/ethernetif.c") +else() + set(priv_requires) +endif() -set(COMPONENT_ADD_LDFRAGMENTS linker.lf) - -register_component() +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS "${include_dirs}" + LDFRAGMENTS linker.lf + REQUIRES vfs esp_wifi + PRIV_REQUIRES ${priv_requires} tcpip_adapter nvs_flash) # lots of LWIP source files evaluate macros that check address of stack variables target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-address) diff --git a/components/lwip/Kconfig b/components/lwip/Kconfig index 6ccbdc113e..4b7d237b54 100644 --- a/components/lwip/Kconfig +++ b/components/lwip/Kconfig @@ -1,5 +1,11 @@ menu "LWIP" + config LWIP_LOCAL_HOSTNAME + string "Local netif hostname" + default 'espressif' + help + The name this device will report to other devices on the network + config LWIP_L2_TO_L3_COPY bool "Enable copy between Layer2 and Layer3 packets" default n @@ -27,6 +33,16 @@ menu "LWIP" If this feature is disabled, all lwip functions will be put into FLASH. + config LWIP_TIMERS_ONDEMAND + bool "Enable LWIP Timers on demand" + default y + help + If this feature is enabled, IGMP and MLD6 timers will be activated only + when joining groups or receiving QUERY packets. + + This feature will reduce the power consumption for applications which do not + use IGMP and MLD6. + config LWIP_MAX_SOCKETS int "Max number of open sockets" range 1 16 @@ -74,15 +90,6 @@ menu "LWIP" help Enabling this option allows checking for available data on a netconn. - config LWIP_DHCP_MAX_NTP_SERVERS - int "Maximum number of NTP servers" - default 1 - range 1 16 - help - Set maximum number of NTP servers used by LwIP SNTP module. - First argument of sntp_setserver/sntp_setservername functions - is limited to this value. - config LWIP_IP_FRAG bool "Enable fragment outgoing IP packets" default n @@ -562,4 +569,26 @@ menu "LWIP" endmenu # LWIP RAW API + menu "SNTP" + + config LWIP_DHCP_MAX_NTP_SERVERS + int "Maximum number of NTP servers" + default 1 + range 1 16 + help + Set maximum number of NTP servers used by LwIP SNTP module. + First argument of sntp_setserver/sntp_setservername functions + is limited to this value. + + config LWIP_SNTP_UPDATE_DELAY + int "Request interval to update time (ms)" + range 15000 4294967295 + default 3600000 + help + This option allows you to set the time update period via SNTP. + Default is 1 hour. Must not be below 15 seconds by specification. + (SNTPv4 RFC 4330 enforces a minimum update time of 15 seconds). + + endmenu # SNTP + endmenu diff --git a/components/lwip/include/apps/sntp/sntp.h b/components/lwip/include/apps/sntp/sntp.h index 418d3c70ed..a94981b5d9 100644 --- a/components/lwip/include/apps/sntp/sntp.h +++ b/components/lwip/include/apps/sntp/sntp.h @@ -15,6 +15,10 @@ #ifndef __SNTP_H__ #define __SNTP_H__ +#ifdef __cplusplus +extern "C" { +#endif + /* * The time update takes place in the sntp_sync_time() function. * The user has the ability to redefine this function in order @@ -116,4 +120,8 @@ void sntp_set_sync_status(sntp_sync_status_t sync_status); */ void sntp_set_time_sync_notification_cb(sntp_sync_time_cb_t callback); +#ifdef __cplusplus +} +#endif + #endif // __SNTP_H__ diff --git a/components/lwip/linker.lf b/components/lwip/linker.lf index b4d47cb546..157e4b88bc 100644 --- a/components/lwip/linker.lf +++ b/components/lwip/linker.lf @@ -2,10 +2,72 @@ archive: liblwip.a entries: if LWIP_IRAM_OPTIMIZATION = y: - ethernetif:ethernet_low_level_output (noflash_text) - ethernetif:ethernetif_input (noflash_text) - wlanif:low_level_output (noflash_text) - wlanif:wlanif_input (noflash_text) + sockets:get_socket (noflash_text) + sockets:tryget_socket (noflash_text) + sockets:tryget_socket_unconn (noflash_text) + sockets:sock_inc_used (noflash_text) + sockets:tryget_socket_unconn_nouse (noflash_text) + sockets:done_socket (noflash_text) + sockets:lwip_recvfrom (noflash_text) + sockets:lwip_recv_tcp (noflash_text) + sockets:lwip_recv_tcp_from (noflash_text) + sockets:lwip_recvfrom_udp_raw (noflash_text) + sockets:lwip_send (noflash_text) + sockets:lwip_sendto (noflash_text) + sockets:event_callback (noflash_text) + api_lib:netconn_apimsg (noflash_text) + api_lib:netconn_recv_data (noflash_text) + api_lib:netconn_tcp_recvd_msg (noflash_text) + api_lib:netconn_tcp_recvd (noflash_text) + api_lib:netconn_recv_data_tcp (noflash_text) + api_lib:netconn_recv_tcp_pbuf_flags (noflash_text) + api_lib:netconn_recv_udp_raw_netbuf_flags (noflash_text) + api_lib:netconn_recv (noflash_text) + api_lib:netconn_sendto (noflash_text) + api_lib:netconn_send (noflash_text) + api_lib:netconn_write_partly (noflash_text) + api_lib:netconn_write_vectors_partly (noflash_text) + api_msg:lwip_netconn_do_send (noflash_text) + api_msg:lwip_netconn_do_write (noflash_text) + netbuf:netbuf_alloc (noflash_text) + netbuf:netbuf_free (noflash_text) + tcpip:tcpip_thread (noflash_text) + tcpip:tcpip_thread_handle_msg (noflash_text) + tcpip:tcpip_inpkt (noflash_text) + tcpip:tcpip_input (noflash_text) + tcpip:tcpip_callback (noflash_text) + tcpip:tcpip_try_callback (noflash_text) + tcpip:tcpip_send_msg_wait_sem (noflash_text) + inet_chksum:inet_cksum_pseudo_base (noflash_text) + inet_chksum:inet_chksum_pseudo (noflash_text) + etharp:etharp_output_to_arp_index (noflash_text) + etharp:etharp_output (noflash_text) + ip4_addr:ip4_addr_isbroadcast_u32 (noflash_text) + ip4:ip4_route_src_hook (noflash_text) + ip4:ip4_route_src (noflash_text) + ip4:ip4_route (noflash_text) + ip4:ip4_input (noflash_text) + ip4:ip4_output_if (noflash_text) + ip4:ip4_output_if_opt (noflash_text) + ip4:ip4_output_if_src (noflash_text) + ip4:ip4_output_if_opt_src (noflash_text) + ip4:ip4_output (noflash_text) + pbuf:pbuf_alloc (noflash_text) + pbuf:pbuf_add_header_impl (noflash_text) + pbuf:pbuf_add_header (noflash_text) + pbuf:pbuf_remove_header (noflash_text) + pbuf:pbuf_header_impl (noflash_text) + pbuf:pbuf_header (noflash_text) + pbuf:pbuf_free (noflash_text) + timeouts:sys_timeouts_mbox_fetch (noflash_text) + udp:udp_input_local_match (noflash_text) + udp:udp_input (noflash_text) + udp:udp_send (noflash_text) + udp:udp_sendto (noflash_text) + udp:udp_sendto_if (noflash_text) + udp:udp_sendto_if_src (noflash_text) + ethernet:ethernet_input (noflash_text) + ethernet:ethernet_output (noflash_text) sys_arch:sys_mutex_lock (noflash_text) sys_arch:sys_mutex_unlock (noflash_text) sys_arch:sys_sem_signal (noflash_text) @@ -13,47 +75,10 @@ entries: sys_arch:sys_mbox_post (noflash_text) sys_arch:sys_mbox_trypost (noflash_text) sys_arch:sys_arch_mbox_fetch (noflash_text) - sockets:get_socket (noflash_text) - sockets:lwip_recvfrom (noflash_text) - sockets:lwip_sendto (noflash_text) - sockets:event_callback (noflash_text) - sockets:lwip_sendto_r (noflash_text) - sockets:lwip_recvfrom_r (noflash_text) - sockets:lwip_recv_r (noflash_text) - api_lib:netconn_apimsg (noflash_text) - api_lib:netconn_recv_data (noflash_text) - api_lib:netconn_recv_tcp_pbuf (noflash_text) - api_lib:netconn_recv (noflash_text) - api_lib:netconn_send (noflash_text) - api_lib:netconn_write_partly (noflash_text) - tcpip:tcpip_thread (noflash_text) - tcpip:tcpip_inpkt (noflash_text) - tcpip:tcpip_input (noflash_text) - tcpip:tcpip_send_msg_wait_sem (noflash_text) - netbuf:netbuf_alloc (noflash_text) - netbuf:netbuf_free (noflash_text) - timeouts:sys_timeouts_mbox_fetch (noflash_text) - inet_chksum:inet_cksum_pseudo_base (noflash_text) - inet_chksum:inet_chksum_pseudo (noflash_text) - inet_chksum:ip_chksum_pseudo (noflash_text) - etharp:etharp_output_to_arp_index (noflash_text) - etharp:etharp_output (noflash_text) - ip4_addr:ip4_addr_isbroadcast_u32 (noflash_text) - ip4:ip4_route_src (noflash_text) - ip4:ip4_route_src_hook (noflash_text) - ip4:ip4_route (noflash_text) - ip4:ip4_input (noflash_text) - ip4:ip4_output_if_src (noflash_text) - ip4:ip4_output_if_opt_src (noflash_text) - udp:udp_input_local_match (noflash_text) - udp:udp_input (noflash_text) - udp:udp_send (noflash_text) - udp:udp_sendto (noflash_text) - udp:udp_sendto_if (noflash_text) - udp:udp_sendto_if_src (noflash_text) - pbuf:pbuf_alloc (noflash_text) - pbuf:pbuf_header_impl (noflash_text) - pbuf:pbuf_header (noflash_text) - ethernet:ethernet_input (noflash_text) + ethernetif:ethernet_low_level_output (noflash_text) + ethernetif:ethernetif_input (noflash_text) + wlanif:low_level_output (noflash_text) + wlanif:wlanif_input (noflash_text) else: + * (default) diff --git a/components/lwip/lwip b/components/lwip/lwip index fe9a58cb7a..61d840ff47 160000 --- a/components/lwip/lwip +++ b/components/lwip/lwip @@ -1 +1 @@ -Subproject commit fe9a58cb7abdc74e7a2196b7c4e0a29ff9042f88 +Subproject commit 61d840ff4778f4946c8743f7e412345abcd537f1 diff --git a/components/lwip/port/esp32/debug/lwip_debug.c b/components/lwip/port/esp32/debug/lwip_debug.c index 8e1574548c..c6c71b5f83 100644 --- a/components/lwip/port/esp32/debug/lwip_debug.c +++ b/components/lwip/port/esp32/debug/lwip_debug.c @@ -191,7 +191,6 @@ void dbg_lwip_stats_show(void) IP6_FRAG_STATS_DISPLAY(); MLD6_STATS_DISPLAY(); ND6_STATS_DISPLAY(); - ESP_STATS_DROP_DISPLAY(); } #if (ESP_STATS_MEM == 1) diff --git a/components/lwip/port/esp32/freertos/sys_arch.c b/components/lwip/port/esp32/freertos/sys_arch.c index fec80d1b9d..a3776d59d7 100644 --- a/components/lwip/port/esp32/freertos/sys_arch.c +++ b/components/lwip/port/esp32/freertos/sys_arch.c @@ -320,7 +320,6 @@ sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg) if (msg == NULL) { msg = &pvDummy; } - if (pdTRUE == xQueueReceive((*mbox)->os_mbox, &(*msg), 0)) { ulReturn = ERR_OK; } else { @@ -349,53 +348,13 @@ sys_mbox_set_owner(sys_mbox_t *mbox, void* owner) void sys_mbox_free(sys_mbox_t *mbox) { - uint32_t mbox_message_num = 0; - if ( (NULL == mbox) || (NULL == *mbox) ) { return; } - - mbox_message_num = uxQueueMessagesWaiting((*mbox)->os_mbox); - - LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("mbox free: mbox=%p os_mbox=%p owner=%p msg_num=%d\n", - *mbox, (*mbox)->os_mbox, (*mbox)->owner, mbox_message_num)); - -#if ESP_THREAD_SAFE - if ((*mbox)->owner) { - if (0 == mbox_message_num) { - /* - * If mbox->owner is not NULL, it indicates the mbox is recvmbox or acceptmbox, - * we need to post a NULL message to mbox in case some application tasks are blocked - * on this mbox - */ - if (sys_mbox_trypost(mbox, NULL) != ERR_OK) { - /* Should never be here because post a message to empty mbox should always be successful */ - ESP_LOGW(TAG, "WARNING: failed to post NULL msg to mbox\n"); - } else { - LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("mbox free: post null successfully\n")); - } - } - (*mbox)->owner = NULL; - } else { - if (mbox_message_num > 1) { - ESP_LOGW(TAG, "WARNING: mbox has %d message, potential memory leaking\n", mbox_message_num); - } - - if (mbox_message_num > 0) { - LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("mbox free: reset mbox queue\n")); - xQueueReset((*mbox)->os_mbox); - } - - /* For recvmbox or acceptmbox, free them in netconn_free() when all sockets' API are returned */ - vQueueDelete((*mbox)->os_mbox); - free(*mbox); - *mbox = NULL; - } -#else vQueueDelete((*mbox)->os_mbox); free(*mbox); *mbox = NULL; -#endif + } /*-----------------------------------------------------------------------------------*/ diff --git a/components/lwip/port/esp32/include/arch/cc.h b/components/lwip/port/esp32/include/arch/cc.h index 1841e3f45a..300291f3bf 100644 --- a/components/lwip/port/esp32/include/arch/cc.h +++ b/components/lwip/port/esp32/include/arch/cc.h @@ -52,7 +52,7 @@ typedef int16_t s16_t; typedef uint32_t u32_t; typedef int32_t s32_t; -typedef unsigned long mem_ptr_t; + typedef int sys_prot_t; #define S16_F "d" diff --git a/components/lwip/port/esp32/include/arch/sys_arch.h b/components/lwip/port/esp32/include/arch/sys_arch.h index 9638fdfd62..5fea8eb552 100644 --- a/components/lwip/port/esp32/include/arch/sys_arch.h +++ b/components/lwip/port/esp32/include/arch/sys_arch.h @@ -80,7 +80,7 @@ typedef struct sys_mbox_s { * However, if the sys_mbox_set_invalid() is not called after sys_mbox_free(), e.g. in netconn_alloc(), * we need to initialize the mbox to invalid explicitly since sys_mbox_set_invalid() now is empty. */ -#define sys_mbox_set_invalid( x ) +#define sys_mbox_set_invalid( x ) *x = NULL #define sys_sem_valid( x ) ( ( ( *x ) == NULL) ? pdFALSE : pdTRUE ) #define sys_sem_set_invalid( x ) ( ( *x ) = NULL ) diff --git a/components/lwip/port/esp32/include/lwipopts.h b/components/lwip/port/esp32/include/lwipopts.h index 6f3f279e02..e37d272ccc 100644 --- a/components/lwip/port/esp32/include/lwipopts.h +++ b/components/lwip/port/esp32/include/lwipopts.h @@ -766,57 +766,35 @@ #define ESP_STATS_MEM CONFIG_LWIP_STATS #define ESP_STATS_DROP CONFIG_LWIP_STATS #define ESP_STATS_TCP 0 -#define ESP_DHCP_TIMER 1 #define ESP_DHCPS_TIMER 1 #define ESP_LWIP_LOGI(...) ESP_LOGI("lwip", __VA_ARGS__) #define ESP_PING 1 #define ESP_HAS_SELECT 1 #define ESP_AUTO_RECV 1 #define ESP_GRATUITOUS_ARP CONFIG_LWIP_ESP_GRATUITOUS_ARP +#define ESP_IP4_ROUTE 1 +#define ESP_AUTO_IP 1 +#define ESP_PBUF 1 +#define ESP_PPP 1 +#define ESP_IPV6 1 +#define ESP_SOCKET 1 #ifdef ESP_IRAM_ATTR #undef ESP_IRAM_ATTR #endif #define ESP_IRAM_ATTR -#if ESP_PERF -#define DBG_PERF_PATH_SET(dir, point) -#define DBG_PERF_FILTER_LEN 1000 - -enum { - DBG_PERF_DIR_RX = 0, - DBG_PERF_DIR_TX, -}; - -enum { - DBG_PERF_POINT_INT = 0, - DBG_PERF_POINT_WIFI_IN = 1, - DBG_PERF_POINT_WIFI_OUT = 2, - DBG_PERF_POINT_LWIP_IN = 3, - DBG_PERF_POINT_LWIP_OUT = 4, - DBG_PERF_POINT_SOC_IN = 5, - DBG_PERF_POINT_SOC_OUT = 6, -}; - +#ifdef CONFIG_LWIP_TIMERS_ONDEMAND +#define ESP_LWIP_IGMP_TIMERS_ONDEMAND 1 +#define ESP_LWIP_MLD6_TIMERS_ONDEMAND 1 #else -#define DBG_PERF_PATH_SET(dir, point) -#define DBG_PERF_FILTER_LEN 1000 +#define ESP_LWIP_IGMP_TIMERS_ONDEMAND 0 +#define ESP_LWIP_MLD6_TIMERS_ONDEMAND 0 #endif #define TCP_SND_BUF CONFIG_LWIP_TCP_SND_BUF_DEFAULT #define TCP_WND CONFIG_LWIP_TCP_WND_DEFAULT -#if ESP_PER_SOC_TCP_WND -#define TCP_WND_DEFAULT CONFIG_LWIP_TCP_WND_DEFAULT -#define TCP_SND_BUF_DEFAULT CONFIG_LWIP_TCP_SND_BUF_DEFAULT -#define TCP_WND(pcb) (pcb->per_soc_tcp_wnd) -#define TCP_SND_BUF(pcb) (pcb->per_soc_tcp_snd_buf) -#define TCP_SND_QUEUELEN(pcb) ((4 * (TCP_SND_BUF((pcb))) + (TCP_MSS - 1))/(TCP_MSS)) -#define TCP_SNDLOWAT(pcb) LWIP_MIN(LWIP_MAX(((TCP_SND_BUF((pcb)))/2), (2 * TCP_MSS) + 1), (TCP_SND_BUF((pcb))) - 1) -#define TCP_SNDQUEUELOWAT(pcb) LWIP_MAX(((TCP_SND_QUEUELEN((pcb)))/2), 5) -#define TCP_WND_UPDATE_THRESHOLD(pcb) LWIP_MIN((TCP_WND((pcb)) / 4), (TCP_MSS * 4)) -#endif - /** * DHCP_DEBUG: Enable debugging in dhcp.c. */ @@ -833,6 +811,22 @@ enum { #define LWIP_DHCP_MAX_NTP_SERVERS CONFIG_LWIP_DHCP_MAX_NTP_SERVERS #define LWIP_TIMEVAL_PRIVATE 0 +/* + -------------------------------------- + ------------ SNTP options ------------ + -------------------------------------- +*/ +/* + * SNTP update delay - in milliseconds + */ +/** Set this to 1 to support DNS names (or IP address strings) to set sntp servers + * One server address/name can be defined as default if SNTP_SERVER_DNS == 1: + * \#define SNTP_SERVER_ADDRESS "pool.ntp.org" + */ +#define SNTP_SERVER_DNS 1 + +#define SNTP_UPDATE_DELAY CONFIG_LWIP_SNTP_UPDATE_DELAY + #define SNTP_SET_SYSTEM_TIME_US(sec, us) \ do { \ struct timeval tv = { .tv_sec = sec, .tv_usec = us }; \ diff --git a/components/lwip/port/esp32/netif/ethernetif.c b/components/lwip/port/esp32/netif/ethernetif.c index d61653fcac..fb758b902e 100644 --- a/components/lwip/port/esp32/netif/ethernetif.c +++ b/components/lwip/port/esp32/netif/ethernetif.c @@ -56,204 +56,174 @@ #define IFNAME1 'n' /** - * In this function, the hardware should be initialized. - * Called from ethernetif_init(). + * @brief Free resources allocated in L2 layer * - * @param netif the already initialized lwip network interface structure - * for this ethernetif + * @param buf memory alloc in L2 layer + * @note this function is also the callback when invoke pbuf_free */ -static void -ethernet_low_level_init(struct netif *netif) +static void ethernet_free_rx_buf_l2(void *buf) { - /* set MAC hardware address length */ - netif->hwaddr_len = ETHARP_HWADDR_LEN; + free(buf); +} - /* set MAC hardware address */ +/** + * In this function, the hardware should be initialized. + * Invoked by ethernetif_init(). + * + * @param netif lwip network interface which has already been initialized + */ +static void ethernet_low_level_init(struct netif *netif) +{ + /* set MAC hardware address length */ + netif->hwaddr_len = ETHARP_HWADDR_LEN; - /* maximum transfer unit */ - netif->mtu = 1500; + /* maximum transfer unit */ + netif->mtu = 1500; - /* device capabilities */ - /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ - netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; + /* device capabilities */ + /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; #if ESP_LWIP #if LWIP_IGMP - netif->flags |= NETIF_FLAG_IGMP; + netif->flags |= NETIF_FLAG_IGMP; #endif #endif - -#ifndef CONFIG_ETH_EMAC_L2_TO_L3_RX_BUF_MODE - netif->l2_buffer_free_notify = esp_eth_free_rx_buf; -#endif } /** - * This function should do the actual transmission of the packet. The packet is - * contained in the pbuf that is passed to the function. This pbuf - * might be chained. + * @brief This function should do the actual transmission of the packet. The packet is + * contained in the pbuf that is passed to the function. This pbuf might be chained. * - * @param netif the lwip network interface structure for this ethernetif - * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type) - * @return ERR_OK if the packet could be sent - * an err_t value if the packet couldn't be sent - * - * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to - * strange results. You might consider waiting for space in the DMA queue - * to become availale since the stack doesn't retry to send a packet - * dropped because of memory failure (except for the TCP timers). + * @param netif lwip network interface structure for this ethernetif + * @param p MAC packet to send (e.g. IP packet including MAC addresses and type) + * @return err_t ERR_OK if the packet has been sent to Ethernet DMA buffer successfully + * ERR_MEM if private data couldn't be allocated + * ERR_IF if netif is not supported + * ERR_ABORT if there's some wrong when send pbuf payload to DMA buffer */ -static err_t ESP_IRAM_ATTR -ethernet_low_level_output(struct netif *netif, struct pbuf *p) +static err_t ethernet_low_level_output(struct netif *netif, struct pbuf *p) { - struct pbuf *q = p; - esp_interface_t eth_if = tcpip_adapter_get_esp_if(netif); - esp_err_t ret; + struct pbuf *q = p; + esp_interface_t eth_if = tcpip_adapter_get_esp_if(netif); + esp_err_t ret = ESP_FAIL; + esp_eth_handle_t eth_handle = (esp_eth_handle_t)netif->state; - if (eth_if != ESP_IF_ETH) { - LWIP_DEBUGF(NETIF_DEBUG, ("eth_if=%d netif=%p pbuf=%p len=%d\n", eth_if, netif, p, p->len)); - - return ERR_IF; - } - - if (q->next == NULL) { - ret = esp_eth_tx(q->payload, q->len); - } else { - LWIP_DEBUGF(PBUF_DEBUG, ("low_level_output: pbuf is a list, application may has bug")); - q = pbuf_alloc(PBUF_RAW_TX, p->tot_len, PBUF_RAM); - if (q != NULL) { - q->l2_owner = NULL; - pbuf_copy(q, p); - } else { - return ERR_MEM; + if (eth_if != ESP_IF_ETH) { + LWIP_DEBUGF(NETIF_DEBUG, ("eth_if=%d netif=%p pbuf=%p len=%d\n", eth_if, netif, p, p->len)); + return ERR_IF; + } + + if (q->next == NULL) { + ret = esp_eth_transmit(eth_handle, q->payload, q->len); + } else { + LWIP_DEBUGF(PBUF_DEBUG, ("low_level_output: pbuf is a list, application may has bug")); + q = pbuf_alloc(PBUF_RAW_TX, p->tot_len, PBUF_RAM); + if (q != NULL) { +#if ESP_LWIP + /* This pbuf RAM was not allocated on layer2, no extra free operation needed in pbuf_free */ + q->l2_owner = NULL; + q->l2_buf = NULL; +#endif + pbuf_copy(q, p); + } else { + return ERR_MEM; + } + ret = esp_eth_transmit(eth_handle, q->payload, q->len); + /* content in payload has been copied to DMA buffer, it's safe to free pbuf now */ + pbuf_free(q); + } + /* Check error */ + if (ret != ESP_OK) { + return ERR_ABRT; + } else { + return ERR_OK; } - ret = esp_eth_tx(q->payload, q->len); - pbuf_free(q); - } - /* error occured when no memory or peripheral wrong state */ - if (ret != ESP_OK) - { - return ERR_ABRT; - } else { - return ERR_OK; - } } /** - * This function should be called when a packet is ready to be read + * @brief This function should be called when a packet is ready to be read * from the interface. It uses the function low_level_input() that * should handle the actual reception of bytes from the network * interface. Then the type of the received packet is determined and * the appropriate input function is called. * - * @param netif the lwip network interface structure for this ethernetif - * @param buffer the ethernet buffer - * @param len the len of buffer - * - * @note When CONFIG_ETH_EMAC_L2_TO_L3_RX_BUF_MODE is enabled, a copy of buffer - * will be made for high layer (LWIP) and ethernet is responsible for - * freeing the buffer. Otherwise, high layer and ethernet share the - * same buffer and high layer is responsible for freeing the buffer. + * @param netif lwip network interface structure for this ethernetif + * @param buffer ethernet buffer + * @param len length of buffer */ -void ESP_IRAM_ATTR -ethernetif_input(struct netif *netif, void *buffer, uint16_t len) +void ethernetif_input(struct netif *netif, void *buffer, uint16_t len) { - struct pbuf *p; + struct pbuf *p; - if(buffer== NULL || !netif_is_up(netif)) { -#ifndef CONFIG_ETH_EMAC_L2_TO_L3_RX_BUF_MODE - if (buffer) { - esp_eth_free_rx_buf(buffer); + if (buffer == NULL || !netif_is_up(netif)) { + if (buffer) { + ethernet_free_rx_buf_l2(buffer); + } + return; } + + /* acquire new pbuf, type: PBUF_REF */ + p = pbuf_alloc(PBUF_RAW, len, PBUF_REF); + if (p == NULL) { + ethernet_free_rx_buf_l2(buffer); + return; + } + p->payload = buffer; +#if ESP_LWIP + p->l2_owner = netif; + p->l2_buf = buffer; #endif - return; - } - -#ifdef CONFIG_ETH_EMAC_L2_TO_L3_RX_BUF_MODE - p = pbuf_alloc(PBUF_RAW, len, PBUF_RAM); - if (p == NULL) { - return; - } - p->l2_owner = NULL; - memcpy(p->payload, buffer, len); - -/* full packet send to tcpip_thread to process */ -if (netif->input(p, netif) != ERR_OK) { - LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); - pbuf_free(p); -} - -#else - p = pbuf_alloc(PBUF_RAW, len, PBUF_REF); - if (p == NULL){ - esp_eth_free_rx_buf(buffer); - return; - } - p->payload = buffer; - p->l2_owner = netif; - p->l2_buf = buffer; - - /* full packet send to tcpip_thread to process */ -if (netif->input(p, netif) != ERR_OK) { - LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); - pbuf_free(p); -} -#endif + /* full packet send to tcpip_thread to process */ + if (netif->input(p, netif) != ERR_OK) { + LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); + pbuf_free(p); + } + /* the pbuf will be free in upper layer, eg: ethernet_input */ } /** - * Should be called at the beginning of the program to set up the - * network interface. It calls the function low_level_init() to do the - * actual setup of the hardware. + * Set up the network interface. It calls the function low_level_init() to do the + * actual init work of the hardware. * * This function should be passed as a parameter to netif_add(). * * @param netif the lwip network interface structure for this ethernetif - * @return ERR_OK if the loopif is initialized - * ERR_MEM if private data couldn't be allocated - * any other err_t on error + * @return ERR_OK if the ethernetif is initialized */ -err_t -ethernetif_init(struct netif *netif) +err_t ethernetif_init(struct netif *netif) { - LWIP_ASSERT("netif != NULL", (netif != NULL)); - + LWIP_ASSERT("netif != NULL", (netif != NULL)); + esp_eth_handle_t eth_handle = (esp_eth_handle_t)netif->state; + /* Initialize interface hostname */ #if LWIP_NETIF_HOSTNAME - /* Initialize interface hostname */ - #if ESP_LWIP - netif->hostname = "espressif"; + netif->hostname = CONFIG_LWIP_LOCAL_HOSTNAME; #else - netif->hostname = "lwip"; + netif->hostname = "lwip"; #endif #endif /* LWIP_NETIF_HOSTNAME */ - /* - * Initialize the snmp variables and counters inside the struct netif. - * The last argument should be replaced with your link speed, in units - * of bits per second. - */ - if(esp_eth_get_speed() == ETH_SPEED_MODE_100M){ - NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 100000000); - } else { - NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 10000000); - } + /* Initialize the snmp variables and counters inside the struct netif. */ + eth_speed_t speed; + esp_eth_ioctl(eth_handle, ETH_CMD_G_SPEED, &speed); + if (speed == ETH_SPEED_100M) { + NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 100000000); + } else { + NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 10000000); + } - netif->name[0] = IFNAME0; - netif->name[1] = IFNAME1; - /* We directly use etharp_output() here to save a function call. - * You can instead declare your own function an call etharp_output() - * from it if you have to do some checks before sending (e.g. if link - * is available...) */ - netif->output = etharp_output; + netif->name[0] = IFNAME0; + netif->name[1] = IFNAME1; + netif->output = etharp_output; #if LWIP_IPV6 - netif->output_ip6 = ethip6_output; + netif->output_ip6 = ethip6_output; #endif /* LWIP_IPV6 */ - netif->linkoutput = ethernet_low_level_output; + netif->linkoutput = ethernet_low_level_output; + netif->l2_buffer_free_notify = ethernet_free_rx_buf_l2; - /* initialize the hardware */ - ethernet_low_level_init(netif); + ethernet_low_level_init(netif); - return ERR_OK; + return ERR_OK; } diff --git a/components/lwip/port/esp32/netif/nettestif.c b/components/lwip/port/esp32/netif/nettestif.c index 741f542797..4422c21952 100644 --- a/components/lwip/port/esp32/netif/nettestif.c +++ b/components/lwip/port/esp32/netif/nettestif.c @@ -39,7 +39,7 @@ err_t nettestif_init(struct netif *netif) g_last_netif = netif; - netif->hostname = "espressif"; + netif->hostname = CONFIG_LWIP_LOCAL_HOSTNAME; /* * Initialize the snmp variables and counters inside the struct netif. diff --git a/components/lwip/port/esp32/netif/wlanif.c b/components/lwip/port/esp32/netif/wlanif.c index 7c60b69349..11e1fc857f 100644 --- a/components/lwip/port/esp32/netif/wlanif.c +++ b/components/lwip/port/esp32/netif/wlanif.c @@ -154,7 +154,6 @@ wlanif_input(struct netif *netif, void *buffer, u16_t len, void* eb) #if (ESP_L2_TO_L3_COPY == 1) p = pbuf_alloc(PBUF_RAW, len, PBUF_RAM); if (p == NULL) { - ESP_STATS_DROP_INC(esp.wlanif_input_pbuf_fail); esp_wifi_internal_free_rx_buffer(eb); return; } @@ -164,7 +163,6 @@ wlanif_input(struct netif *netif, void *buffer, u16_t len, void* eb) #else p = pbuf_alloc(PBUF_RAW, len, PBUF_REF); if (p == NULL){ - ESP_STATS_DROP_INC(esp.wlanif_input_pbuf_fail); esp_wifi_internal_free_rx_buffer(eb); return; } @@ -202,7 +200,7 @@ wlanif_init(struct netif *netif) /* Initialize interface hostname */ #if ESP_LWIP - netif->hostname = "espressif"; + netif->hostname = CONFIG_LWIP_LOCAL_HOSTNAME; #else netif->hostname = "lwip"; #endif diff --git a/components/lwip/port/esp32/vfs_lwip.c b/components/lwip/port/esp32/vfs_lwip.c index 6b687a196c..ffd3e79e1f 100644 --- a/components/lwip/port/esp32/vfs_lwip.c +++ b/components/lwip/port/esp32/vfs_lwip.c @@ -49,23 +49,23 @@ static void *lwip_get_socket_select_semaphore() static int lwip_fcntl_r_wrapper(int fd, int cmd, int arg) { - return lwip_fcntl_r(fd, cmd, arg); + return lwip_fcntl(fd, cmd, arg); } static int lwip_ioctl_r_wrapper(int fd, int cmd, va_list args) { - return lwip_ioctl_r(fd, cmd, va_arg(args, void *)); + return lwip_ioctl(fd, cmd, va_arg(args, void *)); } void esp_vfs_lwip_sockets_register() { esp_vfs_t vfs = { .flags = ESP_VFS_FLAG_DEFAULT, - .write = &lwip_write_r, + .write = &lwip_write, .open = NULL, .fstat = NULL, - .close = &lwip_close_r, - .read = &lwip_read_r, + .close = &lwip_close, + .read = &lwip_read, .fcntl = &lwip_fcntl_r_wrapper, .ioctl = &lwip_ioctl_r_wrapper, .socket_select = &lwip_select, diff --git a/components/lwip/test_afl_host/Makefile b/components/lwip/test_afl_host/Makefile index 7c5cf49f3a..b236b327a8 100644 --- a/components/lwip/test_afl_host/Makefile +++ b/components/lwip/test_afl_host/Makefile @@ -1,6 +1,6 @@ COMPONENTS_DIR=../.. CFLAGS=-std=gnu99 -Og -ggdb -ffunction-sections -fdata-sections -nostdlib -Wall -Werror=all -Wno-int-to-pointer-cast -Wno-error=unused-function -Wno-error=unused-variable -Wno-error=deprecated-declarations -Wextra \ --Wno-unused-parameter -Wno-sign-compare -Wno-address -Wno-unused-variable -DESP_PLATFORM -D IDF_VER=\"v3.1\" -MMD -MP -DWITH_POSIX +-Wno-unused-parameter -Wno-sign-compare -Wno-address -Wno-unused-variable -DESP_PLATFORM -D IDF_VER=\"v3.1\" -MMD -MP -DWITH_POSIX -DLWIP_NO_CTYPE_H=1 INC_DIRS=-I . -I ./build/config -I $(COMPONENTS_DIR)/newlib/platform_include -I $(COMPONENTS_DIR)/newlib/include -I $(COMPONENTS_DIR)/driver/include -I $(COMPONENTS_DIR)/esp32/include -I $(COMPONENTS_DIR)/ethernet/include -I $(COMPONENTS_DIR)/freertos/include -I $(COMPONENTS_DIR)/heap/include -I $(COMPONENTS_DIR)/lwip/lwip/src/include -I $(COMPONENTS_DIR)/lwip/include/apps -I $(COMPONENTS_DIR)/lwip/lwip/src/include/netif -I $(COMPONENTS_DIR)/lwip/lwip/src/include/posix -I $(COMPONENTS_DIR)/lwip/port/esp32/include -I $(COMPONENTS_DIR)/lwip/lwip/src/include/posix -I $(COMPONENTS_DIR)/lwip/include/apps/ping -I $(COMPONENTS_DIR)/lwip/include/apps/sntp -I $(COMPONENTS_DIR)/soc/esp32/include -I $(COMPONENTS_DIR)/soc/include -I $(COMPONENTS_DIR)/tcpip_adapter/include -I $(COMPONENTS_DIR)/esp_rom/include -I $(COMPONENTS_DIR)/esp_common/include -I $(COMPONENTS_DIR)/xtensa/include -I $(COMPONENTS_DIR)/xtensa/esp32/include -I $(COMPONENTS_DIR)/esp_wifi/include -I $(COMPONENTS_DIR)/esp_event/include TEST_NAME=test FUZZ=afl-fuzz diff --git a/components/lwip/test_afl_host/network_mock.c b/components/lwip/test_afl_host/network_mock.c index 947b6b22b2..aeaad72d32 100644 --- a/components/lwip/test_afl_host/network_mock.c +++ b/components/lwip/test_afl_host/network_mock.c @@ -94,7 +94,7 @@ struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) p = (struct pbuf *)malloc(MEMP_PBUF_POOL); p->tot_len = length; p->next = NULL; - p->type = PBUF_POOL; + p->type_internal = PBUF_POOL; p->len = length; p->payload = malloc(length); return p; diff --git a/components/lwip/test_afl_host/test_dns.c b/components/lwip/test_afl_host/test_dns.c index 131a8b3ed7..1e9a588150 100644 --- a/components/lwip/test_afl_host/test_dns.c +++ b/components/lwip/test_afl_host/test_dns.c @@ -66,6 +66,8 @@ int main(int argc, char** argv) p->next = NULL; // Pretend that the response is from our pending querries + IP4_ADDR(&server_ip, 8, 8, 8, 8); + dns_setserver(0, &server_ip); dns_test_inject_port_and_txid(1024, (buf[0]<<8) + buf[1]); dns_test_dns_enqueue("test", 4, NULL, NULL, 0); diff --git a/components/mbedtls/CMakeLists.txt b/components/mbedtls/CMakeLists.txt index aef65d2e1e..f916567fdf 100644 --- a/components/mbedtls/CMakeLists.txt +++ b/components/mbedtls/CMakeLists.txt @@ -1,75 +1,17 @@ idf_build_get_property(idf_target IDF_TARGET) -set(COMPONENT_ADD_INCLUDEDIRS "port/include" "mbedtls/include") -set(COMPONENT_SRCS "mbedtls.c") -set(COMPONENT_REQUIRES lwip) - -set(MBEDTLS_PRIV_REQUIRES ${IDF_COMPONENT_REQUIRES_COMMON} soc) - -register_component() +idf_component_register(INCLUDE_DIRS "port/include" "mbedtls/include" + REQUIRES lwip + PRIV_REQUIRES ${IDF_COMPONENT_REQUIRES_COMMON} soc + ) # Only build mbedtls libraries set(ENABLE_TESTING CACHE BOOL OFF) set(ENABLE_PROGRAMS CACHE BOOL OFF) -# Use same policy between IDF and mbedtls build -function(project) - set(_args ARGV) - _project(${${_args}}) - cmake_policy(SET CMP0022 NEW) -endfunction() - # Needed to for include_next includes to work from within mbedtls include_directories("${COMPONENT_DIR}/port/include") -# Workaround issue with creating symbolic links due to issues with native -# path conversion (TO_NATIVE_PATH). The following summarizes what CMake invocations -# this workaround is for: -# -# 1. CMake from command line + Ninja = No errors -# 2. CMake from command line + MinGW Makefiles = Forward slash for paths, mklink mistakes path for a switch -# 3. CMake from MSYS + Ninja = No errors -# 4. CMake from MSYS + Unix Makefiles/MSYS Makefiles = Forward slash for paths, mklink mistakes path for a switch -# -# There are references to the issue in case (2) and (4) in https://github.com/ARMmbed/mbedtls/issues/1496, -# https://cmake.org/pipermail/cmake/2006-July/010193.html, and https://cmake.org/Bug/view.php?id=5939. -# -# This workaround is meant to circumvent logic inside link_to_source() function in mbedtls/mbedtls/CMakeLists.txt. -if(CMAKE_HOST_WIN32) - set(msystem $ENV{MSYSTEM}) - if(MSYS OR msystem) - # Solves case (4). When in MSYS environment, instead opt to use the Unix equivalent of mklink. - set(CMAKE_HOST_UNIX 1) - else() - # Solves case (2). When invoked from command line, create the symbolic links ahead of link_to_source() invocations - # using a 'hybrid' path format resilient intermediary - in this case a Python wrapper for mklink. This is more unweildy - # than necessary, since string(REPLACE "/" "\\" ... does not actually work. - set(target_links "mbedtls/include/mbedtls" - "mbedtls/scripts") - foreach(target_link ${target_links}) - file(TO_NATIVE_PATH ${CMAKE_CURRENT_BINARY_DIR}/${target_link} link) - file(TO_NATIVE_PATH ${COMPONENT_DIR}/${target_link} target) - - idf_build_get_property(python PYTHON) - if(NOT EXISTS ${link}) - if(IS_DIRECTORY ${target}) - set(command ${python} ${COMPONENT_DIR}/mklink.py /j ${link} ${target}) - else() - set(command ${python} ${COMPONENT_DIR}/mklink.py /h ${link} ${target}) - endif() - - execute_process(COMMAND ${command} - RESULT_VARIABLE result - ERROR_VARIABLE output) - - if(NOT ${result} EQUAL 0) - message(FATAL_ERROR "Could not create symbolic link for: ${target} --> ${output}") - endif() - endif() - endforeach() - endif() -endif() - # Import mbedtls library targets add_subdirectory(mbedtls) @@ -98,9 +40,4 @@ foreach(target ${mbedtls_targets}) endforeach() # Link mbedtls libraries to component library -target_link_libraries(${COMPONENT_LIB} ${mbedtls_targets}) - -# Catch usage of deprecated mbedTLS functions when building tests -if(mbedtls_test IN_LIST BUILD_TEST_COMPONENTS) - add_definitions(-DMBEDTLS_DEPRECATED_WARNING) -endif() +target_link_libraries(${COMPONENT_LIB} INTERFACE ${mbedtls_targets}) diff --git a/components/mbedtls/mbedtls b/components/mbedtls/mbedtls index 19eb57f7f7..97959e7791 160000 --- a/components/mbedtls/mbedtls +++ b/components/mbedtls/mbedtls @@ -1 +1 @@ -Subproject commit 19eb57f7f7b2f4312d497ddbcb5f104fc6877c70 +Subproject commit 97959e77912524bd8db7cbb2e00fc9f6189f7a82 diff --git a/components/mbedtls/mbedtls.c b/components/mbedtls/mbedtls.c deleted file mode 100644 index fab17ac780..0000000000 --- a/components/mbedtls/mbedtls.c +++ /dev/null @@ -1 +0,0 @@ -// Empty file diff --git a/components/mbedtls/mklink.py b/components/mbedtls/mklink.py deleted file mode 100644 index 4195e4f333..0000000000 --- a/components/mbedtls/mklink.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python -# -# Wrapper for symbolic link creation on Windows that works around issues -# with native path conversion. See the component CMakeLists.txt for more details. -# -# Copyright 2018 Espressif Systems (Shanghai) PTE LTD -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http:#www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -import os -import argparse -import subprocess - -parser = argparse.ArgumentParser() -parser.add_argument("type") -parser.add_argument("link") -parser.add_argument("target") - -args = parser.parse_args() - -link = os.path.abspath(args.link) -target = os.path.abspath(args.target) - -try: - os.makedirs(os.path.dirname(link)) -except WindowsError: - pass - -mklink_cmd = ["mklink", args.type, link, target] - -subprocess.call(mklink_cmd, shell=True) diff --git a/components/mbedtls/port/esp32/aes.c b/components/mbedtls/port/esp32/aes.c index 0cf6c4257d..3925f13e47 100644 --- a/components/mbedtls/port/esp32/aes.c +++ b/components/mbedtls/port/esp32/aes.c @@ -408,6 +408,50 @@ int esp_aes_crypt_ctr( esp_aes_context *ctx, return 0; } +/* + * AES-OFB (Output Feedback Mode) buffer encryption/decryption + */ +int esp_aes_crypt_ofb( esp_aes_context *ctx, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int ret = 0; + size_t n; + + if ( ctx == NULL || iv_off == NULL || iv == NULL || + input == NULL || output == NULL ) { + return MBEDTLS_ERR_AES_BAD_INPUT_DATA; + } + + n = *iv_off; + + if( n > 15 ) { + return( MBEDTLS_ERR_AES_BAD_INPUT_DATA ); + } + + esp_aes_acquire_hardware(); + + esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT); + + while( length-- ) { + if( n == 0 ) { + esp_aes_block( iv, iv ); + } + *output++ = *input++ ^ iv[n]; + + n = ( n + 1 ) & 0x0F; + } + + *iv_off = n; + + esp_aes_release_hardware(); + + return( ret ); +} + /* Below XTS implementation is copied aes.c of mbedtls library. * When MBEDTLS_AES_ALT is defined mbedtls expects alternate * definition of XTS functions to be available. Even if this diff --git a/components/mbedtls/port/esp32/esp_bignum.c b/components/mbedtls/port/esp32/esp_bignum.c index 843c40d9b6..50e1d9f364 100644 --- a/components/mbedtls/port/esp32/esp_bignum.c +++ b/components/mbedtls/port/esp32/esp_bignum.c @@ -359,6 +359,18 @@ int mbedtls_mpi_exp_mod( mbedtls_mpi* Z, const mbedtls_mpi* X, const mbedtls_mpi mbedtls_mpi *Rinv; /* points to _Rinv (if not NULL) othwerwise &RR_new */ mbedtls_mpi_uint Mprime; + if (mbedtls_mpi_cmp_int(M, 0) <= 0 || (M->p[0] & 1) == 0) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + if (mbedtls_mpi_cmp_int(Y, 0) < 0) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + if (mbedtls_mpi_cmp_int(Y, 0) == 0) { + return mbedtls_mpi_lset(Z, 1); + } + if (hw_words * 32 > 4096) { return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; } @@ -392,13 +404,24 @@ int mbedtls_mpi_exp_mod( mbedtls_mpi* Z, const mbedtls_mpi* X, const mbedtls_mpi start_op(RSA_START_MODEXP_REG); /* X ^ Y may actually be shorter than M, but unlikely when used for crypto */ - MBEDTLS_MPI_CHK( mbedtls_mpi_grow(Z, m_words) ); + if ((ret = mbedtls_mpi_grow(Z, m_words)) != 0) { + esp_mpi_release_hardware(); + goto cleanup; + } wait_op_complete(RSA_START_MODEXP_REG); mem_block_to_mpi(Z, RSA_MEM_Z_BLOCK_BASE, m_words); esp_mpi_release_hardware(); + // Compensate for negative X + if (X->s == -1 && (Y->p[0] & 1) != 0) { + Z->s = -1; + MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(Z, M, Z)); + } else { + Z->s = 1; + } + cleanup: if (_Rinv == NULL) { mbedtls_mpi_free(&Rinv_new); diff --git a/components/mbedtls/port/include/aes_alt.h b/components/mbedtls/port/include/aes_alt.h index 2f6813729d..993d0689e3 100644 --- a/components/mbedtls/port/include/aes_alt.h +++ b/components/mbedtls/port/include/aes_alt.h @@ -47,6 +47,9 @@ typedef esp_aes_context mbedtls_aes_context; #if defined(MBEDTLS_CIPHER_MODE_CTR) #define mbedtls_aes_crypt_ctr esp_aes_crypt_ctr #endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) +#define mbedtls_aes_crypt_ofb esp_aes_crypt_ofb +#endif #if defined(MBEDTLS_CIPHER_MODE_XTS) typedef esp_aes_xts_context mbedtls_aes_xts_context; #define mbedtls_aes_xts_init esp_aes_xts_init diff --git a/components/mbedtls/port/include/esp32/aes.h b/components/mbedtls/port/include/esp32/aes.h index 6f5c1ff54e..962e148066 100644 --- a/components/mbedtls/port/include/esp32/aes.h +++ b/components/mbedtls/port/include/esp32/aes.h @@ -281,6 +281,31 @@ int esp_aes_xts_setkey_enc( esp_aes_xts_context *ctx, const unsigned char *key, unsigned int keybits ); +/** + * \brief This function performs an AES-OFB (Output Feedback Mode) + * encryption or decryption operation. + * + * \param ctx The AES context to use for encryption or decryption. + * It must be initialized and bound to a key. + * \param length The length of the input data. + * \param iv_off The offset in IV (updated after use). + * It must point to a valid \c size_t. + * \param iv The initialization vector (updated after use). + * It must be a readable and writeable buffer of \c 16 Bytes. + * \param input The buffer holding the input data. + * It must be readable and of size \p length Bytes. + * \param output The buffer holding the output data. + * It must be writeable and of size \p length Bytes. + * + * \return \c 0 on success. + */ +int esp_aes_crypt_ofb( esp_aes_context *ctx, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); + /** * \brief This function prepares an XTS context for decryption and * sets the decryption key. diff --git a/components/mbedtls/port/include/mbedtls/config.h b/components/mbedtls/port/include/mbedtls/config.h deleted file mode 100644 index cf3d904de0..0000000000 --- a/components/mbedtls/port/include/mbedtls/config.h +++ /dev/null @@ -1,9 +0,0 @@ -/* This shim header is added so that any application code - which includes "mbedtls/config.h" directly gets the correct - config. */ -#pragma once -#if !defined(MBEDTLS_CONFIG_FILE) -#include_next "mbedtls/config.h" -#else -#include MBEDTLS_CONFIG_FILE -#endif diff --git a/components/mbedtls/port/include/mbedtls/esp_config.h b/components/mbedtls/port/include/mbedtls/esp_config.h index 40ae3ae368..bdb9bf61a7 100644 --- a/components/mbedtls/port/include/mbedtls/esp_config.h +++ b/components/mbedtls/port/include/mbedtls/esp_config.h @@ -24,14 +24,11 @@ * This file is part of mbed TLS (https://tls.mbed.org) */ -#ifndef MBEDTLS_CONFIG_H -#define MBEDTLS_CONFIG_H +#ifndef ESP_CONFIG_H +#define ESP_CONFIG_H #include "sdkconfig.h" - -#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) -#define _CRT_SECURE_NO_DEPRECATE 1 -#endif +#include "mbedtls/config.h" /** * \name SECTION: System support @@ -40,31 +37,6 @@ * \{ */ -/** - * \def MBEDTLS_HAVE_ASM - * - * The compiler has support for asm(). - * - * Requires support for asm() in compiler. - * - * Used in: - * library/timing.c - * library/padlock.c - * include/mbedtls/bn_mul.h - * - * Comment to disable the use of assembly code. - */ -#define MBEDTLS_HAVE_ASM - -/** - * \def MBEDTLS_HAVE_SSE2 - * - * CPU supports SSE2 instruction set. - * - * Uncomment if the CPU supports SSE2 (IA-32 specific). - */ -//#define MBEDTLS_HAVE_SSE2 - /** * \def MBEDTLS_HAVE_TIME * @@ -76,6 +48,8 @@ */ #ifdef CONFIG_MBEDTLS_HAVE_TIME #define MBEDTLS_HAVE_TIME +#else +#undef MBEDTLS_HAVE_TIME #endif /** @@ -90,6 +64,8 @@ */ #ifdef CONFIG_MBEDTLS_HAVE_TIME_DATE #define MBEDTLS_HAVE_TIME_DATE +#else +#undef MBEDTLS_HAVE_TIME_DATE #endif /** @@ -123,78 +99,6 @@ #define MBEDTLS_PLATFORM_STD_FREE esp_mbedtls_mem_free #endif -/** - * \def MBEDTLS_PLATFORM_NO_STD_FUNCTIONS - * - * Do not assign standard functions in the platform layer (e.g. calloc() to - * MBEDTLS_PLATFORM_STD_CALLOC and printf() to MBEDTLS_PLATFORM_STD_PRINTF) - * - * This makes sure there are no linking errors on platforms that do not support - * these functions. You will HAVE to provide alternatives, either at runtime - * via the platform_set_xxx() functions or at compile time by setting - * the MBEDTLS_PLATFORM_STD_XXX defines, or enabling a - * MBEDTLS_PLATFORM_XXX_MACRO. - * - * Requires: MBEDTLS_PLATFORM_C - * - * Uncomment to prevent default assignment of standard functions in the - * platform layer. - */ -//#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS - -/** - * \def MBEDTLS_PLATFORM_EXIT_ALT - * - * MBEDTLS_PLATFORM_XXX_ALT: Uncomment a macro to let mbed TLS support the - * function in the platform abstraction layer. - * - * Example: In case you uncomment MBEDTLS_PLATFORM_PRINTF_ALT, mbed TLS will - * provide a function "mbedtls_platform_set_printf()" that allows you to set an - * alternative printf function pointer. - * - * All these define require MBEDTLS_PLATFORM_C to be defined! - * - * \note MBEDTLS_PLATFORM_SNPRINTF_ALT is required on Windows; - * it will be enabled automatically by check_config.h - * - * \warning MBEDTLS_PLATFORM_XXX_ALT cannot be defined at the same time as - * MBEDTLS_PLATFORM_XXX_MACRO! - * - * Uncomment a macro to enable alternate implementation of specific base - * platform function - */ -//#define MBEDTLS_PLATFORM_EXIT_ALT -//#define MBEDTLS_PLATFORM_FPRINTF_ALT -//#define MBEDTLS_PLATFORM_PRINTF_ALT -//#define MBEDTLS_PLATFORM_SNPRINTF_ALT - -/** - * \def MBEDTLS_DEPRECATED_WARNING - * - * Mark deprecated functions so that they generate a warning if used. - * Functions deprecated in one version will usually be removed in the next - * version. You can enable this to help you prepare the transition to a new - * major version by making sure your code is not using these functions. - * - * This only works with GCC and Clang. With other compilers, you may want to - * use MBEDTLS_DEPRECATED_REMOVED - * - * Uncomment to get warnings on using deprecated functions. - */ -//#define MBEDTLS_DEPRECATED_WARNING - -/** - * \def MBEDTLS_DEPRECATED_REMOVED - * - * Remove deprecated functions so that they generate an error if used. - * Functions deprecated in one version will usually be removed in the next - * version. You can enable this to help you prepare the transition to a new - * major version by making sure your code is not using these functions. - * - * Uncomment to get errors on using deprecated functions. - */ -//#define MBEDTLS_DEPRECATED_REMOVED - /* \} name SECTION: System support */ /** @@ -205,53 +109,13 @@ * \{ */ -/** - * \def MBEDTLS_TIMING_ALT - * - * Uncomment to provide your own alternate implementation for mbedtls_timing_hardclock(), - * mbedtls_timing_get_timer(), mbedtls_set_alarm(), mbedtls_set/get_delay() - * - * Only works if you have MBEDTLS_TIMING_C enabled. - * - * You will need to provide a header "timing_alt.h" and an implementation at - * compile time. - */ -//#define MBEDTLS_TIMING_ALT - -/** - * \def MBEDTLS_AES_ALT - * - * MBEDTLS__MODULE_NAME__ALT: Uncomment a macro to let mbed TLS use your - * alternate core implementation of a symmetric crypto or hash module (e.g. - * platform specific assembly optimized implementations). Keep in mind that - * the function prototypes should remain the same. - * - * This replaces the whole module. If you only want to replace one of the - * functions, use one of the MBEDTLS__FUNCTION_NAME__ALT flags. - * - * Example: In case you uncomment MBEDTLS_AES_ALT, mbed TLS will no longer - * provide the "struct mbedtls_aes_context" definition and omit the base function - * declarations and implementations. "aes_alt.h" will be included from - * "aes.h" to include the new function definitions. - * - * Uncomment a macro to enable alternate implementation of the corresponding - * module. - */ -//#define MBEDTLS_ARC4_ALT -//#define MBEDTLS_BLOWFISH_ALT -//#define MBEDTLS_CAMELLIA_ALT -//#define MBEDTLS_DES_ALT -//#define MBEDTLS_XTEA_ALT -//#define MBEDTLS_MD2_ALT -//#define MBEDTLS_MD4_ALT -//#define MBEDTLS_MD5_ALT -//#define MBEDTLS_RIPEMD160_ALT - /* The following units have ESP32 hardware support, uncommenting each _ALT macro will use the hardware-accelerated implementation. */ #ifdef CONFIG_MBEDTLS_HARDWARE_AES #define MBEDTLS_AES_ALT +#else +#undef MBEDTLS_AES_ALT #endif /* MBEDTLS_SHAxx_ALT to enable hardware SHA support @@ -261,6 +125,10 @@ #define MBEDTLS_SHA1_ALT #define MBEDTLS_SHA256_ALT #define MBEDTLS_SHA512_ALT +#else +#undef MBEDTLS_SHA1_ALT +#undef MBEDTLS_SHA256_ALT +#undef MBEDTLS_SHA512_ALT #endif /* The following MPI (bignum) functions have ESP32 hardware support, @@ -270,46 +138,11 @@ #ifdef CONFIG_MBEDTLS_HARDWARE_MPI #define MBEDTLS_MPI_EXP_MOD_ALT #define MBEDTLS_MPI_MUL_MPI_ALT +#else +#undef MBEDTLS_MPI_EXP_MOD_ALT +#undef MBEDTLS_MPI_MUL_MPI_ALT #endif -/** - * \def MBEDTLS_MD2_PROCESS_ALT - * - * MBEDTLS__FUNCTION_NAME__ALT: Uncomment a macro to let mbed TLS use you - * alternate core implementation of symmetric crypto or hash function. Keep in - * mind that function prototypes should remain the same. - * - * This replaces only one function. The header file from mbed TLS is still - * used, in contrast to the MBEDTLS__MODULE_NAME__ALT flags. - * - * Example: In case you uncomment MBEDTLS_SHA256_PROCESS_ALT, mbed TLS will - * no longer provide the mbedtls_sha1_process() function, but it will still provide - * the other function (using your mbedtls_sha1_process() function) and the definition - * of mbedtls_sha1_context, so your implementation of mbedtls_sha1_process must be compatible - * with this definition. - * - * Note: if you use the AES_xxx_ALT macros, then is is recommended to also set - * MBEDTLS_AES_ROM_TABLES in order to help the linker garbage-collect the AES - * tables. - * - * Uncomment a macro to enable alternate implementation of the corresponding - * function. - */ -//#define MBEDTLS_MD2_PROCESS_ALT -//#define MBEDTLS_MD4_PROCESS_ALT -//#define MBEDTLS_MD5_PROCESS_ALT -//#define MBEDTLS_RIPEMD160_PROCESS_ALT -//#define MBEDTLS_SHA1_PROCESS_ALT -//#define MBEDTLS_SHA256_PROCESS_ALT -//#define MBEDTLS_SHA512_PROCESS_ALT -//#define MBEDTLS_DES_SETKEY_ALT -//#define MBEDTLS_DES_CRYPT_ECB_ALT -//#define MBEDTLS_DES3_CRYPT_ECB_ALT -//#define MBEDTLS_AES_SETKEY_ENC_ALT -//#define MBEDTLS_AES_SETKEY_DEC_ALT -//#define MBEDTLS_AES_ENCRYPT_ALT -//#define MBEDTLS_AES_DECRYPT_ALT - /** * \def MBEDTLS_ENTROPY_HARDWARE_ALT * @@ -332,15 +165,6 @@ */ #define MBEDTLS_AES_ROM_TABLES -/** - * \def MBEDTLS_CAMELLIA_SMALL_MEMORY - * - * Use less ROM for the Camellia implementation (saves about 768 bytes). - * - * Uncomment this macro to use less memory for Camellia. - */ -//#define MBEDTLS_CAMELLIA_SMALL_MEMORY - /** * \def MBEDTLS_CIPHER_MODE_CBC * @@ -362,6 +186,13 @@ */ #define MBEDTLS_CIPHER_MODE_CTR +/** + * \def MBEDTLS_CIPHER_MODE_OFB + * + * Enable Output Feedback mode (OFB) for symmetric ciphers. + */ +#define MBEDTLS_CIPHER_MODE_OFB + /** * \def MBEDTLS_CIPHER_MODE_XTS * @@ -369,39 +200,6 @@ */ #define MBEDTLS_CIPHER_MODE_XTS -/** - * \def MBEDTLS_CIPHER_NULL_CIPHER - * - * Enable NULL cipher. - * Warning: Only do so when you know what you are doing. This allows for - * encryption or channels without any security! - * - * Requires MBEDTLS_ENABLE_WEAK_CIPHERSUITES as well to enable - * the following ciphersuites: - * MBEDTLS_TLS_ECDH_ECDSA_WITH_NULL_SHA - * MBEDTLS_TLS_ECDH_RSA_WITH_NULL_SHA - * MBEDTLS_TLS_ECDHE_ECDSA_WITH_NULL_SHA - * MBEDTLS_TLS_ECDHE_RSA_WITH_NULL_SHA - * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA384 - * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA256 - * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA - * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA384 - * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA256 - * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA - * MBEDTLS_TLS_RSA_WITH_NULL_SHA256 - * MBEDTLS_TLS_RSA_WITH_NULL_SHA - * MBEDTLS_TLS_RSA_WITH_NULL_MD5 - * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA384 - * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA256 - * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA - * MBEDTLS_TLS_PSK_WITH_NULL_SHA384 - * MBEDTLS_TLS_PSK_WITH_NULL_SHA256 - * MBEDTLS_TLS_PSK_WITH_NULL_SHA - * - * Uncomment this macro to enable the NULL cipher and ciphersuites - */ -//#define MBEDTLS_CIPHER_NULL_CIPHER - /** * \def MBEDTLS_CIPHER_PADDING_PKCS7 * @@ -419,24 +217,24 @@ #define MBEDTLS_CIPHER_PADDING_ZEROS /** - * \def MBEDTLS_ENABLE_WEAK_CIPHERSUITES + * \def MBEDTLS_REMOVE_ARC4_CIPHERSUITES & MBEDTLS_ARC4_C + * + * MBEDTLS_ARC4_C + * Enable the ARCFOUR stream cipher. * - * Enable weak ciphersuites in SSL / TLS. - * Warning: Only do so when you know what you are doing. This allows for - * channels with virtually no security at all! + * This module enables/disables the following ciphersuites + * MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_MD5 + * MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA + * MBEDTLS_TLS_PSK_WITH_RC4_128_SHA * - * This enables the following ciphersuites: - * MBEDTLS_TLS_RSA_WITH_DES_CBC_SHA - * MBEDTLS_TLS_DHE_RSA_WITH_DES_CBC_SHA - * - * Uncomment this macro to enable weak ciphersuites - */ -//#define MBEDTLS_ENABLE_WEAK_CIPHERSUITES - -/** - * \def MBEDTLS_REMOVE_ARC4_CIPHERSUITES - * - * Remove RC4 ciphersuites by default in SSL / TLS. + * MBEDTLS_REMOVE_ARC4_CIPHERSUITES * This flag removes the ciphersuites based on RC4 from the default list as * returned by mbedtls_ssl_list_ciphersuites(). However, it is still possible to * enable (some of) them with mbedtls_ssl_conf_ciphersuites() by including them @@ -445,6 +243,13 @@ * Uncomment this macro to remove RC4 ciphersuites by default. */ #ifdef CONFIG_MBEDTLS_RC4_ENABLED +#define MBEDTLS_ARC4_C +#undef MBEDTLS_REMOVE_ARC4_CIPHERSUITES +#elif defined CONFIG_MBEDTLS_RC4_ENABLED_NO_DEFAULT +#define MBEDTLS_ARC4_C +#define MBEDTLS_REMOVE_ARC4_CIPHERSUITES +#else +#undef MBEDTLS_ARC4_C #define MBEDTLS_REMOVE_ARC4_CIPHERSUITES #endif @@ -458,39 +263,67 @@ */ #ifdef CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED #define MBEDTLS_ECP_DP_SECP192R1_ENABLED +#else +#undef MBEDTLS_ECP_DP_SECP192R1_ENABLED #endif #ifdef CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED #define MBEDTLS_ECP_DP_SECP224R1_ENABLED +#else +#undef MBEDTLS_ECP_DP_SECP224R1_ENABLED #endif #ifdef CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED #define MBEDTLS_ECP_DP_SECP256R1_ENABLED +#else +#undef MBEDTLS_ECP_DP_SECP256R1_ENABLED #endif #ifdef CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED #define MBEDTLS_ECP_DP_SECP384R1_ENABLED +#else +#undef MBEDTLS_ECP_DP_SECP384R1_ENABLED #endif #ifdef CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED #define MBEDTLS_ECP_DP_SECP521R1_ENABLED +#else +#undef MBEDTLS_ECP_DP_SECP521R1_ENABLED #endif #ifdef CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED #define MBEDTLS_ECP_DP_SECP192K1_ENABLED +#else +#undef MBEDTLS_ECP_DP_SECP192K1_ENABLED #endif #ifdef CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED #define MBEDTLS_ECP_DP_SECP224K1_ENABLED +#else +#undef MBEDTLS_ECP_DP_SECP224K1_ENABLED #endif #ifdef CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED #define MBEDTLS_ECP_DP_SECP256K1_ENABLED +#else +#undef MBEDTLS_ECP_DP_SECP256K1_ENABLED #endif #ifdef CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED #define MBEDTLS_ECP_DP_BP256R1_ENABLED +#else +#undef MBEDTLS_ECP_DP_BP256R1_ENABLED #endif #ifdef CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED #define MBEDTLS_ECP_DP_BP384R1_ENABLED +#else +#undef MBEDTLS_ECP_DP_BP384R1_ENABLED #endif #ifdef CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED #define MBEDTLS_ECP_DP_BP512R1_ENABLED +#else +#undef MBEDTLS_ECP_DP_BP512R1_ENABLED #endif #ifdef CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED #define MBEDTLS_ECP_DP_CURVE25519_ENABLED +#else +#undef MBEDTLS_ECP_DP_CURVE25519_ENABLED +#endif + +#ifdef MBEDTLS_ECP_DP_CURVE448_ENABLED +#undef MBEDTLS_ECP_DP_CURVE448_ENABLED #endif /** @@ -504,6 +337,8 @@ */ #ifdef CONFIG_MBEDTLS_ECP_NIST_OPTIM #define MBEDTLS_ECP_NIST_OPTIM +#else +#undef MBEDTLS_ECP_NIST_OPTIM #endif /** @@ -542,6 +377,8 @@ */ #ifdef CONFIG_MBEDTLS_KEY_EXCHANGE_PSK #define MBEDTLS_KEY_EXCHANGE_PSK_ENABLED +#else +#undef MBEDTLS_KEY_EXCHANGE_PSK_ENABLED #endif /** @@ -568,6 +405,8 @@ */ #ifdef CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_PSK #define MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED +#else +#undef MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED #endif /** @@ -590,6 +429,8 @@ */ #ifdef CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_PSK #define MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED +#else +#undef MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED #endif /** @@ -617,6 +458,8 @@ */ #ifdef CONFIG_MBEDTLS_KEY_EXCHANGE_RSA_PSK #define MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED +#else +#undef MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED #endif /** @@ -647,6 +490,8 @@ */ #ifdef CONFIG_MBEDTLS_KEY_EXCHANGE_RSA #define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED +#else +#undef MBEDTLS_KEY_EXCHANGE_RSA_ENABLED #endif /** @@ -675,6 +520,8 @@ */ #ifdef CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA #define MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED +#else +#undef MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED #endif /** @@ -702,6 +549,8 @@ */ #ifdef CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA #define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED +#else +#undef MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED #endif /** @@ -728,6 +577,8 @@ */ #ifdef CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA #define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED +#else +#undef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED #endif /** @@ -754,6 +605,8 @@ */ #ifdef CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA #define MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED +#else +#undef MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED #endif /** @@ -780,27 +633,10 @@ */ #ifdef CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA #define MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED +#else +#undef MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED #endif -/** - * \def MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED - * - * Enable the ECJPAKE based ciphersuite modes in SSL / TLS. - * - * \warning This is currently experimental. EC J-PAKE support is based on the - * Thread v1.0.0 specification; incompatible changes to the specification - * might still happen. For this reason, this is disabled by default. - * - * Requires: MBEDTLS_ECJPAKE_C - * MBEDTLS_SHA256_C - * MBEDTLS_ECP_DP_SECP256R1_ENABLED - * - * This enables the following ciphersuites (if other requisites are - * enabled as well): - * MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8 - */ -//#define MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED - /** * \def MBEDTLS_PK_PARSE_EC_EXTENDED * @@ -846,19 +682,6 @@ */ #define MBEDTLS_FS_IO -/** - * \def MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES - * - * Do not add default entropy sources. These are the platform specific, - * mbedtls_timing_hardclock and HAVEGE based poll functions. - * - * This is useful to have more control over the added entropy sources in an - * application. - * - * Uncomment this macro to prevent loading of default entropy functions. - */ -//#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES - /** * \def MBEDTLS_NO_PLATFORM_ENTROPY * @@ -870,47 +693,6 @@ */ #define MBEDTLS_NO_PLATFORM_ENTROPY -/** - * \def MBEDTLS_ENTROPY_FORCE_SHA256 - * - * Force the entropy accumulator to use a SHA-256 accumulator instead of the - * default SHA-512 based one (if both are available). - * - * Requires: MBEDTLS_SHA256_C - * - * On 32-bit systems SHA-256 can be much faster than SHA-512. Use this option - * if you have performance concerns. - * - * This option is only useful if both MBEDTLS_SHA256_C and - * MBEDTLS_SHA512_C are defined. Otherwise the available hash module is used. - */ -//#define MBEDTLS_ENTROPY_FORCE_SHA256 - -/** - * \def MBEDTLS_MEMORY_DEBUG - * - * Enable debugging of buffer allocator memory issues. Automatically prints - * (to stderr) all (fatal) messages on memory allocation issues. Enables - * function for 'debug output' of allocated memory. - * - * Requires: MBEDTLS_MEMORY_BUFFER_ALLOC_C - * - * Uncomment this macro to let the buffer allocator print out error messages. - */ -//#define MBEDTLS_MEMORY_DEBUG - -/** - * \def MBEDTLS_MEMORY_BACKTRACE - * - * Include backtrace information with each allocated block. - * - * Requires: MBEDTLS_MEMORY_BUFFER_ALLOC_C - * GLIBC-compatible backtrace() an backtrace_symbols() support - * - * Uncomment this macro to include backtrace information - */ -//#define MBEDTLS_MEMORY_BACKTRACE - /** * \def MBEDTLS_PK_RSA_ALT_SUPPORT * @@ -942,16 +724,6 @@ */ #define MBEDTLS_PKCS1_V21 -/** - * \def MBEDTLS_RSA_NO_CRT - * - * Do not use the Chinese Remainder Theorem for the RSA private operation. - * - * Uncomment this macro to disable the use of CRT in RSA. - * - */ -//#define MBEDTLS_RSA_NO_CRT - /** * \def MBEDTLS_SELF_TEST * @@ -959,34 +731,6 @@ */ #define MBEDTLS_SELF_TEST -/** - * \def MBEDTLS_SHA256_SMALLER - * - * Enable an implementation of SHA-256 that has lower ROM footprint but also - * lower performance. - * - * The default implementation is meant to be a reasonnable compromise between - * performance and size. This version optimizes more aggressively for size at - * the expense of performance. Eg on Cortex-M4 it reduces the size of - * mbedtls_sha256_process() from ~2KB to ~0.5KB for a performance hit of about - * 30%. - * - * Uncomment to enable the smaller implementation of SHA256. - */ -//#define MBEDTLS_SHA256_SMALLER - -/** - * \def MBEDTLS_SSL_AEAD_RANDOM_IV - * - * Generate a random IV rather than using the record sequence number as a - * nonce for ciphersuites using and AEAD algorithm (GCM or CCM). - * - * Using the sequence number is generally recommended. - * - * Uncomment this macro to always use random IVs with AEAD ciphersuites. - */ -//#define MBEDTLS_SSL_AEAD_RANDOM_IV - /** * \def MBEDTLS_SSL_ALL_ALERT_MESSAGES * @@ -1001,22 +745,6 @@ */ #define MBEDTLS_SSL_ALL_ALERT_MESSAGES -/** - * \def MBEDTLS_SSL_DEBUG_ALL - * - * Enable the debug messages in SSL module for all issues. - * Debug messages have been disabled in some places to prevent timing - * attacks due to (unbalanced) debugging function calls. - * - * If you need all error reporting you should enable this during debugging, - * but remove this for production servers that should log as well. - * - * Uncomment this macro to report all debug messages on errors introducing - * a timing side-channel. - * - */ -//#define MBEDTLS_SSL_DEBUG_ALL - /** \def MBEDTLS_SSL_ENCRYPT_THEN_MAC * * Enable support for Encrypt-then-MAC, RFC 7366. @@ -1035,6 +763,8 @@ */ #ifdef CONFIG_MBEDTLS_TLS_ENABLED #define MBEDTLS_SSL_ENCRYPT_THEN_MAC +#else +#undef MBEDTLS_SSL_ENCRYPT_THEN_MAC #endif /** \def MBEDTLS_SSL_EXTENDED_MASTER_SECRET @@ -1055,6 +785,8 @@ */ #ifdef CONFIG_MBEDTLS_TLS_ENABLED #define MBEDTLS_SSL_EXTENDED_MASTER_SECRET +#else +#undef MBEDTLS_SSL_EXTENDED_MASTER_SECRET #endif /** @@ -1075,14 +807,36 @@ #define MBEDTLS_SSL_FALLBACK_SCSV /** - * \def MBEDTLS_SSL_HW_RECORD_ACCEL + * \def MBEDTLS_SSL_PROTO_TLS1 * - * Enable hooking functions in SSL module for hardware acceleration of - * individual records. + * Enable support for TLS 1.0. * - * Uncomment this macro to enable hooking functions. + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for TLS 1.0 */ -//#define MBEDTLS_SSL_HW_RECORD_ACCEL +#ifdef CONFIG_MBEDTLS_SSL_PROTO_TLS1 +#define MBEDTLS_SSL_PROTO_TLS1 +#else +#undef MBEDTLS_SSL_PROTO_TLS1 +#endif + +/** + * \def MBEDTLS_SSL_PROTO_SSL3 + * + * Enable support for SSL 3.0. + * + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for SSL 3.0 + */ +#ifdef CONFIG_MBEDTLS_SSL_PROTO_SSL3 +#define MBEDTLS_SSL_PROTO_SSL3 +#else +#undef MBEDTLS_SSL_PROTO_SSL3 +#endif /** * \def MBEDTLS_SSL_CBC_RECORD_SPLITTING @@ -1096,6 +850,8 @@ */ #if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) #define MBEDTLS_SSL_CBC_RECORD_SPLITTING +#else +#undef MBEDTLS_SSL_CBC_RECORD_SPLITTING #endif /** @@ -1113,28 +869,10 @@ */ #ifdef CONFIG_MBEDTLS_SSL_RENEGOTIATION #define MBEDTLS_SSL_RENEGOTIATION +#else +#undef MBEDTLS_SSL_RENEGOTIATION #endif -/** - * \def MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO - * - * Enable support for receiving and parsing SSLv2 Client Hello messages for the - * SSL Server module (MBEDTLS_SSL_SRV_C). - * - * Uncomment this macro to enable support for SSLv2 Client Hello messages. - */ -//#define MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO - -/** - * \def MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE - * - * Pick the ciphersuite according to the client's preferences rather than ours - * in the SSL Server module (MBEDTLS_SSL_SRV_C). - * - * Uncomment this macro to respect client's ciphersuite order - */ -//#define MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE - /** * \def MBEDTLS_SSL_MAX_FRAGMENT_LENGTH * @@ -1144,34 +882,6 @@ */ #define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH -/** - * \def MBEDTLS_SSL_PROTO_SSL3 - * - * Enable support for SSL 3.0. - * - * Requires: MBEDTLS_MD5_C - * MBEDTLS_SHA1_C - * - * Comment this macro to disable support for SSL 3.0 - */ -#ifdef CONFIG_MBEDTLS_SSL_PROTO_SSL3 -#define MBEDTLS_SSL_PROTO_SSL3 -#endif - -/** - * \def MBEDTLS_SSL_PROTO_TLS1 - * - * Enable support for TLS 1.0. - * - * Requires: MBEDTLS_MD5_C - * MBEDTLS_SHA1_C - * - * Comment this macro to disable support for TLS 1.0 - */ -#ifdef CONFIG_MBEDTLS_SSL_PROTO_TLS1 -#define MBEDTLS_SSL_PROTO_TLS1 -#endif - /** * \def MBEDTLS_SSL_PROTO_TLS1_1 * @@ -1198,6 +908,8 @@ */ #ifdef CONFIG_MBEDTLS_SSL_PROTO_TLS1_2 #define MBEDTLS_SSL_PROTO_TLS1_2 +#else +#undef MBEDTLS_SSL_PROTO_TLS1_2 #endif /** @@ -1215,6 +927,8 @@ */ #ifdef CONFIG_MBEDTLS_SSL_PROTO_DTLS #define MBEDTLS_SSL_PROTO_DTLS +#else +#undef MBEDTLS_SSL_PROTO_DTLS #endif /** @@ -1226,6 +940,8 @@ */ #ifdef CONFIG_MBEDTLS_SSL_ALPN #define MBEDTLS_SSL_ALPN +#else +#undef MBEDTLS_SSL_ALPN #endif /** @@ -1243,6 +959,8 @@ */ #ifdef CONFIG_MBEDTLS_SSL_PROTO_DTLS #define MBEDTLS_SSL_DTLS_ANTI_REPLAY +#else +#undef MBEDTLS_SSL_DTLS_ANTI_REPLAY #endif /** @@ -1263,6 +981,8 @@ */ #ifdef CONFIG_MBEDTLS_SSL_PROTO_DTLS #define MBEDTLS_SSL_DTLS_HELLO_VERIFY +#else +#undef MBEDTLS_SSL_DTLS_HELLO_VERIFY #endif /** @@ -1281,6 +1001,8 @@ */ #ifdef CONFIG_MBEDTLS_SSL_PROTO_DTLS #define MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE +#else +#undef MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE #endif /** @@ -1294,6 +1016,8 @@ */ #ifdef CONFIG_MBEDTLS_SSL_PROTO_DTLS #define MBEDTLS_SSL_DTLS_BADMAC_LIMIT +#else +#undef MBEDTLS_SSL_DTLS_BADMAC_LIMIT #endif /** @@ -1310,6 +1034,8 @@ */ #ifdef CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS #define MBEDTLS_SSL_SESSION_TICKETS +#else +#undef MBEDTLS_SSL_SESSION_TICKETS #endif /** @@ -1342,28 +1068,6 @@ */ #define MBEDTLS_SSL_TRUNCATED_HMAC -/** - * \def MBEDTLS_THREADING_ALT - * - * Provide your own alternate threading implementation. - * - * Requires: MBEDTLS_THREADING_C - * - * Uncomment this to allow your own alternate threading implementation. - */ -//#define MBEDTLS_THREADING_ALT - -/** - * \def MBEDTLS_THREADING_PTHREAD - * - * Enable the pthread wrapper layer for the threading layer. - * - * Requires: MBEDTLS_THREADING_C - * - * Uncomment this to enable pthread mutexes. - */ -//#define MBEDTLS_THREADING_PTHREAD - /** * \def MBEDTLS_VERSION_FEATURES * @@ -1377,28 +1081,6 @@ */ #define MBEDTLS_VERSION_FEATURES -/** - * \def MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 - * - * If set, the X509 parser will not break-off when parsing an X509 certificate - * and encountering an extension in a v1 or v2 certificate. - * - * Uncomment to prevent an error. - */ -//#define MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 - -/** - * \def MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION - * - * If set, the X509 parser will not break-off when parsing an X509 certificate - * and encountering an unknown critical extension. - * - * \warning Depending on your PKI use, enabling this can be a security risk! - * - * Uncomment to prevent an error. - */ -//#define MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION - /** * \def MBEDTLS_X509_CHECK_KEY_USAGE * @@ -1436,27 +1118,7 @@ */ #define MBEDTLS_X509_RSASSA_PSS_SUPPORT -/** - * \def MBEDTLS_ZLIB_SUPPORT - * - * If set, the SSL/TLS module uses ZLIB to support compression and - * decompression of packet data. - * - * \warning TLS-level compression MAY REDUCE SECURITY! See for example the - * CRIME attack. Before enabling this option, you should examine with care if - * CRIME or similar exploits may be a applicable to your use case. - * - * \note Currently compression can't be used with DTLS. - * - * Used in: library/ssl_tls.c - * library/ssl_cli.c - * library/ssl_srv.c - * - * This feature requires zlib library and headers to be present. - * - * Uncomment to enable use of ZLIB - */ -//#define MBEDTLS_ZLIB_SUPPORT + /* \} name SECTION: mbed TLS feature support */ /** @@ -1555,31 +1217,8 @@ */ #ifdef CONFIG_MBEDTLS_AES_C #define MBEDTLS_AES_C -#endif - -/** - * \def MBEDTLS_ARC4_C - * - * Enable the ARCFOUR stream cipher. - * - * Module: library/arc4.c - * Caller: library/ssl_tls.c - * - * This module enables the following ciphersuites (if other requisites are - * enabled as well): - * MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA - * MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA - * MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA - * MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA - * MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA - * MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA - * MBEDTLS_TLS_RSA_WITH_RC4_128_SHA - * MBEDTLS_TLS_RSA_WITH_RC4_128_MD5 - * MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA - * MBEDTLS_TLS_PSK_WITH_RC4_128_SHA - */ -#if defined(CONFIG_MBEDTLS_RC4_ENABLED_NO_DEFAULT) || defined(CONFIG_MBEDTLS_RC4_ENABLED) -#define MBEDTLS_ARC4_C +#else +#undef MBEDTLS_AES_C #endif /** @@ -1647,6 +1286,8 @@ */ #ifdef CONFIG_MBEDTLS_BLOWFISH_C #define MBEDTLS_BLOWFISH_C +#else +#undef MBEDTLS_BLOWFISH_C #endif /** @@ -1704,6 +1345,8 @@ */ #ifdef CONFIG_MBEDTLS_CAMELLIA_C #define MBEDTLS_CAMELLIA_C +#else +#undef MBEDTLS_CAMELLIA_C #endif /** @@ -1720,6 +1363,8 @@ */ #ifdef CONFIG_MBEDTLS_CCM_C #define MBEDTLS_CCM_C +#else +#undef MBEDTLS_CCM_C #endif /** @@ -1734,6 +1379,30 @@ */ #define MBEDTLS_CERTS_C +/** + * \def MBEDTLS_CHACHA20_C + * + * Disable the ChaCha20 stream cipher. + * + * Module: library/chacha20.c + */ +#ifdef MBEDTLS_CHACHA20_C +#undef MBEDTLS_CHACHA20_C +#endif + +/** + * \def MBEDTLS_CHACHAPOLY_C + * + * Disable the ChaCha20-Poly1305 AEAD algorithm. + * + * Module: library/chachapoly.c + * + * This module requires: MBEDTLS_CHACHA20_C, MBEDTLS_POLY1305_C + */ +#ifdef MBEDTLS_CHACHAPOLY_C +#undef MBEDTLS_CHACHAPOLY_C +#endif + /** * \def MBEDTLS_CIPHER_C * @@ -1774,6 +1443,8 @@ */ #if CONFIG_MBEDTLS_DEBUG #define MBEDTLS_DEBUG_C +#else +#undef MBEDTLS_DEBUG_C #endif /** @@ -1802,6 +1473,8 @@ */ #ifdef CONFIG_MBEDTLS_DES_C #define MBEDTLS_DES_C +#else +#undef MBEDTLS_DES_C #endif /** @@ -1834,6 +1507,8 @@ */ #ifdef CONFIG_MBEDTLS_ECDH_C #define MBEDTLS_ECDH_C +#else +#undef MBEDTLS_ECDH_C #endif /** @@ -1851,6 +1526,8 @@ */ #ifdef CONFIG_MBEDTLS_ECDSA_C #define MBEDTLS_ECDSA_C +#else +#undef MBEDTLS_ECDSA_C #endif /** @@ -1886,6 +1563,8 @@ */ #ifdef CONFIG_MBEDTLS_ECP_C #define MBEDTLS_ECP_C +#else +#undef MBEDTLS_ECP_C #endif /** @@ -1928,30 +1607,26 @@ */ #ifdef CONFIG_MBEDTLS_GCM_C #define MBEDTLS_GCM_C +#else +#undef MBEDTLS_GCM_C #endif /** - * \def MBEDTLS_HAVEGE_C + * \def MBEDTLS_HKDF_C * - * Enable the HAVEGE random generator. + * Disable the HKDF algorithm (RFC 5869). * - * Warning: the HAVEGE random generator is not suitable for virtualized - * environments - * - * Warning: the HAVEGE random generator is dependent on timing and specific - * processor traits. It is therefore not advised to use HAVEGE as - * your applications primary random generator or primary entropy pool - * input. As a secondary input to your entropy pool, it IS able add - * the (limited) extra entropy it provides. - * - * Module: library/havege.c + * Module: library/hkdf.c * Caller: * - * Requires: MBEDTLS_TIMING_C + * Requires: MBEDTLS_MD_C * - * Uncomment to enable the HAVEGE random generator. + * This module adds support for the Hashed Message Authentication Code + * (HMAC)-based key derivation function (HKDF). */ -//#define MBEDTLS_HAVEGE_C +#ifdef MBEDTLS_HKDF_C +#undef MBEDTLS_HKDF_C +#endif /** * \def MBEDTLS_HMAC_DRBG_C @@ -1979,30 +1654,6 @@ */ #define MBEDTLS_MD_C -/** - * \def MBEDTLS_MD2_C - * - * Enable the MD2 hash algorithm. - * - * Module: library/mbedtls_md2.c - * Caller: - * - * Uncomment to enable support for (rare) MD2-signed X.509 certs. - */ -//#define MBEDTLS_MD2_C - -/** - * \def MBEDTLS_MD4_C - * - * Enable the MD4 hash algorithm. - * - * Module: library/mbedtls_md4.c - * Caller: - * - * Uncomment to enable support for (rare) MD4-signed X.509 certs. - */ -//#define MBEDTLS_MD4_C - /** * \def MBEDTLS_MD5_C * @@ -2018,22 +1669,6 @@ */ #define MBEDTLS_MD5_C -/** - * \def MBEDTLS_MEMORY_BUFFER_ALLOC_C - * - * Enable the buffer allocator implementation that makes use of a (stack) - * based buffer to 'allocate' dynamic memory. (replaces calloc() and free() - * calls) - * - * Module: library/memory_buffer_alloc.c - * - * Requires: MBEDTLS_PLATFORM_C - * MBEDTLS_PLATFORM_MEMORY (to use it within mbed TLS) - * - * Enable this module to enable the buffer memory allocator. - */ -//#define MBEDTLS_MEMORY_BUFFER_ALLOC_C - /** * \def MBEDTLS_NET_C * @@ -2043,7 +1678,9 @@ * * This module provides TCP/IP networking routines. */ -//#define MBEDTLS_NET_C +#ifdef MBEDTLS_NET_C +#undef MBEDTLS_NET_C +#endif /** * \def MBEDTLS_OID_C @@ -2100,6 +1737,8 @@ */ #ifdef CONFIG_MBEDTLS_PEM_PARSE_C #define MBEDTLS_PEM_PARSE_C +#else +#undef MBEDTLS_PEM_PARSE_C #endif /** @@ -2118,6 +1757,8 @@ */ #ifdef CONFIG_MBEDTLS_PEM_WRITE_C #define MBEDTLS_PEM_WRITE_C +#else +#undef MBEDTLS_PEM_WRITE_C #endif /** @@ -2178,21 +1819,6 @@ */ #define MBEDTLS_PKCS5_C -/** - * \def MBEDTLS_PKCS11_C - * - * Enable wrapper for PKCS#11 smartcard support. - * - * Module: library/pkcs11.c - * Caller: library/pk.c - * - * Requires: MBEDTLS_PK_C - * - * This module enables SSL/TLS PKCS #11 smartcard support. - * Requires the presence of the PKCS#11 helper library (libpkcs11-helper) - */ -//#define MBEDTLS_PKCS11_C - /** * \def MBEDTLS_PKCS12_C * @@ -2229,6 +1855,18 @@ */ #define MBEDTLS_PLATFORM_C +/** + * \def MBEDTLS_POLY1305_C + * + * Disable the Poly1305 MAC algorithm. + * + * Module: library/poly1305.c + * Caller: library/chachapoly.c + */ +#ifdef MBEDTLS_POLY1305_C +#undef MBEDTLS_POLY1305_C +#endif + /** * \def MBEDTLS_RIPEMD160_C * @@ -2240,6 +1878,8 @@ */ #ifdef CONFIG_MBEDTLS_RIPEMD160_C #define MBEDTLS_RIPEMD160_C +#else +#undef MBEDTLS_RIPEMD160_C #endif /** @@ -2342,6 +1982,8 @@ */ #ifdef CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS #define MBEDTLS_SSL_TICKET_C +#else +#undef MBEDTLS_SSL_TICKET_C #endif /** @@ -2358,6 +2000,8 @@ */ #ifdef CONFIG_MBEDTLS_TLS_CLIENT #define MBEDTLS_SSL_CLI_C +#else +#undef MBEDTLS_SSL_CLI_C #endif /** @@ -2374,6 +2018,8 @@ */ #ifdef CONFIG_MBEDTLS_TLS_SERVER #define MBEDTLS_SSL_SRV_C +#else +#undef MBEDTLS_SSL_SRV_C #endif /** @@ -2392,40 +2038,34 @@ */ #ifdef CONFIG_MBEDTLS_TLS_ENABLED #define MBEDTLS_SSL_TLS_C +#else +#undef MBEDTLS_SSL_TLS_C #endif -/** - * \def MBEDTLS_THREADING_C - * - * Enable the threading abstraction layer. - * By default mbed TLS assumes it is used in a non-threaded environment or that - * contexts are not shared between threads. If you do intend to use contexts - * between threads, you will need to enable this layer to prevent race - * conditions. - * - * Module: library/threading.c - * - * This allows different threading implementations (self-implemented or - * provided). - * - * You will have to enable either MBEDTLS_THREADING_ALT or - * MBEDTLS_THREADING_PTHREAD. - * - * Enable this layer to allow use of mutexes within mbed TLS - */ -//#define MBEDTLS_THREADING_C - /** * \def MBEDTLS_TIMING_C * - * Enable the portable timing interface. + * Enable the semi-portable timing interface. + * + * \note The provided implementation only works on POSIX/Unix (including Linux, + * BSD and OS X) and Windows. On other platforms, you can either disable that + * module and provide your own implementations of the callbacks needed by + * \c mbedtls_ssl_set_timer_cb() for DTLS, or leave it enabled and provide + * your own implementation of the whole module by setting + * \c MBEDTLS_TIMING_ALT in the current file. + * + * \note See also our Knowledge Base article about porting to a new + * environment: + * https://tls.mbed.org/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-OS * * Module: library/timing.c * Caller: library/havege.c * * This module is used by the HAVEGE random number generator. */ -//#define MBEDTLS_TIMING_C +#ifdef MBEDTLS_TIMING_C +#undef MBEDTLS_TIMING_C +#endif /** * \def MBEDTLS_VERSION_C @@ -2485,6 +2125,8 @@ */ #ifdef CONFIG_MBEDTLS_X509_CRL_PARSE_C #define MBEDTLS_X509_CRL_PARSE_C +#else +#undef MBEDTLS_X509_CRL_PARSE_C #endif /** @@ -2501,6 +2143,8 @@ */ #ifdef CONFIG_MBEDTLS_X509_CSR_PARSE_C #define MBEDTLS_X509_CSR_PARSE_C +#else +#undef MBEDTLS_X509_CSR_PARSE_C #endif /** @@ -2552,6 +2196,8 @@ */ #ifdef CONFIG_MBEDTLS_XTEA_C #define MBEDTLS_XTEA_C +#else +#undef MBEDTLS_XTEA_C #endif /* \} name SECTION: mbed TLS modules */ @@ -2571,59 +2217,6 @@ * \{ */ -/* MPI / BIGNUM options */ -//#define MBEDTLS_MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */ -//#define MBEDTLS_MPI_MAX_SIZE 1024 /**< Maximum number of bytes for usable MPIs. */ - -/* CTR_DRBG options */ -//#define MBEDTLS_CTR_DRBG_ENTROPY_LEN 48 /**< Amount of entropy used per seed by default (48 with SHA-512, 32 with SHA-256) */ -//#define MBEDTLS_CTR_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ -//#define MBEDTLS_CTR_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ -//#define MBEDTLS_CTR_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ -//#define MBEDTLS_CTR_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ - -/* HMAC_DRBG options */ -//#define MBEDTLS_HMAC_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ -//#define MBEDTLS_HMAC_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ -//#define MBEDTLS_HMAC_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ -//#define MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ - -/* ECP options */ -//#define MBEDTLS_ECP_MAX_BITS 521 /**< Maximum bit size of groups */ -//#define MBEDTLS_ECP_WINDOW_SIZE 6 /**< Maximum window size used */ -//#define MBEDTLS_ECP_FIXED_POINT_OPTIM 1 /**< Enable fixed-point speed-up */ - -/* Entropy options */ -//#define MBEDTLS_ENTROPY_MAX_SOURCES 20 /**< Maximum number of sources supported */ -//#define MBEDTLS_ENTROPY_MAX_GATHER 128 /**< Maximum amount requested from entropy sources */ - -/* Memory buffer allocator options */ -//#define MBEDTLS_MEMORY_ALIGN_MULTIPLE 4 /**< Align on multiples of this value */ - -/* Platform options */ -//#define MBEDTLS_PLATFORM_STD_MEM_HDR /**< Header to include if MBEDTLS_PLATFORM_NO_STD_FUNCTIONS is defined. Don't define if no header is needed. */ -//#define MBEDTLS_PLATFORM_STD_CALLOC calloc /**< Default allocator to use, can be undefined */ -//#define MBEDTLS_PLATFORM_STD_FREE free /**< Default free to use, can be undefined */ -//#define MBEDTLS_PLATFORM_STD_EXIT exit /**< Default exit to use, can be undefined */ -//#define MBEDTLS_PLATFORM_STD_FPRINTF fprintf /**< Default fprintf to use, can be undefined */ -//#define MBEDTLS_PLATFORM_STD_PRINTF printf /**< Default printf to use, can be undefined */ -/* Note: your snprintf must correclty zero-terminate the buffer! */ -//#define MBEDTLS_PLATFORM_STD_SNPRINTF snprintf /**< Default snprintf to use, can be undefined */ - -/* To Use Function Macros MBEDTLS_PLATFORM_C must be enabled */ -/* MBEDTLS_PLATFORM_XXX_MACRO and MBEDTLS_PLATFORM_XXX_ALT cannot both be defined */ -//#define MBEDTLS_PLATFORM_CALLOC_MACRO calloc /**< Default allocator macro to use, can be undefined */ -//#define MBEDTLS_PLATFORM_FREE_MACRO free /**< Default free macro to use, can be undefined */ -//#define MBEDTLS_PLATFORM_EXIT_MACRO exit /**< Default exit macro to use, can be undefined */ -//#define MBEDTLS_PLATFORM_FPRINTF_MACRO fprintf /**< Default fprintf macro to use, can be undefined */ -//#define MBEDTLS_PLATFORM_PRINTF_MACRO printf /**< Default printf macro to use, can be undefined */ -/* Note: your snprintf must correclty zero-terminate the buffer! */ -//#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf /**< Default snprintf macro to use, can be undefined */ - -/* SSL Cache options */ -//#define MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT 86400 /**< 1 day */ -//#define MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES 50 /**< Maximum entries in cache */ - /* SSL options */ #ifndef CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN @@ -2665,27 +2258,6 @@ #endif /* !CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN */ -//#define MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME 86400 /**< Lifetime of session tickets (if enabled) */ -//#define MBEDTLS_PSK_MAX_LEN 32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */ -//#define MBEDTLS_SSL_COOKIE_TIMEOUT 60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */ - -/** - * Complete list of ciphersuites to use, in order of preference. - * - * \warning No dependency checking is done on that field! This option can only - * be used to restrict the set of available ciphersuites. It is your - * responsibility to make sure the needed modules are active. - * - * Use this to save a few hundred bytes of ROM (default ordering of all - * available ciphersuites) and a few to a few hundred bytes of RAM. - * - * The value below is only an example, not the default. - */ -//#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 - -/* X509 options */ -//#define MBEDTLS_X509_MAX_INTERMEDIATE_CA 8 /**< Maximum number of intermediate CAs in a verification chain. */ - /** * Allow SHA-1 in the default TLS configuration for TLS 1.2 handshake * signature and ciphersuite selection. Without this build-time option, SHA-1 diff --git a/components/mbedtls/test/CMakeLists.txt b/components/mbedtls/test/CMakeLists.txt index e1aad74fac..ea3ab04172 100644 --- a/components/mbedtls/test/CMakeLists.txt +++ b/components/mbedtls/test/CMakeLists.txt @@ -1,6 +1,9 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity test_utils mbedtls) -set(COMPONENT_REQUIRES unity test_utils mbedtls) - -register_component() +idf_component_get_property(mbedtls mbedtls COMPONENT_LIB) +target_compile_definitions(${mbedtls} INTERFACE "-DMBEDTLS_DEPRECATED_WARNING") +target_compile_definitions(mbedtls PUBLIC "-DMBEDTLS_DEPRECATED_WARNING") +target_compile_definitions(mbedcrypto PUBLIC "-DMBEDTLS_DEPRECATED_WARNING") +target_compile_definitions(mbedx509 PUBLIC "-DMBEDTLS_DEPRECATED_WARNING") diff --git a/components/mbedtls/test/test_mbedtls_mpi.c b/components/mbedtls/test/test_mbedtls_mpi.c index ade0fdb6b8..084fe34845 100644 --- a/components/mbedtls/test/test_mbedtls_mpi.c +++ b/components/mbedtls/test/test_mbedtls_mpi.c @@ -11,6 +11,7 @@ #include "unity.h" #include "sdkconfig.h" +#define MBEDTLS_OK 0 /* Debugging function to print an MPI number to stdout. Happens to print output that can be copy-pasted directly into a Python shell. @@ -116,11 +117,14 @@ TEST_CASE("test MPI multiplication", "[bignum]") 4096); } -static void test_bignum_modexp(const char *z_str, const char *x_str, const char *y_str, const char *m_str) +static bool test_bignum_modexp(const char *z_str, const char *x_str, const char *y_str, const char *m_str, int ret_error) { mbedtls_mpi Z, X, Y, M; char z_buf[400] = { 0 }; size_t z_buf_len = 0; + bool fail = false; + + printf("%s = (%s ^ %s) mod %s ret=%d ... ", z_str, x_str, y_str, m_str, ret_error); mbedtls_mpi_init(&Z); mbedtls_mpi_init(&X); @@ -136,38 +140,72 @@ static void test_bignum_modexp(const char *z_str, const char *x_str, const char //mbedtls_mpi_printf("M", &M); /* Z = (X ^ Y) mod M */ - TEST_ASSERT_FALSE(mbedtls_mpi_exp_mod(&Z, &X, &Y, &M, NULL)); - - mbedtls_mpi_write_string(&Z, 16, z_buf, sizeof(z_buf)-1, &z_buf_len); - TEST_ASSERT_EQUAL_STRING_MESSAGE(z_str, z_buf, "mbedtls_mpi_exp_mod incorrect"); + if (ret_error != mbedtls_mpi_exp_mod(&Z, &X, &Y, &M, NULL)) { + fail = true; + } + if (ret_error == MBEDTLS_OK) { + mbedtls_mpi_write_string(&Z, 16, z_buf, sizeof(z_buf)-1, &z_buf_len); + if (memcmp(z_str, z_buf, strlen(z_str)) != 0) { + printf("\n Expected '%s' Was '%s' \n", z_str, z_buf); + fail = true; + } + } + mbedtls_mpi_free(&Z); mbedtls_mpi_free(&X); mbedtls_mpi_free(&Y); mbedtls_mpi_free(&M); + + if (fail == true) { + printf(" FAIL\n"); + } else { + printf(" PASS\n"); + } + return fail; } TEST_CASE("test MPI modexp", "[bignum]") { - test_bignum_modexp("01000000", "1000", "2", "FFFFFFFF"); - test_bignum_modexp("014B5A90", "1234", "2", "FFFFFFF"); - test_bignum_modexp("01234321", "1111", "2", "FFFFFFFF"); - test_bignum_modexp("02", "5", "1", "3"); - test_bignum_modexp("22", "55", "1", "33"); - test_bignum_modexp("0222", "555", "1", "333"); - test_bignum_modexp("2222", "5555", "1", "3333"); - test_bignum_modexp("11", "5555", "1", "33"); + bool test_error = false; + printf("Z = (X ^ Y) mod M \n"); + // test_bignum_modexp(Z, X, Y, M, ret_error); + test_error |= test_bignum_modexp("01000000", "1000", "2", "FFFFFFFF", MBEDTLS_OK); + test_error |= test_bignum_modexp("014B5A90", "1234", "2", "FFFFFFF", MBEDTLS_OK); + test_error |= test_bignum_modexp("01234321", "1111", "2", "FFFFFFFF", MBEDTLS_OK); + test_error |= test_bignum_modexp("02", "5", "1", "3", MBEDTLS_OK); + test_error |= test_bignum_modexp("22", "55", "1", "33", MBEDTLS_OK); + test_error |= test_bignum_modexp("0222", "555", "1", "333", MBEDTLS_OK); + test_error |= test_bignum_modexp("2222", "5555", "1", "3333", MBEDTLS_OK); + test_error |= test_bignum_modexp("11", "5555", "1", "33", MBEDTLS_OK); + test_error |= test_bignum_modexp("55", "1111", "1", "77", MBEDTLS_OK); + test_error |= test_bignum_modexp("88", "1111", "2", "BB", MBEDTLS_OK); + test_error |= test_bignum_modexp("01000000", "2", "128", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", MBEDTLS_OK); + test_error |= test_bignum_modexp("0ABCDEF12345", "ABCDEF12345", "1", "FFFFFFFFFFFF", MBEDTLS_OK); + test_error |= test_bignum_modexp("0ABCDE", "ABCDE", "1", "FFFFF", MBEDTLS_OK); - test_bignum_modexp("55", "1111", "1", "77"); - test_bignum_modexp("88", "1111", "2", "BB"); + test_error |= test_bignum_modexp("04", "2", "2", "9", MBEDTLS_OK); + test_error |= test_bignum_modexp("04", "2", "-2", "9", MBEDTLS_ERR_MPI_BAD_INPUT_DATA); + test_error |= test_bignum_modexp("04", "2", "2", "-9", MBEDTLS_ERR_MPI_BAD_INPUT_DATA); + test_error |= test_bignum_modexp("04", "2", "-2", "-9", MBEDTLS_ERR_MPI_BAD_INPUT_DATA); - test_bignum_modexp("01000000", "2", "128", - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); + test_error |= test_bignum_modexp("01", "2", "0", "9", MBEDTLS_OK); + test_error |= test_bignum_modexp("04", "2", "0", "0", MBEDTLS_ERR_MPI_BAD_INPUT_DATA); + test_error |= test_bignum_modexp("04", "2", "2", "0", MBEDTLS_ERR_MPI_BAD_INPUT_DATA); + test_error |= test_bignum_modexp("00", "0", "2", "9", MBEDTLS_OK); + test_error |= test_bignum_modexp("01", "0", "0", "9", MBEDTLS_OK); - /* failures below here... */ - test_bignum_modexp("0ABCDEF12345", "ABCDEF12345", "1", "FFFFFFFFFFFF"); - test_bignum_modexp("0ABCDE", "ABCDE", "1", "FFFFF"); + test_error |= test_bignum_modexp("04", "-2", "2", "9", MBEDTLS_OK); + test_error |= test_bignum_modexp("01", "-2", "0", "9", MBEDTLS_OK); + test_error |= test_bignum_modexp("07", "-2", "7", "9", MBEDTLS_OK); + test_error |= test_bignum_modexp("07", "-2", "1", "9", MBEDTLS_OK); + test_error |= test_bignum_modexp("02", "2", "1", "9", MBEDTLS_OK); + test_error |= test_bignum_modexp("01", "2", "0", "9", MBEDTLS_OK); - test_bignum_modexp("04", "2", "2", "9"); + test_error |= test_bignum_modexp("05", "5", "7", "7", MBEDTLS_OK); + test_error |= test_bignum_modexp("02", "-5", "7", "7", MBEDTLS_OK); + test_error |= test_bignum_modexp("01", "-5", "7", "3", MBEDTLS_OK); + + TEST_ASSERT_FALSE_MESSAGE(test_error, "mbedtls_mpi_exp_mod incorrect for some tests\n"); } diff --git a/components/mdns/CMakeLists.txt b/components/mdns/CMakeLists.txt index 0933e30059..7b744dde56 100644 --- a/components/mdns/CMakeLists.txt +++ b/components/mdns/CMakeLists.txt @@ -1,9 +1,7 @@ -set(COMPONENT_SRCS "mdns.c" - "mdns_console.c" - "mdns_networking.c") -set(COMPONENT_ADD_INCLUDEDIRS "include") -set(COMPONENT_PRIV_INCLUDEDIRS "private_include") -set(COMPONENT_REQUIRES lwip mbedtls console tcpip_adapter) - -register_component() +idf_component_register(SRCS "mdns.c" + "mdns_console.c" + "mdns_networking.c" + INCLUDE_DIRS "include" + PRIV_INCLUDE_DIRS "private_include" + REQUIRES lwip mbedtls console tcpip_adapter) diff --git a/components/mdns/mdns.c b/components/mdns/mdns.c index c8a07bcda6..64ed52ebc8 100644 --- a/components/mdns/mdns.c +++ b/components/mdns/mdns.c @@ -174,7 +174,7 @@ static const uint8_t * _mdns_read_fqdn(const uint8_t * packet, const uint8_t * s size_t index = 0; while (start[index]) { if (name->parts == 4) { - return NULL; + name->invalid = true; } uint8_t len = start[index++]; if (len < 0xC0) { @@ -195,7 +195,7 @@ static const uint8_t * _mdns_read_fqdn(const uint8_t * packet, const uint8_t * s strlcat(name->host, buf, sizeof(name->host)); } else if (strcasecmp(buf, MDNS_SUB_STR) == 0) { name->sub = 1; - } else { + } else if (!name->invalid) { char* mdns_name_ptrs[]={name->host, name->service, name->proto, name->domain}; memcpy(mdns_name_ptrs[name->parts++], buf, len+1); } @@ -1312,6 +1312,7 @@ static mdns_tx_packet_t * _mdns_create_probe_packet(tcpip_adapter_if_t tcpip_if, q->domain = MDNS_DEFAULT_DOMAIN; if (!q->host || _mdns_question_exists(q, packet->questions)) { free(q); + continue; } else { queueToEnd(mdns_out_question_t, packet->questions, q); } @@ -2315,6 +2316,7 @@ static const uint8_t * _mdns_parse_fqdn(const uint8_t * packet, const uint8_t * name->service[0] = 0; name->proto[0] = 0; name->domain[0] = 0; + name->invalid = false; static char buf[MDNS_NAME_BUF_LEN]; @@ -2322,7 +2324,7 @@ static const uint8_t * _mdns_parse_fqdn(const uint8_t * packet, const uint8_t * if (!next_data) { return 0; } - if (!name->parts) { + if (!name->parts || name->invalid) { return next_data; } if (name->parts == 3) { @@ -2620,7 +2622,7 @@ void mdns_parse_packet(mdns_rx_packet_t * packet) clas &= 0x7FFF; content = content + 4; - if (clas != 0x0001) {//bad class + if (clas != 0x0001 || name->invalid) {//bad class or invalid name for this question entry continue; } @@ -2801,7 +2803,7 @@ void mdns_parse_packet(mdns_rx_packet_t * packet) col = 1; } else if (!clas) { col = -1; - } else { + } else if (service) { // only detect srv collision if service existed col = _mdns_check_srv_collision(service->service, priority, weight, port, name->host, name->domain); } if (col && (parsed_packet->probe || parsed_packet->authoritative)) { @@ -3837,23 +3839,25 @@ static void _mdns_execute_action(mdns_action_t * action) break; case ACTION_SERVICE_DEL: a = _mdns_server->services; - if (_mdns_server->services == action->data.srv_del.service) { - _mdns_server->services = a->next; - _mdns_send_bye(&a, 1, false); - _mdns_remove_scheduled_service_packets(a->service); - _mdns_free_service(a->service); - free(a); - } else { - while (a->next && a->next != action->data.srv_del.service) { - a = a->next; - } - if (a->next == action->data.srv_del.service) { - mdns_srv_item_t * b = a->next; - a->next = a->next->next; - _mdns_send_bye(&b, 1, false); - _mdns_remove_scheduled_service_packets(b->service); - _mdns_free_service(b->service); - free(b); + if (action->data.srv_del.service) { + if (_mdns_server->services == action->data.srv_del.service) { + _mdns_server->services = a->next; + _mdns_send_bye(&a, 1, false); + _mdns_remove_scheduled_service_packets(a->service); + _mdns_free_service(a->service); + free(a); + } else { + while (a->next && a->next != action->data.srv_del.service) { + a = a->next; + } + if (a->next == action->data.srv_del.service) { + mdns_srv_item_t * b = a->next; + a->next = a->next->next; + _mdns_send_bye(&b, 1, false); + _mdns_remove_scheduled_service_packets(b->service); + _mdns_free_service(b->service); + free(b); + } } } diff --git a/components/mdns/private_include/mdns_private.h b/components/mdns/private_include/mdns_private.h index e3becf28ff..ed7e89cb8f 100644 --- a/components/mdns/private_include/mdns_private.h +++ b/components/mdns/private_include/mdns_private.h @@ -184,6 +184,7 @@ typedef struct { char domain[MDNS_NAME_BUF_LEN]; uint8_t parts; uint8_t sub; + bool invalid; } mdns_name_t; typedef struct mdns_parsed_question_s { diff --git a/components/mdns/test/CMakeLists.txt b/components/mdns/test/CMakeLists.txt new file mode 100644 index 0000000000..516ee0097b --- /dev/null +++ b/components/mdns/test/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRC_DIRS "." + PRIV_REQUIRES unity test_utils mdns) \ No newline at end of file diff --git a/components/mdns/test/component.mk b/components/mdns/test/component.mk new file mode 100644 index 0000000000..5be873488b --- /dev/null +++ b/components/mdns/test/component.mk @@ -0,0 +1,4 @@ +# +#Component Makefile +# +COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive \ No newline at end of file diff --git a/components/mdns/test/test_mdns.c b/components/mdns/test/test_mdns.c new file mode 100644 index 0000000000..6ae5e835ff --- /dev/null +++ b/components/mdns/test/test_mdns.c @@ -0,0 +1,99 @@ +#include "test_utils.h" +#include "mdns.h" +#include "unity.h" + + +#define MDNS_HOSTNAME "test-hostname" +#define MDNS_INSTANCE "test-instance" +#define MDNS_SERVICE_NAME "_http" +#define MDNS_SERVICE_PROTO "_tcp" +#define MDNS_SERVICE_PORT 80 + + +static void yield_to_all_priorities(void) +{ + // Lower the test-task priority before testing to ensure other tasks got executed on forced context switch + size_t test_task_prio_before = uxTaskPriorityGet(NULL); + vTaskPrioritySet(NULL, tskIDLE_PRIORITY); + taskYIELD(); // Let the RTOS to switch context + vTaskPrioritySet(NULL, test_task_prio_before); +} + + +TEST_CASE("mdns api to fail in invalid state", "[mdns][leaks=64]") +{ + TEST_ASSERT_NOT_EQUAL(ESP_OK, mdns_init() ); + TEST_ASSERT_NOT_EQUAL(ESP_OK, mdns_hostname_set(MDNS_HOSTNAME) ); + TEST_ASSERT_NOT_EQUAL(ESP_OK, mdns_instance_name_set(MDNS_INSTANCE) ); + TEST_ASSERT_NOT_EQUAL(ESP_OK, mdns_service_add(MDNS_INSTANCE, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_SERVICE_PORT, NULL, 0) ); +} + +TEST_CASE("mdns init and deinit", "[mdns][leaks=64]") +{ + test_case_uses_tcpip(); + TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_create_default()); + TEST_ASSERT_EQUAL(ESP_OK, mdns_init() ); + yield_to_all_priorities(); // Make sure that mdns task has executed to complete initialization + mdns_free(); + esp_event_loop_delete_default(); +} + +TEST_CASE("mdns api return expected err-code and do not leak memory", "[mdns][leaks=64]") +{ + mdns_txt_item_t serviceTxtData[CONFIG_MDNS_MAX_SERVICES] = { {NULL, NULL}, + }; + for (int i=0; i") - target_link_libraries(${COMPONENT_LIB} extra) + target_link_libraries(${COMPONENT_LIB} PUBLIC extra) else() - target_link_libraries(${COMPONENT_LIB} ${LIBC} ${LIBM} gcc) + target_link_libraries(${COMPONENT_LIB} PUBLIC ${LIBC} ${LIBM} gcc) endif() set_source_files_properties(heap.c PROPERTIES COMPILE_FLAGS -fno-builtin) if(EXTRA_LINK_FLAGS) - target_link_libraries(${COMPONENT_LIB} "${EXTRA_LINK_FLAGS}") + target_link_libraries(${COMPONENT_LIB} INTERFACE "${EXTRA_LINK_FLAGS}") endif() diff --git a/components/newlib/include/sys/syslimits.h b/components/newlib/include/sys/syslimits.h index c0bb3a2ce0..c778f0faf3 100644 --- a/components/newlib/include/sys/syslimits.h +++ b/components/newlib/include/sys/syslimits.h @@ -51,7 +51,7 @@ #endif #define PATH_MAX 1024 /* max bytes in pathname */ #define PIPE_BUF 512 /* max bytes for atomic pipe writes */ -#define IOV_MAX 1024 /* max elements in i/o vector */ + #define BC_BASE_MAX 99 /* max ibase/obase values in bc(1) */ #define BC_DIM_MAX 2048 /* max array elements in bc(1) */ diff --git a/components/newlib/platform_include/net/if.h b/components/newlib/platform_include/net/if.h index 8760bb156e..e3d0a601a0 100644 --- a/components/newlib/platform_include/net/if.h +++ b/components/newlib/platform_include/net/if.h @@ -14,6 +14,8 @@ #ifndef _ESP_PLATFORM_NET_IF_H_ #define _ESP_PLATFORM_NET_IF_H_ +#include "lwip/sockets.h" + #define MSG_DONTROUTE 0x4 /* send without using routing tables */ #define SOCK_SEQPACKET 5 /* sequenced packet stream */ #define MSG_EOR 0x8 /* data completes record */ @@ -29,12 +31,6 @@ #define NI_NUMERICSERV 0x00000008 #define NI_DGRAM 0x00000010 - -struct ipv6_mreq { - struct in6_addr ipv6mr_multiaddr; - unsigned int ipv6mr_interface; -}; - typedef u32_t socklen_t; diff --git a/components/newlib/platform_include/sys/termios.h b/components/newlib/platform_include/sys/termios.h index fd0eb5ca88..c27e107be3 100644 --- a/components/newlib/platform_include/sys/termios.h +++ b/components/newlib/platform_include/sys/termios.h @@ -27,7 +27,7 @@ #include #include "sdkconfig.h" -#ifdef CONFIG_SUPPORT_TERMIOS +#ifdef CONFIG_VFS_SUPPORT_TERMIOS // subscripts for the array c_cc: #define VEOF 0 /** EOF character */ @@ -291,6 +291,6 @@ int tcsetattr(int fd, int optional_actions, const struct termios *p); } // extern "C" #endif -#endif // CONFIG_SUPPORT_TERMIOS +#endif // CONFIG_VFS_SUPPORT_TERMIOS #endif //__ESP_SYS_TERMIOS_H__ diff --git a/components/newlib/pread.c b/components/newlib/pread.c new file mode 100644 index 0000000000..d14bd7257d --- /dev/null +++ b/components/newlib/pread.c @@ -0,0 +1,21 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include "esp_vfs.h" + +ssize_t pread(int fd, void *dst, size_t size, off_t offset) +{ + return esp_vfs_pread(fd, dst, size, offset); +} diff --git a/components/newlib/pwrite.c b/components/newlib/pwrite.c new file mode 100644 index 0000000000..78fd0b85ce --- /dev/null +++ b/components/newlib/pwrite.c @@ -0,0 +1,21 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include "esp_vfs.h" + +ssize_t pwrite(int fd, const void *src, size_t size, off_t offset) +{ + return esp_vfs_pwrite(fd, src, size, offset); +} diff --git a/components/newlib/select.c b/components/newlib/select.c index 38b2523913..a8e68e72b2 100644 --- a/components/newlib/select.c +++ b/components/newlib/select.c @@ -19,9 +19,9 @@ #ifdef CONFIG_LWIP_USE_ONLY_LWIP_SELECT #include "lwip/sockets.h" -#ifdef CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT +#ifdef CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT #define LOG_LOCAL_LEVEL ESP_LOG_NONE -#endif //CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT +#endif //CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT #include "esp_log.h" static const char *TAG = "newlib_select"; diff --git a/components/newlib/termios.c b/components/newlib/termios.c index bccd5bf839..cb0c94b9bb 100644 --- a/components/newlib/termios.c +++ b/components/newlib/termios.c @@ -14,7 +14,7 @@ #include "sdkconfig.h" -#ifdef CONFIG_SUPPORT_TERMIOS +#ifdef CONFIG_VFS_SUPPORT_TERMIOS #include #include @@ -51,4 +51,4 @@ int cfsetospeed(struct termios *p, speed_t sp) } } -#endif // CONFIG_SUPPORT_TERMIOS +#endif // CONFIG_VFS_SUPPORT_TERMIOS diff --git a/components/newlib/test/CMakeLists.txt b/components/newlib/test/CMakeLists.txt index 66a8c82315..b531a14504 100644 --- a/components/newlib/test/CMakeLists.txt +++ b/components/newlib/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity test_utils) - -register_component() \ No newline at end of file +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity test_utils) \ No newline at end of file diff --git a/components/newlib/time.c b/components/newlib/time.c index d9a58508c9..e7b805ca57 100644 --- a/components/newlib/time.c +++ b/components/newlib/time.c @@ -420,10 +420,10 @@ int clock_gettime (clockid_t clock_id, struct timespec *tp) return -1; } struct timeval tv; - _gettimeofday_r(NULL, &tv, NULL); uint64_t monotonic_time_us = 0; switch (clock_id) { case CLOCK_REALTIME: + _gettimeofday_r(NULL, &tv, NULL); tp->tv_sec = tv.tv_sec; tp->tv_nsec = tv.tv_usec * 1000L; break; diff --git a/components/nghttp/CMakeLists.txt b/components/nghttp/CMakeLists.txt index c1c4d80942..1c9ba17a23 100644 --- a/components/nghttp/CMakeLists.txt +++ b/components/nghttp/CMakeLists.txt @@ -1,28 +1,29 @@ -set(COMPONENT_ADD_INCLUDEDIRS port/include nghttp2/lib/includes) -set(COMPONENT_SRCS "nghttp2/lib/nghttp2_buf.c" - "nghttp2/lib/nghttp2_callbacks.c" - "nghttp2/lib/nghttp2_debug.c" - "nghttp2/lib/nghttp2_frame.c" - "nghttp2/lib/nghttp2_hd.c" - "nghttp2/lib/nghttp2_hd_huffman.c" - "nghttp2/lib/nghttp2_hd_huffman_data.c" - "nghttp2/lib/nghttp2_helper.c" - "nghttp2/lib/nghttp2_http.c" - "nghttp2/lib/nghttp2_map.c" - "nghttp2/lib/nghttp2_mem.c" - "nghttp2/lib/nghttp2_npn.c" - "nghttp2/lib/nghttp2_option.c" - "nghttp2/lib/nghttp2_outbound_item.c" - "nghttp2/lib/nghttp2_pq.c" - "nghttp2/lib/nghttp2_priority_spec.c" - "nghttp2/lib/nghttp2_queue.c" - "nghttp2/lib/nghttp2_rcbuf.c" - "nghttp2/lib/nghttp2_session.c" - "nghttp2/lib/nghttp2_stream.c" - "nghttp2/lib/nghttp2_submit.c" - "nghttp2/lib/nghttp2_version.c" - "port/http_parser.c") +set(srcs + "nghttp2/lib/nghttp2_buf.c" + "nghttp2/lib/nghttp2_callbacks.c" + "nghttp2/lib/nghttp2_debug.c" + "nghttp2/lib/nghttp2_frame.c" + "nghttp2/lib/nghttp2_hd.c" + "nghttp2/lib/nghttp2_hd_huffman.c" + "nghttp2/lib/nghttp2_hd_huffman_data.c" + "nghttp2/lib/nghttp2_helper.c" + "nghttp2/lib/nghttp2_http.c" + "nghttp2/lib/nghttp2_map.c" + "nghttp2/lib/nghttp2_mem.c" + "nghttp2/lib/nghttp2_npn.c" + "nghttp2/lib/nghttp2_option.c" + "nghttp2/lib/nghttp2_outbound_item.c" + "nghttp2/lib/nghttp2_pq.c" + "nghttp2/lib/nghttp2_priority_spec.c" + "nghttp2/lib/nghttp2_queue.c" + "nghttp2/lib/nghttp2_rcbuf.c" + "nghttp2/lib/nghttp2_session.c" + "nghttp2/lib/nghttp2_stream.c" + "nghttp2/lib/nghttp2_submit.c" + "nghttp2/lib/nghttp2_version.c" + "port/http_parser.c") -register_component() +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS port/include nghttp2/lib/includes) target_compile_definitions(${COMPONENT_LIB} PUBLIC "-DHAVE_CONFIG_H") diff --git a/components/nvs_flash/CMakeLists.txt b/components/nvs_flash/CMakeLists.txt index 2c815b31ca..1d7e5862dd 100644 --- a/components/nvs_flash/CMakeLists.txt +++ b/components/nvs_flash/CMakeLists.txt @@ -1,13 +1,10 @@ -set(COMPONENT_SRCS "src/nvs_api.cpp" - "src/nvs_encr.cpp" - "src/nvs_item_hash_list.cpp" - "src/nvs_ops.cpp" - "src/nvs_page.cpp" - "src/nvs_pagemanager.cpp" - "src/nvs_storage.cpp" - "src/nvs_types.cpp") -set(COMPONENT_ADD_INCLUDEDIRS include) - -set(COMPONENT_REQUIRES spi_flash mbedtls) - -register_component() +idf_component_register(SRCS "src/nvs_api.cpp" + "src/nvs_encr.cpp" + "src/nvs_item_hash_list.cpp" + "src/nvs_ops.cpp" + "src/nvs_page.cpp" + "src/nvs_pagemanager.cpp" + "src/nvs_storage.cpp" + "src/nvs_types.cpp" + REQUIRES spi_flash mbedtls + INCLUDE_DIRS include) diff --git a/components/nvs_flash/README.rst b/components/nvs_flash/README.rst index 6a4652f2ff..4638b644bc 100644 --- a/components/nvs_flash/README.rst +++ b/components/nvs_flash/README.rst @@ -4,54 +4,60 @@ Non-volatile storage library Introduction ------------ -Non-volatile storage (NVS) library is designed to store key-value pairs in flash. This sections introduces some concepts used by NVS. +Non-volatile storage (NVS) library is designed to store key-value pairs in flash. This section introduces some concepts used by NVS. + Underlying storage ^^^^^^^^^^^^^^^^^^ -Currently NVS uses a portion of main flash memory through ``spi_flash_{read|write|erase}`` APIs. The library uses the all the partitions with ``data`` type and ``nvs`` subtype. The application can choose to use the partition with label ``nvs`` through ``nvs_open`` API or any of the other partition by specifying its name through ``nvs_open_from_part`` API. +Currently, NVS uses a portion of main flash memory through ``spi_flash_{read|write|erase}`` APIs. The library uses all the partitions with ``data`` type and ``nvs`` subtype. The application can choose to use the partition with the label ``nvs`` through the ``nvs_open`` API function or any other partition by specifying its name using the ``nvs_open_from_part`` API function. -Future versions of this library may add other storage backends to keep data in another flash chip (SPI or I2C), RTC, FRAM, etc. +Future versions of this library may have other storage backends to keep data in another flash chip (SPI or I2C), RTC, FRAM, etc. -.. note:: if an NVS partition is truncated (for example, when the partition table layout is changed), its contents should be erased. ESP-IDF build system provides a ``make erase_flash`` target to erase all contents of the flash chip. +.. note:: if an NVS partition is truncated (for example, when the partition table layout is changed), its contents should be erased. ESP-IDF build system provides a ``idf.py erase_flash`` target to erase all contents of the flash chip. + +.. note:: NVS works best for storing many small values, rather than a few large values of the type 'string' and 'blob'. If you need to store large blobs or strings, consider using the facilities provided by the FAT filesystem on top of the wear levelling library. -.. note:: NVS works best for storing many small values, rather than a few large values of type 'string' and 'blob'. If storing large blobs or strings is required, consider using the facilities provided by the FAT filesystem on top of the wear levelling library. Keys and values ^^^^^^^^^^^^^^^ -NVS operates on key-value pairs. Keys are ASCII strings, maximum key length is currently 15 characters. Values can have one of the following types: +NVS operates on key-value pairs. Keys are ASCII strings; the maximum key length is currently 15 characters. Values can have one of the following types: - integer types: ``uint8_t``, ``int8_t``, ``uint16_t``, ``int16_t``, ``uint32_t``, ``int32_t``, ``uint64_t``, ``int64_t`` - zero-terminated string - variable length binary data (blob) .. note:: - String values are currently limited to 4000 bytes. This includes the null terminator. Blob values are limited to 508000 bytes or (97.6% of the partition size - 4000) bytes whichever is lower. -Additional types, such as ``float`` and ``double`` may be added later. + String values are currently limited to 4000 bytes. This includes the null terminator. Blob values are limited to 508000 bytes or 97.6% of the partition size - 4000 bytes, whichever is lower. -Keys are required to be unique. Writing a value for a key which already exists behaves as follows: +Additional types, such as ``float`` and ``double`` might be added later. -- if the new value is of the same type as old one, value is updated -- if the new value has different data type, an error is returned +Keys are required to be unique. Assigning a new value to an existing key works as follows: + +- if the new value is of the same type as the old one, value is updated +- if the new value has a different data type, an error is returned + +Data type check is also performed when reading a value. An error is returned if the data type of the read operation does not match the data type of the value. -Data type check is also performed when reading a value. An error is returned if data type of read operation doesn’t match the data type of the value. Namespaces ^^^^^^^^^^ -To mitigate potential conflicts in key names between different components, NVS assigns each key-value pair to one of namespaces. Namespace names follow the same rules as key names, i.e. 15 character maximum length. Namespace name is specified in the ``nvs_open`` or ``nvs_open_from_part`` call. This call returns an opaque handle, which is used in subsequent calls to ``nvs_read_*``, ``nvs_write_*``, and ``nvs_commit`` functions. This way, handle is associated with a namespace, and key names will not collide with same names in other namespaces. -Please note that the namespaces with same name in different NVS partitions are considered as separate namespaces. +To mitigate potential conflicts in key names between different components, NVS assigns each key-value pair to one of namespaces. Namespace names follow the same rules as key names, i.e., the maximum length is 15 characters. Namespace name is specified in the ``nvs_open`` or ``nvs_open_from_part`` call. This call returns an opaque handle, which is used in subsequent calls to the ``nvs_read_*``, ``nvs_write_*``, and ``nvs_commit`` functions. This way, a handle is associated with a namespace, and key names will not collide with same names in other namespaces. +Please note that the namespaces with the same name in different NVS partitions are considered as separate namespaces. + Security, tampering, and robustness ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ NVS is not directly compatible with the ESP32 flash encryption system. However, data can still be stored in encrypted form if NVS encryption is used together with ESP32 flash encryption. Please refer to :ref:`nvs_encryption` for more details. -If NVS encryption is not used, it is possible for anyone with physical access to the flash chip to alter, erase, or add key-value pairs. With NVS encryption enabled, it is not possible to alter or add a key-value pair and get recognized as a valid pair without knowing corresponding NVS encryption keys. However, there is no tamper-resistance against erase operation. +If NVS encryption is not used, it is possible for anyone with physical access to the flash chip to alter, erase, or add key-value pairs. With NVS encryption enabled, it is not possible to alter or add a key-value pair and get recognized as a valid pair without knowing corresponding NVS encryption keys. However, there is no tamper-resistance against the erase operation. + +The library does try to recover from conditions when flash memory is in an inconsistent state. In particular, one should be able to power off the device at any point and time and then power it back on. This should not result in loss of data, except for the new key-value pair if it was being written at the moment of powering off. The library should also be able to initialize properly with any random data present in flash memory. -The library does try to recover from conditions when flash memory is in an inconsistent state. In particular, one should be able to power off the device at any point and time and then power it back on. This should not result in loss of data, except for the new key-value pair if it was being written at the moment of power off. The library should also be able to initialize properly with any random data present in flash memory. Internals --------- @@ -59,7 +65,7 @@ Internals Log of key-value pairs ^^^^^^^^^^^^^^^^^^^^^^ -NVS stores key-value pairs sequentially, with new key-value pairs being added at the end. When a value of any given key has to be updated, new key-value pair is added at the end of the log and old key-value pair is marked as erased. +NVS stores key-value pairs sequentially, with new key-value pairs being added at the end. When a value of any given key has to be updated, a new key-value pair is added at the end of the log and the old key-value pair is marked as erased. Pages and entries ^^^^^^^^^^^^^^^^^ @@ -67,22 +73,22 @@ Pages and entries NVS library uses two main entities in its operation: pages and entries. Page is a logical structure which stores a portion of the overall log. Logical page corresponds to one physical sector of flash memory. Pages which are in use have a *sequence number* associated with them. Sequence numbers impose an ordering on pages. Higher sequence numbers correspond to pages which were created later. Each page can be in one of the following states: Empty/uninitialized - Flash storage for the page is empty (all bytes are ``0xff``). Page isn't used to store any data at this point and doesn’t have a sequence number. + Flash storage for the page is empty (all bytes are ``0xff``). Page is not used to store any data at this point and does not have a sequence number. Active - Flash storage is initialized, page header has been written to flash, page has a valid sequence number. Page has some empty entries and data can be written there. At most one page can be in this state at any given moment. + Flash storage is initialized, page header has been written to flash, page has a valid sequence number. Page has some empty entries and data can be written there. No more than one page can be in this state at any given moment. Full Flash storage is in a consistent state and is filled with key-value pairs. Writing new key-value pairs into this page is not possible. It is still possible to mark some key-value pairs as erased. Erasing - Non-erased key-value pairs are being moved into another page so that the current page can be erased. This is a transient state, i.e. page should never stay in this state when any API call returns. In case of a sudden power off, move-and-erase process will be completed upon next power on. + Non-erased key-value pairs are being moved into another page so that the current page can be erased. This is a transient state, i.e., page should never stay in this state at the time when any API call returns. In case of a sudden power off, the move-and-erase process will be completed upon the next power-on. Corrupted - Page header contains invalid data, and further parsing of page data was canceled. Any items previously written into this page will not be accessible. Corresponding flash sector will not be erased immediately, and will be kept along with sectors in *uninitialized* state for later use. This may be useful for debugging. + Page header contains invalid data, and further parsing of page data was canceled. Any items previously written into this page will not be accessible. The corresponding flash sector will not be erased immediately and will be kept along with sectors in *uninitialized* state for later use. This may be useful for debugging. -Mapping from flash sectors to logical pages doesn't have any particular order. Library will inspect sequence numbers of pages found in each flash sector and organize pages in a list based on these numbers. +Mapping from flash sectors to logical pages does not have any particular order. The library will inspect sequence numbers of pages found in each flash sector and organize pages in a list based on these numbers. :: @@ -101,11 +107,11 @@ Mapping from flash sectors to logical pages doesn't have any particular order. L Structure of a page ^^^^^^^^^^^^^^^^^^^ -For now we assume that flash sector size is 4096 bytes and that ESP32 flash encryption hardware operates on 32-byte blocks. It is possible to introduce some settings configurable at compile-time (e.g. via menuconfig) to accommodate flash chips with different sector sizes (although it is not clear if other components in the system, e.g. SPI flash driver and SPI flash cache can support these other sizes). +For now, we assume that flash sector size is 4096 bytes and that ESP32 flash encryption hardware operates on 32-byte blocks. It is possible to introduce some settings configurable at compile-time (e.g., via menuconfig) to accommodate flash chips with different sector sizes (although it is not clear if other components in the system, e.g., SPI flash driver and SPI flash cache can support these other sizes). Page consists of three parts: header, entry state bitmap, and entries themselves. To be compatible with ESP32 flash encryption, entry size is 32 bytes. For integer types, entry holds one key-value pair. For strings and blobs, an entry holds part of key-value pair (more on that in the entry structure description). -The following diagram illustrates page structure. Numbers in parentheses indicate size of each part in bytes. :: +The following diagram illustrates the page structure. Numbers in parentheses indicate the size of each part in bytes. :: +-----------+--------------+-------------+-------------------------+ | State (4) | Seq. no. (4) | version (1) | Unused (19) | CRC32 (4) | Header (32) @@ -122,23 +128,23 @@ The following diagram illustrates page structure. Numbers in parentheses indicat | Entry 125 (32) | +------------------------------------------------------------------+ -Page header and entry state bitmap are always written to flash unencrypted. Entries are encrypted if flash encryption feature of the ESP32 is used. +Page header and entry state bitmap are always written to flash unencrypted. Entries are encrypted if flash encryption feature of ESP32 is used. -Page state values are defined in such a way that changing state is possible by writing 0 into some of the bits. Therefore it not necessary to erase the page to change page state, unless that is a change to *erased* state. +Page state values are defined in such a way that changing state is possible by writing 0 into some of the bits. Therefore it is not necessary to erase the page to change its state unless that is a change to the *erased* state. -The version field in the header reflects NVS format version used. For backward compatibility reasons, it is decremented for every version upgrade starting at 0xff (i.e. 0xff for version-1, 0xfe for version-2 and so on). +The version field in the header reflects the NVS format version used. For backward compatibility reasons, it is decremented for every version upgrade starting at 0xff (i.e., 0xff for version-1, 0xfe for version-2 and so on). -CRC32 value in header is calculated over the part which doesn't include state value (bytes 4 to 28). Unused part is currently filled with ``0xff`` bytes. +CRC32 value in the header is calculated over the part which does not include a state value (bytes 4 to 28). The unused part is currently filled with ``0xff`` bytes. -The following sections describe structure of entry state bitmap and entry itself. +The following sections describe the structure of entry state bitmap and entry itself. Entry and entry state bitmap ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Each entry can be in one of the following three states. Each state is represented with two bits in the entry state bitmap. Final four bits in the bitmap (256 - 2 * 126) are unused. +Each entry can be in one of the following three states represented with two bits in the entry state bitmap. The final four bits in the bitmap (256 - 2 * 126) are not used. Empty (2'b11) - Nothing is written into the specific entry yet. It is in an uninitialized state (all bytes ``0xff``). + Nothing is written into the specific entry yet. It is in an uninitialized state (all bytes are ``0xff``). Written (2'b10) A key-value pair (or part of key-value pair which spans multiple entries) has been written into the entry. @@ -152,7 +158,7 @@ Erased (2'b00) Structure of entry ^^^^^^^^^^^^^^^^^^ -For values of primitive types (currently integers from 1 to 8 bytes long), entry holds one key-value pair. For string and blob types, entry holds part of the whole key-value pair. For strings, in case when a key-value pair spans multiple entries, all entries are stored in the same page. Blobs are allowed to span over multiple pages by dividing them into smaller chunks. For the purpose tracking these chunks, an additional fixed length metadata entry is stored called "blob index" entry. Earlier format of blobs are still supported (can be read and modified). However, once the blobs are modified, they are stored using the new format. +For values of primitive types (currently integers from 1 to 8 bytes long), entry holds one key-value pair. For string and blob types, entry holds part of the whole key-value pair. For strings, in case when a key-value pair spans multiple entries, all entries are stored in the same page. Blobs are allowed to span over multiple pages by dividing them into smaller chunks. For tracking these chunks, an additional fixed length metadata entry is stored called "blob index". Earlier formats of blobs are still supported (can be read and modified). However, once the blobs are modified, they are stored using the new format. :: @@ -160,10 +166,10 @@ For values of primitive types (currently integers from 1 to 8 bytes long), entry | NS (1) | Type (1) | Span (1) | ChunkIndex (1) | CRC32 (4) | Key (16) | Data (8) | +--------+----------+----------+----------------+-----------+---------------+----------+ - Primitive +--------------------------------+ - +--------> | Data (8) | + Primitive +--------------------------------+ + +--------> | Data (8) | | Types +--------------------------------+ - +-> Fixed length -- + +-> Fixed length -- | | +---------+--------------+---------------+-------+ | +--------> | Size(4) | ChunkCount(1)| ChunkStart(1) | Rsv(2)| Data format ---+ Blob Index +---------+--------------+---------------+-------+ @@ -176,25 +182,25 @@ For values of primitive types (currently integers from 1 to 8 bytes long), entry Individual fields in entry structure have the following meanings: NS - Namespace index for this entry. See section on namespaces implementation for explanation of this value. + Namespace index for this entry. For more information on this value, see the section on namespaces implementation. Type - One byte indicating data type of value. See ``ItemType`` enumeration in ``nvs_types.h`` for possible values. + One byte indicating the value data type. See the ``ItemType`` enumeration in ``nvs_types.h`` for possible values. Span - Number of entries used by this key-value pair. For integer types, this is equal to 1. For strings and blobs this depends on value length. + Number of entries used by this key-value pair. For integer types, this is equal to 1. For strings and blobs, this depends on value length. ChunkIndex - Used to store index of the blob-data chunk for blob types. For other types, this should be ``0xff``. + Used to store the index of a blob-data chunk for blob types. For other types, this should be ``0xff``. CRC32 Checksum calculated over all the bytes in this entry, except for the CRC32 field itself. Key - Zero-terminated ASCII string containing key name. Maximum string length is 15 bytes, excluding zero terminator. + Zero-terminated ASCII string containing a key name. Maximum string length is 15 bytes, excluding a zero terminator. Data - For integer types, this field contains the value itself. If the value itself is shorter than 8 bytes it is padded to the right, with unused bytes filled with ``0xff``. + For integer types, this field contains the value itself. If the value itself is shorter than 8 bytes, it is padded to the right, with unused bytes filled with ``0xff``. For "blob index" entry, these 8 bytes hold the following information about data-chunks: @@ -205,23 +211,23 @@ Data (Only for blob index.) Total number of blob-data chunks into which the blob was divided during storage. - ChunkStart - (Only for blob index.) ChunkIndex of the first blob-data chunk of this blob. Subsequent chunks have chunkIndex incrementally allocated (step of 1) + (Only for blob index.) ChunkIndex of the first blob-data chunk of this blob. Subsequent chunks have chunkIndex incrementally allocated (step of 1). - For string and blob data chunks, these 8 bytes hold additional data about the value, described next: + For string and blob data chunks, these 8 bytes hold additional data about the value, which are described below: - Size - (Only for strings and blobs.) Size, in bytes, of actual data. For strings, this includes zero terminator. + (Only for strings and blobs.) Size, in bytes, of actual data. For strings, this includes zero terminators. - CRC32 (Only for strings and blobs.) Checksum calculated over all bytes of data. -Variable length values (strings and blobs) are written into subsequent entries, 32 bytes per entry. `Span` field of the first entry indicates how many entries are used. +Variable length values (strings and blobs) are written into subsequent entries, 32 bytes per entry. The `Span` field of the first entry indicates how many entries are used. Namespaces ^^^^^^^^^^ -As mentioned above, each key-value pair belongs to one of the namespaces. Namespaces identifiers (strings) are stored as keys of key-value pairs in namespace with index 0. Values corresponding to these keys are indexes of these namespaces. +As mentioned above, each key-value pair belongs to one of the namespaces. Namespace identifiers (strings) are stored as keys of key-value pairs in namespace with index 0. Values corresponding to these keys are indexes of these namespaces. :: @@ -239,23 +245,23 @@ As mentioned above, each key-value pair belongs to one of the namespaces. Namesp Item hash list ^^^^^^^^^^^^^^ -To reduce the number of reads performed from flash memory, each member of Page class maintains a list of pairs: (item index; item hash). This list makes searches much quicker. Instead of iterating over all entries, reading them from flash one at a time, ``Page::findItem`` first performs search for item hash in the hash list. This gives the item index within the page, if such an item exists. Due to a hash collision it is possible that a different item will be found. This is handled by falling back to iteration over items in flash. +To reduce the number of reads from flash memory, each member of the Page class maintains a list of pairs: item index; item hash. This list makes searches much quicker. Instead of iterating over all entries, reading them from flash one at a time, ``Page::findItem`` first performs a search for the item hash in the hash list. This gives the item index within the page if such an item exists. Due to a hash collision, it is possible that a different item will be found. This is handled by falling back to iteration over items in flash. -Each node in hash list contains a 24-bit hash and 8-bit item index. Hash is calculated based on item namespace, key name and ChunkIndex. CRC32 is used for calculation, result is truncated to 24 bits. To reduce overhead of storing 32-bit entries in a linked list, list is implemented as a doubly-linked list of arrays. Each array holds 29 entries, for the total size of 128 bytes, together with linked list pointers and 32-bit count field. Minimal amount of extra RAM usage per page is therefore 128 bytes, maximum is 640 bytes. +Each node in the hash list contains a 24-bit hash and 8-bit item index. Hash is calculated based on item namespace, key name, and ChunkIndex. CRC32 is used for calculation; the result is truncated to 24 bits. To reduce the overhead for storing 32-bit entries in a linked list, the list is implemented as a double-linked list of arrays. Each array holds 29 entries, for the total size of 128 bytes, together with linked list pointers and a 32-bit count field. The minimum amount of extra RAM usage per page is therefore 128 bytes; maximum is 640 bytes. .. _nvs_encryption: NVS Encryption -------------- -Data stored in NVS partitions can be encrypted using AES-XTS in the manner similar to one mentioned in disc encryption standard IEEE P1619. For the purpose of encryption, each entry is considered as one `sector` and relative address of the entry (w.r.t. partition-start) is fed to the encryption algorithm as `sector-number`. The keys required for nvs encryption are stored in yet another partition, which is protected using :doc:`Flash Encryption <../../security/flash-encryption>`. Therefore, enabling :doc:`Flash Encryption <../../security/flash-encryption>` is a prerequisite for NVS encryption. +Data stored in NVS partitions can be encrypted using AES-XTS in the manner similar to the one mentioned in disk encryption standard IEEE P1619. For the purpose of encryption, each entry is treated as one `sector` and relative address of the entry (w.r.t. partition-start) is fed to the encryption algorithm as `sector-number`. The keys required for NVS encryption are stored in yet another partition, which is protected using :doc:`Flash Encryption <../../security/flash-encryption>`. Therefore, enabling :doc:`Flash Encryption <../../security/flash-encryption>` is a prerequisite for NVS encryption. .. _nvs_key_partition: NVS key partition ^^^^^^^^^^^^^^^^^ -An application requiring NVS encryption support needs to be compiled with a key-partition of type `data` and subtype `key`. This partition should be marked as `encrypted`. Refer to :doc:`Partition Tables <../../api-guides/partition-tables>` for more details. The size of the partition should be 4096 bytes (minimum partition size). The structure of this partition is depicted below. +An application requiring NVS encryption support needs to be compiled with a key-partition of the type `data` and subtype `key`. This partition should be marked as `encrypted`. Refer to :doc:`Partition Tables <../../api-guides/partition-tables>` for more details. The size of the partition should be 4096 bytes (minimum partition size). The structure of this partition is depicted below. :: @@ -267,25 +273,33 @@ An application requiring NVS encryption support needs to be compiled with a key- | CRC32(4) | +---------------------------------------------+ -This partition can be generated using `nvs partition generator` utility and flashed onto the device. Since the partition is marked `encrypted` and :doc:`Flash Encryption <../../security/flash-encryption>` is enabled, bootloader will encrypt this partition using flash encryption key on first boot. Alternatively, the keys can be generated after startup using ``nvs_flash_generate_keys`` API provided by ``nvs_flash.h``, which will then write those keys onto the key-partition in encrypted form. +This partition can be generated using `nvs partition generator` utility and flashed onto the device. Since the partition is marked `encrypted` and :doc:`Flash Encryption <../../security/flash-encryption>` is enabled, bootloader will encrypt this partition using flash encryption key on the first boot. Alternatively, the keys can be generated after startup using the ``nvs_flash_generate_keys`` API function provided by ``nvs_flash.h``, which will then write those keys onto the key-partition in encrypted form. It is possible for an application to use different keys for different NVS partitions and thereby have multiple key-partitions. However, it is a responsibility of the application to provide correct key-partition/keys for the purpose of encryption/decryption. Encrypted Read/Write ^^^^^^^^^^^^^^^^^^^^ -The same NVS APIs ``nvs_read_*`` or ``nvs_write_*`` can be used for reading and writing of encrypted nvs partition as well. However, the APIs for initialising NVS partitions are different. ``nvs_flash_secure_init`` and ``nvs_flash_secure_init_partition`` are used for initialising instead of ``nvs_flash_init`` and ``nvs_flash_init_partition`` respectively. ``nvs_sec_cfg_t`` structure required for these APIs can be populated using ``nvs_flash_generate_keys`` or ``nvs_flash_read_security_cfg``. +The same NVS API functions ``nvs_read_*`` or ``nvs_write_*`` can be used for reading of, and writing to an encrypted nvs partition as well. However, the API functions for initialising NVS partitions are different: ``nvs_flash_secure_init`` and ``nvs_flash_secure_init_partition`` instead of ``nvs_flash_init`` and ``nvs_flash_init_partition`` respectively. The ``nvs_sec_cfg_t`` structure required for these API functions can be populated using ``nvs_flash_generate_keys`` or ``nvs_flash_read_security_cfg``. -Applications are expected to follow the following steps in order to perform NVS read/write operations with encryption enabled. +Applications are expected to follow the steps below in order to perform NVS read/write operations with encryption enabled. - 1. Find key partition and NVS data partition using ``esp_partition_find*`` APIs. - 2. Populate ``nvs_sec_cfg_t`` struct using ``nvs_flash_read_security_cfg`` or ``nvs_flash_generate_keys`` APIs. - 3. Initialise NVS flash partition using ``nvs_flash_secure_init`` or ``nvs_flash_secure_init_partition`` APIs. - 4. Open a namespace using ``nvs_open`` or ``nvs_open_from_part`` APIs - 5. Perform NVS read/write operations using ``nvs_read_*`` or ``nvs_write_*`` - 6. Deinitialise NVS partition using ``nvs_flash_deinit``. + 1. Find key partition and NVS data partition using ``esp_partition_find*`` API functions. + 2. Populate the ``nvs_sec_cfg_t`` struct using the ``nvs_flash_read_security_cfg`` or ``nvs_flash_generate_keys`` API functions. + 3. Initialise NVS flash partition using the ``nvs_flash_secure_init`` or ``nvs_flash_secure_init_partition`` API functions. + 4. Open a namespace using the ``nvs_open`` or ``nvs_open_from_part`` API functions. + 5. Perform NVS read/write operations using ``nvs_read_*`` or ``nvs_write_*``. + 6. Deinitialise an NVS partition using ``nvs_flash_deinit``. NVS iterators ^^^^^^^^^^^^^ -Iterators allow to list key-value pairs stored in NVS based on specified partition name, namespace and data type. ``nvs_entry_find`` returns an opaque handle, which is used in subsequent calls to ``nvs_entry_next`` and ``nvs_entry_info`` function. ``nvs_entry_next`` function returns iterator to the next key-value pair. If none or no other key-value pair was found for given criteria, ``nvs_entry_find`` and ``nvs_entry_next`` functions return NULL. In that case, iterator does not have to be released. Otherwise, ``nvs_release_iterator`` function has to be used, when iterator is no longer needed. Information about each key-value pair can be obtained from ``nvs_entry_info`` function. \ No newline at end of file +Iterators allow to list key-value pairs stored in NVS, based on specified partition name, namespace, and data type. + +There are the following functions available: + +- ``nvs_entry_find`` returns an opaque handle, which is used in subsequent calls to the ``nvs_entry_next`` and ``nvs_entry_info`` functions. +- ``nvs_entry_next`` returns iterator to the next key-value pair. +- ``nvs_entry_info`` returns information about each key-value pair + +If none or no other key-value pair was found for given criteria, ``nvs_entry_find`` and ``nvs_entry_next`` return NULL. In that case, the iterator does not have to be released. If the iterator is no longer needed, you can release it by using the function ``nvs_release_iterator``. diff --git a/components/nvs_flash/nvs_partition_generator/README.rst b/components/nvs_flash/nvs_partition_generator/README.rst index cf31261366..800344223e 100644 --- a/components/nvs_flash/nvs_partition_generator/README.rst +++ b/components/nvs_flash/nvs_partition_generator/README.rst @@ -4,184 +4,306 @@ NVS Partition Generator Utility Introduction ------------ -:component_file:`nvs_flash/nvs_partition_generator/nvs_partition_gen.py` utility is designed to help create a binary file, compatible with NVS architecture defined in :doc:`Non-Volatile Storage `, based on user provided key-value pairs in a CSV file. -Utility is ideally suited for generating a binary blob, containing data specific to ODM/OEM, which can be flashed externally at the time of device manufacturing. This helps manufacturers set unique value for various parameters for each device, e.g. serial number, while using same application firmware for all devices. +The utility :component_file:`nvs_flash/nvs_partition_generator/nvs_partition_gen.py` creates a binary file based on key-value pairs provided in a CSV file. The binary file is compatible with NVS architecture defined in :doc:`Non-Volatile Storage `. +This utility is ideally suited for generating a binary blob, containing data specific to ODM/OEM, which can be flashed externally at the time of device manufacturing. This allows manufacturers to generate many instances of the same application firmware with customized parameters for each device, such as a serial number. Prerequisites ------------- -To use this utility in encryption mode, the following packages need to be installed: +To use this utility in encryption mode, install the following packages: - cryptography package -These dependencies is already captured by including these packages in `requirement.txt` in top level IDF directory. +All the required packages are included in `requirements.txt` in the root of the esp-idf directory. CSV file format --------------- -Each row of the .csv file should have 4 parameters, separated by comma. Below is the description of each of these parameters: +Each line of a .csv file should contain 4 parameters, separated by a comma. The table below provides the description for each of these parameters. -Key - Key of the data. Data can later be accessed from an application via this key. ++-----+-----------+----------------------------------------------------------------------+-----------------------------------------------------+ +| No. | Parameter | Description | Notes | ++=====+===========+======================================================================+=====================================================+ +| 1 | Key | Key of the data. The data can be accessed later from | | +| | | an application using this key. | | ++-----+-----------+----------------------------------------------------------------------+-----------------------------------------------------+ +| 2 | Type | Supported values are ``file``, ``data`` and ``namespace``. | | ++-----+-----------+----------------------------------------------------------------------+-----------------------------------------------------+ +| 3 | Encoding | Supported values are: ``u8``, ``i8``, ``u16``, ``u32``, | As of now, for the ``file`` type, | +| | | ``i32``, ``string``, ``hex2bin``, ``base64`` and ``binary``. | only ``hex2bin``, ``base64``, ``string``, | +| | | This specifies how actual data values are encoded in the | and ``binary`` encoding is supported. | +| | | resulting binary file. The difference between the ``string`` | | +| | | and ``binary`` encoding is that ``string`` data is terminated | | +| | | with a NULL character, whereas ``binary`` data is not. | | ++-----+-----------+----------------------------------------------------------------------+-----------------------------------------------------+ +| 4 | Value | Data value. | Encoding and Value cells for the ``namespace`` | +| | | | field type should be empty. Encoding and Value | +| | | | of ``namespace`` is fixed and is not configurable. | +| | | | Any values in these cells are ignored. | ++-----+-----------+----------------------------------------------------------------------+-----------------------------------------------------+ -Type - Supported values are ``file``, ``data`` and ``namespace``. +.. note:: The first line of the CSV file should always be the column header and it is not configurable. -Encoding - Supported values are: ``u8``, ``i8``, ``u16``, ``u32``, ``i32``, ``string``, ``hex2bin``, ``base64`` and ``binary``. This specifies how actual data values are encoded in the resultant binary file. Difference between ``string`` and ``binary`` encoding is that ``string`` data is terminated with a NULL character, whereas ``binary`` data is not. - -.. note:: For ``file`` type, only ``hex2bin``, ``base64``, ``string`` and ``binary`` is supported as of now. - -Value - Data value. - -.. note:: Encoding and Value cells for ``namespace`` field type should be empty. Encoding and Value of ``namespace`` is fixed and isn't configurable. Any value in these cells are ignored. - -.. note:: First row of the CSV file should always be column header and isn't configurable. - -Below is an example dump of such CSV file:: +Below is an example dump of such a CSV file:: key,type,encoding,value <-- column header namespace_name,namespace,, <-- First entry should be of type "namespace" key1,data,u8,1 key2,file,string,/path/to/file -.. note:: Make sure there are no spaces before and after ',' or at the end of each line in CSV file. +.. note:: + + Make sure there are **no spaces**: + - before and after ',' + - at the end of each line in a CSV file + NVS Entry and Namespace association ----------------------------------- -When a new namespace entry is encountered in the CSV file, each follow-up entries will be part of that namespace, until next namespace entry is found, in which case all the follow-up entries will be part of the new namespace. +When a namespace entry is encountered in a CSV file, each following entry will be treated as part of that namespace until the next namespace entry is found. At this point, all the following entries will be treated as part of the new namespace. + +.. note:: First entry in a CSV file should always be a ``namespace`` entry. -.. note:: First entry in a CSV file should always be ``namespace`` entry. Multipage Blob Support ---------------------- -By default, binary blobs are allowed to span over multiple pages and written in the format mentioned in section :ref:`structure_of_entry`. -If older format is intended to be used, the utility provides an option to disable this feature. +By default, binary blobs are allowed to span over multiple pages and are written in the format mentioned in Section :ref:`structure_of_entry`. +If you intend to use an older format, the utility provides an option to disable this feature. + Encryption Support ------------------- -This utility allows you to create an enrypted binary file also. Encryption used is AES-XTS encryption. Refer to :ref:`nvs_encryption` for more details. + +The NVS Partition Generator utility also allows you to create an encrypted binary file. The utility uses the AES-XTS encryption. Please refer to :ref:`nvs_encryption` for more details. + + +Decryption Support +------------------- +This utility allows you to decrypt an encrypted NVS binary file. The utility uses an NVS binary file encrypted using AES-XTS encryption. Please refer to :ref:`nvs_encryption` for more details. Running the utility ------------------- **Usage**:: - python nvs_partition_gen.py [-h] [--input INPUT] [--output OUTPUT] - [--size SIZE] [--version {v1,v2}] - [--keygen {true,false}] [--encrypt {true,false}] - [--keyfile KEYFILE] [--outdir OUTDIR] + python nvs_partition_gen.py [-h] {generate,generate-key,encrypt,decrypt} ... + + Optional Arguments: + +-----+------------+----------------------------------------------------------------------+ + | No. | Parameter | Description | + +=====+============+======================================================================+ + | 1 | -h, --help | show this help message and exit | + +-----+------------+----------------------------------------------------------------------+ + + Commands: + Run nvs_partition_gen.py {command} -h for additional help + +-----+--------------+--------------------------------------------------------------------+ + | No. | Parameter | Description | + +=====+==============+====================================================================+ + | 1 | generate | Generate NVS partition | + +-----+--------------+--------------------------------------------------------------------+ + | 2 | generate-key | Generate keys for encryption | + +-----+--------------+--------------------------------------------------------------------+ + | 3 | encrypt | Generate NVS encrypted partition | + +-----+--------------+--------------------------------------------------------------------+ + | 4 | decrypt | Decrypt NVS encrypted partition | + +-----+--------------+--------------------------------------------------------------------+ + + +To generate NVS partition (Default): +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + **Usage**:: + + python nvs_partition_gen.py generate [-h] [--version {1,2}] [--outdir OUTDIR] + input output size + + Positional Arguments: + +--------------+----------------------------------------------------------------------+ + | Parameter | Description | + +==============+======================================================================+ + | input | Path to CSV file to parse | + +--------------+----------------------------------------------------------------------+ + | output | Path to output NVS binary file | + +--------------+----------------------------------------------------------------------+ + | size | Size of NVS partition in bytes (must be multiple of 4096) | + +--------------+----------------------------------------------------------------------+ -+------------------------+----------------------------------------------------------------------------------------------+ -| Arguments | Description | -+========================+==============================================================================================+ -| --input INPUT | Path to CSV file to parse. | -+------------------------+----------------------------------------------------------------------------------------------+ -| --output OUTPUT | Path to output generated binary file. | -+------------------------+----------------------------------------------------------------------------------------------+ -| --size SIZE | Size of NVS Partition in bytes (must be multiple of 4096) | -+------------------------+----------------------------------------------------------------------------------------------+ -| --version {v1,v2} | Set version. Default: v2 | -+------------------------+----------------------------------------------------------------------------------------------+ -| --keygen {true,false} | Generate keys for encryption. | -+------------------------+----------------------------------------------------------------------------------------------+ -| --encrypt {true,false} | Set encryption mode. Default: false | -+------------------------+----------------------------------------------------------------------------------------------+ -| --keyfile KEYFILE | File having key for encryption (Applicable only if encryption mode is true) | -+------------------------+----------------------------------------------------------------------------------------------+ -| --outdir OUTDIR | The output directory to store the files created (Default: current directory) | -+------------------------+----------------------------------------------------------------------------------------------+ - -You can run this utility in two modes: - - Default mode - Binary generated in this mode is an unencrypted binary file. - - Encryption mode - Binary generated in this mode is an encrypted binary file. + Optional Arguments: + +-----------------+--------------------------------------------------------------------+ + | Parameter | Description | + +=================+====================================================================+ + | -h, --help | show this help message and exit | + +-----------------+--------------------------------------------------------------------+ + | --version {1,2} | Set multipage blob version. | + | | Version 1 - Multipage blob support disabled. | + | | Version 2 - Multipage blob support enabled. | + | | Default: Version 2 | + | | | + +-----------------+--------------------------------------------------------------------+ + | --outdir OUTDIR | Output directory to store files created | + | | (Default: current directory) | + +-----------------+--------------------------------------------------------------------+ -**In default mode:** --------------------- - -*Usage*:: - - python nvs_partition_gen.py [-h] --input INPUT --output OUTPUT - --size SIZE [--version {v1,v2}] - [--keygen {true,false}] [--encrypt {true,false}] - [--keyfile KEYFILE] [--outdir OUTDIR] - -You can run the utility using below command:: - - python nvs_partition_gen.py --input sample.csv --output sample.bin --size 0x3000 - - - -**In encryption mode:** ------------------------ - -*Usage*:: - - python nvs_partition_gen.py [-h] --input INPUT --output OUTPUT - --size SIZE --encrypt {true,false} - --keygen {true,false} --keyfile KEYFILE - [--version {v1,v2}] [--outdir OUTDIR] - - -You can run the utility using below commands: - - - By enabling generation of encryption keys:: - - python nvs_partition_gen.py --input sample.csv --output sample_encrypted.bin --size 0x3000 --encrypt true --keygen true - - - By taking encryption keys as an input file. A sample encryption keys binary file is provided with the utility:: - - python nvs_partition_gen.py --input sample.csv --output sample_encrypted.bin --size 0x3000 --encrypt true --keyfile testdata/sample_encryption_keys.bin - - - By enabling generation of encryption keys and storing the keys in custom filename:: - - python nvs_partition_gen.py --input sample.csv --output sample_encrypted.bin --size 0x3000 --encrypt true --keygen true --keyfile encryption_keys_generated.bin - -.. note:: If `--keygen` is given with `--keyfile` argument, generated keys will be stored in `--keyfile` file. If `--keygen` argument is absent, `--keyfile` is taken as input file having key for encryption. - - -*To generate* **only** *encryption keys with this utility*:: - - python nvs_partition_gen.py --keygen true - -This creates an `encryption_keys_.bin` file. - -.. note:: This newly created file having encryption keys in `keys/` directory is compatible with NVS key-partition structure. Refer to :ref:`nvs_key_partition` for more details. - - -You can also provide the format version number (in any of the two modes): - - Multipage Blob Support Enabled (v2) - - Multipage Blob Support Disabled (v1) - - -**Multipage Blob Support Enabled (v2):** ----------------------------------------- - -You can run the utility in this format by setting the version parameter to v2, as shown below. +You can run the utility to generate NVS partition using the command below: A sample CSV file is provided with the utility:: - python nvs_partition_gen.py --input sample_multipage_blob.csv --output partition_multipage_blob.bin --size 0x4000 --version v2 + python nvs_partition_gen.py generate sample_singlepage_blob.csv sample.bin 0x3000 -**Multipage Blob Support Disabled (v1):** ------------------------------------------ +To generate only encryption keys: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + **Usage**:: -You can run the utility in this format by setting the version parameter to v1, as shown below. + python nvs_partition_gen.py generate-key [-h] [--keyfile KEYFILE] + [--outdir OUTDIR] + + Optional Arguments: + +--------------------+----------------------------------------------------------------------+ + | Parameter | Description | + +====================+======================================================================+ + | -h, --help | show this help message and exit | + +--------------------+----------------------------------------------------------------------+ + | --keyfile KEYFILE | Path to output encryption keys file | + +--------------------+----------------------------------------------------------------------+ + | --outdir OUTDIR | Output directory to store files created. | + | | (Default: current directory) | + +--------------------+----------------------------------------------------------------------+ + +You can run the utility to generate only encryption keys using the command below:: + + python nvs_partition_gen.py generate-key + + +To generate encrypted NVS partition: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + **Usage**:: + + python nvs_partition_gen.py encrypt [-h] [--version {1,2}] [--keygen] + [--keyfile KEYFILE] [--inputkey INPUTKEY] + [--outdir OUTDIR] + input output size + + Positional Arguments: + +--------------+----------------------------------------------------------------------+ + | Parameter | Description | + +==============+======================================================================+ + | input | Path to CSV file to parse | + +--------------+----------------------------------------------------------------------+ + | output | Path to output NVS binary file | + +--------------+----------------------------------------------------------------------+ + | size | Size of NVS partition in bytes (must be multiple of 4096) | + +--------------+----------------------------------------------------------------------+ + + + Optional Arguments: + +---------------------+--------------------------------------------------------------------+ + | Parameter | Description | + +=====================+====================================================================+ + | -h, --help | show this help message and exit | + | | | + +---------------------+--------------------------------------------------------------------+ + | --version {1,2} | Set multipage blob version. | + | | Version 1 - Multipage blob support disabled. | + | | Version 2 - Multipage blob support enabled. | + | | Default: Version 2 | + +---------------------+--------------------------------------------------------------------+ + | --keygen | Generates key for encrypting NVS partition | + +---------------------+--------------------------------------------------------------------+ + | --keyfile KEYFILE | Path to output encryption keys file | + +---------------------+--------------------------------------------------------------------+ + | --inputkey INPUTKEY | File having key for encrypting NVS partition | + +---------------------+--------------------------------------------------------------------+ + | --outdir OUTDIR | Output directory to store files created | + | | (Default: current directory) | + +---------------------+--------------------------------------------------------------------+ + + +You can run the utility to encrypt NVS partition using the command below: +A sample CSV file is provided with the utility: + +- Encrypt by allowing the utility to generate encryption keys:: + + python nvs_partition_gen.py encrypt sample_singlepage_blob.csv sample_encr.bin 0x3000 --keygen + +.. note:: Encryption key of the following format ``/keys/keys-.bin`` is created. + +- Encrypt by allowing the utility to generate encryption keys and store it in provided custom filename:: + + python nvs_partition_gen.py encrypt sample_singlepage_blob.csv sample_encr.bin 0x3000 --keygen --keyfile sample_keys.bin + +.. note:: Encryption key of the following format ``/keys/sample_keys.bin`` is created. +.. note:: This newly created file having encryption keys in ``keys/`` directory is compatible with NVS key-partition structure. Refer to :ref:`nvs_key_partition` for more details. + +- Encrypt by providing the encryption keys as input binary file:: + + python nvs_partition_gen.py encrypt sample_singlepage_blob.csv sample_encr.bin 0x3000 --inputkey sample_keys.bin + +To decrypt encrypted NVS partition: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + **Usage**:: + + python nvs_partition_gen.py decrypt [-h] [--outdir OUTDIR] input key output + + Positional Arguments: + +--------------+----------------------------------------------------------------------+ + | Parameter | Description | + +==============+======================================================================+ + | input | Path to encrypted NVS partition file to parse | + +--------------+----------------------------------------------------------------------+ + | key | Path to file having keys for decryption | + +--------------+----------------------------------------------------------------------+ + | output | Path to output decrypted binary file | + +--------------+----------------------------------------------------------------------+ + + + Optional Arguments: + +---------------------+--------------------------------------------------------------------+ + | Parameter | Description | + +=====================+====================================================================+ + | -h, --help | show this help message and exit | + +---------------------+--------------------------------------------------------------------+ + | --outdir OUTDIR | Output directory to store files created | + | | (Default: current directory) | + +---------------------+--------------------------------------------------------------------+ + + +You can run the utility to decrypt encrypted NVS partition using the command below:: + + python nvs_partition_gen.py decrypt sample_encr.bin sample_keys.bin sample_decr.bin + +You can also provide the format version number: + - Multipage Blob Support Disabled (Version 1) + - Multipage Blob Support Enabled (Version 2) + + +Multipage Blob Support Disabled (Version 1): +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can run the utility in this format by setting the version parameter to 1, as shown below. A sample CSV file is provided with the utility:: - python nvs_partition_gen.py --input sample_singlepage_blob.csv --output partition_single_page.bin --size 0x3000 --version v1 + python nvs_partition_gen.py generate sample_singlepage_blob.csv sample.bin 0x3000 --version 1 + + +Multipage Blob Support Enabled (Version 2): +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can run the utility in this format by setting the version parameter to 2, as shown below. +A sample CSV file is provided with the utility:: + + python nvs_partition_gen.py generate sample_multipage_blob.csv sample.bin 0x4000 --version 2 .. note:: *Minimum NVS Partition Size needed is 0x3000 bytes.* .. note:: *When flashing the binary onto the device, make sure it is consistent with the application's sdkconfig.* + Caveats ------- -- Utility doesn't check for duplicate keys and will write data pertaining to both keys. User needs to make sure keys are distinct. -- Once a new page is created, no data will be written in the space left in previous page. Fields in the CSV file need to be ordered in such a way so as to optimize memory. +- Utility does not check for duplicate keys and will write data pertaining to both keys. You need to make sure that the keys are distinct. +- Once a new page is created, no data will be written in the space left on the previous page. Fields in the CSV file need to be ordered in such a way as to optimize memory. - 64-bit datatype is not yet supported. diff --git a/components/nvs_flash/nvs_partition_generator/nvs_partition_gen.py b/components/nvs_flash/nvs_partition_generator/nvs_partition_gen.py index 64563869df..3bc10e8c3f 100755 --- a/components/nvs_flash/nvs_partition_generator/nvs_partition_gen.py +++ b/components/nvs_flash/nvs_partition_generator/nvs_partition_gen.py @@ -33,6 +33,7 @@ import zlib import codecs import datetime import distutils.dir_util + try: from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.backends import default_backend @@ -42,8 +43,18 @@ except ImportError: 'setting up the required packages.') raise -VERSION1_PRINT = "v1 - Multipage Blob Support Disabled" -VERSION2_PRINT = "v2 - Multipage Blob Support Enabled" +VERSION1_PRINT = "V1 - Multipage Blob Support Disabled" +VERSION2_PRINT = "V2 - Multipage Blob Support Enabled" + + +def reverse_hexbytes(addr_tmp): + addr = [] + reversed_bytes = "" + for i in range(0, len(addr_tmp), 2): + addr.append(addr_tmp[i:i + 2]) + reversed_bytes = "".join(reversed(addr)) + + return reversed_bytes """ Class for standard NVS page structure """ @@ -81,20 +92,16 @@ class Page(object): VERSION1 = 0xFF VERSION2 = 0xFE - def __init__(self, page_num, is_rsrv_page=False): + def __init__(self, page_num, version, is_rsrv_page=False): self.entry_num = 0 - self.is_encrypt = False - self.encr_key = None self.bitmap_array = array.array('B') - self.version = Page.VERSION2 + self.version = version self.page_buf = bytearray(b'\xff') * Page.PAGE_PARAMS["max_size"] if not is_rsrv_page: self.bitmap_array = self.create_bitmap_array() - self.set_header(page_num) - - def set_header(self, page_num): - global page_header + self.set_header(page_num, version) + def set_header(self, page_num, version): # set page state to active page_header = bytearray(b'\xff') * 32 page_state_active_seq = Page.ACTIVE @@ -141,30 +148,22 @@ class Page(object): return encrypted_data - def reverse_hexbytes(self, addr_tmp): - addr = [] - reversed_bytes = "" - for i in range(0, len(addr_tmp), 2): - addr.append(addr_tmp[i:i + 2]) - reversed_bytes = "".join(reversed(addr)) - - return reversed_bytes - def encrypt_data(self, data_input, no_of_entries, nvs_obj): # Set values needed for encryption and encrypt data byte wise encr_data_to_write = bytearray() data_len_needed = 64 # in hex tweak_len_needed = 32 # in hex + key_len_needed = 64 init_tweak_val = '0' init_data_val = 'f' tweak_tmp = '' encr_key_input = None # Extract encryption key and tweak key from given key input - if len(self.encr_key) == key_len_needed: - encr_key_input = self.encr_key + if len(nvs_obj.encr_key) == key_len_needed: + encr_key_input = nvs_obj.encr_key else: - encr_key_input = codecs.decode(self.encr_key, 'hex') + encr_key_input = codecs.decode(nvs_obj.encr_key, 'hex') rel_addr = nvs_obj.page_num * Page.PAGE_PARAMS["max_size"] + Page.FIRST_ENTRY_OFFSET @@ -187,12 +186,10 @@ class Page(object): if addr_len > 2: if not addr_len % 2: addr_tmp = addr - tweak_tmp = self.reverse_hexbytes(addr_tmp) - tweak_val = tweak_tmp + (init_tweak_val * (tweak_len_needed - (len(tweak_tmp)))) else: addr_tmp = init_tweak_val + addr - tweak_tmp = self.reverse_hexbytes(addr_tmp) - tweak_val = tweak_tmp + (init_tweak_val * (tweak_len_needed - (len(tweak_tmp)))) + tweak_tmp = reverse_hexbytes(addr_tmp) + tweak_val = tweak_tmp + (init_tweak_val * (tweak_len_needed - (len(tweak_tmp)))) else: tweak_val = addr + (init_tweak_val * (tweak_len_needed - len(addr))) @@ -214,7 +211,7 @@ class Page(object): def write_entry_to_buf(self, data, entrycount,nvs_obj): encr_data = bytearray() - if self.is_encrypt: + if nvs_obj.encrypt: encr_data_ret = self.encrypt_data(data, entrycount,nvs_obj) encr_data[0:len(encr_data_ret)] = encr_data_ret data = encr_data @@ -299,9 +296,6 @@ class Page(object): chunk_count = chunk_count + 1 if remaining_size or (tailroom - chunk_size) < Page.SINGLE_ENTRY_SIZE: - if page_header[0:4] != Page.FULL: - page_state_full_seq = Page.FULL - struct.pack_into(' Page.PAGE_PARAMS["max_old_blob_size"]: - if version == Page.VERSION1: - raise InputError("Version %s\n%s: Size exceeds max allowed length." % (VERSION1_PRINT,key)) + if self.version == Page.VERSION1: + raise InputError(" Input File: Size exceeds max allowed length `%s` bytes for key `%s`." % (Page.PAGE_PARAMS["max_old_blob_size"], key)) else: if encoding == "string": - raise InputError("Version %s\n%s: Size exceeds max allowed length." % (VERSION2_PRINT,key)) + raise InputError(" Input File: Size exceeds max allowed length `%s` bytes for key `%s`." % (Page.PAGE_PARAMS["max_old_blob_size"], key)) # Calculate no. of entries data will require rounded_size = (datalen + 31) & ~31 @@ -378,7 +372,7 @@ class Page(object): if self.entry_num >= Page.PAGE_PARAMS["max_entries"]: raise PageFullError() elif (self.entry_num + total_entry_count) >= Page.PAGE_PARAMS["max_entries"]: - if not (version == Page.VERSION2 and encoding in ["hex2bin", "binary", "base64"]): + if not (self.version == Page.VERSION2 and encoding in ["hex2bin", "binary", "base64"]): raise PageFullError() # Entry header @@ -386,7 +380,7 @@ class Page(object): # Set Namespace Index entry_struct[0] = ns_index # Set Span - if version == Page.VERSION2: + if self.version == Page.VERSION2: if encoding == "string": entry_struct[2] = data_entry_count + 1 # Set Chunk Index @@ -406,7 +400,7 @@ class Page(object): elif encoding in ["hex2bin", "binary", "base64"]: entry_struct[1] = Page.BLOB - if version == Page.VERSION2 and (encoding in ["hex2bin", "binary", "base64"]): + if self.version == Page.VERSION2 and (encoding in ["hex2bin", "binary", "base64"]): entry_struct = self.write_varlen_binary_data(entry_struct,ns_index,key,data, datalen,total_entry_count, encoding, nvs_obj) else: @@ -468,13 +462,18 @@ Binary can later be flashed onto device via a flashing utility. class NVS(object): - def __init__(self, fout, input_size): + def __init__(self, fout, input_size, version, encrypt=False, key_input=None): self.size = input_size + self.encrypt = encrypt + self.encr_key = None self.namespace_idx = 0 self.page_num = -1 self.pages = [] - self.cur_page = self.create_new_page() + self.version = version self.fout = fout + if self.encrypt: + self.encr_key = key_input + self.cur_page = self.create_new_page(version) def __enter__(self): return self @@ -490,26 +489,26 @@ class NVS(object): # Creating the last reserved page self.create_new_page(is_rsrv_page=True) break - result = self.get_binary_data() - if version == Page.VERSION1: - print("Version: ", VERSION1_PRINT) - else: - print("Version: ", VERSION2_PRINT) self.fout.write(result) - def create_new_page(self, is_rsrv_page=False): + def create_new_page(self, version=None, is_rsrv_page=False): + # Set previous page state to FULL before creating new page + if self.pages: + curr_page_state = struct.unpack('/ + :param outdir: Target output dir to store files + :param filepath: Path of target file + ''' + bin_ext = '.bin' + # Expand if tilde(~) provided in path + outdir = os.path.expanduser(outdir) - :param input_filename: Name of input file containing data - :param output_filename: Name of output file to store generated binary - :param input_part_size: Size of partition in bytes (must be multiple of 4096) - :param is_key_gen: Enable encryption key generation in encryption mode - :param encrypt_mode: Enable/Disable encryption mode - :param key_file: Input file having encryption keys in encryption mode - :param version_no: Format Version number - :return: None - """ + if filepath: + key_file_name, ext = os.path.splitext(filepath) + if not ext: + filepath = key_file_name + bin_ext + elif bin_ext not in ext: + sys.exit('Error: `%s`. Only `%s` extension allowed.' % (filepath, bin_ext)) - global key_input, key_len_needed - encr_key_bin_file = None - encr_keys_dir = None - backslash = ['/','\\'] + # Create dir if does not exist + if not (os.path.isdir(outdir)): + distutils.dir_util.mkpath(outdir) - key_len_needed = 64 - key_input = bytearray() + filedir, filename = os.path.split(filepath) + filedir = os.path.join(outdir,filedir,'') + if filedir and not os.path.isdir(filedir): + distutils.dir_util.mkpath(filedir) - if key_gen: - key_input = ''.join(random.choice('0123456789abcdef') for _ in range(128)).strip() - elif key_file: - with open(key_file, 'rb') as key_f: - key_input = key_f.read(64) + if os.path.isabs(filepath): + if not outdir == os.getcwd(): + print("\nWarning: `%s` \n\t==> absolute path given so outdir is ignored for this file." % filepath) + # Set to empty as outdir is ignored here + outdir = '' - if all(arg is not None for arg in [input_filename, output_filename, input_size]): - if not os.path.isabs(output_filename) and not any(ch in output_filename for ch in backslash): - output_filename = os.path.join(output_dir, '') + output_filename - input_file = open(input_filename, 'rt', encoding='utf8') - output_file = open(output_filename, 'wb') + # Set full path - outdir + filename + filepath = os.path.join(outdir, '') + filepath - with nvs_open(output_file, input_size) as nvs_obj: - reader = csv.DictReader(filter(lambda row: row[0] != '#',input_file), delimiter=',') - for row in reader: - try: - write_entry(nvs_obj, row["key"], row["type"], row["encoding"], row["value"]) - except (InputError) as e: - print(e) - input_file.close() - output_file.close() - sys.exit(-2) + return outdir, filepath - input_file.close() - output_file.close() - print("NVS binary created: " + output_filename) +def encrypt(args): + ''' + Generate encrypted NVS Partition + :param args: Command line arguments given + ''' + key = None + bin_ext = '.bin' - if key_gen: - keys_page_buf = bytearray(b'\xff') * Page.PAGE_PARAMS["max_size"] - key_bytes = bytearray() - if len(key_input) == key_len_needed: - key_bytes = key_input + check_size(args.size) + if (args.keygen is False) and (not args.inputkey): + sys.exit("Error. --keygen or --inputkey argument needed.") + elif args.keygen and args.inputkey: + sys.exit("Error. --keygen and --inputkey both are not allowed.") + elif not args.keygen and args.keyfile: + print("\nWarning:","--inputkey argument is given. --keyfile argument will be ignored...") + + if args.inputkey: + # Check if key file has .bin extension + filename, ext = os.path.splitext(args.inputkey) + if bin_ext not in ext: + sys.exit('Error: `%s`. Only `%s` extension allowed.' % (args.inputkey, bin_ext)) + key = bytearray() + with open(args.inputkey, 'rb') as key_f: + key = key_f.read(64) + + # Generate encrypted NVS Partition + generate(args, is_encr_enabled=True, encr_key=key) + + +def decrypt_data(data_input, decr_key, page_num, entry_no, entry_size): + ''' + Decrypt NVS data entry + ''' + page_max_size = 4096 + first_entry_offset = 64 + init_tweak_val = '0' + tweak_len_needed = 32 # in hex + tweak_tmp = '' + + data_input = binascii.hexlify(data_input) + rel_addr = page_num * page_max_size + first_entry_offset + + # Set tweak value + offset = entry_no * entry_size + addr = hex(rel_addr + offset)[2:] + addr_len = len(addr) + if addr_len > 2: + if not addr_len % 2: + addr_tmp = addr else: - key_bytes = codecs.decode(key_input, 'hex') - key_len = len(key_bytes) - keys_page_buf[0:key_len] = key_bytes - crc_data = keys_page_buf[0:key_len] - crc_data = bytes(crc_data) - crc = zlib.crc32(crc_data, 0xFFFFFFFF) - struct.pack_into('", args.output) + + +def generate_key(args): + ''' + Generate encryption keys + :param args: Command line arguments given + ''' + page_max_size = 4096 + keys_dir = 'keys' + output_keyfile = None + bin_ext = '.bin' + + if not args.keyfile: + timestamp = datetime.datetime.now().strftime('%m-%d_%H-%M') + args.keyfile = "keys-" + timestamp + bin_ext + + keys_outdir = os.path.join(args.outdir,keys_dir, '') + # Create keys/ dir in if does not exist + if not (os.path.isdir(keys_outdir)): + distutils.dir_util.mkpath(keys_outdir) + keys_outdir, output_keyfile = set_target_filepath(keys_outdir, args.keyfile) + + key = ''.join(random.choice('0123456789abcdef') for _ in range(128)).strip() + encr_key_bytes = codecs.decode(key, 'hex') + key_len = len(encr_key_bytes) + + keys_buf = bytearray(b'\xff') * page_max_size + keys_buf[0:key_len] = encr_key_bytes + crc_data = keys_buf[0:key_len] + crc_data = bytes(crc_data) + crc = zlib.crc32(crc_data, 0xFFFFFFFF) + struct.pack_into(' ", output_keyfile) + + return key + + +def generate(args, is_encr_enabled=False, encr_key=None): + ''' + Generate NVS Partition + :param args: Command line arguments given + :param is_encr_enabled: Encryption enabled/disabled + :param encr_key: Key to encrypt NVS partition + ''' + is_dir_new = False + bin_ext = '.bin' + + input_size = check_size(args.size) + if args.version == 1: + args.version = Page.VERSION1 + elif args.version == 2: + args.version = Page.VERSION2 + + # Check if key file has .bin extension + filename, ext = os.path.splitext(args.output) + if bin_ext not in ext: + sys.exit('Error: `%s`. Only `.bin` extension allowed.' % args.output) + args.outdir, args.output = set_target_filepath(args.outdir, args.output) + + if is_encr_enabled and not encr_key: + encr_key = generate_key(args) + + input_file = open(args.input, 'rt', encoding='utf8') + output_file = open(args.output, 'wb') + + with open(args.input, 'rt', encoding='utf8') as input_file,\ + open(args.output, 'wb') as output_file,\ + nvs_open(output_file, input_size, args.version, is_encrypt=is_encr_enabled, key=encr_key) as nvs_obj: + # Comments are skipped + reader = csv.DictReader(filter(lambda row: row[0] != '#',input_file), delimiter=',') + if nvs_obj.version == Page.VERSION1: + version_set = VERSION1_PRINT else: - if encr_key_prefix: - encr_key_bin_file = encr_keys_dir + encr_key_prefix + "-keys" + ".bin" - else: - encr_key_bin_file = encr_keys_dir + "encryption_keys_" + timestamp + ".bin" + version_set = VERSION2_PRINT + print("\nCreating NVS binary with version:", version_set) + for row in reader: + try: + # Check key length + if len(row["key"]) > 15: + raise InputError("Length of key `%s` should be <= 15 characters." % row["key"]) + write_entry(nvs_obj, row["key"], row["type"], row["encoding"], row["value"]) + except InputError as e: + print(e) + filedir, filename = os.path.split(args.output) + if filename: + print("\nWarning: NVS binary not created...") + os.remove(args.output) + if is_dir_new and not filedir == os.getcwd(): + print("\nWarning: Output dir not created...") + os.rmdir(filedir) + sys.exit(-2) - with open(encr_key_bin_file,'wb') as output_keys_file: - output_keys_file.write(keys_page_buf) - - print("Encryption keys binary created: " + encr_key_bin_file) + print("\nCreated NVS binary: ===>", args.output) def main(): - parser = argparse.ArgumentParser(description="ESP32 NVS partition generation utility") - nvs_part_gen_group = parser.add_argument_group('To generate NVS partition') - nvs_part_gen_group.add_argument("--input", - help="Path to CSV file to parse.", - default=None) - - nvs_part_gen_group.add_argument("--output", - help='Path to output converted binary file.', - default=None) - - nvs_part_gen_group.add_argument("--size", - help='Size of NVS Partition in bytes (must be multiple of 4096)') - - nvs_part_gen_group.add_argument("--version", - help='Set version. Default: v2', - choices=['v1','v2'], - default='v2', - type=str.lower) - - keygen_action_key = nvs_part_gen_group.add_argument("--keygen", - help='Generate keys for encryption.', - choices=['true','false'], - default='false', - type=str.lower) - - nvs_part_gen_group.add_argument("--encrypt", - help='Set encryption mode. Default: false', - choices=['true','false'], - default='false', - type=str.lower) - - keygen_action_file = nvs_part_gen_group.add_argument("--keyfile", - help='File having key for encryption (Applicable only if encryption mode is true).', - default=None) - - keygen_action_dir = nvs_part_gen_group.add_argument('--outdir', - dest='outdir', - default=os.getcwd(), - help='the output directory to store the files created\ - (Default: current directory)') - - key_gen_group = parser.add_argument_group('To generate encryption keys') - key_gen_group._group_actions.append(keygen_action_key) - key_gen_group._group_actions.append(keygen_action_file) - key_gen_group._group_actions.append(keygen_action_dir) + parser = argparse.ArgumentParser(description="\nESP NVS partition generation utility", formatter_class=argparse.RawTextHelpFormatter) + subparser = parser.add_subparsers(title='Commands', + dest='command', + help='\nRun nvs_partition_gen.py {command} -h for additional help\n\n') + parser_gen = subparser.add_parser('generate', + help='Generate NVS partition', + formatter_class=argparse.RawTextHelpFormatter) + parser_gen.set_defaults(func=generate) + parser_gen.add_argument('input', + default=None, + help='Path to CSV file to parse') + parser_gen.add_argument('output', + default=None, + help='Path to output NVS binary file') + parser_gen.add_argument('size', + default=None, + help='Size of NVS partition in bytes\ + \n(must be multiple of 4096)') + parser_gen.add_argument('--version', + choices=[1,2], + default=2, + type=int, + help='''Set multipage blob version.\ + \nVersion 1 - Multipage blob support disabled.\ + \nVersion 2 - Multipage blob support enabled.\ + \nDefault: Version 2''') + parser_gen.add_argument('--outdir', + default=os.getcwd(), + help='Output directory to store files created\ + \n(Default: current directory)') + parser_gen_key = subparser.add_parser('generate-key', + help='Generate keys for encryption', + formatter_class=argparse.RawTextHelpFormatter) + parser_gen_key.set_defaults(func=generate_key) + parser_gen_key.add_argument('--keyfile', + default=None, + help='Path to output encryption keys file') + parser_gen_key.add_argument('--outdir', + default=os.getcwd(), + help='Output directory to store files created.\ + \n(Default: current directory)') + parser_encr = subparser.add_parser('encrypt', + help='Generate NVS encrypted partition', + formatter_class=argparse.RawTextHelpFormatter) + parser_encr.set_defaults(func=encrypt) + parser_encr.add_argument('input', + default=None, + help='Path to CSV file to parse') + parser_encr.add_argument('output', + default=None, + help='Path to output NVS binary file') + parser_encr.add_argument('size', + default=None, + help='Size of NVS partition in bytes\ + \n(must be multiple of 4096)') + parser_encr.add_argument('--version', + choices=[1,2], + default=2, + type=int, + help='''Set multipage blob version.\ + \nVersion 1 - Multipage blob support disabled.\ + \nVersion 2 - Multipage blob support enabled.\ + \nDefault: Version 2''') + parser_encr.add_argument('--keygen', + action="store_true", + default=False, + help='Generates key for encrypting NVS partition') + parser_encr.add_argument('--keyfile', + default=None, + help='Path to output encryption keys file') + parser_encr.add_argument('--inputkey', + default=None, + help='File having key for encrypting NVS partition') + parser_encr.add_argument('--outdir', + default=os.getcwd(), + help='Output directory to store files created.\ + \n(Default: current directory)') + parser_decr = subparser.add_parser('decrypt', + help='Decrypt NVS encrypted partition', + formatter_class=argparse.RawTextHelpFormatter) + parser_decr.set_defaults(func=decrypt) + parser_decr.add_argument('input', + default=None, + help='Path to encrypted NVS partition file to parse') + parser_decr.add_argument('key', + default=None, + help='Path to file having keys for decryption') + parser_decr.add_argument('output', + default=None, + help='Path to output decrypted binary file') + parser_decr.add_argument('--outdir', + default=os.getcwd(), + help='Output directory to store files created.\ + \n(Default: current directory)') args = parser.parse_args() - input_filename = args.input - output_filename = args.output - part_size = args.size - version_no = args.version - is_key_gen = args.keygen - is_encrypt_data = args.encrypt - key_file = args.keyfile - output_dir_path = args.outdir - encr_keys_prefix = None - print_arg_str = "Invalid.\nTo generate nvs partition binary --input, --output and --size arguments are mandatory.\ - \nTo generate encryption keys --keygen argument is mandatory." - print_encrypt_arg_str = "Missing parameter. Enter --keyfile or --keygen." - - check_input_args(input_filename,output_filename, part_size, is_key_gen, is_encrypt_data, key_file, version_no, - print_arg_str, print_encrypt_arg_str, output_dir_path) - nvs_part_gen(input_filename, output_filename, part_size, is_key_gen, is_encrypt_data, key_file, - encr_keys_prefix, version_no, output_dir_path) + args.func(args) if __name__ == "__main__": diff --git a/components/nvs_flash/test/CMakeLists.txt b/components/nvs_flash/test/CMakeLists.txt index f473de05af..ede2a57bae 100644 --- a/components/nvs_flash/test/CMakeLists.txt +++ b/components/nvs_flash/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity test_utils nvs_flash bootloader_support) - -register_component() +idf_component_register(SRCS "." + INCLUDE_DIRS "." + REQUIRES unity test_utils nvs_flash bootloader_support) \ No newline at end of file diff --git a/components/nvs_flash/test_nvs_host/Makefile b/components/nvs_flash/test_nvs_host/Makefile index 1d30266b1f..d509fd6ee3 100644 --- a/components/nvs_flash/test_nvs_host/Makefile +++ b/components/nvs_flash/test_nvs_host/Makefile @@ -21,7 +21,7 @@ SOURCE_FILES = \ crc.cpp \ main.cpp -CPPFLAGS += -I../include -I../src -I./ -I../../esp_common/include -I../../esp32/include -I ../../mbedtls/mbedtls/include -I ../../spi_flash/include -I ../../../tools/catch -I ../../xtensa/include -fprofile-arcs -ftest-coverage -DCONFIG_NVS_ENCRYPTION +CPPFLAGS += -I../include -I../src -I./ -I../../esp_common/include -I../../esp32/include -I ../../mbedtls/mbedtls/include -I ../../spi_flash/include -I ../../soc/include -I ../../../tools/catch -fprofile-arcs -ftest-coverage CFLAGS += -fprofile-arcs -ftest-coverage CXXFLAGS += -std=c++11 -Wall -Werror LDFLAGS += -lstdc++ -Wall -fprofile-arcs -ftest-coverage @@ -61,10 +61,10 @@ clean: rm -f $(COVERAGE_FILES) *.gcov rm -rf coverage_report/ rm -f coverage.info - rm ../nvs_partition_generator/partition_single_page.bin - rm ../nvs_partition_generator/partition_multipage_blob.bin - rm ../nvs_partition_generator/partition_encrypted.bin - rm ../nvs_partition_generator/partition_encrypted_using_keygen.bin - rm ../nvs_partition_generator/partition_encrypted_using_keyfile.bin + rm -f ../nvs_partition_generator/partition_single_page.bin + rm -f ../nvs_partition_generator/partition_multipage_blob.bin + rm -f ../nvs_partition_generator/partition_encrypted.bin + rm -f ../nvs_partition_generator/partition_encrypted_using_keygen.bin + rm -f ../nvs_partition_generator/partition_encrypted_using_keyfile.bin .PHONY: clean all test long-test diff --git a/components/nvs_flash/test_nvs_host/sdkconfig.h b/components/nvs_flash/test_nvs_host/sdkconfig.h index e69de29bb2..a38e0a10d8 100644 --- a/components/nvs_flash/test_nvs_host/sdkconfig.h +++ b/components/nvs_flash/test_nvs_host/sdkconfig.h @@ -0,0 +1,3 @@ +#define CONFIG_NVS_ENCRYPTION 1 +//currently use the legacy implementation, since the stubs for new HAL are not done yet +#define CONFIG_SPI_FLASH_USE_LEGACY_IMPL 1 diff --git a/components/nvs_flash/test_nvs_host/test_nvs.cpp b/components/nvs_flash/test_nvs_host/test_nvs.cpp index bbd4f8ee6d..f78440a0de 100644 --- a/components/nvs_flash/test_nvs_host/test_nvs.cpp +++ b/components/nvs_flash/test_nvs_host/test_nvs.cpp @@ -14,6 +14,7 @@ #include "catch.hpp" #include "nvs.hpp" #include "nvs_test_api.h" +#include "sdkconfig.h" #ifdef CONFIG_NVS_ENCRYPTION #include "nvs_encr.hpp" #endif @@ -2375,14 +2376,14 @@ TEST_CASE("check and read data from partition generated via partition generation if (childpid == 0) { exit(execlp("python", "python", "../nvs_partition_generator/nvs_partition_gen.py", - "--input", + "generate", "../nvs_partition_generator/sample_singlepage_blob.csv", - "--output", - "../nvs_partition_generator/partition_single_page.bin", - "--size", + "partition_single_page.bin", "0x3000", "--version", - "v1",NULL)); + "1", + "--outdir", + "../nvs_partition_generator",NULL)); } else { CHECK(childpid > 0); int status; @@ -2429,14 +2430,14 @@ TEST_CASE("check and read data from partition generated via partition generation if (childpid == 0) { exit(execlp("python", "python", "../nvs_partition_generator/nvs_partition_gen.py", - "--input", + "generate", "../nvs_partition_generator/sample_multipage_blob.csv", - "--output", - "../nvs_partition_generator/partition_multipage_blob.bin", - "--size", + "partition_multipage_blob.bin", "0x4000", "--version", - "v2",NULL)); + "2", + "--outdir", + "../nvs_partition_generator",NULL)); } else { CHECK(childpid > 0); waitpid(childpid, &status, 0); @@ -2469,10 +2470,10 @@ TEST_CASE("check and read data from partition generated via manufacturing utilit if (childpid == 0) { exit(execlp("bash", "bash", "-c", - "rm -rf ../../../tools/mass_mfg/host_test | \ - cp -rf ../../../tools/mass_mfg/testdata mfg_testdata | \ - cp -rf ../nvs_partition_generator/testdata . | \ - mkdir -p ../../../tools/mass_mfg/host_test",NULL)); + "rm -rf ../../../tools/mass_mfg/host_test && \ + cp -rf ../../../tools/mass_mfg/testdata mfg_testdata && \ + cp -rf ../nvs_partition_generator/testdata . && \ + mkdir -p ../../../tools/mass_mfg/host_test", NULL)); } else { CHECK(childpid > 0); waitpid(childpid, &status, 0); @@ -2482,18 +2483,15 @@ TEST_CASE("check and read data from partition generated via manufacturing utilit if (childpid == 0) { exit(execlp("python", "python", "../../../tools/mass_mfg/mfg_gen.py", - "--conf", + "generate", "../../../tools/mass_mfg/samples/sample_config.csv", - "--values", "../../../tools/mass_mfg/samples/sample_values_singlepage_blob.csv", - "--prefix", "Test", - "--size", "0x3000", "--outdir", "../../../tools/mass_mfg/host_test", "--version", - "v1",NULL)); + "1",NULL)); } else { CHECK(childpid > 0); @@ -2504,14 +2502,12 @@ TEST_CASE("check and read data from partition generated via manufacturing utilit if (childpid == 0) { exit(execlp("python", "python", "../nvs_partition_generator/nvs_partition_gen.py", - "--input", + "generate", "../../../tools/mass_mfg/host_test/csv/Test-1.csv", - "--output", "../nvs_partition_generator/Test-1-partition.bin", - "--size", "0x3000", "--version", - "v1",NULL)); + "1",NULL)); } else { CHECK(childpid > 0); @@ -2568,18 +2564,15 @@ TEST_CASE("check and read data from partition generated via manufacturing utilit if (childpid == 0) { exit(execlp("python", "python", "../../../tools/mass_mfg/mfg_gen.py", - "--conf", + "generate", "../../../tools/mass_mfg/samples/sample_config.csv", - "--values", "../../../tools/mass_mfg/samples/sample_values_multipage_blob.csv", - "--prefix", "Test", - "--size", "0x4000", "--outdir", "../../../tools/mass_mfg/host_test", "--version", - "v2",NULL)); + "2",NULL)); } else { CHECK(childpid > 0); @@ -2590,14 +2583,12 @@ TEST_CASE("check and read data from partition generated via manufacturing utilit if (childpid == 0) { exit(execlp("python", "python", "../nvs_partition_generator/nvs_partition_gen.py", - "--input", + "generate", "../../../tools/mass_mfg/host_test/csv/Test-1.csv", - "--output", "../nvs_partition_generator/Test-1-partition.bin", - "--size", "0x4000", "--version", - "v2",NULL)); + "2",NULL)); } else { CHECK(childpid > 0); @@ -2790,16 +2781,14 @@ TEST_CASE("test nvs apis for nvs partition generator utility with encryption ena if (childpid == 0) { exit(execlp("python", "python", "../nvs_partition_generator/nvs_partition_gen.py", - "--input", + "encrypt", "../nvs_partition_generator/sample_multipage_blob.csv", - "--output", - "../nvs_partition_generator/partition_encrypted.bin", - "--size", + "partition_encrypted.bin", "0x4000", - "--encrypt", - "True", - "--keyfile", - "../nvs_partition_generator/testdata/sample_encryption_keys.bin",NULL)); + "--inputkey", + "../nvs_partition_generator/testdata/sample_encryption_keys.bin", + "--outdir", + "../nvs_partition_generator",NULL)); } else { CHECK(childpid > 0); waitpid(childpid, &status, 0); @@ -2831,7 +2820,6 @@ TEST_CASE("test nvs apis for nvs partition generator utility with encryption ena } - TEST_CASE("test nvs apis for nvs partition generator utility with encryption enabled using keygen", "[nvs_part_gen]") { int childpid = fork(); @@ -2852,7 +2840,7 @@ TEST_CASE("test nvs apis for nvs partition generator utility with encryption ena if (childpid == 0) { exit(execlp("rm", " rm", "-rf", - "keys",NULL)); + "../nvs_partition_generator/keys",NULL)); } else { CHECK(childpid > 0); waitpid(childpid, &status, 0); @@ -2862,16 +2850,13 @@ TEST_CASE("test nvs apis for nvs partition generator utility with encryption ena if (childpid == 0) { exit(execlp("python", "python", "../nvs_partition_generator/nvs_partition_gen.py", - "--input", + "encrypt", "../nvs_partition_generator/sample_multipage_blob.csv", - "--output", - "../nvs_partition_generator/partition_encrypted_using_keygen.bin", - "--size", + "partition_encrypted_using_keygen.bin", "0x4000", - "--encrypt", - "True", "--keygen", - "true",NULL)); + "--outdir", + "../nvs_partition_generator",NULL)); } else { CHECK(childpid > 0); @@ -2889,7 +2874,7 @@ TEST_CASE("test nvs apis for nvs partition generator utility with encryption ena char *files; char *file_ext; - dir = opendir("keys"); + dir = opendir("../nvs_partition_generator/keys"); while ((file = readdir(dir)) != NULL) { filename = file->d_name; @@ -2904,7 +2889,7 @@ TEST_CASE("test nvs apis for nvs partition generator utility with encryption ena } } - std::string encr_file = std::string("keys/") + std::string(filename); + std::string encr_file = std::string("../nvs_partition_generator/keys/") + std::string(filename); SpiFlashEmulator emu("../nvs_partition_generator/partition_encrypted_using_keygen.bin"); char buffer[64]; @@ -2927,7 +2912,7 @@ TEST_CASE("test nvs apis for nvs partition generator utility with encryption ena } -TEST_CASE("test nvs apis for nvs partition generator utility with encryption enabled using keyfile", "[nvs_part_gen]") +TEST_CASE("test nvs apis for nvs partition generator utility with encryption enabled using inputkey", "[nvs_part_gen]") { int childpid = fork(); int status; @@ -2938,7 +2923,7 @@ TEST_CASE("test nvs apis for nvs partition generator utility with encryption ena char *files; char *file_ext; - dir = opendir("keys"); + dir = opendir("../nvs_partition_generator/keys"); while ((file = readdir(dir)) != NULL) { filename = file->d_name; @@ -2953,21 +2938,19 @@ TEST_CASE("test nvs apis for nvs partition generator utility with encryption ena } } - std::string encr_file = std::string("keys/") + std::string(filename); + std::string encr_file = std::string("../nvs_partition_generator/keys/") + std::string(filename); if (childpid == 0) { exit(execlp("python", "python", "../nvs_partition_generator/nvs_partition_gen.py", - "--input", + "encrypt", "../nvs_partition_generator/sample_multipage_blob.csv", - "--output", - "../nvs_partition_generator/partition_encrypted_using_keyfile.bin", - "--size", + "partition_encrypted_using_keyfile.bin", "0x4000", - "--encrypt", - "True", - "--keyfile", - encr_file.c_str(),NULL)); + "--inputkey", + encr_file.c_str(), + "--outdir", + "../nvs_partition_generator",NULL)); } else { CHECK(childpid > 0); @@ -2999,7 +2982,7 @@ TEST_CASE("test nvs apis for nvs partition generator utility with encryption ena if (childpid == 0) { exit(execlp("rm", " rm", "-rf", - "keys",NULL)); + "../nvs_partition_generator/keys",NULL)); } else { CHECK(childpid > 0); waitpid(childpid, &status, 0); @@ -3020,7 +3003,7 @@ TEST_CASE("test nvs apis for nvs partition generator utility with encryption ena } -TEST_CASE("check and read data from partition generated via manufacturing utility with encryption enabled using sample keyfile", "[mfg_gen]") +TEST_CASE("check and read data from partition generated via manufacturing utility with encryption enabled using sample inputkey", "[mfg_gen]") { int childpid = fork(); int status; @@ -3041,21 +3024,16 @@ TEST_CASE("check and read data from partition generated via manufacturing utilit if (childpid == 0) { exit(execlp("python", "python", "../../../tools/mass_mfg/mfg_gen.py", - "--conf", + "generate", "../../../tools/mass_mfg/samples/sample_config.csv", - "--values", "../../../tools/mass_mfg/samples/sample_values_multipage_blob.csv", - "--prefix", "Test", - "--size", "0x4000", "--outdir", "../../../tools/mass_mfg/host_test", "--version", - "v2", - "--encrypt", - "true", - "--keyfile", + "2", + "--inputkey", "mfg_testdata/sample_encryption_keys.bin",NULL)); } else { @@ -3067,17 +3045,13 @@ TEST_CASE("check and read data from partition generated via manufacturing utilit if (childpid == 0) { exit(execlp("python", "python", "../nvs_partition_generator/nvs_partition_gen.py", - "--input", + "encrypt", "../../../tools/mass_mfg/host_test/csv/Test-1.csv", - "--output", "../nvs_partition_generator/Test-1-partition-encrypted.bin", - "--size", "0x4000", "--version", - "v2", - "--encrypt", - "true", - "--keyfile", + "2", + "--inputkey", "testdata/sample_encryption_keys.bin",NULL)); } else { @@ -3147,8 +3121,7 @@ TEST_CASE("check and read data from partition generated via manufacturing utilit if (childpid == 0) { exit(execlp("python", "python", "../../../tools/mass_mfg/mfg_gen.py", - "--keygen", - "true", + "generate-key", "--outdir", "../../../tools/mass_mfg/host_test", "--keyfile", @@ -3163,21 +3136,16 @@ TEST_CASE("check and read data from partition generated via manufacturing utilit if (childpid == 0) { exit(execlp("python", "python", "../../../tools/mass_mfg/mfg_gen.py", - "--conf", + "generate", "../../../tools/mass_mfg/samples/sample_config.csv", - "--values", "../../../tools/mass_mfg/samples/sample_values_multipage_blob.csv", - "--prefix", "Test", - "--size", "0x4000", "--outdir", "../../../tools/mass_mfg/host_test", "--version", - "v2", - "--encrypt", - "true", - "--keyfile", + "2", + "--inputkey", "../../../tools/mass_mfg/host_test/keys/encr_keys_host_test.bin",NULL)); } else { @@ -3189,17 +3157,13 @@ TEST_CASE("check and read data from partition generated via manufacturing utilit if (childpid == 0) { exit(execlp("python", "python", "../nvs_partition_generator/nvs_partition_gen.py", - "--input", + "encrypt", "../../../tools/mass_mfg/host_test/csv/Test-1.csv", - "--output", "../nvs_partition_generator/Test-1-partition-encrypted.bin", - "--size", "0x4000", "--version", - "v2", - "--encrypt", - "true", - "--keyfile", + "2", + "--inputkey", "../../../tools/mass_mfg/host_test/keys/encr_keys_host_test.bin",NULL)); } else { diff --git a/components/openssl/CMakeLists.txt b/components/openssl/CMakeLists.txt index 3a96598f01..bba4006f1a 100644 --- a/components/openssl/CMakeLists.txt +++ b/components/openssl/CMakeLists.txt @@ -1,14 +1,11 @@ -set(COMPONENT_ADD_INCLUDEDIRS include) -set(COMPONENT_PRIV_INCLUDEDIRS include/internal include/platform include/openssl) -set(COMPONENT_SRCS "library/ssl_cert.c" - "library/ssl_lib.c" - "library/ssl_methods.c" - "library/ssl_pkey.c" - "library/ssl_stack.c" - "library/ssl_x509.c" - "platform/ssl_pm.c" - "platform/ssl_port.c") - -set(COMPONENT_REQUIRES mbedtls) - -register_component() +idf_component_register(SRCS "library/ssl_cert.c" + "library/ssl_lib.c" + "library/ssl_methods.c" + "library/ssl_pkey.c" + "library/ssl_stack.c" + "library/ssl_x509.c" + "platform/ssl_pm.c" + "platform/ssl_port.c" + REQUIRES mbedtls + INCLUDE_DIRS include + PRIV_INCLUDE_DIRS include/internal include/platform include/openssl) diff --git a/components/partition_table/CMakeLists.txt b/components/partition_table/CMakeLists.txt index d94e3e162f..233e03d77c 100644 --- a/components/partition_table/CMakeLists.txt +++ b/components/partition_table/CMakeLists.txt @@ -1,4 +1,4 @@ -register_config_only_component() +idf_component_register() if(BOOTLOADER_BUILD) return() @@ -40,19 +40,6 @@ add_custom_command(OUTPUT "${build_dir}/partition_table/${unsigned_partition_bin DEPENDS ${partition_csv} "${CMAKE_CURRENT_SOURCE_DIR}/gen_esp32part.py" VERBATIM) -# Add signing steps -if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) - add_custom_target(gen_unsigned_partition_bin ALL DEPENDS - "${build_dir}/partition_table/${unsigned_partition_bin}") - - add_custom_command(OUTPUT "${build_dir}/partition_table/${final_partition_bin}" - COMMAND ${ESPSECUREPY} sign_data --keyfile "${secure_boot_signing_key}" - -o "${build_dir}/partition_table/${final_partition_bin}" - "${build_dir}/partition_table/${unsigned_partition_bin}" - DEPENDS "${build_dir}/partition_table/${unsigned_partition_bin}" - VERBATIM) -endif() - if(EXISTS ${partition_csv}) add_custom_target(partition_table ALL DEPENDS "${build_dir}/partition_table/${final_partition_bin}") else() @@ -64,29 +51,29 @@ else() "Either change partition table in menuconfig or create this input file.") endif() -if(CONFIG_SECURE_BOOT_ENABLED AND - NOT CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) - add_custom_command(TARGET partition_table POST_BUILD - COMMAND ${CMAKE_COMMAND} -E echo - "Partition table built but not signed. Sign partition data before flashing:" - COMMAND ${CMAKE_COMMAND} -E echo - "\t${ESPSECUREPY} sign_data --keyfile KEYFILE ${CMAKE_CURRENT_BINARY_DIR}/${final_partition_bin}" - VERBATIM) -endif() +# Add signing steps +if(CONFIG_SECURE_SIGNED_APPS) + if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) + add_custom_target(gen_unsigned_partition_bin ALL DEPENDS + "${build_dir}/partition_table/${unsigned_partition_bin}") -# If anti-rollback option is set then factory partition should not be in Partition Table. -# In this case, should be used the partition table with two ota app without the factory. -partition_table_get_partition_info(factory_offset "--partition-type app --partition-subtype factory" "offset") -if(CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK AND factory_offset) - fail_at_build_time(check_table_contents - "ERROR: Anti-rollback option is enabled. Partition table should consist of two ota app without factory partition.") -add_dependencies(bootloader check_table_contents) -add_dependencies(app check_table_contents) + add_custom_command(OUTPUT "${build_dir}/partition_table/${final_partition_bin}" + COMMAND ${ESPSECUREPY} sign_data --keyfile "${SECURE_BOOT_SIGNING_KEY}" + -o "${build_dir}/partition_table/${final_partition_bin}" + "${build_dir}/partition_table/${unsigned_partition_bin}" + DEPENDS "${build_dir}/partition_table/${unsigned_partition_bin}" + VERBATIM) + else() + string(REPLACE ";" " " espsecurepy "${ESPSECUREPY}") + add_custom_command(TARGET partition_table POST_BUILD + COMMAND ${CMAKE_COMMAND} -E echo + "Partition table built but not signed. Sign partition data before flashing:" + COMMAND ${CMAKE_COMMAND} -E echo + "\t${espsecurepy} sign_data --keyfile KEYFILE ${build_dir}/partition_table/${final_partition_bin}" + VERBATIM) + endif() endif() -add_dependencies(bootloader partition_table) -add_dependencies(app partition_table) - # Use global properties ESPTOOL_WRITE_FLASH_ARGS to pass this info to build # the list of esptool write arguments for flashing set_property(GLOBAL APPEND_STRING PROPERTY @@ -95,8 +82,3 @@ set_property(GLOBAL APPEND_STRING PROPERTY esptool_py_flash_project_args(partition_table ${PARTITION_TABLE_OFFSET} ${build_dir}/partition_table/partition-table.bin FLASH_IN_PROJECT) - -partition_table_get_partition_info(app_partition_offset "--partition-boot-default" "offset") -esptool_py_flash_project_args(app ${app_partition_offset} ${build_dir}/${PROJECT_BIN} FLASH_IN_PROJECT) - - diff --git a/components/partition_table/Makefile.projbuild b/components/partition_table/Makefile.projbuild index 1785ad811e..6b28b093f5 100644 --- a/components/partition_table/Makefile.projbuild +++ b/components/partition_table/Makefile.projbuild @@ -63,16 +63,21 @@ $(PARTITION_TABLE_BIN_UNSIGNED): $(PARTITION_TABLE_CSV_PATH) $(SDKCONFIG_MAKEFIL all_binaries: $(PARTITION_TABLE_BIN) partition_table_get_info check_table_contents partition_table_get_info: $(PARTITION_TABLE_BIN) - $(eval PHY_DATA_OFFSET:=$(shell $(GET_PART_INFO) --partition-type data --partition-subtype phy \ - --partition-table-file $(PARTITION_TABLE_BIN) get_partition_info --info offset)) - $(eval APP_OFFSET:=$(shell $(GET_PART_INFO) --partition-boot-default \ - --partition-table-file $(PARTITION_TABLE_BIN) get_partition_info --info offset)) - $(eval OTA_DATA_OFFSET:=$(shell $(GET_PART_INFO) --partition-type data --partition-subtype ota \ - --partition-table-file $(PARTITION_TABLE_BIN) get_partition_info --info offset)) - $(eval OTA_DATA_SIZE:=$(shell $(GET_PART_INFO) --partition-type data --partition-subtype ota \ - --partition-table-file $(PARTITION_TABLE_BIN) get_partition_info --info size)) - $(eval FACTORY_OFFSET:=$(shell $(GET_PART_INFO) --partition-type app --partition-subtype factory \ - --partition-table-file $(PARTITION_TABLE_BIN) get_partition_info --info offset)) + $(eval PHY_DATA_OFFSET:=$(shell $(GET_PART_INFO) --partition-table-file $(PARTITION_TABLE_BIN) \ + --partition-table-offset $(PARTITION_TABLE_OFFSET) \ + get_partition_info --partition-type data --partition-subtype phy --info offset)) + $(eval APP_OFFSET:=$(shell $(GET_PART_INFO) --partition-table-file $(PARTITION_TABLE_BIN) \ + --partition-table-offset $(PARTITION_TABLE_OFFSET) \ + get_partition_info --partition-boot-default --info offset)) + $(eval OTA_DATA_OFFSET:=$(shell $(GET_PART_INFO) --partition-table-file $(PARTITION_TABLE_BIN) \ + --partition-table-offset $(PARTITION_TABLE_OFFSET) \ + get_partition_info --partition-type data --partition-subtype ota --info offset)) + $(eval OTA_DATA_SIZE:=$(shell $(GET_PART_INFO) --partition-table-file $(PARTITION_TABLE_BIN) \ + --partition-table-offset $(PARTITION_TABLE_OFFSET) \ + get_partition_info --partition-type data --partition-subtype ota --info size)) + $(eval FACTORY_OFFSET:=$(shell $(GET_PART_INFO) --partition-table-file $(PARTITION_TABLE_BIN) \ + --partition-table-offset $(PARTITION_TABLE_OFFSET) \ + get_partition_info --partition-type app --partition-subtype factory --info offset)) export APP_OFFSET export PHY_DATA_OFFSET diff --git a/components/partition_table/gen_empty_partition.py b/components/partition_table/gen_empty_partition.py new file mode 100644 index 0000000000..f65f74d706 --- /dev/null +++ b/components/partition_table/gen_empty_partition.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +# +# generates an empty binary file +# +# This tool generates an empty binary file of the required size. +# +# Copyright 2018 Espressif Systems (Shanghai) PTE LTD +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from __future__ import print_function, division +from __future__ import unicode_literals +import argparse +import sys + +__version__ = '1.0' + +quiet = False + + +def generate_blanked_file(size, output_path): + output = b"\xFF" * size + try: + stdout_binary = sys.stdout.buffer # Python 3 + except AttributeError: + stdout_binary = sys.stdout + with stdout_binary if output_path == '-' else open(output_path, 'wb') as f: + f.write(output) + + +def main(): + parser = argparse.ArgumentParser(description='Generates an empty binary file of the required size.') + parser.add_argument('size', help='Size of generated the file', type=str) + + parser.add_argument('output', help='Path for binary file.', nargs='?', default='-') + args = parser.parse_args() + + size = int(args.size, 0) + if size > 0: + generate_blanked_file(size, args.output) + return 0 + + +class InputError(RuntimeError): + def __init__(self, e): + super(InputError, self).__init__(e) + + +if __name__ == '__main__': + try: + r = main() + sys.exit(r) + except InputError as e: + print(e, file=sys.stderr) + sys.exit(2) diff --git a/components/partition_table/partitions_singleapp.csv b/components/partition_table/partitions_singleapp.csv index 22cf97bacb..5156e827b4 100644 --- a/components/partition_table/partitions_singleapp.csv +++ b/components/partition_table/partitions_singleapp.csv @@ -1,5 +1,5 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, , 0x6000, phy_init, data, phy, , 0x1000, factory, app, factory, , 1M, diff --git a/components/partition_table/partitions_singleapp_coredump.csv b/components/partition_table/partitions_singleapp_coredump.csv index 8bcf89c20f..bbb55e2b47 100644 --- a/components/partition_table/partitions_singleapp_coredump.csv +++ b/components/partition_table/partitions_singleapp_coredump.csv @@ -1,5 +1,5 @@ # Name, Type, SubType, Offset, Size -# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, , 0x6000 phy_init, data, phy, , 0x1000 factory, app, factory, , 1M diff --git a/components/partition_table/partitions_two_ota.csv b/components/partition_table/partitions_two_ota.csv index 0a325b2f5a..7aee909cd1 100644 --- a/components/partition_table/partitions_two_ota.csv +++ b/components/partition_table/partitions_two_ota.csv @@ -1,5 +1,5 @@ # Name, Type, SubType, Offset, Size, Flags -# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, , 0x4000, otadata, data, ota, , 0x2000, phy_init, data, phy, , 0x1000, diff --git a/components/partition_table/partitions_two_ota_coredump.csv b/components/partition_table/partitions_two_ota_coredump.csv index 3a2143690b..2e1af0eca6 100644 --- a/components/partition_table/partitions_two_ota_coredump.csv +++ b/components/partition_table/partitions_two_ota_coredump.csv @@ -1,5 +1,5 @@ # Name, Type, SubType, Offset, Size -# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, , 0x4000 otadata, data, ota, , 0x2000 phy_init, data, phy, , 0x1000 diff --git a/components/partition_table/parttool.py b/components/partition_table/parttool.py index 14fcdf4fe7..84a0d1eaf4 100755 --- a/components/partition_table/parttool.py +++ b/components/partition_table/parttool.py @@ -22,195 +22,191 @@ import os import sys import subprocess import tempfile +import re import gen_esp32part as gen -__version__ = '1.0' -IDF_COMPONENTS_PATH = os.path.expandvars(os.path.join("$IDF_PATH", "components")) +__version__ = '2.0' + +COMPONENTS_PATH = os.path.expandvars(os.path.join("$IDF_PATH", "components")) +ESPTOOL_PY = os.path.join(COMPONENTS_PATH, "esptool_py", "esptool", "esptool.py") + +PARTITION_TABLE_OFFSET = 0x8000 -ESPTOOL_PY = os.path.join(IDF_COMPONENTS_PATH, "esptool_py", "esptool", "esptool.py") quiet = False def status(msg): - """ Print status message to stderr """ if not quiet: print(msg) -def _invoke_esptool(esptool_args, args): - m_esptool_args = [sys.executable, ESPTOOL_PY] +class _PartitionId(): - if args.port != "": - m_esptool_args.extend(["--port", args.port]) - - m_esptool_args.extend(esptool_args) - - if quiet: - with open(os.devnull, "w") as fnull: - subprocess.check_call(m_esptool_args, stdout=fnull, stderr=fnull) - else: - subprocess.check_call(m_esptool_args) + def __init__(self, name=None, type=None, subtype=None): + self.name = name + self.type = type + self.subtype = subtype -def _get_partition_table(args): - partition_table = None +class PartitionName(_PartitionId): - gen.offset_part_table = int(args.partition_table_offset, 0) - - if args.partition_table_file: - status("Reading partition table from partition table file...") - - try: - with open(args.partition_table_file, "rb") as partition_table_file: - partition_table = gen.PartitionTable.from_binary(partition_table_file.read()) - status("Partition table read from binary file {}".format(partition_table_file.name)) - except (gen.InputError, TypeError): - with open(args.partition_table_file, "r") as partition_table_file: - partition_table_file.seek(0) - partition_table = gen.PartitionTable.from_csv(partition_table_file.read()) - status("Partition table read from CSV file {}".format(partition_table_file.name)) - else: - port_info = (" on port " + args.port if args.port else "") - status("Reading partition table from device{}...".format(port_info)) - - f_name = None - with tempfile.NamedTemporaryFile(delete=False) as f: - f_name = f.name - - try: - invoke_args = ["read_flash", str(gen.offset_part_table), str(gen.MAX_PARTITION_LENGTH), f_name] - _invoke_esptool(invoke_args, args) - with open(f_name, "rb") as f: - partition_table = gen.PartitionTable.from_binary(f.read()) - status("Partition table read from device" + port_info) - finally: - os.unlink(f_name) - - return partition_table + def __init__(self, name): + _PartitionId.__init__(self, name=name) -def _get_partition(args): - partition_table = _get_partition_table(args) +class PartitionType(_PartitionId): - partition = None - - if args.partition_name: - partition = partition_table.find_by_name(args.partition_name) - elif args.partition_type and args.partition_subtype: - partition = partition_table.find_by_type(args.partition_type, args.partition_subtype) - elif args.partition_boot_default: - search = ["factory"] + ["ota_{}".format(d) for d in range(16)] - for subtype in search: - partition = partition_table.find_by_type("app", subtype) - if partition is not None: - break - else: - raise RuntimeError("Invalid partition selection arguments. Specify --partition-name OR \ - --partition-type and --partition-subtype OR --partition--boot-default.") - - if partition: - status("Found partition {}".format(str(partition))) - - return partition + def __init__(self, type, subtype): + _PartitionId.__init__(self, type=type, subtype=subtype) -def _get_and_check_partition(args): - partition = None - - partition = _get_partition(args) - - if not partition: - raise RuntimeError("Unable to find specified partition.") - - return partition +PARTITION_BOOT_DEFAULT = _PartitionId() -def write_partition(args): - erase_partition(args) +class ParttoolTarget(): - partition = _get_and_check_partition(args) + def __init__(self, port=None, baud=None, partition_table_offset=PARTITION_TABLE_OFFSET, partition_table_file=None, + esptool_args=[], esptool_write_args=[], esptool_read_args=[], esptool_erase_args=[]): + self.port = port + self.baud = baud - status("Checking input file size...") + gen.offset_part_table = partition_table_offset - with open(args.input, "rb") as input_file: - content_len = len(input_file.read()) + def parse_esptool_args(esptool_args): + results = list() + for arg in esptool_args: + pattern = re.compile(r"(.+)=(.+)") + result = pattern.match(arg) + try: + key = result.group(1) + value = result.group(2) + results.extend(["--" + key, value]) + except AttributeError: + results.extend(["--" + arg]) + return results - if content_len != partition.size: - status("File size (0x{:x}) does not match partition size (0x{:x})".format(content_len, partition.size)) + self.esptool_args = parse_esptool_args(esptool_args) + self.esptool_write_args = parse_esptool_args(esptool_write_args) + self.esptool_read_args = parse_esptool_args(esptool_read_args) + self.esptool_erase_args = parse_esptool_args(esptool_erase_args) + + if partition_table_file: + try: + with open(partition_table_file, "rb") as f: + partition_table = gen.PartitionTable.from_binary(f.read()) + except (gen.InputError, IOError, TypeError): + with open(partition_table_file, "r") as f: + f.seek(0) + partition_table = gen.PartitionTable.from_csv(f.read()) else: - status("File size matches partition size (0x{:x})".format(partition.size)) - - _invoke_esptool(["write_flash", str(partition.offset), args.input], args) - - status("Written contents of file '{}' to device at offset 0x{:x}".format(args.input, partition.offset)) - - -def read_partition(args): - partition = _get_and_check_partition(args) - _invoke_esptool(["read_flash", str(partition.offset), str(partition.size), args.output], args) - status("Read partition contents from device at offset 0x{:x} to file '{}'".format(partition.offset, args.output)) - - -def erase_partition(args): - partition = _get_and_check_partition(args) - _invoke_esptool(["erase_region", str(partition.offset), str(partition.size)], args) - status("Erased partition at offset 0x{:x} on device".format(partition.offset)) - - -def get_partition_info(args): - partition = None - - if args.table: - partition_table = _get_partition_table(args) - - if args.table.endswith(".csv"): - partition_table = partition_table.to_csv() - else: - partition_table = partition_table.to_binary() - - with open(args.table, "wb") as table_file: - table_file.write(partition_table) - status("Partition table written to " + table_file.name) - else: - partition = _get_partition(args) - - if partition: - info_dict = { - "offset": '0x{:x}'.format(partition.offset), - "size": '0x{:x}'.format(partition.size) - } - - infos = [] + temp_file = tempfile.NamedTemporaryFile(delete=False) + temp_file.close() try: - for info in args.info: - infos += [info_dict[info]] - except KeyError: - raise RuntimeError("Request for unknown partition info {}".format(info)) + self._call_esptool(["read_flash", str(partition_table_offset), str(gen.MAX_PARTITION_LENGTH), temp_file.name]) + with open(temp_file.name, "rb") as f: + partition_table = gen.PartitionTable.from_binary(f.read()) + finally: + os.unlink(temp_file.name) - status("Requested partition information [{}]:".format(", ".join(args.info))) - print(" ".join(infos)) - else: - status("Partition not found") + self.partition_table = partition_table + + def _call_esptool(self, args, out=None): + esptool_args = [sys.executable, ESPTOOL_PY] + self.esptool_args + + if self.port: + esptool_args += ["--port", self.port] + + if self.baud: + esptool_args += ["--baud", str(self.baud)] + + esptool_args += args + + with open(os.devnull, "w") as null_file: + subprocess.check_call(esptool_args, stdout=null_file, stderr=null_file) + + def get_partition_info(self, partition_id): + partition = None + + if partition_id.name: + partition = self.partition_table.find_by_name(partition_id.name) + elif partition_id.type and partition_id.subtype: + partition = self.partition_table.find_by_type(partition_id.type, partition_id.subtype) + else: # default boot partition + search = ["factory"] + ["ota_{}".format(d) for d in range(16)] + for subtype in search: + partition = self.partition_table.find_by_type("app", subtype) + if partition: + break + + if not partition: + raise Exception("Partition does not exist") + + return partition + + def erase_partition(self, partition_id): + partition = self.get_partition_info(partition_id) + self._call_esptool(["erase_region", str(partition.offset), str(partition.size)] + self.esptool_erase_args) + + def read_partition(self, partition_id, output): + partition = self.get_partition_info(partition_id) + self._call_esptool(["read_flash", str(partition.offset), str(partition.size), output] + self.esptool_read_args) + + def write_partition(self, partition_id, input): + self.erase_partition(partition_id) + + partition = self.get_partition_info(partition_id) + + with open(input, "rb") as input_file: + content_len = len(input_file.read()) + + if content_len > partition.size: + raise Exception("Input file size exceeds partition size") + + self._call_esptool(["write_flash", str(partition.offset), input] + self.esptool_write_args) -def generate_blank_partition_file(args): - output = None - stdout_binary = None +def _write_partition(target, partition_id, input): + target.write_partition(partition_id, input) + partition = target.get_partition_info(partition_id) + status("Written contents of file '{}' at offset 0x{:x}".format(input, partition.offset)) - partition = _get_and_check_partition(args) - output = b"\xFF" * partition.size + +def _read_partition(target, partition_id, output): + target.read_partition(partition_id, output) + partition = target.get_partition_info(partition_id) + status("Read partition '{}' contents from device at offset 0x{:x} to file '{}'" + .format(partition.name, partition.offset, output)) + + +def _erase_partition(target, partition_id): + target.erase_partition(partition_id) + partition = target.get_partition_info(partition_id) + status("Erased partition '{}' at offset 0x{:x}".format(partition.name, partition.offset)) + + +def _get_partition_info(target, partition_id, info): + try: + partition = target.get_partition_info(partition_id) + except Exception: + return + + info_dict = { + "offset": '0x{:x}'.format(partition.offset), + "size": '0x{:x}'.format(partition.size) + } + + infos = [] try: - stdout_binary = sys.stdout.buffer # Python 3 - except AttributeError: - stdout_binary = sys.stdout + for i in info: + infos += [info_dict[i]] + except KeyError: + raise RuntimeError("Request for unknown partition info {}".format(i)) - with stdout_binary if args.output == "" else open(args.output, 'wb') as f: - f.write(output) - status("Blank partition file '{}' generated".format(args.output)) + print(" ".join(infos)) def main(): @@ -219,49 +215,51 @@ def main(): parser = argparse.ArgumentParser("ESP-IDF Partitions Tool") parser.add_argument("--quiet", "-q", help="suppress stderr messages", action="store_true") + parser.add_argument("--esptool-args", help="additional main arguments for esptool", nargs="+") + parser.add_argument("--esptool-write-args", help="additional subcommand arguments when writing to flash", nargs="+") + parser.add_argument("--esptool-read-args", help="additional subcommand arguments when reading flash", nargs="+") + parser.add_argument("--esptool-erase-args", help="additional subcommand arguments when erasing regions of flash", nargs="+") - # There are two possible sources for the partition table: a device attached to the host - # or a partition table CSV/binary file. These sources are mutually exclusive. - partition_table_info_source_args = parser.add_mutually_exclusive_group() + # By default the device attached to the specified port is queried for the partition table. If a partition table file + # is specified, that is used instead. + parser.add_argument("--port", "-p", help="port where the target device of the command is connected to; the partition table is sourced from this device \ + when the partition table file is not defined") + parser.add_argument("--baud", "-b", help="baudrate to use", type=int) - partition_table_info_source_args.add_argument("--port", "-p", help="port where the device to read the partition table from is attached", default="") - partition_table_info_source_args.add_argument("--partition-table-file", "-f", help="file (CSV/binary) to read the partition table from") + parser.add_argument("--partition-table-offset", "-o", help="offset to read the partition table from", type=str) + parser.add_argument("--partition-table-file", "-f", help="file (CSV/binary) to read the partition table from; \ + overrides device attached to specified port as the partition table source when defined") - parser.add_argument("--partition-table-offset", "-o", help="offset to read the partition table from", default="0x8000") + partition_selection_parser = argparse.ArgumentParser(add_help=False) # Specify what partition to perform the operation on. This can either be specified using the # partition name or the first partition that matches the specified type/subtype - partition_selection_args = parser.add_mutually_exclusive_group() + partition_selection_args = partition_selection_parser.add_mutually_exclusive_group() partition_selection_args.add_argument("--partition-name", "-n", help="name of the partition") partition_selection_args.add_argument("--partition-type", "-t", help="type of the partition") partition_selection_args.add_argument('--partition-boot-default', "-d", help='select the default boot partition \ using the same fallback logic as the IDF bootloader', action="store_true") - parser.add_argument("--partition-subtype", "-s", help="subtype of the partition") + partition_selection_parser.add_argument("--partition-subtype", "-s", help="subtype of the partition") subparsers = parser.add_subparsers(dest="operation", help="run parttool -h for additional help") # Specify the supported operations - read_part_subparser = subparsers.add_parser("read_partition", help="read partition from device and dump contents into a file") + read_part_subparser = subparsers.add_parser("read_partition", help="read partition from device and dump contents into a file", + parents=[partition_selection_parser]) read_part_subparser.add_argument("--output", help="file to dump the read partition contents to") - write_part_subparser = subparsers.add_parser("write_partition", help="write contents of a binary file to partition on device") + write_part_subparser = subparsers.add_parser("write_partition", help="write contents of a binary file to partition on device", + parents=[partition_selection_parser]) write_part_subparser.add_argument("--input", help="file whose contents are to be written to the partition offset") - subparsers.add_parser("erase_partition", help="erase the contents of a partition on the device") + subparsers.add_parser("erase_partition", help="erase the contents of a partition on the device", parents=[partition_selection_parser]) - print_partition_info_subparser = subparsers.add_parser("get_partition_info", help="get partition information") - print_partition_info_subparser_info_type = print_partition_info_subparser.add_mutually_exclusive_group() - print_partition_info_subparser_info_type.add_argument("--info", help="type of partition information to get", nargs="+") - print_partition_info_subparser_info_type.add_argument("--table", help="dump the partition table to a file") - - generate_blank_subparser = subparsers.add_parser("generate_blank_partition_file", help="generate a blank (all 0xFF) partition file of \ - the specified partition that can be flashed to the device") - generate_blank_subparser.add_argument("--output", help="blank partition file filename") + print_partition_info_subparser = subparsers.add_parser("get_partition_info", help="get partition information", parents=[partition_selection_parser]) + print_partition_info_subparser.add_argument("--info", help="type of partition information to get", nargs="+") args = parser.parse_args() - quiet = args.quiet # No operation specified, display help and exit @@ -270,17 +268,70 @@ def main(): parser.print_help() sys.exit(1) - # Else execute the operation - operation_func = globals()[args.operation] + # Prepare the partition to perform operation on + if args.partition_name: + partition_id = PartitionName(args.partition_name) + elif args.partition_type: + if not args.partition_subtype: + raise RuntimeError("--partition-subtype should be defined when --partition-type is defined") + partition_id = PartitionType(args.partition_type, args.partition_subtype) + elif args.partition_boot_default: + partition_id = PARTITION_BOOT_DEFAULT + else: + raise RuntimeError("Partition to operate on should be defined using --partition-name OR \ + partition-type,--partition-subtype OR partition-boot-default") + + # Prepare the device to perform operation on + target_args = {} + + if args.port: + target_args["port"] = args.port + + if args.baud: + target_args["baud"] = args.baud + + 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) + + if args.esptool_args: + target_args["esptool_args"] = args.esptool_args + + if args.esptool_write_args: + target_args["esptool_write_args"] = args.esptool_write_args + + if args.esptool_read_args: + target_args["esptool_read_args"] = args.esptool_read_args + + if args.esptool_erase_args: + target_args["esptool_erase_args"] = args.esptool_erase_args + + target = ParttoolTarget(**target_args) + + # Create the operation table and execute the operation + common_args = {'target':target, 'partition_id':partition_id} + parttool_ops = { + 'erase_partition':(_erase_partition, []), + 'read_partition':(_read_partition, ["output"]), + 'write_partition':(_write_partition, ["input"]), + 'get_partition_info':(_get_partition_info, ["info"]) + } + + (op, op_args) = parttool_ops[args.operation] + + for op_arg in op_args: + common_args.update({op_arg:vars(args)[op_arg]}) if quiet: # If exceptions occur, suppress and exit quietly try: - operation_func(args) + op(**common_args) except Exception: sys.exit(2) else: - operation_func(args) + op(**common_args) if __name__ == '__main__': diff --git a/components/partition_table/project_include.cmake b/components/partition_table/project_include.cmake index d8e31c7d1d..9f0dc93854 100644 --- a/components/partition_table/project_include.cmake +++ b/components/partition_table/project_include.cmake @@ -39,7 +39,7 @@ function(partition_table_get_partition_info result get_part_info_args part_info) ${idf_path}/components/partition_table/parttool.py -q --partition-table-offset ${PARTITION_TABLE_OFFSET} --partition-table-file ${PARTITION_CSV_PATH} - ${get_part_info_args} get_partition_info --info ${part_info} + get_partition_info ${get_part_info_args} --info ${part_info} OUTPUT_VARIABLE info RESULT_VARIABLE exit_code OUTPUT_STRIP_TRAILING_WHITESPACE) diff --git a/components/partition_table/test/CMakeLists.txt b/components/partition_table/test/CMakeLists.txt index 66a8c82315..b531a14504 100644 --- a/components/partition_table/test/CMakeLists.txt +++ b/components/partition_table/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity test_utils) - -register_component() \ No newline at end of file +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity test_utils) \ No newline at end of file diff --git a/components/partition_table/test_gen_esp32part_host/gen_esp32part_tests.py b/components/partition_table/test_gen_esp32part_host/gen_esp32part_tests.py index 989d4c4758..17f16c5b46 100755 --- a/components/partition_table/test_gen_esp32part_host/gen_esp32part_tests.py +++ b/components/partition_table/test_gen_esp32part_host/gen_esp32part_tests.py @@ -403,13 +403,13 @@ app,app, factory, 32K, 1M class PartToolTests(Py23TestCase): - def _run_parttool(self, csvcontents, args, info): + def _run_parttool(self, csvcontents, args): csvpath = tempfile.mktemp() with open(csvpath, "w") as f: f.write(csvcontents) try: - output = subprocess.check_output([sys.executable, "../parttool.py"] + args.split(" ") - + ["--partition-table-file", csvpath, "get_partition_info", "--info", info], + output = subprocess.check_output([sys.executable, "../parttool.py", "-q", "--partition-table-file", + csvpath, "get_partition_info"] + args, stderr=subprocess.STDOUT) self.assertNotIn(b"WARNING", output) m = re.search(b"0x[0-9a-fA-F]+", output) @@ -425,17 +425,17 @@ phy_init, data, phy, 0xf000, 0x1000 factory, app, factory, 0x10000, 1M """ - def rpt(args, info): - return self._run_parttool(csv, args, info) + def rpt(args): + return self._run_parttool(csv, args) self.assertEqual( - rpt("--partition-type=data --partition-subtype=nvs -q", "offset"), b"0x9000") + rpt(["--partition-type", "data", "--partition-subtype", "nvs", "--info", "offset"]), b"0x9000") self.assertEqual( - rpt("--partition-type=data --partition-subtype=nvs -q", "size"), b"0x4000") + rpt(["--partition-type", "data", "--partition-subtype", "nvs", "--info", "size"]), b"0x4000") self.assertEqual( - rpt("--partition-name=otadata -q", "offset"), b"0xd000") + rpt(["--partition-name", "otadata", "--info", "offset"]), b"0xd000") self.assertEqual( - rpt("--partition-boot-default -q", "offset"), b"0x10000") + rpt(["--partition-boot-default", "--info", "offset"]), b"0x10000") def test_fallback(self): csv = """ @@ -446,16 +446,16 @@ ota_0, app, ota_0, 0x30000, 1M ota_1, app, ota_1, , 1M """ - def rpt(args, info): - return self._run_parttool(csv, args, info) + def rpt(args): + return self._run_parttool(csv, args) self.assertEqual( - rpt("--partition-type=app --partition-subtype=ota_1 -q", "offset"), b"0x130000") + rpt(["--partition-type", "app", "--partition-subtype", "ota_1", "--info", "offset"]), b"0x130000") self.assertEqual( - rpt("--partition-boot-default -q", "offset"), b"0x30000") # ota_0 + rpt(["--partition-boot-default", "--info", "offset"]), b"0x30000") # ota_0 csv_mod = csv.replace("ota_0", "ota_2") self.assertEqual( - self._run_parttool(csv_mod, "--partition-boot-default -q", "offset"), + self._run_parttool(csv_mod, ["--partition-boot-default", "--info", "offset"]), b"0x130000") # now default is ota_1 diff --git a/components/protobuf-c/CMakeLists.txt b/components/protobuf-c/CMakeLists.txt index 1c9a3ffc3f..1801093194 100644 --- a/components/protobuf-c/CMakeLists.txt +++ b/components/protobuf-c/CMakeLists.txt @@ -1,4 +1,2 @@ -set(COMPONENT_ADD_INCLUDEDIRS protobuf-c) -set(COMPONENT_SRCS "protobuf-c/protobuf-c/protobuf-c.c") - -register_component() +idf_component_register(SRCS "protobuf-c/protobuf-c/protobuf-c.c" + INCLUDE_DIRS protobuf-c) diff --git a/components/protocomm/CMakeLists.txt b/components/protocomm/CMakeLists.txt index 79e824ceb6..b58698020e 100644 --- a/components/protocomm/CMakeLists.txt +++ b/components/protocomm/CMakeLists.txt @@ -1,26 +1,34 @@ -set(COMPONENT_ADD_INCLUDEDIRS include/common - include/security - include/transports) -set(COMPONENT_PRIV_INCLUDEDIRS proto-c src/common src/simple_ble) -set(COMPONENT_SRCS "src/common/protocomm.c" - "src/security/security0.c" - "src/security/security1.c" - "proto-c/constants.pb-c.c" - "proto-c/sec0.pb-c.c" - "proto-c/sec1.pb-c.c" - "proto-c/session.pb-c.c" - "src/transports/protocomm_console.c" - "src/transports/protocomm_httpd.c") - -set(COMPONENT_REQUIRES protobuf-c bt) -set(COMPONENT_PRIV_REQUIRES mbedtls console esp_http_server) +set(include_dirs include/common + include/security + include/transports) +set(priv_include_dirs proto-c src/common) +set(srcs + "src/common/protocomm.c" + "src/security/security0.c" + "src/security/security1.c" + "proto-c/constants.pb-c.c" + "proto-c/sec0.pb-c.c" + "proto-c/sec1.pb-c.c" + "proto-c/session.pb-c.c" + "src/transports/protocomm_console.c" + "src/transports/protocomm_httpd.c") if(CONFIG_BT_ENABLED) if(CONFIG_BT_BLUEDROID_ENABLED) - list(APPEND COMPONENT_SRCS + list(APPEND srcs "src/simple_ble/simple_ble.c" "src/transports/protocomm_ble.c") + list(APPEND priv_include_dirs + src/simple_ble) + endif() + if(CONFIG_BT_NIMBLE_ENABLED) + list(APPEND srcs + "src/transports/protocomm_nimble.c") endif() endif() -register_component() +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS "${include_dirs}" + PRIV_INCLUDE_DIRS "${priv_include_dirs}" + PRIV_REQUIRES protobuf-c mbedtls console esp_http_server + REQUIRES bt) diff --git a/components/protocomm/component.mk b/components/protocomm/component.mk index 918fed4ded..fbc0232f08 100644 --- a/components/protocomm/component.mk +++ b/components/protocomm/component.mk @@ -2,6 +2,10 @@ COMPONENT_ADD_INCLUDEDIRS := include/common include/security include/transports COMPONENT_PRIV_INCLUDEDIRS := proto-c src/common src/simple_ble COMPONENT_SRCDIRS := src/common src/security proto-c src/simple_ble src/transports -ifneq ($(filter y, $(CONFIG_BT_ENABLED) $(CONFIG_BT_BLUEDROID_ENABLED)),y y) - COMPONENT_OBJEXCLUDE := src/simple_ble/simple_ble.o src/transports/protocomm_ble.o +ifndef CONFIG_BT_BLUEDROID_ENABLED + COMPONENT_OBJEXCLUDE += src/simple_ble/simple_ble.o src/transports/protocomm_ble.o +endif + +ifndef CONFIG_BT_NIMBLE_ENABLED + COMPONENT_OBJEXCLUDE += src/transports/protocomm_nimble.o endif diff --git a/components/protocomm/include/transports/protocomm_ble.h b/components/protocomm/include/transports/protocomm_ble.h index 92714444f0..b30d5707b6 100644 --- a/components/protocomm/include/transports/protocomm_ble.h +++ b/components/protocomm/include/transports/protocomm_ble.h @@ -14,8 +14,6 @@ #pragma once -#include - #include #ifdef __cplusplus @@ -26,7 +24,8 @@ extern "C" { * BLE device name cannot be larger than this value * 31 bytes (max scan response size) - 1 byte (length) - 1 byte (type) = 29 bytes */ -#define MAX_BLE_DEVNAME_LEN (ESP_BLE_SCAN_RSP_DATA_LEN_MAX - 2) +#define MAX_BLE_DEVNAME_LEN 29 +#define BLE_UUID128_VAL_LENGTH 16 /** * @brief This structure maps handler required by protocomm layer to @@ -49,7 +48,7 @@ typedef struct name_uuid { /** * @brief Config parameters for protocomm BLE service */ -typedef struct { +typedef struct protocomm_ble_config { /** * BLE device name being broadcast at the time of provisioning */ @@ -58,7 +57,7 @@ typedef struct { /** * 128 bit UUID of the provisioning service */ - uint8_t service_uuid[ESP_UUID_LEN_128]; + uint8_t service_uuid[BLE_UUID128_VAL_LENGTH]; /** * Number of entries in the Name-UUID lookup table diff --git a/components/protocomm/proto/CMakeLists.txt b/components/protocomm/proto/CMakeLists.txt new file mode 100644 index 0000000000..8d3e57d063 --- /dev/null +++ b/components/protocomm/proto/CMakeLists.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.5) + +set(PROTO_COMPILER "protoc") +set(PROTO_C_COMPILER "protoc-c") +set(C_OUT_PATH "${CMAKE_CURRENT_LIST_DIR}/../proto-c") +set(PY_OUT_PATH "${CMAKE_CURRENT_LIST_DIR}/../python") + +set(PROTO_SRCS "constants.proto" + "sec0.proto" + "sec1.proto" + "session.proto") + +add_custom_target(c_proto + COMMAND ${PROTO_C_COMPILER} --c_out=${C_OUT_PATH} -I . ${PROTO_SRCS} + VERBATIM + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + ) + +add_custom_target(python_proto + COMMAND ${PROTO_COMPILER} --python_out=${PY_OUT_PATH} -I . ${PROTO_SRCS} + VERBATIM + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + ) + +add_custom_target(proto ALL + DEPENDS c_proto python_proto + VERBATIM + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + ) diff --git a/components/protocomm/proto/README.md b/components/protocomm/proto/README.md index 655e193a38..b77e3150fd 100644 --- a/components/protocomm/proto/README.md +++ b/components/protocomm/proto/README.md @@ -8,6 +8,22 @@ Protocomm uses Google Protobuf for language, transport and architecture agnostic Note : These proto files are not automatically compiled during the build process. -Run "make" (Optional) to generate the respective C and Python files. The generated C files are used by protocomm itself to create, delete and manipulate transaction packets. The generated Python files can be used by python based applications for implementing client side interface to protocomm layer. +# Compilation -Compilation requires protoc (Protobuf Compiler) and protoc-c (Protobuf C Compiler) installed. Since the generated files are to remain the same, as long as the proto files are not modified, therefore the generated files are already available under "protocomm/proto-c" and "protocomm/python" directories, and thus running make (and installing the Protobuf compilers) is optional. +Compilation requires protoc (Protobuf Compiler) and protoc-c (Protobuf C Compiler) installed. Since the generated files are to remain the same, as long as the proto files are not modified, therefore the generated files are already available under `components/protocomm/proto-c` and `components/protocomm/python` directories, and thus running cmake / make (and installing the Protobuf compilers) is optional. + +If using `cmake` follow the below steps. If using `make`, jump to Step 2 directly. + +## Step 1 (Only for cmake) + +When using cmake, first create a build directory and call cmake from inside: + +``` +mkdir build +cd build +cmake .. +``` + +## Step 2 + +Simply run `make` to generate the respective C and Python files. The newly created files will overwrite those under `components/protocomm/proto-c` and `components/protocomm/python` diff --git a/components/protocomm/src/transports/protocomm_ble.c b/components/protocomm/src/transports/protocomm_ble.c index 6bd25406d1..3042c7da28 100644 --- a/components/protocomm/src/transports/protocomm_ble.c +++ b/components/protocomm/src/transports/protocomm_ble.c @@ -140,40 +140,56 @@ static void transport_simple_ble_read(esp_gatts_cb_event_t event, esp_gatt_if_t static esp_err_t prepare_write_event_env(esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { - ESP_LOGD(TAG, "prepare write, handle = %d, value len = %d", - param->write.handle, param->write.len); + ESP_LOGD(TAG, "prepare write, handle = %d, value len = %d, offset = %d", + param->write.handle, param->write.len, param->write.offset); esp_gatt_status_t status = ESP_GATT_OK; - if (prepare_write_env.prepare_buf == NULL) { - prepare_write_env.prepare_buf = (uint8_t *) malloc(PREPARE_BUF_MAX_SIZE * sizeof(uint8_t)); - if (prepare_write_env.prepare_buf == NULL) { - ESP_LOGE(TAG, "%s , failed tp allocate preparebuf", __func__); - status = ESP_GATT_NO_RESOURCES; - } - /* prepare_write_env.prepare_len = 0; */ + + /* Ensure that write data is not larger than max attribute length */ + 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; } 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; + /* If prepare buffer is not allocated, then allocate it */ + if (prepare_write_env.prepare_buf == NULL) { + prepare_write_env.prepare_len = 0; + prepare_write_env.prepare_buf = (uint8_t *) malloc(PREPARE_BUF_MAX_SIZE * sizeof(uint8_t)); + if (prepare_write_env.prepare_buf == NULL) { + ESP_LOGE(TAG, "%s , failed to allocate prepare buf", __func__); + status = ESP_GATT_NO_RESOURCES; + } } } - memcpy(prepare_write_env.prepare_buf + param->write.offset, - param->write.value, - param->write.len); - prepare_write_env.prepare_len += param->write.len; - prepare_write_env.handle = param->write.handle; + + /* If prepare buffer is allocated copy incoming data into it */ + if (status == ESP_GATT_OK) { + memcpy(prepare_write_env.prepare_buf + param->write.offset, + param->write.value, + param->write.len); + prepare_write_env.prepare_len += param->write.len; + prepare_write_env.handle = param->write.handle; + } + + /* Send write response if needed */ if (param->write.need_rsp) { - esp_gatt_rsp_t gatt_rsp = {0}; - 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; - if (gatt_rsp.attr_value.len && param->write.value) { - memcpy(gatt_rsp.attr_value.value, param->write.value, param->write.len); + esp_err_t response_err; + /* If data was successfully appended to prepare buffer + * only then have it reflected in the response */ + if (status == ESP_GATT_OK) { + esp_gatt_rsp_t gatt_rsp = {0}; + 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; + if (gatt_rsp.attr_value.len && param->write.value) { + memcpy(gatt_rsp.attr_value.value, param->write.value, param->write.len); + } + response_err = esp_ble_gatts_send_response(gatts_if, + param->write.conn_id, param->write.trans_id, status, &gatt_rsp); + } else { + response_err = esp_ble_gatts_send_response(gatts_if, + param->write.conn_id, param->write.trans_id, status, NULL); } - 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(TAG, "Send response error in prep write"); } @@ -195,7 +211,7 @@ static void transport_simple_ble_write(esp_gatts_cb_event_t event, esp_gatt_if_t ssize_t outlen = 0; esp_err_t ret; - ESP_LOGD(TAG, "Inside write with session - %d on attr handle - %d \nLen -%d IS Prep - %d", + ESP_LOGD(TAG, "Inside write with session - %d on attr handle = %d \nlen = %d, is_prep = %d", param->write.conn_id, param->write.handle, param->write.len, param->write.is_prep); if (param->write.is_prep) { diff --git a/components/protocomm/src/transports/protocomm_nimble.c b/components/protocomm/src/transports/protocomm_nimble.c new file mode 100644 index 0000000000..cbe7bdb8d8 --- /dev/null +++ b/components/protocomm/src/transports/protocomm_nimble.c @@ -0,0 +1,909 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include "nvs_flash.h" + +#include +#include +#include "protocomm_priv.h" + +/* NimBLE */ +#include "esp_nimble_hci.h" +#include "nimble/nimble_port.h" +#include "nimble/nimble_port_freertos.h" +#include "host/ble_hs.h" +#include "host/ble_uuid.h" +#include "host/util/util.h" +#include "services/gap/ble_svc_gap.h" + +static const char *TAG = "protocomm_nimble"; + +int ble_uuid_flat(const ble_uuid_t *, void *); +static uint8_t ble_uuid_base[BLE_UUID128_VAL_LENGTH]; +static int num_chr_dsc; + +/* Standard 16 bit UUID for characteristic User Description*/ +#define BLE_GATT_UUID_CHAR_DSC 0x2901 + +/******************************************************** +* Maintain database for Attribute specific data * +********************************************************/ +struct data_mbuf { + SLIST_ENTRY(data_mbuf) node; + uint8_t *outbuf; + ssize_t outlen; + uint16_t attr_handle; +}; + +static SLIST_HEAD(data_mbuf_head, data_mbuf) data_mbuf_list = + SLIST_HEAD_INITIALIZER(data_mbuf_list); + +static struct data_mbuf *find_attr_with_handle(uint16_t attr_handle) +{ + struct data_mbuf *cur; + SLIST_FOREACH(cur, &data_mbuf_list, node) { + if (cur->attr_handle == attr_handle) { + return cur; + } + } + return NULL; +} +/************************************************************** +* Initialize GAP, protocomm parameters * +**************************************************************/ +static int simple_ble_gap_event(struct ble_gap_event *event, void *arg); +static uint8_t own_addr_type; +void ble_store_config_init(void); + +typedef struct _protocomm_ble { + protocomm_t *pc_ble; + protocomm_ble_name_uuid_t *g_nu_lookup; + ssize_t g_nu_lookup_count; + uint16_t gatt_mtu; +} _protocomm_ble_internal_t; + +static _protocomm_ble_internal_t *protoble_internal; +static struct ble_gap_adv_params adv_params; +static char *protocomm_ble_device_name; +static struct ble_hs_adv_fields adv_data, resp_data; + +/********************************************************************** +* Maintain database of uuid_name addresses to free memory afterwards * +**********************************************************************/ +struct uuid128_name_buf { + SLIST_ENTRY(uuid128_name_buf) link; + ble_uuid128_t *uuid128_name_table; +}; + +static SLIST_HEAD(uuid128_name_buf_head, uuid128_name_buf) uuid128_name_list = + SLIST_HEAD_INITIALIZER(uuid128_name_list); + +/********************************************************************** +* Initialize simple BLE parameters, advertisement, scan response etc * +**********************************************************************/ +static int +gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg); +static int +gatt_svr_dsc_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg); + +void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg); + +typedef void (simple_ble_cb_t)(struct ble_gap_event *event, void *arg); +static void transport_simple_ble_connect(struct ble_gap_event *event, void *arg); +static void transport_simple_ble_disconnect(struct ble_gap_event *event, void *arg); +static void transport_simple_ble_set_mtu(struct ble_gap_event *event, void *arg); + +typedef struct { + /** Name to be displayed to devices scanning for ESP32 */ + const char *device_name; + /** Advertising data content, according to "Supplement to the Bluetooth Core Specification" */ + struct ble_hs_adv_fields adv_data; + /** Parameters to configure the nature of advertising */ + struct ble_gap_adv_params adv_params; + /** Descriptor table which consists the configuration required by services and characteristics */ + struct ble_gatt_svc_def *gatt_db; + /** Client disconnect callback */ + simple_ble_cb_t *disconnect_fn; + /** Client connect callback */ + simple_ble_cb_t *connect_fn; + /** MTU set callback */ + simple_ble_cb_t *set_mtu_fn; +} simple_ble_cfg_t; + +static simple_ble_cfg_t *ble_cfg_p; + +/************************************************************ +* Functions to set and get attr value based on attr Handle * +************************************************************/ +static int simple_ble_gatts_set_attr_value(uint16_t attr_handle, ssize_t outlen, + uint8_t *outbuf) +{ + struct data_mbuf *attr_mbuf = find_attr_with_handle(attr_handle); + if (!attr_mbuf) { + attr_mbuf = calloc(1, sizeof(struct data_mbuf)); + if (!attr_mbuf) { + ESP_LOGE(TAG, "Failed to allocate memory for storing outbuf and outlen"); + return ESP_ERR_NO_MEM; + } + SLIST_INSERT_HEAD(&data_mbuf_list, attr_mbuf, node); + attr_mbuf->attr_handle = attr_handle; + } else { + free(attr_mbuf->outbuf); + } + attr_mbuf->outbuf = outbuf; + attr_mbuf->outlen = outlen; + return ESP_OK; +} + +static int simple_ble_gatts_get_attr_value(uint16_t attr_handle, ssize_t + *outlen, uint8_t **outbuf) +{ + struct data_mbuf *attr_mbuf = find_attr_with_handle(attr_handle); + if (!attr_mbuf) { + ESP_LOGE(TAG, "Outbuf with handle %d not found", attr_handle); + return ESP_ERR_NOT_FOUND; + } + *outbuf = attr_mbuf->outbuf; + *outlen = attr_mbuf->outlen; + return ESP_OK; +} + +/*****************************************************************************************/ +/* SIMPLE BLE INTEGRATION */ +/*****************************************************************************************/ +static void +simple_ble_advertise(void) +{ + int rc; + + adv_data.flags = (BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP); + adv_data.num_uuids128 = 1; + adv_data.uuids128_is_complete = 1; + + rc = ble_gap_adv_set_fields(&adv_data); + if (rc != 0) { + ESP_LOGE(TAG, "Error setting advertisement data; rc = %d", rc); + return; + } + + rc = ble_gap_adv_rsp_set_fields((const struct ble_hs_adv_fields *) &resp_data); + if (rc != 0) { + ESP_LOGE(TAG, "Error in setting scan response; rc = %d", rc); + return; + } + + adv_params.conn_mode = BLE_GAP_CONN_MODE_UND; + adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN; + adv_params.itvl_min = 0x100; + adv_params.itvl_max = 0x100; + + rc = ble_gap_adv_start(own_addr_type, NULL, BLE_HS_FOREVER, + &adv_params, simple_ble_gap_event, NULL); + if (rc != 0) { + /* If BLE Host is disabled, it probably means device is already + * provisioned in previous session. Avoid error prints for this case.*/ + if (rc == BLE_HS_EDISABLED) { + ESP_LOGD(TAG, "BLE Host is disabled !!"); + } else { + ESP_LOGE(TAG, "Error enabling advertisement; rc = %d", rc); + } + return; + } + /* Take note of free heap space */ + ESP_LOGD(TAG, "Minimum free heap size = %d, free Heap size = %d", + esp_get_minimum_free_heap_size(), esp_get_free_heap_size()); +} + +static int +simple_ble_gap_event(struct ble_gap_event *event, void *arg) +{ + struct ble_gap_conn_desc desc; + int rc; + + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + /* A new connection was established or a connection attempt failed. */ + if (event->connect.status == 0) { + transport_simple_ble_connect(event, arg); + rc = ble_gap_conn_find(event->connect.conn_handle, &desc); + if (rc != 0) { + ESP_LOGE(TAG, "No open connection with the specified handle"); + return rc; + } + } else { + /* Connection failed; resume advertising. */ + simple_ble_advertise(); + } + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + ESP_LOGD(TAG, "disconnect; reason=%d ", event->disconnect.reason); + transport_simple_ble_disconnect(event, arg); + + /* Connection terminated; resume advertising. */ + simple_ble_advertise(); + return 0; + + case BLE_GAP_EVENT_ADV_COMPLETE: + simple_ble_advertise(); + return 0; + + case BLE_GAP_EVENT_MTU: + ESP_LOGI(TAG, "mtu update event; conn_handle=%d cid=%d mtu=%d\n", + event->mtu.conn_handle, + event->mtu.channel_id, + event->mtu.value); + transport_simple_ble_set_mtu(event, arg); + return 0; + } + return 0; +} + +/* Gets `g_nu_lookup name handler` from 128 bit UUID */ +static const char *uuid128_to_handler(uint8_t *uuid) +{ + /* Use it to convert 128 bit UUID to 16 bit UUID.*/ + uint8_t *uuid16 = uuid + 12; + for (int i = 0; i < protoble_internal->g_nu_lookup_count; i++) { + if (protoble_internal->g_nu_lookup[i].uuid == *(uint16_t *)uuid16 ) { + ESP_LOGD(TAG, "UUID (0x%x) matched with proto-name = %s", *uuid16, protoble_internal->g_nu_lookup[i].name); + return protoble_internal->g_nu_lookup[i].name; + } else { + ESP_LOGD(TAG, "UUID did not match... %x", *uuid16); + } + } + return NULL; +} + +/* Callback to handle GATT characteristic descriptor read */ +static int +gatt_svr_dsc_access(uint16_t conn_handle, uint16_t attr_handle, struct + ble_gatt_access_ctxt *ctxt, void *arg) +{ + if (ctxt->op != BLE_GATT_ACCESS_OP_READ_DSC) { + ESP_LOGE(TAG, "Invalid operation on Read-only Descriptor"); + return BLE_ATT_ERR_UNLIKELY; + } + + int rc; + char *temp_outbuf = strdup(ctxt->dsc->arg); + if (temp_outbuf == NULL) { + ESP_LOGE(TAG, "Error duplicating user description of characteristic"); + return ESP_ERR_NO_MEM; + } + + ssize_t temp_outlen = strlen(temp_outbuf); + rc = os_mbuf_append(ctxt->om, temp_outbuf, temp_outlen); + free(temp_outbuf); + return rc; +} + +/* Callback to handle GATT characteristic value Read & Write */ +static int +gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg) +{ + int rc; + esp_err_t ret; + char buf[BLE_UUID_STR_LEN]; + ssize_t temp_outlen = 0; + uint8_t *temp_outbuf = NULL; + uint8_t *uuid = NULL; + + switch (ctxt->op) { + case BLE_GATT_ACCESS_OP_READ_CHR: + ESP_LOGD(TAG, "Read attempeted for Characterstic UUID = %s, attr_handle = %d", + ble_uuid_to_str(ctxt->chr->uuid, buf), attr_handle); + + rc = simple_ble_gatts_get_attr_value(attr_handle, &temp_outlen, + &temp_outbuf); + if (rc != 0) { + ESP_LOGE(TAG, "Failed to read characteristic with attr_handle = %d", attr_handle); + return rc; + } + + rc = os_mbuf_append(ctxt->om, temp_outbuf, temp_outlen); + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + + case BLE_GATT_ACCESS_OP_WRITE_CHR: + uuid = (uint8_t *) calloc(BLE_UUID128_VAL_LENGTH, sizeof(uint8_t)); + if (!uuid) { + ESP_LOGE(TAG, "Error allocating memory for 128 bit UUID"); + return ESP_ERR_NO_MEM; + } + + rc = ble_uuid_flat(ctxt->chr->uuid, uuid); + if (rc != 0) { + free(uuid); + ESP_LOGE(TAG, "Error fetching Characteristic UUID128"); + return rc; + } + + ESP_LOGD(TAG, "Write attempt for uuid = %s, attr_handle = %d, om_len = %d", + ble_uuid_to_str(ctxt->chr->uuid, buf), attr_handle, ctxt->om->om_len); + ret = protocomm_req_handle(protoble_internal->pc_ble, + uuid128_to_handler(uuid), + conn_handle, + ctxt->om->om_data, + ctxt->om->om_len, + &temp_outbuf, &temp_outlen); + /* Release the 16 bytes allocated for uuid*/ + free(uuid); + if (ret == ESP_OK) { + + /* Save data address and length outbuf and outlen internally */ + rc = simple_ble_gatts_set_attr_value(attr_handle, temp_outlen, + temp_outbuf); + if (rc != 0) { + ESP_LOGE(TAG, "Failed to set outbuf for characteristic with attr_handle = %d", + attr_handle); + free(temp_outbuf); + } + + return rc; + } else { + ESP_LOGE(TAG, "Invalid content received, killing connection"); + return BLE_ATT_ERR_INVALID_PDU; + } + + default: + return BLE_ATT_ERR_UNLIKELY; + } +} + +void +gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg) +{ + char buf[BLE_UUID_STR_LEN]; + + switch (ctxt->op) { + case BLE_GATT_REGISTER_OP_SVC: + ESP_LOGD(TAG, "registering service %s with handle=%d TYPE =%d", + ble_uuid_to_str(ctxt->svc.svc_def->uuid, buf), + ctxt->svc.handle, ctxt->svc.svc_def->uuid->type); + break; + + case BLE_GATT_REGISTER_OP_CHR: + ESP_LOGD(TAG, "registering characteristic %s with " + "def_handle=%d val_handle=%d , TYPE = %d", + ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf), + ctxt->chr.def_handle, + ctxt->chr.val_handle, ctxt->chr.chr_def->uuid->type); + break; + + case BLE_GATT_REGISTER_OP_DSC: + ESP_LOGD(TAG, "registering descriptor %s with handle=%d", + ble_uuid_to_str(ctxt->dsc.dsc_def->uuid, buf), + ctxt->dsc.handle); + break; + + default: + assert(0); + break; + } +} + +int +gatt_svr_init(const simple_ble_cfg_t *config) +{ + int rc; + rc = ble_gatts_count_cfg(config->gatt_db); + if (rc != 0) { + return rc; + } + + rc = ble_gatts_add_svcs(config->gatt_db); + if (rc != 0) { + return rc; + } + + return 0; +} + +static void +simple_ble_on_reset(int reason) +{ + ESP_LOGE(TAG, "Resetting state; reason=%d\n", reason); +} + +static void +simple_ble_on_sync(void) +{ + int rc; + + rc = ble_hs_util_ensure_addr(0); + if (rc != 0) { + ESP_LOGE(TAG, "Error loading address"); + return; + } + + /* Figure out address to use while advertising (no privacy for now) */ + rc = ble_hs_id_infer_auto(0, &own_addr_type); + if (rc != 0) { + ESP_LOGE(TAG, "error determining address type; rc=%d\n", rc); + return; + } + + /* Begin advertising. */ + simple_ble_advertise(); +} + +void +nimble_host_task(void *param) +{ + /* This function will return only when nimble_port_stop() is executed */ + ESP_LOGI(TAG, "BLE Host Task Started"); + nimble_port_run(); + + nimble_port_freertos_deinit(); +} + +static int simple_ble_start(const simple_ble_cfg_t *cfg) +{ + ble_cfg_p = (void *)cfg; + int rc; + ESP_LOGD(TAG, "Free mem at start of simple_ble_init %d", esp_get_free_heap_size()); + + ESP_ERROR_CHECK(esp_nimble_hci_and_controller_init()); + nimble_port_init(); + + /* Initialize the NimBLE host configuration. */ + ble_hs_cfg.reset_cb = simple_ble_on_reset; + ble_hs_cfg.sync_cb = simple_ble_on_sync; + ble_hs_cfg.gatts_register_cb = gatt_svr_register_cb; + + rc = gatt_svr_init(cfg); + if (rc != 0) { + ESP_LOGE(TAG, "Error initializing GATT server"); + return rc; + } + + /* Set device name, configure response data to be sent while advertising */ + rc = ble_svc_gap_device_name_set(cfg->device_name); + if (rc != 0) { + ESP_LOGE(TAG, "Error setting device name"); + return rc; + } + + resp_data.name = (void *) ble_svc_gap_device_name(); + if (resp_data.name != NULL) { + resp_data.name_len = strlen(ble_svc_gap_device_name()); + resp_data.name_is_complete = 1; + } + + /* XXX Need to have template for store */ + ble_store_config_init(); + nimble_port_freertos_init(nimble_host_task); + + return 0; +} + +/* transport_simple BLE Fn */ +static void transport_simple_ble_disconnect(struct ble_gap_event *event, void *arg) +{ + esp_err_t ret; + ESP_LOGD(TAG, "Inside disconnect w/ session - %d", + event->disconnect.conn.conn_handle); + if (protoble_internal->pc_ble->sec && + protoble_internal->pc_ble->sec->close_transport_session) { + ret = + protoble_internal->pc_ble->sec->close_transport_session(protoble_internal->pc_ble->sec_inst, event->disconnect.conn.conn_handle); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "error closing the session after disconnect"); + } + } + protoble_internal->gatt_mtu = BLE_ATT_MTU_DFLT; +} + +static void transport_simple_ble_connect(struct ble_gap_event *event, void *arg) +{ + esp_err_t ret; + ESP_LOGD(TAG, "Inside BLE connect w/ conn_id - %d", event->connect.conn_handle); + if (protoble_internal->pc_ble->sec && + protoble_internal->pc_ble->sec->new_transport_session) { + ret = + protoble_internal->pc_ble->sec->new_transport_session(protoble_internal->pc_ble->sec_inst, event->connect.conn_handle); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "error creating the session"); + } + } +} + +static void transport_simple_ble_set_mtu(struct ble_gap_event *event, void *arg) +{ + protoble_internal->gatt_mtu = event->mtu.value; + return; +} + +static esp_err_t protocomm_ble_add_endpoint(const char *ep_name, + protocomm_req_handler_t req_handler, + void *priv_data) +{ + /* Endpoint UUID already added when protocomm_ble_start() was called */ + return ESP_OK; +} + +static esp_err_t protocomm_ble_remove_endpoint(const char *ep_name) +{ + /* Endpoint UUID will be removed when protocomm_ble_stop() is called */ + return ESP_OK; +} + +/* Function to add descriptor to characteristic. The value of descriptor is + * filled with corresponding protocomm endpoint names. Characteristic address, + * its serial no. and XXX 16 bit standard UUID for descriptor to be provided as + * input parameters. Returns 0 on success and returns ESP_ERR_NO_MEM on + * failure. */ +static int +ble_gatt_add_char_dsc(struct ble_gatt_chr_def *characteristics, int idx, uint16_t dsc_uuid) +{ + ble_uuid_t *uuid16 = BLE_UUID16_DECLARE(dsc_uuid); + + /* Allocate memory for 2 descriptors, the 2nd descriptor shall be all NULLs + * to indicate End of Descriptors. */ + (characteristics + idx)->descriptors = (struct ble_gatt_dsc_def *) calloc(2, + sizeof(struct ble_gatt_dsc_def)); + if ((characteristics + idx)->descriptors == NULL) { + ESP_LOGE(TAG, "Error while allocating memory for characteristic descriptor"); + return ESP_ERR_NO_MEM; + } + + (characteristics + idx)->descriptors[0].uuid = (ble_uuid_t *) calloc(1, + sizeof(ble_uuid16_t)); + if ((characteristics + idx)->descriptors[0].uuid == NULL) { + ESP_LOGE(TAG, "Error while allocating memory for characteristic descriptor"); + return ESP_ERR_NO_MEM; + } + memcpy((void *)(characteristics + idx)->descriptors[0].uuid, uuid16, + sizeof(ble_uuid16_t)); + (characteristics + idx)->descriptors[0].att_flags = BLE_ATT_F_READ; + (characteristics + idx)->descriptors[0].access_cb = gatt_svr_dsc_access; + (characteristics + idx)->descriptors[0].arg = (void *) + protoble_internal->g_nu_lookup[idx].name; + + return 0; +} + +/* Function to add characteristics to the service. For simplicity the + * flags and access callbacks are same for all the characteristics. The Fn + * requires pointer to characteristic of service and index of characteristic, + * depending upon the index no. individual characteristics can be handled in + * future. The fn also assumes that the required memory for all characteristics + * is already allocated while adding corresponding service. Returns 0 on + * success and returns ESP_ERR_NO_MEM on failure to add characteristic. */ +static int +ble_gatt_add_characteristics(struct ble_gatt_chr_def *characteristics, int idx) +{ + /* Prepare 128 bit UUID of characteristics using custom base 128 + * bit UUID and replacing byte 12 and 13 with corresponding protocom + * endpoint 16 bit UUID value. */ + ble_uuid128_t temp_uuid128_name = {0}; + temp_uuid128_name.u.type = BLE_UUID_TYPE_128; + memcpy(temp_uuid128_name.value, ble_uuid_base, BLE_UUID128_VAL_LENGTH); + memcpy(&temp_uuid128_name.value[12], &protoble_internal->g_nu_lookup[idx].uuid, 2); + + (characteristics + idx)->flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE; + (characteristics + idx)->access_cb = gatt_svr_chr_access; + + /* Out of 128 bit UUID, 16 bits from g_nu_lookup table. Currently + * g_nu_lookup table has 16 bit UUID, XXX this can be changed to 128 bit UUID + * in future. For time being continue using 16 bit UUID on top of base 128 + * bit service UUID */ + (characteristics + idx)->uuid = (ble_uuid_t *)calloc(1, + sizeof(ble_uuid128_t)); + if ((characteristics + idx)->uuid == NULL) { + ESP_LOGE(TAG, "Error allocating memory for characteristic UUID"); + return ESP_ERR_NO_MEM; + } + memcpy((void *)(characteristics + idx)->uuid, &temp_uuid128_name, + sizeof(ble_uuid128_t)); + + return 0; +} + +/* Function to add primary service. It also allocates memory for the + * characteristics. Returns 0 on success, returns ESP_ERR_NO_MEM on failure to + * add service. */ +static int +ble_gatt_add_primary_svcs(struct ble_gatt_svc_def *gatt_db_svcs, int char_count) +{ + /* Remember the count of characteristics here, as it will be used to free + * memory afterwards */ + num_chr_dsc = char_count; + gatt_db_svcs->type = BLE_GATT_SVC_TYPE_PRIMARY; + + /* Allocate (number of characteristics + 1) memory for characteristics, the + * addtional characteristic consist of all 0s indicating end of + * characteristics */ + gatt_db_svcs->characteristics = (struct ble_gatt_chr_def *) calloc((char_count + 1), + sizeof(struct ble_gatt_chr_def)); + if (gatt_db_svcs->characteristics == NULL) { + ESP_LOGE(TAG, "Memory allocation for GATT characteristics failed"); + return ESP_ERR_NO_MEM; + } + return 0; +} + +static int +populate_gatt_db(struct ble_gatt_svc_def **gatt_db_svcs, const protocomm_ble_config_t *config) +{ + /* Allocate memory for 2 services, 2nd to be all NULL indicating end of + * services */ + *gatt_db_svcs = (struct ble_gatt_svc_def *) calloc(2, sizeof(struct ble_gatt_svc_def)); + if (*gatt_db_svcs == NULL) { + ESP_LOGE(TAG, "Error allocating memory for GATT services"); + return ESP_ERR_NO_MEM; + } + + /* Allocate space for 1st service UUID as well, assume length = 128 bit */ + (*gatt_db_svcs)->uuid = (ble_uuid_t *) calloc(1, sizeof(ble_uuid128_t)); + if ((*gatt_db_svcs)->uuid == NULL) { + ESP_LOGE(TAG, "Error allocating memory for GATT service UUID"); + return ESP_ERR_NO_MEM; + } + + /* Prepare 128 bit UUID for primary service from config service UUID. */ + ble_uuid128_t uuid128 = {0}; + uuid128.u.type = BLE_UUID_TYPE_128; + memcpy(uuid128.value, config->service_uuid, BLE_UUID128_VAL_LENGTH); + memcpy((void *) (*gatt_db_svcs)->uuid, &uuid128, sizeof(ble_uuid128_t)); + + /* GATT: Add primary service. */ + int rc = ble_gatt_add_primary_svcs(*gatt_db_svcs, config->nu_lookup_count); + if (rc != 0) { + ESP_LOGE(TAG, "Error adding primary service !!!"); + return rc; + } + + for (int i = 0 ; i < config->nu_lookup_count; i++) { + + /* GATT: Add characteristics to the service at index no. i*/ + rc = ble_gatt_add_characteristics((void *) (*gatt_db_svcs)->characteristics, i); + if (rc != 0) { + ESP_LOGE(TAG, "Error adding GATT characteristic !!!"); + return rc; + } + /* GATT: Add user description to characteristic no. i*/ + rc = ble_gatt_add_char_dsc((void *) (*gatt_db_svcs)->characteristics, + i, BLE_GATT_UUID_CHAR_DSC); + if (rc != 0) { + ESP_LOGE(TAG, "Error adding GATT Discriptor !!"); + return rc; + } + } + return 0; +} + +static void protocomm_ble_cleanup(void) +{ + if (protoble_internal) { + if (protoble_internal->g_nu_lookup) { + for (unsigned i = 0; i < protoble_internal->g_nu_lookup_count; i++) { + if (protoble_internal->g_nu_lookup[i].name) { + free((void *)protoble_internal->g_nu_lookup[i].name); + } + } + free(protoble_internal->g_nu_lookup); + } + free(protoble_internal); + protoble_internal = NULL; + } + if (protocomm_ble_device_name) { + free(protocomm_ble_device_name); + protocomm_ble_device_name = NULL; + } +} + +static void free_gatt_ble_misc_memory(simple_ble_cfg_t *ble_config) +{ + /* Free up gatt_db memory if exists */ + if (ble_config->gatt_db->characteristics) { + for (int i = 0; i < num_chr_dsc; i++) { + if ((ble_config->gatt_db->characteristics + i)->descriptors) { + free((void *)(ble_config->gatt_db->characteristics + i)->descriptors->uuid); + free((ble_config->gatt_db->characteristics + i)->descriptors); + } + free((void *)(ble_config->gatt_db->characteristics + i)->uuid); + } + free((void *)(ble_config->gatt_db->characteristics)); + } + + if (ble_config->gatt_db) { + free((void *)ble_config->gatt_db->uuid); + free(ble_config->gatt_db); + } + + if (ble_config) { + free(ble_config); + } + ble_config = NULL; + + /* Free the uuid_name_table struct list if exists */ + struct uuid128_name_buf *cur; + while (!SLIST_EMPTY(&uuid128_name_list)) { + cur = SLIST_FIRST(&uuid128_name_list); + SLIST_REMOVE_HEAD(&uuid128_name_list, link); + if (cur->uuid128_name_table) { + free(cur->uuid128_name_table); + } + free(cur); + } + + /* Free the data_mbuf list if exists */ + struct data_mbuf *curr; + while (!SLIST_EMPTY(&data_mbuf_list)) { + curr = SLIST_FIRST(&data_mbuf_list); + SLIST_REMOVE_HEAD(&data_mbuf_list, node); + free(curr->outbuf); + free(curr); + } +} + +esp_err_t protocomm_ble_start(protocomm_t *pc, const protocomm_ble_config_t *config) +{ + /* copy the 128 bit service UUID into local buffer to use as base 128 bit + * UUID. */ + memcpy(ble_uuid_base, config->service_uuid, BLE_UUID128_VAL_LENGTH); + + if (!pc || !config || !config->device_name || !config->nu_lookup) { + return ESP_ERR_INVALID_ARG; + } + + if (protoble_internal) { + ESP_LOGE(TAG, "Protocomm BLE already started"); + return ESP_FAIL; + } + + /* Store 128 bit service UUID internally. */ + ble_uuid128_t *svc_uuid128 = (ble_uuid128_t *) + calloc(1, sizeof(ble_uuid128_t)); + if (svc_uuid128 == NULL) { + ESP_LOGE(TAG, "Error while allocating memory for 128 bit UUID"); + return ESP_ERR_NO_MEM; + } + svc_uuid128->u.type = BLE_UUID_TYPE_128; + memcpy(svc_uuid128->value, config->service_uuid, BLE_UUID128_VAL_LENGTH); + adv_data.uuids128 = (void *)svc_uuid128; + + /* Store service uuid128 in SLIST, to free it afterwards */ + struct uuid128_name_buf *temp_uuid128_name_buf = (struct uuid128_name_buf *) + calloc(1, sizeof(struct uuid128_name_buf)); + + if (temp_uuid128_name_buf == NULL) { + ESP_LOGE(TAG, "Error allocating memory for UUID128 address database"); + return ESP_ERR_NO_MEM; + } + SLIST_INSERT_HEAD(&uuid128_name_list, temp_uuid128_name_buf, link); + temp_uuid128_name_buf->uuid128_name_table = svc_uuid128; + + if (adv_data.uuids128 == NULL) { + ESP_LOGE(TAG, "Error allocating memory for storing service UUID"); + protocomm_ble_cleanup(); + return ESP_ERR_NO_MEM; + } + + /* Store BLE device name internally */ + protocomm_ble_device_name = strdup(config->device_name); + + if (protocomm_ble_device_name == NULL) { + ESP_LOGE(TAG, "Error allocating memory for storing BLE device name"); + protocomm_ble_cleanup(); + return ESP_ERR_NO_MEM; + } + + protoble_internal = (_protocomm_ble_internal_t *) calloc(1, sizeof(_protocomm_ble_internal_t)); + if (protoble_internal == NULL) { + ESP_LOGE(TAG, "Error allocating internal protocomm structure"); + protocomm_ble_cleanup(); + return ESP_ERR_NO_MEM; + } + + protoble_internal->g_nu_lookup_count = config->nu_lookup_count; + protoble_internal->g_nu_lookup = malloc(config->nu_lookup_count * sizeof(protocomm_ble_name_uuid_t)); + if (protoble_internal->g_nu_lookup == NULL) { + ESP_LOGE(TAG, "Error allocating internal name UUID table"); + protocomm_ble_cleanup(); + return ESP_ERR_NO_MEM; + } + + for (unsigned i = 0; i < protoble_internal->g_nu_lookup_count; i++) { + protoble_internal->g_nu_lookup[i].uuid = config->nu_lookup[i].uuid; + protoble_internal->g_nu_lookup[i].name = strdup(config->nu_lookup[i].name); + if (protoble_internal->g_nu_lookup[i].name == NULL) { + ESP_LOGE(TAG, "Error allocating internal name UUID entry"); + protocomm_ble_cleanup(); + return ESP_ERR_NO_MEM; + } + } + + pc->add_endpoint = protocomm_ble_add_endpoint; + pc->remove_endpoint = protocomm_ble_remove_endpoint; + protoble_internal->pc_ble = pc; + protoble_internal->gatt_mtu = BLE_ATT_MTU_DFLT; + + simple_ble_cfg_t *ble_config = (simple_ble_cfg_t *) calloc(1, sizeof(simple_ble_cfg_t)); + if (ble_config == NULL) { + ESP_LOGE(TAG, "Ran out of memory for BLE config"); + protocomm_ble_cleanup(); + return ESP_ERR_NO_MEM; + } + + /* Set function pointers required for simple BLE layer */ + ble_config->connect_fn = transport_simple_ble_connect; + ble_config->disconnect_fn = transport_simple_ble_disconnect; + ble_config->set_mtu_fn = transport_simple_ble_set_mtu; + + /* Set parameters required for advertising */ + ble_config->adv_data = adv_data; + ble_config->adv_params = adv_params; + + ble_config->device_name = protocomm_ble_device_name; + + if (populate_gatt_db(&ble_config->gatt_db, config) != 0) { + ESP_LOGE(TAG, "Error populating GATT Database"); + free_gatt_ble_misc_memory(ble_config); + return ESP_ERR_NO_MEM; + } + + esp_err_t err = simple_ble_start(ble_config); + ESP_LOGD(TAG, "Free Heap size after simple_ble_start= %d", esp_get_free_heap_size()); + + if (err != ESP_OK) { + ESP_LOGE(TAG, "simple_ble_start failed w/ error code 0x%x", err); + free_gatt_ble_misc_memory(ble_config); + protocomm_ble_cleanup(); + return err; + } + + ESP_LOGV(TAG, "Waiting for client to connect ......"); + return ESP_OK; +} + +esp_err_t protocomm_ble_stop(protocomm_t *pc) +{ + ESP_LOGD(TAG, "protocomm_ble_stop called here..."); + if ((pc != NULL) && + (protoble_internal != NULL ) && + (pc == protoble_internal->pc_ble)) { + esp_err_t ret = ESP_OK; + + esp_err_t rc = ble_gap_adv_stop(); + if (rc) { + ESP_LOGD(TAG, "Error in stopping advertisement with err code = %d", + rc); + } + + ret = nimble_port_stop(); + if (ret == 0) { + nimble_port_deinit(); + ret = esp_nimble_hci_and_controller_deinit(); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "esp_nimble_hci_and_controller_deinit() failed with error: %d", ret); + } + } + + free_gatt_ble_misc_memory(ble_cfg_p); + protocomm_ble_cleanup(); + return ret; + } + return ESP_ERR_INVALID_ARG; +} diff --git a/components/protocomm/test/CMakeLists.txt b/components/protocomm/test/CMakeLists.txt index f25cb01a18..6e04b5332e 100644 --- a/components/protocomm/test/CMakeLists.txt +++ b/components/protocomm/test/CMakeLists.txt @@ -1,7 +1,4 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") -set(COMPONENT_PRIV_INCLUDEDIRS "../proto-c/") - -set(COMPONENT_REQUIRES unity mbedtls protocomm protobuf-c) - -register_component() +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + PRIV_INCLUDE_DIRS "../proto-c/" + REQUIRES unity mbedtls protocomm protobuf-c) \ No newline at end of file diff --git a/components/pthread/CMakeLists.txt b/components/pthread/CMakeLists.txt index 5c8bc04a04..136bf9cf1c 100644 --- a/components/pthread/CMakeLists.txt +++ b/components/pthread/CMakeLists.txt @@ -1,9 +1,18 @@ -set(COMPONENT_SRCS "pthread.c" - "pthread_cond_var.c" - "pthread_local_storage.c") -set(COMPONENT_ADD_INCLUDEDIRS "include") -register_component() +idf_component_register(SRCS "pthread.c" + "pthread_cond_var.c" + "pthread_local_storage.c" + INCLUDE_DIRS include) + +if(GCC_NOT_5_2_0) + set(extra_link_flags "-u pthread_include_pthread_impl") + list(APPEND extra_link_flags "-u pthread_include_pthread_cond_impl") + list(APPEND extra_link_flags "-u pthread_include_pthread_local_storage_impl") +endif() if(CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP) target_link_libraries(${COMPONENT_LIB} "-Wl,--wrap=vPortCleanUpTCB") endif() + +if(extra_link_flags) + target_link_libraries(${COMPONENT_LIB} INTERFACE "${extra_link_flags}") +endif() diff --git a/components/pthread/Kconfig b/components/pthread/Kconfig index 61fa8a33e6..20e3f6123f 100644 --- a/components/pthread/Kconfig +++ b/components/pthread/Kconfig @@ -1,46 +1,46 @@ menu "PThreads" - config ESP32_PTHREAD_TASK_PRIO_DEFAULT + config PTHREAD_TASK_PRIO_DEFAULT int "Default task priority" range 0 255 default 5 help Priority used to create new tasks with default pthread parameters. - config ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT + config PTHREAD_TASK_STACK_SIZE_DEFAULT int "Default task stack size" default 3072 help Stack size used to create new tasks with default pthread parameters. - config ESP32_PTHREAD_STACK_MIN + config PTHREAD_STACK_MIN int "Minimum allowed pthread stack size" default 768 help Minimum allowed pthread stack size set in attributes passed to pthread_create - choice ESP32_PTHREAD_TASK_CORE_DEFAULT + choice PTHREAD_TASK_CORE_DEFAULT bool "Default pthread core affinity" - default ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY + default PTHREAD_DEFAULT_CORE_NO_AFFINITY depends on !FREERTOS_UNICORE help The default core to which pthreads are pinned. - config ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY + config PTHREAD_DEFAULT_CORE_NO_AFFINITY bool "No affinity" - config ESP32_DEFAULT_PTHREAD_CORE_0 + config PTHREAD_DEFAULT_CORE_0 bool "Core 0" - config ESP32_DEFAULT_PTHREAD_CORE_1 + config PTHREAD_DEFAULT_CORE_1 bool "Core 1" endchoice - config ESP32_PTHREAD_TASK_CORE_DEFAULT + config PTHREAD_TASK_CORE_DEFAULT int - default -1 if ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY || FREERTOS_UNICORE - default 0 if ESP32_DEFAULT_PTHREAD_CORE_0 - default 1 if ESP32_DEFAULT_PTHREAD_CORE_1 + default -1 if PTHREAD_DEFAULT_CORE_NO_AFFINITY || FREERTOS_UNICORE + default 0 if PTHREAD_DEFAULT_CORE_0 + default 1 if PTHREAD_DEFAULT_CORE_1 - config ESP32_PTHREAD_TASK_NAME_DEFAULT + config PTHREAD_TASK_NAME_DEFAULT string "Default name of pthreads" default "pthread" help diff --git a/components/pthread/component.mk b/components/pthread/component.mk index 9c3eececf5..c5793fded6 100644 --- a/components/pthread/component.mk +++ b/components/pthread/component.mk @@ -11,3 +11,11 @@ COMPONENT_ADD_LDFLAGS := -lpthread ifdef CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP COMPONENT_ADD_LDFLAGS += -Wl,--wrap=vPortCleanUpTCB endif + +ifeq ($(GCC_NOT_5_2_0), 1) +# Forces the linker to include pthread implementation from this component, +# instead of the weak implementations provided by libgcc. +COMPONENT_ADD_LDFLAGS += -u pthread_include_pthread_impl +COMPONENT_ADD_LDFLAGS += -u pthread_include_pthread_cond_impl +COMPONENT_ADD_LDFLAGS += -u pthread_include_pthread_local_storage_impl +endif # GCC_NOT_5_2_0 diff --git a/components/pthread/include/esp_pthread.h b/components/pthread/include/esp_pthread.h index ca93c9c380..76f45a32ab 100644 --- a/components/pthread/include/esp_pthread.h +++ b/components/pthread/include/esp_pthread.h @@ -22,7 +22,7 @@ extern "C" { #endif #ifndef PTHREAD_STACK_MIN -#define PTHREAD_STACK_MIN CONFIG_ESP32_PTHREAD_STACK_MIN +#define PTHREAD_STACK_MIN CONFIG_PTHREAD_STACK_MIN #endif /** pthread configuration structure that influences pthread creation */ diff --git a/components/pthread/pthread.c b/components/pthread/pthread.c index 0efbeaf3a7..8933d5e08a 100644 --- a/components/pthread/pthread.c +++ b/components/pthread/pthread.c @@ -170,14 +170,14 @@ esp_err_t esp_pthread_get_cfg(esp_pthread_cfg_t *p) static int get_default_pthread_core() { - return CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT == -1 ? tskNO_AFFINITY : CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT; + return CONFIG_PTHREAD_TASK_CORE_DEFAULT == -1 ? tskNO_AFFINITY : CONFIG_PTHREAD_TASK_CORE_DEFAULT; } esp_pthread_cfg_t esp_pthread_get_default_config() { esp_pthread_cfg_t cfg = { - .stack_size = CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT, - .prio = CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT, + .stack_size = CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT, + .prio = CONFIG_PTHREAD_TASK_PRIO_DEFAULT, .inherit_cfg = false, .thread_name = NULL, .pin_to_core = get_default_pthread_core() @@ -233,10 +233,10 @@ int pthread_create(pthread_t *thread, const pthread_attr_t *attr, return ENOMEM; } - uint32_t stack_size = CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT; - BaseType_t prio = CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT; + uint32_t stack_size = CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT; + BaseType_t prio = CONFIG_PTHREAD_TASK_PRIO_DEFAULT; BaseType_t core_id = get_default_pthread_core(); - const char *task_name = CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT; + const char *task_name = CONFIG_PTHREAD_TASK_NAME_DEFAULT; esp_pthread_cfg_t *pthread_cfg = pthread_getspecific(s_pthread_cfg_key); if (pthread_cfg) { @@ -256,7 +256,7 @@ int pthread_create(pthread_t *thread, const pthread_attr_t *attr, task_name = pthread_cfg->thread_name; } } else if (pthread_cfg->thread_name == NULL) { - task_name = CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT; + task_name = CONFIG_PTHREAD_TASK_NAME_DEFAULT; } else { task_name = pthread_cfg->thread_name; } @@ -758,7 +758,7 @@ int pthread_attr_init(pthread_attr_t *attr) { if (attr) { /* Nothing to allocate. Set everything to default */ - attr->stacksize = CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT; + attr->stacksize = CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT; attr->detachstate = PTHREAD_CREATE_JOINABLE; return 0; } @@ -769,7 +769,7 @@ int pthread_attr_destroy(pthread_attr_t *attr) { if (attr) { /* Nothing to deallocate. Reset everything to default */ - attr->stacksize = CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT; + attr->stacksize = CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT; attr->detachstate = PTHREAD_CREATE_JOINABLE; return 0; } @@ -820,3 +820,8 @@ int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) } return EINVAL; } + +/* Hook function to force linking this file */ +void pthread_include_pthread_impl() +{ +} diff --git a/components/pthread/pthread_cond_var.c b/components/pthread/pthread_cond_var.c index fe3144512d..8db28ae5e1 100644 --- a/components/pthread/pthread_cond_var.c +++ b/components/pthread/pthread_cond_var.c @@ -198,3 +198,8 @@ int pthread_cond_destroy(pthread_cond_t *cv) return ret; } + +/* Hook function to force linking this file */ +void pthread_include_pthread_cond_var_impl() +{ +} diff --git a/components/pthread/pthread_local_storage.c b/components/pthread/pthread_local_storage.c index 5e2dbafd21..ecf252e4cc 100644 --- a/components/pthread/pthread_local_storage.c +++ b/components/pthread/pthread_local_storage.c @@ -255,3 +255,8 @@ int pthread_setspecific(pthread_key_t key, const void *value) return 0; } + +/* Hook function to force linking this file */ +void pthread_include_pthread_local_storage_impl() +{ +} diff --git a/components/pthread/sdkconfig.rename b/components/pthread/sdkconfig.rename index b72b647076..fb5c0ff34c 100644 --- a/components/pthread/sdkconfig.rename +++ b/components/pthread/sdkconfig.rename @@ -1,4 +1,11 @@ # sdkconfig replacement configurations for deprecated options formatted as # CONFIG_DEPRECATED_OPTION CONFIG_NEW_OPTION -CONFIG_PTHREAD_STACK_MIN CONFIG_ESP32_PTHREAD_STACK_MIN +CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT CONFIG_PTHREAD_TASK_PRIO_DEFAULT +CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT +CONFIG_ESP32_PTHREAD_STACK_MIN CONFIG_PTHREAD_STACK_MIN +CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT CONFIG_PTHREAD_TASK_CORE_DEFAULT +CONFIG_ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY CONFIG_PTHREAD_DEFAULT_CORE_NO_AFFINITY +CONFIG_ESP32_DEFAULT_PTHREAD_CORE_0 CONFIG_PTHREAD_DEFAULT_CORE_0 +CONFIG_ESP32_DEFAULT_PTHREAD_CORE_1 CONFIG_PTHREAD_DEFAULT_CORE_1 +CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT CONFIG_PTHREAD_TASK_NAME_DEFAULT diff --git a/components/pthread/test/CMakeLists.txt b/components/pthread/test/CMakeLists.txt index f57f843b1b..bb02dc7d41 100644 --- a/components/pthread/test/CMakeLists.txt +++ b/components/pthread/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity test_utils pthread) - -register_component() \ No newline at end of file +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity test_utils pthread) \ No newline at end of file diff --git a/components/sdmmc/CMakeLists.txt b/components/sdmmc/CMakeLists.txt index fdba0cf790..cb7de0e805 100644 --- a/components/sdmmc/CMakeLists.txt +++ b/components/sdmmc/CMakeLists.txt @@ -1,10 +1,9 @@ -set(COMPONENT_SRCS "sdmmc_cmd.c" - "sdmmc_common.c" - "sdmmc_init.c" - "sdmmc_io.c" - "sdmmc_mmc.c" - "sdmmc_sd.c") -set(COMPONENT_ADD_INCLUDEDIRS "include") -set(COMPONENT_REQUIRES driver) -set(COMPONENT_PRIV_REQUIRES soc) -register_component() +idf_component_register(SRCS "sdmmc_cmd.c" + "sdmmc_common.c" + "sdmmc_init.c" + "sdmmc_io.c" + "sdmmc_mmc.c" + "sdmmc_sd.c" + INCLUDE_DIRS include + REQUIRES driver + PRIV_REQUIRES soc) \ No newline at end of file diff --git a/components/sdmmc/include/sdmmc_cmd.h b/components/sdmmc/include/sdmmc_cmd.h index aa12a4477a..666f35560d 100644 --- a/components/sdmmc/include/sdmmc_cmd.h +++ b/components/sdmmc/include/sdmmc_cmd.h @@ -220,6 +220,55 @@ esp_err_t sdmmc_io_enable_int(sdmmc_card_t* card); */ esp_err_t sdmmc_io_wait_int(sdmmc_card_t* card, TickType_t timeout_ticks); +/** + * Get the data of CIS region of a SDIO card. + * + * You may provide a buffer not sufficient to store all the CIS data. In this + * case, this functions store as much data into your buffer as possible. Also, + * this function will try to get and return the size required for you. + * + * @param card pointer to card information structure previously initialized + * using sdmmc_card_init + * @param out_buffer Output buffer of the CIS data + * @param buffer_size Size of the buffer. + * @param inout_cis_size Mandatory, pointer to a size, input and output. + * - input: Limitation of maximum searching range, should be 0 or larger than + * buffer_size. The function searches for CIS_CODE_END until this range. Set to + * 0 to search infinitely. + * - output: The size required to store all the CIS data, if CIS_CODE_END is found. + * + * @return + * - ESP_OK: on success + * - ESP_ERR_INVALID_RESPONSE: if the card does not (correctly) support CIS. + * - ESP_ERR_INVALID_SIZE: CIS_CODE_END found, but buffer_size is less than + * required size, which is stored in the inout_cis_size then. + * - ESP_ERR_NOT_FOUND: if the CIS_CODE_END not found. Increase input value of + * inout_cis_size or set it to 0, if you still want to search for the end; + * output value of inout_cis_size is invalid in this case. + * - and other error code return from sdmmc_io_read_bytes + */ +esp_err_t sdmmc_io_get_cis_data(sdmmc_card_t* card, uint8_t* out_buffer, size_t buffer_size, size_t* inout_cis_size); + +/** + * Parse and print the CIS information of a SDIO card. + * + * @note Not all the CIS codes and all kinds of tuples are supported. If you + * see some unresolved code, you can add the parsing of these code in + * sdmmc_io.c and contribute to the IDF through the Github repository. + * + * using sdmmc_card_init + * @param buffer Buffer to parse + * @param buffer_size Size of the buffer. + * @param fp File pointer to print to, set to NULL to print to stdout. + * + * @return + * - ESP_OK: on success + * - ESP_ERR_NOT_SUPPORTED: if the value from the card is not supported to be parsed. + * - ESP_ERR_INVALID_SIZE: if the CIS size fields are not correct. + */ +esp_err_t sdmmc_io_print_cis_info(uint8_t* buffer, size_t buffer_size, FILE* fp); + + #ifdef __cplusplus } #endif diff --git a/components/sdmmc/sdmmc_io.c b/components/sdmmc/sdmmc_io.c index 7229f18983..e77623a17a 100644 --- a/components/sdmmc/sdmmc_io.c +++ b/components/sdmmc/sdmmc_io.c @@ -16,9 +16,50 @@ */ #include "sdmmc_common.h" +#include "esp_attr.h" + + +#define CIS_TUPLE(NAME) (cis_tuple_t) {.code=CISTPL_CODE_##NAME, .name=#NAME, .func=&cis_tuple_func_default, } +#define CIS_TUPLE_WITH_FUNC(NAME, FUNC) (cis_tuple_t) {.code=CISTPL_CODE_##NAME, .name=#NAME, .func=&(FUNC), } + +#define CIS_CHECK_SIZE(SIZE, MINIMAL) do {int store_size = (SIZE); if((store_size) < (MINIMAL)) return ESP_ERR_INVALID_SIZE;} while(0) +#define CIS_CHECK_UNSUPPORTED(COND) do {if(!(COND)) return ESP_ERR_NOT_SUPPORTED;} while(0) +#define CIS_GET_MINIMAL_SIZE 32 + +typedef esp_err_t (*cis_tuple_info_func_t)(const void* tuple_info, uint8_t* data, FILE* fp); + +typedef struct { + int code; + const char *name; + cis_tuple_info_func_t func; +} cis_tuple_t; static const char* TAG = "sdmmc_io"; +static esp_err_t cis_tuple_func_default(const void* p, uint8_t* data, FILE* fp); +static esp_err_t cis_tuple_func_manfid(const void* p, uint8_t* data, FILE* fp); +static esp_err_t cis_tuple_func_cftable_entry(const void* p, uint8_t* data, FILE* fp); +static esp_err_t cis_tuple_func_end(const void* p, uint8_t* data, FILE* fp); + +static const cis_tuple_t cis_table[] = { + CIS_TUPLE(NULL), + CIS_TUPLE(DEVICE), + CIS_TUPLE(CHKSUM), + CIS_TUPLE(VERS1), + CIS_TUPLE(ALTSTR), + CIS_TUPLE(CONFIG), + CIS_TUPLE_WITH_FUNC(CFTABLE_ENTRY, cis_tuple_func_cftable_entry), + CIS_TUPLE_WITH_FUNC(MANFID, cis_tuple_func_manfid), + CIS_TUPLE(FUNCID), + CIS_TUPLE(FUNCE), + CIS_TUPLE(VENDER_BEGIN), + CIS_TUPLE(VENDER_END), + CIS_TUPLE(SDIO_STD), + CIS_TUPLE(SDIO_EXT), + CIS_TUPLE_WITH_FUNC(END, cis_tuple_func_end), +}; + + esp_err_t sdmmc_io_reset(sdmmc_card_t* card) { uint8_t sdio_reset = CCCR_CTL_RES; @@ -352,3 +393,240 @@ esp_err_t sdmmc_io_wait_int(sdmmc_card_t* card, TickType_t timeout_ticks) } return (*card->host.io_int_wait)(card->host.slot, timeout_ticks); } + + +/* + * Print the CIS information of a CIS card, currently only ESP slave supported. + */ + +static esp_err_t cis_tuple_func_default(const void* p, uint8_t* data, FILE* fp) +{ + const cis_tuple_t* tuple = (const cis_tuple_t*)p; + uint8_t code = *(data++); + int size = *(data++); + if (tuple) { + fprintf(fp, "TUPLE: %s, size: %d: ", tuple->name, size); + } else { + fprintf(fp, "TUPLE: unknown(%02X), size: %d: ", code, size); + } + for (int i = 0; i < size; i++) fprintf(fp, "%02X ", *(data++)); + fprintf(fp, "\n"); + return ESP_OK; +} + +static esp_err_t cis_tuple_func_manfid(const void* p, uint8_t* data, FILE* fp) +{ + const cis_tuple_t* tuple = (const cis_tuple_t*)p; + data++; + int size = *(data++); + fprintf(fp, "TUPLE: %s, size: %d\n", tuple->name, size); + CIS_CHECK_SIZE(size, 4); + fprintf(fp, " MANF: %04X, CARD: %04X\n", *(uint16_t*)(data), *(uint16_t*)(data+2)); + return ESP_OK; +} + +static esp_err_t cis_tuple_func_end(const void* p, uint8_t* data, FILE* fp) +{ + const cis_tuple_t* tuple = (const cis_tuple_t*)p; + data++; + fprintf(fp, "TUPLE: %s\n", tuple->name); + return ESP_OK; +} + +static esp_err_t cis_tuple_func_cftable_entry(const void* p, uint8_t* data, FILE* fp) +{ + const cis_tuple_t* tuple = (const cis_tuple_t*)p; + data++; + int size = *(data++); + fprintf(fp, "TUPLE: %s, size: %d\n", tuple->name, size); + CIS_CHECK_SIZE(size, 2); + + CIS_CHECK_SIZE(size--, 1); + bool interface = data[0] & BIT(7); + bool def = data[0] & BIT(6); + int conf_ent_num = data[0] & 0x3F; + fprintf(fp, " INDX: %02X, Intface: %d, Default: %d, Conf-Entry-Num: %d\n", *(data++), interface, def, conf_ent_num); + + if (interface) { + CIS_CHECK_SIZE(size--, 1); + fprintf(fp, " IF: %02X\n", *(data++)); + } + + CIS_CHECK_SIZE(size--, 1); + bool misc = data[0] & BIT(7); + int mem_space = (data[0] >> 5 )&(0x3); + bool irq = data[0] & BIT(4); + bool io_sp = data[0] & BIT(3); + bool timing = data[0] & BIT(2); + int power = data[0] & 3; + fprintf(fp, " FS: %02X, misc: %d, mem_space: %d, irq: %d, io_space: %d, timing: %d, power: %d\n", *(data++), misc, mem_space, irq, io_sp, timing, power); + + CIS_CHECK_UNSUPPORTED(power == 0); //power descriptor is not handled yet + CIS_CHECK_UNSUPPORTED(!timing); //timing descriptor is not handled yet + CIS_CHECK_UNSUPPORTED(!io_sp); //io space descriptor is not handled yet + + if (irq) { + CIS_CHECK_SIZE(size--, 1); + bool mask = data[0] & BIT(4); + fprintf(fp, " IR: %02X, mask: %d, ",*(data++), mask); + if (mask) { + CIS_CHECK_SIZE(size, 2); + size-=2; + fprintf(fp, " IRQ: %02X %02X\n", data[0], data[1]); + data+=2; + } + } + + if (mem_space) { + CIS_CHECK_SIZE(size, 2); + size-=2; + CIS_CHECK_UNSUPPORTED(mem_space==1); //other cases not handled yet + int len = *(uint16_t*)data; + fprintf(fp, " LEN: %04X\n", len); + data+=2; + } + + CIS_CHECK_UNSUPPORTED(misc==0); //misc descriptor is not handled yet + return ESP_OK; +} + +static const cis_tuple_t* get_tuple(uint8_t code) +{ + for (int i = 0; i < sizeof(cis_table)/sizeof(cis_tuple_t); i++) { + if (code == cis_table[i].code) return &cis_table[i]; + } + return NULL; +} + +esp_err_t sdmmc_io_print_cis_info(uint8_t* buffer, size_t buffer_size, FILE* fp) +{ + ESP_LOG_BUFFER_HEXDUMP("CIS", buffer, buffer_size, ESP_LOG_DEBUG); + if (!fp) fp = stdout; + + uint8_t* cis = buffer; + do { + const cis_tuple_t* tuple = get_tuple(cis[0]); + int size = cis[1]; + esp_err_t ret = ESP_OK; + if (tuple) { + ret = tuple->func(tuple, cis, fp); + } else { + ret = cis_tuple_func_default(NULL, cis, fp); + } + if (ret != ESP_OK) return ret; + cis += 2 + size; + if (tuple && tuple->code == CISTPL_CODE_END) break; + } while (cis < buffer + buffer_size) ; + return ESP_OK; +} + +/** + * Check tuples in the buffer. + * + * @param buf Buffer to check + * @param buffer_size Size of the buffer + * @param inout_cis_offset + * - input: the last cis_offset, relative to the beginning of the buf. -1 if + * this buffer begin with the tuple length, otherwise should be no smaller than + * zero. + * - output: when the end tuple found, output offset of the CISTPL_CODE_END + * byte + 1 (relative to the beginning of the buffer; when not found, output + * the address of next tuple code. + * + * @return true if found, false if haven't. + */ +static bool check_tuples_in_buffer(uint8_t* buf, int buffer_size, int* inout_cis_offset) +{ + int cis_offset = *inout_cis_offset; + if (cis_offset == -1) { + //the CIS code is checked in the last buffer, skip to next tuple + cis_offset += buf[0] + 2; + } + assert(cis_offset >= 0); + while (1) { + if (cis_offset < buffer_size) { + //A CIS code in the buffer, check it + if (buf[cis_offset] == CISTPL_CODE_END) { + *inout_cis_offset = cis_offset + 1; + return true; + } + } + if (cis_offset + 1 < buffer_size) { + cis_offset += buf[cis_offset+1] + 2; + } else { + break; + } + } + *inout_cis_offset = cis_offset; + return false; +} + +esp_err_t sdmmc_io_get_cis_data(sdmmc_card_t* card, uint8_t* out_buffer, size_t buffer_size, size_t* inout_cis_size) +{ + esp_err_t ret = ESP_OK; + WORD_ALIGNED_ATTR uint8_t buf[CIS_GET_MINIMAL_SIZE]; + + /* + * CIS region exist in 0x1000~0x17FFF of FUNC 0, get the start address of it + * from CCCR register. + */ + uint32_t addr; + ret = sdmmc_io_read_bytes(card, 0, 9, &addr, 3); + if (ret != ESP_OK) return ret; + //the sdmmc_io driver reads 4 bytes, the most significant byte is not the address. + addr &= 0xffffff; + if (addr < 0x1000 || addr > 0x17FFF) { + return ESP_ERR_INVALID_RESPONSE; + } + + /* + * To avoid reading too long, take the input value as limitation if + * existing. + */ + size_t max_reading = UINT32_MAX; + if (inout_cis_size && *inout_cis_size != 0) { + max_reading = *inout_cis_size; + } + + /* + * Parse the length while reading. If find the end tuple, or reaches the + * limitation, read no more and return both the data and the size already + * read. + */ + int buffer_offset = 0; + int cur_cis_offset = 0; + bool end_tuple_found = false; + do { + ret = sdmmc_io_read_bytes(card, 0, addr + buffer_offset, &buf, CIS_GET_MINIMAL_SIZE); + if (ret != ESP_OK) return ret; + + //calculate relative to the beginning of the buffer + int offset = cur_cis_offset - buffer_offset; + bool finish = check_tuples_in_buffer(buf, CIS_GET_MINIMAL_SIZE, &offset); + + int remain_size = buffer_size - buffer_offset; + int copy_len; + if (finish) { + copy_len = MIN(offset, remain_size); + end_tuple_found = true; + } else { + copy_len = MIN(CIS_GET_MINIMAL_SIZE, remain_size); + } + if (copy_len > 0) { + memcpy(out_buffer + buffer_offset, buf, copy_len); + } + cur_cis_offset = buffer_offset + offset; + buffer_offset += CIS_GET_MINIMAL_SIZE; + } while (!end_tuple_found && buffer_offset < max_reading); + + if (end_tuple_found) { + *inout_cis_size = cur_cis_offset; + if (cur_cis_offset > buffer_size) { + return ESP_ERR_INVALID_SIZE; + } else { + return ESP_OK; + } + } else { + return ESP_ERR_NOT_FOUND; + } +} diff --git a/components/sdmmc/test/CMakeLists.txt b/components/sdmmc/test/CMakeLists.txt index 885cda77a6..c7c2d52a9b 100644 --- a/components/sdmmc/test/CMakeLists.txt +++ b/components/sdmmc/test/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCDIRS ".") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -set(COMPONENT_REQUIRES unity sdmmc) - -register_component() \ No newline at end of file +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity sdmmc) \ No newline at end of file diff --git a/components/smartconfig_ack/CMakeLists.txt b/components/smartconfig_ack/CMakeLists.txt index 1518776ce9..eb34b0713c 100644 --- a/components/smartconfig_ack/CMakeLists.txt +++ b/components/smartconfig_ack/CMakeLists.txt @@ -1,6 +1,3 @@ -set(COMPONENT_SRCS "smartconfig_ack.c") -set(COMPONENT_ADD_INCLUDEDIRS "include") - -set(COMPONENT_PRIV_REQUIRES lwip tcpip_adapter) - -register_component() +idf_component_register(SRCS "smartconfig_ack.c" + INCLUDE_DIRS include + PRIV_REQUIRES lwip tcpip_adapter) \ No newline at end of file diff --git a/components/smartconfig_ack/include/smartconfig_ack.h b/components/smartconfig_ack/include/smartconfig_ack.h index be49fd3bd1..0eb3e4b660 100644 --- a/components/smartconfig_ack/include/smartconfig_ack.h +++ b/components/smartconfig_ack/include/smartconfig_ack.h @@ -19,54 +19,24 @@ extern "C" { #endif -#define SC_ACK_TASK_PRIORITY 2 /*!< Priority of sending smartconfig ACK task */ -#define SC_ACK_TASK_STACK_SIZE 2048 /*!< Stack size of sending smartconfig ACK task */ - -#define SC_ACK_TOUCH_SERVER_PORT 18266 /*!< ESP touch UDP port of server on cellphone */ -#define SC_ACK_AIRKISS_SERVER_PORT 10000 /*!< Airkiss UDP port of server on cellphone */ - -#define SC_ACK_TOUCH_LEN 11 /*!< Length of ESP touch ACK context */ -#define SC_ACK_AIRKISS_LEN 7 /*!< Length of Airkiss ACK context */ - -#define SC_ACK_MAX_COUNT 30 /*!< Maximum count of sending smartconfig ACK */ - -/** - * @brief Smartconfig ACK type. - */ -typedef enum { - SC_ACK_TYPE_ESPTOUCH = 0, /*!< ESP touch ACK type */ - SC_ACK_TYPE_AIRKISS, /*!< Airkiss ACK type */ -} sc_ack_type_t; - -/** - * @brief Smartconfig parameters passed to sc_ack_send call. - */ -typedef struct sc_ack { - sc_ack_type_t type; /*!< Smartconfig ACK type */ - uint8_t *link_flag; /*!< Smartconfig link flag */ - sc_callback_t cb; /*!< Smartconfig callback function */ - struct { - uint8_t token; /*!< Smartconfig token to be sent */ - uint8_t mac[6]; /*!< MAC address of station */ - uint8_t ip[4]; /*!< IP address of cellphone */ - } ctx; -} sc_ack_t; - /** * @brief Send smartconfig ACK to cellphone. * - * @attention The API is only used in libsmartconfig.a. + * @attention The API can only be used when receiving SC_EVENT_GOT_SSID_PSWD event. * - * @param param: smartconfig parameters; + * @param type: smartconfig type(ESPTouch or AirKiss); + * token: token from the cellphone; + * cellphone_ip: IP address of the cellphone; + * + * @retuen ESP_OK: succeed + * others: fail */ -void sc_ack_send(sc_ack_t *param); +esp_err_t sc_send_ack_start(smartconfig_type_t type, uint8_t token, uint8_t *cellphone_ip); /** * @brief Stop sending smartconfig ACK to cellphone. - * - * @attention The API is only used in libsmartconfig.a. */ -void sc_ack_send_stop(void); +void sc_send_ack_stop(void); #ifdef __cplusplus } diff --git a/components/smartconfig_ack/smartconfig_ack.c b/components/smartconfig_ack/smartconfig_ack.c index f84aad3672..fae5e58bbc 100644 --- a/components/smartconfig_ack/smartconfig_ack.c +++ b/components/smartconfig_ack/smartconfig_ack.c @@ -24,9 +24,33 @@ #include "tcpip_adapter.h" #include "esp_log.h" #include "esp_wifi.h" +#include "esp_event.h" #include "esp_smartconfig.h" #include "smartconfig_ack.h" +#define SC_ACK_TASK_PRIORITY 2 /*!< Priority of sending smartconfig ACK task */ +#define SC_ACK_TASK_STACK_SIZE 2048 /*!< Stack size of sending smartconfig ACK task */ + +#define SC_ACK_TOUCH_SERVER_PORT 18266 /*!< ESP touch UDP port of server on cellphone */ +#define SC_ACK_AIRKISS_SERVER_PORT 10000 /*!< Airkiss UDP port of server on cellphone */ + +#define SC_ACK_TOUCH_LEN 11 /*!< Length of ESP touch ACK context */ +#define SC_ACK_AIRKISS_LEN 7 /*!< Length of Airkiss ACK context */ + +#define SC_ACK_MAX_COUNT 30 /*!< Maximum count of sending smartconfig ACK */ + +/** + * @brief Smartconfig parameters passed to sc_ack_send call. + */ +typedef struct sc_ack { + smartconfig_type_t type; /*!< Smartconfig type(ESPTouch or AirKiss) */ + struct { + uint8_t token; /*!< Smartconfig token from the cellphone */ + uint8_t mac[6]; /*!< MAC address of station */ + uint8_t ip[4]; /*!< IP address of cellphone */ + } ctx; +} sc_ack_t; + static const char *TAG = "smartconfig"; /* Flag to indicate sending smartconfig ACK or not. */ @@ -48,13 +72,13 @@ static void sc_ack_send_task(void *pvParameters) tcpip_adapter_ip_info_t local_ip; uint8_t remote_ip[4]; memcpy(remote_ip, ack->ctx.ip, sizeof(remote_ip)); - int remote_port = (ack->type == SC_ACK_TYPE_ESPTOUCH) ? SC_ACK_TOUCH_SERVER_PORT : SC_ACK_AIRKISS_SERVER_PORT; + int remote_port = (ack->type == SC_TYPE_ESPTOUCH) ? SC_ACK_TOUCH_SERVER_PORT : SC_ACK_AIRKISS_SERVER_PORT; struct sockaddr_in server_addr; socklen_t sin_size = sizeof(server_addr); int send_sock = -1; int optval = 1; int sendlen; - int ack_len = (ack->type == SC_ACK_TYPE_ESPTOUCH) ? SC_ACK_TOUCH_LEN : SC_ACK_AIRKISS_LEN; + int ack_len = (ack->type == SC_TYPE_ESPTOUCH) ? SC_ACK_TOUCH_LEN : SC_ACK_AIRKISS_LEN; uint8_t packet_count = 1; int err; int ret; @@ -73,7 +97,7 @@ static void sc_ack_send_task(void *pvParameters) ret = tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &local_ip); if ((ESP_OK == ret) && (local_ip.ip.addr != INADDR_ANY)) { /* If ESP touch, smartconfig ACK contains local IP address. */ - if (ack->type == SC_ACK_TYPE_ESPTOUCH) { + if (ack->type == SC_TYPE_ESPTOUCH) { memcpy(ack->ctx.ip, &local_ip.ip.addr, 4); } @@ -94,12 +118,7 @@ static void sc_ack_send_task(void *pvParameters) if (sendlen > 0) { /* Totally send 30 smartconfig ACKs. Then smartconfig is successful. */ if (packet_count++ >= SC_ACK_MAX_COUNT) { - if (ack->link_flag) { - *ack->link_flag = 1; - } - if (ack->cb) { - ack->cb(SC_STATUS_LINK_OVER, remote_ip); - } + esp_event_post(SC_EVENT, SC_EVENT_SEND_ACK_DONE, NULL, 0, portMAX_DELAY); goto _end; } } @@ -127,31 +146,36 @@ _end: vTaskDelete(NULL); } -void sc_ack_send(sc_ack_t *param) +esp_err_t sc_send_ack_start(smartconfig_type_t type, uint8_t token, uint8_t *cellphone_ip) { sc_ack_t *ack = NULL; - if (param == NULL) { - ESP_LOGE(TAG, "Smart config ack parameter error"); - return; + if (cellphone_ip == NULL) { + ESP_LOGE(TAG, "Cellphone IP address is NULL"); + return ESP_ERR_INVALID_ARG; } ack = malloc(sizeof(sc_ack_t)); if (ack == NULL) { - ESP_LOGE(TAG, "Smart config ack parameter malloc fail"); - return; + ESP_LOGE(TAG, "ACK parameter malloc fail"); + return ESP_ERR_NO_MEM; } - memcpy(ack, param, sizeof(sc_ack_t)); + ack->type = type; + ack->ctx.token = token; + memcpy(ack->ctx.ip, cellphone_ip, 4); s_sc_ack_send = true; if (xTaskCreate(sc_ack_send_task, "sc_ack_send_task", SC_ACK_TASK_STACK_SIZE, ack, SC_ACK_TASK_PRIORITY, NULL) != pdPASS) { ESP_LOGE(TAG, "Create sending smartconfig ACK task fail"); free(ack); + return ESP_ERR_NO_MEM; } + + return ESP_OK; } -void sc_ack_send_stop(void) +void sc_send_ack_stop(void) { s_sc_ack_send = false; } diff --git a/components/soc/CMakeLists.txt b/components/soc/CMakeLists.txt index 464f0907ca..657af94861 100644 --- a/components/soc/CMakeLists.txt +++ b/components/soc/CMakeLists.txt @@ -4,24 +4,23 @@ if(EXISTS "${COMPONENT_DIR}/${soc_name}") include(${COMPONENT_DIR}/${soc_name}/sources.cmake) spaces2list(SOC_SRCS) - add_prefix(COMPONENT_SRCS "${soc_name}/" ${SOC_SRCS}) - set(COMPONENT_ADD_INCLUDEDIRS ${soc_name}/include) + add_prefix(srcs "${soc_name}/" ${SOC_SRCS}) + set(include_dirs ${soc_name}/include) endif() -list(APPEND COMPONENT_ADD_INCLUDEDIRS include) -if(NOT BOOTLOADER_BUILD) - list(APPEND COMPONENT_SRCS "src/memory_layout_utils.c" - "src/lldesc.c" - "src/soc_include_legacy_warn.c") +list(APPEND include_dirs include) +list(APPEND srcs + "src/memory_layout_utils.c" + "src/lldesc.c" + "src/hal/spi_hal.c" + "src/hal/spi_hal_iram.c" + "src/hal/spi_slave_hal.c" + "src/hal/spi_slave_hal_iram.c" + "src/soc_include_legacy_warn.c" + "src/hal/spi_flash_hal.c" + "src/hal/spi_flash_hal_iram.c" + ) - list(APPEND COMPONENT_SRCS "src/hal/spi_hal.c" - "src/hal/spi_hal_iram.c" - "src/hal/spi_slave_hal.c" - "src/hal/spi_slave_hal_iram.c") - - set(COMPONENT_ADD_LDFRAGMENTS linker.lf) -endif() - -set(COMPONENT_REQUIRES) - -register_component() +idf_component_register(SRCS "${srcs}" + INCLUDE_DIRS "${include_dirs}" + LDFRAGMENTS linker.lf) diff --git a/components/soc/esp32/component.mk b/components/soc/esp32/component.mk index 83a2ef722e..52c33c8d24 100644 --- a/components/soc/esp32/component.mk +++ b/components/soc/esp32/component.mk @@ -1 +1,5 @@ +ifndef CONFIG_ETH_USE_ESP32_EMAC + COMPONENT_OBJEXCLUDE += esp32/emac_hal.o +endif + esp32/rtc_clk.o: CFLAGS += -fno-jump-tables -fno-tree-switch-conversion diff --git a/components/soc/esp32/emac_hal.c b/components/soc/esp32/emac_hal.c new file mode 100644 index 0000000000..121bc53269 --- /dev/null +++ b/components/soc/esp32/emac_hal.c @@ -0,0 +1,656 @@ +// 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 "sdkconfig.h" +#include "esp_attr.h" +#include "soc/gpio_periph.h" +#include "soc/rtc.h" +#include "hal/emac.h" + +#define ETH_CRC_LENGTH (4) + +#if CONFIG_ETH_RMII_CLK_OUTPUT +static void emac_config_apll_clock(void) +{ + /* apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2) */ + rtc_xtal_freq_t rtc_xtal_freq = rtc_clk_xtal_freq_get(); + switch (rtc_xtal_freq) { + case RTC_XTAL_FREQ_40M: // Recommended + /* 50 MHz = 40MHz * (4 + 6) / (2 * (2 + 2) = 50.000 */ + /* sdm0 = 0, sdm1 = 0, sdm2 = 6, o_div = 2 */ + rtc_clk_apll_enable(true, 0, 0, 6, 2); + break; + case RTC_XTAL_FREQ_26M: + /* 50 MHz = 26MHz * (4 + 15 + 118 / 256 + 39/65536) / ((3 + 2) * 2) = 49.999992 */ + /* sdm0 = 39, sdm1 = 118, sdm2 = 15, o_div = 3 */ + rtc_clk_apll_enable(true, 39, 118, 15, 3); + break; + case RTC_XTAL_FREQ_24M: + /* 50 MHz = 24MHz * (4 + 12 + 255 / 256 + 255/65536) / ((2 + 2) * 2) = 49.499977 */ + /* sdm0 = 255, sdm1 = 255, sdm2 = 12, o_div = 2 */ + rtc_clk_apll_enable(true, 255, 255, 12, 2); + break; + default: // Assume we have a 40M xtal + rtc_clk_apll_enable(true, 0, 0, 6, 2); + break; + } +} +#endif + +void emac_hal_init(emac_hal_context_t *hal, void *descriptors, + uint8_t **rx_buf, uint8_t **tx_buf) +{ + hal->dma_regs = &EMAC_DMA; + hal->mac_regs = &EMAC_MAC; + hal->ext_regs = &EMAC_EXT; + hal->descriptors = descriptors; + hal->rx_buf = rx_buf; + hal->tx_buf = tx_buf; +} + +void emac_hal_lowlevel_init(emac_hal_context_t *hal) +{ + /* GPIO configuration */ + /* TX_EN to GPIO21 */ + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO21_U, FUNC_GPIO21_EMAC_TX_EN); + PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[21]); + /* TXD0 to GPIO19 */ + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO19_U, FUNC_GPIO19_EMAC_TXD0); + PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[19]); + /* TXD1 to GPIO22 */ + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO22_U, FUNC_GPIO22_EMAC_TXD1); + PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[22]); + /* RXD0 to GPIO25 */ + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO25_U, FUNC_GPIO25_EMAC_RXD0); + PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[25]); + /* RXD1 to GPIO26 */ + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO26_U, FUNC_GPIO26_EMAC_RXD1); + PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[26]); + /* CRS_DV to GPIO27 */ + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO27_U, FUNC_GPIO27_EMAC_RX_DV); + PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[27]); +#if CONFIG_ETH_RMII_CLK_INPUT +#if CONFIG_ETH_RMII_CLK_IN_GPIO == 0 + /* RMII clock (50MHz) input to GPIO0 */ + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_EMAC_TX_CLK); + PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[0]); +#else +#error "ESP32 EMAC only support input RMII clock to GPIO0" +#endif +#endif +#if CONFIG_ETH_RMII_CLK_OUTPUT +#if CONFIG_ETH_RMII_CLK_OUTPUT_GPIO0 + /* APLL clock output to GPIO0 (must be configured to 50MHz!) */ + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1); + PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[0]); +#elif CONFIG_ETH_RMII_CLK_OUT_GPIO == 16 + /* RMII CLK (50MHz) output to GPIO16 */ + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO16_U, FUNC_GPIO16_EMAC_CLK_OUT); + PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[16]); +#elif CONFIG_ETH_RMII_CLK_OUT_GPIO == 17 + /* RMII CLK (50MHz) output to GPIO17 */ + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO17_U, FUNC_GPIO17_EMAC_CLK_OUT_180); + PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[17]); +#endif +#endif // CONFIG_ETH_RMII_CLK_OUTPUT + /* Clock configuration */ +#if CONFIG_ETH_PHY_INTERFACE_MII + hal->ext_regs->ex_phyinf_conf.phy_intf_sel = 0; + hal->ext_regs->ex_clk_ctrl.mii_clk_rx_en = 1; + hal->ext_regs->ex_clk_ctrl.mii_clk_tx_en = 1; +#elif CONFIG_ETH_PHY_INTERFACE_RMII + hal->ext_regs->ex_phyinf_conf.phy_intf_sel = 4; +#if CONFIG_ETH_RMII_CLK_INPUT + hal->ext_regs->ex_clk_ctrl.ext_en = 1; + hal->ext_regs->ex_clk_ctrl.int_en = 0; + hal->ext_regs->ex_oscclk_conf.clk_sel = 1; +#elif CONFIG_ETH_RMII_CLK_OUTPUT + hal->ext_regs->ex_clk_ctrl.ext_en = 0; + hal->ext_regs->ex_clk_ctrl.int_en = 1; + hal->ext_regs->ex_oscclk_conf.clk_sel = 0; + emac_config_apll_clock(); + hal->ext_regs->ex_clkout_conf.div_num = 0; + hal->ext_regs->ex_clkout_conf.h_div_num = 0; +#if CONFIG_ETH_RMII_CLK_OUTPUT_GPIO0 + /* Choose the APLL clock to output on GPIO */ + REG_WRITE(PIN_CTRL, 6); +#endif // CONFIG_RMII_CLK_OUTPUT_GPIO0 +#endif // CONFIG_ETH_RMII_CLK_INPUT +#endif // CONFIG_ETH_PHY_INTERFACE_MII +} + +void emac_hal_reset(emac_hal_context_t *hal) +{ + hal->dma_regs->dmabusmode.sw_rst = 1; +} + +bool emac_hal_is_reset_done(emac_hal_context_t *hal) +{ + return hal->dma_regs->dmabusmode.sw_rst ? false : true; +} + +void emac_hal_set_csr_clock_range(emac_hal_context_t *hal) +{ + /* Tell MAC system clock Frequency, which will determin the frequency range of MDC(1MHz~2.5MHz) */ + if (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ >= 20 && CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ < 35) { + hal->mac_regs->emacgmiiaddr.miicsrclk = 2; + } else if (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ >= 35 && CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ < 60) { + hal->mac_regs->emacgmiiaddr.miicsrclk = 3; + } else if (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ >= 60 && CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ < 100) { + hal->mac_regs->emacgmiiaddr.miicsrclk = 0; + } else if (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ >= 100 && CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ < 150) { + hal->mac_regs->emacgmiiaddr.miicsrclk = 1; + } else if (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ > 150 && CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ < 250) { + hal->mac_regs->emacgmiiaddr.miicsrclk = 4; + } else { + hal->mac_regs->emacgmiiaddr.miicsrclk = 5; + } +} + +void emac_hal_reset_desc_chain(emac_hal_context_t *hal) +{ + /* reset DMA descriptors */ + hal->rx_desc = (eth_dma_rx_descriptor_t *)(hal->descriptors); + hal->tx_desc = (eth_dma_tx_descriptor_t *)(hal->descriptors + + sizeof(eth_dma_rx_descriptor_t) * CONFIG_ETH_DMA_RX_BUFFER_NUM); + /* init rx chain */ + for (int i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) { + /* Set Own bit of the Rx descriptor Status: DMA */ + hal->rx_desc[i].RDES0.Own = 1; + /* Set Buffer1 size and Second Address Chained bit */ + hal->rx_desc[i].RDES1.SecondAddressChained = 1; + hal->rx_desc[i].RDES1.ReceiveBuffer1Size = CONFIG_ETH_DMA_BUFFER_SIZE; + /* Enable Ethernet DMA Rx Descriptor interrupt */ + hal->rx_desc[i].RDES1.DisableInterruptOnComplete = 0; + /* point to the buffer */ + hal->rx_desc[i].Buffer1Addr = (uint32_t)(hal->rx_buf[i]); + /* point to next descriptor */ + hal->rx_desc[i].Buffer2NextDescAddr = (uint32_t)(hal->rx_desc + i + 1); + } + /* For last descriptor, set next descriptor address register equal to the first descriptor base address */ + hal->rx_desc[CONFIG_ETH_DMA_RX_BUFFER_NUM - 1].Buffer2NextDescAddr = (uint32_t)(hal->rx_desc); + + /* init tx chain */ + for (int i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) { + /* Set Second Address Chained bit */ + hal->tx_desc[i].TDES0.SecondAddressChained = 1; + hal->tx_desc[i].TDES1.TransmitBuffer1Size = CONFIG_ETH_DMA_BUFFER_SIZE; + /* Enable Ethernet DMA Tx Descriptor interrupt */ + hal->tx_desc[1].TDES0.InterruptOnComplete = 1; + /* Enable Transmit Timestamp */ + hal->tx_desc[i].TDES0.TransmitTimestampEnable = 1; + /* point to the buffer */ + hal->tx_desc[i].Buffer1Addr = (uint32_t)(hal->tx_buf[i]); + /* point to next descriptor */ + hal->tx_desc[i].Buffer2NextDescAddr = (uint32_t)(hal->tx_desc + i + 1); + } + /* For last descriptor, set next descriptor address register equal to the first descriptor base address */ + hal->tx_desc[CONFIG_ETH_DMA_TX_BUFFER_NUM - 1].Buffer2NextDescAddr = (uint32_t)(hal->tx_desc); + + /* set base address of the first descriptor */ + hal->dma_regs->dmarxbaseaddr = (uint32_t)hal->rx_desc; + hal->dma_regs->dmatxbaseaddr = (uint32_t)hal->tx_desc; +} + +void emac_hal_init_mac_default(emac_hal_context_t *hal) +{ + /* MACCR Configuration */ + typeof(hal->mac_regs->gmacconfig) maccr = hal->mac_regs->gmacconfig; + /* Enable the watchdog on the receiver, frame longer than 2048 Bytes is not allowed */ + maccr.watchdog = EMAC_WATCHDOG_ENABLE; + /* Enable the jabber timer on the transmitter, frame longer than 2048 Bytes is not allowed */ + maccr.jabber = EMAC_JABBER_ENABLE; + /* minimum IFG between frames during transmission is 96 bit times */ + maccr.interframegap = EMAC_INTERFRAME_GAP_96BIT; + /* Enable Carrier Sense During Transmission */ + maccr.disablecrs = EMAC_CARRIERSENSE_ENABLE; + /* Select port: 10/100 Mbps */ + maccr.mii = EMAC_PORT_10_100MBPS; + /* Select speed: here set default 100M, afterwards, will reset by auto-negotiation */ + maccr.fespeed = EMAC_SPEED_100M; + /* Allow the reception of frames when the TX_EN signal is asserted in Half-Duplex mode */ + maccr.rxown = EMAC_RECEIVE_OWN_ENABLE; + /* Disable internal loopback mode */ + maccr.loopback = EMAC_LOOPBACK_DISABLE; + /* Select duplex mode: here set default full duplex, afterwards, will reset by auto-negotiation */ + maccr.duplex = EMAC_DUPLEX_FULL; + /* Select the checksum mode for received frame payload's TCP/UDP/ICMP headers */ + maccr.rxipcoffload = EMAC_CHECKSUM_HW; + /* Enable MAC retry transmission when a colision occurs in half duplex mode */ + maccr.retry = EMAC_RETRY_TRANSMISSION_ENABLE; + /* MAC passes all incoming frames to host, without modifying them */ + maccr.padcrcstrip = EMAC_AUTO_PAD_CRC_STRIP_DISABLE; + /* Set Back-Off limit time before retry a transmittion after a collision */ + maccr.backofflimit = EMAC_BACKOFF_LIMIT_10; + /* Disable deferral check, MAC defers until the CRS signal goes inactive */ + maccr.deferralcheck = EMAC_DEFERRAL_CHECK_DISABLE; + /* Set preamble length 7 Bytes */ + maccr.pltf = EMAC_PREAMBLE_LENGTH_7; + hal->mac_regs->gmacconfig = maccr; + + /* MACFFR Configuration */ + typeof(hal->mac_regs->gmacff) macffr = hal->mac_regs->gmacff; + /* Receiver module passes only those frames to the Application that pass the SA or DA address filter */ + macffr.receive_all = EMAC_RECEIVE_ALL_DISABLE; + /* Disable source address filter */ + macffr.safe = EMAC_SOURCE_ADDR_FILTER_DISABLE; + macffr.saif = 0; + /* MAC blocks all control frames */ + macffr.pcf = EMAC_CONTROL_FRAME_BLOCKALL; + /* AFM module passes all received broadcast frames and multicast frames */ + macffr.dbf = EMAC_RECEPT_BROADCAST_ENABLE; + macffr.pam = 1; + /* Address Check block operates in normal filtering mode for the DA address */ + macffr.daif = EMAC_DEST_ADDR_FILTER_NORMAL; + /* Disable Promiscuous Mode */ + macffr.pmode = EMAC_PROMISCUOUS_DISABLE; + hal->mac_regs->gmacff = macffr; + + /* MACFCR Configuration */ + typeof(hal->mac_regs->gmacfc) macfcr = hal->mac_regs->gmacfc; + /* Pause time */ + macfcr.pause_time = EMAC_PAUSE_TIME; + /* Enable generation of Zero-Quanta Pause Control frames */ + macfcr.dzpq = EMAC_ZERO_QUANTA_PAUSE_ENABLE; + /* Threshold of the PAUSE to be checked for automatic retransmission of PAUSE Frame */ + macfcr.plt = EMAC_PAUSE_LOW_THRESHOLD_MINUS_28; + /* Don't allow MAC detect Pause frames with MAC address0 unicast address and unique multicast address */ + macfcr.upfd = EMAC_UNICAST_PAUSE_DETECT_DISABLE; + /* Enable MAC to decode the received Pause frame and disable its transmitter for a specific time */ + macfcr.rfce = EMAC_RECEIVE_FLOW_CONTROL_ENABLE; + /* Enable MAC to transmit Pause frames in full duplex mode or the MAC back-pressure operation in half duplex mode */ + macfcr.tfce = EMAC_TRANSMIT_FLOW_CONTROL_ENABLE; + hal->mac_regs->gmacfc = macfcr; +} + +void emac_hal_init_dma_default(emac_hal_context_t *hal) +{ + /* DMAOMR Configuration */ + typeof(hal->dma_regs->dmaoperation_mode) dmaomr = hal->dma_regs->dmaoperation_mode; + /* Enable Dropping of TCP/IP Checksum Error Frames */ + dmaomr.dis_drop_tcpip_err_fram = EMAC_DROP_TCPIP_CHECKSUM_ERROR_ENABLE; + /* Enable Receive Store Forward */ + dmaomr.rx_store_forward = EMAC_RECEIVE_STORE_FORWARD_ENABLE; + /* Enable Flushing of Received Frames because of the unavailability of receive descriptors or buffers */ + dmaomr.dis_flush_recv_frames = EMAC_FLUSH_RECEIVED_FRAME_ENABLE; + /* Enable Transmit Store Forward */ + dmaomr.tx_str_fwd = EMAC_TRANSMIT_STORE_FORWARD_ENABLE; + /* Flush Transmit FIFO */ + dmaomr.flush_tx_fifo = 1; + /* Transmit Threshold Control */ + dmaomr.tx_thresh_ctrl = EMAC_TRANSMIT_THRESHOLD_CONTROL_64; + /* Disable Forward Error Frame */ + dmaomr.fwd_err_frame = EMAC_FORWARD_ERROR_FRAME_DISABLE; + /* Disable forward undersized good frame */ + dmaomr.fwd_under_gf = EMAC_FORWARD_UNDERSIZED_GOOD_FRAME_DISABLE; + /* Receive Threshold Control */ + dmaomr.rx_thresh_ctrl = EMAC_RECEIVE_THRESHOLD_CONTROL_64; + /* Allow the DMA to process a second frame of Transmit data even before obtaining the status for the first frame */ + dmaomr.opt_second_frame = EMAC_OPERATE_SECOND_FRAME_ENABLE; + hal->dma_regs->dmaoperation_mode = dmaomr; + + /* DMABMR Configuration */ + typeof(hal->dma_regs->dmabusmode) dmabmr = hal->dma_regs->dmabusmode; + /* Enable Mixed Burst */ + dmabmr.dmamixedburst = EMAC_MIXED_BURST_ENABLE; + /* Enable Address Aligned Beates */ + dmabmr.dmaaddralibea = EMAC_ADDR_ALIGN_BEATS_ENABLE; + /* Use Separate PBL */ + dmabmr.use_sep_pbl = EMAC_USE_SEPARATE_PBL; + /* Set Rx/Tx DMA Burst Length */ + dmabmr.rx_dma_pbl = EMAC_DMA_BURST_LENGTH_32BEAT; + dmabmr.prog_burst_len = EMAC_DMA_BURST_LENGTH_32BEAT; + /* Enable Enhanced Descriptor,8 Words(32 Bytes) */ + dmabmr.alt_desc_size = EMAC_ENHANCED_DESCRIPTOR_ENABLE; + /* Specifies the number of word to skip between two unchained descriptors (Ring mode) */ + dmabmr.desc_skip_len = 0; + /* DMA Arbitration Scheme */ + dmabmr.dma_arb_sch = EMAC_DMA_ARBITRATION_SCHEME_ROUNDROBIN; + /* Set priority ratio in the weighted round-robin arbitration between Rx DMA and Tx DMA */ + dmabmr.pri_ratio = EMAC_DMA_ARBITRATION_ROUNDROBIN_RXTX_1_1; + hal->dma_regs->dmabusmode = dmabmr; +} + +void emac_hal_set_speed(emac_hal_context_t *hal, uint32_t speed) +{ + hal->mac_regs->gmacconfig.fespeed = speed; +} + +void emac_hal_set_duplex(emac_hal_context_t *hal, uint32_t duplex) +{ + hal->mac_regs->gmacconfig.duplex = duplex; +} + +void emac_hal_set_promiscuous(emac_hal_context_t *hal, bool enable) +{ + if (enable) { + hal->mac_regs->gmacff.pmode = 1; + } else { + hal->mac_regs->gmacff.pmode = 0; + } +} + +bool emac_hal_is_mii_busy(emac_hal_context_t *hal) +{ + return hal->mac_regs->emacgmiiaddr.miibusy ? true : false; +} + +void emac_hal_set_phy_cmd(emac_hal_context_t *hal, uint32_t phy_addr, uint32_t phy_reg, bool write) +{ + typeof(hal->mac_regs->emacgmiiaddr) macmiiar = hal->mac_regs->emacgmiiaddr; + macmiiar.miidev = phy_addr; + /* Set the PHY register address */ + macmiiar.miireg = phy_reg; + if (write) { + /* Set write mode */ + macmiiar.miiwrite = 1; + } else { + /* Set read mode */ + macmiiar.miiwrite = 0; + } + /* Set MII busy bit */ + macmiiar.miibusy = 1; + /* Write the result value into the MII Address register */ + hal->mac_regs->emacgmiiaddr = macmiiar; +} + +void emac_hal_set_phy_data(emac_hal_context_t *hal, uint32_t reg_value) +{ + hal->mac_regs->emacmiidata.mii_data = reg_value; +} + +uint32_t emac_hal_get_phy_data(emac_hal_context_t *hal) +{ + return hal->mac_regs->emacmiidata.mii_data; +} + +void emac_hal_set_address(emac_hal_context_t *hal, uint8_t *mac_addr) +{ + /* Make sure mac address is unicast type */ + if (!(mac_addr[0] & 0x01)) { + hal->mac_regs->emacaddr0high.address0_hi = (mac_addr[5] << 8) | mac_addr[4]; + hal->mac_regs->emacaddr0low = (mac_addr[3] << 24) | (mac_addr[2] << 16) | (mac_addr[1] << 8) | (mac_addr[0]); + } +} + +void emac_hal_start(emac_hal_context_t *hal) +{ + typeof(hal->dma_regs->dmaoperation_mode) opm = hal->dma_regs->dmaoperation_mode; + typeof(hal->mac_regs->gmacconfig) cfg = hal->mac_regs->gmacconfig; + + /* Enable Ethernet MAC and DMA Interrupt */ + hal->dma_regs->dmain_en.val = 0xFFFFFFFF; + + /* Flush Transmit FIFO */ + opm.flush_tx_fifo = 1; + /* Start DMA transmission */ + opm.start_stop_transmission_command = 1; + /* Start DMA reception */ + opm.start_stop_rx = 1; + /* Enable transmit state machine of the MAC for transmission on the MII */ + cfg.tx = 1; + /* Enable receive state machine of the MAC for reception from the MII */ + cfg.rx = 1; + + hal->dma_regs->dmaoperation_mode = opm; + hal->mac_regs->gmacconfig = cfg; + + /* Clear all pending interrupts */ + hal->dma_regs->dmastatus.val = 0xFFFFFFFF; +} + +void emac_hal_stop(emac_hal_context_t *hal) +{ + typeof(hal->dma_regs->dmaoperation_mode) opm = hal->dma_regs->dmaoperation_mode; + typeof(hal->mac_regs->gmacconfig) cfg = hal->mac_regs->gmacconfig; + + /* Flush Transmit FIFO */ + opm.flush_tx_fifo = 1; + /* Stop DMA transmission */ + opm.start_stop_transmission_command = 0; + /* Stop DMA reception */ + opm.start_stop_rx = 0; + /* Disable receive state machine of the MAC for reception from the MII */ + cfg.rx = 0; + /* Disable transmit state machine of the MAC for transmission on the MII */ + cfg.tx = 0; + + hal->dma_regs->dmaoperation_mode = opm; + hal->mac_regs->gmacconfig = cfg; + + /* Disable Ethernet MAC and DMA Interrupt */ + hal->dma_regs->dmain_en.val = 0x0; +} + +uint32_t emac_hal_get_tx_desc_owner(emac_hal_context_t *hal) +{ + return hal->tx_desc->TDES0.Own; +} + +void emac_hal_transmit_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t length) +{ + /* Get the number of Tx buffers to use for the frame */ + uint32_t bufcount = 0; + uint32_t lastlen = length; + while (lastlen > CONFIG_ETH_DMA_BUFFER_SIZE) { + lastlen -= CONFIG_ETH_DMA_BUFFER_SIZE; + bufcount++; + } + if (lastlen) { + bufcount++; + } + /* A frame is transmitted in multiple descriptor */ + for (uint32_t i = 0; i < bufcount; i++) { + /* Clear FIRST and LAST segment bits */ + hal->tx_desc->TDES0.FirstSegment = 0; + hal->tx_desc->TDES0.LastSegment = 0; + if (i == 0) { + /* Setting the first segment bit */ + hal->tx_desc->TDES0.FirstSegment = 1; + } + if (i == (bufcount - 1)) { + /* Setting the last segment bit */ + hal->tx_desc->TDES0.LastSegment = 1; + /* Enable transmit interrupt */ + hal->tx_desc->TDES0.InterruptOnComplete = 1; + /* Program size */ + hal->tx_desc->TDES1.TransmitBuffer1Size = lastlen; + /* copy data from uplayer stack buffer */ + memcpy((void *)(hal->tx_desc->Buffer1Addr), buf + i * CONFIG_ETH_DMA_BUFFER_SIZE, lastlen); + } else { + /* Program size */ + hal->tx_desc->TDES1.TransmitBuffer1Size = CONFIG_ETH_DMA_BUFFER_SIZE; + /* copy data from uplayer stack buffer */ + memcpy((void *)(hal->tx_desc->Buffer1Addr), buf + i * CONFIG_ETH_DMA_BUFFER_SIZE, CONFIG_ETH_DMA_BUFFER_SIZE); + } + /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */ + hal->tx_desc->TDES0.Own = EMAC_DMADESC_OWNER_DMA; + /* Point to next descriptor */ + hal->tx_desc = (eth_dma_tx_descriptor_t *)(hal->tx_desc->Buffer2NextDescAddr); + } + hal->dma_regs->dmatxpolldemand = 0; +} + +uint32_t emac_hal_receive_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t *frames_remain) +{ + eth_dma_rx_descriptor_t *desc_iter = NULL; + eth_dma_rx_descriptor_t *first_desc = NULL; + uint32_t iter = 0; + uint32_t seg_count = 0; + uint32_t len = 0; + uint32_t frame_count = 0; + + first_desc = hal->rx_desc; + desc_iter = hal->rx_desc; + /* Traverse descriptors owned by CPU */ + while ((desc_iter->RDES0.Own != EMAC_DMADESC_OWNER_DMA) && (iter < CONFIG_ETH_DMA_RX_BUFFER_NUM) && !frame_count) { + iter++; + seg_count++; + /* Last segment in frame */ + if (desc_iter->RDES0.LastDescriptor) { + /* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */ + len = desc_iter->RDES0.FrameLength - ETH_CRC_LENGTH; + /* update unhandled frame count */ + frame_count++; + } + /* First segment in frame */ + if (desc_iter->RDES0.FirstDescriptor) { + first_desc = desc_iter; + } + /* point to next descriptor */ + desc_iter = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr); + } + /* there's at least one frame to process */ + if (frame_count) { + /* check how many frames left to handle */ + while ((desc_iter->RDES0.Own != EMAC_DMADESC_OWNER_DMA) && (iter < CONFIG_ETH_DMA_RX_BUFFER_NUM)) { + iter++; + if (desc_iter->RDES0.LastDescriptor) { + frame_count++; + } + /* point to next descriptor */ + desc_iter = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr); + } + desc_iter = first_desc; + for (iter = 0; iter < seg_count - 1; iter++) { + /* copy data to buffer */ + memcpy(buf + iter * CONFIG_ETH_DMA_BUFFER_SIZE, + (void *)(desc_iter->Buffer1Addr), CONFIG_ETH_DMA_BUFFER_SIZE); + /* Set Own bit in Rx descriptors: gives the buffers back to DMA */ + desc_iter->RDES0.Own = EMAC_DMADESC_OWNER_DMA; + desc_iter = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr); + } + memcpy(buf + iter * CONFIG_ETH_DMA_BUFFER_SIZE, + (void *)(desc_iter->Buffer1Addr), len % CONFIG_ETH_DMA_BUFFER_SIZE); + desc_iter->RDES0.Own = EMAC_DMADESC_OWNER_DMA; + /* update rxdesc */ + hal->rx_desc = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr); + /* poll rx demand */ + hal->dma_regs->dmarxpolldemand = 0; + frame_count--; + } + *frames_remain = frame_count; + return len; +} + +void emac_hal_isr(void *arg) +{ + emac_hal_context_t *hal = (emac_hal_context_t *)arg; + typeof(hal->dma_regs->dmastatus) dma_status = hal->dma_regs->dmastatus; + /* DMA Normal Interrupt */ + if (dma_status.norm_int_summ) { + /* Transmit Interrupt */ + if (dma_status.trans_int) { + emac_hal_tx_complete_cb(arg); + hal->dma_regs->dmastatus.trans_int = 1; + } + /* Transmit Buffer Unavailable */ + if (dma_status.trans_buf_unavail) { + emac_hal_tx_unavail_cb(arg); + hal->dma_regs->dmastatus.trans_buf_unavail = 1; + } + /* Receive Interrupt */ + if (dma_status.recv_int) { + emac_hal_rx_complete_cb(arg); + hal->dma_regs->dmastatus.recv_int = 1; + } + /* Early Receive Interrupt */ + if (dma_status.early_recv_int) { + emac_hal_rx_early_cb(arg); + hal->dma_regs->dmastatus.early_recv_int = 1; + } + hal->dma_regs->dmastatus.norm_int_summ = 1; + } + /* DMA Abnormal Interrupt */ + if (dma_status.abn_int_summ) { + /* Transmit Process Stopped */ + if (dma_status.trans_proc_stop) { + hal->dma_regs->dmastatus.trans_proc_stop = 1; + } + /* Transmit Jabber Timeout */ + if (dma_status.trans_jabber_to) { + hal->dma_regs->dmastatus.trans_jabber_to = 1; + } + /* Receive FIFO Overflow */ + if (dma_status.recv_ovflow) { + hal->dma_regs->dmastatus.recv_ovflow = 1; + } + /* Transmit Underflow */ + if (dma_status.trans_undflow) { + hal->dma_regs->dmastatus.trans_undflow = 1; + } + /* Receive Buffer Unavailable */ + if (dma_status.recv_buf_unavail) { + emac_hal_rx_unavail_cb(arg); + hal->dma_regs->dmastatus.recv_buf_unavail = 1; + } + /* Receive Process Stopped */ + if (dma_status.recv_proc_stop) { + hal->dma_regs->dmastatus.recv_proc_stop = 1; + } + /* Receive Watchdog Timeout */ + if (dma_status.recv_wdt_to) { + hal->dma_regs->dmastatus.recv_wdt_to = 1; + } + /* Early Transmit Interrupt */ + if (dma_status.early_trans_int) { + hal->dma_regs->dmastatus.early_trans_int = 1; + } + /* Fatal Bus Error */ + if (dma_status.fatal_bus_err_int) { + hal->dma_regs->dmastatus.fatal_bus_err_int = 1; + } + hal->dma_regs->dmastatus.abn_int_summ = 1; + } +} + +__attribute__((weak)) void emac_hal_tx_complete_cb(void *arg) +{ + // This is a weak function, do nothing by default + // Upper code can rewrite this function + // Note: you're in the interrupt context + return; +} + +__attribute__((weak)) void emac_hal_tx_unavail_cb(void *arg) +{ + // This is a weak function, do nothing by default + // Upper code can rewrite this function + // Note: you're in the interrupt context + return; +} + +__attribute__((weak)) void emac_hal_rx_complete_cb(void *arg) +{ + // This is a weak function, do nothing by default + // Upper code can rewrite this function + // Note: you're in the interrupt context + return; +} + +__attribute__((weak)) void emac_hal_rx_early_cb(void *arg) +{ + // This is a weak function, do nothing by default + // Upper code can rewrite this function + // Note: you're in the interrupt context + return; +} + +__attribute__((weak)) void emac_hal_rx_unavail_cb(void *arg) +{ + // This is a weak function, do nothing by default + // Upper code can rewrite this function + // Note: you're in the interrupt context + return; +} diff --git a/components/soc/esp32/include/hal/emac.h b/components/soc/esp32/include/hal/emac.h new file mode 100644 index 0000000000..1b21897b6a --- /dev/null +++ b/components/soc/esp32/include/hal/emac.h @@ -0,0 +1,399 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "esp_err.h" +#include "soc/emac_dma_struct.h" +#include "soc/emac_mac_struct.h" +#include "soc/emac_ext_struct.h" + +#define EMAC_MEDIA_INTERFACE_MII (0) +#define EMAC_MEDIA_INTERFACE_RMII (1) + +#define EMAC_WATCHDOG_ENABLE (0) +#define EMAC_WATCHDOG_DISABLE (1) + +#define EMAC_JABBER_ENABLE (0) +#define EMAC_JABBER_DISABLE (1) + +#define EMAC_INTERFRAME_GAP_96BIT (0) +#define EMAC_INTERFRAME_GAP_88BIT (1) +#define EMAC_INTERFRAME_GAP_80BIT (2) +#define EMAC_INTERFRAME_GAP_72BIT (3) +#define EMAC_INTERFRAME_GAP_64BIT (4) +#define EMAC_INTERFRAME_GAP_56BIT (5) +#define EMAC_INTERFRAME_GAP_48BIT (6) +#define EMAC_INTERFRAME_GAP_40BIT (7) + +#define EMAC_CARRIERSENSE_ENABLE (0) +#define EMAC_CARRIERSENSE_DISABLE (1) + +#define EMAC_PORT_1000MBPS (0) +#define EMAC_PORT_10_100MBPS (1) + +#define EMAC_SPEED_10M (0) +#define EMAC_SPEED_100M (1) + +#define EMAC_RECEIVE_OWN_ENABLE (0) +#define EMAC_RECEIVE_OWN_DISABLE (1) + +#define EMAC_LOOPBACK_DISABLE (0) +#define EMAC_LOOPBACK_ENABLE (1) + +#define EMAC_DUPLEX_HALF (0) +#define EMAC_DUPLEX_FULL (1) + +#define EMAC_CHECKSUM_SW (0) +#define EMAC_CHECKSUM_HW (1) + +#define EMAC_RETRY_TRANSMISSION_ENABLE (0) +#define EMAC_RETRY_TRANSMISSION_DISABLE (1) + +#define EMAC_AUTO_PAD_CRC_STRIP_DISABLE (0) +#define EMAC_AUTO_PAD_CRC_STRIP_ENABLE (1) + +#define EMAC_BACKOFF_LIMIT_10 (0) +#define EMAC_BACKOFF_LIMIT_8 (1) +#define EMAC_BACKOFF_LIMIT_4 (2) +#define EMAC_BACKOFF_LIMIT_1 (3) + +#define EMAC_DEFERRAL_CHECK_DISABLE (0) +#define EMAC_DEFERRAL_CHECK_ENABLE (1) + +#define EMAC_PREAMBLE_LENGTH_7 (0) +#define EMAC_PREAMBLE_LENGTH_5 (1) +#define EMAC_PREAMBLE_LENGTH_3 (2) + +#define EMAC_RECEIVE_ALL_DISABLE (0) +#define EMAC_RECEIVE_ALL_ENABLE (1) + +#define EMAC_SOURCE_ADDR_FILTER_DISABLE (0) +#define EMAC_SOURCE_ADDR_FILTER_NORMAL (2) +#define EMAC_SOURCE_ADDR_FILTER_INVERSE (3) + +#define EMAC_CONTROL_FRAME_BLOCKALL (0) +#define EMAC_CONTROL_FRAME_FORWARDALL_PAUSE (1) +#define EMAC_CONTROL_FRAME_FORWARDALL (2) +#define EMAC_CONTROL_FRAME_FORWARDFILT (3) + +#define EMAC_RECEPT_BROADCAST_ENABLE (0) +#define EMAC_RECEPT_BROADCAST_DISABLE (1) + +#define EMAC_DEST_ADDR_FILTER_NORMAL (0) +#define EMAC_DEST_ADDR_FILTER_INVERSE (1) + +#define EMAC_PROMISCUOUS_DISABLE (0) +#define EMAC_PROMISCUOUS_ENABLE (1) + +#define EMAC_PAUSE_TIME 0x1648 + +#define EMAC_ZERO_QUANTA_PAUSE_ENABLE (0) +#define EMAC_ZERO_QUANTA_PAUSE_DISABLE (1) + +#define EMAC_PAUSE_LOW_THRESHOLD_MINUS_4 (0) +#define EMAC_PAUSE_LOW_THRESHOLD_MINUS_28 (1) +#define EMAC_PAUSE_LOW_THRESHOLD_MINUS_144 (2) +#define EMAC_PAUSE_LOW_THRESHOLD_MINUS_256 + +#define EMAC_UNICAST_PAUSE_DETECT_DISABLE (0) +#define EMAC_UNICAST_PAUSE_DETECT_ENABLE (1) + +#define EMAC_RECEIVE_FLOW_CONTROL_DISABLE (0) +#define EMAC_RECEIVE_FLOW_CONTROL_ENABLE (1) + +#define EMAC_TRANSMIT_FLOW_CONTROL_DISABLE (0) +#define EMAC_TRANSMIT_FLOW_CONTROL_ENABLE (1) + +#define EMAC_DROP_TCPIP_CHECKSUM_ERROR_ENABLE (0) +#define EMAC_DROP_TCPIP_CHECKSUM_ERROR_DISABLE (1) + +#define EMAC_RECEIVE_STORE_FORWARD_DISABLE (0) +#define EMAC_RECEIVE_STORE_FORWARD_ENABLE (1) + +#define EMAC_FLUSH_RECEIVED_FRAME_ENABLE (0) +#define EMAC_FLUSH_RECEIVED_FRAME_DISABLE (1) + +#define EMAC_TRANSMIT_STORE_FORWARD_DISABLE (0) +#define EMAC_TRANSMIT_STORE_FORWARD_ENABLE (1) + +#define EMAC_TRANSMIT_THRESHOLD_CONTROL_64 (0) +#define EMAC_TRANSMIT_THRESHOLD_CONTROL_128 (1) +#define EMAC_TRANSMIT_THRESHOLD_CONTROL_192 (2) +#define EMAC_TRANSMIT_THRESHOLD_CONTROL_256 (3) +#define EMAC_TRANSMIT_THRESHOLD_CONTROL_40 (4) +#define EMAC_TRANSMIT_THRESHOLD_CONTROL_32 (5) +#define EMAC_TRANSMIT_THRESHOLD_CONTROL_24 (6) +#define EMAC_TRANSMIT_THRESHOLD_CONTROL_16 (7) + +#define EMAC_FORWARD_ERROR_FRAME_DISABLE (0) +#define EMAC_FORWARD_ERROR_FRAME_ENABLE (1) + +#define EMAC_FORWARD_UNDERSIZED_GOOD_FRAME_DISABLE (0) +#define EMAC_FORWARD_UNDERSIZED_GOOD_FRAME_ENABLE (1) + +#define EMAC_RECEIVE_THRESHOLD_CONTROL_64 (0) +#define EMAC_RECEIVE_THRESHOLD_CONTROL_32 (1) +#define EMAC_RECEIVE_THRESHOLD_CONTROL_96 (2) +#define EMAC_RECEIVE_THRESHOLD_CONTROL_128 (3) + +#define EMAC_OPERATE_SECOND_FRAME_DISABLE (0) +#define EMAC_OPERATE_SECOND_FRAME_ENABLE (1) + +#define EMAC_MIXED_BURST_DISABLE (0) +#define EMAC_MIXED_BURST_ENABLE (1) + +#define EMAC_ADDR_ALIGN_BEATS_DISABLE (0) +#define EMAC_ADDR_ALIGN_BEATS_ENABLE (1) + +#define EMAC_UNUSE_SEPARATE_PBL (0) +#define EMAC_USE_SEPARATE_PBL (1) + +#define EMAC_DMA_BURST_LENGTH_1BEAT (1) +#define EMAC_DMA_BURST_LENGTH_2BEAT (2) +#define EMAC_DMA_BURST_LENGTH_4BEAT (4) +#define EMAC_DMA_BURST_LENGTH_8BEAT (8) +#define EMAC_DMA_BURST_LENGTH_16BEAT (16) +#define EMAC_DMA_BURST_LENGTH_32BEAT (32) + +#define EMAC_ENHANCED_DESCRIPTOR_DISABLE (0) +#define EMAC_ENHANCED_DESCRIPTOR_ENABLE (1) + +#define EMAC_DMA_ARBITRATION_SCHEME_ROUNDROBIN (0) +#define EMAC_DMA_ARBITRATION_SCHEME_FIXEDPRIO (1) + +#define EMAC_DMA_ARBITRATION_ROUNDROBIN_RXTX_1_1 (0) +#define EMAC_DMA_ARBITRATION_ROUNDROBIN_RXTX_2_1 (1) +#define EMAC_DMA_ARBITRATION_ROUNDROBIN_RXTX_3_1 (2) +#define EMAC_DMA_ARBITRATION_ROUNDROBIN_RXTX_4_1 (3) + +/** +* @brief Ethernet DMA TX Descriptor +* +*/ +typedef struct { + volatile union { + struct { + uint32_t Deferred : 1; /*!< MAC defers before transmission */ + uint32_t UnderflowErr : 1; /*!< DMA encountered an empty transmit buffer */ + uint32_t ExcessiveDeferral : 1; /*!< Excessive deferral of over 24,288 bit times */ + uint32_t CollisionCount : 4; /*!< Number of collisions occurred before transmitted */ + uint32_t VLanFrame : 1; /*!< Transmitted frame is a VLAN-type frame */ + uint32_t ExcessiveCollision : 1; /*!< Transmission aborted after 16 successive collisions */ + uint32_t LateCollision : 1; /*!< Collision occurred after the collision window */ + uint32_t NoCarrier : 1; /*!< Carrier Sense signal from the PHY was not asserted */ + uint32_t LossCarrier : 1; /*!< Loss of carrier occurred during transmission */ + uint32_t PayloadChecksumErr : 1; /*!< Checksum error in TCP/UDP/ICMP datagram payload */ + uint32_t FrameFlushed : 1; /*!< DMA or MTL flushed the frame */ + uint32_t JabberTimeout : 1; /*!< MAC transmitter has experienced a jabber timeout */ + uint32_t ErrSummary : 1; /*!< Error Summary */ + uint32_t IPHeadErr : 1; /*!< IP Header Error */ + uint32_t TxTimestampStatus : 1; /*!< Timestamp captured for the transmit frame */ + uint32_t VLANInsertControl : 2; /*!< VLAN tagging or untagging before transmitting */ + uint32_t SecondAddressChained : 1; /*!< Second address in the descriptor is Next Descriptor address */ + uint32_t TransmitEndRing : 1; /*!< Descriptor list reached its final descriptor */ + uint32_t ChecksumInsertControl : 2; /*!< Control checksum calculation and insertion */ + uint32_t CRCReplacementControl : 1; /*!< Control CRC replace */ + uint32_t TransmitTimestampEnable : 1; /*!< Enable IEEE1588 harware timestamping */ + uint32_t DisablePad : 1; /*!< Control add padding when frame short than 64 bytes */ + uint32_t DisableCRC : 1; /*!< Control append CRC to the end of frame */ + uint32_t FirstSegment : 1; /*!< Buffer contains the first segment of a frame */ + uint32_t LastSegment : 1; /*!< Buffer contains the last segment of a frame */ + uint32_t InterruptOnComplete : 1; /*!< Interrupt after frame transmitted */ + uint32_t Own : 1; /*!< Owner of this descriptor: DMA controller or host */ + }; + uint32_t Value; + } TDES0; + union { + struct { + uint32_t TransmitBuffer1Size : 13; /*!< First data buffer byte size */ + uint32_t Reserved : 3; /*!< Reserved */ + uint32_t TransmitBuffer2Size : 13; /*!< Second data buffer byte size */ + uint32_t SAInsertControl : 3; /*!< Control MAC add or replace Source Address field */ + }; + uint32_t Value; + } TDES1; + uint32_t Buffer1Addr; /*!< Buffer1 address pointer */ + uint32_t Buffer2NextDescAddr; /*!< Buffer2 or next descriptor address pointer */ + uint32_t Reserved1; /*!< Reserved */ + uint32_t Reserved2; /*!< Reserved */ + uint32_t TimeStampLow; /*!< Transmit Frame Timestamp Low */ + uint32_t TimeStampHigh; /*!< Transmit Frame Timestamp High */ +} eth_dma_tx_descriptor_t; +#define EMAC_DMATXDESC_CHECKSUM_BYPASS 0 /*!< Checksum engine bypass */ +#define EMAC_DMATXDESC_CHECKSUM_IPV4HEADER 1 /*!< IPv4 header checksum insertion */ +#define EMAC_DMATXDESC_CHECKSUM_TCPUDPICMPSEGMENT 2 /*!< TCP/UDP/ICMP Checksum Insertion calculated over segment only */ +#define EMAC_DMATXDESC_CHECKSUM_TCPUDPICMPFULL 3 /*!< TCP/UDP/ICMP Checksum Insertion fully calculated */ + +/** +* @brief Ethernet DMA RX Descriptor +* +*/ +typedef struct { + volatile union { + struct { + uint32_t ExtendStatusAvailable : 1; /*!< Extended statsu is available in RDES4 */ + uint32_t CRCErr : 1; /*!< CRC error occurred on frame */ + uint32_t DribbleBitErr : 1; /*!< frame contains non int multiple of 8 bits */ + uint32_t ReceiveErr : 1; /*!< Receive error */ + uint32_t ReceiveWatchdogTimeout : 1; /*!< Receive Watchdog timeout */ + uint32_t FrameType : 1; /*!< Ethernet type or IEEE802.3 */ + uint32_t LateCollision : 1; /*!< Late collision occurred during reception */ + uint32_t TSAvailIPChecksumErrGiantFrame : 1; /*!< Timestamp available or IP Checksum error or Giant frame */ + uint32_t LastDescriptor : 1; /*!< Last buffer of the frame */ + uint32_t FirstDescriptor : 1; /*!< First buffer of the frame */ + uint32_t VLANTag : 1; /*!< VLAN Tag: received frame is a VLAN frame */ + uint32_t OverflowErr : 1; /*!< Frame was damaged due to buffer overflow */ + uint32_t LengthErr : 1; /*!< Frame size not matching with length field */ + uint32_t SourceAddrFilterFail : 1; /*!< SA field of frame failed the SA filter */ + uint32_t DescriptorErr : 1; /*!< Frame truncated and DMA doesn't own next descriptor */ + uint32_t ErrSummary : 1; /*!< Error Summary, OR of all errors in RDES */ + uint32_t FrameLength : 14; /*!< Byte length of received frame */ + uint32_t DestinationAddrFilterFail : 1; /*!< Frame failed in the DA Filter in the MAC */ + uint32_t Own : 1; /*!< Owner of this descriptor: DMA controller or host */ + }; + uint32_t Value; + } RDES0; + union { + struct { + uint32_t ReceiveBuffer1Size : 13; /*!< First data buffer size in bytes */ + uint32_t Reserved1 : 1; /*!< Reserved */ + uint32_t SecondAddressChained : 1; /*!< Seconde address is the Next Descriptor address */ + uint32_t ReceiveEndOfRing : 1; /*!< Descriptor reached its final descriptor */ + uint32_t ReceiveBuffer2Size : 13; /*!< Second data buffer size in bytes */ + uint32_t Reserved : 2; /*!< Reserved */ + uint32_t DisableInterruptOnComplete : 1; /*!< Disable the assertion of interrupt to host */ + }; + uint32_t Value; + } RDES1; + uint32_t Buffer1Addr; /*!< Buffer1 address pointer */ + uint32_t Buffer2NextDescAddr; /*!< Buffer2 or next descriptor address pointer */ + volatile union { + struct { + uint32_t IPPayloadType : 3; /*!< Type of payload in the IP datagram */ + uint32_t IPHeadErr : 1; /*!< IP header error */ + uint32_t IPPayloadErr : 1; /*!< IP payload error */ + uint32_t IPChecksumBypass : 1; /*!< Checksum offload engine is bypassed */ + uint32_t IPv4PacketReceived : 1; /*!< Received packet is an IPv4 packet */ + uint32_t IPv6PacketReceived : 1; /*!< Received packet is an IPv6 packet */ + uint32_t MessageType : 4; /*!< PTP Message Type */ + uint32_t PTPFrameType : 1; /*!< PTP message is over Ethernet or IPv4/IPv6 */ + uint32_t PTPVersion : 1; /*!< Version of PTP protocol */ + uint32_t TimestampDropped : 1; /*!< Timestamp dropped because of overflow */ + uint32_t Reserved1 : 1; /*!< Reserved */ + uint32_t AVPacketReceived : 1; /*!< AV packet is received */ + uint32_t AVTaggedPacketReceived : 1; /*!< AV tagged packet is received */ + uint32_t VLANTagPrioVal : 3; /*!< VLAN tag's user value in the received packekt */ + uint32_t Reserved2 : 3; /*!< Reserved */ + uint32_t Layer3FilterMatch : 1; /*!< Received frame matches one of the enabled Layer3 IP */ + uint32_t Layer4FilterMatch : 1; /*!< Received frame matches one of the enabled Layer4 IP */ + uint32_t Layer3Layer4FilterNumberMatch : 2; /*!< Number of Layer3 and Layer4 Filter that matches the received frame */ + uint32_t Reserved3 : 4; /*!< Reserved */ + }; + uint32_t Value; + } ExtendedStatus; + uint32_t Reserved; /*!< Reserved */ + uint32_t TimeStampLow; /*!< Receive frame timestamp low */ + uint32_t TimeStampHigh; /*!< Receive frame timestamp high */ +} eth_dma_rx_descriptor_t; +#define EMAC_DMAPTPRXDESC_PTPMT_SYNC 0x00000100U /* SYNC message (all clock types) */ +#define EMAC_DMAPTPRXDESC_PTPMT_FOLLOWUP 0x00000200U /* FollowUp message (all clock types) */ +#define EMAC_DMAPTPRXDESC_PTPMT_DELAYREQ 0x00000300U /* DelayReq message (all clock types) */ +#define EMAC_DMAPTPRXDESC_PTPMT_DELAYRESP 0x00000400U /* DelayResp message (all clock types) */ +#define EMAC_DMAPTPRXDESC_PTPMT_PDELAYREQ_ANNOUNCE 0x00000500U /* PdelayReq message (peer-to-peer transparent clock) or Announce message (Ordinary or Boundary clock) */ +#define EMAC_DMAPTPRXDESC_PTPMT_PDELAYRESP_MANAG 0x00000600U /* PdelayResp message (peer-to-peer transparent clock) or Management message (Ordinary or Boundary clock) */ +#define EMAC_DMAPTPRXDESC_PTPMT_PDELAYRESPFOLLOWUP_SIGNAL 0x00000700U /* PdelayRespFollowUp message (peer-to-peer transparent clock) or Signaling message (Ordinary or Boundary clock) */ + +#define EMAC_DMAPTPRXDESC_IPPT_UDP 0x00000001U /* UDP payload encapsulated in the IP datagram */ +#define EMAC_DMAPTPRXDESC_IPPT_TCP 0x00000002U /* TCP payload encapsulated in the IP datagram */ +#define EMAC_DMAPTPRXDESC_IPPT_ICMP 0x00000003U /* ICMP payload encapsulated in the IP datagram */ + +#define EMAC_DMADESC_OWNER_CPU (0) +#define EMAC_DMADESC_OWNER_DMA (1) + +typedef struct { + emac_mac_dev_t *mac_regs; + emac_dma_dev_t *dma_regs; + emac_ext_dev_t *ext_regs; + uint8_t **rx_buf; + uint8_t **tx_buf; + void *descriptors; + eth_dma_rx_descriptor_t *rx_desc; + eth_dma_tx_descriptor_t *tx_desc; +} emac_hal_context_t; + +void emac_hal_init(emac_hal_context_t *hal, void *descriptors, + uint8_t **rx_buf, uint8_t **tx_buf); + +void emac_hal_reset_desc_chain(emac_hal_context_t *hal); + +void emac_hal_lowlevel_init(emac_hal_context_t *hal); + +void emac_hal_reset(emac_hal_context_t *hal); + +bool emac_hal_is_reset_done(emac_hal_context_t *hal); + +void emac_hal_set_csr_clock_range(emac_hal_context_t *hal); + +void emac_hal_init_mac_default(emac_hal_context_t *hal); + +void emac_hal_init_dma_default(emac_hal_context_t *hal); + +void emac_hal_set_speed(emac_hal_context_t *hal, uint32_t speed); + +void emac_hal_set_duplex(emac_hal_context_t *hal, uint32_t duplex); + +void emac_hal_set_promiscuous(emac_hal_context_t *hal, bool enable); + +bool emac_hal_is_mii_busy(emac_hal_context_t *hal); + +void emac_hal_set_phy_cmd(emac_hal_context_t *hal, uint32_t phy_addr, uint32_t phy_reg, bool write); + +void emac_hal_set_phy_data(emac_hal_context_t *hal, uint32_t reg_value); + +uint32_t emac_hal_get_phy_data(emac_hal_context_t *hal); + +void emac_hal_set_address(emac_hal_context_t *hal, uint8_t *mac_addr); + +void emac_hal_start(emac_hal_context_t *hal); + +void emac_hal_stop(emac_hal_context_t *hal); + +uint32_t emac_hal_get_tx_desc_owner(emac_hal_context_t *hal); + +void emac_hal_transmit_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t length); + +uint32_t emac_hal_receive_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t *frames_remain); + +void emac_hal_isr(void *arg); + +void emac_hal_tx_complete_cb(void *arg); + +void emac_hal_tx_unavail_cb (void *arg); + +void emac_hal_rx_complete_cb (void *arg); + +void emac_hal_rx_early_cb(void *arg); + +void emac_hal_rx_unavail_cb(void *arg); + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/esp32/include/hal/spi_flash_ll.h b/components/soc/esp32/include/hal/spi_flash_ll.h new file mode 100644 index 0000000000..5522a17219 --- /dev/null +++ b/components/soc/esp32/include/hal/spi_flash_ll.h @@ -0,0 +1,357 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/******************************************************************************* + * NOTICE + * The ll is not public api, don't use in application code. + * See readme.md in soc/include/hal/readme.md + ******************************************************************************/ + +// The Lowlevel layer for SPI Flash + +#pragma once + +#include +#include "soc/spi_periph.h" +#include "hal/spi_types.h" +#include "hal/spi_flash_types.h" +#include // For MIN/MAX +#include +#include + + +//Supported clock register values +#define SPI_FLASH_LL_CLKREG_VAL_5MHZ ((spi_flash_ll_clock_reg_t){.val=0x0000F1CF}) ///< Clock set to 5 MHz +#define SPI_FLASH_LL_CLKREG_VAL_10MHZ ((spi_flash_ll_clock_reg_t){.val=0x000070C7}) ///< Clock set to 10 MHz +#define SPI_FLASH_LL_CLKREG_VAL_20MHZ ((spi_flash_ll_clock_reg_t){.val=0x00003043}) ///< Clock set to 20 MHz +#define SPI_FLASH_LL_CLKREG_VAL_26MHZ ((spi_flash_ll_clock_reg_t){.val=0x00002002}) ///< Clock set to 26 MHz +#define SPI_FLASH_LL_CLKREG_VAL_40MHZ ((spi_flash_ll_clock_reg_t){.val=0x00001001}) ///< Clock set to 40 MHz +#define SPI_FLASH_LL_CLKREG_VAL_80MHZ ((spi_flash_ll_clock_reg_t){.val=0x80000000}) ///< Clock set to 80 MHz + +/// Get the start address of SPI peripheral registers by the host ID +#define spi_flash_ll_get_hw(host_id) ((host_id)==SPI1_HOST? &SPI1:((host_id)==SPI2_HOST?&SPI2:((host_id)==SPI3_HOST?&SPI3:({abort();(spi_dev_t*)0;})))) + +/// type to store pre-calculated register value in above layers +typedef typeof(SPI1.clock) spi_flash_ll_clock_reg_t; + +/*------------------------------------------------------------------------------ + * Control + *----------------------------------------------------------------------------*/ +/** + * Reset peripheral registers before configuration and starting control + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spi_flash_ll_reset(spi_dev_t *dev) +{ + dev->user.val = 0; + dev->ctrl.val = 0; +} + +/** + * Check whether the previous operation is done. + * + * @param dev Beginning address of the peripheral registers. + * + * @return true if last command is done, otherwise false. + */ +static inline bool spi_flash_ll_cmd_is_done(const spi_dev_t *dev) +{ + return (dev->cmd.val == 0); +} + +/** + * Erase the flash chip. + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spi_flash_ll_erase_chip(spi_dev_t *dev) +{ + dev->cmd.flash_ce = 1; +} + +/** + * Erase the sector, the address should be set by spi_flash_ll_set_address. + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spi_flash_ll_erase_sector(spi_dev_t *dev) +{ + dev->ctrl.val = 0; + dev->cmd.flash_se = 1; +} + +/** + * Erase the block, the address should be set by spi_flash_ll_set_address. + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spi_flash_ll_erase_block(spi_dev_t *dev) +{ + dev->cmd.flash_be = 1; +} + +/** + * Enable/disable write protection for the flash chip. + * + * @param dev Beginning address of the peripheral registers. + * @param wp true to enable the protection, false to disable (write enable). + */ +static inline void spi_flash_ll_set_write_protect(spi_dev_t *dev, bool wp) +{ + if (wp) { + dev->cmd.flash_wrdi = 1; + } else { + dev->cmd.flash_wren = 1; + } +} + +/** + * Get the read data from the buffer after ``spi_flash_ll_read`` is done. + * + * @param dev Beginning address of the peripheral registers. + * @param buffer Buffer to hold the output data + * @param read_len Length to get out of the buffer + */ +static inline void spi_flash_ll_get_buffer_data(spi_dev_t *dev, void *buffer, uint32_t read_len) +{ + if (((intptr_t)buffer % 4 == 0) && (read_len % 4 == 0)) { + // If everything is word-aligned, do a faster memcpy + memcpy(buffer, (void *)dev->data_buf, read_len); + } else { + // Otherwise, slow(er) path copies word by word + int copy_len = read_len; + for (int i = 0; i < (read_len + 3) / 4; i++) { + int word_len = MIN(sizeof(uint32_t), copy_len); + uint32_t word = dev->data_buf[i]; + memcpy(buffer, &word, word_len); + buffer = (void *)((intptr_t)buffer + word_len); + copy_len -= word_len; + } + } +} + +/** + * Write a word to the data buffer. + * + * @param dev Beginning address of the peripheral registers. + * @param word Data to write at address 0. + */ +static inline void spi_flash_ll_write_word(spi_dev_t *dev, uint32_t word) +{ + dev->data_buf[0] = word; +} + +/** + * Program a page of the flash chip. Call ``spi_flash_ll_set_address`` before + * this to set the address to program. + * + * @param dev Beginning address of the peripheral registers. + * @param buffer Buffer holding the data to program + * @param length Length to program. + */ +static inline void spi_flash_ll_program_page(spi_dev_t *dev, const void *buffer, uint32_t length) +{ + dev->user.usr_dummy = 0; + + // Load data registers, word at a time + int num_words = (length + 3) / 4; + for (int i = 0; i < num_words; i++) { + uint32_t word = 0; + uint32_t word_len = MIN(length, sizeof(word)); + memcpy(&word, buffer, word_len); + dev->data_buf[i] = word; + length -= word_len; + buffer = (void *)((intptr_t)buffer + word_len); + } + + dev->cmd.flash_pp = 1; +} + +/** + * Trigger a user defined transaction. All phases, including command, address, dummy, and the data phases, + * should be configured before this is called. + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spi_flash_ll_user_start(spi_dev_t *dev) +{ + dev->cmd.usr = 1; +} + +/** + * Check whether the host is idle to perform new commands. + * + * @param dev Beginning address of the peripheral registers. + * + * @return true if the host is idle, otherwise false + */ +static inline bool spi_flash_ll_host_idle(const spi_dev_t *dev) +{ + return dev->ext2.st != 0; +} + +/** + * Set phases for user-defined transaction to read + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spi_flash_ll_read_phase(spi_dev_t *dev) +{ + typeof (dev->user) user = { + .usr_command = 1, + .usr_mosi = 0, + .usr_miso = 1, + .usr_addr = 1, + }; + dev->user = user; +} +/*------------------------------------------------------------------------------ + * Configs + *----------------------------------------------------------------------------*/ +/** + * Select which pin to use for the flash + * + * @param dev Beginning address of the peripheral registers. + * @param pin Pin ID to use, 0-2. Set to other values to disable all the CS pins. + */ +static inline void spi_flash_ll_set_cs_pin(spi_dev_t *dev, int pin) +{ + dev->pin.cs0_dis = (pin == 0) ? 0 : 1; + dev->pin.cs1_dis = (pin == 1) ? 0 : 1; + dev->pin.cs2_dis = (pin == 2) ? 0 : 1; +} + +/** + * Set the read io mode. + * + * @param dev Beginning address of the peripheral registers. + * @param read_mode I/O mode to use in the following transactions. + */ +static inline void spi_flash_ll_set_read_mode(spi_dev_t *dev, esp_flash_read_mode_t read_mode) +{ + typeof (dev->ctrl) ctrl = dev->ctrl; + ctrl.val &= ~(SPI_FREAD_QIO_M | SPI_FREAD_QUAD_M | SPI_FREAD_DIO_M | SPI_FREAD_DUAL_M); + ctrl.val |= SPI_FASTRD_MODE_M; + switch (read_mode) { + case SPI_FLASH_FASTRD: + //the default option + break; + case SPI_FLASH_QIO: + ctrl.fread_qio = 1; + break; + case SPI_FLASH_QOUT: + ctrl.fread_quad = 1; + break; + case SPI_FLASH_DIO: + ctrl.fread_dio = 1; + break; + case SPI_FLASH_DOUT: + ctrl.fread_dual = 1; + break; + case SPI_FLASH_SLOWRD: + ctrl.fastrd_mode = 0; + break; + default: + abort(); + } + dev->ctrl = ctrl; +} + +/** + * Set clock frequency to work at. + * + * @param dev Beginning address of the peripheral registers. + * @param clock_val pointer to the clock value to set + */ +static inline void spi_flash_ll_set_clock(spi_dev_t *dev, spi_flash_ll_clock_reg_t *clock_val) +{ + dev->clock = *clock_val; +} + +/** + * Set the input length, in bits. + * + * @param dev Beginning address of the peripheral registers. + * @param bitlen Length of input, in bits. + */ +static inline void spi_flash_ll_set_miso_bitlen(spi_dev_t *dev, uint32_t bitlen) +{ + dev->user.usr_miso = bitlen > 0; + dev->miso_dlen.usr_miso_dbitlen = bitlen ? (bitlen - 1) : 0; +} + +/** + * Set the output length, in bits (not including command, address and dummy + * phases) + * + * @param dev Beginning address of the peripheral registers. + * @param bitlen Length of output, in bits. + */ +static inline void spi_flash_ll_set_mosi_bitlen(spi_dev_t *dev, uint32_t bitlen) +{ + dev->user.usr_mosi = bitlen > 0; + dev->mosi_dlen.usr_mosi_dbitlen = bitlen ? (bitlen - 1) : 0; +} + +/** + * Set the command with fixed length (8 bits). + * + * @param dev Beginning address of the peripheral registers. + * @param command Command to send + */ +static inline void spi_flash_ll_set_command8(spi_dev_t *dev, uint8_t command) +{ + dev->user.usr_command = 1; + typeof(dev->user2) user2 = { + .usr_command_value = command, + .usr_command_bitlen = (8 - 1), + }; + dev->user2 = user2; +} + +/** + * Set the address length to send, in bits. Should be called before commands that requires the address e.g. erase sector, read, write... + * + * @param dev Beginning address of the peripheral registers. + * @param bitlen Length of the address, in bits + */ +static inline void spi_flash_ll_set_addr_bitlen(spi_dev_t *dev, uint32_t bitlen) +{ + dev->user1.usr_addr_bitlen = (bitlen - 1); + dev->user.usr_addr = bitlen ? 1 : 0; +} + +/** + * Set the address to send. Should be called before commands that requires the address e.g. erase sector, read, write... + * + * @param dev Beginning address of the peripheral registers. + * @param addr Address to send + */ +static inline void spi_flash_ll_set_address(spi_dev_t *dev, uint32_t addr) +{ + dev->addr = addr; +} + +/** + * Set the length of dummy cycles. + * + * @param dev Beginning address of the peripheral registers. + * @param dummy_n Cycles of dummy phases + */ +static inline void spi_flash_ll_set_dummy(spi_dev_t *dev, uint32_t dummy_n) +{ + dev->user.usr_dummy = dummy_n ? 1 : 0; + dev->user1.usr_dummy_cyclelen = dummy_n - 1; +} diff --git a/components/soc/esp32/include/soc/cpu.h b/components/soc/esp32/include/soc/cpu.h index f28feb59fa..190786a433 100644 --- a/components/soc/esp32/include/soc/cpu.h +++ b/components/soc/esp32/include/soc/cpu.h @@ -110,4 +110,25 @@ void esp_cpu_reset(int cpu_id); */ bool esp_cpu_in_ocd_debug_mode(); +/** + * @brief Convert the PC register value to its true address + * + * The address of the current instruction is not stored as an exact uint32_t + * representation in PC register. This function will convert the value stored in + * the PC register to a uint32_t address. + * + * @param pc_raw The PC as stored in register format. + * + * @return Address in uint32_t format + */ +static inline uint32_t esp_cpu_process_stack_pc(uint32_t pc) +{ + if (pc & 0x80000000) { + //Top two bits of a0 (return address) specify window increment. Overwrite to map to address space. + pc = (pc & 0x3fffffff) | 0x40000000; + } + //Minus 3 to get PC of previous instruction (i.e. instruction executed before return address) + return pc - 3; +} + #endif diff --git a/components/soc/esp32/include/soc/emac_dma_struct.h b/components/soc/esp32/include/soc/emac_dma_struct.h new file mode 100644 index 0000000000..35d1361281 --- /dev/null +++ b/components/soc/esp32/include/soc/emac_dma_struct.h @@ -0,0 +1,162 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + +typedef volatile struct { + union { + struct { + uint32_t sw_rst : 1; /*When this bit is set the MAC DMA Controller resets the logic and all internal registers of the MAC. It is cleared automatically after the reset operation is complete in all of the ETH_MAC clock domains. Before reprogramming any register of the ETH_MAC you should read a zero (0) value in this bit.*/ + uint32_t dma_arb_sch : 1; /*This bit specifies the arbitration scheme between the transmit and receive paths.1'b0: weighted round-robin with RX:TX or TX:RX priority specified in PR (bit[15:14]). 1'b1 Fixed priority (Rx priority to Tx).*/ + uint32_t desc_skip_len : 5; /*This bit specifies the number of Word to skip between two unchained descriptors.The address skipping starts from the end of current descriptor to the start of next descriptor. When the DSL(DESC_SKIP_LEN) value is equal to zero the descriptor table is taken as contiguous by the DMA in Ring mode.*/ + uint32_t alt_desc_size : 1; /*When set the size of the alternate descriptor increases to 32 bytes.*/ + uint32_t prog_burst_len : 6; /*These bits indicate the maximum number of beats to be transferred in one DMA transaction. If the number of beats to be transferred is more than 32 then perform the following steps: 1. Set the PBLx8 mode 2. Set the PBL(PROG_BURST_LEN).*/ + uint32_t pri_ratio : 2; /*These bits control the priority ratio in the weighted round-robin arbitration between the Rx DMA and Tx DMA. These bits are valid only when Bit 1 (DA) is reset. The priority ratio Rx:Tx represented by each bit: 2'b00 -- 1: 1 2'b01 -- 2: 0 2'b10 -- 3: 1 2'b11 -- 4: 1*/ + uint32_t fixed_burst : 1; /*This bit controls whether the AHB master interface performs fixed burst transfers or not. When set the AHB interface uses only SINGLE INCR4 INCR8 or INCR16 during start of the normal burst transfers. When reset the AHB interface uses SINGLE and INCR burst transfer Operations.*/ + uint32_t rx_dma_pbl : 6; /*This field indicates the maximum number of beats to be transferred in one Rx DMA transaction. This is the maximum value that is used in a single block Read or Write.The Rx DMA always attempts to burst as specified in the RPBL(RX_DMA_PBL) bit each time it starts a burst transfer on the host bus. You can program RPBL with values of 1 2 4 8 16 and 32. Any other value results in undefined behavior. This field is valid and applicable only when USP(USE_SEP_PBL) is set high.*/ + uint32_t use_sep_pbl : 1; /*When set high this bit configures the Rx DMA to use the value configured in Bits[22:17] as PBL. The PBL value in Bits[13:8] is applicable only to the Tx DMA operations. When reset to low the PBL value in Bits[13:8] is applicable for both DMA engines.*/ + uint32_t pblx8_mode : 1; /*When set high this bit multiplies the programmed PBL value (Bits[22:17] and Bits[13:8]) eight times. Therefore the DMA transfers the data in 8 16 32 64 128 and 256 beats depending on the PBL value.*/ + uint32_t dmaaddralibea : 1; /*When this bit is set high and the FIXED_BURST bit is 1 the AHB interface generates all bursts aligned to the start address LS bits. If the FIXED_BURST bit is 0 the first burst (accessing the start address of data buffer) is not aligned but subsequent bursts are aligned to the address.*/ + uint32_t dmamixedburst : 1; /*When this bit is set high and the FIXED_BURST bit is low the AHB master interface starts all bursts of a length more than 16 with INCR (undefined burst) whereas it reverts to fixed burst transfers (INCRx and SINGLE) for burst length of 16 and less.*/ + uint32_t reserved27 : 1; + uint32_t reserved28 : 2; + uint32_t reserved30 : 1; + uint32_t reserved31 : 1; + }; + uint32_t val; + } dmabusmode; + uint32_t dmatxpolldemand; /*When these bits are written with any value the DMA reads the current descriptor to which the Register (Current Host Transmit Descriptor Register) is pointing. If that descriptor is not available (owned by the Host) the transmission returns to the suspend state and Bit[2] (TU) of Status Register is asserted. If the descriptor is available the transmission resumes.*/ + uint32_t dmarxpolldemand; /*When these bits are written with any value the DMA reads the current descriptor to which the Current Host Receive Descriptor Register is pointing. If that descriptor is not available (owned by the Host) the reception returns to the Suspended state and Bit[7] (RU) of Status Register is asserted. If the descriptor is available the Rx DMA returns to the active state.*/ + uint32_t dmarxbaseaddr; /*This field contains the base address of the first descriptor in the Receive Descriptor list. The LSB Bits[1:0] are ignored and internally taken as all-zero by the DMA. Therefore these LSB bits are read-only.*/ + uint32_t dmatxbaseaddr; /*This field contains the base address of the first descriptor in the Transmit Descriptor list. The LSB Bits[1:0] are ignored and are internally taken as all-zero by the DMA.Therefore these LSB bits are read-only.*/ + union { + struct { + uint32_t trans_int : 1; /*This bit indicates that the frame transmission is complete. When transmission is complete Bit[31] (OWN) of TDES0 is reset and the specific frame status information is updated in the Descriptor.*/ + uint32_t trans_proc_stop : 1; /*This bit is set when the transmission is stopped.*/ + uint32_t trans_buf_unavail : 1; /*This bit indicates that the host owns the Next Descriptor in the Transmit List and the DMA cannot acquire it. Transmission is suspended. Bits[22:20] explain the Transmit Process state transitions. To resume processing Transmit descriptors the host should change the ownership of the descriptor by setting TDES0[31] and then issue a Transmit Poll Demand Command.*/ + uint32_t trans_jabber_to : 1; /*This bit indicates that the Transmit Jabber Timer expired which happens when the frame size exceeds 2 048 (10 240 bytes when the Jumbo frame is enabled). When the Jabber Timeout occurs the transmission process is aborted and placed in the Stopped state. This causes the Transmit Jabber Timeout TDES0[14] flag to assert.*/ + uint32_t recv_ovflow : 1; /*This bit indicates that the Receive Buffer had an Overflow during frame reception. If the partial frame is transferred to the application the overflow status is set in RDES0[11].*/ + uint32_t trans_undflow : 1; /*This bit indicates that the Transmit Buffer had an Underflow during frame transmission. Transmission is suspended and an Underflow Error TDES0[1] is set.*/ + uint32_t recv_int : 1; /*This bit indicates that the frame reception is complete. When reception is complete the Bit[31] of RDES1 (Disable Interrupt on Completion) is reset in the last Descriptor and the specific frame status information is updated in the descriptor. The reception remains in the Running state.*/ + uint32_t recv_buf_unavail : 1; /*This bit indicates that the host owns the Next Descriptor in the Receive List and the DMA cannot acquire it. The Receive Process is suspended. To resume processing Receive descriptors the host should change the ownership of the descriptor and issue a Receive Poll Demand command. If no Receive Poll Demand is issued the Receive Process resumes when the next recognized incoming frame is received. This bit is set only when the previous Receive Descriptor is owned by the DMA.*/ + uint32_t recv_proc_stop : 1; /*This bit is asserted when the Receive Process enters the Stopped state.*/ + uint32_t recv_wdt_to : 1; /*When set this bit indicates that the Receive Watchdog Timer expired while receiving the current frame and the current frame is truncated after the watchdog timeout.*/ + uint32_t early_trans_int : 1; /*This bit indicates that the frame to be transmitted is fully transferred to the MTL Transmit FIFO.*/ + uint32_t reserved11 : 2; + uint32_t fatal_bus_err_int : 1; /*This bit indicates that a bus error occurred as described in Bits [25:23]. When this bit is set the corresponding DMA engine disables all of its bus accesses.*/ + uint32_t early_recv_int : 1; /*This bit indicates that the DMA filled the first data buffer of the packet. This bit is cleared when the software writes 1 to this bit or when Bit[6] (RI) of this register is set (whichever occurs earlier).*/ + uint32_t abn_int_summ : 1; /*Abnormal Interrupt Summary bit value is the logical OR of the following when the corresponding interrupt bits are enabled in Interrupt Enable Register: Bit[1]: Transmit Process Stopped. Bit[3]: Transmit Jabber Timeout. Bit[4]: Receive FIFO Overflow. Bit[5]: Transmit Underflow. Bit[7]: Receive Buffer Unavailable. Bit[8]: Receive Process Stopped. Bit[9]: Receive Watchdog Timeout. Bit[10]: Early Transmit Interrupt. Bit[13]: Fatal Bus Error. Only unmasked bits affect the Abnormal Interrupt Summary bit. This is a sticky bit and must be cleared (by writing 1 to this bit) each time a corresponding bit which causes AIS to be set is cleared.*/ + uint32_t norm_int_summ : 1; /*Normal Interrupt Summary bit value is the logical OR of the following bits when the corresponding interrupt bits are enabled in Interrupt Enable Register: Bit[0]: Transmit Interrupt. Bit[2]: Transmit Buffer Unavailable. Bit[6]: Receive Interrupt. Bit[14]: Early Receive Interrupt. Only unmasked bits affect the Normal Interrupt Summary bit.This is a sticky bit and must be cleared (by writing 1 to this bit) each time a corresponding bit which causes NIS to be set is cleared.*/ + uint32_t recv_proc_state : 3; /*This field indicates the Receive DMA FSM state. This field does not generate an interrupt. 3'b000: Stopped. Reset or Stop Receive Command issued. 3'b001: Running. Fetching Receive Transfer Descriptor. 3'b010: Reserved for future use. 3'b011: Running. Waiting for RX packets. 3'b100: Suspended. Receive Descriptor Unavailable. 3'b101: Running. Closing Receive Descriptor. 3'b110: TIME_STAMP write state. 3'b111: Running. Transferring the TX packets data from receive buffer to host memory.*/ + uint32_t trans_proc_state : 3; /*This field indicates the Transmit DMA FSM state. This field does not generate an interrupt. 3'b000: Stopped. Reset or Stop Transmit Command issued. 3'b001: Running. Fetching Transmit Transfer Descriptor. 3'b010: Reserved for future use. 3'b011: Running. Waiting for TX packets. 3'b100: Suspended. Receive Descriptor Unavailable. 3'b101: Running. Closing Transmit Descriptor. 3'b110: TIME_STAMP write state. 3'b111: Running. Transferring the TX packets data from transmit buffer to host memory.*/ + uint32_t error_bits : 3; /*This field indicates the type of error that caused a Bus Error for example error response on the AHB interface. This field is valid only when Bit[13] (FBI) is set. This field does not generate an interrupt. 3'b000: Error during Rx DMA Write Data Transfer. 3'b011: Error during Tx DMA Read Data Transfer. 3'b100: Error during Rx DMA Descriptor Write Access. 3'b101: Error during Tx DMA Descriptor Write Access. 3'b110: Error during Rx DMA Descriptor Read Access. 3'b111: Error during Tx DMA Descriptor Read Access.*/ + uint32_t reserved26 : 1; + uint32_t reserved27 : 1; + uint32_t pmt_int : 1; /*This bit indicates an interrupt event in the PMT module of the ETH_MAC. The software must read the PMT Control and Status Register in the MAC to get the exact cause of interrupt and clear its source to reset this bit to 1'b0.*/ + uint32_t ts_tri_int : 1; /*This bit indicates an interrupt event in the Timestamp Generator block of the ETH_MAC.The software must read the corresponding registers in the ETH_MAC to get the exact cause of the interrupt and clear its source to reset this bit to 1'b0.*/ + uint32_t reserved30 : 1; + uint32_t reserved31 : 1; + }; + uint32_t val; + } dmastatus; + union { + struct { + uint32_t reserved0 : 1; + uint32_t start_stop_rx : 1; /*When this bit is set the Receive process is placed in the Running state. The DMA attempts to acquire the descriptor from the Receive list and processes the incoming frames.When this bit is cleared the Rx DMA operation is stopped after the transfer of the current frame.*/ + uint32_t opt_second_frame : 1; /*When this bit is set it instructs the DMA to process the second frame of the Transmit data even before the status for the first frame is obtained.*/ + uint32_t rx_thresh_ctrl : 2; /*These two bits control the threshold level of the MTL Receive FIFO. Transfer (request) to DMA starts when the frame size within the MTL Receive FIFO is larger than the threshold. 2'b00: 64, 2'b01: 32, 2'b10: 96, 2'b11: 128 .*/ + uint32_t drop_gfrm : 1; /*When set the MAC drops the received giant frames in the Rx FIFO that is frames that are larger than the computed giant frame limit.*/ + uint32_t fwd_under_gf : 1; /*When set the Rx FIFO forwards Undersized frames (that is frames with no Error and length less than 64 bytes) including pad-bytes and CRC.*/ + uint32_t fwd_err_frame : 1; /*When this bit is reset the Rx FIFO drops frames with error status (CRC error collision error giant frame watchdog timeout or overflow).*/ + uint32_t reserved8 : 1; + uint32_t reserved9 : 2; + uint32_t reserved11 : 2; + uint32_t start_stop_transmission_command : 1; /*When this bit is set transmission is placed in the Running state and the DMA checks the Transmit List at the current position for a frame to be transmitted.When this bit is reset the transmission process is placed in the Stopped state after completing the transmission of the current frame.*/ + uint32_t tx_thresh_ctrl : 3; /*These bits control the threshold level of the MTL Transmit FIFO. Transmission starts when the frame size within the MTL Transmit FIFO is larger than the threshold. In addition full frames with a length less than the threshold are also transmitted. These bits are used only when Tx_Str_fwd is reset. 3'b000: 64 3'b001: 128 3'b010: 192 3'b011: 256 3'b100: 40 3'b101: 32 3'b110: 24 3'b111: 16 .*/ + uint32_t reserved17 : 3; + uint32_t flush_tx_fifo : 1; /*When this bit is set the transmit FIFO controller logic is reset to its default values and thus all data in the Tx FIFO is lost or flushed. This bit is cleared internally when the flushing operation is complete.*/ + uint32_t tx_str_fwd : 1; /*When this bit is set transmission starts when a full frame resides in the MTL Transmit FIFO. When this bit is set the Tx_Thresh_Ctrl values specified in Tx_Thresh_Ctrl are ignored.*/ + uint32_t reserved22 : 1; + uint32_t reserved23 : 1; + uint32_t dis_flush_recv_frames : 1; /*When this bit is set the Rx DMA does not flush any frames because of the unavailability of receive descriptors or buffers.*/ + uint32_t rx_store_forward : 1; /*When this bit is set the MTL reads a frame from the Rx FIFO only after the complete frame has been written to it.*/ + uint32_t dis_drop_tcpip_err_fram : 1; /*When this bit is set the MAC does not drop the frames which only have errors detected by the Receive Checksum engine.When this bit is reset all error frames are dropped if the Fwd_Err_Frame bit is reset.*/ + uint32_t reserved27 : 5; + }; + uint32_t val; + } dmaoperation_mode; + union { + struct { + uint32_t dmain_tie : 1; /*When this bit is set with Normal Interrupt Summary Enable (Bit[16]) the Transmit Interrupt is enabled. When this bit is reset the Transmit Interrupt is disabled.*/ + uint32_t dmain_tse : 1; /*When this bit is set with Abnormal Interrupt Summary Enable (Bit[15]) the Transmission Stopped Interrupt is enabled. When this bit is reset the Transmission Stopped Interrupt is disabled.*/ + uint32_t dmain_tbue : 1; /*When this bit is set with Normal Interrupt Summary Enable (Bit 16) the Transmit Buffer Unavailable Interrupt is enabled. When this bit is reset the Transmit Buffer Unavailable Interrupt is Disabled.*/ + uint32_t dmain_tjte : 1; /*When this bit is set with Abnormal Interrupt Summary Enable (Bit[15]) the Transmit Jabber Timeout Interrupt is enabled. When this bit is reset the Transmit Jabber Timeout Interrupt is disabled.*/ + uint32_t dmain_oie : 1; /*When this bit is set with Abnormal Interrupt Summary Enable (Bit[15]) the Receive Overflow Interrupt is enabled. When this bit is reset the Overflow Interrupt is disabled.*/ + uint32_t dmain_uie : 1; /*When this bit is set with Abnormal Interrupt Summary Enable (Bit[15]) the Transmit Underflow Interrupt is enabled. When this bit is reset the Underflow Interrupt is disabled.*/ + uint32_t dmain_rie : 1; /*When this bit is set with Normal Interrupt Summary Enable (Bit[16]) the Receive Interrupt is enabled. When this bit is reset the Receive Interrupt is disabled.*/ + uint32_t dmain_rbue : 1; /*When this bit is set with Abnormal Interrupt Summary Enable (Bit[15]) the Receive Buffer Unavailable Interrupt is enabled. When this bit is reset the Receive Buffer Unavailable Interrupt is disabled.*/ + uint32_t dmain_rse : 1; /*When this bit is set with Abnormal Interrupt Summary Enable (Bit[15]) the Receive Stopped Interrupt is enabled. When this bit is reset the Receive Stopped Interrupt is disabled.*/ + uint32_t dmain_rwte : 1; /*When this bit is set with Abnormal Interrupt Summary Enable (Bit[15]) the Receive Watchdog Timeout Interrupt is enabled. When this bit is reset the Receive Watchdog Timeout Interrupt is disabled.*/ + uint32_t dmain_etie : 1; /*When this bit is set with an Abnormal Interrupt Summary Enable (Bit[15]) the Early Transmit Interrupt is enabled. When this bit is reset the Early Transmit Interrupt is disabled.*/ + uint32_t reserved11 : 2; + uint32_t dmain_fbee : 1; /*When this bit is set with Abnormal Interrupt Summary Enable (Bit[15]) the Fatal Bus Error Interrupt is enabled. When this bit is reset the Fatal Bus Error Enable Interrupt is disabled.*/ + uint32_t dmain_erie : 1; /*When this bit is set with Normal Interrupt Summary Enable (Bit[16]) the Early Receive Interrupt is enabled. When this bit is reset the Early Receive Interrupt is disabled.*/ + uint32_t dmain_aise : 1; /*When this bit is set abnormal interrupt summary is enabled. When this bit is reset the abnormal interrupt summary is disabled. This bit enables the following interrupts in Status Register: Bit[1]: Transmit Process Stopped. Bit[3]: Transmit Jabber Timeout. Bit[4]: Receive Overflow. Bit[5]: Transmit Underflow. Bit[7]: Receive Buffer Unavailable. Bit[8]: Receive Process Stopped. Bit[9]: Receive Watchdog Timeout. Bit[10]: Early Transmit Interrupt. Bit[13]: Fatal Bus Error.*/ + uint32_t dmain_nise : 1; /*When this bit is set normal interrupt summary is enabled. When this bit is reset normal interrupt summary is disabled. This bit enables the following interrupts in Status Register: Bit[0]: Transmit Interrupt. Bit[2]: Transmit Buffer Unavailable. Bit[6]: Receive Interrupt. Bit[14]: Early Receive Interrupt.*/ + uint32_t reserved17 : 15; + }; + uint32_t val; + } dmain_en; + union { + struct { + uint32_t missed_fc : 16; /*This field indicates the number of frames missed by the controller because of the Host Receive Buffer being unavailable. This counter is incremented each time the DMA discards an incoming frame. The counter is cleared when this register is read.*/ + uint32_t overflow_bmfc : 1; /*This bit is set every time Missed Frame Counter (Bits[15:0]) overflows that is the DMA discards an incoming frame because of the Host Receive Buffer being unavailable with the missed frame counter at maximum value. In such a scenario the Missed frame counter is reset to all-zeros and this bit indicates that the rollover happened.*/ + uint32_t overflow_fc : 11; /*This field indicates the number of frames missed by the application. This counter is incremented each time the MTL FIFO overflows. The counter is cleared when this register is read.*/ + uint32_t overflow_bfoc : 1; /*This bit is set every time the Overflow Frame Counter (Bits[27:17]) overflows that is the Rx FIFO overflows with the overflow frame counter at maximum value. In such a scenario the overflow frame counter is reset to all-zeros and this bit indicates that the rollover happened.*/ + uint32_t reserved29 : 3; + }; + uint32_t val; + } dmamissedfr; + union { + struct { + uint32_t riwtc : 8; /*This bit indicates the number of system clock cycles multiplied by 256 for which the watchdog timer is set. The watchdog timer gets triggered with the programmed value after the Rx DMA completes the transfer of a frame for which the RI(RECV_INT) status bit is not set because of the setting in the corresponding descriptor RDES1[31]. When the watchdog timer runs out the RI bit is set and the timer is stopped. The watchdog timer is reset when the RI bit is set high because of automatic setting of RI as per RDES1[31] of any received frame.*/ + uint32_t reserved8 : 24; + }; + uint32_t val; + } dmarintwdtimer; + uint32_t reserved_28; + uint32_t reserved_2c; + uint32_t reserved_30; + uint32_t reserved_34; + uint32_t reserved_38; + uint32_t reserved_3c; + uint32_t reserved_40; + uint32_t reserved_44; + uint32_t dmatxcurrdesc; /*The address of the current receive descriptor list. Cleared on Reset.Pointer updated by the DMA during operation.*/ + uint32_t dmarxcurrdesc; /*The address of the current receive descriptor list. Cleared on Reset.Pointer updated by the DMA during operation.*/ + uint32_t dmatxcurraddr_buf; /*The address of the current receive descriptor list. Cleared on Reset.Pointer updated by the DMA during operation.*/ + uint32_t dmarxcurraddr_buf; /*The address of the current receive descriptor list. Cleared on Reset.Pointer updated by the DMA during operation.*/ +} emac_dma_dev_t; + +extern emac_dma_dev_t EMAC_DMA; + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/esp32/include/soc/emac_ex_reg.h b/components/soc/esp32/include/soc/emac_ex_reg.h deleted file mode 100644 index e43217e083..0000000000 --- a/components/soc/esp32/include/soc/emac_ex_reg.h +++ /dev/null @@ -1,161 +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 _EMAC_EX_H_ -#define _EMAC_EX_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "soc.h" -#define REG_EMAC_EX_BASE (DR_REG_EMAC_BASE + 0x800) - -#define EMAC_EX_CLKOUT_CONF_REG (REG_EMAC_EX_BASE + 0x0000) -#define EMAC_EX_CLK_OUT_DLY_NUM 0x00000003 -#define EMAC_EX_CLK_OUT_DLY_NUM_M (EMAC_EX_CLK_OUT_DLY_NUM_V << EMAC_EX_CLK_OUT_DLY_NUM_S) -#define EMAC_EX_CLK_OUT_DLY_NUM_V 0x00000003 -#define EMAC_EX_CLK_OUT_DLY_NUM_S 8 -#define EMAC_EX_CLK_OUT_H_DIV_NUM 0x0000000F -#define EMAC_EX_CLK_OUT_H_DIV_NUM_M (EMAC_EX_CLK_OUT_H_DIV_NUM_V << EMAC_EX_CLK_OUT_H_DIV_NUM_S) -#define EMAC_EX_CLK_OUT_H_DIV_NUM_V 0x0000000F -#define EMAC_EX_CLK_OUT_H_DIV_NUM_S 4 -#define EMAC_EX_CLK_OUT_DIV_NUM 0x0000000F -#define EMAC_EX_CLK_OUT_DIV_NUM_M (EMAC_EX_CLK_OUT_DIV_NUM_V << EMAC_EX_CLK_OUT_DIV_NUM_S) -#define EMAC_EX_CLK_OUT_DIV_NUM_V 0x0000000F -#define EMAC_EX_CLK_OUT_DIV_NUM_S 0 - -#define EMAC_EX_OSCCLK_CONF_REG (REG_EMAC_EX_BASE + 0x0004) -#define EMAC_EX_OSC_CLK_SEL (BIT(24)) -#define EMAC_EX_OSC_CLK_SEL_M (BIT(24)) -#define EMAC_EX_OSC_CLK_SEL_V 1 -#define EMAC_EX_OSC_CLK_SEL_S 24 -#define EMAC_EX_OSC_H_DIV_NUM_100M 0x0000003F -#define EMAC_EX_OSC_H_DIV_NUM_100M_M (EMAC_EX_OSC_H_DIV_NUM_100M_V << EMAC_EX_OSC_H_DIV_NUM_100M_S) -#define EMAC_EX_OSC_H_DIV_NUM_100M_V 0x0000003F -#define EMAC_EX_OSC_H_DIV_NUM_100M_S 18 -#define EMAC_EX_OSC_DIV_NUM_100M 0x0000003F -#define EMAC_EX_OSC_DIV_NUM_100M_M (EMAC_EX_OSC_DIV_NUM_100M_V << EMAC_EX_OSC_DIV_NUM_100M_S) -#define EMAC_EX_OSC_DIV_NUM_100M_V 0x0000003F -#define EMAC_EX_OSC_DIV_NUM_100M_S 12 -#define EMAC_EX_OSC_H_DIV_NUM_10M 0x0000003F -#define EMAC_EX_OSC_H_DIV_NUM_10M_M (EMAC_EX_OSC_H_DIV_NUM_10M_V << EMAC_EX_OSC_H_DIV_NUM_10M_S) -#define EMAC_EX_OSC_H_DIV_NUM_10M_V 0x0000003F -#define EMAC_EX_OSC_H_DIV_NUM_10M_S 6 -#define EMAC_EX_OSC_DIV_NUM_10M 0x0000003F -#define EMAC_EX_OSC_DIV_NUM_10M_M (EMAC_EX_OSC_DIV_NUM_10M_V << EMAC_EX_OSC_DIV_NUM_10M_S) -#define EMAC_EX_OSC_DIV_NUM_10M_V 0x0000003F -#define EMAC_EX_OSC_DIV_NUM_10M_S 0 - -#define EMAC_EX_CLK_CTRL_REG (REG_EMAC_EX_BASE + 0x0008) -#define EMAC_EX_CLK_EN (BIT(5)) -#define EMAC_EX_CLK_EN_M (BIT(5)) -#define EMAC_EX_CLK_EN_V 1 -#define EMAC_EX_CLK_EN_S 5 -#define EMAC_EX_MII_CLK_RX_EN (BIT(4)) -#define EMAC_EX_MII_CLK_RX_EN_M (BIT(4)) -#define EMAC_EX_MII_CLK_RX_EN_V 1 -#define EMAC_EX_MII_CLK_RX_EN_S 4 -#define EMAC_EX_MII_CLK_TX_EN (BIT(3)) -#define EMAC_EX_MII_CLK_TX_EN_M (BIT(3)) -#define EMAC_EX_MII_CLK_TX_EN_V 1 -#define EMAC_EX_MII_CLK_TX_EN_S 3 -#define EMAC_EX_RX_125_CLK_EN (BIT(2)) -#define EMAC_EX_RX_125_CLK_EN_M (BIT(2)) -#define EMAC_EX_RX_125_CLK_EN_V 1 -#define EMAC_EX_RX_125_CLK_EN_S 2 -#define EMAC_EX_INT_OSC_EN (BIT(1)) -#define EMAC_EX_INT_OSC_EN_M (BIT(1)) -#define EMAC_EX_INT_OSC_EN_V 1 -#define EMAC_EX_INT_OSC_EN_S 1 -#define EMAC_EX_EXT_OSC_EN (BIT(0)) -#define EMAC_EX_EXT_OSC_EN_M (BIT(0)) -#define EMAC_EX_EXT_OSC_EN_V 1 -#define EMAC_EX_EXT_OSC_EN_S 0 - -#define EMAC_EX_PHYINF_CONF_REG (REG_EMAC_EX_BASE + 0x000c) -#define EMAC_EX_TX_ERR_OUT_EN (BIT(20)) -#define EMAC_EX_TX_ERR_OUT_EN_M (BIT(20)) -#define EMAC_EX_TX_ERR_OUT_EN_V 1 -#define EMAC_EX_TX_ERR_OUT_EN_S 20 -#define EMAC_EX_SCR_SMI_DLY_RX_SYNC (BIT(19)) -#define EMAC_EX_SCR_SMI_DLY_RX_SYNC_M (BIT(19)) -#define EMAC_EX_SCR_SMI_DLY_RX_SYNC_V 1 -#define EMAC_EX_SCR_SMI_DLY_RX_SYNC_S 19 -#define EMAC_EX_PMT_CTRL_EN (BIT(18)) -#define EMAC_EX_PMT_CTRL_EN_M (BIT(18)) -#define EMAC_EX_PMT_CTRL_EN_V 1 -#define EMAC_EX_PMT_CTRL_EN_S 18 -#define EMAC_EX_SBD_CLK_GATING_EN (BIT(17)) -#define EMAC_EX_SBD_CLK_GATING_EN_M (BIT(17)) -#define EMAC_EX_SBD_CLK_GATING_EN_V 1 -#define EMAC_EX_SBD_CLK_GATING_EN_S 17 -#define EMAC_EX_SS_MODE (BIT(16)) -#define EMAC_EX_SS_MODE_M (BIT(16)) -#define EMAC_EX_SS_MODE_V 1 -#define EMAC_EX_SS_MODE_S 16 -#define EMAC_EX_PHY_INTF_SEL 0x00000007 -#define EMAC_EX_PHY_INTF_SEL_M (EMAC_EX_PHY_INTF_SEL_V << EMAC_EX_PHY_INTF_SEL_S) -#define EMAC_EX_PHY_INTF_SEL_V 0x00000007 -#define EMAC_EX_PHY_INTF_SEL_S 13 -#define EMAC_EX_REVMII_PHY_ADDR 0x0000001F -#define EMAC_EX_REVMII_PHY_ADDR_M (EMAC_EX_REVMII_PHY_ADDR_V << EMAC_EX_REVMII_PHY_ADDR_S) -#define EMAC_EX_REVMII_PHY_ADDR_V 0x0000001F -#define EMAC_EX_REVMII_PHY_ADDR_S 8 -#define EMAC_EX_CORE_PHY_ADDR 0x0000001F -#define EMAC_EX_CORE_PHY_ADDR_M (EMAC_EX_CORE_PHY_ADDR_V << EMAC_EX_CORE_PHY_ADDR_S) -#define EMAC_EX_CORE_PHY_ADDR_V 0x0000001F -#define EMAC_EX_CORE_PHY_ADDR_S 3 -#define EMAC_EX_SBD_FLOWCTRL (BIT(2)) -#define EMAC_EX_SBD_FLOWCTRL_M (BIT(2)) -#define EMAC_EX_SBD_FLOWCTRL_V 1 -#define EMAC_EX_SBD_FLOWCTRL_S 2 -#define EMAC_EX_EXT_REVMII_RX_CLK_SEL (BIT(1)) -#define EMAC_EX_EXT_REVMII_RX_CLK_SEL_M (BIT(1)) -#define EMAC_EX_EXT_REVMII_RX_CLK_SEL_V 1 -#define EMAC_EX_EXT_REVMII_RX_CLK_SEL_S 1 -#define EMAC_EX_INT_REVMII_RX_CLK_SEL (BIT(0)) -#define EMAC_EX_INT_REVMII_RX_CLK_SEL_M (BIT(0)) -#define EMAC_EX_INT_REVMII_RX_CLK_SEL_V 1 -#define EMAC_EX_INT_REVMII_RX_CLK_SEL_S 0 - -#define EMAC_EX_PHY_INTF_RMII 4 - -#define EMAC_EX_EMAC_PD_SEL_REG (REG_EMAC_EX_BASE + 0x0010) -#define EMAC_EX_RAM_PD_EN 0x00000003 -#define EMAC_EX_RAM_PD_EN_M (EMAC_EX_RAM_PD_EN_V << EMAC_EX_RAM_PD_EN_S) -#define EMAC_EX_RAM_PD_EN_V 0x00000003 -#define EMAC_EX_RAM_PD_EN_S 0 - -#define EMAC_EX_DATE_REG (REG_EMAC_EX_BASE + 0x00fc) -#define EMAC_EX_DATE 0xFFFFFFFF -#define EMAC_EX_DATE_M (EMAC_EX_DATE_V << EMAC_EX_DATE_S) -#define EMAC_EX_DATE_V 0xFFFFFFFF -#define EMAC_EX_DATE_S 0 -#define EMAC_EX_DATE_VERSION 0x16042200 -#define EMAC_EX_DATE_VERSION_M (EMAC_EX_DATE_VERSION_V << EMAC_EX_DATE_VERSION_S) -#define EMAC_EX_DATE_VERSION_V 0x16042200 - -#define EMAC_CLK_EN_REG 0x3ff000cc -#define EMAC_CLK_EN_REG_M (EMAC_CLK_EN_REG_V << EMAC_CLK_EN_REG_S) -#define EMAC_CLK_EN_REG_V 0x3ff000cc -#define EMAC_CLK_EN (BIT(14)) -#define EMAC_CLK_EN_M (BIT(14)) -#define EMAC_CLK_EN_V 1 - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/components/soc/esp32/include/soc/emac_ext_struct.h b/components/soc/esp32/include/soc/emac_ext_struct.h new file mode 100644 index 0000000000..6c0b8921be --- /dev/null +++ b/components/soc/esp32/include/soc/emac_ext_struct.h @@ -0,0 +1,74 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef volatile struct { + union { + struct { + uint32_t div_num : 4; + uint32_t h_div_num : 4; + uint32_t reserved8 : 24; + }; + uint32_t val; + } ex_clkout_conf; + union { + struct { + uint32_t div_num_10m : 6; + uint32_t h_div_num_10m : 6; + uint32_t div_num_100m : 6; + uint32_t h_div_num_100m : 6; + uint32_t clk_sel : 1; + uint32_t reserved25 : 7; + }; + uint32_t val; + } ex_oscclk_conf; + union { + struct { + uint32_t ext_en : 1; + uint32_t int_en : 1; + uint32_t reserved2 : 1; + uint32_t mii_clk_tx_en : 1; + uint32_t mii_clk_rx_en : 1; + uint32_t reserved5 : 27; + }; + uint32_t val; + } ex_clk_ctrl; + union { + struct { + uint32_t reserved0 : 13; + uint32_t phy_intf_sel : 3; + uint32_t reserved16 : 16; + }; + uint32_t val; + } ex_phyinf_conf; + union { + struct { + uint32_t ram_pd_en : 2; + uint32_t reserved2 : 30; + }; + uint32_t val; + } pd_sel; +} emac_ext_dev_t; + +extern emac_ext_dev_t EMAC_EXT; + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/esp32/include/soc/emac_mac_struct.h b/components/soc/esp32/include/soc/emac_mac_struct.h new file mode 100644 index 0000000000..0cbf9c3257 --- /dev/null +++ b/components/soc/esp32/include/soc/emac_mac_struct.h @@ -0,0 +1,345 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef volatile struct { + union { + struct { + uint32_t pltf : 2; /*These bits control the number of preamble bytes that are added to the beginning of every Transmit frame. The preamble reduction occurs only when the MAC is operating in the full-duplex mode.2'b00: 7 bytes of preamble. 2'b01: 5 bytes of preamble. 2'b10: 3 bytes of preamble.*/ + uint32_t rx : 1; /*When this bit is set the receiver state machine of the MAC is enabled for receiving frames from the MII. When this bit is reset the MAC receive state machine is disabled after the completion of the reception of the current frame and does not receive any further frames from the MII.*/ + uint32_t tx : 1; /*When this bit is set the transmit state machine of the MAC is enabled for transmission on the MII. When this bit is reset the MAC transmit state machine is disabled after the completion of the transmission of the current frame and does not transmit any further frames.*/ + uint32_t deferralcheck : 1; /*Deferral Check.*/ + uint32_t backofflimit : 2; /*The Back-Off limit determines the random integer number (r) of slot time delays (512 bit times for 10/100 Mbps) for which the MAC waits before rescheduling a transmission attempt during retries after a collision. This bit is applicable only in the half-duplex mode. 00: k= min (n 10). 01: k = min (n 8). 10: k = min (n 4). 11: k = min (n 1) n = retransmission attempt. The random integer r takes the value in the Range 0 ~ 2000.*/ + uint32_t padcrcstrip : 1; /*When this bit is set the MAC strips the Pad or FCS field on the incoming frames only if the value of the length field is less than 1 536 bytes. All received frames with length field greater than or equal to 1 536 bytes are passed to the application without stripping the Pad or FCS field. When this bit is reset the MAC passes all incoming frames without modifying them to the Host.*/ + uint32_t reserved8 : 1; + uint32_t retry : 1; /*When this bit is set the MAC attempts only one transmission. When a collision occurs on the MII interface the MAC ignores the current frame transmission and reports a Frame Abort with excessive collision error in the transmit frame status. When this bit is reset the MAC attempts retries based on the settings of the BL field (Bits [6:5]). This bit is applicable only in the half-duplex Mode.*/ + uint32_t rxipcoffload : 1; /*When this bit is set the MAC calculates the 16-bit one's complement of the one's complement sum of all received Ethernet frame payloads. It also checks whether the IPv4 Header checksum (assumed to be bytes 25/26 or 29/30 (VLAN-tagged) of the received Ethernet frame) is correct for the received frame and gives the status in the receive status word. The MAC also appends the 16-bit checksum calculated for the IP header datagram payload (bytes after the IPv4 header) and appends it to the Ethernet frame transferred to the application (when Type 2 COE is deselected). When this bit is reset this function is disabled.*/ + uint32_t duplex : 1; /*When this bit is set the MAC operates in the full-duplex mode where it can transmit and receive simultaneously. This bit is read only with default value of 1'b1 in the full-duplex-mode.*/ + uint32_t loopback : 1; /*When this bit is set the MAC operates in the loopback mode MII. The MII Receive clock input (CLK_RX) is required for the loopback to work properly because the transmit clock is not looped-back internally.*/ + uint32_t rxown : 1; /*When this bit is set the MAC disables the reception of frames when the TX_EN is asserted in the half-duplex mode. When this bit is reset the MAC receives all packets that are given by the PHY while transmitting. This bit is not applicable if the MAC is operating in the full duplex mode.*/ + uint32_t fespeed : 1; /*This bit selects the speed in the MII RMII interface. 0: 10 Mbps. 1: 100 Mbps.*/ + uint32_t mii : 1; /*This bit selects the Ethernet line speed. It should be set to 1 for 10 or 100 Mbps operations.In 10 or 100 Mbps operations this bit along with FES(EMACFESPEED) bit it selects the exact linespeed. In the 10/100 Mbps-only operations the bit is always 1.*/ + uint32_t disablecrs : 1; /*When set high this bit makes the MAC transmitter ignore the MII CRS signal during frame transmission in the half-duplex mode. This request results in no errors generated because of Loss of Carrier or No Carrier during such transmission. When this bit is low the MAC transmitter generates such errors because of Carrier Sense and can even abort the transmissions.*/ + uint32_t interframegap : 3; /*These bits control the minimum IFG between frames during transmission. 3'b000: 96 bit times. 3'b001: 88 bit times. 3'b010: 80 bit times. 3'b111: 40 bit times. In the half-duplex mode the minimum IFG can be configured only for 64 bit times (IFG = 100). Lower values are not considered.*/ + uint32_t jumboframe : 1; /*When this bit is set the MAC allows Jumbo frames of 9 018 bytes (9 022 bytes for VLAN tagged frames) without reporting a giant frame error in the receive frame status.*/ + uint32_t reserved21 : 1; + uint32_t jabber : 1; /*When this bit is set the MAC disables the jabber timer on the transmitter. The MAC can transfer frames of up to 16 383 bytes. When this bit is reset the MAC cuts off the transmitter if the application sends out more than 2 048 bytes of data (10 240 if JE is set high) during Transmission.*/ + uint32_t watchdog : 1; /*When this bit is set the MAC disables the watchdog timer on the receiver. The MAC can receive frames of up to 16 383 bytes. When this bit is reset the MAC does not allow a receive frame which more than 2 048 bytes (10 240 if JE is set high) or the value programmed in Register (Watchdog Timeout Register). The MAC cuts off any bytes received after the watchdog limit number of bytes.*/ + uint32_t reserved24 : 1; + uint32_t reserved25 : 1; + uint32_t reserved26 : 1; + uint32_t ass2kp : 1; /*When set the MAC considers all frames with up to 2 000 bytes length as normal packets.When Bit[20] (JE) is not set the MAC considers all received frames of size more than 2K bytes as Giant frames. When this bit is reset and Bit[20] (JE) is not set the MAC considers all received frames of size more than 1 518 bytes (1 522 bytes for tagged) as Giant frames. When Bit[20] is set setting this bit has no effect on Giant Frame status.*/ + uint32_t sairc : 3; /*This field controls the source address insertion or replacement for all transmitted frames.Bit[30] specifies which MAC Address register (0 or 1) is used for source address insertion or replacement based on the values of Bits [29:28]: 2'b0x: The input signals mti_sa_ctrl_i and ati_sa_ctrl_i control the SA field generation. 2'b10: If Bit[30] is set to 0 the MAC inserts the content of the MAC Address 0 registers in the SA field of all transmitted frames. If Bit[30] is set to 1 the MAC inserts the content of the MAC Address 1 registers in the SA field of all transmitted frames. 2'b11: If Bit[30] is set to 0 the MAC replaces the content of the MAC Address 0 registers in the SA field of all transmitted frames. If Bit[30] is set to 1 the MAC replaces the content of the MAC Address 1 registers in the SA field of all transmitted frames.*/ + uint32_t reserved31 : 1; + }; + uint32_t val; + } gmacconfig; + union { + struct { + uint32_t pmode : 1; /*When this bit is set the Address Filter module passes all incoming frames irrespective of the destination or source address. The SA or DA Filter Fails status bits of the Receive Status Word are always cleared when PR(PRI_RATIO) is set.*/ + uint32_t reserved1 : 1; + uint32_t reserved2 : 1; + uint32_t daif : 1; /*When this bit is set the Address Check block operates in inverse filtering mode for the DA address comparison for both unicast and multicast frames. When reset normal filtering of frames is performed.*/ + uint32_t pam : 1; /*When set this bit indicates that all received frames with a multicast destination address (first bit in the destination address field is '1') are passed.*/ + uint32_t dbf : 1; /*When this bit is set the AFM(Address Filtering Module) module blocks all incoming broadcast frames. In addition it overrides all other filter settings. When this bit is reset the AFM module passes all received broadcast Frames.*/ + uint32_t pcf : 2; /*These bits control the forwarding of all control frames (including unicast and multicast Pause frames). 2'b00: MAC filters all control frames from reaching the application. 2'b01: MAC forwards all control frames except Pause frames to application even if they fail the Address filter. 2'b10: MAC forwards all control frames to application even if they fail the Address Filter. 2'b11: MAC forwards control frames that pass the Address Filter.The following conditions should be true for the Pause frames processing: Condition 1: The MAC is in the full-duplex mode and flow control is enabled by setting Bit 2 (RFE) of Register (Flow Control Register) to 1. Condition 2: The destination address (DA) of the received frame matches the special multicast address or the MAC Address 0 when Bit 3 (UP) of the Register(Flow Control Register) is set. Condition 3: The Type field of the received frame is 0x8808 and the OPCODE field is 0x0001.*/ + uint32_t saif : 1; /*When this bit is set the Address Check block operates in inverse filtering mode for the SA address comparison. The frames whose SA matches the SA registers are marked as failing the SA Address filter. When this bit is reset frames whose SA does not match the SA registers are marked as failing the SA Address filter.*/ + uint32_t safe : 1; /*When this bit is set the MAC compares the SA field of the received frames with the values programmed in the enabled SA registers. If the comparison fails the MAC drops the frame. When this bit is reset the MAC forwards the received frame to the application with updated SAF bit of the Rx Status depending on the SA address comparison.*/ + uint32_t reserved10 : 1; + uint32_t reserved11 : 5; + uint32_t reserved16 : 1; + uint32_t reserved17 : 3; + uint32_t reserved20 : 1; + uint32_t reserved21 : 1; + uint32_t reserved22 : 9; + uint32_t receive_all : 1; /*When this bit is set the MAC Receiver module passes all received frames irrespective of whether they pass the address filter or not to the Application. The result of the SA or DA filtering is updated (pass or fail) in the corresponding bits in the Receive Status Word. When this bit is reset the Receiver module passes only those frames to the Application that pass the SA or DA address Filter.*/ + }; + uint32_t val; + } gmacff; + uint32_t reserved_1008; + uint32_t reserved_100c; + union { + struct { + uint32_t miibusy : 1; /*This bit should read logic 0 before writing to PHY Addr Register and PHY data Register.During a PHY register access the software sets this bit to 1'b1 to indicate that a Read or Write access is in progress. PHY data Register is invalid until this bit is cleared by the MAC. Therefore PHY data Register (MII Data) should be kept valid until the MAC clears this bit during a PHY Write operation. Similarly for a read operation the contents of Register 5 are not valid until this bit is cleared. The subsequent read or write operation should happen only after the previous operation is complete. Because there is no acknowledgment from the PHY to MAC after a read or write operation is completed there is no change in the functionality of this bit even when the PHY is not Present.*/ + uint32_t miiwrite : 1; /*When set this bit indicates to the PHY that this is a Write operation using the MII Data register. If this bit is not set it indicates that this is a Read operation that is placing the data in the MII Data register.*/ + uint32_t miicsrclk : 4; /*CSR clock range: 1.0 MHz ~ 2.5 MHz. 4'b0000: When the APB clock frequency is 80 MHz the MDC clock frequency is APB CLK/42 4'b0000: When the APB clock frequency is 40 MHz the MDC clock frequency is APB CLK/26.*/ + uint32_t miireg : 5; /*These bits select the desired MII register in the selected PHY device.*/ + uint32_t miidev : 5; /*This field indicates which of the 32 possible PHY devices are being accessed.*/ + uint32_t reserved16 : 16; + }; + uint32_t val; + } emacgmiiaddr; + union { + struct { + uint32_t mii_data : 16; /*This field contains the 16-bit data value read from the PHY after a Management Read operation or the 16-bit data value to be written to the PHY before a Management Write operation.*/ + uint32_t reserved16 : 16; + }; + uint32_t val; + } emacmiidata; + union { + struct { + uint32_t fcbba : 1; /*This bit initiates a Pause frame in the full-duplex mode and activates the backpressure function in the half-duplex mode if the TFCE bit is set. In the full-duplex mode this bit should be read as 1'b0 before writing to the Flow Control register. To initiate a Pause frame the Application must set this bit to 1'b1. During a transfer of the Control Frame this bit continues to be set to signify that a frame transmission is in progress. After the completion of Pause frame transmission the MAC resets this bit to 1'b0. The Flow Control register should not be written to until this bit is cleared. In the half-duplex mode when this bit is set (and TFCE is set) then backpressure is asserted by the MAC. During backpressure when the MAC receives a new frame the transmitter starts sending a JAM pattern resulting in a collision. When the MAC is configured for the full-duplex mode the BPA(backpressure activate) is automatically disabled.*/ + uint32_t tfce : 1; /*In the full-duplex mode when this bit is set the MAC enables the flow control operation to transmit Pause frames. When this bit is reset the flow control operation in the MAC is disabled and the MAC does not transmit any Pause frames. In the half-duplex mode when this bit is set the MAC enables the backpressure operation. When this bit is reset the backpressure feature is Disabled.*/ + uint32_t rfce : 1; /*When this bit is set the MAC decodes the received Pause frame and disables its transmitter for a specified (Pause) time. When this bit is reset the decode function of the Pause frame is disabled.*/ + uint32_t upfd : 1; /*A pause frame is processed when it has the unique multicast address specified in the IEEE Std 802.3. When this bit is set the MAC can also detect Pause frames with unicast address of the station. This unicast address should be as specified in the EMACADDR0 High Register and EMACADDR0 Low Register. When this bit is reset the MAC only detects Pause frames with unique multicast address.*/ + uint32_t plt : 2; /*This field configures the threshold of the Pause timer automatic retransmission of the Pause frame.The threshold values should be always less than the Pause Time configured in Bits[31:16]. For example if PT = 100H (256 slot-times) and PLT = 01 then a second Pause frame is automatically transmitted at 228 (256-28) slot times after the first Pause frame is transmitted. The following list provides the threshold values for different values: 2'b00: The threshold is Pause time minus 4 slot times (PT-4 slot times). 2'b01: The threshold is Pause time minus 28 slot times (PT-28 slot times). 2'b10: The threshold is Pause time minus 144 slot times (PT-144 slot times). 2'b11: The threshold is Pause time minus 256 slot times (PT-256 slot times). The slot time is defined as the time taken to transmit 512 bits (64 bytes) on the MII interface.*/ + uint32_t reserved6 : 1; + uint32_t dzpq : 1; /*When this bit is set it disables the automatic generation of the Zero-Quanta Pause frames on the de-assertion of the flow-control signal from the FIFO layer. When this bit is reset normal operation with automatic Zero-Quanta Pause frame generation is enabled.*/ + uint32_t reserved8 : 8; + uint32_t pause_time : 16; /*This field holds the value to be used in the Pause Time field in the transmit control frame. If the Pause Time bits is configured to be double-synchronized to the MII clock domain then consecutive writes to this register should be performed only after at least four clock cycles in the destination clock domain.*/ + }; + uint32_t val; + } gmacfc; + uint32_t reserved_101c; + uint32_t reserved_1020; + union { + struct { + uint32_t macrpes : 1; /*When high this bit indicates that the MAC MII receive protocol engine is actively receiving data and not in IDLE state.*/ + uint32_t macrffcs : 2; /*When high this field indicates the active state of the FIFO Read and Write controllers of the MAC Receive Frame Controller Module. MACRFFCS[1] represents the status of FIFO Read controller. MACRFFCS[0] represents the status of small FIFO Write controller.*/ + uint32_t reserved3 : 1; + uint32_t mtlrfwcas : 1; /*When high this bit indicates that the MTL Rx FIFO Write Controller is active and is transferring a received frame to the FIFO.*/ + uint32_t mtlrfrcs : 2; /*This field gives the state of the Rx FIFO read Controller: 2'b00: IDLE state.2'b01: Reading frame data.2'b10: Reading frame status (or timestamp).2'b11: Flushing the frame data and status.*/ + uint32_t reserved7 : 1; + uint32_t mtlrffls : 2; /*This field gives the status of the fill-level of the Rx FIFO: 2'b00: Rx FIFO Empty. 2'b01: Rx FIFO fill-level below flow-control deactivate threshold. 2'b10: Rx FIFO fill-level above flow-control activate threshold. 2'b11: Rx FIFO Full.*/ + uint32_t reserved10 : 6; + uint32_t mactpes : 1; /*When high this bit indicates that the MAC MII transmit protocol engine is actively transmitting data and is not in the IDLE state.*/ + uint32_t mactfcs : 2; /*This field indicates the state of the MAC Transmit Frame Controller module: 2'b00: IDLE state. 2'b01: Waiting for status of previous frame or IFG or backoff period to be over. 2'b10: Generating and transmitting a Pause frame (in the full-duplex mode). 2'b11: Transferring input frame for transmission.*/ + uint32_t mactp : 1; /*When high this bit indicates that the MAC transmitter is in the Pause condition (in the full-duplex-mode) and hence does not schedule any frame for transmission.*/ + uint32_t mtltfrcs : 2; /*This field indicates the state of the Tx FIFO Read Controller: 2'b00: IDLE state. 2'b01: READ state (transferring data to the MAC transmitter). 2'b10: Waiting for TxStatus from the MAC transmitter. 2'b11: Writing the received TxStatus or flushing the Tx FIFO.*/ + uint32_t mtltfwcs : 1; /*When high this bit indicates that the MTL Tx FIFO Write Controller is active and is transferring data to the Tx FIFO.*/ + uint32_t reserved23 : 1; + uint32_t mtltfnes : 1; /*When high this bit indicates that the MTL Tx FIFO is not empty and some data is left for Transmission.*/ + uint32_t mtltsffs : 1; /*When high this bit indicates that the MTL TxStatus FIFO is full. Therefore the MTL cannot accept any more frames for transmission.*/ + uint32_t reserved26 : 6; + }; + uint32_t val; + } emacdebug; + uint32_t pmt_rwuffr; /*The MSB (31st bit) must be zero.Bit j[30:0] is the byte mask. If Bit 1/2/3/4 (byte number) of the byte mask is set the CRC block processes the Filter 1/2/3/4 Offset + j of the incoming packet(PWKPTR is 0/1/2/3).RWKPTR is 0:Filter 0 Byte Mask .RWKPTR is 1:Filter 1 Byte Mask RWKPTR is 2:Filter 2 Byte Mask RWKPTR is 3:Filter 3 Byte Mask RWKPTR is 4:Bit 3/11/19/27 specifies the address type defining the destination address type of the pattern.When the bit is set the pattern applies to only multicast packets*/ + union { + struct { + uint32_t pwrdwn : 1; /*When set the MAC receiver drops all received frames until it receives the expected magic packet or remote wake-up frame.This bit must only be set when MGKPKTEN GLBLUCAST or RWKPKTEN bit is set high.*/ + uint32_t mgkpkten : 1; /*When set enables generation of a power management event because of magic packet reception.*/ + uint32_t rwkpkten : 1; /*When set enables generation of a power management event because of remote wake-up frame reception*/ + uint32_t reserved3 : 2; + uint32_t mgkprcvd : 1; /*When set this bit indicates that the power management event is generated because of the reception of a magic packet. This bit is cleared by a Read into this register.*/ + uint32_t rwkprcvd : 1; /*When set this bit indicates the power management event is generated because of the reception of a remote wake-up frame. This bit is cleared by a Read into this register.*/ + uint32_t reserved7 : 2; + uint32_t glblucast : 1; /*When set enables any unicast packet filtered by the MAC (DAFilter) address recognition to be a remote wake-up frame.*/ + uint32_t reserved10 : 14; + uint32_t rwkptr : 5; /*The maximum value of the pointer is 7 the detail information please refer to PMT_RWUFFR.*/ + uint32_t reserved29 : 2; + uint32_t rwkfiltrst : 1; /*When this bit is set it resets the RWKPTR register to 3’b000.*/ + }; + uint32_t val; + } pmt_csr; + union { + struct { + uint32_t tlpien : 1; /*When set this bit indicates that the MAC Transmitter has entered the LPI state because of the setting of the LPIEN bit. This bit is cleared by a read into this register.*/ + uint32_t tlpiex : 1; /*When set this bit indicates that the MAC transmitter has exited the LPI state after the user has cleared the LPIEN bit and the LPI_TW_Timer has expired.This bit is cleared by a read into this register.*/ + uint32_t rlpien : 1; /*When set this bit indicates that the MAC Receiver has received an LPI pattern and entered the LPI state. This bit is cleared by a read into this register.*/ + uint32_t rlpiex : 1; /*When set this bit indicates that the MAC Receiver has stopped receiving the LPI pattern on the MII interface exited the LPI state and resumed the normal reception. This bit is cleared by a read into this register.*/ + uint32_t reserved4 : 4; + uint32_t tlpist : 1; /*When set this bit indicates that the MAC is transmitting the LPI pattern on the MII interface.*/ + uint32_t rlpist : 1; /*When set this bit indicates that the MAC is receiving the LPI pattern on the MII interface.*/ + uint32_t reserved10 : 6; + uint32_t lpien : 1; /*When set this bit instructs the MAC Transmitter to enter the LPI state. When reset this bit instructs the MAC to exit the LPI state and resume normal transmission.This bit is cleared when the LPITXA bit is set and the MAC exits the LPI state because of the arrival of a new packet for transmission.*/ + uint32_t pls : 1; /*This bit indicates the link status of the PHY.When set the link is considered to be okay (up) and when reset the link is considered to be down.*/ + uint32_t reserved18 : 1; + uint32_t lpitxa : 1; /*This bit controls the behavior of the MAC when it is entering or coming out of the LPI mode on the transmit side.If the LPITXA and LPIEN bits are set to 1 the MAC enters the LPI mode only after all outstanding frames and pending frames have been transmitted. The MAC comes out of the LPI mode when the application sends any frame.When this bit is 0 the LPIEN bit directly controls behavior of the MAC when it is entering or coming out of the LPI mode.*/ + uint32_t reserved20 : 12; + }; + uint32_t val; + } gmaclpi_crs; + union { + struct { + uint32_t lpi_tw_timer : 16; /*This field specifies the minimum time (in microseconds) for which the MAC waits after it stops transmitting the LPI pattern to the PHY and before it resumes the normal transmission. The TLPIEX status bit is set after the expiry of this timer.*/ + uint32_t lpi_ls_timer : 10; /*This field specifies the minimum time (in milliseconds) for which the link status from the PHY should be up (OKAY) before the LPI pattern can be transmitted to the PHY. The MAC does not transmit the LPI pattern even when the LPIEN bit is set unless the LPI_LS_Timer reaches the programmed terminal count. The default value of the LPI_LS_Timer is 1000 (1 sec) as defined in the IEEE standard.*/ + uint32_t reserved26 : 6; + }; + uint32_t val; + } gmaclpitimerscontrol; + union { + struct { + uint32_t reserved0 : 1; + uint32_t reserved1 : 1; + uint32_t reserved2 : 1; + uint32_t pmtints : 1; /*This bit is set when a magic packet or remote wake-up frame is received in the power-down mode (see Bit[5] and Bit[6] in the PMT Control and Status Register). This bit is cleared when both Bits[6:5] are cleared because of a read operation to the PMT Control and Status register. This bit is valid only when you select the optional PMT module during core configuration.*/ + uint32_t reserved4 : 1; + uint32_t reserved5 : 1; + uint32_t reserved6 : 1; + uint32_t reserved7 : 1; + uint32_t reserved8 : 1; + uint32_t reserved9 : 1; + uint32_t lpiis : 1; /*When the Energy Efficient Ethernet feature is enabled this bit is set for any LPI state entry or exit in the MAC Transmitter or Receiver. This bit is cleared on reading Bit[0] of Register (LPI Control and Status Register).*/ + uint32_t reserved11 : 1; + uint32_t reserved12 : 20; + }; + uint32_t val; + } emacints; + union { + struct { + uint32_t reserved0 : 1; + uint32_t reserved1 : 1; + uint32_t reserved2 : 1; + uint32_t pmtintmask : 1; /*When set this bit disables the assertion of the interrupt signal because of the setting of PMT Interrupt Status bit in Register (Interrupt Status Register).*/ + uint32_t reserved4 : 5; + uint32_t reserved9 : 1; + uint32_t lpiintmask : 1; /*When set this bit disables the assertion of the interrupt signal because of the setting of the LPI Interrupt Status bit in Register (Interrupt Status Register).*/ + uint32_t reserved11 : 21; + }; + uint32_t val; + } emacintmask; + union { + struct { + uint32_t address0_hi : 16; /*This field contains the upper 16 bits (47:32) of the first 6-byte MAC address.The MAC uses this field for filtering the received frames and inserting the MAC address in the Transmit Flow Control (Pause) Frames.*/ + uint32_t reserved16 : 15; + uint32_t address_enable0 : 1; /*This bit is always set to 1.*/ + }; + uint32_t val; + } emacaddr0high; + uint32_t emacaddr0low; /*This field contains the lower 32 bits of the first 6-byte MAC address. This is used by the MAC for filtering the received frames and inserting the MAC address in the Transmit Flow Control (Pause) Frames.*/ + union { + struct { + uint32_t mac_address1_hi : 16; /*This field contains the upper 16 bits Bits[47:32] of the second 6-byte MAC Address.*/ + uint32_t reserved16 : 8; + uint32_t mask_byte_control : 6; /*These bits are mask control bits for comparison of each of the EMACADDR1 bytes. When set high the MAC does not compare the corresponding byte of received DA or SA with the contents of EMACADDR1 registers. Each bit controls the masking of the bytes as follows: Bit[29]: EMACADDR1 High [15:8]. Bit[28]: EMACADDR1 High [7:0]. Bit[27]: EMACADDR1 Low [31:24]. Bit[24]: EMACADDR1 Low [7:0].You can filter a group of addresses (known as group address filtering) by masking one or more bytes of the address.*/ + uint32_t source_address : 1; /*When this bit is set the EMACADDR1[47:0] is used to compare with the SA fields of the received frame. When this bit is reset the EMACADDR1[47:0] is used to compare with the DA fields of the received frame.*/ + uint32_t address_enable1 : 1; /*When this bit is set the address filter module uses the second MAC address for perfect filtering. When this bit is reset the address filter module ignores the address for filtering.*/ + }; + uint32_t val; + } emacaddr1high; + uint32_t emacaddr1low; /*This field contains the lower 32 bits of the second 6-byte MAC address.The content of this field is undefined so the register needs to be configured after the initialization Process.*/ + union { + struct { + uint32_t mac_address2_hi : 16; /*This field contains the upper 16 bits Bits[47:32] of the third 6-byte MAC address.*/ + uint32_t reserved16 : 8; + uint32_t mask_byte_control2 : 6; /*These bits are mask control bits for comparison of each of the EMACADDR2 bytes. When set high the MAC does not compare the corresponding byte of received DA or SA with the contents of EMACADDR2 registers. Each bit controls the masking of the bytes as follows: Bit[29]: EMACADDR2 High [15:8]. Bit[28]: EMACADDR2 High [7:0]. Bit[27]: EMACADDR2 Low [31:24]. Bit[24]: EMACADDR2 Low [7:0].You can filter a group of addresses (known as group address filtering) by masking one or more bytes of the address.*/ + uint32_t source_address2 : 1; /*When this bit is set the EMACADDR2[47:0] is used to compare with the SA fields of the received frame. When this bit is reset the EMACADDR2[47:0] is used to compare with the DA fields of the received frame.*/ + uint32_t address_enable2 : 1; /*When this bit is set the address filter module uses the third MAC address for perfect filtering. When this bit is reset the address filter module ignores the address for filtering.*/ + }; + uint32_t val; + } emacaddr2high; + uint32_t emacaddr2low; /*This field contains the lower 32 bits of the third 6-byte MAC address. The content of this field is undefined so the register needs to be configured after the initialization process.*/ + union { + struct { + uint32_t mac_address3_hi : 16; /*This field contains the upper 16 bits Bits[47:32] of the fourth 6-byte MAC address.*/ + uint32_t reserved16 : 8; + uint32_t mask_byte_control3 : 6; /*These bits are mask control bits for comparison of each of the EMACADDR3 bytes. When set high the MAC does not compare the corresponding byte of received DA or SA with the contents of EMACADDR3 registers. Each bit controls the masking of the bytes as follows: Bit[29]: EMACADDR3 High [15:8]. Bit[28]: EMACADDR3 High [7:0]. Bit[27]: EMACADDR3 Low [31:24]. Bit[24]: EMACADDR3 Low [7:0].You can filter a group of addresses (known as group address filtering) by masking one or more bytes of the address.*/ + uint32_t source_address3 : 1; /*When this bit is set the EMACADDR3[47:0] is used to compare with the SA fields of the received frame. When this bit is reset the EMACADDR3[47:0] is used to compare with the DA fields of the received frame.*/ + uint32_t address_enable3 : 1; /*When this bit is set the address filter module uses the fourth MAC address for perfect filtering. When this bit is reset the address filter module ignores the address for filtering.*/ + }; + uint32_t val; + } emacaddr3high; + uint32_t emacaddr3low; /*This field contains the lower 32 bits of the fourth 6-byte MAC address.The content of this field is undefined so the register needs to be configured after the initialization Process.*/ + union { + struct { + uint32_t mac_address4_hi : 16; /*This field contains the upper 16 bits Bits[47:32] of the fifth 6-byte MAC address.*/ + uint32_t reserved16 : 8; + uint32_t mask_byte_control4 : 6; /*These bits are mask control bits for comparison of each of the EMACADDR4 bytes. When set high the MAC does not compare the corresponding byte of received DA or SA with the contents of EMACADDR4 registers. Each bit controls the masking of the bytes as follows: Bit[29]: EMACADDR4 High [15:8]. Bit[28]: EMACADDR4 High [7:0]. Bit[27]: EMACADDR4 Low [31:24]. Bit[24]: EMACADDR4 Low [7:0].You can filter a group of addresses (known as group address filtering) by masking one or more bytes of the address.*/ + uint32_t source_address4 : 1; /*When this bit is set the EMACADDR4[47:0] is used to compare with the SA fields of the received frame. When this bit is reset the EMACADDR4[47:0] is used to compare with the DA fields of the received frame.*/ + uint32_t address_enable4 : 1; /*When this bit is set the address filter module uses the fifth MAC address for perfect filtering. When this bit is reset the address filter module ignores the address for filtering.*/ + }; + uint32_t val; + } emacaddr4high; + uint32_t emacaddr4low; /*This field contains the lower 32 bits of the fifth 6-byte MAC address. The content of this field is undefined so the register needs to be configured after the initialization process.*/ + union { + struct { + uint32_t mac_address5_hi : 16; /*This field contains the upper 16 bits Bits[47:32] of the sixth 6-byte MAC address.*/ + uint32_t reserved16 : 8; + uint32_t mask_byte_control5 : 6; /*These bits are mask control bits for comparison of each of the EMACADDR5 bytes. When set high the MAC does not compare the corresponding byte of received DA or SA with the contents of EMACADDR5 registers. Each bit controls the masking of the bytes as follows: Bit[29]: EMACADDR5 High [15:8]. Bit[28]: EMACADDR5 High [7:0]. Bit[27]: EMACADDR5 Low [31:24]. Bit[24]: EMACADDR5 Low [7:0].You can filter a group of addresses (known as group address filtering) by masking one or more bytes of the address.*/ + uint32_t source_address5 : 1; /*When this bit is set the EMACADDR5[47:0] is used to compare with the SA fields of the received frame. When this bit is reset the EMACADDR5[47:0] is used to compare with the DA fields of the received frame.*/ + uint32_t address_enable5 : 1; /*When this bit is set the address filter module uses the sixth MAC address for perfect filtering. When this bit is reset the address filter module ignores the address for filtering.*/ + }; + uint32_t val; + } emacaddr5high; + uint32_t emacaddr5low; /*This field contains the lower 32 bits of the sixth 6-byte MAC address. The content of this field is undefined so the register needs to be configured after the initialization process.*/ + union { + struct { + uint32_t mac_address6_hi : 16; /*This field contains the upper 16 bits Bits[47:32] of the seventh 6-byte MAC Address.*/ + uint32_t reserved16 : 8; + uint32_t mask_byte_control6 : 6; /*These bits are mask control bits for comparison of each of the EMACADDR6 bytes. When set high the MAC does not compare the corresponding byte of received DA or SA with the contents of EMACADDR6 registers. Each bit controls the masking of the bytes as follows: Bit[29]: EMACADDR6 High [15:8]. Bit[28]: EMACADDR6 High [7:0]. Bit[27]: EMACADDR6 Low [31:24]. Bit[24]: EMACADDR6 Low [7:0].You can filter a group of addresses (known as group address filtering) by masking one or more bytes of the address.*/ + uint32_t source_address6 : 1; /*When this bit is set the EMACADDR6[47:0] is used to compare with the SA fields of the received frame. When this bit is reset the EMACADDR6[47:0] is used to compare with the DA fields of the received frame.*/ + uint32_t address_enable6 : 1; /*When this bit is set the address filter module uses the seventh MAC address for perfect filtering. When this bit is reset the address filter module ignores the address for filtering.*/ + }; + uint32_t val; + } emacaddr6high; + uint32_t emacaddr6low; /*This field contains the lower 32 bits of the seventh 6-byte MAC address.The content of this field is undefined so the register needs to be configured after the initialization Process.*/ + union { + struct { + uint32_t mac_address7_hi : 16; /*This field contains the upper 16 bits Bits[47:32] of the eighth 6-byte MAC Address.*/ + uint32_t reserved16 : 8; + uint32_t mask_byte_control7 : 6; /*These bits are mask control bits for comparison of each of the EMACADDR7 bytes. When set high the MAC does not compare the corresponding byte of received DA or SA with the contents of EMACADDR7 registers. Each bit controls the masking of the bytes as follows: Bit[29]: EMACADDR7 High [15:8]. Bit[28]: EMACADDR7 High [7:0]. Bit[27]: EMACADDR7 Low [31:24]. Bit[24]: EMACADDR7 Low [7:0].You can filter a group of addresses (known as group address filtering) by masking one or more bytes of the address.*/ + uint32_t source_address7 : 1; /*When this bit is set the EMACADDR7[47:0] is used to compare with the SA fields of the received frame. When this bit is reset the EMACADDR7[47:0] is used to compare with the DA fields of the received frame.*/ + uint32_t address_enable7 : 1; /*When this bit is set the address filter module uses the eighth MAC address for perfect filtering. When this bit is reset the address filter module ignores the address for filtering.*/ + }; + uint32_t val; + } emacaddr7high; + uint32_t emacaddr7low; /*This field contains the lower 32 bits of the eighth 6-byte MAC address.The content of this field is undefined so the register needs to be configured after the initialization Process.*/ + uint32_t reserved_1080; + uint32_t reserved_1084; + uint32_t reserved_1088; + uint32_t reserved_108c; + uint32_t reserved_1090; + uint32_t reserved_1094; + uint32_t reserved_1098; + uint32_t reserved_109c; + uint32_t reserved_10a0; + uint32_t reserved_10a4; + uint32_t reserved_10a8; + uint32_t reserved_10ac; + uint32_t reserved_10b0; + uint32_t reserved_10b4; + uint32_t reserved_10b8; + uint32_t reserved_10bc; + uint32_t reserved_10c0; + uint32_t reserved_10c4; + uint32_t reserved_10c8; + uint32_t reserved_10cc; + uint32_t reserved_10d0; + uint32_t reserved_10d4; + union { + struct { + uint32_t link_mode : 1; /*This bit indicates the current mode of operation of the link: 1'b0: Half-duplex mode. 1'b1: Full-duplex mode.*/ + uint32_t link_speed : 2; /*This bit indicates the current speed of the link: 2'b00: 2.5 MHz. 2'b01: 25 MHz. 2'b10: 125 MHz.*/ + uint32_t reserved3 : 1; + uint32_t jabber_timeout : 1; /*This bit indicates whether there is jabber timeout error (1'b1) in the received Frame.*/ + uint32_t reserved5 : 1; + uint32_t reserved6 : 10; + uint32_t reserved16 : 1; + uint32_t reserved17 : 15; + }; + uint32_t val; + } emaccstatus; + union { + struct { + uint32_t wdogto : 14; /*When Bit[16] (PWE) is set and Bit[23] (WD) of EMACCONFIG_REG is reset this field is used as watchdog timeout for a received frame. If the length of a received frame exceeds the value of this field such frame is terminated and declared as an error frame.*/ + uint32_t reserved14 : 2; + uint32_t pwdogen : 1; /*When this bit is set and Bit[23] (WD) of EMACCONFIG_REG is reset the WTO field (Bits[13:0]) is used as watchdog timeout for a received frame. When this bit is cleared the watchdog timeout for a received frame is controlled by the setting of Bit[23] (WD) and Bit[20] (JE) in EMACCONFIG_REG.*/ + uint32_t reserved17 : 15; + }; + uint32_t val; + } emacwdogto; +} emac_mac_dev_t; + +extern emac_mac_dev_t EMAC_MAC; + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/esp32/include/soc/emac_reg_v2.h b/components/soc/esp32/include/soc/emac_reg_v2.h deleted file mode 100644 index 72af5bfe36..0000000000 --- a/components/soc/esp32/include/soc/emac_reg_v2.h +++ /dev/null @@ -1,1460 +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 _SOC_EMAC_REG_H_ -#define _SOC_EMAC_REG_H_ - - -#ifdef __cplusplus -extern "C" { -#endif -#include "soc.h" -#define EMAC_DMABUSMODE_REG (DR_REG_EMAC_BASE + 0x0000) -/* EMAC_DMAMIXEDBURST : R/W ;bitpos:[26] ;default: 1'h0 ; */ -/*description: When this bit is set high and the FIXED_BURST bit is low the - AHB master interface starts all bursts of a length more than 16 with INCR (undefined burst) whereas it reverts to fixed burst transfers (INCRx and SINGLE) for burst length of 16 and less.*/ -#define EMAC_DMAMIXEDBURST (BIT(26)) -#define EMAC_DMAMIXEDBURST_M (BIT(26)) -#define EMAC_DMAMIXEDBURST_V 0x1 -#define EMAC_DMAMIXEDBURST_S 26 -/* EMAC_DMAADDRALIBEA : R/W ;bitpos:[25] ;default: 1'h0 ; */ -/*description: When this bit is set high and the FIXED_BURST bit is 1 the AHB - interface generates all bursts aligned to the start address LS bits. If the FIXED_BURST bit is 0 the first burst (accessing the start address of data buffer) is not aligned but subsequent bursts are aligned to the address.*/ -#define EMAC_DMAADDRALIBEA (BIT(25)) -#define EMAC_DMAADDRALIBEA_M (BIT(25)) -#define EMAC_DMAADDRALIBEA_V 0x1 -#define EMAC_DMAADDRALIBEA_S 25 -/* EMAC_PBLX8_MODE : R/W ;bitpos:[24] ;default: 1'h0 ; */ -/*description: When set high this bit multiplies the programmed PBL value (Bits[22:17] - and Bits[13:8]) eight times. Therefore the DMA transfers the data in 8 16 32 64 128 and 256 beats depending on the PBL value.*/ -#define EMAC_PBLX8_MODE (BIT(24)) -#define EMAC_PBLX8_MODE_M (BIT(24)) -#define EMAC_PBLX8_MODE_V 0x1 -#define EMAC_PBLX8_MODE_S 24 -/* EMAC_USE_SEP_PBL : R/W ;bitpos:[23] ;default: 1'h0 ; */ -/*description: When set high this bit configures the Rx DMA to use the value - configured in Bits[22:17] as PBL. The PBL value in Bits[13:8] is applicable only to the Tx DMA operations. When reset to low the PBL value in Bits[13:8] is applicable for both DMA engines.*/ -#define EMAC_USE_SEP_PBL (BIT(23)) -#define EMAC_USE_SEP_PBL_M (BIT(23)) -#define EMAC_USE_SEP_PBL_V 0x1 -#define EMAC_USE_SEP_PBL_S 23 -/* EMAC_RX_DMA_PBL : R/W ;bitpos:[22:17] ;default: 6'h1 ; */ -/*description: This field indicates the maximum number of beats to be transferred - in one Rx DMA transaction. This is the maximum value that is used in a single block Read or Write.The Rx DMA always attempts to burst as specified in the RPBL(RX_DMA_PBL) bit each time it starts a burst transfer on the host bus. You can program RPBL with values of 1 2 4 8 16 and 32. Any other value results in undefined behavior. This field is valid and applicable only when USP(USE_SEP_PBL) is set high.*/ -#define EMAC_RX_DMA_PBL 0x0000003F -#define EMAC_RX_DMA_PBL_M ((EMAC_RX_DMA_PBL_V)<<(EMAC_RX_DMA_PBL_S)) -#define EMAC_RX_DMA_PBL_V 0x3F -#define EMAC_RX_DMA_PBL_S 17 -/* EMAC_FIXED_BURST : R/W ;bitpos:[16] ;default: 1'h0 ; */ -/*description: This bit controls whether the AHB master interface performs fixed - burst transfers or not. When set the AHB interface uses only SINGLE INCR4 INCR8 or INCR16 during start of the normal burst transfers. When reset the AHB interface uses SINGLE and INCR burst transfer Operations.*/ -#define EMAC_FIXED_BURST (BIT(16)) -#define EMAC_FIXED_BURST_M (BIT(16)) -#define EMAC_FIXED_BURST_V 0x1 -#define EMAC_FIXED_BURST_S 16 -/* EMAC_PRI_RATIO : R/W ;bitpos:[15:14] ;default: 2'h0 ; */ -/*description: These bits control the priority ratio in the weighted round-robin - arbitration between the Rx DMA and Tx DMA. These bits are valid only when Bit 1 (DA) is reset. The priority ratio Rx:Tx represented by each bit: 2'b00 -- 1: 1 2'b01 -- 2: 0 2'b10 -- 3: 1 2'b11 -- 4: 1*/ -#define EMAC_PRI_RATIO 0x00000003 -#define EMAC_PRI_RATIO_M ((EMAC_PRI_RATIO_V)<<(EMAC_PRI_RATIO_S)) -#define EMAC_PRI_RATIO_V 0x3 -#define EMAC_PRI_RATIO_S 14 -/* EMAC_PROG_BURST_LEN : R/W ;bitpos:[13:8] ;default: 6'h1 ; */ -/*description: These bits indicate the maximum number of beats to be transferred - in one DMA transaction. If the number of beats to be transferred is more than 32 then perform the following steps: 1. Set the PBLx8 mode 2. Set the PBL(PROG_BURST_LEN).*/ -#define EMAC_PROG_BURST_LEN 0x0000003F -#define EMAC_PROG_BURST_LEN_M ((EMAC_PROG_BURST_LEN_V)<<(EMAC_PROG_BURST_LEN_S)) -#define EMAC_PROG_BURST_LEN_V 0x3F -#define EMAC_PROG_BURST_LEN_S 8 -/* EMAC_ALT_DESC_SIZE : R/W ;bitpos:[7] ;default: 1'h0 ; */ -/*description: When set the size of the alternate descriptor increases to 32 bytes.*/ -#define EMAC_ALT_DESC_SIZE (BIT(7)) -#define EMAC_ALT_DESC_SIZE_M (BIT(7)) -#define EMAC_ALT_DESC_SIZE_V 0x1 -#define EMAC_ALT_DESC_SIZE_S 7 -/* EMAC_DESC_SKIP_LEN : R/W ;bitpos:[6:2] ;default: 5'h0 ; */ -/*description: This bit specifies the number of Word to skip between two unchained - descriptors.The address skipping starts from the end of current descriptor to the start of next descriptor. When the DSL(DESC_SKIP_LEN) value is equal to zero the descriptor table is taken as contiguous by the DMA in Ring mode.*/ -#define EMAC_DESC_SKIP_LEN 0x0000001F -#define EMAC_DESC_SKIP_LEN_M ((EMAC_DESC_SKIP_LEN_V)<<(EMAC_DESC_SKIP_LEN_S)) -#define EMAC_DESC_SKIP_LEN_V 0x1F -#define EMAC_DESC_SKIP_LEN_S 2 -/* EMAC_DMA_ARB_SCH : R/W ;bitpos:[1] ;default: 1'h0 ; */ -/*description: This bit specifies the arbitration scheme between the transmit - and receive paths.1'b0: weighted round-robin with RX:TX or TX:RX priority specified in PR (bit[15:14]). 1'b1 Fixed priority (Rx priority to Tx).*/ -#define EMAC_DMA_ARB_SCH (BIT(1)) -#define EMAC_DMA_ARB_SCH_M (BIT(1)) -#define EMAC_DMA_ARB_SCH_V 0x1 -#define EMAC_DMA_ARB_SCH_S 1 -/* EMAC_SW_RST : R_WS_SC ;bitpos:[0] ;default: 1'h1 ; */ -/*description: When this bit is set the MAC DMA Controller resets the logic - and all internal registers of the MAC. It is cleared automatically after the reset operation is complete in all of the ETH_MAC clock domains. Before reprogramming any register of the ETH_MAC you should read a zero (0) value in this bit.*/ -#define EMAC_SW_RST (BIT(0)) -#define EMAC_SW_RST_M (BIT(0)) -#define EMAC_SW_RST_V 0x1 -#define EMAC_SW_RST_S 0 - -#define EMAC_DMATXPOLLDEMAND_REG (DR_REG_EMAC_BASE + 0x0004) -/* EMAC_TRANS_POLL_DEMAND : RO_WT ;bitpos:[31:0] ;default: 32'h0 ; */ -/*description: When these bits are written with any value the DMA reads the - current descriptor to which the Register (Current Host Transmit Descriptor Register) is pointing. If that descriptor is not available (owned by the Host) the transmission returns to the suspend state and Bit[2] (TU) of Status Register is asserted. If the descriptor is available the transmission resumes.*/ -#define EMAC_TRANS_POLL_DEMAND 0xFFFFFFFF -#define EMAC_TRANS_POLL_DEMAND_M ((EMAC_TRANS_POLL_DEMAND_V)<<(EMAC_TRANS_POLL_DEMAND_S)) -#define EMAC_TRANS_POLL_DEMAND_V 0xFFFFFFFF -#define EMAC_TRANS_POLL_DEMAND_S 0 - -#define EMAC_DMARXPOLLDEMAND_REG (DR_REG_EMAC_BASE + 0x0008) -/* EMAC_RECV_POLL_DEMAND : RO_WT ;bitpos:[31:0] ;default: 32'h0 ; */ -/*description: When these bits are written with any value the DMA reads the - current descriptor to which the Current Host Receive Descriptor Register is pointing. If that descriptor is not available (owned by the Host) the reception returns to the Suspended state and Bit[7] (RU) of Status Register is asserted. If the descriptor is available the Rx DMA returns to the active state.*/ -#define EMAC_RECV_POLL_DEMAND 0xFFFFFFFF -#define EMAC_RECV_POLL_DEMAND_M ((EMAC_RECV_POLL_DEMAND_V)<<(EMAC_RECV_POLL_DEMAND_S)) -#define EMAC_RECV_POLL_DEMAND_V 0xFFFFFFFF -#define EMAC_RECV_POLL_DEMAND_S 0 - -#define EMAC_DMARXBASEADDR_REG (DR_REG_EMAC_BASE + 0x000C) -/* EMAC_START_RECV_LIST : R/W ;bitpos:[31:0] ;default: 32'h0 ; */ -/*description: This field contains the base address of the first descriptor - in the Receive Descriptor list. The LSB Bits[1:0] are ignored and internally taken as all-zero by the DMA. Therefore these LSB bits are read-only.*/ -#define EMAC_START_RECV_LIST 0xFFFFFFFF -#define EMAC_START_RECV_LIST_M ((EMAC_START_RECV_LIST_V)<<(EMAC_START_RECV_LIST_S)) -#define EMAC_START_RECV_LIST_V 0xFFFFFFFF -#define EMAC_START_RECV_LIST_S 0 - -#define EMAC_DMATXBASEADDR_REG (DR_REG_EMAC_BASE + 0x0010) -/* EMAC_START_TRANS_LIST : R/W ;bitpos:[31:0] ;default: 32'h0 ; */ -/*description: This field contains the base address of the first descriptor - in the Transmit Descriptor list. The LSB Bits[1:0] are ignored and are internally taken as all-zero by the DMA.Therefore these LSB bits are read-only.*/ -#define EMAC_START_TRANS_LIST 0xFFFFFFFF -#define EMAC_START_TRANS_LIST_M ((EMAC_START_TRANS_LIST_V)<<(EMAC_START_TRANS_LIST_S)) -#define EMAC_START_TRANS_LIST_V 0xFFFFFFFF -#define EMAC_START_TRANS_LIST_S 0 - -#define EMAC_DMASTATUS_REG (DR_REG_EMAC_BASE + 0x0014) -/* EMAC_TS_TRI_INT : RO ;bitpos:[29] ;default: 1'h0 ; */ -/*description: This bit indicates an interrupt event in the Timestamp Generator - block of the ETH_MAC.The software must read the corresponding registers in the ETH_MAC to get the exact cause of the interrupt and clear its source to reset this bit to 1'b0.*/ -#define EMAC_TS_TRI_INT (BIT(29)) -#define EMAC_TS_TRI_INT_M (BIT(29)) -#define EMAC_TS_TRI_INT_V 0x1 -#define EMAC_TS_TRI_INT_S 29 -/* EMAC_PMT_INT : RO ;bitpos:[28] ;default: 1'h0 ; */ -/*description: This bit indicates an interrupt event in the PMT module of the - ETH_MAC. The software must read the PMT Control and Status Register in the MAC to get the exact cause of interrupt and clear its source to reset this bit to 1'b0.*/ -#define EMAC_PMT_INT (BIT(28)) -#define EMAC_PMT_INT_M (BIT(28)) -#define EMAC_PMT_INT_V 0x1 -#define EMAC_PMT_INT_S 28 -/* EMAC_ERROR_BITS : RO ;bitpos:[25:23] ;default: 3'h0 ; */ -/*description: This field indicates the type of error that caused a Bus Error - for example error response on the AHB interface. This field is valid only when Bit[13] (FBI) is set. This field does not generate an interrupt. 3'b000: Error during Rx DMA Write Data Transfer. 3'b011: Error during Tx DMA Read Data Transfer. 3'b100: Error during Rx DMA Descriptor Write Access. 3'b101: Error during Tx DMA Descriptor Write Access. 3'b110: Error during Rx DMA Descriptor Read Access. 3'b111: Error during Tx DMA Descriptor Read Access.*/ -#define EMAC_ERROR_BITS 0x00000007 -#define EMAC_ERROR_BITS_M ((EMAC_ERROR_BITS_V)<<(EMAC_ERROR_BITS_S)) -#define EMAC_ERROR_BITS_V 0x7 -#define EMAC_ERROR_BITS_S 23 -/* EMAC_TRANS_PROC_STATE : RO ;bitpos:[22:20] ;default: 3'h0 ; */ -/*description: This field indicates the Transmit DMA FSM state. This field does - not generate an interrupt. 3'b000: Stopped. Reset or Stop Transmit Command issued. 3'b001: Running. Fetching Transmit Transfer Descriptor. 3'b010: Reserved for future use. 3'b011: Running. Waiting for TX packets. 3'b100: Suspended. Receive Descriptor Unavailable. 3'b101: Running. Closing Transmit Descriptor. 3'b110: TIME_STAMP write state. 3'b111: Running. Transferring the TX packets data from transmit buffer to host memory.*/ -#define EMAC_TRANS_PROC_STATE 0x00000007 -#define EMAC_TRANS_PROC_STATE_M ((EMAC_TRANS_PROC_STATE_V)<<(EMAC_TRANS_PROC_STATE_S)) -#define EMAC_TRANS_PROC_STATE_V 0x7 -#define EMAC_TRANS_PROC_STATE_S 20 -/* EMAC_RECV_PROC_STATE : RO ;bitpos:[19:17] ;default: 3'h0 ; */ -/*description: This field indicates the Receive DMA FSM state. This field does - not generate an interrupt. 3'b000: Stopped. Reset or Stop Receive Command issued. 3'b001: Running. Fetching Receive Transfer Descriptor. 3'b010: Reserved for future use. 3'b011: Running. Waiting for RX packets. 3'b100: Suspended. Receive Descriptor Unavailable. 3'b101: Running. Closing Receive Descriptor. 3'b110: TIME_STAMP write state. 3'b111: Running. Transferring the TX packets data from receive buffer to host memory.*/ -#define EMAC_RECV_PROC_STATE 0x00000007 -#define EMAC_RECV_PROC_STATE_M ((EMAC_RECV_PROC_STATE_V)<<(EMAC_RECV_PROC_STATE_S)) -#define EMAC_RECV_PROC_STATE_V 0x7 -#define EMAC_RECV_PROC_STATE_S 17 -/* EMAC_NORM_INT_SUMM : R_SS_WC ;bitpos:[16] ;default: 1'h0 ; */ -/*description: Normal Interrupt Summary bit value is the logical OR of the following - bits when the corresponding interrupt bits are enabled in Interrupt Enable Register: Bit[0]: Transmit Interrupt. Bit[2]: Transmit Buffer Unavailable. Bit[6]: Receive Interrupt. Bit[14]: Early Receive Interrupt. Only unmasked bits affect the Normal Interrupt Summary bit.This is a sticky bit and must be cleared (by writing 1 to this bit) each time a corresponding bit which causes NIS to be set is cleared.*/ -#define EMAC_NORM_INT_SUMM (BIT(16)) -#define EMAC_NORM_INT_SUMM_M (BIT(16)) -#define EMAC_NORM_INT_SUMM_V 0x1 -#define EMAC_NORM_INT_SUMM_S 16 -/* EMAC_ABN_INT_SUMM : R_SS_WC ;bitpos:[15] ;default: 1'h0 ; */ -/*description: Abnormal Interrupt Summary bit value is the logical OR of the - following when the corresponding interrupt bits are enabled in Interrupt Enable Register: Bit[1]: Transmit Process Stopped. Bit[3]: Transmit Jabber Timeout. Bit[4]: Receive FIFO Overflow. Bit[5]: Transmit Underflow. Bit[7]: Receive Buffer Unavailable. Bit[8]: Receive Process Stopped. Bit[9]: Receive Watchdog Timeout. Bit[10]: Early Transmit Interrupt. Bit[13]: Fatal Bus Error. Only unmasked bits affect the Abnormal Interrupt Summary bit. This is a sticky bit and must be cleared (by writing 1 to this bit) each time a corresponding bit which causes AIS to be set is cleared.*/ -#define EMAC_ABN_INT_SUMM (BIT(15)) -#define EMAC_ABN_INT_SUMM_M (BIT(15)) -#define EMAC_ABN_INT_SUMM_V 0x1 -#define EMAC_ABN_INT_SUMM_S 15 -/* EMAC_EARLY_RECV_INT : R_SS_WC ;bitpos:[14] ;default: 1'h0 ; */ -/*description: This bit indicates that the DMA filled the first data buffer - of the packet. This bit is cleared when the software writes 1 to this bit or when Bit[6] (RI) of this register is set (whichever occurs earlier).*/ -#define EMAC_EARLY_RECV_INT (BIT(14)) -#define EMAC_EARLY_RECV_INT_M (BIT(14)) -#define EMAC_EARLY_RECV_INT_V 0x1 -#define EMAC_EARLY_RECV_INT_S 14 -/* EMAC_FATAL_BUS_ERR_INT : R_SS_WC ;bitpos:[13] ;default: 1'h0 ; */ -/*description: This bit indicates that a bus error occurred as described in - Bits [25:23]. When this bit is set the corresponding DMA engine disables all of its bus accesses.*/ -#define EMAC_FATAL_BUS_ERR_INT (BIT(13)) -#define EMAC_FATAL_BUS_ERR_INT_M (BIT(13)) -#define EMAC_FATAL_BUS_ERR_INT_V 0x1 -#define EMAC_FATAL_BUS_ERR_INT_S 13 -/* EMAC_EARLY_TRANS_INT : R_SS_WC ;bitpos:[10] ;default: 1'h0 ; */ -/*description: This bit indicates that the frame to be transmitted is fully - transferred to the MTL Transmit FIFO.*/ -#define EMAC_EARLY_TRANS_INT (BIT(10)) -#define EMAC_EARLY_TRANS_INT_M (BIT(10)) -#define EMAC_EARLY_TRANS_INT_V 0x1 -#define EMAC_EARLY_TRANS_INT_S 10 -/* EMAC_RECV_WDT_TO : R_SS_WC ;bitpos:[9] ;default: 1'h0 ; */ -/*description: When set this bit indicates that the Receive Watchdog Timer - expired while receiving the current frame and the current frame is truncated after the watchdog timeout.*/ -#define EMAC_RECV_WDT_TO (BIT(9)) -#define EMAC_RECV_WDT_TO_M (BIT(9)) -#define EMAC_RECV_WDT_TO_V 0x1 -#define EMAC_RECV_WDT_TO_S 9 -/* EMAC_RECV_PROC_STOP : R_SS_WC ;bitpos:[8] ;default: 1'h0 ; */ -/*description: This bit is asserted when the Receive Process enters the Stopped state.*/ -#define EMAC_RECV_PROC_STOP (BIT(8)) -#define EMAC_RECV_PROC_STOP_M (BIT(8)) -#define EMAC_RECV_PROC_STOP_V 0x1 -#define EMAC_RECV_PROC_STOP_S 8 -/* EMAC_RECV_BUF_UNAVAIL : R_SS_WC ;bitpos:[7] ;default: 1'h0 ; */ -/*description: This bit indicates that the host owns the Next Descriptor in - the Receive List and the DMA cannot acquire it. The Receive Process is suspended. To resume processing Receive descriptors the host should change the ownership of the descriptor and issue a Receive Poll Demand command. If no Receive Poll Demand is issued the Receive Process resumes when the next recognized incoming frame is received. This bit is set only when the previous Receive Descriptor is owned by the DMA.*/ -#define EMAC_RECV_BUF_UNAVAIL (BIT(7)) -#define EMAC_RECV_BUF_UNAVAIL_M (BIT(7)) -#define EMAC_RECV_BUF_UNAVAIL_V 0x1 -#define EMAC_RECV_BUF_UNAVAIL_S 7 -/* EMAC_RECV_INT : R_SS_WC ;bitpos:[6] ;default: 1'h0 ; */ -/*description: This bit indicates that the frame reception is complete. When - reception is complete the Bit[31] of RDES1 (Disable Interrupt on Completion) is reset in the last Descriptor and the specific frame status information is updated in the descriptor. The reception remains in the Running state.*/ -#define EMAC_RECV_INT (BIT(6)) -#define EMAC_RECV_INT_M (BIT(6)) -#define EMAC_RECV_INT_V 0x1 -#define EMAC_RECV_INT_S 6 -/* EMAC_TRANS_UNDFLOW : R_SS_WC ;bitpos:[5] ;default: 1'h0 ; */ -/*description: This bit indicates that the Transmit Buffer had an Underflow - during frame transmission. Transmission is suspended and an Underflow Error TDES0[1] is set.*/ -#define EMAC_TRANS_UNDFLOW (BIT(5)) -#define EMAC_TRANS_UNDFLOW_M (BIT(5)) -#define EMAC_TRANS_UNDFLOW_V 0x1 -#define EMAC_TRANS_UNDFLOW_S 5 -/* EMAC_RECV_OVFLOW : R_SS_WC ;bitpos:[4] ;default: 1'h0 ; */ -/*description: This bit indicates that the Receive Buffer had an Overflow during - frame reception. If the partial frame is transferred to the application the overflow status is set in RDES0[11].*/ -#define EMAC_RECV_OVFLOW (BIT(4)) -#define EMAC_RECV_OVFLOW_M (BIT(4)) -#define EMAC_RECV_OVFLOW_V 0x1 -#define EMAC_RECV_OVFLOW_S 4 -/* EMAC_TRANS_JABBER_TO : R_SS_WC ;bitpos:[3] ;default: 1'h0 ; */ -/*description: This bit indicates that the Transmit Jabber Timer expired which - happens when the frame size exceeds 2 048 (10 240 bytes when the Jumbo frame is enabled). When the Jabber Timeout occurs the transmission process is aborted and placed in the Stopped state. This causes the Transmit Jabber Timeout TDES0[14] flag to assert.*/ -#define EMAC_TRANS_JABBER_TO (BIT(3)) -#define EMAC_TRANS_JABBER_TO_M (BIT(3)) -#define EMAC_TRANS_JABBER_TO_V 0x1 -#define EMAC_TRANS_JABBER_TO_S 3 -/* EMAC_TRANS_BUF_UNAVAIL : R_SS_WC ;bitpos:[2] ;default: 1'h0 ; */ -/*description: This bit indicates that the host owns the Next Descriptor in - the Transmit List and the DMA cannot acquire it. Transmission is suspended. Bits[22:20] explain the Transmit Process state transitions. To resume processing Transmit descriptors the host should change the ownership of the descriptor by setting TDES0[31] and then issue a Transmit Poll Demand Command.*/ -#define EMAC_TRANS_BUF_UNAVAIL (BIT(2)) -#define EMAC_TRANS_BUF_UNAVAIL_M (BIT(2)) -#define EMAC_TRANS_BUF_UNAVAIL_V 0x1 -#define EMAC_TRANS_BUF_UNAVAIL_S 2 -/* EMAC_TRANS_PROC_STOP : R_SS_WC ;bitpos:[1] ;default: 1'h0 ; */ -/*description: This bit is set when the transmission is stopped.*/ -#define EMAC_TRANS_PROC_STOP (BIT(1)) -#define EMAC_TRANS_PROC_STOP_M (BIT(1)) -#define EMAC_TRANS_PROC_STOP_V 0x1 -#define EMAC_TRANS_PROC_STOP_S 1 -/* EMAC_TRANS_INT : R_SS_WC ;bitpos:[0] ;default: 1'h0 ; */ -/*description: This bit indicates that the frame transmission is complete. When - transmission is complete Bit[31] (OWN) of TDES0 is reset and the specific frame status information is updated in the Descriptor.*/ -#define EMAC_TRANS_INT (BIT(0)) -#define EMAC_TRANS_INT_M (BIT(0)) -#define EMAC_TRANS_INT_V 0x1 -#define EMAC_TRANS_INT_S 0 - -#define EMAC_DMAOPERATION_MODE_REG (DR_REG_EMAC_BASE + 0x0018) -/* EMAC_DIS_DROP_TCPIP_ERR_FRAM : R/W ;bitpos:[26] ;default: 1'h0 ; */ -/*description: When this bit is set the MAC does not drop the frames which - only have errors detected by the Receive Checksum engine.When this bit is reset all error frames are dropped if the Fwd_Err_Frame bit is reset.*/ -#define EMAC_DIS_DROP_TCPIP_ERR_FRAM (BIT(26)) -#define EMAC_DIS_DROP_TCPIP_ERR_FRAM_M (BIT(26)) -#define EMAC_DIS_DROP_TCPIP_ERR_FRAM_V 0x1 -#define EMAC_DIS_DROP_TCPIP_ERR_FRAM_S 26 -/* EMAC_RX_STORE_FORWARD : R/W ;bitpos:[25] ;default: 1'h0 ; */ -/*description: When this bit is set the MTL reads a frame from the Rx FIFO - only after the complete frame has been written to it.*/ -#define EMAC_RX_STORE_FORWARD (BIT(25)) -#define EMAC_RX_STORE_FORWARD_M (BIT(25)) -#define EMAC_RX_STORE_FORWARD_V 0x1 -#define EMAC_RX_STORE_FORWARD_S 25 -/* EMAC_DIS_FLUSH_RECV_FRAMES : R/W ;bitpos:[24] ;default: 1'h0 ; */ -/*description: When this bit is set the Rx DMA does not flush any frames because - of the unavailability of receive descriptors or buffers.*/ -#define EMAC_DIS_FLUSH_RECV_FRAMES (BIT(24)) -#define EMAC_DIS_FLUSH_RECV_FRAMES_M (BIT(24)) -#define EMAC_DIS_FLUSH_RECV_FRAMES_V 0x1 -#define EMAC_DIS_FLUSH_RECV_FRAMES_S 24 -/* EMAC_TX_STR_FWD : R/W ;bitpos:[21] ;default: 1'h0 ; */ -/*description: When this bit is set transmission starts when a full frame resides - in the MTL Transmit FIFO. When this bit is set the Tx_Thresh_Ctrl values specified in Tx_Thresh_Ctrl are ignored.*/ -#define EMAC_TX_STR_FWD (BIT(21)) -#define EMAC_TX_STR_FWD_M (BIT(21)) -#define EMAC_TX_STR_FWD_V 0x1 -#define EMAC_TX_STR_FWD_S 21 -/* EMAC_FLUSH_TX_FIFO : R_WS_SC ;bitpos:[20] ;default: 1'h0 ; */ -/*description: When this bit is set the transmit FIFO controller logic is reset - to its default values and thus all data in the Tx FIFO is lost or flushed. This bit is cleared internally when the flushing operation is complete.*/ -#define EMAC_FLUSH_TX_FIFO (BIT(20)) -#define EMAC_FLUSH_TX_FIFO_M (BIT(20)) -#define EMAC_FLUSH_TX_FIFO_V 0x1 -#define EMAC_FLUSH_TX_FIFO_S 20 -/* EMAC_TX_THRESH_CTRL : R/W ;bitpos:[16:14] ;default: 3'h0 ; */ -/*description: These bits control the threshold level of the MTL Transmit FIFO. - Transmission starts when the frame size within the MTL Transmit FIFO is larger than the threshold. In addition full frames with a length less than the threshold are also transmitted. These bits are used only when Tx_Str_fwd is reset. 3'b000: 64 3'b001: 128 3'b010: 192 3'b011: 256 3'b100: 40 3'b101: 32 3'b110: 24 3'b111: 16 .*/ -#define EMAC_TX_THRESH_CTRL 0x00000007 -#define EMAC_TX_THRESH_CTRL_M ((EMAC_TX_THRESH_CTRL_V)<<(EMAC_TX_THRESH_CTRL_S)) -#define EMAC_TX_THRESH_CTRL_V 0x7 -#define EMAC_TX_THRESH_CTRL_S 14 -/* EMAC_START_STOP_TRANSMISSION_COMMAND : R/W ;bitpos:[13] ;default: 1'h0 ; */ -/*description: When this bit is set transmission is placed in the Running state - and the DMA checks the Transmit List at the current position for a frame to be transmitted.When this bit is reset the transmission process is placed in the Stopped state after completing the transmission of the current frame.*/ -#define EMAC_START_STOP_TRANSMISSION_COMMAND (BIT(13)) -#define EMAC_START_STOP_TRANSMISSION_COMMAND_M (BIT(13)) -#define EMAC_START_STOP_TRANSMISSION_COMMAND_V 0x1 -#define EMAC_START_STOP_TRANSMISSION_COMMAND_S 13 -/* EMAC_FWD_ERR_FRAME : R/W ;bitpos:[7] ;default: 1'h0 ; */ -/*description: When this bit is reset the Rx FIFO drops frames with error status - (CRC error collision error giant frame watchdog timeout or overflow).*/ -#define EMAC_FWD_ERR_FRAME (BIT(7)) -#define EMAC_FWD_ERR_FRAME_M (BIT(7)) -#define EMAC_FWD_ERR_FRAME_V 0x1 -#define EMAC_FWD_ERR_FRAME_S 7 -/* EMAC_FWD_UNDER_GF : R/W ;bitpos:[6] ;default: 1'h0 ; */ -/*description: When set the Rx FIFO forwards Undersized frames (that is frames - with no Error and length less than 64 bytes) including pad-bytes and CRC.*/ -#define EMAC_FWD_UNDER_GF (BIT(6)) -#define EMAC_FWD_UNDER_GF_M (BIT(6)) -#define EMAC_FWD_UNDER_GF_V 0x1 -#define EMAC_FWD_UNDER_GF_S 6 -/* EMAC_DROP_GFRM : R/W ;bitpos:[5] ;default: 1'h0 ; */ -/*description: When set the MAC drops the received giant frames in the Rx FIFO - that is frames that are larger than the computed giant frame limit.*/ -#define EMAC_DROP_GFRM (BIT(5)) -#define EMAC_DROP_GFRM_M (BIT(5)) -#define EMAC_DROP_GFRM_V 0x1 -#define EMAC_DROP_GFRM_S 5 -/* EMAC_RX_THRESH_CTRL : R/W ;bitpos:[4:3] ;default: 2'h0 ; */ -/*description: These two bits control the threshold level of the MTL Receive - FIFO. Transfer (request) to DMA starts when the frame size within the MTL Receive FIFO is larger than the threshold. 2'b00: 64, 2'b01: 32, 2'b10: 96, 2'b11: 128 .*/ -#define EMAC_RX_THRESH_CTRL 0x00000003 -#define EMAC_RX_THRESH_CTRL_M ((EMAC_RX_THRESH_CTRL_V)<<(EMAC_RX_THRESH_CTRL_S)) -#define EMAC_RX_THRESH_CTRL_V 0x3 -#define EMAC_RX_THRESH_CTRL_S 3 -/* EMAC_OPT_SECOND_FRAME : R/W ;bitpos:[2] ;default: 1'h0 ; */ -/*description: When this bit is set it instructs the DMA to process the second - frame of the Transmit data even before the status for the first frame is obtained.*/ -#define EMAC_OPT_SECOND_FRAME (BIT(2)) -#define EMAC_OPT_SECOND_FRAME_M (BIT(2)) -#define EMAC_OPT_SECOND_FRAME_V 0x1 -#define EMAC_OPT_SECOND_FRAME_S 2 -/* EMAC_START_STOP_RX : R/W ;bitpos:[1] ;default: 1'h0 ; */ -/*description: When this bit is set the Receive process is placed in the Running - state. The DMA attempts to acquire the descriptor from the Receive list and processes the incoming frames.When this bit is cleared the Rx DMA operation is stopped after the transfer of the current frame.*/ -#define EMAC_START_STOP_RX (BIT(1)) -#define EMAC_START_STOP_RX_M (BIT(1)) -#define EMAC_START_STOP_RX_V 0x1 -#define EMAC_START_STOP_RX_S 1 - -#define EMAC_DMAIN_EN_REG (DR_REG_EMAC_BASE + 0x001C) -/* EMAC_DMAIN_NISE : R/W ;bitpos:[16] ;default: 1'h0 ; */ -/*description: When this bit is set normal interrupt summary is enabled. When - this bit is reset normal interrupt summary is disabled. This bit enables the following interrupts in Status Register: Bit[0]: Transmit Interrupt. Bit[2]: Transmit Buffer Unavailable. Bit[6]: Receive Interrupt. Bit[14]: Early Receive Interrupt.*/ -#define EMAC_DMAIN_NISE (BIT(16)) -#define EMAC_DMAIN_NISE_M (BIT(16)) -#define EMAC_DMAIN_NISE_V 0x1 -#define EMAC_DMAIN_NISE_S 16 -/* EMAC_DMAIN_AISE : R/W ;bitpos:[15] ;default: 1'h0 ; */ -/*description: When this bit is set abnormal interrupt summary is enabled. - When this bit is reset the abnormal interrupt summary is disabled. This bit enables the following interrupts in Status Register: Bit[1]: Transmit Process Stopped. Bit[3]: Transmit Jabber Timeout. Bit[4]: Receive Overflow. Bit[5]: Transmit Underflow. Bit[7]: Receive Buffer Unavailable. Bit[8]: Receive Process Stopped. Bit[9]: Receive Watchdog Timeout. Bit[10]: Early Transmit Interrupt. Bit[13]: Fatal Bus Error.*/ -#define EMAC_DMAIN_AISE (BIT(15)) -#define EMAC_DMAIN_AISE_M (BIT(15)) -#define EMAC_DMAIN_AISE_V 0x1 -#define EMAC_DMAIN_AISE_S 15 -/* EMAC_DMAIN_ERIE : R/W ;bitpos:[14] ;default: 1'h0 ; */ -/*description: When this bit is set with Normal Interrupt Summary Enable (Bit[16]) - the Early Receive Interrupt is enabled. When this bit is reset the Early Receive Interrupt is disabled.*/ -#define EMAC_DMAIN_ERIE (BIT(14)) -#define EMAC_DMAIN_ERIE_M (BIT(14)) -#define EMAC_DMAIN_ERIE_V 0x1 -#define EMAC_DMAIN_ERIE_S 14 -/* EMAC_DMAIN_FBEE : R/W ;bitpos:[13] ;default: 1'h0 ; */ -/*description: When this bit is set with Abnormal Interrupt Summary Enable (Bit[15]) - the Fatal Bus Error Interrupt is enabled. When this bit is reset the Fatal Bus Error Enable Interrupt is disabled.*/ -#define EMAC_DMAIN_FBEE (BIT(13)) -#define EMAC_DMAIN_FBEE_M (BIT(13)) -#define EMAC_DMAIN_FBEE_V 0x1 -#define EMAC_DMAIN_FBEE_S 13 -/* EMAC_DMAIN_ETIE : R/W ;bitpos:[10] ;default: 1'h0 ; */ -/*description: When this bit is set with an Abnormal Interrupt Summary Enable - (Bit[15]) the Early Transmit Interrupt is enabled. When this bit is reset the Early Transmit Interrupt is disabled.*/ -#define EMAC_DMAIN_ETIE (BIT(10)) -#define EMAC_DMAIN_ETIE_M (BIT(10)) -#define EMAC_DMAIN_ETIE_V 0x1 -#define EMAC_DMAIN_ETIE_S 10 -/* EMAC_DMAIN_RWTE : R/W ;bitpos:[9] ;default: 1'h0 ; */ -/*description: When this bit is set with Abnormal Interrupt Summary Enable (Bit[15]) - the Receive Watchdog Timeout Interrupt is enabled. When this bit is reset the Receive Watchdog Timeout Interrupt is disabled.*/ -#define EMAC_DMAIN_RWTE (BIT(9)) -#define EMAC_DMAIN_RWTE_M (BIT(9)) -#define EMAC_DMAIN_RWTE_V 0x1 -#define EMAC_DMAIN_RWTE_S 9 -/* EMAC_DMAIN_RSE : R/W ;bitpos:[8] ;default: 1'h0 ; */ -/*description: When this bit is set with Abnormal Interrupt Summary Enable (Bit[15]) - the Receive Stopped Interrupt is enabled. When this bit is reset the Receive Stopped Interrupt is disabled.*/ -#define EMAC_DMAIN_RSE (BIT(8)) -#define EMAC_DMAIN_RSE_M (BIT(8)) -#define EMAC_DMAIN_RSE_V 0x1 -#define EMAC_DMAIN_RSE_S 8 -/* EMAC_DMAIN_RBUE : R/W ;bitpos:[7] ;default: 1'h0 ; */ -/*description: When this bit is set with Abnormal Interrupt Summary Enable (Bit[15]) - the Receive Buffer Unavailable Interrupt is enabled. When this bit is reset the Receive Buffer Unavailable Interrupt is disabled.*/ -#define EMAC_DMAIN_RBUE (BIT(7)) -#define EMAC_DMAIN_RBUE_M (BIT(7)) -#define EMAC_DMAIN_RBUE_V 0x1 -#define EMAC_DMAIN_RBUE_S 7 -/* EMAC_DMAIN_RIE : R/W ;bitpos:[6] ;default: 1'h0 ; */ -/*description: When this bit is set with Normal Interrupt Summary Enable (Bit[16]) - the Receive Interrupt is enabled. When this bit is reset the Receive Interrupt is disabled.*/ -#define EMAC_DMAIN_RIE (BIT(6)) -#define EMAC_DMAIN_RIE_M (BIT(6)) -#define EMAC_DMAIN_RIE_V 0x1 -#define EMAC_DMAIN_RIE_S 6 -/* EMAC_DMAIN_UIE : R/W ;bitpos:[5] ;default: 1'h0 ; */ -/*description: When this bit is set with Abnormal Interrupt Summary Enable (Bit[15]) - the Transmit Underflow Interrupt is enabled. When this bit is reset the Underflow Interrupt is disabled.*/ -#define EMAC_DMAIN_UIE (BIT(5)) -#define EMAC_DMAIN_UIE_M (BIT(5)) -#define EMAC_DMAIN_UIE_V 0x1 -#define EMAC_DMAIN_UIE_S 5 -/* EMAC_DMAIN_OIE : R/W ;bitpos:[4] ;default: 1'h0 ; */ -/*description: When this bit is set with Abnormal Interrupt Summary Enable (Bit[15]) - the Receive Overflow Interrupt is enabled. When this bit is reset the Overflow Interrupt is disabled.*/ -#define EMAC_DMAIN_OIE (BIT(4)) -#define EMAC_DMAIN_OIE_M (BIT(4)) -#define EMAC_DMAIN_OIE_V 0x1 -#define EMAC_DMAIN_OIE_S 4 -/* EMAC_DMAIN_TJTE : R/W ;bitpos:[3] ;default: 1'h0 ; */ -/*description: When this bit is set with Abnormal Interrupt Summary Enable (Bit[15]) - the Transmit Jabber Timeout Interrupt is enabled. When this bit is reset the Transmit Jabber Timeout Interrupt is disabled.*/ -#define EMAC_DMAIN_TJTE (BIT(3)) -#define EMAC_DMAIN_TJTE_M (BIT(3)) -#define EMAC_DMAIN_TJTE_V 0x1 -#define EMAC_DMAIN_TJTE_S 3 -/* EMAC_DMAIN_TBUE : R/W ;bitpos:[2] ;default: 1'h0 ; */ -/*description: When this bit is set with Normal Interrupt Summary Enable (Bit - 16) the Transmit Buffer Unavailable Interrupt is enabled. When this bit is reset the Transmit Buffer Unavailable Interrupt is Disabled.*/ -#define EMAC_DMAIN_TBUE (BIT(2)) -#define EMAC_DMAIN_TBUE_M (BIT(2)) -#define EMAC_DMAIN_TBUE_V 0x1 -#define EMAC_DMAIN_TBUE_S 2 -/* EMAC_DMAIN_TSE : R/W ;bitpos:[1] ;default: 1'h0 ; */ -/*description: When this bit is set with Abnormal Interrupt Summary Enable (Bit[15]) - the Transmission Stopped Interrupt is enabled. When this bit is reset the Transmission Stopped Interrupt is disabled.*/ -#define EMAC_DMAIN_TSE (BIT(1)) -#define EMAC_DMAIN_TSE_M (BIT(1)) -#define EMAC_DMAIN_TSE_V 0x1 -#define EMAC_DMAIN_TSE_S 1 -/* EMAC_DMAIN_TIE : R/W ;bitpos:[0] ;default: 1'h0 ; */ -/*description: When this bit is set with Normal Interrupt Summary Enable (Bit[16]) - the Transmit Interrupt is enabled. When this bit is reset the Transmit Interrupt is disabled.*/ -#define EMAC_DMAIN_TIE (BIT(0)) -#define EMAC_DMAIN_TIE_M (BIT(0)) -#define EMAC_DMAIN_TIE_V 0x1 -#define EMAC_DMAIN_TIE_S 0 - -#define EMAC_DMAMISSEDFR_REG (DR_REG_EMAC_BASE + 0x0020) -/* EMAC_OVERFLOW_BFOC : R_SS_RC ;bitpos:[28] ;default: 1'h0 ; */ -/*description: This bit is set every time the Overflow Frame Counter (Bits[27:17]) - overflows that is the Rx FIFO overflows with the overflow frame counter at maximum value. In such a scenario the overflow frame counter is reset to all-zeros and this bit indicates that the rollover happened.*/ -#define EMAC_OVERFLOW_BFOC (BIT(28)) -#define EMAC_OVERFLOW_BFOC_M (BIT(28)) -#define EMAC_OVERFLOW_BFOC_V 0x1 -#define EMAC_OVERFLOW_BFOC_S 28 -/* EMAC_OVERFLOW_FC : R_SS_RC ;bitpos:[27:17] ;default: 11'h0 ; */ -/*description: This field indicates the number of frames missed by the application. - This counter is incremented each time the MTL FIFO overflows. The counter is cleared when this register is read.*/ -#define EMAC_OVERFLOW_FC 0x000007FF -#define EMAC_OVERFLOW_FC_M ((EMAC_OVERFLOW_FC_V)<<(EMAC_OVERFLOW_FC_S)) -#define EMAC_OVERFLOW_FC_V 0x7FF -#define EMAC_OVERFLOW_FC_S 17 -/* EMAC_OVERFLOW_BMFC : R_SS_RC ;bitpos:[16] ;default: 1'h0 ; */ -/*description: This bit is set every time Missed Frame Counter (Bits[15:0]) - overflows that is the DMA discards an incoming frame because of the Host Receive Buffer being unavailable with the missed frame counter at maximum value. In such a scenario the Missed frame counter is reset to all-zeros and this bit indicates that the rollover happened.*/ -#define EMAC_OVERFLOW_BMFC (BIT(16)) -#define EMAC_OVERFLOW_BMFC_M (BIT(16)) -#define EMAC_OVERFLOW_BMFC_V 0x1 -#define EMAC_OVERFLOW_BMFC_S 16 -/* EMAC_MISSED_FC : R_SS_RC ;bitpos:[15:0] ;default: 16'h0 ; */ -/*description: This field indicates the number of frames missed by the controller - because of the Host Receive Buffer being unavailable. This counter is incremented each time the DMA discards an incoming frame. The counter is cleared when this register is read.*/ -#define EMAC_MISSED_FC 0x0000FFFF -#define EMAC_MISSED_FC_M ((EMAC_MISSED_FC_V)<<(EMAC_MISSED_FC_S)) -#define EMAC_MISSED_FC_V 0xFFFF -#define EMAC_MISSED_FC_S 0 - -#define EMAC_DMARINTWDTIMER_REG (DR_REG_EMAC_BASE + 0x0024) -/* EMAC_RIWTC : R/W ;bitpos:[7:0] ;default: 8'h0 ; */ -/*description: This bit indicates the number of system clock cycles multiplied - by 256 for which the watchdog timer is set. The watchdog timer gets triggered with the programmed value after the Rx DMA completes the transfer of a frame for which the RI(RECV_INT) status bit is not set because of the setting in the corresponding descriptor RDES1[31]. When the watchdog timer runs out the RI bit is set and the timer is stopped. The watchdog timer is reset when the RI bit is set high because of automatic setting of RI as per RDES1[31] of any received frame.*/ -#define EMAC_RIWTC 0x000000FF -#define EMAC_RIWTC_M ((EMAC_RIWTC_V)<<(EMAC_RIWTC_S)) -#define EMAC_RIWTC_V 0xFF -#define EMAC_RIWTC_S 0 - -#define EMAC_DMATXCURRDESC_REG (DR_REG_EMAC_BASE + 0x0048) -/* EMAC_TRANS_DSCR_ADDR_PTR : RO ;bitpos:[31:0] ;default: 32'h0 ; */ -/*description: The address of the current receive descriptor list. Cleared on - Reset.Pointer updated by the DMA during operation.*/ -#define EMAC_TRANS_DSCR_ADDR_PTR 0xFFFFFFFF -#define EMAC_TRANS_DSCR_ADDR_PTR_M ((EMAC_TRANS_DSCR_ADDR_PTR_V)<<(EMAC_TRANS_DSCR_ADDR_PTR_S)) -#define EMAC_TRANS_DSCR_ADDR_PTR_V 0xFFFFFFFF -#define EMAC_TRANS_DSCR_ADDR_PTR_S 0 - -#define EMAC_DMARXCURRDESC_REG (DR_REG_EMAC_BASE + 0x004C) -/* EMAC_RECV_DSCR_ADDR_PTR : RO ;bitpos:[31:0] ;default: 32'h0 ; */ -/*description: The address of the current receive descriptor list. Cleared on - Reset.Pointer updated by the DMA during operation.*/ -#define EMAC_RECV_DSCR_ADDR_PTR 0xFFFFFFFF -#define EMAC_RECV_DSCR_ADDR_PTR_M ((EMAC_RECV_DSCR_ADDR_PTR_V)<<(EMAC_RECV_DSCR_ADDR_PTR_S)) -#define EMAC_RECV_DSCR_ADDR_PTR_V 0xFFFFFFFF -#define EMAC_RECV_DSCR_ADDR_PTR_S 0 - -#define EMAC_DMATXCURRADDR_BUF_REG (DR_REG_EMAC_BASE + 0x0050) -/* EMAC_TRANS_BUFF_ADDR_PTR : RO ;bitpos:[31:0] ;default: 32'h0 ; */ -/*description: The address of the current receive descriptor list. Cleared on - Reset.Pointer updated by the DMA during operation.*/ -#define EMAC_TRANS_BUFF_ADDR_PTR 0xFFFFFFFF -#define EMAC_TRANS_BUFF_ADDR_PTR_M ((EMAC_TRANS_BUFF_ADDR_PTR_V)<<(EMAC_TRANS_BUFF_ADDR_PTR_S)) -#define EMAC_TRANS_BUFF_ADDR_PTR_V 0xFFFFFFFF -#define EMAC_TRANS_BUFF_ADDR_PTR_S 0 - -#define EMAC_DMARXCURRADDR_BUF_REG (DR_REG_EMAC_BASE + 0x0054) -/* EMAC_RECV_BUFF_ADDR_PTR : RO ;bitpos:[31:0] ;default: 32'h0 ; */ -/*description: The address of the current receive descriptor list. Cleared on - Reset.Pointer updated by the DMA during operation.*/ -#define EMAC_RECV_BUFF_ADDR_PTR 0xFFFFFFFF -#define EMAC_RECV_BUFF_ADDR_PTR_M ((EMAC_RECV_BUFF_ADDR_PTR_V)<<(EMAC_RECV_BUFF_ADDR_PTR_S)) -#define EMAC_RECV_BUFF_ADDR_PTR_V 0xFFFFFFFF -#define EMAC_RECV_BUFF_ADDR_PTR_S 0 - -#define EMAC_GMACCONFIG_REG (DR_REG_EMAC_BASE + 0x1000) -/* EMAC_SAIRC : R/W ;bitpos:[30:28] ;default: 3'h0 ; */ -/*description: This field controls the source address insertion or replacement - for all transmitted frames.Bit[30] specifies which MAC Address register (0 or 1) is used for source address insertion or replacement based on the values of Bits [29:28]: 2'b0x: The input signals mti_sa_ctrl_i and ati_sa_ctrl_i control the SA field generation. 2'b10: If Bit[30] is set to 0 the MAC inserts the content of the MAC Address 0 registers in the SA field of all transmitted frames. If Bit[30] is set to 1 the MAC inserts the content of the MAC Address 1 registers in the SA field of all transmitted frames. 2'b11: If Bit[30] is set to 0 the MAC replaces the content of the MAC Address 0 registers in the SA field of all transmitted frames. If Bit[30] is set to 1 the MAC replaces the content of the MAC Address 1 registers in the SA field of all transmitted frames.*/ -#define EMAC_SAIRC 0x00000007 -#define EMAC_SAIRC_M ((EMAC_SAIRC_V)<<(EMAC_SAIRC_S)) -#define EMAC_SAIRC_V 0x7 -#define EMAC_SAIRC_S 28 -/* EMAC_ASS2KP : R/W ;bitpos:[27] ;default: 1'h0 ; */ -/*description: When set the MAC considers all frames with up to 2 000 bytes - length as normal packets.When Bit[20] (JE) is not set the MAC considers all received frames of size more than 2K bytes as Giant frames. When this bit is reset and Bit[20] (JE) is not set the MAC considers all received frames of size more than 1 518 bytes (1 522 bytes for tagged) as Giant frames. When Bit[20] is set setting this bit has no effect on Giant Frame status.*/ -#define EMAC_ASS2KP (BIT(27)) -#define EMAC_ASS2KP_M (BIT(27)) -#define EMAC_ASS2KP_V 0x1 -#define EMAC_ASS2KP_S 27 -/* EMAC_EMACWATCHDOG : R/W ;bitpos:[23] ;default: 1'h0 ; */ -/*description: When this bit is set the MAC disables the watchdog timer on - the receiver. The MAC can receive frames of up to 16 383 bytes. When this bit is reset the MAC does not allow a receive frame which more than 2 048 bytes (10 240 if JE is set high) or the value programmed in Register (Watchdog Timeout Register). The MAC cuts off any bytes received after the watchdog limit number of bytes.*/ -#define EMAC_EMACWATCHDOG (BIT(23)) -#define EMAC_EMACWATCHDOG_M (BIT(23)) -#define EMAC_EMACWATCHDOG_V 0x1 -#define EMAC_EMACWATCHDOG_S 23 -/* EMAC_EMACJABBER : R/W ;bitpos:[22] ;default: 1'h0 ; */ -/*description: When this bit is set the MAC disables the jabber timer on the - transmitter. The MAC can transfer frames of up to 16 383 bytes. When this bit is reset the MAC cuts off the transmitter if the application sends out more than 2 048 bytes of data (10 240 if JE is set high) during Transmission.*/ -#define EMAC_EMACJABBER (BIT(22)) -#define EMAC_EMACJABBER_M (BIT(22)) -#define EMAC_EMACJABBER_V 0x1 -#define EMAC_EMACJABBER_S 22 -/* EMAC_EMACJUMBOFRAME : R/W ;bitpos:[20] ;default: 1'h0 ; */ -/*description: When this bit is set the MAC allows Jumbo frames of 9 018 bytes - (9 022 bytes for VLAN tagged frames) without reporting a giant frame error in the receive frame status.*/ -#define EMAC_EMACJUMBOFRAME (BIT(20)) -#define EMAC_EMACJUMBOFRAME_M (BIT(20)) -#define EMAC_EMACJUMBOFRAME_V 0x1 -#define EMAC_EMACJUMBOFRAME_S 20 -/* EMAC_EMACINTERFRAMEGAP : R/W ;bitpos:[19:17] ;default: 1'h0 ; */ -/*description: These bits control the minimum IFG between frames during transmission. - 3'b000: 96 bit times. 3'b001: 88 bit times. 3'b010: 80 bit times. 3'b111: 40 bit times. In the half-duplex mode the minimum IFG can be configured only for 64 bit times (IFG = 100). Lower values are not considered.*/ -#define EMAC_EMACINTERFRAMEGAP 0x00000007 -#define EMAC_EMACINTERFRAMEGAP_M ((EMAC_EMACINTERFRAMEGAP_V)<<(EMAC_EMACINTERFRAMEGAP_S)) -#define EMAC_EMACINTERFRAMEGAP_V 0x7 -#define EMAC_EMACINTERFRAMEGAP_S 17 -/* EMAC_EMACDISABLECRS : R/W ;bitpos:[16] ;default: 1'h0 ; */ -/*description: When set high this bit makes the MAC transmitter ignore the - MII CRS signal during frame transmission in the half-duplex mode. This request results in no errors generated because of Loss of Carrier or No Carrier during such transmission. When this bit is low the MAC transmitter generates such errors because of Carrier Sense and can even abort the transmissions.*/ -#define EMAC_EMACDISABLECRS (BIT(16)) -#define EMAC_EMACDISABLECRS_M (BIT(16)) -#define EMAC_EMACDISABLECRS_V 0x1 -#define EMAC_EMACDISABLECRS_S 16 -/* EMAC_EMACMII : R/W ;bitpos:[15] ;default: 1'h0 ; */ -/*description: This bit selects the Ethernet line speed. It should be set to - 1 for 10 or 100 Mbps operations.In 10 or 100 Mbps operations this bit along with FES(EMACFESPEED) bit it selects the exact linespeed. In the 10/100 Mbps-only operations the bit is always 1.*/ -#define EMAC_EMACMII (BIT(15)) -#define EMAC_EMACMII_M (BIT(15)) -#define EMAC_EMACMII_V 0x1 -#define EMAC_EMACMII_S 15 -/* EMAC_EMACFESPEED : R/W ;bitpos:[14] ;default: 1'h0 ; */ -/*description: This bit selects the speed in the MII RMII interface. 0: 10 Mbps. 1: 100 Mbps.*/ -#define EMAC_EMACFESPEED (BIT(14)) -#define EMAC_EMACFESPEED_M (BIT(14)) -#define EMAC_EMACFESPEED_V 0x1 -#define EMAC_EMACFESPEED_S 14 -/* EMAC_EMACRXOWN : R/W ;bitpos:[13] ;default: 1'h0 ; */ -/*description: When this bit is set the MAC disables the reception of frames - when the TX_EN is asserted in the half-duplex mode. When this bit is reset the MAC receives all packets that are given by the PHY while transmitting. This bit is not applicable if the MAC is operating in the full duplex mode.*/ -#define EMAC_EMACRXOWN (BIT(13)) -#define EMAC_EMACRXOWN_M (BIT(13)) -#define EMAC_EMACRXOWN_V 0x1 -#define EMAC_EMACRXOWN_S 13 -/* EMAC_EMACLOOPBACK : R/W ;bitpos:[12] ;default: 1'h0 ; */ -/*description: When this bit is set the MAC operates in the loopback mode MII. - The MII Receive clock input (CLK_RX) is required for the loopback to work properly because the transmit clock is not looped-back internally.*/ -#define EMAC_EMACLOOPBACK (BIT(12)) -#define EMAC_EMACLOOPBACK_M (BIT(12)) -#define EMAC_EMACLOOPBACK_V 0x1 -#define EMAC_EMACLOOPBACK_S 12 -/* EMAC_EMACDUPLEX : R/W ;bitpos:[11] ;default: 1'h0 ; */ -/*description: When this bit is set the MAC operates in the full-duplex mode - where it can transmit and receive simultaneously. This bit is read only with default value of 1'b1 in the full-duplex-mode.*/ -#define EMAC_EMACDUPLEX (BIT(11)) -#define EMAC_EMACDUPLEX_M (BIT(11)) -#define EMAC_EMACDUPLEX_V 0x1 -#define EMAC_EMACDUPLEX_S 11 -/* EMAC_EMACRXIPCOFFLOAD : R/W ;bitpos:[10] ;default: 1'h0 ; */ -/*description: When this bit is set the MAC calculates the 16-bit one's complement - of the one's complement sum of all received Ethernet frame payloads. It also checks whether the IPv4 Header checksum (assumed to be bytes 25/26 or 29/30 (VLAN-tagged) of the received Ethernet frame) is correct for the received frame and gives the status in the receive status word. The MAC also appends the 16-bit checksum calculated for the IP header datagram payload (bytes after the IPv4 header) and appends it to the Ethernet frame transferred to the application (when Type 2 COE is deselected). When this bit is reset this function is disabled.*/ -#define EMAC_EMACRXIPCOFFLOAD (BIT(10)) -#define EMAC_EMACRXIPCOFFLOAD_M (BIT(10)) -#define EMAC_EMACRXIPCOFFLOAD_V 0x1 -#define EMAC_EMACRXIPCOFFLOAD_S 10 -/* EMAC_EMACRETRY : R/W ;bitpos:[9] ;default: 1'h0 ; */ -/*description: When this bit is set the MAC attempts only one transmission. - When a collision occurs on the MII interface the MAC ignores the current frame transmission and reports a Frame Abort with excessive collision error in the transmit frame status. When this bit is reset the MAC attempts retries based on the settings of the BL field (Bits [6:5]). This bit is applicable only in the half-duplex Mode.*/ -#define EMAC_EMACRETRY (BIT(9)) -#define EMAC_EMACRETRY_M (BIT(9)) -#define EMAC_EMACRETRY_V 0x1 -#define EMAC_EMACRETRY_S 9 -/* EMAC_EMACPADCRCSTRIP : R/W ;bitpos:[7] ;default: 1'h0 ; */ -/*description: When this bit is set the MAC strips the Pad or FCS field on - the incoming frames only if the value of the length field is less than 1 536 bytes. All received frames with length field greater than or equal to 1 536 bytes are passed to the application without stripping the Pad or FCS field. When this bit is reset the MAC passes all incoming frames without modifying them to the Host.*/ -#define EMAC_EMACPADCRCSTRIP (BIT(7)) -#define EMAC_EMACPADCRCSTRIP_M (BIT(7)) -#define EMAC_EMACPADCRCSTRIP_V 0x1 -#define EMAC_EMACPADCRCSTRIP_S 7 -/* EMAC_EMACBACKOFFLIMIT : R/W ;bitpos:[6:5] ;default: 2'h0 ; */ -/*description: The Back-Off limit determines the random integer number (r) of - slot time delays (512 bit times for 10/100 Mbps) for which the MAC waits before rescheduling a transmission attempt during retries after a collision. This bit is applicable only in the half-duplex mode. 00: k= min (n 10). 01: k = min (n 8). 10: k = min (n 4). 11: k = min (n 1) n = retransmission attempt. The random integer r takes the value in the Range 0 ~ 2000.*/ -#define EMAC_EMACBACKOFFLIMIT 0x00000003 -#define EMAC_EMACBACKOFFLIMIT_M ((EMAC_EMACBACKOFFLIMIT_V)<<(EMAC_EMACBACKOFFLIMIT_S)) -#define EMAC_EMACBACKOFFLIMIT_V 0x3 -#define EMAC_EMACBACKOFFLIMIT_S 5 -/* EMAC_EMACDEFERRALCHECK : R/W ;bitpos:[4] ;default: 1'h0 ; */ -/*description: Deferral Check.*/ -#define EMAC_EMACDEFERRALCHECK (BIT(4)) -#define EMAC_EMACDEFERRALCHECK_M (BIT(4)) -#define EMAC_EMACDEFERRALCHECK_V 0x1 -#define EMAC_EMACDEFERRALCHECK_S 4 -/* EMAC_EMACTX : R/W ;bitpos:[3] ;default: 1'h0 ; */ -/*description: When this bit is set the transmit state machine of the MAC is - enabled for transmission on the MII. When this bit is reset the MAC transmit state machine is disabled after the completion of the transmission of the current frame and does not transmit any further frames.*/ -#define EMAC_EMACTX (BIT(3)) -#define EMAC_EMACTX_M (BIT(3)) -#define EMAC_EMACTX_V 0x1 -#define EMAC_EMACTX_S 3 -/* EMAC_EMACRX : R/W ;bitpos:[2] ;default: 1'h0 ; */ -/*description: When this bit is set the receiver state machine of the MAC is - enabled for receiving frames from the MII. When this bit is reset the MAC receive state machine is disabled after the completion of the reception of the current frame and does not receive any further frames from the MII.*/ -#define EMAC_EMACRX (BIT(2)) -#define EMAC_EMACRX_M (BIT(2)) -#define EMAC_EMACRX_V 0x1 -#define EMAC_EMACRX_S 2 -/* EMAC_PLTF : R/W ;bitpos:[1:0] ;default: 2'h0 ; */ -/*description: These bits control the number of preamble bytes that are added - to the beginning of every Transmit frame. The preamble reduction occurs only when the MAC is operating in the full-duplex mode.2'b00: 7 bytes of preamble. 2'b01: 5 bytes of preamble. 2'b10: 3 bytes of preamble.*/ -#define EMAC_PLTF 0x00000003 -#define EMAC_PLTF_M ((EMAC_PLTF_V)<<(EMAC_PLTF_S)) -#define EMAC_PLTF_V 0x3 -#define EMAC_PLTF_S 0 - -#define EMAC_GMACFF_REG (DR_REG_EMAC_BASE + 0x1004) -/* EMAC_RECEIVE_ALL : R/W ;bitpos:[31] ;default: 1'h0 ; */ -/*description: When this bit is set the MAC Receiver module passes all received - frames irrespective of whether they pass the address filter or not to the Application. The result of the SA or DA filtering is updated (pass or fail) in the corresponding bits in the Receive Status Word. When this bit is reset the Receiver module passes only those frames to the Application that pass the SA or DA address Filter.*/ -#define EMAC_RECEIVE_ALL (BIT(31)) -#define EMAC_RECEIVE_ALL_M (BIT(31)) -#define EMAC_RECEIVE_ALL_V 0x1 -#define EMAC_RECEIVE_ALL_S 31 -/* EMAC_SAFE : R/W ;bitpos:[9] ;default: 1'h0 ; */ -/*description: When this bit is set the MAC compares the SA field of the received - frames with the values programmed in the enabled SA registers. If the comparison fails the MAC drops the frame. When this bit is reset the MAC forwards the received frame to the application with updated SAF bit of the Rx Status depending on the SA address comparison.*/ -#define EMAC_SAFE (BIT(9)) -#define EMAC_SAFE_M (BIT(9)) -#define EMAC_SAFE_V 0x1 -#define EMAC_SAFE_S 9 -/* EMAC_SAIF : R/W ;bitpos:[8] ;default: 1'h0 ; */ -/*description: When this bit is set the Address Check block operates in inverse - filtering mode for the SA address comparison. The frames whose SA matches the SA registers are marked as failing the SA Address filter. When this bit is reset frames whose SA does not match the SA registers are marked as failing the SA Address filter.*/ -#define EMAC_SAIF (BIT(8)) -#define EMAC_SAIF_M (BIT(8)) -#define EMAC_SAIF_V 0x1 -#define EMAC_SAIF_S 8 -/* EMAC_PCF : R/W ;bitpos:[7:6] ;default: 2'h0 ; */ -/*description: These bits control the forwarding of all control frames (including - unicast and multicast Pause frames). 2'b00: MAC filters all control frames from reaching the application. 2'b01: MAC forwards all control frames except Pause frames to application even if they fail the Address filter. 2'b10: MAC forwards all control frames to application even if they fail the Address Filter. 2'b11: MAC forwards control frames that pass the Address Filter.The following conditions should be true for the Pause frames processing: Condition 1: The MAC is in the full-duplex mode and flow control is enabled by setting Bit 2 (RFE) of Register (Flow Control Register) to 1. Condition 2: The destination address (DA) of the received frame matches the special multicast address or the MAC Address 0 when Bit 3 (UP) of the Register(Flow Control Register) is set. Condition 3: The Type field of the received frame is 0x8808 and the OPCODE field is 0x0001.*/ -#define EMAC_PCF 0x00000003 -#define EMAC_PCF_M ((EMAC_PCF_V)<<(EMAC_PCF_S)) -#define EMAC_PCF_V 0x3 -#define EMAC_PCF_S 6 -/* EMAC_DBF : R/W ;bitpos:[5] ;default: 1'h0 ; */ -/*description: When this bit is set the AFM(Address Filtering Module) module - blocks all incoming broadcast frames. In addition it overrides all other filter settings. When this bit is reset the AFM module passes all received broadcast Frames.*/ -#define EMAC_DBF (BIT(5)) -#define EMAC_DBF_M (BIT(5)) -#define EMAC_DBF_V 0x1 -#define EMAC_DBF_S 5 -/* EMAC_PAM : R/W ;bitpos:[4] ;default: 1'h0 ; */ -/*description: When set this bit indicates that all received frames with a - multicast destination address (first bit in the destination address field is '1') are passed.*/ -#define EMAC_PAM (BIT(4)) -#define EMAC_PAM_M (BIT(4)) -#define EMAC_PAM_V 0x1 -#define EMAC_PAM_S 4 -/* EMAC_DAIF : R/W ;bitpos:[3] ;default: 1'h0 ; */ -/*description: When this bit is set the Address Check block operates in inverse - filtering mode for the DA address comparison for both unicast and multicast frames. When reset normal filtering of frames is performed.*/ -#define EMAC_DAIF (BIT(3)) -#define EMAC_DAIF_M (BIT(3)) -#define EMAC_DAIF_V 0x1 -#define EMAC_DAIF_S 3 -/* EMAC_PMODE : R/W ;bitpos:[0] ;default: 1'h0 ; */ -/*description: When this bit is set the Address Filter module passes all incoming - frames irrespective of the destination or source address. The SA or DA Filter Fails status bits of the Receive Status Word are always cleared when PR(PRI_RATIO) is set.*/ -#define EMAC_PMODE (BIT(0)) -#define EMAC_PMODE_M (BIT(0)) -#define EMAC_PMODE_V 0x1 -#define EMAC_PMODE_S 0 - -#define EMAC_GMIIADDR_REG (DR_REG_EMAC_BASE + 0x1010) -/* EMAC_MIIDEV : R/W ;bitpos:[15:11] ;default: 6'h0 ; */ -/*description: This field indicates which of the 32 possible PHY devices are being accessed.*/ -#define EMAC_MIIDEV 0x0000001F -#define EMAC_MIIDEV_M ((EMAC_MIIDEV_V)<<(EMAC_MIIDEV_S)) -#define EMAC_MIIDEV_V 0x1F -#define EMAC_MIIDEV_S 11 -/* EMAC_MIIREG : R/W ;bitpos:[10:6] ;default: 5'h0 ; */ -/*description: These bits select the desired MII register in the selected PHY device.*/ -#define EMAC_MIIREG 0x0000001F -#define EMAC_MIIREG_M ((EMAC_MIIREG_V)<<(EMAC_MIIREG_S)) -#define EMAC_MIIREG_V 0x1F -#define EMAC_MIIREG_S 6 -/* EMAC_MIICSRCLK : R/W ;bitpos:[5:2] ;default: 5'h0 ; */ -/*description: CSR clock range: 1.0 MHz ~ 2.5 MHz. 4'b0000: When the APB clock - frequency is 80 MHz the MDC clock frequency is APB CLK/42 4'b0000: When the APB clock frequency is 40 MHz the MDC clock frequency is APB CLK/26.*/ -#define EMAC_MIICSRCLK 0x0000000F -#define EMAC_MIICSRCLK_M ((EMAC_MIICSRCLK_V)<<(EMAC_MIICSRCLK_S)) -#define EMAC_MIICSRCLK_V 0xF -#define EMAC_MIICSRCLK_S 2 -/* EMAC_MIIWRITE : R/W ;bitpos:[1] ;default: 1'h0 ; */ -/*description: When set this bit indicates to the PHY that this is a Write - operation using the MII Data register. If this bit is not set it indicates that this is a Read operation that is placing the data in the MII Data register.*/ -#define EMAC_MIIWRITE (BIT(1)) -#define EMAC_MIIWRITE_M (BIT(1)) -#define EMAC_MIIWRITE_V 0x1 -#define EMAC_MIIWRITE_S 1 -/* EMAC_MIIBUSY : R_WS_SC ;bitpos:[0] ;default: 1'h0 ; */ -/*description: This bit should read logic 0 before writing to PHY Addr Register - and PHY data Register.During a PHY register access the software sets this bit to 1'b1 to indicate that a Read or Write access is in progress. PHY data Register is invalid until this bit is cleared by the MAC. Therefore PHY data Register (MII Data) should be kept valid until the MAC clears this bit during a PHY Write operation. Similarly for a read operation the contents of Register 5 are not valid until this bit is cleared. The subsequent read or write operation should happen only after the previous operation is complete. Because there is no acknowledgment from the PHY to MAC after a read or write operation is completed there is no change in the functionality of this bit even when the PHY is not Present.*/ -#define EMAC_MIIBUSY (BIT(0)) -#define EMAC_MIIBUSY_M (BIT(0)) -#define EMAC_MIIBUSY_V 0x1 -#define EMAC_MIIBUSY_S 0 - -#define EMAC_MIIDATA_REG (DR_REG_EMAC_BASE + 0x1014) -/* EMAC_MII_DATA : R/W ;bitpos:[15:0] ;default: 16'h0 ; */ -/*description: This field contains the 16-bit data value read from the PHY after - a Management Read operation or the 16-bit data value to be written to the PHY before a Management Write operation.*/ -#define EMAC_MII_DATA 0x0000FFFF -#define EMAC_MII_DATA_M ((EMAC_MII_DATA_V)<<(EMAC_MII_DATA_S)) -#define EMAC_MII_DATA_V 0xFFFF -#define EMAC_MII_DATA_S 0 - -#define EMAC_GMACFC_REG (DR_REG_EMAC_BASE + 0x1018) -/* EMAC_PAUSE_TIME : R/W ;bitpos:[31:16] ;default: 16'h0 ; */ -/*description: This field holds the value to be used in the Pause Time field - in the transmit control frame. If the Pause Time bits is configured to be double-synchronized to the MII clock domain then consecutive writes to this register should be performed only after at least four clock cycles in the destination clock domain.*/ -#define EMAC_PAUSE_TIME 0x0000FFFF -#define EMAC_PAUSE_TIME_M ((EMAC_PAUSE_TIME_V)<<(EMAC_PAUSE_TIME_S)) -#define EMAC_PAUSE_TIME_V 0xFFFF -#define EMAC_PAUSE_TIME_S 16 -/* EMAC_DZPQ : R/W ;bitpos:[7] ;default: 1'h0 ; */ -/*description: When this bit is set it disables the automatic generation of - the Zero-Quanta Pause frames on the de-assertion of the flow-control signal from the FIFO layer. When this bit is reset normal operation with automatic Zero-Quanta Pause frame generation is enabled.*/ -#define EMAC_DZPQ (BIT(7)) -#define EMAC_DZPQ_M (BIT(7)) -#define EMAC_DZPQ_V 0x1 -#define EMAC_DZPQ_S 7 -/* EMAC_PLT : R/W ;bitpos:[5:4] ;default: 2'h0 ; */ -/*description: This field configures the threshold of the Pause timer automatic - retransmission of the Pause frame.The threshold values should be always less than the Pause Time configured in Bits[31:16]. For example if PT = 100H (256 slot-times) and PLT = 01 then a second Pause frame is automatically transmitted at 228 (256-28) slot times after the first Pause frame is transmitted. The following list provides the threshold values for different values: 2'b00: The threshold is Pause time minus 4 slot times (PT-4 slot times). 2'b01: The threshold is Pause time minus 28 slot times (PT-28 slot times). 2'b10: The threshold is Pause time minus 144 slot times (PT-144 slot times). 2'b11: The threshold is Pause time minus 256 slot times (PT-256 slot times). The slot time is defined as the time taken to transmit 512 bits (64 bytes) on the MII interface.*/ -#define EMAC_PLT 0x00000003 -#define EMAC_PLT_M ((EMAC_PLT_V)<<(EMAC_PLT_S)) -#define EMAC_PLT_V 0x3 -#define EMAC_PLT_S 4 -/* EMAC_UPFD : R/W ;bitpos:[3] ;default: 1'h0 ; */ -/*description: A pause frame is processed when it has the unique multicast address - specified in the IEEE Std 802.3. When this bit is set the MAC can also detect Pause frames with unicast address of the station. This unicast address should be as specified in the EMACADDR0 High Register and EMACADDR0 Low Register. When this bit is reset the MAC only detects Pause frames with unique multicast address.*/ -#define EMAC_UPFD (BIT(3)) -#define EMAC_UPFD_M (BIT(3)) -#define EMAC_UPFD_V 0x1 -#define EMAC_UPFD_S 3 -/* EMAC_RFCE : R/W ;bitpos:[2] ;default: 1'h0 ; */ -/*description: When this bit is set the MAC decodes the received Pause frame - and disables its transmitter for a specified (Pause) time. When this bit is reset the decode function of the Pause frame is disabled.*/ -#define EMAC_RFCE (BIT(2)) -#define EMAC_RFCE_M (BIT(2)) -#define EMAC_RFCE_V 0x1 -#define EMAC_RFCE_S 2 -/* EMAC_TFCE : R/W ;bitpos:[1] ;default: 1'h0 ; */ -/*description: In the full-duplex mode when this bit is set the MAC enables - the flow control operation to transmit Pause frames. When this bit is reset the flow control operation in the MAC is disabled and the MAC does not transmit any Pause frames. In the half-duplex mode when this bit is set the MAC enables the backpressure operation. When this bit is reset the backpressure feature is Disabled.*/ -#define EMAC_TFCE (BIT(1)) -#define EMAC_TFCE_M (BIT(1)) -#define EMAC_TFCE_V 0x1 -#define EMAC_TFCE_S 1 -/* EMAC_FCBBA : R_WS_SC(FCB)/R_W(BPA) ;bitpos:[0] ;default: 1'h0 ; */ -/*description: This bit initiates a Pause frame in the full-duplex mode and - activates the backpressure function in the half-duplex mode if the TFCE bit is set. In the full-duplex mode this bit should be read as 1'b0 before writing to the Flow Control register. To initiate a Pause frame the Application must set this bit to 1'b1. During a transfer of the Control Frame this bit continues to be set to signify that a frame transmission is in progress. After the completion of Pause frame transmission the MAC resets this bit to 1'b0. The Flow Control register should not be written to until this bit is cleared. In the half-duplex mode when this bit is set (and TFCE is set) then backpressure is asserted by the MAC. During backpressure when the MAC receives a new frame the transmitter starts sending a JAM pattern resulting in a collision. When the MAC is configured for the full-duplex mode the BPA(backpressure activate) is automatically disabled.*/ -#define EMAC_FCBBA (BIT(0)) -#define EMAC_FCBBA_M (BIT(0)) -#define EMAC_FCBBA_V 0x1 -#define EMAC_FCBBA_S 0 - -#define EMAC_DEBUG_REG (DR_REG_EMAC_BASE + 0x1024) -/* EMAC_MTLTSFFS : RO ;bitpos:[25] ;default: 1'h0 ; */ -/*description: When high this bit indicates that the MTL TxStatus FIFO is full. - Therefore the MTL cannot accept any more frames for transmission.*/ -#define EMAC_MTLTSFFS (BIT(25)) -#define EMAC_MTLTSFFS_M (BIT(25)) -#define EMAC_MTLTSFFS_V 0x1 -#define EMAC_MTLTSFFS_S 25 -/* EMAC_MTLTFNES : RO ;bitpos:[24] ;default: 1'h0 ; */ -/*description: When high this bit indicates that the MTL Tx FIFO is not empty - and some data is left for Transmission.*/ -#define EMAC_MTLTFNES (BIT(24)) -#define EMAC_MTLTFNES_M (BIT(24)) -#define EMAC_MTLTFNES_V 0x1 -#define EMAC_MTLTFNES_S 24 -/* EMAC_MTLTFWCS : RO ;bitpos:[22] ;default: 1'h0 ; */ -/*description: When high this bit indicates that the MTL Tx FIFO Write Controller - is active and is transferring data to the Tx FIFO.*/ -#define EMAC_MTLTFWCS (BIT(22)) -#define EMAC_MTLTFWCS_M (BIT(22)) -#define EMAC_MTLTFWCS_V 0x1 -#define EMAC_MTLTFWCS_S 22 -/* EMAC_MTLTFRCS : RO ;bitpos:[21:20] ;default: 2'h0 ; */ -/*description: This field indicates the state of the Tx FIFO Read Controller: - 2'b00: IDLE state. 2'b01: READ state (transferring data to the MAC transmitter). 2'b10: Waiting for TxStatus from the MAC transmitter. 2'b11: Writing the received TxStatus or flushing the Tx FIFO.*/ -#define EMAC_MTLTFRCS 0x00000003 -#define EMAC_MTLTFRCS_M ((EMAC_MTLTFRCS_V)<<(EMAC_MTLTFRCS_S)) -#define EMAC_MTLTFRCS_V 0x3 -#define EMAC_MTLTFRCS_S 20 -/* EMAC_MACTP : RO ;bitpos:[19] ;default: 1'h0 ; */ -/*description: When high this bit indicates that the MAC transmitter is in - the Pause condition (in the full-duplex-mode) and hence does not schedule any frame for transmission.*/ -#define EMAC_MACTP (BIT(19)) -#define EMAC_MACTP_M (BIT(19)) -#define EMAC_MACTP_V 0x1 -#define EMAC_MACTP_S 19 -/* EMAC_MACTFCS : RO ;bitpos:[18:17] ;default: 2'h0 ; */ -/*description: This field indicates the state of the MAC Transmit Frame Controller - module: 2'b00: IDLE state. 2'b01: Waiting for status of previous frame or IFG or backoff period to be over. 2'b10: Generating and transmitting a Pause frame (in the full-duplex mode). 2'b11: Transferring input frame for transmission.*/ -#define EMAC_MACTFCS 0x00000003 -#define EMAC_MACTFCS_M ((EMAC_MACTFCS_V)<<(EMAC_MACTFCS_S)) -#define EMAC_MACTFCS_V 0x3 -#define EMAC_MACTFCS_S 17 -/* EMAC_MACTPES : RO ;bitpos:[16] ;default: 1'h0 ; */ -/*description: When high this bit indicates that the MAC MII transmit protocol - engine is actively transmitting data and is not in the IDLE state.*/ -#define EMAC_MACTPES (BIT(16)) -#define EMAC_MACTPES_M (BIT(16)) -#define EMAC_MACTPES_V 0x1 -#define EMAC_MACTPES_S 16 -/* EMAC_MTLRFFLS : RO ;bitpos:[9:8] ;default: 2'h0 ; */ -/*description: This field gives the status of the fill-level of the Rx FIFO: - 2'b00: Rx FIFO Empty. 2'b01: Rx FIFO fill-level below flow-control deactivate threshold. 2'b10: Rx FIFO fill-level above flow-control activate threshold. 2'b11: Rx FIFO Full.*/ -#define EMAC_MTLRFFLS 0x00000003 -#define EMAC_MTLRFFLS_M ((EMAC_MTLRFFLS_V)<<(EMAC_MTLRFFLS_S)) -#define EMAC_MTLRFFLS_V 0x3 -#define EMAC_MTLRFFLS_S 8 -/* EMAC_MTLRFRCS : RO ;bitpos:[6:5] ;default: 2'h0 ; */ -/*description: This field gives the state of the Rx FIFO read Controller: 2'b00: - IDLE state.2'b01: Reading frame data.2'b10: Reading frame status (or timestamp).2'b11: Flushing the frame data and status.*/ -#define EMAC_MTLRFRCS 0x00000003 -#define EMAC_MTLRFRCS_M ((EMAC_MTLRFRCS_V)<<(EMAC_MTLRFRCS_S)) -#define EMAC_MTLRFRCS_V 0x3 -#define EMAC_MTLRFRCS_S 5 -/* EMAC_MTLRFWCAS : RO ;bitpos:[4] ;default: 1'h0 ; */ -/*description: When high this bit indicates that the MTL Rx FIFO Write Controller - is active and is transferring a received frame to the FIFO.*/ -#define EMAC_MTLRFWCAS (BIT(4)) -#define EMAC_MTLRFWCAS_M (BIT(4)) -#define EMAC_MTLRFWCAS_V 0x1 -#define EMAC_MTLRFWCAS_S 4 -/* EMAC_MACRFFCS : RO ;bitpos:[2:1] ;default: 2'h0 ; */ -/*description: When high this field indicates the active state of the FIFO - Read and Write controllers of the MAC Receive Frame Controller Module. MACRFFCS[1] represents the status of FIFO Read controller. MACRFFCS[0] represents the status of small FIFO Write controller.*/ -#define EMAC_MACRFFCS 0x00000003 -#define EMAC_MACRFFCS_M ((EMAC_MACRFFCS_V)<<(EMAC_MACRFFCS_S)) -#define EMAC_MACRFFCS_V 0x3 -#define EMAC_MACRFFCS_S 1 -/* EMAC_MACRPES : RO ;bitpos:[0] ;default: 1'h0 ; */ -/*description: When high this bit indicates that the MAC MII receive protocol - engine is actively receiving data and not in IDLE state.*/ -#define EMAC_MACRPES (BIT(0)) -#define EMAC_MACRPES_M (BIT(0)) -#define EMAC_MACRPES_V 0x1 -#define EMAC_MACRPES_S 0 - -#define EMAC_PMT_RWUFFR_REG (DR_REG_EMAC_BASE + 0x1028) -/* EMAC_WKUPPKTFILTER : R/W ;bitpos:[31:0] ;default: 32'h0 ; */ -/*description: The MSB (31st bit) must be zero.Bit j[30:0] is the byte mask. - If Bit 1/2/3/4 (byte number) of the byte mask is set the CRC block processes the Filter 0/1/2/3 Offset + j of the incoming packet(PWKPTR is 0/1/2/3).RWKPTR is 0:Filter 0 Byte Mask .RWKPTR is 1:Filter 1 Byte Mask RWKPTR is 2:Filter 2 Byte Mask RWKPTR is 3:Filter 3 Byte Mask RWKPTR is 4:Bit 3/11/19/27 specifies the address type defining the destination address type of the pattern.When the bit is set the pattern applies to only multicast packets*/ -#define EMAC_WKUPPKTFILTER 0xFFFFFFFF -#define EMAC_WKUPPKTFILTER_M ((EMAC_WKUPPKTFILTER_V)<<(EMAC_WKUPPKTFILTER_S)) -#define EMAC_WKUPPKTFILTER_V 0xFFFFFFFF -#define EMAC_WKUPPKTFILTER_S 0 - -#define EMAC_PMT_CSR_REG (DR_REG_EMAC_BASE + 0x102C) -/* EMAC_RWKFILTRST : R_WS_SC ;bitpos:[31] ;default: 1'h0 ; */ -/*description: When this bit is set it resets the RWKPTR register to 3’b000.*/ -#define EMAC_RWKFILTRST (BIT(31)) -#define EMAC_RWKFILTRST_M (BIT(31)) -#define EMAC_RWKFILTRST_V 0x1 -#define EMAC_RWKFILTRST_S 31 -/* EMAC_RWKPTR : RO ;bitpos:[28:24] ;default: 6'h0 ; */ -/*description: The maximum value of the pointer is 7 the detail information - please refer to PMT_RWUFFR.*/ -#define EMAC_RWKPTR 0x0000001F -#define EMAC_RWKPTR_M ((EMAC_RWKPTR_V)<<(EMAC_RWKPTR_S)) -#define EMAC_RWKPTR_V 0x1F -#define EMAC_RWKPTR_S 24 -/* EMAC_GLBLUCAST : R/W ;bitpos:[9] ;default: 1'h0 ; */ -/*description: When set enables any unicast packet filtered by the MAC (DAFilter) - address recognition to be a remote wake-up frame.*/ -#define EMAC_GLBLUCAST (BIT(9)) -#define EMAC_GLBLUCAST_M (BIT(9)) -#define EMAC_GLBLUCAST_V 0x1 -#define EMAC_GLBLUCAST_S 9 -/* EMAC_RWKPRCVD : R_SS_RC ;bitpos:[6] ;default: 1'h0 ; */ -/*description: When set this bit indicates the power management event is generated - because of the reception of a remote wake-up frame. This bit is cleared by a Read into this register.*/ -#define EMAC_RWKPRCVD (BIT(6)) -#define EMAC_RWKPRCVD_M (BIT(6)) -#define EMAC_RWKPRCVD_V 0x1 -#define EMAC_RWKPRCVD_S 6 -/* EMAC_MGKPRCVD : R_SS_RC ;bitpos:[5] ;default: 1'h0 ; */ -/*description: When set this bit indicates that the power management event - is generated because of the reception of a magic packet. This bit is cleared by a Read into this register.*/ -#define EMAC_MGKPRCVD (BIT(5)) -#define EMAC_MGKPRCVD_M (BIT(5)) -#define EMAC_MGKPRCVD_V 0x1 -#define EMAC_MGKPRCVD_S 5 -/* EMAC_RWKPKTEN : R/W ;bitpos:[2] ;default: 1'h0 ; */ -/*description: When set enables generation of a power management event because - of remote wake-up frame reception*/ -#define EMAC_RWKPKTEN (BIT(2)) -#define EMAC_RWKPKTEN_M (BIT(2)) -#define EMAC_RWKPKTEN_V 0x1 -#define EMAC_RWKPKTEN_S 2 -/* EMAC_MGKPKTEN : R/W ;bitpos:[1] ;default: 1'h0 ; */ -/*description: When set enables generation of a power management event because - of magic packet reception.*/ -#define EMAC_MGKPKTEN (BIT(1)) -#define EMAC_MGKPKTEN_M (BIT(1)) -#define EMAC_MGKPKTEN_V 0x1 -#define EMAC_MGKPKTEN_S 1 -/* EMAC_PWRDWN : R_WS_SC ;bitpos:[0] ;default: 1'h0 ; */ -/*description: When set the MAC receiver drops all received frames until it - receives the expected magic packet or remote wake-up frame.This bit must only be set when MGKPKTEN GLBLUCAST or RWKPKTEN bit is set high.*/ -#define EMAC_PWRDWN (BIT(0)) -#define EMAC_PWRDWN_M (BIT(0)) -#define EMAC_PWRDWN_V 0x1 -#define EMAC_PWRDWN_S 0 - -#define EMAC_GMACLPI_CRS_REG (DR_REG_EMAC_BASE + 0x1030) -/* EMAC_LPITXA : R/W ;bitpos:[19] ;default: 1'h0 ; */ -/*description: This bit controls the behavior of the MAC when it is entering - or coming out of the LPI mode on the transmit side.If the LPITXA and LPIEN bits are set to 1 the MAC enters the LPI mode only after all outstanding frames and pending frames have been transmitted. The MAC comes out of the LPI mode when the application sends any frame.When this bit is 0 the LPIEN bit directly controls behavior of the MAC when it is entering or coming out of the LPI mode.*/ -#define EMAC_LPITXA (BIT(19)) -#define EMAC_LPITXA_M (BIT(19)) -#define EMAC_LPITXA_V 0x1 -#define EMAC_LPITXA_S 19 -/* EMAC_PLS : R/W ;bitpos:[17] ;default: 1'h0 ; */ -/*description: This bit indicates the link status of the PHY.When set the link - is considered to be okay (up) and when reset the link is considered to be down.*/ -#define EMAC_PLS (BIT(17)) -#define EMAC_PLS_M (BIT(17)) -#define EMAC_PLS_V 0x1 -#define EMAC_PLS_S 17 -/* EMAC_LPIEN : R_W_SC ;bitpos:[16] ;default: 1'h0 ; */ -/*description: When set this bit instructs the MAC Transmitter to enter the - LPI state. When reset this bit instructs the MAC to exit the LPI state and resume normal transmission.This bit is cleared when the LPITXA bit is set and the MAC exits the LPI state because of the arrival of a new packet for transmission.*/ -#define EMAC_LPIEN (BIT(16)) -#define EMAC_LPIEN_M (BIT(16)) -#define EMAC_LPIEN_V 0x1 -#define EMAC_LPIEN_S 16 -/* EMAC_RLPIST : R/W ;bitpos:[9] ;default: 1'h0 ; */ -/*description: When set this bit indicates that the MAC is receiving the LPI - pattern on the MII interface.*/ -#define EMAC_RLPIST (BIT(9)) -#define EMAC_RLPIST_M (BIT(9)) -#define EMAC_RLPIST_V 0x1 -#define EMAC_RLPIST_S 9 -/* EMAC_TLPIST : R/W ;bitpos:[8] ;default: 1'h0 ; */ -/*description: When set this bit indicates that the MAC is transmitting the - LPI pattern on the MII interface.*/ -#define EMAC_TLPIST (BIT(8)) -#define EMAC_TLPIST_M (BIT(8)) -#define EMAC_TLPIST_V 0x1 -#define EMAC_TLPIST_S 8 -/* EMAC_RLPIEX : R_SS_RC ;bitpos:[3] ;default: 1'h0 ; */ -/*description: When set this bit indicates that the MAC Receiver has stopped - receiving the LPI pattern on the MII interface exited the LPI state and resumed the normal reception. This bit is cleared by a read into this register.*/ -#define EMAC_RLPIEX (BIT(3)) -#define EMAC_RLPIEX_M (BIT(3)) -#define EMAC_RLPIEX_V 0x1 -#define EMAC_RLPIEX_S 3 -/* EMAC_RLPIEN : R_SS_RC ;bitpos:[2] ;default: 1'h0 ; */ -/*description: When set this bit indicates that the MAC Receiver has received - an LPI pattern and entered the LPI state. This bit is cleared by a read into this register.*/ -#define EMAC_RLPIEN (BIT(2)) -#define EMAC_RLPIEN_M (BIT(2)) -#define EMAC_RLPIEN_V 0x1 -#define EMAC_RLPIEN_S 2 -/* EMAC_TLPIEX : R_SS_RC ;bitpos:[1] ;default: 1'h0 ; */ -/*description: When set this bit indicates that the MAC transmitter has exited - the LPI state after the user has cleared the LPIEN bit and the LPI_TW_Timer has expired.This bit is cleared by a read into this register.*/ -#define EMAC_TLPIEX (BIT(1)) -#define EMAC_TLPIEX_M (BIT(1)) -#define EMAC_TLPIEX_V 0x1 -#define EMAC_TLPIEX_S 1 -/* EMAC_TLPIEN : R_SS_RC ;bitpos:[0] ;default: 1'h0 ; */ -/*description: When set this bit indicates that the MAC Transmitter has entered - the LPI state because of the setting of the LPIEN bit. This bit is cleared by a read into this register.*/ -#define EMAC_TLPIEN (BIT(0)) -#define EMAC_TLPIEN_M (BIT(0)) -#define EMAC_TLPIEN_V 0x1 -#define EMAC_TLPIEN_S 0 - -#define EMAC_GMACLPITIMERSCONTROL_REG (DR_REG_EMAC_BASE + 0x1034) -/* EMAC_LPI_LS_TIMER : R/W ;bitpos:[25:16] ;default: 10'h3E8 ; */ -/*description: This field specifies the minimum time (in milliseconds) for which - the link status from the PHY should be up (OKAY) before the LPI pattern can be transmitted to the PHY. The MAC does not transmit the LPI pattern even when the LPIEN bit is set unless the LPI_LS_Timer reaches the programmed terminal count. The default value of the LPI_LS_Timer is 1000 (1 sec) as defined in the IEEE standard.*/ -#define EMAC_LPI_LS_TIMER 0x000003FF -#define EMAC_LPI_LS_TIMER_M ((EMAC_LPI_LS_TIMER_V)<<(EMAC_LPI_LS_TIMER_S)) -#define EMAC_LPI_LS_TIMER_V 0x3FF -#define EMAC_LPI_LS_TIMER_S 16 -/* EMAC_LPI_TW_TIMER : R/W ;bitpos:[15:0] ;default: 16'h0 ; */ -/*description: This field specifies the minimum time (in microseconds) for which - the MAC waits after it stops transmitting the LPI pattern to the PHY and before it resumes the normal transmission. The TLPIEX status bit is set after the expiry of this timer.*/ -#define EMAC_LPI_TW_TIMER 0x0000FFFF -#define EMAC_LPI_TW_TIMER_M ((EMAC_LPI_TW_TIMER_V)<<(EMAC_LPI_TW_TIMER_S)) -#define EMAC_LPI_TW_TIMER_V 0xFFFF -#define EMAC_LPI_TW_TIMER_S 0 - -#define EMAC_INTS_REG (DR_REG_EMAC_BASE + 0x1038) -/* EMAC_LPIIS : RO ;bitpos:[10] ;default: 1'h0 ; */ -/*description: When the Energy Efficient Ethernet feature is enabled this bit - is set for any LPI state entry or exit in the MAC Transmitter or Receiver. This bit is cleared on reading Bit[0] of Register (LPI Control and Status Register).*/ -#define EMAC_LPIIS (BIT(10)) -#define EMAC_LPIIS_M (BIT(10)) -#define EMAC_LPIIS_V 0x1 -#define EMAC_LPIIS_S 10 -/* EMAC_PMTINTS : RO ;bitpos:[3] ;default: 1'h0 ; */ -/*description: This bit is set when a magic packet or remote wake-up frame is - received in the power-down mode (see Bit[5] and Bit[6] in the PMT Control and Status Register). This bit is cleared when both Bits[6:5] are cleared because of a read operation to the PMT Control and Status register. This bit is valid only when you select the optional PMT module during core configuration.*/ -#define EMAC_PMTINTS (BIT(3)) -#define EMAC_PMTINTS_M (BIT(3)) -#define EMAC_PMTINTS_V 0x1 -#define EMAC_PMTINTS_S 3 - -#define EMAC_INTMASK_REG (DR_REG_EMAC_BASE + 0x103C) -/* EMAC_LPIINTMASK : R/W ;bitpos:[10] ;default: 1'h0 ; */ -/*description: When set this bit disables the assertion of the interrupt signal - because of the setting of the LPI Interrupt Status bit in Register (Interrupt Status Register).*/ -#define EMAC_LPIINTMASK (BIT(10)) -#define EMAC_LPIINTMASK_M (BIT(10)) -#define EMAC_LPIINTMASK_V 0x1 -#define EMAC_LPIINTMASK_S 10 -/* EMAC_PMTINTMASK : R/W ;bitpos:[3] ;default: 1'h0 ; */ -/*description: When set this bit disables the assertion of the interrupt signal - because of the setting of PMT Interrupt Status bit in Register (Interrupt Status Register).*/ -#define EMAC_PMTINTMASK (BIT(3)) -#define EMAC_PMTINTMASK_M (BIT(3)) -#define EMAC_PMTINTMASK_V 0x1 -#define EMAC_PMTINTMASK_S 3 - -#define EMAC_ADDR0HIGH_REG (DR_REG_EMAC_BASE + 0x1040) -/* EMAC_ADDRESS_ENABLE0 : RO ;bitpos:[31] ;default: 1'h0 ; */ -/*description: This bit is always set to 1.*/ -#define EMAC_ADDRESS_ENABLE0 (BIT(31)) -#define EMAC_ADDRESS_ENABLE0_M (BIT(31)) -#define EMAC_ADDRESS_ENABLE0_V 0x1 -#define EMAC_ADDRESS_ENABLE0_S 31 -/* EMAC_ADDRESS0_HI : R/W ;bitpos:[15:0] ;default: 16'hFFFF ; */ -/*description: This field contains the upper 16 bits (47:32) of the first 6-byte - MAC address.The MAC uses this field for filtering the received frames and inserting the MAC address in the Transmit Flow Control (Pause) Frames.*/ -#define EMAC_ADDRESS0_HI 0x0000FFFF -#define EMAC_ADDRESS0_HI_M ((EMAC_ADDRESS0_HI_V)<<(EMAC_ADDRESS0_HI_S)) -#define EMAC_ADDRESS0_HI_V 0xFFFF -#define EMAC_ADDRESS0_HI_S 0 - -#define EMAC_ADDR0LOW_REG (DR_REG_EMAC_BASE + 0x1044) -/* EMAC_MAC_ADDRESS0_LOW : R/W ;bitpos:[31:0] ;default: 32'hFFFFFFFF ; */ -/*description: This field contains the lower 32 bits of the first 6-byte MAC - address. This is used by the MAC for filtering the received frames and inserting the MAC address in the Transmit Flow Control (Pause) Frames.*/ -#define EMAC_MAC_ADDRESS0_LOW 0xFFFFFFFF -#define EMAC_MAC_ADDRESS0_LOW_M ((EMAC_MAC_ADDRESS0_LOW_V)<<(EMAC_MAC_ADDRESS0_LOW_S)) -#define EMAC_MAC_ADDRESS0_LOW_V 0xFFFFFFFF -#define EMAC_MAC_ADDRESS0_LOW_S 0 - -#define EMAC_ADDR1HIGH_REG (DR_REG_EMAC_BASE + 0x1048) -/* EMAC_ADDRESS_ENABLE1 : R/W ;bitpos:[31] ;default: 1'h0 ; */ -/*description: When this bit is set the address filter module uses the second - MAC address for perfect filtering. When this bit is reset the address filter module ignores the address for filtering.*/ -#define EMAC_ADDRESS_ENABLE1 (BIT(31)) -#define EMAC_ADDRESS_ENABLE1_M (BIT(31)) -#define EMAC_ADDRESS_ENABLE1_V 0x1 -#define EMAC_ADDRESS_ENABLE1_S 31 -/* EMAC_SOURCE_ADDRESS : R/W ;bitpos:[30] ;default: 1'h0 ; */ -/*description: When this bit is set the EMACADDR1[47:0] is used to compare - with the SA fields of the received frame. When this bit is reset the EMACADDR1[47:0] is used to compare with the DA fields of the received frame.*/ -#define EMAC_SOURCE_ADDRESS (BIT(30)) -#define EMAC_SOURCE_ADDRESS_M (BIT(30)) -#define EMAC_SOURCE_ADDRESS_V 0x1 -#define EMAC_SOURCE_ADDRESS_S 30 -/* EMAC_MASK_BYTE_CONTROL : R/W ;bitpos:[29:24] ;default: 6'h0 ; */ -/*description: These bits are mask control bits for comparison of each of the - EMACADDR1 bytes. When set high the MAC does not compare the corresponding byte of received DA or SA with the contents of EMACADDR1 registers. Each bit controls the masking of the bytes as follows: Bit[29]: EMACADDR1 High [15:8]. Bit[28]: EMACADDR1 High [7:0]. Bit[27]: EMACADDR1 Low [31:24]. Bit[24]: EMACADDR1 Low [7:0].You can filter a group of addresses (known as group address filtering) by masking one or more bytes of the address.*/ -#define EMAC_MASK_BYTE_CONTROL 0x0000003F -#define EMAC_MASK_BYTE_CONTROL_M ((EMAC_MASK_BYTE_CONTROL_V)<<(EMAC_MASK_BYTE_CONTROL_S)) -#define EMAC_MASK_BYTE_CONTROL_V 0x3F -#define EMAC_MASK_BYTE_CONTROL_S 24 -/* EMAC_MAC_ADDRESS1_HI : R/W ;bitpos:[15:0] ;default: 16'hFFFF ; */ -/*description: This field contains the upper 16 bits Bits[47:32] of the second - 6-byte MAC Address.*/ -#define EMAC_MAC_ADDRESS1_HI 0x0000FFFF -#define EMAC_MAC_ADDRESS1_HI_M ((EMAC_MAC_ADDRESS1_HI_V)<<(EMAC_MAC_ADDRESS1_HI_S)) -#define EMAC_MAC_ADDRESS1_HI_V 0xFFFF -#define EMAC_MAC_ADDRESS1_HI_S 0 - -#define EMAC_ADDR1LOW_REG (DR_REG_EMAC_BASE + 0x104C) -/* EMAC_MAC_ADDRESS1_LOW : R/W ;bitpos:[31:0] ;default: 32'hFFFFFFFF ; */ -/*description: This field contains the lower 32 bits of the second 6-byte MAC - address.The content of this field is undefined so the register needs to be configured after the initialization Process.*/ -#define EMAC_MAC_ADDRESS1_LOW 0xFFFFFFFF -#define EMAC_MAC_ADDRESS1_LOW_M ((EMAC_MAC_ADDRESS1_LOW_V)<<(EMAC_MAC_ADDRESS1_LOW_S)) -#define EMAC_MAC_ADDRESS1_LOW_V 0xFFFFFFFF -#define EMAC_MAC_ADDRESS1_LOW_S 0 - -#define EMAC_ADDR2HIGH_REG (DR_REG_EMAC_BASE + 0x1050) -/* EMAC_ADDRESS_ENABLE2 : R/W ;bitpos:[31] ;default: 1'h0 ; */ -/*description: When this bit is set the address filter module uses the third - MAC address for perfect filtering. When this bit is reset the address filter module ignores the address for filtering.*/ -#define EMAC_ADDRESS_ENABLE2 (BIT(31)) -#define EMAC_ADDRESS_ENABLE2_M (BIT(31)) -#define EMAC_ADDRESS_ENABLE2_V 0x1 -#define EMAC_ADDRESS_ENABLE2_S 31 -/* EMAC_SOURCE_ADDRESS2 : R/W ;bitpos:[30] ;default: 1'h0 ; */ -/*description: When this bit is set the EMACADDR2[47:0] is used to compare - with the SA fields of the received frame. When this bit is reset the EMACADDR2[47:0] is used to compare with the DA fields of the received frame.*/ -#define EMAC_SOURCE_ADDRESS2 (BIT(30)) -#define EMAC_SOURCE_ADDRESS2_M (BIT(30)) -#define EMAC_SOURCE_ADDRESS2_V 0x1 -#define EMAC_SOURCE_ADDRESS2_S 30 -/* EMAC_MASK_BYTE_CONTROL2 : R/W ;bitpos:[29:24] ;default: 6'h0 ; */ -/*description: These bits are mask control bits for comparison of each of the - EMACADDR2 bytes. When set high the MAC does not compare the corresponding byte of received DA or SA with the contents of EMACADDR2 registers. Each bit controls the masking of the bytes as follows: Bit[29]: EMACADDR2 High [15:8]. Bit[28]: EMACADDR2 High [7:0]. Bit[27]: EMACADDR2 Low [31:24]. Bit[24]: EMACADDR2 Low [7:0].You can filter a group of addresses (known as group address filtering) by masking one or more bytes of the address.*/ -#define EMAC_MASK_BYTE_CONTROL2 0x0000003F -#define EMAC_MASK_BYTE_CONTROL2_M ((EMAC_MASK_BYTE_CONTROL2_V)<<(EMAC_MASK_BYTE_CONTROL2_S)) -#define EMAC_MASK_BYTE_CONTROL2_V 0x3F -#define EMAC_MASK_BYTE_CONTROL2_S 24 -/* EMAC_MAC_ADDRESS2_HI : R/W ;bitpos:[15:0] ;default: 16'hFFFF ; */ -/*description: This field contains the upper 16 bits Bits[47:32] of the third - 6-byte MAC address.*/ -#define EMAC_MAC_ADDRESS2_HI 0x0000FFFF -#define EMAC_MAC_ADDRESS2_HI_M ((EMAC_MAC_ADDRESS2_HI_V)<<(EMAC_MAC_ADDRESS2_HI_S)) -#define EMAC_MAC_ADDRESS2_HI_V 0xFFFF -#define EMAC_MAC_ADDRESS2_HI_S 0 - -#define EMAC_ADDR2LOW_REG (DR_REG_EMAC_BASE + 0x1054) -/* EMAC_MAC_ADDRESS2_LOW : R/W ;bitpos:[31:0] ;default: 32'hFFFFFFFF ; */ -/*description: This field contains the lower 32 bits of the third 6-byte MAC - address. The content of this field is undefined so the register needs to be configured after the initialization process.*/ -#define EMAC_MAC_ADDRESS2_LOW 0xFFFFFFFF -#define EMAC_MAC_ADDRESS2_LOW_M ((EMAC_MAC_ADDRESS2_LOW_V)<<(EMAC_MAC_ADDRESS2_LOW_S)) -#define EMAC_MAC_ADDRESS2_LOW_V 0xFFFFFFFF -#define EMAC_MAC_ADDRESS2_LOW_S 0 - -#define EMAC_ADDR3HIGH_REG (DR_REG_EMAC_BASE + 0x1058) -/* EMAC_ADDRESS_ENABLE3 : R/W ;bitpos:[31] ;default: 1'h0 ; */ -/*description: When this bit is set the address filter module uses the fourth - MAC address for perfect filtering. When this bit is reset the address filter module ignores the address for filtering.*/ -#define EMAC_ADDRESS_ENABLE3 (BIT(31)) -#define EMAC_ADDRESS_ENABLE3_M (BIT(31)) -#define EMAC_ADDRESS_ENABLE3_V 0x1 -#define EMAC_ADDRESS_ENABLE3_S 31 -/* EMAC_SOURCE_ADDRESS3 : R/W ;bitpos:[30] ;default: 1'h0 ; */ -/*description: When this bit is set the EMACADDR3[47:0] is used to compare - with the SA fields of the received frame. When this bit is reset the EMACADDR3[47:0] is used to compare with the DA fields of the received frame.*/ -#define EMAC_SOURCE_ADDRESS3 (BIT(30)) -#define EMAC_SOURCE_ADDRESS3_M (BIT(30)) -#define EMAC_SOURCE_ADDRESS3_V 0x1 -#define EMAC_SOURCE_ADDRESS3_S 30 -/* EMAC_MASK_BYTE_CONTROL3 : R/W ;bitpos:[29:24] ;default: 6'h0 ; */ -/*description: These bits are mask control bits for comparison of each of the - EMACADDR3 bytes. When set high the MAC does not compare the corresponding byte of received DA or SA with the contents of EMACADDR3 registers. Each bit controls the masking of the bytes as follows: Bit[29]: EMACADDR3 High [15:8]. Bit[28]: EMACADDR3 High [7:0]. Bit[27]: EMACADDR3 Low [31:24]. Bit[24]: EMACADDR3 Low [7:0].You can filter a group of addresses (known as group address filtering) by masking one or more bytes of the address.*/ -#define EMAC_MASK_BYTE_CONTROL3 0x0000003F -#define EMAC_MASK_BYTE_CONTROL3_M ((EMAC_MASK_BYTE_CONTROL3_V)<<(EMAC_MASK_BYTE_CONTROL3_S)) -#define EMAC_MASK_BYTE_CONTROL3_V 0x3F -#define EMAC_MASK_BYTE_CONTROL3_S 24 -/* EMAC_MAC_ADDRESS3_HI : R/W ;bitpos:[15:0] ;default: 16'hFFFF ; */ -/*description: This field contains the upper 16 bits Bits[47:32] of the fourth - 6-byte MAC address.*/ -#define EMAC_MAC_ADDRESS3_HI 0x0000FFFF -#define EMAC_MAC_ADDRESS3_HI_M ((EMAC_MAC_ADDRESS3_HI_V)<<(EMAC_MAC_ADDRESS3_HI_S)) -#define EMAC_MAC_ADDRESS3_HI_V 0xFFFF -#define EMAC_MAC_ADDRESS3_HI_S 0 - -#define EMAC_ADDR3LOW_REG (DR_REG_EMAC_BASE + 0x105C) -/* EMAC_MAC_ADDRESS3_LOW : R/W ;bitpos:[31:0] ;default: 32'hFFFFFFFF ; */ -/*description: This field contains the lower 32 bits of the fourth 6-byte MAC - address.The content of this field is undefined so the register needs to be configured after the initialization Process.*/ -#define EMAC_MAC_ADDRESS3_LOW 0xFFFFFFFF -#define EMAC_MAC_ADDRESS3_LOW_M ((EMAC_MAC_ADDRESS3_LOW_V)<<(EMAC_MAC_ADDRESS3_LOW_S)) -#define EMAC_MAC_ADDRESS3_LOW_V 0xFFFFFFFF -#define EMAC_MAC_ADDRESS3_LOW_S 0 - -#define EMAC_ADDR4HIGH_REG (DR_REG_EMAC_BASE + 0x1060) -/* EMAC_ADDRESS_ENABLE4 : R/W ;bitpos:[31] ;default: 1'h0 ; */ -/*description: When this bit is set the address filter module uses the fifth - MAC address for perfect filtering. When this bit is reset the address filter module ignores the address for filtering.*/ -#define EMAC_ADDRESS_ENABLE4 (BIT(31)) -#define EMAC_ADDRESS_ENABLE4_M (BIT(31)) -#define EMAC_ADDRESS_ENABLE4_V 0x1 -#define EMAC_ADDRESS_ENABLE4_S 31 -/* EMAC_SOURCE_ADDRESS4 : R/W ;bitpos:[30] ;default: 1'h0 ; */ -/*description: When this bit is set the EMACADDR4[47:0] is used to compare - with the SA fields of the received frame. When this bit is reset the EMACADDR4[47:0] is used to compare with the DA fields of the received frame.*/ -#define EMAC_SOURCE_ADDRESS4 (BIT(30)) -#define EMAC_SOURCE_ADDRESS4_M (BIT(30)) -#define EMAC_SOURCE_ADDRESS4_V 0x1 -#define EMAC_SOURCE_ADDRESS4_S 30 -/* EMAC_MASK_BYTE_CONTROL4 : R/W ;bitpos:[29:24] ;default: 6'h0 ; */ -/*description: These bits are mask control bits for comparison of each of the - EMACADDR4 bytes. When set high the MAC does not compare the corresponding byte of received DA or SA with the contents of EMACADDR4 registers. Each bit controls the masking of the bytes as follows: Bit[29]: EMACADDR4 High [15:8]. Bit[28]: EMACADDR4 High [7:0]. Bit[27]: EMACADDR4 Low [31:24]. Bit[24]: EMACADDR4 Low [7:0].You can filter a group of addresses (known as group address filtering) by masking one or more bytes of the address.*/ -#define EMAC_MASK_BYTE_CONTROL4 0x0000003F -#define EMAC_MASK_BYTE_CONTROL4_M ((EMAC_MASK_BYTE_CONTROL4_V)<<(EMAC_MASK_BYTE_CONTROL4_S)) -#define EMAC_MASK_BYTE_CONTROL4_V 0x3F -#define EMAC_MASK_BYTE_CONTROL4_S 24 -/* EMAC_MAC_ADDRESS4_HI : R/W ;bitpos:[15:0] ;default: 16'hFFFF ; */ -/*description: This field contains the upper 16 bits Bits[47:32] of the fifth - 6-byte MAC address.*/ -#define EMAC_MAC_ADDRESS4_HI 0x0000FFFF -#define EMAC_MAC_ADDRESS4_HI_M ((EMAC_MAC_ADDRESS4_HI_V)<<(EMAC_MAC_ADDRESS4_HI_S)) -#define EMAC_MAC_ADDRESS4_HI_V 0xFFFF -#define EMAC_MAC_ADDRESS4_HI_S 0 - -#define EMAC_ADDR4LOW_REG (DR_REG_EMAC_BASE + 0x1064) -/* EMAC_MAC_ADDRESS4_LOW : R/W ;bitpos:[31:0] ;default: 32'hFFFFFFFF ; */ -/*description: This field contains the lower 32 bits of the fifth 6-byte MAC - address. The content of this field is undefined so the register needs to be configured after the initialization process.*/ -#define EMAC_MAC_ADDRESS4_LOW 0xFFFFFFFF -#define EMAC_MAC_ADDRESS4_LOW_M ((EMAC_MAC_ADDRESS4_LOW_V)<<(EMAC_MAC_ADDRESS4_LOW_S)) -#define EMAC_MAC_ADDRESS4_LOW_V 0xFFFFFFFF -#define EMAC_MAC_ADDRESS4_LOW_S 0 - -#define EMAC_ADDR5HIGH_REG (DR_REG_EMAC_BASE + 0x1068) -/* EMAC_ADDRESS_ENABLE5 : R/W ;bitpos:[31] ;default: 1'h0 ; */ -/*description: When this bit is set the address filter module uses the sixth - MAC address for perfect filtering. When this bit is reset the address filter module ignores the address for filtering.*/ -#define EMAC_ADDRESS_ENABLE5 (BIT(31)) -#define EMAC_ADDRESS_ENABLE5_M (BIT(31)) -#define EMAC_ADDRESS_ENABLE5_V 0x1 -#define EMAC_ADDRESS_ENABLE5_S 31 -/* EMAC_SOURCE_ADDRESS5 : R/W ;bitpos:[30] ;default: 1'h0 ; */ -/*description: When this bit is set the EMACADDR5[47:0] is used to compare - with the SA fields of the received frame. When this bit is reset the EMACADDR5[47:0] is used to compare with the DA fields of the received frame.*/ -#define EMAC_SOURCE_ADDRESS5 (BIT(30)) -#define EMAC_SOURCE_ADDRESS5_M (BIT(30)) -#define EMAC_SOURCE_ADDRESS5_V 0x1 -#define EMAC_SOURCE_ADDRESS5_S 30 -/* EMAC_MASK_BYTE_CONTROL5 : R/W ;bitpos:[29:24] ;default: 6'h0 ; */ -/*description: These bits are mask control bits for comparison of each of the - EMACADDR5 bytes. When set high the MAC does not compare the corresponding byte of received DA or SA with the contents of EMACADDR5 registers. Each bit controls the masking of the bytes as follows: Bit[29]: EMACADDR5 High [15:8]. Bit[28]: EMACADDR5 High [7:0]. Bit[27]: EMACADDR5 Low [31:24]. Bit[24]: EMACADDR5 Low [7:0].You can filter a group of addresses (known as group address filtering) by masking one or more bytes of the address.*/ -#define EMAC_MASK_BYTE_CONTROL5 0x0000003F -#define EMAC_MASK_BYTE_CONTROL5_M ((EMAC_MASK_BYTE_CONTROL5_V)<<(EMAC_MASK_BYTE_CONTROL5_S)) -#define EMAC_MASK_BYTE_CONTROL5_V 0x3F -#define EMAC_MASK_BYTE_CONTROL5_S 24 -/* EMAC_MAC_ADDRESS5_HI : R/W ;bitpos:[15:0] ;default: 16'hFFFF ; */ -/*description: This field contains the upper 16 bits Bits[47:32] of the sixth - 6-byte MAC address.*/ -#define EMAC_MAC_ADDRESS5_HI 0x0000FFFF -#define EMAC_MAC_ADDRESS5_HI_M ((EMAC_MAC_ADDRESS5_HI_V)<<(EMAC_MAC_ADDRESS5_HI_S)) -#define EMAC_MAC_ADDRESS5_HI_V 0xFFFF -#define EMAC_MAC_ADDRESS5_HI_S 0 - -#define EMAC_ADDR5LOW_REG (DR_REG_EMAC_BASE + 0x106C) -/* EMAC_MAC_ADDRESS5_LOW : R/W ;bitpos:[31:0] ;default: 32'hFFFFFFFF ; */ -/*description: This field contains the lower 32 bits of the sixth 6-byte MAC - address. The content of this field is undefined so the register needs to be configured after the initialization process.*/ -#define EMAC_MAC_ADDRESS5_LOW 0xFFFFFFFF -#define EMAC_MAC_ADDRESS5_LOW_M ((EMAC_MAC_ADDRESS5_LOW_V)<<(EMAC_MAC_ADDRESS5_LOW_S)) -#define EMAC_MAC_ADDRESS5_LOW_V 0xFFFFFFFF -#define EMAC_MAC_ADDRESS5_LOW_S 0 - -#define EMAC_ADDR6HIGH_REG (DR_REG_EMAC_BASE + 0x1070) -/* EMAC_ADDRESS_ENABLE6 : R/W ;bitpos:[31] ;default: 1'h0 ; */ -/*description: When this bit is set the address filter module uses the seventh - MAC address for perfect filtering. When this bit is reset the address filter module ignores the address for filtering.*/ -#define EMAC_ADDRESS_ENABLE6 (BIT(31)) -#define EMAC_ADDRESS_ENABLE6_M (BIT(31)) -#define EMAC_ADDRESS_ENABLE6_V 0x1 -#define EMAC_ADDRESS_ENABLE6_S 31 -/* EMAC_SOURCE_ADDRESS6 : R/W ;bitpos:[30] ;default: 1'h0 ; */ -/*description: When this bit is set the EMACADDR6[47:0] is used to compare - with the SA fields of the received frame. When this bit is reset the EMACADDR6[47:0] is used to compare with the DA fields of the received frame.*/ -#define EMAC_SOURCE_ADDRESS6 (BIT(30)) -#define EMAC_SOURCE_ADDRESS6_M (BIT(30)) -#define EMAC_SOURCE_ADDRESS6_V 0x1 -#define EMAC_SOURCE_ADDRESS6_S 30 -/* EMAC_MASK_BYTE_CONTROL6 : R/W ;bitpos:[29:24] ;default: 6'h0 ; */ -/*description: These bits are mask control bits for comparison of each of the - EMACADDR6 bytes. When set high the MAC does not compare the corresponding byte of received DA or SA with the contents of EMACADDR6 registers. Each bit controls the masking of the bytes as follows: Bit[29]: EMACADDR6 High [15:8]. Bit[28]: EMACADDR6 High [7:0]. Bit[27]: EMACADDR6 Low [31:24]. Bit[24]: EMACADDR6 Low [7:0].You can filter a group of addresses (known as group address filtering) by masking one or more bytes of the address.*/ -#define EMAC_MASK_BYTE_CONTROL6 0x0000003F -#define EMAC_MASK_BYTE_CONTROL6_M ((EMAC_MASK_BYTE_CONTROL6_V)<<(EMAC_MASK_BYTE_CONTROL6_S)) -#define EMAC_MASK_BYTE_CONTROL6_V 0x3F -#define EMAC_MASK_BYTE_CONTROL6_S 24 -/* EMAC_MAC_ADDRESS6_HI : R/W ;bitpos:[15:0] ;default: 16'hFFFF ; */ -/*description: This field contains the upper 16 bits Bits[47:32] of the seventh - 6-byte MAC Address.*/ -#define EMAC_MAC_ADDRESS6_HI 0x0000FFFF -#define EMAC_MAC_ADDRESS6_HI_M ((EMAC_MAC_ADDRESS6_HI_V)<<(EMAC_MAC_ADDRESS6_HI_S)) -#define EMAC_MAC_ADDRESS6_HI_V 0xFFFF -#define EMAC_MAC_ADDRESS6_HI_S 0 - -#define EMAC_ADDR6LOW_REG (DR_REG_EMAC_BASE + 0x1074) -/* EMAC_MAC_ADDRESS6_LOW : R/W ;bitpos:[31:0] ;default: 32'hFFFFFFFF ; */ -/*description: This field contains the lower 32 bits of the seventh 6-byte MAC - address.The content of this field is undefined so the register needs to be configured after the initialization Process.*/ -#define EMAC_MAC_ADDRESS6_LOW 0xFFFFFFFF -#define EMAC_MAC_ADDRESS6_LOW_M ((EMAC_MAC_ADDRESS6_LOW_V)<<(EMAC_MAC_ADDRESS6_LOW_S)) -#define EMAC_MAC_ADDRESS6_LOW_V 0xFFFFFFFF -#define EMAC_MAC_ADDRESS6_LOW_S 0 - -#define EMAC_ADDR7HIGH_REG (DR_REG_EMAC_BASE + 0x1078) -/* EMAC_ADDRESS_ENABLE7 : R/W ;bitpos:[31] ;default: 1'h0 ; */ -/*description: When this bit is set the address filter module uses the eighth - MAC address for perfect filtering. When this bit is reset the address filter module ignores the address for filtering.*/ -#define EMAC_ADDRESS_ENABLE7 (BIT(31)) -#define EMAC_ADDRESS_ENABLE7_M (BIT(31)) -#define EMAC_ADDRESS_ENABLE7_V 0x1 -#define EMAC_ADDRESS_ENABLE7_S 31 -/* EMAC_SOURCE_ADDRESS7 : R/W ;bitpos:[30] ;default: 1'h0 ; */ -/*description: When this bit is set the EMACADDR7[47:0] is used to compare - with the SA fields of the received frame. When this bit is reset the EMACADDR7[47:0] is used to compare with the DA fields of the received frame.*/ -#define EMAC_SOURCE_ADDRESS7 (BIT(30)) -#define EMAC_SOURCE_ADDRESS7_M (BIT(30)) -#define EMAC_SOURCE_ADDRESS7_V 0x1 -#define EMAC_SOURCE_ADDRESS7_S 30 -/* EMAC_MASK_BYTE_CONTROL7 : R/W ;bitpos:[29:24] ;default: 6'h0 ; */ -/*description: These bits are mask control bits for comparison of each of the - EMACADDR7 bytes. When set high the MAC does not compare the corresponding byte of received DA or SA with the contents of EMACADDR7 registers. Each bit controls the masking of the bytes as follows: Bit[29]: EMACADDR7 High [15:8]. Bit[28]: EMACADDR7 High [7:0]. Bit[27]: EMACADDR7 Low [31:24]. Bit[24]: EMACADDR7 Low [7:0].You can filter a group of addresses (known as group address filtering) by masking one or more bytes of the address.*/ -#define EMAC_MASK_BYTE_CONTROL7 0x0000003F -#define EMAC_MASK_BYTE_CONTROL7_M ((EMAC_MASK_BYTE_CONTROL7_V)<<(EMAC_MASK_BYTE_CONTROL7_S)) -#define EMAC_MASK_BYTE_CONTROL7_V 0x3F -#define EMAC_MASK_BYTE_CONTROL7_S 24 -/* EMAC_MAC_ADDRESS7_HI : R/W ;bitpos:[15:0] ;default: 16'hFFFF ; */ -/*description: This field contains the upper 16 bits Bits[47:32] of the eighth - 6-byte MAC Address.*/ -#define EMAC_MAC_ADDRESS7_HI 0x0000FFFF -#define EMAC_MAC_ADDRESS7_HI_M ((EMAC_MAC_ADDRESS7_HI_V)<<(EMAC_MAC_ADDRESS7_HI_S)) -#define EMAC_MAC_ADDRESS7_HI_V 0xFFFF -#define EMAC_MAC_ADDRESS7_HI_S 0 - -#define EMAC_ADDR7LOW_REG (DR_REG_EMAC_BASE + 0x107C) -/* EMAC_MAC_ADDRESS7_LOW : R/W ;bitpos:[31:0] ;default: 32'hFFFFFFFF ; */ -/*description: This field contains the lower 32 bits of the eighth 6-byte MAC - address.The content of this field is undefined so the register needs to be configured after the initialization Process.*/ -#define EMAC_MAC_ADDRESS7_LOW 0xFFFFFFFF -#define EMAC_MAC_ADDRESS7_LOW_M ((EMAC_MAC_ADDRESS7_LOW_V)<<(EMAC_MAC_ADDRESS7_LOW_S)) -#define EMAC_MAC_ADDRESS7_LOW_V 0xFFFFFFFF -#define EMAC_MAC_ADDRESS7_LOW_S 0 - -#define EMAC_CSTATUS_REG (DR_REG_EMAC_BASE + 0x10D8) -/* EMAC_JABBER_TIMEOUT : RO ;bitpos:[4] ;default: 1'h0 ; */ -/*description: This bit indicates whether there is jabber timeout error (1'b1) - in the received Frame.*/ -#define EMAC_JABBER_TIMEOUT (BIT(4)) -#define EMAC_JABBER_TIMEOUT_M (BIT(4)) -#define EMAC_JABBER_TIMEOUT_V 0x1 -#define EMAC_JABBER_TIMEOUT_S 4 -/* EMAC_LINK_SPEED : RO ;bitpos:[2:1] ;default: 1'h0 ; */ -/*description: This bit indicates the current speed of the link: 2'b00: 2.5 - MHz. 2'b01: 25 MHz. 2'b10: 125 MHz.*/ -#define EMAC_LINK_SPEED 0x00000003 -#define EMAC_LINK_SPEED_M ((EMAC_LINK_SPEED_V)<<(EMAC_LINK_SPEED_S)) -#define EMAC_LINK_SPEED_V 0x3 -#define EMAC_LINK_SPEED_S 1 -/* EMAC_LINK_MODE : RO ;bitpos:[0] ;default: 1'h0 ; */ -/*description: This bit indicates the current mode of operation of the link: - 1'b0: Half-duplex mode. 1'b1: Full-duplex mode.*/ -#define EMAC_LINK_MODE (BIT(0)) -#define EMAC_LINK_MODE_M (BIT(0)) -#define EMAC_LINK_MODE_V 0x1 -#define EMAC_LINK_MODE_S 0 - -#define EMAC_WDOGTO_REG (DR_REG_EMAC_BASE + 0x10DC) -/* EMAC_PWDOGEN : R/W ;bitpos:[16] ;default: 1'h0 ; */ -/*description: When this bit is set and Bit[23] (WD) of EMACCONFIG_REG is reset - the WTO field (Bits[13:0]) is used as watchdog timeout for a received frame. When this bit is cleared the watchdog timeout for a received frame is controlled by the setting of Bit[23] (WD) and Bit[20] (JE) in EMACCONFIG_REG.*/ -#define EMAC_PWDOGEN (BIT(16)) -#define EMAC_PWDOGEN_M (BIT(16)) -#define EMAC_PWDOGEN_V 0x1 -#define EMAC_PWDOGEN_S 16 -/* EMAC_WDOGTO : R/W ;bitpos:[13:0] ;default: 14'h0 ; */ -/*description: When Bit[16] (PWE) is set and Bit[23] (WD) of EMACCONFIG_REG - is reset this field is used as watchdog timeout for a received frame. If the length of a received frame exceeds the value of this field such frame is terminated and declared as an error frame.*/ -#define EMAC_WDOGTO 0x00003FFF -#define EMAC_WDOGTO_M ((EMAC_WDOGTO_V)<<(EMAC_WDOGTO_S)) -#define EMAC_WDOGTO_V 0x3FFF -#define EMAC_WDOGTO_S 0 - -#ifdef __cplusplus -} -#endif - - - -#endif /*_SOC_EMAC_REG_H_ */ - - diff --git a/components/soc/esp32/include/soc/rtc_i2c_reg.h b/components/soc/esp32/include/soc/rtc_i2c_reg.h index be7b64c6b1..556a455663 100644 --- a/components/soc/esp32/include/soc/rtc_i2c_reg.h +++ b/components/soc/esp32/include/soc/rtc_i2c_reg.h @@ -35,13 +35,13 @@ #define RTC_I2C_CTRL_REG (DR_REG_RTC_I2C_BASE + 0x004) /* RTC_I2C_RX_LSB_FIRST : R/W ;bitpos:[7] ;default: 1'b0 ; */ -/*description: Send LSB first */ +/*description: Receive LSB first */ #define RTC_I2C_RX_LSB_FIRST BIT(7) #define RTC_I2C_RX_LSB_FIRST_M BIT(7) #define RTC_I2C_RX_LSB_FIRST_V (1) #define RTC_I2C_RX_LSB_FIRST_S (7) /* RTC_I2C_TX_LSB_FIRST : R/W ;bitpos:[6] ;default: 1'b0 ; */ -/*description: Receive LSB first */ +/*description: Send LSB first */ #define RTC_I2C_TX_LSB_FIRST BIT(6) #define RTC_I2C_TX_LSB_FIRST_M BIT(6) #define RTC_I2C_TX_LSB_FIRST_V (1) diff --git a/components/soc/esp32/include/soc/spi_caps.h b/components/soc/esp32/include/soc/spi_caps.h index c0230ad788..bd0bdb87a5 100644 --- a/components/soc/esp32/include/soc/spi_caps.h +++ b/components/soc/esp32/include/soc/spi_caps.h @@ -28,6 +28,15 @@ #define SPI_IOMUX_PIN_NUM_HD 9 #define HSPI_FUNC_NUM 1 + +//For D2WD and PICO-D4 chip +#define SPI_D2WD_PIN_NUM_MISO 17 +#define SPI_D2WD_PIN_NUM_MOSI 8 +#define SPI_D2WD_PIN_NUM_CLK 6 +#define SPI_D2WD_PIN_NUM_CS 16 +#define SPI_D2WD_PIN_NUM_WP 7 +#define SPI_D2WD_PIN_NUM_HD 11 + #define HSPI_IOMUX_PIN_NUM_MISO 12 #define HSPI_IOMUX_PIN_NUM_MOSI 13 #define HSPI_IOMUX_PIN_NUM_CLK 14 @@ -46,6 +55,8 @@ #define SOC_SPI_MAXIMUM_BUFFER_SIZE 64 #define SOC_SPI_SUPPORT_AS_CS 1 //Support to toggle the CS while the clock toggles + //#define SOC_SPI_SUPPORT_DDRCLK //#define SOC_SPI_SLAVE_SUPPORT_SEG_TRANS //#define SOC_SPI_SUPPORT_CD_SIG + diff --git a/components/soc/esp32/sources.cmake b/components/soc/esp32/sources.cmake index 69765bb953..6e384f269e 100644 --- a/components/soc/esp32/sources.cmake +++ b/components/soc/esp32/sources.cmake @@ -15,6 +15,10 @@ set(SOC_SRCS "cpu_util.c" "ledc_periph.c" "i2s_periph.c") +if(NOT BOOTLOADER_BUILD AND CONFIG_ETH_USE_ESP32_EMAC) + list(APPEND SOC_SRCS "emac_hal.c") +endif() + if(NOT CMAKE_BUILD_EARLY_EXPANSION) set_source_files_properties("esp32/rtc_clk.c" PROPERTIES COMPILE_FLAGS "-fno-jump-tables -fno-tree-switch-conversion") diff --git a/components/soc/include/hal/esp_flash_err.h b/components/soc/include/hal/esp_flash_err.h new file mode 100644 index 0000000000..cde56aa507 --- /dev/null +++ b/components/soc/include/hal/esp_flash_err.h @@ -0,0 +1,45 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Possible errors returned from esp flash internal functions, these error codes + * should be consistent with esp_err_t codes. But in order to make the source + * files less dependent to esp_err_t, they use the error codes defined in this + * replacable header. This header should ensure the consistency to esp_err_t. + */ + +/* These should be consistent with esp_err_t errors */ +#define ESP_ERR_FLASH_SIZE_NOT_MATCH ESP_ERR_INVALID_SIZE ///< The chip doesn't have enough space for the current partition table +#define ESP_ERR_FLASH_NO_RESPONSE ESP_ERR_INVALID_RESPONSE ///< Chip did not respond to the command, or timed out. + + +#define ESP_ERR_FLASH_ERR_BASE 0x6000 ///< Starting number of Flash error codes */ +//The ROM code has already taken 1 and 2, to avoid possible conflicts, start from 3. +#define ESP_ERR_FLASH_NOT_INITIALISED (ESP_ERR_FLASH_ERR_BASE+3) ///< esp_flash_chip_t structure not correctly initialised by esp_flash_init(). +#define ESP_ERR_FLASH_UNSUPPORTED_HOST (ESP_ERR_FLASH_ERR_BASE+4) ///< Requested operation isn't supported via this host SPI bus (chip->spi field). +#define ESP_ERR_FLASH_UNSUPPORTED_CHIP (ESP_ERR_FLASH_ERR_BASE+5) ///< Requested operation isn't supported by this model of SPI flash chip. +#define ESP_ERR_FLASH_PROTECTED (ESP_ERR_FLASH_ERR_BASE+6) ///< Write operation failed due to chip's write protection being enabled. + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/include/hal/spi_flash_hal.h b/components/soc/include/hal/spi_flash_hal.h new file mode 100644 index 0000000000..3a18e4ca5f --- /dev/null +++ b/components/soc/include/hal/spi_flash_hal.h @@ -0,0 +1,221 @@ +// Copyright 2010-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/******************************************************************************* + * NOTICE + * The HAL is not public api, don't use in application code. + * See readme.md in soc/include/hal/readme.md + ******************************************************************************/ + +// The HAL layer for SPI Flash (common part) + +#pragma once + +#include "hal/spi_flash_ll.h" +#include "hal/spi_types.h" +#include "hal/spi_flash_types.h" +#include "soc/soc_memory_layout.h" + +/* Hardware host-specific constants */ +#define SPI_FLASH_HAL_MAX_WRITE_BYTES 64 +#define SPI_FLASH_HAL_MAX_READ_BYTES 64 + +/** + * Generic driver context structure for all chips using the SPI peripheral. + * Include this into the HEAD of the driver data for other driver + * implementations that also use the SPI peripheral. + */ +typedef struct { + spi_dev_t *spi; ///< Pointer to SPI peripheral registers (SP1, SPI2 or SPI3). Set before initialisation. + int cs_num; ///< Which cs pin is used, 0-2. + int extra_dummy; + spi_flash_ll_clock_reg_t clock_conf; +} spi_flash_memspi_data_t; + +/// Configuration structure for the SPI driver. +typedef struct { + spi_host_device_t host_id; ///< SPI peripheral ID. + int cs_num; ///< Which cs pin is used, 0-2. + bool iomux; ///< Whether the IOMUX is used, used for timing compensation. + int input_delay_ns; ///< Input delay on the MISO pin after the launch clock, used for timing compensation. + esp_flash_speed_t speed;///< SPI flash clock speed to work at. +} spi_flash_memspi_config_t; + +/** + * Configure SPI flash hal settings. + * + * @param data Buffer to hold configured data, the buffer should be in DRAM to be available when cache disabled + * @param cfg Configurations to set + * + * @return + * - ESP_OK: success + * - ESP_ERR_INVALID_ARG: the data buffer is not in the DRAM. + */ +esp_err_t spi_flash_hal_init(spi_flash_memspi_data_t *data_out, const spi_flash_memspi_config_t *cfg); + +/** + * Configure the device-related register before transactions. + * + * @param driver The driver context. + * + * @return always return ESP_OK. + */ +esp_err_t spi_flash_hal_device_config(spi_flash_host_driver_t *driver); + +/** + * Send an user-defined spi transaction to the device. + * + * @note This is usually used when the memspi interface doesn't support some + * particular commands. Since this function supports timing compensation, it is + * also used to receive some data when the frequency is high. + * + * @param driver The driver context. + * @param trans The transaction to send, also holds the received data. + * + * @return always return ESP_OK. + */ +esp_err_t spi_flash_hal_common_command(spi_flash_host_driver_t *driver, spi_flash_trans_t *trans); + +/** + * Erase whole flash chip. + * + * @param driver The driver context. + */ +void spi_flash_hal_erase_chip(spi_flash_host_driver_t *driver); + +/** + * Erase a specific sector by its start address. + * + * @param driver The driver context. + * @param start_address Start address of the sector to erase. + */ +void spi_flash_hal_erase_sector(spi_flash_host_driver_t *driver, uint32_t start_address); + +/** + * Erase a specific block by its start address. + * + * @param driver The driver context. + * @param start_address Start address of the block to erase. + */ +void spi_flash_hal_erase_block(spi_flash_host_driver_t *driver, uint32_t start_address); + +/** + * Program a page of the flash. + * + * @param driver The driver context. + * @param address Address of the page to program + * @param buffer Data to program + * @param length Size of the buffer in bytes, no larger than ``SPI_FLASH_HAL_MAX_WRITE_BYTES`` (64) bytes. + */ +void spi_flash_hal_program_page(spi_flash_host_driver_t *driver, const void *buffer, uint32_t address, uint32_t length); + +/** + * Read from the flash. The read command should be set by ``spi_flash_hal_configure_host_read_mode`` before. + * + * @param driver The driver context. + * @param buffer Buffer to store the read data + * @param address Address to read + * @param length Length to read, no larger than ``SPI_FLASH_HAL_MAX_READ_BYTES`` (64) bytes. + * + * @return always return ESP_OK. + */ +esp_err_t spi_flash_hal_read(spi_flash_host_driver_t *driver, void *buffer, uint32_t address, uint32_t read_len); + +/** + * Enable or disable the write protection of the flash chip. + * + * @param driver The driver context. + * @param wp true to enable the write protection, otherwise false. + * + * @return always return ESP_OK. + */ +esp_err_t spi_flash_hal_set_write_protect(spi_flash_host_driver_t *chip_drv, bool wp); + +/** + * Check whether the SPI host is idle and can perform other operations. + * + * @param driver The driver context. + * + * @return ture if idle, otherwise false. + */ +bool spi_flash_hal_host_idle(spi_flash_host_driver_t *driver); + +/** + * Configure the SPI host hardware registers for the specified read mode. + * + * Note that calling this configures SPI host registers, so if running any + * other commands as part of set_read_mode() then these must be run before + * calling this function. + * + * @param driver The driver context + * @param read_mode The HW read mode to use + * @param addr_bitlen Length of the address phase, in bits + * @param dummy_cyclelen_base Base cycles of the dummy phase, some extra dummy cycles may be appended to compensate the timing. + * @param read_command Actual reading command to send to flash chip on the bus. + * + * @return always return ESP_OK. + */ +esp_err_t spi_flash_hal_configure_host_read_mode(spi_flash_host_driver_t *driver, esp_flash_read_mode_t read_mode, + uint32_t addr_bitlen, uint32_t dummy_cyclelen_base, + uint32_t read_command); + +/** + * Poll until the last operation is done. + * + * @param driver The driver context. + */ +void spi_flash_hal_poll_cmd_done(spi_flash_host_driver_t *driver); + +/** + * Check whether the given buffer can be used as the write buffer directly. If 'chip' is connected to the main SPI bus, we can only write directly from + * regions that are accessible ith cache disabled. * + * + * @param driver The driver context + * @param p The buffer holding data to send. + * + * @return True if the buffer can be used to send data, otherwise false. + */ +static inline bool spi_flash_hal_supports_direct_write(spi_flash_host_driver_t *driver, const void *p) +{ +#ifdef ESP_PLATFORM + bool direct_write = ( ((spi_flash_memspi_data_t *)driver->driver_data)->spi != &SPI1 + || esp_ptr_in_dram(p) ); +#else + //If it is not on real chips, there is no limitation that the data has to be in DRAM. + bool direct_write = true; +#endif + return direct_write; +} + +/** + * Check whether the given buffer can be used as the read buffer directly. If 'chip' is connected to the main SPI bus, we can only read directly from + * regions that are accessible ith cache disabled. * + * + * @param driver The driver context + * @param p The buffer to hold the received data. + * + * @return True if the buffer can be used to receive data, otherwise false. + */ +static inline bool spi_flash_hal_supports_direct_read(spi_flash_host_driver_t *driver, const void *p) +{ +#ifdef ESP_PLATFORM +//currently the driver doesn't support to read through DMA, no word-aligned requirements + bool direct_read = ( ((spi_flash_memspi_data_t *)driver->driver_data)->spi != &SPI1 + || esp_ptr_in_dram(p) ); +#else + //If it is not on real chips, there is no limitation that the data has to be in DRAM. + bool direct_read = true; +#endif + return direct_read; +} \ No newline at end of file diff --git a/components/soc/include/hal/spi_flash_types.h b/components/soc/include/hal/spi_flash_types.h new file mode 100644 index 0000000000..7babeee0c9 --- /dev/null +++ b/components/soc/include/hal/spi_flash_types.h @@ -0,0 +1,154 @@ +// Copyright 2010-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include "hal/esp_flash_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Definition of a common transaction. Also holds the return value. */ +typedef struct { + uint8_t command; ///< Command to send, always 8bits + uint8_t mosi_len; ///< Output data length, in bits + uint8_t miso_len; ///< Input data length, in bits + uint32_t mosi_data; ///< Output data to slave + uint32_t miso_data[2]; ///< [out] Input data from slave, little endian +} spi_flash_trans_t; + +/** + * @brief SPI flash clock speed values, always refer to them by the enum rather + * than the actual value (more speed may be appended into the list). + * + * A strategy to select the maximum allowed speed is to enumerate from the + * ``ESP_FLSH_SPEED_MAX-1`` or highest frequency supported by your flash, and + * decrease the speed until the probing success. + */ +typedef enum { + ESP_FLASH_5MHZ = 0, ///< The flash runs under 5MHz + ESP_FLASH_10MHZ, ///< The flash runs under 10MHz + ESP_FLASH_20MHZ, ///< The flash runs under 20MHz + ESP_FLASH_26MHZ, ///< The flash runs under 26MHz + ESP_FLASH_40MHZ, ///< The flash runs under 40MHz + ESP_FLASH_80MHZ, ///< The flash runs under 80MHz + ESP_FLASH_SPEED_MAX, ///< The maximum frequency supported by the host is ``ESP_FLASH_SPEED_MAX-1``. +} esp_flash_speed_t; + +///Lowest speed supported by the driver, currently 5 MHz +#define ESP_FLASH_SPEED_MIN ESP_FLASH_5MHZ + +/** @brief Mode used for reading from SPI flash */ +typedef enum { + SPI_FLASH_SLOWRD = 0, ///< Data read using single I/O, some limits on speed + SPI_FLASH_FASTRD, ///< Data read using single I/O, no limit on speed + SPI_FLASH_DOUT, ///< Data read using dual I/O + SPI_FLASH_DIO, ///< Both address & data transferred using dual I/O + SPI_FLASH_QOUT, ///< Data read using quad I/O + SPI_FLASH_QIO, ///< Both address & data transferred using quad I/O + + SPI_FLASH_READ_MODE_MAX, ///< The fastest io mode supported by the host is ``ESP_FLASH_READ_MODE_MAX-1``. +} esp_flash_read_mode_t; + +///Slowest io mode supported by ESP32, currently SlowRd +#define SPI_FLASH_READ_MODE_MIN SPI_FLASH_SLOWRD + +struct spi_flash_host_driver_t; +typedef struct spi_flash_host_driver_t spi_flash_host_driver_t; + +/** Host driver configuration and context structure. */ +struct spi_flash_host_driver_t { + /** + * Configuration and static data used by the specific host driver. The type + * is determined by the host driver. + */ + void *driver_data; + /** + * Configure the device-related register before transactions. This saves + * some time to re-configure those registers when we send continuously + */ + esp_err_t (*dev_config)(spi_flash_host_driver_t *driver); + /** + * Send an user-defined spi transaction to the device. + */ + esp_err_t (*common_command)(spi_flash_host_driver_t *driver, spi_flash_trans_t *t); + /** + * Read flash ID. + */ + esp_err_t (*read_id)(spi_flash_host_driver_t *driver, uint32_t *id); + /** + * Erase whole flash chip. + */ + void (*erase_chip)(spi_flash_host_driver_t *driver); + /** + * Erase a specific sector by its start address. + */ + void (*erase_sector)(spi_flash_host_driver_t *driver, uint32_t start_address); + /** + * Erase a specific block by its start address. + */ + void (*erase_block)(spi_flash_host_driver_t *driver, uint32_t start_address); + /** + * Read the status of the flash chip. + */ + esp_err_t (*read_status)(spi_flash_host_driver_t *driver, uint8_t *out_sr); + /** + * Disable write protection. + */ + esp_err_t (*set_write_protect)(spi_flash_host_driver_t *driver, bool wp); + /** + * Program a page of the flash. Check ``max_write_bytes`` for the maximum allowed writing length. + */ + void (*program_page)(spi_flash_host_driver_t *driver, const void *buffer, uint32_t address, uint32_t length); + /** Check whether need to allocate new buffer to write */ + bool (*supports_direct_write)(spi_flash_host_driver_t *driver, const void *p); + /** Check whether need to allocate new buffer to read */ + bool (*supports_direct_read)(spi_flash_host_driver_t *driver, const void *p); + /** maximum length of program_page */ + int max_write_bytes; + /** + * Read data from the flash. Check ``max_read_bytes`` for the maximum allowed reading length. + */ + esp_err_t (*read)(spi_flash_host_driver_t *driver, void *buffer, uint32_t address, uint32_t read_len); + /** maximum length of read */ + int max_read_bytes; + /** + * Check whether the host is idle to perform new operations. + */ + bool (*host_idle)(spi_flash_host_driver_t *driver); + /** + * Configure the host to work at different read mode. + */ + esp_err_t (*configure_host_read_mode)(spi_flash_host_driver_t *driver, esp_flash_read_mode_t read_mode, uint32_t addr_bitlen, uint32_t dummy_bitlen_base, uint32_t read_command); + /** + * Internal use, poll the HW until the last operation is done. + */ + void (*poll_cmd_done)(spi_flash_host_driver_t *driver); + /** + * For some host (SPI1), they are shared with a cache. When the data is + * modified, the cache needs to be flushed. Left NULL if not supported. + */ + esp_err_t (*flush_cache)(spi_flash_host_driver_t* driver, uint32_t addr, uint32_t size); + /** + * Check if the given region is protected (e.g. is the bootloader). Left + * NULL if current host doesn't need protection. + */ + bool (*region_protected)(spi_flash_host_driver_t* driver, uint32_t addr, uint32_t size); +}; + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/include/hal/spi_types.h b/components/soc/include/hal/spi_types.h index 798af87a6c..715626a820 100644 --- a/components/soc/include/hal/spi_types.h +++ b/components/soc/include/hal/spi_types.h @@ -40,4 +40,3 @@ typedef enum { #define HSPI_HOST SPI3_HOST #define VSPI_HOST SPI4_HOST #endif - diff --git a/components/soc/include/soc/soc_memory_layout.h b/components/soc/include/soc/soc_memory_layout.h index 6cc73023dd..8aef575c09 100644 --- a/components/soc/include/soc/soc_memory_layout.h +++ b/components/soc/include/soc/soc_memory_layout.h @@ -205,3 +205,10 @@ inline static bool IRAM_ATTR esp_ptr_in_diram_dram(const void *p) { inline static bool IRAM_ATTR esp_ptr_in_diram_iram(const void *p) { return ((intptr_t)p >= SOC_DIRAM_IRAM_LOW && (intptr_t)p < SOC_DIRAM_IRAM_HIGH); } + + +inline static bool IRAM_ATTR esp_stack_ptr_is_sane(uint32_t sp) +{ + //Check if stack ptr is in between SOC_DRAM_LOW and SOC_DRAM_HIGH, and 16 byte aligned. + return !(sp < SOC_DRAM_LOW + 0x10 || sp > SOC_DRAM_HIGH - 0x10 || ((sp & 0xF) != 0)); +} diff --git a/components/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/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..59da629c13 100644 --- a/components/spi_flash/CMakeLists.txt +++ b/components/spi_flash/CMakeLists.txt @@ -1,23 +1,33 @@ +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" + "spi_flash_os_func_app.c" + "spi_flash_os_func_noos.c" + "memspi_host_driver.c") + if(NOT CONFIG_SPI_FLASH_USE_LEGACY_IMPL) + list(APPEND srcs "esp_flash_api.c" "esp_flash_spi_init.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) + 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..8a10651ff0 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,29 @@ 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 + 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/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/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..1ce52e47b2 --- /dev/null +++ b/components/spi_flash/esp_flash_api.c @@ -0,0 +1,673 @@ +// 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); + bool write_protect = false; + + esp_err_t err = spiflash_start(chip); + if (err != ESP_OK) { + return err; + } + + err = esp_flash_get_chip_write_protect(chip, &write_protect); + + if (err == ESP_OK && write_protect) { + err = ESP_ERR_FLASH_PROTECTED; + } + + if (err == ESP_OK) { + err = chip->chip_drv->erase_chip(chip); + } + + return spiflash_end(chip, err); +} + +esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, uint32_t len) +{ + VERIFY_OP(erase_sector); + VERIFY_OP(erase_block); + CHECK_WRITE_ADDRESS(chip, start, len); + uint32_t block_erase_size = chip->chip_drv->erase_block == NULL ? 0 : chip->chip_drv->block_erase_size; + uint32_t sector_size = chip->chip_drv->sector_size; + bool write_protect = false; + + if (sector_size == 0 || (block_erase_size % sector_size) != 0) { + return ESP_ERR_FLASH_NOT_INITIALISED; + } + if (start > chip->size || start + len > chip->size) { + return ESP_ERR_INVALID_ARG; + } + if ((start % chip->chip_drv->sector_size) != 0 || (len % chip->chip_drv->sector_size) != 0) { + // Can only erase multiples of the sector size, starting at sector boundary + return ESP_ERR_INVALID_ARG; + } + + esp_err_t err = spiflash_start(chip); + if (err != ESP_OK) { + return err; + } + + // Check for write protection on whole chip + if (chip->chip_drv->get_chip_write_protect != NULL) { + err = chip->chip_drv->get_chip_write_protect(chip, &write_protect); + if (err == ESP_OK && write_protect) { + err = ESP_ERR_FLASH_PROTECTED; + } + } + + // Check for write protected regions overlapping the erase region + if (err == ESP_OK && chip->chip_drv->get_protected_regions != NULL && chip->chip_drv->num_protectable_regions > 0) { + uint64_t protected = 0; + err = chip->chip_drv->get_protected_regions(chip, &protected); + if (err == ESP_OK && protected != 0) { + for (int i = 0; i < chip->chip_drv->num_protectable_regions && err == ESP_OK; i++) { + const esp_flash_region_t *region = &chip->chip_drv->protectable_regions[i]; + if ((protected & BIT64(i)) + && regions_overlap(start, len, region->offset, region->size)) { + err = ESP_ERR_FLASH_PROTECTED; + } + } + } + } + + // Don't lock the SPI flash for the entire erase, as this may be very long + err = spiflash_end(chip, err); + + while (err == ESP_OK && len >= sector_size) { + err = spiflash_start(chip); + if (err != ESP_OK) { + return err; + } + + // If possible erase an entire multi-sector block + if (block_erase_size > 0 && len >= block_erase_size && (start % block_erase_size) == 0) { + err = chip->chip_drv->erase_block(chip, start); + start += block_erase_size; + len -= block_erase_size; + } + else { + // Otherwise erase individual sector only + err = chip->chip_drv->erase_sector(chip, start); + start += sector_size; + len -= sector_size; + } + + err = spiflash_end(chip, err); + } + return err; +} + +esp_err_t IRAM_ATTR esp_flash_get_chip_write_protect(esp_flash_t *chip, bool *write_protected) +{ + VERIFY_OP(get_chip_write_protect); + if (write_protected == NULL) { + return ESP_ERR_INVALID_ARG; + } + + esp_err_t err = spiflash_start(chip); + if (err != ESP_OK) { + return err; + } + + err = chip->chip_drv->get_chip_write_protect(chip, write_protected); + + return spiflash_end(chip, err); +} + +esp_err_t IRAM_ATTR esp_flash_set_chip_write_protect(esp_flash_t *chip, bool write_protect) +{ + 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() +{ + 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..ecd5666860 --- /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() +{ + 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() +{ + return esp_flash_init_os_functions(&default_chip, 0); +} diff --git a/components/spi_flash/flash_ops.c b/components/spi_flash/flash_ops.c index dfb51e7f4b..6064b33c7c 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,24 +117,14 @@ 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; } @@ -191,7 +179,8 @@ static inline void IRAM_ATTR spi_flash_guard_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() { 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() +{ + 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) { @@ -653,76 +700,3 @@ 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; - } -} -#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..86737f791a --- /dev/null +++ b/components/spi_flash/include/esp_flash.h @@ -0,0 +1,300 @@ +// 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). + * + * If write protection is enabled, destructive operations will fail with ESP_ERR_FLASH_PROTECTED. + * + * Some SPI flash chips may require a power cycle before write protect status can be cleared. Otherwise, + * write protection can be removed via a follow-up call to this function. + * + * @return 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(); + +/** + * 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(); + +/** + * 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..9365b65e97 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) @@ -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; diff --git a/components/spi_flash/include/memspi_host_driver.h b/components/spi_flash/include/memspi_host_driver.h new file mode 100644 index 0000000000..2347398aa1 --- /dev/null +++ b/components/spi_flash/include/memspi_host_driver.h @@ -0,0 +1,111 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once +#include "hal/spi_flash_hal.h" + +/** Default configuration for the memspi (high speed version) */ +#define ESP_FLASH_DEFAULT_HOST_DRIVER() (spi_flash_host_driver_t) { \ + .dev_config = spi_flash_hal_device_config, \ + .common_command = spi_flash_hal_common_command, \ + .read_id = memspi_host_read_id_hs, \ + .erase_chip = spi_flash_hal_erase_chip, \ + .erase_sector = spi_flash_hal_erase_sector, \ + .erase_block = spi_flash_hal_erase_block, \ + .read_status = memspi_host_read_status_hs, \ + .set_write_protect = spi_flash_hal_set_write_protect, \ + .supports_direct_write = spi_flash_hal_supports_direct_write, \ + .supports_direct_read = spi_flash_hal_supports_direct_read, \ + .program_page = spi_flash_hal_program_page, \ + .max_write_bytes = SPI_FLASH_HAL_MAX_WRITE_BYTES, \ + .read = spi_flash_hal_read, \ + .max_read_bytes = SPI_FLASH_HAL_MAX_READ_BYTES, \ + .host_idle = spi_flash_hal_host_idle, \ + .configure_host_read_mode = spi_flash_hal_configure_host_read_mode, \ + .poll_cmd_done = spi_flash_hal_poll_cmd_done, \ + .flush_cache = memspi_host_flush_cache, \ + .region_protected = memspi_region_protected, \ +} + +/// configuration for the memspi host +typedef spi_flash_memspi_config_t memspi_host_config_t; +/// context for the memspi host +typedef spi_flash_memspi_data_t memspi_host_data_t; + +/** + * Initialize the memory SPI host. + * + * @param host Pointer to the host structure. + * @param data Pointer to allocated space to hold the context of host driver. + * @param cfg Pointer to configuration structure + * + * @return always return ESP_OK + */ +esp_err_t memspi_host_init_pointers(spi_flash_host_driver_t *host, memspi_host_data_t *data, const memspi_host_config_t *cfg); + +/******************************************************************************* + * NOTICE + * Rest part of this file are part of the HAL layer + * The HAL is not public api, don't use in application code. + * See readme.md in soc/include/hal/readme.md + ******************************************************************************/ + +/** + * High speed implementation of RDID through memspi interface relying on the + * ``common_command``. + * + * @param driver The driver context. + * @param id Output of the read ID from the slave. + * + * @return + * - ESP_OK: if success + * - ESP_ERR_FLASH_NO_RESPONSE: if no response from chip + * - or other cases from ``spi_hal_common_command`` + */ +esp_err_t memspi_host_read_id_hs(spi_flash_host_driver_t *driver, uint32_t *id); + +/** + * High speed implementation of RDSR through memspi interface relying on the + * ``common_command``. + * + * @param driver The driver context. + * @param id Output of the read ID from the slave. + * + * @return + * - ESP_OK: if success + * - or other cases from ``spi_hal_common_command`` + */ +esp_err_t memspi_host_read_status_hs(spi_flash_host_driver_t *driver, uint8_t *out_sr); + +/** + * Flush the cache (if needed) after the contents are modified. + * + * @param driver The driver context. + * @param addr Start address of the modified region + * @param size Size of the region modified. + * + * @return always ESP_OK. + */ +esp_err_t memspi_host_flush_cache(spi_flash_host_driver_t* driver, uint32_t addr, uint32_t size); + +/** + * Check if the given region is protected. + * + * @param driver The driver context. + * @param addr Start address of the region. + * @param size Size of the region to check. + * + * @return true if protected, otherwise false. + */ +bool memspi_region_protected(spi_flash_host_driver_t* driver, uint32_t addr, uint32_t size); \ No newline at end of file diff --git a/components/spi_flash/include/spi_flash_chip_driver.h b/components/spi_flash/include/spi_flash_chip_driver.h new file mode 100644 index 0000000000..fd5c1e4c92 --- /dev/null +++ b/components/spi_flash/include/spi_flash_chip_driver.h @@ -0,0 +1,165 @@ +// 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 *write_protected); + + /* Set the write protect status of the entire chip. */ + esp_err_t (*set_chip_write_protect)(esp_flash_t *chip, bool write_protect_chip); + + /* 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); + + /* Set the write enable flag. This function is called internally by other functions in this structure, before a destructive + operation takes place. */ + esp_err_t (*set_write_protect)(esp_flash_t *chip, bool write_protect); + + /* Wait for the SPI flash chip to be idle (any write operation to be complete.) This function is both called from the higher-level API functions, and from other functions in this structure. + + 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..676e173111 --- /dev/null +++ b/components/spi_flash/include/spi_flash_chip_generic.h @@ -0,0 +1,275 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include "esp_flash.h" +#include "spi_flash_chip_driver.h" + + +/* + * The 'chip_generic' SPI flash operations are a lowest common subset of SPI + * flash commands, that work across most chips. + * + * These can be used as-is via the esp_flash_common_chip_driver chip_drv, or + * they can be used as "base chip_drv" functions when creating a new + * spi_flash_host_driver_t chip_drv structure. + * + * All of the functions in this header are internal functions, not part of a + * public API. See esp_flash.h for the public API. + */ + +/** + * @brief Generic probe function + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * @param flash_id expected manufacture id. + * + * @return ESP_OK if the id read from chip->drv_read_id matches (always). + */ +esp_err_t spi_flash_chip_generic_probe(esp_flash_t *chip, uint32_t flash_id); + +/** + * @brief Generic reset function + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * + * @return ESP_OK if sending success, or error code passed from ``common_command`` or ``wait_idle`` functions of host driver. + */ +esp_err_t spi_flash_chip_generic_reset(esp_flash_t *chip); + +/** + * @brief Generic size detection function + * + * Tries to detect the size of chip by using the lower 4 bits of the chip->drv->read_id result = N, and assuming size is 2 ^ N. + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * @param size Output of the detected size + * + * @return + * - ESP_OK if success + * - ESP_ERR_FLASH_UNSUPPORTED_CHIP if the manufacturer id is not correct, which may means an error in the reading + * - or other error passed from the ``read_id`` function of host driver + */ +esp_err_t spi_flash_chip_generic_detect_size(esp_flash_t *chip, uint32_t *size); + +/** + * @brief Erase chip by using the generic erase chip (C7h) command. + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * + * @return + * - ESP_OK if success + * - or other error passed from the ``set_write_protect``, ``wait_idle`` or ``erase_chip`` function of host driver + */ +esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip); + +/** + * @brief Erase sector by using the generic sector erase (20h) command. + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * @param start_address Start address of the sector to erase + * + * @return + * - ESP_OK if success + * - or other error passed from the ``set_write_protect``, ``wait_idle`` or ``erase_sector`` function of host driver + */ +esp_err_t spi_flash_chip_generic_erase_sector(esp_flash_t *chip, uint32_t start_address); + +/** + * @brief Erase block by using the generic 64KB block erase (D8h) command + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * @param start_address Start address of the block to erase + * + * @return + * - ESP_OK if success + * - or other error passed from the ``set_write_protect``, ``wait_idle`` or ``erase_block`` function of host driver + */ +esp_err_t spi_flash_chip_generic_erase_block(esp_flash_t *chip, uint32_t start_address); + +/** + * @brief Read from flash by using a read command that matches the programmed + * read mode. + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * @param buffer Buffer to hold the data read from flash + * @param address Start address of the data on the flash + * @param length Length to read + * + * @return always ESP_OK currently + */ +esp_err_t spi_flash_chip_generic_read(esp_flash_t *chip, void *buffer, uint32_t address, uint32_t length); + +/** + * @brief Perform a page program using the page program (02h) command. + * + * @note Length of each call should not excced the limitation in + * ``chip->host->max_write_bytes``. This function is called in + * ``spi_flash_chip_generic_write`` recursively until the whole page is + * programmed. Strongly suggest to call ``spi_flash_chip_generic_write`` + * instead. + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * @param buffer Buffer holding the data to program + * @param address Start address to write to flash + * @param length Length to write, no longer than ``chip->host->max_write_bytes``. + * + * @return + * - ESP_OK if success + * - or other error passed from the ``wait_idle`` or ``program_page`` function of host driver + */ +esp_err_t +spi_flash_chip_generic_page_program(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length); + +/** + * @brief Perform a generic write. Split the write buffer into page program + * operations, and call chip->chip_drv->page-program() for each. + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * @param buffer Buffer holding the data to program + * @param address Start address to write to flash + * @param length Length to write + * + * @return + * - ESP_OK if success + * - or other error passed from the ``wait_idle`` or ``program_page`` function of host driver + */ +esp_err_t spi_flash_chip_generic_write(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length); + +/** + * @brief Perform a write using on-chip flash encryption. Not implemented yet. + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * @param buffer Buffer holding the data to program + * @param address Start address to write to flash + * @param length Length to write + * + * @return always ESP_ERR_FLASH_UNSUPPORTED_HOST. + */ +esp_err_t +spi_flash_chip_generic_write_encrypted(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length); + +/** + * @brief Send the write enable (06h) command and verify the expected bit (1) in + * the status register is set. + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * @param write_protect true to enable write protection, false to send write enable. + * + * @return + * - ESP_OK if success + * - or other error passed from the ``wait_idle``, ``read_status`` or ``set_write_protect`` function of host driver + */ +esp_err_t spi_flash_chip_generic_write_enable(esp_flash_t *chip, bool write_protect); + +/** + * @brief Read flash status via the RDSR command (05h) and wait for bit 0 (write + * in progress bit) to be cleared. + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * @param timeout_ms Time to wait before timeout, in ms. + * + * @return + * - ESP_OK if success + * - ESP_ERR_TIMEOUT if not idle before timeout + * - or other error passed from the ``wait_idle`` or ``read_status`` function of host driver + */ +esp_err_t spi_flash_chip_generic_wait_idle(esp_flash_t *chip, uint32_t timeout_ms); + +/** + * @brief Set the specified SPI read mode according to the data in the chip + * context. Set quad enable status register bit if needed. + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * + * @return + * - ESP_OK if success +* - ESP_ERR_TIMEOUT if not idle before timeout + * - or other error passed from the ``set_write_protect`` or ``common_command`` function of host driver + */ +esp_err_t spi_flash_chip_generic_set_read_mode(esp_flash_t *chip); + +/** + * Generic SPI flash chip_drv, uses all the above functions for its operations. + * In default autodetection, this is used as a catchall if a more specific + * chip_drv is not found. + */ +extern const spi_flash_chip_t esp_flash_chip_generic; + +/******************************************************************************* + * Utilities +*******************************************************************************/ + +/** + * @brief Wait for the SPI host hardware state machine to be idle. + * + * This isn't a flash chip_drv operation, but it's called by + * spi_flash_chip_generic_wait_idle() and may be useful when implementing + * alternative drivers. + * + * timeout_ms will be decremented if the function needs to wait until the host hardware is idle. + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * + * @return + * - ESP_OK if success + * - ESP_ERR_TIMEOUT if not idle before timeout + * - or other error passed from the ``set_write_protect`` or ``common_command`` function of host driver + */ +esp_err_t spi_flash_generic_wait_host_idle(esp_flash_t *chip, uint32_t *timeout_ms); + +/** + * @brief Utility function for set_read_mode chip_drv function + * + * Most setting of read mode follows a common pattern, except for how to enable Quad I/O modes (QIO/QOUT). + * These use different commands to read/write the status register, and a different bit is set/cleared. + * + * This is a generic utility function to implement set_read_mode() for this pattern. Also configures host + * registers via spi_flash_common_configure_host_read_mode(). + * + * @param qe_rdsr_command SPI flash command to read status register + * @param qe_wrsr_command SPI flash command to write status register + * @param qe_sr_bitwidth Width of the status register these commands operate on, in bits. + * @param qe_sr_bit Bit mask for enabling Quad Enable functions on this chip. + * + * @return always ESP_OK (currently). + */ +esp_err_t spi_flash_common_set_read_mode(esp_flash_t *chip, uint8_t qe_rdsr_command, uint8_t qe_wrsr_command, uint8_t qe_sr_bitwidth, unsigned qe_sr_bit); + +/** + * @brief Configure the host to use the specified read mode set in the ``chip->read_mode``. + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * + * @return + * - ESP_OK if success + * - ESP_ERR_FLASH_NOT_INITIALISED if chip not initialized properly + * - or other error passed from the ``configure_host_mode`` function of host driver + */ +esp_err_t spi_flash_chip_generic_config_host_read_mode(esp_flash_t *chip); + +/** + * @brief Returns true if chip is configured for Quad I/O or Quad Fast Read. + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * + * @return true if flash works in quad mode, otherwise false + */ +static inline bool spi_flash_is_quad_mode(const esp_flash_t *chip) +{ + return (chip->read_mode == SPI_FLASH_QIO) || (chip->read_mode == SPI_FLASH_QOUT); +} + diff --git a/components/spi_flash/include/spi_flash_chip_issi.h b/components/spi_flash/include/spi_flash_chip_issi.h new file mode 100644 index 0000000000..2b1d411552 --- /dev/null +++ b/components/spi_flash/include/spi_flash_chip_issi.h @@ -0,0 +1,27 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include "esp_flash.h" +#include "spi_flash_chip_driver.h" + + +/** + * ISSI SPI flash chip_drv, uses all the above functions for its operations. In + * default autodetection, this is used as a catchall if a more specific chip_drv + * is not found. + */ +extern const spi_flash_chip_t esp_flash_chip_issi; diff --git a/components/spi_flash/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..f31705c81c 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; @@ -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..1a275d5180 100644 --- a/components/spi_flash/sim/flash_mock.cpp +++ b/components/spi_flash/sim/flash_mock.cpp @@ -109,3 +109,5 @@ void *heap_caps_malloc( size_t size, uint32_t caps ) { return NULL; } + +esp_flash_t* esp_flash_default_chip = NULL; diff --git a/components/spi_flash/spi_flash_chip_drivers.c b/components/spi_flash/spi_flash_chip_drivers.c new file mode 100644 index 0000000000..ae10bcec37 --- /dev/null +++ b/components/spi_flash/spi_flash_chip_drivers.c @@ -0,0 +1,38 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include "spi_flash_chip_driver.h" +#include "spi_flash_chip_generic.h" +#include "spi_flash_chip_issi.h" +#include "sdkconfig.h" + +/* + * Default registered chip drivers. Note these are tested in order and first + * match is taken, so generic/catchall entries should go last. Note that the + * esp_flash_registered_flash_ops pointer can be changed to point to a different + * array of registered ops, if desired. + * + * It can be configured to support only available chips in the sdkconfig, to + * avoid possible issues, and speed up the auto-detecting. + */ +static const spi_flash_chip_t *default_registered_chips[] = { +#ifdef CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP + &esp_flash_chip_issi, +#endif + &esp_flash_chip_generic, + NULL, +}; + +const spi_flash_chip_t **esp_flash_registered_chips = default_registered_chips; diff --git a/components/spi_flash/spi_flash_chip_generic.c b/components/spi_flash/spi_flash_chip_generic.c new file mode 100644 index 0000000000..0e80e8eb1d --- /dev/null +++ b/components/spi_flash/spi_flash_chip_generic.c @@ -0,0 +1,405 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include // For MIN/MAX +#include "spi_flash_chip_generic.h" +#include "spi_flash_defs.h" +#include "esp_log.h" + +static const char TAG[] = "chip_generic"; + +#define SPI_FLASH_GENERIC_CHIP_ERASE_TIMEOUT 4000 +#define SPI_FLASH_GENERIC_SECTOR_ERASE_TIMEOUT 500 +#define SPI_FLASH_GENERIC_BLOCK_ERASE_TIMEOUT 1000 + +#define DEFAULT_IDLE_TIMEOUT 200 +#define DEFAULT_PAGE_PROGRAM_TIMEOUT 500 + +esp_err_t spi_flash_chip_generic_probe(esp_flash_t *chip, uint32_t flash_id) +{ + // This is the catch-all probe function, claim the chip always if nothing + // else has claimed it yet. + return ESP_OK; +} + +esp_err_t spi_flash_chip_generic_reset(esp_flash_t *chip) +{ + //this is written following the winbond spec.. + spi_flash_trans_t t; + t = (spi_flash_trans_t) { + .command = CMD_RST_EN, + }; + esp_err_t err = chip->host->common_command(chip->host, &t); + if (err != ESP_OK) { + return err; + } + + t = (spi_flash_trans_t) { + .command = CMD_RST_DEV, + }; + err = chip->host->common_command(chip->host, &t); + if (err != ESP_OK) { + return err; + } + + err = chip->chip_drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT); + return err; +} + +esp_err_t spi_flash_chip_generic_detect_size(esp_flash_t *chip, uint32_t *size) +{ + uint32_t id = 0; + *size = 0; + esp_err_t err = chip->host->read_id(chip->host, &id); + if (err != ESP_OK) { + return err; + } + + /* Can't detect size unless the high byte of the product ID matches the same convention, which is usually 0x40 or + * 0xC0 or similar. */ + if ((id & 0x0F00) != 0) { + return ESP_ERR_FLASH_UNSUPPORTED_CHIP; + } + + *size = 1 << (id & 0xFF); + return ESP_OK; +} + + +esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip) +{ + esp_err_t err; + + err = chip->chip_drv->set_write_protect(chip, false); + if (err == ESP_OK) { + err = chip->chip_drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT); + } + if (err == ESP_OK) { + chip->host->erase_chip(chip->host); + //to save time, flush cache here + if (chip->host->flush_cache) { + err = chip->host->flush_cache(chip->host, 0, chip->size); + if (err != ESP_OK) { + return err; + } + } + err = chip->chip_drv->wait_idle(chip, SPI_FLASH_GENERIC_CHIP_ERASE_TIMEOUT); + } + return err; +} + +esp_err_t spi_flash_chip_generic_erase_sector(esp_flash_t *chip, uint32_t start_address) +{ + esp_err_t err = chip->chip_drv->set_write_protect(chip, false); + if (err == ESP_OK) { + err = chip->chip_drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT); + } + if (err == ESP_OK) { + chip->host->erase_sector(chip->host, start_address); + //to save time, flush cache here + if (chip->host->flush_cache) { + err = chip->host->flush_cache(chip->host, start_address, chip->chip_drv->sector_size); + if (err != ESP_OK) { + return err; + } + } + err = chip->chip_drv->wait_idle(chip, SPI_FLASH_GENERIC_SECTOR_ERASE_TIMEOUT); + } + return err; +} + +esp_err_t spi_flash_chip_generic_erase_block(esp_flash_t *chip, uint32_t start_address) +{ + esp_err_t err = chip->chip_drv->set_write_protect(chip, false); + if (err == ESP_OK) { + err = chip->chip_drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT); + } + if (err == ESP_OK) { + chip->host->erase_block(chip->host, start_address); + //to save time, flush cache here + if (chip->host->flush_cache) { + err = chip->host->flush_cache(chip->host, start_address, chip->chip_drv->block_erase_size); + if (err != ESP_OK) { + return err; + } + } + err = chip->chip_drv->wait_idle(chip, SPI_FLASH_GENERIC_BLOCK_ERASE_TIMEOUT); + } + return err; +} + +esp_err_t spi_flash_chip_generic_read(esp_flash_t *chip, void *buffer, uint32_t address, uint32_t length) +{ + esp_err_t err = ESP_OK; + // Configure the host, and return + spi_flash_chip_generic_config_host_read_mode(chip); + + while (err == ESP_OK && length > 0) { + uint32_t read_len = MIN(length, chip->host->max_read_bytes); + err = chip->host->read(chip->host, buffer, address, read_len); + + buffer += read_len; + length -= read_len; + address += read_len; + } + + return err; +} + +esp_err_t spi_flash_chip_generic_page_program(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length) +{ + esp_err_t err; + + err = chip->chip_drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT); + + if (err == ESP_OK) { + // Perform the actual Page Program command + chip->host->program_page(chip->host, buffer, address, length); + + err = chip->chip_drv->wait_idle(chip, DEFAULT_PAGE_PROGRAM_TIMEOUT); + } + return err; +} + +esp_err_t spi_flash_chip_generic_write(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length) +{ + esp_err_t err = ESP_OK; + const uint32_t page_size = chip->chip_drv->page_size; + + while (err == ESP_OK && length > 0) { + uint32_t page_len = MIN(chip->host->max_write_bytes, MIN(page_size, length)); + if ((address + page_len) / page_size != address / page_size) { + // Most flash chips can't page write across a page boundary + page_len = page_size - (address % page_size); + } + + err = chip->chip_drv->set_write_protect(chip, false); + + if (err == ESP_OK) { + err = chip->chip_drv->program_page(chip, buffer, address, page_len); + address += page_len; + buffer = (void *)((intptr_t)buffer + page_len); + length -= page_len; + } + } + if (err == ESP_OK && chip->host->flush_cache) { + err = chip->host->flush_cache(chip->host, address, length); + } + return err; +} + +esp_err_t spi_flash_chip_generic_write_encrypted(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length) +{ + return ESP_ERR_FLASH_UNSUPPORTED_HOST; // TODO +} + +esp_err_t spi_flash_chip_generic_write_enable(esp_flash_t *chip, bool write_protect) +{ + esp_err_t err = ESP_OK; + + err = chip->chip_drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT); + + if (err == ESP_OK) { + chip->host->set_write_protect(chip->host, write_protect); + } + + uint8_t status; + err = chip->host->read_status(chip->host, &status); + if (err != ESP_OK) { + return err; + } + + if ((status & SR_WREN) == 0) { + // WREN flag has not been set! + err = ESP_ERR_NOT_FOUND; + } + + return err; +} + +esp_err_t spi_flash_generic_wait_host_idle(esp_flash_t *chip, uint32_t *timeout_ms) +{ + while (chip->host->host_idle(chip->host) && *timeout_ms > 0) { + if (*timeout_ms > 1) { + chip->os_func->delay_ms(chip->os_func_data, 1); + } + (*timeout_ms)--; + } + return (*timeout_ms > 0) ? ESP_OK : ESP_ERR_TIMEOUT; +} + +esp_err_t spi_flash_chip_generic_wait_idle(esp_flash_t *chip, uint32_t timeout_ms) +{ + timeout_ms++; // allow at least one pass before timeout, last one has no sleep cycle + + uint8_t status = 0; + while (timeout_ms > 0) { + + esp_err_t err = spi_flash_generic_wait_host_idle(chip, &timeout_ms); + if (err != ESP_OK) { + return err; + } + + err = chip->host->read_status(chip->host, &status); + if (err != ESP_OK) { + return err; + } + if ((status & SR_WIP) == 0) { + break; // Write in progress is complete + } + if (timeout_ms > 1) { + chip->os_func->delay_ms(chip->os_func_data, 1); + } + timeout_ms--; + } + + return (timeout_ms > 0) ? ESP_OK : ESP_ERR_TIMEOUT; +} + +esp_err_t spi_flash_chip_generic_config_host_read_mode(esp_flash_t *chip) +{ + uint32_t dummy_cyclelen_base; + uint32_t addr_bitlen; + uint32_t read_command; + + switch (chip->read_mode) { + case SPI_FLASH_QIO: + //for QIO mode, the 4 bit right after the address are used for continuous mode, should be set to 0 to avoid that. + addr_bitlen = 32; + dummy_cyclelen_base = 4; + read_command = CMD_FASTRD_QIO; + break; + case SPI_FLASH_QOUT: + addr_bitlen = 24; + dummy_cyclelen_base = 8; + read_command = CMD_FASTRD_QUAD; + break; + case SPI_FLASH_DIO: + //for DIO mode, the 4 bit right after the address are used for continuous mode, should be set to 0 to avoid that. + addr_bitlen = 28; + dummy_cyclelen_base = 2; + read_command = CMD_FASTRD_DIO; + break; + case SPI_FLASH_DOUT: + addr_bitlen = 24; + dummy_cyclelen_base = 8; + read_command = CMD_FASTRD_DUAL; + break; + case SPI_FLASH_FASTRD: + addr_bitlen = 24; + dummy_cyclelen_base = 8; + read_command = CMD_FASTRD; + break; + case SPI_FLASH_SLOWRD: + addr_bitlen = 24; + dummy_cyclelen_base = 0; + read_command = CMD_READ; + break; + default: + return ESP_ERR_FLASH_NOT_INITIALISED; + } + + return chip->host->configure_host_read_mode(chip->host, chip->read_mode, addr_bitlen, dummy_cyclelen_base, read_command); +} + +esp_err_t spi_flash_common_set_read_mode(esp_flash_t *chip, uint8_t qe_rdsr_command, uint8_t qe_wrsr_command, uint8_t qe_sr_bitwidth, unsigned qe_sr_bit) +{ + if (spi_flash_is_quad_mode(chip)) { + // Ensure quad modes are enabled, using the Quad Enable parameters supplied. + spi_flash_trans_t t = { + .command = qe_rdsr_command, + .mosi_data = 0, + .mosi_len = 0, + .miso_len = qe_sr_bitwidth, + }; + chip->host->common_command(chip->host, &t); + unsigned sr = t.miso_data[0]; + ESP_EARLY_LOGV(TAG, "set_read_mode: status before 0x%x", sr); + if ((sr & qe_sr_bit) == 0) { + //some chips needs the write protect to be disabled before writing to Status Register + chip->chip_drv->set_write_protect(chip, false); + + sr |= qe_sr_bit; + spi_flash_trans_t t = { + .command = qe_wrsr_command, + .mosi_data = sr, + .mosi_len = qe_sr_bitwidth, + .miso_len = 0, + }; + chip->host->common_command(chip->host, &t); + + /* Check the new QE bit has stayed set */ + spi_flash_trans_t t_rdsr = { + .command = qe_rdsr_command, + .mosi_data = 0, + .mosi_len = 0, + .miso_len = qe_sr_bitwidth + }; + chip->host->common_command(chip->host, &t_rdsr); + sr = t_rdsr.miso_data[0]; + ESP_EARLY_LOGV(TAG, "set_read_mode: status after 0x%x", sr); + if ((sr & qe_sr_bit) == 0) { + return ESP_ERR_FLASH_NO_RESPONSE; + } + + chip->chip_drv->set_write_protect(chip, true); + } + } + return ESP_OK; +} + +esp_err_t spi_flash_chip_generic_set_read_mode(esp_flash_t *chip) +{ + // On "generic" chips, this involves checking + // bit 1 (QE) of RDSR2 (35h) result + // (it works this way on GigaDevice & Fudan Micro chips, probably others...) + const uint8_t BIT_QE = 1 << 1; + return spi_flash_common_set_read_mode(chip, CMD_RDSR2, CMD_WRSR2, 8, BIT_QE); +} + +static const char chip_name[] = "generic"; + +const spi_flash_chip_t esp_flash_chip_generic = { + .name = chip_name, + .probe = spi_flash_chip_generic_probe, + .reset = spi_flash_chip_generic_reset, + .detect_size = spi_flash_chip_generic_detect_size, + .erase_chip = spi_flash_chip_generic_erase_chip, + .erase_sector = spi_flash_chip_generic_erase_sector, + .erase_block = spi_flash_chip_generic_erase_block, + .sector_size = 4 * 1024, + .block_erase_size = 64 * 1024, + + // TODO: figure out if generic chip-wide protection bits exist across some manufacturers + .get_chip_write_protect = NULL, + .set_chip_write_protect = NULL, + + // Chip write protection regions do not appear to be standardised + // at all, this is implemented in chip-specific drivers only. + .num_protectable_regions = 0, + .protectable_regions = NULL, + .get_protected_regions = NULL, + .set_protected_regions = NULL, + + .read = spi_flash_chip_generic_read, + .write = spi_flash_chip_generic_write, + .program_page = spi_flash_chip_generic_page_program, + .page_size = 256, + .write_encrypted = spi_flash_chip_generic_write_encrypted, + + .set_write_protect = spi_flash_chip_generic_write_enable, + .wait_idle = spi_flash_chip_generic_wait_idle, + .set_read_mode = spi_flash_chip_generic_set_read_mode, +}; diff --git a/components/spi_flash/spi_flash_chip_issi.c b/components/spi_flash/spi_flash_chip_issi.c new file mode 100644 index 0000000000..d32c3a1929 --- /dev/null +++ b/components/spi_flash/spi_flash_chip_issi.c @@ -0,0 +1,79 @@ +// 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, + + // TODO: support get/set chip write protect for ISSI flash + .get_chip_write_protect = NULL, + .set_chip_write_protect = NULL, + + // TODO support protected regions on ISSI flash + .num_protectable_regions = 0, + .protectable_regions = NULL, + .get_protected_regions = NULL, + .set_protected_regions = NULL, + + .read = spi_flash_chip_generic_read, + .write = spi_flash_chip_generic_write, + .program_page = spi_flash_chip_generic_page_program, + .page_size = 256, + .write_encrypted = spi_flash_chip_generic_write_encrypted, + + .set_write_protect = spi_flash_chip_generic_write_enable, + .wait_idle = spi_flash_chip_generic_wait_idle, + .set_read_mode = spi_flash_chip_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..b2e13c8e44 --- /dev/null +++ b/components/spi_flash/spi_flash_os_func_app.c @@ -0,0 +1,120 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include "esp32/rom/ets_sys.h" +#include "esp_attr.h" +#include "esp_spi_flash.h" //for ``g_flash_guard_default_ops`` +#include "esp_flash.h" + +/* + * OS functions providing delay service and arbitration among chips, and with the cache. + * + * The cache needs to be disabled when chips on the SPI1 bus is under operation, hence these functions need to be put + * into the IRAM,and their data should be put into the DRAM. + */ + +typedef struct { + int host_id; +} app_func_arg_t; + +// in the future we will have arbitration among devices, including flash on the same flash bus +static IRAM_ATTR esp_err_t spi_bus_acquire(int host_id) +{ + return ESP_OK; +} + +static IRAM_ATTR esp_err_t spi_bus_release(int host_id) +{ + return ESP_OK; +} + +//for SPI1, we have to disable the cache and interrupts before using the SPI bus +static IRAM_ATTR esp_err_t spi1_start(void *arg) +{ + g_flash_guard_default_ops.start(); + + spi_bus_acquire(((app_func_arg_t *)arg)->host_id); + + return ESP_OK; +} +static IRAM_ATTR esp_err_t spi1_end(void *arg) +{ + g_flash_guard_default_ops.end(); + + spi_bus_release(((app_func_arg_t *)arg)->host_id); + + return ESP_OK; +} + +static esp_err_t spi23_start(void *arg) +{ + spi_bus_acquire(((app_func_arg_t *)arg)->host_id); + return ESP_OK; +} + +static esp_err_t spi23_end(void *arg) +{ + spi_bus_release(((app_func_arg_t *)arg)->host_id); + return ESP_OK; +} + +static IRAM_ATTR esp_err_t delay_ms(void *arg, unsigned ms) +{ + ets_delay_us(1000 * ms); + return ESP_OK; +} + +static DRAM_ATTR app_func_arg_t spi1_arg = { + .host_id = 0, //for SPI1, +}; + +static app_func_arg_t spi2_arg = { + .host_id = 1, //for SPI2, +}; + +static app_func_arg_t spi3_arg = { + .host_id = 2, //for SPI3, +}; + +//for SPI1, we have to disable the cache and interrupts before using the SPI bus +const DRAM_ATTR esp_flash_os_functions_t 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..4b494279b0 --- /dev/null +++ b/components/spi_flash/spi_flash_os_func_noos.c @@ -0,0 +1,48 @@ +// 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_flash.h" + +#include "esp32/rom/ets_sys.h" +#include "esp32/rom/cache.h" +#include "esp_attr.h" + + +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..905518792a 100644 --- a/components/spi_flash/spi_flash_rom_patch.c +++ b/components/spi_flash/spi_flash_rom_patch.c @@ -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)) { 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..bf13845453 --- /dev/null +++ b/components/spi_flash/test/test_esp_flash.c @@ -0,0 +1,495 @@ +#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() +{ + 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 const uint8_t large_const_buffer[16400] = { + 203, // first byte + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + [50 ... 99] = 2, + [1600 ... 2000] = 3, + [8000 ... 9000] = 77, + [15000 ... 16398] = 8, + 43 // last byte +}; + +static void test_write_large_buffer(esp_flash_t *chip, const uint8_t *source, size_t length); +static void write_large_buffer(esp_flash_t *chip, const esp_partition_t *part, const uint8_t *source, size_t length); +static void read_and_check(esp_flash_t *chip, const esp_partition_t *part, const uint8_t *source, size_t length); + +TEST_CASE("SPI flash test reading with all speed/mode permutations", "[esp_flash]") +{ + const int length = sizeof(large_const_buffer); + uint8_t *source_buf = malloc(length); + TEST_ASSERT_NOT_NULL(source_buf); + srand(778); + for (int i = 0; i < length; i++) { + source_buf[i] = rand(); + } + + const esp_partition_t *part = get_test_data_partition(); + TEST_ASSERT(part->size > length + 2 + SPI_FLASH_SEC_SIZE); + +#ifndef SKIP_EXTENDED_CHIP_TEST + //use the lowest speed to write and read to make sure success + setup_new_chip(TEST_SPI_READ_MODE, ESP_FLASH_SPEED_MIN); + write_large_buffer(test_chip, part, source_buf, length); + read_and_check(test_chip, part, source_buf, length); + teardown_test_chip(); + + esp_flash_read_mode_t io_mode = SPI_FLASH_READ_MODE_MIN; + while (io_mode != SPI_FLASH_READ_MODE_MAX) { + esp_flash_speed_t speed = ESP_FLASH_SPEED_MIN; + while (speed != ESP_FLASH_SPEED_MAX) { + ESP_LOGI(TAG, "test flash io mode: %d, speed: %d", io_mode, speed); + setup_new_chip(io_mode, speed); + read_and_check(test_chip, part, source_buf, length); + teardown_test_chip(); + speed++; + } + io_mode++; + } +#endif + + //test main flash BTW + write_large_buffer(NULL, part, source_buf, length); + read_and_check(NULL, part, source_buf, length); + + free(source_buf); +} + +TEST_CASE("Test esp_flash_write large const buffer", "[esp_flash]") +{ + //buffer in flash + test_write_large_buffer(NULL, large_const_buffer, sizeof(large_const_buffer)); +#ifndef SKIP_EXTENDED_CHIP_TEST + setup_new_chip(TEST_SPI_READ_MODE, TEST_SPI_SPEED); + test_write_large_buffer(test_chip, large_const_buffer, sizeof(large_const_buffer)); + teardown_test_chip(); +#endif +} + +#ifndef SKIP_EXTENDED_CHIP_TEST +TEST_CASE("Test esp_flash_write large RAM buffer", "[esp_flash]") +{ + // buffer in RAM + uint8_t *source_buf = malloc(sizeof(large_const_buffer)); + TEST_ASSERT_NOT_NULL(source_buf); + memcpy(source_buf, large_const_buffer, sizeof(large_const_buffer)); + + setup_new_chip(TEST_SPI_READ_MODE, TEST_SPI_SPEED); + test_write_large_buffer(test_chip, source_buf, sizeof(large_const_buffer)); + teardown_test_chip(); + + free(source_buf); +} +#endif + +static void write_large_buffer(esp_flash_t *chip, const esp_partition_t *part, const uint8_t *source, size_t length) +{ + printf("Writing chip %p, %d bytes from source %p\n", chip, length, source); + + ESP_ERROR_CHECK( esp_flash_erase_region(chip, part->address, (length + SPI_FLASH_SEC_SIZE) & ~(SPI_FLASH_SEC_SIZE - 1)) ); + + // note writing to unaligned address + ESP_ERROR_CHECK( esp_flash_write(chip, source, part->address + 1, length) ); +} + +static void read_and_check(esp_flash_t *chip, const esp_partition_t *part, const uint8_t *source, size_t length) +{ + printf("Checking chip %p, %d bytes\n", chip, length); + uint8_t *buf = malloc(length); + TEST_ASSERT_NOT_NULL(buf); + ESP_ERROR_CHECK( esp_flash_read(chip, buf, part->address + 1, length) ); + TEST_ASSERT_EQUAL_HEX8_ARRAY(source, buf, length); + free(buf); + + // check nothing was written at beginning or end + uint8_t ends[8]; + + ESP_ERROR_CHECK( esp_flash_read(chip, ends, part->address, sizeof(ends)) ); + TEST_ASSERT_EQUAL_HEX8(0xFF, ends[0]); + TEST_ASSERT_EQUAL_HEX8(source[0], ends[1]); + + ESP_ERROR_CHECK( esp_flash_read(chip, ends, part->address + length, sizeof(ends)) ); + + TEST_ASSERT_EQUAL_HEX8(source[length - 1], ends[0]); + TEST_ASSERT_EQUAL_HEX8(0xFF, ends[1]); + TEST_ASSERT_EQUAL_HEX8(0xFF, ends[2]); + TEST_ASSERT_EQUAL_HEX8(0xFF, ends[3]); +} + +static void test_write_large_buffer(esp_flash_t *chip, const uint8_t *source, size_t length) +{ + ESP_LOGI(TAG, "Testing chip %p...", chip); + const esp_partition_t *part = get_test_data_partition(); + TEST_ASSERT(part->size > length + 2 + SPI_FLASH_SEC_SIZE); + + write_large_buffer(chip, part, source, length); + read_and_check(chip, part, source, length); +} + diff --git a/components/spi_flash/test/test_large_flash_writes.c b/components/spi_flash/test/test_large_flash_writes.c index f530ca3788..11824cd11b 100644 --- a/components/spi_flash/test/test_large_flash_writes.c +++ b/components/spi_flash/test/test_large_flash_writes.c @@ -42,13 +42,13 @@ static const uint8_t large_const_buffer[16400] = { static void test_write_large_buffer(const uint8_t *source, size_t length); -TEST_CASE("Test spi_flash_write large const buffer", "[spi_flash]") +TEST_CASE("Test spi_flash_write large const buffer", "[spi_flash][esp_flash]") { // buffer in flash test_write_large_buffer(large_const_buffer, sizeof(large_const_buffer)); } -TEST_CASE("Test spi_flash_write large RAM buffer", "[spi_flash]") +TEST_CASE("Test spi_flash_write large RAM buffer", "[spi_flash][esp_flash]") { // buffer in RAM uint8_t *source_buf = malloc(sizeof(large_const_buffer)); diff --git a/components/spi_flash/test/test_mmap.c b/components/spi_flash/test/test_mmap.c index 4cdb775943..fe14a8be05 100644 --- a/components/spi_flash/test/test_mmap.c +++ b/components/spi_flash/test/test_mmap.c @@ -200,7 +200,7 @@ TEST_CASE("Can mmap unordered pages into contiguous memory", "[spi_flash]") pages[i]=startpage+(nopages-1)-i; printf("Offset %x page %d\n", i*0x10000, pages[i]); } - + printf("Attempting mapping of unordered pages to contiguous memory area\n"); spi_flash_mmap_handle_t handle1; @@ -277,7 +277,7 @@ TEST_CASE("flash_mmap invalidates just-written data", "[spi_flash]") TEST_CASE("flash_mmap can mmap after get enough free MMU pages", "[spi_flash]") { - //this test case should make flash size >= 4MB, because max size of Dcache can mapped is 4MB + //this test case should make flash size >= 4MB, because max size of Dcache can mapped is 4MB setup_mmap_tests(); printf("Mapping %x (+%x)\n", start, end - start); diff --git a/components/spi_flash/test/test_out_of_bounds_write.c b/components/spi_flash/test/test_out_of_bounds_write.c index 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..e6bb6bc03d 100644 --- a/components/spi_flash/test/test_read_write.c +++ b/components/spi_flash/test/test_read_write.c @@ -79,7 +79,7 @@ static void IRAM_ATTR test_read(int src_off, int dst_off, int len) spi_flash_disable_interrupts_caches_and_other_cpu(); esp_rom_spiflash_result_t rc = esp_rom_spiflash_write(start, src_buf, sizeof(src_buf)); spi_flash_enable_interrupts_caches_and_other_cpu(); - TEST_ASSERT_EQUAL_INT(rc, ESP_ROM_SPIFLASH_RESULT_OK); + TEST_ASSERT_EQUAL_HEX(rc, ESP_ROM_SPIFLASH_RESULT_OK); memset(dst_buf, 0x55, sizeof(dst_buf)); memset(dst_gold, 0x55, sizeof(dst_gold)); fill(dst_gold + dst_off, src_off, len); @@ -87,7 +87,7 @@ static void IRAM_ATTR test_read(int src_off, int dst_off, int len) TEST_ASSERT_EQUAL_INT(cmp_or_dump(dst_buf, dst_gold, sizeof(dst_buf)), 0); } -TEST_CASE("Test spi_flash_read", "[spi_flash]") +TEST_CASE("Test spi_flash_read", "[spi_flash][esp_flash]") { setup_tests(); #if CONFIG_SPI_FLASH_MINIMAL_TEST @@ -158,14 +158,16 @@ static void IRAM_ATTR test_write(int dst_off, int src_off, int len) fill(dst_gold + dst_off, src_off, len); } ESP_ERROR_CHECK(spi_flash_write(start + dst_off, src_buf + src_off, len)); + spi_flash_disable_interrupts_caches_and_other_cpu(); esp_rom_spiflash_result_t rc = esp_rom_spiflash_read(start, dst_buf, sizeof(dst_buf)); spi_flash_enable_interrupts_caches_and_other_cpu(); - TEST_ASSERT_EQUAL_INT(rc, ESP_ROM_SPIFLASH_RESULT_OK); + TEST_ASSERT_EQUAL_HEX(rc, ESP_ROM_SPIFLASH_RESULT_OK); + TEST_ASSERT_EQUAL_INT(cmp_or_dump(dst_buf, dst_gold, sizeof(dst_buf)), 0); } -TEST_CASE("Test spi_flash_write", "[spi_flash]") +TEST_CASE("Test spi_flash_write", "[spi_flash][esp_flash]") { setup_tests(); #if CONFIG_SPI_FLASH_MINIMAL_TEST diff --git a/components/spi_flash/test/test_spi_flash.c b/components/spi_flash/test/test_spi_flash.c index bd135a0c7f..f5143b21c1 100644 --- a/components/spi_flash/test/test_spi_flash.c +++ b/components/spi_flash/test/test_spi_flash.c @@ -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_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/tcp_transport/CMakeLists.txt b/components/tcp_transport/CMakeLists.txt index 9c2ef846b8..9d5028a1b6 100644 --- a/components/tcp_transport/CMakeLists.txt +++ b/components/tcp_transport/CMakeLists.txt @@ -1,12 +1,9 @@ -set(COMPONENT_SRCS "transport.c" - "transport_ssl.c" - "transport_tcp.c" - "transport_ws.c" - "transport_utils.c" - "transport_strcasestr.c") - -set(COMPONENT_ADD_INCLUDEDIRS "include") - -set(COMPONENT_REQUIRES lwip esp-tls) - -register_component() +idf_component_register(SRCS "transport.c" + "transport_ssl.c" + "transport_tcp.c" + "transport_ws.c" + "transport_utils.c" + "transport_strcasestr.c" + INCLUDE_DIRS "include" + PRIVATE_INCLUDE_DIRS "private_include" + REQUIRES lwip esp-tls) diff --git a/components/tcp_transport/component.mk b/components/tcp_transport/component.mk index 308f64f0ea..c81b547721 100644 --- a/components/tcp_transport/component.mk +++ b/components/tcp_transport/component.mk @@ -1,4 +1,2 @@ -# -# Component Makefile -# -# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) +COMPONENT_ADD_INCLUDEDIRS := include +COMPONENT_PRIV_INCLUDEDIRS := private_include \ No newline at end of file diff --git a/components/tcp_transport/include/esp_transport.h b/components/tcp_transport/include/esp_transport.h index e163a010cd..9dd7ff4495 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,6 +33,8 @@ typedef int (*poll_func)(esp_transport_handle_t t, int timeout_ms); typedef int (*connect_async_func)(esp_transport_handle_t t, const char *host, int port, int timeout_ms); typedef esp_transport_handle_t (*payload_transfer_func)(esp_transport_handle_t); +typedef struct esp_tls_last_error* esp_tls_error_handle_t; + /** * @brief Create transport list * @@ -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..0f83c1d6e4 100644 --- a/components/tcp_transport/include/esp_transport_ssl.h +++ b/components/tcp_transport/include/esp_transport_ssl.h @@ -69,6 +69,15 @@ 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 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); + #ifdef __cplusplus } #endif 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..b48acf908d 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) { /* @@ -62,34 +72,37 @@ static esp_transport_handle_t esp_transport_get_default_parent(esp_transport_han esp_transport_list_handle_t esp_transport_list_init() { - esp_transport_list_handle_t list = calloc(1, sizeof(struct esp_transport_list_t)); - ESP_TRANSPORT_MEM_CHECK(TAG, list, return NULL); - STAILQ_INIT(list); - return list; + esp_transport_list_handle_t transport = calloc(1, sizeof(esp_transport_internal_t)); + ESP_TRANSPORT_MEM_CHECK(TAG, transport, return NULL); + STAILQ_INIT(&transport->list); + transport->error_handle = calloc(1, sizeof(esp_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,26 +110,24 @@ 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; } @@ -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..1651a2f87f 100644 --- a/components/tcp_transport/transport_ssl.c +++ b/components/tcp_transport/transport_ssl.c @@ -24,6 +24,7 @@ #include "esp_transport.h" #include "esp_transport_ssl.h" #include "esp_transport_utils.h" +#include "esp_transport_ssl_internal.h" static const char *TAG = "TRANS_SSL"; @@ -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; @@ -190,6 +196,14 @@ void esp_transport_ssl_set_client_key_data(esp_transport_handle_t t, const char } } +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() { esp_transport_handle_t t = esp_transport_init(); diff --git a/components/tcp_transport/transport_ws.c b/components/tcp_transport/transport_ws.c index e31149e178..12aaa3d232 100644 --- a/components/tcp_transport/transport_ws.c +++ b/components/tcp_transport/transport_ws.c @@ -25,12 +25,13 @@ static const char *TAG = "TRANSPORT_WS"; #define WS_MASK 0x80 #define WS_SIZE16 126 #define WS_SIZE64 127 -#define MAX_WEBSOCKET_HEADER_SIZE 10 +#define MAX_WEBSOCKET_HEADER_SIZE 16 #define WS_RESPONSE_OK 101 typedef struct { char *path; char *buffer; + char *sub_protocol; esp_transport_handle_t parent; } transport_ws_t; @@ -80,7 +81,7 @@ static int ws_connect(esp_transport_handle_t t, const char *host, int port, int { transport_ws_t *ws = esp_transport_get_context_data(t); if (esp_transport_connect(ws->parent, host, port, timeout_ms) < 0) { - ESP_LOGE(TAG, "Error connect to the server"); + ESP_LOGE(TAG, "Error connecting to host %s:%d", host, port); return -1; } @@ -98,12 +99,15 @@ static int ws_connect(esp_transport_handle_t t, const char *host, int port, int "Host: %s:%d\r\n" "Upgrade: websocket\r\n" "Sec-WebSocket-Version: 13\r\n" - "Sec-WebSocket-Protocol: mqtt\r\n" "Sec-WebSocket-Key: %s\r\n" - "User-Agent: ESP32 Websocket Client\r\n\r\n", + "User-Agent: ESP32 Websocket Client\r\n", ws->path, host, port, client_key); + if (ws->sub_protocol) { + len += snprintf(ws->buffer + len, DEFAULT_WS_BUFFER - len, "Sec-WebSocket-Protocol: %s\r\n", ws->sub_protocol); + } + len += snprintf(ws->buffer + len, DEFAULT_WS_BUFFER - len, "\r\n"); if (len <= 0 || len >= DEFAULT_WS_BUFFER) { ESP_LOGE(TAG, "Error in request generation, %d", len); return -1; @@ -152,40 +156,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 +321,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 +331,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 +340,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 +359,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..83a75d9de1 100644 --- a/components/tcpip_adapter/event_handlers.c +++ b/components/tcpip_adapter/event_handlers.c @@ -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) diff --git a/components/tcpip_adapter/include/tcpip_adapter.h b/components/tcpip_adapter/include/tcpip_adapter.h index 033dfd0e76..4c0a4af4fd 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 @@ -739,6 +740,14 @@ esp_err_t tcpip_adapter_set_default_wifi_handlers(); */ esp_err_t tcpip_adapter_clear_default_wifi_handlers(); +/** + * @brief Search nefit index through netif interface + * @param[in] tcpip_if Interface to search for netif index + * @return + * - netif_index on success + * - -1 if an invalid parameter is supplied + */ +int tcpip_adapter_get_netif_index(tcpip_adapter_if_t tcpip_if); #ifdef __cplusplus } diff --git a/components/tcpip_adapter/tcpip_adapter_lwip.c b/components/tcpip_adapter/tcpip_adapter_lwip.c index c8570a832c..237b082a34 100644 --- a/components/tcpip_adapter/tcpip_adapter_lwip.c +++ b/components/tcpip_adapter/tcpip_adapter_lwip.c @@ -29,6 +29,7 @@ #include "lwip/netif.h" #if LWIP_DNS /* don't build if not configured for use in lwipopts.h */ #include "lwip/dns.h" +#include "lwip/netif.h" #endif #include "netif/wlanif.h" #include "netif/ethernetif.h" @@ -49,19 +50,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 +70,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 +92,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 +130,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 +158,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 +193,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 +208,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 +225,34 @@ 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); + esp_netif_init_fn[TCPIP_ADAPTER_IF_ETH] = ethernetif_init; + return tcpip_adapter_start(TCPIP_ADAPTER_IF_ETH, mac, ip_info, args); } 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 +294,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 +319,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 +352,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 +471,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 +531,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 +686,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 +694,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 +723,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 +733,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 +756,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 +782,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 +800,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 +845,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 +880,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 +902,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 +916,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 +975,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 +996,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 +1070,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,11 +1104,11 @@ 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); } @@ -1193,9 +1201,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 +1236,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 +1259,12 @@ bool tcpip_adapter_is_netif_up(tcpip_adapter_if_t tcpip_if) } } +int tcpip_adapter_get_netif_index(tcpip_adapter_if_t tcpip_if) +{ + if (tcpip_if >= TCPIP_ADAPTER_IF_MAX || esp_netif[tcpip_if] == NULL) { + return -1; + } + return netif_get_index(esp_netif[tcpip_if]); +} + #endif /* CONFIG_TCPIP_LWIP */ diff --git a/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/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/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..20bc9770e7 100644 --- a/components/vfs/README.rst +++ b/components/vfs/README.rst @@ -4,18 +4,17 @@ Virtual filesystem component Overview -------- -Virtual filesystem (VFS) component provides a unified interface for drivers which can perform operations on file-like objects. This can be a real filesystems (FAT, SPIFFS, etc.), or device drivers which exposes file-like interface. +Virtual filesystem (VFS) component provides a unified interface for drivers which can perform operations on file-like objects. These can be real filesystems (FAT, SPIFFS, etc.) or device drivers which provide a file-like interface. -This component allows C library functions, such as fopen and fprintf, to work with FS drivers. At high level, each FS driver is associated with some path prefix. When one of C library functions needs to open a file, VFS component searches for the FS driver associated with the file's path, and forwards the call to that driver. VFS also forwards read, write, and other calls for the given file to the same FS driver. +This component allows C library functions, such as fopen and fprintf, to work with FS drivers. At a high level, each FS driver is associated with some path prefix. When one of C library functions needs to open a file, the VFS component searches for the FS driver associated with the file path and forwards the call to that driver. VFS also forwards read, write, and other calls for the given file to the same FS driver. + +For example, one can register a FAT filesystem driver with the ``/fat`` prefix and call ``fopen("/fat/file.txt", "w")``. The VFS component will then call the function ``open`` of the FAT driver and pass the argument ``/file.txt`` to it together with appropriate mode flags. All subsequent calls to C library functions for the returned ``FILE*`` stream will also be forwarded to the FAT driver. -For example, one can register a FAT filesystem driver with ``/fat`` prefix, and call ``fopen("/fat/file.txt", "w")``. VFS component will then call ``open`` function of FAT driver and pass ``/file.txt`` argument to it (and appropriate mode flags). All subsequent calls to C library functions for the returned ``FILE*`` stream will also be forwarded to the FAT driver. FS registration --------------- - - -To register an FS driver, application needs to define in instance of :cpp:type:`esp_vfs_t` structure and populate it with function pointers to FS APIs: +To register an FS driver, an application needs to define an instance of the :cpp:type:`esp_vfs_t` structure and populate it with function pointers to FS APIs: .. highlight:: c @@ -32,9 +31,9 @@ To register an FS driver, application needs to define in instance of :cpp:type:` ESP_ERROR_CHECK(esp_vfs_register("/data", &myfs, NULL)); -Depending on the way FS driver declares its APIs, either ``read``, ``write``, etc., or ``read_p``, ``write_p``, etc. should be used. +Depending on the way how the FS driver declares its API functions, either ``read``, ``write``, etc., or ``read_p``, ``write_p``, etc., should be used. -Case 1: API functions are declared without an extra context pointer (FS driver is a singleton):: +Case 1: API functions are declared without an extra context pointer (the FS driver is a singleton):: ssize_t myfs_write(int fd, const void * data, size_t size); @@ -46,7 +45,7 @@ Case 1: API functions are declared without an extra context pointer (FS driver i // When registering FS, context pointer (third argument) is NULL: ESP_ERROR_CHECK(esp_vfs_register("/data", &myfs, NULL)); -Case 2: API functions are declared with an extra context pointer (FS driver supports multiple instances):: +Case 2: API functions are declared with an extra context pointer (the FS driver supports multiple instances):: ssize_t myfs_write(myfs_t* fs, int fd, const void * data, size_t size); @@ -68,8 +67,8 @@ Synchronous input/output multiplexing ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If you want to use synchronous input/output multiplexing by :cpp:func:`select` -then you need to register the VFS with :cpp:func:`start_select` and -:cpp:func:`end_select` functions similarly to the following example: +then you need to register VFS with the functions :cpp:func:`start_select` and +:cpp:func:`end_select` similar to the following example: .. highlight:: c @@ -85,22 +84,27 @@ detection of read/write/error conditions on file descriptors belonging to the given VFS. :cpp:func:`end_select` is called to stop/deinitialize/free the environment which was setup by :cpp:func:`start_select`. Please refer to the reference implementation for the UART peripheral in -:component_file:`vfs/vfs_uart.c` and most particularly to functions -:cpp:func:`esp_vfs_dev_uart_register`, :cpp:func:`uart_start_select` and +:component_file:`vfs/vfs_uart.c` and most particularly to the functions +:cpp:func:`esp_vfs_dev_uart_register`, :cpp:func:`uart_start_select`, and :cpp:func:`uart_end_select`. -Examples demonstrating the use of :cpp:func:`select` with VFS file descriptors -are the :example:`peripherals/uart_select` and the :example:`system/select` -examples. +Please check the following examples that demonstrate the use of :cpp:func:`select` with VFS file descriptors: +- :example:`peripherals/uart_select` +- :example:`system/select` +<<<<<<< HEAD If :cpp:func:`select` is used for socket file descriptors only then one can enable the :envvar:`CONFIG_LWIP_USE_ONLY_LWIP_SELECT` option which can reduce the code +======= +If you use :cpp:func:`select` for socket file descriptors, you can enable the :envvar:`CONFIG_LWIP_USE_ONLY_LWIP_SELECT` option to reduce the code +>>>>>>> afc2fdf27... Review all the files in the esp-idf's api_ref/storage directory size and improve performance. + Paths ----- -Each registered FS has a path prefix associated with it. This prefix may be considered a "mount point" of this partition. +Each registered FS has a path prefix associated with it. This prefix can be considered as a "mount point" of this partition. In case when mount points are nested, the mount point with the longest matching path prefix is used when opening the file. For instance, suppose that the following filesystems are registered in VFS: @@ -111,45 +115,49 @@ Then: - FS 1 will be used when opening a file called ``/data/log.txt`` - FS 2 will be used when opening a file called ``/data/static/index.html`` -- Even if ``/index.html"`` doesn't exist in FS 2, FS 1 will *not* be searched for ``/static/index.html``. +- Even if ``/index.html"`` does not exist in FS 2, FS 1 will *not* be searched for ``/static/index.html``. -As a general rule, mount point names must start with the path separator (``/``) and must contain at least one character after path separator. However an empty mount point name is also supported, and may be used in cases when application needs to provide "fallback" filesystem, or override VFS functionality altogether. Such filesystem will be used if no prefix matches the path given. +As a general rule, mount point names must start with the path separator (``/``) and must contain at least one character after path separator. However, an empty mount point name is also supported and might be used in cases when an application needs to provide a "fallback" filesystem or to override VFS functionality altogether. Such filesystem will be used if no prefix matches the path given. -VFS does not handle dots (``.``) in path names in any special way. VFS does not treat ``..`` as a reference to the parent directory. I.e. in the above example, using a path ``/data/static/../log.txt`` will not result in a call to FS 1 to open ``/log.txt``. Specific FS drivers (such as FATFS) may handle dots in file names differently. +VFS does not handle dots (``.``) in path names in any special way. VFS does not treat ``..`` as a reference to the parent directory. In the above example, using a path ``/data/static/../log.txt`` will not result in a call to FS 1 to open ``/log.txt``. Specific FS drivers (such as FATFS) might handle dots in file names differently. -When opening files, FS driver will only be given relative path to files. For example: +When opening files, the FS driver receives only relative paths to files. For example: -- ``myfs`` driver is registered with ``/data`` as path prefix -- and application calls ``fopen("/data/config.json", ...)`` -- then VFS component will call ``myfs_open("/config.json", ...)``. -- ``myfs`` driver will open ``/config.json`` file +1. The ``myfs`` driver is registered with ``/data`` as a path prefix. +2. The application calls ``fopen("/data/config.json", ...)``. +3. The VFS component calls ``myfs_open("/config.json", ...)``. +4. The ``myfs`` driver opens the ``/config.json`` file. + +VFS does not impose any limit on total file path length, but it does limit the FS path prefix to ``ESP_VFS_PATH_MAX`` characters. Individual FS drivers may have their own filename length limitations. -VFS doesn't impose a limit on total file path length, but it does limit FS path prefix to ``ESP_VFS_PATH_MAX`` characters. Individual FS drivers may have their own filename length limitations. File descriptors ---------------- -File descriptors are small positive integers from ``0`` to ``FD_SETSIZE - 1`` where ``FD_SETSIZE`` is defined in newlib's ``sys/types.h``. The largest file descriptors (configured by ``CONFIG_LWIP_MAX_SOCKETS``) are reserved for sockets. The VFS component contains a lookup-table called ``s_fd_table`` for mapping global file descriptors to VFS driver indexes registered in the ``s_vfs`` array. +File descriptors are small positive integers from ``0`` to ``FD_SETSIZE - 1``, where ``FD_SETSIZE`` is defined in newlib's ``sys/types.h``. The largest file descriptors (configured by ``CONFIG_LWIP_MAX_SOCKETS``) are reserved for sockets. The VFS component contains a lookup-table called ``s_fd_table`` for mapping global file descriptors to VFS driver indexes registered in the ``s_vfs`` array. + Standard IO streams (stdin, stdout, stderr) ------------------------------------------- -If "UART for console output" menuconfig option is not set to "None", then ``stdin``, ``stdout``, and ``stderr`` are configured to read from, and write to, a UART. It is possible to use UART0 or UART1 for standard IO. By default, UART0 is used, with 115200 baud rate, TX pin is GPIO1 and RX pin is GPIO3. These parameters can be changed in menuconfig. +If the menuconfig option ``UART for console output`` is not set to ``None``, then ``stdin``, ``stdout``, and ``stderr`` are configured to read from, and write to, a UART. It is possible to use UART0 or UART1 for standard IO. By default, UART0 is used with 115200 baud rate; TX pin is GPIO1; RX pin is GPIO3. These parameters can be changed in menuconfig. Writing to ``stdout`` or ``stderr`` will send characters to the UART transmit FIFO. Reading from ``stdin`` will retrieve characters from the UART receive FIFO. -By default, VFS uses simple functions for reading from and writing to UART. Writes busy-wait until all data is put into UART FIFO, and reads are non-blocking, returning only the data present in the FIFO. Because of this non-blocking read behavior, higher level C library calls, such as ``fscanf("%d\n", &var);`` may not have desired results. +By default, VFS uses simple functions for reading from and writing to UART. Writes busy-wait until all data is put into UART FIFO, and reads are non-blocking, returning only the data present in the FIFO. Due to this non-blocking read behavior, higher level C library calls, such as ``fscanf("%d\n", &var);``, might not have desired results. -Applications which use UART driver may instruct VFS to use the driver's interrupt driven, blocking read and write functions instead. This can be done using a call to ``esp_vfs_dev_uart_use_driver`` function. It is also possible to revert to the basic non-blocking functions using a call to ``esp_vfs_dev_uart_use_nonblocking``. +Applications which use the UART driver can instruct VFS to use the driver's interrupt driven, blocking read and write functions instead. This can be done using a call to the ``esp_vfs_dev_uart_use_driver`` function. It is also possible to revert to the basic non-blocking functions using a call to ``esp_vfs_dev_uart_use_nonblocking``. -VFS also provides optional newline conversion feature for input and output. Internally, most applications send and receive lines terminated by LF (''\n'') character. Different terminal programs may require different line termination, such as CR or CRLF. Applications can configure this separately for input and output either via menuconfig, or by calls to ``esp_vfs_dev_uart_set_rx_line_endings`` and ``esp_vfs_dev_uart_set_tx_line_endings`` functions. +VFS also provides an optional newline conversion feature for input and output. Internally, most applications send and receive lines terminated by the LF (''\n'') character. Different terminal programs may require different line termination, such as CR or CRLF. Applications can configure this separately for input and output either via menuconfig, or by calls to the functions ``esp_vfs_dev_uart_set_rx_line_endings`` and ``esp_vfs_dev_uart_set_tx_line_endings``. Standard streams and FreeRTOS tasks ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -``FILE`` objects for ``stdin``, ``stdout``, and ``stderr`` are shared between all FreeRTOS tasks, but the pointers to these objects are are stored in per-task ``struct _reent``. The following code: +``FILE`` objects for ``stdin``, ``stdout``, and ``stderr`` are shared between all FreeRTOS tasks, but the pointers to these objects are stored in per-task ``struct _reent``. + +The following code is transferred to ``fprintf(__getreent()->_stderr, "42\n");`` by the preprocessor: .. highlight:: c @@ -157,14 +165,11 @@ Standard streams and FreeRTOS tasks fprintf(stderr, "42\n"); -actually is translated to to this (by the preprocessor):: - fprintf(__getreent()->_stderr, "42\n"); - -where the ``__getreent()`` function returns a per-task pointer to ``struct _reent`` (:component_file:`newlib/include/sys/reent.h#L370-L417`). This structure is allocated on the TCB of each task. When a task is initialized, ``_stdin``, ``_stdout`` and ``_stderr`` members of ``struct _reent`` are set to the values of ``_stdin``, ``_stdout`` and ``_stderr`` of ``_GLOBAL_REENT`` (i.e. the structure which is used before FreeRTOS is started). +The ``__getreent()`` function returns a per-task pointer to ``struct _reent`` (:component_file:`newlib/include/sys/reent.h#L370-L417`). This structure is allocated on the TCB of each task. When a task is initialized, ``_stdin``, ``_stdout``, and ``_stderr`` members of ``struct _reent`` are set to the values of ``_stdin``, ``_stdout``, and ``_stderr`` of ``_GLOBAL_REENT`` (i.e., the structure which is used before FreeRTOS is started). Such a design has the following consequences: -- It is possible to set ``stdin``, ``stdout``, and ``stderr`` for any given task without affecting other tasks, e.g. by doing ``stdin = fopen("/dev/uart/1", "r")``. -- Closing default ``stdin``, ``stdout``, or ``stderr`` using ``fclose`` will close the ``FILE`` stream object — this will affect all other tasks. +- It is possible to set ``stdin``, ``stdout``, and ``stderr`` for any given task without affecting other tasks, e.g., by doing ``stdin = fopen("/dev/uart/1", "r")``. +- Closing default ``stdin``, ``stdout``, or ``stderr`` using ``fclose`` will close the ``FILE`` stream object, which will affect all other tasks. - To change the default ``stdin``, ``stdout``, ``stderr`` streams for new tasks, modify ``_GLOBAL_REENT->_stdin`` (``_stdout``, ``_stderr``) before creating the task. diff --git a/components/vfs/include/esp_vfs.h b/components/vfs/include/esp_vfs.h index 1d8abd8b35..4d9396c1c4 100644 --- a/components/vfs/include/esp_vfs.h +++ b/components/vfs/include/esp_vfs.h @@ -112,6 +112,14 @@ typedef struct ssize_t (*read_p)(void* ctx, int fd, void * dst, size_t size); ssize_t (*read)(int fd, void * dst, size_t size); }; + union { + ssize_t (*pread_p)(void *ctx, int fd, void * dst, size_t size, off_t offset); + ssize_t (*pread)(int fd, void * dst, size_t size, off_t offset); + }; + union { + ssize_t (*pwrite_p)(void *ctx, int fd, const void *src, size_t size, off_t offset); + ssize_t (*pwrite)(int fd, const void *src, size_t size, off_t offset); + }; union { int (*open_p)(void* ctx, const char * path, int flags, int mode); int (*open)(const char * path, int flags, int mode); @@ -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,7 +233,7 @@ typedef struct int (*tcsendbreak_p)(void *ctx, int fd, int duration); int (*tcsendbreak)(int fd, int duration); }; -#endif // CONFIG_SUPPORT_TERMIOS +#endif // CONFIG_VFS_SUPPORT_TERMIOS /** start_select is called for setting up synchronous I/O multiplexing of the desired file descriptors in the given VFS */ esp_err_t (*start_select)(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, esp_vfs_select_sem_t sem); @@ -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/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_uart.c b/components/vfs/test/test_vfs_uart.c index d46c7cb757..5c3d3f1d60 100644 --- a/components/vfs/test/test_vfs_uart.c +++ b/components/vfs/test/test_vfs_uart.c @@ -202,7 +202,7 @@ TEST_CASE("can write to UART while another task is reading", "[vfs]") vSemaphoreDelete(write_arg.done); } -#ifdef CONFIG_SUPPORT_TERMIOS +#ifdef CONFIG_VFS_SUPPORT_TERMIOS TEST_CASE("Can use termios for UART", "[vfs]") { uart_config_t uart_config = { @@ -328,4 +328,4 @@ TEST_CASE("Can use termios for UART", "[vfs]") close(uart_fd); uart_driver_delete(UART_NUM_1); } -#endif // CONFIG_SUPPORT_TERMIOS +#endif // CONFIG_VFS_SUPPORT_TERMIOS diff --git a/components/vfs/vfs.c b/components/vfs/vfs.c index 19f081c5a3..0fc5aead31 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) { @@ -1032,7 +1059,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 +1157,7 @@ int tcsendbreak(int fd, int duration) CHECK_AND_CALL(ret, r, vfs, tcsendbreak, local_fd, duration); return ret; } -#endif // CONFIG_SUPPORT_TERMIOS +#endif // CONFIG_VFS_SUPPORT_TERMIOS int esp_vfs_utime(const char *path, const struct utimbuf *times) { diff --git a/components/vfs/vfs_uart.c b/components/vfs/vfs_uart.c index 36fade118a..2f6a64d23c 100644 --- a/components/vfs/vfs_uart.c +++ b/components/vfs/vfs_uart.c @@ -475,7 +475,7 @@ static void uart_end_select() _lock_release(&s_one_select_lock); } -#ifdef CONFIG_SUPPORT_TERMIOS +#ifdef CONFIG_VFS_SUPPORT_TERMIOS static int uart_tcsetattr(int fd, int optional_actions, const struct termios *p) { if (fd < 0 || fd >= UART_NUM) { @@ -925,7 +925,7 @@ static int uart_tcflush(int fd, int select) return 0; } -#endif // CONFIG_SUPPORT_TERMIOS +#endif // CONFIG_VFS_SUPPORT_TERMIOS void esp_vfs_dev_uart_register() { @@ -941,12 +941,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/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/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..2b7e14924f 100644 --- a/components/wpa_supplicant/CMakeLists.txt +++ b/components/wpa_supplicant/CMakeLists.txt @@ -1,88 +1,93 @@ -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_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/aes_wrap.h b/components/wpa_supplicant/include/crypto/aes_wrap.h index 933031e4ba..e6912054f0 100644 --- a/components/wpa_supplicant/include/crypto/aes_wrap.h +++ b/components/wpa_supplicant/include/crypto/aes_wrap.h @@ -44,10 +44,4 @@ int __must_check aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len); int __must_check aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len); -int __must_check fast_aes_wrap(const uint8_t *kek, int n, const uint8_t *plain, uint8_t *cipher); -int __must_check fast_aes_unwrap(const uint8_t *kek, int n, const uint8_t *cipher, uint8_t *plain); -int __must_check fast_aes_128_cbc_encrypt(const uint8_t *key, const uint8_t *iv, uint8_t *data, - size_t data_len); -int __must_check fast_aes_128_cbc_decrypt(const uint8_t *key, const uint8_t *iv, uint8_t *data, - size_t data_len); #endif /* AES_WRAP_H */ diff --git a/components/wpa_supplicant/include/crypto/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/crypto/crypto.h b/components/wpa_supplicant/include/crypto/crypto.h index f6b7b2f2c4..9c57c50db1 100644 --- a/components/wpa_supplicant/include/crypto/crypto.h +++ b/components/wpa_supplicant/include/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/include/crypto/dh_group5.h b/components/wpa_supplicant/include/crypto/dh_group5.h index f92c1115d5..822d47a6e3 100644 --- a/components/wpa_supplicant/include/crypto/dh_group5.h +++ b/components/wpa_supplicant/include/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/include/crypto/sha256.h b/components/wpa_supplicant/include/crypto/sha256.h index 8025a29de3..dc597f09b5 100644 --- a/components/wpa_supplicant/include/crypto/sha256.h +++ b/components/wpa_supplicant/include/crypto/sha256.h @@ -24,10 +24,4 @@ void hmac_sha256(const u8 *key, size_t key_len, const u8 *data, void sha256_prf(const u8 *key, size_t key_len, const char *label, const u8 *data, size_t data_len, u8 *buf, size_t buf_len); -void fast_hmac_sha256_vector(const uint8_t *key, size_t key_len, size_t num_elem, - const uint8_t *addr[], const size_t *len, uint8_t *mac); -void fast_hmac_sha256(const uint8_t *key, size_t key_len, const uint8_t *data, - size_t data_len, uint8_t *mac); -void fast_sha256_prf(const uint8_t *key, size_t key_len, const char *label, - const uint8_t *data, size_t data_len, uint8_t *buf, size_t buf_len); #endif /* SHA256_H */ diff --git a/components/wpa_supplicant/include/crypto/wepkey.h b/components/wpa_supplicant/include/crypto/wepkey.h new file mode 100644 index 0000000000..32a8cf9b37 --- /dev/null +++ b/components/wpa_supplicant/include/crypto/wepkey.h @@ -0,0 +1,10 @@ +#ifndef WEPKEY_H +#define WEPKEY_H + +#define WEPKEY_64_BYTES 5 +#define WePKEY_128_BYTES 13 + +unsigned int wepkey_64(uint8_t *out, unsigned int size, const char *in, int n); +unsigned int wepkey_128(uint8_t *out, unsigned int size, const char *in, int n); + +#endif /* WEPKEY_H */ \ No newline at end of file diff --git a/components/wpa_supplicant/include/esp_supplicant/esp_wpa.h b/components/wpa_supplicant/include/esp_supplicant/esp_wpa.h new file mode 100644 index 0000000000..33f0fe57a4 --- /dev/null +++ b/components/wpa_supplicant/include/esp_supplicant/esp_wpa.h @@ -0,0 +1,66 @@ +// 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 + * @{ + */ + + +/** + * @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..5b459a7865 --- /dev/null +++ b/components/wpa_supplicant/src/ap/ieee802_1x.c @@ -0,0 +1,78 @@ +/* + * 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 "crypto/random.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..24c5670090 100644 --- a/components/wpa_supplicant/src/crypto/aes-cbc.c +++ b/components/wpa_supplicant/src/crypto/aes-cbc.c @@ -12,13 +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 "utils/common.h" #include "crypto/aes.h" #include "crypto/aes_wrap.h" +#ifdef USE_MBEDTLS_CRYPTO +#include "mbedtls/aes.h" + /** * aes_128_cbc_encrypt - AES-128 CBC encryption * @key: Encryption key @@ -27,7 +45,70 @@ * @data_len: Length of data in bytes (must be divisible by 16) * Returns: 0 on success, -1 on failure */ -int +int +aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) +{ + int ret = 0; + mbedtls_aes_context ctx; + u8 cbc[AES_BLOCK_SIZE]; + + mbedtls_aes_init(&ctx); + + ret = mbedtls_aes_setkey_enc(&ctx, key, 128); + if(ret < 0) { + mbedtls_aes_free(&ctx); + return ret; + } + + os_memcpy(cbc, iv, AES_BLOCK_SIZE); + ret = mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_ENCRYPT, data_len, cbc, data, data); + mbedtls_aes_free(&ctx); + + return ret; +} + + +/** + * aes_128_cbc_decrypt - AES-128 CBC decryption + * @key: Decryption key + * @iv: Decryption IV for CBC mode (16 bytes) + * @data: Data to decrypt in-place + * @data_len: Length of data in bytes (must be divisible by 16) + * Returns: 0 on success, -1 on failure + */ +int +aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) +{ + int ret = 0; + mbedtls_aes_context ctx; + u8 cbc[AES_BLOCK_SIZE]; + + mbedtls_aes_init(&ctx); + + ret = mbedtls_aes_setkey_dec(&ctx, key, 128); + if(ret < 0) { + mbedtls_aes_free(&ctx); + return ret; + } + + os_memcpy(cbc, iv, AES_BLOCK_SIZE); + ret = mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_DECRYPT, data_len, cbc, data, data); + mbedtls_aes_free(&ctx); + + return ret; + +} +#else /* USE_MBEDTLS_CRYPTO */ + +/** + * aes_128_cbc_encrypt - AES-128 CBC encryption + * @key: Encryption key + * @iv: Encryption IV for CBC mode (16 bytes) + * @data: Data to encrypt in-place + * @data_len: Length of data in bytes (must be divisible by 16) + * Returns: 0 on success, -1 on failure + */ +int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) { void *ctx; @@ -61,7 +142,7 @@ aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) * @data_len: Length of data in bytes (must be divisible by 16) * Returns: 0 on success, -1 on failure */ -int +int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) { void *ctx; @@ -86,3 +167,4 @@ aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) aes_decrypt_deinit(ctx); return 0; } +#endif /* USE_MBEDTLS_CRYPTO */ diff --git a/components/wpa_supplicant/src/crypto/aes-internal-dec.c b/components/wpa_supplicant/src/crypto/aes-internal-dec.c index 46371c5557..5cea5f745f 100644 --- a/components/wpa_supplicant/src/crypto/aes-internal-dec.c +++ b/components/wpa_supplicant/src/crypto/aes-internal-dec.c @@ -21,9 +21,9 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" +#include "utils/common.h" #include "crypto/crypto.h" #include "crypto/aes_i.h" diff --git a/components/wpa_supplicant/src/crypto/aes-internal-enc.c b/components/wpa_supplicant/src/crypto/aes-internal-enc.c index 7b1080c450..5b714fedba 100644 --- a/components/wpa_supplicant/src/crypto/aes-internal-enc.c +++ b/components/wpa_supplicant/src/crypto/aes-internal-enc.c @@ -21,8 +21,8 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" -#include "crypto/common.h" +#include "utils/includes.h" +#include "utils/common.h" #include "crypto/crypto.h" #include "crypto/aes_i.h" diff --git a/components/wpa_supplicant/src/crypto/aes-internal.c b/components/wpa_supplicant/src/crypto/aes-internal.c index 9618239f93..537d4034a7 100644 --- a/components/wpa_supplicant/src/crypto/aes-internal.c +++ b/components/wpa_supplicant/src/crypto/aes-internal.c @@ -21,10 +21,9 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -//#include "wpa/common.h" -#include "crypto/common.h" +#include "utils/common.h" #include "crypto/crypto.h" #include "crypto/aes_i.h" diff --git a/components/wpa_supplicant/src/crypto/aes-unwrap.c b/components/wpa_supplicant/src/crypto/aes-unwrap.c index 4a92f1cd31..9f513b0ac5 100644 --- a/components/wpa_supplicant/src/crypto/aes-unwrap.c +++ b/components/wpa_supplicant/src/crypto/aes-unwrap.c @@ -12,12 +12,31 @@ * * See README and COPYING for more details. */ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Hardware crypto support Copyright 2017-2019 Espressif Systems (Shanghai) PTE LTD + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" +#include "utils/common.h" +#ifdef USE_MBEDTLS_CRYPTO +#include "mbedtls/aes.h" +#else /* USE_MBEDTLS_CRYPTO */ #include "crypto/aes.h" #include "crypto/aes_wrap.h" +#endif /* USE_MBEDTLS_CRYPTO */ /** * aes_unwrap - Unwrap key with AES Key Wrap Algorithm (128-bit KEK) (RFC3394) @@ -33,16 +52,30 @@ aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain) { u8 a[8], *r, b[16]; int i, j; +#ifdef USE_MBEDTLS_CRYPTO + int32_t ret = 0; + mbedtls_aes_context ctx; +#else /* USE_MBEDTLS_CRYPTO */ void *ctx; +#endif /* USE_MBEDTLS_CRYPTO */ /* 1) Initialize variables. */ os_memcpy(a, cipher, 8); r = plain; os_memcpy(r, cipher + 8, 8 * n); +#ifdef USE_MBEDTLS_CRYPTO + mbedtls_aes_init(&ctx); + ret = mbedtls_aes_setkey_dec(&ctx, kek, 128); + if (ret < 0) { + mbedtls_aes_free(&ctx); + return ret; + } +#else /* USE_MBEDTLS_CRYPTO */ ctx = aes_decrypt_init(kek, 16); if (ctx == NULL) return -1; +#endif /* USE_MBEDTLS_CRYPTO */ /* 2) Compute intermediate values. * For j = 5 to 0 @@ -58,13 +91,21 @@ aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain) b[7] ^= n * j + i; os_memcpy(b + 8, r, 8); +#ifdef USE_MBEDTLS_CRYPTO + ret = mbedtls_internal_aes_decrypt(&ctx, b, b); +#else /* USE_MBEDTLS_CRYPTO */ aes_decrypt(ctx, b, b); +#endif /* USE_MBEDTLS_CRYPTO */ os_memcpy(a, b, 8); os_memcpy(r, b + 8, 8); r -= 8; } } +#ifdef USE_MBEDTLS_CRYPTO + mbedtls_aes_free(&ctx); +#else /* USE_MBEDTLS_CRYPTO */ aes_decrypt_deinit(ctx); +#endif /* USE_MBEDTLS_CRYPTO */ /* 3) Output results. * diff --git a/components/wpa_supplicant/src/crypto/aes-wrap.c b/components/wpa_supplicant/src/crypto/aes-wrap.c index 388dd97a82..9d180f5222 100644 --- a/components/wpa_supplicant/src/crypto/aes-wrap.c +++ b/components/wpa_supplicant/src/crypto/aes-wrap.c @@ -6,12 +6,30 @@ * This software may be distributed under the terms of the BSD license. * See README for more details. */ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Hardware crypto support Copyright 2017-2019 Espressif Systems (Shanghai) PTE LTD + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" +#include "utils/common.h" #include "crypto/aes.h" #include "crypto/aes_wrap.h" +#ifdef USE_MBEDTLS_CRYPTO +#include "mbedtls/aes.h" +#endif /* USE_MBEDTLS_CRYPTO */ /** * aes_wrap - Wrap keys with AES Key Wrap Algorithm (128-bit KEK) (RFC3394) @@ -26,7 +44,12 @@ int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher) { u8 *a, *r, b[16]; int i, j; +#ifdef USE_MBEDTLS_CRYPTO + int32_t ret = 0; + mbedtls_aes_context ctx; +#else /* USE_MBEDTLS_CRYPTO */ void *ctx; +#endif /* USE_MBEDTLS_CRYPTO */ a = cipher; r = cipher + 8; @@ -35,9 +58,18 @@ int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher) os_memset(a, 0xa6, 8); os_memcpy(r, plain, 8 * n); +#ifdef USE_MBEDTLS_CRYPTO + mbedtls_aes_init(&ctx); + ret = mbedtls_aes_setkey_enc(&ctx, kek, 128); + if (ret < 0) { + mbedtls_aes_free(&ctx); + return ret; + } +#else /* USE_MBEDTLS_CRYPTO */ ctx = aes_encrypt_init(kek, 16); if (ctx == NULL) return -1; +#endif /* USE_MBEDTLS_CRYPTO */ /* 2) Calculate intermediate values. * For j = 0 to 5 @@ -51,14 +83,24 @@ int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher) for (i = 1; i <= n; i++) { os_memcpy(b, a, 8); os_memcpy(b + 8, r, 8); +#ifdef USE_MBEDTLS_CRYPTO + ret = mbedtls_internal_aes_encrypt(&ctx, b, b); + if (ret != 0) + break; +#else /* USE_MBEDTLS_CRYPTO */ aes_encrypt(ctx, b, b); +#endif /* USE_MBEDTLS_CRYPTO */ os_memcpy(a, b, 8); a[7] ^= n * j + i; os_memcpy(r, b + 8, 8); r += 8; } } +#ifdef USE_MBEDTLS_CRYPTO + mbedtls_aes_free(&ctx); +#else /* USE_MBEDTLS_CRYPTO */ aes_encrypt_deinit(ctx); +#endif /* USE_MBEDTLS_CRYPTO */ /* 3) Output the results. * diff --git a/components/wpa_supplicant/include/crypto/aes_i.h b/components/wpa_supplicant/src/crypto/aes_i.h similarity index 99% rename from components/wpa_supplicant/include/crypto/aes_i.h rename to components/wpa_supplicant/src/crypto/aes_i.h index 1063422a81..290ac423bd 100644 --- a/components/wpa_supplicant/include/crypto/aes_i.h +++ b/components/wpa_supplicant/src/crypto/aes_i.h @@ -15,7 +15,7 @@ #ifndef AES_I_H #define AES_I_H -#include "aes.h" +#include "crypto/aes.h" /* #define FULL_UNROLL */ #define AES_SMALL_TABLES diff --git a/components/wpa_supplicant/src/crypto/bignum.c b/components/wpa_supplicant/src/crypto/bignum.c index 7b8446c3ba..12a273e5ff 100644 --- a/components/wpa_supplicant/src/crypto/bignum.c +++ b/components/wpa_supplicant/src/crypto/bignum.c @@ -12,10 +12,10 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" -#include "crypto/common.h" -#include "wpa/wpabuf.h" -#include "wpa/wpa_debug.h" +#include "utils/includes.h" +#include "utils/common.h" +#include "utils/wpabuf.h" +#include "utils/wpa_debug.h" #include "bignum.h" #define CONFIG_INTERNAL_LIBTOMMATH diff --git a/components/wpa_supplicant/src/crypto/crypto_internal-cipher.c b/components/wpa_supplicant/src/crypto/crypto_internal-cipher.c index 7d89795797..3fe2412e10 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 "utils/common.h" +#include "utils/includes.h" #include "crypto/crypto.h" #include "crypto/aes.h" #if defined(CONFIG_DES) || defined(CONFIG_DES3) #include "crypto/des_i.h" #endif - -#ifdef 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..f37139ba19 100644 --- a/components/wpa_supplicant/src/crypto/crypto_internal-modexp.c +++ b/components/wpa_supplicant/src/crypto/crypto_internal-modexp.c @@ -11,14 +11,72 @@ * * See README and COPYING for more details. */ +/* + * Hardware crypto support Copyright 2017-2019 Espressif Systems (Shanghai) PTE LTD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ -#include "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" +#endif /* USE_MBEDTLS_CRYPTO */ #include "crypto/crypto.h" +#ifdef USE_MBEDTLS_CRYPTO +int +crypto_mod_exp(const uint8_t *base, size_t base_len, + const uint8_t *power, size_t power_len, + const uint8_t *modulus, size_t modulus_len, + uint8_t *result, size_t *result_len) +{ + mbedtls_mpi bn_base, bn_exp, bn_modulus, bn_result, bn_rinv; + int ret = 0; + mbedtls_mpi_init(&bn_base); + mbedtls_mpi_init(&bn_exp); + mbedtls_mpi_init(&bn_modulus); + mbedtls_mpi_init(&bn_result); + mbedtls_mpi_init(&bn_rinv); + mbedtls_mpi_read_binary(&bn_base, base, base_len); + mbedtls_mpi_read_binary(&bn_exp, power, power_len); + mbedtls_mpi_read_binary(&bn_modulus, modulus, modulus_len); + + ret = mbedtls_mpi_exp_mod(&bn_result, &bn_base, &bn_exp, &bn_modulus, &bn_rinv); + if (ret < 0) { + mbedtls_mpi_free(&bn_base); + mbedtls_mpi_free(&bn_exp); + mbedtls_mpi_free(&bn_modulus); + mbedtls_mpi_free(&bn_result); + mbedtls_mpi_free(&bn_rinv); + return ret; + } + + ret = mbedtls_mpi_write_binary(&bn_result, result, *result_len); + + mbedtls_mpi_free(&bn_base); + mbedtls_mpi_free(&bn_exp); + mbedtls_mpi_free(&bn_modulus); + mbedtls_mpi_free(&bn_result); + mbedtls_mpi_free(&bn_rinv); + + return ret; +} +#else /* USE_MBEDTLS_CRYPTO */ int crypto_mod_exp(const u8 *base, size_t base_len, const u8 *power, size_t power_len, @@ -54,3 +112,4 @@ error: bignum_deinit(bn_result); return ret; } +#endif /* USE_MBEDTLS_CRYPTO */ diff --git a/components/wpa_supplicant/src/crypto/crypto_internal-rsa.c b/components/wpa_supplicant/src/crypto/crypto_internal-rsa.c index 19934f063b..de7c8091e9 100644 --- a/components/wpa_supplicant/src/crypto/crypto_internal-rsa.c +++ b/components/wpa_supplicant/src/crypto/crypto_internal-rsa.c @@ -6,16 +6,16 @@ * See README for more details. */ -#include "crypto/common.h" +#include "utils/common.h" #include "crypto/crypto.h" -#include "wpa/includes.h" -#include "wpa/common.h" -#include "wpa/wpa_debug.h" +#include "utils/includes.h" +#include "utils/common.h" +#include "utils/wpa_debug.h" -#include "wpa2/tls/rsa.h" -#include "wpa2/tls/pkcs1.h" -#include "wpa2/tls/pkcs8.h" +#include "tls/rsa.h" +#include "tls/pkcs1.h" +#include "tls/pkcs8.h" /* Dummy structures; these are just typecast to struct crypto_rsa_key */ struct crypto_public_key; diff --git a/components/wpa_supplicant/src/crypto/crypto_internal.c b/components/wpa_supplicant/src/crypto/crypto_internal.c index d8d59dfb9d..4622cfcb89 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 "utils/includes.h" +#include "utils/common.h" #include "crypto/crypto.h" -//#include "crypto/sha256_i.h" #include "crypto/sha1_i.h" #include "crypto/md5_i.h" - -#ifdef MEMLEAK_DEBUG -static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__; +#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..315a6834ff 100644 --- a/components/wpa_supplicant/src/crypto/crypto_mbedtls.c +++ b/components/wpa_supplicant/src/crypto/crypto_mbedtls.c @@ -17,8 +17,8 @@ #include "mbedtls/bignum.h" #endif -#include "crypto/includes.h" -#include "crypto/common.h" +#include "utils/includes.h" +#include "utils/common.h" #include "crypto/crypto.h" #include "mbedtls/ecp.h" diff --git a/components/wpa_supplicant/src/crypto/des-internal.c b/components/wpa_supplicant/src/crypto/des-internal.c index a29c21a1bb..7c66412286 100644 --- a/components/wpa_supplicant/src/crypto/des-internal.c +++ b/components/wpa_supplicant/src/crypto/des-internal.c @@ -9,9 +9,9 @@ */ -#include "wpa/includes.h" +#include "utils/includes.h" -#include "wpa/common.h" +#include "utils/common.h" #include "crypto/crypto.h" //#include "des_i.h" diff --git a/components/wpa_supplicant/src/crypto/des_i.h b/components/wpa_supplicant/src/crypto/des_i.h new file mode 100644 index 0000000000..c9563d2204 --- /dev/null +++ b/components/wpa_supplicant/src/crypto/des_i.h @@ -0,0 +1,25 @@ +/* + * DES and 3DES-EDE ciphers + * Copyright (c) 2006-2009, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef DES_I_H +#define DES_I_H + +struct des3_key_s { + u32 ek[3][32]; + u32 dk[3][32]; +}; + +void des_key_setup(const u8 *key, u32 *ek, u32 *dk); +void des_block_encrypt(const u8 *plain, const u32 *ek, u8 *crypt); +void des_block_decrypt(const u8 *crypt, const u32 *dk, u8 *plain); + +void des3_key_setup(const u8 *key, struct des3_key_s *dkey); +void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt); +void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain); + +#endif /* DES_I_H */ diff --git a/components/wpa_supplicant/src/crypto/dh_group5.c b/components/wpa_supplicant/src/crypto/dh_group5.c index 710f5c7d02..5ae75da2e1 100644 --- a/components/wpa_supplicant/src/crypto/dh_group5.c +++ b/components/wpa_supplicant/src/crypto/dh_group5.c @@ -12,9 +12,9 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" +#include "utils/common.h" #include "crypto/dh_groups.h" #include "crypto/dh_group5.h" diff --git a/components/wpa_supplicant/src/crypto/dh_groups.c b/components/wpa_supplicant/src/crypto/dh_groups.c index c08f8f29df..e3c7519ece 100644 --- a/components/wpa_supplicant/src/crypto/dh_groups.c +++ b/components/wpa_supplicant/src/crypto/dh_groups.c @@ -12,18 +12,16 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" +#include "utils/common.h" #include "crypto/crypto.h" #include "crypto/random.h" #include "crypto/dh_groups.h" -#include "wpa/wpabuf.h" -#include "wpa/wpa_debug.h" +#include "utils/wpabuf.h" +#include "utils/wpa_debug.h" #include "esp_wifi_crypto_types.h" -extern wps_crypto_funcs_t wps_crypto_funcs; - #ifdef ALL_DH_GROUPS /* RFC 4306, B.1. Group 1 - 768 Bit MODP @@ -588,16 +586,10 @@ dh_init(const struct dh_group *dh, struct wpabuf **priv) if (pv == NULL) return NULL; - if (wps_crypto_funcs.crypto_mod_exp) { - if (wps_crypto_funcs.crypto_mod_exp(dh->generator, dh->generator_len, - wpabuf_head(*priv), wpabuf_len(*priv), - dh->prime, dh->prime_len, wpabuf_mhead(pv), - &pv_len)) { - wpabuf_free(pv); - wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed"); - return NULL; - } - } else { + if (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/src/crypto/md4-internal.c b/components/wpa_supplicant/src/crypto/md4-internal.c index a3ad58129a..cc988492d3 100644 --- a/components/wpa_supplicant/src/crypto/md4-internal.c +++ b/components/wpa_supplicant/src/crypto/md4-internal.c @@ -4,8 +4,8 @@ * This software may be distributed under the terms of BSD license. */ -#include "crypto/includes.h" -#include "crypto/common.h" +#include "utils/includes.h" +#include "utils/common.h" #include "crypto/crypto.h" #define MD4_BLOCK_LENGTH 64 diff --git a/components/wpa_supplicant/src/crypto/md5-internal.c b/components/wpa_supplicant/src/crypto/md5-internal.c index a430e297a5..3a98b36d49 100644 --- a/components/wpa_supplicant/src/crypto/md5-internal.c +++ b/components/wpa_supplicant/src/crypto/md5-internal.c @@ -12,9 +12,9 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" +#include "utils/common.h" #include "crypto/md5.h" #include "crypto/md5_i.h" #include "crypto/crypto.h" diff --git a/components/wpa_supplicant/src/crypto/md5.c b/components/wpa_supplicant/src/crypto/md5.c index 3125c98311..3a05742961 100644 --- a/components/wpa_supplicant/src/crypto/md5.c +++ b/components/wpa_supplicant/src/crypto/md5.c @@ -12,9 +12,9 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" +#include "utils/common.h" #include "crypto/md5.h" #include "crypto/crypto.h" diff --git a/components/wpa_supplicant/include/crypto/md5_i.h b/components/wpa_supplicant/src/crypto/md5_i.h similarity index 100% rename from components/wpa_supplicant/include/crypto/md5_i.h rename to components/wpa_supplicant/src/crypto/md5_i.h diff --git a/components/wpa_supplicant/src/crypto/ms_funcs.c b/components/wpa_supplicant/src/crypto/ms_funcs.c index 038f5af950..191aa2bcf2 100644 --- a/components/wpa_supplicant/src/crypto/ms_funcs.c +++ b/components/wpa_supplicant/src/crypto/ms_funcs.c @@ -7,9 +7,9 @@ */ -#include "wpa/includes.h" +#include "utils/includes.h" -#include "wpa/common.h" +#include "utils/common.h" #include "crypto/sha1.h" #include "crypto/ms_funcs.h" #include "crypto/crypto.h" diff --git a/components/wpa_supplicant/src/crypto/rc4.c b/components/wpa_supplicant/src/crypto/rc4.c index 678632297f..aa914dcc72 100644 --- a/components/wpa_supplicant/src/crypto/rc4.c +++ b/components/wpa_supplicant/src/crypto/rc4.c @@ -12,9 +12,9 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" +#include "utils/common.h" #include "crypto/crypto.h" #define S_SWAP(a,b) do { u8 t = S[a]; S[a] = S[b]; S[b] = t; } while(0) diff --git a/components/wpa_supplicant/src/crypto/sha1-internal.c b/components/wpa_supplicant/src/crypto/sha1-internal.c index a1c255e416..9eb190039e 100644 --- a/components/wpa_supplicant/src/crypto/sha1-internal.c +++ b/components/wpa_supplicant/src/crypto/sha1-internal.c @@ -12,9 +12,9 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" +#include "utils/common.h" #include "crypto/sha1.h" #include "crypto/sha1_i.h" #include "crypto/md5.h" diff --git a/components/wpa_supplicant/src/crypto/sha1-pbkdf2.c b/components/wpa_supplicant/src/crypto/sha1-pbkdf2.c index 915a23aa78..ec7100142c 100644 --- a/components/wpa_supplicant/src/crypto/sha1-pbkdf2.c +++ b/components/wpa_supplicant/src/crypto/sha1-pbkdf2.c @@ -12,8 +12,8 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" -#include "crypto/common.h" +#include "utils/includes.h" +#include "utils/common.h" #include "crypto/sha1.h" #include "crypto/md5.h" #include "crypto/crypto.h" diff --git a/components/wpa_supplicant/src/crypto/sha1.c b/components/wpa_supplicant/src/crypto/sha1.c index 3d6da417ac..5b228292b2 100644 --- a/components/wpa_supplicant/src/crypto/sha1.c +++ b/components/wpa_supplicant/src/crypto/sha1.c @@ -12,9 +12,9 @@ * See README and COPYING for more details. */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" +#include "utils/common.h" #include "crypto/sha1.h" #include "crypto/crypto.h" diff --git a/components/wpa_supplicant/include/crypto/sha1_i.h b/components/wpa_supplicant/src/crypto/sha1_i.h similarity index 100% rename from components/wpa_supplicant/include/crypto/sha1_i.h rename to components/wpa_supplicant/src/crypto/sha1_i.h diff --git a/components/wpa_supplicant/src/crypto/sha256-internal.c b/components/wpa_supplicant/src/crypto/sha256-internal.c index 9a1fca1c17..df0706b5c1 100644 --- a/components/wpa_supplicant/src/crypto/sha256-internal.c +++ b/components/wpa_supplicant/src/crypto/sha256-internal.c @@ -11,12 +11,73 @@ * * See README and COPYING for more details. */ +/* + * Hardware crypto support Copyright 2017-2019 Espressif Systems (Shanghai) PTE LTD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ -#include "crypto/includes.h" +#include "utils/includes.h" -#include "crypto/common.h" +#include "utils/common.h" +#ifdef USE_MBEDTLS_CRYPTO +#include "mbedtls/sha256.h" +#else /* USE_MBEDTLS_CRYPTO */ #include "crypto/sha256.h" #include "crypto/crypto.h" +#endif /* USE_MBEDTLS_CRYPTO */ + +#ifdef USE_MBEDTLS_CRYPTO +/** + * sha256_vector - SHA256 hash for data vector + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash + * Returns: 0 on success, -1 of failure + */ +int +sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, + u8 *mac) +{ + int ret = 0; + mbedtls_sha256_context ctx; + + mbedtls_sha256_init(&ctx); + + if (mbedtls_sha256_starts_ret(&ctx, 0) != 0) { + ret = -1; + goto out; + } + + for(size_t index = 0; index < num_elem; index++) { + if (mbedtls_sha256_update_ret(&ctx, addr[index], len[index]) != 0) { + ret = -1; + goto out; + } + } + + if (mbedtls_sha256_finish_ret(&ctx, mac) != 0) { + ret = -1; + goto out; + } + +out: + mbedtls_sha256_free(&ctx); + + return ret; +} +#else /* USE_MBEDTLS_CRYPTO */ #define SHA256_BLOCK_SIZE 64 @@ -245,5 +306,6 @@ sha256_done(struct sha256_state *md, unsigned char *out) return 0; } +#endif /* USE_MBEDTLS_CRYPTO */ /* ===== end - public domain SHA256 implementation ===== */ diff --git a/components/wpa_supplicant/src/crypto/sha256.c b/components/wpa_supplicant/src/crypto/sha256.c index f62cc11827..6380897e42 100644 --- a/components/wpa_supplicant/src/crypto/sha256.c +++ b/components/wpa_supplicant/src/crypto/sha256.c @@ -11,10 +11,25 @@ * * 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 "utils/common.h" #include "crypto/sha256.h" #include "crypto/crypto.h" diff --git a/components/wpa_supplicant/src/wpa2/eap_peer/chap.c b/components/wpa_supplicant/src/eap_peer/chap.c similarity index 89% rename from components/wpa_supplicant/src/wpa2/eap_peer/chap.c rename to components/wpa_supplicant/src/eap_peer/chap.c index eb613ca4c1..f48db98193 100644 --- a/components/wpa_supplicant/src/wpa2/eap_peer/chap.c +++ b/components/wpa_supplicant/src/eap_peer/chap.c @@ -4,8 +4,8 @@ */ #ifdef CHAP_MD5 -#include "wpa/includes.h" -#include "wpa/common.h" +#include "utils/includes.h" +#include "utils/common.h" #include "crypto/crypto.h" #include "wpa2/eap_peer/chap.h" diff --git a/components/wpa_supplicant/src/wpa2/eap_peer/eap.c b/components/wpa_supplicant/src/eap_peer/eap.c similarity index 73% rename from components/wpa_supplicant/src/wpa2/eap_peer/eap.c rename to components/wpa_supplicant/src/eap_peer/eap.c index 3ddd294274..114985c9e5 100644 --- a/components/wpa_supplicant/src/wpa2/eap_peer/eap.c +++ b/components/wpa_supplicant/src/eap_peer/eap.c @@ -18,34 +18,34 @@ #include "esp_err.h" -#include "wpa/includes.h" -#include "wpa/common.h" -#include "wpa/wpa_debug.h" -#include "wpa/eapol_common.h" -#include "wpa/ieee802_11_defs.h" -#include "wpa/state_machine.h" -#include "wpa/wpa.h" +#include "utils/includes.h" +#include "utils/common.h" +#include "utils/wpa_debug.h" +#include "common/eapol_common.h" +#include "common/ieee802_11_defs.h" +#include "utils/state_machine.h" +#include "rsn_supp/wpa.h" #include "crypto/crypto.h" -#include "wpa2/utils/ext_password.h" -#include "wpa2/tls/tls.h" -#include "wpa2/eap_peer/eap_i.h" -#include "wpa2/eap_peer/eap_config.h" -#include "wpa2/eap_peer/eap.h" -#include "wpa2/eap_peer/eap_tls.h" +#include "utils/ext_password.h" +#include "tls/tls.h" +#include "eap_peer/eap_i.h" +#include "eap_peer/eap_config.h" +#include "eap_peer/eap.h" +#include "eap_peer/eap_tls.h" +#include "esp_supplicant/esp_wifi_driver.h" #ifdef EAP_PEER_METHOD -#include "wpa2/eap_peer/eap_methods.h" +#include "eap_peer/eap_methods.h" #endif +#include "supplicant_opt.h" + -static bool gl_disable_time_check = true; void eap_peer_config_deinit(struct eap_sm *sm); void eap_peer_blob_deinit(struct eap_sm *sm); void eap_deinit_prev_method(struct eap_sm *sm, const char *txt); -extern bool ieee80211_unregister_wpa2_cb(void); - #ifdef EAP_PEER_METHOD static struct eap_method *eap_methods = NULL; @@ -333,7 +333,7 @@ struct wpabuf * eap_sm_build_nak(struct eap_sm *sm, EapType type, u8 id) #endif int eap_peer_config_init( - struct eap_sm *sm, u8 *private_key_passwd, + struct eap_sm *sm, const u8 *private_key_passwd, int private_key_passwd_len) { if (!sm) @@ -478,8 +478,6 @@ void eap_sm_abort(struct eap_sm *sm) { wpabuf_free(sm->lastRespData); sm->lastRespData = NULL; - //os_free(sm->eapKeyData); - //sm->eapKeyData = NULL; } /** @@ -559,184 +557,3 @@ const struct wpa_config_blob * eap_get_config_blob(struct eap_sm *sm, return NULL; } -esp_err_t esp_wifi_sta_wpa2_ent_set_cert_key(const unsigned char *client_cert, int client_cert_len, const unsigned char *private_key, int private_key_len, const unsigned char *private_key_passwd, int private_key_passwd_len) -{ - if (client_cert && client_cert_len > 0) { - g_wpa_client_cert = client_cert; - g_wpa_client_cert_len = client_cert_len; - } - if (private_key && private_key_len > 0) { - g_wpa_private_key = private_key; - g_wpa_private_key_len = private_key_len; - } - if (private_key_passwd && private_key_passwd_len > 0) { - g_wpa_private_key_passwd = private_key_passwd; - g_wpa_private_key_passwd_len = private_key_passwd_len; - } - - return ESP_OK; -} - -void esp_wifi_sta_wpa2_ent_clear_cert_key(void) -{ - ieee80211_unregister_wpa2_cb(); - - g_wpa_client_cert = NULL; - g_wpa_client_cert_len = 0; - g_wpa_private_key = NULL; - g_wpa_private_key_len = 0; - g_wpa_private_key_passwd = NULL; - g_wpa_private_key_passwd_len = 0; -} - -esp_err_t esp_wifi_sta_wpa2_ent_set_ca_cert(const unsigned char *ca_cert, int ca_cert_len) -{ - if (ca_cert && ca_cert_len > 0) { - g_wpa_ca_cert = ca_cert; - g_wpa_ca_cert_len = ca_cert_len; - } - - return ESP_OK; -} - -void esp_wifi_sta_wpa2_ent_clear_ca_cert(void) -{ - g_wpa_ca_cert = NULL; - g_wpa_ca_cert_len = 0; -} - -#define ANONYMOUS_ID_LEN_MAX 128 -esp_err_t esp_wifi_sta_wpa2_ent_set_identity(const unsigned char *identity, int len) -{ - if (len <= 0 || len > ANONYMOUS_ID_LEN_MAX) { - return ESP_ERR_INVALID_ARG; - } - - if (g_wpa_anonymous_identity) { - os_free(g_wpa_anonymous_identity); - g_wpa_anonymous_identity = NULL; - } - - g_wpa_anonymous_identity = (u8 *)os_zalloc(len); - if (g_wpa_anonymous_identity == NULL) { - return ESP_ERR_NO_MEM; - } - - os_memcpy(g_wpa_anonymous_identity, identity, len); - g_wpa_anonymous_identity_len = len; - - return ESP_OK; -} - -void esp_wifi_sta_wpa2_ent_clear_identity(void) -{ - if (g_wpa_anonymous_identity) - os_free(g_wpa_anonymous_identity); - - g_wpa_anonymous_identity = NULL; - g_wpa_anonymous_identity_len = 0; -} - -#define USERNAME_LEN_MAX 128 -esp_err_t esp_wifi_sta_wpa2_ent_set_username(const unsigned char *username, int len) -{ - if (len <= 0 || len > USERNAME_LEN_MAX) - return ESP_ERR_INVALID_ARG; - - if (g_wpa_username) { - os_free(g_wpa_username); - g_wpa_username = NULL; - } - - g_wpa_username = (u8 *)os_zalloc(len); - if (g_wpa_username == NULL) - return ESP_ERR_NO_MEM; - - os_memcpy(g_wpa_username, username, len); - g_wpa_username_len = len; - - return ESP_OK; -} - -void esp_wifi_sta_wpa2_ent_clear_username(void) -{ - if (g_wpa_username) - os_free(g_wpa_username); - - g_wpa_username = NULL; - g_wpa_username_len = 0; -} - -esp_err_t esp_wifi_sta_wpa2_ent_set_password(const unsigned char *password, int len) -{ - if (len <= 0) - return ESP_ERR_INVALID_ARG; - - if (g_wpa_password) { - os_free(g_wpa_password); - g_wpa_password = NULL; - } - - g_wpa_password = (u8 *)os_zalloc(len); - if (g_wpa_password == NULL) - return ESP_ERR_NO_MEM; - - os_memcpy(g_wpa_password, password, len); - g_wpa_password_len = len; - - return ESP_OK; -} - -void esp_wifi_sta_wpa2_ent_clear_password(void) -{ - if (g_wpa_password) - os_free(g_wpa_password); - g_wpa_password = NULL; - g_wpa_password_len = 0; -} - -esp_err_t esp_wifi_sta_wpa2_ent_set_new_password(const unsigned char *new_password, int len) -{ - if (len <= 0) - return ESP_ERR_INVALID_ARG; - - if (g_wpa_new_password) { - os_free(g_wpa_new_password); - g_wpa_new_password = NULL; - } - - g_wpa_new_password = (u8 *)os_zalloc(len); - if (g_wpa_new_password == NULL) - return ESP_ERR_NO_MEM; - - os_memcpy(g_wpa_new_password, new_password, len); - g_wpa_password_len = len; - - return ESP_OK; -} - -void esp_wifi_sta_wpa2_ent_clear_new_password(void) -{ - if (g_wpa_new_password) - os_free(g_wpa_new_password); - g_wpa_new_password = NULL; - g_wpa_new_password_len = 0; -} - -esp_err_t esp_wifi_sta_wpa2_ent_set_disable_time_check(bool disable) -{ - gl_disable_time_check = disable; - return ESP_OK; -} - -bool wifi_sta_get_enterprise_disable_time_check(void) -{ - return gl_disable_time_check; -} - -esp_err_t esp_wifi_sta_wpa2_ent_get_disable_time_check(bool *disable) -{ - *disable = wifi_sta_get_enterprise_disable_time_check(); - return ESP_OK; -} - diff --git a/components/wpa_supplicant/include/wpa2/eap_peer/eap.h b/components/wpa_supplicant/src/eap_peer/eap.h similarity index 92% rename from components/wpa_supplicant/include/wpa2/eap_peer/eap.h rename to components/wpa_supplicant/src/eap_peer/eap.h index 9e1c3efa94..4e84ea7fc7 100644 --- a/components/wpa_supplicant/include/wpa2/eap_peer/eap.h +++ b/components/wpa_supplicant/src/eap_peer/eap.h @@ -9,8 +9,8 @@ #ifndef EAP_H #define EAP_H -#include "wpa/defs.h" -#include "wpa2/eap_peer/eap_defs.h" +#include "common/defs.h" +#include "eap_peer/eap_defs.h" struct eap_sm; @@ -45,7 +45,7 @@ struct wpabuf * eap_sm_build_nak(struct eap_sm *sm, EapType type, u8 id); int eap_peer_blob_init(struct eap_sm *sm); void eap_peer_blob_deinit(struct eap_sm *sm); int eap_peer_config_init( - struct eap_sm *sm, u8 *private_key_passwd, + struct eap_sm *sm, const u8 *private_key_passwd, int private_key_passwd_len); void eap_peer_config_deinit(struct eap_sm *sm); void eap_sm_abort(struct eap_sm *sm); diff --git a/components/wpa_supplicant/src/wpa2/eap_peer/eap_common.c b/components/wpa_supplicant/src/eap_peer/eap_common.c similarity index 97% rename from components/wpa_supplicant/src/wpa2/eap_peer/eap_common.c rename to components/wpa_supplicant/src/eap_peer/eap_common.c index a1748b140f..e6973fac6e 100644 --- a/components/wpa_supplicant/src/wpa2/eap_peer/eap_common.c +++ b/components/wpa_supplicant/src/eap_peer/eap_common.c @@ -6,11 +6,11 @@ * See README for more details. */ -#include "wpa/includes.h" +#include "utils/includes.h" -#include "wpa/common.h" -#include "wpa2/eap_peer/eap_defs.h" -#include "wpa2/eap_peer/eap_common.h" +#include "utils/common.h" +#include "eap_peer/eap_defs.h" +#include "eap_peer/eap_common.h" /** * eap_hdr_len_valid - Validate EAP header length field diff --git a/components/wpa_supplicant/include/wpa2/eap_peer/eap_common.h b/components/wpa_supplicant/src/eap_peer/eap_common.h similarity index 96% rename from components/wpa_supplicant/include/wpa2/eap_peer/eap_common.h rename to components/wpa_supplicant/src/eap_peer/eap_common.h index 38c5710058..b7b8afcc50 100644 --- a/components/wpa_supplicant/include/wpa2/eap_peer/eap_common.h +++ b/components/wpa_supplicant/src/eap_peer/eap_common.h @@ -9,7 +9,7 @@ #ifndef EAP_COMMON_H #define EAP_COMMON_H -#include "wpa/wpabuf.h" +#include "utils/wpabuf.h" int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload); const u8 * eap_hdr_validate(int vendor, EapType eap_type, diff --git a/components/wpa_supplicant/include/wpa2/eap_peer/eap_config.h b/components/wpa_supplicant/src/eap_peer/eap_config.h similarity index 99% rename from components/wpa_supplicant/include/wpa2/eap_peer/eap_config.h rename to components/wpa_supplicant/src/eap_peer/eap_config.h index f95dcda3a1..3698e73252 100644 --- a/components/wpa_supplicant/include/wpa2/eap_peer/eap_config.h +++ b/components/wpa_supplicant/src/eap_peer/eap_config.h @@ -141,7 +141,7 @@ struct eap_peer_config { * * If left out, this will be asked through control interface. */ - u8 *private_key_passwd; + const u8 *private_key_passwd; /** * Phase 2 diff --git a/components/wpa_supplicant/include/wpa2/eap_peer/eap_defs.h b/components/wpa_supplicant/src/eap_peer/eap_defs.h similarity index 100% rename from components/wpa_supplicant/include/wpa2/eap_peer/eap_defs.h rename to components/wpa_supplicant/src/eap_peer/eap_defs.h diff --git a/components/wpa_supplicant/include/wpa2/eap_peer/eap_i.h b/components/wpa_supplicant/src/eap_peer/eap_i.h similarity index 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..fb5515913e 100644 --- a/components/wpa_supplicant/src/wpa2/eap_peer/eap_ttls.c +++ b/components/wpa_supplicant/src/eap_peer/eap_ttls.c @@ -6,23 +6,20 @@ * See README for more details. */ +#include "utils/includes.h" + #ifdef EAP_TTLS - -#include "wpa/includes.h" - -#include "wpa/common.h" +#include "utils/common.h" #include "crypto/ms_funcs.h" #include "crypto/sha1.h" -#include "wpa2/tls/tls.h" -//#include "eap_common/chap.h" -#include "wpa2/eap_peer/eap.h" -#include "wpa2/eap_peer/eap_ttls.h" -#include "wpa2/eap_peer/mschapv2.h" -//#include "wpa2/eap_peer/chap.h" -#include "wpa2/eap_peer/eap_i.h" -#include "wpa2/eap_peer/eap_tls_common.h" -#include "wpa2/eap_peer/eap_config.h" -#include "wpa2/eap_peer/eap_methods.h" +#include "tls/tls.h" +#include "eap_peer/eap.h" +#include "eap_peer/eap_ttls.h" +#include "eap_peer/mschapv2.h" +#include "eap_peer/eap_i.h" +#include "eap_peer/eap_tls_common.h" +#include "eap_peer/eap_config.h" +#include "eap_peer/eap_methods.h" #define EAP_TTLS_VERSION 0 @@ -73,7 +70,6 @@ static void * eap_ttls_init(struct eap_sm *sm) { struct eap_ttls_data *data; struct eap_peer_config *config = eap_get_config(sm); - //char *selected; data = (struct eap_ttls_data *)os_zalloc(sizeof(*data)); if (data == NULL) @@ -83,7 +79,6 @@ static void * eap_ttls_init(struct eap_sm *sm) /* selected = "MSCHAPV2"; - //TODO: Now only support EAP-TTLS/MSCHAPV2 if (config && config->phase2) { if (os_strstr(config->phase2, "autheap=")) { selected = "EAP"; @@ -187,32 +182,6 @@ static u8 * eap_ttls_avp_add(u8 *start, u8 *avphdr, u32 avp_code, return pos; } -#if 0 -static int eap_ttls_avp_encapsulate(struct wpabuf **resp, u32 avp_code, - int mandatory) -{ - struct wpabuf *msg; - u8 *avp, *pos; - - msg = wpabuf_alloc(sizeof(struct ttls_avp) + wpabuf_len(*resp) + 4); - if (msg == NULL) { - wpabuf_free(*resp); - *resp = NULL; - return -1; - } - - avp = wpabuf_mhead(msg); - pos = eap_ttls_avp_hdr(avp, avp_code, 0, mandatory, wpabuf_len(*resp)); - os_memcpy(pos, wpabuf_head(*resp), wpabuf_len(*resp)); - pos += wpabuf_len(*resp); - AVP_PAD(avp, pos); - wpabuf_free(*resp); - wpabuf_put(msg, pos - avp); - *resp = msg; - return 0; -} -#endif - static int eap_ttls_v0_derive_key(struct eap_sm *sm, struct eap_ttls_data *data) { @@ -244,170 +213,6 @@ static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm, return eap_peer_tls_derive_key(sm, &data->ssl, "ttls challenge", len); } -#if 0 -static void eap_ttls_phase2_select_eap_method(struct eap_ttls_data *data, - u8 method) -{ - size_t i; - for (i = 0; i < data->num_phase2_eap_types; i++) { - if (data->phase2_eap_types[i].vendor != EAP_VENDOR_IETF || - data->phase2_eap_types[i].method != method) - continue; - - data->phase2_eap_type.vendor = - data->phase2_eap_types[i].vendor; - data->phase2_eap_type.method = - data->phase2_eap_types[i].method; - wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected " - "Phase 2 EAP vendor %d method %d\n", - data->phase2_eap_type.vendor, - data->phase2_eap_type.method); - break; - } -} - -static int eap_ttls_phase2_eap_process(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct eap_hdr *hdr, size_t len, - struct wpabuf **resp) -{ - struct wpabuf msg; - struct eap_method_ret iret; - - os_memset(&iret, 0, sizeof(iret)); - wpabuf_set(&msg, hdr, len); - *resp = data->phase2_method->process(sm, data->phase2_priv, &iret, - &msg); - if ((iret.methodState == METHOD_DONE || - iret.methodState == METHOD_MAY_CONT) && - (iret.decision == DECISION_UNCOND_SUCC || - iret.decision == DECISION_COND_SUCC || - iret.decision == DECISION_FAIL)) { - ret->methodState = iret.methodState; - ret->decision = iret.decision; - } - - return 0; -} - - -static int eap_ttls_phase2_request_eap_method(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct eap_hdr *hdr, size_t len, - u8 method, struct wpabuf **resp) -{ -#ifdef EAP_TNC - if (data->tnc_started && data->phase2_method && - data->phase2_priv && method == EAP_TYPE_TNC && - data->phase2_eap_type.method == EAP_TYPE_TNC) - return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len, - resp); - - if (data->ready_for_tnc && !data->tnc_started && - method == EAP_TYPE_TNC) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed " - "EAP method\n"); - data->tnc_started = 1; - } - - if (data->tnc_started) { - if (data->phase2_eap_type.vendor != EAP_VENDOR_IETF || - data->phase2_eap_type.method == EAP_TYPE_TNC) { - wpa_printf(MSG_ERROR, "EAP-TTLS: Unexpected EAP " - "type %d for TNC\n", method); - return -1; - } - - data->phase2_eap_type.vendor = EAP_VENDOR_IETF; - data->phase2_eap_type.method = method; - wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected " - "Phase 2 EAP vendor %d method %d (TNC)\n", - data->phase2_eap_type.vendor, - data->phase2_eap_type.method); - - if (data->phase2_type == EAP_TTLS_PHASE2_EAP) - eap_ttls_phase2_eap_deinit(sm, data); - } -#endif /* EAP_TNC */ - - if (data->phase2_eap_type.vendor == EAP_VENDOR_IETF && - data->phase2_eap_type.method == EAP_TYPE_NONE) - eap_ttls_phase2_select_eap_method(data, method); - - if (method != data->phase2_eap_type.method || method == EAP_TYPE_NONE) - { - return -1; - if (eap_peer_tls_phase2_nak(data->phase2_eap_types, - data->num_phase2_eap_types, - hdr, resp)) - return -1; - return 0; - - } - - if (data->phase2_priv == NULL) { - data->phase2_method = eap_peer_get_eap_method( - EAP_VENDOR_IETF, method); - if (data->phase2_method) { - sm->init_phase2 = 1; - data->phase2_priv = data->phase2_method->init(sm); - sm->init_phase2 = 0; - } - } - if (data->phase2_priv == NULL || data->phase2_method == NULL) { - wpa_printf(MSG_ERROR, "EAP-TTLS: failed to initialize " - "Phase 2 EAP method %d\n", method); - return -1; - } - - return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len, resp); -} - -#if 0 -static int eap_ttls_phase2_request_eap(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct eap_hdr *hdr, - struct wpabuf **resp) -{ - size_t len = be_to_host16(hdr->length); - u8 *pos; - struct eap_peer_config *config = eap_get_config(sm); - - if (len <= sizeof(struct eap_hdr)) { - wpa_printf(MSG_ERROR, "EAP-TTLS: too short " - "Phase 2 request (len=%lu)\n", (unsigned long) len); - return -1; - } - pos = (u8 *) (hdr + 1); - wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP Request: type=%d\n", *pos); - switch (*pos) { - case EAP_TYPE_IDENTITY: - *resp = eap_sm_build_identity_resp(sm, hdr->identifier, 1); - break; - default: - if (eap_ttls_phase2_request_eap_method(sm, data, ret, hdr, len, - *pos, resp) < 0) - return -1; - break; - } - - if (*resp == NULL && - (config->pending_req_identity || config->pending_req_password || - config->pending_req_otp)) { - return 0; - } - - if (*resp == NULL) - return -1; - - return eap_ttls_avp_encapsulate(resp, RADIUS_ATTR_EAP_MESSAGE, 1); -} -#endif -#endif - static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm, struct eap_ttls_data *data, struct eap_method_ret *ret, @@ -507,202 +312,6 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm, #endif /* EAP_MSCHAPv2 */ } -#if 0 -//only support MSCHAPv2 -static int eap_ttls_phase2_request_mschap(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct wpabuf **resp) -{ - struct wpabuf *msg; - u8 *buf, *pos, *challenge; - const u8 *identity, *password; - size_t identity_len, password_len; - int pwhash; - - wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAP Request\n"); - - identity = eap_get_config_identity(sm, &identity_len); - password = eap_get_config_password2(sm, &password_len, &pwhash); - if (identity == NULL || password == NULL) - return -1; - - msg = wpabuf_alloc(identity_len + 1000); - if (msg == NULL) { - wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAP: Failed to allocate memory\n"); - return -1; - } - pos = buf = wpabuf_mhead(msg); - - // User-Name - pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, - identity, identity_len); - - // MS-CHAP-Challenge - challenge = eap_ttls_implicit_challenge( - sm, data, EAP_TTLS_MSCHAP_CHALLENGE_LEN + 1); - if (challenge == NULL) { - wpabuf_free(msg); - wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAP: Failed to derive " - "implicit challenge\n"); - return -1; - } - - pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE, - RADIUS_VENDOR_ID_MICROSOFT, 1, - challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN); - - // MS-CHAP-Response - pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP_RESPONSE, - RADIUS_VENDOR_ID_MICROSOFT, 1, - EAP_TTLS_MSCHAP_RESPONSE_LEN); - data->ident = challenge[EAP_TTLS_MSCHAP_CHALLENGE_LEN]; - *pos++ = data->ident; - *pos++ = 1; // Flags: Use NT style passwords - os_memset(pos, 0, 24); // LM-Response - pos += 24; - if (pwhash) { - challenge_response(challenge, password, pos); // NT-Response - } else { - nt_challenge_response(challenge, password, password_len, - pos); // NT-Response - } - pos += 24; - os_free(challenge); - AVP_PAD(buf, pos); - - wpabuf_put(msg, pos - buf); - *resp = msg; - - // EAP-TTLS/MSCHAP does not provide tunneled success - // notification, so assume that Phase2 succeeds. - ret->methodState = METHOD_DONE; - ret->decision = DECISION_COND_SUCC; - - return 0; -} - - -static int eap_ttls_phase2_request_pap(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct wpabuf **resp) -{ - struct wpabuf *msg; - u8 *buf, *pos; - size_t pad; - const u8 *identity, *password; - size_t identity_len, password_len; - - wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 PAP Request\n"); - - identity = eap_get_config_identity(sm, &identity_len); - password = eap_get_config_password(sm, &password_len); - if (identity == NULL || password == NULL) - return -1; - - msg = wpabuf_alloc(identity_len + password_len + 100); - if (msg == NULL) { - wpa_printf(MSG_ERROR, "EAP-TTLS/PAP: Failed to allocate memory\n"); - return -1; - } - pos = buf = wpabuf_mhead(msg); - - // User-Name - pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, - identity, identity_len); - - // User-Password; in RADIUS, this is encrypted, but EAP-TTLS encrypts - // the data, so no separate encryption is used in the AVP itself. - // However, the password is padded to obfuscate its length. - pad = password_len == 0 ? 16 : (16 - (password_len & 15)) & 15; - pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_USER_PASSWORD, 0, 1, - password_len + pad); - os_memcpy(pos, password, password_len); - pos += password_len; - os_memset(pos, 0, pad); - pos += pad; - AVP_PAD(buf, pos); - - wpabuf_put(msg, pos - buf); - *resp = msg; - - // EAP-TTLS/PAP does not provide tunneled success notification, - // so assume that Phase2 succeeds. - ret->methodState = METHOD_DONE; - ret->decision = DECISION_COND_SUCC; - - return 0; -} - - -static int eap_ttls_phase2_request_chap(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct wpabuf **resp) -{ - struct wpabuf *msg; - u8 *buf, *pos, *challenge; - const u8 *identity, *password; - size_t identity_len, password_len; - - wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 CHAP Request\n"); - - identity = eap_get_config_identity(sm, &identity_len); - password = eap_get_config_password(sm, &password_len); - if (identity == NULL || password == NULL) - return -1; - - msg = wpabuf_alloc(identity_len + 1000); - if (msg == NULL) { - wpa_printf(MSG_ERROR, "EAP-TTLS/CHAP: Failed to allocate memory\n"); - return -1; - } - pos = buf = wpabuf_mhead(msg); - - // User-Name - pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, - identity, identity_len); - - // CHAP-Challenge - challenge = eap_ttls_implicit_challenge( - sm, data, EAP_TTLS_CHAP_CHALLENGE_LEN + 1); - if (challenge == NULL) { - wpabuf_free(msg); - wpa_printf(MSG_ERROR, "EAP-TTLS/CHAP: Failed to derive " - "implicit challenge\n"); - return -1; - } - - pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_CHAP_CHALLENGE, 0, 1, - challenge, EAP_TTLS_CHAP_CHALLENGE_LEN); - - // CHAP-Password - pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_CHAP_PASSWORD, 0, 1, - 1 + EAP_TTLS_CHAP_PASSWORD_LEN); - data->ident = challenge[EAP_TTLS_CHAP_CHALLENGE_LEN]; - *pos++ = data->ident; - - // MD5(Ident + Password + Challenge) - chap_md5(data->ident, password, password_len, challenge, - EAP_TTLS_CHAP_CHALLENGE_LEN, pos); - - pos += EAP_TTLS_CHAP_PASSWORD_LEN; - os_free(challenge); - AVP_PAD(buf, pos); - - wpabuf_put(msg, pos - buf); - *resp = msg; - - // EAP-TTLS/CHAP does not provide tunneled success - // notification, so assume that Phase2 succeeds. - ret->methodState = METHOD_DONE; - ret->decision = DECISION_COND_SUCC; - - return 0; -} -#endif - static int eap_ttls_phase2_request(struct eap_sm *sm, struct eap_ttls_data *data, struct eap_method_ret *ret, @@ -745,9 +354,7 @@ static int eap_ttls_phase2_request(struct eap_sm *sm, phase2_type == EAP_TTLS_PHASE2_CHAP) { if (eap_get_config_identity(sm, &len) == NULL) { wpa_printf(MSG_ERROR, "EAP-TTLS: Identity not configured\n"); - //eap_sm_request_identity(sm); if (eap_get_config_password(sm, &len) == NULL); - // eap_sm_request_password(sm); printf("[Debug] Return because no identity EAP_TTLS_PHASE2_MSCHAPV2 EAP_TTLS_PHASE2_MSCHAP\n"); return 0; } @@ -755,7 +362,6 @@ static int eap_ttls_phase2_request(struct eap_sm *sm, if (eap_get_config_password(sm, &len) == NULL) { wpa_printf(MSG_ERROR, "EAP-TTLS: Password not configured\n"); printf("[Debug] Return because no password EAP_TTLS_PHASE2_MSCHAPV2 EAP_TTLS_PHASE2_MSCHAP\n"); - //eap_sm_request_password(sm); return 0; } } @@ -992,61 +598,6 @@ static int eap_ttls_encrypt_response(struct eap_sm *sm, return 0; } -#if 0 -static int eap_ttls_process_phase2_eap(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - struct ttls_parse_avp *parse, - struct wpabuf **resp) -{ - struct eap_hdr *hdr; - size_t len; - - if (parse->eapdata == NULL) { - wpa_printf(MSG_ERROR, "EAP-TTLS: No EAP Message in the " - "packet - dropped\n"); - return -1; - } - - hdr = (struct eap_hdr *) parse->eapdata; - - if (parse->eap_len < sizeof(*hdr)) { - wpa_printf(MSG_ERROR, "EAP-TTLS: Too short Phase 2 EAP " - "frame (len=%lu, expected %lu or more) - dropped\n", - (unsigned long) parse->eap_len, - (unsigned long) sizeof(*hdr)); - return -1; - } - len = be_to_host16(hdr->length); - if (len > parse->eap_len) { - wpa_printf(MSG_ERROR, "EAP-TTLS: Length mismatch in Phase 2 " - "EAP frame (EAP hdr len=%lu, EAP data len in " - "AVP=%lu)\n", - (unsigned long) len, - (unsigned long) parse->eap_len); - return -1; - } - wpa_printf(MSG_DEBUG, "EAP-TTLS: received Phase 2: code=%d " - "identifier=%d length=%lu\n", - hdr->code, hdr->identifier, (unsigned long) len); - switch (hdr->code) { - case EAP_CODE_REQUEST: - if (eap_ttls_phase2_request(sm, data, ret, hdr, resp)) { - wpa_printf(MSG_ERROR, "EAP-TTLS: Phase2 Request " - "processing failed\n"); - return -1; - } - break; - default: - wpa_printf(MSG_ERROR, "EAP-TTLS: Unexpected code=%d in " - "Phase 2 EAP header\n", hdr->code); - return -1; - } - - return 0; -} -#endif - static int eap_ttls_process_phase2_mschapv2(struct eap_sm *sm, struct eap_ttls_data *data, struct eap_method_ret *ret, @@ -1149,7 +700,6 @@ static int eap_ttls_process_decrypted(struct eap_sm *sm, struct wpabuf **out_data) { struct wpabuf *resp = NULL; - //struct eap_peer_config *config = eap_get_config(sm); int res; enum phase2_types phase2_type = data->phase2_type; @@ -1242,7 +792,6 @@ static int eap_ttls_implicit_identity_request(struct eap_sm *sm, "processing failed\n"); retval = -1; } else { - //struct eap_peer_config *config = eap_get_config(sm); if (resp == NULL) {/* && (config->pending_req_identity || config->pending_req_password || diff --git a/components/wpa_supplicant/include/wpa2/eap_peer/eap_ttls.h b/components/wpa_supplicant/src/eap_peer/eap_ttls.h similarity index 100% rename from components/wpa_supplicant/include/wpa2/eap_peer/eap_ttls.h rename to components/wpa_supplicant/src/eap_peer/eap_ttls.h diff --git a/components/wpa_supplicant/src/wpa2/eap_peer/mschapv2.c b/components/wpa_supplicant/src/eap_peer/mschapv2.c similarity index 96% rename from components/wpa_supplicant/src/wpa2/eap_peer/mschapv2.c rename to components/wpa_supplicant/src/eap_peer/mschapv2.c index 33351989b5..84859111ec 100644 --- a/components/wpa_supplicant/src/wpa2/eap_peer/mschapv2.c +++ b/components/wpa_supplicant/src/eap_peer/mschapv2.c @@ -4,10 +4,10 @@ #ifdef EAP_MSCHAPv2 -#include "wpa/includes.h" -#include "wpa/common.h" +#include "utils/includes.h" +#include "utils/common.h" #include "crypto/ms_funcs.h" -#include "wpa2/eap_peer/mschapv2.h" +#include "eap_peer/mschapv2.h" const u8 * mschapv2_remove_domain(const u8 *username, size_t *len) { diff --git a/components/wpa_supplicant/include/wpa2/eap_peer/mschapv2.h b/components/wpa_supplicant/src/eap_peer/mschapv2.h similarity index 100% rename from components/wpa_supplicant/include/wpa2/eap_peer/mschapv2.h rename to components/wpa_supplicant/src/eap_peer/mschapv2.h diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_hostap.c b/components/wpa_supplicant/src/esp_supplicant/esp_hostap.c new file mode 100644 index 0000000000..e1eca8b195 --- /dev/null +++ b/components/wpa_supplicant/src/esp_supplicant/esp_hostap.c @@ -0,0 +1,134 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "utils/includes.h" + +#include "utils/common.h" +#include "crypto/sha1.h" +#include "common/ieee802_11_defs.h" +#include "common/eapol_common.h" +#include "ap/wpa_auth.h" +#include "ap/ap_config.h" +#include "utils/wpa_debug.h" +#include "ap/hostapd.h" +#include "ap/wpa_auth_i.h" +#include "esp_wifi_driver.h" +#include "esp_wifi_types.h" + +void *hostap_init(void) +{ + struct wifi_ssid *ssid = esp_wifi_ap_get_prof_ap_ssid_internal(); + struct hostapd_data *hapd = NULL; + struct wpa_auth_config *auth_conf; + u8 mac[6]; + + hapd = (struct hostapd_data *)os_zalloc(sizeof(struct hostapd_data)); + + if (hapd == NULL) { + return NULL; + } + + hapd->conf = (struct hostapd_bss_config *)os_zalloc(sizeof(struct hostapd_bss_config)); + + if (hapd->conf == NULL) { + os_free(hapd); + return NULL; + } + + auth_conf = (struct wpa_auth_config *)os_zalloc(sizeof(struct wpa_auth_config)); + + if (auth_conf == NULL) { + os_free(hapd->conf); + os_free(hapd); + hapd = NULL; + return NULL; + } + if (esp_wifi_ap_get_prof_authmode_internal() == WIFI_AUTH_WPA_PSK) { + auth_conf->wpa = WPA_PROTO_WPA; + } + if (esp_wifi_ap_get_prof_authmode_internal() == WIFI_AUTH_WPA2_PSK) { + auth_conf->wpa = WPA_PROTO_RSN; + } + if (esp_wifi_ap_get_prof_authmode_internal() == WIFI_AUTH_WPA_WPA2_PSK) { + auth_conf->wpa = WPA_PROTO_RSN | WPA_PROTO_WPA; + } + + auth_conf->wpa_group = WPA_CIPHER_TKIP; + auth_conf->wpa_pairwise = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP; + auth_conf->rsn_pairwise = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP; + auth_conf->wpa_key_mgmt = WPA_KEY_MGMT_PSK; + auth_conf->eapol_version = EAPOL_VERSION; + + memcpy(hapd->conf->ssid.ssid, ssid->ssid, ssid->len); + hapd->conf->ssid.ssid_len = ssid->len; + hapd->conf->ssid.wpa_passphrase = (char *)os_zalloc(64); + if (hapd->conf->ssid.wpa_passphrase == NULL) { + os_free(auth_conf); + os_free(hapd->conf); + os_free(hapd); + hapd = NULL; + return NULL; + } + memcpy(hapd->conf->ssid.wpa_passphrase, esp_wifi_ap_get_prof_password_internal(), strlen((char *)esp_wifi_ap_get_prof_password_internal())); + + hapd->conf->ap_max_inactivity = 5 * 60; + hostapd_setup_wpa_psk(hapd->conf); + + esp_wifi_get_macaddr_internal(WIFI_IF_AP, mac); + + hapd->wpa_auth = wpa_init(mac, auth_conf, NULL); + esp_wifi_set_appie_internal(WIFI_APPIE_WPA, hapd->wpa_auth->wpa_ie, (uint16_t)hapd->wpa_auth->wpa_ie_len, 0); //michael ML + os_free(auth_conf); + + return (void *)hapd; +} + +bool hostap_deinit(void *data) +{ + struct hostapd_data *hapd = (struct hostapd_data *)data; + + if (hapd == NULL) { + return true; + } + + if (hapd->wpa_auth->wpa_ie != NULL) { + os_free(hapd->wpa_auth->wpa_ie); + } + + if (hapd->wpa_auth->group != NULL) { + os_free(hapd->wpa_auth->group); + } + + if (hapd->wpa_auth != NULL) { + os_free(hapd->wpa_auth); + } + + if (hapd->conf->ssid.wpa_psk != NULL) { + os_free(hapd->conf->ssid.wpa_psk); + } + + if (hapd->conf->ssid.wpa_passphrase != NULL) { + os_free(hapd->conf->ssid.wpa_passphrase); + } + + if (hapd->conf != NULL) { + os_free(hapd->conf); + } + + if (hapd != NULL) { + os_free(hapd); + } + + return true; +} diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_hostap.h b/components/wpa_supplicant/src/esp_supplicant/esp_hostap.h new file mode 100644 index 0000000000..59a183f21e --- /dev/null +++ b/components/wpa_supplicant/src/esp_supplicant/esp_hostap.h @@ -0,0 +1,21 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ESP_HOSTAP_H +#define ESP_HOSTAP_H + +void *hostap_init(void); +bool hostap_deinit(void *data); + +#endif /* ESP_HOSTAP_H */ diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h b/components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h new file mode 100644 index 0000000000..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..d565cd1cba --- /dev/null +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c @@ -0,0 +1,239 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "utils/includes.h" +#include "utils/common.h" +#include "rsn_supp/wpa.h" +#include "rsn_supp/wpa_i.h" +#include "common/eapol_common.h" +#include "common/ieee802_11_defs.h" +#include "rsn_supp/wpa_ie.h" +#include "ap/wpa_auth.h" +#include "ap/wpa_auth_i.h" +#include "ap/ap_config.h" +#include "ap/hostapd.h" +#include "esp_wpas_glue.h" +#include "esp_hostap.h" + +#include "crypto/crypto.h" +#include "crypto/sha1.h" +#include "crypto/aes_wrap.h" +#include "crypto/wepkey.h" + +#include "esp_wifi_driver.h" +#include "esp_private/wifi.h" + +void wpa_install_key(enum wpa_alg alg, u8 *addr, int key_idx, int set_tx, + u8 *seq, size_t seq_len, u8 *key, size_t key_len, int key_entry_valid) +{ + esp_wifi_set_sta_key_internal(alg, addr, key_idx, set_tx, seq, seq_len, key, key_len, key_entry_valid); +} + +int wpa_get_key(uint8_t *ifx, int *alg, u8 *addr, int *key_idx, + u8 *key, size_t key_len, int key_entry_valid) +{ + return esp_wifi_get_sta_key_internal(ifx, alg, addr, key_idx, key, key_len, key_entry_valid); +} + +/** + * eapol_sm_notify_eap_success - Notification of external EAP success trigger + * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() + * @success: %TRUE = set success, %FALSE = clear success + * + * Notify the EAPOL state machine that external event has forced EAP state to + * success (success = %TRUE). This can be cleared by setting success = %FALSE. + * + * This function is called to update EAP state when WPA-PSK key handshake has + * been completed successfully since WPA-PSK does not use EAP state machine. + */ + +/* fix buf for tx for now */ +#define WPA_TX_MSG_BUFF_MAXLEN 200 + +void wpa_sendto_wrapper(void *buffer, u16 len) +{ + esp_wifi_internal_tx(0, buffer, len); +} + +void wpa_deauthenticate(u8 reason_code) +{ + esp_wifi_deauthenticate_internal(reason_code); +} + +void wpa_config_profile() +{ + if (esp_wifi_sta_prof_is_wpa_internal()) { + wpa_set_profile(WPA_PROTO_WPA, esp_wifi_sta_get_prof_authmode_internal()); + } else if (esp_wifi_sta_prof_is_wpa2_internal()) { + wpa_set_profile(WPA_PROTO_RSN, esp_wifi_sta_get_prof_authmode_internal()); + } else { + WPA_ASSERT(0); + } +} + +int wpa_config_bss(uint8_t *bssid) +{ + struct wifi_ssid *ssid = esp_wifi_sta_get_prof_ssid_internal(); + u8 mac[6]; + + esp_wifi_get_macaddr_internal(0, mac); + wpa_set_bss((char *)mac, (char *)bssid, esp_wifi_sta_get_pairwise_cipher_internal(), esp_wifi_sta_get_group_cipher_internal(), + (char *)esp_wifi_sta_get_prof_password_internal(), ssid->ssid, ssid->len); + return ESP_OK; +} + +void wpa_config_assoc_ie(u8 proto, u8 *assoc_buf, u32 assoc_wpa_ie_len) +{ + if (proto == BIT(0)) { + esp_wifi_set_appie_internal(WIFI_APPIE_WPA, assoc_buf, assoc_wpa_ie_len, 1); + } else { + esp_wifi_set_appie_internal(WIFI_APPIE_RSN, assoc_buf, assoc_wpa_ie_len, 1); + } +} + +void wpa_neg_complete() +{ + esp_wifi_auth_done_internal(); +} + +void wpa_attach(void) +{ +#ifndef IOT_SIP_MODE + wpa_register(NULL, wpa_sendto_wrapper, + wpa_config_assoc_ie, wpa_install_key, wpa_get_key, wpa_deauthenticate, wpa_neg_complete); +#else + u8 *payload = (u8 *)os_malloc(WPA_TX_MSG_BUFF_MAXLEN); + wpa_register(payload, wpa_sendto_wrapper, + wpa_config_assoc_ie, wpa_install_key, wpa_get_key, wpa_deauthenticate, wpa_neg_complete); +#endif + + esp_wifi_register_tx_cb_internal(eapol_txcb, WIFI_TXCB_EAPOL_ID); +} + +uint8_t *wpa_ap_get_wpa_ie(uint8_t *ie_len) +{ + struct hostapd_data *hapd = (struct hostapd_data *)esp_wifi_get_hostap_private_internal(); + + if (!hapd || !hapd->wpa_auth || !hapd->wpa_auth->wpa_ie) { + return NULL; + } + + *ie_len = hapd->wpa_auth->wpa_ie_len; + return hapd->wpa_auth->wpa_ie; +} + +bool wpa_ap_rx_eapol(void *hapd_data, void *sm_data, u8 *data, size_t data_len) +{ + struct hostapd_data *hapd = (struct hostapd_data *)hapd_data; + struct wpa_state_machine *sm = (struct wpa_state_machine *)sm_data; + + if (!hapd || !sm) { + return false; + } + + wpa_receive(hapd->wpa_auth, sm, data, data_len); + + return true; +} + +bool wpa_deattach(void) +{ + return true; +} + +void wpa_sta_connect(uint8_t *bssid) +{ + wpa_config_profile(); + wpa_config_bss(bssid); +} + +int cipher_type_map(int wpa_cipher) +{ + switch (wpa_cipher) { + case WPA_CIPHER_NONE: + return WIFI_CIPHER_TYPE_NONE; + + case WPA_CIPHER_WEP40: + return WIFI_CIPHER_TYPE_WEP40; + + case WPA_CIPHER_WEP104: + return WIFI_CIPHER_TYPE_WEP104; + + case WPA_CIPHER_TKIP: + return WIFI_CIPHER_TYPE_TKIP; + + case WPA_CIPHER_CCMP: + return WIFI_CIPHER_TYPE_CCMP; + + case WPA_CIPHER_CCMP|WPA_CIPHER_TKIP: + return WIFI_CIPHER_TYPE_TKIP_CCMP; + + default: + return WIFI_CIPHER_TYPE_UNKNOWN; + } +} + +int wpa_parse_wpa_ie_wrapper(const u8 *wpa_ie, size_t wpa_ie_len, wifi_wpa_ie_t *data) +{ + struct wpa_ie_data ie; + int ret = 0; + + ret = wpa_parse_wpa_ie(wpa_ie, wpa_ie_len, &ie); + data->proto = ie.proto; + data->pairwise_cipher = cipher_type_map(ie.pairwise_cipher); + data->group_cipher = cipher_type_map(ie.group_cipher); + data->key_mgmt = ie.key_mgmt; + data->capabilities = ie.capabilities; + data->pmkid = ie.pmkid; + data->mgmt_group_cipher = cipher_type_map(ie.mgmt_group_cipher); + + return ret; +} + +int esp_supplicant_init(void) +{ + struct wpa_funcs *wpa_cb; + + wpa_cb = (struct wpa_funcs *)os_malloc(sizeof(struct wpa_funcs)); + if (!wpa_cb) { + return ESP_ERR_NO_MEM; + } + + wpa_cb->wpa_sta_init = wpa_attach; + wpa_cb->wpa_sta_deinit = wpa_deattach; + wpa_cb->wpa_sta_rx_eapol = wpa_sm_rx_eapol; + wpa_cb->wpa_sta_connect = wpa_sta_connect; + wpa_cb->wpa_sta_in_4way_handshake = wpa_sta_in_4way_handshake; + + wpa_cb->wpa_ap_join = wpa_ap_join; + wpa_cb->wpa_ap_remove = wpa_ap_remove; + wpa_cb->wpa_ap_get_wpa_ie = wpa_ap_get_wpa_ie; + wpa_cb->wpa_ap_rx_eapol = wpa_ap_rx_eapol; + wpa_cb->wpa_ap_init = hostap_init; + wpa_cb->wpa_ap_deinit = hostap_deinit; + + wpa_cb->wpa_config_parse_string = wpa_config_parse_string; + wpa_cb->wpa_parse_wpa_ie = wpa_parse_wpa_ie_wrapper; + wpa_cb->wpa_config_bss = wpa_config_bss; + wpa_cb->wpa_michael_mic_failure = wpa_michael_mic_failure; + + esp_wifi_register_wpa_cb_internal(wpa_cb); + + return ESP_OK; +} + +bool wpa_hook_deinit(void) +{ + return esp_wifi_unregister_wpa_cb_internal(); +} diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wpas_glue.c b/components/wpa_supplicant/src/esp_supplicant/esp_wpas_glue.c new file mode 100644 index 0000000000..89c901f802 --- /dev/null +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wpas_glue.c @@ -0,0 +1,114 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifdef ESP_SUPPLICANT + +#include "utils/includes.h" +#include "utils/common.h" +#include "common/eapol_common.h" +#include "rsn_supp/wpa.h" + +u8 *wpa_sm_alloc_eapol(struct wpa_sm *sm, u8 type, + const void *data, u16 data_len, + size_t *msg_len, void **data_pos) +{ + void *buffer; + struct ieee802_1x_hdr *hdr; + + *msg_len = sizeof(struct ieee802_1x_hdr) + data_len; + + buffer = os_malloc(*msg_len + sizeof(struct l2_ethhdr)); + + if (buffer == NULL) { + return NULL; + } + + /* XXX: reserve l2_ethhdr is enough */ + hdr = (struct ieee802_1x_hdr *)((char *)buffer + sizeof(struct l2_ethhdr)); + + hdr->version = sm->eapol_version; + hdr->type = type; + hdr->length = host_to_be16(data_len); + + if (data) { + memcpy(hdr + 1, data, data_len); + } else { + memset(hdr + 1, 0, data_len); + } + + if (data_pos) { + *data_pos = hdr + 1; + } + + return (u8 *) hdr; +} + +void wpa_sm_free_eapol(u8 *buffer) +{ + buffer = buffer - sizeof(struct l2_ethhdr); + os_free(buffer); +} + +void wpa_sm_deauthenticate(struct wpa_sm *sm, u8 reason_code) +{ + + /*only need send deauth frame when associated*/ + if (WPA_SM_STATE(sm) >= WPA_ASSOCIATED) { + sm->wpa_deauthenticate(reason_code); + } +} + +/** + * mlme_setprotection - MLME-SETPROTECTION.request primitive + * @priv: Private driver interface data + * @addr: Address of the station for which to set protection (may be + * %NULL for group keys) + * @protect_type: MLME_SETPROTECTION_PROTECT_TYPE_* + * @key_type: MLME_SETPROTECTION_KEY_TYPE_* + * Returns: 0 on success, -1 on failure + * + * This is an optional function that can be used to set the driver to + * require protection for Tx and/or Rx frames. This uses the layer + * interface defined in IEEE 802.11i-2004 clause 10.3.22.1 + * (MLME-SETPROTECTION.request). Many drivers do not use explicit + * set protection operation; instead, they set protection implicitly + * based on configured keys. + */ +int wpa_sm_mlme_setprotection(struct wpa_sm *sm, const u8 *addr, + int protect_type, int key_type) +{ + return 0; +} + +/* + *use above two functions to get wpa_ie and rsn_ie, then don't need wpa_sm_get_beacon_ie function +*/ +int wpa_sm_get_beacon_ie(struct wpa_sm *sm) +{ + return 0; +} + +/** + * wpa_supplicant_disassociate - Disassociate the current connection + * @wpa_s: Pointer to wpa_supplicant data + * @reason_code: IEEE 802.11 reason code for the disassociate frame + * + * This function is used to request %wpa_supplicant to disassociate with the + * current AP. + */ +void wpa_sm_disassociate(struct wpa_sm *sm, int reason_code) +{ + /*check if need clear internal state and data value*/ +} +#endif diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wpas_glue.h b/components/wpa_supplicant/src/esp_supplicant/esp_wpas_glue.h new file mode 100644 index 0000000000..4d867962e7 --- /dev/null +++ b/components/wpa_supplicant/src/esp_supplicant/esp_wpas_glue.h @@ -0,0 +1,33 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef WPAS_GLUE_H +#define WPAS_GLUE_H + +u8 *wpa_sm_alloc_eapol(struct wpa_sm *sm, u8 type, + const void *data, u16 data_len, + size_t *msg_len, void **data_pos); + +int wpa_sm_mlme_setprotection(struct wpa_sm *sm, const u8 *addr, + int protect_type, int key_type); + +void wpa_sm_deauthenticate(struct wpa_sm *sm, u8 reason_code); + +void wpa_sm_disassociate(struct wpa_sm *sm, int reason_code); + +int wpa_sm_get_beacon_ie(struct wpa_sm *sm); + +void wpa_sm_free_eapol(u8 *buffer); + +#endif /* WPAS_GLUE_H */ diff --git a/components/wpa_supplicant/src/esp_supplicant/esp_wps.c b/components/wpa_supplicant/src/esp_supplicant/esp_wps.c new file mode 100644 index 0000000000..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..2ce7bbebe5 --- /dev/null +++ b/components/wpa_supplicant/src/rsn_supp/wpa.c @@ -0,0 +1,1976 @@ + +/* + * WPA Supplicant - WPA state machine and EAPOL-Key processing + * Copyright (c) 2003-2010, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ +#include "utils/includes.h" + +#include "utils/common.h" +#include "rsn_supp/wpa.h" +#include "rsn_supp/wpa_i.h" +#include "common/eapol_common.h" +#include "common/ieee802_11_defs.h" +#include "rsn_supp/wpa_ie.h" +#include "esp_supplicant/esp_wpas_glue.h" +#include "esp_supplicant/esp_wifi_driver.h" + +#include "crypto/crypto.h" +#include "crypto/sha1.h" +#include "crypto/aes_wrap.h" +#include "crypto/wepkey.h" + +/** + * eapol_sm_notify_eap_success - Notification of external EAP success trigger + * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() + * @success: %TRUE = set success, %FALSE = clear success + * + * Notify the EAPOL state machine that external event has forced EAP state to + * success (success = %TRUE). This can be cleared by setting success = %FALSE. + * + * This function is called to update EAP state when WPA-PSK key handshake has + * been completed successfully since WPA-PSK does not use EAP state machine. + */ + +#define WPA_4_4_HANDSHAKE_BIT (1<<13) +#define WPA_GROUP_HANDSHAKE_BIT (1<<14) + struct wpa_sm gWpaSm; +/* fix buf for tx for now */ +#define WPA_TX_MSG_BUFF_MAXLEN 200 + +#define ASSOC_IE_LEN 24 +u8 assoc_ie_buf[ASSOC_IE_LEN+2]; + +void set_assoc_ie(u8 * assoc_buf); + +int wpa_sm_set_key(struct install_key *sm, enum wpa_alg alg, + u8 *addr, int key_idx, int set_tx, + u8 *seq, size_t seq_len, + u8 *key, size_t key_len, + int key_entry_valid); + +int wpa_sm_get_key(uint8_t *ifx, int *alg, u8 *addr, int *key_idx, u8 *key, size_t key_len, int key_entry_valid); + +void wpa_set_passphrase(char * passphrase, u8 *ssid, size_t ssid_len); + +static inline enum wpa_states wpa_sm_get_state(struct wpa_sm *sm) +{ + return sm->wpa_state;; +} + +static inline void wpa_sm_cancel_auth_timeout(struct wpa_sm *sm) +{ + +} + +void eapol_sm_notify_eap_success(Boolean success) +{ + +} +/** + * get_bssid - Get the current BSSID + * @priv: private driver interface data + * @bssid: buffer for BSSID (ETH_ALEN = 6 bytes) + * + * Returns: 0 on success, -1 on failure + * + * Query kernel driver for the current BSSID and copy it to bssid. + * Setting bssid to 00:00:00:00:00:00 is recommended if the STA is not + * associated. + */ +static inline int wpa_sm_get_bssid(struct wpa_sm *sm, u8 *bssid) +{ + memcpy(bssid, sm->bssid, ETH_ALEN); + return 0; +} + + /* + * wpa_ether_send - Send Ethernet frame + * @wpa_s: Pointer to wpa_supplicant data + * @dest: Destination MAC address + * @proto: Ethertype in host byte order + * @buf: Frame payload starting from IEEE 802.1X header + * @len: Frame payload length + * Returns: >=0 on success, <0 on failure + */ +static inline int wpa_sm_ether_send( struct wpa_sm *sm, const u8 *dest, u16 proto, + const u8 *data, size_t data_len) +{ + void *buffer = (void *)(data - sizeof(struct l2_ethhdr)); + struct l2_ethhdr *eth = (struct l2_ethhdr *)buffer; + + memcpy(eth->h_dest, dest, ETH_ALEN); + memcpy(eth->h_source, sm->own_addr, ETH_ALEN); + eth->h_proto = host_to_be16(proto); + sm->sendto(buffer, sizeof(struct l2_ethhdr) + data_len); + + return 0; +} + +/** + * wpa_eapol_key_send - Send WPA/RSN EAPOL-Key message + * @sm: Pointer to WPA state machine data from wpa_sm_init() + * @kck: Key Confirmation Key (KCK, part of PTK) + * @ver: Version field from Key Info + * @dest: Destination address for the frame + * @proto: Ethertype (usually ETH_P_EAPOL) + * @msg: EAPOL-Key message + * @msg_len: Length of message + * @key_mic: Pointer to the buffer to which the EAPOL-Key MIC is written + */ +void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, + int ver, const u8 *dest, u16 proto, + u8 *msg, size_t msg_len, u8 *key_mic) +{ + if (is_zero_ether_addr(dest) && is_zero_ether_addr(sm->bssid)) { + /* + * Association event was not yet received; try to fetch + * BSSID from the driver. + */ + if (wpa_sm_get_bssid(sm, sm->bssid) < 0) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Failed to read BSSID for " + "EAPOL-Key destination address"); + #endif + } else { + dest = sm->bssid; + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Use BSSID (" MACSTR + ") as the destination for EAPOL-Key", + MAC2STR(dest)); + #endif + } + } + if (key_mic && + wpa_eapol_key_mic(kck, ver, msg, msg_len, key_mic)) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Failed to generate EAPOL-Key " + "version %d MIC", ver); + #endif + goto out; + } + wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key", msg, msg_len); + wpa_sm_ether_send(sm, dest, proto, msg, msg_len); +out: + return; +} + +/** + * wpa_sm_key_request - Send EAPOL-Key Request + * @sm: Pointer to WPA state machine data from wpa_sm_init() + * @error: Indicate whether this is an Michael MIC error report + * @pairwise: 1 = error report for pairwise packet, 0 = for group packet + * + * Send an EAPOL-Key Request to the current authenticator. This function is + * used to request rekeying and it is usually called when a local Michael MIC + * failure is detected. + */ +void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise) +{ + size_t rlen; + struct wpa_eapol_key *reply; + int key_info, ver; + u8 bssid[ETH_ALEN], *rbuf; + + if (wpa_key_mgmt_ft(sm->key_mgmt) || wpa_key_mgmt_sha256(sm->key_mgmt)) + ver = WPA_KEY_INFO_TYPE_AES_128_CMAC; + else if (sm->pairwise_cipher == WPA_CIPHER_CCMP) + ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES; + else + ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4; + + if (wpa_sm_get_bssid(sm, bssid) < 0) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "Failed to read BSSID for EAPOL-Key " + "request"); + #endif + return; + } + + rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, + sizeof(*reply), &rlen, (void *) &reply); + if (rbuf == NULL) + return; + + reply->type = sm->proto == WPA_PROTO_RSN ? + EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; + key_info = WPA_KEY_INFO_REQUEST | ver; + if (sm->ptk_set) + key_info |= WPA_KEY_INFO_MIC; + if (error) + key_info |= WPA_KEY_INFO_ERROR|WPA_KEY_INFO_SECURE; + if (pairwise) + key_info |= WPA_KEY_INFO_KEY_TYPE; + WPA_PUT_BE16(reply->key_info, key_info); + WPA_PUT_BE16(reply->key_length, 0); + memcpy(reply->replay_counter, sm->request_counter, + WPA_REPLAY_COUNTER_LEN); + inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN); + + WPA_PUT_BE16(reply->key_data_length, 0); + + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Sending EAPOL-Key Request (error=%d " + "pairwise=%d ptk_set=%d len=%lu)", + error, pairwise, sm->ptk_set, (unsigned long) rlen); + #endif + wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL, + rbuf, rlen, key_info & WPA_KEY_INFO_MIC ? + reply->key_mic : NULL); + wpa_sm_free_eapol(rbuf); +} + +int wpa_supplicant_get_pmk(struct wpa_sm *sm) +{ + if(sm->pmk_len >0) { + return 0; + } else { + return 1; + } +} + +/** + * wpa_supplicant_send_2_of_4 - Send message 2 of WPA/RSN 4-Way Handshake + * @sm: Pointer to WPA state machine data from wpa_sm_init() + * @dst: Destination address for the frame + * @key: Pointer to the EAPOL-Key frame header + * @ver: Version bits from EAPOL-Key Key Info + * @nonce: Nonce value for the EAPOL-Key frame + * @wpa_ie: WPA/RSN IE + * @wpa_ie_len: Length of the WPA/RSN IE + * @ptk: PTK to use for keyed hash and encryption + * Returns: 0 on success, -1 on failure + */ +int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, + const struct wpa_eapol_key *key, + int ver, const u8 *nonce, + const u8 *wpa_ie, size_t wpa_ie_len, + struct wpa_ptk *ptk) +{ + size_t rlen; + struct wpa_eapol_key *reply; + u8 *rbuf; + + if (wpa_ie == NULL) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_ERROR, "WPA: No wpa_ie set - cannot " + "generate msg 2/4"); + #endif + return -1; + } + + wpa_hexdump(MSG_MSGDUMP, "WPA: WPA IE for msg 2/4\n", wpa_ie, wpa_ie_len); + + rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, + NULL, sizeof(*reply) + wpa_ie_len, + &rlen, (void *) &reply); + if (rbuf == NULL) { + return -1; + } + + reply->type = sm->proto == WPA_PROTO_RSN ? + EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; + WPA_PUT_BE16(reply->key_info, + ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC); + if (sm->proto == WPA_PROTO_RSN) + WPA_PUT_BE16(reply->key_length, 0); + else + memcpy(reply->key_length, key->key_length, 2); + + memcpy(reply->replay_counter, key->replay_counter, + WPA_REPLAY_COUNTER_LEN); + + WPA_PUT_BE16(reply->key_data_length, wpa_ie_len); + memcpy(reply + 1, wpa_ie, wpa_ie_len); + + memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN); + + wpa_printf(MSG_DEBUG, "WPA Send EAPOL-Key 2/4\n"); + + wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL, + rbuf, rlen, reply->key_mic); + wpa_sm_free_eapol(rbuf); + + return 0; +} + +int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr, + const struct wpa_eapol_key *key, + struct wpa_ptk *ptk) +{ + size_t ptk_len = sm->pairwise_cipher == WPA_CIPHER_CCMP ? 48 : 64; + + wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion", + sm->own_addr, sm->bssid, sm->snonce, key->key_nonce, + (u8 *) ptk, ptk_len, + wpa_key_mgmt_sha256(sm->key_mgmt)); + return 0; +} + +void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, + const unsigned char *src_addr, + const struct wpa_eapol_key *key, + u16 ver) +{ + struct wpa_eapol_ie_parse ie; + struct wpa_ptk *ptk; + int res; + + wpa_sm_set_state(WPA_FIRST_HALF_4WAY_HANDSHAKE); + + wpa_printf(MSG_DEBUG, "WPA 1/4-Way Handshake\n"); + + memset(&ie, 0, sizeof(ie)); + +#ifndef CONFIG_NO_WPA2 + if (sm->proto == WPA_PROTO_RSN) { + /* RSN: msg 1/4 should contain PMKID for the selected PMK */ + const u8 *_buf = (const u8 *) (key + 1); + size_t len = WPA_GET_BE16(key->key_data_length); + wpa_hexdump(MSG_MSGDUMP, "RSN: msg 1/4 key data", _buf, len); + wpa_supplicant_parse_ies(_buf, len, &ie); + if (ie.pmkid) { + wpa_hexdump(MSG_DEBUG, "RSN: PMKID from " + "Authenticator", ie.pmkid, PMKID_LEN); + } + } +#endif /* CONFIG_NO_WPA2 */ + + res = wpa_supplicant_get_pmk(sm); + if (res == -2) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "RSN: Do not reply to msg 1/4 - " + "requesting full EAP authentication"); + #endif + return; + } + if (res) + goto failed; + + if (sm->renew_snonce) { + if (os_get_random(sm->snonce, WPA_NONCE_LEN)) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Failed to get random data for SNonce"); + #endif + goto failed; + } + + sm->renew_snonce = 0; + wpa_hexdump(MSG_DEBUG, "WPA: Renewed SNonce", + sm->snonce, WPA_NONCE_LEN); + } + + /* Calculate PTK which will be stored as a temporary PTK until it has + * been verified when processing message 3/4. */ + ptk = &sm->tptk; + wpa_derive_ptk(sm, src_addr, key, ptk); + /* Supplicant: swap tx/rx Mic keys */ + sm->tptk_set = 1; + sm->ptk_set = 0; + sm->key_install = true; + + if (wpa_supplicant_send_2_of_4(sm, sm->bssid, key, ver, sm->snonce, + sm->assoc_wpa_ie, sm->assoc_wpa_ie_len, + ptk)) + goto failed; + + memcpy(sm->anonce, key->key_nonce, WPA_NONCE_LEN); + return; + +failed: + wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED); +} + + void wpa_sm_rekey_ptk(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_sm *sm = eloop_ctx; + + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Request PTK rekeying"); + #endif + wpa_sm_key_request(sm, 0, 1); +} + + +int wpa_supplicant_install_ptk(struct wpa_sm *sm) +{ + int keylen; + enum wpa_alg alg; + + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Installing PTK to the driver.\n"); + #endif + + switch (sm->pairwise_cipher) { + case WPA_CIPHER_CCMP: + alg = WPA_ALG_CCMP; + keylen = 16; + break; + case WPA_CIPHER_TKIP: + alg = WPA_ALG_TKIP; + keylen = 32; + break; + case WPA_CIPHER_NONE: + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Pairwise Cipher Suite: " + "NONE - do not use pairwise keys"); + #endif + return 0; + default: + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Unsupported pairwise cipher %d", + sm->pairwise_cipher); + #endif + return -1; + } + + //now only use keyentry 0 for pairwise key + sm->key_entry_valid = 5; + + if (wpa_sm_set_key(&(sm->install_ptk), alg, sm->bssid, 0, 1, (sm->install_ptk).seq, WPA_KEY_RSC_LEN, + (u8 *) sm->ptk.tk1, keylen,sm->key_entry_valid) < 0) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Failed to set PTK to the " + "driver (alg=%d keylen=%d bssid=" MACSTR ")", + alg, keylen, MAC2STR(sm->bssid)); + #endif + return -1; + } + + if (sm->wpa_ptk_rekey) { + eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL); + eloop_register_timeout(sm->wpa_ptk_rekey, 0, wpa_sm_rekey_ptk, + sm, NULL); + } + + return 0; +} + +int wpa_supplicant_check_group_cipher(int group_cipher, + int keylen, int maxkeylen, + int *key_rsc_len, + enum wpa_alg *alg) +{ + int ret = 0; + + switch (group_cipher) { + case WPA_CIPHER_CCMP: + if (keylen != 16 || maxkeylen < 16) { + ret = -1; + break; + } + *key_rsc_len = 6; + *alg = WPA_ALG_CCMP; + break; + case WPA_CIPHER_TKIP: + if (keylen != 32 || maxkeylen < 32) { + ret = -1; + break; + } + *key_rsc_len = 6; + *alg = WPA_ALG_TKIP; + break; + case WPA_CIPHER_WEP104: + if (keylen != 13 || maxkeylen < 13) { + ret = -1; + break; + } + *key_rsc_len = 0; + *alg = WPA_ALG_WEP104; + break; + case WPA_CIPHER_WEP40: + if (keylen != 5 || maxkeylen < 5) { + ret = -1; + break; + } + *key_rsc_len = 0; + *alg = WPA_ALG_WEP40; + break; + default: + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Unsupported Group Cipher %d", + group_cipher); + #endif + return -1; + } + + if (ret < 0 ) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Unsupported %s Group Cipher key " + "length %d (%d).", + wpa_cipher_txt(group_cipher), keylen, maxkeylen); + #endif + } + + return ret; +} + +void wpa_supplicant_key_neg_complete(struct wpa_sm *sm, + const u8 *addr, int secure) +{ +#ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Key negotiation completed with " + MACSTR " [PTK=%s GTK=%s]\n", MAC2STR(addr), + wpa_cipher_txt(sm->pairwise_cipher), + wpa_cipher_txt(sm->group_cipher)); +#endif + wpa_sm_cancel_auth_timeout(sm); + wpa_sm_set_state(WPA_COMPLETED); + + sm->wpa_neg_complete(); + + if (secure) { + wpa_sm_mlme_setprotection( + sm, addr, MLME_SETPROTECTION_PROTECT_TYPE_RX_TX, + MLME_SETPROTECTION_KEY_TYPE_PAIRWISE); + + if (wpa_key_mgmt_wpa_psk(sm->key_mgmt)) + eapol_sm_notify_eap_success(TRUE); + /* + * Start preauthentication after a short wait to avoid a + * possible race condition between the data receive and key + * configuration after the 4-Way Handshake. This increases the + * likelyhood of the first preauth EAPOL-Start frame getting to + * the target AP. + */ + } + +} + + +int wpa_supplicant_install_gtk(struct wpa_sm *sm, + struct wpa_gtk_data *gd) +{ + u8 *_gtk = gd->gtk; + u8 gtk_buf[32]; + u8 *key_rsc=(sm->install_gtk).seq; + + wpa_hexdump(MSG_DEBUG, "WPA: Group Key", gd->gtk, gd->gtk_len); + + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Installing GTK to the driver " + "(keyidx=%d tx=%d len=%d).\n", gd->keyidx, gd->tx, + gd->gtk_len); + #endif + wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, gd->key_rsc_len); + if (sm->group_cipher == WPA_CIPHER_TKIP) { + /* Swap Tx/Rx keys for Michael MIC */ + memcpy(gtk_buf, gd->gtk, 16); + memcpy(gtk_buf + 16, gd->gtk + 16, 8); + memcpy(gtk_buf + 24, gd->gtk + 24, 8); + _gtk = gtk_buf; + } + //now only use keycache entry1 for group key + sm->key_entry_valid = gd->keyidx; + if (sm->pairwise_cipher == WPA_CIPHER_NONE) { + if (wpa_sm_set_key(&(sm->install_gtk), gd->alg, + sm->bssid, //(u8 *) "\xff\xff\xff\xff\xff\xff", + gd->keyidx, 1, key_rsc, gd->key_rsc_len, + _gtk, gd->gtk_len,sm->key_entry_valid) < 0) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Failed to set " + "GTK to the driver (Group only)."); + #endif + return -1; + } + } else if (wpa_sm_set_key(&(sm->install_gtk), gd->alg, + sm->bssid, //(u8 *) "\xff\xff\xff\xff\xff\xff", + gd->keyidx, gd->tx, key_rsc, gd->key_rsc_len, + _gtk, gd->gtk_len, sm->key_entry_valid) < 0) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Failed to set GTK to " + "the driver (alg=%d keylen=%d keyidx=%d)", + gd->alg, gd->gtk_len, gd->keyidx); + #endif + return -1; + } + + return 0; +} + +bool wpa_supplicant_gtk_in_use(struct wpa_sm *sm, struct wpa_gtk_data *gd) +{ + u8 *_gtk = gd->gtk; + u8 gtk_buf[32]; + u8 gtk_get[32] = {0}; + u8 ifx; + int alg; + u8 bssid[6]; + int keyidx; + + wpa_hexdump(MSG_DEBUG, "WPA: Group Key", gd->gtk, gd->gtk_len); + + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Judge GTK: (keyidx=%d len=%d).", gd->keyidx, gd->gtk_len); + #endif + + if (sm->group_cipher == WPA_CIPHER_TKIP) { + /* Swap Tx/Rx keys for Michael MIC */ + memcpy(gtk_buf, gd->gtk, 16); + memcpy(gtk_buf + 16, gd->gtk + 16, 8); + memcpy(gtk_buf + 24, gd->gtk + 24, 8); + _gtk = gtk_buf; + } + + //check if gtk is in use. + if (wpa_sm_get_key(&ifx, &alg, bssid, &keyidx, gtk_get, gd->gtk_len, gd->keyidx) == 0) { + if (ifx == 0 && alg == gd->alg && memcmp(bssid, sm->bssid, ETH_ALEN) == 0 && + memcmp(_gtk, gtk_get, gd->gtk_len) == 0) { + wpa_printf(MSG_DEBUG, "GTK %d is already in use in entry %d, it may be an attack, ignor it.", gd->keyidx, gd->keyidx + 2); + return true; + } + } + + if (wpa_sm_get_key(&ifx, &alg, bssid, &keyidx, gtk_get, gd->gtk_len, (gd->keyidx+1)%2) == 0) { + if (ifx == 0 && alg == gd->alg && memcmp(bssid, sm->bssid, ETH_ALEN) == 0 && + memcmp(_gtk, gtk_get, gd->gtk_len) == 0) { + wpa_printf(MSG_DEBUG, "GTK %d is already in use in entry %d, it may be an attack, ignor it.", gd->keyidx, (gd->keyidx+1)%2 + 2); + return true; + } + } + + return false; +} + +int wpa_supplicant_gtk_tx_bit_workaround(const struct wpa_sm *sm, + int tx) +{ + if (tx && sm->pairwise_cipher != WPA_CIPHER_NONE) { + /* Ignore Tx bit for GTK if a pairwise key is used. One AP + * seemed to set this bit (incorrectly, since Tx is only when + * doing Group Key only APs) and without this workaround, the + * data connection does not work because wpa_supplicant + * configured non-zero keyidx to be used for unicast. */ + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Tx bit set for GTK, but pairwise " + "keys are used - ignore Tx bit"); + #endif + return 0; + } + return tx; +} + +int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm, + const u8 *gtk, size_t gtk_len, + int key_info) +{ +#ifndef CONFIG_NO_WPA2 + struct wpa_gtk_data *gd=&(sm->gd); + + /* + * IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames - Figure 43x + * GTK KDE format: + * KeyID[bits 0-1], Tx [bit 2], Reserved [bits 3-7] + * Reserved [bits 0-7] + * GTK + */ + + memset(gd, 0, sizeof(struct wpa_gtk_data)); + wpa_hexdump(MSG_DEBUG, "RSN: received GTK in pairwise handshake", + gtk, gtk_len); + + if (gtk_len < 2 || gtk_len - 2 > sizeof(gd->gtk)) + return -1; + + gd->keyidx = gtk[0] & 0x3; + gd->tx = wpa_supplicant_gtk_tx_bit_workaround(sm, + !!(gtk[0] & BIT(2))); + gtk += 2; + gtk_len -= 2; + + memcpy(gd->gtk, gtk, gtk_len); + gd->gtk_len = gtk_len; + + if (wpa_supplicant_check_group_cipher(sm->group_cipher, + gtk_len, gtk_len, + &(gd->key_rsc_len), &(gd->alg))) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "RSN: Failed to install GTK"); + #endif + return -1; + } + return 0; +#else /* CONFIG_NO_WPA2 */ + return -1; +#endif /* CONFIG_NO_WPA2 */ +} + +#ifdef DEBUG_PRINT +void wpa_report_ie_mismatch(struct wpa_sm *sm, + const char *reason, const u8 *src_addr, + const u8 *wpa_ie, size_t wpa_ie_len, + const u8 *rsn_ie, size_t rsn_ie_len) +#else +void wpa_report_ie_mismatch(struct wpa_sm *sm, const u8 *src_addr, + const u8 *wpa_ie, size_t wpa_ie_len, + const u8 *rsn_ie, size_t rsn_ie_len) +#endif +{ + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: %s (src=" MACSTR ")", + reason, MAC2STR(src_addr)); + #endif + if (sm->ap_wpa_ie) { + wpa_hexdump(MSG_INFO, "WPA: WPA IE in Beacon/ProbeResp", + sm->ap_wpa_ie, sm->ap_wpa_ie_len); + } + if (wpa_ie) { + if (!sm->ap_wpa_ie) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: No WPA IE in " + "Beacon/ProbeResp"); + #endif + } + wpa_hexdump(MSG_INFO, "WPA: WPA IE in 3/4 msg", + wpa_ie, wpa_ie_len); + } + + if (sm->ap_rsn_ie) { + wpa_hexdump(MSG_INFO, "WPA: RSN IE in Beacon/ProbeResp", + sm->ap_rsn_ie, sm->ap_rsn_ie_len); + } + if (rsn_ie) { + if (!sm->ap_rsn_ie) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: No RSN IE in " + "Beacon/ProbeResp"); + #endif + } + wpa_hexdump(MSG_INFO, "WPA: RSN IE in 3/4 msg", + rsn_ie, rsn_ie_len); + } + + wpa_sm_disassociate(sm, WLAN_REASON_IE_IN_4WAY_DIFFERS); +} + +int ieee80211w_set_keys(struct wpa_sm *sm, + struct wpa_eapol_ie_parse *ie) +{ + return 0; +} + + int wpa_supplicant_validate_ie(struct wpa_sm *sm, + const unsigned char *src_addr, + struct wpa_eapol_ie_parse *ie) +{ + if (sm->ap_wpa_ie == NULL && sm->ap_rsn_ie == NULL) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: No WPA/RSN IE for this AP known. " + "Trying to get from scan results\n"); + #endif + if (wpa_sm_get_beacon_ie(sm) < 0) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Could not find AP from " + "the scan results"); + #endif + } else { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Found the current AP from " + "updated scan results\n"); + #endif + } + } + + if (ie->wpa_ie == NULL && ie->rsn_ie == NULL && + (sm->ap_wpa_ie || sm->ap_rsn_ie)) { +#ifdef DEBUG_PRINT + wpa_report_ie_mismatch(sm, "IE in 3/4 msg does not match " + "with IE in Beacon/ProbeResp (no IE?)", + src_addr, ie->wpa_ie, ie->wpa_ie_len, + ie->rsn_ie, ie->rsn_ie_len); +#else + wpa_report_ie_mismatch(sm, + src_addr, ie->wpa_ie, ie->wpa_ie_len, + ie->rsn_ie, ie->rsn_ie_len); +#endif + return -1; + } + + if ((ie->wpa_ie && sm->ap_wpa_ie && + (ie->wpa_ie_len != sm->ap_wpa_ie_len || + memcmp(ie->wpa_ie, sm->ap_wpa_ie, ie->wpa_ie_len) != 0)) || + (ie->rsn_ie && sm->ap_rsn_ie && + wpa_compare_rsn_ie(wpa_key_mgmt_ft(sm->key_mgmt), + sm->ap_rsn_ie, sm->ap_rsn_ie_len, + ie->rsn_ie, ie->rsn_ie_len))) { +#ifdef DEBUG_PRINT + wpa_report_ie_mismatch(sm, "IE in 3/4 msg does not match " + "with IE in Beacon/ProbeResp", + src_addr, ie->wpa_ie, ie->wpa_ie_len, + ie->rsn_ie, ie->rsn_ie_len); +#else + wpa_report_ie_mismatch(sm, + src_addr, ie->wpa_ie, ie->wpa_ie_len, + ie->rsn_ie, ie->rsn_ie_len); +#endif + return -1; + } + + if (sm->proto == WPA_PROTO_WPA && + ie->rsn_ie && sm->ap_rsn_ie == NULL && sm->rsn_enabled) { +#ifdef DEBUG_PRINT + wpa_report_ie_mismatch(sm, "Possible downgrade attack " + "detected - RSN was enabled and RSN IE " + "was in msg 3/4, but not in " + "Beacon/ProbeResp", + src_addr, ie->wpa_ie, ie->wpa_ie_len, + ie->rsn_ie, ie->rsn_ie_len); +#else + wpa_report_ie_mismatch(sm, + src_addr, ie->wpa_ie, ie->wpa_ie_len, + ie->rsn_ie, ie->rsn_ie_len); +#endif + return -1; + } + + return 0; +} + +/** + * wpa_supplicant_send_4_of_4 - Send message 4 of WPA/RSN 4-Way Handshake + * @sm: Pointer to WPA state machine data from wpa_sm_init() + * @dst: Destination address for the frame + * @key: Pointer to the EAPOL-Key frame header + * @ver: Version bits from EAPOL-Key Key Info + * @key_info: Key Info + * @kde: KDEs to include the EAPOL-Key frame + * @kde_len: Length of KDEs + * @ptk: PTK to use for keyed hash and encryption + * Returns: 0 on success, -1 on failure + */ + int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst, + const struct wpa_eapol_key *key, + u16 ver, u16 key_info, + const u8 *kde, size_t kde_len, + struct wpa_ptk *ptk) +{ + size_t rlen; + struct wpa_eapol_key *reply; + u8 *rbuf; + + if (kde) + wpa_hexdump(MSG_DEBUG, "WPA: KDE for msg 4/4", kde, kde_len); + + rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, + sizeof(*reply) + kde_len, + &rlen, (void *) &reply); + if (rbuf == NULL) + return -1; + + sm->txcb_flags |= WPA_4_4_HANDSHAKE_BIT; + wpa_printf(MSG_DEBUG, "tx 4/4 txcb_flags=%d\n", sm->txcb_flags); + + reply->type = sm->proto == WPA_PROTO_RSN ? + EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; + key_info &= WPA_KEY_INFO_SECURE; + key_info |= ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC; + WPA_PUT_BE16(reply->key_info, key_info); + if (sm->proto == WPA_PROTO_RSN) + WPA_PUT_BE16(reply->key_length, 0); + else + memcpy(reply->key_length, key->key_length, 2); + memcpy(reply->replay_counter, key->replay_counter, + WPA_REPLAY_COUNTER_LEN); + + WPA_PUT_BE16(reply->key_data_length, kde_len); + if (kde) + memcpy(reply + 1, kde, kde_len); + + wpa_printf(MSG_DEBUG, "WPA Send EAPOL-Key 4/4\n"); + wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL, + rbuf, rlen, reply->key_mic); + wpa_sm_free_eapol(rbuf); + + return 0; +} + + void wpa_sm_set_seq(struct wpa_sm *sm, struct wpa_eapol_key *key, u8 isptk) +{ + u8 *key_rsc, *seq; + u8 null_rsc[WPA_KEY_RSC_LEN]; + + os_bzero(null_rsc, WPA_KEY_RSC_LEN); + + if (sm->proto == WPA_PROTO_RSN) { + key_rsc = null_rsc; + } else { + key_rsc = key->key_rsc; + wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, WPA_KEY_RSC_LEN); + } + + seq=(isptk) ? (sm->install_ptk).seq : (sm->install_gtk).seq; + memcpy(seq, key_rsc, WPA_KEY_RSC_LEN); +} + + void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, + struct wpa_eapol_key *key, + u16 ver) +{ + u16 key_info, keylen, len; + const u8 *pos; + struct wpa_eapol_ie_parse ie; + + wpa_sm_set_state(WPA_LAST_HALF_4WAY_HANDSHAKE); + wpa_printf(MSG_DEBUG, "WPA 3/4-Way Handshake\n"); + + key_info = WPA_GET_BE16(key->key_info); + + pos = (const u8 *) (key + 1); + len = WPA_GET_BE16(key->key_data_length); + wpa_hexdump(MSG_DEBUG, "WPA: IE KeyData", pos, len); + wpa_supplicant_parse_ies(pos, len, &ie); + if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: GTK IE in unencrypted key data"); + #endif + goto failed; + } + + if (wpa_supplicant_validate_ie(sm, sm->bssid, &ie) < 0) + goto failed; + + if (memcmp(sm->anonce, key->key_nonce, WPA_NONCE_LEN) != 0) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: ANonce from message 1 of 4-Way " + "Handshake differs from 3 of 4-Way Handshake - drop" + " packet (src=" MACSTR ")", MAC2STR(sm->bssid)); + #endif + goto failed; + } + + keylen = WPA_GET_BE16(key->key_length); + switch (sm->pairwise_cipher) { + case WPA_CIPHER_CCMP: + if (keylen != 16) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Invalid CCMP key length " + "%d (src=" MACSTR ")", + keylen, MAC2STR(sm->bssid)); + #endif + goto failed; + } + break; + case WPA_CIPHER_TKIP: + if (keylen != 32) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Invalid TKIP key length " + "%d (src=" MACSTR ")", + keylen, MAC2STR(sm->bssid)); + #endif + goto failed; + } + break; + } + + + /* SNonce was successfully used in msg 3/4, so mark it to be renewed + * for the next 4-Way Handshake. If msg 3 is received again, the old + * SNonce will still be used to avoid changing PTK. */ + sm->renew_snonce = 1; + + /*ready for txcallback , set seq and set txcallback param*/ + wpa_sm_set_seq(sm, key, 1); + sm->key_info=key_info; + (sm->gd).gtk_len=0; //used as flag if gtk is installed in callback + if (ie.gtk) { + wpa_sm_set_seq(sm, key, 0); + if (wpa_supplicant_pairwise_gtk(sm, + ie.gtk, ie.gtk_len, key_info) < 0) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "RSN: Failed to configure GTK"); + #endif + goto failed; + } + } + + if (ieee80211w_set_keys(sm, &ie) < 0) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "RSN: Failed to configure IGTK"); + #endif + goto failed; + } + + /*after txover, callback will continue run remain task*/ + if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info, + NULL, 0, &sm->ptk)) { + goto failed; + } + + return; + +failed: + wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED); +} + + + int wpa_supplicant_send_4_of_4_txcallback(struct wpa_sm *sm) +{ + u16 key_info=sm->key_info; + + if (sm->key_install && key_info & WPA_KEY_INFO_INSTALL) { + if (wpa_supplicant_install_ptk(sm)) + goto failed; + } + else if (sm->key_install == false) { + wpa_printf(MSG_DEBUG, "PTK has been installed, it may be an attack, ignor it."); + } + + wpa_sm_set_state(WPA_GROUP_HANDSHAKE); + + if((sm->gd).gtk_len) { + if (sm->key_install) { + if (wpa_supplicant_install_gtk(sm, &(sm->gd))) + goto failed; + } + else { + wpa_printf(MSG_DEBUG, "GTK has been installed, it may be an attack, ignor it."); + } + wpa_supplicant_key_neg_complete(sm, sm->bssid, + key_info & WPA_KEY_INFO_SECURE); + } + + + if (key_info & WPA_KEY_INFO_SECURE) { + wpa_sm_mlme_setprotection( + sm, sm->bssid, MLME_SETPROTECTION_PROTECT_TYPE_RX, + MLME_SETPROTECTION_KEY_TYPE_PAIRWISE); + } + + sm->key_install = false; + + return 0; + +failed: + return WLAN_REASON_UNSPECIFIED; +} + + + int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm, + const u8 *keydata, + size_t keydatalen, + u16 key_info, + struct wpa_gtk_data *gd) +{ + int maxkeylen; + struct wpa_eapol_ie_parse ie; + + wpa_hexdump(MSG_DEBUG, "RSN: msg 1/2 key data", keydata, keydatalen); + wpa_supplicant_parse_ies(keydata, keydatalen, &ie); + if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: GTK IE in unencrypted key data"); + #endif + return -1; + } + if (ie.gtk == NULL) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: No GTK IE in Group Key msg 1/2"); + #endif + return -1; + } + maxkeylen = gd->gtk_len = ie.gtk_len - 2; + + if (wpa_supplicant_check_group_cipher(sm->group_cipher, + gd->gtk_len, maxkeylen, + &gd->key_rsc_len, &gd->alg)) + return -1; + + wpa_hexdump(MSG_DEBUG, "RSN: received GTK in group key handshake", + ie.gtk, ie.gtk_len); + gd->keyidx = ie.gtk[0] & 0x3; + gd->tx = wpa_supplicant_gtk_tx_bit_workaround(sm, + !!(ie.gtk[0] & BIT(2))); + if (ie.gtk_len - 2 > sizeof(gd->gtk)) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "RSN: Too long GTK in GTK IE " + "(len=%lu)", (unsigned long) ie.gtk_len - 2); + #endif + return -1; + } + memcpy(gd->gtk, ie.gtk + 2, ie.gtk_len - 2); + + if (ieee80211w_set_keys(sm, &ie) < 0) + { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "RSN: Failed to configure IGTK"); + #endif + } + return 0; +} + + int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm, + const struct wpa_eapol_key *key, + size_t keydatalen, int key_info, + size_t extra_len, u16 ver, + struct wpa_gtk_data *gd) +{ + size_t maxkeylen; + u8 ek[32]; + + gd->gtk_len = WPA_GET_BE16(key->key_length); + maxkeylen = keydatalen; + if (keydatalen > extra_len) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Truncated EAPOL-Key packet:" + " key_data_length=%lu > extra_len=%lu", + (unsigned long) keydatalen, + (unsigned long) extra_len); + #endif + return -1; + } + if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { + if (maxkeylen < 8) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Too short maxkeylen (%lu)", + (unsigned long) maxkeylen); + #endif + return -1; + } + maxkeylen -= 8; + } + + if (wpa_supplicant_check_group_cipher(sm->group_cipher, + gd->gtk_len, maxkeylen, + &gd->key_rsc_len, &gd->alg)) + return -1; + + gd->keyidx = (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >> + WPA_KEY_INFO_KEY_INDEX_SHIFT; + if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) { + memcpy(ek, key->key_iv, 16); + memcpy(ek + 16, sm->ptk.kek, 16); + if (keydatalen > sizeof(gd->gtk)) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: RC4 key data " + "too long (%lu)", + (unsigned long) keydatalen); + #endif + return -1; + } + memcpy(gd->gtk, key + 1, keydatalen); + if (rc4_skip(ek, 32, 256, gd->gtk, keydatalen)) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: RC4 failed"); + #endif + return -1; + } + } else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { + if (keydatalen % 8) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: Unsupported AES-WRAP " + "len %lu", (unsigned long) keydatalen); + #endif + return -1; + } + if (maxkeylen > sizeof(gd->gtk)) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: AES-WRAP key data " + "too long (keydatalen=%lu maxkeylen=%lu)", + (unsigned long) keydatalen, + (unsigned long) maxkeylen); + #endif + return -1; + } + if (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 60% rename from components/wpa_supplicant/include/wpa/wpa_i.h rename to components/wpa_supplicant/src/rsn_supp/wpa.h index a43c33d332..c3475eafee 100644 --- a/components/wpa_supplicant/include/wpa/wpa_i.h +++ b/components/wpa_supplicant/src/rsn_supp/wpa.h @@ -1,6 +1,6 @@ /* - * Internal WPA/RSN supplicant state machine definitions - * Copyright (c) 2004-2010, Jouni Malinen + * wpa_supplicant - WPA definitions + * Copyright (c) 2003-2007, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -12,8 +12,31 @@ * See README and COPYING for more details. */ -#ifndef WPA_I_H -#define WPA_I_H +#ifndef WPA_H +#define WPA_H + +#include "esp32/rom/ets_sys.h" +#include "utils/common.h" +#include "common/defs.h" +#include "common/wpa_common.h" +#include "esp_wifi_crypto_types.h" +#include "wpa_i.h" + + +#define WPA_SM_STATE(_sm) ((_sm)->wpa_state) + +struct wpa_sm; + +int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len); +bool wpa_sta_in_4way_handshake(void); + +#define WPA_ASSERT assert + +struct l2_ethhdr { + u8 h_dest[ETH_ALEN]; + u8 h_source[ETH_ALEN]; + be16 h_proto; +} STRUCT_PACKED; /** * set_key - Configure encryption key @@ -60,30 +83,43 @@ * example on how this can be done. */ -typedef void (* WPA_SEND_FUNC)(struct pbuf *pb); -typedef void (* WPA_SET_ASSOC_IE)(uint8 proto, u8 *assoc_buf, u32 assoc_wpa_ie_len); +/** + * send_eapol - Optional function for sending EAPOL packets + * @priv: private driver interface data + * @dest: Destination MAC address + * @proto: Ethertype + * @data: EAPOL packet starting with IEEE 802.1X header + * @data_len: Size of the EAPOL packet + * + * Returns: 0 on success, -1 on failure + * + * This optional function can be used to override l2_packet operations + * with driver specific functionality. If this function pointer is set, + * l2_packet module is not used at all and the driver interface code is + * responsible for receiving and sending all EAPOL packets. The + * received EAPOL packets are sent to core code with EVENT_EAPOL_RX + * event. The driver interface is required to implement get_mac_addr() + * handler if send_eapol() is used. + */ -typedef void (*WPA_INSTALL_KEY) (enum wpa_alg alg, uint8 *addr, int key_idx, int set_tx, - uint8 *seq, size_t seq_len, uint8 *key, size_t key_len, int key_entry_valid); +#define KEYENTRY_TABLE_MAP(key_entry_valid) ((key_entry_valid)%5) -typedef void (*WPA_DEAUTH)(uint8 reason_code); +void pp_michael_mic_failure(u16 isunicast); -typedef void (*WPA_NEG_COMPLETE)(); +void wpa_sm_set_state(enum wpa_states state); -void wpa_register(char * payload, WPA_SEND_FUNC snd_func, \ - WPA_SET_ASSOC_IE set_assoc_ie_func, \ - WPA_INSTALL_KEY ppinstallkey, \ - WPA_DEAUTH wpa_deauth, \ - WPA_NEG_COMPLETE wpa_neg_complete); +char * dup_binstr(const void *src, size_t len); -#include "pp/esf_buf.h" -void eapol_txcb(esf_buf_t *eb); +void wpa_set_pmk(uint8_t *pmk); -void wpa_set_profile(uint32 wpa_proto); +int wpa_hook_init(void); -void wpa_set_bss(char *macddr, char * bssid, uint8 pairwise_cipher, uint8 group_cipher, char *passphrase, u8 *ssid, size_t ssid_len); +bool wpa_hook_deinit(void); -int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len); -#endif /* WPA_I_H */ +char * dup_binstr(const void *src, size_t len); + +int wpa_michael_mic_failure(u16 isunicast); + +#endif /* WPA_H */ diff --git a/components/wpa_supplicant/include/wpa/wpa.h b/components/wpa_supplicant/src/rsn_supp/wpa_i.h similarity index 72% rename from components/wpa_supplicant/include/wpa/wpa.h rename to components/wpa_supplicant/src/rsn_supp/wpa_i.h index f2ab9898d4..3a09eff1d2 100644 --- a/components/wpa_supplicant/include/wpa/wpa.h +++ b/components/wpa_supplicant/src/rsn_supp/wpa_i.h @@ -1,6 +1,6 @@ /* - * wpa_supplicant - WPA definitions - * Copyright (c) 2003-2007, Jouni Malinen + * Internal WPA/RSN supplicant state machine definitions + * Copyright (c) 2004-2010, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -12,22 +12,8 @@ * See README and COPYING for more details. */ -#ifndef WPA_H -#define WPA_H - -// #include "esp32/rom/ets_sys.h" -#include "common.h" -#include "wpa/defs.h" -#include "wpa/wpa_common.h" - - -#define WPA_SM_STATE(_sm) ((_sm)->wpa_state) - -struct wpa_sm; - -int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len); - -#define WPA_ASSERT ASSERT +#ifndef WPA_I_H +#define WPA_I_H struct install_key { int mic_errors_seen; /* Michael MIC errors with the current PTK */ @@ -82,28 +68,26 @@ struct wpa_sm { u8 *ap_wpa_ie, *ap_rsn_ie; size_t ap_wpa_ie_len, ap_rsn_ie_len; + bool key_install; + struct install_key install_ptk; struct install_key install_gtk; int key_entry_valid; //present current avaliable entry for bssid, for pairkey:0,5,10,15,20, gtk: pairkey_no+i (i:1~4) - struct pbuf *pb; - - void (* sendto) (struct pbuf *pb); + void (* sendto) (void *buffer, uint16_t len); void (*config_assoc_ie) (u8 proto, u8 *assoc_buf, u32 assoc_wpa_ie_len); void (*install_ppkey) (enum wpa_alg alg, u8 *addr, int key_idx, int set_tx, u8 *seq, unsigned int seq_len, u8 *key, unsigned int key_len, int key_entry_valid); + int (*get_ppkey) (uint8_t *ifx, int *alg, uint8_t *addr, int *key_idx, + uint8_t *key, size_t key_len, int key_entry_valid); void (*wpa_deauthenticate)(u8 reason_code); void (*wpa_neg_complete)(); struct wpa_gtk_data gd; //used for calllback save param - u16 key_info; //used for txcallback param + u16 key_info; //used for txcallback param + u16 txcb_flags; + bool ap_notify_completed_rsne; }; -struct l2_ethhdr { - u8 h_dest[ETH_ALEN]; - u8 h_source[ETH_ALEN]; - be16 h_proto; -} STRUCT_PACKED; - /** * set_key - Configure encryption key * @ifname: Interface name (for multi-SSID/VLAN support) @@ -150,30 +134,32 @@ struct l2_ethhdr { */ -/** - * send_eapol - Optional function for sending EAPOL packets - * @priv: private driver interface data - * @dest: Destination MAC address - * @proto: Ethertype - * @data: EAPOL packet starting with IEEE 802.1X header - * @data_len: Size of the EAPOL packet - * - * Returns: 0 on success, -1 on failure - * - * This optional function can be used to override l2_packet operations - * with driver specific functionality. If this function pointer is set, - * l2_packet module is not used at all and the driver interface code is - * responsible for receiving and sending all EAPOL packets. The - * received EAPOL packets are sent to core code with EVENT_EAPOL_RX - * event. The driver interface is required to implement get_mac_addr() - * handler if send_eapol() is used. - */ +typedef void (* WPA_SEND_FUNC)(void *buffer, u16 len); -#define KEYENTRY_TABLE_MAP(key_entry_valid) ((key_entry_valid)%5) +typedef void (* WPA_SET_ASSOC_IE)(u8 proto, u8 *assoc_buf, u32 assoc_wpa_ie_len); -void wpa_sm_set_state(enum wpa_states state); +typedef void (*WPA_INSTALL_KEY) (enum wpa_alg alg, u8 *addr, int key_idx, int set_tx, + u8 *seq, size_t seq_len, u8 *key, size_t key_len, int key_entry_valid); -char * dup_binstr(const void *src, size_t len); +typedef int (*WPA_GET_KEY) (u8 *ifx, int *alg, u8 *addt, int *keyidx, u8 *key, size_t key_len, int key_entry_valid); -#endif /* WPA_H */ +typedef void (*WPA_DEAUTH_FUNC)(u8 reason_code); + +typedef void (*WPA_NEG_COMPLETE)(); + +void wpa_register(char * payload, WPA_SEND_FUNC snd_func, \ + WPA_SET_ASSOC_IE set_assoc_ie_func, \ + WPA_INSTALL_KEY ppinstallkey, \ + WPA_GET_KEY ppgetkey, \ + WPA_DEAUTH_FUNC wpa_deauth, \ + WPA_NEG_COMPLETE wpa_neg_complete); + +void eapol_txcb(void *eb); + +void wpa_set_profile(u32 wpa_proto, u8 auth_mode); + +void wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher, char *passphrase, u8 *ssid, size_t ssid_len); + +int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len); +#endif /* WPA_I_H */ diff --git a/components/wpa_supplicant/src/rsn_supp/wpa_ie.c b/components/wpa_supplicant/src/rsn_supp/wpa_ie.c new file mode 100644 index 0000000000..ce85191c7c --- /dev/null +++ b/components/wpa_supplicant/src/rsn_supp/wpa_ie.c @@ -0,0 +1,371 @@ +/* + * wpa_supplicant - WPA/RSN IE and KDE processing + * Copyright (c) 2003-2008, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + #ifdef ESP_SUPPLICANT + +#include "utils/includes.h" + +#include "utils/common.h" +#include "rsn_supp/wpa.h" +#include "common/ieee802_11_defs.h" +#include "rsn_supp/wpa_ie.h" + +/** + * wpa_parse_wpa_ie - Parse WPA/RSN IE + * @wpa_ie: Pointer to WPA or RSN IE + * @wpa_ie_len: Length of the WPA/RSN IE + * @data: Pointer to data area for parsing results + * Returns: 0 on success, -1 on failure + * + * Parse the contents of WPA or RSN IE and write the parsed data into data. + */ +int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len, + struct wpa_ie_data *data) +{ + if (wpa_ie_len >= 1 && wpa_ie[0] == WLAN_EID_RSN) + return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data); + else + return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data); +} + +/** + * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs + * @pos: Pointer to the IE header + * @end: Pointer to the end of the Key Data buffer + * @ie: Pointer to parsed IE data + * Returns: 0 on success, 1 if end mark is found, -1 on failure + */ +static int wpa_parse_generic(const u8 *pos, const u8 *end, + struct wpa_eapol_ie_parse *ie) +{ + if (pos[1] == 0) + return 1; + + if (pos[1] >= 6 && + RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE && + pos[2 + WPA_SELECTOR_LEN] == 1 && + pos[2 + WPA_SELECTOR_LEN + 1] == 0) { + ie->wpa_ie = pos; + ie->wpa_ie_len = pos[1] + 2; + wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key", + ie->wpa_ie, ie->wpa_ie_len); + return 0; + } + + if (pos + 1 + RSN_SELECTOR_LEN < end && + pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN && + RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) { + ie->pmkid = pos + 2 + RSN_SELECTOR_LEN; + wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key", + pos, pos[1] + 2); + return 0; + } + + if (pos[1] > RSN_SELECTOR_LEN + 2 && + RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) { + ie->gtk = pos + 2 + RSN_SELECTOR_LEN; + ie->gtk_len = pos[1] - RSN_SELECTOR_LEN; + wpa_hexdump(MSG_DEBUG, "WPA: GTK in EAPOL-Key", + pos, pos[1] + 2); + return 0; + } + + if (pos[1] > RSN_SELECTOR_LEN + 2 && + RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) { + ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN; + ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN; + wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key", + pos, pos[1] + 2); + return 0; + } + return 0; +} + + +/** + * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs + * @buf: Pointer to the Key Data buffer + * @len: Key Data Length + * @ie: Pointer to parsed IE data + * Returns: 0 on success, -1 on failure + */ +int wpa_supplicant_parse_ies(const u8 *buf, size_t len, + struct wpa_eapol_ie_parse *ie) +{ + const u8 *pos, *end; + int ret = 0; + + memset(ie, 0, sizeof(*ie)); + for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) { + if (pos[0] == 0xdd && + ((pos == buf + len - 1) || pos[1] == 0)) { + /* Ignore padding */ + break; + } + if (pos + 2 + pos[1] > end) { + #ifdef DEBUG_PRINT + wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data " + "underflow (ie=%d len=%d pos=%d)", + pos[0], pos[1], (int) (pos - buf)); + #endif + wpa_hexdump(MSG_DEBUG, "WPA: Key Data", + buf, len); + ret = -1; + break; + } + if (*pos == WLAN_EID_RSN) { + ie->rsn_ie = pos; + ie->rsn_ie_len = pos[1] + 2; + wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key", + ie->rsn_ie, ie->rsn_ie_len); + } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) { + ret = wpa_parse_generic(pos, end, ie); + if (ret < 0) + break; + if (ret > 0) { + ret = 0; + break; + } + } else { + wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key " + "Key Data IE", pos, 2 + pos[1]); + } + } + + return ret; +} + + +static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len, + int pairwise_cipher, int group_cipher, + int key_mgmt) +{ + u8 *pos; + struct wpa_ie_hdr *hdr; + + if (wpa_ie_len < sizeof(*hdr) + WPA_SELECTOR_LEN + + 2 + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN) + return -1; + + hdr = (struct wpa_ie_hdr *) wpa_ie; + hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC; + RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE); + WPA_PUT_LE16(hdr->version, WPA_VERSION); + pos = (u8 *) (hdr + 1); + + if (group_cipher == WPA_CIPHER_CCMP) { + RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP); + } else if (group_cipher == WPA_CIPHER_TKIP) { + RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP); + } else if (group_cipher == WPA_CIPHER_WEP104) { + RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP104); + } else if (group_cipher == WPA_CIPHER_WEP40) { + RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP40); + } else { + wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).", + group_cipher); + return -1; + } + pos += WPA_SELECTOR_LEN; + + *pos++ = 1; + *pos++ = 0; + if (pairwise_cipher == WPA_CIPHER_CCMP) { + RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP); + } else if (pairwise_cipher == WPA_CIPHER_TKIP) { + RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP); + } else if (pairwise_cipher == WPA_CIPHER_NONE) { + RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE); + } else { + wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).", + pairwise_cipher); + return -1; + } + pos += WPA_SELECTOR_LEN; + + *pos++ = 1; + *pos++ = 0; + if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) { + RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X); + } else if (key_mgmt == WPA_KEY_MGMT_PSK) { + RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X); + } else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) { + RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_NONE); + } else { + wpa_printf(MSG_DEBUG, "Invalid key management type (%d).", + key_mgmt); + return -1; + } + pos += WPA_SELECTOR_LEN; + + /* WPA Capabilities; use defaults, so no need to include it */ + + hdr->len = (pos - wpa_ie) - 2; + + WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len); + + return pos - wpa_ie; +} + + +static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, + int pairwise_cipher, int group_cipher, + int key_mgmt, int mgmt_group_cipher, + struct wpa_sm *sm) +{ +#ifndef CONFIG_NO_WPA2 + u8 *pos; + struct rsn_ie_hdr *hdr; + u16 capab; + u8 min_len = 0; + + + /* For WPA2-PSK, if the RSNE in AP beacon/probe response doesn't specify the + * pairwise cipher or AKM suite, the RSNE IE in association request + * should only contain group cihpher suite, otherwise the WPA2 improvements + * certification will fail. + */ + if ( (sm->ap_notify_completed_rsne == true) || (key_mgmt == WPA_KEY_MGMT_IEEE8021X) ) { + min_len = sizeof(*hdr) + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2; + } else { + min_len = sizeof(*hdr) + RSN_SELECTOR_LEN; + } + + if (rsn_ie_len < min_len) { + wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)", (unsigned long) rsn_ie_len); + } + + hdr = (struct rsn_ie_hdr *) rsn_ie; + hdr->elem_id = WLAN_EID_RSN; + WPA_PUT_LE16(hdr->version, RSN_VERSION); + pos = (u8 *) (hdr + 1); + + if (group_cipher == WPA_CIPHER_CCMP) { + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); + } else if (group_cipher == WPA_CIPHER_TKIP) { + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); + } else if (group_cipher == WPA_CIPHER_WEP104) { + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP104); + } else if (group_cipher == WPA_CIPHER_WEP40) { + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP40); + } else { + wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).", + group_cipher); + return -1; + } + pos += RSN_SELECTOR_LEN; + + if ( (sm->ap_notify_completed_rsne == false) && (key_mgmt != WPA_KEY_MGMT_IEEE8021X) ) { + hdr->len = (pos - rsn_ie) - 2; + return (pos - rsn_ie); + } + + *pos++ = 1; + *pos++ = 0; + if (pairwise_cipher == WPA_CIPHER_CCMP) { + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); + } else if (pairwise_cipher == WPA_CIPHER_TKIP) { + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); + } else if (pairwise_cipher == WPA_CIPHER_NONE) { + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE); + } else { + wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).", + pairwise_cipher); + return -1; + } + pos += RSN_SELECTOR_LEN; + + *pos++ = 1; + *pos++ = 0; + if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) { + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X); + } else if (key_mgmt == WPA_KEY_MGMT_PSK) { + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X); +#ifdef CONFIG_IEEE80211R + } else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) { + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); + } else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) { + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); +#endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_IEEE80211W + } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) { + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256); + } else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) { + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256); +#endif /* CONFIG_IEEE80211W */ + } else { + wpa_printf(MSG_DEBUG, "Invalid key management type (%d).", + key_mgmt); + return -1; + } + pos += RSN_SELECTOR_LEN; + + /* RSN Capabilities */ + capab = 0; +#ifdef CONFIG_IEEE80211W + if (sm->mfp) + capab |= WPA_CAPABILITY_MFPC; + if (sm->mfp == 2) + capab |= WPA_CAPABILITY_MFPR; +#endif /* CONFIG_IEEE80211W */ + WPA_PUT_LE16(pos, capab); + pos += 2; + +#ifdef CONFIG_IEEE80211W + if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) { + if (!sm->cur_pmksa) { + /* PMKID Count */ + WPA_PUT_LE16(pos, 0); + pos += 2; + } + + /* Management Group Cipher Suite */ + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); + pos += RSN_SELECTOR_LEN; + } +#endif /* CONFIG_IEEE80211W */ + + hdr->len = (pos - rsn_ie) - 2; + + WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len); + + return pos - rsn_ie; +#else /* CONFIG_NO_WPA2 */ + return -1; +#endif /* CONFIG_NO_WPA2 */ +} + + +/** + * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy + * @sm: Pointer to WPA state machine data from wpa_sm_init() + * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE + * @wpa_ie_len: Maximum length of the generated WPA/RSN IE + * Returns: Length of the generated WPA/RSN IE or -1 on failure + */ +int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len) +{ + if (sm->proto == WPA_PROTO_RSN) + return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len, + sm->pairwise_cipher, + sm->group_cipher, + sm->key_mgmt, sm->mgmt_group_cipher, + sm); + else + return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len, + sm->pairwise_cipher, + sm->group_cipher, + sm->key_mgmt); +} +#endif // ESP_SUPPLICANT + diff --git a/components/wpa_supplicant/include/wpa/wpa_ie.h b/components/wpa_supplicant/src/rsn_supp/wpa_ie.h similarity index 93% rename from components/wpa_supplicant/include/wpa/wpa_ie.h rename to components/wpa_supplicant/src/rsn_supp/wpa_ie.h index 94518d8457..c71a926f2b 100644 --- a/components/wpa_supplicant/include/wpa/wpa_ie.h +++ b/components/wpa_supplicant/src/rsn_supp/wpa_ie.h @@ -53,4 +53,7 @@ int wpa_supplicant_parse_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie); int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len); +int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len, + struct wpa_ie_data *data); + #endif /* WPA_IE_H */ diff --git a/components/wpa_supplicant/src/wpa2/tls/asn1.c b/components/wpa_supplicant/src/tls/asn1.c similarity index 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..1700f0f4b1 100644 --- a/components/wpa_supplicant/src/wps/wps.c +++ b/components/wpa_supplicant/src/wps/wps.c @@ -7,20 +7,20 @@ */ #include -#include "wpa/includes.h" -#include "wpa/wpa.h" -#include "wpa/common.h" -#include "wpa/eapol_common.h" -#include "wpa/wpa_debug.h" -#include "wpa/ieee802_11_defs.h" +#include "utils/includes.h" +#include "rsn_supp/wpa.h" +#include "utils/common.h" +#include "common/eapol_common.h" +#include "utils/wpa_debug.h" +#include "common/ieee802_11_defs.h" #include "crypto/dh_group5.h" #include "wps/wps_i.h" #include "wps/wps_dev_attr.h" -#include "wpa2/eap_peer/eap_defs.h" -#include "wpa2/eap_peer/eap_common.h" +#include "eap_peer/eap_defs.h" +#include "eap_peer/eap_common.h" /** @@ -109,16 +109,7 @@ int wps_is_selected_pbc_registrar(const struct wpabuf *msg, u8 *bssid) os_free(attr); return 0; } -#if 0 -#ifdef CONFIG_WPS_STRICT - if (!attr->sel_reg_config_methods || - !(WPA_GET_BE16(attr->sel_reg_config_methods) & - WPS_CONFIG_PUSHBUTTON)) { - os_free(attr); - return 0; - } -#endif /* CONFIG_WPS_STRICT */ -#endif + os_free(attr); return 1; } @@ -160,9 +151,7 @@ static int is_selected_pin_registrar(struct wps_parse_attr *attr, u8 *bssid) return 0; } #ifdef CONFIG_WPS_STRICT - if (!attr->sel_reg_config_methods)// || - //!(WPA_GET_BE16(attr->sel_reg_config_methods) & - //(WPS_CONFIG_LABEL | WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD))) + if (!attr->sel_reg_config_methods) return 0; #endif /* CONFIG_WPS_STRICT */ return 1; diff --git a/components/wpa_supplicant/include/wps/wps.h b/components/wpa_supplicant/src/wps/wps.h similarity index 98% rename from components/wpa_supplicant/include/wps/wps.h rename to components/wpa_supplicant/src/wps/wps.h index 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..bd2aa5e947 100644 --- a/components/wpa_supplicant/src/wps/wps_attr_build.c +++ b/components/wpa_supplicant/src/wps/wps_attr_build.c @@ -5,9 +5,9 @@ * This software may be distributed under the terms of the BSD license. * See README for more details. */ -#include "wpa/includes.h" -#include "wpa/common.h" -#include "wpa/wpa_debug.h" +#include "utils/includes.h" +#include "utils/common.h" +#include "utils/wpa_debug.h" #include "crypto/aes_wrap.h" #include "crypto/crypto.h" @@ -15,7 +15,7 @@ #include "crypto/sha256.h" #include "crypto/random.h" -#include "wpa/ieee802_11_defs.h" +#include "common/ieee802_11_defs.h" #include "wps/wps_i.h" int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg, wps_key_mode_t mode) @@ -166,12 +166,7 @@ int wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg) len[0] = wpabuf_len(wps->last_msg); addr[1] = wpabuf_head(msg); len[1] = wpabuf_len(msg); - if (wps_crypto_funcs.hmac_sha256_vector) { - wps_crypto_funcs.hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, (int *)len, hash); - } else { - wpa_printf(MSG_ERROR, "Fail to register hmac sha256 vector!\r\n"); - return -1; - } + 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..e37a35b273 100644 --- a/components/wpa_supplicant/src/wps/wps_common.c +++ b/components/wpa_supplicant/src/wps/wps_common.c @@ -7,8 +7,8 @@ */ #include -#include "wpa/includes.h" -#include "wpa/common.h" +#include "utils/includes.h" +#include "utils/common.h" #include "crypto/aes_wrap.h" #include "crypto/crypto.h" @@ -46,12 +46,7 @@ void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len, for (i = 1; i <= iter; i++) { WPA_PUT_BE32(i_buf, i); - if (wps_crypto_funcs.hmac_sha256_vector) { - wps_crypto_funcs.hmac_sha256_vector(key, SHA256_MAC_LEN, 4, addr, (int *)len, hash); - } else { - wpa_printf(MSG_ERROR, "In function %s, fail to reigster hmac sha256 vector function!\r\n", __FUNCTION__); - return ; - } + 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..e6bde10c2b 100644 --- a/components/xtensa/CMakeLists.txt +++ b/components/xtensa/CMakeLists.txt @@ -1,18 +1,23 @@ -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") + + 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..564e6eb159 --- /dev/null +++ b/components/xtensa/debug_helpers.c @@ -0,0 +1,72 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "esp_types.h" +#include "esp_attr.h" +#include "esp_err.h" +#include "esp_debug_helpers.h" +#include "esp32/rom/ets_sys.h" +#include "soc/soc_memory_layout.h" +#include "soc/cpu.h" + +bool IRAM_ATTR esp_backtrace_get_next_frame(esp_backtrace_frame_t *frame) +{ + //Use frame(i-1)'s BS area located below frame(i)'s sp to get frame(i-1)'s sp and frame(i-2)'s pc + void *base_save = (void *)frame->sp; //Base save area consists of 4 words under SP + frame->pc = frame->next_pc; + frame->next_pc = *((uint32_t *)(base_save - 16)); //If next_pc = 0, indicates frame(i-1) is the last frame on the stack + frame->sp = *((uint32_t *)(base_save - 12)); + + //Return true if both sp and pc of frame(i-1) are sane, false otherwise + return (esp_stack_ptr_is_sane(frame->sp) && esp_ptr_executable((void*)esp_cpu_process_stack_pc(frame->pc))); +} + +esp_err_t IRAM_ATTR esp_backtrace_print(int depth) +{ + //Check arguments + if (depth <= 0) { + return ESP_ERR_INVALID_ARG; + } + + //Initialize stk_frame with first frame of stack + esp_backtrace_frame_t stk_frame; + esp_backtrace_get_start(&(stk_frame.pc), &(stk_frame.sp), &(stk_frame.next_pc)); + //esp_cpu_get_backtrace_start(&stk_frame); + ets_printf("\r\n\r\nBacktrace:"); + ets_printf("0x%08X:0x%08X ", esp_cpu_process_stack_pc(stk_frame.pc), stk_frame.sp); + + //Check if first frame is valid + bool corrupted = (esp_stack_ptr_is_sane(stk_frame.sp) && + esp_ptr_executable((void*)esp_cpu_process_stack_pc(stk_frame.pc))) ? + false : true; + + uint32_t i = (depth <= 0) ? INT32_MAX : depth; + while (i-- > 0 && stk_frame.next_pc != 0 && !corrupted) { + if (!esp_backtrace_get_next_frame(&stk_frame)) { //Get previous stack frame + corrupted = true; + } + ets_printf("0x%08X:0x%08X ", esp_cpu_process_stack_pc(stk_frame.pc), stk_frame.sp); + } + + //Print backtrace termination marker + esp_err_t ret = ESP_OK; + if (corrupted) { + ets_printf(" |<-CORRUPTED"); + ret = ESP_FAIL; + } else if (stk_frame.next_pc != 0) { //Backtrace continues + ets_printf(" |<-CONTINUES"); + } + ets_printf("\r\n\r\n"); + return ret; +} diff --git a/components/xtensa/debug_helpers_asm.S b/components/xtensa/debug_helpers_asm.S new file mode 100644 index 0000000000..0df70df863 --- /dev/null +++ b/components/xtensa/debug_helpers_asm.S @@ -0,0 +1,57 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include + +/* + * esp_backtrace_get_start(uint32_t *pc, uint32_t *sp, uint32_t *next_pc) + * + * High Addr + * .................. + * | i-3 BS | + * | i-1 locals | Function B + * .................. i-1 SP + * | i-2 BS | + * | i locals | Function A (Start of backtrace) + * ------------------ i SP + * | i-1 BS | + * | i+1 locals | Backtracing function (e.g. esp_backtrace_print()) + * ------------------ i+1 SP + * | i BS | + * | i+2 locals | esp_backtrace_get_start() <- This function + * ------------------ i+2 SP + * | i+1 BS | + * | i+3 locals | xthal_window_spill() + * ------------------ i+3 SP + * .................. Low Addr + */ + .section .iram1, "ax" + .align 4 + .global esp_backtrace_get_start + .type esp_backtrace_get_start, @function +esp_backtrace_get_start: + entry a1, 32 + call8 xthal_window_spill //Spill registers onto stack (excluding this function) + //a2, a3, a4 should be out arguments for i SP, i PC, i-1 PC respectively. Use a5 and a6 as scratch + l32e a5, sp, -16 //Get i PC, which is ret addres of i+1 + s32i a5, a2, 0 //Store i PC to arg *pc + l32e a6, sp, -12 //Get i+1 SP. Used to access i BS + l32e a5, a6, -12 //Get i SP + s32i a5, a3, 0 //Store i SP to arg *sp + l32e a5, a6, -16 //Get i-1 PC, which is ret address of i + s32i a5, a4, 0 //Store i-1 PC to arg *next_pc + retw diff --git a/components/xtensa/include/esp_debug_helpers.h b/components/xtensa/include/esp_debug_helpers.h index 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/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/conf_common.py b/docs/conf_common.py index a008829bda..8fd13cbaf2 100644 --- a/docs/conf_common.py +++ b/docs/conf_common.py @@ -18,6 +18,7 @@ from __future__ import print_function from __future__ import unicode_literals import sys import os +import re import subprocess # Note: If extensions (or modules to document with autodoc) are in another directory, @@ -235,19 +236,14 @@ pygments_style = 'sphinx' # Custom added feature to allow redirecting old URLs # -# list of tuples (old_url, new_url) for pages to redirect -# (URLs should be relative to document root, only) -html_redirect_pages = [('api-reference/ethernet/index', 'api-reference/network/index'), - ('api-reference/ethernet/esp_eth', 'api-reference/network/esp_eth'), - ('api-reference/mesh/index', 'api-reference/network/index'), - ('api-reference/mesh/esp_mesh', 'api-reference/network/esp_mesh'), - ('api-reference/wifi/index', 'api-reference/network/index'), - ('api-reference/wifi/esp_now', 'api-reference/network/esp_now'), - ('api-reference/wifi/esp_smartconfig', 'api-reference/network/esp_smartconfig'), - ('api-reference/wifi/esp_wifi', 'api-reference/network/esp_wifi'), - ('api-reference/system/tcpip_adapter', 'api-reference/network/tcpip_adapter'), - ('get-started/idf-monitor', 'api-guides/tools/idf-monitor'), - ('get-started-cmake/idf-monitor', 'api-guides/tools/idf-monitor'),] +# 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..2671b353fc 100644 --- a/docs/en/api-guides/bootloader.rst +++ b/docs/en/api-guides/bootloader.rst @@ -33,7 +33,7 @@ Partitions of type "app" cannot be specified here. Partition table.:: # Name, Type, SubType, Offset, Size, Flags - # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild + # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x4000 otadata, data, ota, 0xd000, 0x2000 phy_init, data, phy, 0xf000, 0x1000 @@ -42,13 +42,15 @@ Partition table.:: ota_0, 0, ota_0, , 512K ota_1, 0, ota_1, , 512K +.. _bootloader_boot_from_test_firmware: + Boot from TEST firmware ------------------------ The user can write a special firmware for testing in production, and run it as needed. The partition table also needs a dedicated partition for this testing firmware (See `partition table`). To trigger a test app you need to set :ref:`CONFIG_BOOTLOADER_APP_TEST`. -:ref:`CONFIG_BOOTLOADER_NUM_PIN_APP_TEST` - number of the GPIO input to boot TEST partition. The selected GPIO will be configured as an input with internal pull-up enabled. To trigger a test app, this GPIO must be pulled low on reset. -After the GPIO input is deactivated and the device reboots, the old application will boot (factory or any OTA slot). +:ref:`CONFIG_BOOTLOADER_NUM_PIN_APP_TEST` - GPIO number to boot TEST partition. The selected GPIO will be configured as an input with internal pull-up enabled. To trigger a test app, this GPIO must be pulled low on reset. +After the GPIO input is deactivated and the device reboots, the normally configured application will boot (factory or any OTA slot). :ref:`CONFIG_BOOTLOADER_HOLD_TIME_GPIO` - this is hold time of GPIO for reset/test mode (by default 5 seconds). The GPIO must be held low continuously for this period of time after reset before a factory reset or test partition boot (as applicable) is performed. diff --git a/docs/en/api-guides/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..8a28a1e163 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,544 @@ 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: +Build Process Internals +======================= -- Verbose output (same as ``V=1``, see below). If you don't want verbose output, also set ``V=0``. -- If the project configuration is missing new configuration items (from new components or esp-idf updates) then the project use the default values, instead of prompting the user for each item. -- If the build system needs to invoke ``menuconfig``, an error is printed and the build fails. +For full details about CMake_ and CMake commands, see the `CMake v3.5 documentation`_. -.. _make-size: +project.cmake contents +---------------------- -Advanced Make Targets ---------------------- +When included from a project CMakeLists file, the ``project.cmake`` file defines some utility modules and global variables and then sets ``IDF_PATH`` if it was not set in the system environment. -- ``make app``, ``make bootloader``, ``make partition table`` can be used to build only the app, bootloader, or partition table from the project as applicable. -- ``make erase_flash`` and ``make erase_ota`` will use esptool.py to erase the entire flash chip and the OTA selection setting from the flash chip, respectively. -- ``make size`` prints some size information about the app. ``make size-components`` and ``make size-files`` are similar targets which print more detailed per-component or per-source-file information, respectively. +It also defines an overridden custom version of the built-in CMake_ ``project`` function. This function is overridden to add all of the ESP-IDF specific project functionality. +project function +---------------- -Debugging The Make Process --------------------------- +The custom ``project()`` function performs the following steps: -Some tips for debugging the esp-idf build system: +- Determines the target (set by ``IDF_TARGET`` environment variable) and saves the target in CMake cache. If the target set in the environment does not match the one in cache, exits with an error. +- Evaluates component dependencies and builds the ``BUILD_COMPONENTS`` list of components to include in the build (see :ref:`above`). +- Finds all components in the project (searching ``COMPONENT_DIRS`` and filtering by ``COMPONENTS`` if this is set). +- Loads the project configuration from the ``sdkconfig`` file and generates a ``sdkconfig.cmake`` file and a ``sdkconfig.h`` header. These define configuration values in CMake and C/C++, respectively. If the project configuration changes, cmake will automatically be re-run to re-generate these files and re-configure the project. +- Sets the `CMAKE_TOOLCHAIN_FILE`_ variable to the correct toolchain file, depending on the target. +- Declares the actual cmake-level project by calling the `CMake project function `_. +- Loads the git version. This includes some magic which will automatically re-run CMake if a new revision is checked out in git. See `File Globbing & Incremental Builds`_. +- Includes :ref:`project_include.cmake` files from any components which have them. +- Adds each component to the build. Each component CMakeLists file calls ``idf_component_register``, calls the CMake `add_library `_ function to add a library and then adds source files, compile options, etc. +- Adds the final app executable to the build. +- Goes back and adds inter-component dependencies between components (ie adding the public header directories of each component to each other component). -- Appending ``V=1`` to the make arguments (or setting it as an environment variable) will cause make to echo all commands executed, and also each directory as it is entered for a sub-make. -- Running ``make -w`` will cause make to echo each directory as it is entered for a sub-make - same as ``V=1`` but without also echoing all commands. -- Running ``make --trace`` (possibly in addition to one of the above arguments) will print out every target as it is built, and the dependency which caused it to be built. -- Running ``make -p`` prints a (very verbose) summary of every generated target in each makefile. +Browse the :idf_file:`/tools/cmake/project.cmake` file and supporting functions in :idf_file:`/tools/cmake/idf_functions.cmake` for more details. -For more debugging tips and general make information, see the `GNU Make Manual`. +Debugging CMake +--------------- + +Some tips for debugging the ESP-IDF CMake-based build system: + +- When CMake runs, it prints quite a lot of diagnostic information including lists of components and component paths. +- Running ``cmake -DDEBUG=1`` will produce more verbose diagnostic output from the IDF build system. +- Running ``cmake`` with the ``--trace`` or ``--trace-expand`` options will give a lot of information about control flow. See the `cmake command line documentation`_. + +When included from a project CMakeLists file, the ``project.cmake`` file defines some utility modules and global variables and then sets ``IDF_PATH`` if it was not set in the system environment. + +It also defines an overridden custom version of the built-in CMake_ ``project`` function. This function is overridden to add all of the ESP-IDF specific project functionality. .. _warn-undefined-variables: Warning On Undefined Variables ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -By default, 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 -^^^^^^^^^^^^^^^^^^ +.. _project_include.cmake: -For components that have build requirements that must be evaluated in the top-level -project make pass, you can create a file called ``Makefile.projbuild`` in the -component directory. This makefile is included when ``project.mk`` is evaluated. +project_include.cmake +^^^^^^^^^^^^^^^^^^^^^ -For example, if your component needs to add to CFLAGS for the entire -project (not just for its own source files) then you can set -``CFLAGS +=`` in Makefile.projbuild. +For components that have build requirements which must be evaluated before any component CMakeLists +files are evaluated, you can create a file called ``project_include.cmake`` in the +component directory. This CMake file is included when ``project.cmake`` is evaluating the entire project. -``Makefile.projbuild`` files are used heavily inside esp-idf, for defining project-wide build features such as ``esptool.py`` command line arguments and the ``bootloader`` "special app". +``project_include.cmake`` files are used inside ESP-IDF, for defining project-wide build features such as ``esptool.py`` command line arguments and the ``bootloader`` "special app". -Note that ``Makefile.projbuild`` isn't necessary for the most common component uses - such as adding include directories to the project, or LDFLAGS to the final linking step. These values can be customised via the ``component.mk`` file itself. See `Optional Project-Wide Component Variables`_ for details. +Unlike component ``CMakeLists.txt`` files, when including a ``project_include.cmake`` file the current source directory (``CMAKE_CURRENT_SOURCE_DIR`` and working directory) is the project directory. Use the variable ``COMPONENT_DIR`` for the absolute directory of the component. -Take care when setting variables or targets in this file. As the values are included into the top-level project makefile pass, they can influence or break functionality across all components! +Note that ``project_include.cmake`` isn't necessary for the most common component uses - such as adding include directories to the project, or ``LDFLAGS`` to the final linking step. These values can be customised via the ``CMakeLists.txt`` file itself. See `Optional Project Variables`_ for details. + +``project_include.cmake`` files are included in the order given in ``BUILD_COMPONENTS`` variable (as logged by CMake). This means that a component's ``project_include.cmake`` file will be included after it's all dependencies' ``project_include.cmake`` files, unless both components are part of a dependency cycle. This is important if a ``project_include.cmake`` file relies on variables set by another component. See also :ref:`above`. + +Take great care when setting variables or targets in a ``project_include.cmake`` file. As the values are included into the top-level project CMake pass, they can influence or break functionality across all components! KConfig.projbuild ^^^^^^^^^^^^^^^^^ -This is an equivalent to ``Makefile.projbuild`` for `component configuration` KConfig files. If you want to include -configuration options at the top-level of menuconfig, rather than inside the "Component Configuration" sub-menu, then these can be defined in the KConfig.projbuild file alongside the ``component.mk`` file. +This is an equivalent to ``project_include.cmake`` for :ref:`component-configuration` KConfig files. If you want to include +configuration options at the top-level of menuconfig, rather than inside the "Component Configuration" sub-menu, then these can be defined in the KConfig.projbuild file alongside the ``CMakeLists.txt`` file. -Take care when adding configuration values in this file, as they will be included across the entire project configuration. Where possible, it's generally better to create a KConfig file for `component configuration`. +Take care when adding configuration values in this file, as they will be included across the entire project configuration. Where possible, it's generally better to create a KConfig file for :ref:`component-configuration`. - -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. +``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 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Some special components which contain no source files, only ``Kconfig.projbuild`` and ``Makefile.projbuild``, may set the flag ``COMPONENT_CONFIG_ONLY`` in the component.mk file. If this flag is set, most other component variables are ignored and no build step is run for the component. +Special components which contain no source files, only ``Kconfig.projbuild`` and ``KConfig``, can have a one-line ``CMakeLists.txt`` file which calls the function ``idf_component_register()`` with no +arguments specified. This function will include the component in the project build, but no library will be built *and* no header files will be added to any include paths. -Example Component Makefiles ---------------------------- +Example Component CMakeLists +============================ Because the build environment tries to set reasonable defaults that will work most -of the time, component.mk can be very small or even empty (see `Minimal Component Makefile`_). However, overriding `component variables` is usually required for some functionality. +of the time, component ``CMakeLists.txt`` can be very small or even empty (see `Minimal Component CMakeLists`_). However, overriding `component variables`_ is usually required for some functionality. -Here are some more advanced examples of ``component.mk`` makefiles: - - -Adding source directories -^^^^^^^^^^^^^^^^^^^^^^^^^ - -By default, sub-directories are ignored. If your project has sources in sub-directories -instead of in the root of the component then you can tell that to the build -system by setting ``COMPONENT_SRCDIRS``:: - - COMPONENT_SRCDIRS := src1 src2 - -This will compile all source files in the src1/ and src2/ sub-directories -instead. - -Specifying source files -^^^^^^^^^^^^^^^^^^^^^^^ - -The standard component.mk logic adds all .S and .c files in the source -directories as sources to be compiled unconditionally. It is possible -to circumvent that logic and hard-code the objects to be compiled by -manually setting the ``COMPONENT_OBJS`` variable to the name of the -objects that need to be generated:: - - COMPONENT_OBJS := file1.o file2.o thing/filea.o thing/fileb.o anotherthing/main.o - COMPONENT_SRCDIRS := . thing anotherthing - -Note that ``COMPONENT_SRCDIRS`` must be set as well. +Here are some more advanced examples of component CMakeLists files. Adding conditional configuration -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +-------------------------------- The configuration system can be used to conditionally compile some files -depending on the options selected in ``make menuconfig``. For this, ESP-IDF -has the compile_only_if and compile_only_if_not macros: +depending on the options selected in the project configuration. + +.. highlight:: none ``Kconfig``:: @@ -475,17 +569,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 +600,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 +636,678 @@ 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. + +.. _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/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..cc762d3b33 100644 --- a/docs/en/api-guides/index.rst +++ b/docs/en/api-guides/index.rst @@ -7,7 +7,7 @@ API Guides General Notes Build System - Build System (CMake) + Build System (Legacy GNU Make) Error Handling Fatal Errors Event Handling @@ -22,9 +22,9 @@ API Guides Partition Tables Secure Boot <../security/secure-boot> ULP Coprocessor - ULP Coprocessor (CMake) + ULP Coprocessor (Legacy GNU Make) Unit Testing - Unit Testing (CMake) + Unit Testing (Legacy GNU Make) Application Level Tracing Console Component ROM debug console @@ -34,3 +34,4 @@ API Guides BluFi External SPI-connected RAM Linker Script Generation + Tools 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..da9f19d65c 100644 --- a/docs/en/api-reference/bluetooth/index.rst +++ b/docs/en/api-reference/bluetooth/index.rst @@ -10,6 +10,11 @@ Bluetooth API 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/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/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/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..c35c954f35 100644 --- a/docs/en/api-reference/protocols/index.rst +++ b/docs/en/api-reference/protocols/index.rst @@ -8,11 +8,13 @@ Application Protocols mDNS ESP-TLS HTTP Client + Websocket Client HTTP Server HTTPS Server ASIO ESP-MQTT Modbus + Local Control Code examples for this API section are provided in the :example:`protocols` directory of ESP-IDF examples. diff --git a/docs/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/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..d80e30b56e 100644 --- a/docs/en/api-reference/storage/index.rst +++ b/docs/en/api-reference/storage/index.rst @@ -15,4 +15,4 @@ Storage API Mass Manufacturing Utility -Example code for this API section is provided in :example:`storage` directory of ESP-IDF examples. +Code examples for this API section are provided in the :example:`storage` directory of ESP-IDF examples. diff --git a/docs/en/api-reference/storage/nvs_flash.rst b/docs/en/api-reference/storage/nvs_flash.rst index 4daa17ea21..b3e0e38c92 100644 --- a/docs/en/api-reference/storage/nvs_flash.rst +++ b/docs/en/api-reference/storage/nvs_flash.rst @@ -3,29 +3,29 @@ NVS Partition Generator Utility ------------------------------- -This utility helps in generating NVS-esque partition binary file which can be flashed separately on a dedicated partition via a flashing utility. Key-value pairs to be flashed onto the partition can be provided via a CSV file. Refer to :doc:`NVS Partition Generator Utility ` for more details. +This utility helps generate NVS partition binary files which can be flashed separately on a dedicated partition via a flashing utility. Key-value pairs to be flashed onto the partition can be provided via a CSV file. For more details, please refer to :doc:`NVS Partition Generator Utility `. Application Example ------------------- -Two examples are provided in :example:`storage` directory of ESP-IDF examples: +You can find two code examples in the :example:`storage` directory of ESP-IDF examples: :example:`storage/nvs_rw_value` - Demonstrates how to read and write a single integer value using NVS. + Demonstrates how to read a single integer value from, and write it to NVS. - The value holds the number of ESP32 module restarts. Since it is written to NVS, the value is preserved between restarts. + The value checked in this example holds the number of the ESP32 module restarts. The value's function as a counter is only possible due to its storing in NVS. - Example also shows how to check if read / write operation was successful, or certain value is not initialized in NVS. Diagnostic is provided in plain text to help track program flow and capture any issues on the way. + The example also shows how to check if a read / write operation was successful, or if a certain value has not been initialized in NVS. The diagnostic procedure is provided in plain text to help you track the program flow and capture any issues on the way. :example:`storage/nvs_rw_blob` - Demonstrates how to read and write a single integer value and a blob (binary large object) using NVS to preserve them between ESP32 module restarts. + Demonstrates how to read a single integer value and a blob (binary large object), and write them to NVS to preserve this value between ESP32 module restarts. - * value - tracks number of ESP32 module soft and hard restarts. - * blob - contains a table with module run times. The table is read from NVS to dynamically allocated RAM. New run time is added to the table on each manually triggered soft restart and written back to NVS. Triggering is done by pulling down GPIO0. + * value - tracks the number of the ESP32 module soft and hard restarts. + * blob - contains a table with module run times. The table is read from NVS to dynamically allocated RAM. A new run time is added to the table on each manually triggered soft restart, and then the added run time is written to NVS. Triggering is done by pulling down GPIO0. - Example also shows how to implement diagnostics if read / write operation was successful. + The example also shows how to implement the diagnostic procedure to check if the read / write operation was successful. API Reference diff --git a/docs/en/api-reference/storage/sdmmc.rst b/docs/en/api-reference/storage/sdmmc.rst index 2aae6a09c1..2b7490ddb3 100644 --- a/docs/en/api-reference/storage/sdmmc.rst +++ b/docs/en/api-reference/storage/sdmmc.rst @@ -4,77 +4,93 @@ SD/SDIO/MMC Driver Overview -------- -SD/SDIO/MMC driver currently supports SD memory, SDIO cards, and eMMC chips. This protocol level driver builds on top of SDMMC and SD SPI host drivers. +The SD/SDIO/MMC driver currently supports SD memory, SDIO cards, and eMMC chips. This is a protocol level driver built on top of SDMMC and SD SPI host drivers. -SDMMC and SD SPI host drivers (``driver/sdmmc_host.h``) provide APIs to send commands to the slave device(s), send and receive data, and handle error conditions on the bus. - -- See :doc:`SDMMC Host API <../peripherals/sdmmc_host>` for functions used to initialize and configure SDMMC host. -- See :doc:`SD SPI Host API <../peripherals/sdspi_host>` for functions used to initialize and configure SD SPI host. +SDMMC and SD SPI host drivers (:component:`driver/include/driver/sdmmc_host.h`) provide API functions for: -SDMMC protocol layer (``sdmmc_cmd.h``), described in this document, handles specifics of SD protocol such as card initialization and data transfer commands. +- Sending commands to slave devices +- Sending and receiving data +- Handling error conditions within the bus + +For functions used to initialize and configure: + +- SDMMC host, see :doc:`SDMMC Host API <../peripherals/sdmmc_host>` +- SD SPI host, see :doc:`SD SPI Host API <../peripherals/sdspi_host>` + + +The SDMMC protocol layer described in this document handles the specifics of the SD protocol, such as the card initialization and data transfer commands. + +The protocol layer works with the host via the :cpp:class:`sdmmc_host_t` structure. This structure contains pointers to various functions of the host. -Protocol layer works with the host via :cpp:class:`sdmmc_host_t` structure. This structure contains pointers to various functions of the host. Application Example ------------------- -An example which combines SDMMC driver with FATFS library is provided in ``examples/storage/sd_card`` directory. This example initializes the card, writes and reads data from it using POSIX and C library APIs. See README.md file in the example directory for more information. +An example which combines the SDMMC driver with the FATFS library is provided in the :example:`storage/sd_card` directory of ESP-IDF examples. This example initializes the card, then writes and reads data from it using POSIX and C library APIs. See README.md file in the example directory for more information. -Protocol layer APIs -------------------- -Protocol layer is given :cpp:class:`sdmmc_host_t` structure which describes the SD/MMC host driver, lists its capabilites, and provides pointers to functions of the driver. Protocol layer stores card-specific information in :cpp:class:`sdmmc_card_t` structure. When sending commands to the SD/MMC host driver, protocol layer uses :cpp:class:`sdmmc_command_t` structure to describe the command, argument, expected return value, and data to transfer, if any. +Protocol layer API +------------------ -Usage with SD memory cards -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -1. Call the host driver functions to initialize the host (e.g. :cpp:func:`sdmmc_host_init`, :cpp:func:`sdmmc_host_init_slot`). -2. Call :cpp:func:`sdmmc_card_init` to initialize the card, passing it host driver information (``host``) and a pointer to :cpp:class:`sdmmc_card_t` structure which will be filled in (``card``). -3. To read and write sectors of the card, use :cpp:func:`sdmmc_read_sectors` and :cpp:func:`sdmmc_write_sectors`, passing the pointer to card information structure (``card``). -4. When card is not used anymore, call the host driver function to disable the host peripheral and free resources allocated by the driver (e.g. :cpp:func:`sdmmc_host_deinit`). - -Usage with eMMC chips -^^^^^^^^^^^^^^^^^^^^^ - -From the perspective of the protocol layer, eMMC memory chips behave the same way as SD memory cards. Because of similarity of the protocol, even though eMMC are chips don't have the "card" form factor, same terminology is used as for SD cards (`sdmmc_card_t`, `sdmmc_card_init`). Note that eMMC chips can not be used over SPI, therefore are incompatible with SD SPI host driver. - -To initialize eMMC memory and do read/write operations, follow the steps listed above for SD cards. +The protocol layer is given the :cpp:class:`sdmmc_host_t` structure. This structure describes the SD/MMC host driver, lists its capabilities, and provides pointers to functions of the driver. The protocol layer stores card-specific information in the :cpp:class:`sdmmc_card_t` structure. When sending commands to the SD/MMC host driver, the protocol layer uses the :cpp:class:`sdmmc_command_t` structure to describe the command, arguments, expected return values, and data to transfer if there is any. -Usage with SDIO cards -^^^^^^^^^^^^^^^^^^^^^ +Using API with SD memory cards +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Initialization an probing process is the same as with SD memory cards. Only data transfer commands differ in SDIO mode. +1. To initialize the host, call the host driver functions, e.g., :cpp:func:`sdmmc_host_init`, :cpp:func:`sdmmc_host_init_slot`. +2. To initialize the card, call :cpp:func:`sdmmc_card_init` and pass to it the parameters ``host`` - the host driver information, and ``card`` - a pointer to the structure :cpp:class:`sdmmc_card_t` which will be filled with information about the card when the function completes. +3. To read and write sectors of the card, use :cpp:func:`sdmmc_read_sectors` and :cpp:func:`sdmmc_write_sectors` respectively and pass to it the parameter ``card`` - a pointer to the card information structure. +4. If the card is not used anymore, call the host driver function - e.g., :cpp:func:`sdmmc_host_deinit` - to disable the host peripheral and free the resources allocated by the driver. -During probing and card initialization (done by :cpp:func:`sdmmc_card_init`), the driver only configures the following registers of the IO card: -1. The IO portion of the card is reset by setting RES bit in "I/O Abort" (0x06) register. -2. If 4-line mode is enalbed in host and slot configuration, driver attempts to set "Bus width" field in "Bus Interface Control" (0x07) register. If that succeeds (which means that slave supports 4-line mode), host is also switched to 4-line mode. -3. If high-speed mode is enabled in host configuration, SHS bit is set in "High Speed" (0x13) register. +Using API with eMMC chips +^^^^^^^^^^^^^^^^^^^^^^^^^ -In particular, the driver does not set any of the bits in I/O Enable, Int Enable registers, IO block sizes, etc. Applications can set these by calling :cpp:func:`sdmmc_io_write_byte`. +From the protocol layer's perspective, eMMC memory chips behave exactly like SD memory cards. Even though eMMCs are chips and do not have a card form factor, the terminology for SD cards can still be applied to eMMC due to the similarity of the protocol (`sdmmc_card_t`, `sdmmc_card_init`). Note that eMMC chips cannot be used over SPI, which makes them incompatible with the SD SPI host driver. -For card configuration and data transfer, use one of the following functions: +To initialize eMMC memory and perform read/write operations, follow the steps listed for SD cards in the previous section. -- :cpp:func:`sdmmc_io_read_byte`, :cpp:func:`sdmmc_io_write_byte` — read and write single byte using IO_RW_DIRECT (CMD52). -- :cpp:func:`sdmmc_io_read_bytes`, :cpp:func:`sdmmc_io_write_bytes` — read and write multiple bytes using IO_RW_EXTENDED (CMD53), in byte mode. -- :cpp:func:`sdmmc_io_read_blocks`, :cpp:func:`sdmmc_io_write_blocks` — read and write blocks of data using IO_RW_EXTENDED (CMD53), in block mode. -SDIO interrupts can be enabled by the application using :cpp:func:`sdmmc_io_enable_int` function. When using SDIO in 1-line mode, D1 line also needs to be connected to use SDIO interrupts. +Using API with SDIO cards +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Initialization and the probing process is the same as with SD memory cards. The only difference is in data transfer commands in SDIO mode. + +During the card initialization and probing, performed with :cpp:func:`sdmmc_card_init`, the driver only configures the following registers of the IO card: + +1. The IO portion of the card is reset by setting RES bit in the I/O Abort (0x06) register. +2. If 4-line mode is enabled in host and slot configuration, the driver attempts to set the Bus width field in the Bus Interface Control (0x07) register. If setting the filed is successful, which means that the slave supports 4-line mode, the host is also switched to 4-line mode. +3. If high-speed mode is enabled in the host configuration, the SHS bit is set in the High Speed (0x13) register. + +In particular, the driver does not set any bits in (1) I/O Enable and Int Enable registers, (2) I/O block sizes, etc. Applications can set them by calling :cpp:func:`sdmmc_io_write_byte`. + +For card configuration and data transfer, choose the pair of functions relevant to your case from the table below. + +========================================================================= ================================= ================================= +Action Read Function Write Function +========================================================================= ================================= ================================= +Read and write a single byte using IO_RW_DIRECT (CMD52) :cpp:func:`sdmmc_io_read_byte` :cpp:func:`sdmmc_io_write_byte` +Read and write multiple bytes using IO_RW_EXTENDED (CMD53) in byte mode :cpp:func:`sdmmc_io_read_bytes` :cpp:func:`sdmmc_io_write_bytes` +Read and write blocks of data using IO_RW_EXTENDED (CMD53) in block mode :cpp:func:`sdmmc_io_read_blocks` :cpp:func:`sdmmc_io_write_blocks` +========================================================================= ================================= ================================= + +SDIO interrupts can be enabled by the application using the function :cpp:func:`sdmmc_io_enable_int`. When using SDIO in 1-line mode, the D1 line also needs to be connected to use SDIO interrupts. + +If you want the application to wait until the SDIO interrupt occurs, use :cpp:func:`sdmmc_io_wait_int`. -The application can wait for SDIO interrupt to occur using :cpp:func:`sdmmc_io_wait_int`. Combo (memory + IO) cards ^^^^^^^^^^^^^^^^^^^^^^^^^ -The driver does not support SD combo cards. Combo cards will be treated as IO cards. +The driver does not support SD combo cards. Combo cards are treated as IO cards. Thread safety ^^^^^^^^^^^^^ -Most applications need to use the protocol layer only in one task; therefore the protocol layer doesn't implement any kind of locking on the :cpp:class:`sdmmc_card_t` structure, or when accessing SDMMC or SD SPI host drivers. Such locking is usually implemented in the higher layer (e.g. in the filesystem driver). +Most applications need to use the protocol layer only in one task. For this reason, the protocol layer does not implement any kind of locking on the :cpp:class:`sdmmc_card_t` structure, or when accessing SDMMC or SD SPI host drivers. Such locking is usually implemented on a higher layer, e.g., in the filesystem driver. API Reference diff --git a/docs/en/api-reference/storage/spi_flash.rst b/docs/en/api-reference/storage/spi_flash.rst index 1dbb92bdd5..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..1f2c25940f 100644 --- a/docs/en/api-reference/system/index.rst +++ b/docs/en/api-reference/system/index.rst @@ -23,6 +23,7 @@ System API ESP HTTPS OTA ESP pthread Error Codes and Helper Functions + App image format Miscellaneous System APIs 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..a96992c062 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 `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..d0bef754df 100644 --- a/docs/en/get-started/windows-setup-scratch.rst +++ b/docs/en/get-started/windows-setup-scratch.rst @@ -1,117 +1,120 @@ -************************************ +******************************************** 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 `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: + +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`. +.. _ninja: https://ninja-build.org/ +.. _Python: https://www.python.org/downloads/windows/ .. _MSYS2: https://msys2.github.io/ -.. _MSYS2-packages issues list: https://github.com/Alexpux/MSYS2-packages/issues/ -.. _raise an IDF issue: https://github.com/espressif/esp-idf/issues/new +.. _Stable version: https://docs.espressif.com/projects/esp-idf/en/stable/ + diff --git a/docs/en/get-started/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..838348e252 100644 --- a/docs/en/hw-reference/modules-and-boards.rst +++ b/docs/en/hw-reference/modules-and-boards.rst @@ -4,42 +4,44 @@ ESP32 Modules and Boards ************************ -Espressif designed and manufactured several development modules and boards to help users evaluate functionality of the ESP32 family of chips. Development boards, depending on intended functionality, have exposed GPIO pins headers, provide USB programming interface, JTAG interface as well as peripherals like touch pads, LCD screen, SD card slot, camera module header, etc. +Espressif designs and manufactures different modules and development boards to help users evaluate the potential of the ESP32 family of chips. -For details please refer to documentation below, provided together with description of particular boards. +This document provides description of modules and development boards currently available from Espressif. .. note:: - This section describes the latest versions of boards. Previous versions of boards, including these not produced anymore, are described in section :ref:`esp-modules-and-boards-previous`. + For description of previous versions of modules and development boards as well as for description of discontinued ones, please go to Section :ref:`esp-modules-and-boards-previous`. .. _esp-wroom-solo-wrover-modules: -WROOM, SOLO and WROVER Modules -============================== +WROOM, SOLO, WROVER, and PICO Modules +===================================== -A family of small modules that contain ESP32 chip on board together with some key components including a crystal oscillator and an antenna matching circuit. This makes it easier to provide an ESP32 based solution ready to integrate into final products. Such modules can be also used for evaluation after adding a few extra components like a programming interface, bootstrapping resistors and break out headers. The key characteristics of these modules are summarized in the following table. Some additional details are covered in the following chapters. +This is a family of ESP32-based modules with some integrated key components, including a crystal oscillator and an antenna matching circuit. The modules constitute ready-made solutions for integration into final products. If combined with a few extra components, such as a programming interface, bootstrapping resistors, and pin headers, these modules can also be used for evaluation of ESP32's functionality. -=============== ============ ===== ====== ==== --- Key Components ---------------- --------------------------------- -Module Chip Flash PSRAM Ant. -=============== ============ ===== ====== ==== -ESP32-WROOM-32 ESP32-D0WDQ6 4MB -- MIFA -ESP32-WROOM-32D ESP32-D0WD 4MB -- MIFA -ESP32-WROOM-32U ESP32-D0WD 4MB -- U.FL -ESP32-SOLO-1 ESP32-S0WD 4MB -- MIFA -ESP32-WROVER ESP32-D0WDQ6 4MB 8MB MIFA -ESP32-WROVER-I ESP32-D0WDQ6 4MB 8MB U.FL -ESP32-WROVER-B ESP32-D0WD 4MB 8MB MIFA -ESP32-WROVER-IB ESP32-D0WD 4MB 8MB U.FL -=============== ============ ===== ====== ==== +The key characteristics of these modules are summarized in the table below. Some additional details are covered in the following sections. -* ESP32-**D**.. denotes dual core, ESP32-**S**.. denotes single core chip -* MIFA - Meandered Inverted-F Antenna +=================== ============ =========== ========= ==== =============== + Key Components +------------------- ------------------------------------------ --------------- +Module Chip Flash, MB PSRAM, MB Ant. Dimensions, mm +=================== ============ =========== ========= ==== =============== +ESP32-WROOM-32 ESP32-D0WDQ6 4 -- MIFA 18 × 25.5 × 3.1 +ESP32-WROOM-32D ESP32-D0WD 4, 8, or 16 -- MIFA 18 × 25.5 × 3.1 +ESP32-WROOM-32U ESP32-D0WD 4, 8, or 16 -- U.FL 18 × 19.2 × 3.1 +ESP32-SOLO-1 ESP32-S0WD 4 -- MIFA 18 × 25.5 × 3.1 +ESP32-WROVER (PCB) ESP32-D0WDQ6 4 8 MIFA 18 × 31.4 × 3.3 +ESP32-WROVER (IPEX) ESP32-D0WDQ6 4 8 U.FL 18 × 31.4 × 3.3 +ESP32-WROVER-B ESP32-D0WD 4, 8, or 16 8 MIFA 18 × 31.4 × 3.3 +ESP32-WROVER-IB ESP32-D0WD 4, 8, or 16 8 U.FL 18 × 31.4 × 3.3 +=================== ============ =========== ========= ==== =============== + +* ESP32-**D**.. identifies a dual-core chip, ESP32-**S**.. identifies a single-core chip +* MIFA - Meandered Inverted-F Antenna * U.FL - U.FL / IPEX antenna connector -* ESP32-WROOM-x and ESP32-WROVER-x modules are also available with custom flash sizes of 8MB or 16MB, see `Espressif Products Ordering Information`_ (PDF) +* ESP32-WROOM-32x, ESP32-WROVER-B and ESP32-WROVER-IB modules come with 4 MB flash by default but also available with custom flash sizes of 8 MB and 16 MB, see `Espressif Products Ordering Information`_ (PDF) * `ESP32 Chip Datasheet `__ (PDF) -* Initial release of ESP32-WROVER module had 4MB of PSRAM +* Initial release of the ESP32-WROVER module had 4 MB of PSRAM * *ESP32-WROOM-32* was previously called *ESP-WROOM-32* @@ -48,7 +50,10 @@ ESP32-WROVER-IB ESP32-D0WD 4MB 8MB U.FL ESP32-WROOM-32 -------------- -A basic and commonly adopted ESP32 module with ESP32-D0WDQ6 chip on board. The first one of the WROOM / WROVER family released to the market. By default the module has 4MB flash and may be also ordered with custom flash size of 8 or 16MB, see `Espressif Products Ordering Information`_. +This is a basic and commonly adopted ESP32 module with the ESP32-D0WDQ6 chip on board. It was the first module of the WROOM / WROVER family released to the market. + +For key characteristics, see the table in Section :ref:`esp-wroom-solo-wrover-modules`, `Espressif Products Ordering Information`_. + .. figure:: https://dl.espressif.com/dl/schematics/pictures/esp32-wroom-32-front-back.jpg :align: center @@ -61,7 +66,7 @@ Documentation ^^^^^^^^^^^^^ * `ESP32-WROOM-32 Datasheet `__ (PDF) -* `ESP32-WROOM-32 Reference Design `_ containing OrCAD schematic, PCB layout, gerbers and BOM +* `ESP32-WROOM-32 Reference Design `_ containing OrCAD schematic, PCB layout, gerber and BOM files .. _esp-modules-and-boards-esp32-wroom-32d-and-u: @@ -69,7 +74,11 @@ Documentation ESP32-WROOM-32D / ESP32-WROOM-32U --------------------------------- -Both modules have ESP32-D0WD chip on board of a smaller footprint than ESP32-D0WDQ6 installed in :ref:`esp-modules-and-boards-esp32-wroom-32`. By default the module has 4MB flash and may be also ordered with custom flash size of 8 or 16MB, see `Espressif Products Ordering Information`_. Version "D" has a MIFA antenna. Version "U" has just an U.FL / IPEX antenna connector. That makes it 6.3 mm shorter comparing to "D", and also the smallest representative of the whole WROOM / WROVER family of modules. +Both modules integrate the ESP32-D0WD chip which has a smaller footprint than the chip ESP32-D0WDQ6 installed in :ref:`esp-modules-and-boards-esp32-wroom-32`. + +For key characteristics, see the table in Section :ref:`esp-wroom-solo-wrover-modules` and `Espressif Products Ordering Information`_. + +ESP32-WROOM-32U is the smallest representative of the whole WROOM / WROVER family of modules. .. figure:: https://dl.espressif.com/dl/schematics/pictures/esp32-wroom-32d-front-back.jpg :align: center @@ -96,7 +105,9 @@ Documentation ESP32-SOLO-1 ------------ -Simplified version of ESP32-WROOM-32D module. It contains a single core ESP32 chip that supports clock frequency of up to 160 MHz. +This is a simplified version of the ESP32-WROOM-32D module. It contains a single-core ESP32 chip that supports a clock frequency of up to 160 MHz. + +For key characteristics, see the table in Section :ref:`esp-wroom-solo-wrover-modules` and `Espressif Products Ordering Information`_. .. figure:: https://dl.espressif.com/dl/schematics/pictures/esp32-solo-1-front-back.jpg :align: center @@ -114,19 +125,17 @@ Documentation .. _esp-modules-and-boards-esp32-wrover: -ESP32-WROVER ------------- +ESP32-WROVER series +------------------- -A step upgrade of ESP32-WROOM-32x modules with an additional 8MB SPI PSRAM (Pseudo static RAM). +This series consists of a few modifications of ESP32-WROOM-32x modules, which among other upgrades include additional 8 MB SPI PSRAM (pseudo static RAM). -The module comes in couple of versions listed in section :ref:`esp-wroom-solo-wrover-modules`: +For details, see the table in Section :ref:`esp-wroom-solo-wrover-modules` and `Espressif Products Ordering Information`_. -* **ESP32-WROVER** and **ESP32-WROVER-I** have PSRAM that operates at 1.8V and can support up to 144 MHz clock rate. -* **ESP32-WROVER-B** and **ESP32-WROVER-IB** have PSRAM that operates at 3.3V and can support up to 133 MHz clock rate. +* **ESP32-WROVER (PCB)** and **ESP32-WROVER (IPEX)** have PSRAM that operates at 1.8 V and supports up to 144 MHz clock rate. +* **ESP32-WROVER-B** and **ESP32-WROVER-IB** have PSRAM that operates at 3.3 V and can supports up to 133 MHz clock rate. -By default the module has 4MB flash and may be also ordered with custom flash size of 8 or 16MB, see `Espressif Products Ordering Information`_. - -Depending on version the module has PCB antenna (shown below) or an U.FL / IPEX antenna connector. Because of additional components inside, this module is 5.9 mm longer than :ref:`esp-modules-and-boards-esp32-wroom-32`. +The picture below shows an ESP32-WROVER module with a PCB antenna. .. figure:: https://dl.espressif.com/dl/schematics/pictures/esp32-wrover.jpg :align: center @@ -139,16 +148,47 @@ Documentation ^^^^^^^^^^^^^ * `ESP32-WROVER Datasheet `__ (PDF) +* `ESP32-WROVER-B Datasheet `__ (PDF) * `ESP-PSRAM64 & ESP-PSRAM64H Datasheet `__ (PDF) -* `ESP32-WROVER Reference Design `_ containing OrCAD schematic, PCB layout, gerbers and BOM +* `ESP32-WROVER Reference Design `_ containing OrCAD schematic, PCB layout, gerber and BOM files +ESP32-PICO-D4 +------------- + +ESP32-PICO-D4 is a System-in-Package (SiP) module, integrating all peripheral components seamlessly, including the following: + +- 4 MB flash memory +- crystal oscillator +- filter capacitors +- RF matching circuit + +For key characteristics, see `Espressif Products Ordering Information`_. + + +Documentation +^^^^^^^^^^^^^ + +* `ESP32-PICO-D4 Datasheet `__ (PDF) + + +Development Boards +================== + +Depending on the intended functionality, different development boards feature: + +- Access to different ESP32 GPIO pins. +- Different interfaces: USB, JTAG. +- Different peripherals: touchpads, LCD screens, SD card slots, headers for camera modules, etc. + .. _esp-modules-and-boards-esp32-pico-kit: ESP32-PICO-KIT V4.1 -=================== +------------------- -The smallest ESP32 development board with all the components required to connect it directly to a PC USB port, and pin headers to plug into a mini breadboard. It is equipped with ESP32-PICO-D4 module that integrates 4 MB flash memory, a crystal oscillator, filter capacitors and RF matching circuit in one single package. As result, the fully functional development board requires only a few external components that can easy fit on a 20 x 52 mm PCB including antenna, LDO, USB-UART bridge and two buttons to reset it and put into download mode. +This is the smallest available ESP32-based development board. It features all the components for direct connection to a computer's USB port as well as pin headers for plugging into a mini breadboard. + +The board is equipped with the `ESP32-PICO-D4`_ module. With such a module, the creation of a fully functional development board required only a few external components that fit on a PCB as small as 20 x 52 mm. The external components include antenna, LDO, USB-UART bridge, and two buttons for reset and activation of Firmware Download mode. .. figure:: https://dl.espressif.com/dl/schematics/pictures/esp32-pico-kit-v4.1.jpg :align: center @@ -157,18 +197,18 @@ The smallest ESP32 development board with all the components required to connect ESP32-PICO-KIT V4.1 board -Comparing to ESP32-PICO-KIT V4, this version contains a more capable CP2102N USB-UART bridge that provides up to 3 Mbps transfers rates. +Comparing to ESP32-PICO-KIT V4, this version features the CP2102N USB-UART bridge that provides faster transfer rates of up to 3 Mbps. Documentation -------------- +^^^^^^^^^^^^^ -* :doc:`../get-started/get-started-pico-kit` +* :doc:`../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 +- header for a camera module +- RGB diode for diagnostics +- 32.768 kHz XTAL for internal RTC to operate it in low power modes + +Power can be supplied either via USB or via a standard 5 mm power supply jack. A power source can be selected with a jumper and can be turned on/off with a separate switch. + +This version of the ESP-WROVER-KIT board integrates the ESP-WROVER-B module that has 8 MB PSRAM for flexible extended storage and data processing capabilities. The board can accommodate other versions of ESP modules described in :ref:`esp-wroom-solo-wrover-modules`. Comparing to :ref:`esp-modules-and-boards-esp-wrover-kit-v3`, this board has the following design changes: - * JP8, JP11 and JP13 have been combined into a single JP2 - * USB connector has been changed to DIP type and moved to the lower right corner of the board - * R61 has been changed to 0R - * Some other components, e.g. EN and Boot buttons, have been replaced with functional equivalents basing on test results and sourcing options +- JP8, JP11, and JP13 have been combined into a single JP2. +- USB connector has been changed to DIP type and moved to the lower right corner of the board. +- R61 has been changed to a Zero-ohm resistor. +- Some components have been replaced with functional equivalents based on test results and sourcing options, e.g., the EN and Boot buttons. .. figure:: https://dl.espressif.com/dl/schematics/pictures/esp-wrover-kit-v4.1-front.jpg :align: center @@ -225,18 +283,18 @@ Comparing to :ref:`esp-modules-and-boards-esp-wrover-kit-v3`, this board has the ESP-WROVER-KIT V4.1 board -The board on picture above has ESP32-WROVER-B module is installed. +The board in the picture above integrates the ESP32-WROVER-B module. Documentation -------------- +^^^^^^^^^^^^^ -* :doc:`../get-started/get-started-wrover-kit` +* :doc:`../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/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..c3a1d10035 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 @@ -21,10 +21,10 @@ API 指南 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/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..e5b4a0c4fc 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). +* Run `idf.py menuconfig` to open the project configuration menu. Most examples have a project-specific "Example Configuration" section here (for example, to set the WiFi SSID & password to use). * `make` to build the example. -* Follow the printed instructions to flash, or run `make flash`. +* Follow the printed instructions to flash, or run `idf.py flash`. # Copying Examples diff --git a/examples/bluetooth/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/ethernet/ethernet/CMakeLists.txt b/examples/bluetooth/ble_ancs/CMakeLists.txt similarity index 91% rename from examples/ethernet/ethernet/CMakeLists.txt rename to examples/bluetooth/ble_ancs/CMakeLists.txt index 6a5d19af02..ecfe4e5ad8 100644 --- a/examples/ethernet/ethernet/CMakeLists.txt +++ b/examples/bluetooth/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/ble_ancs/Makefile b/examples/bluetooth/ble_ancs/Makefile new file mode 100644 index 0000000000..a5208ef071 --- /dev/null +++ b/examples/bluetooth/ble_ancs/Makefile @@ -0,0 +1,10 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := ble_ancs + +COMPONENT_ADD_INCLUDEDIRS := components/include + +include $(IDF_PATH)/make/project.mk diff --git a/examples/bluetooth/ble_ancs/README.md b/examples/bluetooth/ble_ancs/README.md new file mode 100644 index 0000000000..06a7f4625e --- /dev/null +++ b/examples/bluetooth/ble_ancs/README.md @@ -0,0 +1,18 @@ +ESP-IDF BLE ANCS Example +========================== + +The purpose of the Apple Notification Center Service (ANCS) is to give Bluetooth accessories (that connect to iOS devices through a Bluetooth low-energy link) a simple and convenient way to access many kinds of notifications that are generated on iOS devices. + +The Apple Notification Center Service is a primary service whose service UUID is 7905F431-B5CE-4E99-A40F-4B1E122D00D0. + +Only one instance of the ANCS may be present on an NP. Due to the nature of iOS, the ANCS is not guaranteed to always be present. As a result, the NC should look for and subscribe to the Service Changed characteristic of the GATT service in order to monitor for the potential publishing and unpublishing of the ANCS at any time. + +In its basic form, the ANCS exposes three characteristics: +Notification Source: UUID 9FBF120D-6301-42D9-8C58-25E699A21DBD (notifiable) +Control Point: UUID 69D1D8F3-45E1-49A8-9821-9BBDFDAAD9D9 (writeable with response) +Data Source: UUID 22EAC6E9-24D6-4BB5-BE44-B36ACE7C7BFB (notifiable) +All these characteristics require authorization for access. + + + + diff --git a/examples/bluetooth/ble_ancs/main/CMakeLists.txt b/examples/bluetooth/ble_ancs/main/CMakeLists.txt new file mode 100644 index 0000000000..7e64fd8041 --- /dev/null +++ b/examples/bluetooth/ble_ancs/main/CMakeLists.txt @@ -0,0 +1,5 @@ +set(COMPONENT_SRCS "ble_ancs_demo.c" + "ble_ancs.c") +set(COMPONENT_ADD_INCLUDEDIRS ".") + +register_component() diff --git a/examples/bluetooth/ble_ancs/main/ble_ancs.c b/examples/bluetooth/ble_ancs/main/ble_ancs.c new file mode 100644 index 0000000000..2035b67516 --- /dev/null +++ b/examples/bluetooth/ble_ancs/main/ble_ancs.c @@ -0,0 +1,228 @@ +// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include "esp_log.h" +#include "ble_ancs.h" + +#define BLE_ANCS_TAG "BLE_ANCS" + +/* +| EventID(1 Byte) | EventFlags(1 Byte) | CategoryID(1 Byte) | CategoryCount(1 Byte) | NotificationUID(4 Bytes) | + +A GATT notification delivered through the Notification Source characteristic contains the following information: +* EventID: This field informs the accessory whether the given iOS notification was added, modified, or removed. The enumerated values for this field are defined + in EventID Values. +* EventFlags: A bitmask whose set bits inform an NC of specificities with the iOS notification. For example, if an iOS notification is considered “important”, + the NC may want to display a more aggressive user interface (UI) to make sure the user is properly alerted. The enumerated bits for this field + are defined in EventFlags. +* CategoryID: A numerical value providing a category in which the iOS notification can be classified. The NP will make a best effort to provide an accurate category + for each iOS notification. The enumerated values for this field are defined in CategoryID Values. +* CategoryCount: The current number of active iOS notifications in the given category. For example, if two unread emails are sitting in a user’s email inbox, and a new + email is pushed to the user’s iOS device, the value of CategoryCount is 3. +* NotificationUID: A 32-bit numerical value that is the unique identifier (UID) for the iOS notification. This value can be used as a handle in commands sent to the + Control Point characteristic to interact with the iOS notification. +*/ + +char *EventID_to_String(uint8_t EventID) +{ + char *str = NULL; + switch (EventID) + { + case EventIDNotificationAdded: + str = "New message"; + break; + case EventIDNotificationModified: + str = "Modified message"; + break; + case EventIDNotificationRemoved: + str = "Removed message"; + break; + default: + str = "unknown EventID"; + break; + } + return str; +} + +char *CategoryID_to_String(uint8_t CategoryID) +{ + char *Cidstr = NULL; + switch(CategoryID) { + case CategoryIDOther: + Cidstr = "Other"; + break; + case CategoryIDIncomingCall: + Cidstr = "IncomingCall"; + break; + case CategoryIDMissedCall: + Cidstr = "MissedCall"; + break; + case CategoryIDVoicemail: + Cidstr = "Voicemail"; + break; + case CategoryIDSocial: + Cidstr = "Social"; + break; + case CategoryIDSchedule: + Cidstr = "Schedule"; + break; + case CategoryIDEmail: + Cidstr = "Email"; + break; + case CategoryIDNews: + Cidstr = "News"; + break; + case CategoryIDHealthAndFitness: + Cidstr = "HealthAndFitness"; + break; + case CategoryIDBusinessAndFinance: + Cidstr = "BusinessAndFinance"; + break; + case CategoryIDLocation: + Cidstr = "Location"; + break; + case CategoryIDEntertainment: + Cidstr = "Entertainment"; + break; + default: + Cidstr = "Unknown CategoryID"; + break; + } + return Cidstr; +} + +/* +| EventID(1 Byte) | EventFlags(1 Byte) | CategoryID(1 Byte) | CategoryCount(1 Byte) | NotificationUID(4 Bytes) | +*/ + +void esp_receive_apple_notification_source(uint8_t *message, uint16_t message_len) +{ + if (!message || message_len < 5) { + return; + } + + uint8_t EventID = message[0]; + char *EventIDS = EventID_to_String(EventID); + uint8_t EventFlags = message[1]; + uint8_t CategoryID = message[2]; + char *Cidstr = CategoryID_to_String(CategoryID); + uint8_t CategoryCount = message[3]; + uint32_t NotificationUID = (message[4]) | (message[5]<< 8) | (message[6]<< 16) | (message[7] << 24); + ESP_LOGI(BLE_ANCS_TAG, "EventID:%s EventFlags:0x%x CategoryID:%s CategoryCount:%d NotificationUID:%d", EventIDS, EventFlags, Cidstr, CategoryCount, NotificationUID); +} + +void esp_receive_apple_data_source(uint8_t *message, uint16_t message_len) +{ + //esp_log_buffer_hex("data source", message, message_len); + if (!message || message_len == 0) { + return; + } + uint8_t Command_id = message[0]; + switch (Command_id) + { + case CommandIDGetNotificationAttributes: { + uint32_t NotificationUID = (message[1]) | (message[2]<< 8) | (message[3]<< 16) | (message[4] << 24); + uint32_t remian_attr_len = message_len - 5; + uint8_t *attrs = &message[5]; + ESP_LOGI(BLE_ANCS_TAG, "recevice Notification Attributes response Command_id %d NotificationUID %d", Command_id, NotificationUID); + while(remian_attr_len > 0) { + uint8_t AttributeID = attrs[0]; + uint16_t len = attrs[1] | (attrs[2] << 8); + if(len > (remian_attr_len -3)) { + ESP_LOGE(BLE_ANCS_TAG, "data error"); + break; + } + switch (AttributeID) + { + case NotificationAttributeIDAppIdentifier: + esp_log_buffer_char("Identifier", &attrs[3], len); + break; + case NotificationAttributeIDTitle: + esp_log_buffer_char("Title", &attrs[3], len); + break; + case NotificationAttributeIDSubtitle: + esp_log_buffer_char("Subtitle", &attrs[3], len); + break; + case NotificationAttributeIDMessage: + esp_log_buffer_char("Message", &attrs[3], len); + break; + case NotificationAttributeIDMessageSize: + esp_log_buffer_char("MessageSize", &attrs[3], len); + break; + case NotificationAttributeIDDate: + //yyyyMMdd'T'HHmmSS + esp_log_buffer_char("Date", &attrs[3], len); + break; + case NotificationAttributeIDPositiveActionLabel: + esp_log_buffer_hex("PActionLabel", &attrs[3], len); + break; + case NotificationAttributeIDNegativeActionLabel: + esp_log_buffer_hex("NActionLabel", &attrs[3], len); + break; + default: + esp_log_buffer_hex("unknownAttributeID", &attrs[3], len); + break; + } + + attrs += (1 + 2 + len); + remian_attr_len -= (1 + 2 + len); + } + + break; + } + case CommandIDGetAppAttributes: + ESP_LOGI(BLE_ANCS_TAG, "recevice APP Attributes response"); + break; + case CommandIDPerformNotificationAction: + ESP_LOGI(BLE_ANCS_TAG, "recevice Perform Notification Action"); + break; + default: + ESP_LOGI(BLE_ANCS_TAG, "unknown Command ID"); + break; + } +} + +char *Errcode_to_String(uint16_t status) +{ + char *Errstr = NULL; + switch (status) { + case Unknown_command: + Errstr = "Unknown_command"; + break; + case Invalid_command: + Errstr = "Invalid_command"; + break; + case Invalid_parameter: + Errstr = "Invalid_parameter"; + break; + case Action_failed: + Errstr = "Action_failed"; + break; + default: + Errstr = "unknown_failed"; + break; + } + return Errstr; + +} + + + + + + + + diff --git a/examples/bluetooth/ble_ancs/main/ble_ancs.h b/examples/bluetooth/ble_ancs/main/ble_ancs.h new file mode 100644 index 0000000000..64608ea029 --- /dev/null +++ b/examples/bluetooth/ble_ancs/main/ble_ancs.h @@ -0,0 +1,124 @@ +/* + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + + +#include +#include +#include + +//EventID values +typedef enum { + EventIDNotificationAdded = 0, + EventIDNotificationModified = 1, + EventIDNotificationRemoved = 2, + //Reserved EventID values = 3–255 +} esp_EventID; + +//EventFlags +typedef enum { + EventFlagSilent = (1 << 0), + EventFlagImportant = (1 << 1), + EventFlagPreExisting = (1 << 2), + EventFlagPositiveAction = (1 << 3), + EventFlagNegativeAction = (1 << 4), + //Reserved EventFlags = (1 << 5)–(1 << 7 +}esp_EventFlags; + +// CategoryID values +typedef enum { + CategoryIDOther = 0, + CategoryIDIncomingCall = 1, + CategoryIDMissedCall = 2, + CategoryIDVoicemail = 3, + CategoryIDSocial = 4, + CategoryIDSchedule = 5, + CategoryIDEmail = 6, + CategoryIDNews = 7, + CategoryIDHealthAndFitness = 8, + CategoryIDBusinessAndFinance = 9, + CategoryIDLocation = 10, + CategoryIDEntertainment = 11, + //Reserved CategoryID values = 12–255 +} esp_CategoryID; + +//CommandID values +typedef enum { + CommandIDGetNotificationAttributes = 0, + CommandIDGetAppAttributes = 1, + CommandIDPerformNotificationAction = 2, + //Reserved CommandID values = 3–255 +} esp_CommandID; + +//NotificationAttributeID +typedef enum { + NotificationAttributeIDAppIdentifier = 0, + NotificationAttributeIDTitle = 1, //(Needs to be followed by a 2-bytes max length parameter) + NotificationAttributeIDSubtitle = 2, //(Needs to be followed by a 2-bytes max length parameter) + NotificationAttributeIDMessage = 3, //(Needs to be followed by a 2-bytes max length parameter) + NotificationAttributeIDMessageSize = 4, + NotificationAttributeIDDate = 5, + NotificationAttributeIDPositiveActionLabel = 6, + NotificationAttributeIDNegativeActionLabel = 7, + //Reserved NotificationAttributeID values = 8–255 +} esp_NotificationAttributeID; + +/* +Note: The format of the NotificationAttributeIDMessageSize constant is a string that represents the integral value +of the message size. The format of the NotificationAttributeIDDate constant is a string that uses the Unicode Technical +Standard (UTS) #35 date format pattern yyyyMMdd'T'HHmmSS. The format of all the other constants in Table 3-5 are UTF-8 +strings. +*/ + +//ActionID values +typedef enum { + ActionIDPositive = 0, + ActionIDNegative = 1, + //Reserved ActionID values = 2–255 +} esp_ActionID; + +//AppAttributeID Values +typedef enum { + AppAttributeIDDisplayName = 0, + //Reserved AppAttributeID values = 1–255 +} esp_AppAttributeID; + +typedef struct { + uint8_t noti_attribute_id; + uint16_t attribute_len; +} esp_noti_attr_list_t; + +typedef enum { + Unknown_command = (0xA0), //The commandID was not recognized by the NP. + Invalid_command = (0xA1), //The command was improperly formatted. + Invalid_parameter = (0xA2), // One of the parameters (for example, the NotificationUID) does not refer to an existing object on the NP. + Action_failed = (0xA3), //The action was not performed +} esp_error_code; + +typedef enum { + attr_appidentifier_index = 0, //The commandID was not recognized by the NP. + attr_title_index, + attr_subtitle_index, + attr_message_index, + attr_messagesize_index, + attr_date_index, + attr_positiveactionlabel_index, + attr_negativeactionlabel_index, +} esp_attr_index; + +#define ESP_NOTIFICATIONUID_LEN 4 + + +char *EventID_to_String(uint8_t EventID); +char *CategoryID_to_String(uint8_t CategoryID); +void esp_receive_apple_notification_source(uint8_t *message, uint16_t message_len); +void esp_receive_apple_data_source(uint8_t *message, uint16_t message_len); +char *Errcode_to_String(uint16_t status); + + + + diff --git a/examples/bluetooth/ble_ancs/main/ble_ancs_demo.c b/examples/bluetooth/ble_ancs/main/ble_ancs_demo.c new file mode 100644 index 0000000000..28ca4629fc --- /dev/null +++ b/examples/bluetooth/ble_ancs/main/ble_ancs_demo.c @@ -0,0 +1,688 @@ +/* + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" +#include "esp_system.h" +#include "esp_log.h" +#include "nvs_flash.h" +#include "esp_bt.h" + +#include "esp_gap_ble_api.h" +#include "esp_gatts_api.h" +#include "esp_bt_defs.h" +#include "esp_bt_main.h" +#include "esp_gattc_api.h" +#include "esp_gatt_defs.h" +#include "esp_gatt_common_api.h" +#include "ble_ancs.h" + +#define BLE_ANCS_TAG "BLE_ANCS" +#define EXCAMPLE_DEVICE_NAME "ESP_BLE_ANCS" +#define PROFILE_A_APP_ID 0 +#define PROFILE_NUM 1 +#define ADV_CONFIG_FLAG (1 << 0) +#define SCAN_RSP_CONFIG_FLAG (1 << 1) +#define INVALID_HANDLE 0 +static uint8_t adv_config_done = 0; +static bool get_service = false; +static esp_gattc_char_elem_t *char_elem_result = NULL; +static esp_gattc_descr_elem_t *descr_elem_result = NULL; +static void periodic_timer_callback(void* arg); +esp_timer_handle_t periodic_timer; + +const esp_timer_create_args_t periodic_timer_args = { + .callback = &periodic_timer_callback, + /* name is optional, but may help identify the timer when debugging */ + .name = "periodic" +}; + +struct data_source_buffer { + uint8_t buffer[1024]; + uint16_t len; +}; + +static struct data_source_buffer data_buffer = {0}; + +//In its basic form, the ANCS exposes three characteristics: +// service UUID: 7905F431-B5CE-4E99-A40F-4B1E122D00D0 +uint8_t Apple_NC_UUID[16] = {0xD0, 0x00, 0x2D, 0x12, 0x1E, 0x4B, 0x0F, 0xA4, 0x99, 0x4E, 0xCE, 0xB5, 0x31, 0xF4, 0x05, 0x79}; +// Notification Source UUID: 9FBF120D-6301-42D9-8C58-25E699A21DBD(notifiable) +uint8_t notification_source[16] = {0xbd, 0x1d, 0xa2, 0x99, 0xe6, 0x25, 0x58, 0x8c, 0xd9, 0x42, 0x01, 0x63, 0x0d, 0x12, 0xbf, 0x9f}; +// Control Point UUID:69D1D8F3-45E1-49A8-9821-9BBDFDAAD9D9(writeable with response) +uint8_t control_point[16] = {0xd9, 0xd9, 0xaa, 0xfd, 0xbd, 0x9b, 0x21, 0x98, 0xa8, 0x49, 0xe1, 0x45, 0xf3, 0xd8, 0xd1, 0x69}; +// Data Source UUID:22EAC6E9-24D6-4BB5-BE44-B36ACE7C7BFB(notifiable) +uint8_t data_source[16] = {0xfb, 0x7b, 0x7c, 0xce, 0x6a, 0xb3, 0x44, 0xbe, 0xb5, 0x4b, 0xd6, 0x24, 0xe9, 0xc6, 0xea, 0x22}; + +/* +Note: There may be more characteristics present in the ANCS than the three listed above. That said, an NC may ignore any characteristic it does not recognize. +*/ + +static void gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param); + +static esp_bt_uuid_t apple_nc_uuid = { + .len = ESP_UUID_LEN_128, +}; + +static uint8_t hidd_service_uuid128[] = { + /* LSB <--------------------------------------------------------------------------------> MSB */ + //first uuid, 16bit, [12],[13] is the value + 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x12, 0x18, 0x00, 0x00, +}; + +// config adv data +static esp_ble_adv_data_t adv_config = { + .set_scan_rsp = false, + .include_txpower = false, + .min_interval = 0x0006, //slave connection min interval, Time = min_interval * 1.25 msec + .max_interval = 0x0010, //slave connection max interval, Time = max_interval * 1.25 msec + .appearance = ESP_BLE_APPEARANCE_GENERIC_HID, + .service_uuid_len = sizeof(hidd_service_uuid128), + .p_service_uuid = hidd_service_uuid128, + .flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT), +}; +// config scan response data +static esp_ble_adv_data_t scan_rsp_config = { + .set_scan_rsp = true, + .include_name = true, + .manufacturer_len = 0, + .p_manufacturer_data = NULL, +}; + +static esp_ble_adv_params_t adv_params = { + .adv_int_min = 0x100, + .adv_int_max = 0x100, + .adv_type = ADV_TYPE_IND, + .own_addr_type = BLE_ADDR_TYPE_RANDOM, + .channel_map = ADV_CHNL_ALL, + .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, +}; + +struct gattc_profile_inst { + esp_gattc_cb_t gattc_cb; + uint16_t gattc_if; + uint16_t app_id; + uint16_t conn_id; + uint16_t service_start_handle; + uint16_t service_end_handle; + uint16_t notification_source_handle; + uint16_t data_source_handle; + uint16_t contol_point_handle; + esp_bd_addr_t remote_bda; + uint16_t MTU_size; +}; + +static struct gattc_profile_inst gl_profile_tab[PROFILE_NUM] = { + [PROFILE_A_APP_ID] = { + .gattc_cb = gattc_profile_event_handler, + .gattc_if = ESP_GATT_IF_NONE, /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */ + }, +}; + +esp_noti_attr_list_t p_attr[8] = { + [attr_appidentifier_index] = { + .noti_attribute_id = NotificationAttributeIDAppIdentifier, + .attribute_len = 0, + }, + [attr_title_index] = { + .noti_attribute_id = NotificationAttributeIDTitle, + .attribute_len = 0xFFFF, + }, + [attr_subtitle_index] = { + .noti_attribute_id = NotificationAttributeIDSubtitle, + .attribute_len = 0xFFFF, + }, + [attr_message_index] = { + .noti_attribute_id = NotificationAttributeIDMessage, + .attribute_len = 0xFFFF, + }, + [attr_messagesize_index] = { + .noti_attribute_id = NotificationAttributeIDMessageSize, + .attribute_len = 0, + }, + [attr_date_index] = { + .noti_attribute_id = NotificationAttributeIDDate, + .attribute_len = 0, + }, + [attr_positiveactionlabel_index] = { + .noti_attribute_id = NotificationAttributeIDPositiveActionLabel, + .attribute_len = 0, + }, + [attr_negativeactionlabel_index] = { + .noti_attribute_id = NotificationAttributeIDNegativeActionLabel, + .attribute_len = 0, + }, + +}; + +/* + | CommandID(1 Byte) | NotificationUID(4 Bytes) | AttributeIDs | +*/ + +void esp_get_notification_attributes(uint8_t *notificationUID, uint8_t num_attr, esp_noti_attr_list_t *p_attr) +{ + uint8_t cmd[600] = {0}; + uint32_t index = 0; + cmd[0] = CommandIDGetNotificationAttributes; + index ++; + memcpy(&cmd[index], notificationUID, ESP_NOTIFICATIONUID_LEN); + index += ESP_NOTIFICATIONUID_LEN; + while(num_attr > 0) { + cmd[index ++] = p_attr->noti_attribute_id; + if (p_attr->attribute_len > 0) { + cmd[index ++] = p_attr->attribute_len; + cmd[index ++] = (p_attr->attribute_len << 8); + } + p_attr ++; + num_attr --; + } + + esp_ble_gattc_write_char( gl_profile_tab[PROFILE_A_APP_ID].gattc_if, + gl_profile_tab[PROFILE_A_APP_ID].conn_id, + gl_profile_tab[PROFILE_A_APP_ID].contol_point_handle, + index, + cmd, + ESP_GATT_WRITE_TYPE_RSP, + ESP_GATT_AUTH_REQ_NONE); +} + +void esp_get_app_attributes(uint8_t *appidentifier, uint16_t appidentifier_len, uint8_t num_attr, uint8_t *p_app_attrs) +{ + uint8_t buffer[600] = {0}; + uint32_t index = 0; + buffer[0] = CommandIDGetAppAttributes; + index ++; + memcpy(&buffer[index], appidentifier, appidentifier_len); + index += appidentifier_len; + memcpy(&buffer[index], p_app_attrs, num_attr); + index += num_attr; + + esp_ble_gattc_write_char( gl_profile_tab[PROFILE_A_APP_ID].gattc_if, + gl_profile_tab[PROFILE_A_APP_ID].conn_id, + gl_profile_tab[PROFILE_A_APP_ID].contol_point_handle, + index, + buffer, + ESP_GATT_WRITE_TYPE_RSP, + ESP_GATT_AUTH_REQ_NONE); +} + +void esp_perform_notification_action(uint8_t *notificationUID, uint8_t ActionID) +{ + uint8_t buffer[600] = {0}; + uint32_t index = 0; + buffer[0] = CommandIDPerformNotificationAction; + index ++; + memcpy(&buffer[index], notificationUID, ESP_NOTIFICATIONUID_LEN); + index += ESP_NOTIFICATIONUID_LEN; + buffer[index] = ActionID; + index ++; + esp_ble_gattc_write_char( gl_profile_tab[PROFILE_A_APP_ID].gattc_if, + gl_profile_tab[PROFILE_A_APP_ID].conn_id, + gl_profile_tab[PROFILE_A_APP_ID].contol_point_handle, + index, + buffer, + ESP_GATT_WRITE_TYPE_RSP, + ESP_GATT_AUTH_REQ_NONE); +} + +static void periodic_timer_callback(void* arg) +{ + esp_timer_stop(periodic_timer); + if (data_buffer.len > 0) { + esp_receive_apple_data_source(data_buffer.buffer, data_buffer.len); + memset(data_buffer.buffer, 0, data_buffer.len); + data_buffer.len = 0; + } +} + +static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) +{ + ESP_LOGV(BLE_ANCS_TAG, "GAP_EVT, event %d\n", event); + + switch (event) { + case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT: + adv_config_done &= (~SCAN_RSP_CONFIG_FLAG); + if (adv_config_done == 0) { + esp_ble_gap_start_advertising(&adv_params); + } + break; + case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: + adv_config_done &= (~ADV_CONFIG_FLAG); + if (adv_config_done == 0) { + esp_ble_gap_start_advertising(&adv_params); + } + break; + case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: + //advertising start complete event to indicate advertising start successfully or failed + if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) { + ESP_LOGE(BLE_ANCS_TAG, "advertising start failed, error status = %x", param->adv_start_cmpl.status); + break; + } + ESP_LOGI(BLE_ANCS_TAG, "advertising start success"); + break; + case ESP_GAP_BLE_PASSKEY_REQ_EVT: /* passkey request event */ + ESP_LOGI(BLE_ANCS_TAG, "ESP_GAP_BLE_PASSKEY_REQ_EVT"); + /* Call the following function to input the passkey which is displayed on the remote device */ + //esp_ble_passkey_reply(heart_rate_profile_tab[HEART_PROFILE_APP_IDX].remote_bda, true, 0x00); + break; + case ESP_GAP_BLE_OOB_REQ_EVT: { + ESP_LOGI(BLE_ANCS_TAG, "ESP_GAP_BLE_OOB_REQ_EVT"); + uint8_t tk[16] = {1}; //If you paired with OOB, both devices need to use the same tk + esp_ble_oob_req_reply(param->ble_security.ble_req.bd_addr, tk, sizeof(tk)); + break; + } + case ESP_GAP_BLE_NC_REQ_EVT: + /* The app will receive this evt when the IO has DisplayYesNO capability and the peer device IO also has DisplayYesNo capability. + show the passkey number to the user to confirm it with the number displayed by peer device. */ + esp_ble_confirm_reply(param->ble_security.ble_req.bd_addr, true); + ESP_LOGI(BLE_ANCS_TAG, "ESP_GAP_BLE_NC_REQ_EVT, the passkey Notify number:%d", param->ble_security.key_notif.passkey); + break; + case ESP_GAP_BLE_SEC_REQ_EVT: + /* send the positive(true) security response to the peer device to accept the security request. + If not accept the security request, should send the security response with negative(false) accept value*/ + esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true); + break; + case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: ///the app will receive this evt when the IO has Output capability and the peer device IO has Input capability. + ///show the passkey number to the user to input it in the peer device. + ESP_LOGI(BLE_ANCS_TAG, "The passkey Notify number:%06d", param->ble_security.key_notif.passkey); + break; + case ESP_GAP_BLE_AUTH_CMPL_EVT: { + esp_log_buffer_hex("addr", param->ble_security.auth_cmpl.bd_addr, ESP_BD_ADDR_LEN); + ESP_LOGI(BLE_ANCS_TAG, "pair status = %s",param->ble_security.auth_cmpl.success ? "success" : "fail"); + if (!param->ble_security.auth_cmpl.success) { + ESP_LOGI(BLE_ANCS_TAG, "fail reason = 0x%x",param->ble_security.auth_cmpl.fail_reason); + } + break; + } + case ESP_GAP_BLE_SET_LOCAL_PRIVACY_COMPLETE_EVT: + if (param->local_privacy_cmpl.status != ESP_BT_STATUS_SUCCESS) { + ESP_LOGE(BLE_ANCS_TAG, "config local privacy failed, error status = %x", param->local_privacy_cmpl.status); + break; + } + + esp_err_t ret = esp_ble_gap_config_adv_data(&adv_config); + if (ret) { + ESP_LOGE(BLE_ANCS_TAG, "config adv data failed, error code = %x", ret); + } else { + adv_config_done |= ADV_CONFIG_FLAG; + } + + ret = esp_ble_gap_config_adv_data(&scan_rsp_config); + if (ret) { + ESP_LOGE(BLE_ANCS_TAG, "config adv data failed, error code = %x", ret); + } else { + adv_config_done |= SCAN_RSP_CONFIG_FLAG; + } + + break; + default: + break; + } +} + +static void gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) +{ + switch (event) { + case ESP_GATTC_REG_EVT: + ESP_LOGI(BLE_ANCS_TAG, "REG_EVT"); + esp_ble_gap_set_device_name(EXCAMPLE_DEVICE_NAME); + esp_ble_gap_config_local_icon (ESP_BLE_APPEARANCE_GENERIC_WATCH); + //generate a resolvable random address + esp_ble_gap_config_local_privacy(true); + break; + case ESP_GATTC_OPEN_EVT: + if (param->open.status != ESP_GATT_OK) { + ESP_LOGE(BLE_ANCS_TAG, "open failed, error status = %x", param->open.status); + break; + } + ESP_LOGI(BLE_ANCS_TAG, "ESP_GATTC_OPEN_EVT"); + gl_profile_tab[PROFILE_A_APP_ID].conn_id = param->open.conn_id; + esp_ble_set_encryption(param->open.remote_bda, ESP_BLE_SEC_ENCRYPT_MITM); + esp_err_t mtu_ret = esp_ble_gattc_send_mtu_req (gattc_if, param->open.conn_id); + if (mtu_ret) { + ESP_LOGE(BLE_ANCS_TAG, "config MTU error, error code = %x", mtu_ret); + } + break; + case ESP_GATTC_CFG_MTU_EVT: + if (param->cfg_mtu.status != ESP_GATT_OK) { + ESP_LOGE(BLE_ANCS_TAG,"config mtu failed, error status = %x", param->cfg_mtu.status); + } + ESP_LOGI(BLE_ANCS_TAG, "ESP_GATTC_CFG_MTU_EVT, Status %d, MTU %d, conn_id %d", param->cfg_mtu.status, param->cfg_mtu.mtu, param->cfg_mtu.conn_id); + gl_profile_tab[PROFILE_A_APP_ID].MTU_size = param->cfg_mtu.mtu; + memcpy(apple_nc_uuid.uuid.uuid128, Apple_NC_UUID,16); + esp_ble_gattc_search_service(gl_profile_tab[PROFILE_A_APP_ID].gattc_if, gl_profile_tab[PROFILE_A_APP_ID].conn_id, &apple_nc_uuid); + break; + case ESP_GATTC_SEARCH_RES_EVT: { + if (param->search_res.srvc_id.uuid.len == ESP_UUID_LEN_128) { + gl_profile_tab[PROFILE_A_APP_ID].service_start_handle = param->search_res.start_handle; + gl_profile_tab[PROFILE_A_APP_ID].service_end_handle = param->search_res.end_handle; + get_service = true; + } + break; + } + case ESP_GATTC_SEARCH_CMPL_EVT: + if (param->search_cmpl.status != ESP_GATT_OK) { + ESP_LOGE(BLE_ANCS_TAG, "search service failed, error status = %x", param->search_cmpl.status); + break; + } + ESP_LOGI(BLE_ANCS_TAG, "ESP_GATTC_SEARCH_CMPL_EVT"); + if (get_service) { + uint16_t count = 0; + uint16_t offset = 0; + esp_gatt_status_t ret_status = esp_ble_gattc_get_attr_count(gattc_if, + gl_profile_tab[PROFILE_A_APP_ID].conn_id, + ESP_GATT_DB_CHARACTERISTIC, + gl_profile_tab[PROFILE_A_APP_ID].service_start_handle, + gl_profile_tab[PROFILE_A_APP_ID].service_end_handle, + INVALID_HANDLE, + &count); + if (ret_status != ESP_GATT_OK) { + ESP_LOGE(BLE_ANCS_TAG, "esp_ble_gattc_get_attr_count error, %d", __LINE__); + } + if (count > 0) { + char_elem_result = (esp_gattc_char_elem_t *)malloc(sizeof(esp_gattc_char_elem_t) * count); + memset(char_elem_result, 0xff, sizeof(esp_gattc_char_elem_t) * count); + if (!char_elem_result) { + ESP_LOGE(BLE_ANCS_TAG, "gattc no mem"); + } else { + ret_status = esp_ble_gattc_get_all_char(gattc_if, + gl_profile_tab[PROFILE_A_APP_ID].conn_id, + gl_profile_tab[PROFILE_A_APP_ID].service_start_handle, + gl_profile_tab[PROFILE_A_APP_ID].service_end_handle, + char_elem_result, + &count, + offset); + if (ret_status != ESP_GATT_OK) { + ESP_LOGE(BLE_ANCS_TAG, "esp_ble_gattc_get_all_char error, %d", __LINE__); + } + if (count > 0) { + + for (int i = 0; i < count; i ++) { + if (char_elem_result[i].uuid.len == ESP_UUID_LEN_128) { + if (char_elem_result[i].properties & ESP_GATT_CHAR_PROP_BIT_NOTIFY + && memcmp(char_elem_result[i].uuid.uuid.uuid128, notification_source, 16) == 0) { + gl_profile_tab[PROFILE_A_APP_ID].notification_source_handle = char_elem_result[i].char_handle; + esp_ble_gattc_register_for_notify (gattc_if, + gl_profile_tab[PROFILE_A_APP_ID].remote_bda, + char_elem_result[i].char_handle); + ESP_LOGI(BLE_ANCS_TAG, "Find Apple noticification source char"); + + } else if (char_elem_result[i].properties & ESP_GATT_CHAR_PROP_BIT_NOTIFY + && memcmp(char_elem_result[i].uuid.uuid.uuid128, data_source, 16) == 0) { + gl_profile_tab[PROFILE_A_APP_ID].data_source_handle = char_elem_result[i].char_handle; + esp_ble_gattc_register_for_notify (gattc_if, + gl_profile_tab[PROFILE_A_APP_ID].remote_bda, + char_elem_result[i].char_handle); + ESP_LOGI(BLE_ANCS_TAG, "Find Apple data source char"); + + } else if (char_elem_result[i].properties & ESP_GATT_CHAR_PROP_BIT_WRITE + && memcmp(char_elem_result[i].uuid.uuid.uuid128, control_point, 16) == 0) { + gl_profile_tab[PROFILE_A_APP_ID].contol_point_handle = char_elem_result[i].char_handle; + ESP_LOGI(BLE_ANCS_TAG, "Find Apple control point char"); + + } + } + } + } + } + free(char_elem_result); + } + } else { + ESP_LOGE(BLE_ANCS_TAG, "No Apple Notification Service found"); + } + + break; + case ESP_GATTC_REG_FOR_NOTIFY_EVT: { + if (param->reg_for_notify.status != ESP_GATT_OK) { + ESP_LOGI(BLE_ANCS_TAG, "ESP_GATTC_REG_FOR_NOTIFY_EVT status %d", param->reg_for_notify.status); + break; + } + uint16_t count = 0; + uint16_t offset = 0; + //uint16_t notify_en = 1; + uint8_t notify_en[2] = {0x01, 0x00}; + esp_gatt_status_t ret_status = esp_ble_gattc_get_attr_count(gattc_if, + gl_profile_tab[PROFILE_A_APP_ID].conn_id, + ESP_GATT_DB_DESCRIPTOR, + gl_profile_tab[PROFILE_A_APP_ID].service_start_handle, + gl_profile_tab[PROFILE_A_APP_ID].service_end_handle, + param->reg_for_notify.handle, + &count); + if (ret_status != ESP_GATT_OK) { + ESP_LOGE(BLE_ANCS_TAG, "esp_ble_gattc_get_attr_count error, %d", __LINE__); + } + if (count > 0) { + descr_elem_result = malloc(sizeof(esp_gattc_descr_elem_t) * count); + if (!descr_elem_result) { + ESP_LOGE(BLE_ANCS_TAG, "malloc error, gattc no mem"); + } else { + ret_status = esp_ble_gattc_get_all_descr(gattc_if, + gl_profile_tab[PROFILE_A_APP_ID].conn_id, + param->reg_for_notify.handle, + descr_elem_result, + &count, + offset); + if (ret_status != ESP_GATT_OK) { + ESP_LOGE(BLE_ANCS_TAG, "esp_ble_gattc_get_all_descr error, %d", __LINE__); + } + + for (int i = 0; i < count; ++ i) { + if (descr_elem_result[i].uuid.len == ESP_UUID_LEN_16 && descr_elem_result[i].uuid.uuid.uuid16 == ESP_GATT_UUID_CHAR_CLIENT_CONFIG) { + esp_ble_gattc_write_char_descr (gattc_if, + gl_profile_tab[PROFILE_A_APP_ID].conn_id, + descr_elem_result[i].handle, + sizeof(notify_en), + (uint8_t *)¬ify_en, + ESP_GATT_WRITE_TYPE_RSP, + ESP_GATT_AUTH_REQ_NONE); + + break; + } + } + } + free(descr_elem_result); + } + break; + } + case ESP_GATTC_NOTIFY_EVT: + //esp_log_buffer_hex(BLE_ANCS_TAG, param->notify.value, param->notify.value_len); + if (param->notify.handle == gl_profile_tab[PROFILE_A_APP_ID].notification_source_handle) { + esp_receive_apple_notification_source(param->notify.value, param->notify.value_len); + uint8_t *notificationUID = ¶m->notify.value[4]; + if (param->notify.value[0] == EventIDNotificationAdded && param->notify.value[2] == CategoryIDIncomingCall) { + ESP_LOGI(BLE_ANCS_TAG, "IncomingCall, reject"); + //Call reject + esp_perform_notification_action(notificationUID, ActionIDNegative); + } else if (param->notify.value[0] == EventIDNotificationAdded) { + //get more information + ESP_LOGI(BLE_ANCS_TAG, "Get detailed information"); + esp_get_notification_attributes(notificationUID, sizeof(p_attr)/sizeof(esp_noti_attr_list_t), p_attr); + } + } else if (param->notify.handle == gl_profile_tab[PROFILE_A_APP_ID].data_source_handle) { + memcpy(&data_buffer.buffer[data_buffer.len], param->notify.value, param->notify.value_len); + data_buffer.len += param->notify.value_len; + if (param->notify.value_len == (gl_profile_tab[PROFILE_A_APP_ID].MTU_size - 3)) { + // cpoy and wait next packet, start timer 500ms + esp_timer_start_periodic(periodic_timer, 500000); + } else { + esp_timer_stop(periodic_timer); + esp_receive_apple_data_source(data_buffer.buffer, data_buffer.len); + memset(data_buffer.buffer, 0, data_buffer.len); + data_buffer.len = 0; + } + } else { + ESP_LOGI(BLE_ANCS_TAG, "unknown handle, receive notify value:"); + } + break; + case ESP_GATTC_WRITE_DESCR_EVT: + if (param->write.status != ESP_GATT_OK) { + ESP_LOGE(BLE_ANCS_TAG, "write descr failed, error status = %x", param->write.status); + break; + } + //ESP_LOGI(BLE_ANCS_TAG, "write descr successfully"); + break; + case ESP_GATTC_SRVC_CHG_EVT: { + ESP_LOGI(BLE_ANCS_TAG, "ESP_GATTC_SRVC_CHG_EVT, bd_addr:"); + esp_log_buffer_hex(BLE_ANCS_TAG, param->srvc_chg.remote_bda, 6); + break; + } + case ESP_GATTC_WRITE_CHAR_EVT: + if (param->write.status != ESP_GATT_OK) { + char *Errstr = Errcode_to_String(param->write.status); + if (Errstr) { + ESP_LOGE(BLE_ANCS_TAG, "write control point error %s", Errstr); + } + break; + } + //ESP_LOGI(BLE_ANCS_TAG, "Write char success "); + break; + case ESP_GATTC_DISCONNECT_EVT: + ESP_LOGI(BLE_ANCS_TAG, "ESP_GATTC_DISCONNECT_EVT, reason = 0x%x", param->disconnect.reason); + get_service = false; + esp_ble_gap_start_advertising(&adv_params); + break; + case ESP_GATTC_CONNECT_EVT: + //ESP_LOGI(BLE_ANCS_TAG, "ESP_GATTC_CONNECT_EVT"); + //esp_log_buffer_hex("bda", param->connect.remote_bda, 6); + memcpy(gl_profile_tab[PROFILE_A_APP_ID].remote_bda, param->connect.remote_bda, 6); + // create gattc virtual connection + esp_ble_gattc_open(gl_profile_tab[PROFILE_A_APP_ID].gattc_if, gl_profile_tab[PROFILE_A_APP_ID].remote_bda, BLE_ADDR_TYPE_RANDOM, true); + break; + case ESP_GATTC_DIS_SRVC_CMPL_EVT: + ESP_LOGI(BLE_ANCS_TAG, "ESP_GATTC_DIS_SRVC_CMPL_EVT"); + break; + default: + break; + } +} + +static void esp_gattc_cb(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) +{ + /* If event is register event, store the gattc_if for each profile */ + if (event == ESP_GATTC_REG_EVT) { + if (param->reg.status == ESP_GATT_OK) { + gl_profile_tab[param->reg.app_id].gattc_if = gattc_if; + } else { + ESP_LOGI(BLE_ANCS_TAG, "Reg app failed, app_id %04x, status %d", + param->reg.app_id, + param->reg.status); + return; + } + } + + /* If the gattc_if equal to profile A, call profile A cb handler, + * so here call each profile's callback */ + do { + int idx; + for (idx = 0; idx < PROFILE_NUM; idx++) { + if (gattc_if == ESP_GATT_IF_NONE || /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */ + gattc_if == gl_profile_tab[idx].gattc_if) { + if (gl_profile_tab[idx].gattc_cb) { + gl_profile_tab[idx].gattc_cb(event, gattc_if, param); + } + } + } + } while (0); +} + +void init_timer(void) +{ + ESP_ERROR_CHECK(esp_timer_create(&periodic_timer_args, &periodic_timer)); +} + +void app_main() +{ + esp_err_t ret; + + // Initialize NVS. + ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK( ret ); + + // init timer + init_timer(); + + ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT)); + + esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); + ret = esp_bt_controller_init(&bt_cfg); + if (ret) { + ESP_LOGE(BLE_ANCS_TAG, "%s init controller failed: %s", __func__, esp_err_to_name(ret)); + return; + } + ret = esp_bt_controller_enable(ESP_BT_MODE_BLE); + if (ret) { + ESP_LOGE(BLE_ANCS_TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(ret)); + return; + } + + ESP_LOGI(BLE_ANCS_TAG, "%s init bluetooth", __func__); + ret = esp_bluedroid_init(); + if (ret) { + ESP_LOGE(BLE_ANCS_TAG, "%s init bluetooth failed: %s", __func__, esp_err_to_name(ret)); + return; + } + ret = esp_bluedroid_enable(); + if (ret) { + ESP_LOGE(BLE_ANCS_TAG, "%s enable bluetooth failed: %s", __func__, esp_err_to_name(ret)); + return; + } + + //register the callback function to the gattc module + ret = esp_ble_gattc_register_callback(esp_gattc_cb); + if (ret) { + ESP_LOGE(BLE_ANCS_TAG, "%s gattc register error, error code = %x\n", __func__, ret); + return; + } + + ret = esp_ble_gap_register_callback(gap_event_handler); + if (ret) { + ESP_LOGE(BLE_ANCS_TAG, "gap register error, error code = %x", ret); + return; + } + + ret = esp_ble_gattc_app_register(PROFILE_A_APP_ID); + if (ret) { + ESP_LOGE(BLE_ANCS_TAG, "%s gattc app register error, error code = %x\n", __func__, ret); + } + + ret = esp_ble_gatt_set_local_mtu(500); + if (ret) { + ESP_LOGE(BLE_ANCS_TAG, "set local MTU failed, error code = %x", ret); + } + + /* set the security iocap & auth_req & key size & init key response key parameters to the stack*/ + esp_ble_auth_req_t auth_req = ESP_LE_AUTH_REQ_SC_MITM_BOND; //bonding with peer device after authentication + esp_ble_io_cap_t iocap = ESP_IO_CAP_NONE; //set the IO capability to No output No input + uint8_t key_size = 16; //the key size should be 7~16 bytes + uint8_t init_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK; + uint8_t rsp_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK; + //set static passkey + uint32_t passkey = 123456; + uint8_t auth_option = ESP_BLE_ONLY_ACCEPT_SPECIFIED_AUTH_DISABLE; + uint8_t oob_support = ESP_BLE_OOB_DISABLE; + esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, &passkey, sizeof(uint32_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &auth_req, sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &key_size, sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_ONLY_ACCEPT_SPECIFIED_SEC_AUTH, &auth_option, sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_OOB_SUPPORT, &oob_support, sizeof(uint8_t)); + /* If your BLE device acts as a Slave, the init_key means you hope which types of key of the master should distribute to you, + and the response key means which key you can distribute to the master; + If your BLE device acts as a master, the response key means you hope which types of key of the slave should distribute to you, + and the init key means which key you can distribute to the slave. */ + esp_ble_gap_set_security_param(ESP_BLE_SM_SET_INIT_KEY, &init_key, sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_SET_RSP_KEY, &rsp_key, sizeof(uint8_t)); +} + + + diff --git a/examples/bluetooth/gatt_security_server/main/component.mk b/examples/bluetooth/ble_ancs/main/component.mk similarity index 100% rename from examples/bluetooth/gatt_security_server/main/component.mk rename to examples/bluetooth/ble_ancs/main/component.mk diff --git a/examples/bluetooth/ble_ancs/sdkconfig.defaults b/examples/bluetooth/ble_ancs/sdkconfig.defaults new file mode 100644 index 0000000000..50fc4ba9d8 --- /dev/null +++ b/examples/bluetooth/ble_ancs/sdkconfig.defaults @@ -0,0 +1,6 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY=y +CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY= +CONFIG_BTDM_CONTROLLER_MODE_BTDM= diff --git a/examples/bluetooth/ble_compatibility_test/README.md b/examples/bluetooth/ble_compatibility_test/README.md new file mode 100644 index 0000000000..928a4b6a77 --- /dev/null +++ b/examples/bluetooth/ble_compatibility_test/README.md @@ -0,0 +1,16 @@ +ESP-IDF BLE Compatibility Test Example +======================================= + +This demo is to test the compatibility of Bluetooth and mobile phones. + +* ESP32 Module: ESP-WROOM-32 + +* IDF version: 7c29a39d6f9f2dfbefc49d34d34e9267afc7200d + +* [Test case](https://github.com/espressif/esp-idf/blob/master/examples/bluetooth/ble_compatibility_test/ble_compatibility_test_case.md) + +* Test APK: LightBlue V1.1.3 + +* [Test report](https://github.com/espressif/esp-idf/blob/master/examples/bluetooth/ble_compatibility_test/esp_ble_compatibility_test_report.md) + + diff --git a/examples/bluetooth/ble_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/bluetooth/ble_compatibility_test/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_compatibility_test/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_compatibility_test/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/ble_compatibility_test/CMakeLists.txt diff --git a/examples/bluetooth/ble_compatibility_test/Makefile b/examples/bluetooth/bluedroid/ble/ble_compatibility_test/Makefile similarity index 100% rename from examples/bluetooth/ble_compatibility_test/Makefile rename to examples/bluetooth/bluedroid/ble/ble_compatibility_test/Makefile diff --git a/examples/bluetooth/ble_compatibility_test/ble_compatibility_test_case.md b/examples/bluetooth/bluedroid/ble/ble_compatibility_test/ble_compatibility_test_case.md similarity index 98% rename from examples/bluetooth/ble_compatibility_test/ble_compatibility_test_case.md rename to examples/bluetooth/bluedroid/ble/ble_compatibility_test/ble_compatibility_test_case.md index b0d544c1ab..84922d014b 100644 --- a/examples/bluetooth/ble_compatibility_test/ble_compatibility_test_case.md +++ b/examples/bluetooth/bluedroid/ble/ble_compatibility_test/ble_compatibility_test_case.md @@ -6,7 +6,7 @@ This document provides a test case for BLE smartphone compatibility and includes ### What You Need -* ESP device which needs to flash [this test program] (https://github.com/espressif/esp-idf/blob/master/examples/bluetooth/ble_compatibility_test/main/ble_compatibility_test.c) +* ESP device which needs to flash [this test program] (https://github.com/espressif/esp-idf/blob/master/examples/bluetooth/bluedroid/ble/ble_compatibility_test/main/ble_compatibility_test.c) * Smartphone with LightBlue® Explorer app ### Initialization diff --git a/examples/bluetooth/ble_compatibility_test/esp_ble_compatibility_test_report.md b/examples/bluetooth/bluedroid/ble/ble_compatibility_test/esp_ble_compatibility_test_report.md similarity index 99% rename from examples/bluetooth/ble_compatibility_test/esp_ble_compatibility_test_report.md rename to examples/bluetooth/bluedroid/ble/ble_compatibility_test/esp_ble_compatibility_test_report.md index a8ed4efac7..dd11e24290 100644 --- a/examples/bluetooth/ble_compatibility_test/esp_ble_compatibility_test_report.md +++ b/examples/bluetooth/bluedroid/ble/ble_compatibility_test/esp_ble_compatibility_test_report.md @@ -12,7 +12,7 @@ Test Demo: - https://github.com/espressif/esp-idf/tree/master/examples/bluetooth/ble_compatibility_test + https://github.com/espressif/esp-idf/tree/master/examples/bluetooth/bluedroid/ble/ble_compatibility_test Phone Brand diff --git a/examples/bluetooth/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 100% rename from examples/bluetooth/ble_compatibility_test/main/ble_compatibility_test.c rename to examples/bluetooth/bluedroid/ble/ble_compatibility_test/main/ble_compatibility_test.c diff --git a/examples/bluetooth/ble_compatibility_test/main/ble_compatibility_test.h b/examples/bluetooth/bluedroid/ble/ble_compatibility_test/main/ble_compatibility_test.h similarity index 100% rename from examples/bluetooth/ble_compatibility_test/main/ble_compatibility_test.h rename to examples/bluetooth/bluedroid/ble/ble_compatibility_test/main/ble_compatibility_test.h diff --git a/examples/bluetooth/ble_adv/main/component.mk b/examples/bluetooth/bluedroid/ble/ble_compatibility_test/main/component.mk similarity index 100% rename from examples/bluetooth/ble_adv/main/component.mk rename to examples/bluetooth/bluedroid/ble/ble_compatibility_test/main/component.mk diff --git a/examples/bluetooth/ble_compatibility_test/sdkconfig.defaults b/examples/bluetooth/bluedroid/ble/ble_compatibility_test/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/ble_compatibility_test/sdkconfig.defaults rename to examples/bluetooth/bluedroid/ble/ble_compatibility_test/sdkconfig.defaults diff --git a/examples/bluetooth/ble_eddystone/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_eddystone/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_eddystone/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/ble_eddystone/CMakeLists.txt diff --git a/examples/bluetooth/ble_eddystone/Makefile b/examples/bluetooth/bluedroid/ble/ble_eddystone/Makefile similarity index 100% rename from examples/bluetooth/ble_eddystone/Makefile rename to examples/bluetooth/bluedroid/ble/ble_eddystone/Makefile diff --git a/examples/bluetooth/ble_eddystone/README.md b/examples/bluetooth/bluedroid/ble/ble_eddystone/README.md similarity index 100% rename from examples/bluetooth/ble_eddystone/README.md rename to examples/bluetooth/bluedroid/ble/ble_eddystone/README.md diff --git a/examples/bluetooth/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 100% rename from examples/bluetooth/ble_eddystone/main/esp_eddystone_demo.c rename to examples/bluetooth/bluedroid/ble/ble_eddystone/main/esp_eddystone_demo.c diff --git a/examples/bluetooth/ble_eddystone/main/esp_eddystone_protocol.h b/examples/bluetooth/bluedroid/ble/ble_eddystone/main/esp_eddystone_protocol.h similarity index 100% rename from examples/bluetooth/ble_eddystone/main/esp_eddystone_protocol.h rename to examples/bluetooth/bluedroid/ble/ble_eddystone/main/esp_eddystone_protocol.h diff --git a/examples/bluetooth/ble_eddystone/sdkconfig.defaults b/examples/bluetooth/bluedroid/ble/ble_eddystone/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/ble_eddystone/sdkconfig.defaults rename to examples/bluetooth/bluedroid/ble/ble_eddystone/sdkconfig.defaults diff --git a/examples/bluetooth/ble_hid_device_demo/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_hid_device_demo/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_hid_device_demo/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/ble_hid_device_demo/CMakeLists.txt diff --git a/examples/bluetooth/ble_hid_device_demo/Makefile b/examples/bluetooth/bluedroid/ble/ble_hid_device_demo/Makefile similarity index 100% rename from examples/bluetooth/ble_hid_device_demo/Makefile rename to examples/bluetooth/bluedroid/ble/ble_hid_device_demo/Makefile diff --git a/examples/bluetooth/ble_hid_device_demo/README.md b/examples/bluetooth/bluedroid/ble/ble_hid_device_demo/README.md similarity index 100% rename from examples/bluetooth/ble_hid_device_demo/README.md rename to examples/bluetooth/bluedroid/ble/ble_hid_device_demo/README.md diff --git a/examples/bluetooth/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 100% rename from examples/bluetooth/ble_hid_device_demo/main/ble_hidd_demo_main.c rename to examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/ble_hidd_demo_main.c diff --git a/examples/bluetooth/ble_hid_device_demo/main/component.mk b/examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/component.mk similarity index 100% rename from examples/bluetooth/ble_hid_device_demo/main/component.mk rename to examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/component.mk diff --git a/examples/bluetooth/ble_hid_device_demo/main/esp_hidd_prf_api.c b/examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/esp_hidd_prf_api.c similarity index 100% rename from examples/bluetooth/ble_hid_device_demo/main/esp_hidd_prf_api.c rename to examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/esp_hidd_prf_api.c diff --git a/examples/bluetooth/ble_hid_device_demo/main/esp_hidd_prf_api.h b/examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/esp_hidd_prf_api.h similarity index 100% rename from examples/bluetooth/ble_hid_device_demo/main/esp_hidd_prf_api.h rename to examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/esp_hidd_prf_api.h diff --git a/examples/bluetooth/ble_hid_device_demo/main/hid_dev.c b/examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/hid_dev.c similarity index 100% rename from examples/bluetooth/ble_hid_device_demo/main/hid_dev.c rename to examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/hid_dev.c diff --git a/examples/bluetooth/ble_hid_device_demo/main/hid_dev.h b/examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/hid_dev.h similarity index 100% rename from examples/bluetooth/ble_hid_device_demo/main/hid_dev.h rename to examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/hid_dev.h diff --git a/examples/bluetooth/ble_hid_device_demo/main/hid_device_le_prf.c b/examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/hid_device_le_prf.c similarity index 100% rename from examples/bluetooth/ble_hid_device_demo/main/hid_device_le_prf.c rename to examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/hid_device_le_prf.c diff --git a/examples/bluetooth/ble_hid_device_demo/main/hidd_le_prf_int.h b/examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/hidd_le_prf_int.h similarity index 100% rename from examples/bluetooth/ble_hid_device_demo/main/hidd_le_prf_int.h rename to examples/bluetooth/bluedroid/ble/ble_hid_device_demo/main/hidd_le_prf_int.h diff --git a/examples/bluetooth/ble_hid_device_demo/sdkconfig.defaults b/examples/bluetooth/bluedroid/ble/ble_hid_device_demo/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/ble_hid_device_demo/sdkconfig.defaults rename to examples/bluetooth/bluedroid/ble/ble_hid_device_demo/sdkconfig.defaults diff --git a/examples/bluetooth/ble_ibeacon/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_ibeacon/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_ibeacon/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/ble_ibeacon/CMakeLists.txt diff --git a/examples/bluetooth/ble_ibeacon/Makefile b/examples/bluetooth/bluedroid/ble/ble_ibeacon/Makefile similarity index 100% rename from examples/bluetooth/ble_ibeacon/Makefile rename to examples/bluetooth/bluedroid/ble/ble_ibeacon/Makefile diff --git a/examples/bluetooth/ble_ibeacon/README.md b/examples/bluetooth/bluedroid/ble/ble_ibeacon/README.md similarity index 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 100% rename from examples/bluetooth/ble_ibeacon/main/ibeacon_demo.c rename to examples/bluetooth/bluedroid/ble/ble_ibeacon/main/ibeacon_demo.c diff --git a/examples/bluetooth/ble_ibeacon/sdkconfig.defaults b/examples/bluetooth/bluedroid/ble/ble_ibeacon/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/ble_ibeacon/sdkconfig.defaults rename to examples/bluetooth/bluedroid/ble/ble_ibeacon/sdkconfig.defaults diff --git a/examples/bluetooth/ble_spp_client/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_spp_client/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_spp_client/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/ble_spp_client/CMakeLists.txt diff --git a/examples/bluetooth/ble_spp_client/Makefile b/examples/bluetooth/bluedroid/ble/ble_spp_client/Makefile similarity index 100% rename from examples/bluetooth/ble_spp_client/Makefile rename to examples/bluetooth/bluedroid/ble/ble_spp_client/Makefile diff --git a/examples/bluetooth/ble_spp_client/README.md b/examples/bluetooth/bluedroid/ble/ble_spp_client/README.md similarity index 100% rename from examples/bluetooth/ble_spp_client/README.md rename to examples/bluetooth/bluedroid/ble/ble_spp_client/README.md diff --git a/examples/bluetooth/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..ae3da8e1c6 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){ 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 100% rename from examples/bluetooth/ble_spp_server/main/ble_spp_server_demo.c rename to examples/bluetooth/bluedroid/ble/ble_spp_server/main/ble_spp_server_demo.c diff --git a/examples/bluetooth/ble_spp_server/main/ble_spp_server_demo.h b/examples/bluetooth/bluedroid/ble/ble_spp_server/main/ble_spp_server_demo.h similarity index 100% rename from examples/bluetooth/ble_spp_server/main/ble_spp_server_demo.h rename to examples/bluetooth/bluedroid/ble/ble_spp_server/main/ble_spp_server_demo.h diff --git a/examples/bluetooth/ble_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 100% rename from examples/bluetooth/ble_throughput/throughput_client/main/example_ble_client_throughput.c rename to examples/bluetooth/bluedroid/ble/ble_throughput/throughput_client/main/example_ble_client_throughput.c diff --git a/examples/bluetooth/ble_throughput/throughput_client/sdkconfig.defaults b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_client/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/ble_throughput/throughput_client/sdkconfig.defaults rename to examples/bluetooth/bluedroid/ble/ble_throughput/throughput_client/sdkconfig.defaults diff --git a/examples/bluetooth/ble_throughput/throughput_server/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_throughput/throughput_server/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/CMakeLists.txt diff --git a/examples/bluetooth/ble_throughput/throughput_server/Makefile b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/Makefile similarity index 100% rename from examples/bluetooth/ble_throughput/throughput_server/Makefile rename to examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/Makefile diff --git a/examples/bluetooth/ble_throughput/throughput_server/README.md b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/README.md similarity index 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 100% rename from examples/bluetooth/ble_throughput/throughput_server/main/example_ble_server_throughput.c rename to examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/main/example_ble_server_throughput.c diff --git a/examples/bluetooth/ble_throughput/throughput_server/sdkconfig.defaults b/examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/ble_throughput/throughput_server/sdkconfig.defaults rename to examples/bluetooth/bluedroid/ble/ble_throughput/throughput_server/sdkconfig.defaults diff --git a/examples/bluetooth/blufi/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/blufi/CMakeLists.txt similarity index 100% rename from examples/bluetooth/blufi/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/blufi/CMakeLists.txt diff --git a/examples/bluetooth/blufi/Makefile b/examples/bluetooth/bluedroid/ble/blufi/Makefile similarity index 100% rename from examples/bluetooth/blufi/Makefile rename to examples/bluetooth/bluedroid/ble/blufi/Makefile diff --git a/examples/bluetooth/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 100% rename from examples/bluetooth/blufi/main/blufi_example_main.c rename to examples/bluetooth/bluedroid/ble/blufi/main/blufi_example_main.c diff --git a/examples/bluetooth/blufi/main/blufi_security.c b/examples/bluetooth/bluedroid/ble/blufi/main/blufi_security.c similarity index 100% rename from examples/bluetooth/blufi/main/blufi_security.c rename to examples/bluetooth/bluedroid/ble/blufi/main/blufi_security.c diff --git a/examples/bluetooth/ble_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 100% rename from examples/bluetooth/gatt_client/main/gattc_demo.c rename to examples/bluetooth/bluedroid/ble/gatt_client/main/gattc_demo.c diff --git a/examples/bluetooth/gatt_client/sdkconfig.defaults b/examples/bluetooth/bluedroid/ble/gatt_client/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/gatt_client/sdkconfig.defaults rename to examples/bluetooth/bluedroid/ble/gatt_client/sdkconfig.defaults diff --git a/examples/bluetooth/gatt_client/tutorial/Gatt_Client_Example_Walkthrough.md b/examples/bluetooth/bluedroid/ble/gatt_client/tutorial/Gatt_Client_Example_Walkthrough.md similarity index 98% rename from examples/bluetooth/gatt_client/tutorial/Gatt_Client_Example_Walkthrough.md rename to examples/bluetooth/bluedroid/ble/gatt_client/tutorial/Gatt_Client_Example_Walkthrough.md index 2ed2c86b5e..44cb2af8df 100644 --- a/examples/bluetooth/gatt_client/tutorial/Gatt_Client_Example_Walkthrough.md +++ b/examples/bluetooth/bluedroid/ble/gatt_client/tutorial/Gatt_Client_Example_Walkthrough.md @@ -6,7 +6,7 @@ In this tutorial, the GATT client example code for the ESP32 is reviewed. The co # Includes -This example is located in the examples folder of the ESP-IDF under the [bluetooth/gatt_client/main](../main). The [gattc_demo.c](../main/gattc_demo.c) file located in the main folder contains all the functionality that we are going to review. The header files contained in [gattc_demo.c](../main/gattc_demo.c) are: +This example is located in the examples folder of the ESP-IDF under the [bluetooth/bluedroid/ble/gatt_client/main](../main). The [gattc_demo.c](../main/gattc_demo.c) file located in the main folder contains all the functionality that we are going to review. The header files contained in [gattc_demo.c](../main/gattc_demo.c) are: ```c #include @@ -511,7 +511,7 @@ In case that the client finds the service that it is looking for, the flag get_s ## Getting Characteristics -This examples implements getting characteristic data from a predefined service. The service that we want the characteristics from has an UUID of 0x00FF, and the characteristic we are interested in has an UUID of 0xFF01: +This example implements getting characteristic data from a predefined service. The service that we want the characteristics from has an UUID of 0x00FF, and the characteristic we are interested in has an UUID of 0xFF01: ```c #define REMOTE_NOTIFY_CHAR_UUID 0xFF01 diff --git a/examples/bluetooth/gatt_security_client/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/gatt_security_client/CMakeLists.txt similarity index 100% rename from examples/bluetooth/gatt_security_client/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/gatt_security_client/CMakeLists.txt diff --git a/examples/bluetooth/gatt_security_client/Makefile b/examples/bluetooth/bluedroid/ble/gatt_security_client/Makefile similarity index 100% rename from examples/bluetooth/gatt_security_client/Makefile rename to examples/bluetooth/bluedroid/ble/gatt_security_client/Makefile diff --git a/examples/bluetooth/gatt_security_client/README.md b/examples/bluetooth/bluedroid/ble/gatt_security_client/README.md similarity index 100% rename from examples/bluetooth/gatt_security_client/README.md rename to examples/bluetooth/bluedroid/ble/gatt_security_client/README.md diff --git a/examples/bluetooth/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 100% rename from examples/bluetooth/gatt_security_client/main/example_ble_sec_gattc_demo.c rename to examples/bluetooth/bluedroid/ble/gatt_security_client/main/example_ble_sec_gattc_demo.c diff --git a/examples/bluetooth/gatt_security_client/sdkconfig.defaults b/examples/bluetooth/bluedroid/ble/gatt_security_client/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/gatt_security_client/sdkconfig.defaults rename to examples/bluetooth/bluedroid/ble/gatt_security_client/sdkconfig.defaults diff --git a/examples/bluetooth/gatt_security_client/tutorial/Gatt_Security_Client_Example_Walkthrough.md b/examples/bluetooth/bluedroid/ble/gatt_security_client/tutorial/Gatt_Security_Client_Example_Walkthrough.md similarity index 100% rename from examples/bluetooth/gatt_security_client/tutorial/Gatt_Security_Client_Example_Walkthrough.md rename to examples/bluetooth/bluedroid/ble/gatt_security_client/tutorial/Gatt_Security_Client_Example_Walkthrough.md diff --git a/examples/bluetooth/gatt_security_server/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/gatt_security_server/CMakeLists.txt similarity index 100% rename from examples/bluetooth/gatt_security_server/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/gatt_security_server/CMakeLists.txt diff --git a/examples/bluetooth/gatt_security_server/Makefile b/examples/bluetooth/bluedroid/ble/gatt_security_server/Makefile similarity index 100% rename from examples/bluetooth/gatt_security_server/Makefile rename to examples/bluetooth/bluedroid/ble/gatt_security_server/Makefile diff --git a/examples/bluetooth/gatt_security_server/README.md b/examples/bluetooth/bluedroid/ble/gatt_security_server/README.md similarity index 100% rename from examples/bluetooth/gatt_security_server/README.md rename to examples/bluetooth/bluedroid/ble/gatt_security_server/README.md diff --git a/examples/bluetooth/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 100% rename from examples/bluetooth/gatt_security_server/main/example_ble_sec_gatts_demo.c rename to examples/bluetooth/bluedroid/ble/gatt_security_server/main/example_ble_sec_gatts_demo.c diff --git a/examples/bluetooth/gatt_security_server/main/example_ble_sec_gatts_demo.h b/examples/bluetooth/bluedroid/ble/gatt_security_server/main/example_ble_sec_gatts_demo.h similarity index 100% rename from examples/bluetooth/gatt_security_server/main/example_ble_sec_gatts_demo.h rename to examples/bluetooth/bluedroid/ble/gatt_security_server/main/example_ble_sec_gatts_demo.h diff --git a/examples/bluetooth/gatt_security_server/sdkconfig.defaults b/examples/bluetooth/bluedroid/ble/gatt_security_server/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/gatt_security_server/sdkconfig.defaults rename to examples/bluetooth/bluedroid/ble/gatt_security_server/sdkconfig.defaults diff --git a/examples/bluetooth/gatt_security_server/tutorial/Gatt_Security_Server_Example_Walkthrough.md b/examples/bluetooth/bluedroid/ble/gatt_security_server/tutorial/Gatt_Security_Server_Example_Walkthrough.md similarity index 100% rename from examples/bluetooth/gatt_security_server/tutorial/Gatt_Security_Server_Example_Walkthrough.md rename to examples/bluetooth/bluedroid/ble/gatt_security_server/tutorial/Gatt_Security_Server_Example_Walkthrough.md diff --git a/examples/bluetooth/gatt_server/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/gatt_server/CMakeLists.txt similarity index 100% rename from examples/bluetooth/gatt_server/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/gatt_server/CMakeLists.txt diff --git a/examples/bluetooth/gatt_server/Makefile b/examples/bluetooth/bluedroid/ble/gatt_server/Makefile similarity index 100% rename from examples/bluetooth/gatt_server/Makefile rename to examples/bluetooth/bluedroid/ble/gatt_server/Makefile diff --git a/examples/bluetooth/gatt_server/README.md b/examples/bluetooth/bluedroid/ble/gatt_server/README.md similarity index 100% rename from examples/bluetooth/gatt_server/README.md rename to examples/bluetooth/bluedroid/ble/gatt_server/README.md diff --git a/examples/bluetooth/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..6770d8f862 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], 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 100% rename from examples/bluetooth/gatt_server_service_table/main/gatts_table_creat_demo.c rename to examples/bluetooth/bluedroid/ble/gatt_server_service_table/main/gatts_table_creat_demo.c diff --git a/examples/bluetooth/gatt_server_service_table/main/gatts_table_creat_demo.h b/examples/bluetooth/bluedroid/ble/gatt_server_service_table/main/gatts_table_creat_demo.h similarity index 100% rename from examples/bluetooth/gatt_server_service_table/main/gatts_table_creat_demo.h rename to examples/bluetooth/bluedroid/ble/gatt_server_service_table/main/gatts_table_creat_demo.h diff --git a/examples/bluetooth/gatt_server_service_table/sdkconfig.defaults b/examples/bluetooth/bluedroid/ble/gatt_server_service_table/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/gatt_server_service_table/sdkconfig.defaults rename to examples/bluetooth/bluedroid/ble/gatt_server_service_table/sdkconfig.defaults diff --git a/examples/bluetooth/gatt_server_service_table/tutorial/Gatt_Server_Service_Table_Example_Walkthrough.md b/examples/bluetooth/bluedroid/ble/gatt_server_service_table/tutorial/Gatt_Server_Service_Table_Example_Walkthrough.md similarity index 100% rename from examples/bluetooth/gatt_server_service_table/tutorial/Gatt_Server_Service_Table_Example_Walkthrough.md rename to examples/bluetooth/bluedroid/ble/gatt_server_service_table/tutorial/Gatt_Server_Service_Table_Example_Walkthrough.md diff --git a/examples/bluetooth/gatt_server_service_table/tutorial/image/Heart_Rate_Service.png b/examples/bluetooth/bluedroid/ble/gatt_server_service_table/tutorial/image/Heart_Rate_Service.png similarity index 100% rename from examples/bluetooth/gatt_server_service_table/tutorial/image/Heart_Rate_Service.png rename to examples/bluetooth/bluedroid/ble/gatt_server_service_table/tutorial/image/Heart_Rate_Service.png diff --git a/examples/bluetooth/gattc_multi_connect/CMakeLists.txt b/examples/bluetooth/bluedroid/ble/gattc_multi_connect/CMakeLists.txt similarity index 100% rename from examples/bluetooth/gattc_multi_connect/CMakeLists.txt rename to examples/bluetooth/bluedroid/ble/gattc_multi_connect/CMakeLists.txt diff --git a/examples/bluetooth/gattc_multi_connect/Makefile b/examples/bluetooth/bluedroid/ble/gattc_multi_connect/Makefile similarity index 100% rename from examples/bluetooth/gattc_multi_connect/Makefile rename to examples/bluetooth/bluedroid/ble/gattc_multi_connect/Makefile diff --git a/examples/bluetooth/gattc_multi_connect/README.md b/examples/bluetooth/bluedroid/ble/gattc_multi_connect/README.md similarity index 100% rename from examples/bluetooth/gattc_multi_connect/README.md rename to examples/bluetooth/bluedroid/ble/gattc_multi_connect/README.md diff --git a/examples/bluetooth/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 100% rename from examples/bluetooth/gattc_multi_connect/main/gattc_multi_connect.c rename to examples/bluetooth/bluedroid/ble/gattc_multi_connect/main/gattc_multi_connect.c diff --git a/examples/bluetooth/gattc_multi_connect/sdkconfig.defaults b/examples/bluetooth/bluedroid/ble/gattc_multi_connect/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/gattc_multi_connect/sdkconfig.defaults rename to examples/bluetooth/bluedroid/ble/gattc_multi_connect/sdkconfig.defaults diff --git a/examples/bluetooth/gattc_multi_connect/tutorial/Gatt_Client_Multi_Connection_Example_Walkthrough.md b/examples/bluetooth/bluedroid/ble/gattc_multi_connect/tutorial/Gatt_Client_Multi_Connection_Example_Walkthrough.md similarity index 99% rename from examples/bluetooth/gattc_multi_connect/tutorial/Gatt_Client_Multi_Connection_Example_Walkthrough.md rename to examples/bluetooth/bluedroid/ble/gattc_multi_connect/tutorial/Gatt_Client_Multi_Connection_Example_Walkthrough.md index 918f6377ab..17614d0391 100644 --- a/examples/bluetooth/gattc_multi_connect/tutorial/Gatt_Client_Multi_Connection_Example_Walkthrough.md +++ b/examples/bluetooth/bluedroid/ble/gattc_multi_connect/tutorial/Gatt_Client_Multi_Connection_Example_Walkthrough.md @@ -8,7 +8,7 @@ This example’s workflow is similar to the [GATT Client Example Walkthrough](.. Four ESP32 devices are needed in order to demonstrate this example, among which: * one would be employed as a GATT Client flashed with the [gattc_multi_connect](../../gattc_multi_connect) demo, and, -* the rest run as GATT servers flashed with the [gatt_server](../../gatt_server) demo of the ESP-IDF Bluetooth examples folder. +* the rest run as GATT servers flashed with the [gatt_server](../../gatt_server) demo of the ESP-IDF examples/bluetooth/bluedroid/ble folder.
Multi-Connection GATT Client Flowchart
diff --git a/examples/bluetooth/gattc_multi_connect/tutorial/image/ESP32_GATT_Multi_Connect_Client_Application_Profiles.png b/examples/bluetooth/bluedroid/ble/gattc_multi_connect/tutorial/image/ESP32_GATT_Multi_Connect_Client_Application_Profiles.png similarity index 100% rename from examples/bluetooth/gattc_multi_connect/tutorial/image/ESP32_GATT_Multi_Connect_Client_Application_Profiles.png rename to examples/bluetooth/bluedroid/ble/gattc_multi_connect/tutorial/image/ESP32_GATT_Multi_Connect_Client_Application_Profiles.png diff --git a/examples/bluetooth/gattc_multi_connect/tutorial/image/Multi_Connection_GATT_Client_Flowchart.png b/examples/bluetooth/bluedroid/ble/gattc_multi_connect/tutorial/image/Multi_Connection_GATT_Client_Flowchart.png similarity index 100% rename from examples/bluetooth/gattc_multi_connect/tutorial/image/Multi_Connection_GATT_Client_Flowchart.png rename to examples/bluetooth/bluedroid/ble/gattc_multi_connect/tutorial/image/Multi_Connection_GATT_Client_Flowchart.png diff --git a/examples/bluetooth/a2dp_sink/CMakeLists.txt b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/CMakeLists.txt similarity index 100% rename from examples/bluetooth/a2dp_sink/CMakeLists.txt rename to examples/bluetooth/bluedroid/classic_bt/a2dp_sink/CMakeLists.txt diff --git a/examples/bluetooth/a2dp_sink/Makefile b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/Makefile similarity index 100% rename from examples/bluetooth/a2dp_sink/Makefile rename to examples/bluetooth/bluedroid/classic_bt/a2dp_sink/Makefile diff --git a/examples/bluetooth/a2dp_sink/README.md b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/README.md similarity index 96% rename from examples/bluetooth/a2dp_sink/README.md rename to examples/bluetooth/bluedroid/classic_bt/a2dp_sink/README.md index 9a3c5d611b..7d0889eccc 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 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 100% rename from examples/bluetooth/a2dp_sink/main/main.c rename to examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/main.c diff --git a/examples/bluetooth/a2dp_sink/sdkconfig.defaults b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/sdkconfig.defaults similarity index 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..a3971f8cdb 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) @@ -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 100% rename from examples/bluetooth/bt_discovery/main/bt_discovery.c rename to examples/bluetooth/bluedroid/classic_bt/bt_discovery/main/bt_discovery.c diff --git a/examples/bluetooth/a2dp_source/main/component.mk b/examples/bluetooth/bluedroid/classic_bt/bt_discovery/main/component.mk similarity index 100% rename from examples/bluetooth/a2dp_source/main/component.mk rename to examples/bluetooth/bluedroid/classic_bt/bt_discovery/main/component.mk diff --git a/examples/bluetooth/bt_discovery/sdkconfig.defaults b/examples/bluetooth/bluedroid/classic_bt/bt_discovery/sdkconfig.defaults similarity index 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 100% rename from examples/bluetooth/bt_spp_acceptor/main/example_spp_acceptor_demo.c rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_acceptor/main/example_spp_acceptor_demo.c diff --git a/examples/bluetooth/bt_spp_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 100% rename from examples/bluetooth/bt_spp_initiator/main/example_spp_initiator_demo.c rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/main/example_spp_initiator_demo.c diff --git a/examples/bluetooth/bt_spp_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 100% rename from examples/bluetooth/bt_spp_vfs_acceptor/main/example_spp_vfs_acceptor_demo.c rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/main/example_spp_vfs_acceptor_demo.c diff --git a/examples/bluetooth/bt_spp_vfs_acceptor/main/spp_task.c b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/main/spp_task.c similarity index 100% rename from examples/bluetooth/bt_spp_vfs_acceptor/main/spp_task.c rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/main/spp_task.c diff --git a/examples/bluetooth/bt_spp_vfs_acceptor/main/spp_task.h b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/main/spp_task.h similarity index 100% rename from examples/bluetooth/bt_spp_vfs_acceptor/main/spp_task.h rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_acceptor/main/spp_task.h diff --git a/examples/bluetooth/bt_spp_vfs_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 100% rename from examples/bluetooth/bt_spp_vfs_initiator/main/example_spp_vfs_initiator_demo.c rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/main/example_spp_vfs_initiator_demo.c diff --git a/examples/bluetooth/bt_spp_vfs_initiator/main/spp_task.c b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/main/spp_task.c similarity index 100% rename from examples/bluetooth/bt_spp_vfs_initiator/main/spp_task.c rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/main/spp_task.c diff --git a/examples/bluetooth/bt_spp_vfs_initiator/main/spp_task.h b/examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/main/spp_task.h similarity index 100% rename from examples/bluetooth/bt_spp_vfs_initiator/main/spp_task.h rename to examples/bluetooth/bluedroid/classic_bt/bt_spp_vfs_initiator/main/spp_task.h diff --git a/examples/bluetooth/bt_spp_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 100% rename from examples/bluetooth/a2dp_gatts_coex/main/main.c rename to examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/main/main.c diff --git a/examples/bluetooth/a2dp_gatts_coex/sdkconfig.defaults b/examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/a2dp_gatts_coex/sdkconfig.defaults rename to examples/bluetooth/bluedroid/coex/a2dp_gatts_coex/sdkconfig.defaults diff --git a/examples/bluetooth/bluedroid/coex/gattc_gatts_coex/CMakeLists.txt b/examples/bluetooth/bluedroid/coex/gattc_gatts_coex/CMakeLists.txt new file mode 100644 index 0000000000..f520a3ae27 --- /dev/null +++ b/examples/bluetooth/bluedroid/coex/gattc_gatts_coex/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(gattc_gatts_coex) diff --git a/examples/bluetooth/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..3e4989372c --- /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() +{ + 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 100% rename from examples/bluetooth/controller_hci_uart/main/controller_hci_uart_demo.c rename to examples/bluetooth/bluedroid/hci/controller_hci_uart/main/controller_hci_uart_demo.c diff --git a/examples/bluetooth/controller_hci_uart/sdkconfig.defaults b/examples/bluetooth/bluedroid/hci/controller_hci_uart/sdkconfig.defaults similarity index 100% rename from examples/bluetooth/controller_hci_uart/sdkconfig.defaults rename to examples/bluetooth/bluedroid/hci/controller_hci_uart/sdkconfig.defaults diff --git a/examples/bluetooth/ble_adv/CMakeLists.txt b/examples/bluetooth/bluedroid/hci/controller_vhci_ble_adv/CMakeLists.txt similarity index 100% rename from examples/bluetooth/ble_adv/CMakeLists.txt rename to examples/bluetooth/bluedroid/hci/controller_vhci_ble_adv/CMakeLists.txt diff --git a/examples/bluetooth/ble_adv/Makefile b/examples/bluetooth/bluedroid/hci/controller_vhci_ble_adv/Makefile similarity index 100% rename from examples/bluetooth/ble_adv/Makefile rename to examples/bluetooth/bluedroid/hci/controller_vhci_ble_adv/Makefile diff --git a/examples/bluetooth/ble_adv/README.md b/examples/bluetooth/bluedroid/hci/controller_vhci_ble_adv/README.md similarity index 67% rename from examples/bluetooth/ble_adv/README.md rename to examples/bluetooth/bluedroid/hci/controller_vhci_ble_adv/README.md index 5e9ff15c5c..6db914225d 100644 --- a/examples/bluetooth/ble_adv/README.md +++ b/examples/bluetooth/bluedroid/hci/controller_vhci_ble_adv/README.md @@ -1,5 +1,5 @@ -ESP-IDF ble_advertising app -==================== +ESP-IDF VHCI ble_advertising app +================================ This is a BLE advertising demo with virtual HCI interface. Send Reset/ADV_PARAM/ADV_DATA/ADV_ENABLE HCI command for BLE advertising. diff --git a/examples/bluetooth/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 100% rename from examples/bluetooth/ble_adv/main/app_bt.c rename to examples/bluetooth/bluedroid/hci/controller_vhci_ble_adv/main/app_bt.c diff --git a/examples/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..f384288f31 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(ble_mesh_client_model) diff --git a/examples/bluetooth/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..74361e558c --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_node/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(ble_mesh_console_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..5cf017bdca --- /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() +{ + 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() +{ + 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() +{ + 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..06c876fd64 --- /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 ble_mesh_set_node_prestore_params(uint16_t netkey_index, uint16_t unicast_addr); +esp_ble_mesh_model_t *ble_mesh_get_model(uint16_t model_id); +esp_ble_mesh_comp_t *ble_mesh_get_component(uint16_t model_id); +void ble_mesh_node_statistics_get(); +int ble_mesh_node_statistics_accumultate(uint8_t *data, uint32_t value, uint16_t type); +int ble_mesh_node_statistics_init(uint16_t package_num); +void ble_mesh_node_statistics_destroy(); + +#endif //_BLE_MESH_ADAOTER_H_ diff --git a/examples/bluetooth/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..22ab3a7f59 --- /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(); + +// Register blutooth +void register_bluetooth(); + +// Register mesh node cmd +void ble_mesh_register_mesh_node(); + +// Register mesh config server and generic server operation cmd +void ble_mesh_register_server(); + +#if (CONFIG_BLE_MESH_CFG_CLI) +// Register mesh config client operation cmd +void ble_mesh_register_configuration_client_model(); +#endif diff --git a/examples/bluetooth/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..f1f9635526 --- /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() +{ + static wl_handle_t wl_handle; + const esp_vfs_fat_mount_config_t mount_config = { + .max_files = 4, + .format_if_mount_failed = true + }; + esp_err_t err = esp_vfs_fat_spiflash_mount(MOUNT_PATH, "storage", &mount_config, &wl_handle); + if (err != ESP_OK) { + printf("Failed to mount FATFS (0x%x)", err); + return; + } +} +#endif // CONFIG_STORE_HISTORY + +static void initialize_console() +{ + /* Disable buffering on stdin and stdout */ + setvbuf(stdin, NULL, _IONBF, 0); + setvbuf(stdout, NULL, _IONBF, 0); + + /* Minicom, screen, idf_monitor send CR when ENTER key is pressed */ + esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR); + /* Move the caret to the beginning of the next line on '\n' */ + esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF); + + /* Install UART driver for interrupt-driven reads and writes */ + ESP_ERROR_CHECK( uart_driver_install(CONFIG_CONSOLE_UART_NUM, + 256, 0, 0, NULL, 0) ); + + /* Tell VFS to use UART driver */ + esp_vfs_dev_uart_use_driver(CONFIG_CONSOLE_UART_NUM); + + /* Initialize the console */ + esp_console_config_t console_config = { + .max_cmdline_args = 20, + .max_cmdline_length = 256, +#if CONFIG_LOG_COLORS + .hint_color = atoi(LOG_COLOR_CYAN) +#endif + }; + ESP_ERROR_CHECK( esp_console_init(&console_config) ); + + /* Configure linenoise line completion library */ + /* Enable multiline editing. If not set, long commands will scroll within + * single line. + */ + linenoiseSetMultiLine(1); + + /* Tell linenoise where to get command completions and hints */ + linenoiseSetCompletionCallback(&esp_console_get_completion); + linenoiseSetHintsCallback((linenoiseHintsCallback *) &esp_console_get_hint); + + /* Set command history size */ + linenoiseHistorySetMaxLen(100); + +#if CONFIG_STORE_HISTORY + /* Load command history from filesystem */ + linenoiseHistoryLoad(HISTORY_PATH); +#endif +} + + +esp_err_t bluetooth_init(void) +{ + esp_err_t ret; + + esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); + ret = esp_bt_controller_init(&bt_cfg); + if (ret) { + printf("%s initialize controller failed\n", __func__); + return ret; + } + + ret = esp_bt_controller_enable(ESP_BT_MODE_BLE); + if (ret) { + printf("%s enable controller failed\n", __func__); + return ret; + } + ret = esp_bluedroid_init(); + if (ret) { + printf("%s init bluetooth failed\n", __func__); + return ret; + } + ret = esp_bluedroid_enable(); + if (ret) { + printf("%s enable bluetooth failed\n", __func__); + return ret; + } + + return ret; +} + +void app_main(void) +{ + esp_err_t res; + + nvs_flash_init(); + + // init and enable bluetooth + res = bluetooth_init(); + if (res) { + printf("esp32_bluetooth_init failed (ret %d)", res); + } + +#if CONFIG_STORE_HISTORY + initialize_filesystem(); +#endif + + initialize_console(); + + /* Register commands */ + esp_console_register_help_command(); + register_system(); + register_bluetooth(); + ble_mesh_register_mesh_node(); + ble_mesh_register_server(); + + /* Prompt to be printed before each line. + * This can be customized, made dynamic, etc. + */ + const char *prompt = LOG_COLOR_I "esp32> " LOG_RESET_COLOR; + + printf("\n" + "This is an example of ESP-IDF console component.\n" + "Type 'help' to get the list of commands.\n" + "Use UP/DOWN arrows to navigate through command history.\n" + "Press TAB when typing command name to auto-complete.\n"); + + /* Figure out if the terminal supports escape sequences */ + int probe_status = linenoiseProbe(); + if (probe_status) { /* zero indicates success */ + printf("\n" + "Your terminal application does not support escape sequences.\n" + "Line editing and history features are disabled.\n" + "On Windows, try using Putty instead.\n"); + linenoiseSetDumbMode(1); +#if CONFIG_LOG_COLORS + /* Since the terminal doesn't support escape sequences, + * don't use color codes in the prompt. + */ + prompt = "esp32> "; +#endif //CONFIG_LOG_COLORS + } + + /* Main loop */ + while (true) { + /* Get a line using linenoise. + * The line is returned when ENTER is pressed. + */ + char *line = linenoise(prompt); + if (line == NULL) { /* Ignore empty lines */ + continue; + } + /* Add the command to the history */ + linenoiseHistoryAdd(line); +#if CONFIG_STORE_HISTORY + /* Save command history to filesystem */ + linenoiseHistorySave(HISTORY_PATH); +#endif + + /* Try to run the command */ + int ret; + esp_err_t err = esp_console_run(line, &ret); + if (err == ESP_ERR_NOT_FOUND) { + printf("Unrecognized command\n"); + } else if (err == ESP_ERR_INVALID_ARG) { + // command was empty + } else if (err == ESP_OK && ret != ESP_OK) { + printf("\nCommand returned non-zero error code: 0x%x\n", ret); + } else if (err != ESP_OK) { + printf("Internal error: 0x%x\n", err); + } + /* linenoise allocates line buffer on the heap, so need to free it */ + linenoiseFree(line); + } +} diff --git a/examples/bluetooth/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..cc8805dbf2 --- /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(); +static void register_restart(); +static void register_make(); + +void register_system() +{ + register_free(); + register_restart(); + register_make(); +} + +/** 'restart' command restarts the program */ + +static int restart(int argc, char **argv) +{ + printf("%s, %s", __func__, "Restarting"); + esp_restart(); +} + +static void register_restart() +{ + const esp_console_cmd_t cmd = { + .command = "restart", + .help = "Restart the program", + .hint = NULL, + .func = &restart, + }; + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) ); +} + +/** 'free' command prints available heap memory */ + +static int free_mem(int argc, char **argv) +{ + printf("%d\n", esp_get_free_heap_size()); + return 0; +} + +static void register_free() +{ + const esp_console_cmd_t cmd = { + .command = "free", + .help = "Get the total size of heap memory available", + .hint = NULL, + .func = &free_mem, + }; + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) ); +} + +static int make(int argc, char **argv) +{ + int count = REG_READ(RTC_CNTL_STORE0_REG); + if (++count >= 3) { + printf("This is not the console you are looking for.\n"); + return 0; + } + REG_WRITE(RTC_CNTL_STORE0_REG, count); + + const char *make_output = + R"(LD build/console.elf +esptool.py v2.1-beta1 +)"; + + const char* flash_output[] = { +R"(Flashing binaries to serial port )" CONFIG_ESPTOOLPY_PORT R"( (app at offset 0x10000)... +esptool.py v2.1-beta1 +Connecting.... +)", +R"(Chip is ESP32D0WDQ6 (revision 0) +Uploading stub... +Running stub... +Stub running... +Changing baud rate to 921600 +Changed. +Configuring flash size... +Auto-detected Flash size: 4MB +Flash params set to 0x0220 +Compressed 15712 bytes to 9345... +)", +R"(Wrote 15712 bytes (9345 compressed) at 0x00001000 in 0.1 seconds (effective 1126.9 kbit/s)... +Hash of data verified. +Compressed 333776 bytes to 197830... +)", +R"(Wrote 333776 bytes (197830 compressed) at 0x00010000 in 3.3 seconds (effective 810.3 kbit/s)... +Hash of data verified. +Compressed 3072 bytes to 82... +)", +R"(Wrote 3072 bytes (82 compressed) at 0x00008000 in 0.0 seconds (effective 1588.4 kbit/s)... +Hash of data verified. +Leaving... +Hard resetting... +)" + }; + + const char* monitor_output = +R"(MONITOR +)" LOG_COLOR_W R"(--- idf_monitor on )" CONFIG_ESPTOOLPY_PORT R"( 115200 --- +--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H -- +)" LOG_RESET_COLOR; + + bool need_make = false; + bool need_flash = false; + bool need_monitor = false; + for (int i = 1; i < argc; ++i) { + if (strcmp(argv[i], "all") == 0) { + need_make = true; + } else if (strcmp(argv[i], "flash") == 0) { + need_make = true; + need_flash = true; + } else if (strcmp(argv[i], "monitor") == 0) { + need_monitor = true; + } else if (argv[i][0] == '-') { + /* probably -j option */ + } else if (isdigit((int) argv[i][0])) { + /* might be an argument to -j */ + } else { + printf("make: *** No rule to make target `%s'. Stop.\n", argv[i]); + /* Technically this is an error, but let's not spoil the output */ + return 0; + } + } + if (argc == 1) { + need_make = true; + } + if (need_make) { + printf("%s", make_output); + } + if (need_flash) { + size_t n_items = sizeof(flash_output) / sizeof(flash_output[0]); + for (int i = 0; i < n_items; ++i) { + printf("%s", flash_output[i]); + vTaskDelay(200/portTICK_PERIOD_MS); + } + } + if (need_monitor) { + printf("%s", monitor_output); + esp_restart(); + } + return 0; +} + +static void register_make() +{ + const esp_console_cmd_t cmd = { + .command = "make", + .help = NULL, /* Do not include in 'help' output */ + .hint = "all | flash | monitor", + .func = &make, + }; + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) ); +} + + diff --git a/examples/bluetooth/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..919e69f777 --- /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(); +// Register callback function +void ble_mesh_prov_cb(esp_ble_mesh_prov_cb_event_t event, esp_ble_mesh_prov_cb_param_t *param); +void ble_mesh_model_cb(esp_ble_mesh_model_cb_event_t event, esp_ble_mesh_model_cb_param_t *param); + + +void ble_mesh_register_mesh_node() +{ + ble_mesh_register_node_cmd(); +} + +int ble_mesh_register_node_cb() +{ + ESP_LOGD(TAG, "enter %s\n", __func__); + ble_mesh_node_init(); + esp_ble_mesh_register_prov_callback(ble_mesh_prov_cb); + esp_ble_mesh_register_custom_model_callback(ble_mesh_model_cb); + ESP_LOGI(TAG, "Node:Reg,OK"); + ESP_LOGD(TAG, "exit %s\n", __func__); + return 0; +} + +void ble_mesh_prov_cb(esp_ble_mesh_prov_cb_event_t event, esp_ble_mesh_prov_cb_param_t *param) +{ + ESP_LOGD(TAG, "enter %s, event = %d", __func__, event); + switch (event) { + case ESP_BLE_MESH_PROV_REGISTER_COMP_EVT: + ble_mesh_callback_check_err_code(param->prov_register_comp.err_code, "Provisioning:Register"); + break; + case ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT: + ble_mesh_callback_check_err_code(param->node_prov_enable_comp.err_code, "Node:EnBearer"); + break; + case ESP_BLE_MESH_NODE_PROV_DISABLE_COMP_EVT: + ble_mesh_callback_check_err_code(param->node_prov_disable_comp.err_code, "Node:DisBearer"); + break; + case ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT: + ESP_LOGI(TAG, "Node:LinkOpen,OK,%d", param->node_prov_link_open.bearer); + break; + case ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT: + ESP_LOGI(TAG, "Node:LinkClose,OK,%d", param->node_prov_link_close.bearer); + break; + case ESP_BLE_MESH_NODE_PROV_OUTPUT_NUMBER_EVT: + ESP_LOGI(TAG, "Node:OutPut,%d,%d", param->node_prov_output_num.action, param->node_prov_output_num.number); + break; + case ESP_BLE_MESH_NODE_PROV_OUTPUT_STRING_EVT: + ESP_LOGI(TAG, "Node:OutPutStr,%s", param->node_prov_output_str.string); + break; + case ESP_BLE_MESH_NODE_PROV_INPUT_EVT: + ESP_LOGI(TAG, "Node:InPut,%d,%d", param->node_prov_input.action, param->node_prov_input.size); + break; + case ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT: + ESP_LOGI(TAG, "Provisioning:Success,%d", param->node_prov_complete.addr); + ble_mesh_set_node_prestore_params(param->node_prov_complete.net_idx, param->node_prov_complete.addr); + break; + case ESP_BLE_MESH_NODE_PROV_RESET_EVT: + ESP_LOGI(TAG, "Node:Reset"); + break; + case ESP_BLE_MESH_NODE_PROV_INPUT_NUMBER_COMP_EVT: + ble_mesh_callback_check_err_code(param->node_prov_input_num_comp.err_code, "Node:InputNum"); + break; + case ESP_BLE_MESH_NODE_PROV_INPUT_STRING_COMP_EVT: + ble_mesh_callback_check_err_code(param->node_prov_input_str_comp.err_code, "Node:InputStr"); + break; + case ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT: + ble_mesh_callback_check_err_code(param->node_set_unprov_dev_name_comp.err_code, "Node:SetName"); + break; + case ESP_BLE_MESH_NODE_PROXY_IDENTITY_ENABLE_COMP_EVT: + ble_mesh_callback_check_err_code(param->node_proxy_identity_enable_comp.err_code, "Node:ProxyIndentity"); + break; + case ESP_BLE_MESH_NODE_PROXY_GATT_ENABLE_COMP_EVT: + ble_mesh_callback_check_err_code(param->node_proxy_gatt_enable_comp.err_code, "Node:EnProxyGatt"); + break; + case ESP_BLE_MESH_NODE_PROXY_GATT_DISABLE_COMP_EVT: + ble_mesh_callback_check_err_code(param->node_proxy_gatt_disable_comp.err_code, "Node:DisProxyGatt"); + break; + default: + break; + } + ESP_LOGD(TAG, "exit %s", __func__); +} + +void ble_mesh_model_cb(esp_ble_mesh_model_cb_event_t event, esp_ble_mesh_model_cb_param_t *param) +{ + uint8_t status; + uint16_t result; + uint8_t data[4]; + + ESP_LOGD(TAG, "enter %s, event=%x\n", __func__, event); + printf("enter %s, event=%x\n", __func__, event); + switch (event) { + case ESP_BLE_MESH_MODEL_OPERATION_EVT: + if (param->model_operation.model != NULL && param->model_operation.model->op != NULL) { + if (param->model_operation.opcode == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET) { + ESP_LOGI(TAG, "Node:GetStatus,Success"); + ble_mesh_node_get_state(status); + esp_ble_mesh_server_model_send_msg(param->model_operation.model, param->model_operation.ctx, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, + sizeof(status), &status); + } else if (param->model_operation.opcode == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET) { + ESP_LOGI(TAG, "Node:SetAck,Success,%d,%d,%d", param->model_operation.msg[0], param->model_operation.ctx->recv_ttl, param->model_operation.length); + ble_mesh_node_set_state(param->model_operation.msg[0]); + ble_mesh_node_get_state(status); + esp_ble_mesh_server_model_send_msg(param->model_operation.model, param->model_operation.ctx, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, + sizeof(status), &status); + } else if (param->model_operation.opcode == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK) { + ble_mesh_node_set_state(param->model_operation.msg[0]); + ESP_LOGI(TAG, "Node:SetUnAck,Success,%d,%d", param->model_operation.msg[0], param->model_operation.ctx->recv_ttl); + } else if (param->model_operation.opcode == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS) { + ESP_LOGI(TAG, "Node:Status,Success,%d", param->model_operation.length); + } else if (param->model_operation.opcode == ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET) { + ESP_LOGI(TAG, "VendorModel:SetAck,Success,%d", param->model_operation.ctx->recv_ttl); + data[0] = param->model_operation.msg[0]; + data[1] = param->model_operation.msg[1]; + data[2] = param->model_operation.msg[2]; + data[3] = param->model_operation.ctx->recv_ttl; + result = ble_mesh_node_statistics_accumultate(param->model_operation.msg, param->model_operation.length, VENDOR_MODEL_PERF_OPERATION_TYPE_SET); + if (result == 0) { + esp_ble_mesh_server_model_send_msg(param->model_operation.model, param->model_operation.ctx, + ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_STATUS, sizeof(data), data); + } + } else if (param->model_operation.opcode == ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET_UNACK) { + ESP_LOGI(TAG, "VendorModel:SetUnAck,Success,%d,%d", param->model_operation.ctx->recv_ttl, param->model_operation.length); + result = ble_mesh_node_statistics_accumultate(param->model_operation.msg, param->model_operation.length, VENDOR_MODEL_PERF_OPERATION_TYPE_SET_UNACK); + if (result == 0) { + esp_ble_mesh_server_model_send_msg(param->model_operation.model, param->model_operation.ctx, + ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_STATUS, param->model_operation.length, param->model_operation.msg); + } + } + } + break; + case ESP_BLE_MESH_MODEL_SEND_COMP_EVT: + if (param->model_send_comp.err_code == ESP_OK) { + ESP_LOGI(TAG, "Node:ModelSend,OK"); + } else { + ESP_LOGE(TAG, "Node:ModelSend,Fail"); + } + break; + case ESP_BLE_MESH_MODEL_PUBLISH_COMP_EVT: + ESP_LOGI(TAG, "PublishSend,OK,0x%x,%d,", param->model_publish_comp.model->model_id, param->model_publish_comp.model->pub->msg->len); + break; + case ESP_BLE_MESH_MODEL_PUBLISH_UPDATE_EVT: + ESP_LOGI(TAG, "PublishUpdate,OK"); + break; + case ESP_BLE_MESH_CLIENT_MODEL_SEND_TIMEOUT_EVT: + ESP_LOGI(TAG, "Node:TimeOut"); + break; + case ESP_BLE_MESH_MODEL_EVT_MAX: + ESP_LOGI(TAG, "Node:MaxEvt"); + break; + default: + break; + } + + ESP_LOGD(TAG, "exit %s\n", __func__); +} + +int ble_mesh_power_set(int argc, char **argv) +{ + esp_err_t result = ESP_OK; + ESP_LOGD(TAG, "enter %s\n", __func__); + int nerrors = arg_parse(argc, argv, (void **) &power_set); + if (nerrors != 0) { + arg_print_errors(stderr, power_set.end, argv[0]); + return 1; + } + + if (strcmp(power_set.action_type->sval[0], "tx") == 0) { + result = esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, power_set.tx_sense_power->ival[0]); + } else if (strcmp(power_set.action_type->sval[0], "sense") == 0) { + uint32_t *reg = (uint32_t *)(0x6001c07c); + int reg_addr = 0x6001c07c; + uint32_t flag = 0x00FF0000; + uint32_t sense_new = power_set.tx_sense_power->ival[0]; + uint32_t reg_to_write = ((*reg) &= ~flag) | ((256 - sense_new) << 16); + REG_WRITE(reg_addr, reg_to_write); + + } + + if (result == ESP_OK) { + ESP_LOGI(TAG, "Node:SetPower,OK\n"); + } + ESP_LOGD(TAG, "exit %s\n", __func__); + return result; +} + +static int ble_mesh_load_oob(int argc, char **argv) +{ + uint8_t *static_val; + int nerrors = arg_parse(argc, argv, (void **) &oob); + + ESP_LOGD(TAG, "enter %s \n", __func__); + + if (nerrors != 0) { + arg_print_errors(stderr, oob.end, argv[0]); + return 1; + } + + //parsing prov + if (oob.static_val->count != 0) { + static_val = malloc(oob.static_val_len->ival[0] + 1); + get_value_string((char *)oob.static_val->sval[0], (char *)static_val); + prov.static_val = static_val; + } + + arg_int_to_value(oob.static_val_len, prov.static_val_len, "static_val_len"); + arg_int_to_value(oob.output_size, prov.output_size, "output_size"); + arg_int_to_value(oob.output_actions, prov.output_actions, "output_actions"); + arg_int_to_value(oob.input_size, prov.input_size, "input_size"); + arg_int_to_value(oob.input_actions, prov.input_actions, "input_action"); + + ESP_LOGI(TAG, "OOB:Load,OK\n"); + ESP_LOGD(TAG, "exit %s\n", __func__); + return 0; +} + +int ble_mesh_init(int argc, char **argv) +{ + int err; + esp_ble_mesh_comp_t *local_component = NULL; + uint8_t *device_uuid =NULL; + + int nerrors = arg_parse(argc, argv, (void **) &component); + if (nerrors != 0) { + arg_print_errors(stderr, component.end, argv[0]); + return 1; + } + + ESP_LOGD(TAG, "enter %s, module %x\n", __func__, component.model_type->ival[0]); + local_component = ble_mesh_get_component(component.model_type->ival[0]); + + if (component.dev_uuid->count != 0) { + device_uuid = malloc((16 + 1) * sizeof(uint8_t)); + if (device_uuid == NULL) { + ESP_LOGE(TAG, "ble mesh malloc failed, %d\n", __LINE__); + } + get_value_string((char *)component.dev_uuid->sval[0], (char *) device_uuid); + memcpy(dev_uuid, device_uuid, 16); + } else { + memcpy(dev_uuid, esp_bt_dev_get_address(), 6); + } + + err = esp_ble_mesh_init(&prov, local_component); + if (err) { + ESP_LOGE(TAG, "Initializing mesh failed (err %d)\n", err); + return err; + } + + free(device_uuid); + ESP_LOGD(TAG, "exit %s\n", __func__); + return err; +} + +int ble_mesh_node_enable_bearer(int argc, char **argv) +{ + esp_err_t err = 0; + + ESP_LOGD(TAG, "enter %s \n", __func__); + + int nerrors = arg_parse(argc, argv, (void **) &bearer); + if (nerrors != 0) { + arg_print_errors(stderr, bearer.end, argv[0]); + return 1; + } + + if (bearer.enable->count != 0) { + if (bearer.enable->ival[0]) { + //err = esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, ESP_PWR_LVL_N12); + err = esp_ble_mesh_node_prov_enable(bearer.bearer->ival[0]); + } else { + err = esp_ble_mesh_node_prov_disable(bearer.bearer->ival[0]); + } + } else { + return 1; + } + + ESP_LOGD(TAG, "exit %s\n", __func__); + return err; +} + +int ble_mesh_node_reset() +{ + esp_err_t err; + ESP_LOGD(TAG, "enter %s\n", __func__); + + err = esp_ble_mesh_node_local_reset(); + + ESP_LOGD(TAG, "exit %s\n", __func__); + return err; +} + +int ble_mesh_node_statistics_regist(int argc, char **argv) +{ + int result = ESP_OK; + + int nerrors = arg_parse(argc, argv, (void **) &node_statistices); + if (nerrors != 0) { + arg_print_errors(stderr, node_statistices.end, argv[0]); + return 1; + } + + ESP_LOGD(TAG, "enter %s\n", __func__); + + if (strcmp(node_statistices.action_type->sval[0], "init") == 0) { + result = ble_mesh_node_statistics_init(node_statistices.package_num->ival[0]); + ESP_LOGI(TAG, "Node:InitStatistics,OK\n"); + } else if (strcmp(node_statistices.action_type->sval[0], "get") == 0) { + ble_mesh_node_statistics_get(); + ESP_LOGI(TAG, "Node:GetStatistics,OK\n"); + } else if (strcmp(node_statistices.action_type->sval[0], "destroy") == 0) { + ble_mesh_node_statistics_destroy(); + ESP_LOGI(TAG, "Node:DestroyStatistics\n"); + } + + ESP_LOGD(TAG, "exit %s\n", __func__); + return result; +} + +int ble_mesh_node_enter_network_auto(int argc, char **argv) +{ + esp_err_t err = ESP_OK; + struct bt_mesh_device_network_info info = { + .flags = 0, + .iv_index = 0, + }; + + int nerrors = arg_parse(argc, argv, (void **) &node_network_info); + if (nerrors != 0) { + arg_print_errors(stderr, node_network_info.end, argv[0]); + return 1; + } + + ESP_LOGD(TAG, "enter %s\n", __func__); + + arg_int_to_value(node_network_info.net_idx, info.net_idx, "network key index"); + arg_int_to_value(node_network_info.unicast_addr, info.unicast_addr, "unicast address"); + arg_int_to_value(node_network_info.app_idx, info.app_idx, "appkey index"); + arg_int_to_value(node_network_info.group_addr, info.group_addr, "group address"); + err = get_value_string((char *)node_network_info.net_key->sval[0], (char *)info.net_key); + err = get_value_string((char *)node_network_info.dev_key->sval[0], (char *)info.dev_key); + err = get_value_string((char *)node_network_info.app_key->sval[0], (char *)info.app_key); + + err = bt_mesh_device_auto_enter_network(&info); + if (err == ESP_OK) { + ESP_LOGD(TAG, "NODE:EnNetwork,OK"); + } else { + ESP_LOGE(TAG, "NODE:EnNetwork,FAIL,%d", err); + } + + ESP_LOGD(TAG, "exit %s\n", __func__); + return err; +} + +void ble_mesh_register_node_cmd() +{ + const esp_console_cmd_t register_cmd = { + .command = "bmreg", + .help = "ble mesh: provisioner/node register callback", + .hint = NULL, + .func = &ble_mesh_register_node_cb, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(®ister_cmd)); + + oob.static_val = arg_str0("s", NULL, "", "Static OOB value"); + oob.static_val_len = arg_int0("l", NULL, "", "Static OOB value length"); + oob.output_size = arg_int0("x", NULL, "", "Maximum size of Output OOB"); + oob.output_actions = arg_int0("o", NULL, "", "Supported Output OOB Actions"); + oob.input_size = arg_int0("y", NULL, "", "Maximum size of Input OOB"); + oob.input_actions = arg_int0("i", NULL, "", "Supported Input OOB Actions"); + oob.end = arg_end(1); + + const esp_console_cmd_t oob_cmd = { + .command = "bmoob", + .help = "ble mesh: provisioner/node config OOB parameters", + .hint = NULL, + .func = &ble_mesh_load_oob, + .argtable = &oob, + }; + ESP_ERROR_CHECK( esp_console_cmd_register(&oob_cmd) ); + + component.model_type = arg_int0("m", NULL, "", "mesh model"); + component.config_index = arg_int0("c", NULL, "", "mesh model op"); + component.config_index->ival[0] = 0; // set default value + component.pub_config = arg_int0("p", NULL, "", "publish message buffer"); + component.dev_uuid = arg_str0("d", NULL, "", "device uuid"); + component.end = arg_end(1); + + const esp_console_cmd_t model_cmd = { + .command = "bminit", + .help = "ble mesh: provisioner/node init", + .hint = NULL, + .func = &ble_mesh_init, + .argtable = &component, + }; + ESP_ERROR_CHECK( esp_console_cmd_register(&model_cmd) ); + + bearer.bearer = arg_int0("b", NULL, "", "supported bearer"); + bearer.enable = arg_int0("e", NULL, "", "bearers node supported"); + bearer.end = arg_end(1); + + const esp_console_cmd_t bearer_cmd = { + .command = "bmnbearer", + .help = "ble mesh node: enable/disable different bearer", + .hint = NULL, + .func = &ble_mesh_node_enable_bearer, + .argtable = &bearer, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&bearer_cmd)); + + const esp_console_cmd_t reset_cmd = { + .command = "bmnreset", + .help = "ble mesh node: reset", + .hint = NULL, + .func = &ble_mesh_node_reset, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&reset_cmd)); + + node_statistices.action_type = arg_str1("z", NULL, "", "action type"); + node_statistices.package_num = arg_int0("p", NULL, "", "package number"); + node_statistices.end = arg_end(1); + + const esp_console_cmd_t node_statistices_cmd = { + .command = "bmsperf", + .help = "ble mesh server: performance statistics", + .hint = NULL, + .func = &ble_mesh_node_statistics_regist, + .argtable = &node_statistices, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&node_statistices_cmd)); + + power_set.action_type = arg_str1("z", NULL, "", "action type"); + power_set.tx_sense_power = arg_int0("t", NULL, "", "tx power or sense"); + power_set.end = arg_end(1); + + const esp_console_cmd_t power_set_cmd = { + .command = "bmtxpower", + .help = "ble mesh: set tx power or sense", + .hint = NULL, + .func = &ble_mesh_power_set, + .argtable = &power_set, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&power_set_cmd)); + + node_network_info.net_key = arg_str1("k", NULL, "", "network key"); + node_network_info.net_idx = arg_int1("n", NULL, "", "network key index"); + node_network_info.unicast_addr = arg_int1("u", NULL, "", "unicast address"); + node_network_info.dev_key = arg_str1("d", NULL, "", "device key"); + node_network_info.app_key = arg_str1("a", NULL, "", "app key"); + node_network_info.app_idx = arg_int1("i", NULL, "", "appkey index"); + node_network_info.group_addr = arg_int1("g", NULL, "", "group address"); + node_network_info.end = arg_end(1); + + const esp_console_cmd_t node_network_info_cmd = { + .command = "bmnnwk", + .help = "ble mesh node: auto join network", + .hint = NULL, + .func = &ble_mesh_node_enter_network_auto, + .argtable = &node_network_info, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&node_network_info_cmd)); +} diff --git a/examples/bluetooth/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..e2ae583bf8 --- /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(); + +typedef struct { + struct arg_str *data; + struct arg_int *opcode; + struct arg_int *model; + struct arg_int *role; + struct arg_end *end; +} ble_mesh_publish_message; +ble_mesh_publish_message msg_publish; + +void ble_mesh_register_server() +{ + ble_mesh_register_server_operation(); +} + +int ble_mesh_module_publish_message(int argc, char **argv) +{ + esp_err_t err; + esp_ble_mesh_model_t *model = NULL; + uint8_t *data = NULL; + uint8_t device_role = ROLE_NODE; + uint16_t length = 0; + + ESP_LOGD(TAG, "enter %s \n", __func__); + + int nerrors = arg_parse(argc, argv, (void **) &msg_publish); + if (nerrors != 0) { + arg_print_errors(stderr, msg_publish.end, argv[0]); + return 1; + } + + data = malloc(strlen(msg_publish.data->sval[0])); + get_value_string((char *)msg_publish.data->sval[0], (char *) data); + + arg_int_to_value(msg_publish.role, device_role, "device role"); + model = ble_mesh_get_model(msg_publish.model->ival[0]); + + err = esp_ble_mesh_model_publish(model, msg_publish.opcode->ival[0], length, data, device_role); + + ESP_LOGD(TAG, "exit %s \n", __func__); + free(data); + return err; +} + +void ble_mesh_register_server_operation() +{ + msg_publish.data = arg_str1("d", NULL, "", "message data"); + msg_publish.opcode = arg_int1("o", NULL, "", "operation opcode"); + msg_publish.model = arg_int1("m", NULL, "", "module published to"); + msg_publish.role = arg_int1("r", NULL, "", "device role"); + msg_publish.end = arg_end(1); + + const esp_console_cmd_t msg_publish_cmd = { + .command = "bmpublish", + .help = "ble mesh: publish message", + .hint = NULL, + .func = &ble_mesh_module_publish_message, + .argtable = &msg_publish, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&msg_publish_cmd)); +} + diff --git a/examples/bluetooth/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..e6b03ed590 --- /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 register_bluetooth() +{ + register_ble_address(); +} + +int bt_mac() +{ + const uint8_t *mac = esp_bt_dev_get_address(); + printf("+BTMAC:"MACSTR"\n", MAC2STR(mac)); + return 0; +} + +void register_ble_address() +{ + const esp_console_cmd_t cmd = { + .command = "btmac", + .help = "get BT mac address", + .hint = NULL, + .func = (esp_console_cmd_func_t)&bt_mac, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&cmd)); +} + diff --git a/examples/bluetooth/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..6ce28d7d57 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_console/ble_mesh_provisioner/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(ble_mesh_console_provisioner) diff --git a/examples/bluetooth/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..754b0115fa --- /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() +{ + uint16_t i; + + for (i = 0; i < NODE_MAX_GROUP_CONFIG; i++) { + ble_mesh_node_prestore_params[i].net_idx = 0xFFFF; + ble_mesh_node_prestore_params[i].unicast_addr = 0xFFFF; + } + + ble_mesh_node_sema = xSemaphoreCreateMutex(); + if (!ble_mesh_node_sema) { + ESP_LOGE(TAG, "%s failed to init, failed to create mesh node semaphore", __func__); + } +} + +void ble_mesh_set_node_prestore_params(uint16_t netkey_index, uint16_t unicast_addr) +{ + uint16_t i; + xSemaphoreTake(ble_mesh_node_sema, portMAX_DELAY); + for (i = 0; i < NODE_MAX_GROUP_CONFIG; i++) { + if (ble_mesh_node_prestore_params[i].net_idx != 0xFFFF && ble_mesh_node_prestore_params[i].unicast_addr != 0xFFFF) { + ble_mesh_node_prestore_params[i].net_idx = netkey_index; + ble_mesh_node_prestore_params[i].unicast_addr = unicast_addr; + } + } + xSemaphoreGive(ble_mesh_node_sema); +} + +void ble_mesh_create_send_data(char *data, uint16_t byte_num, uint16_t sequence_num, uint32_t opcode) +{ + uint16_t i; + + // first two bytes are sequence num, third is type + data[0] = sequence_num >> 8; + data[1] = sequence_num & 0xFF; + switch (opcode) { + case ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_GET: + data[2] = VENDOR_MODEL_PERF_OPERATION_TYPE_GET; + break; + case ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET: + data[2] = VENDOR_MODEL_PERF_OPERATION_TYPE_SET; + break; + case ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET_UNACK: + data[2] = VENDOR_MODEL_PERF_OPERATION_TYPE_SET_UNACK; + break; + } + + for (i = 3; i < byte_num; i++) { + data[i] = i; + } +} + +void ble_mesh_test_performance_client_model_get() +{ + uint32_t i, j; + uint32_t sum_time = 0; + + xSemaphoreTake(ble_mesh_test_perf_sema, portMAX_DELAY); + + for (i = 0, j = 0; i < test_perf_statistics.test_num; i++) { + if (test_perf_statistics.time[i] != 0) { + sum_time += test_perf_statistics.time[i]; + j += 1; + } else { + continue; + } + + if (j == test_perf_statistics.test_num - 1) { + break; + } + } + + ESP_LOGI(TAG, "VendorModel:Statistics,%d,%d\n", + test_perf_statistics.statistics, (sum_time / (j + 1))); + + xSemaphoreGive(ble_mesh_test_perf_sema); +} + +void ble_mesh_test_performance_client_model_get_received_percent() +{ + uint32_t i, j; + uint32_t max_time = 1400; + uint32_t min_time = 0; + uint32_t time_level_num = 0; + typedef struct { + uint16_t time_level; + uint16_t time_num; + } statistics_time_performance; + statistics_time_performance *statistics_time_percent; + + xSemaphoreTake(ble_mesh_test_perf_sema, portMAX_DELAY); + + time_level_num = ((max_time - min_time) / 50 + 1); + statistics_time_percent = malloc(sizeof(statistics_time_performance) * time_level_num); + + for (j = 0; j < time_level_num; j++) { + statistics_time_percent[j].time_level = min_time + 50 * j; + statistics_time_percent[j].time_num = 0; + } + + for (i = 0; i < test_perf_statistics.test_num; i++) { + for (j = 0; j < time_level_num; j++) { + if (test_perf_statistics.time[i] > max_time) { + j -= 1; + break; + } + if (test_perf_statistics.time[i] >= min_time + 50 * j + && test_perf_statistics.time[i] < min_time + 50 * (j + 1)) { + statistics_time_percent[j].time_num += 1; + break; + } + } + } + + // for script match + ESP_LOGI(TAG, "VendorModel:Statistics"); + for (j = 0; j < time_level_num; j++) { + printf(",%d:%d", statistics_time_percent[j].time_level, statistics_time_percent[j].time_num); + } + printf("\n"); + + free(statistics_time_percent); + xSemaphoreGive(ble_mesh_test_perf_sema); +} + +void ble_mesh_test_performance_client_model_accumulate_statistics(uint32_t value) +{ + xSemaphoreTake(ble_mesh_test_perf_sema, portMAX_DELAY); + test_perf_statistics.statistics += value; + xSemaphoreGive(ble_mesh_test_perf_sema); +} + +int ble_mesh_test_performance_client_model_accumulate_time(uint16_t time, uint8_t *data, uint8_t ack_ttl, uint16_t length) +{ + uint16_t i; + uint16_t sequence_num = 0; + uint16_t node_received_ttl = 0; + xSemaphoreTake(ble_mesh_test_perf_sema, portMAX_DELAY); + + // received fail + if (length != test_perf_statistics.test_length) { + xSemaphoreGive(ble_mesh_test_perf_sema); + return 1; + } + + if (data != NULL) { + sequence_num = (data[0] << 8) | data[1]; + if (data[2] == VENDOR_MODEL_PERF_OPERATION_TYPE_SET) { + node_received_ttl = data[3]; + } + } + + for (i = 0; i < test_perf_statistics.test_num; i++) { + if (test_perf_statistics.package_index[i] == sequence_num) { + xSemaphoreGive(ble_mesh_test_perf_sema); + return 1; + } + } + + for (i = 0; i < test_perf_statistics.test_num; i++) { + if (test_perf_statistics.package_index[i] == 0) { + test_perf_statistics.package_index[i] = sequence_num; + if (data[2] == VENDOR_MODEL_PERF_OPERATION_TYPE_SET) { + if (node_received_ttl == test_perf_statistics.ttl && ack_ttl == test_perf_statistics.ttl) { + test_perf_statistics.time[i] = time; + } else { + test_perf_statistics.time[i] = 0; + } + } else if (data[2] == VENDOR_MODEL_PERF_OPERATION_TYPE_SET_UNACK) { + test_perf_statistics.time[i] = time; + } + break; + } + } + + xSemaphoreGive(ble_mesh_test_perf_sema); + return 0; +} + +int ble_mesh_test_performance_client_model_init(uint16_t node_num, uint32_t test_num, uint8_t ttl) +{ + uint16_t i; + + // malloc time + test_perf_statistics.time = malloc(test_num * sizeof(uint16_t)); + if (test_perf_statistics.time == NULL) { + ESP_LOGE(TAG, " %s %d, malloc fail\n", __func__, __LINE__); + return 1; + } + + test_perf_statistics.package_index = malloc(test_num * sizeof(uint16_t)); + if (test_perf_statistics.package_index == NULL) { + ESP_LOGE(TAG, " %s %d, malloc fail\n", __func__, __LINE__); + } + for (i = 0; i < test_num; i++) { + test_perf_statistics.time[i] = 0; + test_perf_statistics.package_index[i] = 0; + } + + test_perf_statistics.test_num = test_num; + test_perf_statistics.node_num = node_num; + test_perf_statistics.ttl = ttl; + test_perf_statistics.statistics = 0; + return 0; +} + +void ble_mesh_test_performance_client_model_destroy() +{ + if (test_perf_statistics.time != NULL) { + free(test_perf_statistics.time); + } + + if (test_perf_statistics.package_index != NULL) { + free(test_perf_statistics.package_index); + } + + test_perf_statistics.test_num = 0; + test_perf_statistics.ttl = 0; + test_perf_statistics.node_num = 0; + test_perf_statistics.statistics = 0; +} diff --git a/examples/bluetooth/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..bdc083a215 --- /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 ble_mesh_set_node_prestore_params(uint16_t netkey_index, uint16_t unicast_addr); + +esp_ble_mesh_model_t *ble_mesh_get_model(uint16_t model_id); +esp_ble_mesh_comp_t *ble_mesh_get_component(uint16_t model_id); +void ble_mesh_create_send_data(char *data, uint16_t byte_num, uint16_t sequence_num, uint32_t opcode); + +void ble_mesh_test_performance_client_model_get(); +void ble_mesh_test_performance_client_model_get_received_percent(); +void ble_mesh_test_performance_client_model_accumulate_statistics(uint32_t value); +int ble_mesh_test_performance_client_model_accumulate_time(uint16_t time, uint8_t *data, uint8_t ack_ttl, uint16_t length); +int ble_mesh_test_performance_client_model_init(uint16_t node_num, uint32_t test_num, uint8_t ttl); +void ble_mesh_test_performance_client_model_destroy(); + +#endif //_BLE_MESH_ADAPTER_H_ \ No newline at end of file diff --git a/examples/bluetooth/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..90e52a61d9 --- /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(); + +// Register bluetooth +void register_bluetooth(); + +// Register mesh node cmd +void ble_mesh_register_mesh_node(); + +// Register Test Perf client cmd +void ble_mesh_register_mesh_test_performance_client(); + +#if (CONFIG_BLE_MESH_CFG_CLI) +// Register mesh config client operation cmd +void ble_mesh_register_configuration_client_model(); +#endif + +#if (CONFIG_BLE_MESH_GENERIC_ONOFF_CLI) +// Register mesh client operation cmd +void ble_mesh_register_gen_onoff_client(); +#endif + +#if CONFIG_BLE_MESH_PROVISIONER +// Regitster mesh provisioner cmd +void ble_mesh_register_mesh_provisioner(); +#endif diff --git a/examples/bluetooth/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..d9d4a9e4e9 --- /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() +{ + static wl_handle_t wl_handle; + const esp_vfs_fat_mount_config_t mount_config = { + .max_files = 4, + .format_if_mount_failed = true + }; + esp_err_t err = esp_vfs_fat_spiflash_mount(MOUNT_PATH, "storage", &mount_config, &wl_handle); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to mount FATFS (0x%x)", err); + return; + } +} +#endif // CONFIG_STORE_HISTORY + +static void initialize_console() +{ + /* Disable buffering on stdin and stdout */ + setvbuf(stdin, NULL, _IONBF, 0); + setvbuf(stdout, NULL, _IONBF, 0); + + /* Minicom, screen, idf_monitor send CR when ENTER key is pressed */ + esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR); + /* Move the caret to the beginning of the next line on '\n' */ + esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF); + + /* Install UART driver for interrupt-driven reads and writes */ + ESP_ERROR_CHECK( uart_driver_install(CONFIG_CONSOLE_UART_NUM, + 256, 0, 0, NULL, 0) ); + + /* Tell VFS to use UART driver */ + esp_vfs_dev_uart_use_driver(CONFIG_CONSOLE_UART_NUM); + + /* Initialize the console */ + esp_console_config_t console_config = { + .max_cmdline_args = 20, + .max_cmdline_length = 256, +#if CONFIG_LOG_COLORS + .hint_color = atoi(LOG_COLOR_CYAN) +#endif + }; + ESP_ERROR_CHECK( esp_console_init(&console_config) ); + + /* Configure linenoise line completion library */ + /* Enable multiline editing. If not set, long commands will scroll within + * a single line. + */ + linenoiseSetMultiLine(1); + + /* Tell linenoise where to get command completions and hints */ + linenoiseSetCompletionCallback(&esp_console_get_completion); + linenoiseSetHintsCallback((linenoiseHintsCallback *) &esp_console_get_hint); + + /* Set command history size */ + linenoiseHistorySetMaxLen(100); + +#if CONFIG_STORE_HISTORY + /* Load command history from filesystem */ + linenoiseHistoryLoad(HISTORY_PATH); +#endif +} + + +esp_err_t bluetooth_init(void) +{ + esp_err_t ret; + + esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); + ret = esp_bt_controller_init(&bt_cfg); + if (ret) { + ESP_LOGE(TAG, "%s failed to initialize controller\n", __func__); + return ret; + } + + ret = esp_bt_controller_enable(ESP_BT_MODE_BLE); + if (ret) { + ESP_LOGE(TAG, "%s failed to enable controller\n", __func__); + return ret; + } + ret = esp_bluedroid_init(); + if (ret) { + ESP_LOGE(TAG, "%s failed to initialize bluetooth\n", __func__); + return ret; + } + ret = esp_bluedroid_enable(); + if (ret) { + ESP_LOGE(TAG, "%s failed to enable bluetooth\n", __func__); + return ret; + } + + return ret; +} + +void app_main(void) +{ + esp_err_t res; + + nvs_flash_init(); + + // init and enable bluetooth + res = bluetooth_init(); + if (res) { + printf("esp32_bluetooth_init failed (ret %d)", res); + } + +#if CONFIG_STORE_HISTORY + initialize_filesystem(); +#endif + + initialize_console(); + + /* Register commands */ + esp_console_register_help_command(); + register_system(); + register_bluetooth(); + ble_mesh_register_mesh_node(); + ble_mesh_register_mesh_test_performance_client(); +#if (CONFIG_BLE_MESH_GENERIC_ONOFF_CLI) + ble_mesh_register_gen_onoff_client(); +#endif +#if (CONFIG_BLE_MESH_PROVISIONER) + ble_mesh_register_mesh_provisioner(); +#endif +#if (CONFIG_BLE_MESH_CFG_CLI) + ble_mesh_register_configuration_client_model(); +#endif + + + /* Prompt to be printed before each line. + * This can be customized, made dynamic, etc. + */ + const char *prompt = LOG_COLOR_I "esp32> " LOG_RESET_COLOR; + + printf("\n" + "This is an example of an ESP-IDF console component.\n" + "Type 'help' to get the list of commands.\n" + "Use UP/DOWN arrows to navigate through the command history.\n" + "Press TAB when typing a command name to auto-complete.\n"); + + /* Figure out if the terminal supports escape sequences */ + int probe_status = linenoiseProbe(); + if (probe_status) { /* zero indicates OK */ + printf("\n" + "Your terminal application does not support escape sequences.\n" + "Line editing and history features are disabled.\n" + "On Windows, try using Putty instead.\n"); + linenoiseSetDumbMode(1); +#if CONFIG_LOG_COLORS + /* Since the terminal doesn't support escape sequences, + * don't use color codes in the prompt. + */ + prompt = "esp32> "; +#endif //CONFIG_LOG_COLORS + } + + /* Main loop */ + while (true) { + /* Get a line using linenoise. + * The line is returned when ENTER is pressed. + */ + char *line = linenoise(prompt); + if (line == NULL) { /* Ignore empty lines */ + continue; + } + /* Add the command to the history */ + linenoiseHistoryAdd(line); +#if CONFIG_STORE_HISTORY + /* Save command history to filesystem */ + linenoiseHistorySave(HISTORY_PATH); +#endif + + /* Try to run the command */ + int ret; + esp_err_t err = esp_console_run(line, &ret); + if (err == ESP_ERR_NOT_FOUND) { + printf("Unrecognized command\n"); + } else if (err == ESP_ERR_INVALID_ARG) { + // command was empty + } else if (err == ESP_OK && ret != ESP_OK) { + printf("\nCommand returned non-zero error code: 0x%x\n", ret); + } else if (err != ESP_OK) { + printf("Internal error: 0x%x\n", err); + } + /* linenoise allocates line buffer on the heap, so need to free it */ + linenoiseFree(line); + } +} diff --git a/examples/bluetooth/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..d3dc6c12f9 --- /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(); +static void register_restart(); +static void register_make(); + +void register_system() +{ + register_free(); + register_restart(); + register_make(); +} + +/** 'restart' command restarts the program */ + +static int restart(int argc, char **argv) +{ + printf("%s, %s", __func__, "Restarting"); + esp_restart(); +} + +static void register_restart() +{ + const esp_console_cmd_t cmd = { + .command = "restart", + .help = "Restart the program", + .hint = NULL, + .func = &restart, + }; + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) ); +} + +/** 'free' command prints available heap memory */ + +static int free_mem(int argc, char **argv) +{ + printf("%d\n", esp_get_free_heap_size()); + return 0; +} + +static void register_free() +{ + const esp_console_cmd_t cmd = { + .command = "free", + .help = "Get the total size of heap memory available", + .hint = NULL, + .func = &free_mem, + }; + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) ); +} + +static int make(int argc, char **argv) +{ + int count = REG_READ(RTC_CNTL_STORE0_REG); + if (++count >= 3) { + printf("This is not the console you are looking for.\n"); + return 0; + } + REG_WRITE(RTC_CNTL_STORE0_REG, count); + + const char *make_output = + R"(LD build/console.elf +esptool.py v2.1-beta1 +)"; + + const char* flash_output[] = { +R"(Flashing binaries to serial port )" CONFIG_ESPTOOLPY_PORT R"( (app at offset 0x10000)... +esptool.py v2.1-beta1 +Connecting.... +)", +R"(Chip is ESP32D0WDQ6 (revision 0) +Uploading stub... +Running stub... +Stub running... +Changing baud rate to 921600 +Changed. +Configuring flash size... +Auto-detected Flash size: 4MB +Flash params set to 0x0220 +Compressed 15712 bytes to 9345... +)", +R"(Wrote 15712 bytes (9345 compressed) at 0x00001000 in 0.1 seconds (effective 1126.9 kbit/s)... +Hash of data verified. +Compressed 333776 bytes to 197830... +)", +R"(Wrote 333776 bytes (197830 compressed) at 0x00010000 in 3.3 seconds (effective 810.3 kbit/s)... +Hash of data verified. +Compressed 3072 bytes to 82... +)", +R"(Wrote 3072 bytes (82 compressed) at 0x00008000 in 0.0 seconds (effective 1588.4 kbit/s)... +Hash of data verified. +Leaving... +Hard resetting... +)" + }; + + const char* monitor_output = +R"(MONITOR +)" LOG_COLOR_W R"(--- idf_monitor on )" CONFIG_ESPTOOLPY_PORT R"( 115200 --- +--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H -- +)" LOG_RESET_COLOR; + + bool need_make = false; + bool need_flash = false; + bool need_monitor = false; + for (int i = 1; i < argc; ++i) { + if (strcmp(argv[i], "all") == 0) { + need_make = true; + } else if (strcmp(argv[i], "flash") == 0) { + need_make = true; + need_flash = true; + } else if (strcmp(argv[i], "monitor") == 0) { + need_monitor = true; + } else if (argv[i][0] == '-') { + /* probably -j option */ + } else if (isdigit((int) argv[i][0])) { + /* might be an argument to -j */ + } else { + printf("make: *** No rule to make target `%s'. Stop.\n", argv[i]); + /* Technically this is an error, but let's not spoil the output */ + return 0; + } + } + if (argc == 1) { + need_make = true; + } + if (need_make) { + printf("%s", make_output); + } + if (need_flash) { + size_t n_items = sizeof(flash_output) / sizeof(flash_output[0]); + for (int i = 0; i < n_items; ++i) { + printf("%s", flash_output[i]); + vTaskDelay(200/portTICK_PERIOD_MS); + } + } + if (need_monitor) { + printf("%s", monitor_output); + esp_restart(); + } + return 0; +} + +static void register_make() +{ + const esp_console_cmd_t cmd = { + .command = "make", + .help = NULL, /* Do not include in 'help' output */ + .hint = "all | flash | monitor", + .func = &make, + }; + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) ); +} + + diff --git a/examples/bluetooth/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..53a10d38d1 --- /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 ble_mesh_configuration_client_model_cb(esp_ble_mesh_cfg_client_cb_event_t event, + esp_ble_mesh_cfg_client_cb_param_t *param); + +void ble_mesh_register_configuration_client_model() +{ + ble_mesh_register_configuration_client_model_command(); +} + +void ble_mesh_configuration_client_model_cb(esp_ble_mesh_cfg_client_cb_event_t event, + esp_ble_mesh_cfg_client_cb_param_t *param) +{ + uint32_t opcode; + ESP_LOGD(TAG, "enter %s, event = %x\n, error_code = %x\n", __func__, event, param->error_code); + + if (!param->error_code) { + opcode = param->params->opcode; + switch (event) { + case ESP_BLE_MESH_CFG_CLIENT_GET_STATE_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_BEACON_GET: + ESP_LOGI(TAG, "CfgClient:beacon,0x%x", param->status_cb.beacon_status.beacon); + break; + case ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET: + ESP_LOGI(TAG, "CfgClient:page,0x%x,len,0x%x", param->status_cb.comp_data_status.page, param->status_cb.comp_data_status.composition_data->len); + break; + case ESP_BLE_MESH_MODEL_OP_DEFAULT_TTL_GET: + ESP_LOGI(TAG, "CfgClient:ttl,0x%x", param->status_cb.default_ttl_status.default_ttl); + break; + case ESP_BLE_MESH_MODEL_OP_GATT_PROXY_GET: + ESP_LOGI(TAG, "CfgClient:proxy,0x%x", param->status_cb.gatt_proxy_status.gatt_proxy); + break; + case ESP_BLE_MESH_MODEL_OP_RELAY_GET: + ESP_LOGI(TAG, "CfgClient:relay,0x%x,retransmit,0x%x", param->status_cb.relay_status.relay, param->status_cb.relay_status.retransmit); + break; + case ESP_BLE_MESH_MODEL_OP_MODEL_PUB_GET: + if (param->status_cb.model_pub_status.status == ESP_OK) { + ESP_LOGI(TAG, "CfgClient:PublishGet,OK,0x%x", param->status_cb.model_pub_status.publish_addr); + } else { + ESP_LOGI(TAG, "CfgClient:PublishGet,Fail"); + } + + break; + case ESP_BLE_MESH_MODEL_OP_FRIEND_GET: + ESP_LOGI(TAG, "CfgClient:friend,0x%x", param->status_cb.friend_status.friend_state); + break; + case ESP_BLE_MESH_MODEL_OP_HEARTBEAT_PUB_GET: + if (param->status_cb.heartbeat_pub_status.status == ESP_OK) { + ESP_LOGI(TAG, "CfgClient:HeartBeatPubGet,OK,destination:0x%x,countlog:0x%x,periodlog:0x%x,ttl:0x%x,features:0x%x,net_idx:0x%x", + param->status_cb.heartbeat_pub_status.dst, param->status_cb.heartbeat_pub_status.count, param->status_cb.heartbeat_pub_status.period, + param->status_cb.heartbeat_pub_status.ttl, param->status_cb.heartbeat_pub_status.features, param->status_cb.heartbeat_pub_status.net_idx); + } else { + ESP_LOGI(TAG, "CfgClient:HeartBeatGet,Fail,%d", param->status_cb.heartbeat_pub_status.status); + } + break; + case ESP_BLE_MESH_MODEL_OP_HEARTBEAT_SUB_GET: + if (param->status_cb.heartbeat_sub_status.status == ESP_OK) { + ESP_LOGI(TAG, "CfgClient:HeartBeatSubGet,OK,source:0x%x,destination:0x%x, periodlog:0x%x,countlog:0x%x,minhops:0x%x,maxhops:0x%x", + param->status_cb.heartbeat_sub_status.src, param->status_cb.heartbeat_sub_status.dst, param->status_cb.heartbeat_sub_status.period, + param->status_cb.heartbeat_sub_status.count, param->status_cb.heartbeat_sub_status.min_hops, param->status_cb.heartbeat_sub_status.max_hops); + } else { + ESP_LOGI(TAG, "CfgClient:HeartBeatSubGet,Fail,%d", param->status_cb.heartbeat_sub_status.status); + } + break; + default: + ESP_LOGI(TAG, "Not supported config client get message opcode"); + break; + } + break; + case ESP_BLE_MESH_CFG_CLIENT_SET_STATE_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_BEACON_SET: + ESP_LOGI(TAG, "CfgClient:beacon,0x%x", param->status_cb.beacon_status.beacon); + break; + case ESP_BLE_MESH_MODEL_OP_DEFAULT_TTL_SET: + ESP_LOGI(TAG, "CfgClient:ttl,0x%x", param->status_cb.default_ttl_status.default_ttl); + break; + case ESP_BLE_MESH_MODEL_OP_GATT_PROXY_SET: + ESP_LOGI(TAG, "CfgClient:proxy,0x%x", param->status_cb.gatt_proxy_status.gatt_proxy); + break; + case ESP_BLE_MESH_MODEL_OP_RELAY_SET: + ESP_LOGI(TAG, "CfgClient:relay,0x%x, retransmit: 0x%x", param->status_cb.relay_status.relay, param->status_cb.relay_status.retransmit); + break; + case ESP_BLE_MESH_MODEL_OP_MODEL_PUB_SET: + if (param->status_cb.model_pub_status.status == ESP_OK) { + ESP_LOGI(TAG, "CfgClient:PublishSet,OK,0x%x", param->status_cb.model_pub_status.publish_addr); + } else { + ESP_LOGI(TAG, "CfgClient:PublishSet,Fail"); + } + break; + case ESP_BLE_MESH_MODEL_OP_MODEL_SUB_ADD: + if (param->status_cb.model_sub_status.status == ESP_OK) { + ESP_LOGI(TAG, "CnfClient:SubAdd,OK,%x,%x", param->status_cb.model_sub_status.element_addr, param->status_cb.model_sub_status.sub_addr); + } else { + ESP_LOGI(TAG, "CnfClient:SubAdd,Fail,%x", param->status_cb.model_sub_status.status); + } + break; + case ESP_BLE_MESH_MODEL_OP_MODEL_SUB_DELETE: + if (param->status_cb.model_sub_status.status == ESP_OK) { + ESP_LOGI(TAG, "CnfClient:SubDel,OK,%x,%x", param->status_cb.model_sub_status.element_addr, param->status_cb.model_sub_status.sub_addr); + } else { + ESP_LOGI(TAG, "CnfClient:SubDel,Fail,%x", param->status_cb.model_sub_status.status); + } + break; + case ESP_BLE_MESH_MODEL_OP_MODEL_SUB_OVERWRITE: + break; + case ESP_BLE_MESH_MODEL_OP_MODEL_SUB_VIRTUAL_ADDR_ADD: + break; + case ESP_BLE_MESH_MODEL_OP_MODEL_SUB_VIRTUAL_ADDR_DELETE: + break; + case ESP_BLE_MESH_MODEL_OP_MODEL_SUB_VIRTUAL_ADDR_OVERWRITE: + break; + case ESP_BLE_MESH_MODEL_OP_NET_KEY_ADD: + if (param->status_cb.netkey_status.status == ESP_OK) { + ESP_LOGI(TAG, "CfgClient:NetKeyAdd,OK"); + } else { + ESP_LOGI(TAG, "CfgClient:NetKeyAdd,Fail,%d", param->status_cb.netkey_status.status); + } + break; + case ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD: + if (param->status_cb.appkey_status.status == ESP_OK) { + ESP_LOGI(TAG, "CnfClient:AddAppkey,OK,%x,%x,%x", param->status_cb.appkey_status.net_idx, param->status_cb.appkey_status.app_idx, param->params->ctx.addr); + } else { + ESP_LOGI(TAG, "CnfClient:AddAppkey,Fail,%x", param->status_cb.appkey_status.status); + } + break; + case ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND: + if (param->status_cb.model_app_status.status == ESP_OK) { + ESP_LOGI(TAG, "CnfClient:AppkeyBind,OK,%x,%x,%x", param->status_cb.model_app_status.app_idx, param->status_cb.model_app_status.model_id, param->params->ctx.addr); + } else { + ESP_LOGI(TAG, "CnfClient:AppkeyBind,Fail,%x", param->status_cb.model_app_status.status); + } + break; + case ESP_BLE_MESH_MODEL_OP_FRIEND_SET: + ESP_LOGI(TAG, "CfgClient:friend: 0x%x", param->status_cb.friend_status.friend_state); + break; + case ESP_BLE_MESH_MODEL_OP_HEARTBEAT_PUB_SET: + if (param->status_cb.heartbeat_pub_status.status == ESP_OK) { + ESP_LOGI(TAG, "CfgClient:HeartBeatPubSet,OK,destination:0x%x,countlog:0x%x, periodlog:0x%x,ttl:0x%x,features:0x%x,net_idx: 0x%x", + param->status_cb.heartbeat_pub_status.dst, param->status_cb.heartbeat_pub_status.count, param->status_cb.heartbeat_pub_status.period, + param->status_cb.heartbeat_pub_status.ttl, param->status_cb.heartbeat_pub_status.features, param->status_cb.heartbeat_pub_status.net_idx); + } else { + ESP_LOGI(TAG, "CfgClient:HeartBeatSet,Fail,%d", param->status_cb.heartbeat_pub_status.status); + } + break; + case ESP_BLE_MESH_MODEL_OP_HEARTBEAT_SUB_SET: + if (param->status_cb.heartbeat_sub_status.status == ESP_OK) { + ESP_LOGI(TAG, "CfgClient:HeartBeatSubSet,OK,source:0x%x,destination:0x%x, periodlog:0x%x,countlog:0x%x,minhops:0x%x,maxhops:0x%x", + param->status_cb.heartbeat_sub_status.src, param->status_cb.heartbeat_sub_status.dst, param->status_cb.heartbeat_sub_status.period, + param->status_cb.heartbeat_sub_status.count, param->status_cb.heartbeat_sub_status.min_hops, param->status_cb.heartbeat_sub_status.max_hops); + } else { + ESP_LOGI(TAG, "CfgClient:HeartBeatSubSet,Fail,%d", param->status_cb.heartbeat_sub_status.status); + } + break; + default: + ESP_LOGI(TAG, "Not supported config client set message opcode"); + break; + } + break; + case ESP_BLE_MESH_CFG_CLIENT_PUBLISH_EVT: + ESP_LOGI(TAG, "CnfClient:Publish,OK"); + break; + case ESP_BLE_MESH_CFG_CLIENT_EVT_MAX: + ESP_LOGI(TAG, "CnfClient:MaxEvt"); + break; + case ESP_BLE_MESH_CFG_CLIENT_TIMEOUT_EVT: + ESP_LOGI(TAG, "CfgClient:TimeOut"); + break; + default: + ESP_LOGI(TAG, "CfgClient:InvalidEvent"); + break; + } + } else { + ESP_LOGI(TAG, "CnfClient:Fail,%d", param->error_code); + } + ESP_LOGD(TAG, "exit %s \n", __func__); +} + +int ble_mesh_configuration_client_model_operation(int argc, char **argv) +{ + int err = ESP_OK; + const uint8_t *app_key = NULL; + esp_ble_mesh_cfg_default_ttl_set_t ttl_set; + esp_ble_mesh_cfg_gatt_proxy_set_t proxy_set; + esp_ble_mesh_cfg_app_key_add_t app_key_add; + esp_ble_mesh_cfg_model_pub_set_t mod_pub_set = { + .company_id = 0xFFFF, + .cred_flag = false, + .publish_period = 0, + .publish_retransmit = 0, + }; + esp_ble_mesh_cfg_model_sub_add_t mod_sub_add = { + .company_id = 0xFFFF, + }; + esp_ble_mesh_cfg_model_sub_delete_t mod_sub_del = { + .company_id = 0xFFFF, + }; + esp_ble_mesh_cfg_relay_set_t relay_set; + esp_ble_mesh_client_common_param_t client_common = { + .msg_role = ROLE_PROVISIONER, + .msg_timeout = 0, + .ctx.send_ttl = 7, + }; + esp_ble_mesh_cfg_client_get_state_t get_state = { + .comp_data_get.page = 0, + .model_pub_get.company_id = 0xFFFF, + }; + esp_ble_mesh_cfg_model_app_bind_t mod_app_bind = { + .company_id = 0xFFFF, + }; + + client_common.model = ble_mesh_get_model(ESP_BLE_MESH_MODEL_ID_CONFIG_CLI); + + ESP_LOGD(TAG, "enter %s \n", __func__); + + int nerrors = arg_parse(argc, argv, (void **) &configuration_client_model_operation); + if (nerrors != 0) { + arg_print_errors(stderr, configuration_client_model_operation.end, argv[0]); + return 1; + } + + if (configuration_client_model_operation.opcode->count != 0) { + client_common.opcode = configuration_client_model_operation.opcode->ival[0]; + } + + if (configuration_client_model_operation.net_idx->count != 0) { + client_common.ctx.net_idx = configuration_client_model_operation.net_idx->ival[0]; + app_key_add.net_idx = configuration_client_model_operation.net_idx->ival[0]; + } + + if (configuration_client_model_operation.unicast_address->count != 0) { + client_common.ctx.addr = configuration_client_model_operation.unicast_address->ival[0]; + get_state.model_pub_get.element_addr = configuration_client_model_operation.unicast_address->ival[0]; + mod_app_bind.element_addr = configuration_client_model_operation.unicast_address->ival[0]; + mod_sub_add.element_addr = configuration_client_model_operation.unicast_address->ival[0]; + mod_sub_del.element_addr = configuration_client_model_operation.unicast_address->ival[0]; + mod_pub_set.element_addr = configuration_client_model_operation.unicast_address->ival[0]; + } + + if (configuration_client_model_operation.appkey_index->count != 0) { + client_common.ctx.app_idx = configuration_client_model_operation.appkey_index->ival[0]; + mod_app_bind.model_app_idx = configuration_client_model_operation.appkey_index->ival[0]; + app_key_add.app_idx = configuration_client_model_operation.appkey_index->ival[0]; + mod_pub_set.publish_app_idx = configuration_client_model_operation.appkey_index->ival[0]; + } + + if (configuration_client_model_operation.value->count != 0) { + ttl_set.ttl = configuration_client_model_operation.value->ival[0]; + proxy_set.gatt_proxy = configuration_client_model_operation.value->ival[0]; + mod_pub_set.publish_ttl = configuration_client_model_operation.value->ival[0]; + } + + if (configuration_client_model_operation.addr->count != 0) { + mod_sub_del.sub_addr = configuration_client_model_operation.addr->ival[0]; + mod_sub_add.sub_addr = configuration_client_model_operation.addr->ival[0]; + mod_pub_set.publish_addr = configuration_client_model_operation.addr->ival[0]; + } + + if (configuration_client_model_operation.mod_id->count != 0) { + mod_app_bind.model_id = configuration_client_model_operation.mod_id->ival[0]; + mod_sub_add.model_id = configuration_client_model_operation.mod_id->ival[0]; + mod_sub_del.model_id = configuration_client_model_operation.mod_id->ival[0]; + get_state.model_pub_get.model_id = configuration_client_model_operation.mod_id->ival[0];; + mod_pub_set.model_id = configuration_client_model_operation.mod_id->ival[0]; + } + + if (configuration_client_model_operation.relay_statue->count != 0) { + relay_set.relay = configuration_client_model_operation.relay_statue->ival[0]; + mod_pub_set.publish_period = configuration_client_model_operation.relay_statue->ival[0]; + } + + if (configuration_client_model_operation.relay_transmit->count != 0) { + relay_set.relay_retransmit = configuration_client_model_operation.relay_transmit->ival[0]; + mod_pub_set.publish_retransmit = configuration_client_model_operation.relay_transmit->ival[0]; + } + + if (configuration_client_model_operation.cid->count != 0) { + mod_app_bind.company_id = configuration_client_model_operation.cid->ival[0]; + mod_sub_del.company_id = configuration_client_model_operation.cid->ival[0]; + mod_sub_add.company_id = configuration_client_model_operation.cid->ival[0]; + mod_pub_set.company_id = configuration_client_model_operation.cid->ival[0]; + } + + if (configuration_client_model_operation.action_type->count != 0) { + if (strcmp(configuration_client_model_operation.action_type->sval[0], "get") == 0) { + err = esp_ble_mesh_config_client_get_state(&client_common, &get_state); + } else if (strcmp(configuration_client_model_operation.action_type->sval[0], "set") == 0) { + if (configuration_client_model_operation.set_state->count != 0) { + if (strcmp(configuration_client_model_operation.set_state->sval[0], "appkey") == 0) { + app_key = esp_ble_mesh_provisioner_get_local_app_key(app_key_add.net_idx, app_key_add.app_idx); + if (app_key == NULL) { + ESP_LOGE(TAG, "CnfClient:AddAppkey,Fail,app key or network key NULL"); + return ESP_FAIL; + } else { + memcpy(app_key_add.app_key, app_key, 16); + } + err = esp_ble_mesh_config_client_set_state(&client_common, (esp_ble_mesh_cfg_client_set_state_t *)&app_key_add); + } else if (strcmp(configuration_client_model_operation.set_state->sval[0], "appbind") == 0) { + err = esp_ble_mesh_config_client_set_state(&client_common, (esp_ble_mesh_cfg_client_set_state_t *)&mod_app_bind); + } else if (strcmp(configuration_client_model_operation.set_state->sval[0], "ttl") == 0) { + err = esp_ble_mesh_config_client_set_state(&client_common, (esp_ble_mesh_cfg_client_set_state_t *)&ttl_set); + } else if (strcmp(configuration_client_model_operation.set_state->sval[0], "proxy") == 0) { + err = esp_ble_mesh_config_client_set_state(&client_common, (esp_ble_mesh_cfg_client_set_state_t *)&proxy_set); + } else if (strcmp(configuration_client_model_operation.set_state->sval[0], "subadd") == 0) { + err = esp_ble_mesh_config_client_set_state(&client_common, (esp_ble_mesh_cfg_client_set_state_t *)&mod_sub_add); + } else if (strcmp(configuration_client_model_operation.set_state->sval[0], "subdel") == 0) { + err = esp_ble_mesh_config_client_set_state(&client_common, (esp_ble_mesh_cfg_client_set_state_t *)&mod_sub_del); + } else if (strcmp(configuration_client_model_operation.set_state->sval[0], "relay") == 0) { + err = esp_ble_mesh_config_client_set_state(&client_common, (esp_ble_mesh_cfg_client_set_state_t *)&relay_set); + } else if (strcmp(configuration_client_model_operation.set_state->sval[0], "pubset") == 0) { + err = esp_ble_mesh_config_client_set_state(&client_common, (esp_ble_mesh_cfg_client_set_state_t *)&mod_pub_set); + } + } + } else if (strcmp(configuration_client_model_operation.action_type->sval[0], "reg") == 0) { + err = esp_ble_mesh_register_config_client_callback(ble_mesh_configuration_client_model_cb); + } + } + + if (err == ESP_OK) { + ESP_LOGI(TAG, "ConfigClient:OK"); + } else { + ESP_LOGI(TAG, "ConfigClient:Fail"); + } + + ESP_LOGD(TAG, "exit %s %d\n", __func__, err); + return err; +} + + +void ble_mesh_register_configuration_client_model_command() +{ + configuration_client_model_operation.action_type = arg_str1("z", NULL, "", "action type"); + configuration_client_model_operation.set_state = arg_str0("x", NULL, "", "set state"); + configuration_client_model_operation.opcode = arg_int0("o", NULL, "", "message opcode"); + configuration_client_model_operation.unicast_address = arg_int0("u", NULL, "
", "unicast address"); + configuration_client_model_operation.net_idx = arg_int0("n", NULL, "", "net work index"); + configuration_client_model_operation.appkey_index = arg_int0("i", NULL, "", "appkey index"); + configuration_client_model_operation.relay_statue = arg_int0("r", NULL, "", "relay statue"); + configuration_client_model_operation.relay_transmit = arg_int0("t", NULL, "", "relay transmit"); + configuration_client_model_operation.cid = arg_int0("c", NULL, "", "company id"); + configuration_client_model_operation.value = arg_int0("v", NULL, "", "value"); + configuration_client_model_operation.addr = arg_int0("a", NULL, "
", "address"); + configuration_client_model_operation.mod_id = arg_int0("m", NULL, "", "model id"); + configuration_client_model_operation.end = arg_end(1); + + const esp_console_cmd_t client_stconfiguration_client_model_operationate_cmd = { + .command = "bmccm", + .help = "ble mesh configuration client model", + .hint = NULL, + .func = &ble_mesh_configuration_client_model_operation, + .argtable = &configuration_client_model_operation, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&client_stconfiguration_client_model_operationate_cmd)); +} +#endif diff --git a/examples/bluetooth/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..6f34a1b271 --- /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 ble_mesh_generic_onoff_client_model_cb(esp_ble_mesh_generic_client_cb_event_t event, + esp_ble_mesh_generic_client_cb_param_t *param); + +void ble_mesh_register_gen_onoff_client() +{ + ble_mesh_register_gen_onoff_client_command(); +} + +void ble_mesh_generic_onoff_client_model_cb(esp_ble_mesh_generic_client_cb_event_t event, + esp_ble_mesh_generic_client_cb_param_t *param) +{ + uint32_t opcode = param->params->opcode; + + ESP_LOGD(TAG, "enter %s: event is %d, error code is %d, opcode is 0x%x\n", + __func__, event, param->error_code, opcode); + + switch (event) { + case ESP_BLE_MESH_GENERIC_CLIENT_GET_STATE_EVT: { + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET: + if (param->error_code == ESP_OK) { + ESP_LOGI(TAG, "GenOnOffClient:GetStatus,OK,%d", param->status_cb.onoff_status.present_onoff); + } else { + ESP_LOGE(TAG, "GenOnOffClient:GetStatus,Fail,%d", param->error_code); + } + break; + default: + break; + } + break; + } + case ESP_BLE_MESH_GENERIC_CLIENT_SET_STATE_EVT: { + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET: + if (param->error_code == ESP_OK) { + ESP_LOGI(TAG, "GenOnOffClient:SetStatus,OK,%d", param->status_cb.onoff_status.present_onoff); + } else { + ESP_LOGE(TAG, "GenOnOffClient:SetStatus,Fail,%d", param->error_code); + } + break; + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK: + if (param->error_code == ESP_OK) { + ESP_LOGI(TAG, "GenOnOffClient:SetUNACK,OK"); + } else { + ESP_LOGE(TAG, "GenOnOffClient:SetUNACK,Fail,%d", param->error_code); + } + break; + default: + break; + } + break; + } + case ESP_BLE_MESH_GENERIC_CLIENT_PUBLISH_EVT: { + if (param->error_code == ESP_OK) { + ESP_LOGI(TAG, "GenOnOffClient:Publish,OK"); + } else { + ESP_LOGE(TAG, "GenOnOffClient:Publish,Fail,%d", param->error_code); + } + break; + } + case ESP_BLE_MESH_GENERIC_CLIENT_TIMEOUT_EVT: + ESP_LOGE(TAG, "GenOnOffClient:TimeOut,%d", param->error_code); + break; + case ESP_BLE_MESH_GENERIC_CLIENT_EVT_MAX: + ESP_LOGE(TAG, "GenONOFFClient:InvalidEvt,%d", param->error_code); + break; + default: + break; + } + ESP_LOGD(TAG, "exit %s \n", __func__); +} + +int ble_mesh_generic_onoff_client_model(int argc, char **argv) +{ + int err = ESP_OK; + esp_ble_mesh_generic_client_set_state_t gen_client_set; + esp_ble_mesh_generic_client_get_state_t gen_client_get; + esp_ble_mesh_client_common_param_t onoff_common = { + .msg_timeout = 0, + .ctx.send_ttl = 7, + }; + + ESP_LOGD(TAG, "enter %s\n", __func__); + + int nerrors = arg_parse(argc, argv, (void **) &gen_onoff_state); + if (nerrors != 0) { + arg_print_errors(stderr, gen_onoff_state.end, argv[0]); + return 1; + } + + onoff_common.model = ble_mesh_get_model(ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_CLI); + + arg_int_to_value(gen_onoff_state.appkey_idx, onoff_common.ctx.app_idx, "appkey_index"); + arg_int_to_value(gen_onoff_state.opcode, onoff_common.opcode, "opcode"); + arg_int_to_value(gen_onoff_state.role, onoff_common.msg_role, "role"); + arg_int_to_value(gen_onoff_state.unicast_address, onoff_common.ctx.addr, "address"); + arg_int_to_value(gen_onoff_state.net_idx, onoff_common.ctx.net_idx, "network key index"); + arg_int_to_value(gen_onoff_state.op_en, gen_client_set.onoff_set.op_en, "op_en"); + arg_int_to_value(gen_onoff_state.onoff_state, gen_client_set.onoff_set.onoff, "onoff"); + arg_int_to_value(gen_onoff_state.trans_id, gen_client_set.onoff_set.tid, "tid"); + arg_int_to_value(gen_onoff_state.trans_time, gen_client_set.onoff_set.trans_time, "trans_time"); + arg_int_to_value(gen_onoff_state.delay, gen_client_set.onoff_set.delay, "delay"); + + if (gen_onoff_state.action_type->count != 0) { + if (strcmp(gen_onoff_state.action_type->sval[0], "get") == 0) { + err = esp_ble_mesh_generic_client_get_state(&onoff_common, &gen_client_get); + } else if (strcmp(gen_onoff_state.action_type->sval[0], "set") == 0) { + err = esp_ble_mesh_generic_client_set_state(&onoff_common, &gen_client_set); + } else if (strcmp(gen_onoff_state.action_type->sval[0], "reg") == 0) { + err = esp_ble_mesh_register_generic_client_callback(ble_mesh_generic_onoff_client_model_cb); + if (err == ESP_OK) { + ESP_LOGI(TAG, "GenONOFFClient:Reg,OK"); + } + } + } + ESP_LOGD(TAG, "exit %s\n", __func__); + return err; +} + +void ble_mesh_register_gen_onoff_client_command() +{ + gen_onoff_state.action_type = arg_str1("z", NULL, "", "action type"); + gen_onoff_state.opcode = arg_int0("o", NULL, "", "message opcode"); + gen_onoff_state.appkey_idx = arg_int0("a", NULL, "", "appkey index"); + gen_onoff_state.role = arg_int0("r", NULL, "", "role"); + gen_onoff_state.unicast_address = arg_int0("u", NULL, "
", "unicast address"); + gen_onoff_state.net_idx = arg_int0("n", NULL, "", "network key index"); + gen_onoff_state.op_en = arg_int0("e", NULL, "", "whether optional parameters included"); + gen_onoff_state.onoff_state = arg_int0("s", NULL, "", "present onoff state"); + gen_onoff_state.trans_id = arg_int0("i", NULL, "", "transaction identifier"); + gen_onoff_state.trans_time = arg_int0("t", NULL, "