Merge remote-tracking branch 'origin/master' into feature/github-5838

This commit is contained in:
Zim Kalinowski 2021-10-04 08:38:39 +08:00
commit d98b3948b8
1492 changed files with 417923 additions and 41598 deletions

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-v3"
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-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

@ -161,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

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

View File

@ -66,7 +66,7 @@ check_docs_lang_sync:
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
@ -128,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:

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
@ -367,3 +363,10 @@ test_cxx_gpio:
- 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

@ -30,7 +30,7 @@ check_pylint:
- .pre_check_base_template
- .rules:patterns:python-files
- .before_script_minimal
image: $CI_DOCKER_REGISTRY/sonarqube-scanner:2
image: $SONARQUBE_SCANNER_IMAGE
artifacts:
when: always
paths:
@ -62,11 +62,19 @@ check_pylint:
.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 /**
- 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>
- 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"
- export SONAR_SCANNER_OPTS="-Xmx2048m"
variables:
GIT_DEPTH: 0
REPORT_PATTERN: clang_tidy_reports/*.txt
@ -95,8 +103,10 @@ code_quality_check:
-Dsonar.analysis.mode=preview
-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.merge_request_discussion=true
-Dsonar.gitlab.ref_name=$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
-Dsonar.host.url=$SONAR_HOST_URL
-Dsonar.login=$SONAR_LOGIN
@ -112,6 +122,7 @@ code_quality_report:
- sonar-scanner
-Dsonar.branch.name=$CI_COMMIT_REF_NAME
-Dsonar.cxx.clangtidy.reportPath=$REPORT_PATTERN
-Dsonar.exclusions=$EXCLUSIONS
-Dsonar.gitlab.commit_sha=$CI_COMMIT_SHA
-Dsonar.gitlab.ref_name=$CI_COMMIT_REF_NAME
-Dsonar.host.url=$SONAR_HOST_URL

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:
@ -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
@ -482,7 +479,7 @@ UT_006:
UT_007:
extends: .unit_test_esp32_template
parallel: 3
parallel: 4
tags:
- ESP32_IDF
- UT_T1_1
@ -633,7 +630,7 @@ UT_046:
UT_047:
extends: .unit_test_esp32s2_template
parallel: 3
parallel: 5
tags:
- ESP32S2_IDF
- UT_T1_1
@ -644,6 +641,12 @@ 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: 32
@ -682,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
@ -702,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

@ -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,7 +2,24 @@
* [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 进行开发
@ -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

@ -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

@ -502,6 +502,7 @@ menu "Security features"
bool "Enable hardware Secure Boot in bootloader (READ DOCS FIRST)"
default n
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.
@ -892,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

@ -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

@ -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

@ -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

@ -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();

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

@ -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();

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

@ -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

@ -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"
@ -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();

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

@ -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

@ -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;
@ -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:

@ -1 +1 @@
Subproject commit fb49791b7c1a8a35f06e68124c90022667b4cff1
Subproject commit fe0a3d00f11dbf9d219f2a291e3cab7419e5cac1

@ -1 +1 @@
Subproject commit 9ca8afd50afde57958a67fca65847edc52f7d91c
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

@ -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
@ -4498,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)
/*******************************************************************************
**

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;
}

View File

@ -24,9 +24,9 @@
******************************************************************************/
#include "common/bt_target.h"
#include "bta/bta_hh_api.h"
#if defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == TRUE)
#include "bta/bta_hh_api.h"
/* max number of device types supported by BTA */

View File

@ -32,7 +32,7 @@
#include "bta/utl.h"
#define LOG_TAG "bt_bta_hh"
#include "osi/include/log.h"
// #include "osi/include/log.h"
#ifndef BTA_HH_LE_RECONN
#define BTA_HH_LE_RECONN TRUE

View File

@ -292,6 +292,8 @@ void bta_hh_sm_execute(tBTA_HH_DEV_CB *p_cb, UINT16 event, tBTA_HH_DATA *p_data)
bdcpy(cback_data.conn.bda, ((tBTA_HH_API_CONN *)p_data)->bd_addr);
cback_data.conn.status = BTA_HH_ERR_DB_FULL;
cback_data.conn.handle = BTA_HH_INVALID_HANDLE;
/* check if host initiate the connection*/
cback_data.conn.is_orig = !p_cb->incoming_conn;
break;
/* DB full, BTA_HhAddDev */
case BTA_HH_API_MAINT_DEV_EVT:
@ -340,7 +342,7 @@ void bta_hh_sm_execute(tBTA_HH_DEV_CB *p_cb, UINT16 event, tBTA_HH_DATA *p_data)
default:
/* invalid handle, call bad API event */
APPL_TRACE_ERROR("wrong device handle: [%d]", p_data->hdr.layer_specific);
APPL_TRACE_ERROR("wrong device handle: [%d], event:%d", p_data->hdr.layer_specific, event - BTA_HH_API_OPEN_EVT);
/* Free the callback buffer now */
if (p_data != NULL && p_data->hid_cback.p_data != NULL) {
osi_free(p_data->hid_cback.p_data);
@ -443,6 +445,10 @@ BOOLEAN bta_hh_hdl_event(BT_HDR *p_msg)
}
} else if (p_msg->event == BTA_HH_INT_OPEN_EVT) {
index = bta_hh_find_cb(((tBTA_HH_CBACK_DATA *)p_msg)->addr);
uint8_t hdl = BTA_HH_IDX_INVALID;
if (HID_HostGetDev(((tBTA_HH_CBACK_DATA *)p_msg)->addr, &hdl) == HID_SUCCESS && hdl != BTA_HH_IDX_INVALID) {
bta_hh_cb.cb_index[hdl] = bta_hh_cb.kdev[index].index;
}
} else {
index = bta_hh_dev_handle_to_cb_idx((UINT8)p_msg->layer_specific);
}

View File

@ -237,7 +237,7 @@ BOOLEAN bta_hh_tod_spt(tBTA_HH_DEV_CB *p_cb, UINT8 sub_class)
}
}
#if BTA_HH_DEBUG
APPL_TRACE_EVENT("bta_hh_tod_spt sub_class:0x%x NOT supported", sub_class);
APPL_TRACE_ERROR("bta_hh_tod_spt sub_class:0x%x NOT supported", sub_class);
#endif
return FALSE;
}
@ -460,9 +460,11 @@ void bta_hh_cleanup_disable(tBTA_HH_STATUS status)
}
utl_freebuf((void **)&bta_hh_cb.p_disc_db);
(* bta_hh_cb.p_cback)(BTA_HH_DISABLE_EVT, (tBTA_HH *)&status);
/* all connections are down, no waiting for diconnect */
memset(&bta_hh_cb, 0, sizeof(tBTA_HH_CB));
if (bta_hh_cb.p_cback) {
(*bta_hh_cb.p_cback)(BTA_HH_DISABLE_EVT, (tBTA_HH*)&status);
/* all connections are down, no waiting for diconnect */
memset(&bta_hh_cb, 0, sizeof(tBTA_HH_CB));
}
}
/*******************************************************************************

View File

@ -243,6 +243,7 @@ typedef struct {
UINT8 incoming_hid_handle; /* temporary handle for incoming connection? */
BOOLEAN opened; /* TRUE if device successfully opened HID connection */
tBTA_HH_PROTO_MODE mode; /* protocol mode */
tBTA_HH_PROTO_MODE new_mode; /* protocol mode */
tBTA_HH_STATE state; /* CB state */
#if (BTA_HH_LE_INCLUDED == TRUE)
@ -364,6 +365,7 @@ extern void bta_hh_disc_cmpl(void);
extern tBTA_HH_STATUS bta_hh_read_ssr_param(BD_ADDR bd_addr, UINT16 *p_max_ssr_lat, UINT16 *p_min_ssr_tout);
/* functions for LE HID */
#if (BTA_HH_LE_INCLUDED == TRUE)
extern void bta_hh_le_enable(void);
extern BOOLEAN bta_hh_le_is_hh_gatt_if(tBTA_GATTC_IF client_if);
extern void bta_hh_le_deregister(void);
@ -391,6 +393,7 @@ extern void bta_hh_security_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf);
extern void bta_hh_le_update_scpp(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf);
extern void bta_hh_le_notify_enc_cmpl(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data);
extern void bta_hh_ci_load_rpt (tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_buf);
#endif
#if BTA_HH_DEBUG
extern void bta_hh_trace_dev_db(void);

View File

@ -78,7 +78,7 @@ typedef UINT8 tBTA_STATUS;
#define BTA_SAP_SERVICE_ID 17 /* SIM Access profile */
#define BTA_A2DP_SINK_SERVICE_ID 18 /* A2DP Sink */
#define BTA_AVRCP_SERVICE_ID 19 /* A/V remote control */
#define BTA_HID_SERVICE_ID 20 /* HID */
#define BTA_HID_SERVICE_ID 20 /* HID Host*/
#define BTA_VDP_SERVICE_ID 21 /* Video distribution */
#define BTA_PBAP_SERVICE_ID 22 /* PhoneBook Access Server*/
#define BTA_HSP_HS_SERVICE_ID 23 /* HFP HS role */
@ -1331,8 +1331,8 @@ typedef UINT8 tBTA_DM_PM_ACTION;
#endif
#ifndef BTA_DM_PM_SNIFF2_MAX
#define BTA_DM_PM_SNIFF2_MAX 180
#define BTA_DM_PM_SNIFF2_MIN 150
#define BTA_DM_PM_SNIFF2_MAX 54 //180
#define BTA_DM_PM_SNIFF2_MIN 30 //150
#define BTA_DM_PM_SNIFF2_ATTEMPT 4
#define BTA_DM_PM_SNIFF2_TIMEOUT 1
#endif
@ -1345,8 +1345,8 @@ typedef UINT8 tBTA_DM_PM_ACTION;
#endif
#ifndef BTA_DM_PM_SNIFF4_MAX
#define BTA_DM_PM_SNIFF4_MAX 54
#define BTA_DM_PM_SNIFF4_MIN 30
#define BTA_DM_PM_SNIFF4_MAX 18 //54
#define BTA_DM_PM_SNIFF4_MIN 10 //30
#define BTA_DM_PM_SNIFF4_ATTEMPT 4
#define BTA_DM_PM_SNIFF4_TIMEOUT 1
#endif

View File

@ -0,0 +1,295 @@
/******************************************************************************
*
* Copyright (C) 2016 The Android Open Source Project
* Copyright (C) 2002-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.
*
******************************************************************************/
#ifndef BTA_HD_API_H
#define BTA_HD_API_H
#include "bta_api.h"
#include "stack/hidd_api.h"
#if BTA_HD_INCLUDED == TRUE
/*****************************************************************************
* Constants and Type Definitions
****************************************************************************/
#ifndef BTA_HD_DEBUG
#define BTA_HD_DEBUG TRUE
#endif
/* BTA HID Device callback events */
#define BTA_HD_ENABLE_EVT 0 /* BT-HD enabled */
#define BTA_HD_DISABLE_EVT 1 /* BT-HD disabled */
#define BTA_HD_REGISTER_APP_EVT 2 /* application registered */
#define BTA_HD_UNREGISTER_APP_EVT 3 /* application unregistered */
#define BTA_HD_OPEN_EVT 4 /* connection to host opened */
#define BTA_HD_CLOSE_EVT 5 /* connection to host closed */
#define BTA_HD_GET_REPORT_EVT 6 /* GET_REPORT request from host */
#define BTA_HD_SET_REPORT_EVT 7 /* SET_REPORT request from host */
#define BTA_HD_SET_PROTOCOL_EVT 8 /* SET_PROTOCOL request from host */
#define BTA_HD_INTR_DATA_EVT 9 /* DATA received from host on intr */
#define BTA_HD_VC_UNPLUG_EVT 10 /* Virtual Cable Unplug */
// #define BTA_HD_CONN_STATE_EVT 11 /* Report connection state change */
#define BTA_HD_SEND_REPORT_EVT 12 /* Send report finish */
#define BTA_HD_REPORT_ERR_EVT 13 /* Report Handshake finish */
#define BTA_HD_API_ERR_EVT 99 /* BT-HD API error */
typedef uint16_t tBTA_HD_EVT;
enum { BTA_HD_OK, BTA_HD_ERROR };
typedef enum {
BTA_HD_CONN_STATE_CONNECTED,
BTA_HD_CONN_STATE_CONNECTING,
BTA_HD_CONN_STATE_DISCONNECTED,
BTA_HD_CONN_STATE_DISCONNECTING,
BTA_HD_CONN_STATE_UNKNOWN
} tBTA_HD_CONN_STAT;
typedef uint8_t tBTA_HD_STATUS;
typedef tHID_DEV_DSCP_INFO tBTA_HD_DEV_DESCR;
typedef struct {
char *p_name;
char *p_description;
char *p_provider;
uint8_t subclass;
tBTA_HD_DEV_DESCR descriptor;
} tBTA_HD_APP_INFO;
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;
} tBTA_HD_QOS_INFO;
typedef struct {
bool use_intr;
uint8_t type;
uint8_t id;
uint16_t len;
uint8_t *p_data;
} tBTA_HD_REPORT;
typedef struct {
tBTA_HD_STATUS status;
bool in_use;
BD_ADDR bda;
} tBTA_HD_REG_STATUS;
typedef struct {
BD_ADDR bda;
tBTA_HD_STATUS status;
tBTA_HD_CONN_STAT conn_status;
} tBTA_HD_CONN;
typedef struct {
uint8_t report_type;
uint8_t report_id;
uint16_t buffer_size;
} tBTA_HD_GET_REPORT;
typedef struct {
uint8_t report_type;
uint8_t report_id;
uint16_t len;
uint8_t *p_data;
} tBTA_HD_SET_REPORT;
typedef uint8_t tBTA_HD_SET_PROTOCOL;
typedef struct {
uint8_t report_id;
uint16_t len;
uint8_t *p_data;
} tBTA_HD_INTR_DATA;
typedef struct {
tBTA_HD_STATUS status;
uint8_t reason;
uint8_t report_type;
uint8_t report_id;
} tBTA_HD_API_SEND_REPORT;
typedef struct {
tBTA_HD_STATUS status;
uint8_t reason;
} tBTA_HD_API_REPORT_ERR;
/* union of data associated with HD callback */
typedef union {
tBTA_HD_STATUS status; /* BTA_HD_ENABLE_EVT
BTA_HD_DISABLE_EVT
BTA_HD_UNREGISTER_APP_EVT */
tBTA_HD_REG_STATUS reg_status; /* BTA_HD_REGISTER_APP_EVT */
tBTA_HD_CONN conn; /* BTA_HD_OPEN_EVT
BTA_HD_CLOSE_EVT
BTA_HD_VC_UNPLUG_EVT
BTA_HD_OWN_VC_UNPLUG_EVT */
tBTA_HD_GET_REPORT get_report; /* BTA_HD_GET_REPORT */
tBTA_HD_SET_REPORT set_report; /* BTA_HD_SET_REPORT */
tBTA_HD_SET_PROTOCOL set_protocol; /* BTA_HD_SETPROTOCOL */
tBTA_HD_INTR_DATA intr_data; /* BTA_HD_INTR_DATA_EVT */
tBTA_HD_API_SEND_REPORT send_report; /* BTA_HD_API_SEND_REPORT_EVT */
tBTA_HD_API_REPORT_ERR report_err; /* BTA_HD_API_REPORT_ERR_EVT */
} tBTA_HD;
/* BTA HD callback function */
typedef void (tBTA_HD_CBACK)(tBTA_HD_EVT event, tBTA_HD *p_data);
/*****************************************************************************
* External Function Declarations
****************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
/*******************************************************************************
*
* Function BTA_HhRegister
*
* Description This function enable HID host and registers HID-Host with
* lower layers.
*
* Returns void
*
******************************************************************************/
extern void BTA_HdEnable(tBTA_HD_CBACK *p_cback);
/*******************************************************************************
*
* Function BTA_HhDeregister
*
* Description This function is called when the host is about power down.
*
* Returns void
*
******************************************************************************/
extern void BTA_HdDisable(void);
/*******************************************************************************
*
* 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);
/*******************************************************************************
*
* Function BTA_HdUnregisterApp
*
* Description This function is called when application should be
* unregistered
*
* Returns void
*
******************************************************************************/
extern void BTA_HdUnregisterApp(void);
/*******************************************************************************
*
* 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);
/*******************************************************************************
*
* Function BTA_HdVirtualCableUnplug
*
* Description This function is called when VCU shall be sent
*
* Returns void
*
******************************************************************************/
extern void BTA_HdVirtualCableUnplug(void);
/*******************************************************************************
*
* Function BTA_HdConnect
*
* Description This function is called when connection to host shall be
* made.
*
* Returns void
*
******************************************************************************/
extern void BTA_HdConnect(BD_ADDR addr);
/*******************************************************************************
*
* Function BTA_HdDisconnect
*
* Description This function is called when host shall be disconnected
*
* Returns void
*
******************************************************************************/
extern void BTA_HdDisconnect(void);
/*******************************************************************************
*
* Function BTA_HdAddDevice
*
* Description This function is called when a device is virtually cabled
*
* Returns void
*
******************************************************************************/
extern void BTA_HdAddDevice(BD_ADDR addr);
/*******************************************************************************
*
* Function BTA_HdRemoveDevice
*
* Description This function is called when a device is virtually uncabled
*
* Returns void
*
******************************************************************************/
extern void BTA_HdRemoveDevice(BD_ADDR addr);
/*******************************************************************************
*
* Function BTA_HdReportError
*
* Description This function is called when reporting error for set report
*
* Returns void
*
******************************************************************************/
extern void BTA_HdReportError(uint8_t error);
#ifdef __cplusplus
}
#endif
#endif /* BTA_HD_INCLUDED */
#endif /* BTA_HD_API_H */

View File

