Merge branch 'master' into feature/github-7365-second

This commit is contained in:
Zim Kalinowski 2021-10-03 18:40:13 +08:00
commit ea7122e3fb
2115 changed files with 520080 additions and 81032 deletions

View File

@ -164,3 +164,7 @@ exclude =
components/wifi_provisioning/python/wifi_constants_pb2.py,
components/esp_local_ctrl/python/esp_local_ctrl_pb2.py,
examples/provisioning/legacy/custom_config/components/custom_provisioning/python/custom_config_pb2.py,
per-file-ignores =
# Sphinx conf.py files use star imports to setup config variables
docs/conf_common.py: F405

View File

@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [2.7, 3.5, 3.6, 3.7, 3.8]
python-version: [3.6, 3.7, 3.8]
steps:
- name: Checkout

3
.gitignore vendored
View File

@ -88,3 +88,6 @@ build
# lock files for examples and components
dependencies.lock
# managed_components for examples
managed_components

View File

@ -48,10 +48,11 @@ variables:
# Docker images
BOT_DOCKER_IMAGE_TAG: ":latest"
ESP_IDF_DOC_ENV_IMAGE: "$CI_DOCKER_REGISTRY/esp-idf-doc-env:v4.4-1-v2"
ESP_IDF_DOC_ENV_IMAGE: "$CI_DOCKER_REGISTRY/esp-idf-doc-env:v4.4-1-v4"
ESP_ENV_IMAGE: "$CI_DOCKER_REGISTRY/esp-env:v4.4-1"
AFL_FUZZER_TEST_IMAGE: "$CI_DOCKER_REGISTRY/afl-fuzzer-test:v4.4-1-1"
CLANG_STATIC_ANALYSIS_IMAGE: "${CI_DOCKER_REGISTRY}/clang-static-analysis:v4.4-1-1"
CLANG_STATIC_ANALYSIS_IMAGE: "${CI_DOCKER_REGISTRY}/clang-static-analysis:v4.4-1-2"
SONARQUBE_SCANNER_IMAGE: "${CI_DOCKER_REGISTRY}/sonarqube-scanner:3"
# target test config file, used by assign test job
CI_TARGET_TEST_CONFIG_FILE: "$CI_PROJECT_DIR/.gitlab/ci/target-test.yml"

View File

@ -57,6 +57,7 @@
/export.* @esp-idf-codeowners/tools
/install.* @esp-idf-codeowners/tools
/sdkconfig.rename @esp-idf-codeowners/build-config
/sonar-project.properties @esp-idf-codeowners/ci
# sort-order-reset
@ -66,6 +67,7 @@
/components/bootloader*/ @esp-idf-codeowners/system @esp-idf-codeowners/security
/components/bt/ @esp-idf-codeowners/bluetooth
/components/cbor/ @esp-idf-codeowners/app-utilities
/components/cmock/ @esp-idf-codeowners/system
/components/coap/ @esp-idf-codeowners/app-utilities
/components/console/ @esp-idf-codeowners/system @esp-idf-codeowners/app-utilities
/components/cxx/ @esp-idf-codeowners/system
@ -159,6 +161,7 @@
/examples/ethernet/ @esp-idf-codeowners/network
/examples/get-started/ @esp-idf-codeowners/system
/examples/mesh/ @esp-idf-codeowners/wifi
/examples/network/ @esp-idf-codeowners/network @esp-idf-codeowners/wifi
/examples/openthread/ @esp-idf-codeowners/ieee802154
/examples/peripherals/ @esp-idf-codeowners/peripherals
/examples/protocols/ @esp-idf-codeowners/network @esp-idf-codeowners/app-utilities
@ -183,6 +186,7 @@
/tools/kconfig*/ @esp-idf-codeowners/build-config
/tools/ldgen/ @esp-idf-codeowners/build-config
/tools/mass_mfg/ @esp-idf-codeowners/app-utilities
/tools/mocks/ @esp-idf-codeowners/system
## Note: owners here should be the same as the owners for the same example subdir, above
/tools/test_apps/build_system/ @esp-idf-codeowners/build-config

View File

@ -221,6 +221,14 @@ build_examples_cmake_esp32s2:
variables:
IDF_TARGET: esp32s2
build_examples_cmake_esp32s3:
extends:
- .build_examples_cmake_template
- .rules:build:example_test-esp32s3
parallel: 8
variables:
IDF_TARGET: esp32s3
build_examples_cmake_esp32c3:
extends:
- .build_examples_cmake_template
@ -344,6 +352,7 @@ build_docker:
- .before_script_minimal
- .rules:build:docker
stage: host_test
needs: []
image: espressif/docker-builder:1
tags:
- build_docker_amd64_brno
@ -366,6 +375,7 @@ build_docker:
- .before_script_minimal
- .rules:build:windows
stage: host_test
needs: []
image: $CI_DOCKER_REGISTRY/esp32-toolchain-win-cross
tags:
- build

View File

@ -39,7 +39,6 @@
check_readme_links:
extends:
- .pre_check_job_template
- .doc-rules:build:docs
tags: ["build", "amd64", "internet"]
allow_failure: true
script:
@ -62,12 +61,12 @@ check_docs_lang_sync:
dependencies: []
script:
- cd docs
- python -m pip install -r requirements.txt
- python ./build_docs.py -bs $DOC_BUILDERS -l $DOCLANG -t $DOCTGT build
- pip install -r requirements.txt
- build-docs -t $DOCTGT -bs $DOC_BUILDERS -l $DOCLANG build
parallel:
matrix:
- DOCLANG: ["en", "zh_CN"]
DOCTGT: ["esp32", "esp32s2", "esp32c3"]
DOCTGT: ["esp32", "esp32s2", "esp32s3", "esp32c3"]
check_docs_gh_links:
image: $ESP_IDF_DOC_ENV_IMAGE
@ -78,8 +77,8 @@ check_docs_gh_links:
- .doc-rules:build:docs
script:
- cd docs
- python -m pip install -r requirements.txt
- python ./build_docs.py gh-linkcheck
- pip install -r requirements.txt
- build-docs gh-linkcheck
# stage: build_doc
# Add this stage to let the build_docs job run in parallel with build
@ -129,13 +128,6 @@ build_docs_html_fast:
variables:
DOC_BUILDERS: "html"
DOCS_FAST_BUILD: "yes"
# matrix is redefined to include esp32s3 here
# that we can build for S3 MRs during bringup phase without
# anything being built and published from master branch
parallel:
matrix:
- DOCLANG: ["en", "zh_CN"]
DOCTGT: ["esp32", "esp32s2", "esp32s3", "esp32c3"]
build_docs_pdf:
extends:
@ -168,7 +160,8 @@ build_docs_pdf:
script:
- add_doc_server_ssh_keys $DOCS_DEPLOY_PRIVATEKEY $DOCS_DEPLOY_SERVER $DOCS_DEPLOY_SERVER_USER
- export GIT_VER=$(git describe --always)
- python ${IDF_PATH}/tools/ci/deploy_docs.py
- pip install -r docs/requirements.txt
- deploy-docs
# stage: test_deploy
deploy_docs_preview:
@ -227,6 +220,6 @@ check_doc_links:
allow_failure: true
script:
- cd docs
- python -m pip install -r requirements.txt
- pip install -r requirements.txt
# At the moment this check will always fail due to multiple known limitations, ignore result
- python ./build_docs.py -l $DOCLANG -t $DOCTGT linkcheck || { echo "THERE ARE ISSUES DUE TO KNOWN LIMITATIONS, PLEASE FIX THEM. Nowadays we're ignored them to pass pipeline."; true; }
- build-docs -t $DOCTGT -l $DOCLANG linkcheck || { echo "THERE ARE ISSUES DUE TO KNOWN LIMITATIONS, PLEASE FIX THEM. Nowadays we're ignored them to pass pipeline."; true; }

View File

@ -220,11 +220,6 @@ test_efuse_table_on_host_esp32s2:
variables:
IDF_TARGET: esp32s2
test_efuse_table_on_host_esp32s2:
extends: .test_efuse_table_on_host_template
variables:
IDF_TARGET: esp32s2
test_efuse_table_on_host_esp32s3:
extends: .test_efuse_table_on_host_template
variables:
@ -250,10 +245,11 @@ test_espcoredump:
expire_in: 1 week
variables:
IDF_COREDUMP_ELF_REPO: "https://gitlab-ci-token:${BOT_TOKEN}@${CI_SERVER_HOST}:${CI_SERVER_PORT}/idf/idf-coredump-elf.git"
IDF_COREDUMP_ELF_TAG: idf-20210910-00
# install CMake version specified in tools.json
SETUP_TOOLS_LIST: "all"
script:
- retry_failed git clone ${IDF_COREDUMP_ELF_REPO} -b master
- retry_failed git clone ${IDF_COREDUMP_ELF_REPO} -b $IDF_COREDUMP_ELF_TAG
- cd ${IDF_PATH}/components/espcoredump/test/
- ./test_espcoredump.sh ${CI_PROJECT_DIR}/idf-coredump-elf
@ -295,22 +291,6 @@ test_mkuf2:
- cd ${IDF_PATH}/tools/test_mkuf2
- ./test_mkuf2.py
test_docs:
extends: .host_test_template
image: $ESP_IDF_DOC_ENV_IMAGE
variables:
PYTHON_VER: 3.6.13
artifacts:
when: on_failure
paths:
- docs/test/_build/*/*/*/html/*
expire_in: 1 week
script:
- cd ${IDF_PATH}/docs/test
- python -m pip install -r ${IDF_PATH}/docs/requirements.txt
- ./test_docs.py
- ./test_sphinx_idf_extensions.py
test_autocomplete:
extends: .host_test_template
image: $CI_DOCKER_REGISTRY/linux-shells:1
@ -340,7 +320,7 @@ test_nvs_page:
script:
- cd ${IDF_PATH}/components/nvs_flash/host_test/nvs_page_test
- idf.py build
- build/host_nvs_page_test.elf
- build/test_nvs_page_host.elf
test_log:
extends: .host_test_template
@ -349,9 +329,44 @@ test_log:
- idf.py build
- build/test_log_host.elf
test_esp_event:
extends: .host_test_template
script:
- cd ${IDF_PATH}/components/esp_event/host_test/esp_event_unit_test
- idf.py build
- build/test_esp_event_host.elf
test_esp_timer_cxx:
extends: .host_test_template
script:
- cd ${IDF_PATH}/examples/cxx/experimental/experimental_cpp_component/host_test/esp_timer
- idf.py build
- build/test_esp_timer_cxx_host.elf
test_eh_frame_parser:
extends: .host_test_template
script:
- cd ${IDF_PATH}/components/esp_system/test_eh_frame_parser
- make
- ./eh_frame_test
test_rom_on_linux_works:
extends: .host_test_template
script:
- cd ${IDF_PATH}/components/esp_rom/host_test/rom_test
- idf.py build
- build/test_rom_host.elf
test_cxx_gpio:
extends: .host_test_template
script:
- cd ${IDF_PATH}/examples/cxx/experimental/experimental_cpp_component/host_test/gpio
- idf.py build
- build/test_gpio_cxx_host.elf
test_linux_example:
extends: .host_test_template
script:
- cd ${IDF_PATH}/examples/build_system/cmake/linux_host_app
- idf.py build
- build/linux_host_app.elf

View File

@ -113,6 +113,15 @@ check_public_headers:
script:
- python tools/ci/check_public_headers.py --jobs 4 --prefix xtensa-esp32-elf-
check_soc_struct_headers:
extends:
- .pre_check_base_template
- .rules:build
tags:
- build
script:
- find ${IDF_PATH}/components/soc/*/include/soc/ -name "*_struct.h" -print0 | xargs -0 -n1 ./tools/ci/check_soc_struct_headers.py
check_esp_err_to_name:
extends:
- .pre_check_base_template

View File

@ -3,7 +3,10 @@
############
.patterns-c-files: &patterns-c-files
- ".gitlab/ci/static-code-analysis.yml"
- "tools/ci/static-analysis-rules.yml"
- "tools/ci/clang_tidy_dirs.txt"
- "**/*.{c,C}"
- "**/*.{h,H}"
- "components/**/Kconfig"
@ -37,6 +40,7 @@
.patterns-build_components: &patterns-build_components
- "components/**/*"
- "examples/cxx/experimental/experimental_cpp_component/*"
.patterns-build_system: &patterns-build_system
- "tools/cmake/**/*"

View File

@ -5,17 +5,46 @@ clang_tidy_check:
- .rules:patterns:clang_tidy
image: ${CLANG_STATIC_ANALYSIS_IMAGE}
artifacts:
reports:
junit: $IDF_PATH/output.xml
paths:
- $OUTPUT_DIR
when: always
expire_in: 1 day
variables:
CLANG_TIDY_RUNNER_PROJ: 2107 # idf/clang-tidy-runner
CLANG_TIDY_DIRS_TXT: ${CI_PROJECT_DIR}/tools/ci/clang_tidy_dirs.txt
RULES_FILE: ${CI_PROJECT_DIR}/tools/ci/static-analysis-rules.yml
OUTPUT_DIR: ${CI_PROJECT_DIR}/clang_tidy_reports
script:
- python -m pip install -U pip
- internal_pip_install $CLANG_TIDY_RUNNER_PROJ pyclang
- export PATH=$PATH:$(python -c "import sys; print(sys.executable.rsplit('/', 1)[0])")
- dirs=$(cat ${CLANG_TIDY_DIRS_TXT} | while read line; do echo ${CI_PROJECT_DIR}/${line}; done | xargs)
- run_cmd idf_clang ${dirs}
--output-path ${OUTPUT_DIR}
--limit-file ${RULES_FILE}
--xtensa-include-dir
--run-clang-tidy-py ${RUN_CLANG_TIDY_PY}
check_pylint:
extends:
- .pre_check_base_template
- .rules:patterns:python-files
- .before_script_minimal
image: $SONARQUBE_SCANNER_IMAGE
artifacts:
when: always
paths:
- $IDF_PATH/examples/get-started/hello_world/tidybuild/report/*
expire_in: 1 day
- pylint-report.txt
expire_in: 1 week
script:
- retry_failed git clone $IDF_ANALYSIS_UTILS static_analysis_utils && cd static_analysis_utils
# Setup parameters of triggered/regular job
- export TARGET_BRANCH=${BOT_CUSTOMIZED_REVISION-}
- ./analyze.sh $IDF_PATH/examples/get-started/hello_world/ $IDF_PATH/tools/ci/static-analysis-rules.yml $IDF_PATH/output.xml
- export PYTHONPATH="$IDF_PATH/tools:$IDF_PATH/tools/ci/python_packages:$PYTHONPATH"
- |
if [ -n "$CI_MERGE_REQUEST_IID" ]; then
export files=$(python ${CI_PROJECT_DIR}/tools/ci/ci_get_mr_info.py files ${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME} | grep ".py");
else
export files=$(find . -iname "*.py" -print);
fi
- pylint --rcfile=.pylintrc $files -r n --output-format=parseable > pylint-report.txt || exit 0
# build stage
# Sonarqube related jobs put here for this reason:
@ -33,26 +62,31 @@ clang_tidy_check:
.sonar_scan_template:
stage: build
image:
name: $CI_DOCKER_REGISTRY/sonarqube-scanner:2
name: $SONARQUBE_SCANNER_IMAGE
before_script:
- source tools/ci/utils.sh
- export PYTHONPATH="$CI_PROJECT_DIR/tools:$CI_PROJECT_DIR/tools/ci/python_packages:$PYTHONPATH"
- fetch_submodules
# Exclude the submodules, all paths ends with /**
- export SUBMODULES=$(get_all_submodules)
- submodules=$(get_all_submodules)
# get all exclude paths specified in tools/ci/sonar_exclude_list.txt | ignore lines start with # | xargs | replace all <space> to <comma>
- export CUSTOM_EXCLUDES=$(cat $CI_PROJECT_DIR/tools/ci/sonar_exclude_list.txt | grep -v '^#' | xargs | sed -e 's/ /,/g')
- custom_excludes=$(cat $CI_PROJECT_DIR/tools/ci/sonar_exclude_list.txt | grep -v '^#' | xargs | sed -e 's/ /,/g')
# Exclude the report dir as well
- export EXCLUSIONS="$CUSTOM_EXCLUDES,$SUBMODULES,$REPORT_DIR/**,docs/_static/**,**/*.png,**/*.jpg"
- python $NORMALIZE_CLANGTIDY_PY $CI_PROJECT_DIR/$REPORT_DIR/warnings.txt $CI_PROJECT_DIR/$REPORT_DIR/clang_tidy_report.txt $CI_PROJECT_DIR
- export EXCLUSIONS="$custom_excludes,$submodules"
- export SONAR_SCANNER_OPTS="-Xmx2048m"
variables:
GIT_DEPTH: 0
NORMALIZE_CLANGTIDY_PY: $CI_PROJECT_DIR/tools/ci/normalize_clangtidy_path.py
REPORT_DIR: examples/get-started/hello_world/tidybuild/report
REPORT_PATTERN: clang_tidy_reports/*.txt
artifacts:
when: always
paths:
- $REPORT_PATTERN
tags:
- host_test
dependencies: # Here is not a hard dependency relationship, could be skipped when only python files changed. so we do not use "needs" here.
- clang_tidy_check
- check_pylint
code_quality_check:
extends:
@ -67,23 +101,16 @@ code_quality_check:
- test -n "$CI_MERGE_REQUEST_COMMITS" || exit 0
- sonar-scanner
-Dsonar.analysis.mode=preview
-Dsonar.branch.name=$CI_COMMIT_REF_NAME
-Dsonar.cxx.clangtidy.reportPath=$REPORT_DIR/clang_tidy_report.txt
-Dsonar.cxx.includeDirectories=components,/usr/include
-Dsonar.branch.name=$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
-Dsonar.cxx.clangtidy.reportPath=$REPORT_PATTERN
-Dsonar.exclusions=$EXCLUSIONS
-Dsonar.gitlab.ci_merge_request_iid=$CI_MERGE_REQUEST_IID
-Dsonar.gitlab.commit_sha=$CI_MERGE_REQUEST_COMMITS
-Dsonar.gitlab.failure_notification_mode=exit-code
-Dsonar.gitlab.merge_request_discussion=true
-Dsonar.gitlab.project_id=$CI_PROJECT_ID
-Dsonar.gitlab.ref_name=$CI_COMMIT_REF_NAME
-Dsonar.gitlab.ref_name=$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
-Dsonar.host.url=$SONAR_HOST_URL
-Dsonar.login=$SONAR_LOGIN
-Dsonar.projectBaseDir=$CI_PROJECT_DIR
-Dsonar.projectKey=esp-idf
-Dsonar.python.pylint_config=.pylintrc
-Dsonar.sourceEncoding=UTF-8
-Dsonar.sources=$CI_PROJECT_DIR
-Dsonar.python.pylint.reportPath=pylint-report.txt
code_quality_report:
extends:
@ -94,41 +121,10 @@ code_quality_report:
script:
- sonar-scanner
-Dsonar.branch.name=$CI_COMMIT_REF_NAME
-Dsonar.cxx.clangtidy.reportPath=$REPORT_DIR/clang_tidy_report.txt
-Dsonar.cxx.includeDirectories=components,/usr/include
-Dsonar.cxx.clangtidy.reportPath=$REPORT_PATTERN
-Dsonar.exclusions=$EXCLUSIONS
-Dsonar.gitlab.commit_sha=$CI_COMMIT_SHA
-Dsonar.gitlab.failure_notification_mode=exit-code
-Dsonar.gitlab.project_id=$CI_PROJECT_ID
-Dsonar.gitlab.ref_name=$CI_COMMIT_REF_NAME
-Dsonar.host.url=$SONAR_HOST_URL
-Dsonar.login=$SONAR_LOGIN
-Dsonar.projectBaseDir=$CI_PROJECT_DIR
-Dsonar.projectKey=esp-idf
-Dsonar.python.pylint_config=.pylintrc
-Dsonar.sourceEncoding=UTF-8
-Dsonar.sources=$CI_PROJECT_DIR
# deploy stage
clang_tidy_deploy:
extends:
- .deploy_job_template
- .rules:patterns:clang_tidy
needs:
- clang_tidy_check
tags:
- deploy
- shiny
script:
- add_doc_server_ssh_keys $DOCS_DEPLOY_KEY $DOCS_SERVER $DOCS_SERVER_USER
- export GIT_VER=$(git describe --always)
- cd $IDF_PATH/examples/get-started/hello_world/tidybuild
- mv report $GIT_VER
- tar czvf $GIT_VER.tar.gz $GIT_VER
- export STATIC_REPORT_PATH="web/static_analysis/esp-idf/"
- ssh $DOCS_SERVER -x "mkdir -p $STATIC_REPORT_PATH/clang-tidy"
- scp $GIT_VER.tar.gz $DOCS_SERVER:$STATIC_REPORT_PATH/clang-tidy
- ssh $DOCS_SERVER -x "cd $STATIC_REPORT_PATH/clang-tidy && tar xzvf $GIT_VER.tar.gz && rm -f latest && ln -s $GIT_VER latest"
# add link to view the report
- echo "[static analysis][clang tidy] $CI_DOCKER_REGISTRY/static_analysis/esp-idf/clang-tidy/${GIT_VER}/index.html"
- test ! -e ${GIT_VER}/FAILED_RULES || { echo 'Failed static analysis rules!'; cat ${GIT_VER}/FAILED_RULES; exit 1; }
-Dsonar.python.pylint.reportPath=pylint-report.txt

View File

@ -46,7 +46,7 @@
extends:
- .example_test_template
- .rules:test:example_test-esp32
variables:
variables:
SUBMODULES_TO_FETCH: "all"
test_weekend_mqtt:
@ -60,7 +60,7 @@ test_weekend_mqtt:
- export MQTT_PUBLISH_TEST=1
- export TEST_PATH=$CI_PROJECT_DIR/tools/test_apps/protocols/mqtt/publish_connect_test
- cd $IDF_PATH/tools/ci/python_packages/tiny_test_fw/bin
- run_cmd python Runner.py $TEST_PATH -c $TEST_PATH/publish_connect_mqtt_.yml -e $TEST_PATH/env.yml
- run_cmd python Runner.py $TEST_PATH -c $TEST_PATH/publish_connect_mqtt_.yml
.example_test_esp32_template:
extends:
@ -97,7 +97,7 @@ example_test_001B_V3:
example_test_001C:
extends: .example_test_esp32_template
parallel: 3
parallel: 4
tags:
- ESP32
- Example_GENERIC
@ -129,7 +129,7 @@ example_test_002:
- ESP32
- Example_ShieldBox_Basic
example_test_enternet:
example_test_ethernet:
extends: .example_test_esp32_template
tags:
- ESP32
@ -270,20 +270,17 @@ example_test_ESP32_SDSPI:
- ESP32
- UT_T1_SPIMODE
# uncomment when ESP32S2 & ESP32C3 runners with external SD connected over SPI are available
# ensure the runners have required tags created
#
#example_test_ESP32S2_SDSPI:
# extends: .example_test_esp32s2_template
# tags:
# - ESP32S2
# - UT_T1_SPIMODE
#
#example_test_ESP32C3_SDSPI:
# extends: .example_test_esp32c3_template
# tags:
# - ESP32C3
# - UT_T1_SPIMODE
example_test_ESP32S2_SDSPI:
extends: .example_test_esp32s2_template
tags:
- ESP32S2
- UT_T1_SPIMODE
example_test_ESP32C3_SDSPI:
extends: .example_test_esp32c3_template
tags:
- ESP32C3
- UT_T1_SPIMODE
.test_app_template:
extends: .target_test_job_template
@ -447,7 +444,7 @@ UT_001:
UT_002:
extends: .unit_test_esp32_template
parallel: 16
parallel: 14
tags:
- ESP32_IDF
- UT_T1_1
@ -482,7 +479,7 @@ UT_006:
UT_007:
extends: .unit_test_esp32_template
parallel: 2
parallel: 4
tags:
- ESP32_IDF
- UT_T1_1
@ -508,19 +505,6 @@ UT_014:
- UT_T2_RS485
- psram
UT_015:
extends: .unit_test_esp32_template
tags:
- ESP32_IDF
- UT_T1_RMT
UT_016:
extends: .unit_test_esp32_template
tags:
- ESP32_IDF
- UT_T1_RMT
- psram
UT_017:
extends: .unit_test_esp32_template
tags:
@ -544,7 +528,6 @@ UT_020:
UT_021:
extends: .unit_test_esp32_template
parallel: 2
tags:
- ESP32_IDF
- psram
@ -579,7 +562,7 @@ UT_033:
UT_034:
extends: .unit_test_esp32_template
parallel: 3
parallel: 2
tags:
- ESP32_IDF
- UT_T1_ESP_FLASH
@ -607,7 +590,7 @@ UT_036:
UT_038:
extends: .unit_test_esp32s2_template
parallel: 3
parallel: 2
tags:
- ESP32S2_IDF
- UT_T1_ESP_FLASH
@ -647,7 +630,7 @@ UT_046:
UT_047:
extends: .unit_test_esp32s2_template
parallel: 3
parallel: 5
tags:
- ESP32S2_IDF
- UT_T1_1
@ -658,9 +641,15 @@ UT_S2_SPI_DUAL:
- ESP32S2_IDF
- Example_SPI_Multi_device
UT_S2_SDSPI:
extends: .unit_test_esp32s2_template
tags:
- ESP32S2_IDF
- UT_T1_SPIMODE
UT_C3:
extends: .unit_test_esp32c3_template
parallel: 33
parallel: 32
tags:
- ESP32C3_IDF
- UT_T1_1
@ -674,7 +663,6 @@ UT_C3_FLASH:
UT_C3_SPI_DUAL:
extends: .unit_test_esp32c3_template
parallel: 2
tags:
- ESP32C3_IDF
- Example_SPI_Multi_device
@ -697,9 +685,15 @@ UT_C3_FLASH_SUSPEND:
- ESP32C3_IDF
- UT_T1_Flash_Suspend
UT_C3_SDSPI:
extends: .unit_test_esp32c3_template
tags:
- ESP32C3_IDF
- UT_T1_SPIMODE
UT_S3:
extends: .unit_test_esp32s3_template
parallel: 27
parallel: 29
tags:
- ESP32S3_IDF
- UT_T1_1
@ -717,6 +711,18 @@ UT_S3_FLASH:
- ESP32S3_IDF
- UT_T1_ESP_FLASH
component_ut_test_ip101:
extends: .component_ut_esp32_template
tags:
- ESP32
- COMPONENT_UT_IP101
component_ut_test_lan8720:
extends: .component_ut_esp32_template
tags:
- ESP32
- COMPONENT_UT_LAN8720
.integration_test_template:
extends:
- .target_test_job_template

View File

@ -3,7 +3,7 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.4.0
rev: v4.0.1
hooks:
- id: trailing-whitespace
# note: whitespace exclusions use multiline regex, see https://pre-commit.com/#regular-expressions
@ -26,12 +26,12 @@ repos:
args: ['-f=lf']
- id: double-quote-string-fixer
- repo: https://gitlab.com/pycqa/flake8
rev: 3.8.4
rev: 3.9.2
hooks:
- id: flake8
args: ['--config=.flake8', '--tee', '--benchmark']
- repo: https://github.com/pycqa/isort
rev: 5.6.4
rev: 5.9.3
hooks:
- id: isort
name: isort (python)
@ -92,11 +92,24 @@ repos:
- id: mypy-check
name: Check type annotations in python files
entry: tools/ci/check_type_comments.py
additional_dependencies: ['mypy==0.800', 'mypy-extensions==0.4.3']
additional_dependencies:
- 'mypy==0.800'
- 'mypy-extensions==0.4.3'
language: python
types: [python]
- id: check-copyright
name: Check copyright notices
entry: tools/ci/check_copyright.py --verbose --replace
additional_dependencies:
- 'comment_parser == 1.2.3'
- 'thefuzz == 0.19.0'
- 'thefuzz[speedup] == 0.19.0; sys_platform != "win32"'
# don't depend on python-Levenshtein on Windows, as it requires Microsoft C++ Build Tools to install
language: python
files: \.(py|c|h|cpp|hpp|ld)$
require_serial: true
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.4.0
rev: v4.0.1
hooks:
- id: file-contents-sorter
files: '(tools\/ci\/executable-list\.txt|tools\/ci\/mypy_ignore_list\.txt)'
files: 'tools\/ci\/(executable-list\.txt|mypy_ignore_list\.txt|check_copyright_ignore\.txt)'

View File

@ -20,7 +20,9 @@ if(NOT BOOTLOADER_BUILD)
if(CONFIG_COMPILER_OPTIMIZATION_SIZE)
list(APPEND compile_options "-Os")
list(APPEND compile_options "-freorder-blocks")
if(CMAKE_C_COMPILER_ID MATCHES "GNU")
list(APPEND compile_options "-freorder-blocks")
endif()
elseif(CONFIG_COMPILER_OPTIMIZATION_DEFAULT)
list(APPEND compile_options "-Og")
elseif(CONFIG_COMPILER_OPTIMIZATION_NONE)
@ -33,7 +35,9 @@ else() # BOOTLOADER_BUILD
if(CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE)
list(APPEND compile_options "-Os")
list(APPEND compile_options "-freorder-blocks")
if(CMAKE_C_COMPILER_ID MATCHES "GNU")
list(APPEND compile_options "-freorder-blocks")
endif()
elseif(CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG)
list(APPEND compile_options "-Og")
elseif(CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_NONE)
@ -74,6 +78,48 @@ if(CONFIG_COMPILER_DISABLE_GCC8_WARNINGS)
"-Wno-int-in-bool-context")
endif()
if(CMAKE_C_COMPILER_ID MATCHES "GNU")
list(APPEND c_compile_options "-Wno-old-style-declaration")
endif()
# Clang finds some warnings in IDF code which GCC doesn't.
# All these warnings should be fixed before Clang is presented
# as a toolchain choice for users.
if(CMAKE_C_COMPILER_ID MATCHES "Clang")
# Clang checks Doxygen comments for being in sync with function prototype.
# There are some inconsistencies, especially in ROM headers.
list(APPEND compile_options "-Wno-documentation")
# GCC allows repeated typedefs when the source and target types are the same.
# Clang doesn't allow this. This occurs in many components due to forward
# declarations.
list(APPEND compile_options "-Wno-typedef-redefinition")
# This issue is seemingly related to newlib's char type functions.
# Fix is not clear yet.
list(APPEND compile_options "-Wno-char-subscripts")
# Clang seems to notice format string issues which GCC doesn't.
list(APPEND compile_options "-Wno-format-security")
# Logic bug in essl component
list(APPEND compile_options "-Wno-tautological-overlap-compare")
# Some pointer checks in mDNS component check addresses which can't be NULL
list(APPEND compile_options "-Wno-tautological-pointer-compare")
# Similar to the above, in tcp_transport
list(APPEND compile_options "-Wno-pointer-bool-conversion")
# mbedTLS md5.c triggers this warning in md5_test_buf (false positive)
list(APPEND compile_options "-Wno-string-concatenation")
# multiple cases of implict convertions between unrelated enum types
list(APPEND compile_options "-Wno-enum-conversion")
# When IRAM_ATTR is specified both in function declaration and definition,
# it produces different section names, since section names include __COUNTER__.
# Occurs in multiple places.
list(APPEND compile_options "-Wno-section")
# Multiple cases of attributes unknown to clang, for example
# __attribute__((optimize("-O3")))
list(APPEND compile_options "-Wno-unknown-attributes")
# Clang also produces many -Wunused-function warnings which GCC doesn't.
# However these aren't treated as errors.
endif()
# More warnings may exist in unit tests and example projects.
if(CONFIG_COMPILER_WARN_WRITE_STRINGS)
list(APPEND compile_options "-Wwrite-strings")
endif()
@ -118,7 +164,15 @@ list(APPEND link_options "-fno-lto")
# Placing jump tables in flash would cause issues with code that required
# to be placed in IRAM
list(APPEND compile_options "-fno-jump-tables")
list(APPEND compile_options "-fno-tree-switch-conversion")
if(CMAKE_C_COMPILER_ID MATCHES "GNU")
# This flag is GCC-specific.
# Not clear yet if some other flag should be used for Clang.
list(APPEND compile_options "-fno-tree-switch-conversion")
endif()
if(CMAKE_C_COMPILER_ID MATCHES "LLVM")
list(APPEND compile_options "-fno-use-cxa-atexit")
endif()
idf_build_set_property(COMPILE_OPTIONS "${compile_options}" APPEND)
idf_build_set_property(C_COMPILE_OPTIONS "${c_compile_options}" APPEND)

View File

@ -56,7 +56,6 @@ Related Documents
style-guide
install-pre-commit-hook
documenting-code
add-ons-reference
creating-examples
../api-reference/template
contributor-agreement

View File

@ -11,7 +11,6 @@ mainmenu "Espressif IoT Development Framework Configuration"
config IDF_ENV_FPGA
# This option is for internal use only
bool
default "y" if IDF_TARGET="esp32h2" # ESP32H2-TODO: IDF-3378
option env="IDF_ENV_FPGA"
config IDF_TARGET_ARCH_RISCV

View File

@ -2,7 +2,24 @@
* [中文版](./README_CN.md)
ESP-IDF is the development framework for Espressif SoCs (released after 2016<sup>[1](#fn1)</sup>) provided for Windows, Linux and macOS.
ESP-IDF is the development framework for Espressif SoCs supported on Windows, Linux and macOS.
# ESP-IDF Release and SoC Compatibility
The following table shows ESP-IDF support of Espressif SoCs where ![alt text][preview] and ![alt text][supported] denote preview status and support, respectively. In preview status the build is not yet enabled and some crucial parts could be missing (like documentation, datasheet). Please use an ESP-IDF release where the desired SoC is already supported.
|Chip | v3.3 | v4.0 | v4.1 | v4.2 | v4.3 | v4.4 | |
|:----------- |:---------------------: | :---------------------:| :---------------------:| :---------------------:| :---------------------:| :---------------------:|:---------------------------------------------------------- |
|ESP32 | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | |
|ESP32-S2 | | | | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | |
|ESP32-C3 | | | | | ![alt text][supported] | ![alt text][supported] | |
|ESP32-S3 | | | | | ![alt text][preview] | ![alt text][supported] | [Announcement](https://www.espressif.com/en/news/ESP32_S3) |
|ESP32-H2 | | | | | | ![alt text][preview] | [Announcement](https://www.espressif.com/en/news/ESP32_H2) |
[supported]: https://img.shields.io/badge/-supported-green "supported"
[preview]: https://img.shields.io/badge/-preview-orange "preview"
Espressif SoCs released before 2016 (ESP8266 and ESP8285) are supported by [RTOS SDK](https://github.com/espressif/ESP8266_RTOS_SDK) instead.
# Developing With ESP-IDF
@ -99,8 +116,3 @@ This can be combined with other targets, ie `idf.py -p PORT erase_flash flash` w
* [Check the Issues section on github](https://github.com/espressif/esp-idf/issues) if you find a bug or have a feature request. Please check existing Issues before opening a new one.
* If you're interested in contributing to ESP-IDF, please check the [Contributions Guide](https://docs.espressif.com/projects/esp-idf/en/latest/contribute/index.html).
________
<a name="fn1">1</a>: ESP8266 and ESP8285 are not supported in ESP-IDF. See [RTOS SDK](https://github.com/espressif/ESP8266_RTOS_SDK) instead.

View File

@ -2,13 +2,30 @@
* [English Version](./README.md)
ESP-IDF 是由乐鑫官方针对乐鑫各系列芯片产品(发布于 2016 年后<sup>[1](#fn1)</sup>)推出的开发框架,支持 Windows、Linux 和 macOS 操作系统。
ESP-IDF 是乐鑫官方推出的物联网开发框架,支持 Windows、Linux 和 macOS 操作系统。
# ESP-IDF 与乐鑫芯片
下表总结了乐鑫芯片在 ESP-IDF 各版本中的支持状态,其中 ![alt text][supported] 代表已支持,![alt text][preview] 代表目前处于预览支持状态。在预览支持阶段,因为新芯片尚未完全添加到构建系统目录,所以一些重要的内容(如文档和技术规格书等)可能会缺失。请确保使用与芯片相匹配的 ESP-IDF 版本。
| 芯片 | v3.3 | v4.0 | v4.1 | v4.2 | v4.3 | v4.4 | |
|:----------- |:---------------------: | :---------------------:| :---------------------:| :---------------------:| :---------------------:| :---------------------:|:---------------------------------------------------------- |
|ESP32 | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | |
|ESP32-S2 | | | | ![alt text][supported] | ![alt text][supported] | ![alt text][supported] | |
|ESP32-C3 | | | | | ![alt text][supported] | ![alt text][supported] | |
|ESP32-S3 | | | | | ![alt text][preview] | ![alt text][supported] | [芯片发布公告](https://www.espressif.com/en/news/ESP32_S3) |
|ESP32-H2 | | | | | | ![alt text][preview] | [芯片发布公告](https://www.espressif.com/en/news/ESP32_H2) |
[supported]: https://img.shields.io/badge/-%E6%94%AF%E6%8C%81-green "supported"
[preview]: https://img.shields.io/badge/-%E9%A2%84%E8%A7%88-orange "preview"
对于 2016 年之前发布的乐鑫芯片(包括 ESP8266 和 ESP8285请参考 [RTOS SDK](https://github.com/espressif/ESP8266_RTOS_SDK)。
# 使用 ESP-IDF 进行开发
## 搭建 ESP-IDF 开发环境
关于不同芯片如何搭建 ESP-IDF 的开发环境,请参考 https://idf.espressif.com/。
关于不同芯片如何搭建 ESP-IDF 的开发环境,请参考 https://idf.espressif.com/
**注意:** 不同系列芯片和不同 ESP-IDF 版本都有其对应的文档。请参阅[版本](https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/versions.html)部分,获得关于如何查找文档以及如何检出 ESP-IDF 的特定发行版的详细信息。
@ -99,8 +116,3 @@ ESP-IDF 中的子模块采用相对路径([详见 .gitmodules 文件](.gitmodu
* 如果你在使用中发现了错误或者需要新的功能,请先[查看 GitHub Issues](https://github.com/espressif/esp-idf/issues),确保该问题没有重复提交。
* 如果你有兴趣为 ESP-IDF 作贡献,请先阅读[贡献指南](https://docs.espressif.com/projects/esp-idf/en/latest/contribute/index.html)。
__________
<a name="fn1">1</a>: ESP-IDF 不支持 ESP8266 和 ESP8285。如有需要请参考 [RTOS SDK](https://github.com/espressif/ESP8266_RTOS_SDK)。

160
components/README.md Normal file
View File

@ -0,0 +1,160 @@
# Core Components
## Overview
This document contains details about what the core components are, what they contain, and how they are organized.
## Organization
The core components are organized into two groups.
The first group (referred to as `G0` from now on) contains `hal`, `xtensa` and `riscv` (referred to as `arch` components from now on), `esp_rom`, `esp_common`, and `soc`. This
group contain information about and low-level access to underlying hardware; or in the case of `esp_common`, hardware-agnostic code and utilities.
These components can depend on each other, but as much as possible have no dependencies outside the group. The reason for this is that, due to the
nature of what these components contain, the likelihood is high that a lot of other components will require these. Ideally, then, the dependency
relationship only goes one way. This makes it easier for these components, as a group, to be usable in another project. One can conceivably implement
a competing SDK to ESP-IDF on top of these components.
The second group (referred to as `G1` from now on) sits at a higher level than the first group. This group contains the components `esp_hw_support`, `esp_system`, `newlib`, `spi_flash`,
`freertos`, `log`, and `heap`. Like the first group, circular dependencies within the group are allowed; and being at a higher level, dependency on the first group
is allowed. These components represent software mechanisms essential to building other components.
## Descriptions
The following is a short description of the components mentioned above.
### `G0` Components
#### `hal`
Contains the hardware abstraction layer and low-level operation implementations for the various peripherals. The low-level functions assign meaningful names to register-level manipulations; the hardware abstraction provide operations one level above this, grouping these low-level functions
into routines that achieve a meaningful action or state of the peripheral.
Example:
- `spi_flash_ll_set_address` is a low-level function part of the hardware abstraction `spi_flash_hal_read_block`
#### `arch`
Contains low-level architecture operations and definitions, including those for customizations (can be thought of on the same level as the low-level functions of `hal`).
This can also contain files provided by the architecture vendor.
Example:
- `xt_set_exception_handler`
- `riscv_global_interrupts_enable`
- `ERI_PERFMON_MAX`
#### `esp_common`
Contains hardware-agnostic definitions, constants, macros, utilities, 'pure' and/or algorithmic functions that is useable by all other components (that is, barring there being a more appropriate component to put them in).
Example:
- `BIT(nr)` and other bit manipulation utilities in the future
- `IDF_DEPRECATED(REASON)`
- `ESP_IDF_VERSION_MAJOR`
#### `soc`
Contains description of the underlying hardware: register structure, addresses, pins, capabilities, etc.
Example:
- `DR_REG_DPORT_BASE`
- `SOC_MCPWM_SUPPORTED`
- `uart_dev_s`
#### `esp_rom`
Contains headers, linker scripts, abstraction layer, patches, and other related files to ROM functions.
Example:
- `esp32.rom.eco3.ld`
- `rom/aes.h`
### `G1` Components
#### `spi_flash`
SPI flash device access implementation.
#### `freertos`
FreeRTOS port to targets supported by ESP-IDF.
#### `log`
Logging library.
#### `heap`
Heap implementation.
#### `newlib`
Some functions n the standard library are implemented here, especially those needing other `G1` components.
Example:
- `malloc` is implemented in terms of the component `heap`'s functions
- `gettimeofday` is implemented in terms of system time in `esp_system`
#### `esp_system`
Contains implementation of system services and controls system behavior. The implementations
here may take hardware resources and/or decide on a hardware state needed for support of a system service/feature/mechanism.
Currently, this encompasses the following, but not limited to:
- Startup and initialization
- Panic and debug
- Reset and reset reason
- Task and interrupt watchdogs
#### `esp_hw_support`
Contains implementations that provide hardware operations, arbitration, or resource sharing, especially those that
is used in the system. Unlike `esp_system`, implementations here do not decide on a hardware state or takes hardware resource, acting
merely as facilitator to hardware access. Currently, this encompasses the following, but not limited to:
- Interrupt allocation
- Sleep functions
- Memory functions (external SPIRAM, async memory, etc.)
- Clock and clock control
- Random generation
- CPU utilities
- MAC settings
### `esp_hw_support` vs `esp_system`
This section details list some implementations and the reason for placing it in either `esp_hw_support` or `esp_system`.
#### `task_wdt.c` (`esp_system`) vs `intr_alloc.c` (`esp_hw_support`)
The task watchdog fits the definition of taking and configuring hardware resources (wdt, interrupt) for implementation of a system service/mechanism.
This is in contrast with interrupt allocation that merely facilitates access to the underlying hardware for other implementations -
drivers, user code, and even the task watchdog mentioned previously!
#### `crosscore_int.c` (`esp_system`)
The current implementation of crosscore interrupts is tightly coupled with a number of interrupt reasons
associated with system services/mechanisms: REASON_YIELD (scheduler), REASON_FREQ_SWITCH (power management)
REASON_PRINT_BACKTRACE (panic and debug).
However, if an implementation exists that makes it possible to register an arbitrary interrupt reason - a
lower level inter-processor call if you will, then this implementation is a good candidate for `esp_hw_support`.
The current implementation in `esp_system` can then just register the interrupt reasons mentioned above.
#### `esp_mac.h`, `esp_chip_info.h`, `esp_random.h` (`esp_hw_support`)
The functions in these headers used to be in `esp_system.h`, but have been split-off.
However, to maintain backward compatibility, `esp_system.h` includes these headers.
The remaining functions in `esp_system.h` are those that deal with system behavior, such
as `esp_register_shutdown_handler`, or are proxy for other system components's APIs such as
`esp_get_free_heap_size`.
The functions split-off from `esp_system.h` are much more hardware manipulation oriented such as:
`esp_read_mac`, `esp_random` and `esp_chip_info`.

View File

@ -47,7 +47,7 @@ endif()
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "${include_dirs}"
PRIV_INCLUDE_DIRS "${priv_include_dirs}"
PRIV_REQUIRES soc
PRIV_REQUIRES soc esp_ipc
LDFRAGMENTS linker.lf)
# disable --coverage for this component, as it is used as transport

View File

@ -14,7 +14,9 @@
#include "soc/cpu.h"
#include "soc/timer_periph.h"
#include "esp_app_trace.h"
#include "esp_freertos_hooks.h"
#include "esp_private/dbg_stubs.h"
#include "esp_ipc.h"
#include "hal/wdt_hal.h"
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/rom/libc_stubs.h"
@ -28,128 +30,113 @@
#include "esp_log.h"
const static char *TAG = "esp_gcov_rtio";
static volatile bool s_create_gcov_task = false;
static volatile bool s_gcov_task_running = false;
extern void __gcov_dump(void);
extern void __gcov_reset(void);
static struct syscall_stub_table s_gcov_stub_table;
static int gcov_stub_lock_try_acquire_recursive(_lock_t *lock)
void gcov_dump_task(void *pvParameter)
{
if (*lock && uxSemaphoreGetCount((xSemaphoreHandle)(*lock)) == 0) {
// we can do nothing here, gcov dump is initiated with some resource locked
// which is also used by gcov functions
ESP_EARLY_LOGE(TAG, "Lock 0x%x is busy during GCOV dump! System state can be inconsistent after dump!", lock);
}
return pdTRUE;
}
int dump_result = 0;
bool *running = (bool *)pvParameter;
static void gcov_stub_lock_acquire_recursive(_lock_t *lock)
{
gcov_stub_lock_try_acquire_recursive(lock);
}
ESP_EARLY_LOGV(TAG, "%s stack use in %d", __FUNCTION__, uxTaskGetStackHighWaterMark(NULL));
static void gcov_stub_lock_release_recursive(_lock_t *lock)
{
}
static int esp_dbg_stub_gcov_dump_do(void)
{
int ret = ESP_OK;
FILE* old_stderr = stderr;
FILE* old_stdout = stdout;
static struct syscall_stub_table *old_tables[portNUM_PROCESSORS];
old_tables[0] = syscall_table_ptr_pro;
#if portNUM_PROCESSORS > 1
old_tables[1] = syscall_table_ptr_app;
#endif
ESP_EARLY_LOGV(TAG, "Alloc apptrace down buf %d bytes", ESP_GCOV_DOWN_BUF_SIZE);
void *down_buf = malloc(ESP_GCOV_DOWN_BUF_SIZE);
if (down_buf == NULL) {
ESP_EARLY_LOGE(TAG, "Could not allocate memory for the buffer");
return ESP_ERR_NO_MEM;
dump_result = ESP_ERR_NO_MEM;
goto gcov_exit;
}
ESP_EARLY_LOGV(TAG, "Config apptrace down buf");
esp_apptrace_down_buffer_config(down_buf, ESP_GCOV_DOWN_BUF_SIZE);
/* we are directing the std outputs to the fake ones in order to reduce stack usage */
FILE *old_stderr = stderr;
FILE *old_stdout = stdout;
stderr = (FILE *) &__sf_fake_stderr;
stdout = (FILE *) &__sf_fake_stdout;
ESP_EARLY_LOGV(TAG, "Dump data...");
// incase of dual-core chip APP and PRO CPUs share the same table, so it is safe to save only PRO's table
memcpy(&s_gcov_stub_table, syscall_table_ptr_pro, sizeof(s_gcov_stub_table));
s_gcov_stub_table._lock_acquire_recursive = &gcov_stub_lock_acquire_recursive;
s_gcov_stub_table._lock_release_recursive = &gcov_stub_lock_release_recursive;
s_gcov_stub_table._lock_try_acquire_recursive = &gcov_stub_lock_try_acquire_recursive,
syscall_table_ptr_pro = &s_gcov_stub_table;
#if portNUM_PROCESSORS > 1
syscall_table_ptr_app = &s_gcov_stub_table;
#endif
stderr = (FILE*) &__sf_fake_stderr;
stdout = (FILE*) &__sf_fake_stdout;
__gcov_dump();
// reset dump status to allow incremental data accumulation
__gcov_reset();
stdout = old_stdout;
stderr = old_stderr;
syscall_table_ptr_pro = old_tables[0];
#if portNUM_PROCESSORS > 1
syscall_table_ptr_app = old_tables[1];
#endif
ESP_EARLY_LOGV(TAG, "Free apptrace down buf");
free(down_buf);
stderr = old_stderr;
stdout = old_stdout;
ESP_EARLY_LOGV(TAG, "Finish file transfer session");
ret = esp_apptrace_fstop(ESP_APPTRACE_DEST_TRAX);
if (ret != ESP_OK) {
ESP_EARLY_LOGE(TAG, "Failed to send files transfer stop cmd (%d)!", ret);
dump_result = esp_apptrace_fstop(ESP_APPTRACE_DEST_TRAX);
if (dump_result != ESP_OK) {
ESP_EARLY_LOGE(TAG, "Failed to send files transfer stop cmd (%d)!", dump_result);
}
gcov_exit:
ESP_EARLY_LOGV(TAG, "dump_result %d", dump_result);
if (running) {
*running = false;
}
ESP_EARLY_LOGV(TAG, "%s stack use out %d", __FUNCTION__, uxTaskGetStackHighWaterMark(NULL));
vTaskDelete(NULL);
}
void gcov_create_task(void *arg)
{
ESP_EARLY_LOGV(TAG, "%s", __FUNCTION__);
xTaskCreatePinnedToCore(&gcov_dump_task, "gcov_dump_task", 2048, (void *)&s_gcov_task_running, configMAX_PRIORITIES - 1, NULL, 0);
}
void gcov_create_task_tick_hook(void)
{
extern esp_err_t esp_ipc_start_gcov_from_isr(uint32_t cpu_id, esp_ipc_func_t func, void* arg);
if (s_create_gcov_task) {
if (esp_ipc_start_gcov_from_isr(xPortGetCoreID(), &gcov_create_task, NULL) == ESP_OK) {
s_create_gcov_task = false;
}
}
ESP_EARLY_LOGV(TAG, "exit %d", ret);
return ret;
}
/**
* @brief Triggers gcov info dump.
* @brief Triggers gcov info dump task
* This function is to be called by OpenOCD, not by normal user code.
* TODO: what about interrupted flash access (when cache disabled)???
* TODO: what about interrupted flash access (when cache disabled)
*
* @return ESP_OK on success, otherwise see esp_err_t
*/
static int esp_dbg_stub_gcov_entry(void)
{
return esp_dbg_stub_gcov_dump_do();
/* we are in isr context here */
s_create_gcov_task = true;
return ESP_OK;
}
int gcov_rtio_atexit(void (*function)(void) __attribute__ ((unused)))
{
uint32_t capabilities = 0;
ESP_EARLY_LOGV(TAG, "%s", __FUNCTION__);
esp_dbg_stub_entry_set(ESP_DBG_STUB_ENTRY_GCOV, (uint32_t)&esp_dbg_stub_gcov_entry);
return 0;
if (esp_dbg_stub_entry_get(ESP_DBG_STUB_ENTRY_CAPABILITIES, &capabilities) == ESP_OK) {
esp_dbg_stub_entry_set(ESP_DBG_STUB_ENTRY_CAPABILITIES, capabilities | ESP_DBG_STUB_CAP_GCOV_TASK);
}
esp_register_freertos_tick_hook(gcov_create_task_tick_hook);
return ESP_OK;
}
void esp_gcov_dump(void)
{
// disable IRQs on this CPU, other CPU is halted by OpenOCD
unsigned irq_state = portENTER_CRITICAL_NESTED();
#if !CONFIG_FREERTOS_UNICORE
int other_core = cpu_hal_get_core_id() ? 0 : 1;
esp_cpu_stall(other_core);
#endif
ESP_EARLY_LOGV(TAG, "%s", __FUNCTION__);
while (!esp_apptrace_host_is_connected(ESP_APPTRACE_DEST_TRAX)) {
wdt_hal_context_t twdt = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0};
wdt_hal_context_t iwdt = {.inst = WDT_MWDT1, .mwdt_dev = &TIMERG1};
//Feed the Task Watchdog (TG0) to prevent it from timing out
wdt_hal_write_protect_disable(&twdt);
wdt_hal_feed(&twdt);
wdt_hal_write_protect_enable(&twdt);
//Likewise, feed the Interrupt Watchdog (TG1) to prevent a reboot
wdt_hal_write_protect_disable(&iwdt);
wdt_hal_feed(&iwdt);
wdt_hal_write_protect_enable(&iwdt);
vTaskDelay(pdMS_TO_TICKS(10));
}
esp_dbg_stub_gcov_dump_do();
#if !CONFIG_FREERTOS_UNICORE
esp_cpu_unstall(other_core);
#endif
portEXIT_CRITICAL_NESTED(irq_state);
/* We are not in isr context here. Waiting for the completion is safe */
s_gcov_task_running = true;
s_create_gcov_task = true;
while (s_gcov_task_running) {
vTaskDelay(pdMS_TO_TICKS(10));
}
}
void *gcov_rtio_fopen(const char *path, const char *mode)
@ -168,7 +155,7 @@ int gcov_rtio_fclose(void *stream)
size_t gcov_rtio_fread(void *ptr, size_t size, size_t nmemb, void *stream)
{
ESP_EARLY_LOGV(TAG, "%s read %u", __FUNCTION__, size*nmemb);
ESP_EARLY_LOGV(TAG, "%s read %u", __FUNCTION__, size * nmemb);
size_t sz = esp_apptrace_fread(ESP_APPTRACE_DEST_TRAX, ptr, size, nmemb, stream);
ESP_EARLY_LOGV(TAG, "%s actually read %u", __FUNCTION__, sz);
return sz;

View File

@ -151,16 +151,17 @@ extern const SEGGER_SYSVIEW_OS_API SYSVIEW_X_OS_TraceAPI;
// The lowest RAM address used for IDs (pointers)
#define SYSVIEW_RAM_BASE (SOC_DROM_LOW)
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
#ifdef CONFIG_FREERTOS_TICK_SUPPORT_CORETIMER
#if CONFIG_FREERTOS_CORETIMER_0
#define SYSTICK_INTR_ID (ETS_INTERNAL_TIMER0_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF)
#endif
#if CONFIG_FREERTOS_CORETIMER_1
#define SYSTICK_INTR_ID (ETS_INTERNAL_TIMER1_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF)
#endif
#elif CONFIG_IDF_TARGET_ESP32C3
#define SYSTICK_INTR_ID (ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF)
#endif
#elif CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER
#define SYSTICK_INTR_ID (ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE)
#endif // CONFIG_FREERTOS_TICK_SUPPORT_CORETIMER
// SystemView is single core specific: it implies that SEGGER_SYSVIEW_LOCK()
// disables IRQs (disables rescheduling globally). So we can not use finite timeouts for locks and return error

View File

@ -209,7 +209,7 @@ Notes:
#define apiID_VEVENTGROUPDELETE (72u)
#define apiID_UXEVENTGROUPGETNUMBER (73u)
#define traceTASK_NOTIFY_TAKE() SEGGER_SYSVIEW_RecordU32x2(apiFastID_OFFSET + apiID_ULTASKNOTIFYTAKE, xClearCountOnExit, xTicksToWait)
#define traceTASK_NOTIFY_TAKE( uxIndexToWait ) SEGGER_SYSVIEW_RecordU32x2(apiFastID_OFFSET + apiID_ULTASKNOTIFYTAKE, xClearCountOnExit, xTicksToWait)
#define traceTASK_DELAY() SEGGER_SYSVIEW_RecordU32(apiFastID_OFFSET + apiID_VTASKDELAY, xTicksToDelay)
#define traceTASK_DELAY_UNTIL() SEGGER_SYSVIEW_RecordVoid(apiFastID_OFFSET + apiID_VTASKDELAYUNTIL)
#define traceTASK_DELETE( pxTCB ) if (pxTCB != NULL) { \
@ -217,16 +217,16 @@ Notes:
SEGGER_SYSVIEW_ShrinkId((U32)pxTCB)); \
SYSVIEW_DeleteTask((U32)pxTCB); \
}
#define traceTASK_NOTIFY_GIVE_FROM_ISR() SEGGER_SYSVIEW_RecordU32x2(apiFastID_OFFSET + apiID_VTASKNOTIFYGIVEFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB), (U32)pxHigherPriorityTaskWoken)
#define traceTASK_NOTIFY_GIVE_FROM_ISR( uxIndexToNotify ) SEGGER_SYSVIEW_RecordU32x2(apiFastID_OFFSET + apiID_VTASKNOTIFYGIVEFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB), (U32)pxHigherPriorityTaskWoken)
#define traceTASK_PRIORITY_INHERIT( pxTCB, uxPriority ) SEGGER_SYSVIEW_RecordU32(apiFastID_OFFSET + apiID_VTASKPRIORITYINHERIT, (U32)pxMutexHolder)
#define traceTASK_RESUME( pxTCB ) SEGGER_SYSVIEW_RecordU32(apiFastID_OFFSET + apiID_VTASKRESUME, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB))
#define traceINCREASE_TICK_COUNT( xTicksToJump ) SEGGER_SYSVIEW_RecordU32(apiFastID_OFFSET + apiID_VTASKSTEPTICK, xTicksToJump)
#define traceTASK_SUSPEND( pxTCB ) SEGGER_SYSVIEW_RecordU32(apiFastID_OFFSET + apiID_VTASKSUSPEND, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB))
#define traceTASK_PRIORITY_DISINHERIT( pxTCB, uxBasePriority ) SEGGER_SYSVIEW_RecordU32(apiFastID_OFFSET + apiID_XTASKPRIORITYDISINHERIT, (U32)pxMutexHolder)
#define traceTASK_RESUME_FROM_ISR( pxTCB ) SEGGER_SYSVIEW_RecordU32(apiFastID_OFFSET + apiID_XTASKRESUMEFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB))
#define traceTASK_NOTIFY() SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XTASKGENERICNOTIFY, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB), ulValue, eAction, (U32)pulPreviousNotificationValue)
#define traceTASK_NOTIFY_FROM_ISR() SYSVIEW_RecordU32x5(apiFastID_OFFSET + apiID_XTASKGENERICNOTIFYFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB), ulValue, eAction, (U32)pulPreviousNotificationValue, (U32)pxHigherPriorityTaskWoken)
#define traceTASK_NOTIFY_WAIT() SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XTASKNOTIFYWAIT, ulBitsToClearOnEntry, ulBitsToClearOnExit, (U32)pulNotificationValue, xTicksToWait)
#define traceTASK_NOTIFY( uxIndexToNotify ) SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XTASKGENERICNOTIFY, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB), ulValue, eAction, (U32)pulPreviousNotificationValue)
#define traceTASK_NOTIFY_FROM_ISR( uxIndexToNotify ) SYSVIEW_RecordU32x5(apiFastID_OFFSET + apiID_XTASKGENERICNOTIFYFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB), ulValue, eAction, (U32)pulPreviousNotificationValue, (U32)pxHigherPriorityTaskWoken)
#define traceTASK_NOTIFY_WAIT( uxIndexToWait ) SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XTASKNOTIFYWAIT, ulBitsToClearOnEntry, ulBitsToClearOnExit, (U32)pulNotificationValue, xTicksToWait)
#define traceQUEUE_CREATE( pxNewQueue ) SEGGER_SYSVIEW_RecordU32x3(apiFastID_OFFSET + apiID_XQUEUEGENERICCREATE, uxQueueLength, uxItemSize, ucQueueType)
#define traceQUEUE_DELETE( pxQueue ) SEGGER_SYSVIEW_RecordU32(apiFastID_OFFSET + apiID_VQUEUEDELETE, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue))