@ -58,7 +58,8 @@
#define BTA_HH_VC_UNPLUG_EVT 13 /* virtually unplugged */
#define BTA_HH_DATA_EVT 15
#define BTA_HH_API_ERR_EVT 16 /* API error is caught */
#define BTA_HH_UPDATE_SCPP_EVT 17 /* update scan paramter complete */
#define BTA_HH_UPDATE_SCPP_EVT 17 /* update scan paramter complete */
#define BTA_HH_DATA_IND_EVT 18 /* Data on interrupt channel */
typedef UINT16 tBTA_HH_EVT;
@ -131,8 +132,8 @@ enum {
BTA_HH_ERR_TOD_UNSPT, /* type of device not supported */
BTA_HH_ERR_NO_RES, /* out of system resources */
BTA_HH_ERR_AUTH_FAILED, /* authentication fail */
BTA_HH_ERR_HDL,
BTA_HH_ERR_SEC
BTA_HH_ERR_HDL, /* connection handle error */
BTA_HH_ERR_SEC, /* encryption error */
};
typedef UINT8 tBTA_HH_STATUS;
@ -210,6 +211,7 @@ typedef struct {
BD_ADDR bda; /* HID device bd address */
tBTA_HH_STATUS status; /* operation status */
UINT8 handle; /* device handle */
BOOLEAN is_orig; /* indicate if host initiate connection */
#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
BOOLEAN le_hid; /* is LE devices? */
BOOLEAN scps_supported; /* scan parameter service supported */
@ -257,9 +259,9 @@ typedef struct {
typedef struct {
tBTA_HH_BOOT_RPT_ID dev_type; /* type of device report */
union {
tBTA_HH_KEYBD_RPT keybd_rpt; /* keyboard report */
tBTA_HH_MICE_RPT mice_rpt; /* mouse report */
} data_rpt;
tBTA_HH_KEYBD_RPT keybd_rpt; /* keyboard report */
tBTA_HH_MICE_RPT mice_rpt; /* mouse report */
} data_rpt;
} tBTA_HH_BOOT_RPT;
/* handshake data */
@ -267,13 +269,29 @@ typedef struct {
tBTA_HH_STATUS status; /* handshake status */
UINT8 handle; /* device handle */
union {
tBTA_HH_PROTO_MODE proto_mode; /* GET_PROTO_EVT :protocol mode */
BT_HDR *p_rpt_data; /* GET_RPT_EVT : report data */
UINT8 idle_rate; /* GET_IDLE_EVT : idle rate */
} rsp_data;
tBTA_HH_PROTO_MODE proto_mode; /* GET_PROTO_EVT :protocol mode */
BT_HDR *p_rpt_data; /* GET_RPT_EVT : report data */
UINT8 idle_rate; /* GET_IDLE_EVT : idle rate */
} rsp_data;
} tBTA_HH_HSDATA;
/* upper layer send data */
typedef struct {
tBTA_HH_STATUS status; /* handshake status */
UINT8 handle; /* device handle */
UINT8 reason; /* send data failed reason */
} tBTA_HH_API_SENDDATA;
/* interrupt channel data */
typedef struct {
tBTA_HH_STATUS status; /* handshake status */
UINT8 handle; /* device handle */
tBTA_HH_PROTO_MODE proto_mode; /* protocol mode */
BT_HDR *p_data; /* DATA_EVT : feature report data */
} tBTA_HH_INTDATA;
/* union of data associated with HD callback */
typedef union {
tBTA_HH_DEV_INFO dev_info; /* BTA_HH_ADD_DEV_EVT, BTA_HH_RMV_DEV_EVT */
@ -290,10 +308,12 @@ typedef union {
BTA_HH_GET_RPT_EVT
BTA_HH_GET_PROTO_EVT
BTA_HH_GET_IDLE_EVT */
tBTA_HH_API_SENDDATA send_data; /* BTA_HH_DATA_EVT */
tBTA_HH_INTDATA int_data; /* BTA_HH_DATA_IND_EVT */
} tBTA_HH;
/* BTA HH callback function */
typedef void (tBTA_HH_CBACK) (tBTA_HH_EVT event, tBTA_HH *p_data);
typedef void (tBTA_HH_CBACK)(tBTA_HH_EVT event, tBTA_HH *p_data);
/*****************************************************************************

View File

@ -16,11 +16,13 @@
#include "btc/btc_storage.h"
#include "btc/btc_util.h"
#include "osi/osi.h"
#include "osi/allocator.h"
#include "common/bt_trace.h"
#include "esp_system.h"
#include "bta/bta_api.h"
#include "device/bdaddr.h"
#include "btc/btc_config.h"
#include "btc_hh.h"
/*******************************************************************************
**
@ -247,3 +249,252 @@ bt_status_t btc_storage_get_bonded_bt_devices_list(bt_bdaddr_t *bond_dev, int *d
return BT_STATUS_SUCCESS;
}
#if (defined BTC_HH_INCLUDED && BTC_HH_INCLUDED == TRUE)
/*******************************************************************************
*
* Function btc_storage_add_hid_device_info
*
* Description BTC storage API - Adds the hid information of bonded hid
* devices-to NVRAM
*
* Returns BT_STATUS_SUCCESS if the store was successful,
* BT_STATUS_FAIL otherwise
*
******************************************************************************/
bt_status_t btc_storage_add_hid_device_info(bt_bdaddr_t *remote_bd_addr, uint16_t attr_mask, uint8_t sub_class,
uint8_t app_id, uint16_t vendor_id, uint16_t product_id, uint16_t version,
uint8_t ctry_code, uint16_t ssr_max_latency, uint16_t ssr_min_tout,
uint16_t dl_len, uint8_t *dsc_list)
{
BTC_TRACE_DEBUG("btc_storage_add_hid_device_info:");
bdstr_t bdstr;
bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
btc_config_lock();
int ret = btc_config_set_int(bdstr, "HidAttrMask", attr_mask);
ret &= btc_config_set_int(bdstr, "HidSubClass", sub_class);
ret &= btc_config_set_int(bdstr, "HidAppId", app_id);
ret &= btc_config_set_int(bdstr, "HidVendorId", vendor_id);
ret &= btc_config_set_int(bdstr, "HidProductId", product_id);
ret &= btc_config_set_int(bdstr, "HidVersion", version);
ret &= btc_config_set_int(bdstr, "HidCountryCode", ctry_code);
ret &= btc_config_set_int(bdstr, "HidSSRMaxLatency", ssr_max_latency);
ret &= btc_config_set_int(bdstr, "HidSSRMinTimeout", ssr_min_tout);
if (dl_len > 0)
btc_config_set_bin(bdstr, "HidDescriptor", dsc_list, dl_len);
btc_config_flush();
btc_config_unlock();
BTC_TRACE_DEBUG("Storage add hid device info %d\n", ret);
return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
}
/*******************************************************************************
*
* Function btc_storage_load_bonded_hid_info
*
* Description BTIF storage API - Loads hid info for all the bonded devices
* from NVRAM and adds those devices to the BTA_HH.
*
* Returns BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
*
******************************************************************************/
bt_status_t btc_storage_load_bonded_hid_info(void)
{
int value;
btc_config_lock();
for (const btc_config_section_iter_t *iter = btc_config_section_begin(); iter != btc_config_section_end();
iter = btc_config_section_next(iter)) {
const char *name = btc_config_section_name(iter);
if (string_is_bdaddr(name) && btc_config_exist(name, BTC_STORAGE_LINK_KEY_TYPE_STR) &&
btc_config_exist(name, BTC_STORAGE_PIN_LENGTH_STR) && btc_config_exist(name, BTC_STORAGE_SC_SUPPORT) &&
btc_config_exist(name, BTC_STORAGE_LINK_KEY_STR) && btc_config_exist(name, "HidAttrMask")) {
btc_config_get_int(name, "HidAttrMask", &value);
uint16_t attr_mask = (uint16_t)value;
tBTA_HH_DEV_DSCP_INFO dscp_info;
memset(&dscp_info, 0, sizeof(dscp_info));
btc_config_get_int(name, "HidSubClass", &value);
uint8_t sub_class = (uint8_t)value;
btc_config_get_int(name, "HidAppId", &value);
uint8_t app_id = (uint8_t)value;
btc_config_get_int(name, "HidVendorId", &value);
dscp_info.vendor_id = (uint16_t)value;
btc_config_get_int(name, "HidProductId", &value);
dscp_info.product_id = (uint16_t)value;
btc_config_get_int(name, "HidVersion", &value);
dscp_info.version = (uint8_t)value;
btc_config_get_int(name, "HidCountryCode", &value);
dscp_info.ctry_code = (uint8_t)value;
value = 0;
btc_config_get_int(name, "HidSSRMaxLatency", &value);
dscp_info.ssr_max_latency = (uint16_t)value;
value = 0;
btc_config_get_int(name, "HidSSRMinTimeout", &value);
dscp_info.ssr_min_tout = (uint16_t)value;
size_t len = btc_config_get_bin_length(name, "HidDescriptor");
if (len > 0) {
dscp_info.descriptor.dl_len = (uint16_t)len;
dscp_info.descriptor.dsc_list = (uint8_t *)osi_malloc(len);
btc_config_get_bin(name, "HidDescriptor", (uint8_t *)dscp_info.descriptor.dsc_list, &len);
}
// add extracted information to BTA HH
bt_bdaddr_t bd_addr;
if (string_to_bdaddr(name, &bd_addr) && btc_hh_add_added_dev(*(BD_ADDR *)&bd_addr, attr_mask)) {
BTA_HhAddDev(*(BD_ADDR *)&bd_addr, attr_mask, sub_class, app_id, dscp_info);
}
if (dscp_info.descriptor.dsc_list) {
osi_free(dscp_info.descriptor.dsc_list);
dscp_info.descriptor.dsc_list = NULL;
}
}
}
btc_config_unlock();
return BT_STATUS_SUCCESS;
}
/*******************************************************************************
*
* Function btc_storage_remove_hid_info
*
* Description BTC storage API - Deletes the bonded hid device info from
* NVRAM
*
* Returns BT_STATUS_SUCCESS if the deletion was successful,
* BT_STATUS_FAIL otherwise
*
******************************************************************************/
bt_status_t btc_storage_remove_hid_info(bt_bdaddr_t *remote_bd_addr)
{
bdstr_t bdstr;
bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
int ret = 1;
btc_config_lock();
if (btc_config_exist(bdstr, "HidAttrMask")) {
ret &= btc_config_remove(bdstr, "HidAttrMask");
}
if (btc_config_exist(bdstr, "HidSubClass")) {
ret &= btc_config_remove(bdstr, "HidSubClass");
}
if (btc_config_exist(bdstr, "HidAppId")) {
ret &= btc_config_remove(bdstr, "HidAppId");
}
if (btc_config_exist(bdstr, "HidVendorId")) {
ret &= btc_config_remove(bdstr, "HidVendorId");
}
if (btc_config_exist(bdstr, "HidProductId")) {
ret &= btc_config_remove(bdstr, "HidProductId");
}
if (btc_config_exist(bdstr, "HidVersion")) {
ret &= btc_config_remove(bdstr, "HidVersion");
}
if (btc_config_exist(bdstr, "HidCountryCode")) {
ret &= btc_config_remove(bdstr, "HidCountryCode");
}
if (btc_config_exist(bdstr, "HidSSRMaxLatency")) {
ret &= btc_config_remove(bdstr, "HidSSRMaxLatency");
}
if (btc_config_exist(bdstr, "HidSSRMinTimeout")) {
ret &= btc_config_remove(bdstr, "HidSSRMinTimeout");
}
if (btc_config_exist(bdstr, "HidDescriptor")) {
ret &= btc_config_remove(bdstr, "HidDescriptor");
}
btc_config_flush();
btc_config_unlock();
BTC_TRACE_DEBUG("%s ret:%d", __func__, ret);
return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
}
#endif //(defined BTC_HH_INCLUDED && BTC_HH_INCLUDED == TRUE)
#if (defined BTC_HD_INCLUDED && BTC_HD_INCLUDED == TRUE)
#include "bta/bta_hd_api.h"
/*******************************************************************************
* Function btc_storage_load_hidd
*
* Description Loads hidd bonded device and "plugs" it into hidd
*
* Returns BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
*
******************************************************************************/
bt_status_t btc_storage_load_hidd(void)
{
bt_bdaddr_t bd_addr;
int value;
btc_config_lock();
for (const btc_config_section_iter_t *iter = btc_config_section_begin(); iter != btc_config_section_end();
iter = btc_config_section_next(iter)) {
const char *name = btc_config_section_name(iter);
if (string_is_bdaddr(name) && btc_config_exist(name, BTC_STORAGE_LINK_KEY_TYPE_STR) &&
btc_config_exist(name, BTC_STORAGE_PIN_LENGTH_STR) && btc_config_exist(name, BTC_STORAGE_SC_SUPPORT) &&
btc_config_exist(name, BTC_STORAGE_LINK_KEY_STR)) {
BTC_TRACE_DEBUG("Remote device:%s", name);
if (btc_config_get_int(name, "HidDeviceCabled", &value)) {
string_to_bdaddr(name, &bd_addr);
BTA_HdAddDevice(bd_addr.address);
break;
}
}
}
btc_config_unlock();
return BT_STATUS_SUCCESS;
}
/*******************************************************************************
*
* Function btc_storage_set_hidd
*
* Description Stores hidd bonded device info in nvram.
*
* Returns BT_STATUS_SUCCESS
*
******************************************************************************/
bt_status_t btc_storage_set_hidd(bt_bdaddr_t *remote_bd_addr)
{
bdstr_t bdstr = {0};
bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
btc_config_lock();
int ret = btc_config_set_int(bdstr, "HidDeviceCabled", 1);
btc_config_flush();
btc_config_unlock();
BTC_TRACE_DEBUG("%s ret:%d", __func__, ret);
return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
}
/*******************************************************************************
*
* Function btc_storage_remove_hidd
*
* Description Removes hidd bonded device info from nvram
*
* Returns BT_STATUS_SUCCESS
*
******************************************************************************/
bt_status_t btc_storage_remove_hidd(bt_bdaddr_t *remote_bd_addr)
{
bdstr_t bdstr;
int ret = 0;
bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
btc_config_lock();
if (btc_config_exist(bdstr, "HidVersion")) {
ret = btc_config_remove(bdstr, "HidDeviceCabled");
}
btc_config_flush();
btc_config_unlock();
BTC_TRACE_DEBUG("%s ret:%d", __func__, ret);
return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
}
#endif //(defined BTC_HD_INCLUDED && BTC_HD_INCLUDED == TRUE)

View File

@ -35,6 +35,10 @@
#include "bta/bta_ag_api.h"
#endif ///BTA_AG_INCLUDED == TRUE
#if (BTA_HH_INCLUDED == TRUE)
#include "bta/bta_hh_api.h"
#endif ///BTA_HH_INCLUDED == TRUE
#include "bta/bta_hd_api.h"
#include "common/bt_defs.h"
#include "stack/btm_api.h"
#include "bta/bta_api.h"
@ -209,6 +213,56 @@ const char* dump_hf_call_setup_state(esp_hf_call_setup_status_t call_setup_state
#endif // #if (BTA_AG_INCLUDED == TRUE)
#if (BTA_HH_INCLUDED == TRUE)
const char *dump_hh_event(uint16_t event)
{
switch (event) {
CASE_RETURN_STR(BTA_HH_ENABLE_EVT)
CASE_RETURN_STR(BTA_HH_DISABLE_EVT)
CASE_RETURN_STR(BTA_HH_OPEN_EVT)
CASE_RETURN_STR(BTA_HH_CLOSE_EVT)
CASE_RETURN_STR(BTA_HH_GET_RPT_EVT)
CASE_RETURN_STR(BTA_HH_SET_RPT_EVT)
CASE_RETURN_STR(BTA_HH_GET_PROTO_EVT)
CASE_RETURN_STR(BTA_HH_SET_PROTO_EVT)
CASE_RETURN_STR(BTA_HH_GET_IDLE_EVT)
CASE_RETURN_STR(BTA_HH_SET_IDLE_EVT)
CASE_RETURN_STR(BTA_HH_GET_DSCP_EVT)
CASE_RETURN_STR(BTA_HH_ADD_DEV_EVT)
CASE_RETURN_STR(BTA_HH_RMV_DEV_EVT)
CASE_RETURN_STR(BTA_HH_VC_UNPLUG_EVT)
CASE_RETURN_STR(BTA_HH_DATA_EVT)
CASE_RETURN_STR(BTA_HH_API_ERR_EVT)
CASE_RETURN_STR(BTA_HH_UPDATE_SCPP_EVT)
CASE_RETURN_STR(BTA_HH_DATA_IND_EVT)
default:
return "UNKNOWN MSG ID";
}
}
#endif ///BTA_HH_INCLUDED
#if BTA_HD_INCLUDED == TRUE
const char* dump_hd_event(uint16_t event) {
switch (event) {
CASE_RETURN_STR(BTA_HD_ENABLE_EVT)
CASE_RETURN_STR(BTA_HD_DISABLE_EVT)
CASE_RETURN_STR(BTA_HD_REGISTER_APP_EVT)
CASE_RETURN_STR(BTA_HD_UNREGISTER_APP_EVT)
CASE_RETURN_STR(BTA_HD_OPEN_EVT)
CASE_RETURN_STR(BTA_HD_CLOSE_EVT)
CASE_RETURN_STR(BTA_HD_GET_REPORT_EVT)
CASE_RETURN_STR(BTA_HD_SET_REPORT_EVT)
CASE_RETURN_STR(BTA_HD_SET_PROTOCOL_EVT)
CASE_RETURN_STR(BTA_HD_INTR_DATA_EVT)
CASE_RETURN_STR(BTA_HD_VC_UNPLUG_EVT)
//CASE_RETURN_STR(BTA_HD_CONN_STATE_EVT)
CASE_RETURN_STR(BTA_HD_API_ERR_EVT)
default:
return "UNKNOWN MSG ID";
}
}
#endif ///BTA_HD_INCLUDED
UINT32 devclass2uint(DEV_CLASS dev_class)
{
UINT32 cod = 0;

View File

@ -27,6 +27,10 @@
#define BTC_STORAGE_PIN_LENGTH_STR "PinLength"
#define BTC_STORAGE_SC_SUPPORT "SCSupport"
#ifdef __cplusplus
extern "C" {
#endif
/*******************************************************************************
**
** Function btc_storage_add_bonded_device
@ -91,4 +95,85 @@ int btc_storage_get_num_bt_bond_devices(void);
*******************************************************************************/
bt_status_t btc_storage_get_bonded_bt_devices_list(bt_bdaddr_t *bond_dev, int *dev_num);
#if (defined BTC_HH_INCLUDED && BTC_HH_INCLUDED == TRUE)
/*******************************************************************************
*
* Function btc_storage_add_hid_device_info
*
* Description BTC storage API - Adds the hid information of bonded hid
* devices-to NVRAM
*
* Returns BT_STATUS_SUCCESS if the store was successful,
* BT_STATUS_FAIL otherwise
*
******************************************************************************/
bt_status_t btc_storage_add_hid_device_info(bt_bdaddr_t *remote_bd_addr, uint16_t attr_mask, uint8_t sub_class,
uint8_t app_id, uint16_t vendor_id, uint16_t product_id, uint16_t version,
uint8_t ctry_code, uint16_t ssr_max_latency, uint16_t ssr_min_tout,
uint16_t dl_len, uint8_t *dsc_list);
/*******************************************************************************
*
* Function btc_storage_load_bonded_hid_info
*
* Description BTIF storage API - Loads hid info for all the bonded devices
* from NVRAM and adds those devices to the BTA_HH.
*
* Returns BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
*
******************************************************************************/
bt_status_t btc_storage_load_bonded_hid_info(void);
/*******************************************************************************
*
* Function btc_storage_remove_hid_info
*
* Description BTC storage API - Deletes the bonded hid device info from
* NVRAM
*
* Returns BT_STATUS_SUCCESS if the deletion was successful,
* BT_STATUS_FAIL otherwise
*
******************************************************************************/
bt_status_t btc_storage_remove_hid_info(bt_bdaddr_t *remote_bd_addr);
#endif // (defined BTC_HH_INCLUDED && BTC_HH_INCLUDED == TRUE)
#if (defined BTC_HD_INCLUDED && BTC_HD_INCLUDED == TRUE)
/*******************************************************************************
* Function btc_storage_load_hidd
*
* Description Loads hidd bonded device and "plugs" it into hidd
*
* Returns BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
*
******************************************************************************/
bt_status_t btc_storage_load_hidd(void);
/*******************************************************************************
*
* Function btc_storage_set_hidd
*
* Description Stores hidd bonded device info in nvram.
*
* Returns BT_STATUS_SUCCESS
*
******************************************************************************/
bt_status_t btc_storage_set_hidd(bt_bdaddr_t *remote_bd_addr);
/*******************************************************************************
*
* Function btc_storage_remove_hidd
*
* Description Removes hidd bonded device info from nvram
*
* Returns BT_STATUS_SUCCESS
*
******************************************************************************/
bt_status_t btc_storage_remove_hidd(bt_bdaddr_t *remote_bd_addr);
#endif //(defined BTC_HD_INCLUDED && BTC_HD_INCLUDED == TRUE)
#ifdef __cplusplus
}
#endif
#endif /* BTC_STORAGE_H */

View File

@ -31,7 +31,9 @@
********************************************************************************/
typedef char bdstr_t[18];
#ifdef __cplusplus
extern "C" {
#endif
/*******************************************************************************
** Functions
********************************************************************************/
@ -48,6 +50,14 @@ const char *dump_hf_call_state(esp_hf_call_status_t call_state);
const char* dump_hf_call_setup_state(esp_hf_call_setup_status_t call_setup_state);
#endif
#if(BTA_HD_INCLUDED == TRUE)
const char* dump_hd_event(uint16_t event);
#endif
#if(BTA_HH_INCLUDED == TRUE)
const char* dump_hh_event(uint16_t event);
#endif
UINT32 devclass2uint(DEV_CLASS dev_class);
void uint2devclass(UINT32 dev, DEV_CLASS dev_class);
void uuid128_be_to_esp_uuid(esp_bt_uuid_t *u, uint8_t* uuid128);
@ -58,4 +68,8 @@ esp_bt_status_t btc_hci_to_esp_status(uint8_t hci_status);
esp_bt_status_t btc_btm_status_to_esp_status (uint8_t btm_status);
esp_bt_status_t btc_bta_status_to_esp_status (uint8_t bta_status);
#ifdef __cplusplus
}
#endif
#endif /* __BTC_UTIL_H__ */

View File

@ -0,0 +1,152 @@
#include "btc_hh.h"
#include "osi/allocator.h"
#include "string.h"
#if HID_HOST_INCLUDED == TRUE
/*******************************************************************************
*
* Function bta_hh_co_open
*
* Description When connection is opened, this call-out function is executed
* by HH to do platform specific initialization.
*
* Returns void.
******************************************************************************/
void bta_hh_co_open(uint8_t dev_handle, uint8_t sub_class, tBTA_HH_ATTR_MASK attr_mask, uint8_t app_id)
{
uint32_t i;
btc_hh_device_t *p_dev = NULL;
if (dev_handle == BTA_HH_INVALID_HANDLE) {
APPL_TRACE_WARNING("%s: Oops, dev_handle (%d) is invalid...", __func__, dev_handle);
return;
}
for (i = 0; i < BTC_HH_MAX_HID; i++) {
p_dev = &btc_hh_cb.devices[i];
if (p_dev->dev_status != ESP_HIDH_CONN_STATE_UNKNOWN && p_dev->dev_handle == dev_handle) {
// We found a device with the same handle. Must be a device reconnected.
APPL_TRACE_WARNING("%s: Found an existing device with the same handle dev_status=%d, "
"dev_handle=0x%2x, attr_mask=0x%04x, sub_class=0x%02x, app_id=%d",
__func__, p_dev->dev_status, dev_handle, p_dev->attr_mask, p_dev->sub_class,
p_dev->app_id);
break;
}
p_dev = NULL;
}
if (p_dev == NULL) {
// Did not find a device reconnection case. Find an empty slot now.
for (i = 0; i < BTC_HH_MAX_HID; i++) {
if (btc_hh_cb.devices[i].dev_status == ESP_HIDH_CONN_STATE_UNKNOWN) {
p_dev = &btc_hh_cb.devices[i];
p_dev->dev_handle = dev_handle;
p_dev->attr_mask = attr_mask;
p_dev->sub_class = sub_class;
p_dev->app_id = app_id;
p_dev->local_vup = false;
btc_hh_cb.device_num++;
break;
}
}
}
if (p_dev == NULL) {
APPL_TRACE_ERROR("%s: Error: too many HID devices are connected", __func__);
return;
}
p_dev->dev_status = ESP_HIDH_CONN_STATE_CONNECTED;
APPL_TRACE_DEBUG("%s: Return device status %d", __func__, p_dev->dev_status);
}
/*******************************************************************************
*
* Function bta_hh_co_close
*
* Description When connection is closed, this call-out function is executed
* by HH to do platform specific finalization.
*
* Parameters dev_handle - device handle
* app_id - application id
*
* Returns void.
******************************************************************************/
void bta_hh_co_close(uint8_t dev_handle, uint8_t app_id)
{
uint32_t i;
btc_hh_device_t *p_dev = NULL;
APPL_TRACE_WARNING("%s: dev_handle = %d, app_id = %d", __func__, dev_handle, app_id);
if (dev_handle == BTA_HH_INVALID_HANDLE) {
APPL_TRACE_WARNING("%s: Oops, dev_handle (%d) is invalid...", __func__, dev_handle);
return;
}
for (i = 0; i < BTC_HH_MAX_HID; i++) {
p_dev = &btc_hh_cb.devices[i];
if (p_dev->dev_status != ESP_HIDH_CONN_STATE_UNKNOWN && p_dev->dev_handle == dev_handle) {
APPL_TRACE_WARNING("%s: Found an existing device with the same handle "
"dev_status = %d, dev_handle =%d",
__func__, p_dev->dev_status, p_dev->dev_handle);
break;
}
}
}
/*******************************************************************************
*
* Function bta_hh_co_data
*
* Description This function is executed by BTA when HID host receive a
* data report on interrupt channel.
*
* Parameters dev_handle - device handle
* *p_rpt - pointer to the report data
* len - length of report data
* mode - Hid host Protocol Mode
* sub_clas - Device Subclass
* app_id - application id
*
* Returns void
******************************************************************************/
void bta_hh_co_data(UINT8 dev_handle, UINT8 *p_rpt, UINT16 len, tBTA_HH_PROTO_MODE mode, UINT8 sub_class, UINT8 ctry_code,
BD_ADDR peer_addr, UINT8 app_id)
{
btc_msg_t msg;
tBTA_HH p_data;
BT_HDR *p_buf = NULL;
bt_status_t status;
tBTA_HH_STATUS ret = BTA_HH_OK;
msg.sig = BTC_SIG_API_CB;
msg.pid = BTC_PID_HH;
msg.act = BTA_HH_DATA_IND_EVT;
APPL_TRACE_DEBUG("%s: dev_handle = %d, subclass = 0x%02X, mode = %d, "
"ctry_code = %d, app_id = %d",
__func__, dev_handle, sub_class, mode, ctry_code, app_id);
do {
if ((p_buf = osi_malloc(sizeof(BT_HDR) + len)) == NULL) {
APPL_TRACE_ERROR("%s malloc failed!", __func__);
ret = BTA_HH_ERR_NO_RES;
break;
}
p_buf->offset = 0;
p_buf->len = len;
p_buf->event = 0;
p_buf->layer_specific = dev_handle;
memcpy(p_buf->data, p_rpt, len);
} while (0);
p_data.int_data.status = ret;
p_data.int_data.handle = dev_handle;
p_data.int_data.p_data = p_buf;
p_data.int_data.proto_mode = mode;
status = btc_transfer_context(&msg, &p_data, sizeof(tBTA_HH), NULL);
assert(status == BT_STATUS_SUCCESS);
}
#endif /* HID_HOST_INCLUDED == TRUE */

View File

@ -0,0 +1,831 @@
/******************************************************************************
*
* Copyright (C) 2016 The Android Open Source Project
* Copyright (C) 2009-2012 Broadcom Corporation
* Copyright (C) 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.
*
******************************************************************************/
/************************************************************************************
*
* Filename: btc_hd.c
*
* Description: HID Device Profile Bluetooth Interface
*
*
***********************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bta/bta_api.h"
#include "bta/bta_hd_api.h"
#include "bta/bta_hh_api.h"
#include "bta/utl.h"
#include "btc/btc_storage.h"
#include "btc/btc_util.h"
#include "btc/btc_manage.h"
#include "btc_hd.h"
#include "osi/allocator.h"
#include "esp_hidd_api.h"
#if HID_DEV_INCLUDED == TRUE
#include "bta_dm_int.h"
/* HD request events */
typedef enum { BTC_HD_DUMMY_REQ_EVT = 0 } btc_hd_req_evt_t;
/*******************************************************************************
* Static variables
******************************************************************************/
btc_hd_cb_t btc_hd_cb;
// static tBTA_HD_APP_INFO app_info;
// static tBTA_HD_QOS_INFO in_qos;
// static tBTA_HD_QOS_INFO out_qos;
/******************************************************************************
* Constants & Macros
*****************************************************************************/
#define BTC_HD_APP_NAME_LEN 50
#define BTC_HD_APP_DESCRIPTION_LEN 50
#define BTC_HD_APP_PROVIDER_LEN 50
#define BTC_HD_APP_DESCRIPTOR_LEN 2048
#define COD_HID_KEYBOARD 0x0540
#define COD_HID_POINTING 0x0580
#define COD_HID_COMBO 0x05C0
#define COD_HID_MAJOR 0x0500
#define is_hidd_init() (btc_hd_cb.status > BTC_HD_DISABLED)
#define is_hidd_app_register() (btc_hd_cb.app_registered)
typedef void (bt_hid_copy_cb_t)(btc_msg_t *msg, void *p_dest, void *p_src);
static inline void btc_hd_cb_to_app(esp_hidd_cb_event_t event, esp_hidd_cb_param_t *param)
{
esp_hd_cb_t *btc_hd_cb = (esp_hd_cb_t *)btc_profile_cb_get(BTC_PID_HD);
if (btc_hd_cb) {
btc_hd_cb(event, param);
}
}
static void free_app_info_param(void)
{
utl_freebuf((void **)&btc_hd_cb.app_info.descriptor.dsc_list);
utl_freebuf((void **)&btc_hd_cb.app_info.p_provider);
utl_freebuf((void **)&btc_hd_cb.app_info.p_description);
utl_freebuf((void **)&btc_hd_cb.app_info.p_name);
}
static void bte_hd_arg_deep_copy(btc_msg_t *msg, void *p_dst, void *p_src)
{
tBTA_HD *p_dst_data = (tBTA_HD *)p_dst;
tBTA_HD *p_src_data = (tBTA_HD *)p_src;
switch (msg->act)
{
case BTA_HD_SET_REPORT_EVT: {
uint8_t *src_data = p_src_data->set_report.p_data;
if (src_data) {
p_dst_data->set_report.p_data = osi_malloc(p_src_data->set_report.len);
if (p_dst_data->set_report.p_data == NULL) {
BTC_TRACE_ERROR("%s malloc set_report data failed!", __func__);
break;
}
memcpy(p_dst_data->set_report.p_data, src_data, p_src_data->set_report.len);
}
break;
}
case BTA_HD_INTR_DATA_EVT: {
uint8_t *src_data = p_src_data->intr_data.p_data;
if (src_data) {
p_dst_data->intr_data.p_data = osi_malloc(p_src_data->intr_data.len);
if (p_dst_data->intr_data.p_data == NULL) {
BTC_TRACE_ERROR("%s malloc intr_data data failed!", __func__);
break;
}
memcpy(p_dst_data->intr_data.p_data, src_data, p_src_data->intr_data.len);
}
break;
}
default:
break;
}
}
/*******************************************************************************
*
* Function btc_hd_remove_device
*
* Description Removes plugged device
*
* Returns void
*
******************************************************************************/
void btc_hd_remove_device(bt_bdaddr_t bd_addr)
{
BTA_HdRemoveDevice((uint8_t *)&bd_addr);
// btc_storage_remove_hidd(&bd_addr);
}
/*******************************************************************************
*
* Function bte_hd_evt
*
* Description Switches context from BTE to BTC for all BT-HD events
*
* Returns void
*
******************************************************************************/
static void bte_hd_evt(tBTA_HD_EVT event, tBTA_HD *p_data)
{
bt_status_t status;
int param_len = 0;
BTC_TRACE_API("%s event=%d", __func__, event);
switch (event) {
case BTA_HD_ENABLE_EVT:
case BTA_HD_DISABLE_EVT:
case BTA_HD_UNREGISTER_APP_EVT:
param_len = sizeof(tBTA_HD_STATUS);
break;
case BTA_HD_REGISTER_APP_EVT:
param_len = sizeof(tBTA_HD_REG_STATUS);
break;
case BTA_HD_OPEN_EVT:
case BTA_HD_CLOSE_EVT:
case BTA_HD_VC_UNPLUG_EVT:
param_len = sizeof(tBTA_HD_CONN);
break;
case BTA_HD_GET_REPORT_EVT:
param_len += sizeof(tBTA_HD_GET_REPORT);
break;
case BTA_HD_SET_REPORT_EVT:
param_len = sizeof(tBTA_HD_SET_REPORT);
break;
case BTA_HD_SET_PROTOCOL_EVT:
param_len += sizeof(p_data->set_protocol);
break;
case BTA_HD_INTR_DATA_EVT:
param_len = sizeof(tBTA_HD_INTR_DATA);
break;
case BTA_HD_SEND_REPORT_EVT:
param_len = sizeof(tBTA_HD_API_SEND_REPORT);
break;
case BTA_HD_REPORT_ERR_EVT:
param_len = sizeof(tBTA_HD_API_REPORT_ERR);
break;
}
btc_msg_t msg;
msg.sig = BTC_SIG_API_CB;
msg.pid = BTC_PID_HD;
msg.act = event;
status = btc_transfer_context(&msg, p_data, param_len, bte_hd_arg_deep_copy);
if (status != BT_STATUS_SUCCESS) {
BTC_TRACE_ERROR("context transfer failed");
}
}
/*******************************************************************************
*
* Function btc_hd_init
*
* Description Initializes BT-HD interface
*
* Returns void
*
******************************************************************************/
static void btc_hd_init(void)
{
BTC_TRACE_API("%s", __func__);
esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
do {
if (is_hidd_init()) {
BTC_TRACE_ERROR("%s HD has been initiated, shall uninit first!", __func__);
ret = ESP_HIDD_NEED_DEINIT;
break;
}
memset(&btc_hd_cb, 0, sizeof(btc_hd_cb));
/* enable HD */
BTA_HdEnable(bte_hd_evt);
} while (0);
if (ret != ESP_HIDD_SUCCESS) {
esp_hidd_cb_param_t param;
param.init.status = ret;
btc_hd_cb_to_app(ESP_HIDD_INIT_EVT, &param);
}
}
/*******************************************************************************
*
* Function btc_hd_deinit
*
* Description de-initializes the hd interface
*
* Returns void
*
******************************************************************************/
static void btc_hd_unregister_app(void);
static void btc_hd_deinit(void)
{
BTC_TRACE_API("%s", __func__);
esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
do {
if (!is_hidd_init()) {
BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__);
ret = ESP_HIDD_NEED_INIT;
break;
}
btc_hd_cb.service_dereg_active = FALSE;
btc_hd_cb.status = BTC_HD_DISABLING;
// unresgister app will also relase the connection
// and disable after receiving unregister event from lower layer
if (is_hidd_app_register()) {
btc_hd_unregister_app();
} else {
BTC_TRACE_WARNING("%s disabling hid device service now", __func__);
BTA_HdDisable();
}
} while (0);
if (ret != ESP_HIDD_SUCCESS) {
esp_hidd_cb_param_t param;
param.deinit.status = ret;
btc_hd_cb_to_app(ESP_HIDD_DEINIT_EVT, &param);
}
}
/*******************************************************************************
*
* Function btc_hd_register_app
*
* Description Registers HID Device application
*
* Returns void
*
******************************************************************************/
static void btc_hd_register_app(esp_hidd_app_param_t *p_app_param, esp_hidd_qos_param_t *p_in_qos,
esp_hidd_qos_param_t *p_out_qos)
{
BTC_TRACE_API("%s", __func__);
esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
do {
if (!is_hidd_init()) {
BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__);
ret = ESP_HIDD_NEED_INIT;
break;
}
if (is_hidd_app_register()) {
BTC_TRACE_ERROR("%s: application already registered, shall deregister first!", __func__);
ret = ESP_HIDD_NEED_DEREG;
break;
}
if ((btc_hd_cb.app_info.p_name = (char *)osi_malloc(BTC_HD_APP_NAME_LEN)) == NULL ||
(btc_hd_cb.app_info.p_description = (char *)osi_malloc(BTC_HD_APP_DESCRIPTION_LEN)) == NULL ||
(btc_hd_cb.app_info.p_provider = (char *)osi_malloc(BTC_HD_APP_PROVIDER_LEN)) == NULL ||
(btc_hd_cb.app_info.descriptor.dsc_list = (uint8_t *)osi_malloc(p_app_param->desc_list_len)) == NULL) {
BTC_TRACE_ERROR(
"%s malloc app_info failed! p_name:%p, p_description:%p, p_provider:%p, descriptor.dsc_list:%p",
__func__, btc_hd_cb.app_info.p_name, btc_hd_cb.app_info.p_description, btc_hd_cb.app_info.p_provider,
btc_hd_cb.app_info.descriptor.dsc_list);
ret = ESP_HIDD_NO_RES;
break;
}
memcpy(btc_hd_cb.app_info.p_name, p_app_param->name, BTC_HD_APP_NAME_LEN);
memcpy(btc_hd_cb.app_info.p_description, p_app_param->description, BTC_HD_APP_DESCRIPTION_LEN);
memcpy(btc_hd_cb.app_info.p_provider, p_app_param->provider, BTC_HD_APP_PROVIDER_LEN);
memcpy(btc_hd_cb.app_info.descriptor.dsc_list, p_app_param->desc_list, p_app_param->desc_list_len);
btc_hd_cb.app_info.subclass = p_app_param->subclass;
btc_hd_cb.app_info.descriptor.dl_len = p_app_param->desc_list_len;
btc_hd_cb.in_qos.service_type = p_in_qos->service_type;
btc_hd_cb.in_qos.token_rate = p_in_qos->token_rate;
btc_hd_cb.in_qos.token_bucket_size = p_in_qos->token_bucket_size;
btc_hd_cb.in_qos.peak_bandwidth = p_in_qos->peak_bandwidth;
btc_hd_cb.in_qos.access_latency = p_in_qos->access_latency;
btc_hd_cb.in_qos.delay_variation = p_in_qos->delay_variation;
btc_hd_cb.out_qos.service_type = p_out_qos->service_type;
btc_hd_cb.out_qos.token_rate = p_out_qos->token_rate;
btc_hd_cb.out_qos.token_bucket_size = p_out_qos->token_bucket_size;
btc_hd_cb.out_qos.peak_bandwidth = p_out_qos->peak_bandwidth;
btc_hd_cb.out_qos.access_latency = p_out_qos->access_latency;
btc_hd_cb.out_qos.delay_variation = p_out_qos->delay_variation;
BTA_HdRegisterApp(&btc_hd_cb.app_info, &btc_hd_cb.in_qos, &btc_hd_cb.out_qos);
} while(0);
if (ret != ESP_HIDD_SUCCESS) {
esp_hidd_cb_param_t param;
param.register_app.status = ret;
param.register_app.in_use = false;
memset(param.register_app.bd_addr, 0, BD_ADDR_LEN);
btc_hd_cb_to_app(ESP_HIDD_REGISTER_APP_EVT, &param);
}
free_app_info_param();
}
/*******************************************************************************
*
* Function btc_hd_unregister_app
*
* Description Unregisters HID Device application
*
* Returns void
*
******************************************************************************/
static void btc_hd_unregister_app(void)
{
BTC_TRACE_API("%s", __func__);
esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
do {
if (!is_hidd_init()) {
BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__);
ret = ESP_HIDD_NEED_INIT;
break;
}
if (!is_hidd_app_register()) {
BTC_TRACE_ERROR("%s: application has not been registered, shall register first!", __func__);
ret = ESP_HIDD_NEED_REG;
break;
}
if (btc_hd_cb.service_dereg_active) {
BTC_TRACE_ERROR("%s: BT-HD deregistering in progress", __func__);
ret = ESP_HIDD_BUSY;
break;
}
btc_hd_cb.service_dereg_active = TRUE;
BTA_HdUnregisterApp();
} while(0);
if (ret != ESP_HIDD_SUCCESS) {
esp_hidd_cb_param_t param;
param.unregister_app.status = ret;
btc_hd_cb_to_app(ESP_HIDD_UNREGISTER_APP_EVT, &param);
}
}
/*******************************************************************************
*
* Function btc_hd_connect
*
* Description Connects to host
*
* Returns void
*
******************************************************************************/
static void btc_hd_connect(BD_ADDR bd_addr)
{
BTC_TRACE_API("%s", __func__);
esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
do {
if (!is_hidd_init()) {
BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__);
ret = ESP_HIDD_NEED_INIT;
break;
}
if (!is_hidd_app_register()) {
BTC_TRACE_ERROR("%s: application has not been registered, shall register first!", __func__);
ret = ESP_HIDD_NEED_REG;
break;
}
BTA_HdConnect(bd_addr);
} while (0);
if (ret != ESP_HIDD_SUCCESS) {
esp_hidd_cb_param_t param;
param.open.status = ret;
param.open.conn_status = ESP_HIDD_CONN_STATE_DISCONNECTED;
memcpy(param.open.bd_addr, bd_addr, BD_ADDR_LEN);
btc_hd_cb_to_app(ESP_HIDD_OPEN_EVT, &param);
}
}
/*******************************************************************************
*
* Function btc_hd_disconnect
*
* Description Disconnects from host
*
* Returns void
*
******************************************************************************/
static void btc_hd_disconnect(void)
{
BTC_TRACE_API("%s", __func__);
esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
do {
if (!is_hidd_init()) {
BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__);
ret = ESP_HIDD_NEED_INIT;
break;
}
if (!is_hidd_app_register()) {
BTC_TRACE_ERROR("%s: application has not been registered, shall register first!", __func__);
ret = ESP_HIDD_NEED_REG;
break;
}
BTA_HdDisconnect();
} while (0);
if (ret != ESP_HIDD_SUCCESS) {
esp_hidd_cb_param_t param;
param.close.status = ret;
param.close.conn_status = ESP_HIDD_CONN_STATE_DISCONNECTED;
btc_hd_cb_to_app(ESP_HIDD_CLOSE_EVT, &param);
}
}
/*******************************************************************************
*
* Function btc_hd_send_report
*
* Description Sends Reports to hid host
*
* Returns void
*
******************************************************************************/
static void btc_hd_send_report(esp_hidd_report_type_t type, uint8_t id, uint16_t len, uint8_t *p_data)
{
tBTA_HD_REPORT report;
BTC_TRACE_API("%s: type=%d id=%d len=%d", __func__, type, id, len);
esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
do {
if (!is_hidd_init()) {
BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__);
ret = ESP_HIDD_NEED_INIT;
break;
}
if (!is_hidd_app_register()) {
BTC_TRACE_ERROR("%s: application has not been registered, shall register first!", __func__);
ret = ESP_HIDD_NEED_REG;
break;
}
if (type == ESP_HIDD_REPORT_TYPE_INTRDATA) {
report.type = ESP_HIDD_REPORT_TYPE_INPUT;
report.use_intr = TRUE;
} else {
report.type = (type & 0x03);
report.use_intr = FALSE;
}
report.id = id;
report.len = len;
report.p_data = p_data;
BTA_HdSendReport(&report);
} while (0);
if (ret != ESP_HIDD_SUCCESS) {
esp_hidd_cb_param_t param;
param.send_report.status = ret;
param.send_report.reason = 0;
param.send_report.report_type = report.type;
param.send_report.report_id = report.id;
btc_hd_cb_to_app(ESP_HIDD_SEND_REPORT_EVT, &param);
}
}
/*******************************************************************************
*
* Function btc_hd_report_error
*
* Description Sends HANDSHAKE with error info for invalid SET_REPORT
*
* Returns void
*
******************************************************************************/
static void btc_hd_report_error(uint8_t error)
{
BTC_TRACE_API("%s", __func__);
esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
do {
if (!is_hidd_init()) {
BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__);
ret = ESP_HIDD_NEED_INIT;
break;
}
if (!is_hidd_app_register()) {
BTC_TRACE_ERROR("%s: application has not been registered, shall register first!", __func__);
ret = ESP_HIDD_NEED_REG;
break;
}
BTA_HdReportError(error);
} while (0);
if (ret != ESP_HIDD_SUCCESS) {
esp_hidd_cb_param_t param;
param.report_err.status = ret;
param.report_err.reason = 0;
btc_hd_cb_to_app(ESP_HIDD_REPORT_ERR_EVT, &param);
}
}
/*******************************************************************************
*
* Function btc_hd_virtual_cable_unplug
*
* Description Sends Virtual Cable Unplug to host
*
* Returns void
*
******************************************************************************/
static void btc_hd_virtual_cable_unplug(void)
{
BTC_TRACE_API("%s", __func__);
esp_hidd_status_t ret = ESP_HIDD_SUCCESS;
do {
if (!is_hidd_init()) {
BTC_TRACE_ERROR("%s HD has not been initiated, shall init first!", __func__);
ret = ESP_HIDD_NEED_INIT;
break;
}
if (!is_hidd_app_register()) {
BTC_TRACE_ERROR("%s: application has not been registered, shall register first!", __func__);
ret = ESP_HIDD_NEED_REG;
break;
}
BTA_HdVirtualCableUnplug();
} while (0);
if (ret != ESP_HIDD_SUCCESS) {
esp_hidd_cb_param_t param;
param.report_err.status = ret;
param.report_err.reason = 0;
btc_hd_cb_to_app(ESP_HIDD_VC_UNPLUG_EVT, &param);
}
}
static void btc_hd_call_arg_deep_free(btc_msg_t *msg)
{
btc_hidd_args_t *arg = (btc_hidd_args_t *)msg->arg;
switch (msg->act) {
case BTC_HD_SEND_REPORT_EVT:
utl_freebuf((void **)&arg->send_report.data);
break;
default:
break;
}
}
void btc_hd_call_handler(btc_msg_t *msg)
{
btc_hidd_args_t *arg = (btc_hidd_args_t *)(msg->arg);
switch (msg->act) {
case BTC_HD_INIT_EVT:
btc_hd_init();
break;
case BTC_HD_DEINIT_EVT:
btc_hd_deinit();
break;
case BTC_HD_REGISTER_APP_EVT:
btc_hd_register_app(arg->register_app.app_param, arg->register_app.in_qos, arg->register_app.out_qos);
break;
case BTC_HD_UNREGISTER_APP_EVT:
btc_hd_unregister_app();
break;
case BTC_HD_CONNECT_EVT:
btc_hd_connect(arg->connect.bd_addr);
break;
case BTC_HD_DISCONNECT_EVT:
btc_hd_disconnect();
break;
case BTC_HD_SEND_REPORT_EVT:
btc_hd_send_report(arg->send_report.type, arg->send_report.id, arg->send_report.len, arg->send_report.data);
break;
case BTC_HD_REPORT_ERROR_EVT:
btc_hd_report_error(arg->error);
break;
case BTC_HD_UNPLUG_EVT:
btc_hd_virtual_cable_unplug();
break;
default:
BTC_TRACE_WARNING("unknown hidd action %i", msg->act);
break;
}
btc_hd_call_arg_deep_free(msg);
}
static void btc_hd_cb_arg_deep_free(btc_msg_t *msg)
{
tBTA_HD *arg = (tBTA_HD *)msg->arg;
switch (msg->act) {
case BTA_HD_SET_REPORT_EVT:
utl_freebuf((void **)&arg->set_report.p_data);
break;
case BTA_HD_INTR_DATA_EVT:
utl_freebuf((void **)&arg->intr_data.p_data);
break;
default:
break;
}
}
void btc_hd_cb_handler(btc_msg_t *msg)
{
uint16_t event = msg->act;
tBTA_HD *p_data = (tBTA_HD *)msg->arg;
esp_hidd_cb_param_t param = {0};
BTC_TRACE_API("%s: event=%s", __func__, dump_hd_event(event));
switch (event) {
case BTA_HD_ENABLE_EVT:
BTC_TRACE_DEBUG("%s: status=%d", __func__, p_data->status);
if (p_data->status == BTA_HD_OK) {
btc_storage_load_hidd();
btc_hd_cb.status = BTC_HD_ENABLED;
} else {
btc_hd_cb.status = BTC_HD_DISABLED;
BTC_TRACE_WARNING("Failed to enable BT-HD, status=%d", p_data->status);
}
param.init.status = p_data->status;
btc_hd_cb_to_app(ESP_HIDD_INIT_EVT, &param);
break;
case BTA_HD_DISABLE_EVT:
BTC_TRACE_DEBUG("%s: status=%d", __func__, p_data->status);
if (p_data->status == BTA_HD_OK){
btc_hd_cb.status = BTC_HD_DISABLED;
if (btc_hd_cb.service_dereg_active) {
btc_hd_cb.service_dereg_active = FALSE;
}
free_app_info_param();
memset(&btc_hd_cb, 0, sizeof(btc_hd_cb));
} else {
BTC_TRACE_WARNING("Failed to disable BT-HD, status=%d", p_data->status);
}
param.deinit.status = p_data->status;
btc_hd_cb_to_app(ESP_HIDD_DEINIT_EVT, &param);
break;
case BTA_HD_REGISTER_APP_EVT:
if (p_data->reg_status.status == BTA_HD_OK) {
btc_hd_cb.app_registered = TRUE;
}
param.register_app.status = p_data->reg_status.status;
param.register_app.in_use = p_data->reg_status.in_use;
if (!p_data->reg_status.in_use) {
memset(param.register_app.bd_addr, 0, BD_ADDR_LEN);
} else {
memcpy(param.register_app.bd_addr, p_data->reg_status.bda, BD_ADDR_LEN);
}
btc_hd_cb_to_app(ESP_HIDD_REGISTER_APP_EVT, &param);
break;
case BTA_HD_UNREGISTER_APP_EVT:
btc_hd_cb.app_registered = FALSE;
param.unregister_app.status = p_data->status;
btc_hd_cb_to_app(ESP_HIDD_UNREGISTER_APP_EVT, &param);
if (btc_hd_cb.status == BTC_HD_DISABLING) {
BTC_TRACE_WARNING("disabling hid device service now");
BTA_HdDisable();
}
break;
case BTA_HD_OPEN_EVT: {
bt_bdaddr_t *addr = (bt_bdaddr_t *)&p_data->conn.bda;
BTC_TRACE_EVENT("BTA_HD_OPEN_EVT, address (%02x:%02x:%02x:%02x:%02x:%02x)", addr->address[0], addr->address[1],
addr->address[2], addr->address[3], addr->address[4], addr->address[5]);
if (p_data->conn.status == BTA_HD_OK && p_data->conn.conn_status == BTA_HD_CONN_STATE_CONNECTED) {
// /* Check if the connection is from hid host and not hid device */
// if (check_cod_hid(addr)) {
// /* Incoming connection from hid device, reject it */
// BTC_TRACE_WARNING("remote device is not hid host, disconnecting");
// btc_hd_cb.forced_disc = TRUE;
// BTA_HdDisconnect();
// break;
// }
// btc_storage_set_hidd((bt_bdaddr_t *)&p_data->conn.bda);
}
param.open.status = p_data->conn.status;
param.open.conn_status = p_data->conn.conn_status;
memcpy(param.open.bd_addr, p_data->conn.bda, BD_ADDR_LEN);
btc_hd_cb_to_app(ESP_HIDD_OPEN_EVT, &param);
break;
}
case BTA_HD_CLOSE_EVT:
if (btc_hd_cb.forced_disc && p_data->conn.conn_status == BTA_HD_CONN_STATE_DISCONNECTED) {
bt_bdaddr_t *addr = (bt_bdaddr_t *)&p_data->conn.bda;
BTC_TRACE_WARNING("remote device was forcefully disconnected");
btc_hd_remove_device(*addr);
btc_hd_cb.forced_disc = FALSE;
break;
}
param.close.status = p_data->conn.status;
param.close.conn_status = p_data->conn.conn_status;
btc_hd_cb_to_app(ESP_HIDD_CLOSE_EVT, &param);
break;
case BTA_HD_GET_REPORT_EVT:
param.get_report.report_type = p_data->get_report.report_type;
param.get_report.report_id = p_data->get_report.report_id;
param.get_report.buffer_size = p_data->get_report.buffer_size;
btc_hd_cb_to_app(ESP_HIDD_GET_REPORT_EVT, &param);
break;
case BTA_HD_SET_REPORT_EVT:
param.set_report.report_type = p_data->set_report.report_type;
param.set_report.report_id = p_data->set_report.report_id;
param.set_report.len = p_data->set_report.len;
param.set_report.data = p_data->set_report.p_data;
btc_hd_cb_to_app(ESP_HIDD_SET_REPORT_EVT, &param);
break;
case BTA_HD_SET_PROTOCOL_EVT:
switch (p_data->set_protocol) {
case HID_PAR_PROTOCOL_BOOT_MODE:
param.set_protocol.protocol_mode = ESP_HIDD_BOOT_MODE;
break;
case HID_PAR_PROTOCOL_REPORT:
param.set_protocol.protocol_mode = ESP_HIDD_REPORT_MODE;
break;
default:
param.set_protocol.protocol_mode = ESP_HIDD_UNSUPPORTED_MODE;
break;
}
btc_hd_cb_to_app(ESP_HIDD_SET_PROTOCOL_EVT, &param);
break;
case BTA_HD_INTR_DATA_EVT:
param.intr_data.report_id = p_data->intr_data.report_id;
param.intr_data.len = p_data->intr_data.len;
param.intr_data.data = p_data->intr_data.p_data;
btc_hd_cb_to_app(ESP_HIDD_INTR_DATA_EVT, &param);
break;
case BTA_HD_VC_UNPLUG_EVT: {
bt_bdaddr_t *bd_addr = (bt_bdaddr_t *)&p_data->conn.bda;
if (bta_dm_check_if_only_hd_connected(p_data->conn.bda)) {
BTC_TRACE_DEBUG("%s: Removing bonding as only HID profile connected", __func__);
BTA_DmRemoveDevice((uint8_t *)&p_data->conn.bda, BT_TRANSPORT_BR_EDR);
} else {
BTC_TRACE_DEBUG("%s: Only removing HID data as some other profiles connected", __func__);
btc_hd_remove_device(*bd_addr);
}
param.close.status = p_data->conn.status;
param.close.conn_status = p_data->conn.conn_status;
btc_hd_cb_to_app(ESP_HIDD_CLOSE_EVT, &param);
param.vc_unplug.status = p_data->conn.status;
param.vc_unplug.conn_status = p_data->conn.conn_status;
btc_hd_cb_to_app(ESP_HIDD_VC_UNPLUG_EVT, &param);
break;
}
case BTA_HD_SEND_REPORT_EVT:
param.send_report.status = p_data->send_report.status;
param.send_report.reason = p_data->send_report.reason;
param.send_report.report_type = p_data->send_report.report_type;
param.send_report.report_id = p_data->send_report.report_id;
btc_hd_cb_to_app(ESP_HIDD_SEND_REPORT_EVT, &param);
break;
case BTA_HD_REPORT_ERR_EVT:
param.report_err.status = p_data->report_err.status;
param.report_err.reason = p_data->report_err.reason;
btc_hd_cb_to_app(ESP_HIDD_REPORT_ERR_EVT, &param);
break;
default:
BTC_TRACE_WARNING("%s: unknown event (%d)", __func__, event);
break;
}
btc_hd_cb_arg_deep_free(msg);
}
void btc_hd_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
{
btc_hidd_args_t *dst = (btc_hidd_args_t *)p_dest;
btc_hidd_args_t *src = (btc_hidd_args_t *)p_src;
switch (msg->act) {
case BTC_HD_SEND_REPORT_EVT:
dst->send_report.data = (uint8_t *)osi_malloc(src->send_report.len);
if (dst->send_report.data) {
memcpy(dst->send_report.data, src->send_report.data, src->send_report.len);
} else {
BTC_TRACE_ERROR("%s %d osi_malloc failed\n", __func__, msg->act);
}
break;
default:
break;
}
}
#endif // HID_DEV_INCLUDED==TRUE

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,103 @@
/******************************************************************************
*
* Copyright (C) 2016 The Android Open Source Project
* Copyright (C) 2009-2012 Broadcom Corporation
* Copyright (C) 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 BTC_HD_H
#define BTC_HD_H
#if BTC_HD_INCLUDED == TRUE
#include <stdint.h>
#include "bta/bta_hd_api.h"
#include "btc/btc_task.h"
#include "esp_hidd_api.h"
typedef enum {
BTC_HD_INIT_EVT = 0,
BTC_HD_DEINIT_EVT,
BTC_HD_REGISTER_APP_EVT,
BTC_HD_UNREGISTER_APP_EVT,
BTC_HD_CONNECT_EVT,
BTC_HD_DISCONNECT_EVT,
BTC_HD_SEND_REPORT_EVT,
BTC_HD_REPORT_ERROR_EVT,
BTC_HD_UNPLUG_EVT,
} BTC_HD_EVT;
typedef enum { BTC_HD_DISABLED = 0, BTC_HD_ENABLED, BTC_HD_DISABLING } BTC_HD_STATUS;
/* BTIF-HD control block */
typedef struct {
BTC_HD_STATUS status;
bool app_registered;
bool service_dereg_active;
bool forced_disc;
tBTA_HD_APP_INFO app_info;
tBTA_HD_QOS_INFO in_qos;
tBTA_HD_QOS_INFO out_qos;
} btc_hd_cb_t;
/* btc_hidd_args_t */
typedef union {
// BTC_HD_CONNECT_EVT
struct connect_arg {
BD_ADDR bd_addr;
} connect;
// BTC_HD_REGISTER_APP_EVT
struct register_app_arg {
esp_hidd_app_param_t *app_param;
esp_hidd_qos_param_t *in_qos;
esp_hidd_qos_param_t *out_qos;
} register_app;
// BTC_HD_SEND_REPORT_EVT
struct send_report_arg {
esp_hidd_report_type_t type;
uint8_t id;
uint16_t len;
uint8_t *data;
} send_report;
// BTC_HD_REPORT_ERROR_EVT
uint8_t error;
} btc_hidd_args_t;
#ifdef __cplusplus
extern "C" {
#endif
/******************************************************************************
* Functions
******************************************************************************/
void btc_hd_call_handler(btc_msg_t *msg);
void btc_hd_cb_handler(btc_msg_t *msg);
// extern btc_hd_cb_t btc_hd_cb;
// extern void btc_hd_remove_device(bt_bdaddr_t bd_addr);
// extern void btc_hd_service_registration();
void btc_hd_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src);
#ifdef __cplusplus
}
#endif
#endif /* BTC_HD_INCLUDED == TRUE */
#endif /* BTC_HD_H */

View File

@ -0,0 +1,187 @@
/******************************************************************************
*
* Copyright (C) 2016 The Android Open Source Project
* Copyright (C) 2009-2012 Broadcom Corporation
* Copyright (C) 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 BTC_HH_H
#define BTC_HH_H
#include <stdint.h>
#include "bta/bta_hh_api.h"
#include "btc/btc_task.h"
#include "osi/alarm.h"
#include "esp_hidh_api.h"
#define BTC_HH_MAX_HID 8
#define BTC_HH_MAX_ADDED_DEV 32
#define BTC_HH_MAX_KEYSTATES 3
#define BTC_HH_KEYSTATE_MASK_NUMLOCK 0x01
#define BTC_HH_KEYSTATE_MASK_CAPSLOCK 0x02
#define BTC_HH_KEYSTATE_MASK_SCROLLLOCK 0x04
#define BTC_HH_MAX_POLLING_ATTEMPTS 10
#define BTC_HH_POLLING_SLEEP_DURATION_US 5000
/*******************************************************************************
* Type definitions and return values
******************************************************************************/
typedef enum {
BTC_HH_INIT_EVT = 0,
BTC_HH_CONNECT_EVT,
BTC_HH_DISCONNECT_EVT,
BTC_HH_UNPLUG_EVT,
BTC_HH_SET_INFO_EVT,
BTC_HH_GET_PROTO_EVT,
BTC_HH_SET_PROTO_EVT,
BTC_HH_GET_IDLE_EVT,
BTC_HH_SET_IDLE_EVT,
BTC_HH_GET_REPORT_EVT,
BTC_HH_SET_REPORT_EVT,
BTC_HH_SEND_DATA_EVT,
BTC_HH_DEINIT_EVT,
} BTC_HH_EVT;
typedef enum {
BTC_HH_DISABLED = 0,
BTC_HH_ENABLED,
BTC_HH_DISABLING,
BTC_HH_DEV_UNKNOWN,
BTC_HH_DEV_CONNECTING,
BTC_HH_DEV_CONNECTED,
BTC_HH_DEV_DISCONNECTED
} BTC_HH_STATUS;
typedef struct {
esp_hidh_connection_state_t dev_status;
uint8_t dev_handle;
BD_ADDR bd_addr;
uint16_t attr_mask;
uint8_t sub_class;
uint8_t app_id;
bool ready_for_data;
osi_alarm_t *vup_timer;
bool local_vup; // Indicated locally initiated VUP
} btc_hh_device_t;
/* Control block to maintain properties of devices */
typedef struct {
uint8_t dev_handle;
BD_ADDR bd_addr;
uint16_t attr_mask;
} btc_hh_added_device_t;
/**
* BTC-HH control block to maintain added devices and currently
* connected hid devices
*/
typedef struct {
BTC_HH_STATUS status;
btc_hh_device_t devices[BTC_HH_MAX_HID];
uint32_t device_num;
BTC_HH_EVT add_event;
btc_hh_added_device_t added_devices[BTC_HH_MAX_ADDED_DEV];
btc_hh_device_t *p_curr_dev;
bool service_dereg_active;
BD_ADDR pending_conn_address;
} btc_hh_cb_t;
/* btc_spp_args_t */
typedef union {
// BTC_HH_CONNECT_EVT
struct connect_arg {
BD_ADDR bd_addr;
} connect;
// BTC_HH_DISCONNECT_EVT
struct disconnect_arg {
BD_ADDR bd_addr;
} disconnect;
// BTC_HH_UNPLUG_EVT
struct unplug_arg {
BD_ADDR bd_addr;
} unplug;
// BTC_HH_SET_INFO_EVT
struct set_info_arg {
BD_ADDR bd_addr;
esp_hidh_hid_info_t *hid_info;
} set_info;
// BTC_HH_GET_PROTO_EVT
struct get_protocol_arg {
BD_ADDR bd_addr;
} get_protocol;
// BTC_HH_SET_PROTO_EVT
struct set_protocol_arg {
BD_ADDR bd_addr;
esp_hidh_protocol_mode_t protocol_mode;
} set_protocol;
// BTC_HH_GET_IDLE_EVT
struct get_idle_arg {
BD_ADDR bd_addr;
} get_idle;
// BTC_HH_SET_IDLE_EVT
struct set_idle_arg {
BD_ADDR bd_addr;
uint16_t idle_time;
} set_idle;
// BTC_HH_GET_REPORT_EVT
struct get_report_arg {
BD_ADDR bd_addr;
esp_hidh_report_type_t report_type;
uint8_t report_id;
int buffer_size;
} get_report;
// BTC_HH_SET_REPORT_EVT
struct set_report_arg {
BD_ADDR bd_addr;
esp_hidh_report_type_t report_type;
size_t len;
uint8_t *report;
} set_report;
// BTC_HH_SEND_DATA_EVT
struct send_data_arg {
BD_ADDR bd_addr;
size_t len;
uint8_t *data;
} send_data;
} btc_hidh_args_t;
/*******************************************************************************
* Variables
******************************************************************************/
extern btc_hh_cb_t btc_hh_cb;
/*******************************************************************************
* Functions
******************************************************************************/
void btc_hh_call_handler(btc_msg_t *msg);
void btc_hh_cb_handler(btc_msg_t *msg);
void btc_hh_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src);
bool btc_hh_add_added_dev(BD_ADDR bd_addr, uint16_t attr_mask);
#endif /* BTC_HH_H */