View File

@ -46,6 +46,7 @@ if(NOT BOOTLOADER_BUILD)
add_custom_target(blank_ota_data ALL DEPENDS ${blank_otadata_file})
add_dependencies(flash blank_ota_data)
add_dependencies(encrypted-flash blank_ota_data)
set(otatool_py ${python} ${COMPONENT_DIR}/otatool.py)

View File

@ -386,6 +386,15 @@ menu "Bootloader config"
in this area of memory, you can increase it. It must be a multiple of 4 bytes.
This area (rtc_retain_mem_t) is reserved and has access from the bootloader and an application.
config BOOTLOADER_FLASH_XMC_SUPPORT
bool "Enable the support for flash chips of XMC (READ HELP FIRST)"
default y
help
Perform the startup flow recommended by XMC. Please consult XMC for the details of this flow.
XMC chips will be forbidden to be used, when this option is disabled.
DON'T DISABLE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.
endmenu # Bootloader
@ -415,12 +424,12 @@ menu "Security features"
config SECURE_BOOT_SUPPORTS_RSA
bool
default y
depends on ESP32_REV_MIN_3 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3
depends on ESP32_REV_MIN_3 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3
config SECURE_TARGET_HAS_SECURE_ROM_DL_MODE
bool
default y
depends on IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3
depends on IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3
config SECURE_SIGNED_APPS_NO_SECURE_BOOT
@ -492,7 +501,8 @@ menu "Security features"
config SECURE_BOOT
bool "Enable hardware Secure Boot in bootloader (READ DOCS FIRST)"
default n
depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || ESP32C3_REV_MIN_3
depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || ESP32C3_REV_MIN_3 || IDF_TARGET_ESP32S3
select ESPTOOLPY_NO_STUB if !IDF_TARGET_ESP32 && !IDF_TARGET_ESP32S2
help
Build a bootloader which enables Secure Boot on first boot.
@ -755,9 +765,17 @@ menu "Security features"
efuse when Secure Boot is enabled. This prevents any more efuses from being read protected.
If this option is set, it will remain possible to write the EFUSE_RD_DIS efuse field after Secure
Boot is enabled. This may allow an attacker to read-protect the BLK2 efuse holding the public
key digest, causing an immediate denial of service and possibly allowing an additional fault
injection attack to bypass the signature protection.
Boot is enabled. This may allow an attacker to read-protect the BLK2 efuse (for ESP32) and
BLOCK4-BLOCK10 (i.e. BLOCK_KEY0-BLOCK_KEY5)(for other chips) holding the public key digest, causing an
immediate denial of service and possibly allowing an additional fault injection attack to
bypass the signature protection.
NOTE: Once a BLOCK is read-protected, the application will read all zeros from that block
NOTE: If "UART ROM download mode (Permanently disabled (recommended))" or
"UART ROM download mode (Permanently switch to Secure mode (recommended))" is set,
then it is __NOT__ possible to read/write efuses using espefuse.py utility.
However, efuse can be read/written from the application
config SECURE_BOOT_ALLOW_UNUSED_DIGEST_SLOTS
bool "Leave unused digest slots available (not revoke)"
@ -875,6 +893,8 @@ menu "Security features"
It is also possible to enable secure download mode at runtime by calling
esp_efuse_enable_rom_secure_download_mode()
Note: Secure Download mode is not available for ESP32 (includes revisions till ECO3).
config SECURE_INSECURE_ALLOW_DL_MODE
bool "UART ROM download mode (Enabled (not recommended))"
help

View File

@ -49,6 +49,7 @@ SECTIONS
*libbootloader_support.a:bootloader_sha.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_console_loader.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_panic.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_soc.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:esp_image_format.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:flash_encrypt.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:flash_encryption_secure_features.*(.literal .text .literal.* .text.*)

View File

@ -36,6 +36,7 @@ SECTIONS
*libbootloader_support.a:bootloader_sha.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_console_loader.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_panic.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_soc.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:esp_image_format.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:flash_encrypt.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:flash_encryption_secure_features.*(.literal .text .literal.* .text.*)

View File

@ -36,6 +36,7 @@ SECTIONS
*libbootloader_support.a:bootloader_sha.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_console_loader.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_panic.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_soc.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:esp_image_format.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:flash_encrypt.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:flash_partitions.*(.literal .text .literal.* .text.*)

View File

@ -36,6 +36,7 @@ SECTIONS
*libbootloader_support.a:bootloader_sha.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_console_loader.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_panic.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_soc.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:esp_image_format.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:flash_encrypt.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:flash_encryption_secure_features.*(.literal .text .literal.* .text.*)

View File

@ -37,6 +37,7 @@ SECTIONS
*libbootloader_support.a:bootloader_sha.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_console_loader.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_panic.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_soc.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:esp_image_format.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:flash_encrypt.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:flash_encryption_secure_features.*(.literal .text .literal.* .text.*)

View File

@ -26,6 +26,7 @@ if(BOOTLOADER_BUILD)
"src/bootloader_console_loader.c"
"src/bootloader_panic.c"
"src/${IDF_TARGET}/bootloader_sha.c"
"src/${IDF_TARGET}/bootloader_soc.c"
"src/${IDF_TARGET}/bootloader_${IDF_TARGET}.c"
)
list(APPEND priv_requires hal)

View File

@ -119,6 +119,15 @@ bool bootloader_common_label_search(const char *list, char *label);
*/
void bootloader_configure_spi_pins(int drv);
/**
* @brief Get flash CS IO
*
* Can be determined by eFuse values, or the default value
*
* @return Flash CS IO
*/
uint8_t bootloader_flash_get_cs_io(void);
/**
* @brief Calculates a sha-256 for a given partition or returns a appended digest.
*

View File

@ -14,6 +14,14 @@
extern "C" {
#endif
/**
* @brief Read flash ID by sending RDID command (0x9F)
* @return flash raw ID
* mfg_id = (ID >> 16) & 0xFF;
flash_id = ID & 0xffff;
*/
uint32_t bootloader_read_flash_id(void);
#if SOC_CACHE_SUPPORT_WRAP
/**
* @brief Set the burst mode setting command for specified wrap mode.
@ -32,6 +40,13 @@ esp_err_t bootloader_flash_wrap_set(spi_flash_wrap_mode_t mode);
*/
esp_err_t bootloader_flash_unlock(void);
/**
* @brief Startup flow recommended by XMC. Call at startup before any erase/write operation.
*
* @return ESP_OK When startup successfully, otherwise ESP_FAIL (indiciating you should reboot before erase/write).
*/
esp_err_t bootloader_flash_xmc_startup(void);
#ifdef __cplusplus
}
#endif

View File

@ -29,6 +29,7 @@
#define CMD_RDSR 0x05
#define CMD_RDSR2 0x35 /* Not all SPI flash uses this command */
#define CMD_OTPEN 0x3A /* Enable OTP mode, not all SPI flash uses this command */
#define CMD_RDSFDP 0x5A /* Read the SFDP of the flash */
#define CMD_WRAP 0x77 /* Set burst with wrap command */
#define CMD_RESUME 0x7A /* Resume command to clear flash suspend bit */
@ -156,6 +157,15 @@ static inline uint32_t bootloader_cache_pages_to_map(uint32_t size, uint32_t vad
*/
uint32_t bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len);
/**
* @brief Read the SFDP of the flash
*
* @param sfdp_addr Address of the parameter to read
* @param miso_byte_num Bytes to read
* @return The read SFDP, little endian, 4 bytes at most
*/
uint32_t bootloader_flash_read_sfdp(uint32_t sfdp_addr, unsigned int miso_byte_num);
/**
* @brief Enable the flash write protect (WEL bit).
*/

View File

@ -0,0 +1,27 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
/**
* @brief Configure analog super WDT reset
*
* @param enable Boolean to enable or disable super WDT reset
*/
void bootloader_ana_super_wdt_reset_config(bool enable);
/**
* @brief Configure analog brownout reset
*
* @param enable Boolean to enable or disable brownout reset
*/
void bootloader_ana_bod_reset_config(bool enable);
/**
* @brief Configure analog clock glitch reset
*
* @param enable Boolean to enable or disable clock glitch reset
*/
void bootloader_ana_clock_glitch_reset_config(bool enable);

View File

@ -23,6 +23,7 @@
#include "esp_rom_crc.h"
#include "esp_rom_gpio.h"
#include "esp_rom_sys.h"
#include "esp_rom_efuse.h"
#include "esp_flash_partitions.h"
#include "bootloader_flash_priv.h"
#include "bootloader_common.h"
@ -191,8 +192,19 @@ void bootloader_common_vddsdio_configure(void)
#endif // CONFIG_BOOTLOADER_VDDSDIO_BOOST
}
RESET_REASON bootloader_common_get_reset_reason(int cpu_no)
{
return (RESET_REASON)esp_rom_get_reset_reason(cpu_no);
}
uint8_t bootloader_flash_get_cs_io(void)
{
uint8_t cs_io;
const uint32_t spiconfig = esp_rom_efuse_get_flash_gpio_info();
if (spiconfig == ESP_ROM_EFUSE_FLASH_DEFAULT_SPI) {
cs_io = SPI_CS0_GPIO_NUM;
} else {
cs_io = (spiconfig >> 18) & 0x3f;
}
return cs_io;
}

View File

@ -71,8 +71,8 @@ void bootloader_console_init(void)
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_U0RXD_U, PIN_FUNC_GPIO);
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_U0TXD_U, PIN_FUNC_GPIO);
// Route GPIO signals to/from pins
const uint32_t tx_idx = uart_periph_signal[uart_num].tx_sig;
const uint32_t rx_idx = uart_periph_signal[uart_num].rx_sig;
const uint32_t tx_idx = UART_PERIPH_SIGNAL(uart_num, SOC_UART_TX_PIN_IDX);
const uint32_t rx_idx = UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX);
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[uart_rx_gpio]);
esp_rom_gpio_pad_pullup_only(uart_rx_gpio);
esp_rom_gpio_connect_out_signal(uart_tx_gpio, tx_idx, 0, 0);

View File

@ -7,14 +7,14 @@
#include "bootloader_common.h"
#include "bootloader_clock.h"
#include "soc/efuse_reg.h"
#include "soc/apb_ctrl_reg.h"
#include "soc/syscon_reg.h"
uint8_t bootloader_common_get_chip_revision(void)
{
uint8_t eco_bit0, eco_bit1, eco_bit2;
eco_bit0 = (REG_READ(EFUSE_BLK0_RDATA3_REG) & 0xF000) >> 15;
eco_bit1 = (REG_READ(EFUSE_BLK0_RDATA5_REG) & 0x100000) >> 20;
eco_bit2 = (REG_READ(APB_CTRL_DATE_REG) & 0x80000000) >> 31;
eco_bit2 = (REG_READ(SYSCON_DATE_REG) & 0x80000000) >> 31;
uint32_t combine_value = (eco_bit2 << 2) | (eco_bit1 << 1) | eco_bit0;
uint8_t chip_ver = 0;
switch (combine_value) {
@ -28,7 +28,7 @@ uint8_t bootloader_common_get_chip_revision(void)
chip_ver = 2;
break;
#if CONFIG_IDF_ENV_FPGA
case 4: /* Empty efuses, but APB_CTRL_DATE_REG bit is set */
case 4: /* Empty efuses, but SYSCON_DATE_REG bit is set */
chip_ver = 3;
break;
#endif

View File

@ -19,5 +19,5 @@ uint8_t bootloader_common_get_chip_revision(void)
uint32_t bootloader_common_get_chip_ver_pkg(void)
{
// should return the same value as esp_efuse_get_pkg_ver()
return REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_3_REG, EFUSE_PKG_VERSION);
return REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_4_REG, EFUSE_PKG_VERSION);
}

View File