View File

@ -67,6 +67,13 @@
#define UC_BT_HFP_CLIENT_ENABLED FALSE
#endif
//HID
#ifdef CONFIG_BT_HID_ENABLED
#define UC_BT_HID_ENABLED CONFIG_BT_HID_ENABLED
#else
#define UC_BT_HID_ENABLED FALSE
#endif
//HID HOST(BT)
#ifdef CONFIG_BT_HID_HOST_ENABLED
#define UC_BT_HID_HOST_ENABLED CONFIG_BT_HID_HOST_ENABLED
@ -74,6 +81,13 @@
#define UC_BT_HID_HOST_ENABLED FALSE
#endif
//HID Device(BT)
#ifdef CONFIG_BT_HID_DEVICE_ENABLED
#define UC_BT_HID_DEVICE_ENABLED CONFIG_BT_HID_DEVICE_ENABLED
#else
#define UC_BT_HID_DEVICE_ENABLED FALSE
#endif
//SSP
#ifdef CONFIG_BT_SSP_ENABLED
#define UC_BT_SSP_ENABLED CONFIG_BT_SSP_ENABLED
@ -148,7 +162,7 @@
#define UC_BT_SMP_SLAVE_CON_PARAMS_UPD_ENABLE FALSE
#endif
#if CONFIG_BT_CTRL_ESP32
#if CONFIG_IDF_TARGET_ESP32
//BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP
#ifdef CONFIG_BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP
#define UC_BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP CONFIG_BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP
@ -170,9 +184,9 @@
#define UC_BTDM_BLE_ADV_REPORT_DISCARD_THRSHOLD 20
#endif
#endif //CONFIG_BT_CTRL_ESP32
#endif //CONFIG_IDF_TARGET_ESP32
#if (CONFIG_BT_CTRL_ESP32C3 || CONFIG_BT_CTRL_ESP32S3)
#if (CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3)
//BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP
#ifdef CONFIG_BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_SUPP
#define UC_BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP CONFIG_BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_SUPP
@ -194,7 +208,7 @@
#define UC_BTDM_BLE_ADV_REPORT_DISCARD_THRSHOLD 20
#endif
#endif //(CONFIG_BT_CTRL_ESP32C3 || CONFIG_BT_CTRL_ESP32S3)
#endif //(CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3)
//BT ACL CONNECTIONS
#ifdef CONFIG_BT_ACL_CONNECTIONS
@ -365,10 +379,18 @@
#define UC_BT_LOG_MCA_TRACE_LEVEL UC_TRACE_LEVEL_WARNING
#endif
#ifdef CONFIG_BT_LOG_HIDH_TRACE_LEVEL
#define UC_BT_LOG_HIDH_TRACE_LEVEL CONFIG_BT_LOG_HIDH_TRACE_LEVEL
#ifdef CONFIG_BT_LOG_HID_TRACE_LEVEL
#if UC_BT_HID_HOST_ENABLED
#define UC_BT_LOG_HIDH_TRACE_LEVEL CONFIG_BT_LOG_HID_TRACE_LEVEL
#elif UC_BT_HID_DEVICE_ENABLED
#define UC_BT_LOG_HIDD_TRACE_LEVEL CONFIG_BT_LOG_HID_TRACE_LEVEL
#endif
#else
#if UC_BT_HID_HOST_ENABLED
#define UC_BT_LOG_HIDH_TRACE_LEVEL UC_TRACE_LEVEL_WARNING
#elif UC_BT_HID_DEVICE_ENABLED
#define UC_BT_LOG_HIDD_TRACE_LEVEL UC_TRACE_LEVEL_WARNING
#endif
#endif
#ifdef CONFIG_BT_LOG_APPL_TRACE_LEVEL

View File

@ -130,11 +130,22 @@
#define BT_SSP_INCLUDED TRUE
#endif /* UC_BT_SSP_ENABLED */
#if UC_BT_HID_ENABLED
#define BT_HID_INCLUDED TRUE
#endif /* UC_BT_HID_ENABLED */
#if UC_BT_HID_HOST_ENABLED
#define HID_HOST_INCLUDED TRUE
#define BTA_HH_INCLUDED TRUE
#define BTC_HH_INCLUDED TRUE
#endif /* UC_BT_HID_HOST_ENABLED */
#if UC_BT_HID_DEVICE_ENABLED
#define HID_DEV_INCLUDED TRUE
#define BTA_HD_INCLUDED TRUE
#define BTC_HD_INCLUDED TRUE
#endif /* UC_BT_HID_DEVICE_ENABLED */
#endif /* UC_BT_CLASSIC_ENABLED */
/* This is set to enable use of GAP L2CAP connections. */
@ -321,6 +332,14 @@
#define BTC_SPP_INCLUDED FALSE
#endif
#ifndef BTC_HH_INCLUDED
#define BTC_HH_INCLUDED FALSE
#endif
#ifndef BTC_HD_INCLUDED
#define BTC_HD_INCLUDED FALSE
#endif
#ifndef SBC_DEC_INCLUDED
#define SBC_DEC_INCLUDED FALSE
#endif
@ -350,6 +369,10 @@
#define BTA_PAN_INCLUDED FALSE
#endif
#ifndef BTA_HD_INCLUDED
#define BTA_HD_INCLUDED FALSE
#endif
#ifndef BTA_HH_INCLUDED
#define BTA_HH_INCLUDED FALSE
#endif
@ -1378,7 +1401,11 @@
/* The maximum number of attributes in each record. */
#ifndef SDP_MAX_REC_ATTR
#if defined(HID_DEV_INCLUDED) && (HID_DEV_INCLUDED==TRUE)
#define SDP_MAX_REC_ATTR 25
#else
#define SDP_MAX_REC_ATTR 8
#endif /* defined(HID_DEV_INCLUDED) && (HID_DEV_INCLUDED==TRUE) */
#endif
#ifndef SDP_MAX_PAD_LEN
@ -1845,6 +1872,18 @@ Range: 2 octets
** HID
**
******************************************************************************/
#ifndef BT_HID_INCLUDED
#define BT_HID_INCLUDED FALSE
#endif
/* HID Device Role Included */
#ifndef HID_DEV_INCLUDED
#define HID_DEV_INCLUDED FALSE
#endif
#ifndef HID_DEV_SUBCLASS
#define HID_DEV_SUBCLASS COD_MINOR_POINTING
#endif
#ifndef HID_CONTROL_BUF_SIZE
#define HID_CONTROL_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
@ -1854,6 +1893,14 @@ Range: 2 octets
#define HID_INTERRUPT_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
#endif
#ifndef HID_DEV_MTU_SIZE
#define HID_DEV_MTU_SIZE 64
#endif
#ifndef HID_DEV_FLUSH_TO
#define HID_DEV_FLUSH_TO 0xffff
#endif
/*************************************************************************
** Definitions for Both HID-Host & Device
*/

View File