@ -122,7 +122,7 @@ esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size)
return spi_flash_erase_range(start_addr, size);
}
#else
#else //BOOTLOADER_BUILD
/* Bootloader version, uses ROM functions only */
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/rom/spi_flash.h"
@ -481,7 +481,8 @@ esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size)
return spi_to_esp_err(rc);
}
#endif
#endif // BOOTLOADER_BUILD
FORCE_INLINE_ATTR bool is_issi_chip(const esp_rom_spiflash_chip_t* chip)
{
@ -563,29 +564,49 @@ esp_err_t IRAM_ATTR __attribute__((weak)) bootloader_flash_unlock(void)
return err;
}
/* dummy_len_plus values defined in ROM for SPI flash configuration */
#ifndef g_rom_spiflash_dummy_len_plus // ESP32-C3 uses a macro to access ROM data here
extern uint8_t g_rom_spiflash_dummy_len_plus[];
#endif
uint32_t IRAM_ATTR bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len)
IRAM_ATTR static uint32_t bootloader_flash_execute_command_common(
uint8_t command,
uint32_t addr_len, uint32_t address,
uint8_t dummy_len,
uint8_t mosi_len, uint32_t mosi_data,
uint8_t miso_len)
{
assert(mosi_len <= 32);
assert(miso_len <= 32);
uint32_t old_ctrl_reg = SPIFLASH.ctrl.val;
uint32_t old_user_reg = SPIFLASH.user.val;
uint32_t old_user1_reg = SPIFLASH.user1.val;
#if CONFIG_IDF_TARGET_ESP32
SPIFLASH.ctrl.val = SPI_WP_REG_M; // keep WP high while idle, otherwise leave DIO mode
#else
SPIFLASH.ctrl.val = SPI_MEM_WP_REG_M; // keep WP high while idle, otherwise leave DIO mode
#endif
SPIFLASH.user.usr_dummy = 0;
SPIFLASH.user.usr_addr = 0;
//command phase
SPIFLASH.user.usr_command = 1;
SPIFLASH.user2.usr_command_bitlen = 7;
SPIFLASH.user2.usr_command_value = command;
SPIFLASH.user.usr_miso = miso_len > 0;
//addr phase
SPIFLASH.user.usr_addr = addr_len > 0;
SPIFLASH.user1.usr_addr_bitlen = addr_len - 1;
#if CONFIG_IDF_TARGET_ESP32
SPIFLASH.miso_dlen.usr_miso_dbitlen = miso_len ? (miso_len - 1) : 0;
SPIFLASH.addr = (addr_len > 0)? (address << (32-addr_len)) : 0;
#else
SPIFLASH.miso_dlen.usr_miso_bit_len = miso_len ? (miso_len - 1) : 0;
SPIFLASH.addr = address;
#endif
//dummy phase
if (miso_len > 0) {
uint32_t total_dummy = dummy_len + g_rom_spiflash_dummy_len_plus[1];
SPIFLASH.user.usr_dummy = total_dummy > 0;
SPIFLASH.user1.usr_dummy_cyclelen = total_dummy - 1;
} else {
SPIFLASH.user.usr_dummy = 0;
SPIFLASH.user1.usr_dummy_cyclelen = 0;
}
//output data
SPIFLASH.user.usr_mosi = mosi_len > 0;
#if CONFIG_IDF_TARGET_ESP32
SPIFLASH.mosi_dlen.usr_mosi_dbitlen = mosi_len ? (mosi_len - 1) : 0;
@ -593,24 +614,52 @@ uint32_t IRAM_ATTR bootloader_execute_flash_command(uint8_t command, uint32_t mo
SPIFLASH.mosi_dlen.usr_mosi_bit_len = mosi_len ? (mosi_len - 1) : 0;
#endif
SPIFLASH.data_buf[0] = mosi_data;
if (g_rom_spiflash_dummy_len_plus[1]) {
/* When flash pins are mapped via GPIO matrix, need a dummy cycle before reading via MISO */
if (miso_len > 0) {
SPIFLASH.user.usr_dummy = 1;
SPIFLASH.user1.usr_dummy_cyclelen = g_rom_spiflash_dummy_len_plus[1] - 1;
} else {
SPIFLASH.user.usr_dummy = 0;
SPIFLASH.user1.usr_dummy_cyclelen = 0;
}
}
//input data
SPIFLASH.user.usr_miso = miso_len > 0;
#if CONFIG_IDF_TARGET_ESP32
SPIFLASH.miso_dlen.usr_miso_dbitlen = miso_len ? (miso_len - 1) : 0;
#else
SPIFLASH.miso_dlen.usr_miso_bit_len = miso_len ? (miso_len - 1) : 0;
#endif
SPIFLASH.cmd.usr = 1;
while (SPIFLASH.cmd.usr != 0) {
}
SPIFLASH.ctrl.val = old_ctrl_reg;
return SPIFLASH.data_buf[0];
SPIFLASH.user.val = old_user_reg;
SPIFLASH.user1.val = old_user1_reg;
uint32_t ret = SPIFLASH.data_buf[0];
if (miso_len < 32) {
//set unused bits to 0
ret &= ~(UINT32_MAX << miso_len);
}
return ret;
}
uint32_t IRAM_ATTR bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len)
{
const uint8_t addr_len = 0;
const uint8_t address = 0;
const uint8_t dummy_len = 0;
return bootloader_flash_execute_command_common(command, addr_len, address,
dummy_len, mosi_len, mosi_data, miso_len);
}
// cmd(0x5A) + 24bit address + 8 cycles dummy
uint32_t IRAM_ATTR bootloader_flash_read_sfdp(uint32_t sfdp_addr, unsigned int miso_byte_num)
{
assert(miso_byte_num <= 4);
const uint8_t command = CMD_RDSFDP;
const uint8_t addr_len = 24;
const uint8_t dummy_len = 8;
const uint8_t mosi_len = 0;
const uint32_t mosi_data = 0;
const uint8_t miso_len = miso_byte_num * 8;
return bootloader_flash_execute_command_common(command, addr_len, sfdp_addr,
dummy_len, mosi_len, mosi_data, miso_len);
}
void bootloader_enable_wp(void)
@ -618,6 +667,13 @@ void bootloader_enable_wp(void)
bootloader_execute_flash_command(CMD_WRDI, 0, 0, 0); /* Exit OTP mode */
}
uint32_t IRAM_ATTR bootloader_read_flash_id(void)
{
uint32_t id = bootloader_execute_flash_command(CMD_RDID, 0, 0, 24);
id = ((id & 0xff) << 16) | ((id >> 16) & 0xff) | (id & 0xff00);
return id;
}
#if SOC_CACHE_SUPPORT_WRAP
esp_err_t bootloader_flash_wrap_set(spi_flash_wrap_mode_t mode)
{
@ -649,3 +705,104 @@ esp_err_t bootloader_flash_wrap_set(spi_flash_wrap_mode_t mode)
return ESP_OK;
}
#endif //SOC_CACHE_SUPPORT_WRAP
/*******************************************************************************
* XMC startup flow
******************************************************************************/
#define XMC_SUPPORT CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT
#define XMC_VENDOR_ID 0x20
#if BOOTLOADER_BUILD
#define BOOTLOADER_FLASH_LOG(level, ...) ESP_LOG##level(TAG, ##__VA_ARGS__)
#else
static DRAM_ATTR char bootloader_flash_tag[] = "bootloader_flash";
#define BOOTLOADER_FLASH_LOG(level, ...) ESP_DRAM_LOG##level(bootloader_flash_tag, ##__VA_ARGS__)
#endif
#if XMC_SUPPORT
//strictly check the model
static IRAM_ATTR bool is_xmc_chip_strict(uint32_t rdid)
{
uint32_t vendor_id = BYTESHIFT(rdid, 2);
uint32_t mfid = BYTESHIFT(rdid, 1);
uint32_t cpid = BYTESHIFT(rdid, 0);
if (vendor_id != XMC_VENDOR_ID) {
return false;
}
bool matched = false;
if (mfid == 0x40) {
if (cpid >= 0x13 && cpid <= 0x20) {
matched = true;
}
} else if (mfid == 0x41) {
if (cpid >= 0x17 && cpid <= 0x20) {
matched = true;
}
} else if (mfid == 0x50) {
if (cpid >= 0x15 && cpid <= 0x16) {
matched = true;
}
}
return matched;
}
esp_err_t IRAM_ATTR bootloader_flash_xmc_startup(void)
{
// If the RDID value is a valid XMC one, may skip the flow
const bool fast_check = true;
if (fast_check && is_xmc_chip_strict(g_rom_flashchip.device_id)) {
BOOTLOADER_FLASH_LOG(D, "XMC chip detected by RDID (%08X), skip.", g_rom_flashchip.device_id);
return ESP_OK;
}
// Check the Manufacturer ID in SFDP registers (JEDEC standard). If not XMC chip, no need to run the flow
const int sfdp_mfid_addr = 0x10;
uint8_t mf_id = (bootloader_flash_read_sfdp(sfdp_mfid_addr, 1) & 0xff);
if (mf_id != XMC_VENDOR_ID) {
BOOTLOADER_FLASH_LOG(D, "non-XMC chip detected by SFDP Read (%02X), skip.", mf_id);
return ESP_OK;
}
BOOTLOADER_FLASH_LOG(I, "XM25QHxxC startup flow");
// Enter DPD
bootloader_execute_flash_command(0xB9, 0, 0, 0);
// Enter UDPD
bootloader_execute_flash_command(0x79, 0, 0, 0);
// Exit UDPD
bootloader_execute_flash_command(0xFF, 0, 0, 0);
// Delay tXUDPD
esp_rom_delay_us(2000);
// Release Power-down
bootloader_execute_flash_command(0xAB, 0, 0, 0);
esp_rom_delay_us(20);
// Read flash ID and check again
g_rom_flashchip.device_id = bootloader_read_flash_id();
if (!is_xmc_chip_strict(g_rom_flashchip.device_id)) {
BOOTLOADER_FLASH_LOG(E, "XMC flash startup fail");
return ESP_FAIL;
}
return ESP_OK;
}
#else
//only compare the vendor id
static IRAM_ATTR bool is_xmc_chip(uint32_t rdid)
{
uint32_t vendor_id = (rdid >> 16) & 0xFF;
return (vendor_id == XMC_VENDOR_ID);
}
esp_err_t IRAM_ATTR bootloader_flash_xmc_startup(void)
{
if (is_xmc_chip(g_rom_flashchip.device_id)) {
BOOTLOADER_FLASH_LOG(E, "XMC chip detected (%08X) while support disabled.", g_rom_flashchip.device_id);
return ESP_FAIL;
}
return ESP_OK;
}
#endif //XMC_SUPPORT

View File

@ -33,18 +33,18 @@ void bootloader_flash_update_id()
void IRAM_ATTR bootloader_flash_cs_timing_config()
{
// SPI0/1 share the cs_hold / cs_setup, cd_hold_time / cd_setup_time, cs_hold_delay registers for FLASH/PSRAM, so we only need to set SPI0 related registers here
//SPI0/1 share the cs_hold / cs_setup, cd_hold_time / cd_setup_time, cs_hold_delay registers for FLASH, so we only need to set SPI0 related registers here
#if CONFIG_ESPTOOLPY_OCT_FLASH
SET_PERI_REG_MASK(SPI_MEM_USER_REG(0), SPI_MEM_CS_HOLD_M | SPI_MEM_CS_SETUP_M);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_HOLD_TIME_V, FLASH_CS_HOLD_TIME, SPI_MEM_CS_HOLD_TIME_S);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_SETUP_TIME_V, FLASH_CS_SETUP_TIME, SPI_MEM_CS_SETUP_TIME_S);
SET_PERI_REG_MASK(SPI_MEM_SPI_SMEM_AC_REG(0), SPI_MEM_SPI_SMEM_CS_HOLD_M | SPI_MEM_SPI_SMEM_CS_SETUP_M);
SET_PERI_REG_BITS(SPI_MEM_SPI_SMEM_AC_REG(0), SPI_MEM_SPI_SMEM_CS_HOLD_TIME_V, FLASH_CS_HOLD_TIME, SPI_MEM_SPI_SMEM_CS_HOLD_TIME_S);
SET_PERI_REG_BITS(SPI_MEM_SPI_SMEM_AC_REG(0), SPI_MEM_SPI_SMEM_CS_SETUP_TIME_V, FLASH_CS_SETUP_TIME, SPI_MEM_SPI_SMEM_CS_SETUP_TIME_S);
// cs high time
//CS high time
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_HOLD_DELAY_V, FLASH_CS_HOLD_DELAY, SPI_MEM_CS_HOLD_DELAY_S);
SET_PERI_REG_BITS(SPI_MEM_SPI_SMEM_AC_REG(0), SPI_MEM_SPI_SMEM_CS_HOLD_DELAY_V, FLASH_CS_HOLD_DELAY, SPI_MEM_SPI_SMEM_CS_HOLD_DELAY_S);
#else
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_HOLD_TIME_V, 0, SPI_MEM_CS_HOLD_TIME_S);
SET_PERI_REG_BITS(SPI_MEM_CTRL2_REG(0), SPI_MEM_CS_SETUP_TIME_V, 0, SPI_MEM_CS_SETUP_TIME_S);
SET_PERI_REG_MASK(SPI_MEM_USER_REG(0), SPI_MEM_CS_HOLD_M | SPI_MEM_CS_SETUP_M);
#endif
}
void IRAM_ATTR bootloader_flash_clock_config(const esp_image_header_t *pfhdr)

View File

@ -76,6 +76,7 @@
#include "bootloader_utility.h"
#include "bootloader_sha.h"
#include "bootloader_console.h"
#include "bootloader_soc.h"
#include "esp_efuse.h"
static const char *TAG = "boot";
@ -636,6 +637,12 @@ static void load_image(const esp_image_metadata_t *image_data)
ESP_LOGI(TAG, "Disabling RNG early entropy source...");
bootloader_random_disable();
/* Disable glitch reset after all the security checks are completed.
* Glitch detection can be falsely triggered by EMI interference (high RF TX power, etc)
* and to avoid such false alarms, disable it.
*/
bootloader_ana_clock_glitch_reset_config(false);
// copy loaded segments to RAM, set up caches for mapped segments, and start application
unpack_load_app(image_data);
}

View File

@ -387,6 +387,11 @@ esp_err_t bootloader_init(void)
bootloader_print_banner();
// update flash ID
bootloader_flash_update_id();
// Check and run XMC startup flow
if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) {
ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!");
goto err;
}
// read bootloader header
if ((ret = bootloader_read_bootloader_header()) != ESP_OK) {
goto err;

View File

@ -0,0 +1,21 @@
/*
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
void bootloader_ana_super_wdt_reset_config(bool enable)
{
(void)enable;
}
void bootloader_ana_bod_reset_config(bool enable)
{
(void)enable;
}
void bootloader_ana_clock_glitch_reset_config(bool enable)
{
(void)enable;
}

View File

@ -36,6 +36,7 @@
#include "regi2c_ctrl.h"
#include "bootloader_console.h"
#include "bootloader_flash_priv.h"
#include "bootloader_soc.h"
#include "esp_efuse.h"
static const char *TAG = "boot.esp32c3";
@ -263,7 +264,7 @@ static inline void bootloader_hardware_init(void)
}
}
static inline void bootloader_glitch_reset_disable(void)
static inline void bootloader_ana_reset_config(void)
{
/*
For origin chip & ECO1: only support swt reset;
@ -271,10 +272,27 @@ static inline void bootloader_glitch_reset_disable(void)
For ECO3: fix clock glitch reset bug, support all reset, include: swt & brownout & clock glitch reset.
*/
uint8_t chip_version = bootloader_common_get_chip_revision();
if (chip_version < 2) {
REG_SET_FIELD(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_SEL, RTC_CNTL_FIB_SUPER_WDT_RST);
} else if (chip_version == 2) {
REG_SET_FIELD(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_SEL, RTC_CNTL_FIB_SUPER_WDT_RST | RTC_CNTL_FIB_BOR_RST);
switch (chip_version) {
case 0:
case 1:
//Enable WDT reset. Disable BOR and GLITCH reset
bootloader_ana_super_wdt_reset_config(true);
bootloader_ana_bod_reset_config(false);
bootloader_ana_clock_glitch_reset_config(false);
break;
case 2:
//Enable WDT and BOR reset. Disable GLITCH reset
bootloader_ana_super_wdt_reset_config(true);
bootloader_ana_bod_reset_config(true);
bootloader_ana_clock_glitch_reset_config(false);
break;
case 3:
default:
//Enable WDT, BOR, and GLITCH reset
bootloader_ana_super_wdt_reset_config(true);
bootloader_ana_bod_reset_config(true);
bootloader_ana_clock_glitch_reset_config(true);
break;
}
}
@ -283,7 +301,7 @@ esp_err_t bootloader_init(void)
esp_err_t ret = ESP_OK;
bootloader_hardware_init();
bootloader_glitch_reset_disable();
bootloader_ana_reset_config();
bootloader_super_wdt_auto_feed();
// protect memory region
bootloader_init_mem();
@ -309,6 +327,11 @@ esp_err_t bootloader_init(void)
bootloader_print_banner();
// update flash ID
bootloader_flash_update_id();
// Check and run XMC startup flow
if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) {
ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!");
goto err;
}
// read bootloader header
if ((ret = bootloader_read_bootloader_header()) != ESP_OK) {
goto err;

View File

@ -0,0 +1,41 @@
/*
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
void bootloader_ana_super_wdt_reset_config(bool enable)
{
REG_CLR_BIT(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_SUPER_WDT_RST);
if (enable) {
REG_SET_BIT(RTC_CNTL_SWD_CONF_REG, RTC_CNTL_SWD_BYPASS_RST);
} else {
REG_CLR_BIT(RTC_CNTL_SWD_CONF_REG, RTC_CNTL_SWD_BYPASS_RST);
}
}
void bootloader_ana_bod_reset_config(bool enable)
{
REG_CLR_BIT(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_BOR_RST);
if (enable) {
REG_SET_BIT(RTC_CNTL_BROWN_OUT_REG, RTC_CNTL_BROWN_OUT_ANA_RST_EN);
} else {
REG_CLR_BIT(RTC_CNTL_BROWN_OUT_REG, RTC_CNTL_BROWN_OUT_ANA_RST_EN);
}
}
void bootloader_ana_clock_glitch_reset_config(bool enable)
{
REG_CLR_BIT(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_GLITCH_RST);
if (enable) {
REG_SET_BIT(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_GLITCH_RST_EN);
} else {
REG_CLR_BIT(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_GLITCH_RST_EN);
}
}

View File

@ -40,5 +40,11 @@ esp_err_t esp_flash_encryption_enable_secure_features(void)
esp_efuse_write_field_bit(ESP_EFUSE_DIS_LEGACY_SPI_BOOT);
#if defined(CONFIG_SECURE_BOOT_V2_ENABLED) && !defined(CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS)
// This bit is set when enabling Secure Boot V2, but we can't enable it until this later point in the first boot
// otherwise the Flash Encryption key cannot be read protected
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
#endif
return ESP_OK;
}

View File

@ -40,5 +40,20 @@ esp_err_t esp_secure_boot_enable_secure_features(void)
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
#ifndef CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS
bool rd_dis_now = true;
#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
/* If flash encryption is not enabled yet then don't read-disable efuses yet, do it later in the boot
when Flash Encryption is being enabled */
rd_dis_now = esp_flash_encryption_enabled();
#endif
if (rd_dis_now) {
ESP_LOGI(TAG, "Prevent read disabling of additional efuses...");
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
}
#else
ESP_LOGW(TAG, "Allowing read disabling of additional efuses - SECURITY COMPROMISED");
#endif
return ESP_OK;
}

View File

@ -36,6 +36,7 @@
#include "regi2c_ctrl.h"
#include "bootloader_console.h"
#include "bootloader_flash_priv.h"
#include "bootloader_soc.h"
static const char *TAG = "boot.esp32h2";
@ -254,27 +255,15 @@ static void bootloader_super_wdt_auto_feed(void)
static inline void bootloader_hardware_init(void)
{
// This check is always included in the bootloader so it can
// print the minimum revision error message later in the boot
if (bootloader_common_get_chip_revision() < 3) {
REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_FORCE_XPD_IPH, 1);
REGI2C_WRITE_MASK(I2C_BIAS, I2C_BIAS_DREG_1P1_PVT, 12);
}
}
static inline void bootloader_glitch_reset_disable(void)
static inline void bootloader_ana_reset_config(void)
{
/*
For origin chip & ECO1: only support swt reset;
For ECO2: fix brownout reset bug, support swt & brownout reset;
For ECO3: fix clock glitch reset bug, support all reset, include: swt & brownout & clock glitch reset.
*/
uint8_t chip_version = bootloader_common_get_chip_revision();
if (chip_version < 2) {
REG_SET_FIELD(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_SEL, RTC_CNTL_FIB_SUPER_WDT_RST);
} else if (chip_version == 2) {
REG_SET_FIELD(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_SEL, RTC_CNTL_FIB_SUPER_WDT_RST | RTC_CNTL_FIB_BOR_RST);
}
//Enable WDT, BOR, and GLITCH reset
bootloader_ana_super_wdt_reset_config(true);
bootloader_ana_bod_reset_config(true);
bootloader_ana_clock_glitch_reset_config(true);
}
esp_err_t bootloader_init(void)
@ -282,7 +271,7 @@ esp_err_t bootloader_init(void)
esp_err_t ret = ESP_OK;
bootloader_hardware_init();
bootloader_glitch_reset_disable();
bootloader_ana_reset_config();
bootloader_super_wdt_auto_feed();
// protect memory region
bootloader_init_mem();
@ -301,6 +290,11 @@ esp_err_t bootloader_init(void)
bootloader_print_banner();
// update flash ID
bootloader_flash_update_id();
// Check and run XMC startup flow
if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) {
ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!");
goto err;
}
// read bootloader header
if ((ret = bootloader_read_bootloader_header()) != ESP_OK) {
goto err;

View File

@ -0,0 +1,41 @@
/*
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
void bootloader_ana_super_wdt_reset_config(bool enable)
{
REG_CLR_BIT(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_SUPER_WDT_RST);
if (enable) {
REG_SET_BIT(RTC_CNTL_SWD_CONF_REG, RTC_CNTL_SWD_BYPASS_RST);
} else {
REG_CLR_BIT(RTC_CNTL_SWD_CONF_REG, RTC_CNTL_SWD_BYPASS_RST);
}
}
void bootloader_ana_bod_reset_config(bool enable)
{
REG_CLR_BIT(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_BOR_RST);
if (enable) {
REG_SET_BIT(RTC_CNTL_BROWN_OUT_REG, RTC_CNTL_BROWN_OUT_ANA_RST_EN);
} else {
REG_CLR_BIT(RTC_CNTL_BROWN_OUT_REG, RTC_CNTL_BROWN_OUT_ANA_RST_EN);
}
}
void bootloader_ana_clock_glitch_reset_config(bool enable)
{
REG_CLR_BIT(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_GLITCH_RST);
if (enable) {
REG_SET_BIT(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_GLITCH_RST_EN);
} else {
REG_CLR_BIT(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_GLITCH_RST_EN);
}
}

View File

@ -307,6 +307,11 @@ esp_err_t bootloader_init(void)
bootloader_print_banner();
// update flash ID
bootloader_flash_update_id();
// Check and run XMC startup flow
if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) {
ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!");
goto err;
}
// read bootloader header
if ((ret = bootloader_read_bootloader_header()) != ESP_OK) {
goto err;

View File

@ -0,0 +1,21 @@
/*
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
void bootloader_ana_super_wdt_reset_config(bool enable)
{
(void)enable;
}
void bootloader_ana_bod_reset_config(bool enable)
{
(void)enable;
}
void bootloader_ana_clock_glitch_reset_config(bool enable)
{
(void)enable;
}

View File

@ -41,5 +41,11 @@ esp_err_t esp_flash_encryption_enable_secure_features(void)
esp_efuse_write_field_bit(ESP_EFUSE_DIS_BOOT_REMAP);
esp_efuse_write_field_bit(ESP_EFUSE_DIS_LEGACY_SPI_BOOT);
#if defined(CONFIG_SECURE_BOOT_V2_ENABLED) && !defined(CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS)
// This bit is set when enabling Secure Boot V2, but we can't enable it until this later point in the first boot
// otherwise the Flash Encryption key cannot be read protected
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
#endif
return ESP_OK;
}

View File

@ -40,5 +40,20 @@ esp_err_t esp_secure_boot_enable_secure_features(void)
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
#ifndef CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS
bool rd_dis_now = true;
#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
/* If flash encryption is not enabled yet then don't read-disable efuses yet, do it later in the boot
when Flash Encryption is being enabled */
rd_dis_now = esp_flash_encryption_enabled();
#endif
if (rd_dis_now) {
ESP_LOGI(TAG, "Prevent read disabling of additional efuses...");
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
}
#else
ESP_LOGW(TAG, "Allowing read disabling of additional efuses - SECURITY COMPROMISED");
#endif
return ESP_OK;
}

View File

@ -34,6 +34,7 @@
#include "bootloader_mem.h"
#include "bootloader_console.h"
#include "bootloader_flash_priv.h"
#include "bootloader_soc.h"
#include "esp_efuse.h"
@ -139,7 +140,7 @@ static void print_flash_info(const esp_image_header_t *bootloader_hdr)
str = "20MHz";
break;
}
ESP_LOGI(TAG, "SPI Speed : %s", str);
ESP_LOGI(TAG, "Boot SPI Speed : %s", str);
/* SPI mode could have been set to QIO during boot already,
so test the SPI registers not the flash header */
@ -296,9 +297,18 @@ static void bootloader_super_wdt_auto_feed(void)
REG_WRITE(RTC_CNTL_SWD_WPROTECT_REG, 0);
}
static inline void bootloader_ana_reset_config(void)
{
//Enable WDT, BOR, and GLITCH reset
bootloader_ana_super_wdt_reset_config(true);
bootloader_ana_bod_reset_config(true);
bootloader_ana_clock_glitch_reset_config(true);
}
esp_err_t bootloader_init(void)
{
esp_err_t ret = ESP_OK;
bootloader_ana_reset_config();
bootloader_super_wdt_auto_feed();
// protect memory region
bootloader_init_mem();
@ -328,6 +338,11 @@ esp_err_t bootloader_init(void)
bootloader_print_banner();
// update flash ID
bootloader_flash_update_id();
// Check and run XMC startup flow
if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) {
ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!");
goto err;
}
// read bootloader header
if ((ret = bootloader_read_bootloader_header()) != ESP_OK) {
goto err;

View File

@ -0,0 +1,41 @@
/*
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
void bootloader_ana_super_wdt_reset_config(bool enable)
{
REG_CLR_BIT(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_SUPER_WDT_RST);
if (enable) {
REG_SET_BIT(RTC_CNTL_SWD_CONF_REG, RTC_CNTL_SWD_BYPASS_RST);
} else {
REG_CLR_BIT(RTC_CNTL_SWD_CONF_REG, RTC_CNTL_SWD_BYPASS_RST);
}
}
void bootloader_ana_bod_reset_config(bool enable)
{
REG_CLR_BIT(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_BOR_RST);
if (enable) {
REG_SET_BIT(RTC_CNTL_BROWN_OUT_REG, RTC_CNTL_BROWN_OUT_ANA_RST_EN);
} else {
REG_CLR_BIT(RTC_CNTL_BROWN_OUT_REG, RTC_CNTL_BROWN_OUT_ANA_RST_EN);
}
}
void bootloader_ana_clock_glitch_reset_config(bool enable)
{
REG_CLR_BIT(RTC_CNTL_FIB_SEL_REG, RTC_CNTL_FIB_GLITCH_RST);
if (enable) {
REG_SET_BIT(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_GLITCH_RST_EN);
} else {
REG_CLR_BIT(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_GLITCH_RST_EN);
}
}

View File

@ -41,5 +41,11 @@ esp_err_t esp_flash_encryption_enable_secure_features(void)
esp_efuse_write_field_bit(ESP_EFUSE_DIS_LEGACY_SPI_BOOT);
#if defined(CONFIG_SECURE_BOOT_V2_ENABLED) && !defined(CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS)
// This bit is set when enabling Secure Boot V2, but we can't enable it until this later point in the first boot
// otherwise the Flash Encryption key cannot be read protected
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
#endif
return ESP_OK;
}

View File

@ -27,6 +27,7 @@ esp_err_t esp_secure_boot_enable_secure_features(void)
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
ESP_LOGI(TAG, "Disable hardware & software JTAG...");
esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
esp_efuse_write_field_bit(ESP_EFUSE_HARD_DIS_JTAG);
esp_efuse_write_field_cnt(ESP_EFUSE_SOFT_DIS_JTAG, ESP_EFUSE_SOFT_DIS_JTAG[0]->bit_count);
#else
@ -39,5 +40,20 @@ esp_err_t esp_secure_boot_enable_secure_features(void)
esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
#ifndef CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS
bool rd_dis_now = true;
#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
/* If flash encryption is not enabled yet then don't read-disable efuses yet, do it later in the boot
when Flash Encryption is being enabled */
rd_dis_now = esp_flash_encryption_enabled();
#endif
if (rd_dis_now) {
ESP_LOGI(TAG, "Prevent read disabling of additional efuses...");
esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS);
}
#else
ESP_LOGW(TAG, "Allowing read disabling of additional efuses - SECURITY COMPROMISED");
#endif
return ESP_OK;
}

View File