@ -106,6 +106,7 @@ static inline void trc_dump_buffer(const char *prefix, uint8_t *data, uint16_t l
#define BTTRC_ID_STK_CE 51
#define BTTRC_ID_STK_SNEP 52
#define BTTRC_ID_STK_NDEF 53
#define BTTRC_ID_STK_HIDD 54
/* LayerIDs for BTA */
#define BTTRC_ID_BTA_ACC 55 /* Advanced Camera Client */
@ -199,6 +200,7 @@ static inline void trc_dump_buffer(const char *prefix, uint8_t *data, uint16_t l
#define AVRC_INITIAL_TRACE_LEVEL UC_BT_LOG_AVRC_TRACE_LEVEL
#define MCA_INITIAL_TRACE_LEVEL UC_BT_LOG_MCA_TRACE_LEVEL
#define HIDH_INITIAL_TRACE_LEVEL UC_BT_LOG_HIDH_TRACE_LEVEL
#define HIDD_INITIAL_TRACE_LEVEL UC_BT_LOG_HIDD_TRACE_LEVEL
#define APPL_INITIAL_TRACE_LEVEL UC_BT_LOG_APPL_TRACE_LEVEL
#define GATT_INITIAL_TRACE_LEVEL UC_BT_LOG_GATT_TRACE_LEVEL
#define SMP_INITIAL_TRACE_LEVEL UC_BT_LOG_SMP_TRACE_LEVEL
@ -258,6 +260,14 @@ static inline void trc_dump_buffer(const char *prefix, uint8_t *data, uint16_t l
#define HIDH_TRACE_EVENT(fmt, args...) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_EVENT && BT_LOG_LEVEL_CHECK(HIDH,EVENT)) BT_PRINT_D("BT_HIDH", fmt, ## args);}
#define HIDH_TRACE_DEBUG(fmt, args...) {if (hh_cb.trace_level >= BT_TRACE_LEVEL_DEBUG && BT_LOG_LEVEL_CHECK(HIDH,DEBUG)) BT_PRINT_D("BT_HIDH", fmt, ## args);}
/* define traces for HID Device */
#define HIDD_TRACE_ERROR(fmt, args...) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_ERROR && BT_LOG_LEVEL_CHECK(HIDD, ERROR)) BT_PRINT_E("BT_HIDD", fmt, ## args);}
#define HIDD_TRACE_WARNING(fmt, args...) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_WARNING && BT_LOG_LEVEL_CHECK(HIDD, WARNING)) BT_PRINT_W("BT_HIDD", fmt, ## args);}
#define HIDD_TRACE_API(fmt, args...) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_API && BT_LOG_LEVEL_CHECK(HIDD,API)) BT_PRINT_I("BT_HIDD", fmt, ## args);}
#define HIDD_TRACE_EVENT(fmt, args...) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_EVENT && BT_LOG_LEVEL_CHECK(HIDD,EVENT)) BT_PRINT_D("BT_HIDD", fmt, ## args);}
#define HIDD_TRACE_DEBUG(fmt, args...) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_DEBUG && BT_LOG_LEVEL_CHECK(HIDD,DEBUG)) BT_PRINT_D("BT_HIDD", fmt, ## args);}
#define HIDD_TRACE_VERBOSE(fmt, args...) {if (hd_cb.trace_level >= BT_TRACE_LEVEL_VERBOSE && BT_LOG_LEVEL_CHECK(HIDD,VERBOSE)) BT_PRINT_D("BT_HIDD", fmt, ## args);}
/* define traces for BNEP */
#define BNEP_TRACE_ERROR(fmt, args...) {if (bnep_cb.trace_level >= BT_TRACE_LEVEL_ERROR && BT_LOG_LEVEL_CHECK(BNEP, ERROR)) BT_PRINT_E("BT_BNEP", fmt, ## args);}
@ -418,6 +428,14 @@ extern UINT8 btif_trace_level;
#define HIDH_TRACE_EVENT(fmt, args...)
#define HIDH_TRACE_DEBUG(fmt, args...)
/* define traces for HID Device */
#define HIDD_TRACE_ERROR(fmt, args...)
#define HIDD_TRACE_WARNING(fmt, args...)
#define HIDD_TRACE_API(fmt, args...)
#define HIDD_TRACE_EVENT(fmt, args...)
#define HIDD_TRACE_DEBUG(fmt, args...)
#define HIDD_TRACE_VERBOSE(fmt, args...)
/* define traces for BNEP */
#define BNEP_TRACE_ERROR(fmt, args...)

View File

@ -52,6 +52,14 @@
#include "pan_api.h"
#endif
#if (defined(HID_HOST_INCLUDED) && HID_HOST_INCLUDED == TRUE)
#include "stack/hidh_api.h"
#endif
#if (defined(HID_DEV_INCLUDED) && HID_DEV_INCLUDED == TRUE)
#include "stack/hidd_api.h"
#endif
#if (defined(AVRC_INCLUDED) && AVRC_INCLUDED == TRUE)
#include "stack/avrc_api.h"
#endif
@ -118,6 +126,10 @@
#include "bta_hh_int.h"
#endif
#if BTA_HD_INCLUDED==TRUE
#include "bta_hd_int.h"
#endif
#if BTA_JV_INCLUDED==TRUE
#include "bta_jv_int.h"
#endif
@ -175,6 +187,12 @@ void BTE_DeinitStack(void)
bta_gattc_cb_ptr = NULL;
}
#endif
#if BTA_HD_INCLUDED==TRUE
if (bta_hd_cb_ptr){
osi_free(bta_hd_cb_ptr);
bta_hd_cb_ptr = NULL;
}
#endif
#if BTA_HH_INCLUDED==TRUE
if (bta_hh_cb_ptr){
osi_free(bta_hh_cb_ptr);
@ -249,6 +267,14 @@ void BTE_DeinitStack(void)
}
#endif // BTA_INCLUDED == TRUE
#if (defined(HID_DEV_INCLUDED) && HID_DEV_INCLUDED == TRUE)
HID_DevDeinit();
#endif
#if (defined(HID_HOST_INCLUDED) && HID_HOST_INCLUDED == TRUE)
HID_HostDeinit();
#endif
#if (defined(GAP_INCLUDED) && GAP_INCLUDED == TRUE)
GAP_Deinit();
#endif
@ -347,7 +373,15 @@ bt_status_t BTE_InitStack(void)
#endif
#if (defined(HID_HOST_INCLUDED) && HID_HOST_INCLUDED == TRUE)
HID_HostInit();
if (HID_HostInit() != HID_SUCCESS) {
goto error_exit;
}
#endif
#if (defined(HID_DEV_INCLUDED) && HID_DEV_INCLUDED == TRUE)
if (HID_DevInit() != HID_SUCCESS) {
goto error_exit;
}
#endif
#if (defined(MCA_INCLUDED) && MCA_INCLUDED == TRUE)
@ -434,6 +468,12 @@ bt_status_t BTE_InitStack(void)
}
memset((void *)bta_hh_cb_ptr, 0, sizeof(tBTA_HH_CB));
#endif
#if BTA_HD_INCLUDED==TRUE
if ((bta_hd_cb_ptr = (tBTA_HD_CB *)osi_malloc(sizeof(tBTA_HD_CB))) == NULL) {
goto error_exit;
}
memset((void *)bta_hd_cb_ptr, 0, sizeof(tBTA_HD_CB));
#endif
#if BTA_HL_INCLUDED==TRUE
memset((void *)bta_hl_cb_ptr, 0, sizeof(tBTA_HL_CB));
#endif

View File

@ -2981,6 +2981,7 @@ void btm_sec_rmt_name_request_complete (UINT8 *p_bd_addr, UINT8 *p_bd_name, UINT
int i;
DEV_CLASS dev_class;
UINT8 old_sec_state;
UINT8 res;
BTM_TRACE_EVENT ("btm_sec_rmt_name_request_complete\n");
if (((p_bd_addr == NULL) && !BTM_ACL_IS_CONNECTED(btm_cb.connecting_bda))
@ -3161,9 +3162,12 @@ void btm_sec_rmt_name_request_complete (UINT8 *p_bd_addr, UINT8 *p_bd_name, UINT
/* This is required when different entities receive link notification and auth complete */
if (!(p_dev_rec->security_required & BTM_SEC_OUT_AUTHENTICATE)) {
if (btm_cb.api.p_auth_complete_callback) {
(*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
p_dev_rec->dev_class,
p_dev_rec->sec_bd_name, HCI_SUCCESS);
res = (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
p_dev_rec->dev_class,
p_dev_rec->sec_bd_name, HCI_SUCCESS);
if (res == BTM_SEC_DEV_REC_REMOVED) {
p_dev_rec = NULL;
}
}
}
@ -3853,6 +3857,7 @@ static void btm_sec_auth_collision (UINT16 handle)
#if (SMP_INCLUDED == TRUE)
void btm_sec_auth_complete (UINT16 handle, UINT8 status)
{
UINT8 res;
UINT8 old_sm4;
tBTM_PAIRING_STATE old_state = btm_cb.pairing_state;
tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle);
@ -3942,9 +3947,12 @@ void btm_sec_auth_complete (UINT16 handle, UINT8 status)
if (btm_cb.api.p_auth_complete_callback) {
/* report the authentication status */
if (old_state != BTM_PAIR_STATE_IDLE) {
(*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
p_dev_rec->dev_class,
p_dev_rec->sec_bd_name, status);
res = (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
p_dev_rec->dev_class,
p_dev_rec->sec_bd_name, status);
if (res == BTM_SEC_DEV_REC_REMOVED) {
p_dev_rec = NULL;
}
}
}
@ -4241,6 +4249,7 @@ void btm_sec_connected (UINT8 *bda, UINT16 handle, UINT8 status, UINT8 enc_mode)
{
tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bda);
UINT8 res;
UINT8 sec_dev_rec_status;
BOOLEAN is_pairing_device = FALSE;
tACL_CONN *p_acl_cb;
UINT8 bit_shift = 0;
@ -4379,9 +4388,12 @@ void btm_sec_connected (UINT8 *bda, UINT16 handle, UINT8 status, UINT8 enc_mode)
/* We need to notify host that the key is not known any more */
if (btm_cb.api.p_auth_complete_callback) {
(*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
p_dev_rec->dev_class,
p_dev_rec->sec_bd_name, status);
sec_dev_rec_status = (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
p_dev_rec->dev_class,
p_dev_rec->sec_bd_name, status);
if (sec_dev_rec_status == BTM_SEC_DEV_REC_REMOVED) {
p_dev_rec = NULL;
}
}
}
/*
@ -4412,9 +4424,12 @@ void btm_sec_connected (UINT8 *bda, UINT16 handle, UINT8 status, UINT8 enc_mode)
/* We need to notify host that the key is not known any more */
if (btm_cb.api.p_auth_complete_callback) {
(*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
p_dev_rec->dev_class,
p_dev_rec->sec_bd_name, status);
sec_dev_rec_status = (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
p_dev_rec->dev_class,
p_dev_rec->sec_bd_name, status);
if (sec_dev_rec_status == BTM_SEC_DEV_REC_REMOVED) {
p_dev_rec = NULL;
}
}
}
@ -4447,9 +4462,12 @@ void btm_sec_connected (UINT8 *bda, UINT16 handle, UINT8 status, UINT8 enc_mode)
}
if (btm_cb.api.p_auth_complete_callback) {
(*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
p_dev_rec->dev_class,
p_dev_rec->sec_bd_name, HCI_SUCCESS);
sec_dev_rec_status = (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr,
p_dev_rec->dev_class,
p_dev_rec->sec_bd_name, HCI_SUCCESS);
if (sec_dev_rec_status == BTM_SEC_DEV_REC_REMOVED) {
p_dev_rec = NULL;
}
}
btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE);
@ -4668,6 +4686,7 @@ void btm_sec_link_key_notification (UINT8 *p_bda, UINT8 *p_link_key, UINT8 key_t
tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev (p_bda);
BOOLEAN we_are_bonding = FALSE;
BOOLEAN ltk_derived_lk = FALSE;
UINT8 res;
BTM_TRACE_EVENT ("btm_sec_link_key_notification() BDA:%04x%08x, TYPE: %d\n",
(p_bda[0] << 8) + p_bda[1], (p_bda[2] << 24) + (p_bda[3] << 16) + (p_bda[4] << 8) + p_bda[5],
@ -4772,8 +4791,11 @@ void btm_sec_link_key_notification (UINT8 *p_bda, UINT8 *p_link_key, UINT8 key_t
/* for derived key, always send authentication callback for BR channel */
|| ltk_derived_lk) {
if (btm_cb.api.p_auth_complete_callback) {
(*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class,
p_dev_rec->sec_bd_name, HCI_SUCCESS);
res = (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class,
p_dev_rec->sec_bd_name, HCI_SUCCESS);
if (res == BTM_SEC_DEV_REC_REMOVED) {
p_dev_rec = NULL;
}
}
}
@ -5760,9 +5782,10 @@ static char *btm_pair_state_descr (tBTM_PAIRING_STATE state)
*******************************************************************************/
void btm_sec_dev_rec_cback_event (tBTM_SEC_DEV_REC *p_dev_rec, UINT8 res, BOOLEAN is_le_transport)
{
tBTM_SEC_CALLBACK *p_callback = p_dev_rec->p_callback;
tBTM_SEC_CALLBACK *p_callback;
if (p_dev_rec->p_callback) {
if (p_dev_rec && p_dev_rec->p_callback) {
p_callback = p_dev_rec->p_callback;
p_dev_rec->p_callback = NULL;
#if BLE_INCLUDED == TRUE

View File

@ -394,9 +394,7 @@ tBTM_STATUS btm_ble_start_inquiry (UINT8 mode, UINT8 duration);
void btm_ble_stop_scan(void);
void btm_clear_all_pending_le_entry(void);
BOOLEAN btm_ble_send_extended_scan_params(UINT8 scan_type, UINT32 scan_int,
UINT32 scan_win, UINT8 addr_type_own,
UINT8 scan_filter_policy);
BOOLEAN btm_ble_send_extended_scan_params(UINT8 scan_type, UINT32 scan_int, UINT32 scan_win, UINT8 addr_type_own, UINT8 scan_filter_policy);
void btm_ble_stop_inquiry(void);
void btm_ble_init (void);
void btm_ble_free (void);
@ -407,8 +405,7 @@ void btm_ble_conn_complete(UINT8 *p, UINT16 evt_len, BOOLEAN enhanced);
void btm_read_ble_local_supported_states_complete(UINT8 *p, UINT16 evt_len);
tBTM_BLE_CONN_ST btm_ble_get_conn_st(void);
void btm_ble_set_conn_st(tBTM_BLE_CONN_ST new_st);
UINT8 *btm_ble_build_adv_data(tBTM_BLE_AD_MASK *p_data_mask, UINT8 **p_dst,
tBTM_BLE_ADV_DATA *p_data);
UINT8 *btm_ble_build_adv_data(tBTM_BLE_AD_MASK *p_data_mask, UINT8 **p_dst, tBTM_BLE_ADV_DATA *p_data);
tBTM_STATUS btm_ble_start_adv(void);
tBTM_STATUS btm_ble_stop_adv(void);
tBTM_STATUS btm_ble_start_scan(void);

View File

@ -961,12 +961,10 @@ extern tBTM_CallbackFunc conn_param_update_cb;
typedef UINT8 tBTM_SEC_ACTION;
/*
#ifdef __cplusplus
extern "C"
{
#endif
*/
#if BTM_DYNAMIC_MEMORY == FALSE
extern tBTM_CB btm_cb;

View File

@ -54,7 +54,7 @@
#endif
#if (defined(HID_HOST_INCLUDED) && HID_HOST_INCLUDED == TRUE )
#include "hidh_int.h"
#include "hid_int.h"
#endif
#if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE)

View File

@ -0,0 +1,586 @@
/******************************************************************************
*
* Copyright (C) 2016 The Android Open Source Project
* Copyright (C) 2002-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 entry points
*
******************************************************************************/
//#include <errno.h>
//#include <hardware/bluetooth.h>
//#include <hardware/bt_hd.h>
#include "stack/hidd_api.h"
#include "esp_hidd_api.h"
#include "hid_int.h"
#include "osi/allocator.h"
#include "stack/btm_api.h"
#include "stack/btu.h"
#include "stack/hiddefs.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if (HID_DEV_INCLUDED == TRUE)
#if HID_DYNAMIC_MEMORY == FALSE
tHID_DEV_CTB hd_cb;
#else
tHID_DEV_CTB *hidd_cb_ptr = NULL;
#endif
/*******************************************************************************
*
* Function HID_DevInit
*
* Description Initializes control block
*
* Returns tHID_STATUS
*
******************************************************************************/
tHID_STATUS HID_DevInit(void)
{
#if (HID_DYNAMIC_MEMORY)
if (!hidd_cb_ptr) {
hidd_cb_ptr = (tHID_DEV_CTB *)osi_malloc(sizeof(tHID_DEV_CTB));
if (!hidd_cb_ptr) {
return HID_ERR_NO_RESOURCES;
}
}
#endif /* #if (HID_DYNAMIC_MEMORY) */
memset(&hd_cb, 0, sizeof(tHID_DEV_CTB));
#if defined(HIDD_INITIAL_TRACE_LEVEL)
hd_cb.trace_level = HIDD_INITIAL_TRACE_LEVEL;
#else
hd_cb.trace_level = BT_TRACE_LEVEL_NONE;
#endif
return HID_SUCCESS;
}
/*******************************************************************************
*
* Function HID_DevDeinit
*
* Description Deinitializes control block
*
* Returns void
*
******************************************************************************/
void HID_DevDeinit(void)
{
#if (HID_DYNAMIC_MEMORY)
if (hidd_cb_ptr) {
osi_free(hidd_cb_ptr);
hidd_cb_ptr = NULL;
}
#endif /* #if (HID_DYNAMIC_MEMORY) */
}
/*******************************************************************************
*
* Function HID_DevSetTraceLevel
*
* Description This function sets the trace level for HID Dev. If called
* with
* a value of 0xFF, it simply reads the current trace level.
*
* Returns the new (current) trace level
*
******************************************************************************/
uint8_t HID_DevSetTraceLevel(uint8_t new_level)
{
if (new_level != 0xFF) {
hd_cb.trace_level = new_level;
}
return (hd_cb.trace_level);
}
/*******************************************************************************
*
* Function HID_DevRegister
*
* Description Registers HID device with lower layers
*
* Returns tHID_STATUS
*
******************************************************************************/
tHID_STATUS HID_DevRegister(tHID_DEV_HOST_CALLBACK *host_cback)
{
tHID_STATUS st;
HIDD_TRACE_API("%s", __func__);
if (hd_cb.reg_flag) {
return HID_ERR_ALREADY_REGISTERED;
}
if (host_cback == NULL) {
return HID_ERR_INVALID_PARAM;
}
/* Register with L2CAP */
if ((st = hidd_conn_reg()) != HID_SUCCESS) {
return st;
}
hd_cb.callback = host_cback;
hd_cb.reg_flag = TRUE;
if (hd_cb.pending_data) {
osi_free(hd_cb.pending_data);
hd_cb.pending_data = NULL;
}
return (HID_SUCCESS);
}
/*******************************************************************************
*
* Function HID_DevDeregister
*
* Description Deregisters HID device with lower layers
*
* Returns tHID_STATUS
*
******************************************************************************/
tHID_STATUS HID_DevDeregister(void)
{
HIDD_TRACE_API("%s", __func__);
if (!hd_cb.reg_flag)
return (HID_ERR_NOT_REGISTERED);
hidd_conn_dereg();
hd_cb.reg_flag = FALSE;
return (HID_SUCCESS);
}
tHID_STATUS HID_DevSetSecurityLevel(uint8_t sec_lvl)
{
HIDD_TRACE_API("%s", __func__);
if (!BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_HIDD_SEC_CTRL, sec_lvl, HID_PSM_CONTROL, BTM_SEC_PROTO_HID,
HIDD_SEC_CHN)) {
HIDD_TRACE_ERROR("Security Registration 1 failed");
return (HID_ERR_NO_RESOURCES);
}
if (!BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_HIDD_SEC_CTRL, sec_lvl, HID_PSM_CONTROL, BTM_SEC_PROTO_HID,
HIDD_SEC_CHN)) {
HIDD_TRACE_ERROR("Security Registration 2 failed");
return (HID_ERR_NO_RESOURCES);
}
if (!BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_HIDD_NOSEC_CTRL, BTM_SEC_NONE, HID_PSM_CONTROL,
BTM_SEC_PROTO_HID, HIDD_NOSEC_CHN)) {
HIDD_TRACE_ERROR("Security Registration 3 failed");
return (HID_ERR_NO_RESOURCES);
}
if (!BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_HIDD_NOSEC_CTRL, BTM_SEC_NONE, HID_PSM_CONTROL,
BTM_SEC_PROTO_HID, HIDD_NOSEC_CHN)) {
HIDD_TRACE_ERROR("Security Registration 4 failed");
return (HID_ERR_NO_RESOURCES);
}
if (!BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_HIDD_INTR, BTM_SEC_NONE, HID_PSM_INTERRUPT, BTM_SEC_PROTO_HID,
0)) {
HIDD_TRACE_ERROR("Security Registration 5 failed");
return (HID_ERR_NO_RESOURCES);
}
if (!BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_HIDD_INTR, BTM_SEC_NONE, HID_PSM_INTERRUPT, BTM_SEC_PROTO_HID,
0)) {
HIDD_TRACE_ERROR("Security Registration 6 failed");
return (HID_ERR_NO_RESOURCES);
}
return (HID_SUCCESS);
}
/*******************************************************************************
*
* Function HID_DevAddRecord
*
* Description Creates SDP record for HID device
*
* Returns tHID_STATUS
*
******************************************************************************/
tHID_STATUS HID_DevAddRecord(uint32_t handle, char *p_name, char *p_description, char *p_provider, uint16_t subclass,
uint16_t desc_len, uint8_t *p_desc_data)
{
bool result = TRUE;
HIDD_TRACE_API("%s", __func__);
// Service Class ID List
if (result) {
uint16_t uuid = UUID_SERVCLASS_HUMAN_INTERFACE;
result &= SDP_AddServiceClassIdList(handle, 1, &uuid);
}
// Protocol Descriptor List
if (result) {
tSDP_PROTOCOL_ELEM proto_list[2];
proto_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
proto_list[0].num_params = 1;
proto_list[0].params[0] = BT_PSM_HIDC;
proto_list[1].protocol_uuid = UUID_PROTOCOL_HIDP;
proto_list[1].num_params = 0;
result &= SDP_AddProtocolList(handle, 2, proto_list);
}
// Language Base Attribute ID List
if (result) {
result &=
SDP_AddLanguageBaseAttrIDList(handle, LANG_ID_CODE_ENGLISH, LANG_ID_CHAR_ENCODE_UTF8, LANGUAGE_BASE_ID);
}
// Additional Protocol Descriptor List
if (result) {
tSDP_PROTO_LIST_ELEM add_proto_list;
add_proto_list.num_elems = 2;
add_proto_list.list_elem[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
add_proto_list.list_elem[0].num_params = 1;
add_proto_list.list_elem[0].params[0] = BT_PSM_HIDI;
add_proto_list.list_elem[1].protocol_uuid = UUID_PROTOCOL_HIDP;
add_proto_list.list_elem[1].num_params = 0;
result &= SDP_AddAdditionProtoLists(handle, 1, &add_proto_list);
}
// Service Name (O)
// Service Description (O)
// Provider Name (O)
if (result) {
const char *srv_name = p_name;
const char *srv_desc = p_description;
const char *provider_name = p_provider;
result &= SDP_AddAttribute(handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE, strlen(srv_name) + 1,
(uint8_t *)srv_name);
result &= SDP_AddAttribute(handle, ATTR_ID_SERVICE_DESCRIPTION, TEXT_STR_DESC_TYPE, strlen(srv_desc) + 1,
(uint8_t *)srv_desc);
result &= SDP_AddAttribute(handle, ATTR_ID_PROVIDER_NAME, TEXT_STR_DESC_TYPE, strlen(provider_name) + 1,
(uint8_t *)provider_name);
}
// Bluetooth Profile Descriptor List
if (result) {
const uint16_t profile_uuid = UUID_SERVCLASS_HUMAN_INTERFACE;
const uint16_t version = 0x0100;
result &= SDP_AddProfileDescriptorList(handle, profile_uuid, version);
}
// HID Parser Version
if (result) {
uint8_t *p;
const uint16_t rel_num = 0x0100;
const uint16_t parser_version = 0x0111;
const uint16_t prof_ver = 0x0100;
const uint8_t dev_subclass = subclass;
const uint8_t country_code = 0x21;
const uint8_t bool_false = 0x00;
const uint8_t bool_true = 0x01;
uint16_t temp;
p = (uint8_t *)&temp;
UINT16_TO_BE_STREAM(p, rel_num);
result &= SDP_AddAttribute(handle, ATTR_ID_HID_DEVICE_RELNUM, UINT_DESC_TYPE, 2, (uint8_t *)&temp);
p = (uint8_t *)&temp;
UINT16_TO_BE_STREAM(p, parser_version);
result &= SDP_AddAttribute(handle, ATTR_ID_HID_PARSER_VERSION, UINT_DESC_TYPE, 2, (uint8_t *)&temp);
result &= SDP_AddAttribute(handle, ATTR_ID_HID_DEVICE_SUBCLASS, UINT_DESC_TYPE, 1, (uint8_t *)&dev_subclass);
result &= SDP_AddAttribute(handle, ATTR_ID_HID_COUNTRY_CODE, UINT_DESC_TYPE, 1, (uint8_t *)&country_code);
result &= SDP_AddAttribute(handle, ATTR_ID_HID_VIRTUAL_CABLE, BOOLEAN_DESC_TYPE, 1, (uint8_t *)&bool_true);
result &= SDP_AddAttribute(handle, ATTR_ID_HID_RECONNECT_INITIATE, BOOLEAN_DESC_TYPE, 1, (uint8_t *)&bool_true);
{
static uint8_t cdt = 0x22;
uint8_t *p_buf;
uint8_t seq_len = 4 + desc_len;
p_buf = (uint8_t *)osi_malloc(2048);
if (p_buf == NULL) {
HIDD_TRACE_ERROR("%s: Buffer allocation failure for size = 2048 ", __func__);
return HID_ERR_NOT_REGISTERED;
}
p = p_buf;
UINT8_TO_BE_STREAM(p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
UINT8_TO_BE_STREAM(p, seq_len);
UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_ONE_BYTE);
UINT8_TO_BE_STREAM(p, cdt);
UINT8_TO_BE_STREAM(p, (TEXT_STR_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
UINT8_TO_BE_STREAM(p, desc_len);
ARRAY_TO_BE_STREAM(p, p_desc_data, (int)desc_len);
result &= SDP_AddAttribute(handle, ATTR_ID_HID_DESCRIPTOR_LIST, DATA_ELE_SEQ_DESC_TYPE, p - p_buf, p_buf);
osi_free(p_buf);
}
{
uint8_t lang_buf[8];
p = lang_buf;
uint8_t seq_len = 6;
uint16_t lang_english = 0x0409;
UINT8_TO_BE_STREAM(p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
UINT8_TO_BE_STREAM(p, seq_len);
UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
UINT16_TO_BE_STREAM(p, lang_english);
UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
UINT16_TO_BE_STREAM(p, LANGUAGE_BASE_ID);
result &=
SDP_AddAttribute(handle, ATTR_ID_HID_LANGUAGE_ID_BASE, DATA_ELE_SEQ_DESC_TYPE, p - lang_buf, lang_buf);
}
result &= SDP_AddAttribute(handle, ATTR_ID_HID_BATTERY_POWER, BOOLEAN_DESC_TYPE, 1, (uint8_t *)&bool_true);
result &= SDP_AddAttribute(handle, ATTR_ID_HID_REMOTE_WAKE, BOOLEAN_DESC_TYPE, 1, (uint8_t *)&bool_false);
result &=
SDP_AddAttribute(handle, ATTR_ID_HID_NORMALLY_CONNECTABLE, BOOLEAN_DESC_TYPE, 1, (uint8_t *)&bool_true);
result &= SDP_AddAttribute(handle, ATTR_ID_HID_BOOT_DEVICE, BOOLEAN_DESC_TYPE, 1, (uint8_t *)&bool_true);
p = (uint8_t *)&temp;
UINT16_TO_BE_STREAM(p, prof_ver);
result &= SDP_AddAttribute(handle, ATTR_ID_HID_PROFILE_VERSION, UINT_DESC_TYPE, 2, (uint8_t *)&temp);
}
if (result) {
uint16_t browse_group = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
result &= SDP_AddUuidSequence(handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse_group);
}
if (!result) {
HIDD_TRACE_ERROR("%s: failed to complete SDP record", __func__);
return HID_ERR_NOT_REGISTERED;
}
return HID_SUCCESS;
}
/*******************************************************************************
*
* Function HID_DevSendReport
*
* Description Sends report
*
* Returns tHID_STATUS
*
******************************************************************************/
tHID_STATUS HID_DevSendReport(uint8_t channel, uint8_t type, uint8_t id, uint16_t len, uint8_t *p_data)
{
HIDD_TRACE_VERBOSE("%s: channel=%d type=%d id=%d len=%d", __func__, channel, type, id, len);
if (channel == HID_CHANNEL_CTRL) {
return hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_DATA, type, id, len, p_data);
}
if (channel == HID_CHANNEL_INTR && type == HID_PAR_REP_TYPE_INPUT) {
// on INTR we can only send INPUT
return hidd_conn_send_data(HID_CHANNEL_INTR, HID_TRANS_DATA, HID_PAR_REP_TYPE_INPUT, id, len, p_data);
}
return HID_ERR_INVALID_PARAM;
}
/*******************************************************************************
*
* Function HID_DevVirtualCableUnplug
*
* Description Sends Virtual Cable Unplug
*
* Returns tHID_STATUS
*
******************************************************************************/
tHID_STATUS HID_DevVirtualCableUnplug(void)
{
HIDD_TRACE_API("%s", __func__);
return hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_CONTROL, HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG, 0, 0, NULL);
}
/*******************************************************************************
*
* Function HID_DevPlugDevice
*
* Description Establishes virtual cable to given host
*
* Returns tHID_STATUS
*
******************************************************************************/
tHID_STATUS HID_DevPlugDevice(BD_ADDR addr)
{
hd_cb.device.in_use = TRUE;
memcpy(hd_cb.device.addr, addr, sizeof(BD_ADDR));
return HID_SUCCESS;
}
/*******************************************************************************
*
* Function HID_DevUnplugDevice
*
* Description Unplugs virtual cable from given host
*
* Returns tHID_STATUS
*
******************************************************************************/
tHID_STATUS HID_DevUnplugDevice(BD_ADDR addr)
{
if (!memcmp(hd_cb.device.addr, addr, sizeof(BD_ADDR))) {
hd_cb.device.in_use = FALSE;
hd_cb.device.conn.conn_state = HID_CONN_STATE_UNUSED;
hd_cb.device.conn.ctrl_cid = 0;
hd_cb.device.conn.intr_cid = 0;
}
return HID_SUCCESS;
}
/*******************************************************************************
*
* Function HID_DevConnect
*
* Description Connects to device
*
* Returns tHID_STATUS
*
******************************************************************************/
tHID_STATUS HID_DevConnect(void)
{
if (!hd_cb.reg_flag) {
return HID_ERR_NOT_REGISTERED;
}
if (!hd_cb.device.in_use) {
return HID_ERR_INVALID_PARAM;
}
if (hd_cb.device.state != HIDD_DEV_NO_CONN) {
return HID_ERR_ALREADY_CONN;
}
return hidd_conn_initiate();
}
/*******************************************************************************
*
* Function HID_DevDisconnect
*
* Description Disconnects from device
*
* Returns tHID_STATUS
*
******************************************************************************/
tHID_STATUS HID_DevDisconnect(void)
{
if (!hd_cb.reg_flag) {
return HID_ERR_NOT_REGISTERED;
}
if (!hd_cb.device.in_use) {
return HID_ERR_INVALID_PARAM;
}
if (hd_cb.device.state == HIDD_DEV_NO_CONN) {
return HID_ERR_NO_CONNECTION;
}
return hidd_conn_disconnect();
}
/*******************************************************************************
*
* Function HID_DevSetIncomingPolicy
*
* Description Sets policy for incoming connections (allowed/disallowed)
*
* Returns tHID_STATUS
*
******************************************************************************/
tHID_STATUS HID_DevSetIncomingPolicy(bool allow)
{
hd_cb.allow_incoming = allow;
return HID_SUCCESS;
}
/*******************************************************************************
*
* Function HID_DevReportError
*
* Description Reports error for Set Report via HANDSHAKE
*
* Returns tHID_STATUS
*
******************************************************************************/
tHID_STATUS HID_DevReportError(uint8_t error)
{
uint8_t handshake_param;
HIDD_TRACE_API("%s: error = %d", __func__, error);
switch (error) {
case HID_PAR_HANDSHAKE_RSP_SUCCESS:
case HID_PAR_HANDSHAKE_RSP_NOT_READY:
case HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID:
case HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ:
case HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM:
case HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN:
case HID_PAR_HANDSHAKE_RSP_ERR_FATAL:
handshake_param = error;
break;
default:
handshake_param = HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN;
break;
}
return hidd_conn_send_data(0, HID_TRANS_HANDSHAKE, handshake_param, 0, 0, NULL);
}
/*******************************************************************************
*
* Function HID_DevGetDevice
*
* Description Returns the BD Address of virtually cabled device
*
* Returns tHID_STATUS
*
******************************************************************************/
tHID_STATUS HID_DevGetDevice(BD_ADDR *addr)
{
HIDD_TRACE_API("%s", __func__);
if (hd_cb.device.in_use) {
memcpy(addr, hd_cb.device.addr, sizeof(BD_ADDR));
} else {
return HID_ERR_NOT_REGISTERED;
}
return HID_SUCCESS;
}
/*******************************************************************************
*
* Function HID_DevSetIncomingQos
*
* Description Sets Incoming QoS values for Interrupt L2CAP Channel
*
* Returns tHID_STATUS
*
******************************************************************************/
tHID_STATUS HID_DevSetIncomingQos(uint8_t service_type, uint32_t token_rate, uint32_t token_bucket_size,
uint32_t peak_bandwidth, uint32_t latency, uint32_t delay_variation)
{
HIDD_TRACE_API("%s", __func__);
hd_cb.use_in_qos = TRUE;
hd_cb.in_qos.service_type = service_type;
hd_cb.in_qos.token_rate = token_rate;
hd_cb.in_qos.token_bucket_size = token_bucket_size;
hd_cb.in_qos.peak_bandwidth = peak_bandwidth;
hd_cb.in_qos.latency = latency;
hd_cb.in_qos.delay_variation = delay_variation;
return HID_SUCCESS;
}
/*******************************************************************************
*
* Function HID_DevSetOutgoingQos
*
* Description Sets Outgoing QoS values for Interrupt L2CAP Channel
*
* Returns tHID_STATUS
*
******************************************************************************/
tHID_STATUS HID_DevSetOutgoingQos(uint8_t service_type, uint32_t token_rate, uint32_t token_bucket_size,
uint32_t peak_bandwidth, uint32_t latency, uint32_t delay_variation)
{
HIDD_TRACE_API("%s", __func__);
hd_cb.l2cap_intr_cfg.qos_present = TRUE;
hd_cb.l2cap_intr_cfg.qos.service_type = service_type;
hd_cb.l2cap_intr_cfg.qos.token_rate = token_rate;
hd_cb.l2cap_intr_cfg.qos.token_bucket_size = token_bucket_size;
hd_cb.l2cap_intr_cfg.qos.peak_bandwidth = peak_bandwidth;
hd_cb.l2cap_intr_cfg.qos.latency = latency;
hd_cb.l2cap_intr_cfg.qos.delay_variation = delay_variation;
return HID_SUCCESS;
}
#endif

View File

@ -0,0 +1,780 @@
/******************************************************************************
*
* Copyright (C) 2016 The Android Open Source Project
* Copyright (C) 2002-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 connection interface functions
*
******************************************************************************/
#include "btm_int.h"
#include "hid_conn.h"
#include "hid_int.h"
#include "osi/allocator.h"
#include "osi/osi.h"
#include "stack/btm_api.h"
#include "stack/btu.h"
#include "stack/hidd_api.h"
#include "stack/hiddefs.h"
#include "stack/l2c_api.h"
#include "stack/l2cdefs.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if (HID_DEV_INCLUDED == TRUE)
static void hidd_l2cif_connect_ind(BD_ADDR bd_addr, uint16_t cid, uint16_t psm, uint8_t id);
static void hidd_l2cif_connect_cfm(uint16_t cid, uint16_t result);
static void hidd_l2cif_config_ind(uint16_t cid, tL2CAP_CFG_INFO *p_cfg);
static void hidd_l2cif_config_cfm(uint16_t cid, tL2CAP_CFG_INFO *p_cfg);
static void hidd_l2cif_disconnect_ind(uint16_t cid, bool ack_needed);
static void hidd_l2cif_disconnect_cfm(uint16_t cid, uint16_t result);
static void hidd_l2cif_data_ind(uint16_t cid, BT_HDR *p_msg);
static void hidd_l2cif_cong_ind(uint16_t cid, bool congested);
static const tL2CAP_APPL_INFO dev_reg_info = {hidd_l2cif_connect_ind,
hidd_l2cif_connect_cfm,
NULL,
hidd_l2cif_config_ind,
hidd_l2cif_config_cfm,
hidd_l2cif_disconnect_ind,
hidd_l2cif_disconnect_cfm,
NULL,
hidd_l2cif_data_ind,
hidd_l2cif_cong_ind,
NULL};
/*******************************************************************************
*
* Function hidd_check_config_done
*
* Description Checks if connection is configured and callback can be fired
*
* Returns void
*
******************************************************************************/
static void hidd_check_config_done(void)
{
tHID_CONN *p_hcon;
p_hcon = &hd_cb.device.conn;
if (((p_hcon->conn_flags & HID_CONN_FLAGS_ALL_CONFIGURED) == HID_CONN_FLAGS_ALL_CONFIGURED) &&
(p_hcon->conn_state == HID_CONN_STATE_CONFIG)) {
p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
hd_cb.device.state = HIDD_DEV_CONNECTED;
hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_OPEN, 0, NULL);
// send outstanding data on intr
if (hd_cb.pending_data) {
L2CA_DataWrite(p_hcon->intr_cid, hd_cb.pending_data);
hd_cb.pending_data = NULL;
}
}
}
/*******************************************************************************
*
* Function hidh_sec_check_complete_term
*
* Description HID security check complete callback function.
*
* Returns Send L2CA_ConnectRsp OK if secutiry check succeed; otherwise
* send security block L2C connection response.
*
******************************************************************************/
static void hidd_sec_check_complete(UNUSED_ATTR BD_ADDR bd_addr, UNUSED_ATTR tBT_TRANSPORT transport, void *p_ref_data,
uint8_t res)
{
tHID_DEV_DEV_CTB *p_dev = (tHID_DEV_DEV_CTB *)p_ref_data;
if (res == BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY) {
p_dev->conn.disc_reason = HID_SUCCESS;
p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_INTR;
L2CA_ConnectRsp(p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
L2CA_ConfigReq(p_dev->conn.ctrl_cid, &hd_cb.l2cap_cfg);
} else if (res != BTM_SUCCESS) {
HIDD_TRACE_WARNING("%s: connection rejected by security", __func__);
p_dev->conn.disc_reason = HID_ERR_AUTH_FAILED;
p_dev->conn.conn_state = HID_CONN_STATE_UNUSED;
L2CA_ConnectRsp(p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid, L2CAP_CONN_SECURITY_BLOCK,
L2CAP_CONN_OK);
return;
}
}
/*******************************************************************************
*
* Function hidd_sec_check_complete_orig
*
* Description HID security check complete callback function (device
*originated)
*
* Returns void
*
******************************************************************************/
void hidd_sec_check_complete_orig(UNUSED_ATTR BD_ADDR bd_addr, UNUSED_ATTR tBT_TRANSPORT transport, void *p_ref_data,
uint8_t res)
{
tHID_DEV_DEV_CTB *p_dev = (tHID_DEV_DEV_CTB *)p_ref_data;
if (p_dev->conn.conn_state != HID_CONN_STATE_SECURITY) {
HIDD_TRACE_WARNING("%s: invalid state (%02x)", __func__, p_dev->conn.conn_state);
return;
}
if (res == BTM_SUCCESS) {
HIDD_TRACE_EVENT("%s: security ok", __func__);
p_dev->conn.disc_reason = HID_SUCCESS;
p_dev->conn.conn_state = HID_CONN_STATE_CONFIG;
L2CA_ConfigReq(p_dev->conn.ctrl_cid, &hd_cb.l2cap_cfg);
} else {
HIDD_TRACE_WARNING("%s: security check failed (%02x)", __func__, res);
p_dev->conn.disc_reason = HID_ERR_AUTH_FAILED;
hidd_conn_disconnect();
}
}
/*******************************************************************************
*
* Function hidd_l2cif_connect_ind
*
* Description Handles incoming L2CAP connection (we act as server)
*
* Returns void
*
******************************************************************************/
static void hidd_l2cif_connect_ind(BD_ADDR bd_addr, uint16_t cid, uint16_t psm, uint8_t id)
{
tHID_CONN *p_hcon;
tHID_DEV_DEV_CTB *p_dev;
bool accept = TRUE; // accept by default
HIDD_TRACE_EVENT("%s: psm=%04x cid=%04x id=%02x", __func__, psm, cid, id);
p_dev = &hd_cb.device;
if (!hd_cb.allow_incoming) {
HIDD_TRACE_WARNING("%s: incoming connections not allowed, rejecting", __func__);
L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_NO_RESOURCES, 0);
return;
}
if (p_dev->in_use && memcmp(bd_addr, p_dev->addr, sizeof(BD_ADDR))) {
HIDD_TRACE_WARNING("%s: incoming connections from different device, rejecting", __func__);
L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_NO_RESOURCES, 0);
return;
} else if (!p_dev->in_use) {
p_dev->in_use = TRUE;
memcpy(p_dev->addr, bd_addr, sizeof(BD_ADDR));
p_dev->state = HIDD_DEV_NO_CONN;
}
p_hcon = &hd_cb.device.conn;
switch (psm) {
case HID_PSM_INTERRUPT:
if (p_hcon->ctrl_cid == 0) {
accept = FALSE;
HIDD_TRACE_WARNING("%s: incoming INTR without CTRL, rejecting", __func__);
}
if (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR) {
accept = FALSE;
HIDD_TRACE_WARNING("%s: incoming INTR in invalid state (%d), rejecting", __func__, p_hcon->conn_state);
}
break;
case HID_PSM_CONTROL:
if (p_hcon->conn_state != HID_CONN_STATE_UNUSED) {
accept = FALSE;
HIDD_TRACE_WARNING("%s: incoming CTRL in invalid state (%d), rejecting", __func__, p_hcon->conn_state);
}
break;
default:
accept = FALSE;
HIDD_TRACE_ERROR("%s: received invalid PSM, rejecting", __func__);
break;
}
if (!accept) {
L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_NO_RESOURCES, 0);
return;
}
// for CTRL we need to go through security and we reply in callback from there
if (psm == HID_PSM_CONTROL) {
p_hcon->conn_flags = 0;
p_hcon->ctrl_cid = cid;
p_hcon->ctrl_id = id;
p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;
p_hcon->conn_state = HID_CONN_STATE_SECURITY;
if (btm_sec_mx_access_request(p_dev->addr, HID_PSM_CONTROL, FALSE, BTM_SEC_PROTO_HID, HIDD_NOSEC_CHN,
&hidd_sec_check_complete, p_dev) == BTM_CMD_STARTED) {
L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_PENDING, L2CAP_CONN_OK);
}
return;
}
// for INTR we go directly to config state
p_hcon->conn_state = HID_CONN_STATE_CONFIG;
p_hcon->intr_cid = cid;
L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
L2CA_ConfigReq(cid, &hd_cb.l2cap_intr_cfg);
}
/*******************************************************************************
*
* Function hidd_l2cif_connect_cfm
*
* Description Handles L2CAP connection response (we act as client)
*
* Returns void
*
******************************************************************************/
static void hidd_l2cif_connect_cfm(uint16_t cid, uint16_t result)
{
tHID_DEV_DEV_CTB *p_dev = &hd_cb.device;
tHID_CONN *p_hcon = &hd_cb.device.conn;
HIDD_TRACE_EVENT("%s: cid=%04x result=%d, conn_state=%d", __func__, cid, result, p_hcon->conn_state);
if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) {
HIDD_TRACE_WARNING("%s: unknown cid", __func__);
return;
}
if (!(p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) ||
((cid == p_hcon->ctrl_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_CTRL && (p_hcon->conn_state != HID_CONN_STATE_DISCONNECTING_INTR))) ||
((cid == p_hcon->intr_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR) && (p_hcon->conn_state != HID_CONN_STATE_DISCONNECTING_CTRL))) {
HIDD_TRACE_WARNING("%s: unexpected, cid:0x%04x, ctrl_cid:0x%04x, intr_cid:0x%04x, conn_state:%d", __func__, cid,
p_hcon->ctrl_cid, p_hcon->intr_cid, p_hcon->conn_state);
return;
}
if (result != L2CAP_CONN_OK) {
HIDD_TRACE_WARNING("%s: connection failed, now disconnect", __func__);
if (cid == p_hcon->ctrl_cid)
p_hcon->ctrl_cid = 0;
else
p_hcon->intr_cid = 0;
hidd_conn_disconnect();
hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, HID_L2CAP_CONN_FAIL | (uint32_t)result, NULL);
return;
}
/* CTRL connect conf */
if (cid == p_hcon->ctrl_cid) {
p_hcon->conn_state = HID_CONN_STATE_SECURITY;
p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* in case disconnected before sec completed */
btm_sec_mx_access_request(p_dev->addr, HID_PSM_CONTROL, TRUE, BTM_SEC_PROTO_HID, HIDD_SEC_CHN,
&hidd_sec_check_complete_orig, p_dev);
} else {
p_hcon->conn_state = HID_CONN_STATE_CONFIG;
L2CA_ConfigReq(cid, &hd_cb.l2cap_intr_cfg);
}
return;
}
/*******************************************************************************
*
* Function hidd_l2cif_config_ind
*
* Description Handles incoming L2CAP configuration request
*
* Returns void
*
******************************************************************************/
static void hidd_l2cif_config_ind(uint16_t cid, tL2CAP_CFG_INFO *p_cfg)
{
tHID_CONN *p_hcon;
HIDD_TRACE_EVENT("%s: cid=%04x", __func__, cid);
p_hcon = &hd_cb.device.conn;
if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) {
HIDD_TRACE_WARNING("%s: unknown cid", __func__);
return;
}
if ((!p_cfg->mtu_present) || (p_cfg->mtu > HID_DEV_MTU_SIZE))
p_hcon->rem_mtu_size = HID_DEV_MTU_SIZE;
else
p_hcon->rem_mtu_size = p_cfg->mtu;
// accept without changes
p_cfg->flush_to_present = FALSE;
p_cfg->mtu_present = FALSE;
p_cfg->result = L2CAP_CFG_OK;
if (cid == p_hcon->intr_cid && hd_cb.use_in_qos && !p_cfg->qos_present) {
p_cfg->qos_present = TRUE;
memcpy(&p_cfg->qos, &hd_cb.in_qos, sizeof(FLOW_SPEC));
}
L2CA_ConfigRsp(cid, p_cfg);
// update flags
if (cid == p_hcon->ctrl_cid) {
p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_CTRL_CFG_DONE;
if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) && (p_hcon->conn_flags & HID_CONN_FLAGS_MY_CTRL_CFG_DONE)) {
p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;
if ((p_hcon->intr_cid = L2CA_ConnectReq(HID_PSM_INTERRUPT, hd_cb.device.addr)) == 0) {
p_hcon->conn_state = HID_CONN_STATE_UNUSED;
hidd_conn_disconnect();
HIDD_TRACE_WARNING("%s: could not start L2CAP connection for INTR", __func__);
hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, HID_ERR_L2CAP_FAILED, NULL);
return;
} else {
p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
}
}
} else {
p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_INTR_CFG_DONE;
}
hidd_check_config_done();
}
/*******************************************************************************
*
* Function hidd_l2cif_config_cfm
*
* Description Handles incoming L2CAP configuration response
*
* Returns void
*
******************************************************************************/
static void hidd_l2cif_config_cfm(uint16_t cid, tL2CAP_CFG_INFO *p_cfg)
{
tHID_CONN *p_hcon;
uint32_t reason;
HIDD_TRACE_EVENT("%s: cid=%04x pcfg->result=%d", __func__, cid, p_cfg->result);
p_hcon = &hd_cb.device.conn;
if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) {
HIDD_TRACE_WARNING("%s: unknown cid", __func__);
return;
}
if (p_hcon->intr_cid == cid && p_cfg->result == L2CAP_CFG_UNACCEPTABLE_PARAMS && p_cfg->qos_present) {
tL2CAP_CFG_INFO new_qos;
// QoS parameters not accepted for intr, try again with host proposal
memcpy(&new_qos, &hd_cb.l2cap_intr_cfg, sizeof(new_qos));
memcpy(&new_qos.qos, &p_cfg->qos, sizeof(FLOW_SPEC));
new_qos.qos_present = TRUE;
HIDD_TRACE_WARNING("%s: config failed, retry", __func__);
L2CA_ConfigReq(cid, &new_qos);
return;
} else if (p_hcon->intr_cid == cid && p_cfg->result == L2CAP_CFG_UNKNOWN_OPTIONS) {
// QoS not understood by remote device, try configuring without QoS
HIDD_TRACE_WARNING("%s: config failed, retry without QoS", __func__);
L2CA_ConfigReq(cid, &hd_cb.l2cap_cfg);
return;
} else if (p_cfg->result != L2CAP_CFG_OK) {
HIDD_TRACE_WARNING("%s: config failed, disconnecting", __func__);
hidd_conn_disconnect();
reason = HID_L2CAP_CFG_FAIL | (uint32_t)p_cfg->result;
hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, reason, NULL);
return;
}
// update flags
if (cid == p_hcon->ctrl_cid) {
p_hcon->conn_flags |= HID_CONN_FLAGS_MY_CTRL_CFG_DONE;
if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) && (p_hcon->conn_flags & HID_CONN_FLAGS_HIS_CTRL_CFG_DONE)) {
p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;
if ((p_hcon->intr_cid = L2CA_ConnectReq(HID_PSM_INTERRUPT, hd_cb.device.addr)) == 0) {
p_hcon->conn_state = HID_CONN_STATE_UNUSED;
hidd_conn_disconnect();
HIDD_TRACE_WARNING("%s: could not start L2CAP connection for INTR", __func__);
hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, HID_ERR_L2CAP_FAILED, NULL);
return;
} else {
p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
}
}
} else {
p_hcon->conn_flags |= HID_CONN_FLAGS_MY_INTR_CFG_DONE;
}
hidd_check_config_done();
}
/*******************************************************************************
*
* Function hidd_l2cif_disconnect_ind
*
* Description Handler incoming L2CAP disconnection request
*
* Returns void
*
******************************************************************************/
static void hidd_l2cif_disconnect_ind(uint16_t cid, bool ack_needed)
{
tHID_CONN *p_hcon;
HIDD_TRACE_EVENT("%s: cid=%04x ack_needed=%d", __func__, cid, ack_needed);
p_hcon = &hd_cb.device.conn;
if (p_hcon->conn_state == HID_CONN_STATE_UNUSED || (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
HIDD_TRACE_WARNING("%s: unknown cid", __func__);
return;
}
if (ack_needed)
L2CA_DisconnectRsp(cid);
if (cid == p_hcon->ctrl_cid) {
p_hcon->ctrl_cid = 0;
p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING_CTRL;
} else {
p_hcon->intr_cid = 0;
p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING_INTR;
}
if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) {
HIDD_TRACE_EVENT("%s: INTR and CTRL disconnected", __func__);
// clean any outstanding data on intr
if (hd_cb.pending_data) {
osi_free(hd_cb.pending_data);
hd_cb.pending_data = NULL;
}
hd_cb.device.state = HIDD_DEV_NO_CONN;
p_hcon->conn_state = HID_CONN_STATE_UNUSED;
hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, p_hcon->disc_reason, NULL);
}
}
/*******************************************************************************
*
* Function hidd_l2cif_disconnect_cfm
*
* Description Handles L2CAP disconection response
*
* Returns void
*
******************************************************************************/
static void hidd_l2cif_disconnect_cfm(uint16_t cid, uint16_t result)
{
tHID_CONN *p_hcon;
HIDD_TRACE_EVENT("%s: cid=%04x result=%d", __func__, cid, result);
p_hcon = &hd_cb.device.conn;
if (p_hcon->conn_state == HID_CONN_STATE_UNUSED || (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
HIDD_TRACE_WARNING("%s: unknown cid", __func__);
return;
}
if (cid == p_hcon->ctrl_cid) {
p_hcon->ctrl_cid = 0;
} else {
p_hcon->intr_cid = 0;
// now disconnect CTRL
L2CA_DisconnectReq(p_hcon->ctrl_cid);
}
if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) {
HIDD_TRACE_EVENT("%s: INTR and CTRL disconnected", __func__);
hd_cb.device.state = HIDD_DEV_NO_CONN;
p_hcon->conn_state = HID_CONN_STATE_UNUSED;
if (hd_cb.pending_vc_unplug) {
hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_VC_UNPLUG, p_hcon->disc_reason, NULL);
hd_cb.pending_vc_unplug = FALSE;
} else {
hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, p_hcon->disc_reason, NULL);
}
}
}
/*******************************************************************************
*
* Function hidd_l2cif_cong_ind
*
* Description Handles L2CAP congestion status event
*
* Returns void
*
******************************************************************************/
static void hidd_l2cif_cong_ind(uint16_t cid, bool congested)
{
tHID_CONN *p_hcon;
HIDD_TRACE_EVENT("%s: cid=%04x congested=%d", __func__, cid, congested);
p_hcon = &hd_cb.device.conn;
if (p_hcon->conn_state == HID_CONN_STATE_UNUSED || (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
HIDD_TRACE_WARNING("%s: unknown cid", __func__);
return;
}
if (congested) {
p_hcon->conn_flags |= HID_CONN_FLAGS_CONGESTED;
} else {
p_hcon->conn_flags &= ~HID_CONN_FLAGS_CONGESTED;
}
}
/*******************************************************************************
*
* Function hidd_l2cif_data_ind
*
* Description Handler incoming data on L2CAP channel
*
* Returns void
*
******************************************************************************/
static void hidd_l2cif_data_ind(uint16_t cid, BT_HDR *p_msg)
{
tHID_CONN *p_hcon;
uint8_t *p_data = (uint8_t *)(p_msg + 1) + p_msg->offset;
uint8_t msg_type, param;
bool err = FALSE;
HIDD_TRACE_EVENT("%s: cid=%04x", __func__, cid);
p_hcon = &hd_cb.device.conn;
if (p_hcon->conn_state == HID_CONN_STATE_UNUSED || (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
HIDD_TRACE_WARNING("%s: unknown cid", __func__);
osi_free(p_msg);
return;
}
msg_type = HID_GET_TRANS_FROM_HDR(*p_data);
param = HID_GET_PARAM_FROM_HDR(*p_data);
if (msg_type == HID_TRANS_DATA && cid == p_hcon->intr_cid) {
// skip HID header
p_msg->offset++;
p_msg->len--;
hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_INTR_DATA, 0, p_msg);
return;
}
switch (msg_type) {
case HID_TRANS_GET_REPORT:
// at this stage we don't know if Report Id shall be included in request
// so we pass complete packet in callback and let other code analyze this
hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_GET_REPORT, !!(param & HID_PAR_GET_REP_BUFSIZE_FOLLOWS), p_msg);
break;
case HID_TRANS_SET_REPORT:
// as above
hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_SET_REPORT, 0, p_msg);
break;
case HID_TRANS_GET_IDLE:
hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_DATA, HID_PAR_REP_TYPE_OTHER, hd_cb.device.idle_time, 0, NULL);
osi_free(p_msg);
break;
case HID_TRANS_SET_IDLE:
if (p_msg->len != 2) {
HIDD_TRACE_ERROR("%s: invalid len (%d) set idle request received", __func__, p_msg->len);
err = TRUE;
} else {
hd_cb.device.idle_time = p_data[1];
HIDD_TRACE_DEBUG("%s: idle_time = %d", __func__, hd_cb.device.idle_time);
if (hd_cb.device.idle_time) {
HIDD_TRACE_WARNING("%s: idle_time of %d ms not supported by HID Device", __func__,
(hd_cb.device.idle_time * 4));
err = TRUE;
}
}
if (!err) {
hidd_conn_send_data(0, HID_TRANS_HANDSHAKE, HID_PAR_HANDSHAKE_RSP_SUCCESS, 0, 0, NULL);
} else {
hidd_conn_send_data(0, HID_TRANS_HANDSHAKE, HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM, 0, 0, NULL);
}
osi_free(p_msg);
break;
case HID_TRANS_GET_PROTOCOL:
hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_DATA, HID_PAR_REP_TYPE_OTHER, !hd_cb.device.boot_mode, 0, NULL);
osi_free(p_msg);
break;
case HID_TRANS_SET_PROTOCOL:
hd_cb.device.boot_mode = !(param & HID_PAR_PROTOCOL_MASK);
hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_SET_PROTOCOL, param & HID_PAR_PROTOCOL_MASK, NULL);
hidd_conn_send_data(0, HID_TRANS_HANDSHAKE, HID_PAR_HANDSHAKE_RSP_SUCCESS, 0, 0, NULL);
osi_free(p_msg);
break;
case HID_TRANS_CONTROL:
switch (param) {
case HID_PAR_CONTROL_SUSPEND:
hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_SUSPEND, 0, NULL);
break;
case HID_PAR_CONTROL_EXIT_SUSPEND:
hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_EXIT_SUSPEND, 0, NULL);
break;
case HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG:
hidd_conn_disconnect();
// set flag so we can notify properly when disconnected
hd_cb.pending_vc_unplug = TRUE;
break;
}
osi_free(p_msg);
break;
case HID_TRANS_DATA:
default:
HIDD_TRACE_WARNING("%s: got unsupported msg (%d)", __func__, msg_type);
hidd_conn_send_data(0, HID_TRANS_HANDSHAKE, HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ, 0, 0, NULL);
osi_free(p_msg);
break;
}
}
/*******************************************************************************
*
* Function hidd_conn_reg
*
* Description Registers L2CAP channels
*
* Returns void
*
******************************************************************************/
tHID_STATUS hidd_conn_reg(void)
{
HIDD_TRACE_API("%s", __func__);
memset(&hd_cb.l2cap_cfg, 0, sizeof(tL2CAP_CFG_INFO));
hd_cb.l2cap_cfg.mtu_present = TRUE;
hd_cb.l2cap_cfg.mtu = HID_DEV_MTU_SIZE;
hd_cb.l2cap_cfg.flush_to_present = TRUE;
hd_cb.l2cap_cfg.flush_to = HID_DEV_FLUSH_TO;
memset(&hd_cb.l2cap_intr_cfg, 0, sizeof(tL2CAP_CFG_INFO));
hd_cb.l2cap_intr_cfg.mtu_present = TRUE;
hd_cb.l2cap_intr_cfg.mtu = HID_DEV_MTU_SIZE;
hd_cb.l2cap_intr_cfg.flush_to_present = TRUE;
hd_cb.l2cap_intr_cfg.flush_to = HID_DEV_FLUSH_TO;
if (!L2CA_Register(HID_PSM_CONTROL, (tL2CAP_APPL_INFO *)&dev_reg_info)) {
HIDD_TRACE_ERROR("HID Control (device) registration failed");
return (HID_ERR_L2CAP_FAILED);
}
if (!L2CA_Register(HID_PSM_INTERRUPT, (tL2CAP_APPL_INFO *)&dev_reg_info)) {
L2CA_Deregister(HID_PSM_CONTROL);
HIDD_TRACE_ERROR("HID Interrupt (device) registration failed");
return (HID_ERR_L2CAP_FAILED);
}
return (HID_SUCCESS);
}
/*******************************************************************************
*
* Function hidd_conn_dereg
*
* Description Deregisters L2CAP channels
*
* Returns void
*
******************************************************************************/
void hidd_conn_dereg(void)
{
HIDD_TRACE_API("%s", __func__);
L2CA_Deregister(HID_PSM_CONTROL);
L2CA_Deregister(HID_PSM_INTERRUPT);
}
/*******************************************************************************
*
* Function hidd_conn_initiate
*
* Description Initiates HID connection to plugged device
*
* Returns HID_SUCCESS
*
******************************************************************************/
tHID_STATUS hidd_conn_initiate(void)
{
tHID_DEV_DEV_CTB *p_dev = &hd_cb.device;
HIDD_TRACE_API("%s", __func__);
if (!p_dev->in_use) {
HIDD_TRACE_WARNING("%s: no virtual cable established", __func__);
return (HID_ERR_NOT_REGISTERED);
}
if (p_dev->conn.conn_state != HID_CONN_STATE_UNUSED) {
HIDD_TRACE_WARNING("%s: connection already in progress", __func__);
return (HID_ERR_CONN_IN_PROCESS);
}
p_dev->conn.ctrl_cid = 0;
p_dev->conn.intr_cid = 0;
p_dev->conn.disc_reason = HID_L2CAP_CONN_FAIL;
p_dev->conn.conn_flags = HID_CONN_FLAGS_IS_ORIG;
BTM_SetOutService(p_dev->addr, BTM_SEC_SERVICE_HIDD_SEC_CTRL, HIDD_SEC_CHN);
/* Check if L2CAP started the connection process */
if ((p_dev->conn.ctrl_cid = L2CA_ConnectReq(HID_PSM_CONTROL, p_dev->addr)) == 0) {
HIDD_TRACE_WARNING("%s: could not start L2CAP connection", __func__);
hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, HID_ERR_L2CAP_FAILED, NULL);
} else {
p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_CTRL;
}
return (HID_SUCCESS);
}
/*******************************************************************************
*
* Function hidd_conn_disconnect
*
* Description Disconnects existing HID connection
*
* Returns HID_SUCCESS
*
******************************************************************************/
tHID_STATUS hidd_conn_disconnect(void)
{
tHID_CONN *p_hcon;
HIDD_TRACE_API("%s", __func__);
// clean any outstanding data on intr
if (hd_cb.pending_data) {
osi_free(hd_cb.pending_data);
hd_cb.pending_data = NULL;
}
p_hcon = &hd_cb.device.conn;
if ((p_hcon->ctrl_cid != 0) || (p_hcon->intr_cid != 0)) {
/* Set l2cap idle timeout to 0 (so ACL link is disconnected
* immediately after last channel is closed) */
L2CA_SetIdleTimeoutByBdAddr(hd_cb.device.addr, 0, BT_TRANSPORT_BR_EDR);
if (p_hcon->intr_cid) {
p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING_INTR;
L2CA_DisconnectReq(p_hcon->intr_cid);
} else if (p_hcon->ctrl_cid) {
p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING_CTRL;
L2CA_DisconnectReq(p_hcon->ctrl_cid);
}
} else {
HIDD_TRACE_WARNING("%s: already disconnected", __func__);
p_hcon->conn_state = HID_CONN_STATE_UNUSED;
}
return (HID_SUCCESS);
}
/*******************************************************************************
*
* Function hidd_conn_send_data
*
* Description Sends data to host
*
* Returns tHID_STATUS
*
******************************************************************************/
tHID_STATUS hidd_conn_send_data(uint8_t channel, uint8_t msg_type, uint8_t param, uint8_t data, uint16_t len,
uint8_t *p_data)
{
tHID_CONN *p_hcon;
BT_HDR *p_buf;
uint8_t *p_out;
uint16_t cid;
uint16_t buf_size;
HIDD_TRACE_VERBOSE("%s: channel(%d), msg_type(%d), len(%d)", __func__, channel, msg_type, len);
p_hcon = &hd_cb.device.conn;
if (p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) {
return HID_ERR_CONGESTED;
}
switch (msg_type) {
case HID_TRANS_HANDSHAKE:
case HID_TRANS_CONTROL:
cid = p_hcon->ctrl_cid;
buf_size = HID_CONTROL_BUF_SIZE;
break;
case HID_TRANS_DATA:
if (channel == HID_CHANNEL_CTRL) {
cid = p_hcon->ctrl_cid;
buf_size = HID_CONTROL_BUF_SIZE;
} else {
cid = p_hcon->intr_cid;
buf_size = HID_INTERRUPT_BUF_SIZE;
}
break;
default:
return (HID_ERR_INVALID_PARAM);
}
p_buf = (BT_HDR *)osi_malloc(buf_size);
if (p_buf == NULL)
return (HID_ERR_NO_RESOURCES);
p_buf->offset = L2CAP_MIN_OFFSET;
p_out = (uint8_t *)(p_buf + 1) + p_buf->offset;
*p_out = HID_BUILD_HDR(msg_type, param);
p_out++;
p_buf->len = 1; // start with header only
// add report id prefix only if non-zero (which is reserved)
if (msg_type == HID_TRANS_DATA && (data || param == HID_PAR_REP_TYPE_OTHER)) {
*p_out = data; // report_id
p_out++;
p_buf->len++;
}
if (len > 0 && p_data != NULL) {
memcpy(p_out, p_data, len);
p_buf->len += len;
}
// check if connected
if (hd_cb.device.state != HIDD_DEV_CONNECTED) {
// for DATA on intr we hold transfer and try to reconnect
if (msg_type == HID_TRANS_DATA && cid == p_hcon->intr_cid) {
// drop previous data, we do not queue it for now
if (hd_cb.pending_data) {
osi_free(hd_cb.pending_data);
}
hd_cb.pending_data = p_buf;
if (hd_cb.device.conn.conn_state == HID_CONN_STATE_UNUSED) {
hidd_conn_initiate();
}
return HID_SUCCESS;
}
return HID_ERR_NO_CONNECTION;
}
#ifdef REPORT_TRANSFER_TIMESTAMP
if (report_transfer) {
HIDD_TRACE_ERROR("%s: report sent", __func__);
}
#endif
HIDD_TRACE_VERBOSE("%s: report sent", __func__);
if (!L2CA_DataWrite(cid, p_buf))
return (HID_ERR_CONGESTED);
return (HID_SUCCESS);
}
#endif

View File

@ -31,7 +31,7 @@
#include "stack/bt_types.h"
#include "stack/hiddefs.h"
#include "stack/hidh_api.h"
#include "hidh_int.h"
#include "hid_int.h"
#include "stack/btm_api.h"
#include "stack/btu.h"
#include "btm_int.h"
@ -39,7 +39,9 @@
#if (HID_HOST_INCLUDED == TRUE)
#if HID_DYNAMIC_MEMORY == FALSE
tHID_HOST_CTB hh_cb;
tHID_HOST_CTB hh_cb;
#else
tHID_HOST_CTB *hidh_cb_ptr = NULL;
#endif
static void hidh_search_callback (UINT16 sdp_result);
@ -218,18 +220,46 @@ static void hidh_search_callback (UINT16 sdp_result)
**
** Description This function initializes the control block and trace variable
**
** Returns void
** Returns tHID_STATUS
**
*******************************************************************************/
void HID_HostInit (void)
tHID_STATUS HID_HostInit (void)
{
#if (HID_DYNAMIC_MEMORY)
if (!hidh_cb_ptr) {
hidh_cb_ptr = (tHID_HOST_CTB *)osi_malloc(sizeof(tHID_HOST_CTB));
if (!hidh_cb_ptr) {
return HID_ERR_NO_RESOURCES;
}
}
#endif /* #if (HID_DYNAMIC_MEMORY) */
memset(&hh_cb, 0, sizeof(tHID_HOST_CTB));
#if defined(HID_INITIAL_TRACE_LEVEL)
hh_cb.trace_level = HID_INITIAL_TRACE_LEVEL;
#if defined(HIDH_INITIAL_TRACE_LEVEL)
hh_cb.trace_level = HIDH_INITIAL_TRACE_LEVEL;
#else
hh_cb.trace_level = BT_TRACE_LEVEL_NONE;
#endif
return HID_SUCCESS;
}
/*******************************************************************************
**
** Function HID_HostInit
**
** Description This function deinitializes the control block
**
** Returns void
**
*******************************************************************************/
void HID_HostDeinit (void)
{
#if (HID_DYNAMIC_MEMORY)
if (hidh_cb_ptr) {
osi_free(hidh_cb_ptr);
hidh_cb_ptr = NULL;
}
#endif /* #if (HID_DYNAMIC_MEMORY) */
}
/*******************************************************************************
@ -362,6 +392,36 @@ tHID_STATUS HID_HostAddDev ( BD_ADDR addr, UINT16 attr_mask, UINT8 *handle )
return (HID_SUCCESS);
}
/*******************************************************************************
**
** Function HID_HostGetDev
**
** Description This is called so HID-host can find this device.
**
** Returns tHID_STATUS
**
*******************************************************************************/
tHID_STATUS HID_HostGetDev(BD_ADDR addr, UINT8 *handle)
{
int i;
/* Find an entry for this device in hh_cb.devices array */
if (!hh_cb.reg_flag) {
return (HID_ERR_NOT_REGISTERED);
}
for (i = 0; i < HID_HOST_MAX_DEVICES; i++) {
if ((hh_cb.devices[i].in_use) && (!memcmp(addr, hh_cb.devices[i].addr, BD_ADDR_LEN))) {
break;
}
}
if (i == HID_HOST_MAX_DEVICES) {
*handle = 0xff;
} else {
*handle = i;
}
return (HID_SUCCESS);
}
/*******************************************************************************
**

View File

@ -41,7 +41,7 @@
#include "stack/hiddefs.h"
#include "stack/hidh_api.h"
#include "hidh_int.h"
#include "hid_int.h"
#include "osi/osi.h"
#if (HID_HOST_INCLUDED == TRUE)
@ -132,15 +132,16 @@ tHID_STATUS hidh_conn_disconnect (UINT8 dhandle)
HIDH_TRACE_EVENT ("HID-Host disconnect");
if ((p_hcon->ctrl_cid != 0) || (p_hcon->intr_cid != 0)) {
p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
/* Set l2cap idle timeout to 0 (so ACL link is disconnected
* immediately after last channel is closed) */
L2CA_SetIdleTimeoutByBdAddr(hh_cb.devices[dhandle].addr, 0, BT_TRANSPORT_BR_EDR);
/* Disconnect both interrupt and control channels */
if (p_hcon->intr_cid) {
p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING_INTR;
L2CA_DisconnectReq (p_hcon->intr_cid);
} else if (p_hcon->ctrl_cid) {
p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING_CTRL;
L2CA_DisconnectReq (p_hcon->ctrl_cid);
}
} else {
@ -360,12 +361,12 @@ static void hidh_l2cif_connect_cfm (UINT16 l2cap_cid, UINT16 result)
p_hcon = &hh_cb.devices[dhandle].conn;
}
if ((p_hcon == NULL)
|| (!(p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG))
|| ((l2cap_cid == p_hcon->ctrl_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_CTRL))
|| ((l2cap_cid == p_hcon->intr_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR)
&& (p_hcon->conn_state != HID_CONN_STATE_DISCONNECTING))) {
HIDH_TRACE_WARNING ("HID-Host Rcvd unexpected conn cnf, CID 0x%x ", l2cap_cid);
if ((p_hcon == NULL) || (!(p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG)) ||
((l2cap_cid == p_hcon->ctrl_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_CTRL) &&
(p_hcon->conn_state != HID_CONN_STATE_DISCONNECTING_INTR)) ||
((l2cap_cid == p_hcon->intr_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR) &&
(p_hcon->conn_state != HID_CONN_STATE_DISCONNECTING_CTRL))) {
HIDH_TRACE_WARNING("HID-Host Rcvd unexpected conn cnf, CID 0x%x ", l2cap_cid);
return;
}
@ -592,12 +593,12 @@ static void hidh_l2cif_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed)
HIDH_TRACE_EVENT ("HID-Host Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
if (l2cap_cid == p_hcon->ctrl_cid) {
p_hcon->ctrl_cid = 0;
p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING_CTRL;
} else {
p_hcon->intr_cid = 0;
p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING_INTR;
}
if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) {

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