@ -105,14 +105,6 @@ static esp_err_t enable_qio_mode(read_status_fn_t read_status_fn,
The command passed here is always the on-the-wire command given to the SPI flash unit.
*/
/* dummy_len_plus values defined in ROM for SPI flash configuration */
uint32_t bootloader_read_flash_id(void)
{
uint32_t id = bootloader_execute_flash_command(CMD_RDID, 0, 0, 24);
id = ((id & 0xff) << 16) | ((id >> 16) & 0xff) | (id & 0xff00);
return id;
}
void bootloader_enable_qio_mode(void)
{
uint32_t raw_flash_id;

View File

@ -1,6 +1,8 @@
if(CONFIG_BT_ENABLED)
if(CONFIG_IDF_TARGET_ESP32)
set(srcs "controller/esp32/bt.c")
set(srcs "controller/esp32/bt.c"
"controller/esp32/hli_api.c"
"controller/esp32/hli_vectors.S")
elseif(CONFIG_IDF_TARGET_ESP32C3)
set(srcs "controller/esp32c3/bt.c")
elseif(CONFIG_IDF_TARGET_ESP32S3)
@ -55,6 +57,7 @@ if(CONFIG_BT_ENABLED)
host/bluedroid/bta/gatt/include
host/bluedroid/bta/hf_ag/include
host/bluedroid/bta/hf_client/include
host/bluedroid/bta/hd/include
host/bluedroid/bta/hh/include
host/bluedroid/bta/jv/include
host/bluedroid/bta/sdp/include
@ -66,12 +69,12 @@ if(CONFIG_BT_ENABLED)
host/bluedroid/external/sbc/plc/include
host/bluedroid/btc/profile/esp/include
host/bluedroid/btc/profile/std/a2dp/include
host/bluedroid/btc/profile/std/hid/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/hid/include
host/bluedroid/stack/l2cap/include
host/bluedroid/stack/sdp/include
host/bluedroid/stack/smp/include
@ -94,6 +97,8 @@ if(CONFIG_BT_ENABLED)
"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_hidd_api.c"
"host/bluedroid/api/esp_hidh_api.c"
"host/bluedroid/api/esp_hf_ag_api.c"
"host/bluedroid/api/esp_hf_client_api.c"
"host/bluedroid/api/esp_spp_api.c"
@ -128,6 +133,9 @@ if(CONFIG_BT_ENABLED)
"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/hd/bta_hd_api.c"
"host/bluedroid/bta/hd/bta_hd_act.c"
"host/bluedroid/bta/hd/bta_hd_main.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"
@ -184,8 +192,9 @@ if(CONFIG_BT_ENABLED)
"host/bluedroid/btc/profile/std/hf_ag/btc_hf_ag.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/hid/hidh_api.c"
"host/bluedroid/btc/profile/std/hid/hidh_conn.c"
"host/bluedroid/btc/profile/std/hid/btc_hd.c"
"host/bluedroid/btc/profile/std/hid/btc_hh.c"
"host/bluedroid/btc/profile/std/hid/bta_hh_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"
@ -251,6 +260,10 @@ if(CONFIG_BT_ENABLED)
"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/hid/hidd_api.c"
"host/bluedroid/stack/hid/hidd_conn.c"
"host/bluedroid/stack/hid/hidh_api.c"
"host/bluedroid/stack/hid/hidh_conn.c"
"host/bluedroid/stack/btm/btm_acl.c"
"host/bluedroid/stack/btm/btm_ble.c"
"host/bluedroid/stack/btm/btm_ble_addr.c"
@ -597,6 +610,8 @@ if(CONFIG_BT_ENABLED)
if(CONFIG_IDF_TARGET_ESP32)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-L${CMAKE_CURRENT_LIST_DIR}/controller/lib_esp32/esp32")
target_link_libraries(${COMPONENT_LIB} PUBLIC btdm_app)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u ld_include_hli_vectors_bt")
elseif(CONFIG_IDF_TARGET_ESP32C3)
target_link_libraries(${COMPONENT_LIB} INTERFACE
"-L${CMAKE_CURRENT_LIST_DIR}/controller/lib_esp32c3_family/esp32c3")

View File

@ -7,42 +7,16 @@ menu "Bluetooth"
help
Select this option to enable Bluetooth and show the submenu with Bluetooth configuration choices.
config BT_CTRL_ESP32
bool
depends on BT_ENABLED && IDF_TARGET_ESP32
default y
config BT_CTRL_ESP32C3
bool
depends on BT_ENABLED && IDF_TARGET_ESP32C3
default y
config BT_CTRL_ESP32S3
bool
depends on BT_ENABLED && IDF_TARGET_ESP32S3
default y
config BT_SOC_SUPPORT_5_0
bool
depends on BT_ENABLED && (IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3)
default y if BT_ENABLED && (IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3)
default n
menu "Bluetooth controller(ESP32 Dual Mode Bluetooth)"
visible if BT_CTRL_ESP32
menu "Bluetooth controller"
depends on BT_ENABLED
source "$IDF_PATH/components/bt/controller/esp32/Kconfig.in"
endmenu
menu "Bluetooth controller(ESP32C3 Bluetooth Low Energy)"
visible if BT_CTRL_ESP32C3
source "$IDF_PATH/components/bt/controller/esp32c3/Kconfig.in"
endmenu
menu "Bluetooth controller(ESP32S3 Bluetooth Low Energy)"
visible if BT_CTRL_ESP32S3
source "$IDF_PATH/components/bt/controller/esp32s3/Kconfig.in"
source "$IDF_PATH/components/bt/controller/$IDF_TARGET/Kconfig.in"
endmenu
choice BT_HOST
@ -73,12 +47,12 @@ menu "Bluetooth"
endchoice
menu "Bluedroid Options"
visible if BT_BLUEDROID_ENABLED
depends on BT_BLUEDROID_ENABLED
source "$IDF_PATH/components/bt/host/bluedroid/Kconfig.in"
endmenu
menu "NimBLE Options"
visible if BT_NIMBLE_ENABLED
depends on BT_NIMBLE_ENABLED
source "$IDF_PATH/components/bt/host/nimble/Kconfig.in"
endmenu

View File

@ -53,6 +53,12 @@
#if BTC_HF_CLIENT_INCLUDED
#include "btc_hf_client.h"
#endif /* #if BTC_HF_CLIENT_INCLUDED */
#if BTC_HD_INCLUDED == TRUE
#include "btc_hd.h"
#endif /* BTC_HD_INCLUDED */
#if BTC_HH_INCLUDED == TRUE
#include "btc_hh.h"
#endif /* BTC_HH_INCLUDED */
#endif /* #if CLASSIC_BT_INCLUDED */
#endif
@ -120,6 +126,12 @@ static const btc_func_t profile_tab[BTC_PID_NUM] = {
#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 */
#if BTC_HD_INCLUDED
[BTC_PID_HD] = {btc_hd_call_handler, btc_hd_cb_handler },
#endif
#if BTC_HH_INCLUDED
[BTC_PID_HH] = {btc_hh_call_handler, btc_hh_cb_handler },
#endif
#endif /* #if CLASSIC_BT_INCLUDED */
#endif
#if CONFIG_BLE_MESH

View File

@ -65,6 +65,8 @@ typedef enum {
BTC_PID_AVRC_CT,
BTC_PID_AVRC_TG,
BTC_PID_SPP,
BTC_PID_HD,
BTC_PID_HH,
#if (BTC_HF_INCLUDED == TRUE)
BTC_PID_HF,
#endif /* BTC_HF_INCLUDED */
@ -99,6 +101,10 @@ typedef struct {
typedef void (* btc_arg_deep_copy_t)(btc_msg_t *msg, void *dst, void *src);
#ifdef __cplusplus
extern "C" {
#endif
/**
* transfer an message to another module in the different task.
* @param msg message
@ -124,4 +130,8 @@ void btc_deinit(void);
bool btc_check_queue_is_congest(void);
int get_btc_work_queue_size(void);
#ifdef __cplusplus
}
#endif
#endif /* __BTC_TASK_H__ */

View File

@ -318,3 +318,14 @@ uint32_t osi_time_get_os_boottime_ms(void)
{
return (uint32_t)(esp_timer_get_time() / 1000);
}
bool osi_alarm_is_active(osi_alarm_t *alarm)
{
assert(alarm != NULL);
if (alarm->alarm_hdl != NULL) {
return esp_timer_is_active(alarm->alarm_hdl);
}
return false;
}

View File

@ -77,4 +77,8 @@ period_ms_t osi_alarm_get_remaining_ms(const osi_alarm_t *alarm);
uint32_t osi_time_get_os_boottime_ms(void);
// This function returns whether the given |alarm| is active or not.
// Return true if active, false otherwise.
bool osi_alarm_is_active(osi_alarm_t *alarm);
#endif /*_ALARM_H_*/

View File

@ -10,6 +10,7 @@ COMPONENT_ADD_INCLUDEDIRS := include
LIBS := btdm_app
COMPONENT_ADD_LDFLAGS := -lbt -L $(COMPONENT_PATH)/controller/lib_esp32/esp32 \
-u ld_include_hli_vectors_bt \
$(addprefix -l,$(LIBS))
# re-link program if BT binary libs change
@ -46,6 +47,7 @@ COMPONENT_PRIV_INCLUDEDIRS += host/bluedroid/bta/include \
host/bluedroid/bta/hf_client/include \
host/bluedroid/bta/dm/include \
host/bluedroid/bta/gatt/include \
host/bluedroid/bta/hd/include \
host/bluedroid/bta/hh/include \
host/bluedroid/bta/jv/include \
host/bluedroid/bta/sdp/include \
@ -70,6 +72,7 @@ COMPONENT_PRIV_INCLUDEDIRS += host/bluedroid/bta/include \
host/bluedroid/stack/gap/include \
host/bluedroid/stack/gatt/include \
host/bluedroid/stack/hcic/include \
host/bluedroid/stack/hid/include \
host/bluedroid/stack/l2cap/include \
host/bluedroid/stack/sdp/include \
host/bluedroid/stack/smp/include \
@ -86,6 +89,7 @@ COMPONENT_ADD_INCLUDEDIRS += host/bluedroid/api/include/api \
COMPONENT_SRCDIRS += host/bluedroid/bta/dm \
host/bluedroid/bta/gatt \
host/bluedroid/bta/hd \
host/bluedroid/bta/hh \
host/bluedroid/bta/sdp \
host/bluedroid/bta/av \
@ -118,6 +122,7 @@ COMPONENT_SRCDIRS += host/bluedroid/bta/dm \
host/bluedroid/stack/gap \
host/bluedroid/stack/gatt \
host/bluedroid/stack/hcic \
host/bluedroid/stack/hid \
host/bluedroid/stack/include \
host/bluedroid/stack/l2cap \
host/bluedroid/stack/sdp \

View File

@ -1,6 +1,5 @@
choice BTDM_CTRL_MODE
prompt "Bluetooth controller mode (BR/EDR/BLE/DUALMODE)"
depends on BT_CTRL_ESP32
help
Specify the bluetooth controller mode (BR/EDR, BLE or dual mode).
@ -152,7 +151,7 @@ config BTDM_CTRL_BR_EDR_MAX_SYNC_CONN_EFF
choice BTDM_CTRL_PINNED_TO_CORE_CHOICE
prompt "The cpu core which bluetooth controller run"
depends on BT_CTRL_ESP32 && !FREERTOS_UNICORE
depends on !FREERTOS_UNICORE
help
Specify the cpu core to run bluetooth controller.
Can not specify no-affinity.
@ -172,7 +171,6 @@ config BTDM_CTRL_PINNED_TO_CORE
choice BTDM_CTRL_HCI_MODE_CHOICE
prompt "HCI mode"
depends on BT_CTRL_ESP32
help
Speicify HCI mode as VHCI or UART(H4)
@ -210,11 +208,8 @@ menu "HCI UART(H4) Options"
endmenu
menu "MODEM SLEEP Options"
visible if BT_CTRL_ESP32
config BTDM_CTRL_MODEM_SLEEP
bool "Bluetooth modem sleep"
depends on BT_CTRL_ESP32
default y
help
Enable/disable bluetooth controller low power mode.
@ -415,3 +410,16 @@ config BTDM_BLE_ADV_REPORT_DISCARD_THRSHOLD
of ADV packets lost in the controller reaches this threshold. It is better to set a larger value.
If you set `BTDM_BLE_ADV_REPORT_DISCARD_THRSHOLD` to a small value or printf every adv lost event, it
may cause adv packets lost more.
config BTDM_RESERVE_DRAM
hex
default 0xdb5c if BT_ENABLED
default 0
config BTDM_CTRL_HLI
bool "High level interrupt"
depends on BT_ENABLED
default y
help
Using Level 4 interrupt for Bluetooth.

View File

@ -40,6 +40,7 @@
#include "driver/periph_ctrl.h"
#include "soc/rtc.h"
#include "soc/soc_memory_layout.h"
#include "soc/dport_reg.h"
#include "esp32/clk.h"
#include "esp_coexist_internal.h"
#if !CONFIG_FREERTOS_UNICORE
@ -47,6 +48,7 @@
#endif
#include "esp_rom_sys.h"
#include "hli_api.h"
#if CONFIG_BT_ENABLED
@ -54,6 +56,7 @@
************************************************************************
*/
#define UNUSED(x) (void)(x)
#define BTDM_LOG_TAG "BTDM_INIT"
#define BTDM_INIT_PERIOD (5000) /* ms */
@ -92,12 +95,12 @@ do{\
} while(0)
#define OSI_FUNCS_TIME_BLOCKING 0xffffffff
#define OSI_VERSION 0x00010002
#define OSI_VERSION 0x00010003
#define OSI_MAGIC_VALUE 0xFADEBEAD
/* SPIRAM Configuration */
#if CONFIG_SPIRAM_USE_MALLOC
#define BTDM_MAX_QUEUE_NUM (5)
#define BTDM_MAX_QUEUE_NUM (6)
#endif
/* Types definition
@ -184,6 +187,10 @@ struct osi_funcs_t {
void *(* _coex_schm_curr_phase_get)(void);
int (* _coex_wifi_channel_get)(uint8_t *primary, uint8_t *secondary);
int (* _coex_register_wifi_channel_change_callback)(void *cb);
xt_handler (*_set_isr_l3)(int n, xt_handler f, void *arg);
void (*_interrupt_l3_disable)(void);
void (*_interrupt_l3_restore)(void);
void *(* _customer_queue_create)(uint32_t queue_len, uint32_t item_size);
uint32_t _magic;
};
@ -268,8 +275,13 @@ extern uint32_t _btdm_data_end;
static bool btdm_queue_generic_register(const btdm_queue_item_t *queue);
static bool btdm_queue_generic_deregister(btdm_queue_item_t *queue);
#endif /* CONFIG_SPIRAM_USE_MALLOC */
static void IRAM_ATTR interrupt_disable(void);
static void IRAM_ATTR interrupt_restore(void);
#if CONFIG_BTDM_CTRL_HLI
static xt_handler set_isr_hlevel_wrapper(int n, xt_handler f, void *arg);
static void IRAM_ATTR interrupt_hlevel_disable(void);
static void IRAM_ATTR interrupt_hlevel_restore(void);
#endif /* CONFIG_BTDM_CTRL_HLI */
static void IRAM_ATTR task_yield(void);
static void IRAM_ATTR task_yield_from_isr(void);
static void *semphr_create_wrapper(uint32_t max, uint32_t init);
static void semphr_delete_wrapper(void *semphr);
@ -281,12 +293,21 @@ static void *mutex_create_wrapper(void);
static void mutex_delete_wrapper(void *mutex);
static int32_t mutex_lock_wrapper(void *mutex);
static int32_t mutex_unlock_wrapper(void *mutex);
#if CONFIG_BTDM_CTRL_HLI
static void *queue_create_hlevel_wrapper(uint32_t queue_len, uint32_t item_size);
static void queue_delete_hlevel_wrapper(void *queue);
static int32_t IRAM_ATTR queue_send_hlevel_wrapper(void *queue, void *item, uint32_t block_time_ms);
static int32_t IRAM_ATTR queue_send_from_isr_hlevel_wrapper(void *queue, void *item, void *hptw);
static int32_t IRAM_ATTR queue_recv_hlevel_wrapper(void *queue, void *item, uint32_t block_time_ms);
static int32_t IRAM_ATTR queue_recv_from_isr_hlevel_wrapper(void *queue, void *item, void *hptw);
#else
static void *queue_create_wrapper(uint32_t queue_len, uint32_t item_size);
static void queue_delete_wrapper(void *queue);
static int32_t queue_send_wrapper(void *queue, void *item, uint32_t block_time_ms);
static int32_t IRAM_ATTR queue_send_wrapper(void *queue, void *item, uint32_t block_time_ms);
static int32_t IRAM_ATTR queue_send_from_isr_wrapper(void *queue, void *item, void *hptw);
static int32_t queue_recv_wrapper(void *queue, void *item, uint32_t block_time_ms);
static int32_t IRAM_ATTR queue_recv_wrapper(void *queue, void *item, uint32_t block_time_ms);
static int32_t IRAM_ATTR queue_recv_from_isr_wrapper(void *queue, void *item, void *hptw);
#endif /* CONFIG_BTDM_CTRL_HLI */
static int32_t task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id);
static void task_delete_wrapper(void *task_handle);
static bool IRAM_ATTR is_in_isr_wrapper(void);
@ -317,17 +338,30 @@ static uint8_t coex_schm_curr_period_get_wrapper(void);
static void * coex_schm_curr_phase_get_wrapper(void);
static int coex_wifi_channel_get_wrapper(uint8_t *primary, uint8_t *secondary);
static int coex_register_wifi_channel_change_callback_wrapper(void *cb);
#if CONFIG_BTDM_CTRL_HLI
static void *customer_queue_create_hlevel_wrapper(uint32_t queue_len, uint32_t item_size);
#endif /* CONFIG_BTDM_CTRL_HLI */
static void IRAM_ATTR interrupt_l3_disable(void);
static void IRAM_ATTR interrupt_l3_restore(void);
/* Local variable definition
***************************************************************************
*/
/* OSI funcs */
static const struct osi_funcs_t osi_funcs_ro = {
._version = OSI_VERSION,
#if CONFIG_BTDM_CTRL_HLI
._set_isr = set_isr_hlevel_wrapper,
._ints_on = xt_ints_on,
._interrupt_disable = interrupt_hlevel_disable,
._interrupt_restore = interrupt_hlevel_restore,
#else
._set_isr = xt_set_interrupt_handler,
._ints_on = xt_ints_on,
._interrupt_disable = interrupt_disable,
._interrupt_restore = interrupt_restore,
._task_yield = vPortYield,
._interrupt_disable = interrupt_l3_disable,
._interrupt_restore = interrupt_l3_restore,
#endif /* CONFIG_BTDM_CTRL_HLI */
._task_yield = task_yield,
._task_yield_from_isr = task_yield_from_isr,
._semphr_create = semphr_create_wrapper,
._semphr_delete = semphr_delete_wrapper,
@ -339,12 +373,21 @@ static const struct osi_funcs_t osi_funcs_ro = {
._mutex_delete = mutex_delete_wrapper,
._mutex_lock = mutex_lock_wrapper,
._mutex_unlock = mutex_unlock_wrapper,
#if CONFIG_BTDM_CTRL_HLI
._queue_create = queue_create_hlevel_wrapper,
._queue_delete = queue_delete_hlevel_wrapper,
._queue_send = queue_send_hlevel_wrapper,
._queue_send_from_isr = queue_send_from_isr_hlevel_wrapper,
._queue_recv = queue_recv_hlevel_wrapper,
._queue_recv_from_isr = queue_recv_from_isr_hlevel_wrapper,
#else
._queue_create = queue_create_wrapper,
._queue_delete = queue_delete_wrapper,
._queue_send = queue_send_wrapper,
._queue_send_from_isr = queue_send_from_isr_wrapper,
._queue_recv = queue_recv_wrapper,
._queue_recv_from_isr = queue_recv_from_isr_wrapper,
#endif /* CONFIG_BTDM_CTRL_HLI */
._task_create = task_create_wrapper,
._task_delete = task_delete_wrapper,
._is_in_isr = is_in_isr_wrapper,
@ -378,6 +421,14 @@ static const struct osi_funcs_t osi_funcs_ro = {
._coex_schm_curr_phase_get = coex_schm_curr_phase_get_wrapper,
._coex_wifi_channel_get = coex_wifi_channel_get_wrapper,
._coex_register_wifi_channel_change_callback = coex_register_wifi_channel_change_callback_wrapper,
._set_isr_l3 = xt_set_interrupt_handler,
._interrupt_l3_disable = interrupt_l3_disable,
._interrupt_l3_restore = interrupt_l3_restore,
#if CONFIG_BTDM_CTRL_HLI
._customer_queue_create = customer_queue_create_hlevel_wrapper,
#else
._customer_queue_create = NULL,
#endif /* CONFIG_BTDM_CTRL_HLI */
._magic = OSI_MAGIC_VALUE,
};
@ -494,7 +545,48 @@ static bool btdm_queue_generic_deregister(btdm_queue_item_t *queue)
#endif /* CONFIG_SPIRAM_USE_MALLOC */
static void IRAM_ATTR interrupt_disable(void)
#if CONFIG_BTDM_CTRL_HLI
struct interrupt_hlevel_cb{
uint32_t status;
uint8_t nested;
};
static DRAM_ATTR struct interrupt_hlevel_cb hli_cb = {
.status = 0,
.nested = 0,
};
static xt_handler set_isr_hlevel_wrapper(int mask, xt_handler f, void *arg)
{
esp_err_t err = hli_intr_register((intr_handler_t) f, arg, DPORT_PRO_INTR_STATUS_0_REG, mask);
if (err == ESP_OK) {
return f;
} else {
return 0;
}
}
static void IRAM_ATTR interrupt_hlevel_disable(void)
{
assert(xPortGetCoreID() == CONFIG_BTDM_CTRL_PINNED_TO_CORE);
assert(hli_cb.nested != ~0);
uint32_t status = hli_intr_disable();
if (hli_cb.nested++ == 0) {
hli_cb.status = status;
}
}
static void IRAM_ATTR interrupt_hlevel_restore(void)
{
assert(xPortGetCoreID() == CONFIG_BTDM_CTRL_PINNED_TO_CORE);
assert(hli_cb.nested > 0);
if (--hli_cb.nested == 0) {
hli_intr_restore(hli_cb.status);
}
}
#endif /* CONFIG_BTDM_CTRL_HLI */
static void IRAM_ATTR interrupt_l3_disable(void)
{
if (xPortInIsrContext()) {
portENTER_CRITICAL_ISR(&global_int_mux);
@ -503,7 +595,7 @@ static void IRAM_ATTR interrupt_disable(void)
}
}
static void IRAM_ATTR interrupt_restore(void)
static void IRAM_ATTR interrupt_l3_restore(void)
{
if (xPortInIsrContext()) {
portEXIT_CRITICAL_ISR(&global_int_mux);
@ -512,6 +604,12 @@ static void IRAM_ATTR interrupt_restore(void)
}
}
static void IRAM_ATTR task_yield(void)
{
vPortYield();
}
static void IRAM_ATTR task_yield_from_isr(void)
{
portYIELD_FROM_ISR();
@ -519,18 +617,19 @@ static void IRAM_ATTR task_yield_from_isr(void)
static void *semphr_create_wrapper(uint32_t max, uint32_t init)
{
void *handle = NULL;
#if !CONFIG_SPIRAM_USE_MALLOC
return (void *)xSemaphoreCreateCounting(max, init);
handle = (void *)xSemaphoreCreateCounting(max, init);
#else
StaticQueue_t *queue_buffer = NULL;
QueueHandle_t handle = NULL;
queue_buffer = heap_caps_malloc(sizeof(StaticQueue_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
if (!queue_buffer) {
goto error;
}
handle = xSemaphoreCreateCountingStatic(max, init, queue_buffer);
handle = (void *)xSemaphoreCreateCountingStatic(max, init, queue_buffer);
if (!handle) {
goto error;
}
@ -544,8 +643,19 @@ static void *semphr_create_wrapper(uint32_t max, uint32_t init)
if (!btdm_queue_generic_register(&item)) {
goto error;
}
return handle;
#endif
#if CONFIG_BTDM_CTRL_HLI
SemaphoreHandle_t downstream_semaphore = handle;
assert(downstream_semaphore);
hli_queue_handle_t s_semaphore = hli_semaphore_create(max, downstream_semaphore);
assert(downstream_semaphore);
return s_semaphore;
#else
return handle;
#endif /* CONFIG_BTDM_CTRL_HLI */
#if CONFIG_SPIRAM_USE_MALLOC
error:
if (handle) {
vSemaphoreDelete(handle);
@ -560,11 +670,22 @@ static void *semphr_create_wrapper(uint32_t max, uint32_t init)
static void semphr_delete_wrapper(void *semphr)
{
void *handle = NULL;
#if CONFIG_BTDM_CTRL_HLI
if (((hli_queue_handle_t)semphr)->downstream != NULL) {
handle = ((hli_queue_handle_t)semphr)->downstream;
}
hli_queue_delete(semphr);
#else
handle = semphr;
#endif /* CONFIG_BTDM_CTRL_HLI */
#if !CONFIG_SPIRAM_USE_MALLOC
vSemaphoreDelete(semphr);
vSemaphoreDelete(handle);
#else
btdm_queue_item_t item = {
.handle = semphr,
.handle = handle,
.storage = NULL,
.buffer = NULL,
};
@ -573,33 +694,55 @@ static void semphr_delete_wrapper(void *semphr)
vSemaphoreDelete(item.handle);
free(item.buffer);
}
return;
#endif
}
static int32_t IRAM_ATTR semphr_take_from_isr_wrapper(void *semphr, void *hptw)
{
#if CONFIG_BTDM_CTRL_HLI
return (int32_t)xSemaphoreTakeFromISR(((hli_queue_handle_t)semphr)->downstream, hptw);
#else
return (int32_t)xSemaphoreTakeFromISR(semphr, hptw);
#endif /* CONFIG_BTDM_CTRL_HLI */
}
static int32_t IRAM_ATTR semphr_give_from_isr_wrapper(void *semphr, void *hptw)
{
#if CONFIG_BTDM_CTRL_HLI
UNUSED(hptw);
assert(xPortGetCoreID() == CONFIG_BTDM_CTRL_PINNED_TO_CORE);
return hli_semaphore_give(semphr);
#else
return (int32_t)xSemaphoreGiveFromISR(semphr, hptw);
#endif /* CONFIG_BTDM_CTRL_HLI */
}
static int32_t semphr_take_wrapper(void *semphr, uint32_t block_time_ms)
{
bool ret;
#if CONFIG_BTDM_CTRL_HLI
if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) {
return (int32_t)xSemaphoreTake(semphr, portMAX_DELAY);
ret = xSemaphoreTake(((hli_queue_handle_t)semphr)->downstream, portMAX_DELAY);
} else {
return (int32_t)xSemaphoreTake(semphr, block_time_ms / portTICK_PERIOD_MS);
ret = xSemaphoreTake(((hli_queue_handle_t)semphr)->downstream, block_time_ms / portTICK_PERIOD_MS);
}
#else
if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) {
ret = xSemaphoreTake(semphr, portMAX_DELAY);
} else {
ret = xSemaphoreTake(semphr, block_time_ms / portTICK_PERIOD_MS);
}
#endif /* CONFIG_BTDM_CTRL_HLI */
return (int32_t)ret;
}
static int32_t semphr_give_wrapper(void *semphr)
{
#if CONFIG_BTDM_CTRL_HLI
return (int32_t)xSemaphoreGive(((hli_queue_handle_t)semphr)->downstream);
#else
return (int32_t)xSemaphoreGive(semphr);
#endif /* CONFIG_BTDM_CTRL_HLI */
}
static void *mutex_create_wrapper(void)
@ -745,6 +888,79 @@ static void queue_delete_wrapper(void *queue)
#endif
}
#if CONFIG_BTDM_CTRL_HLI
static void *queue_create_hlevel_wrapper(uint32_t queue_len, uint32_t item_size)
{
QueueHandle_t downstream_queue = queue_create_wrapper(queue_len, item_size);
assert(downstream_queue);
hli_queue_handle_t queue = hli_queue_create(queue_len, item_size, downstream_queue);
assert(queue);
return queue;
}
static void *customer_queue_create_hlevel_wrapper(uint32_t queue_len, uint32_t item_size)
{
QueueHandle_t downstream_queue = queue_create_wrapper(queue_len, item_size);
assert(downstream_queue);
hli_queue_handle_t queue = hli_customer_queue_create(queue_len, item_size, downstream_queue);
assert(queue);
return queue;
}
static void queue_delete_hlevel_wrapper(void *queue)
{
if (((hli_queue_handle_t)queue)->downstream != NULL) {
queue_delete_wrapper(((hli_queue_handle_t)queue)->downstream);
}
hli_queue_delete(queue);
}
static int32_t queue_send_hlevel_wrapper(void *queue, void *item, uint32_t block_time_ms)
{
if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) {
return (int32_t)xQueueSend(((hli_queue_handle_t)queue)->downstream, item, portMAX_DELAY);
} else {
return (int32_t)xQueueSend(((hli_queue_handle_t)queue)->downstream, item, block_time_ms / portTICK_PERIOD_MS);
}
}
/**
* Queue send from isr
* @param queue The queue which will send to
* @param item The message which will be send
* @param hptw need do task yield or not
* @return send success or not
* There is an issue here: When the queue is full, it may reture true but it send fail to the queue, sometimes.
* But in Bluetooth controller's isr, We don't care about the return value.
* It only required tp send success when the queue is empty all the time.
* So, this function meets the requirement.
*/
static int32_t IRAM_ATTR queue_send_from_isr_hlevel_wrapper(void *queue, void *item, void *hptw)
{
UNUSED(hptw);
assert(xPortGetCoreID() == CONFIG_BTDM_CTRL_PINNED_TO_CORE);
return hli_queue_put(queue, item);
}
static int32_t queue_recv_hlevel_wrapper(void *queue, void *item, uint32_t block_time_ms)
{
bool ret;
if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) {
ret = xQueueReceive(((hli_queue_handle_t)queue)->downstream, item, portMAX_DELAY);
} else {
ret = xQueueReceive(((hli_queue_handle_t)queue)->downstream, item, block_time_ms / portTICK_PERIOD_MS);
}
return (int32_t)ret;
}
static int32_t IRAM_ATTR queue_recv_from_isr_hlevel_wrapper(void *queue, void *item, void *hptw)
{
return (int32_t)xQueueReceiveFromISR(((hli_queue_handle_t)queue)->downstream, item, hptw);
}
#else
static int32_t queue_send_wrapper(void *queue, void *item, uint32_t block_time_ms)
{
if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) {
@ -760,18 +976,23 @@ static int32_t IRAM_ATTR queue_send_from_isr_wrapper(void *queue, void *item, vo
}
static int32_t queue_recv_wrapper(void *queue, void *item, uint32_t block_time_ms)
{
{
bool ret;
if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) {
return (int32_t)xQueueReceive(queue, item, portMAX_DELAY);
ret = xQueueReceive(queue, item, portMAX_DELAY);
} else {
return (int32_t)xQueueReceive(queue, item, block_time_ms / portTICK_PERIOD_MS);
ret = xQueueReceive(queue, item, block_time_ms / portTICK_PERIOD_MS);
}
}
return (int32_t)ret;
}
static int32_t IRAM_ATTR queue_recv_from_isr_wrapper(void *queue, void *item, void *hptw)
{
return (int32_t)xQueueReceiveFromISR(queue, item, hptw);
}
#endif /* CONFIG_BTDM_CTRL_HLI */
static int32_t task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id)
{
@ -1317,11 +1538,35 @@ esp_err_t esp_bt_mem_release(esp_bt_mode_t mode)
return ESP_OK;
}
#if CONFIG_BTDM_CTRL_HLI
static void hli_queue_setup_cb(void* arg)
{
hli_queue_setup();
}
static void hli_queue_setup_pinned_to_core(int core_id)
{
#if CONFIG_FREERTOS_UNICORE
hli_queue_setup_cb(NULL);
#else /* CONFIG_FREERTOS_UNICORE */
if (xPortGetCoreID() == core_id) {
hli_queue_setup_cb(NULL);
} else {
esp_ipc_call(core_id, hli_queue_setup_cb, NULL);
}
#endif /* !CONFIG_FREERTOS_UNICORE */
}
#endif /* CONFIG_BTDM_CTRL_HLI */
esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
{
esp_err_t err;
uint32_t btdm_cfg_mask = 0;
#if CONFIG_BTDM_CTRL_HLI
hli_queue_setup_pinned_to_core(CONFIG_BTDM_CTRL_PINNED_TO_CORE);
#endif /* CONFIG_BTDM_CTRL_HLI */
//if all the bt available memory was already released, cannot initialize bluetooth controller
if (btdm_dram_available_region[0].mode == ESP_BT_MODE_IDLE) {
return ESP_ERR_INVALID_STATE;
@ -1394,7 +1639,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
#if CONFIG_BTDM_CTRL_LPCLK_SEL_EXT_32K_XTAL
// check whether or not EXT_CRYS is working
if (rtc_clk_slow_freq_get() == RTC_SLOW_FREQ_32K_XTAL) {
btdm_lpclk_sel = BTDM_LPCLK_SEL_XTAL32K; // set default value
btdm_lpclk_sel = BTDM_LPCLK_SEL_XTAL32K; // External 32kHz XTAL
#ifdef CONFIG_PM_ENABLE
s_btdm_allow_light_sleep = true;
#endif
@ -1736,4 +1981,15 @@ esp_err_t esp_ble_scan_dupilcate_list_flush(void)
return ESP_OK;
}
/**
* This function re-write controller's function,
* As coredump can not show paramerters in function which is in a .a file.
*
* After coredump fixing this issue, just delete this function.
*/
void IRAM_ATTR r_assert(const char *condition, int param0, int param1, const char *file, int line)
{
__asm__ __volatile__("ill\n");
}
#endif /* CONFIG_BT_ENABLED */

View File

@ -0,0 +1,306 @@
// Copyright 2015-2021 Espressif Systems (Shanghai) CO LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include "esp_log.h"
#include "esp_heap_caps.h"
#include "xtensa/core-macros.h"
#include "soc/dport_reg.h"
#include "hli_api.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#if CONFIG_BTDM_CTRL_HLI
#define HLI_MAX_HANDLERS 4
typedef struct {
intr_handler_t handler;
void* arg;
uint32_t intr_reg;
uint32_t intr_mask;
} hli_handler_info_t;
typedef struct {
#define CUSTOMER_TYPE_REQUEST (0)
#define CUSTOMER_TYPE_RELEASE (1)
struct {
uint32_t cb_type;
union {
int (* request)(uint32_t, uint32_t, uint32_t);
int (* release)(uint32_t);
} cb;
} customer_cb;
uint32_t arg0, arg1, arg2;
} customer_swisr_t;
static void IRAM_ATTR customer_swisr_handle(customer_swisr_t *cus_swisr)
{
if (cus_swisr->customer_cb.cb_type == CUSTOMER_TYPE_REQUEST) {
if (cus_swisr->customer_cb.cb.request != NULL) {
cus_swisr->customer_cb.cb.request(cus_swisr->arg0, cus_swisr->arg1, cus_swisr->arg2);
}
} else if(cus_swisr->customer_cb.cb_type == CUSTOMER_TYPE_RELEASE) {
if (cus_swisr->customer_cb.cb.release != NULL) {
cus_swisr->customer_cb.cb.release(cus_swisr->arg0);
}
}
}
static DRAM_ATTR hli_handler_info_t s_hli_handlers[HLI_MAX_HANDLERS];
esp_err_t hli_intr_register(intr_handler_t handler, void* arg, uint32_t intr_reg, uint32_t intr_mask)
{
for (hli_handler_info_t* hip = s_hli_handlers;
hip < s_hli_handlers + HLI_MAX_HANDLERS;
++hip) {
if (hip->handler == NULL) {
hip->arg = arg;
hip->intr_reg = intr_reg;
hip->intr_mask = intr_mask;
hip->handler = handler; /* set last, indicates the entry as valid */
return ESP_OK;
}
}
return ESP_ERR_NO_MEM;
}
void IRAM_ATTR hli_c_handler(void)
{
bool handled = false;
/* Iterate over registered interrupt handlers,
* and check if the expected mask is present in the interrupt status register.
*/
for (hli_handler_info_t* hip = s_hli_handlers;
hip < s_hli_handlers + HLI_MAX_HANDLERS;
++hip) {
if (hip->handler == NULL) {
continue;
}
uint32_t reg = hip->intr_reg;
uint32_t val;
if (reg == 0) { /* special case for CPU internal interrupts */
val = XTHAL_GET_INTERRUPT();
} else {
/* "reg" might not be in DPORT, but this will work in any case */
val = DPORT_REG_READ(reg);
}
if ((val & hip->intr_mask) != 0) {
handled = true;
(*hip->handler)(hip->arg);
}
}
if (!handled) {
/* no handler found, it is OK in this case. */
}
}
uint32_t IRAM_ATTR hli_intr_disable(void)
{
/* disable level 4 and below */
return XTOS_SET_INTLEVEL(XCHAL_DEBUGLEVEL - 2);
}
void IRAM_ATTR hli_intr_restore(uint32_t state)
{
XTOS_RESTORE_JUST_INTLEVEL(state);
}
#define HLI_META_QUEUE_SIZE 16
#define HLI_QUEUE_MAX_ELEM_SIZE 32
#define HLI_QUEUE_SW_INT_NUM 29
#define HLI_QUEUE_FLAG_SEMAPHORE BIT(0)
#define HLI_QUEUE_FLAG_CUSTOMER BIT(1)
static DRAM_ATTR struct hli_queue_t *s_meta_queue_ptr = NULL;
static intr_handle_t ret_handle;
static inline char* IRAM_ATTR wrap_ptr(hli_queue_handle_t queue, char *ptr)
{
return (ptr == queue->bufend) ? queue->buf : ptr;
}
static inline bool IRAM_ATTR queue_empty(hli_queue_handle_t queue)
{
return queue->begin == queue->end;
}
static inline bool IRAM_ATTR queue_full(hli_queue_handle_t queue)
{
return wrap_ptr(queue, queue->end + queue->elem_size) == queue->begin;
}
static void IRAM_ATTR queue_isr_handler(void* arg)
{
int do_yield = pdFALSE;
XTHAL_SET_INTCLEAR(BIT(HLI_QUEUE_SW_INT_NUM));
hli_queue_handle_t queue;
while (hli_queue_get(s_meta_queue_ptr, &queue)) {
static DRAM_ATTR char scratch[HLI_QUEUE_MAX_ELEM_SIZE];
while (hli_queue_get(queue, scratch)) {
int res = pdPASS;
if ((queue->flags & HLI_QUEUE_FLAG_CUSTOMER) != 0) {
customer_swisr_handle((customer_swisr_t *)scratch);
} else if ((queue->flags & HLI_QUEUE_FLAG_SEMAPHORE) != 0) {
res = xSemaphoreGiveFromISR((SemaphoreHandle_t) queue->downstream, &do_yield);
} else {
res = xQueueSendFromISR(queue->downstream, scratch, &do_yield);
}
if (res == pdFAIL) {
/* Failed to send to downstream queue, it is OK in this case. */
}
}
}
if (do_yield) {
portYIELD_FROM_ISR();
}
}
/* Notify the level 3 handler that an element is added to the given hli queue.
* Do this by placing the queue handle onto s_meta_queue, and raising a SW interrupt.
*
* This function must be called with HL interrupts disabled!
*/
static void IRAM_ATTR queue_signal(hli_queue_handle_t queue)
{
/* See if the queue is already in s_meta_queue, before adding */
bool found = false;
const hli_queue_handle_t *end = (hli_queue_handle_t*) s_meta_queue_ptr->end;
hli_queue_handle_t *item = (hli_queue_handle_t*) s_meta_queue_ptr->begin;
for (;item != end; item = (hli_queue_handle_t*) wrap_ptr(s_meta_queue_ptr, (char*) (item + 1))) {
if (*item == queue) {
found = true;
break;
}
}
if (!found) {
bool res = hli_queue_put(s_meta_queue_ptr, &queue);
if (!res) {
esp_rom_printf(DRAM_STR("Fatal error in queue_signal: s_meta_queue full\n"));
abort();
}
XTHAL_SET_INTSET(BIT(HLI_QUEUE_SW_INT_NUM));
}
}
static void queue_init(hli_queue_handle_t queue, size_t buf_size, size_t elem_size, QueueHandle_t downstream)
{
queue->elem_size = elem_size;
queue->begin = queue->buf;
queue->end = queue->buf;
queue->bufend = queue->buf + buf_size;
queue->downstream = downstream;
queue->flags = 0;
}
void hli_queue_setup(void)
{
if (s_meta_queue_ptr == NULL) {
s_meta_queue_ptr = hli_queue_create(HLI_META_QUEUE_SIZE, sizeof(void*), NULL);
ESP_ERROR_CHECK(esp_intr_alloc(ETS_INTERNAL_SW1_INTR_SOURCE, ESP_INTR_FLAG_IRAM, queue_isr_handler, NULL, &ret_handle));
xt_ints_on(BIT(HLI_QUEUE_SW_INT_NUM));
}
}
void hli_queue_shutdown(void)
{
if (s_meta_queue_ptr != NULL) {
hli_queue_delete(s_meta_queue_ptr);
s_meta_queue_ptr = NULL;
esp_intr_free(ret_handle);
xt_ints_off(BIT(HLI_QUEUE_SW_INT_NUM));
}
}
hli_queue_handle_t hli_queue_create(size_t nelem, size_t elem_size, QueueHandle_t downstream)
{
const size_t buf_elem = nelem + 1;
if (elem_size > HLI_QUEUE_MAX_ELEM_SIZE) {
return NULL;
}
size_t buf_size = buf_elem * elem_size;
hli_queue_handle_t res = (hli_queue_handle_t) heap_caps_malloc(sizeof(struct hli_queue_t) + buf_size,
MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
if (res == NULL) {
return NULL;
}
queue_init(res, buf_size, elem_size, downstream);
return res;
}
hli_queue_handle_t hli_customer_queue_create(size_t nelem, size_t elem_size, QueueHandle_t downstream)
{
hli_queue_handle_t res = hli_queue_create(nelem, elem_size, (QueueHandle_t) downstream);
if (res == NULL) {
return NULL;
}
res->flags |= HLI_QUEUE_FLAG_CUSTOMER;
return res;
}
hli_queue_handle_t hli_semaphore_create(size_t max_count, SemaphoreHandle_t downstream)
{
const size_t elem_size = 1;
hli_queue_handle_t res = hli_queue_create(max_count, elem_size, (QueueHandle_t) downstream);
if (res == NULL) {
return NULL;
}
res->flags |= HLI_QUEUE_FLAG_SEMAPHORE;
return res;
}
void hli_queue_delete(hli_queue_handle_t queue)
{
free(queue);
}
bool IRAM_ATTR hli_queue_get(hli_queue_handle_t queue, void* out)
{
uint32_t int_state = hli_intr_disable();
bool res = false;
if (!queue_empty(queue)) {
memcpy(out, queue->begin, queue->elem_size);
queue->begin = wrap_ptr(queue, queue->begin + queue->elem_size);
res = true;
}
hli_intr_restore(int_state);
return res;
}
bool IRAM_ATTR hli_queue_put(hli_queue_handle_t queue, const void* data)
{
uint32_t int_state = hli_intr_disable();
bool res = false;
bool was_empty = queue_empty(queue);
if (!queue_full(queue)) {
memcpy(queue->end, data, queue->elem_size);
queue->end = wrap_ptr(queue, queue->end + queue->elem_size);
if (was_empty && queue != s_meta_queue_ptr) {
queue_signal(queue);
}
res = true;
}
hli_intr_restore(int_state);
return res;
}
bool IRAM_ATTR hli_semaphore_give(hli_queue_handle_t queue)
{
uint8_t data = 0;
return hli_queue_put(queue, &data);
}
#endif /* CONFIG_BTDM_CTRL_HLI */

View File

@ -0,0 +1,176 @@
// Copyright 2015-2021 Espressif Systems (Shanghai) CO LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT 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 <stdint.h>
#include "esp_err.h"
#include "esp_intr_alloc.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#ifdef __cplusplus
extern "C" {
#endif
#if CONFIG_BTDM_CTRL_HLI
/*** Queues ***/
struct hli_queue_t
{
size_t elem_size;
char* begin;
char* end;
const char* bufend;
QueueHandle_t downstream;
int flags;
char buf[0];
};
/**
* @brief Register a high level interrupt function
*
* @param handler interrupt handler function
* @param arg argument to pass to the interrupt handler
* @param intr_reg address of the peripheral register containing the interrupt status,
* or value 0 to get the status from CPU INTERRUPT register
* @param intr_mask mask of the interrupt, in the interrupt status register
* @return
* - ESP_OK on success
* - ESP_ERR_NO_MEM if too many handlers are registered
*/
esp_err_t hli_intr_register(intr_handler_t handler, void* arg, uint32_t intr_reg, uint32_t intr_mask);
/**
* @brief Mask all interrupts (including high level ones) on the current CPU
*
* @return uint32_t interrupt status, pass it to hli_intr_restore
*/
uint32_t hli_intr_disable(void);
/**
* @brief Re-enable interrupts
*
* @param state value returned by hli_intr_disable
*/
void hli_intr_restore(uint32_t state);
/**
* @brief Type of a hli queue
*/
typedef struct hli_queue_t* hli_queue_handle_t;
/**
* @brief Initialize hli_queue module. Must be called once before using hli queue APIs.
*/
void hli_queue_setup(void);
/**
* @brief Shutdown hli_queue module.
*/
void hli_queue_shutdown(void);
/**
* @brief Create a hli queue, wrapping a FreeRTOS queue
*
* This queue can be used from high level interrupts,
* but **ONLY ON THE CPU WHERE hli_queue_setup WAS CALLED**. Values sent to this
* queue are automatically forwarded to "downstream" FreeRTOS queue using a level 3
* software interrupt.
*
* @param nelem number of elements in the queue
* @param elem_size size of one element; must match element size of a downstream queue
* @param downstream FreeRTOS queue to send the values to
* @return hli_queue_handle_t handle of the created queue, or NULL on failure
*/
hli_queue_handle_t hli_queue_create(size_t nelem, size_t elem_size, QueueHandle_t downstream);
/**
* @brief Create a customer hli queue, wrapping a FreeRTOS queue
*
* This queue can be used from high level interrupts,
* but **ONLY ON THE CPU WHERE hli_queue_setup WAS CALLED**. Values sent to this
* queue are automatically forwarded to "downstream" FreeRTOS queue using a level 3
* software interrupt.
*
* @param nelem number of elements in the queue
* @param elem_size size of one element; must match element size of a downstream queue
* @param downstream FreeRTOS queue to send the values to
* @return hli_queue_handle_t handle of the created queue, or NULL on failure
*/
hli_queue_handle_t hli_customer_queue_create(size_t nelem, size_t elem_size, QueueHandle_t downstream);
/**
* @brief Create a hli queue, wrapping a FreeRTOS semaphore
*
* See notes on hli_queue_create.
*
* @param max_count maximum semaphore count
* @param downstream FreeRTOS semaphore to forward the calls to
* @return hli_queue_handle_t handle of the created queue, or NULL on failure
*/
hli_queue_handle_t hli_semaphore_create(size_t max_count, SemaphoreHandle_t downstream);
/**
* @brief Delete a hli queue
*
* Make sure noone is using the queue before deleting it.
*
* @param queue handle returned by hli_queue_create or hli_semaphore_create
*/
void hli_queue_delete(hli_queue_handle_t queue);
/**
* @brief Get one element from a hli queue
*
* Usually not used, values get sent to a downstream FreeRTOS queue automatically.
* However if downstream queue is NULL, this API can be used to get values from a hli queue.
*
* @param queue handle of a queue
* @param out pointer where to store the element
* @return true if the element was successfully read from the queue
*/
bool hli_queue_get(hli_queue_handle_t queue, void* out);
/**
* @brief Put one element into a hli queue
*
* This puts copies an element into the queue and raises a software interrupt (level 3).
* In the interrupt, the value is copied to a FreeRTOS "downstream" queue.
*
* Note that if the value does not fit into a downstream queue, no error is returned,
* and the value is lost.
*
* @param queue handle of a queue
* @param data pointer to the element to be sent
* @return true if data was placed into the hli queue successfully
*/
bool hli_queue_put(hli_queue_handle_t queue, const void* data);
/**
* @brief "Give" a semaphore wrapped by a hli queue
*
* @param queue handle returned by hli_semaphore_create
* @return true if the event was sent to a hli queue successfully
*/
bool hli_semaphore_give(hli_queue_handle_t queue);
#endif /* CONFIG_BTDM_CTRL_HLI */
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,275 @@
// Copyright 2015-2021 Espressif Systems (Shanghai) CO LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <xtensa/coreasm.h>
#include <xtensa/corebits.h>
#include <xtensa/config/system.h>
#include "freertos/xtensa_context.h"
#include "sdkconfig.h"
#include "soc/soc.h"
#if CONFIG_BTDM_CTRL_HLI
/* Interrupt stack size, for C code.
* TODO: reduce and make configurable.
*/
#define L4_INTR_STACK_SIZE 4096
/* Save area for the CPU state:
* - 64 words for the general purpose registers
* - 7 words for some of the special registers:
* - WINDOWBASE, WINDOWSTART only WINDOWSTART is truly needed
* - SAR, LBEG, LEND, LCOUNT since the C code might use these
* - EPC1 since the C code might cause window overflow exceptions
* This is not laid out as standard exception frame structure
* for simplicity of the save/restore code.
*/
#define REG_FILE_SIZE (64 * 4)
#define SPECREG_OFFSET REG_FILE_SIZE
#define SPECREG_SIZE (7 * 4)
#define REG_SAVE_AREA_SIZE (SPECREG_OFFSET + SPECREG_SIZE)
.data
_l4_intr_stack:
.space L4_INTR_STACK_SIZE
_l4_save_ctx:
.space REG_SAVE_AREA_SIZE
.section .iram1,"ax"
.global xt_highint4
.type xt_highint4,@function
.align 4
xt_highint4:
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
/*
Here, Timer2 is used to count a little time(50us).
The subsequent dram0 write operation is blocked due to live lock, which will
cause timer2 to timeout and trigger a level 5 interrupt.
*/
rsr.ccount a0
addmi a0, a0, (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ*50)
wsr a0, CCOMPARE2
/* Enable Timer 2 interrupt */
rsr a0, INTENABLE
extui a0, a0, 16, 1
bnez a0, 1f
movi a0, 0
xsr a0, INTENABLE /* disable all interrupts */
/* And a0 with (1 << 16) for Timer 2 interrupt mask */
addmi a0, a0, (1<<14)
addmi a0, a0, (1<<14)
addmi a0, a0, (1<<14)
addmi a0, a0, (1<<14)
wsr a0, INTENABLE /* Enable Timer 2 */
1:
#endif
movi a0, _l4_save_ctx
/* save 4 lower registers */
s32i a1, a0, 4
s32i a2, a0, 8
s32i a3, a0, 12
rsr a2, EXCSAVE_4 /* holds the value of a0 */
s32i a2, a0, 0
/* Save special registers */
addi a0, a0, SPECREG_OFFSET
rsr a2, WINDOWBASE
s32i a2, a0, 0
rsr a2, WINDOWSTART
s32i a2, a0, 4
rsr a2, SAR
s32i a2, a0, 8
rsr a2, LBEG
s32i a2, a0, 12
rsr a2, LEND
s32i a2, a0, 16
rsr a2, LCOUNT
s32i a2, a0, 20
rsr a2, EPC1
s32i a2, a0, 24
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
movi a0, 0
xsr a0, INTENABLE /* disable all interrupts */
movi a2, ~(1<<16)
and a0, a2, a0
wsr a0, INTENABLE
#endif
/* disable exception mode, window overflow */
movi a0, PS_INTLEVEL(5) | PS_EXCM
wsr a0, PS
rsync
/* Save the remaining physical registers.
* 4 registers are already saved, which leaves 60 registers to save.
* (FIXME: consider the case when the CPU is configured with physical 32 registers)
* These 60 registers are saved in 5 iterations, 12 registers at a time.
*/
movi a1, 5
movi a3, _l4_save_ctx + 4 * 4
/* This is repeated 5 times, each time the window is shifted by 12 registers.
* We come here with a1 = downcounter, a3 = save pointer, a2 and a0 unused.
*/
1:
s32i a4, a3, 0
s32i a5, a3, 4
s32i a6, a3, 8
s32i a7, a3, 12
s32i a8, a3, 16
s32i a9, a3, 20
s32i a10, a3, 24
s32i a11, a3, 28
s32i a12, a3, 32
s32i a13, a3, 36
s32i a14, a3, 40
s32i a15, a3, 44
/* We are about to rotate the window, so that a12-a15 will become the new a0-a3.
* Copy a0-a3 to a12-15 to still have access to these values.
* At the same time we can decrement the counter and adjust the save area pointer
*/
/* a0 is constant (_l4_save_ctx), no need to copy */
addi a13, a1, -1 /* copy and decrement the downcounter */
/* a2 is scratch so no need to copy */
addi a15, a3, 48 /* copy and adjust the save area pointer */
beqz a13, 2f /* have saved all registers ? */
rotw 3 /* rotate the window and go back */
j 1b
/* the loop is complete */
2:
rotw 4 /* this brings us back to the original window */
/* a0 still points to _l4_save_ctx */
/* Can clear WINDOWSTART now, all registers are saved */
rsr a2, WINDOWBASE
/* WINDOWSTART = (1 << WINDOWBASE) */
movi a3, 1
ssl a2
sll a3, a3
wsr a3, WINDOWSTART
_highint4_stack_switch:
movi a0, 0
movi sp, _l4_intr_stack + L4_INTR_STACK_SIZE - 16
s32e a0, sp, -12 /* For GDB: set null SP */
s32e a0, sp, -16 /* For GDB: set null PC */
movi a0, _highint4_stack_switch /* For GDB: cosmetics, for the frame where stack switch happened */
/* Set up PS for C, disable all interrupts except NMI and debug, and clear EXCM. */
movi a6, PS_INTLEVEL(4) | PS_UM | PS_WOE
wsr a6, PS
rsync
/* Call C handler */
mov a6, sp
call4 hli_c_handler
l32e sp, sp, -12 /* switch back to the original stack */
/* Done with C handler; re-enable exception mode, disabling window overflow */
movi a2, PS_INTLEVEL(5) | PS_EXCM /* TOCHECK */
wsr a2, PS
rsync
/* Restore the special registers.
* WINDOWSTART will be restored near the end.
*/
movi a0, _l4_save_ctx + SPECREG_OFFSET
l32i a2, a0, 8
wsr a2, SAR
l32i a2, a0, 12
wsr a2, LBEG
l32i a2, a0, 16
wsr a2, LEND
l32i a2, a0, 20
wsr a2, LCOUNT
l32i a2, a0, 24
wsr a2, EPC1
/* Restoring the physical registers.
* This is the reverse to the saving process above.
*/
/* Rotate back to the final window, then start loading 12 registers at a time,
* in 5 iterations.
* Again, a1 is the downcounter and a3 is the save area pointer.
* After each rotation, a1 and a3 are copied from a13 and a15.
* To simplify the loop, we put the initial values into a13 and a15.
*/
rotw -4
movi a15, _l4_save_ctx + 64 * 4 /* point to the end of the save area */
movi a13, 5
1:
/* Copy a1 and a3 from their previous location,
* at the same time decrementing and adjusting the save area pointer.
*/
addi a1, a13, -1
addi a3, a15, -48
/* Load 12 registers */
l32i a4, a3, 0
l32i a5, a3, 4
l32i a6, a3, 8
l32i a7, a3, 12
l32i a8, a3, 16
l32i a9, a3, 20
l32i a10, a3, 24
l32i a11, a3, 28 /* ensure PS and EPC written */
l32i a12, a3, 32
l32i a13, a3, 36
l32i a14, a3, 40
l32i a15, a3, 44
/* Done with the loop? */
beqz a1, 2f
/* If no, rotate the window and repeat */
rotw -3
j 1b
2:
/* Done with the loop. Only 4 registers (a0-a3 in the original window) remain
* to be restored. Also need to restore WINDOWSTART, since all the general
* registers are now in place.
*/
movi a0, _l4_save_ctx
l32i a2, a0, SPECREG_OFFSET + 4
wsr a2, WINDOWSTART
l32i a1, a0, 4
l32i a2, a0, 8
l32i a3, a0, 12
rsr a0, EXCSAVE_4 /* holds the value of a0 before the interrupt handler */
/* Return from the interrupt, restoring PS from EPS_4 */
rfi 4
#endif /* CONFIG_BTDM_CTRL_HLI */
/* 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_hli_vectors_bt
ld_include_hli_vectors_bt:

View File

@ -359,7 +359,8 @@ menu "MODEM SLEEP Options"
bool "Internal 150kHz RC oscillator"
depends on ESP32C3_RTC_CLK_SRC_INT_RC
help
Internal 150kHz RC oscillator.
Internal 150kHz RC oscillator. The accuracy of this clock is a lot larger than 500ppm which is required
in Bluetooth communication, so don't select this option in scenarios such as BLE connection state.
endchoice

View File

@ -992,7 +992,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
// configure and initialize resources
s_lp_cntl.enable = (cfg->sleep_mode == ESP_BT_SLEEP_MODE_1) ? 1 : 0;
s_lp_cntl.no_light_sleep = 0;
s_lp_cntl.no_light_sleep = 1;
if (s_lp_cntl.enable) {
#if (CONFIG_MAC_BB_PD)
@ -1029,31 +1029,29 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT;
btdm_lpcycle_us = 2 << (btdm_lpcycle_us_frac);
// // set default bluetooth sleep clock source
// s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL;
// set default bluetooth sleep clock source
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value
#if CONFIG_BT_CTRL_LPCLK_SEL_EXT_32K_XTAL
// check whether or not EXT_CRYS is working
if (rtc_clk_slow_freq_get() == RTC_SLOW_FREQ_32K_XTAL) {
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL32K; // set default value
// #ifdef CONFIG_PM_ENABLE
// s_btdm_allow_light_sleep = true;
// #endif
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL32K; // External 32 kHz XTAL
s_lp_cntl.no_light_sleep = 0;
} else {
ESP_LOGW(BTDM_LOG_TAG, "32.768kHz XTAL not detected, fall back to main XTAL as Bluetooth sleep clock\n"
"light sleep mode will not be able to apply when bluetooth is enabled");
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value
}
#elif (CONFIG_BT_CTRL_LPCLK_SEL_RTC_SLOW)
// check whether or not EXT_CRYS is working
if (rtc_clk_slow_freq_get() == RTC_SLOW_FREQ_RTC) {
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_RTC_SLOW; // set default value
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_RTC_SLOW; // Internal 150 kHz RC oscillator
ESP_LOGW(BTDM_LOG_TAG, "Internal 150kHz RC osciallator. The accuracy of this clock is a lot larger than 500ppm which is "
"required in Bluetooth communication, so don't select this option in scenarios such as BLE connection state.");
} else {
ESP_LOGW(BTDM_LOG_TAG, "Internal 150kHz RC oscillator not detected, fall back to main XTAL as Bluetooth sleep clock\n"
"light sleep mode will not be able to apply when bluetooth is enabled");
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value
ESP_LOGW(BT_LOG_TAG, "Internal 150kHz RC oscillator not detected.");
assert(0);
}
#else
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value
s_lp_cntl.no_light_sleep = 1;
#endif
bool select_src_ret __attribute__((unused));

View File

@ -373,10 +373,11 @@ menu "MODEM SLEEP Options"
modem sleep to be used with both DFS and light sleep.
config BT_CTRL_LPCLK_SEL_RTC_SLOW
bool "Internal 90kHz RC oscillator"
bool "Internal 150kHz RC oscillator"
depends on ESP32S3_RTC_CLK_SRC_INT_RC
help
Internal 90kHz RC oscillator.
Internal 150kHz RC oscillator. The accuracy of this clock is a lot larger than 500ppm which is required
in Bluetooth communication, so don't select this option in scenarios such as BLE connection state.
endchoice

View File

@ -972,7 +972,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
// configure and initialize resources
s_lp_cntl.enable = (cfg->sleep_mode == ESP_BT_SLEEP_MODE_1) ? 1 : 0;
s_lp_cntl.no_light_sleep = 0;
s_lp_cntl.no_light_sleep = 1;
if (s_lp_cntl.enable) {
#if (CONFIG_MAC_BB_PD)
@ -1009,31 +1009,29 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
btdm_lpcycle_us_frac = RTC_CLK_CAL_FRACT;
btdm_lpcycle_us = 2 << (btdm_lpcycle_us_frac);
// // set default bluetooth sleep clock source
// s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL;
// set default bluetooth sleep clock source
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value
#if CONFIG_BT_CTRL_LPCLK_SEL_EXT_32K_XTAL
// check whether or not EXT_CRYS is working
if (rtc_clk_slow_freq_get() == RTC_SLOW_FREQ_32K_XTAL) {
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL32K; // set default value
// #ifdef CONFIG_PM_ENABLE
// s_btdm_allow_light_sleep = true;
// #endif
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL32K; // External 32 kHz XTAL
s_lp_cntl.no_light_sleep = 0;
} else {
ESP_LOGW(BT_LOG_TAG, "32.768kHz XTAL not detected, fall back to main XTAL as Bluetooth sleep clock\n"
"light sleep mode will not be able to apply when bluetooth is enabled");
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value
}
#elif (CONFIG_BT_CTRL_LPCLK_SEL_RTC_SLOW)
// check whether or not EXT_CRYS is working
if (rtc_clk_slow_freq_get() == RTC_SLOW_FREQ_RTC) {
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_RTC_SLOW; // set default value
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_RTC_SLOW; // Internal 150 kHz RC oscillator
ESP_LOGW(BTDM_LOG_TAG, "Internal 150kHz RC osciallator. The accuracy of this clock is a lot larger than 500ppm which is "
"required in Bluetooth communication, so don't select this option in scenarios such as BLE connection state.");
} else {
ESP_LOGW(BT_LOG_TAG, "Internal 90kHz RC oscillator not detected, fall back to main XTAL as Bluetooth sleep clock\n"
"light sleep mode will not be able to apply when bluetooth is enabled");
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value
ESP_LOGW(BT_LOG_TAG, "Internal 150kHz RC oscillator not detected.");
assert(0);
}
#else
s_lp_cntl.lpclk_sel = BTDM_LPCLK_SEL_XTAL; // set default value
s_lp_cntl.no_light_sleep = 1;
#endif
bool select_src_ret __attribute__((unused));

@ -1 +1 @@
Subproject commit b97b2abd1a98ab887fb4cdc0553fabcba95aedaf
Subproject commit fe0a3d00f11dbf9d219f2a291e3cab7419e5cac1

@ -1 +1 @@
Subproject commit b223604efd557d0a5314afb3b751229df424d244
Subproject commit 32f15e826a102d2d64e612620468122ea2234a2e

View File

@ -9,10 +9,10 @@ if BLE_MESH
config BLE_MESH_USE_DUPLICATE_SCAN
bool "Support Duplicate Scan in BLE Mesh"
depends on BT_BLUEDROID_ENABLED
select BTDM_BLE_SCAN_DUPL if BT_CTRL_ESP32
select BTDM_BLE_MESH_SCAN_DUPL_EN if BT_CTRL_ESP32
select BT_CTRL_BLE_SCAN_DUPL if BT_CTRL_ESP32C3
select BT_CTRL_BLE_MESH_SCAN_DUPL_EN if BT_CTRL_ESP32C3
select BTDM_BLE_SCAN_DUPL if IDF_TARGET_ESP32
select BTDM_BLE_MESH_SCAN_DUPL_EN if IDF_TARGET_ESP32
select BT_CTRL_BLE_SCAN_DUPL if IDF_TARGET_ESP32C3
select BT_CTRL_BLE_MESH_SCAN_DUPL_EN if IDF_TARGET_ESP32C3
default y
help
Enable this option to allow using specific duplicate scan filter

View File

@ -69,6 +69,12 @@ 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.
*
* @note In order to avoid suffering brute-forcing attack (CVE-2020-26559).
* The Bluetooth SIG recommends that potentially vulnerable mesh provisioners
* use an out-of-band mechanism to exchange the public keys.
* So as an unprovisioned device, it should use this function to input
* the Public Key exchanged through the out-of-band mechanism.
*
* @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
@ -121,6 +127,10 @@ esp_err_t esp_ble_mesh_set_unprovisioned_device_name(const char *name);
/**
* @brief Provisioner inputs unprovisioned device's oob public key.
*
* @note In order to avoid suffering brute-forcing attack (CVE-2020-26559).
* The Bluetooth SIG recommends that potentially vulnerable mesh provisioners
* use an out-of-band mechanism to exchange the public keys.
*
* @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
@ -329,6 +339,14 @@ esp_err_t esp_ble_mesh_provisioner_set_prov_data_info(esp_ble_mesh_prov_data_inf
* A large entropy helps ensure that a brute-force of the AuthValue, even a static
* AuthValue, cannot normally be completed in a reasonable time (CVE-2020-26557).
*
* AuthValues selected using a cryptographically secure random or pseudorandom number
* generator and having the maximum permitted entropy (128-bits) will be most difficult
* to brute-force. AuthValues with reduced entropy or generated in a predictable manner
* will not grant the same level of protection against this vulnerability. Selecting a
* new AuthValue with each provisioning attempt can also make it more difficult to launch
* a brute-force attack by requiring the attacker to restart the search with each
* provisioning attempt (CVE-2020-26556).
*
* @param[in] value: Pointer to the static oob value.
* @param[in] length: Length of the static oob value.
*

View File

@ -573,8 +573,10 @@ typedef struct {
esp_ble_mesh_prov_oob_info_t oob_info;
/* NOTE: In order to avoid suffering brute-forcing attack (CVE-2020-26559).
* The Bluetooth SIG recommends that potentially vulnerable mesh node
* The Bluetooth SIG recommends that potentially vulnerable mesh provisioners
* support an out-of-band mechanism to exchange the public keys.
* So as an unprovisioned device, it should enable this flag to support
* using an out-of-band mechanism to exchange Public Key.
*/
/** Flag indicates whether unprovisioned devices support OOB public key */
bool oob_pub_key;
@ -629,7 +631,7 @@ typedef struct {
/** Provisioning Algorithm for the Provisioner */
uint8_t prov_algorithm;
/* NOTE: In order to avoid suffering brute-forcing attack(CVE-2020-26559).
/* NOTE: In order to avoid suffering brute-forcing attack (CVE-2020-26559).
* The Bluetooth SIG recommends that potentially vulnerable mesh provisioners
* use an out-of-band mechanism to exchange the public keys.
*/
@ -643,6 +645,14 @@ typedef struct {
* selected AuthValue using all of the available bits, where permitted by the
* implementation. A large entropy helps ensure that a brute-force of the AuthValue,
* even a static AuthValue, cannot normally be completed in a reasonable time (CVE-2020-26557).
*
* AuthValues selected using a cryptographically secure random or pseudorandom number
* generator and having the maximum permitted entropy (128-bits) will be most difficult
* to brute-force. AuthValues with reduced entropy or generated in a predictable manner
* will not grant the same level of protection against this vulnerability. Selecting a
* new AuthValue with each provisioning attempt can also make it more difficult to launch
* a brute-force attack by requiring the attacker to restart the search with each
* provisioning attempt (CVE-2020-26556).
*/
/** Provisioner static oob value */
uint8_t *prov_static_oob_val;

View File

@ -1930,6 +1930,19 @@ static int prov_auth(const uint8_t idx, uint8_t method, uint8_t action, uint8_t
/* Provisioner ouput number/string and wait for device's Provisioning Input Complete PDU */
link[idx].expect = PROV_INPUT_COMPLETE;
/* NOTE: The Bluetooth SIG recommends that mesh implementations enforce a randomly
* selected AuthValue using all of the available bits, where permitted by the
* implementation. A large entropy helps ensure that a brute-force of the AuthValue,
* even a static AuthValue, cannot normally be completed in a reasonable time (CVE-2020-26557).
*
* AuthValues selected using a cryptographically secure random or pseudorandom number
* generator and having the maximum permitted entropy (128-bits) will be most difficult
* to brute-force. AuthValues with reduced entropy or generated in a predictable manner
* will not grant the same level of protection against this vulnerability. Selecting a
* new AuthValue with each provisioning attempt can also make it more difficult to launch
* a brute-force attack by requiring the attacker to restart the search with each
* provisioning attempt (CVE-2020-26556).
*/
if (input == BLE_MESH_ENTER_STRING) {
unsigned char str[9] = {'\0'};
uint8_t j = 0U;
@ -2312,12 +2325,11 @@ static void prov_confirm(const uint8_t idx, const uint8_t *data)
BT_DBG("Remote Confirm: %s", bt_hex(data, 16));
/* NOTE: The Bluetooth SIG recommends that potentially vulnerable mesh
* provisioners restrict the authentication procedure and not accept
* provisioning random and provisioning confirmation numbers from a remote
* peer that are the same as those selected by the local device (CVE-2020-26556
* & CVE-2020-26560).
* */
/* NOTE: The Bluetooth SIG recommends that potentially vulnerable mesh provisioners
* restrict the authentication procedure and not accept provisioning random and
* provisioning confirmation numbers from a remote peer that are the same as those
* selected by the local device (CVE-2020-26560).
*/
if (!memcmp(data, link[idx].local_conf, 16)) {
BT_ERR("Confirmation value is identical to ours, rejecting.");
close_link(idx, CLOSE_REASON_FAILED);
@ -2534,12 +2546,11 @@ static void prov_random(const uint8_t idx, const uint8_t *data)
BT_DBG("Remote Random: %s", bt_hex(data, 16));
/* NOTE: The Bluetooth SIG recommends that potentially vulnerable mesh
* provisioners restrict the authentication procedure and not accept
* provisioning random and provisioning confirmation numbers from a remote
* peer that are the same as those selected by the local device (CVE-2020-26556
* & CVE-2020-26560).
* */
/* NOTE: The Bluetooth SIG recommends that potentially vulnerable mesh provisioners
* restrict the authentication procedure and not accept provisioning random and
* provisioning confirmation numbers from a remote peer that are the same as those
* selected by the local device (CVE-2020-26560).
*/
if (!memcmp(data, link[idx].rand, 16)) {
BT_ERR("Random value is identical to ours, rejecting.");
goto fail;

View File

@ -42,7 +42,7 @@ config BT_BLUEDROID_MEM_DEBUG
config BT_CLASSIC_ENABLED
bool "Classic Bluetooth"
depends on BT_BLUEDROID_ENABLED && BT_CTRL_ESP32
depends on BT_BLUEDROID_ENABLED && IDF_TARGET_ESP32
default n
help
For now this option needs "SMP_ENABLE" to be set to yes
@ -99,13 +99,27 @@ config BT_HFP_WBS_ENABLE
This enables Wide Band Speech. Should disable it when SCO data path is PCM.
Otherwise there will be no data transmited via GPIOs.
config BT_HID_HOST_ENABLED
bool "Classic BT HID Host"
config BT_HID_ENABLED
bool "Classic BT HID"
depends on BT_CLASSIC_ENABLED
default n
help
This enables the BT HID Host
choice BT_HID_ROLE
prompt "Profile Role configuration"
depends on BT_HID_ENABLED
config BT_HID_HOST_ENABLED
bool "Classic BT HID Host"
help
This enables the BT HID Host
config BT_HID_DEVICE_ENABLED
bool "Classic BT HID Device"
help
This enables the BT HID Device
endchoice
config BT_SSP_ENABLED
bool "Secure Simple Pairing"
depends on BT_CLASSIC_ENABLED
@ -1056,8 +1070,3 @@ config BT_BLE_42_FEATURES_SUPPORTED
default n
help
This enables BLE 4.2 features.
config BT_RESERVE_DRAM
hex
default 0xdb5c if BT_ENABLED
default 0

View File

@ -0,0 +1,176 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
// Copyright 2019 Blake Felt
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include "esp_err.h"
#include "esp_bt_main.h"
#include "btc/btc_manage.h"
#include "btc_hd.h"
#include "esp_hidd_api.h"
#if (defined BTC_HD_INCLUDED && BTC_HD_INCLUDED == TRUE)
esp_err_t esp_bt_hid_device_register_callback(esp_hd_cb_t *callback)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (callback == NULL) {
return ESP_FAIL;
}
btc_profile_cb_set(BTC_PID_HD, callback);
return ESP_OK;
}
esp_err_t esp_bt_hid_device_init(void)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HD;
msg.act = BTC_HD_INIT_EVT;
/* Switch to BTC context */
bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_device_deinit(void)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HD;
msg.act = BTC_HD_DEINIT_EVT;
bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_device_register_app(esp_hidd_app_param_t* app_param, esp_hidd_qos_param_t* in_qos, esp_hidd_qos_param_t* out_qos)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
btc_hidd_args_t args;
memset(&args, 0, sizeof(btc_hidd_args_t));
args.register_app.app_param = app_param;
args.register_app.in_qos = in_qos;
args.register_app.out_qos = out_qos;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HD;
msg.act = BTC_HD_REGISTER_APP_EVT;
bt_status_t stat = btc_transfer_context(&msg, &args, sizeof(btc_hidd_args_t), NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_device_unregister_app(void)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HD;
msg.act = BTC_HD_UNREGISTER_APP_EVT;
bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_device_connect(esp_bd_addr_t bd_addr)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
btc_hidd_args_t args;
memset(&args, 0, sizeof(btc_hidd_args_t));
memcpy(args.connect.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HD;
msg.act = BTC_HD_CONNECT_EVT;
bt_status_t stat = btc_transfer_context(&msg, &args, sizeof(btc_hidd_args_t), NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_device_disconnect(void)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HD;
msg.act = BTC_HD_DISCONNECT_EVT;
bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_device_send_report(esp_hidd_report_type_t type, uint8_t id, uint16_t len, uint8_t* data)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HD;
msg.act = BTC_HD_SEND_REPORT_EVT;
btc_hidd_args_t args;
memset(&args, 0, sizeof(btc_hidd_args_t));
args.send_report.type = type;
args.send_report.id = id;
args.send_report.len = len;
args.send_report.data = data;
bt_status_t stat = btc_transfer_context(&msg, &args, sizeof(btc_hidd_args_t), btc_hd_arg_deep_copy);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_device_report_error(esp_hidd_handshake_error_t error)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HD;
msg.act = BTC_HD_REPORT_ERROR_EVT;
btc_hidd_args_t args;
memset(&args, 0, sizeof(btc_hidd_args_t));
args.error = error;
bt_status_t stat = btc_transfer_context(&msg, &args, sizeof(btc_hidd_args_t), NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_device_virtual_cable_unplug(void)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HD;
msg.act = BTC_HD_UNPLUG_EVT;
bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
#endif /* defined BTC_HD_INCLUDED && BTC_HD_INCLUDED == TRUE */

View File

@ -0,0 +1,254 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
// Copyright 2019 Blake Felt
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "btc/btc_manage.h"
#include "btc_hh.h"
#include "esp_bt_main.h"
#include "esp_err.h"
#include "esp_hidh_api.h"
#include <string.h>
#if (defined BTC_HH_INCLUDED && BTC_HH_INCLUDED == TRUE)
esp_err_t esp_bt_hid_host_register_callback(esp_hh_cb_t *callback)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
if (callback == NULL) {
return ESP_FAIL;
}
btc_profile_cb_set(BTC_PID_HH, callback);
return ESP_OK;
}
esp_err_t esp_bt_hid_host_init(void)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HH;
msg.act = BTC_HH_INIT_EVT;
bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_host_deinit(void)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HH;
msg.act = BTC_HH_DEINIT_EVT;
bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_host_connect(esp_bd_addr_t bd_addr)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
btc_hidh_args_t arg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HH;
msg.act = BTC_HH_CONNECT_EVT;
memcpy(arg.connect.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_host_disconnect(esp_bd_addr_t bd_addr)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
btc_hidh_args_t arg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HH;
msg.act = BTC_HH_DISCONNECT_EVT;
memcpy(arg.disconnect.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_host_virtual_cable_unplug(esp_bd_addr_t bd_addr)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
btc_hidh_args_t arg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HH;
msg.act = BTC_HH_UNPLUG_EVT;
memcpy(arg.unplug.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_host_set_info(esp_bd_addr_t bd_addr, esp_hidh_hid_info_t *hid_info)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
btc_hidh_args_t arg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HH;
msg.act = BTC_HH_SET_INFO_EVT;
memcpy(arg.set_info.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
arg.set_info.hid_info = hid_info;
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), btc_hh_arg_deep_copy);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_host_get_protocol(esp_bd_addr_t bd_addr)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
btc_hidh_args_t arg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HH;
msg.act = BTC_HH_GET_PROTO_EVT;
memcpy(arg.get_protocol.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_host_set_protocol(esp_bd_addr_t bd_addr, esp_hidh_protocol_mode_t protocol_mode)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
btc_hidh_args_t arg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HH;
msg.act = BTC_HH_SET_PROTO_EVT;
memcpy(arg.set_protocol.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
arg.set_protocol.protocol_mode = protocol_mode;
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_host_get_idle(esp_bd_addr_t bd_addr)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
btc_hidh_args_t arg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HH;
msg.act = BTC_HH_GET_IDLE_EVT;
memcpy(arg.get_idle.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_host_set_idle(esp_bd_addr_t bd_addr, uint16_t idle_time)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
btc_hidh_args_t arg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HH;
msg.act = BTC_HH_SET_IDLE_EVT;
memcpy(arg.set_idle.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
arg.set_idle.idle_time = idle_time;
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_host_get_report(esp_bd_addr_t bd_addr, esp_hidh_report_type_t report_type, uint8_t report_id,
int buffer_size)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
btc_hidh_args_t arg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HH;
msg.act = BTC_HH_GET_REPORT_EVT;
memcpy(arg.get_report.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
arg.get_report.report_type = report_type;
arg.get_report.report_id = report_id;
arg.get_report.buffer_size = buffer_size;
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), NULL);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_host_set_report(esp_bd_addr_t bd_addr, esp_hidh_report_type_t report_type, uint8_t *report,
size_t len)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
btc_hidh_args_t arg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HH;
msg.act = BTC_HH_SET_REPORT_EVT;
memcpy(arg.set_report.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
arg.set_report.report_type = report_type;
arg.set_report.len = len;
arg.set_report.report = report;
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), btc_hh_arg_deep_copy);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_bt_hid_host_send_data(esp_bd_addr_t bd_addr, uint8_t *data, size_t len)
{
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
btc_msg_t msg;
btc_hidh_args_t arg;
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_HH;
msg.act = BTC_HH_SEND_DATA_EVT;
memcpy(arg.send_data.bd_addr, bd_addr, sizeof(esp_bd_addr_t));
arg.send_data.len = len;
arg.send_data.data = data;
bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hidh_args_t), btc_hh_arg_deep_copy);
return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
}
#endif /* defined BTC_HH_INCLUDED && BTC_HH_INCLUDED == TRUE */

View File

@ -467,7 +467,7 @@ typedef struct
{
uint16_t rx_len; /*!< pkt rx data length value */
uint16_t tx_len; /*!< pkt tx data length value */
}esp_ble_pkt_data_length_params_t;
} esp_ble_pkt_data_length_params_t;
/**
* @brief BLE encryption keys
@ -648,7 +648,7 @@ typedef enum {
typedef enum{
ESP_BLE_WHITELIST_REMOVE = 0X00, /*!< remove mac from whitelist */
ESP_BLE_WHITELIST_ADD = 0X01, /*!< add address to whitelist */
}esp_ble_wl_opration_t;
} esp_ble_wl_opration_t;
#if (BLE_42_FEATURE_SUPPORT == TRUE)
typedef enum {
ESP_BLE_DUPLICATE_EXCEPTIONAL_LIST_ADD = 0, /*!< Add device info into duplicate scan exceptional list */
@ -998,7 +998,7 @@ typedef union {
uint16_t conn_int; /*!< Current connection interval */
uint16_t timeout; /*!< Supervision timeout for the LE Link. Range: 0x000A to 0x0C80.
Mandatory Range: 0x000A to 0x0C80 Time = N * 10 msec */
}update_conn_params; /*!< Event parameter of ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT */
} update_conn_params; /*!< Event parameter of ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT */
/**
* @brief ESP_GAP_BLE_SET_PKT_LENGTH_COMPLETE_EVT
*/
@ -1018,13 +1018,13 @@ typedef union {
struct ble_remove_bond_dev_cmpl_evt_param {
esp_bt_status_t status; /*!< Indicate the remove bond device operation success status */
esp_bd_addr_t bd_addr; /*!< The device address which has been remove from the bond list */
}remove_bond_dev_cmpl; /*!< Event parameter of ESP_GAP_BLE_REMOVE_BOND_DEV_COMPLETE_EVT */
} remove_bond_dev_cmpl; /*!< Event parameter of ESP_GAP_BLE_REMOVE_BOND_DEV_COMPLETE_EVT */
/**
* @brief ESP_GAP_BLE_CLEAR_BOND_DEV_COMPLETE_EVT
*/
struct ble_clear_bond_dev_cmpl_evt_param {
esp_bt_status_t status; /*!< Indicate the clear bond device operation success status */
}clear_bond_dev_cmpl; /*!< Event parameter of ESP_GAP_BLE_CLEAR_BOND_DEV_COMPLETE_EVT */
} clear_bond_dev_cmpl; /*!< Event parameter of ESP_GAP_BLE_CLEAR_BOND_DEV_COMPLETE_EVT */
/**
* @brief ESP_GAP_BLE_GET_BOND_DEV_COMPLETE_EVT
*/
@ -1032,7 +1032,7 @@ typedef union {
esp_bt_status_t status; /*!< Indicate the get bond device operation success status */
uint8_t dev_num; /*!< Indicate the get number device in the bond list */
esp_ble_bond_dev_t *bond_dev; /*!< the pointer to the bond device Structure */
}get_bond_dev_cmpl; /*!< Event parameter of ESP_GAP_BLE_GET_BOND_DEV_COMPLETE_EVT */
} get_bond_dev_cmpl; /*!< Event parameter of ESP_GAP_BLE_GET_BOND_DEV_COMPLETE_EVT */
/**
* @brief ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT
*/

View File

@ -380,7 +380,7 @@ esp_err_t esp_ble_gattc_search_service(esp_gatt_if_t gattc_if, uint16_t conn_id,
/**
* @brief Find all the service with the given service uuid in the gattc cache, if the svc_uuid is NULL, find all the service.
* Note: It just get service from local cache, won't get from remote devices. If want to get it from remote device, need
* to used the esp_ble_gattc_search_service.
* to used the esp_ble_gattc_cache_refresh, then call esp_ble_gattc_get_service again.
*
* @param[in] gattc_if: Gatt client access interface.
* @param[in] conn_id: connection ID which identify the server.

View File

@ -0,0 +1,379 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
// Copyright 2019 Blake Felt
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT 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_HIDD_API_H__
#define __ESP_HIDD_API_H__
#include "esp_bt_defs.h"
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
/* sub_class of hid device */
#define ESP_HID_CLASS_UNKNOWN (0x00<<2)
#define ESP_HID_CLASS_JOS (0x01<<2) /* joy stick */
#define ESP_HID_CLASS_GPD (0x02<<2) /* game pad */
#define ESP_HID_CLASS_RMC (0x03<<2) /* remote control */
#define ESP_HID_CLASS_SED (0x04<<2) /* sensing device */
#define ESP_HID_CLASS_DGT (0x05<<2) /* Digitizer tablet */
#define ESP_HID_CLASS_CDR (0x06<<2) /* card reader */
#define ESP_HID_CLASS_KBD (0x10<<2) /* keyboard */
#define ESP_HID_CLASS_MIC (0x20<<2) /* pointing device */
#define ESP_HID_CLASS_COM (0x30<<2) /* Combo keyboard/pointing */
/**
* @brief HIDD handshake error
*/
typedef enum {
ESP_HID_PAR_HANDSHAKE_RSP_SUCCESS = 0,
ESP_HID_PAR_HANDSHAKE_RSP_NOT_READY = 1,
ESP_HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID = 2,
ESP_HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ = 3,
ESP_HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM = 4,
ESP_HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN = 14,
ESP_HID_PAR_HANDSHAKE_RSP_ERR_FATAL = 15
} esp_hidd_handshake_error_t;
/**
* @brief HIDD report types
*/
typedef enum {
ESP_HIDD_REPORT_TYPE_OTHER = 0,
ESP_HIDD_REPORT_TYPE_INPUT,
ESP_HIDD_REPORT_TYPE_OUTPUT,
ESP_HIDD_REPORT_TYPE_FEATURE,
// special value for reports to be sent on INTR(INPUT is assumed)
ESP_HIDD_REPORT_TYPE_INTRDATA
} esp_hidd_report_type_t;
/**
* @brief HIDD connection state
*/
typedef enum {
ESP_HIDD_CONN_STATE_CONNECTED,
ESP_HIDD_CONN_STATE_CONNECTING,
ESP_HIDD_CONN_STATE_DISCONNECTED,
ESP_HIDD_CONN_STATE_DISCONNECTING,
ESP_HIDD_CONN_STATE_UNKNOWN
} esp_hidd_connection_state_t;
/**
* @brief HID device protocol modes
*/
typedef enum {
ESP_HIDD_REPORT_MODE = 0x00,
ESP_HIDD_BOOT_MODE = 0x01,
ESP_HIDD_UNSUPPORTED_MODE = 0xff
} esp_hidd_protocol_mode_t;
/**
* @brief HIDD characteristics for SDP report
*/
typedef struct {
const char *name;
const char *description;
const char *provider;
uint8_t subclass;
uint8_t *desc_list;
int desc_list_len;
} esp_hidd_app_param_t;
/**
* @brief HIDD Quality of Service parameters
*/
typedef struct {
uint8_t service_type;
uint32_t token_rate;
uint32_t token_bucket_size;
uint32_t peak_bandwidth;
uint32_t access_latency;
uint32_t delay_variation;
} esp_hidd_qos_param_t;
/**
* @brief HID device callback function events
*/
typedef enum {
ESP_HIDD_INIT_EVT = 0, /*!< When HID device is inited, the event comes */
ESP_HIDD_DEINIT_EVT, /*!< When HID device is deinited, the event comes */
ESP_HIDD_REGISTER_APP_EVT, /*!< When HID device application registered, the event comes */
ESP_HIDD_UNREGISTER_APP_EVT, /*!< When HID device application unregistered, the event comes */
ESP_HIDD_OPEN_EVT, /*!< When HID device connection to host opened, the event comes */
ESP_HIDD_CLOSE_EVT, /*!< When HID device connection to host closed, the event comes */
ESP_HIDD_SEND_REPORT_EVT, /*!< When HID device send report to lower layer, the event comes */
ESP_HIDD_REPORT_ERR_EVT, /*!< When HID device report handshanke error to lower layer, the event comes */
ESP_HIDD_GET_REPORT_EVT, /*!< When HID device receives GET_REPORT request from host, the event comes */
ESP_HIDD_SET_REPORT_EVT, /*!< When HID device receives SET_REPORT request from host, the event comes */
ESP_HIDD_SET_PROTOCOL_EVT, /*!< When HID device receives SET_PROTOCOL request from host, the event comes */
ESP_HIDD_INTR_DATA_EVT, /*!< When HID device receives DATA from host on intr, the event comes */
ESP_HIDD_VC_UNPLUG_EVT, /*!< When HID device initiates Virtual Cable Unplug, the event comes */
ESP_HIDD_API_ERR_EVT /*!< When HID device has API error, the event comes */
} esp_hidd_cb_event_t;
typedef enum {
ESP_HIDD_SUCCESS,
ESP_HIDD_ERROR, /*!< general ESP HD error */
ESP_HIDD_NO_RES, /*!< out of system resources */
ESP_HIDD_BUSY, /*!< Temporarily can not handle this request. */
ESP_HIDD_NO_DATA, /*!< No data. */
ESP_HIDD_NEED_INIT, /*!< HIDD module shall init first */
ESP_HIDD_NEED_DEINIT, /*!< HIDD module shall deinit first */
ESP_HIDD_NEED_REG, /*!< HIDD module shall register first */
ESP_HIDD_NEED_DEREG, /*!< HIDD module shall deregister first */
ESP_HIDD_NO_CONNECTION, /*!< connection may have been closed */
} esp_hidd_status_t;
/**
* @brief HID device callback parameters union
*/
typedef union {
/**
* @brief ESP_HIDD_INIT_EVT
*/
struct hidd_init_evt_param {
esp_hidd_status_t status; /*!< operation status */
} init; /*!< HIDD callback param of ESP_HIDD_INIT_EVT */
/**
* @brief ESP_HIDD_DEINIT_EVT
*/
struct hidd_deinit_evt_param {
esp_hidd_status_t status; /*!< operation status */
} deinit; /*!< HIDD callback param of ESP_HIDD_DEINIT_EVT */
/**
* @brief ESP_HIDD_REGISTER_APP_EVT
*/
struct hidd_register_app_evt_param {
esp_hidd_status_t status; /*!< operation status */
bool in_use; /*!< indicate whether use virtual cable plug host address */
esp_bd_addr_t bd_addr; /*!< host address */
} register_app; /*!< HIDD callback param of ESP_HIDD_REGISTER_APP_EVT */
/**
* @brief ESP_HIDD_UNREGISTER_APP_EVT
*/
struct hidd_unregister_app_evt_param {
esp_hidd_status_t status; /*!< operation status */
} unregister_app; /*!< HIDD callback param of ESP_HIDD_UNREGISTER_APP_EVT */
/**
* @brief ESP_HIDD_OPEN_EVT
*/
struct hidd_open_evt_param {
esp_hidd_status_t status; /*!< operation status */
esp_hidd_connection_state_t conn_status; /*!< connection status */
esp_bd_addr_t bd_addr; /*!< host address */
} open; /*!< HIDD callback param of ESP_HIDD_OPEN_EVT */
/**
* @brief ESP_HIDD_CLOSE_EVT
*/
struct hidd_close_evt_param {
esp_hidd_status_t status; /*!< operation status */
esp_hidd_connection_state_t conn_status; /*!< connection status */
} close; /*!< HIDD callback param of ESP_HIDD_CLOSE_EVT */
/**
* @brief ESP_HIDD_SEND_REPORT_EVT
*/
struct hidd_send_report_evt_param {
esp_hidd_status_t status; /*!< operation status */
uint8_t reason; /*!< lower layer failed reason(ref hiddefs.h) */
esp_hidd_report_type_t report_type; /*!< report type */
uint8_t report_id; /*!< report id */
} send_report; /*!< HIDD callback param of ESP_HIDD_SEND_REPORT_EVT */
/**
* @brief ESP_HIDD_REPORT_ERR_EVT
*/
struct hidd_report_err_evt_param {
esp_hidd_status_t status; /*!< operation status */
uint8_t reason; /*!< lower layer failed reason(ref hiddefs.h) */
} report_err; /*!< HIDD callback param of ESP_HIDD_REPORT_ERR_EVT */
/**
* @brief ESP_HIDD_GET_REPORT_EVT
*/
struct hidd_get_report_evt_param {
esp_hidd_report_type_t report_type; /*!< report type */
uint8_t report_id; /*!< report id */
uint16_t buffer_size; /*!< buffer size */
} get_report; /*!< HIDD callback param of ESP_HIDD_GET_REPORT_EVT */
/**
* @brief ESP_HIDD_SET_REPORT_EVT
*/
struct hidd_set_report_evt_param {
esp_hidd_report_type_t report_type; /*!< report type */
uint8_t report_id; /*!< report id */
uint16_t len; /*!< set_report data length */
uint8_t *data; /*!< set_report data pointer */
} set_report; /*!< HIDD callback param of ESP_HIDD_SET_REPORT_EVT */
/**
* @brief ESP_HIDD_SET_PROTOCOL_EVT
*/
struct hidd_set_protocol_evt_param {
esp_hidd_protocol_mode_t protocol_mode; /*!< protocol mode */
} set_protocol; /*!< HIDD callback param of ESP_HIDD_SET_PROTOCOL_EVT */
/**
* @brief ESP_HIDD_INTR_DATA_EVT
*/
struct hidd_intr_data_evt_param {
uint8_t report_id; /*!< interrupt channel report id */
uint16_t len; /*!< interrupt channel report data length */
uint8_t *data; /*!< interrupt channel report data pointer */
} intr_data; /*!< HIDD callback param of ESP_HIDD_INTR_DATA_EVT */
/**
* @brief ESP_HIDD_VC_UNPLUG_EVT
*/
struct hidd_vc_unplug_param {
esp_hidd_status_t status; /*!< operation status */
esp_hidd_connection_state_t conn_status; /*!< connection status */
} vc_unplug; /*!< HIDD callback param of ESP_HIDD_VC_UNPLUG_EVT */
} esp_hidd_cb_param_t;
/**
* @brief HID device callback function type.
* @param event: Event type
* @param param: Point to callback parameter, currently is union type
*/
typedef void (esp_hd_cb_t)(esp_hidd_cb_event_t event, esp_hidd_cb_param_t *param);
/**
* @brief This function is called to init callbacks with HID device module.
*
* @param[in] callback: pointer to the init callback function.
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_device_register_callback(esp_hd_cb_t callback);
/**
* @brief This function initializes HIDD. This function should be called after esp_bluedroid_enable and
* esp_blueroid_init success, and should be called after esp_bt_hid_device_register_callback.
* When the operation is complete the callback function will be called with ESP_HIDD_INIT_EVT.
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_device_init(void);
/**
* @brief This function de-initializes HIDD interface. This function should be called after esp_bluedroid_enable() and
* esp_blueroid_init() success, and should be called after esp_bt_hid_device_init(). When the operation is complete the callback
* function will be called with ESP_HIDD_DEINIT_EVT.
*
* @return - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_device_deinit(void);
/**
* @brief Registers HIDD parameters with SDP and sets l2cap Quality of Service. This function should be called after
* esp_bluedroid_enable and esp_blueroid_init success, and must be done after esp_bt_hid_device_init. When the operation is complete the callback
* function will be called with ESP_HIDD_REGISTER_APP_EVT.
*
* @param[in] app_param: HIDD parameters
* @param[in] in_qos: incoming QoS parameters
* @param[in] out_qos: outgoing QoS parameters
*
* @return - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_device_register_app(esp_hidd_app_param_t *app_param, esp_hidd_qos_param_t *in_qos,
esp_hidd_qos_param_t *out_qos);
/**
* @brief Removes HIDD parameters from SDP and resets l2cap Quality of Service. This function should be called after esp_bluedroid_enable and
* esp_blueroid_init success, and should be called after esp_bt_hid_device_init. When the operation is complete the callback
* function will be called with ESP_HIDD_UNREGISTER_APP_EVT.
*
* @return - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_device_unregister_app(void);
/**
* @brief This function connects HIDD interface to connected bluetooth device, if not done already. When the operation is complete the callback
* function will be called with ESP_HIDD_OPEN_EVT.
*
* @param[in] bd_addr: Remote host bluetooth device address.
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_device_connect(esp_bd_addr_t bd_addr);
/**
* @brief This function disconnects HIDD interface. When the operation is complete the callback
* function will be called with ESP_HIDD_CLOSE_EVT.
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_device_disconnect(void);
/**
* @brief Send HIDD report. When the operation is complete the callback
* function will be called with ESP_HIDD_SEND_REPORT_EVT.
*
* @param[in] type: type of report
* @param[in] id: report id as defined by descriptor
* @param[in] len: length of report
* @param[in] data: report data
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_device_send_report(esp_hidd_report_type_t type, uint8_t id, uint16_t len, uint8_t *data);
/**
* @brief Sends HIDD handshake with error info for invalid set_report. When the operation is complete the callback
* function will be called with ESP_HIDD_REPORT_ERR_EVT.
*
* @param[in] error: type of error
*
* @return - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_device_report_error(esp_hidd_handshake_error_t error);
/**
* @brief Unplug virtual cable of HIDD. When the operation is complete the callback
* function will be called with ESP_HIDD_VC_UNPLUG_EVT.
*
* @return - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_device_virtual_cable_unplug(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,465 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
// Copyright 2019 Blake Felt
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT 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_HIDH_API_H__
#define __ESP_HIDH_API_H__
#include "esp_bt_defs.h"
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
#define BTHH_MAX_DSC_LEN 884
/**
* @brief HID host connection state
*/
typedef enum {
ESP_HIDH_CONN_STATE_CONNECTED = 0, /*!< connected state */
ESP_HIDH_CONN_STATE_CONNECTING, /*!< connecting state */
ESP_HIDH_CONN_STATE_DISCONNECTED, /*!< disconnected state */
ESP_HIDH_CONN_STATE_DISCONNECTING, /*!< disconnecting state */
ESP_HIDH_CONN_STATE_UNKNOWN /*!< unknown state(initial state) */
} esp_hidh_connection_state_t;
typedef enum {
ESP_HIDH_OK,
ESP_HIDH_HS_HID_NOT_READY, /*!< handshake error : device not ready */
ESP_HIDH_HS_INVALID_RPT_ID, /*!< handshake error : invalid report ID */
ESP_HIDH_HS_TRANS_NOT_SPT, /*!< handshake error : transaction not spt */
ESP_HIDH_HS_INVALID_PARAM, /*!< handshake error : invalid paremter */
ESP_HIDH_HS_ERROR, /*!< handshake error : unspecified HS error */
ESP_HIDH_ERR, /*!< general ESP HH error */
ESP_HIDH_ERR_SDP, /*!< SDP error */
ESP_HIDH_ERR_PROTO, /*!< SET_Protocol error,
only used in ESP_HIDH_OPEN_EVT callback */
ESP_HIDH_ERR_DB_FULL, /*!< device database full error, used in
ESP_HIDH_OPEN_EVT/ESP_HIDH_ADD_DEV_EVT */
ESP_HIDH_ERR_TOD_UNSPT, /*!< type of device not supported */
ESP_HIDH_ERR_NO_RES, /*!< out of system resources */
ESP_HIDH_ERR_AUTH_FAILED, /*!< authentication fail */
ESP_HIDH_ERR_HDL, /*!< connection handle error */
ESP_HIDH_ERR_SEC, /*!< encryption error */
// self_defined
ESP_HIDH_BUSY, /*!< Temporarily can not handle this request. */
ESP_HIDH_NO_DATA, /*!< No data. */
ESP_HIDH_NEED_INIT, /*!< HIDH module shall init first */
ESP_HIDH_NEED_DEINIT, /*!< HIDH module shall deinit first */
ESP_HIDH_NO_CONNECTION, /*!< connection may have been closed */
} esp_hidh_status_t;
/**
* @brief HID host protocol modes
*/
typedef enum {
ESP_HIDH_BOOT_MODE = 0x00, /*!< boot protocol mode */
ESP_HIDH_REPORT_MODE = 0x01, /*!< report protocol mode */
ESP_HIDH_UNSUPPORTED_MODE = 0xff /*!< unsupported protocol mode */
} esp_hidh_protocol_mode_t;
/**
* @brief HID host report types
*/
typedef enum {
ESP_HIDH_REPORT_TYPE_OTHER = 0, /*!< unsupported report type */
ESP_HIDH_REPORT_TYPE_INPUT, /*!< input report type */
ESP_HIDH_REPORT_TYPE_OUTPUT, /*!< output report type */
ESP_HIDH_REPORT_TYPE_FEATURE, /*!< feature report type */
} esp_hidh_report_type_t;
/**
* @brief HID host callback function events
*/
typedef enum {
ESP_HIDH_INIT_EVT = 0, /*!< When HID host is inited, the event comes */
ESP_HIDH_DEINIT_EVT, /*!< When HID host is deinited, the event comes */
ESP_HIDH_OPEN_EVT, /*!< When HID host connection opened, the event comes */
ESP_HIDH_CLOSE_EVT, /*!< When HID host connection closed, the event comes */
ESP_HIDH_GET_RPT_EVT, /*!< When Get_Report command is called, the event comes */
ESP_HIDH_SET_RPT_EVT, /*!< When Set_Report command is called, the event comes */
ESP_HIDH_GET_PROTO_EVT, /*!< When Get_Protocol command is called, the event comes */
ESP_HIDH_SET_PROTO_EVT, /*!< When Set_Protocol command is called, the event comes */
ESP_HIDH_GET_IDLE_EVT, /*!< When Get_Idle command is called, the event comes */
ESP_HIDH_SET_IDLE_EVT, /*!< When Set_Idle command is called, the event comes */
ESP_HIDH_GET_DSCP_EVT, /*!< When HIDH is inited, the event comes */
ESP_HIDH_ADD_DEV_EVT, /*!< When a device is added, the event comes */
ESP_HIDH_RMV_DEV_EVT, /*!< When a device is removed, the event comes */
ESP_HIDH_VC_UNPLUG_EVT, /*!< When virtually unplugged, the event comes */
ESP_HIDH_DATA_EVT, /*!< When send data on interrupt channel, the event comes */
ESP_HIDH_DATA_IND_EVT, /*!< When receive data on interrupt channel, the event comes */
ESP_HIDH_SET_INFO_EVT /*!< When set the HID device descriptor, the event comes */
} esp_hidh_cb_event_t;
typedef struct {
int attr_mask;
uint8_t sub_class;
uint8_t app_id;
int vendor_id;
int product_id;
int version;
uint8_t ctry_code;
int dl_len;
uint8_t dsc_list[BTHH_MAX_DSC_LEN];
} esp_hidh_hid_info_t;
/**
* @brief HID host callback parameters union
*/
typedef union {
/**
* @brief ESP_HIDH_INIT_EVT
*/
struct hidh_init_evt_param {
esp_hidh_status_t status; /*!< status */
} init; /*!< HIDH callback param of ESP_HIDH_INIT_EVT */
/**
* @brief ESP_HIDH_DEINIT_EVT
*/
struct hidh_uninit_evt_param {
esp_hidh_status_t status; /*!< status */
} deinit; /*!< HIDH callback param of ESP_HIDH_DEINIT_EVT */
/**
* @brief ESP_HIDH_OPEN_EVT
*/
struct hidh_open_evt_param {
esp_hidh_status_t status; /*!< operation status */
esp_hidh_connection_state_t conn_status; /*!< connection status */
bool is_orig; /*!< indicate if host intiate the connection */
uint8_t handle; /*!< device handle */
esp_bd_addr_t bd_addr; /*!< device address */
} open; /*!< HIDH callback param of ESP_HIDH_OPEN_EVT */
/**
* @brief ESP_HIDH_CLOSE_EVT
*/
struct hidh_close_evt_param {
esp_hidh_status_t status; /*!< operation status */
uint8_t reason; /*!< lower layer failed reason(ref hiddefs.h) */
esp_hidh_connection_state_t conn_status; /*!< connection status */
uint8_t handle; /*!< device handle */
} close; /*!< HIDH callback param of ESP_HIDH_CLOSE_EVT */
/**
* @brief ESP_HIDH_VC_UNPLUG_EVT
*/
struct hidh_unplug_evt_param {
esp_hidh_status_t status; /*!< operation status */
esp_hidh_connection_state_t conn_status; /*!< connection status */
uint8_t handle; /*!< device handle */
} unplug; /*!< HIDH callback param of ESP_HIDH_VC_UNPLUG_EVT */
/**
* @brief ESP_HIDH_GET_PROTO_EVT
*/
struct hidh_get_proto_evt_param {
esp_hidh_status_t status; /*!< operation status */
uint8_t handle; /*!< device handle */
esp_hidh_protocol_mode_t proto_mode; /*!< protocol mode */
} get_proto; /*!< HIDH callback param of ESP_HIDH_GET_PROTO_EVT */
/**
* @brief ESP_HIDH_SET_PROTO_EVT
*/
struct hidh_set_proto_evt_param {
esp_hidh_status_t status; /*!< operation status */
uint8_t handle; /*!< device handle */
} set_proto; /*!< HIDH callback param of ESP_HIDH_SET_PROTO_EVT */
/**
* @brief ESP_HIDH_GET_RPT_EVT
*/
struct hidh_get_rpt_evt_param {
esp_hidh_status_t status; /*!< operation status */
uint8_t handle; /*!< device handle */
uint16_t len; /*!< data length */
uint8_t *data; /*!< data pointer */
} get_rpt; /*!< HIDH callback param of ESP_HIDH_GET_RPT_EVT */
/**
* @brief ESP_HIDH_SET_RPT_EVT
*/
struct hidh_set_rpt_evt_param {
esp_hidh_status_t status; /*!< operation status */
uint8_t handle; /*!< device handle */
} set_rpt; /*!< HIDH callback param of ESP_HIDH_SET_RPT_EVT */
/**
* @brief ESP_HIDH_DATA_EVT
*/
struct hidh_send_data_evt_param {
esp_hidh_status_t status; /*!< operation status */
uint8_t handle; /*!< device handle */
uint8_t reason; /*!< lower layer failed reason(ref hiddefs.h) */
} send_data; /*!< HIDH callback param of ESP_HIDH_DATA_EVT */
/**
* @brief ESP_HIDH_GET_IDLE_EVT
*/
struct hidh_get_idle_evt_param {
esp_hidh_status_t status; /*!< operation status */
uint8_t handle; /*!< device handle */
uint8_t idle_rate; /*!< idle rate */
} get_idle; /*!< HIDH callback param of ESP_HIDH_GET_IDLE_EVT */
/**
* @brief ESP_HIDH_SET_IDLE_EVT
*/
struct hidh_set_idle_evt_param {
esp_hidh_status_t status; /*!< operation status */
uint8_t handle; /*!< device handle */
} set_idle; /*!< HIDH callback param of ESP_HIDH_SET_IDLE_EVT */
/**
* @brief ESP_HIDH_DATA_IND_EVT
*/
struct hidh_data_ind_evt_param {
esp_hidh_status_t status; /*!< operation status */
uint8_t handle; /*!< device handle */
esp_hidh_protocol_mode_t proto_mode; /*!< protocol mode */
uint16_t len; /*!< data length */
uint8_t *data; /*!< data pointer */
} data_ind; /*!< HIDH callback param of ESP_HIDH_DATA_IND_EVT */
/**
* @brief ESP_HIDH_ADD_DEV_EVT
*/
struct hidh_add_dev_evt_param {
esp_hidh_status_t status; /*!< operation status */
uint8_t handle; /*!< device handle */
esp_bd_addr_t bd_addr; /*!< device address */
} add_dev; /*!< HIDH callback param of ESP_HIDH_ADD_DEV_EVT */
/**
* @brief ESP_HIDH_RMV_DEV_EVT
*/
struct hidh_rmv_dev_evt_param {
esp_hidh_status_t status; /*!< operation status */
uint8_t handle; /*!< device handle */
esp_bd_addr_t bd_addr; /*!< device address */
} rmv_dev; /*!< HIDH callback param of ESP_HIDH_RMV_DEV_EVT */
/**
* @brief ESP_HIDH_GET_DSCP_EVT
*/
struct hidh_get_dscp_evt_param {
esp_hidh_status_t status; /*!< operation status */
uint8_t handle; /*!< device handle */
bool added; /*!< Indicate if added */
uint16_t vendor_id; /*!< Vendor ID */
uint16_t product_id; /*!< Product ID */
uint16_t version; /*!< Version */
uint16_t ssr_max_latency; /*!< SSR max latency */
uint16_t ssr_min_tout; /*!< SSR min timeout */
uint8_t ctry_code; /*!< Country Code */
uint16_t dl_len; /*!< Device descriptor length */
uint8_t *dsc_list; /*!< Device descriptor pointer */
} dscp; /*!< HIDH callback param of ESP_HIDH_GET_DSCP_EVT */
/**
* @brief ESP_HIDH_SET_INFO_EVT
*/
struct hidh_set_info_evt_param {
esp_hidh_status_t status; /*!< operation status */
uint8_t handle; /*!< device handle */
esp_bd_addr_t bd_addr; /*!< device address */
} set_info; /*!< HIDH callback param of ESP_HIDH_SET_INFO_EVT */
} esp_hidh_cb_param_t;
/**
* @brief HID host callback function type
* @param event: Event type
* @param param: Point to callback parameter, currently is union type
*/
typedef void (esp_hh_cb_t)(esp_hidh_cb_event_t event, esp_hidh_cb_param_t *param);
/**
* @brief This function is called to init callbacks with HID host module.
*
* @param[in] callback: pointer to the init callback function.
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_host_register_callback(esp_hh_cb_t callback);
/**
* @brief This function initializes HID host. This function should be called after esp_bluedroid_enable() and
* esp_blueroid_init() success, and should be called after esp_bt_hid_host_register_callback().
* When the operation is complete the callback function will be called with ESP_HIDH_INIT_EVT.
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_host_init(void);
/**
* @brief Closes the interface. This function should be called after esp_bluedroid_enable() and
* esp_blueroid_init() success, and should be called after esp_bt_hid_host_init().
* When the operation is complete the callback function will be called with ESP_HIDH_DEINIT_EVT.
*
* @return - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_host_deinit(void);
/**
* @brief Connect to hid device. When the operation is complete the callback
* function will be called with ESP_HIDH_OPEN_EVT.
*
* @param[in] bd_addr: Remote device bluetooth device address.
*
* @return - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_host_connect(esp_bd_addr_t bd_addr);
/**
* @brief Disconnect from hid device. When the operation is complete the callback
* function will be called with ESP_HIDH_CLOSE_EVT.
*
* @param[in] bd_addr: Remote device bluetooth device address.
*
* @return - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_host_disconnect(esp_bd_addr_t bd_addr);
/**
* @brief Virtual UnPlug (VUP) the specified HID device. When the operation is complete the callback
* function will be called with ESP_HIDH_VC_UNPLUG_EVT.
*
* @param[in] bd_addr: Remote device bluetooth device address.
*
* @return - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_host_virtual_cable_unplug(esp_bd_addr_t bd_addr);
/**
* @brief Set the HID device descriptor for the specified HID device. When the operation is complete the callback
* function will be called with ESP_HIDH_SET_INFO_EVT.
*
* @param[in] bd_addr: Remote device bluetooth device address.
* @param[in] hid_info: HID device descriptor structure.
*
* @return - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_host_set_info(esp_bd_addr_t bd_addr, esp_hidh_hid_info_t *hid_info);
/**
* @brief Get the HID proto mode. When the operation is complete the callback
* function will be called with ESP_HIDH_GET_PROTO_EVT.
*
* @param[in] bd_addr: Remote device bluetooth device address.
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_host_get_protocol(esp_bd_addr_t bd_addr);
/**
* @brief Set the HID proto mode. When the operation is complete the callback
* function will be called with ESP_HIDH_SET_PROTO_EVT.
*
* @param[in] bd_addr: Remote device bluetooth device address.
* @param[in] protocol_mode: Protocol mode type.
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_host_set_protocol(esp_bd_addr_t bd_addr, esp_hidh_protocol_mode_t protocol_mode);
/**
* @brief Get the HID Idle Time. When the operation is complete the callback
* function will be called with ESP_HIDH_GET_IDLE_EVT.
*
* @param[in] bd_addr: Remote device bluetooth device address.
*
* @return
* - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_host_get_idle(esp_bd_addr_t bd_addr);
/**
* @brief Set the HID Idle Time. When the operation is complete the callback
* function will be called with ESP_HIDH_SET_IDLE_EVT.
*
* @param[in] bd_addr: Remote device bluetooth device address.
* @param[in] idle_time: Idle time rate
*
* @return - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_host_set_idle(esp_bd_addr_t bd_addr, uint16_t idle_time);
/**
* @brief Send a GET_REPORT to HID device. When the operation is complete the callback
* function will be called with ESP_HIDH_GET_RPT_EVT.
*
* @param[in] bd_addr: Remote device bluetooth device address.
* @param[in] report_type: Report type
* @param[in] report_id: Report id
* @param[in] buffer_size: Buffer size
*
* @return - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_host_get_report(esp_bd_addr_t bd_addr, esp_hidh_report_type_t report_type, uint8_t report_id,
int buffer_size);
/**
* @brief Send a SET_REPORT to HID device. When the operation is complete the callback
* function will be called with ESP_HIDH_SET_RPT_EVT.
*
* @param[in] bd_addr: Remote device bluetooth device address.
* @param[in] report_type: Report type
* @param[in] report: Report data pointer
* @param[in] len: Report data length
*
* @return - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_host_set_report(esp_bd_addr_t bd_addr, esp_hidh_report_type_t report_type, uint8_t *report,
size_t len);
/**
* @brief Send data to HID device. When the operation is complete the callback
* function will be called with ESP_HIDH_DATA_EVT.
*
* @param[in] bd_addr: Remote device bluetooth device address.
* @param[in] data: Data pointer
* @param[in] len: Data length
*
* @return - ESP_OK: success
* - other: failed
*/
esp_err_t esp_bt_hid_host_send_data(esp_bd_addr_t bd_addr, uint8_t *data, size_t len);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -126,7 +126,7 @@ static void bta_dm_ctrl_features_rd_cmpl_cback(tBTM_STATUS result);
#endif
#endif
#if (SMP_INCLUDED == TRUE)
static void bta_dm_remove_sec_dev_entry(BD_ADDR remote_bd_addr);
static BOOLEAN 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);
@ -3069,7 +3069,9 @@ static UINT8 bta_dm_authentication_complete_cback(BD_ADDR bd_addr, DEV_CLASS dev
bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event);
}
bta_dm_remove_sec_dev_entry(bd_addr);
if (bta_dm_remove_sec_dev_entry(bd_addr)) {
return BTM_SEC_DEV_REC_REMOVED;
}
}
return BTM_SUCCESS;
@ -3740,12 +3742,13 @@ static void bta_dm_delay_role_switch_cback(TIMER_LIST_ENT *p_tle)
** remtoe device does not exist, else schedule for dev entry removal upon
ACL close
**
** Returns void
** Returns TRUE if device entry is removed from Security device DB, FALSE otherwise
**
*******************************************************************************/
#if (SMP_INCLUDED == TRUE)
static void bta_dm_remove_sec_dev_entry(BD_ADDR remote_bd_addr)
static BOOLEAN bta_dm_remove_sec_dev_entry(BD_ADDR remote_bd_addr)
{
BOOLEAN is_device_deleted = FALSE;
UINT16 index = 0;
if ( BTM_IsAclConnectionUp(remote_bd_addr, BT_TRANSPORT_LE) ||
BTM_IsAclConnectionUp(remote_bd_addr, BT_TRANSPORT_BR_EDR)) {
@ -3763,7 +3766,7 @@ static void bta_dm_remove_sec_dev_entry(BD_ADDR remote_bd_addr)
APPL_TRACE_ERROR(" %s Device does not exist in DB", __FUNCTION__);
}
} else {
BTM_SecDeleteDevice (remote_bd_addr, bta_dm_cb.device_list.peer_device[index].transport);
is_device_deleted = BTM_SecDeleteDevice (remote_bd_addr, bta_dm_cb.device_list.peer_device[index].transport);
#if (BLE_INCLUDED == TRUE && GATTC_INCLUDED == TRUE)
/* need to remove all pending background connection */
BTA_GATTC_CancelOpen(0, remote_bd_addr, FALSE);
@ -3771,6 +3774,7 @@ static void bta_dm_remove_sec_dev_entry(BD_ADDR remote_bd_addr)
BTA_GATTC_Refresh(remote_bd_addr, false);
#endif
}
return is_device_deleted;
}
#endif ///SMP_INCLUDED == TRUE
@ -3835,7 +3839,10 @@ static void bta_dm_adjust_roles(BOOLEAN delay_role_switch)
} else {
bta_dm_cb.switch_delay_timer[i].p_cback =
(TIMER_CBACK *)&bta_dm_delay_role_switch_cback;
bta_sys_start_timer(&bta_dm_cb.switch_delay_timer[i], 0, 500);
/* Start the timer if not active */
if (!bta_sys_timer_is_active(&bta_dm_cb.switch_delay_timer[i])) {
bta_sys_start_timer(&bta_dm_cb.switch_delay_timer[i], 0, 500);
}
}
}
@ -4495,6 +4502,22 @@ void bta_dm_set_encryption (tBTA_DM_MSG *p_data)
}
#endif ///SMP_INCLUDED == TRUE
#if (BTA_HD_INCLUDED == TRUE)
BOOLEAN bta_dm_check_if_only_hd_connected(BD_ADDR peer_addr)
{
APPL_TRACE_DEBUG("%s: count(%d)", __func__, bta_dm_conn_srvcs.count);
for (uint8_t j = 0; j < bta_dm_conn_srvcs.count; j++) {
// Check if profiles other than hid are connected
if ((bta_dm_conn_srvcs.conn_srvc[j].id != BTA_ID_HD) &&
!bdcmp(bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr, peer_addr)) {
APPL_TRACE_DEBUG("%s: Another profile (id=%d) is connected", __func__, bta_dm_conn_srvcs.conn_srvc[j].id);
return FALSE;
}
}
return TRUE;
}
#endif /* BTA_HD_INCLUDED == TRUE */
#if (BLE_INCLUDED == TRUE)
/*******************************************************************************
**
@ -4975,9 +4998,6 @@ void bta_dm_ble_update_conn_params (tBTA_DM_MSG *p_data)
p_data->ble_update_conn_params.latency,
p_data->ble_update_conn_params.timeout)) {
APPL_TRACE_ERROR("Update connection parameters failed!");
} else {
BTM_BleConfigConnParams(p_data->ble_update_conn_params.min_int, p_data->ble_update_conn_params.max_int,
p_data->ble_update_conn_params.latency, p_data->ble_update_conn_params.timeout);
}
}
/*******************************************************************************

View File

@ -117,11 +117,11 @@ tBTA_DM_CFG *const p_bta_dm_cfg = (tBTA_DM_CFG *) &bta_dm_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 10 /* number of entries in bta_dm_pm_cfg except the first */
# define BTA_DM_NUM_PM_SPEC 10 /* number of entries in bta_dm_pm_spec */
#else
# define BTA_DM_NUM_PM_ENTRY 8 /* number of entries in bta_dm_pm_cfg except the first */
# define BTA_DM_NUM_PM_SPEC 8 /* number of entries in bta_dm_pm_spec */
#else
# define BTA_DM_NUM_PM_ENTRY 6 /* number of entries in bta_dm_pm_cfg except the first */
# define BTA_DM_NUM_PM_SPEC 6 /* number of entries in bta_dm_pm_spec */
#endif
#if (BTA_DM_PM_INCLUDED == TRUE)
@ -133,10 +133,12 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_CFG bta_dm_pm_cfg[BTA_DM_NUM_PM_ENTRY + 1]
{BTA_ID_JV, BTA_APP_ID_1, 2}, /* app BTA_JV_PM_ID_1, reuse ftc spec table */
{BTA_ID_JV, BTA_ALL_APP_ID, 3}, /* reuse fts spec table */
{BTA_ID_HS, BTA_ALL_APP_ID, 4}, /* HS spec table */
{BTA_ID_AVK, BTA_ALL_APP_ID, 5} /* avk spec table */
{BTA_ID_AVK, BTA_ALL_APP_ID, 5}, /* avk spec table */
{BTA_ID_HD, BTA_ALL_APP_ID, 6}, /* hd spec table */
{BTA_ID_HH, BTA_ALL_APP_ID, 7} /* hh spec table */
#if BLE_INCLUDED == TRUE
, {BTA_ID_GATTC, BTA_ALL_APP_ID, 6} /* gattc spec table */
, {BTA_ID_GATTS, BTA_ALL_APP_ID, 7} /* gatts spec table */
, {BTA_ID_GATTC, BTA_ALL_APP_ID, 8} /* gattc spec table */
, {BTA_ID_GATTS, BTA_ALL_APP_ID, 9} /* gatts spec table */
#endif
};
@ -254,10 +256,48 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = {
{{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
{{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
}
},
/* HD : 6 */
{
(BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
#if (BTM_SSR_INCLUDED == TRUE)
(BTA_DM_PM_SSR3), /* the SSR entry */
#endif
{
{{BTA_DM_PM_SNIFF_HD_ACTIVE_IDX, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */
{{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */
{{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
{{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
{{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */
{{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */
{{BTA_DM_PM_SNIFF_HD_IDLE_IDX, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
{{BTA_DM_PM_SNIFF_HD_ACTIVE_IDX, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
{{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
}
},
/* HH : 7 */
{
(BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
#if (BTM_SSR_INCLUDED == TRUE)
(BTA_DM_PM_SSR1), /* the SSR entry */
#endif
{
{{BTA_DM_PM_SNIFF_HH_OPEN_IDX, BTA_DM_PM_HH_OPEN_DELAY + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */
{{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */
{{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
{{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
{{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */
{{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close, used for HH suspend */
{{BTA_DM_PM_SNIFF_HH_IDLE_IDX, BTA_DM_PM_HH_IDLE_DELAY + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
{{BTA_DM_PM_SNIFF_HH_ACTIVE_IDX, BTA_DM_PM_HH_ACTIVE_DELAY + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
{{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
}
}
#if BLE_INCLUDED == TRUE
/* GATTC : 6 */
/* GATTC : 8 */
, {
(BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
#if (BTM_SSR_INCLUDED == TRUE)
@ -278,7 +318,7 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = {
{{BTA_DM_PM_RETRY, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
}
}
/* GATTS : 7 */
/* GATTS : 9 */
, {
(BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
#if (BTM_SSR_INCLUDED == TRUE)
@ -372,7 +412,7 @@ tBTA_DM_SSR_SPEC bta_dm_ssr_spec[] = {
seting default max latency and min remote timeout as 0,
and always read individual device preference from HH module */
{1200, 2, 2}, /* BTA_DM_PM_SSR2 - others (as long as sniff is allowed)*/
{360, 160, 2} /* BTA_DM_PM_SSR3 - HD */
{360, 160, 1600} /* BTA_DM_PM_SSR3 - HD */
};
tBTA_DM_SSR_SPEC *const p_bta_dm_ssr_spec = (tBTA_DM_SSR_SPEC *) &bta_dm_ssr_spec;

View File

@ -26,6 +26,7 @@
#include "common/bt_target.h"
#include "freertos/semphr.h"
#include "bta/bta_sys.h"
#if (BLE_INCLUDED == TRUE && (defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE))
#include "bta/bta_gatt_api.h"
#endif
@ -1596,6 +1597,11 @@ extern void bta_dm_ble_get_energy_info(tBTA_DM_MSG *p_data);
extern void bta_dm_set_encryption(tBTA_DM_MSG *p_data);
extern void bta_dm_confirm(tBTA_DM_MSG *p_data);
extern void bta_dm_key_req(tBTA_DM_MSG *p_data);
#if (BTA_HD_INCLUDED == TRUE)
extern BOOLEAN bta_dm_check_if_only_hd_connected(BD_ADDR peer_addr);
#endif /* BTA_HD_INCLUDED */
#if (BTM_OOB_INCLUDED == TRUE)
extern void bta_dm_loc_oob(tBTA_DM_MSG *p_data);
extern void bta_dm_oob_reply(tBTA_DM_MSG *p_data);

View File

@ -35,6 +35,7 @@
#include "gatt_int.h"
#include "osi/allocator.h"
#include "osi/mutex.h"
#include "bta_hh_int.h"
#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
#include "bta_hh_int.h"
@ -304,7 +305,10 @@ void bta_gattc_deregister(tBTA_GATTC_CB *p_cb, tBTA_GATTC_RCB *p_clreg)
bta_gattc_deregister_cmpl(p_clreg);
}
} else {
APPL_TRACE_ERROR("bta_gattc_deregister Deregister Failedm unknown client cif");
APPL_TRACE_ERROR("Deregister Failed unknown client cif");
#if defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == TRUE)
bta_hh_cleanup_disable(BTA_HH_OK);
#endif
}
}
/*******************************************************************************

View File

@ -0,0 +1,774 @@
/******************************************************************************
*
* Copyright (C) 2016 The Android Open Source Project
* Copyright (C) 2005-2012 Broadcom Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT 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 contains the HID device action functions.
*
******************************************************************************/
#include "common/bt_target.h"
#if defined(BTA_HD_INCLUDED) && (BTA_HD_INCLUDED == TRUE)
#include "bta/bta_sys.h"
#include "bta_hd_int.h"
#include "osi/allocator.h"
#include "osi/osi.h"
#include "stack/btm_api.h"
#include <string.h>
static void bta_hd_cback(BD_ADDR bd_addr, uint8_t event, uint32_t data, BT_HDR *pdata);
static bool check_descriptor(uint8_t *data, uint16_t length, bool *has_report_id)
{
uint8_t *ptr = data;
*has_report_id = FALSE;
while (ptr < data + length) {
uint8_t item = *ptr++;
switch (item) {
case 0xfe: // long item indicator
if (ptr < data + length) {
ptr += ((*ptr) + 2);
} else {
return false;
}
break;
case 0x85: // Report ID
*has_report_id = TRUE;
default:
ptr += (item & 0x03);
break;
}
}
return (ptr == data + length);
}
/*******************************************************************************
*
* Function bta_hd_api_enable
*
* Description Enables HID device
*
* Returns void
*
******************************************************************************/
void bta_hd_api_enable(tBTA_HD_DATA *p_data)
{
tBTA_HD_STATUS status = BTA_HD_ERROR;
tHID_STATUS ret;
APPL_TRACE_API("%s", __func__);
HID_DevInit();
memset(&bta_hd_cb, 0, sizeof(tBTA_HD_CB));
HID_DevSetSecurityLevel(BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
/* store parameters */
bta_hd_cb.p_cback = p_data->api_enable.p_cback;
ret = HID_DevRegister(bta_hd_cback);
if (ret == HID_SUCCESS) {
status = BTA_HD_OK;
} else {
APPL_TRACE_ERROR("%s: Failed to register HID device (%d)", __func__, ret);
}
/* signal BTA call back event */
(*bta_hd_cb.p_cback)(BTA_HD_ENABLE_EVT, (tBTA_HD *)&status);
}
/*******************************************************************************
*
* Function bta_hd_api_disable
*
* Description Disables HID device
*
* Returns void
*
******************************************************************************/
void bta_hd_api_disable(void)
{
tBTA_HD_STATUS status = BTA_HD_ERROR;
tHID_STATUS ret;
APPL_TRACE_API("%s", __func__);
/* service is not enabled */
if (bta_hd_cb.p_cback == NULL)
return;
/* Remove service record */
if (bta_hd_cb.sdp_handle != 0) {
SDP_DeleteRecord(bta_hd_cb.sdp_handle);
bta_sys_remove_uuid(UUID_SERVCLASS_HUMAN_INTERFACE);
}
/* Deregister with lower layer */
ret = HID_DevDeregister();
if (ret == HID_SUCCESS) {
status = BTA_HD_OK;
} else {
APPL_TRACE_ERROR("%s: Failed to deregister HID device (%d)", __func__, ret);
}
(*bta_hd_cb.p_cback)(BTA_HD_DISABLE_EVT, (tBTA_HD *)&status);
memset(&bta_hd_cb, 0, sizeof(tBTA_HD_CB));
}
/*******************************************************************************
*
* Function bta_hd_register_act
*
* Description Registers SDP record
*
* Returns void
*
******************************************************************************/
void bta_hd_register_act(tBTA_HD_DATA *p_data)
{
tBTA_HD ret;
tBTA_HD_REGISTER_APP *p_app_data = (tBTA_HD_REGISTER_APP *)p_data;
bool use_report_id = FALSE;
APPL_TRACE_API("%s", __func__);
ret.reg_status.in_use = FALSE;
/* Check if len doesn't exceed BTA_HD_APP_DESCRIPTOR_LEN and descriptor
* itself is well-formed. Also check if descriptor has Report Id item so we
* know if report will have prefix or not. */
if (p_app_data->d_len > BTA_HD_APP_DESCRIPTOR_LEN ||
!check_descriptor(p_app_data->d_data, p_app_data->d_len, &use_report_id)) {
APPL_TRACE_ERROR("%s: Descriptor is too long or malformed", __func__);
ret.reg_status.status = BTA_HD_ERROR;
(*bta_hd_cb.p_cback)(BTA_HD_REGISTER_APP_EVT, &ret);
return;
}
ret.reg_status.status = BTA_HD_OK;
/* Remove old record if for some reason it's already registered */
if (bta_hd_cb.sdp_handle != 0) {
SDP_DeleteRecord(bta_hd_cb.sdp_handle);
}
bta_hd_cb.use_report_id = use_report_id;
bta_hd_cb.sdp_handle = SDP_CreateRecord();
HID_DevAddRecord(bta_hd_cb.sdp_handle, p_app_data->name, p_app_data->description, p_app_data->provider,
p_app_data->subclass, p_app_data->d_len, p_app_data->d_data);
bta_sys_add_uuid(UUID_SERVCLASS_HUMAN_INTERFACE);
HID_DevSetIncomingQos(p_app_data->in_qos.service_type, p_app_data->in_qos.token_rate,
p_app_data->in_qos.token_bucket_size, p_app_data->in_qos.peak_bandwidth,
p_app_data->in_qos.access_latency, p_app_data->in_qos.delay_variation);
HID_DevSetOutgoingQos(p_app_data->out_qos.service_type, p_app_data->out_qos.token_rate,
p_app_data->out_qos.token_bucket_size, p_app_data->out_qos.peak_bandwidth,
p_app_data->out_qos.access_latency, p_app_data->out_qos.delay_variation);
// application is registered so we can accept incoming connections
HID_DevSetIncomingPolicy(TRUE);
if (HID_DevGetDevice(&ret.reg_status.bda) == HID_SUCCESS) {
ret.reg_status.in_use = TRUE;
}
(*bta_hd_cb.p_cback)(BTA_HD_REGISTER_APP_EVT, &ret);
}
/*******************************************************************************
*
* Function bta_hd_unregister_act
*
* Description Unregisters SDP record
*
* Returns void
*
******************************************************************************/
void bta_hd_unregister_act(UNUSED_ATTR tBTA_HD_DATA *p_data)
{
tBTA_HD_STATUS status = BTA_HD_OK;
APPL_TRACE_API("%s", __func__);
// application is no longer registered so we do not want incoming connections
HID_DevSetIncomingPolicy(FALSE);
if (bta_hd_cb.sdp_handle != 0) {
SDP_DeleteRecord(bta_hd_cb.sdp_handle);
}
bta_hd_cb.sdp_handle = 0;
bta_sys_remove_uuid(UUID_SERVCLASS_HUMAN_INTERFACE);
(*bta_hd_cb.p_cback)(BTA_HD_UNREGISTER_APP_EVT, (tBTA_HD *)&status);
}
/*******************************************************************************
*
* Function bta_hd_unregister2_act
*
* Description
*
* Returns void
*
******************************************************************************/
void bta_hd_unregister2_act(tBTA_HD_DATA *p_data)
{
APPL_TRACE_API("%s", __func__);
// close first
bta_hd_close_act(p_data);
// then unregister
bta_hd_unregister_act(p_data);
if (bta_hd_cb.disable_w4_close) {
bta_hd_api_disable();
}
}
/*******************************************************************************
*
* Function bta_hd_connect_act
*
* Description Connect to device (must be virtually plugged)
*
* Returns void
*
******************************************************************************/
extern void bta_hd_connect_act(tBTA_HD_DATA *p_data)
{
tHID_STATUS ret;
tBTA_HD_DEVICE_CTRL *p_ctrl = (tBTA_HD_DEVICE_CTRL *)p_data;
tBTA_HD cback_data;
APPL_TRACE_API("%s", __func__);
do {
ret = HID_DevPlugDevice(p_ctrl->addr);
if (ret != HID_SUCCESS) {
APPL_TRACE_WARNING("%s: HID_DevPlugDevice returned %d", __func__, ret);
return;
}
ret = HID_DevConnect();
if (ret != HID_SUCCESS) {
APPL_TRACE_WARNING("%s: HID_DevConnect returned %d", __func__, ret);
return;
}
} while (0);
bdcpy(cback_data.conn.bda, p_ctrl->addr);
cback_data.conn.status = (ret == HID_SUCCESS ? BTA_HD_OK : BTA_HD_ERROR);
cback_data.conn.conn_status = BTA_HD_CONN_STATE_CONNECTING;
bta_hd_cb.p_cback(BTA_HD_OPEN_EVT, &cback_data);
}
/*******************************************************************************
*
* Function bta_hd_disconnect_act
*
* Description Disconnect from device
*
* Returns void
*
******************************************************************************/
extern void bta_hd_disconnect_act(UNUSED_ATTR tBTA_HD_DATA *p_data)
{
tHID_STATUS ret;
tBTA_HD cback_data;
APPL_TRACE_API("%s", __func__);
ret = HID_DevDisconnect();
if (ret != HID_SUCCESS) {
APPL_TRACE_WARNING("%s: HID_DevDisconnect returned %d", __func__, ret);
return;
}
if (HID_DevGetDevice(&cback_data.conn.bda) == HID_SUCCESS) {
cback_data.conn.status = BTA_HD_OK;
cback_data.conn.conn_status = BTA_HD_CONN_STATE_DISCONNECTING;
bta_hd_cb.p_cback(BTA_HD_CLOSE_EVT, &cback_data);
}
}
/*******************************************************************************
*
* Function bta_hd_add_device_act
*
* Description
*
* Returns void
*
******************************************************************************/
extern void bta_hd_add_device_act(tBTA_HD_DATA *p_data)
{
tBTA_HD_DEVICE_CTRL *p_ctrl = (tBTA_HD_DEVICE_CTRL *)p_data;
APPL_TRACE_API("%s", __func__);
HID_DevPlugDevice(p_ctrl->addr);
}
/*******************************************************************************
*
* Function bta_hd_remove_device_act
*
* Description
*
* Returns void
*
******************************************************************************/
extern void bta_hd_remove_device_act(tBTA_HD_DATA *p_data)
{
tBTA_HD_DEVICE_CTRL *p_ctrl = (tBTA_HD_DEVICE_CTRL *)p_data;
APPL_TRACE_API("%s", __func__);
HID_DevUnplugDevice(p_ctrl->addr);
}
/*******************************************************************************
*
* Function bta_hd_send_report_act
*
* Description Sends report
*
* Returns void
*
******************************************************************************/
extern void bta_hd_send_report_act(tBTA_HD_DATA *p_data)
{
tBTA_HD_SEND_REPORT *p_report = (tBTA_HD_SEND_REPORT *)p_data;
uint8_t channel;
uint8_t report_id;
tBTA_HD cback_data;
tHID_STATUS ret;
APPL_TRACE_VERBOSE("%s", __func__);
channel = p_report->use_intr ? HID_CHANNEL_INTR : HID_CHANNEL_CTRL;
report_id = (bta_hd_cb.use_report_id || bta_hd_cb.boot_mode) ? p_report->id : 0x00;
ret = HID_DevSendReport(channel, p_report->type, report_id, p_report->len, p_report->data);
/* trigger PM */
bta_sys_busy(BTA_ID_HD, 1, bta_hd_cb.bd_addr);
bta_sys_idle(BTA_ID_HD, 1, bta_hd_cb.bd_addr);
cback_data.send_report.status = (ret == HID_SUCCESS ? BTA_HD_OK : BTA_HD_ERROR);
cback_data.send_report.reason = ret;
cback_data.send_report.report_id = report_id;
cback_data.send_report.report_type = p_report->type;
bta_hd_cb.p_cback(BTA_HD_SEND_REPORT_EVT, &cback_data);
}
/*******************************************************************************
*
* Function bta_hd_report_error_act
*
* Description
*
* Returns void
*
******************************************************************************/
extern void bta_hd_report_error_act(tBTA_HD_DATA *p_data)
{
tBTA_HD_REPORT_ERR *p_report = (tBTA_HD_REPORT_ERR *)p_data;
tHID_STATUS ret;
tBTA_HD cback_data;
APPL_TRACE_API("%s: error = %d", __func__, p_report->error);
ret = HID_DevReportError(p_report->error);
if (ret != HID_SUCCESS) {
APPL_TRACE_WARNING("%s: HID_DevReportError returned %d", __func__, ret);
}
cback_data.report_err.status = (ret == HID_SUCCESS ? BTA_HD_OK : BTA_HD_ERROR);
cback_data.report_err.reason = ret;
bta_hd_cb.p_cback(BTA_HD_REPORT_ERR_EVT, &cback_data);
}
/*******************************************************************************
*
* Function bta_hd_vc_unplug_act
*
* Description Sends Virtual Cable Unplug
*
* Returns void
*
******************************************************************************/
extern void bta_hd_vc_unplug_act(UNUSED_ATTR tBTA_HD_DATA *p_data)
{
tHID_STATUS ret;
APPL_TRACE_API("%s", __func__);
bta_hd_cb.vc_unplug = TRUE;
ret = HID_DevVirtualCableUnplug();
if (ret != HID_SUCCESS) {
APPL_TRACE_WARNING("%s: HID_DevVirtualCableUnplug returned %d", __func__, ret);
}
/* trigger PM */
bta_sys_busy(BTA_ID_HD, 1, bta_hd_cb.bd_addr);
bta_sys_idle(BTA_ID_HD, 1, bta_hd_cb.bd_addr);
}
/*******************************************************************************
*
* Function bta_hd_open_act
*
* Description
*
* Returns void
*
******************************************************************************/
extern void bta_hd_open_act(tBTA_HD_DATA *p_data)
{
tBTA_HD_CBACK_DATA *p_cback = (tBTA_HD_CBACK_DATA *)p_data;
tBTA_HD cback_data;
APPL_TRACE_API("%s", __func__);
HID_DevPlugDevice(p_cback->addr);
bta_sys_conn_open(BTA_ID_HD, 1, p_cback->addr);
bdcpy(cback_data.conn.bda, p_cback->addr);
bdcpy(bta_hd_cb.bd_addr, p_cback->addr);
cback_data.conn.status = BTA_HD_OK;
cback_data.conn.conn_status = BTA_HD_CONN_STATE_CONNECTED;
bta_hd_cb.p_cback(BTA_HD_OPEN_EVT, &cback_data);
}
/*******************************************************************************
*
* Function bta_hd_close_act
*
* Description
*
* Returns void
*
******************************************************************************/
extern void bta_hd_close_act(tBTA_HD_DATA *p_data)
{
tBTA_HD_CBACK_DATA *p_cback = (tBTA_HD_CBACK_DATA *)p_data;
tBTA_HD cback_data;
tBTA_HD_EVT cback_event = BTA_HD_CLOSE_EVT;
APPL_TRACE_API("%s", __func__);
bta_sys_conn_close(BTA_ID_HD, 1, p_cback->addr);
if (bta_hd_cb.vc_unplug) {
bta_hd_cb.vc_unplug = FALSE;
HID_DevUnplugDevice(p_cback->addr);
cback_event = BTA_HD_VC_UNPLUG_EVT;
}
bdcpy(cback_data.conn.bda, p_cback->addr);
memset(bta_hd_cb.bd_addr, 0, sizeof(BD_ADDR));
cback_data.conn.status = BTA_HD_OK;
cback_data.conn.conn_status = BTA_HD_CONN_STATE_DISCONNECTED;
bta_hd_cb.p_cback(cback_event, &cback_data);
}
/*******************************************************************************
*
* Function bta_hd_intr_data_act
*
* Description Handles incoming DATA request on intr
*
* Returns void
*
******************************************************************************/
extern void bta_hd_intr_data_act(tBTA_HD_DATA *p_data)
{
tBTA_HD_CBACK_DATA *p_cback = (tBTA_HD_CBACK_DATA *)p_data;
BT_HDR *p_msg = p_cback->p_data;
uint16_t len = p_msg->len;
uint8_t *p_buf = (uint8_t *)(p_msg + 1) + p_msg->offset;
tBTA_HD_INTR_DATA ret;
APPL_TRACE_API("%s", __func__);
if (bta_hd_cb.use_report_id || bta_hd_cb.boot_mode) {
ret.report_id = *p_buf;
len--;
p_buf++;
} else {
ret.report_id = 0;
}
ret.len = len;
ret.p_data = p_buf;
(*bta_hd_cb.p_cback)(BTA_HD_INTR_DATA_EVT, (tBTA_HD *)&ret);
if (p_msg) {
osi_free(p_msg);
}
}
/*******************************************************************************
*
* Function bta_hd_get_report_act
*
* Description Handles incoming GET_REPORT request
*
* Returns void
*
******************************************************************************/
extern void bta_hd_get_report_act(tBTA_HD_DATA *p_data)
{
tBTA_HD_CBACK_DATA *p_cback = (tBTA_HD_CBACK_DATA *)p_data;
bool rep_size_follows = p_cback->data;
BT_HDR *p_msg = p_cback->p_data;
uint8_t *p_buf = (uint8_t *)(p_msg + 1) + p_msg->offset;
tBTA_HD_GET_REPORT ret = {0, 0, 0};
uint16_t remaining_len = p_msg->len;
APPL_TRACE_API("%s", __func__);
if (remaining_len < 1) {
APPL_TRACE_ERROR("%s invalid data, remaining_len:%d", __func__, remaining_len);
return;
}
ret.report_type = *p_buf & HID_PAR_REP_TYPE_MASK;
p_buf++;
remaining_len--;
if (bta_hd_cb.use_report_id) {
if (remaining_len < 1) {
APPL_TRACE_ERROR("%s invalid data, remaining_len:%d", __func__, remaining_len);
return;
}
ret.report_id = *p_buf;
p_buf++;
remaining_len--;
}
if (rep_size_follows) {
if (remaining_len < 2) {
APPL_TRACE_ERROR("%s invalid data, remaining_len:%d", __func__, remaining_len);
return;
}
ret.buffer_size = *p_buf | (*(p_buf + 1) << 8);
}
(*bta_hd_cb.p_cback)(BTA_HD_GET_REPORT_EVT, (tBTA_HD *)&ret);
if (p_msg) {
osi_free(p_msg);
}
}
/*******************************************************************************
*
* Function bta_hd_set_report_act
*
* Description Handles incoming SET_REPORT request
*
* Returns void
*
******************************************************************************/
extern void bta_hd_set_report_act(tBTA_HD_DATA *p_data)
{
tBTA_HD_CBACK_DATA *p_cback = (tBTA_HD_CBACK_DATA *)p_data;
BT_HDR *p_msg = p_cback->p_data;
uint16_t len = p_msg->len;
uint8_t *p_buf = (uint8_t *)(p_msg + 1) + p_msg->offset;
tBTA_HD_SET_REPORT ret = {0, 0, 0, NULL};
APPL_TRACE_API("%s", __func__);
ret.report_type = *p_buf & HID_PAR_REP_TYPE_MASK;
p_buf++;
len--;
if (bta_hd_cb.use_report_id || bta_hd_cb.boot_mode) {
ret.report_id = *p_buf;
len--;
p_buf++;
} else {
ret.report_id = 0;
}
ret.len = len;
ret.p_data = p_buf;
(*bta_hd_cb.p_cback)(BTA_HD_SET_REPORT_EVT, (tBTA_HD *)&ret);
if (p_msg) {
osi_free(p_msg);
}
}
/*******************************************************************************
*
* Function bta_hd_set_protocol_act
*
* Description
*
* Returns void
*
******************************************************************************/
extern void bta_hd_set_protocol_act(tBTA_HD_DATA *p_data)
{
tBTA_HD_CBACK_DATA *p_cback = (tBTA_HD_CBACK_DATA *)p_data;
tBTA_HD cback_data;
APPL_TRACE_API("%s", __func__);
bta_hd_cb.boot_mode = (p_cback->data == HID_PAR_PROTOCOL_BOOT_MODE);
cback_data.set_protocol = p_cback->data;
(*bta_hd_cb.p_cback)(BTA_HD_SET_PROTOCOL_EVT, &cback_data);
}
/*******************************************************************************
*
* Function bta_hd_vc_unplug_done_act
*
* Description
*
* Returns void
*
******************************************************************************/
extern void bta_hd_vc_unplug_done_act(tBTA_HD_DATA *p_data)
{
tBTA_HD_CBACK_DATA *p_cback = (tBTA_HD_CBACK_DATA *)p_data;
tBTA_HD cback_data;
APPL_TRACE_API("%s", __func__);
bta_sys_conn_close(BTA_ID_HD, 1, p_cback->addr);
HID_DevUnplugDevice(p_cback->addr);
bdcpy(cback_data.conn.bda, p_cback->addr);
bdcpy(bta_hd_cb.bd_addr, p_cback->addr);
cback_data.conn.status = BTA_HD_OK;
cback_data.conn.conn_status = BTA_HD_CONN_STATE_DISCONNECTED;
(*bta_hd_cb.p_cback)(BTA_HD_VC_UNPLUG_EVT, &cback_data);
}
/*******************************************************************************
*
* Function bta_hd_suspend_act
*
* Description
*
* Returns void
*
******************************************************************************/
extern void bta_hd_suspend_act(tBTA_HD_DATA *p_data)
{
tBTA_HD_CBACK_DATA *p_cback = (tBTA_HD_CBACK_DATA *)p_data;
APPL_TRACE_API("%s", __func__);
bta_sys_idle(BTA_ID_HD, 1, p_cback->addr);
}
/*******************************************************************************
*
* Function bta_hd_exit_suspend_act
*
* Description
*
* Returns void
*
******************************************************************************/
extern void bta_hd_exit_suspend_act(tBTA_HD_DATA *p_data)
{
tBTA_HD_CBACK_DATA *p_cback = (tBTA_HD_CBACK_DATA *)p_data;
APPL_TRACE_API("%s", __func__);
bta_sys_busy(BTA_ID_HD, 1, p_cback->addr);
bta_sys_idle(BTA_ID_HD, 1, p_cback->addr);
}
/*******************************************************************************
*
* Function bta_hd_cback
*
* Description BTA HD callback function
*
* Returns void
*
******************************************************************************/
static void bta_hd_cback(BD_ADDR bd_addr, uint8_t event, uint32_t data, BT_HDR *pdata)
{
tBTA_HD_CBACK_DATA *p_buf = NULL;
uint16_t sm_event = BTA_HD_INVALID_EVT;
APPL_TRACE_API("%s: event=%d", __func__, event);
switch (event) {
case HID_DHOST_EVT_OPEN:
sm_event = BTA_HD_INT_OPEN_EVT;
break;
case HID_DHOST_EVT_CLOSE:
sm_event = BTA_HD_INT_CLOSE_EVT;
break;
case HID_DHOST_EVT_GET_REPORT:
sm_event = BTA_HD_INT_GET_REPORT_EVT;
break;
case HID_DHOST_EVT_SET_REPORT:
sm_event = BTA_HD_INT_SET_REPORT_EVT;
break;
case HID_DHOST_EVT_SET_PROTOCOL:
sm_event = BTA_HD_INT_SET_PROTOCOL_EVT;
break;
case HID_DHOST_EVT_INTR_DATA:
sm_event = BTA_HD_INT_INTR_DATA_EVT;
break;
case HID_DHOST_EVT_VC_UNPLUG:
sm_event = BTA_HD_INT_VC_UNPLUG_EVT;
break;
case HID_DHOST_EVT_SUSPEND:
sm_event = BTA_HD_INT_SUSPEND_EVT;
break;
case HID_DHOST_EVT_EXIT_SUSPEND:
sm_event = BTA_HD_INT_EXIT_SUSPEND_EVT;
break;
}
if (sm_event != BTA_HD_INVALID_EVT &&
(p_buf = (tBTA_HD_CBACK_DATA *)osi_malloc(sizeof(tBTA_HD_CBACK_DATA) + sizeof(BT_HDR))) != NULL) {
p_buf->hdr.event = sm_event;
bdcpy(p_buf->addr, bd_addr);
p_buf->data = data;
p_buf->p_data = pdata;
bta_sys_sendmsg(p_buf);
}
}
#endif /* BTA_HD_INCLUDED */

View File

@ -0,0 +1,287 @@
/******************************************************************************
*
* Copyright (C) 2016 The Android Open Source Project
* Copyright (C) 2005-2012 Broadcom Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT 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 contains the HID DEVICE API in the subsystem of BTA.
*
******************************************************************************/
#include "common/bt_target.h"
#if defined(BTA_HD_INCLUDED) && (BTA_HD_INCLUDED == TRUE)
#include "bta/bta_hd_api.h"
#include "bta_hd_int.h"
#include "osi/allocator.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*****************************************************************************
* Constants
****************************************************************************/
static const tBTA_SYS_REG bta_hd_reg = {bta_hd_hdl_event, BTA_HdDisable};
/*******************************************************************************
*
* Function BTA_HdEnable
*
* Description Enables HID device
*
* Returns void
*
******************************************************************************/
void BTA_HdEnable(tBTA_HD_CBACK *p_cback)
{
tBTA_HD_API_ENABLE *p_buf;
APPL_TRACE_API("%s", __func__);
bta_sys_register(BTA_ID_HD, &bta_hd_reg);
p_buf = (tBTA_HD_API_ENABLE *)osi_malloc((uint16_t)sizeof(tBTA_HD_API_ENABLE));
if (p_buf != NULL) {
memset(p_buf, 0, sizeof(tBTA_HD_API_ENABLE));
p_buf->hdr.event = BTA_HD_API_ENABLE_EVT;
p_buf->p_cback = p_cback;
bta_sys_sendmsg(p_buf);
}
}
/*******************************************************************************
*
* Function BTA_HdDisable
*
* Description Disables HID device.
*
* Returns void
*
******************************************************************************/
void BTA_HdDisable(void)
{
BT_HDR *p_buf;
APPL_TRACE_API("%s", __func__);
bta_sys_deregister(BTA_ID_HD);
if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR))) != NULL) {
p_buf->event = BTA_HD_API_DISABLE_EVT;
bta_sys_sendmsg(p_buf);
}
}
/*******************************************************************************
*
* Function BTA_HdRegisterApp
*
* Description This function is called when application should be
*registered
*
* Returns void
*
******************************************************************************/
extern void BTA_HdRegisterApp(tBTA_HD_APP_INFO *p_app_info, tBTA_HD_QOS_INFO *p_in_qos, tBTA_HD_QOS_INFO *p_out_qos)
{
tBTA_HD_REGISTER_APP *p_buf;
APPL_TRACE_API("%s", __func__);
if ((p_buf = (tBTA_HD_REGISTER_APP *)osi_malloc(sizeof(tBTA_HD_REGISTER_APP))) != NULL) {
p_buf->hdr.event = BTA_HD_API_REGISTER_APP_EVT;
if (p_app_info->p_name) {
strncpy(p_buf->name, p_app_info->p_name, BTA_HD_APP_NAME_LEN);
p_buf->name[BTA_HD_APP_NAME_LEN] = '\0';
} else {
p_buf->name[0] = '\0';
}
if (p_app_info->p_description) {
strncpy(p_buf->description, p_app_info->p_description, BTA_HD_APP_DESCRIPTION_LEN);
p_buf->description[BTA_HD_APP_DESCRIPTION_LEN] = '\0';
} else {
p_buf->description[0] = '\0';
}
if (p_app_info->p_provider) {
strncpy(p_buf->provider, p_app_info->p_provider, BTA_HD_APP_PROVIDER_LEN);
p_buf->provider[BTA_HD_APP_PROVIDER_LEN] = '\0';
} else {
p_buf->provider[0] = '\0';
}
p_buf->subclass = p_app_info->subclass;
p_buf->d_len = p_app_info->descriptor.dl_len;
memcpy(p_buf->d_data, p_app_info->descriptor.dsc_list, p_app_info->descriptor.dl_len);
// copy qos data as-is
memcpy(&p_buf->in_qos, p_in_qos, sizeof(tBTA_HD_QOS_INFO));
memcpy(&p_buf->out_qos, p_out_qos, sizeof(tBTA_HD_QOS_INFO));
bta_sys_sendmsg(p_buf);
}
}
/*******************************************************************************
*
* Function BTA_HdUnregisterApp
*
* Description This function is called when application should be
*unregistered
*
* Returns void
*
******************************************************************************/
extern void BTA_HdUnregisterApp(void)
{
BT_HDR *p_buf;
APPL_TRACE_API("%s", __func__);
if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR))) != NULL) {
p_buf->event = BTA_HD_API_UNREGISTER_APP_EVT;
bta_sys_sendmsg(p_buf);
}
}
/*******************************************************************************
*
* Function BTA_HdSendReport
*
* Description This function is called when report is to be sent
*
* Returns void
*
******************************************************************************/
extern void BTA_HdSendReport(tBTA_HD_REPORT *p_report)
{
tBTA_HD_SEND_REPORT *p_buf;
APPL_TRACE_VERBOSE("%s", __func__);
if (p_report->len > BTA_HD_REPORT_LEN) {
APPL_TRACE_WARNING("%s, report len (%d) > MTU len (%d), can't send report."
" Increase value of HID_DEV_MTU_SIZE to send larger reports",
__func__, p_report->len, BTA_HD_REPORT_LEN);
return;
}
if ((p_buf = (tBTA_HD_SEND_REPORT *)osi_malloc(sizeof(tBTA_HD_SEND_REPORT))) != NULL) {
p_buf->hdr.event = BTA_HD_API_SEND_REPORT_EVT;
p_buf->use_intr = p_report->use_intr;
p_buf->type = p_report->type;
p_buf->id = p_report->id;
p_buf->len = p_report->len;
memcpy(p_buf->data, p_report->p_data, p_report->len);
bta_sys_sendmsg(p_buf);
}
}
/*******************************************************************************
*
* Function BTA_HdVirtualCableUnplug
*
* Description This function is called when VCU shall be sent
*
* Returns void
*
******************************************************************************/
extern void BTA_HdVirtualCableUnplug(void)
{
BT_HDR *p_buf;
APPL_TRACE_API("%s", __func__);
if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR))) != NULL) {
p_buf->event = BTA_HD_API_VC_UNPLUG_EVT;
bta_sys_sendmsg(p_buf);
}
}
/*******************************************************************************
*
* Function BTA_HdConnect
*
* Description This function is called when connection to host shall be
* made
*
* Returns void
*
******************************************************************************/
extern void BTA_HdConnect(BD_ADDR addr)
{
tBTA_HD_DEVICE_CTRL *p_buf;
APPL_TRACE_API("%s", __func__);
if ((p_buf = (tBTA_HD_DEVICE_CTRL *)osi_malloc(sizeof(tBTA_HD_DEVICE_CTRL))) != NULL) {
p_buf->hdr.event = BTA_HD_API_CONNECT_EVT;
memcpy(p_buf->addr, addr, sizeof(BD_ADDR));
bta_sys_sendmsg(p_buf);
}
}
/*******************************************************************************
*
* Function BTA_HdDisconnect
*
* Description This function is called when host shall be disconnected
*
* Returns void
*
******************************************************************************/
extern void BTA_HdDisconnect(void)
{
BT_HDR *p_buf;
APPL_TRACE_API("%s", __func__);
if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR))) != NULL) {
p_buf->event = BTA_HD_API_DISCONNECT_EVT;
bta_sys_sendmsg(p_buf);
}
}
/*******************************************************************************
*
* Function BTA_HdAddDevice
*
* Description This function is called when a device is virtually cabled
*
* Returns void
*
******************************************************************************/
extern void BTA_HdAddDevice(BD_ADDR addr)
{
tBTA_HD_DEVICE_CTRL *p_buf;
APPL_TRACE_API("%s", __func__);
if ((p_buf = (tBTA_HD_DEVICE_CTRL *)osi_malloc(sizeof(tBTA_HD_DEVICE_CTRL))) != NULL) {
p_buf->hdr.event = BTA_HD_API_ADD_DEVICE_EVT;
memcpy(p_buf->addr, addr, sizeof(BD_ADDR));
bta_sys_sendmsg(p_buf);
}
}
/*******************************************************************************
*
* Function BTA_HdRemoveDevice
*
* Description This function is called when a device is virtually uncabled
*
* Returns void
*
******************************************************************************/
extern void BTA_HdRemoveDevice(BD_ADDR addr)
{
tBTA_HD_DEVICE_CTRL *p_buf;
APPL_TRACE_API("%s", __func__);
if ((p_buf = (tBTA_HD_DEVICE_CTRL *)osi_malloc(sizeof(tBTA_HD_DEVICE_CTRL))) != NULL) {
p_buf->hdr.event = BTA_HD_API_REMOVE_DEVICE_EVT;
memcpy(p_buf->addr, addr, sizeof(BD_ADDR));
bta_sys_sendmsg(p_buf);
}
}
/*******************************************************************************
*
* Function BTA_HdReportError
*
* Description This function is called when reporting error for set report
*
* Returns void
*
******************************************************************************/
extern void BTA_HdReportError(uint8_t error)
{
tBTA_HD_REPORT_ERR *p_buf;
APPL_TRACE_API("%s", __func__);
if ((p_buf = (tBTA_HD_REPORT_ERR *)osi_malloc(sizeof(tBTA_HD_REPORT_ERR))) != NULL) {
p_buf->hdr.event = BTA_HD_API_REPORT_ERROR_EVT;
p_buf->error = error;
bta_sys_sendmsg(p_buf);
}
}
#endif /* BTA_HD_INCLUDED */

View File

@ -0,0 +1,320 @@
/******************************************************************************
*
* Copyright (C) 2016 The Android Open Source Project
* Copyright (C) 2005-2012 Broadcom Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT 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 contains the HID host main functions and state machine.
*
******************************************************************************/
#include "common/bt_target.h"
#if defined(BTA_HD_INCLUDED) && (BTA_HD_INCLUDED == TRUE)
#include "bta/bta_hd_api.h"
#include "bta_hd_int.h"
#include <string.h>
/*****************************************************************************
* Constants and types
****************************************************************************/
/* state machine states */
enum {
BTA_HD_INIT_ST,
BTA_HD_IDLE_ST, /* not connected, waiting for connection */
BTA_HD_CONN_ST, /* host connected */
BTA_HD_TRANSIENT_TO_INIT_ST, /* transient state: going back from CONN to INIT */
};
typedef uint8_t tBTA_HD_STATE;
/* state machine actions */
enum {
BTA_HD_REGISTER_ACT,
BTA_HD_UNREGISTER_ACT,
BTA_HD_UNREGISTER2_ACT,
BTA_HD_CONNECT_ACT,
BTA_HD_DISCONNECT_ACT,
BTA_HD_ADD_DEVICE_ACT,
BTA_HD_REMOVE_DEVICE_ACT,
BTA_HD_SEND_REPORT_ACT,
BTA_HD_REPORT_ERROR_ACT,
BTA_HD_VC_UNPLUG_ACT,
BTA_HD_OPEN_ACT,
BTA_HD_CLOSE_ACT,
BTA_HD_INTR_DATA_ACT,
BTA_HD_GET_REPORT_ACT,
BTA_HD_SET_REPORT_ACT,
BTA_HD_SET_PROTOCOL_ACT,
BTA_HD_VC_UNPLUG_DONE_ACT,
BTA_HD_SUSPEND_ACT,
BTA_HD_EXIT_SUSPEND_ACT,
BTA_HD_NUM_ACTIONS
};
#define BTA_HD_IGNORE BTA_HD_NUM_ACTIONS
typedef void (*tBTA_HD_ACTION)(tBTA_HD_DATA *p_data);
/* action functions */
const tBTA_HD_ACTION bta_hd_action[] = {
bta_hd_register_act, bta_hd_unregister_act, bta_hd_unregister2_act, bta_hd_connect_act,
bta_hd_disconnect_act, bta_hd_add_device_act, bta_hd_remove_device_act, bta_hd_send_report_act,
bta_hd_report_error_act, bta_hd_vc_unplug_act, bta_hd_open_act, bta_hd_close_act,
bta_hd_intr_data_act, bta_hd_get_report_act, bta_hd_set_report_act, bta_hd_set_protocol_act,
bta_hd_vc_unplug_done_act, bta_hd_suspend_act, bta_hd_exit_suspend_act,
};
/* state table information */
#define BTA_HD_ACTION 0 /* position of action */
#define BTA_HD_NEXT_STATE 1 /* position of next state */
#define BTA_HD_NUM_COLS 2 /* number of columns */
const uint8_t bta_hd_st_init[][BTA_HD_NUM_COLS] = {
/* Event Action Next state
*/
/* BTA_HD_API_REGISTER_APP_EVT */ {BTA_HD_REGISTER_ACT, BTA_HD_IDLE_ST},
/* BTA_HD_API_UNREGISTER_APP_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
/* BTA_HD_API_CONNECT_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
/* BTA_HD_API_DISCONNECT_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
/* BTA_HD_API_ADD_DEVICE_EVT */ {BTA_HD_ADD_DEVICE_ACT, BTA_HD_INIT_ST},
/* BTA_HD_API_REMOVE_DEVICE_EVT */ {BTA_HD_REMOVE_DEVICE_ACT, BTA_HD_INIT_ST},
/* BTA_HD_API_SEND_REPORT_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
/* BTA_HD_API_REPORT_ERROR_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
/* BTA_HD_API_VC_UNPLUG_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
/* BTA_HD_INT_OPEN_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
/* BTA_HD_INT_CLOSE_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
/* BTA_HD_INT_INTR_DATA_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
/* BTA_HD_INT_GET_REPORT_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
/* BTA_HD_INT_SET_REPORT_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
/* BTA_HD_INT_SET_PROTOCOL_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
/* BTA_HD_INT_VC_UNPLUG_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
/* BTA_HD_INT_SUSPEND_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
/* BTA_HD_INT_EXIT_SUSPEND_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
};
const uint8_t bta_hd_st_idle[][BTA_HD_NUM_COLS] = {
/* Event Action Next state
*/
/* BTA_HD_API_REGISTER_APP_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
/* BTA_HD_API_UNREGISTER_APP_EVT */ {BTA_HD_UNREGISTER_ACT, BTA_HD_INIT_ST},
/* BTA_HD_API_CONNECT_EVT */ {BTA_HD_CONNECT_ACT, BTA_HD_IDLE_ST},
/* BTA_HD_API_DISCONNECT_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
/* BTA_HD_API_ADD_DEVICE_EVT */ {BTA_HD_ADD_DEVICE_ACT, BTA_HD_IDLE_ST},
/* BTA_HD_API_REMOVE_DEVICE_EVT */ {BTA_HD_REMOVE_DEVICE_ACT, BTA_HD_IDLE_ST},
/* BTA_HD_API_SEND_REPORT_EVT */ {BTA_HD_SEND_REPORT_ACT, BTA_HD_IDLE_ST},
/* BTA_HD_API_REPORT_ERROR_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
/* BTA_HD_API_VC_UNPLUG_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
/* BTA_HD_INT_OPEN_EVT */ {BTA_HD_OPEN_ACT, BTA_HD_CONN_ST},
/* BTA_HD_INT_CLOSE_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
/* BTA_HD_INT_INTR_DATA_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
/* BTA_HD_INT_GET_REPORT_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
/* BTA_HD_INT_SET_REPORT_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
/* BTA_HD_INT_SET_PROTOCOL_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
/* BTA_HD_INT_VC_UNPLUG_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
/* BTA_HD_INT_SUSPEND_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
/* BTA_HD_INT_EXIT_SUSPEND_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
};
const uint8_t bta_hd_st_conn[][BTA_HD_NUM_COLS] = {
/* Event Action Next state */
/* BTA_HD_API_REGISTER_APP_EVT */ {BTA_HD_IGNORE, BTA_HD_CONN_ST},
/* BTA_HD_API_UNREGISTER_APP_EVT */ {BTA_HD_DISCONNECT_ACT, BTA_HD_TRANSIENT_TO_INIT_ST},
/* BTA_HD_API_CONNECT_EVT */ {BTA_HD_IGNORE, BTA_HD_CONN_ST},
/* BTA_HD_API_DISCONNECT_EVT */ {BTA_HD_DISCONNECT_ACT, BTA_HD_CONN_ST},
/* BTA_HD_API_ADD_DEVICE_EVT */ {BTA_HD_ADD_DEVICE_ACT, BTA_HD_CONN_ST},
/* BTA_HD_API_REMOVE_DEVICE_EVT */ {BTA_HD_REMOVE_DEVICE_ACT, BTA_HD_CONN_ST},
/* BTA_HD_API_SEND_REPORT_EVT */ {BTA_HD_SEND_REPORT_ACT, BTA_HD_CONN_ST},
/* BTA_HD_API_REPORT_ERROR_EVT */ {BTA_HD_REPORT_ERROR_ACT, BTA_HD_CONN_ST},
/* BTA_HD_API_VC_UNPLUG_EVT */ {BTA_HD_VC_UNPLUG_ACT, BTA_HD_CONN_ST},
/* BTA_HD_INT_OPEN_EVT */ {BTA_HD_IGNORE, BTA_HD_CONN_ST},
/* BTA_HD_INT_CLOSE_EVT */ {BTA_HD_CLOSE_ACT, BTA_HD_IDLE_ST},
/* BTA_HD_INT_INTR_DATA_EVT */ {BTA_HD_INTR_DATA_ACT, BTA_HD_CONN_ST},
/* BTA_HD_INT_GET_REPORT_EVT */ {BTA_HD_GET_REPORT_ACT, BTA_HD_CONN_ST},
/* BTA_HD_INT_SET_REPORT_EVT */ {BTA_HD_SET_REPORT_ACT, BTA_HD_CONN_ST},
/* BTA_HD_INT_SET_PROTOCOL_EVT */ {BTA_HD_SET_PROTOCOL_ACT, BTA_HD_CONN_ST},
/* BTA_HD_INT_VC_UNPLUG_EVT */ {BTA_HD_VC_UNPLUG_DONE_ACT, BTA_HD_IDLE_ST},
/* BTA_HD_INT_SUSPEND_EVT */ {BTA_HD_SUSPEND_ACT, BTA_HD_CONN_ST},
/* BTA_HD_INT_EXIT_SUSPEND_EVT */ {BTA_HD_EXIT_SUSPEND_ACT, BTA_HD_CONN_ST},
};
const uint8_t bta_hd_st_transient_to_init[][BTA_HD_NUM_COLS] = {
/* Event Action Next state */
/* BTA_HD_API_REGISTER_APP_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
/* BTA_HD_API_UNREGISTER_APP_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
/* BTA_HD_API_CONNECT_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
/* BTA_HD_API_DISCONNECT_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
/* BTA_HD_API_ADD_DEVICE_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
/* BTA_HD_API_REMOVE_DEVICE_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
/* BTA_HD_API_SEND_REPORT_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
/* BTA_HD_API_REPORT_ERROR_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
/* BTA_HD_API_VC_UNPLUG_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
/* BTA_HD_INT_OPEN_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
/* BTA_HD_INT_CLOSE_EVT */ {BTA_HD_UNREGISTER2_ACT, BTA_HD_INIT_ST},
/* BTA_HD_INT_INTR_DATA_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
/* BTA_HD_INT_GET_REPORT_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
/* BTA_HD_INT_SET_REPORT_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
/* BTA_HD_INT_SET_PROTOCOL_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
/* BTA_HD_INT_VC_UNPLUG_EVT */ {BTA_HD_UNREGISTER2_ACT, BTA_HD_INIT_ST},
/* BTA_HD_INT_SUSPEND_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
/* BTA_HD_INT_EXIT_SUSPEND_EVT */ {BTA_HD_IGNORE, BTA_HD_TRANSIENT_TO_INIT_ST},
};
/* type for state table */
typedef const uint8_t (*tBTA_HD_ST_TBL)[BTA_HD_NUM_COLS];
/* state table */
const tBTA_HD_ST_TBL bta_hd_st_tbl[] = {bta_hd_st_init, bta_hd_st_idle, bta_hd_st_conn, bta_hd_st_transient_to_init};
/*****************************************************************************
* Global data
****************************************************************************/
#if BTA_DYNAMIC_MEMORY == FALSE
tBTA_HD_CB bta_hd_cb;
#else
tBTA_HD_CB *bta_hd_cb_ptr;
#endif
static const char *bta_hd_evt_code(tBTA_HD_INT_EVT evt_code);
static const char *bta_hd_state_code(tBTA_HD_STATE state_code);
/*******************************************************************************
*
* Function bta_hd_sm_execute
*
* Description State machine event handling function for HID Device
*
* Returns void
*
******************************************************************************/
void bta_hd_sm_execute(uint16_t event, tBTA_HD_DATA *p_data)
{
tBTA_HD_ST_TBL state_table;
tBTA_HD_STATE prev_state;
uint8_t action;
tBTA_HD cback_data;
APPL_TRACE_EVENT("%s: state=%s (%d) event=%s (%d)", __func__, bta_hd_state_code(bta_hd_cb.state), bta_hd_cb.state,
bta_hd_evt_code(event), event);
prev_state = bta_hd_cb.state;
memset(&cback_data, 0, sizeof(tBTA_HD));
state_table = bta_hd_st_tbl[bta_hd_cb.state];
event &= 0xff;
if ((action = state_table[event][BTA_HD_ACTION]) < BTA_HD_IGNORE) {
(*bta_hd_action[action])(p_data);
}
bta_hd_cb.state = state_table[event][BTA_HD_NEXT_STATE];
if (bta_hd_cb.state != prev_state) {
APPL_TRACE_EVENT("%s: [new] state=%s (%d)", __func__, bta_hd_state_code(bta_hd_cb.state), bta_hd_cb.state);
}
return;
}
/*******************************************************************************
*
* Function bta_hd_hdl_event
*
* Description HID device main event handling function.
*
* Returns void
*
******************************************************************************/
bool bta_hd_hdl_event(BT_HDR *p_msg)
{
APPL_TRACE_API("%s: p_msg->event=%d", __func__, p_msg->event);
switch (p_msg->event) {
case BTA_HD_API_ENABLE_EVT:
bta_hd_api_enable((tBTA_HD_DATA *)p_msg);
break;
case BTA_HD_API_DISABLE_EVT:
if (bta_hd_cb.state == BTA_HD_CONN_ST) {
APPL_TRACE_WARNING("%s: host connected, disconnect before disabling", __func__);
// unregister (and disconnect)
bta_hd_cb.disable_w4_close = TRUE;
bta_hd_sm_execute(BTA_HD_API_UNREGISTER_APP_EVT, (tBTA_HD_DATA *)p_msg);
} else {
bta_hd_api_disable();
}
break;
default:
bta_hd_sm_execute(p_msg->event, (tBTA_HD_DATA *)p_msg);
}
return (TRUE);
}
static const char *bta_hd_evt_code(tBTA_HD_INT_EVT evt_code)
{
switch (evt_code) {
case BTA_HD_API_REGISTER_APP_EVT:
return "BTA_HD_API_REGISTER_APP_EVT";
case BTA_HD_API_UNREGISTER_APP_EVT:
return "BTA_HD_API_UNREGISTER_APP_EVT";
case BTA_HD_API_CONNECT_EVT:
return "BTA_HD_API_CONNECT_EVT";
case BTA_HD_API_DISCONNECT_EVT:
return "BTA_HD_API_DISCONNECT_EVT";
case BTA_HD_API_ADD_DEVICE_EVT:
return "BTA_HD_API_ADD_DEVICE_EVT";
case BTA_HD_API_REMOVE_DEVICE_EVT:
return "BTA_HD_API_REMOVE_DEVICE_EVT";
case BTA_HD_API_SEND_REPORT_EVT:
return "BTA_HD_API_SEND_REPORT_EVT";
case BTA_HD_API_REPORT_ERROR_EVT:
return "BTA_HD_API_REPORT_ERROR_EVT";
case BTA_HD_API_VC_UNPLUG_EVT:
return "BTA_HD_API_VC_UNPLUG_EVT";
case BTA_HD_INT_OPEN_EVT:
return "BTA_HD_INT_OPEN_EVT";
case BTA_HD_INT_CLOSE_EVT:
return "BTA_HD_INT_CLOSE_EVT";
case BTA_HD_INT_INTR_DATA_EVT:
return "BTA_HD_INT_INTR_DATA_EVT";
case BTA_HD_INT_GET_REPORT_EVT:
return "BTA_HD_INT_GET_REPORT_EVT";
case BTA_HD_INT_SET_REPORT_EVT:
return "BTA_HD_INT_SET_REPORT_EVT";
case BTA_HD_INT_SET_PROTOCOL_EVT:
return "BTA_HD_INT_SET_PROTOCOL_EVT";
case BTA_HD_INT_VC_UNPLUG_EVT:
return "BTA_HD_INT_VC_UNPLUG_EVT";
case BTA_HD_INT_SUSPEND_EVT:
return "BTA_HD_INT_SUSPEND_EVT";
case BTA_HD_INT_EXIT_SUSPEND_EVT:
return "BTA_HD_INT_EXIT_SUSPEND_EVT";
default:
return "<unknown>";
}
}
static const char *bta_hd_state_code(tBTA_HD_STATE state_code)
{
switch (state_code) {
case BTA_HD_INIT_ST:
return "BTA_HD_INIT_ST";
case BTA_HD_IDLE_ST:
return "BTA_HD_IDLE_ST";
case BTA_HD_CONN_ST:
return "BTA_HD_CONN_ST";
case BTA_HD_TRANSIENT_TO_INIT_ST:
return "BTA_HD_TRANSIENT_TO_INIT_ST";
default:
return "<unknown>";
}
}
#endif /* BTA_HD_INCLUDED */

View File

@ -0,0 +1,168 @@
/******************************************************************************
*
* Copyright (C) 2016 The Android Open Source Project
* Copyright (C) 2005-2012 Broadcom Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT 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 contains BTA HID Device internal definitions
*
******************************************************************************/
#ifndef BTA_HD_INT_H
#define BTA_HD_INT_H
#include "bta/bta_hd_api.h"
#include "bta/bta_sys.h"
#include "stack/hiddefs.h"
enum {
BTA_HD_API_REGISTER_APP_EVT = BTA_SYS_EVT_START(BTA_ID_HD),
BTA_HD_API_UNREGISTER_APP_EVT,
BTA_HD_API_CONNECT_EVT,
BTA_HD_API_DISCONNECT_EVT,
BTA_HD_API_ADD_DEVICE_EVT,
BTA_HD_API_REMOVE_DEVICE_EVT,
BTA_HD_API_SEND_REPORT_EVT,
BTA_HD_API_REPORT_ERROR_EVT,
BTA_HD_API_VC_UNPLUG_EVT,
BTA_HD_INT_OPEN_EVT,
BTA_HD_INT_CLOSE_EVT,
BTA_HD_INT_INTR_DATA_EVT,
BTA_HD_INT_GET_REPORT_EVT,
BTA_HD_INT_SET_REPORT_EVT,
BTA_HD_INT_SET_PROTOCOL_EVT,
BTA_HD_INT_VC_UNPLUG_EVT,
BTA_HD_INT_SUSPEND_EVT,
BTA_HD_INT_EXIT_SUSPEND_EVT,
/* handled outside state machine */
BTA_HD_API_ENABLE_EVT,
BTA_HD_API_DISABLE_EVT
};
typedef uint16_t tBTA_HD_INT_EVT;
#define BTA_HD_INVALID_EVT (BTA_HD_API_DISABLE_EVT + 1)
typedef struct {
BT_HDR hdr;
tBTA_HD_CBACK *p_cback;
} tBTA_HD_API_ENABLE;
#define BTA_HD_APP_NAME_LEN 50
#define BTA_HD_APP_DESCRIPTION_LEN 50
#define BTA_HD_APP_PROVIDER_LEN 50
#define BTA_HD_APP_DESCRIPTOR_LEN 2048
#define BTA_HD_STATE_DISABLED 0x00
#define BTA_HD_STATE_ENABLED 0x01
#define BTA_HD_STATE_IDLE 0x02
#define BTA_HD_STATE_CONNECTED 0x03
#define BTA_HD_STATE_DISABLING 0x04
#define BTA_HD_STATE_REMOVING 0x05
typedef struct {
BT_HDR hdr;
char name[BTA_HD_APP_NAME_LEN + 1];
char description[BTA_HD_APP_DESCRIPTION_LEN + 1];
char provider[BTA_HD_APP_PROVIDER_LEN + 1];
uint8_t subclass;
uint16_t d_len;
uint8_t d_data[BTA_HD_APP_DESCRIPTOR_LEN];
tBTA_HD_QOS_INFO in_qos;
tBTA_HD_QOS_INFO out_qos;
} tBTA_HD_REGISTER_APP;
#define BTA_HD_REPORT_LEN HID_DEV_MTU_SIZE
typedef struct {
BT_HDR hdr;
bool use_intr;
uint8_t type;
uint8_t id;
uint16_t len;
uint8_t data[BTA_HD_REPORT_LEN];
} tBTA_HD_SEND_REPORT;
typedef struct {
BT_HDR hdr;
BD_ADDR addr;
} tBTA_HD_DEVICE_CTRL;
typedef struct {
BT_HDR hdr;
uint8_t error;
} tBTA_HD_REPORT_ERR;
/* union of all event data types */
typedef union {
BT_HDR hdr;
tBTA_HD_API_ENABLE api_enable;
tBTA_HD_REGISTER_APP register_app;
tBTA_HD_SEND_REPORT send_report;
tBTA_HD_DEVICE_CTRL device_ctrl;
tBTA_HD_REPORT_ERR report_err;
} tBTA_HD_DATA;
typedef struct {
BT_HDR hdr;
BD_ADDR addr;
uint32_t data;
BT_HDR *p_data;
} tBTA_HD_CBACK_DATA;
/******************************************************************************
* Main Control Block
******************************************************************************/
typedef struct {
tBTA_HD_CBACK *p_cback;
uint32_t sdp_handle;
uint8_t trace_level;
uint8_t state;
BD_ADDR bd_addr;
bool use_report_id;
bool boot_mode;
bool vc_unplug;
bool disable_w4_close;
} tBTA_HD_CB;
#if BTA_DYNAMIC_MEMORY == FALSE
extern tBTA_HD_CB bta_hd_cb;
#else
extern tBTA_HD_CB *bta_hd_cb_ptr;
#define bta_hd_cb (*bta_hd_cb_ptr)
#endif
/*****************************************************************************
* Function prototypes
****************************************************************************/
extern bool bta_hd_hdl_event(BT_HDR *p_msg);
extern void bta_hd_api_enable(tBTA_HD_DATA *p_data);
extern void bta_hd_api_disable(void);
extern void bta_hd_register_act(tBTA_HD_DATA *p_data);
extern void bta_hd_unregister_act(tBTA_HD_DATA *p_data);
extern void bta_hd_unregister2_act(tBTA_HD_DATA *p_data);
extern void bta_hd_connect_act(tBTA_HD_DATA *p_data);
extern void bta_hd_disconnect_act(tBTA_HD_DATA *p_data);
extern void bta_hd_add_device_act(tBTA_HD_DATA *p_data);
extern void bta_hd_remove_device_act(tBTA_HD_DATA *p_data);
extern void bta_hd_send_report_act(tBTA_HD_DATA *p_data);
extern void bta_hd_report_error_act(tBTA_HD_DATA *p_data);
extern void bta_hd_vc_unplug_act(tBTA_HD_DATA *p_data);
extern void bta_hd_open_act(tBTA_HD_DATA *p_data);
extern void bta_hd_close_act(tBTA_HD_DATA *p_data);
extern void bta_hd_intr_data_act(tBTA_HD_DATA *p_data);
extern void bta_hd_get_report_act(tBTA_HD_DATA *p_data);
extern void bta_hd_set_report_act(tBTA_HD_DATA *p_data);
extern void bta_hd_set_protocol_act(tBTA_HD_DATA *p_data);
extern void bta_hd_vc_unplug_done_act(tBTA_HD_DATA *p_data);
extern void bta_hd_suspend_act(tBTA_HD_DATA *p_data);
extern void bta_hd_exit_suspend_act(tBTA_HD_DATA *p_data);
#endif

View File

@ -214,7 +214,7 @@ const UINT8 bta_hf_client_st_closing[][BTA_HF_CLIENT_NUM_COLS] = {
/* DISC_OK_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST},
/* DISC_FAIL_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST},
/* SCO_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST},
/* SCO_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST},
/* SCO_CLOSE_EVT */ {BTA_HF_CLIENT_SCO_CONN_CLOSE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST},
/* SEND_AT_CMD_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST},
#if (BTM_SCO_HCI_INCLUDED == TRUE )
/* CI_SCO_DATA_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_CLOSING_ST},

View File

@ -323,6 +323,7 @@ void bta_hh_start_sdp(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
p_cb->sec_mask = p_data->api_conn.sec_mask;
p_cb->mode = p_data->api_conn.mode;
p_cb->new_mode = p_data->api_conn.mode;
bta_hh_cb.p_cur = p_cb;
#if (BTA_HH_LE_INCLUDED == TRUE)
@ -451,6 +452,8 @@ void bta_hh_sdp_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
HID_HostRemoveDev( p_cb->incoming_hid_handle);
}
conn_dat.status = status;
/* check if host initiate the connection*/
conn_dat.is_orig = !p_cb->incoming_conn;
(* bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn_dat);
/* move state machine W4_CONN ->IDLE */
@ -521,6 +524,8 @@ void bta_hh_open_cmpl_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
memset((void *)&conn, 0, sizeof (tBTA_HH_CONN));
conn.handle = dev_handle;
/* check if host initiate the connection*/
conn.is_orig = !p_cb->incoming_conn;
bdcpy(conn.bda, p_cb->addr);
/* increase connection number */
@ -587,6 +592,7 @@ void bta_hh_open_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
APPL_TRACE_EVENT ("bta_hh_open_act: Device[%d] connected", dev_handle);
#endif
p_cb->incoming_conn = TRUE;
/* SDP has been done */
if (p_cb->app_id != 0) {
bta_hh_sm_execute(p_cb, BTA_HH_OPEN_CMPL_EVT, p_data);
@ -594,7 +600,6 @@ void bta_hh_open_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
/* app_id == 0 indicates an incoming conenction request arrives without SDP
performed, do it first */
{
p_cb->incoming_conn = TRUE;
/* store the handle here in case sdp fails - need to disconnect */
p_cb->incoming_hid_handle = dev_handle;
@ -676,6 +681,11 @@ void bta_hh_handsk_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
case BTA_HH_SET_IDLE_EVT :
cback_data.handle = p_cb->hid_handle;
cback_data.status = bta_hh_get_trans_status(p_data->hid_cback.data);
if (cback_data.status == BTA_HH_OK) {
p_cb->mode = p_cb->new_mode;
} else {
p_cb->new_mode = p_cb->mode;
}
(* bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH *)&cback_data);
p_cb->w4_evt = 0;
break;
@ -684,6 +694,8 @@ void bta_hh_handsk_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
case BTA_HH_OPEN_EVT:
conn.status = p_data->hid_cback.data ? BTA_HH_ERR_PROTO : BTA_HH_OK;
conn.handle = p_cb->hid_handle;
/* check if host initiate the connection*/
conn.is_orig = !p_cb->incoming_conn;
bdcpy(conn.bda, p_cb->addr);
(* bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH *)&conn);
#if BTA_HH_DEBUG
@ -787,6 +799,8 @@ void bta_hh_open_failure(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
conn_dat.handle = p_cb->hid_handle;
conn_dat.status = (reason == HID_ERR_AUTH_FAILED) ?
BTA_HH_ERR_AUTH_FAILED : BTA_HH_ERR;
/* check if host initiate the connection*/
conn_dat.is_orig = !p_cb->incoming_conn;
bdcpy(conn_dat.bda, p_cb->addr);
HID_HostCloseDev(p_cb->hid_handle);
@ -836,6 +850,8 @@ void bta_hh_close_act (tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
/* Failure in opening connection */
conn_dat.handle = p_cb->hid_handle;
conn_dat.status = (reason == HID_ERR_AUTH_FAILED) ? BTA_HH_ERR_AUTH_FAILED : BTA_HH_ERR;
/* check if host initiate the connection*/
conn_dat.is_orig = !p_cb->incoming_conn;
bdcpy(conn_dat.bda, p_cb->addr);
HID_HostCloseDev(p_cb->hid_handle);
@ -1019,7 +1035,9 @@ void bta_hh_maint_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
*******************************************************************************/
void bta_hh_write_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
{
tHID_STATUS status;
tBTA_HH_CBDATA cbdata = {BTA_HH_OK, 0};
tBTA_HH_API_SENDDATA send_data = {BTA_HH_OK, 0, 0};
UINT16 event = (p_data->api_sndcmd.t_type - BTA_HH_FST_BTE_TRANS_EVT) +
BTA_HH_FST_TRANS_CB_EVT;
@ -1031,25 +1049,33 @@ void bta_hh_write_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
{
cbdata.handle = p_cb->hid_handle;
send_data.handle = p_cb->hid_handle;
/* match up BTE/BTA report/boot mode def */
if (p_data->api_sndcmd.t_type == HID_TRANS_SET_PROTOCOL) {
p_cb->new_mode = p_data->api_sndcmd.param;
p_data->api_sndcmd.param = ( p_data->api_sndcmd.param == BTA_HH_PROTO_RPT_MODE) ? \
HID_PAR_PROTOCOL_REPORT : HID_PAR_PROTOCOL_BOOT_MODE;
}
if (HID_HostWriteDev (p_cb->hid_handle,
p_data->api_sndcmd.t_type,
p_data->api_sndcmd.param,
p_data->api_sndcmd.data,
p_data->api_sndcmd.rpt_id,
p_data->api_sndcmd.p_data) != HID_SUCCESS) {
APPL_TRACE_ERROR("HID_HostWriteDev Error ");
status = HID_HostWriteDev(p_cb->hid_handle, p_data->api_sndcmd.t_type, p_data->api_sndcmd.param,
p_data->api_sndcmd.data, p_data->api_sndcmd.rpt_id, p_data->api_sndcmd.p_data);
if (status != HID_SUCCESS) {
APPL_TRACE_ERROR("HID_HostWriteDev status:%d", status);
cbdata.status = BTA_HH_ERR;
send_data.status = BTA_HH_ERR;
if (p_data->api_sndcmd.t_type != HID_TRANS_CONTROL &&
p_data->api_sndcmd.t_type != HID_TRANS_DATA) {
(* bta_hh_cb.p_cback)(event, (tBTA_HH *)&cbdata);
if (p_data->api_sndcmd.t_type != HID_TRANS_CONTROL) {
switch (p_data->api_sndcmd.t_type) {
case HID_TRANS_DATA:
event = BTA_HH_DATA_EVT;
send_data.reason = status;
(*bta_hh_cb.p_cback)(event, (tBTA_HH *)&send_data);
break;
default:
(*bta_hh_cb.p_cback)(event, (tBTA_HH *)&cbdata);
break;
}
} else if (p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG) {
(* bta_hh_cb.p_cback)(BTA_HH_VC_UNPLUG_EVT, (tBTA_HH *)&cbdata);
}
@ -1070,6 +1096,7 @@ void bta_hh_write_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
p_cb->w4_evt = event;
break;
case HID_TRANS_DATA: /* output report */
(*bta_hh_cb.p_cback)(BTA_HH_DATA_EVT, (tBTA_HH *)&send_data);
/* fall through */
case HID_TRANS_CONTROL:
/* no handshake event will be generated */
@ -1098,7 +1125,6 @@ void bta_hh_write_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->addr);
}
}
}
return;
}

Some files were not shown because too many files have changed in this diff Show More