diff --git a/.github/workflows/bluetooth.yaml b/.github/workflows/bluetooth.yaml index a52e9f27f6b..1ccd2d53e80 100644 --- a/.github/workflows/bluetooth.yaml +++ b/.github/workflows/bluetooth.yaml @@ -42,14 +42,17 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 + path: ./zephyr - name: west setup + working-directory: ./zephyr run: | west init -l . || true west config --global update.narrow true west update 2>&1 1> west.update.log || west update 2>&1 1> west.update2.log - name: Run Bluetooth Tests with BSIM + working-directory: ./zephyr run: | export ZEPHYR_BASE=${PWD} WORK_DIR=${ZEPHYR_BASE}/bsim_bt_out tests/bluetooth/bsim_bt/compile.sh @@ -61,7 +64,7 @@ jobs: uses: actions/upload-artifact@v2 with: name: Bluetooth Test Results - path: ./bsim_bt_out/bsim_results.xml + path: ./zephyr/bsim_bt_out/bsim_results.xml bluetooth-test-results: name: "Publish Bluetooth Test Results" diff --git a/.github/workflows/clang.yaml b/.github/workflows/clang.yaml index 29464db4b2c..4b7bb7ab7d3 100644 --- a/.github/workflows/clang.yaml +++ b/.github/workflows/clang.yaml @@ -11,7 +11,7 @@ jobs: with: access_token: ${{ github.token }} clang-build: - runs-on: zephyr_runner + runs-on: ubuntu-latest needs: clang-build-prep container: image: zephyrprojectrtos/ci:v0.21.0 @@ -21,12 +21,13 @@ jobs: strategy: fail-fast: false matrix: - platform: ["native_posix"] + subset: [1, 2, 3, 4, 5] env: ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.13.2 CLANG_ROOT_DIR: /usr/lib/llvm-12 COMMIT_RANGE: ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }} BASE_REF: ${{ github.base_ref }} + MATRIX_SIZE: 5 outputs: report_needed: ${{ steps.twister.outputs.report_needed }} steps: @@ -39,8 +40,10 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 + path: ./zephyr - name: Environment Setup + working-directory: ./zephyr run: | pip3 install GitPython echo "$HOME/.local/bin" >> $GITHUB_PATH @@ -59,6 +62,7 @@ jobs: west update --path-cache /github/cache/zephyrproject 2>&1 1> west.log || west update --path-cache /github/cache/zephyrproject 2>&1 1> west2.log || ( rm -rf ../modules ../bootloader ../tools && west update --path-cache /github/cache/zephyrproject) - name: Check Environment + working-directory: ./zephyr run: | cmake --version ${CLANG_ROOT_DIR}/bin/clang --version @@ -66,6 +70,7 @@ jobs: ls -la - name: Prepare ccache timestamp/data + working-directory: ./zephyr id: ccache_cache_timestamp shell: cmake -P {0} run: | @@ -77,7 +82,7 @@ jobs: id: cache-ccache uses: nashif/action-s3-cache@master with: - key: ${{ steps.ccache_cache_timestamp.outputs.repo }}-${{ github.ref_name }}-clang-${{ matrix.platform }}-ccache + key: ${{ steps.ccache_cache_timestamp.outputs.repo }}-${{ github.ref_name }}-clang-${{ matrix.subset }}-ccache path: /github/home/.ccache aws-s3-bucket: ccache.zephyrproject.org aws-access-key-id: ${{ secrets.CCACHE_S3_ACCESS_KEY_ID }} @@ -85,30 +90,41 @@ jobs: aws-region: us-east-2 - name: ccache stats initial + working-directory: ./zephyr run: | test -d github/home/.ccache && rm -rf /github/home/.ccache && mv github/home/.ccache /github/home/.ccache ccache -M 10G -s - - name: Run Tests with Twister - id: twister + - name: Build test plan with Twister + working-directory: ./zephyr + id: twister_test_plan run: | export ZEPHYR_BASE=${PWD} export ZEPHYR_TOOLCHAIN_VARIANT=llvm # check if we need to run a full twister or not based on files changed - python3 ./scripts/ci/test_plan.py --platform ${{ matrix.platform }} -c origin/${BASE_REF}.. + python3 ./scripts/ci/test_plan.py -p native_posix -c origin/${BASE_REF}.. + + + - name: Run Tests with Twister + working-directory: ./zephyr + id: twister + run: | + export ZEPHYR_BASE=${PWD} + export ZEPHYR_TOOLCHAIN_VARIANT=llvm # We can limit scope to just what has changed if [ -s testplan.csv ]; then echo "::set-output name=report_needed::1"; # Full twister but with options based on changes - ./scripts/twister --inline-logs -M -N -v --load-tests testplan.csv --retry-failed 2 + ./scripts/twister --inline-logs -M -N -v --load-tests testplan.csv --retry-failed 2 --subset ${{matrix.subset}}/${MATRIX_SIZE} else # if nothing is run, skip reporting step echo "::set-output name=report_needed::0"; fi - name: ccache stats post + working-directory: ./zephyr run: | ccache -s @@ -116,8 +132,8 @@ jobs: if: always() && steps.twister.outputs.report_needed != 0 uses: actions/upload-artifact@v2 with: - name: Unit Test Results (Subset ${{ matrix.platform }}) - path: twister-out/twister.xml + name: Unit Test Results (Subset ${{ matrix.subset }}) + path: zephyr/twister-out/twister.xml clang-build-results: name: "Publish Unit Tests Results" diff --git a/.github/workflows/compliance.yml b/.github/workflows/compliance.yml index 7abcd1243fc..84e7d20f064 100644 --- a/.github/workflows/compliance.yml +++ b/.github/workflows/compliance.yml @@ -12,7 +12,9 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 + path: ./zephyr - name: Run Maintainers Script + working-directory: ./zephyr id: maintainer env: BASE_REF: ${{ github.base_ref }} @@ -32,6 +34,7 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 + path: ./zephyr - name: cache-pip uses: actions/cache@v1 @@ -47,12 +50,15 @@ jobs: pip3 install west - name: west setup + working-directory: ./zephyr env: BASE_REF: ${{ github.base_ref }} run: | git config --global user.email "you@example.com" git config --global user.name "Your Name" git remote -v + # Sauce tag checks before rebasing + git log --oneline --first-parent origin/${BASE_REF}..HEAD | grep -E -v "\[nrf (mergeup|fromtree|fromlist|noup)\][ ]" && { echo 'Sauce tag missing or invalid, format is "[nrf ] "'; exit 1; } git rebase origin/${BASE_REF} # debug git log --pretty=oneline | head -n 10 @@ -60,6 +66,7 @@ jobs: west update 2>&1 1> west.update.log || west update 2>&1 1> west.update2.log - name: Run Compliance Tests + working-directory: ./zephyr continue-on-error: true id: compliance env: @@ -69,22 +76,23 @@ jobs: # debug ls -la git log --pretty=oneline | head -n 10 - ./scripts/ci/check_compliance.py -m Codeowners -m Devicetree -m Gitlint -m Identity -m Nits -m pylint -m checkpatch -m Kconfig -c origin/${BASE_REF}.. + ./scripts/ci/check_compliance.py -m Codeowners -m Devicetree -m Gitlint -m Identity -m Nits -m pylint -m checkpatch -m KconfigBasic -c origin/${BASE_REF}.. - name: upload-results uses: actions/upload-artifact@master continue-on-error: True with: name: compliance.xml - path: compliance.xml + path: zephyr/compliance.xml - name: check-warns + working-directory: ./zephyr run: | if [[ ! -s "compliance.xml" ]]; then exit 1; fi - for file in Nits.txt checkpatch.txt Identity.txt Gitlint.txt pylint.txt Devicetree.txt Kconfig.txt Codeowners.txt; do + for file in Nits.txt checkpatch.txt Identity.txt Gitlint.txt pylint.txt Devicetree.txt KconfigBasic.txt Codeowners.txt; do if [[ -s $file ]]; then errors=$(cat $file) errors="${errors//'%'/'%25'}" diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index cb3f365a591..9c7a4223970 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -44,8 +44,11 @@ jobs: steps: - name: checkout uses: actions/checkout@v2 + with: + path: ./zephyr - name: install-pkgs + working-directory: ./zephyr run: | sudo apt-get install -y ninja-build graphviz libclang1-9 libclang-cpp9 wget -q https://www.doxygen.nl/files/doxygen-${DOXYGEN_VERSION}.linux.bin.tar.gz @@ -56,20 +59,22 @@ jobs: uses: actions/cache@v1 with: path: ~/.cache/pip - key: pip-${{ hashFiles('scripts/requirements-doc.txt') }} + key: pip-${{ hashFiles('zephyr/scripts/requirements-doc.txt') }} - name: install-pip run: | sudo pip3 install -U setuptools wheel pip - pip3 install -r scripts/requirements-doc.txt + pip3 install -r zephyr/scripts/requirements-doc.txt pip3 install west==${WEST_VERSION} pip3 install cmake==${CMAKE_VERSION} - name: west setup + working-directory: ./zephyr run: | west init -l . - name: build-docs + working-directory: ./zephyr run: | if [[ "$GITHUB_REF" =~ "refs/tags/v" ]]; then DOC_TAG="release" @@ -86,6 +91,7 @@ jobs: DOC_TAG=${DOC_TAG} SPHINXOPTS="-q -W -t publish" make -C doc ${DOC_TARGET} - name: compress-docs + working-directory: ./zephyr run: | tar cfJ html-output.tar.xz --directory=doc/_build html @@ -93,7 +99,7 @@ jobs: uses: actions/upload-artifact@master with: name: html-output - path: html-output.tar.xz + path: zephyr/html-output.tar.xz doc-build-pdf: name: "Documentation Build (PDF)" @@ -107,6 +113,8 @@ jobs: steps: - name: checkout uses: actions/checkout@v2 + with: + path: ./zephyr - name: install-pkgs run: | @@ -117,20 +125,22 @@ jobs: uses: actions/cache@v1 with: path: ~/.cache/pip - key: pip-${{ hashFiles('scripts/requirements-doc.txt') }} + key: pip-${{ hashFiles('zephyr/scripts/requirements-doc.txt') }} - name: install-pip run: | pip3 install -U setuptools wheel pip - pip3 install -r scripts/requirements-doc.txt + pip3 install -r zephyr/scripts/requirements-doc.txt pip3 install west==${WEST_VERSION} pip3 install cmake==${CMAKE_VERSION} - name: west setup + working-directory: ./zephyr run: | west init -l . - name: build-docs + working-directory: ./zephyr run: | if [[ "$GITHUB_REF" =~ "refs/tags/v" ]]; then DOC_TAG="release" @@ -144,4 +154,4 @@ jobs: uses: actions/upload-artifact@master with: name: pdf-output - path: doc/_build/latex/zephyr.pdf + path: zephyr/doc/_build/latex/zephyr.pdf diff --git a/.github/workflows/twister_tests.yml b/.github/workflows/twister_tests.yml index 19f747b0432..b6e93014bba 100644 --- a/.github/workflows/twister_tests.yml +++ b/.github/workflows/twister_tests.yml @@ -28,6 +28,8 @@ jobs: steps: - name: checkout uses: actions/checkout@v2 + with: + path: ./zephyr - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v1 with: @@ -44,6 +46,7 @@ jobs: run: | pip3 install pytest colorama pyyaml ply mock - name: Run pytest + working-directory: ./zephyr env: ZEPHYR_BASE: ./ ZEPHYR_TOOLCHAIN_VARIANT: zephyr diff --git a/.gitlint b/.gitlint index 851fd915d38..b05227ed86f 100644 --- a/.gitlint +++ b/.gitlint @@ -13,7 +13,7 @@ debug = false extra-path=scripts/gitlint [title-max-length-no-revert] -line-length=75 +line-length=120 [body-min-line-count] min-line-count=1 @@ -39,7 +39,7 @@ words=wip [max-line-length-with-exceptions] # B1 = body-max-line-length -line-length=75 +line-length=120 [body-min-length] min-length=3 diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 00000000000..3b9cf002239 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,5 @@ +@Library("CI_LIB") _ + +def pipeline = new ncs.sdk_zephyr.Main() + +pipeline.run(JOB_NAME) diff --git a/Kconfig.zephyr b/Kconfig.zephyr index d2d3e0a8db1..ae6835721fd 100644 --- a/Kconfig.zephyr +++ b/Kconfig.zephyr @@ -120,9 +120,7 @@ config FLASH_LOAD_SIZE endif # HAS_FLASH_LOAD_OFFSET config ROM_START_OFFSET - hex - prompt "ROM start offset" if !BOOTLOADER_MCUBOOT - default 0x200 if BOOTLOADER_MCUBOOT + hex "ROM start offset" default 0 help If the application is built for chain-loading by a bootloader this diff --git a/arch/Kconfig b/arch/Kconfig index 1c907c9ec1f..ccb2eb20303 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -843,9 +843,13 @@ config SRAM_REGION_PERMISSIONS menu "Floating Point Options" +config IS_SPM + bool + config FPU bool "Enable floating point unit (FPU)" depends on CPU_HAS_FPU + depends on !IS_SPM help This option enables the hardware Floating Point Unit (FPU), in order to support using the floating point registers and instructions. diff --git a/boards/arm/bl5340_dvk/bl5340_dvk_cpunet_reset.c b/boards/arm/bl5340_dvk/bl5340_dvk_cpunet_reset.c index d3e97148878..fb685f1c77a 100644 --- a/boards/arm/bl5340_dvk/bl5340_dvk_cpunet_reset.c +++ b/boards/arm/bl5340_dvk/bl5340_dvk_cpunet_reset.c @@ -10,51 +10,43 @@ #include #include +#include LOG_MODULE_REGISTER(bl5340_dvk_cpuapp, CONFIG_LOG_DEFAULT_LEVEL); -#if !defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) - -/* This should come from DTS, possibly an overlay. */ -#if defined(CONFIG_BOARD_BL5340_DVK_CPUAPP) -#define CPUNET_UARTE_PIN_TX 8 -#define CPUNET_UARTE_PIN_RX 10 -#define CPUNET_UARTE_PORT_TRX NRF_P1 -#define CPUNET_UARTE_PIN_RTS 7 -#define CPUNET_UARTE_PIN_CTS 9 -#define CPUNET_UARTE_PORT_RCTS NRF_P1 -#endif +/* TODO: This should come from DTS, possibly an overlay. */ +#define CPUNET_UARTE_PIN_TX 33 +#define CPUNET_UARTE_PIN_RX 32 +#define CPUNET_UARTE_PIN_RTS 11 +#define CPUNET_UARTE_PIN_CTS 10 static void remoteproc_mgr_config(void) { +#if !defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) || defined(CONFIG_BUILD_WITH_TFM) /* UARTE */ /* Assign specific GPIOs that will be used to get UARTE from * nRF5340 Network MCU. */ - CPUNET_UARTE_PORT_TRX->PIN_CNF[CPUNET_UARTE_PIN_TX] = - GPIO_PIN_CNF_MCUSEL_NetworkMCU << GPIO_PIN_CNF_MCUSEL_Pos; - CPUNET_UARTE_PORT_TRX->PIN_CNF[CPUNET_UARTE_PIN_RX] = - GPIO_PIN_CNF_MCUSEL_NetworkMCU << GPIO_PIN_CNF_MCUSEL_Pos; - CPUNET_UARTE_PORT_RCTS->PIN_CNF[CPUNET_UARTE_PIN_RTS] = - GPIO_PIN_CNF_MCUSEL_NetworkMCU << GPIO_PIN_CNF_MCUSEL_Pos; - CPUNET_UARTE_PORT_RCTS->PIN_CNF[CPUNET_UARTE_PIN_CTS] = - GPIO_PIN_CNF_MCUSEL_NetworkMCU << GPIO_PIN_CNF_MCUSEL_Pos; + soc_secure_gpio_pin_mcu_select(CPUNET_UARTE_PIN_TX, NRF_GPIO_PIN_MCUSEL_NETWORK); + soc_secure_gpio_pin_mcu_select(CPUNET_UARTE_PIN_RX, NRF_GPIO_PIN_MCUSEL_NETWORK); + soc_secure_gpio_pin_mcu_select(CPUNET_UARTE_PIN_RTS, NRF_GPIO_PIN_MCUSEL_NETWORK); + soc_secure_gpio_pin_mcu_select(CPUNET_UARTE_PIN_CTS, NRF_GPIO_PIN_MCUSEL_NETWORK); +#endif /* !defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) || defined(CONFIG_BUILD_WITH_TFM) */ +#if !defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) /* Retain nRF5340 Network MCU in Secure domain (bus * accesses by Network MCU will have Secure attribute set). */ NRF_SPU->EXTDOMAIN[0].PERM = 1 << 4; -} #endif /* !CONFIG_TRUSTED_EXECUTION_NONSECURE */ +} static int remoteproc_mgr_boot(const struct device *dev) { ARG_UNUSED(dev); -#if !defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) /* Secure domain may configure permissions for the Network MCU. */ remoteproc_mgr_config(); -#endif /* !CONFIG_TRUSTED_EXECUTION_NONSECURE */ #if !defined(CONFIG_TRUSTED_EXECUTION_SECURE) /* diff --git a/boards/arm/nrf5340dk_nrf5340/Kconfig.defconfig b/boards/arm/nrf5340dk_nrf5340/Kconfig.defconfig index ce5086e5052..ea0896d8c3f 100644 --- a/boards/arm/nrf5340dk_nrf5340/Kconfig.defconfig +++ b/boards/arm/nrf5340dk_nrf5340/Kconfig.defconfig @@ -12,7 +12,10 @@ config BOARD # force building with TF-M as the Secure Execution Environment. config BUILD_WITH_TFM - default y if BOARD_NRF5340DK_NRF5340_CPUAPP_NS + # Temporarily disable building Non-Secure images with TF-M support by + # default. + # default y if BOARD_NRF5340DK_NRF5340_CPUAPP_NS + default n if BUILD_WITH_TFM diff --git a/boards/arm/nrf5340dk_nrf5340/nrf5340_cpunet_reset.c b/boards/arm/nrf5340dk_nrf5340/nrf5340_cpunet_reset.c index d0f5e5eefbf..0223ce8cf1a 100644 --- a/boards/arm/nrf5340dk_nrf5340/nrf5340_cpunet_reset.c +++ b/boards/arm/nrf5340dk_nrf5340/nrf5340_cpunet_reset.c @@ -9,19 +9,15 @@ #include #include +#include LOG_MODULE_REGISTER(nrf5340dk_nrf5340_cpuapp, CONFIG_LOG_DEFAULT_LEVEL); -#if !defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) - -/* This should come from DTS, possibly an overlay. */ -#if defined(CONFIG_BOARD_NRF5340DK_NRF5340_CPUAPP) -#define CPUNET_UARTE_PIN_TX 1 -#define CPUNET_UARTE_PIN_RX 0 -#define CPUNET_UARTE_PORT_TRX NRF_P1 +/* TODO: This should come from DTS, possibly an overlay. */ +#define CPUNET_UARTE_PIN_TX 33 +#define CPUNET_UARTE_PIN_RX 32 #define CPUNET_UARTE_PIN_RTS 11 #define CPUNET_UARTE_PIN_CTS 10 -#endif #if defined(CONFIG_BT_CTLR_DEBUG_PINS_CPUAPP) #include <../subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/debug.h> @@ -31,37 +27,34 @@ LOG_MODULE_REGISTER(nrf5340dk_nrf5340_cpuapp, CONFIG_LOG_DEFAULT_LEVEL); static void remoteproc_mgr_config(void) { +#if !defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) || defined(CONFIG_BUILD_WITH_TFM) /* UARTE */ /* Assign specific GPIOs that will be used to get UARTE from * nRF5340 Network MCU. */ - CPUNET_UARTE_PORT_TRX->PIN_CNF[CPUNET_UARTE_PIN_TX] = - GPIO_PIN_CNF_MCUSEL_NetworkMCU << GPIO_PIN_CNF_MCUSEL_Pos; - CPUNET_UARTE_PORT_TRX->PIN_CNF[CPUNET_UARTE_PIN_RX] = - GPIO_PIN_CNF_MCUSEL_NetworkMCU << GPIO_PIN_CNF_MCUSEL_Pos; - NRF_P0->PIN_CNF[CPUNET_UARTE_PIN_RTS] = - GPIO_PIN_CNF_MCUSEL_NetworkMCU << GPIO_PIN_CNF_MCUSEL_Pos; - NRF_P0->PIN_CNF[CPUNET_UARTE_PIN_CTS] = - GPIO_PIN_CNF_MCUSEL_NetworkMCU << GPIO_PIN_CNF_MCUSEL_Pos; + soc_secure_gpio_pin_mcu_select(CPUNET_UARTE_PIN_TX, NRF_GPIO_PIN_MCUSEL_NETWORK); + soc_secure_gpio_pin_mcu_select(CPUNET_UARTE_PIN_RX, NRF_GPIO_PIN_MCUSEL_NETWORK); + soc_secure_gpio_pin_mcu_select(CPUNET_UARTE_PIN_RTS, NRF_GPIO_PIN_MCUSEL_NETWORK); + soc_secure_gpio_pin_mcu_select(CPUNET_UARTE_PIN_CTS, NRF_GPIO_PIN_MCUSEL_NETWORK); /* Route Bluetooth Controller Debug Pins */ DEBUG_SETUP(); +#endif /* !defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) || defined(CONFIG_BUILD_WITH_TFM) */ +#if !defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) /* Retain nRF5340 Network MCU in Secure domain (bus * accesses by Network MCU will have Secure attribute set). */ NRF_SPU->EXTDOMAIN[0].PERM = 1 << 4; +#endif /* !defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) */ } -#endif /* !CONFIG_TRUSTED_EXECUTION_NONSECURE */ static int remoteproc_mgr_boot(const struct device *dev) { ARG_UNUSED(dev); -#if !defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) /* Secure domain may configure permissions for the Network MCU. */ remoteproc_mgr_config(); -#endif /* !CONFIG_TRUSTED_EXECUTION_NONSECURE */ #if !defined(CONFIG_TRUSTED_EXECUTION_SECURE) /* diff --git a/boards/arm/nrf9160dk_nrf9160/Kconfig.defconfig b/boards/arm/nrf9160dk_nrf9160/Kconfig.defconfig index 4b30798ae73..e51bc95b55d 100644 --- a/boards/arm/nrf9160dk_nrf9160/Kconfig.defconfig +++ b/boards/arm/nrf9160dk_nrf9160/Kconfig.defconfig @@ -8,12 +8,6 @@ if BOARD_NRF9160DK_NRF9160 || BOARD_NRF9160DK_NRF9160_NS config BOARD default "nrf9160dk_nrf9160" -# By default, if we build for a Non-Secure version of the board, -# force building with TF-M as the Secure Execution Environment. - -config BUILD_WITH_TFM - default y if BOARD_NRF9160DK_NRF9160_NS - if BUILD_WITH_TFM # By default, if we build with TF-M, instruct build system to diff --git a/boards/arm/nucleo_f767zi/doc/index.rst b/boards/arm/nucleo_f767zi/doc/index.rst index 4a375722313..1bd38ad492c 100644 --- a/boards/arm/nucleo_f767zi/doc/index.rst +++ b/boards/arm/nucleo_f767zi/doc/index.rst @@ -127,7 +127,7 @@ features: (*) nucleo_f767zi with soc cut-A (Device marking A) has some ethernet - instability (https://github.com/zephyrproject-rtos/zephyr/issues/26519). + instability (:github:`26519`). Use of cut-Z is advised. see restrictions errata: https://www.st.com/content/ccc/resource/technical/document/errata_sheet/group0/23/a6/11/0b/30/24/46/a5/DM00257543/files/DM00257543.pdf/jcr:content/translations/en.DM00257543.pdf diff --git a/cmake/app/boilerplate.cmake b/cmake/app/boilerplate.cmake index 6102d739c9f..ea9cfb8f88b 100644 --- a/cmake/app/boilerplate.cmake +++ b/cmake/app/boilerplate.cmake @@ -674,6 +674,10 @@ set_property(TARGET app PROPERTY ARCHIVE_OUTPUT_DIRECTORY app) add_subdirectory(${ZEPHYR_BASE} ${__build_dir}) +if(ZEPHYR_NRF_MODULE_DIR) + include(${ZEPHYR_NRF_MODULE_DIR}/cmake/partition_manager.cmake) +endif() + # Link 'app' with the Zephyr interface libraries. # # NB: This must be done in boilerplate.cmake because 'app' can only be diff --git a/cmake/linker/ld/target.cmake b/cmake/linker/ld/target.cmake index f29d4e6be78..a41e2d1744c 100644 --- a/cmake/linker/ld/target.cmake +++ b/cmake/linker/ld/target.cmake @@ -67,7 +67,6 @@ macro(configure_linker_script linker_script_gen linker_pass_define) endif() zephyr_get_include_directories_for_lang(C current_includes) - get_filename_component(base_name ${CMAKE_CURRENT_BINARY_DIR} NAME) get_property(current_defines GLOBAL PROPERTY PROPERTY_LINKER_SCRIPT_DEFINES) add_custom_command( @@ -81,7 +80,7 @@ macro(configure_linker_script linker_script_gen linker_pass_define) COMMAND ${CMAKE_C_COMPILER} -x assembler-with-cpp ${NOSYSDEF_CFLAG} - -MD -MF ${linker_script_gen}.dep -MT ${base_name}/${linker_script_gen} + -MD -MF ${linker_script_gen}.dep -MT ${linker_script_gen} -D_LINKER -D_ASMLANGUAGE -imacros ${AUTOCONF_H} diff --git a/doc/contribute/coding_guidelines/index.rst b/doc/contribute/coding_guidelines/index.rst index 01504a8d177..b26bcf5efd7 100644 --- a/doc/contribute/coding_guidelines/index.rst +++ b/doc/contribute/coding_guidelines/index.rst @@ -926,7 +926,7 @@ Related GitHub Issues and Pull Requests are tagged with the `Inclusive Language terminology is confirmed by a public announcement or updated specification. - See `Zephyr issue 27033`_. + See :github:`Zephyr issue 27033 <27033>`. * - :ref:`i2s_api` - * ``master / slave`` => TBD @@ -951,7 +951,6 @@ Related GitHub Issues and Pull Requests are tagged with the `Inclusive Language .. _I2C Specification: https://www.nxp.com/docs/en/user-guide/UM10204.pdf .. _Bluetooth Appropriate Language Mapping Tables: https://btprodspecificationrefs.blob.core.windows.net/language-mapping/Appropriate_Language_Mapping_Table.pdf .. _OSHWA Resolution to Redefine SPI Signal Names: https://www.oshwa.org/a-resolution-to-redefine-spi-signal-names/ -.. _Zephyr issue 27033: https://github.com/zephyrproject-rtos/zephyr/issues/27033 Parasoft Codescan Tool ********************** diff --git a/doc/contribute/external.rst b/doc/contribute/external.rst index 09381213a47..004c4ec037a 100644 --- a/doc/contribute/external.rst +++ b/doc/contribute/external.rst @@ -124,7 +124,8 @@ Follow the steps below to begin the submission process: #. Make sure to read through the :ref:`external-contributions` section in detail, so that you are informed of the criteria used by the TSC and board in order to approve or reject a request -#. Use the `New External Source Code Issue`_ to open an issue +#. Use the :github:`New External Source Code Issue + ` to open an issue #. Fill out all required sections, making sure you provide enough detail for the TSC to assess the merit of the request. Optionally you can also create a Pull Request that demonstrates the integration of the external source code and @@ -163,6 +164,3 @@ The flowchart below shows an overview of the process: :align: center Submission process - -.. _New External Source Code Issue: - https://github.com/zephyrproject-rtos/zephyr/issues/new?assignees=&labels=RFC&template=ext-source.md&title= diff --git a/doc/development_process/project_roles.rst b/doc/development_process/project_roles.rst index acba6a0f432..adc10ce0faf 100644 --- a/doc/development_process/project_roles.rst +++ b/doc/development_process/project_roles.rst @@ -60,8 +60,8 @@ Contributors who show dedication and skill are granted the Triage permission level to the Zephyr GitHub repository. You may nominate yourself, or another GitHub user, for promotion to the Triage -permission level by creating a GitHub issue, using the `nomination template -`_. +permission level by creating a GitHub issue, using the :github:`nomination +template `. Contributors granted the Triage permission level are permitted to add reviewers to a pull request and can be added as a reviewer by other GitHub users. diff --git a/doc/getting_started/installation_win.rst b/doc/getting_started/installation_win.rst index c71a9e3a9cc..2bf569d52c1 100644 --- a/doc/getting_started/installation_win.rst +++ b/doc/getting_started/installation_win.rst @@ -16,7 +16,7 @@ command-prompt. This allows you to use software such as the :ref:`Zephyr SDK .. warning:: Windows 10 version 1803 has an issue that will cause CMake to not work properly and is fixed in version 1809 (and later). - More information can be found in `Zephyr Issue 10420`_ + More information can be found in :github:`Zephyr Issue 10420 <10420>`. #. `Install the Windows Subsystem for Linux (WSL)`_. @@ -33,4 +33,3 @@ command-prompt. This allows you to use software such as the :ref:`Zephyr SDK the documentation itself here. .. _Install the Windows Subsystem for Linux (WSL): https://msdn.microsoft.com/en-us/commandline/wsl/install_guide -.. _Zephyr Issue 10420: https://github.com/zephyrproject-rtos/zephyr/issues/10420 diff --git a/doc/guides/west/why.rst b/doc/guides/west/why.rst index e1f513812c7..628d557592e 100644 --- a/doc/guides/west/why.rst +++ b/doc/guides/west/why.rst @@ -117,7 +117,4 @@ West is: interoperability with third party tools, and means Zephyr developers can always find out what is happening "under the hood" when using west. -See `Zephyr issue #6205`_ and for more details and discussion. - -.. _Zephyr issue #6205: - https://github.com/zephyrproject-rtos/zephyr/issues/6205 +See :github:`Zephyr issue #6205 <6205>` and for more details and discussion. diff --git a/doc/releases/release-notes-3.0.rst b/doc/releases/release-notes-3.0.rst index 2406c39a698..9e22c25d666 100644 --- a/doc/releases/release-notes-3.0.rst +++ b/doc/releases/release-notes-3.0.rst @@ -44,7 +44,13 @@ Changes in this release Changes in this release ======================= -Removed APIs in this release: +* GATT callbacks ``bt_gatt_..._func_t`` would previously be called with argument + ``conn = NULL`` in the event of a disconnect. This was not documented as part + of the API. This behavior is changed so the ``conn`` argument is provided as + normal when a disconnect occurs. + +Removed APIs in this release +============================ * The following Kconfig options related to radio front-end modules (FEMs) were removed: diff --git a/drivers/bluetooth/hci/h4.c b/drivers/bluetooth/hci/h4.c index b8c77282b49..9b145be82de 100644 --- a/drivers/bluetooth/hci/h4.c +++ b/drivers/bluetooth/hci/h4.c @@ -164,8 +164,7 @@ static inline void get_evt_hdr(void) if (!rx.remaining) { if (rx.evt.evt == BT_HCI_EVT_LE_META_EVENT && - (rx.hdr[sizeof(*hdr)] == BT_HCI_EVT_LE_ADVERTISING_REPORT || - rx.hdr[sizeof(*hdr)] == BT_HCI_EVT_LE_EXT_ADVERTISING_REPORT)) { + (rx.hdr[sizeof(*hdr)] == BT_HCI_EVT_LE_ADVERTISING_REPORT)) { BT_DBG("Marking adv report as discardable"); rx.discardable = true; } diff --git a/drivers/bluetooth/hci/hci_esp32.c b/drivers/bluetooth/hci/hci_esp32.c index 70da2163da9..0a866e2199f 100644 --- a/drivers/bluetooth/hci/hci_esp32.c +++ b/drivers/bluetooth/hci/hci_esp32.c @@ -41,8 +41,6 @@ static bool is_hci_event_discardable(const uint8_t *evt_data) switch (subevt_type) { case BT_HCI_EVT_LE_ADVERTISING_REPORT: return true; - case BT_HCI_EVT_LE_EXT_ADVERTISING_REPORT: - return true; default: return false; } diff --git a/drivers/bluetooth/hci/ipm_stm32wb.c b/drivers/bluetooth/hci/ipm_stm32wb.c index fb0c6a1f494..a487b8b0193 100644 --- a/drivers/bluetooth/hci/ipm_stm32wb.c +++ b/drivers/bluetooth/hci/ipm_stm32wb.c @@ -181,8 +181,7 @@ static void bt_ipm_rx_thread(void) default: mev = (void *)&hcievt->evtserial.evt.payload; if (hcievt->evtserial.evt.evtcode == BT_HCI_EVT_LE_META_EVENT && - (mev->subevent == BT_HCI_EVT_LE_ADVERTISING_REPORT || - mev->subevent == BT_HCI_EVT_LE_EXT_ADVERTISING_REPORT)) { + (mev->subevent == BT_HCI_EVT_LE_ADVERTISING_REPORT)) { discardable = true; timeout = K_NO_WAIT; } diff --git a/drivers/bluetooth/hci/rpmsg.c b/drivers/bluetooth/hci/rpmsg.c index 1f702089ab8..281a77d90e9 100644 --- a/drivers/bluetooth/hci/rpmsg.c +++ b/drivers/bluetooth/hci/rpmsg.c @@ -41,8 +41,6 @@ static bool is_hci_event_discardable(const uint8_t *evt_data) switch (subevt_type) { case BT_HCI_EVT_LE_ADVERTISING_REPORT: return true; - case BT_HCI_EVT_LE_EXT_ADVERTISING_REPORT: - return true; default: return false; } diff --git a/drivers/bluetooth/hci/spi.c b/drivers/bluetooth/hci/spi.c index 642c3799c24..359667aad69 100644 --- a/drivers/bluetooth/hci/spi.c +++ b/drivers/bluetooth/hci/spi.c @@ -370,8 +370,7 @@ static void bt_spi_rx_thread(void) continue; default: if (rxmsg[1] == BT_HCI_EVT_LE_META_EVENT && - (rxmsg[3] == BT_HCI_EVT_LE_ADVERTISING_REPORT || - rxmsg[3] == BT_HCI_EVT_LE_EXT_ADVERTISING_REPORT)) { + (rxmsg[3] == BT_HCI_EVT_LE_ADVERTISING_REPORT)) { discardable = true; timeout = K_NO_WAIT; } diff --git a/drivers/bluetooth/hci/userchan.c b/drivers/bluetooth/hci/userchan.c index 1dc5a9f5dc5..d856f89e94c 100644 --- a/drivers/bluetooth/hci/userchan.c +++ b/drivers/bluetooth/hci/userchan.c @@ -64,8 +64,7 @@ static struct net_buf *get_rx(const uint8_t *buf) switch (buf[0]) { case H4_EVT: if (buf[1] == BT_HCI_EVT_LE_META_EVENT && - (buf[3] == BT_HCI_EVT_LE_ADVERTISING_REPORT || - buf[3] == BT_HCI_EVT_LE_EXT_ADVERTISING_REPORT)) { + (buf[3] == BT_HCI_EVT_LE_ADVERTISING_REPORT)) { discardable = true; timeout = K_NO_WAIT; } diff --git a/drivers/clock_control/clock_control_nrf.c b/drivers/clock_control/clock_control_nrf.c index 2712e8f4393..04dfe1c65c0 100644 --- a/drivers/clock_control/clock_control_nrf.c +++ b/drivers/clock_control/clock_control_nrf.c @@ -14,11 +14,6 @@ #include #include -#if defined(CONFIG_SOC_NRF5340_CPUAPP) && \ - !defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) -#include -#endif - LOG_MODULE_REGISTER(clock_control, CONFIG_CLOCK_CONTROL_LOG_LEVEL); #define DT_DRV_COMPAT nordic_nrf_clock diff --git a/drivers/flash/nrf_qspi_nor.c b/drivers/flash/nrf_qspi_nor.c index ea60a5806e0..9ed6dd18ac6 100644 --- a/drivers/flash/nrf_qspi_nor.c +++ b/drivers/flash/nrf_qspi_nor.c @@ -38,6 +38,9 @@ struct qspi_nor_data { */ volatile bool ready; #endif /* CONFIG_MULTITHREADING */ +#if defined(CONFIG_SOC_SERIES_NRF53X) + bool keep_base_clock_div_set; +#endif }; struct qspi_nor_config { @@ -57,10 +60,63 @@ struct qspi_nor_config { /* instance 0 flash size in bytes */ #define INST_0_BYTES (DT_INST_PROP(0, size) / 8) +/* + * Determine a configuration value (INST_0_SCK_CFG) to be used to achieve the + * SCK frequency specified in DT and, if needed, a divider (BASE_CLOCK_DIV) for + * the clock from which the SCK frequency is derived. + */ #define INST_0_SCK_FREQUENCY DT_INST_PROP(0, sck_frequency) BUILD_ASSERT(INST_0_SCK_FREQUENCY >= (NRF_QSPI_BASE_CLOCK_FREQ / 16), "Unsupported SCK frequency."); +#if defined(CONFIG_SOC_SERIES_NRF53X) +/* + * On nRF53 Series SoCs, the highest SCK frequencies can only be achieved + * when the HFCLK192M clock divider is changed from the default /4 setting. + * Such change results in increased power consumption, so the divider needs + * to be changed only for periods when it is actually needed. + */ +#if (INST_0_SCK_FREQUENCY >= NRF_QSPI_BASE_CLOCK_FREQ) +/* Use HFCLK192M / 1 / (2*1) = 96 MHz */ +#define BASE_CLOCK_DIV NRF_CLOCK_HFCLK_DIV_1 +#define INST_0_SCK_CFG NRF_QSPI_FREQ_DIV1 +#elif (INST_0_SCK_FREQUENCY >= (NRF_QSPI_BASE_CLOCK_FREQ / 2)) +/* Use HFCLK192M / 2 / (2*1) = 48 MHz */ +#define BASE_CLOCK_DIV NRF_CLOCK_HFCLK_DIV_2 +#define INST_0_SCK_CFG NRF_QSPI_FREQ_DIV1 +#elif (INST_0_SCK_FREQUENCY >= (NRF_QSPI_BASE_CLOCK_FREQ / 3)) +/* Use HFCLK192M / 1 / (2*3) = 32 MHz */ +#define BASE_CLOCK_DIV NRF_CLOCK_HFCLK_DIV_1 +#define INST_0_SCK_CFG NRF_QSPI_FREQ_DIV3 +#elif (INST_0_SCK_FREQUENCY >= (NRF_QSPI_BASE_CLOCK_FREQ / 4)) +/* Use HFCLK192M / 4 / (2*1) = 24 MHz */ +/* BASE_CLOCK_DIV not defined => the default NRF_CLOCK_HFCLK_DIV_4 is used. */ +#define INST_0_SCK_CFG NRF_QSPI_FREQ_DIV1 +#elif (INST_0_SCK_FREQUENCY >= (NRF_QSPI_BASE_CLOCK_FREQ / 6)) +/* Use HFCLK192M / 2 / (2*3) = 16 MHz */ +#define BASE_CLOCK_DIV NRF_CLOCK_HFCLK_DIV_2 +#define INST_0_SCK_CFG NRF_QSPI_FREQ_DIV3 +#else +/* BASE_CLOCK_DIV not defined => the default NRF_CLOCK_HFCLK_DIV_4 is used. */ +#define INST_0_SCK_CFG (ceiling_fraction(NRF_QSPI_BASE_CLOCK_FREQ / 4, \ + INST_0_SCK_FREQUENCY) - 1) +#endif + +#else +/* + * On nRF52 Series SoCs, the base clock divider is not configurable, + * so BASE_CLOCK_DIV is not defined. + */ +#if (INST_0_SCK_FREQUENCY >= NRF_QSPI_BASE_CLOCK_FREQ) +#define INST_0_SCK_CFG NRF_QSPI_FREQ_DIV1 +#else +#define INST_0_SCK_CFG (ceiling_fraction(NRF_QSPI_BASE_CLOCK_FREQ, \ + INST_0_SCK_FREQUENCY) - 1) + +#endif + +#endif /* defined(CONFIG_SOC_SERIES_NRF53X) */ + /* 0 for MODE0 (CPOL=0, CPHA=0), 1 for MODE3 (CPOL=1, CPHA=1). */ #define INST_0_SPI_MODE DT_INST_PROP(0, cpol) BUILD_ASSERT(DT_INST_PROP(0, cpol) == DT_INST_PROP(0, cpha), @@ -152,24 +208,42 @@ static inline int qspi_get_zephyr_ret_code(nrfx_err_t res) static inline void qspi_lock(const struct device *dev) { -#ifdef CONFIG_MULTITHREADING struct qspi_nor_data *dev_data = dev->data; +#ifdef CONFIG_MULTITHREADING k_sem_take(&dev_data->sem, K_FOREVER); #else /* CONFIG_MULTITHREADING */ - ARG_UNUSED(dev); + ARG_UNUSED(dev_data); #endif /* CONFIG_MULTITHREADING */ + + /* + * If the base clock divider needs to be changed, change it only + * for the time the driver is locked to perform a QSPI operation, + * unless the divider is forced to be kept set permanently. + */ +#if defined(BASE_CLOCK_DIV) + if (!dev_data->keep_base_clock_div_set) { + nrf_clock_hfclk192m_div_set(NRF_CLOCK, BASE_CLOCK_DIV); + } +#endif } static inline void qspi_unlock(const struct device *dev) { -#ifdef CONFIG_MULTITHREADING struct qspi_nor_data *dev_data = dev->data; +#if defined(BASE_CLOCK_DIV) + /* Restore the default base clock divider, unless instructed not to. */ + if (!dev_data->keep_base_clock_div_set) { + nrf_clock_hfclk192m_div_set(NRF_CLOCK, NRF_CLOCK_HFCLK_DIV_4); + } +#endif + +#ifdef CONFIG_MULTITHREADING k_sem_give(&dev_data->sem); -#else /* CONFIG_MULTITHREADING */ - ARG_UNUSED(dev); -#endif /* CONFIG_MULTITHREADING */ +#else + ARG_UNUSED(dev_data); +#endif } static inline void qspi_trans_lock(const struct device *dev) @@ -975,11 +1049,8 @@ static int qspi_nor_configure(const struct device *dev) static int qspi_nor_init(const struct device *dev) { #if defined(CONFIG_SOC_SERIES_NRF53X) - /* Make sure the PCLK192M clock, from which the SCK frequency is - * derived, is not prescaled (the default setting after reset is - * "divide by 4"). - */ - nrf_clock_hfclk192m_div_set(NRF_CLOCK, NRF_CLOCK_HFCLK_DIV_1); + /* Make sure the default /4 divider is set initially. */ + nrf_clock_hfclk192m_div_set(NRF_CLOCK, NRF_CLOCK_HFCLK_DIV_4); #endif IRQ_CONNECT(DT_IRQN(QSPI_NODE), DT_IRQ(QSPI_NODE, priority), @@ -1142,6 +1213,40 @@ static int qspi_nor_pm_action(const struct device *dev, } #endif /* CONFIG_PM_DEVICE */ +void z_impl_nrf_qspi_nor_base_clock_div_force(const struct device *dev, + bool force) +{ +#if defined(BASE_CLOCK_DIV) + struct qspi_nor_data *dev_data = dev->data; + /* + * The divider is normally changed, unless the flag is set, only for + * periods when the driver is locked, so the flag itself also can only + * be modified while the driver is locked. + */ + qspi_lock(dev); + dev_data->keep_base_clock_div_set = force; + qspi_unlock(dev); +#else + ARG_UNUSED(dev); + ARG_UNUSED(force); +#endif +} + +#ifdef CONFIG_USERSPACE +#include + +void z_vrfy_nrf_qspi_nor_base_clock_div_force(const struct device *dev, + bool force) +{ + Z_OOPS(Z_SYSCALL_SPECIFIC_DRIVER(dev, K_OBJ_DRIVER_FLASH, + &qspi_nor_api)); + + z_impl_nrf_qspi_nor_base_clock_div_force(dev, force); +} + +#include +#endif /* CONFIG_USERSPACE */ + static struct qspi_nor_data qspi_nor_dev_data = { #ifdef CONFIG_MULTITHREADING .trans = Z_SEM_INITIALIZER(qspi_nor_dev_data.trans, 1, 1), @@ -1183,10 +1288,7 @@ static const struct qspi_nor_config qspi_nor_dev_config = { : NRF_QSPI_ADDRMODE_24BIT, }, .nrfx_cfg.phy_if = { - .sck_freq = (INST_0_SCK_FREQUENCY > NRF_QSPI_BASE_CLOCK_FREQ) - ? NRF_QSPI_FREQ_DIV1 - : (NRF_QSPI_BASE_CLOCK_FREQ / - INST_0_SCK_FREQUENCY) - 1, + .sck_freq = INST_0_SCK_CFG, .sck_delay = DT_INST_PROP(0, sck_delay), .spi_mode = INST_0_SPI_MODE, }, diff --git a/drivers/flash/soc_flash_nrf.c b/drivers/flash/soc_flash_nrf.c index f6833430cb6..81e6b3aab39 100644 --- a/drivers/flash/soc_flash_nrf.c +++ b/drivers/flash/soc_flash_nrf.c @@ -37,6 +37,13 @@ LOG_MODULE_REGISTER(flash_nrf); #define SOC_NV_FLASH_NODE DT_INST(0, soc_nv_flash) +#if CONFIG_ARM_NONSECURE_FIRMWARE && CONFIG_SPM +#include +#if USE_PARTITION_MANAGER +#include +#endif /* USE_PARTITION_MANAGER */ +#endif /* CONFIG_ARM_NONSECURE_FIRMWARE && CONFIG_SPM */ + #ifndef CONFIG_SOC_FLASH_NRF_RADIO_SYNC_NONE #define FLASH_SLOT_WRITE 7500 #if defined(CONFIG_SOC_FLASH_NRF_PARTIAL_ERASE) @@ -146,6 +153,13 @@ static int flash_nrf_read(const struct device *dev, off_t addr, return 0; } +#if CONFIG_ARM_NONSECURE_FIRMWARE && CONFIG_SPM && USE_PARTITION_MANAGER \ + && CONFIG_SPM_SECURE_SERVICES + if (addr < PM_APP_ADDRESS) { + return spm_request_read(data, addr, len); + } +#endif + memcpy(data, (void *)addr, len); return 0; diff --git a/drivers/gpio/gpio_nrfx.c b/drivers/gpio/gpio_nrfx.c index e22db2e9451..9c9aa7e9519 100644 --- a/drivers/gpio/gpio_nrfx.c +++ b/drivers/gpio/gpio_nrfx.c @@ -111,6 +111,8 @@ static int gpio_nrfx_pin_configure(const struct device *port, gpio_pin_t pin, gpio_flags_t flags) { nrfx_err_t err; + uint8_t ch; + bool free_ch; const struct gpio_nrfx_cfg *cfg = get_port_cfg(port); nrfx_gpiote_pin_t abs_pin = NRF_GPIO_PIN_MAP(cfg->port_num, pin); @@ -122,12 +124,19 @@ static int gpio_nrfx_pin_configure(const struct device *port, gpio_pin_t pin, .trigger = NRFX_GPIOTE_TRIGGER_NONE }; + err = nrfx_gpiote_channel_get(pin, &ch); + free_ch = (err == NRFX_SUCCESS); + /* Remove previously configured trigger when pin is reconfigured. */ err = nrfx_gpiote_input_configure(abs_pin, NULL, &trigger_config, NULL); if (err != NRFX_SUCCESS) { return -EINVAL; } + if (free_ch) { + err = nrfx_gpiote_channel_free(ch); + } + if (flags & GPIO_OUTPUT) { nrf_gpio_pin_drive_t drive; int rv = get_drive(flags, &drive); diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index fbf74d351b9..6edb3586be1 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -39,6 +39,14 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include +#if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) +#if defined(CONFIG_SPM_SERVICE_READ) +#include +#elif defined(CONFIG_BUILD_WITH_TFM) +#include +#endif +#endif + #include "ieee802154_nrf5.h" #include "nrf_802154.h" #include "nrf_802154_const.h" @@ -70,13 +78,21 @@ static struct nrf5_802154_data nrf5_data; #if defined(CONFIG_IEEE802154_NRF5_UICR_EUI64_ENABLE) #if defined(CONFIG_SOC_NRF5340_CPUAPP) +#if defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) +#define EUI64_ADDR (NRF_UICR_S->OTP) +#else #define EUI64_ADDR (NRF_UICR->OTP) +#endif /* CONFIG_TRUSTED_EXECUTION_NONSECURE */ #else #define EUI64_ADDR (NRF_UICR->CUSTOMER) #endif /* CONFIG_SOC_NRF5340_CPUAPP */ #else #if defined(CONFIG_SOC_NRF5340_CPUAPP) || defined(CONFIG_SOC_NRF5340_CPUNET) +#if defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) +#define EUI64_ADDR (NRF_FICR_S->INFO.DEVICEID) +#else #define EUI64_ADDR (NRF_FICR->INFO.DEVICEID) +#endif /* CONFIG_TRUSTED_EXECUTION_NONSECURE */ #else #define EUI64_ADDR (NRF_FICR->DEVICEID) #endif /* CONFIG_SOC_NRF5340_CPUAPP || CONFIG_SOC_NRF5340_CPUNET */ @@ -115,9 +131,32 @@ static void nrf5_get_eui64(uint8_t *mac) mac[index++] = IEEE802154_NRF5_VENDOR_OUI & 0xff; #endif -#if defined(CONFIG_SOC_NRF5340_CPUAPP) && \ - defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) -#error Accessing EUI64 on the non-secure mode is not supported at the moment +#if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) + int ret = -EPERM; +#if defined(CONFIG_SPM_SERVICE_READ) + ret = spm_request_read(&factoryAddress, + (uint32_t)&EUI64_ADDR[EUI64_ADDR_HIGH], + sizeof(factoryAddress)); +#elif defined(CONFIG_BUILD_WITH_TFM) + enum tfm_platform_err_t tfmError; + uint32_t tfmServiceError; + + tfmError = tfm_platform_mem_read(&factoryAddress, (uint32_t)&EUI64_ADDR[EUI64_ADDR_HIGH], + sizeof(factoryAddress), &tfmServiceError); + + if (tfmError == TFM_PLATFORM_ERR_SUCCESS && tfmServiceError == 0) { + ret = 0; + } else if (tfmError == TFM_PLATFORM_ERR_INVALID_PARAM) { + ret = -EINVAL; + } else if (tfmError == TFM_PLATFORM_ERR_NOT_SUPPORTED) { + ret = -ENOTSUP; + } +#endif + if (ret != 0) { + LOG_ERR("Unable to read EUI64 from the secure zone: %d", ret); + LOG_ERR("Setting EUI64 to 0"); + factoryAddress = 0ULL; + } #else /* Use device identifier assigned during the production. */ factoryAddress = (uint64_t)EUI64_ADDR[EUI64_ADDR_HIGH] << 32; @@ -462,8 +501,7 @@ static bool nrf5_tx_csma_ca(struct net_pkt *pkt, uint8_t *payload) return nrf_802154_transmit_csma_ca_raw(payload, &metadata); } -/* This function cannot be used in the serialized version yet. */ -#if defined(CONFIG_NET_PKT_TXTIME) && !defined(CONFIG_NRF_802154_SER_HOST) +#if IS_ENABLED(CONFIG_NET_PKT_TXTIME) static bool nrf5_tx_at(struct net_pkt *pkt, uint8_t *payload, bool cca) { nrf_802154_transmit_at_metadata_t metadata = { @@ -515,8 +553,7 @@ static int nrf5_tx(const struct device *dev, case IEEE802154_TX_MODE_CSMA_CA: ret = nrf5_tx_csma_ca(pkt, nrf5_radio->tx_psdu); break; -/* This function cannot be used in the serialized version yet. */ -#if defined(CONFIG_NET_PKT_TXTIME) && !defined(CONFIG_NRF_802154_SER_HOST) +#if IS_ENABLED(CONFIG_NET_PKT_TXTIME) case IEEE802154_TX_MODE_TXTIME: case IEEE802154_TX_MODE_TXTIME_CCA: __ASSERT_NO_MSG(pkt); @@ -711,7 +748,8 @@ static void nrf5_config_mac_keys(struct ieee802154_key *mac_keys) } i = 0; - for (struct ieee802154_key *keys = mac_keys; keys->key_value; keys++) { + for (struct ieee802154_key *keys = mac_keys; keys->key_value + && i < NRF_802154_SECURITY_KEY_STORAGE_SIZE; keys++, i++) { nrf_802154_key_t key = { .value.p_cleartext_key = keys->key_value, .id.mode = keys->key_id_mode, @@ -721,16 +759,15 @@ static void nrf5_config_mac_keys(struct ieee802154_key *mac_keys) .use_global_frame_counter = !(keys->frame_counter_per_key), }; - nrf_802154_security_error_t err = nrf_802154_security_key_store(&key); - __ASSERT(err == NRF_802154_SECURITY_ERROR_NONE || - err == NRF_802154_SECURITY_ERROR_ALREADY_PRESENT, - "Storing key failed, err: %d", err); + __ASSERT_EVAL((void)nrf_802154_security_key_store(&key), + nrf_802154_security_error_t err = nrf_802154_security_key_store(&key), + err == NRF_802154_SECURITY_ERROR_NONE || + err == NRF_802154_SECURITY_ERROR_ALREADY_PRESENT, + "Storing key failed, err: %d", err); - __ASSERT(i < NRF_802154_SECURITY_KEY_STORAGE_SIZE, "Store buffer is full"); stored_ids[i] = *key.id.p_key_id; stored_key_ids[i].mode = key.id.mode; stored_key_ids[i].p_key_id = &stored_ids[i]; - i++; }; } #endif /* CONFIG_NRF_802154_ENCRYPTION */ @@ -903,7 +940,7 @@ void nrf_802154_received_timestamp_raw(uint8_t *data, int8_t power, uint8_t lqi, nrf5_data.rx_frames[i].rssi = power; nrf5_data.rx_frames[i].lqi = lqi; -#if !defined(CONFIG_NRF_802154_SER_HOST) && defined(CONFIG_NET_PKT_TIMESTAMP) +#if IS_ENABLED(CONFIG_NET_PKT_TIMESTAMP) nrf5_data.rx_frames[i].time = nrf_802154_first_symbol_timestamp_get(time, data[0]); #endif @@ -925,9 +962,12 @@ void nrf_802154_received_timestamp_raw(uint8_t *data, int8_t power, uint8_t lqi, void nrf_802154_receive_failed(nrf_802154_rx_error_t error, uint32_t id) { + const struct device *dev = net_if_get_device(nrf5_data.iface); + #if defined(CONFIG_IEEE802154_CSL_ENDPOINT) if ((id == DRX_SLOT_PH) || (id == DRX_SLOT_RX)) { - nrf5_stop(net_if_get_device(nrf5_data.iface)); + __ASSERT_NO_MSG(nrf5_data.event_handler); + nrf5_data.event_handler(dev, IEEE802154_EVENT_SLEEP, NULL); return; } #else @@ -957,9 +997,7 @@ void nrf_802154_receive_failed(nrf_802154_rx_error_t error, uint32_t id) nrf5_data.last_frame_ack_fpb = false; if (nrf5_data.event_handler) { - nrf5_data.event_handler(net_if_get_device(nrf5_data.iface), - IEEE802154_EVENT_RX_FAILED, - (void *)&reason); + nrf5_data.event_handler(dev, IEEE802154_EVENT_RX_FAILED, (void *)&reason); } } @@ -983,7 +1021,7 @@ void nrf_802154_transmitted_raw(uint8_t *frame, nrf5_data.ack_frame.rssi = metadata->data.transmitted.power; nrf5_data.ack_frame.lqi = metadata->data.transmitted.lqi; -#if !IS_ENABLED(CONFIG_NRF_802154_SER_HOST) && IS_ENABLED(CONFIG_NET_PKT_TIMESTAMP) +#if IS_ENABLED(CONFIG_NET_PKT_TIMESTAMP) nrf5_data.ack_frame.time = nrf_802154_first_symbol_timestamp_get( metadata->data.transmitted.time, nrf5_data.ack_frame.psdu[0]); diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index c61bf461271..34ca6c2256f 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -18,6 +18,11 @@ menuconfig NET_PPP if NET_PPP +config NET_PPP_ASYNC_UART + bool "Asynchronous UART API is used" + depends on UART_ASYNC_API + depends on !GSM_MUX + config NET_PPP_UART_NAME string "UART device name the PPP is connected to" depends on !MODEM_GSM_PPP @@ -89,6 +94,32 @@ config PPP_NET_IF_NO_AUTO_START This option allows user to disable autostarting of the PPP interface immediately after initialization. +if NET_PPP_ASYNC_UART + +config NET_PPP_ASYNC_UART_TX_BUF_LEN + int "Buffer length from where the write to async UART is done" + default 2048 + help + This options sets the size of the UART TX buffer where data + is being written from to UART. + +config NET_PPP_ASYNC_UART_RX_RECOVERY_TIMEOUT + int "UART RX recovery timeout in milliseconds" + default 200 + help + The time that UART RX is in disabled state in case + when we cannot receive more data from UART. + +config NET_PPP_ASYNC_UART_RX_ENABLE_TIMEOUT + int "A timeout for uart_rx_enable()" + default 100 + +config NET_PPP_ASYNC_UART_TX_TIMEOUT + int "A timeout for uart_tx()" + default 100 + +endif # NET_PPP_ASYNC_UART + module = NET_PPP module-dep = LOG module-str = Log level for ppp driver diff --git a/drivers/net/ppp.c b/drivers/net/ppp.c index eeeee459130..34643b5db1e 100644 --- a/drivers/net/ppp.c +++ b/drivers/net/ppp.c @@ -37,6 +37,7 @@ LOG_MODULE_REGISTER(net_ppp, LOG_LEVEL); #include "../../subsys/net/ip/net_private.h" #define UART_BUF_LEN CONFIG_NET_PPP_UART_BUF_LEN +#define UART_TX_BUF_LEN CONFIG_NET_PPP_ASYNC_UART_TX_BUF_LEN enum ppp_driver_state { STATE_HDLC_FRAME_START, @@ -61,9 +62,17 @@ struct ppp_driver_context { /* ppp data is read into this buf */ uint8_t buf[UART_BUF_LEN]; +#if defined(CONFIG_NET_PPP_ASYNC_UART) + /* with async we use 2 rx buffers */ + uint8_t buf2[UART_BUF_LEN]; + struct k_work_delayable uart_recovery_work; + /* ppp buf use when sending data */ + uint8_t send_buf[UART_TX_BUF_LEN]; +#else /* ppp buf use when sending data */ uint8_t send_buf[UART_BUF_LEN]; +#endif uint8_t mac_addr[6]; struct net_linkaddr ll_addr; @@ -95,6 +104,155 @@ struct ppp_driver_context { static struct ppp_driver_context ppp_driver_context_data; +#if defined(CONFIG_NET_PPP_ASYNC_UART) +static bool rx_retry_pending; +static bool uart_recovery_pending; +static uint8_t *next_buf; + +static K_SEM_DEFINE(uarte_tx_finished, 0, 1); + +static void uart_callback(const struct device *dev, + struct uart_event *evt, + void *user_data) +{ + struct ppp_driver_context *context = user_data; + uint8_t *p; + int err, ret, len, space_left; + + switch (evt->type) { + case UART_TX_DONE: + LOG_DBG("UART_TX_DONE: sent %d bytes", evt->data.tx.len); + k_sem_give(&uarte_tx_finished); + break; + + case UART_TX_ABORTED: + LOG_DBG("Tx aborted"); + k_sem_give(&uarte_tx_finished); + break; + + case UART_RX_RDY: + len = evt->data.rx.len; + p = evt->data.rx.buf + evt->data.rx.offset; + + LOG_DBG("Received data %d bytes", len); + + ret = ring_buf_put(&context->rx_ringbuf, p, len); + if (ret < evt->data.rx.len) { + LOG_WRN("Rx buffer doesn't have enough space. " + "Bytes pending: %d, written only: %d. " + "Disabling RX for now.", + evt->data.rx.len, ret); + + /* No possibility to set flow ctrl ON towards PC, + * thus workrounding this lack in async API by turning + * rx off for now and re-enabling that later. + */ + if (!rx_retry_pending) { + uart_rx_disable(dev); + rx_retry_pending = true; + } + } + + space_left = ring_buf_space_get(&context->rx_ringbuf); + if (!rx_retry_pending && space_left < (sizeof(context->rx_buf) / 8)) { + /* Not much room left in buffer after a write to ring buffer. + * We submit a work, but enable flow ctrl also + * in this case to avoid packet losses. + */ + uart_rx_disable(dev); + rx_retry_pending = true; + LOG_WRN("%d written to RX buf, but after that only %d space left. " + "Disabling RX for now.", + ret, space_left); + } + + k_work_submit_to_queue(&context->cb_workq, &context->cb_work); + break; + + case UART_RX_BUF_REQUEST: + { + LOG_DBG("UART_RX_BUF_REQUEST: buf %p", next_buf); + + if (next_buf) { + err = uart_rx_buf_rsp(dev, next_buf, sizeof(context->buf)); + if (err) { + LOG_ERR("uart_rx_buf_rsp() err: %d", err); + } + } + + break; + } + + case UART_RX_BUF_RELEASED: + next_buf = evt->data.rx_buf.buf; + LOG_DBG("UART_RX_BUF_RELEASED: buf %p", next_buf); + break; + + case UART_RX_DISABLED: + LOG_DBG("UART_RX_DISABLED - re-enabling in a while"); + + if (rx_retry_pending && !uart_recovery_pending) { + k_work_schedule(&context->uart_recovery_work, + K_MSEC(CONFIG_NET_PPP_ASYNC_UART_RX_RECOVERY_TIMEOUT)); + rx_retry_pending = false; + uart_recovery_pending = true; + } + break; + + case UART_RX_STOPPED: + LOG_DBG("UART_RX_STOPPED: stop reason %d", evt->data.rx_stop.reason); + + if (evt->data.rx_stop.reason != 0) { + rx_retry_pending = true; + } + break; + } +} + +static int ppp_async_uart_rx_enable(struct ppp_driver_context *context) +{ + int err; + + next_buf = context->buf2; + err = uart_callback_set(context->dev, uart_callback, (void *)context); + if (err) { + LOG_ERR("Failed to set uart callback, err %d", err); + } + + err = uart_rx_enable(context->dev, context->buf, sizeof(context->buf), + CONFIG_NET_PPP_ASYNC_UART_RX_ENABLE_TIMEOUT * USEC_PER_MSEC); + if (err) { + LOG_ERR("uart_rx_enable() failed, err %d", err); + } else { + LOG_DBG("RX enabled"); + } + rx_retry_pending = false; + return err; +} + +static void uart_recovery(struct k_work *work) +{ + struct ppp_driver_context *ppp = + CONTAINER_OF(work, struct ppp_driver_context, uart_recovery_work); + int ret; + + ret = ring_buf_space_get(&ppp->rx_ringbuf); + if (ret >= (sizeof(ppp->rx_buf) / 2)) { + ret = ppp_async_uart_rx_enable(ppp); + if (ret) { + LOG_ERR("ppp_async_uart_rx_enable() failed, err %d", ret); + } else { + LOG_WRN("UART RX recovered"); + } + uart_recovery_pending = false; + } else { + LOG_ERR("Rx buffer still doesn't have enough room %d to be re-enabled", ret); + k_work_schedule(&ppp->uart_recovery_work, + K_MSEC(CONFIG_NET_PPP_ASYNC_UART_RX_RECOVERY_TIMEOUT)); + } +} +#endif + static int ppp_save_byte(struct ppp_driver_context *ppp, uint8_t byte) { int ret; @@ -206,6 +364,19 @@ static int ppp_send_flush(struct ppp_driver_context *ppp, int off) */ if (IS_ENABLED(CONFIG_GSM_MUX)) { (void)uart_fifo_fill(ppp->dev, buf, off); + } else if (IS_ENABLED(CONFIG_NET_PPP_ASYNC_UART)) { +#if defined(CONFIG_NET_PPP_ASYNC_UART) + int ret; + + k_sem_take(&uarte_tx_finished, K_FOREVER); + + ret = uart_tx(ppp->dev, buf, off, + CONFIG_NET_PPP_ASYNC_UART_TX_TIMEOUT * USEC_PER_MSEC); + if (ret) { + LOG_ERR("uart_tx() failed, err %d", ret); + k_sem_give(&uarte_tx_finished); + } +#endif } else { while (off--) { uart_poll_out(ppp->dev, *buf++); @@ -350,7 +521,7 @@ static int ppp_input_byte(struct ppp_driver_context *ppp, uint8_t byte) break; default: - LOG_DBG("[%p] Invalid state %d", ppp, ppp->state); + LOG_ERR("[%p] Invalid state %d", ppp, ppp->state); break; } @@ -720,8 +891,10 @@ static int ppp_driver_init(const struct device *dev) K_KERNEL_STACK_SIZEOF(ppp_workq), K_PRIO_COOP(PPP_WORKQ_PRIORITY), NULL); k_thread_name_set(&ppp->cb_workq.thread, "ppp_workq"); +#if defined(CONFIG_NET_PPP_ASYNC_UART) + k_work_init_delayable(&ppp->uart_recovery_work, uart_recovery); +#endif #endif - ppp->pkt = NULL; ppp_change_state(ppp, STATE_HDLC_FRAME_START); #if defined(CONFIG_PPP_CLIENT_CLIENTSERVER) @@ -800,7 +973,7 @@ static struct net_stats_ppp *ppp_get_stats(const struct device *dev) } #endif -#if !defined(CONFIG_NET_TEST) +#if !defined(CONFIG_NET_TEST) && !defined(CONFIG_NET_PPP_ASYNC_UART) static void ppp_uart_flush(const struct device *dev) { uint8_t c; @@ -833,7 +1006,7 @@ static void ppp_uart_isr(const struct device *uart, void *user_data) k_work_submit_to_queue(&context->cb_workq, &context->cb_work); } } -#endif /* !CONFIG_NET_TEST */ +#endif /* !CONFIG_NET_TEST && !CONFIG_NET_PPP_ASYNC_UART */ static int ppp_start(const struct device *dev) { @@ -880,13 +1053,17 @@ static int ppp_start(const struct device *dev) LOG_ERR("Cannot find dev %s", dev_name); return -ENODEV; } - +#if defined(CONFIG_NET_PPP_ASYNC_UART) + k_sem_give(&uarte_tx_finished); + ppp_async_uart_rx_enable(context); +#else uart_irq_rx_disable(context->dev); uart_irq_tx_disable(context->dev); ppp_uart_flush(context->dev); uart_irq_callback_user_data_set(context->dev, ppp_uart_isr, context); uart_irq_rx_enable(context->dev); +#endif } #endif /* !CONFIG_NET_TEST */ diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index 3244ac0d001..fb4dde2e7fa 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -67,6 +67,7 @@ add_subdirectory_ifdef(CONFIG_MCP9808 mcp9808) add_subdirectory_ifdef(CONFIG_MHZ19B mhz19b) add_subdirectory_ifdef(CONFIG_MPR mpr) add_subdirectory_ifdef(CONFIG_MPU6050 mpu6050) +add_subdirectory_ifdef(CONFIG_MPU9250 mpu9250) add_subdirectory_ifdef(CONFIG_MS5607 ms5607) add_subdirectory_ifdef(CONFIG_MS5837 ms5837) add_subdirectory_ifdef(CONFIG_OPT3001 opt3001) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index 6681449292f..2909d735e86 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -174,6 +174,8 @@ source "drivers/sensor/mpr/Kconfig" source "drivers/sensor/mpu6050/Kconfig" +source "drivers/sensor/mpu9250/Kconfig" + source "drivers/sensor/ms5837/Kconfig" source "drivers/sensor/ms5607/Kconfig" diff --git a/drivers/sensor/mpu9250/CMakeLists.txt b/drivers/sensor/mpu9250/CMakeLists.txt new file mode 100644 index 00000000000..49ba5d8613d --- /dev/null +++ b/drivers/sensor/mpu9250/CMakeLists.txt @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(mpu9250.c) +zephyr_library_sources_ifdef(CONFIG_MPU9250_TRIGGER mpu9250_trigger.c) +zephyr_library_sources_ifdef(CONFIG_MPU9250_MAGN_EN ak8963.c) diff --git a/drivers/sensor/mpu9250/Kconfig b/drivers/sensor/mpu9250/Kconfig new file mode 100644 index 00000000000..2f1e9733501 --- /dev/null +++ b/drivers/sensor/mpu9250/Kconfig @@ -0,0 +1,58 @@ +# MPU9250 Nine-Axis Motion Tracking device configuration options + +# Copyright (c) 2021 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +menuconfig MPU9250 + bool "MPU9250 Nine-Axis Motion Tracking Device" + depends on I2C + help + Enable driver for MPU9250 I2C-based nine-axis motion tracking device. + +if MPU9250 + +choice + prompt "Trigger mode" + default MPU9250_TRIGGER_GLOBAL_THREAD + help + Specify the type of triggering to be used by the driver. + +config MPU9250_TRIGGER_NONE + bool "No trigger" + +config MPU9250_TRIGGER_GLOBAL_THREAD + bool "Use global thread" + depends on GPIO + select MPU9250_TRIGGER + +config MPU9250_TRIGGER_OWN_THREAD + bool "Use own thread" + depends on GPIO + select MPU9250_TRIGGER + +endchoice + +config MPU9250_TRIGGER + bool + +config MPU9250_THREAD_PRIORITY + int "Thread priority" + depends on MPU9250_TRIGGER_OWN_THREAD + default 10 + help + Priority of thread used by the driver to handle interrupts. + +config MPU9250_THREAD_STACK_SIZE + int "Thread stack size" + depends on MPU9250_TRIGGER_OWN_THREAD + default 1024 + help + Stack size of thread used by the driver to handle interrupts. + +config MPU9250_MAGN_EN + bool "Magnetometer enable" + default y + help + Enable AK8963 builtin magnetometer. + +endif # MPU9250 diff --git a/drivers/sensor/mpu9250/ak8963.c b/drivers/sensor/mpu9250/ak8963.c new file mode 100644 index 00000000000..0321f7a1152 --- /dev/null +++ b/drivers/sensor/mpu9250/ak8963.c @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2021, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "mpu9250.h" +#include "ak8963.h" + +LOG_MODULE_DECLARE(MPU9250, CONFIG_SENSOR_LOG_LEVEL); + + +#define I2C_READ_FLAG BIT(7) + +#define AK8963_I2C_ADDR 0x0C + +#define AK8963_REG_ID 0x00 +#define AK8963_REG_ID_VAL 0x48 + +#define AK8963_REG_DATA 0x03 + +#define AK8963_ST2_OVRFL_BIT BIT(3) + +#define AK8963_REG_CNTL1 0x0A +#define AK8963_REG_CNTL1_POWERDOWN_VAL 0x00 +#define AK8963_REG_CNTL1_FUSE_ROM_VAL 0x0F +#define AK8963_REG_CNTL1_16BIT_100HZ_VAL 0x16 +#define AK8963_SET_MODE_DELAY_MS 1 + +#define AK8963_REG_CNTL2 0x0B +#define AK8963_REG_CNTL2_RESET_VAL 0x01 +#define AK8963_RESET_DELAY_MS 1 + +#define AK8963_REG_ADJ_DATA_X 0x10 +#define AK8963_REG_ADJ_DATA_Y 0x11 +#define AK8963_REG_ADJ_DATA_Z 0x12 + +#define AK9863_SCALE_TO_UG 1499 + +#define MPU9250_REG_I2C_MST_CTRL 0x24 +#define MPU9250_REG_I2C_MST_CTRL_WAIT_MAG_400KHZ_VAL 0x4D + +#define MPU9250_REG_I2C_SLV0_ADDR 0x25 +#define MPU9250_REG_I2C_SLV0_REG 0x26 +#define MPU9250_REG_I2C_SLV0_CTRL 0x27 +#define MPU9250_REG_I2C_SLV0_DATA0 0x63 +#define MPU9250_REG_READOUT_CTRL_VAL (BIT(7) | 0x07) + +#define MPU9250_REG_USER_CTRL 0x6A +#define MPU9250_REG_USER_CTRL_I2C_MASTERMODE_VAL 0x20 + +#define MPU9250_REG_EXT_DATA00 0x49 + +#define MPU9250_REG_I2C_SLV4_ADDR 0x31 +#define MPU9250_REG_I2C_SLV4_REG 0x32 +#define MPU9250_REG_I2C_SLV4_DO 0x33 +#define MPU9250_REG_I2C_SLV4_CTRL 0x34 +#define MPU9250_REG_I2C_SLV4_CTRL_VAL 0x80 +#define MPU9250_REG_I2C_SLV4_DI 0x35 + +#define MPU9250_I2C_MST_STS 0x36 +#define MPU9250_I2C_MST_STS_SLV4_DONE BIT(6) + + +int ak8963_convert_magn(struct sensor_value *val, int16_t raw_val, + int16_t scale, uint8_t st2) +{ + /* The sensor device returns 10^-9 Teslas after scaling. + * Scale adjusts for calibration data and units + * So sensor instance returns Gauss units + */ + + /* If overflow happens then value is invalid */ + if ((st2 & AK8963_ST2_OVRFL_BIT) != 0) { + LOG_INF("Magnetometer value overflow."); + return -EOVERFLOW; + } + + int32_t scaled_val = (int32_t)raw_val * (int32_t)scale; + + val->val1 = scaled_val / 1000000; + val->val2 = scaled_val % 1000000; + return 0; +} + + +static int ak8963_execute_rw(const struct device *dev, uint8_t reg, bool write) +{ + /* Instruct the MPU9250 to access over its external i2c bus + * given device register with given details + */ + const struct mpu9250_config *cfg = dev->config; + uint8_t mode_bit = 0x00; + uint8_t status; + int ret; + + if (!write) { + mode_bit = I2C_READ_FLAG; + } + + /* Set target i2c address */ + ret = i2c_reg_write_byte_dt(&cfg->i2c, + MPU9250_REG_I2C_SLV4_ADDR, + AK8963_I2C_ADDR | mode_bit); + if (ret < 0) { + LOG_ERR("Failed to write i2c target slave address."); + return ret; + } + + /* Set target i2c register */ + ret = i2c_reg_write_byte_dt(&cfg->i2c, + MPU9250_REG_I2C_SLV4_REG, + reg); + if (ret < 0) { + LOG_ERR("Failed to write i2c target slave register."); + return ret; + } + + /* Initiate transfer */ + ret = i2c_reg_write_byte_dt(&cfg->i2c, + MPU9250_REG_I2C_SLV4_CTRL, + MPU9250_REG_I2C_SLV4_CTRL_VAL); + if (ret < 0) { + LOG_ERR("Failed to initiate i2c slave transfer."); + return ret; + } + + /* Wait for a transfer to be ready */ + do { + ret = i2c_reg_read_byte_dt(&cfg->i2c, + MPU9250_I2C_MST_STS, &status); + if (ret < 0) { + LOG_ERR("Waiting for slave failed."); + return ret; + } + } while (!(status & MPU9250_I2C_MST_STS_SLV4_DONE)); + + return 0; +} + +static int ak8963_read_reg(const struct device *dev, uint8_t reg, uint8_t *data) +{ + const struct mpu9250_config *cfg = dev->config; + int ret; + + /* Execute transfer */ + ret = ak8963_execute_rw(dev, reg, false); + if (ret < 0) { + LOG_ERR("Failed to prepare transfer."); + return ret; + } + + /* Read the result */ + ret = i2c_reg_read_byte_dt(&cfg->i2c, + MPU9250_REG_I2C_SLV4_DI, data); + if (ret < 0) { + LOG_ERR("Failed to read data from slave."); + return ret; + } + + return 0; +} + +static int ak8963_write_reg(const struct device *dev, uint8_t reg, uint8_t data) +{ + const struct mpu9250_config *cfg = dev->config; + int ret; + + /* Set the data to write */ + ret = i2c_reg_write_byte_dt(&cfg->i2c, + MPU9250_REG_I2C_SLV4_DO, data); + if (ret < 0) { + LOG_ERR("Failed to write data to slave."); + return ret; + } + + /* Execute transfer */ + ret = ak8963_execute_rw(dev, reg, true); + if (ret < 0) { + LOG_ERR("Failed to transfer write to slave."); + return ret; + } + + return 0; +} + + +static int ak8963_set_mode(const struct device *dev, uint8_t mode) +{ + int ret; + + ret = ak8963_write_reg(dev, AK8963_REG_CNTL1, mode); + if (ret < 0) { + LOG_ERR("Failed to set AK8963 mode."); + return ret; + } + + /* Wait for mode to change */ + k_msleep(AK8963_SET_MODE_DELAY_MS); + return 0; +} + +static int16_t ak8963_calc_adj(int16_t val) +{ + + /** Datasheet says the actual register value is in 16bit output max + * value of 32760 that corresponds to 4912 uT flux, yielding factor + * of 0.149938. + * + * Now Zephyr unit is Gauss, and conversion is 1T = 10^4G + * -> 0.1499 * 10^4 = 1499 + * So if we multiply with scaling with 1499 the unit is uG. + * + * Calculation from MPU-9250 Register Map and Descriptions + * adj = (((val-128)*0.5)/128)+1 + */ + return ((AK9863_SCALE_TO_UG * (val - 128)) / 256) + AK9863_SCALE_TO_UG; +} + +static int ak8963_fetch_adj(const struct device *dev) +{ + /* Read magnetometer adjustment data from the AK8963 chip */ + struct mpu9250_data *drv_data = dev->data; + uint8_t buf; + int ret; + + /* Change to FUSE access mode to access adjustment registers */ + ret = ak8963_set_mode(dev, AK8963_REG_CNTL1_FUSE_ROM_VAL); + if (ret < 0) { + LOG_ERR("Failed to set chip in fuse access mode."); + return ret; + } + + ret = ak8963_read_reg(dev, AK8963_REG_ADJ_DATA_X, &buf); + if (ret < 0) { + LOG_ERR("Failed to read adjustment data."); + return ret; + } + drv_data->magn_scale_x = ak8963_calc_adj(buf); + + ret = ak8963_read_reg(dev, AK8963_REG_ADJ_DATA_Y, &buf); + if (ret < 0) { + LOG_ERR("Failed to read adjustment data."); + return ret; + } + drv_data->magn_scale_y = ak8963_calc_adj(buf); + + ret = ak8963_read_reg(dev, AK8963_REG_ADJ_DATA_Z, &buf); + if (ret < 0) { + LOG_ERR("Failed to read adjustment data."); + return ret; + } + drv_data->magn_scale_z = ak8963_calc_adj(buf); + + /* Change back to the powerdown mode */ + ret = ak8963_set_mode(dev, AK8963_REG_CNTL1_POWERDOWN_VAL); + if (ret < 0) { + LOG_ERR("Failed to set chip in power down mode."); + return ret; + } + + LOG_DBG("Adjustment values %d %d %d", drv_data->magn_scale_x, + drv_data->magn_scale_y, drv_data->magn_scale_z); + + return 0; +} + +static int ak8963_reset(const struct device *dev) +{ + int ret; + + /* Reset the chip -> reset all settings. */ + ret = ak8963_write_reg(dev, AK8963_REG_CNTL2, + AK8963_REG_CNTL2_RESET_VAL); + if (ret < 0) { + LOG_ERR("Failed to reset AK8963."); + return ret; + } + + /* Wait for reset */ + k_msleep(AK8963_RESET_DELAY_MS); + + return 0; +} + +static int ak8963_init_master(const struct device *dev) +{ + const struct mpu9250_config *cfg = dev->config; + int ret; + + /* Instruct MPU9250 to use its external I2C bus as master */ + ret = i2c_reg_write_byte_dt(&cfg->i2c, + MPU9250_REG_USER_CTRL, + MPU9250_REG_USER_CTRL_I2C_MASTERMODE_VAL); + if (ret < 0) { + LOG_ERR("Failed to set MPU9250 master i2c mode."); + return ret; + } + + /* Set MPU9250 I2C bus as 400kHz and issue interrupt at data ready. */ + ret = i2c_reg_write_byte_dt(&cfg->i2c, + MPU9250_REG_I2C_MST_CTRL, + MPU9250_REG_I2C_MST_CTRL_WAIT_MAG_400KHZ_VAL); + if (ret < 0) { + LOG_ERR("Failed to set MPU9250 master i2c speed."); + return ret; + } + + return 0; +} + +static int ak8963_init_readout(const struct device *dev) +{ + const struct mpu9250_config *cfg = dev->config; + int ret; + + /* Set target i2c address */ + ret = i2c_reg_write_byte_dt(&cfg->i2c, + MPU9250_REG_I2C_SLV0_ADDR, + AK8963_I2C_ADDR | I2C_READ_FLAG); + if (ret < 0) { + LOG_ERR("Failed to set AK8963 slave address."); + return ret; + } + + /* Set target as data registers */ + ret = i2c_reg_write_byte_dt(&cfg->i2c, + MPU9250_REG_I2C_SLV0_REG, AK8963_REG_DATA); + if (ret < 0) { + LOG_ERR("Failed to set AK8963 register address."); + return ret; + } + + /* Initiate readout at sample rate */ + ret = i2c_reg_write_byte_dt(&cfg->i2c, + MPU9250_REG_I2C_SLV0_CTRL, + MPU9250_REG_READOUT_CTRL_VAL); + if (ret < 0) { + LOG_ERR("Failed to init AK8963 value readout."); + return ret; + } + + return 0; +} + +int ak8963_init(const struct device *dev) +{ + uint8_t buf; + int ret; + + ret = ak8963_init_master(dev); + if (ret < 0) { + LOG_ERR("Initializing MPU9250 master mode failed."); + return ret; + } + + ret = ak8963_reset(dev); + if (ret < 0) { + LOG_ERR("Resetting AK8963 failed."); + return ret; + } + + /* First check that the chip says hello */ + ret = ak8963_read_reg(dev, AK8963_REG_ID, &buf); + if (ret < 0) { + LOG_ERR("Failed to read AK8963 chip id."); + return ret; + } + + if (buf != AK8963_REG_ID_VAL) { + LOG_ERR("Invalid AK8963 chip id (0x%X).", buf); + return -ENOTSUP; + } + + /* Fetch calibration data */ + ret = ak8963_fetch_adj(dev); + if (ret < 0) { + LOG_ERR("Calibrating AK8963 failed."); + return ret; + } + + /* Set AK sample rate and resolution */ + ret = ak8963_set_mode(dev, AK8963_REG_CNTL1_16BIT_100HZ_VAL); + if (ret < 0) { + LOG_ERR("Failed set sample rate for AK8963."); + return ret; + } + + /* Init constant readouts at sample rate */ + ret = ak8963_init_readout(dev); + if (ret < 0) { + LOG_ERR("Initializing AK8963 readout failed."); + return ret; + } + + return 0; +} diff --git a/drivers/sensor/mpu9250/ak8963.h b/drivers/sensor/mpu9250/ak8963.h new file mode 100644 index 00000000000..2afe513e50a --- /dev/null +++ b/drivers/sensor/mpu9250/ak8963.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2021, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_MPU9250_AK8963_H_ +#define ZEPHYR_DRIVERS_SENSOR_MPU9250_AK8963_H_ + +#include + +#include +#include + + +int ak8963_convert_magn(struct sensor_value *val, int16_t raw_val, + int16_t scale, uint8_t st2); + +int ak8963_init(const struct device *dev); + +#endif /* ZEPHYR_DRIVERS_SENSOR_MPU9250_AK8963_H_ */ diff --git a/drivers/sensor/mpu9250/mpu9250.c b/drivers/sensor/mpu9250/mpu9250.c new file mode 100644 index 00000000000..cecf9612b84 --- /dev/null +++ b/drivers/sensor/mpu9250/mpu9250.c @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2021, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT invensense_mpu9250 + +#include +#include +#include + +#include "mpu9250.h" + +#ifdef CONFIG_MPU9250_MAGN_EN +#include "ak8963.h" +#endif + +LOG_MODULE_REGISTER(MPU9250, CONFIG_SENSOR_LOG_LEVEL); + + +#define MPU9250_REG_CHIP_ID 0x75 +#define MPU9250_CHIP_ID 0x71 + +#define MPU9250_REG_SR_DIV 0x19 + +#define MPU9250_REG_CONFIG 0x1A +#define MPU9250_GYRO_DLPF_MAX 7 + +#define MPU9250_REG_GYRO_CFG 0x1B +#define MPU9250_GYRO_FS_SHIFT 3 +#define MPU9250_GYRO_FS_MAX 3 + +#define MPU9250_REG_ACCEL_CFG 0x1C +#define MPU9250_ACCEL_FS_SHIFT 3 +#define MPU9250_ACCEL_FS_MAX 3 + +#define MPU9250_REG_ACCEL_CFG2 0x1D +#define MPU9250_ACCEL_DLPF_MAX 7 + +#define MPU9250_REG_DATA_START 0x3B + +#define MPU0259_TEMP_SENSITIVITY 334 +#define MPU9250_TEMP_OFFSET 21 + +#define MPU9250_REG_PWR_MGMT1 0x6B +#define MPU9250_SLEEP_EN BIT(6) + + +#ifdef CONFIG_MPU9250_MAGN_EN +#define MPU9250_READ_BUF_SIZE 11 +#else +#define MPU9250_READ_BUF_SIZE 7 +#endif + + +/* see "Accelerometer Measurements" section from register map description */ +static void mpu9250_convert_accel(struct sensor_value *val, int16_t raw_val, + uint16_t sensitivity_shift) +{ + int64_t conv_val; + + conv_val = ((int64_t)raw_val * SENSOR_G) >> sensitivity_shift; + val->val1 = conv_val / 1000000; + val->val2 = conv_val % 1000000; +} + +/* see "Gyroscope Measurements" section from register map description */ +static void mpu9250_convert_gyro(struct sensor_value *val, int16_t raw_val, + uint16_t sensitivity_x10) +{ + int64_t conv_val; + + conv_val = ((int64_t)raw_val * SENSOR_PI * 10) / + (sensitivity_x10 * 180U); + val->val1 = conv_val / 1000000; + val->val2 = conv_val % 1000000; +} + +/* see "Temperature Measurement" section from register map description */ +static inline void mpu9250_convert_temp(struct sensor_value *val, + int16_t raw_val) +{ + /* Temp[*C] = (raw / sensitivity) + offset */ + val->val1 = (raw_val / MPU0259_TEMP_SENSITIVITY) + MPU9250_TEMP_OFFSET; + val->val2 = (((int64_t)(raw_val % MPU0259_TEMP_SENSITIVITY) * 1000000) + / MPU0259_TEMP_SENSITIVITY); + + if (val->val2 < 0) { + val->val1--; + val->val2 += 1000000; + } else if (val->val2 >= 1000000) { + val->val1++; + val->val2 -= 1000000; + } +} + +static int mpu9250_channel_get(const struct device *dev, + enum sensor_channel chan, + struct sensor_value *val) +{ + struct mpu9250_data *drv_data = dev->data; +#ifdef CONFIG_MPU9250_MAGN_EN + int ret; +#endif + + switch (chan) { + case SENSOR_CHAN_ACCEL_XYZ: + mpu9250_convert_accel(val, drv_data->accel_x, + drv_data->accel_sensitivity_shift); + mpu9250_convert_accel(val + 1, drv_data->accel_y, + drv_data->accel_sensitivity_shift); + mpu9250_convert_accel(val + 2, drv_data->accel_z, + drv_data->accel_sensitivity_shift); + break; + case SENSOR_CHAN_ACCEL_X: + mpu9250_convert_accel(val, drv_data->accel_x, + drv_data->accel_sensitivity_shift); + break; + case SENSOR_CHAN_ACCEL_Y: + mpu9250_convert_accel(val, drv_data->accel_y, + drv_data->accel_sensitivity_shift); + break; + case SENSOR_CHAN_ACCEL_Z: + mpu9250_convert_accel(val, drv_data->accel_z, + drv_data->accel_sensitivity_shift); + break; + case SENSOR_CHAN_GYRO_XYZ: + mpu9250_convert_gyro(val, drv_data->gyro_x, + drv_data->gyro_sensitivity_x10); + mpu9250_convert_gyro(val + 1, drv_data->gyro_y, + drv_data->gyro_sensitivity_x10); + mpu9250_convert_gyro(val + 2, drv_data->gyro_z, + drv_data->gyro_sensitivity_x10); + break; + case SENSOR_CHAN_GYRO_X: + mpu9250_convert_gyro(val, drv_data->gyro_x, + drv_data->gyro_sensitivity_x10); + break; + case SENSOR_CHAN_GYRO_Y: + mpu9250_convert_gyro(val, drv_data->gyro_y, + drv_data->gyro_sensitivity_x10); + break; + case SENSOR_CHAN_GYRO_Z: + mpu9250_convert_gyro(val, drv_data->gyro_z, + drv_data->gyro_sensitivity_x10); + break; +#ifdef CONFIG_MPU9250_MAGN_EN + case SENSOR_CHAN_MAGN_XYZ: + ret = ak8963_convert_magn(val, drv_data->magn_x, + drv_data->magn_scale_x, + drv_data->magn_st2); + if (ret < 0) { + return ret; + } + ret = ak8963_convert_magn(val + 1, drv_data->magn_y, + drv_data->magn_scale_y, + drv_data->magn_st2); + if (ret < 0) { + return ret; + } + ret = ak8963_convert_magn(val + 2, drv_data->magn_z, + drv_data->magn_scale_z, + drv_data->magn_st2); + return ret; + case SENSOR_CHAN_MAGN_X: + return ak8963_convert_magn(val, drv_data->magn_x, + drv_data->magn_scale_x, + drv_data->magn_st2); + case SENSOR_CHAN_MAGN_Y: + return ak8963_convert_magn(val, drv_data->magn_y, + drv_data->magn_scale_y, + drv_data->magn_st2); + case SENSOR_CHAN_MAGN_Z: + return ak8963_convert_magn(val, drv_data->magn_z, + drv_data->magn_scale_z, + drv_data->magn_st2); + case SENSOR_CHAN_DIE_TEMP: + mpu9250_convert_temp(val, drv_data->temp); + break; +#endif + default: + return -ENOTSUP; + } + + return 0; +} + +static int mpu9250_sample_fetch(const struct device *dev, + enum sensor_channel chan) +{ + struct mpu9250_data *drv_data = dev->data; + const struct mpu9250_config *cfg = dev->config; + int16_t buf[MPU9250_READ_BUF_SIZE]; + int ret; + + ret = i2c_burst_read_dt(&cfg->i2c, + MPU9250_REG_DATA_START, (uint8_t *)buf, + sizeof(buf)); + if (ret < 0) { + LOG_ERR("Failed to read data sample."); + return ret; + } + + drv_data->accel_x = sys_be16_to_cpu(buf[0]); + drv_data->accel_y = sys_be16_to_cpu(buf[1]); + drv_data->accel_z = sys_be16_to_cpu(buf[2]); + drv_data->temp = sys_be16_to_cpu(buf[3]); + drv_data->gyro_x = sys_be16_to_cpu(buf[4]); + drv_data->gyro_y = sys_be16_to_cpu(buf[5]); + drv_data->gyro_z = sys_be16_to_cpu(buf[6]); +#ifdef CONFIG_MPU9250_MAGN_EN + drv_data->magn_x = sys_be16_to_cpu(buf[7]); + drv_data->magn_y = sys_be16_to_cpu(buf[8]); + drv_data->magn_z = sys_be16_to_cpu(buf[9]); + drv_data->magn_st2 = ((uint8_t *)buf)[20]; + LOG_DBG("magn_st2: %u", drv_data->magn_st2); +#endif + + return 0; +} + +static const struct sensor_driver_api mpu9250_driver_api = { +#if CONFIG_MPU9250_TRIGGER + .trigger_set = mpu9250_trigger_set, +#endif + .sample_fetch = mpu9250_sample_fetch, + .channel_get = mpu9250_channel_get, +}; + +/* measured in degrees/sec x10 to avoid floating point */ +static const uint16_t mpu9250_gyro_sensitivity_x10[] = { + 1310, 655, 328, 164 +}; + +static int mpu9250_init(const struct device *dev) +{ + struct mpu9250_data *drv_data = dev->data; + const struct mpu9250_config *cfg = dev->config; + uint8_t id; + int ret; + + if (!device_is_ready(cfg->i2c.bus)) { + LOG_ERR("I2C dev %s not ready", cfg->i2c.bus->name); + return -ENODEV; + } + + /* check chip ID */ + ret = i2c_reg_read_byte_dt(&cfg->i2c, MPU9250_REG_CHIP_ID, &id); + if (ret < 0) { + LOG_ERR("Failed to read chip ID."); + return ret; + } + + if (id != MPU9250_CHIP_ID) { + LOG_ERR("Invalid chip ID."); + return -ENOTSUP; + } + + /* wake up chip */ + ret = i2c_reg_update_byte_dt(&cfg->i2c, + MPU9250_REG_PWR_MGMT1, + MPU9250_SLEEP_EN, 0); + if (ret < 0) { + LOG_ERR("Failed to wake up chip."); + return ret; + } + + if (cfg->accel_fs > MPU9250_ACCEL_FS_MAX) { + LOG_ERR("Accel FS is too big: %d", cfg->accel_fs); + return -EINVAL; + } + + ret = i2c_reg_write_byte_dt(&cfg->i2c, MPU9250_REG_ACCEL_CFG, + cfg->accel_fs << MPU9250_ACCEL_FS_SHIFT); + if (ret < 0) { + LOG_ERR("Failed to write accel full-scale range."); + return ret; + } + drv_data->accel_sensitivity_shift = 14 - cfg->accel_fs; + + if (cfg->gyro_fs > MPU9250_GYRO_FS_MAX) { + LOG_ERR("Gyro FS is too big: %d", cfg->accel_fs); + return -EINVAL; + } + + ret = i2c_reg_write_byte_dt(&cfg->i2c, MPU9250_REG_GYRO_CFG, + cfg->gyro_fs << MPU9250_GYRO_FS_SHIFT); + if (ret < 0) { + LOG_ERR("Failed to write gyro full-scale range."); + return ret; + } + + if (cfg->gyro_dlpf > MPU9250_GYRO_DLPF_MAX) { + LOG_ERR("Gyro DLPF is too big: %d", cfg->gyro_dlpf); + return -EINVAL; + } + + ret = i2c_reg_write_byte_dt(&cfg->i2c, MPU9250_REG_CONFIG, + cfg->gyro_dlpf); + if (ret < 0) { + LOG_ERR("Failed to write gyro digital LPF settings."); + return ret; + } + + if (cfg->accel_dlpf > MPU9250_ACCEL_DLPF_MAX) { + LOG_ERR("Accel DLPF is too big: %d", cfg->accel_dlpf); + return -EINVAL; + } + + ret = i2c_reg_write_byte_dt(&cfg->i2c, MPU9250_REG_ACCEL_CFG2, + cfg->gyro_dlpf); + if (ret < 0) { + LOG_ERR("Failed to write accel digital LPF settings."); + return ret; + } + + ret = i2c_reg_write_byte_dt(&cfg->i2c, MPU9250_REG_SR_DIV, + cfg->gyro_sr_div); + if (ret < 0) { + LOG_ERR("Failed to write gyro ODR divider."); + return ret; + } + + drv_data->gyro_sensitivity_x10 = + mpu9250_gyro_sensitivity_x10[cfg->gyro_fs]; + +#ifdef CONFIG_MPU9250_MAGN_EN + ret = ak8963_init(dev); + if (ret < 0) { + LOG_ERR("Failed to initialize AK8963."); + return ret; + } +#endif + +#ifdef CONFIG_MPU9250_TRIGGER + ret = mpu9250_init_interrupt(dev); + if (ret < 0) { + LOG_ERR("Failed to initialize interrupts."); + return ret; + } +#endif + + return 0; +} + + +#define INIT_MPU9250_INST(inst) \ + static struct mpu9250_data mpu9250_data_##inst; \ + static const struct mpu9250_config mpu9250_cfg_##inst = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + .gyro_sr_div = DT_INST_PROP(inst, gyro_sr_div), \ + .gyro_dlpf = DT_INST_ENUM_IDX(inst, gyro_dlpf), \ + .gyro_fs = DT_INST_ENUM_IDX(inst, gyro_fs), \ + .accel_fs = DT_INST_ENUM_IDX(inst, accel_fs), \ + .accel_dlpf = DT_INST_ENUM_IDX(inst, accel_dlpf), \ + IF_ENABLED(CONFIG_MPU9250_TRIGGER, \ + (.int_pin = GPIO_DT_SPEC_INST_GET(inst, irq_gpios))) \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, mpu9250_init, NULL, \ + &mpu9250_data_##inst, &mpu9250_cfg_##inst,\ + POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \ + &mpu9250_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(INIT_MPU9250_INST) diff --git a/drivers/sensor/mpu9250/mpu9250.h b/drivers/sensor/mpu9250/mpu9250.h new file mode 100644 index 00000000000..b636ded7ecc --- /dev/null +++ b/drivers/sensor/mpu9250/mpu9250.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2021, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_MPU9250_MPU9250_H_ +#define ZEPHYR_DRIVERS_SENSOR_MPU9250_MPU9250_H_ + +#include +#include +#include +#include +#include +#include + +struct mpu9250_data { + int16_t accel_x; + int16_t accel_y; + int16_t accel_z; + uint16_t accel_sensitivity_shift; + + int16_t temp; + + int16_t gyro_x; + int16_t gyro_y; + int16_t gyro_z; + uint16_t gyro_sensitivity_x10; + +#ifdef CONFIG_MPU9250_MAGN_EN + int16_t magn_x; + int16_t magn_scale_x; + int16_t magn_y; + int16_t magn_scale_y; + int16_t magn_z; + int16_t magn_scale_z; + uint8_t magn_st2; +#endif + +#ifdef CONFIG_MPU9250_TRIGGER + const struct device *dev; + struct gpio_callback gpio_cb; + + struct sensor_trigger data_ready_trigger; + sensor_trigger_handler_t data_ready_handler; + +#if defined(CONFIG_MPU9250_TRIGGER_OWN_THREAD) + K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_MPU9250_THREAD_STACK_SIZE); + struct k_thread thread; + struct k_sem gpio_sem; +#elif defined(CONFIG_MPU9250_TRIGGER_GLOBAL_THREAD) + struct k_work work; +#endif + +#endif /* CONFIG_MPU9250_TRIGGER */ +}; + +struct mpu9250_config { + const struct i2c_dt_spec i2c; + uint8_t gyro_sr_div; + uint8_t gyro_dlpf; + uint8_t gyro_fs; + uint8_t accel_fs; + uint8_t accel_dlpf; +#ifdef CONFIG_MPU9250_TRIGGER + const struct gpio_dt_spec int_pin; +#endif /* CONFIG_MPU9250_TRIGGER */ +}; + +#ifdef CONFIG_MPU9250_TRIGGER +int mpu9250_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler); + +int mpu9250_init_interrupt(const struct device *dev); +#endif + +#endif /* ZEPHYR_DRIVERS_SENSOR_MPU9250_MPU9250_H_ */ diff --git a/drivers/sensor/mpu9250/mpu9250_trigger.c b/drivers/sensor/mpu9250/mpu9250_trigger.c new file mode 100644 index 00000000000..3bdeda4f747 --- /dev/null +++ b/drivers/sensor/mpu9250/mpu9250_trigger.c @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2021, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "mpu9250.h" + +LOG_MODULE_DECLARE(MPU9250, CONFIG_SENSOR_LOG_LEVEL); + + +#define MPU9250_REG_INT_EN 0x38 +#define MPU9250_DRDY_EN BIT(0) + + +int mpu9250_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) +{ + struct mpu9250_data *drv_data = dev->data; + const struct mpu9250_config *cfg = dev->config; + int ret; + + if (trig->type != SENSOR_TRIG_DATA_READY) { + return -ENOTSUP; + } + + ret = gpio_pin_interrupt_configure_dt(&cfg->int_pin, GPIO_INT_DISABLE); + if (ret < 0) { + LOG_ERR("Failed to disable gpio interrupt."); + return ret; + } + + drv_data->data_ready_handler = handler; + if (handler == NULL) { + return 0; + } + + drv_data->data_ready_trigger = *trig; + + ret = gpio_pin_interrupt_configure_dt(&cfg->int_pin, + GPIO_INT_EDGE_TO_ACTIVE); + if (ret < 0) { + LOG_ERR("Failed to enable gpio interrupt."); + return ret; + } + + return 0; +} + +static void mpu9250_gpio_callback(const struct device *dev, + struct gpio_callback *cb, uint32_t pins) +{ + struct mpu9250_data *drv_data = + CONTAINER_OF(cb, struct mpu9250_data, gpio_cb); + const struct mpu9250_config *cfg = drv_data->dev->config; + int ret; + + ARG_UNUSED(pins); + + ret = gpio_pin_interrupt_configure_dt(&cfg->int_pin, GPIO_INT_DISABLE); + if (ret < 0) { + LOG_ERR("Disabling gpio interrupt failed with err: %d", ret); + return; + } + +#if defined(CONFIG_MPU9250_TRIGGER_OWN_THREAD) + k_sem_give(&drv_data->gpio_sem); +#elif defined(CONFIG_MPU9250_TRIGGER_GLOBAL_THREAD) + k_work_submit(&drv_data->work); +#endif +} + +static void mpu9250_thread_cb(const struct device *dev) +{ + struct mpu9250_data *drv_data = dev->data; + const struct mpu9250_config *cfg = dev->config; + int ret; + + if (drv_data->data_ready_handler != NULL) { + drv_data->data_ready_handler(dev, + &drv_data->data_ready_trigger); + } + + ret = gpio_pin_interrupt_configure_dt(&cfg->int_pin, + GPIO_INT_EDGE_TO_ACTIVE); + if (ret < 0) { + LOG_ERR("Enabling gpio interrupt failed with err: %d", ret); + } + +} + +#ifdef CONFIG_MPU9250_TRIGGER_OWN_THREAD +static void mpu9250_thread(struct mpu9250_data *drv_data) +{ + while (1) { + k_sem_take(&drv_data->gpio_sem, K_FOREVER); + mpu9250_thread_cb(drv_data->dev); + } +} +#endif + +#ifdef CONFIG_MPU9250_TRIGGER_GLOBAL_THREAD +static void mpu9250_work_cb(struct k_work *work) +{ + struct mpu9250_data *drv_data = + CONTAINER_OF(work, struct mpu9250_data, work); + + mpu9250_thread_cb(drv_data->dev); +} +#endif + +int mpu9250_init_interrupt(const struct device *dev) +{ + struct mpu9250_data *drv_data = dev->data; + const struct mpu9250_config *cfg = dev->config; + int ret; + + /* setup data ready gpio interrupt */ + if (!device_is_ready(cfg->int_pin.port)) { + LOG_ERR("Interrupt pin is not ready."); + return -EIO; + } + + drv_data->dev = dev; + + ret = gpio_pin_configure_dt(&cfg->int_pin, GPIO_INPUT); + if (ret < 0) { + LOG_ERR("Failed to configure interrupt pin."); + return ret; + } + + gpio_init_callback(&drv_data->gpio_cb, + mpu9250_gpio_callback, + BIT(cfg->int_pin.pin)); + + ret = gpio_add_callback(cfg->int_pin.port, &drv_data->gpio_cb); + if (ret < 0) { + LOG_ERR("Failed to set gpio callback."); + return ret; + } + + /* enable data ready interrupt */ + ret = i2c_reg_write_byte_dt(&cfg->i2c, MPU9250_REG_INT_EN, + MPU9250_DRDY_EN); + if (ret < 0) { + LOG_ERR("Failed to enable data ready interrupt."); + return ret; + } + +#if defined(CONFIG_MPU9250_TRIGGER_OWN_THREAD) + ret = k_sem_init(&drv_data->gpio_sem, 0, K_SEM_MAX_LIMIT); + if (ret < 0) { + LOG_ERR("Failed to enable semaphore"); + return ret; + } + + k_thread_create(&drv_data->thread, drv_data->thread_stack, + CONFIG_MPU9250_THREAD_STACK_SIZE, + (k_thread_entry_t)mpu9250_thread, drv_data, + NULL, NULL, K_PRIO_COOP(CONFIG_MPU9250_THREAD_PRIORITY), + 0, K_NO_WAIT); +#elif defined(CONFIG_MPU9250_TRIGGER_GLOBAL_THREAD) + drv_data->work.handler = mpu9250_work_cb; +#endif + + ret = gpio_pin_interrupt_configure_dt(&cfg->int_pin, + GPIO_INT_EDGE_TO_ACTIVE); + if (ret < 0) { + LOG_ERR("Failed to enable interrupt"); + return ret; + } + + return 0; +} diff --git a/drivers/serial/Kconfig.nrfx b/drivers/serial/Kconfig.nrfx index 8b1965afb18..026a3d8541d 100644 --- a/drivers/serial/Kconfig.nrfx +++ b/drivers/serial/Kconfig.nrfx @@ -17,6 +17,16 @@ menuconfig UART_NRFX if UART_NRFX +config UART_ASYNC_TX_CACHE_SIZE + int "TX cache buffer size" + depends on UART_ASYNC_API + depends on NRF_UARTE_PERIPHERAL + default 8 + help + For UARTE, TX cache buffer is used when provided TX buffer is not located + in RAM, because EasyDMA in UARTE peripherals can only transfer data + from RAM. + # Workaround for not being able to have commas in macro arguments DT_COMPAT_NORDIC_NRF_UART := nordic,nrf-uart DT_COMPAT_NORDIC_NRF_UARTE := nordic,nrf-uarte diff --git a/drivers/serial/uart_nrfx_uarte.c b/drivers/serial/uart_nrfx_uarte.c index 1bb8378c4c9..5910bac54b6 100644 --- a/drivers/serial/uart_nrfx_uarte.c +++ b/drivers/serial/uart_nrfx_uarte.c @@ -74,7 +74,11 @@ struct uarte_async_cb { const uint8_t *tx_buf; volatile size_t tx_size; - uint8_t *pend_tx_buf; + const uint8_t *xfer_buf; + size_t xfer_len; + + uint8_t tx_cache[CONFIG_UART_ASYNC_TX_CACHE_SIZE]; + size_t tx_cache_offset; struct k_timer tx_timeout_timer; @@ -100,6 +104,7 @@ struct uarte_async_cb { uint8_t rx_flush_cnt; bool rx_enabled; bool hw_rx_counting; + bool pending_tx; /* Flag to ensure that RX timeout won't be executed during ENDRX ISR */ volatile bool is_in_irq; }; @@ -739,6 +744,44 @@ static int uarte_nrfx_init(const struct device *dev) return 0; } +/* Attempt to start TX (asynchronous transfer). If hardware is not ready, then pending + * flag is set. When current poll_out is completed, pending transfer is started. + * Function must be called with interrupts locked. + */ +static void start_tx_locked(const struct device *dev, struct uarte_nrfx_data *data) +{ + if (!is_tx_ready(dev)) { + /* Active poll out, postpone until it is completed. */ + data->async->pending_tx = true; + } else { + data->async->pending_tx = false; + data->async->tx_amount = -1; + tx_start(dev, data->async->xfer_buf, data->async->xfer_len); + } +} + +/* Setup cache buffer (used for sending data outside of RAM memory). + * During setup data is copied to cache buffer and transfer length is set. + * + * @return True if cache was set, false if no more data to put in cache. + */ +static bool setup_tx_cache(struct uarte_nrfx_data *data) +{ + size_t remaining = data->async->tx_size - data->async->tx_cache_offset; + + if (!remaining) { + return false; + } + + size_t len = MIN(remaining, sizeof(data->async->tx_cache)); + + data->async->xfer_len = len; + data->async->xfer_buf = data->async->tx_cache; + memcpy(data->async->tx_cache, &data->async->tx_buf[data->async->tx_cache_offset], len); + + return true; +} + static int uarte_nrfx_tx(const struct device *dev, const uint8_t *buf, size_t len, int32_t timeout) @@ -746,10 +789,6 @@ static int uarte_nrfx_tx(const struct device *dev, const uint8_t *buf, struct uarte_nrfx_data *data = get_dev_data(dev); NRF_UARTE_Type *uarte = get_uarte_instance(dev); - if (!nrfx_is_in_ram(buf)) { - return -ENOTSUP; - } - int key = irq_lock(); if (data->async->tx_size) { @@ -758,17 +797,19 @@ static int uarte_nrfx_tx(const struct device *dev, const uint8_t *buf, } data->async->tx_size = len; + data->async->tx_buf = buf; nrf_uarte_int_enable(uarte, NRF_UARTE_INT_TXSTOPPED_MASK); - if (!is_tx_ready(dev)) { - /* Active poll out, postpone until it is completed. */ - data->async->pend_tx_buf = (uint8_t *)buf; + if (nrfx_is_in_ram(buf)) { + data->async->xfer_buf = buf; + data->async->xfer_len = len; } else { - data->async->tx_buf = buf; - data->async->tx_amount = -1; - tx_start(dev, buf, len); + data->async->tx_cache_offset = 0; + (void)setup_tx_cache(data); } + start_tx_locked(dev, data); + irq_unlock(key); if (data->uart_config.flow_ctrl == UART_CFG_FLOW_CTRL_RTS_CTS @@ -787,6 +828,8 @@ static int uarte_nrfx_tx_abort(const struct device *dev) if (data->async->tx_buf == NULL) { return -EFAULT; } + + data->async->pending_tx = false; k_timer_stop(&data->async->tx_timeout_timer); nrf_uarte_task_trigger(uarte, NRF_UARTE_TASK_STOPTX); @@ -1290,7 +1333,16 @@ static void rxto_isr(const struct device *dev) notify_rx_buf_release(dev, &data->async->rx_buf, true); notify_rx_buf_release(dev, &data->async->rx_next_buf, true); - if (!data->async->rx_enabled) { + /* If the rx_enabled flag is still set at this point, it means that + * RX is being disabled because all provided RX buffers have been + * filled up. Clear the flag then, so that RX can be enabled again. + * + * If the flag is already cleared, it means that RX was aborted by + * a call to uart_rx_disable() and data from FIFO should be discarded. + */ + if (data->async->rx_enabled) { + data->async->rx_enabled = false; + } else { (void)rx_flush(dev, NULL, 0); } @@ -1317,35 +1369,50 @@ static void txstopped_isr(const struct device *dev) } if (!data->async->tx_buf) { - /* If there is a pending tx request, it means that uart_tx() - * was called when there was ongoing uart_poll_out. Handling - * TXSTOPPED interrupt means that uart_poll_out has completed. - */ - if (data->async->pend_tx_buf) { - key = irq_lock(); - - if (nrf_uarte_event_check(uarte, - NRF_UARTE_EVENT_TXSTOPPED)) { - data->async->tx_buf = data->async->pend_tx_buf; - data->async->pend_tx_buf = NULL; - data->async->tx_amount = -1; - tx_start(dev, data->async->tx_buf, - data->async->tx_size); - } - - irq_unlock(key); - } return; } - k_timer_stop(&data->async->tx_timeout_timer); - key = irq_lock(); size_t amount = (data->async->tx_amount >= 0) ? data->async->tx_amount : nrf_uarte_tx_amount_get(uarte); irq_unlock(key); + /* If there is a pending tx request, it means that uart_tx() + * was called when there was ongoing uart_poll_out. Handling + * TXSTOPPED interrupt means that uart_poll_out has completed. + */ + if (data->async->pending_tx) { + key = irq_lock(); + start_tx_locked(dev, data); + irq_unlock(key); + return; + } + + /* Cache buffer is used because tx_buf wasn't in RAM. */ + if (data->async->tx_buf != data->async->xfer_buf) { + /* In that case setup next chunk. If that was the last chunk + * fall back to reporting TX_DONE. + */ + if (amount == data->async->xfer_len) { + data->async->tx_cache_offset += amount; + if (setup_tx_cache(data)) { + key = irq_lock(); + start_tx_locked(dev, data); + irq_unlock(key); + return; + } + + /* Amount is already included in tx_cache_offset. */ + amount = data->async->tx_cache_offset; + } else { + /* TX was aborted, include tx_cache_offset in amount. */ + amount += data->async->tx_cache_offset; + } + } + + k_timer_stop(&data->async->tx_timeout_timer); + struct uart_event evt = { .data.tx.buf = data->async->tx_buf, .data.tx.len = amount, diff --git a/drivers/spi/spi_nrfx_spi.c b/drivers/spi/spi_nrfx_spi.c index a11ce60866a..b24456ca6eb 100644 --- a/drivers/spi/spi_nrfx_spi.c +++ b/drivers/spi/spi_nrfx_spi.c @@ -294,8 +294,10 @@ static int spi_nrfx_pm_action(const struct device *dev, break; case PM_DEVICE_ACTION_SUSPEND: - nrfx_spi_uninit(&config->spi); - data->initialized = false; + if (data->initialized) { + nrfx_spi_uninit(&config->spi); + data->initialized = false; + } break; default: diff --git a/drivers/spi/spi_nrfx_spim.c b/drivers/spi/spi_nrfx_spim.c index e434d68f3eb..6f16515e515 100644 --- a/drivers/spi/spi_nrfx_spim.c +++ b/drivers/spi/spi_nrfx_spim.c @@ -453,8 +453,10 @@ static int spim_nrfx_pm_action(const struct device *dev, break; case PM_DEVICE_ACTION_SUSPEND: - nrfx_spim_uninit(&config->spim); - data->initialized = false; + if (data->initialized) { + nrfx_spim_uninit(&config->spim); + data->initialized = false; + } break; default: diff --git a/dts/arm/nordic/nrf52840.dtsi b/dts/arm/nordic/nrf52840.dtsi index 93ddfd1be5f..db6ff79b740 100644 --- a/dts/arm/nordic/nrf52840.dtsi +++ b/dts/arm/nordic/nrf52840.dtsi @@ -5,7 +5,7 @@ / { chosen { - zephyr,entropy = &rng; + zephyr,entropy = &cryptocell; zephyr,flash-controller = &flash_controller; }; diff --git a/dts/arm/nordic/nrf5340_cpuapp.dtsi b/dts/arm/nordic/nrf5340_cpuapp.dtsi index b65ed1cdc0d..6c4bf87ddfb 100644 --- a/dts/arm/nordic/nrf5340_cpuapp.dtsi +++ b/dts/arm/nordic/nrf5340_cpuapp.dtsi @@ -28,6 +28,7 @@ }; chosen { + zephyr,entropy = &cryptocell; zephyr,flash-controller = &flash_controller; }; diff --git a/dts/arm/nordic/nrf5340_cpuappns.dtsi b/dts/arm/nordic/nrf5340_cpuappns.dtsi index eb39f04ff40..1620249c767 100644 --- a/dts/arm/nordic/nrf5340_cpuappns.dtsi +++ b/dts/arm/nordic/nrf5340_cpuappns.dtsi @@ -30,6 +30,15 @@ chosen { zephyr,flash-controller = &flash_controller; + + /* + * By default, system entropy comes from the entropy_cc310.c + * driver in the nrf repository. This is devicetree glue + * needed to make the system aware of that fact. Individual + * applications can override this by changing this property + * value. + */ + zephyr,entropy = &cryptocell_sw; }; soc { @@ -48,6 +57,13 @@ #include "nrf5340_cpuapp_peripherals.dtsi" }; }; + + /* For cryptocell access via platform library; see above */ + cryptocell_sw: cryptocell-sw { + compatible = "nordic,nrf-cc312-sw"; + #address-cells = <0>; + label = "CRYPTOCELL_SW"; + }; }; &nvic { diff --git a/dts/arm/nordic/nrf9160.dtsi b/dts/arm/nordic/nrf9160.dtsi index 09b030d1358..e797d79ab52 100644 --- a/dts/arm/nordic/nrf9160.dtsi +++ b/dts/arm/nordic/nrf9160.dtsi @@ -28,6 +28,7 @@ }; chosen { + zephyr,entropy = &cryptocell; zephyr,flash-controller = &flash_controller; }; diff --git a/dts/arm/nordic/nrf9160ns.dtsi b/dts/arm/nordic/nrf9160ns.dtsi index 1742580e76c..a85dada2ba6 100644 --- a/dts/arm/nordic/nrf9160ns.dtsi +++ b/dts/arm/nordic/nrf9160ns.dtsi @@ -29,6 +29,15 @@ chosen { zephyr,flash-controller = &flash_controller; + + /* + * By default, system entropy comes from the entropy_cc310.c + * driver in the nrf repository. This is devicetree glue + * needed to make the system aware of that fact. Individual + * applications can override this by changing this property + * value. + */ + zephyr,entropy = &cryptocell_sw; }; soc { @@ -54,6 +63,13 @@ label = "GPIOTE_1"; }; }; + + + /* For cryptocell access via platform library; see above */ + cryptocell_sw: cryptocell-sw { + compatible = "nordic,nrf-cc310-sw"; + label = "CRYPTOCELL_SW"; + }; }; &nvic { diff --git a/dts/bindings/crypto/nordic,nrf-cc310-sw.yaml b/dts/bindings/crypto/nordic,nrf-cc310-sw.yaml new file mode 100644 index 00000000000..a0724a45938 --- /dev/null +++ b/dts/bindings/crypto/nordic,nrf-cc310-sw.yaml @@ -0,0 +1,17 @@ +# Copyright (c) 2020, Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: | + Stub access to cryptocell via platform driver + + Non-secure configurations can use this compatible to declare + devicetree nodes which access the CC310 via callbacks into secure + code. + +compatible: "nordic,nrf-cc310-sw" + +include: base.yaml + +properties: + label: + required: true diff --git a/dts/bindings/crypto/nordic,nrf-cc312-sw.yaml b/dts/bindings/crypto/nordic,nrf-cc312-sw.yaml new file mode 100644 index 00000000000..9c3f936bf20 --- /dev/null +++ b/dts/bindings/crypto/nordic,nrf-cc312-sw.yaml @@ -0,0 +1,17 @@ +# Copyright (c) 2021, Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: | + Stub access to cryptocell via platform driver + + Non-secure configurations can use this compatible to declare + devicetree nodes which access the CC312 via callbacks into secure + code. + +compatible: "nordic,nrf-cc312-sw" + +include: base.yaml + +properties: + label: + required: true diff --git a/dts/bindings/sensor/invensense,mpu9250.yaml b/dts/bindings/sensor/invensense,mpu9250.yaml new file mode 100644 index 00000000000..fb9590554f3 --- /dev/null +++ b/dts/bindings/sensor/invensense,mpu9250.yaml @@ -0,0 +1,85 @@ +# Copyright (c) 2021 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +description: | + InvenSense MPU-9250 Nine-Axis (Gyro + Accelerometer + Compass). See more + info at https://www.invensense.com/products/motion-tracking/9-axis/mpu-9250/ + +compatible: "invensense,mpu9250" + +include: i2c-device.yaml + +properties: + irq-gpios: + type: phandle-array + required: false + description: | + The INT signal default configuration is active-high. The + property value should ensure the flags properly describe the + signal that is presented to the driver. + This property is required when the trigger mode is used. + + gyro-sr-div: + type: int + required: true + description: | + Default gyrscope sample rate divider. This divider is only effective + when gyro-dlpf is in range 5-184. + rate = sample_rate / (1 + gyro-sr-div) + Valid range: 0 - 255 + + gyro-dlpf: + type: int + required: true + description: | + Default digital low pass filter frequency of gyroscope. + Maps to DLPF_CFG field in Configuration setting. + enum: + - 250 + - 184 + - 92 + - 41 + - 20 + - 10 + - 5 + - 3600 + + gyro-fs: + type: int + required: true + description: | + Default full scale of gyroscope. (Unit - DPS). + Maps to GYRO_FS_SEL field in Gyroscope Configuration setting. + enum: + - 250 + - 500 + - 1000 + - 2000 + + accel-fs: + type: int + required: true + description: | + Default full scale of accelerometer. (Unit - g) + Maps to ACCEL_FS_SEL field in Accelerometer Configuration setting + enum: + - 2 + - 4 + - 8 + - 16 + + accel-dlpf: + type: string + required: true + description: | + Default digital low pass filter frequency of accelerometer. + Maps to DLPF_CFG field in Accelerometer Configuration 2 setting. + enum: + - "218.1" + - "218.1a" + - "99" + - "44.8" + - "21.2" + - "10.2" + - "5.05" + - "420" diff --git a/include/arch/arm/aarch32/cortex_m/scripts/linker.ld b/include/arch/arm/aarch32/cortex_m/scripts/linker.ld index 6ccb15dbc75..87f2063c917 100644 --- a/include/arch/arm/aarch32/cortex_m/scripts/linker.ld +++ b/include/arch/arm/aarch32/cortex_m/scripts/linker.ld @@ -28,6 +28,35 @@ #define RAMABLE_REGION SRAM #endif +#if USE_PARTITION_MANAGER + +#include + +#if CONFIG_NCS_IS_VARIANT_IMAGE +/* We are linking against S1, create symbol containing the flash ID of S0. + * This is used when writing code operating on the "other" slot. + */ +_image_1_primary_slot_id = PM_S0_ID; + +#else /* ! CONFIG_NCS_IS_VARIANT_IMAGE */ + +#ifdef PM_S1_ID +/* We are linking against S0, create symbol containing the flash ID of S1. + * This is used when writing code operating on the "other" slot. + */ +_image_1_primary_slot_id = PM_S1_ID; +#endif /* PM_S1_ID */ + +#endif /* CONFIG_NCS_IS_VARIANT_IMAGE */ + +#define ROM_ADDR PM_ADDRESS +#define ROM_SIZE PM_SIZE + +#define RAM_SIZE PM_SRAM_SIZE +#define RAM_ADDR PM_SRAM_ADDRESS + +#else /* ! USE_PARTITION_MANAGER */ + #if !defined(CONFIG_XIP) && (CONFIG_FLASH_SIZE == 0) #define ROM_ADDR RAM_ADDR #else @@ -54,6 +83,23 @@ #define RAM_ADDR CONFIG_SRAM_BASE_ADDRESS #endif +#endif /* USE_PARTITION_MANAGER */ + +#if DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_ccm), okay) +#define CCM_SIZE DT_REG_SIZE(DT_CHOSEN(zephyr_ccm)) +#define CCM_ADDR DT_REG_ADDR(DT_CHOSEN(zephyr_ccm)) +#endif + +#if DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_itcm), okay) +#define ITCM_SIZE DT_REG_SIZE(DT_CHOSEN(zephyr_itcm)) +#define ITCM_ADDR DT_REG_ADDR(DT_CHOSEN(zephyr_itcm)) +#endif + +#if DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_dtcm), okay) +#define DTCM_SIZE DT_REG_SIZE(DT_CHOSEN(zephyr_dtcm)) +#define DTCM_ADDR DT_REG_ADDR(DT_CHOSEN(zephyr_dtcm)) +#endif + #if defined(CONFIG_CUSTOM_SECTION_ALIGN) _region_min_align = CONFIG_CUSTOM_SECTION_MIN_ALIGN_SIZE; #else diff --git a/include/arch/posix/linker.ld b/include/arch/posix/linker.ld index d56260e76af..dccb4593c58 100644 --- a/include/arch/posix/linker.ld +++ b/include/arch/posix/linker.ld @@ -22,22 +22,31 @@ SECTIONS { -/* Located in generated directory. This file is populated by the - * zephyr_linker_sources() Cmake function. - */ -#include +SECTION_PROLOGUE(rom_start,,) +{ + /* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. + */ + #include +} GROUP_LINK_IN(ROMABLE_REGION) #include -/* Located in generated directory. This file is populated by the - * zephyr_linker_sources() Cmake function. - */ -#include - -/* Located in generated directory. This file is populated by the - * zephyr_linker_sources() Cmake function. - */ -#include +SECTION_PROLOGUE(_RODATA_SECTION_NAME,,) +{ + /* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. + */ + #include +} GROUP_LINK_IN(ROMABLE_REGION) + +SECTION_DATA_PROLOGUE(_DATA_SECTION_NAME,,) +{ + /* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. + */ + #include +} GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) #include @@ -55,10 +64,13 @@ SECTIONS __data_region_end = .; -/* Located in generated directory. This file is populated by the - * zephyr_linker_sources() Cmake function. - */ -#include +SECTION_DATA_PROLOGUE(_NOINIT_SECTION_NAME,,) +{ + /* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. + */ + #include +} GROUP_LINK_IN(RAMABLE_REGION) /* Located in generated directory. This file is populated by the * zephyr_linker_sources() Cmake function. diff --git a/include/bluetooth/direction.h b/include/bluetooth/direction.h index f080d2d4310..c5cb2f1bf1e 100644 --- a/include/bluetooth/direction.h +++ b/include/bluetooth/direction.h @@ -137,7 +137,18 @@ struct bt_df_conn_cte_rx_param { const uint8_t *ant_ids; }; +enum bt_df_conn_iq_report_err { + /** IQ samples report received successfully. */ + BT_DF_IQ_REPORT_ERR_SUCCESS, + /** Received PDU without CTE. No valid data in report. */ + BT_DF_IQ_REPORT_ERR_NO_CTE, + /** Peer rejected CTE request. No valid data in report. */ + BT_DF_IQ_REPORT_ERR_PEER_REJECTED, +}; + struct bt_df_conn_iq_samples_report { + /** Report receive failed reason. */ + enum bt_df_conn_iq_report_err err; /** PHY that was used to receive PDU with CTE that was sampled. */ uint8_t rx_phy; /** Channel index used to receive PDU with CTE that was sampled. */ @@ -179,7 +190,7 @@ struct bt_df_conn_cte_req_params { * Value 0x0 means, run the procedure once. Other values are intervals in number of * connection events, to run the command periodically. */ - uint8_t interval; + uint16_t interval; /** Requested length of the CTE in 8 us units. */ uint8_t cte_length; /** diff --git a/include/bluetooth/gap.h b/include/bluetooth/gap.h index 86b478db8dc..e9df2941182 100644 --- a/include/bluetooth/gap.h +++ b/include/bluetooth/gap.h @@ -50,6 +50,7 @@ extern "C" { #define BT_DATA_LE_SC_CONFIRM_VALUE 0x22 /* LE SC Confirmation Value */ #define BT_DATA_LE_SC_RANDOM_VALUE 0x23 /* LE SC Random Value */ #define BT_DATA_URI 0x24 /* URI */ +#define BT_DATA_LE_SUPPORTED_FEATURES 0x27 /* LE Supported Features */ #define BT_DATA_CHANNEL_MAP_UPDATE_IND 0x28 /* Channel Map Update Indication */ #define BT_DATA_MESH_PROV 0x29 /* Mesh Provisioning PDU */ #define BT_DATA_MESH_MESSAGE 0x2a /* Mesh Networking PDU */ @@ -162,6 +163,12 @@ enum { /** Maximum Periodic Advertising Interval (N * 1.25 ms) */ #define BT_GAP_PER_ADV_MAX_INTERVAL 0xFFFF +/** + * @brief Convert periodic advertising interval (N * 1.25 ms) to milliseconds + * + * 5 / 4 represents 1.25 ms unit. + */ +#define BT_GAP_PER_ADV_INTERVAL_TO_MS(interval) ((interval) * 5 / 4) /** Constant Tone Extension (CTE) types */ enum { @@ -175,7 +182,6 @@ enum { BT_GAP_CTE_NONE = 0xFF, }; - /** @brief Peripheral sleep clock accuracy (SCA) in ppm (parts per million) */ enum { BT_GAP_SCA_UNKNOWN = 0, @@ -189,6 +195,137 @@ enum { BT_GAP_SCA_0_20 = 7, }; +/** + * @brief Encode 40 least significant bits of 64-bit LE Supported Features into array values + * in little-endian format. + * + * Helper macro to encode 40 least significant bits of 64-bit LE Supported Features value into + * advertising data. The number of bits that are encoded is a number of LE Supported Features + * defined by BT 5.3 Core specification. + * + * Example of how to encode the `0x000000DFF00DF00D` into advertising data. + * + * @code + * BT_DATA_BYTES(BT_DATA_LE_SUPPORTED_FEATURES, BT_LE_SUPP_FEAT_40_ENCODE(0x000000DFF00DF00D)) + * @endcode + * + * @param w64 LE Supported Features value (64-bits) + * + * @return The comma separated values for LE Supported Features value that + * may be used directly as an argument for @ref BT_DATA_BYTES. + */ +#define BT_LE_SUPP_FEAT_40_ENCODE(w64) \ + (((w64) >> 0) & 0xFF), \ + (((w64) >> 8) & 0xFF), \ + (((w64) >> 16) & 0xFF), \ + (((w64) >> 24) & 0xFF), \ + (((w64) >> 32) & 0xFF) + +/** @brief Encode 4 least significant bytes of 64-bit LE Supported Features into + * 4 bytes long array of values in little-endian format. + * + * Helper macro to encode 64-bit LE Supported Features value into advertising + * data. The macro encodes 4 least significant bytes into advertising data. + * Other 4 bytes are not encoded. + * + * Example of how to encode the `0x000000DFF00DF00D` into advertising data. + * + * @code + * BT_DATA_BYTES(BT_DATA_LE_SUPPORTED_FEATURES, BT_LE_SUPP_FEAT_32_ENCODE(0x000000DFF00DF00D)) + * @endcode + * + * @param w64 LE Supported Features value (64-bits) + * + * @return The comma separated values for LE Supported Features value that + * may be used directly as an argument for @ref BT_DATA_BYTES. + */ +#define BT_LE_SUPP_FEAT_32_ENCODE(w64) \ + (((w64) >> 0) & 0xFF), \ + (((w64) >> 8) & 0xFF), \ + (((w64) >> 16) & 0xFF), \ + (((w64) >> 24) & 0xFF) + +/** + * @brief Encode 3 least significant bytes of 64-bit LE Supported Features into + * 3 bytes long array of values in little-endian format. + * + * Helper macro to encode 64-bit LE Supported Features value into advertising + * data. The macro encodes 3 least significant bytes into advertising data. + * Other 5 bytes are not encoded. + * + * Example of how to encode the `0x000000DFF00DF00D` into advertising data. + * + * @code + * BT_DATA_BYTES(BT_DATA_LE_SUPPORTED_FEATURES, BT_LE_SUPP_FEAT_24_ENCODE(0x000000DFF00DF00D)) + * @endcode + * + * @param w64 LE Supported Features value (64-bits) + * + * @return The comma separated values for LE Supported Features value that + * may be used directly as an argument for @ref BT_DATA_BYTES. + */ +#define BT_LE_SUPP_FEAT_24_ENCODE(w64) \ + (((w64) >> 0) & 0xFF), \ + (((w64) >> 8) & 0xFF), \ + (((w64) >> 16) & 0xFF), + +/** + * @brief Encode 2 least significant bytes of 64-bit LE Supported Features into + * 2 bytes long array of values in little-endian format. + * + * Helper macro to encode 64-bit LE Supported Features value into advertising + * data. The macro encodes 3 least significant bytes into advertising data. + * Other 6 bytes are not encoded. + * + * Example of how to encode the `0x000000DFF00DF00D` into advertising data. + * + * @code + * BT_DATA_BYTES(BT_DATA_LE_SUPPORTED_FEATURES, BT_LE_SUPP_FEAT_16_ENCODE(0x000000DFF00DF00D)) + * @endcode + * + * @param w64 LE Supported Features value (64-bits) + * + * @return The comma separated values for LE Supported Features value that + * may be used directly as an argument for @ref BT_DATA_BYTES. + */ +#define BT_LE_SUPP_FEAT_16_ENCODE(w64) \ + (((w64) >> 0) & 0xFF), \ + (((w64) >> 8) & 0xFF), + +/** + * @brief Encode the least significant byte of 64-bit LE Supported Features into + * single byte long array. + * + * Helper macro to encode 64-bit LE Supported Features value into advertising + * data. The macro encodes the least significant byte into advertising data. + * Other 7 bytes are not encoded. + * + * Example of how to encode the `0x000000DFF00DF00D` into advertising data. + * + * @code + * BT_DATA_BYTES(BT_DATA_LE_SUPPORTED_FEATURES, BT_LE_SUPP_FEAT_8_ENCODE(0x000000DFF00DF00D)) + * @endcode + * + * @param w64 LE Supported Features value (64-bits) + * + * @return The value of least significant byte of LE Supported Features value + * that may be used directly as an argument for @ref BT_DATA_BYTES. + */ +#define BT_LE_SUPP_FEAT_8_ENCODE(w64) \ + (((w64) >> 0) & 0xFF) + +/** + * @brief Validate wheather LE Supported Features value does not use bits that are reserved for + * future use. + * + * Helper macro to check if @p w64 has zeros as bits 40-63. The macro is compliant with BT 5.3 + * Core Specifiaction where bits 0-40 has assigned values. In case of invalid value, build time + * error is reported. + */ +#define BT_LE_SUPP_FEAT_VALIDATE(w64) \ + BUILD_ASSERT(!((w64) & (~BIT64_MASK(40))), \ + "RFU bit in LE Supported Features are not zeros.") + /** * @} */ diff --git a/include/bluetooth/hci.h b/include/bluetooth/hci.h index 1061d0c2a27..8ed57b234a0 100644 --- a/include/bluetooth/hci.h +++ b/include/bluetooth/hci.h @@ -166,6 +166,10 @@ struct bt_hci_cmd_hdr { #define BT_LE_FEAT_BIT_PWR_CTRL_REQ 33 #define BT_LE_FEAT_BIT_PWR_CHG_IND 34 #define BT_LE_FEAT_BIT_PATH_LOSS_MONITOR 35 +#define BT_LE_FEAT_BIT_PER_ADV_ADI_SUPP 36 +#define BT_LE_FEAT_BIT_CONN_SUBRATING 37 +#define BT_LE_FEAT_BIT_CONN_SUBRATING_HOST_SUPP 38 +#define BT_LE_FEAT_BIT_CHANNEL_CLASSIFICATION 39 #define BT_LE_FEAT_TEST(feat, n) (feat[(n) >> 3] & \ BIT((n) & 7)) @@ -1372,7 +1376,7 @@ struct bt_hci_cp_le_set_per_adv_data { uint8_t handle; uint8_t op; uint8_t len; - uint8_t data[251]; + uint8_t data[BT_HCI_LE_PER_ADV_FRAG_MAX_LEN]; } __packed; #define BT_HCI_LE_SET_PER_ADV_ENABLE_ENABLE BIT(0) @@ -1607,7 +1611,7 @@ struct bt_hci_rp_le_set_conn_cte_tx_params { struct bt_hci_cp_le_conn_cte_req_enable { uint16_t handle; uint8_t enable; - uint8_t cte_request_interval; + uint16_t cte_request_interval; uint8_t requested_cte_length; uint8_t requested_cte_type; } __packed; @@ -2495,8 +2499,15 @@ struct bt_hci_evt_le_connection_iq_report { struct bt_hci_le_iq_sample sample[0]; } __packed; +#define BT_HCI_CTE_REQ_STATUS_RSP_WITHOUT_CTE 0x0 + #define BT_HCI_EVT_LE_CTE_REQUEST_FAILED 0x17 struct bt_hci_evt_le_cte_req_failed { + /* According to BT 5.3 Core Spec the status field may have following + * values: + * - BT_HCI_CTE_REQ_STATUS_RSP_WIHOUT_CTE when received LL_CTE_RSP_PDU without CTE. + * - Other Controller error code for peer rejected request. + */ uint8_t status; uint16_t conn_handle; } __packed; diff --git a/include/drivers/flash/nrf_qspi_nor.h b/include/drivers/flash/nrf_qspi_nor.h new file mode 100644 index 00000000000..8eb56acfef0 --- /dev/null +++ b/include/drivers/flash/nrf_qspi_nor.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __ZEPHYR_INCLUDE_DRIVERS_FLASH_NRF_QSPI_NOR_H__ +#define __ZEPHYR_INCLUDE_DRIVERS_FLASH_NRF_QSPI_NOR_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Specifies whether the QSPI base clock divider should be kept set + * when the driver is idle + * + * On nRF53 Series SoCs, it is necessary to change the default base clock + * divider to achieve the highest possible SCK frequencies. This divider + * should be changed only for periods when it is actually needed, as such + * configuration significantly increases power consumption, so the driver + * normally does this only when it performs an operation on the QSPI bus. + * But when XIP accesses to the flash chip are also used, and the driver + * is not aware of those, it may be necessary for the divider to be kept + * changed also when the driver is idle. This function allows forcing this. + * + * @param dev flash device + * @param force if true, forces the base clock divider to be kept set even + * when the driver is idle + */ +__syscall void nrf_qspi_nor_base_clock_div_force(const struct device *dev, + bool force); + +#ifdef __cplusplus +} +#endif + +#include + +#endif /* __ZEPHYR_INCLUDE_DRIVERS_FLASH_NRF_QSPI_NOR_H__ */ diff --git a/include/net/lwm2m.h b/include/net/lwm2m.h index 751d3d5fdcf..310fd6689fc 100644 --- a/include/net/lwm2m.h +++ b/include/net/lwm2m.h @@ -371,6 +371,25 @@ void lwm2m_firmware_set_write_cb(lwm2m_engine_set_data_cb_t cb); */ lwm2m_engine_set_data_cb_t lwm2m_firmware_get_write_cb(void); +/** + * @brief Set data callback for firmware block transfer. + * + * LwM2M clients use this function to register a callback for receiving the + * block transfer data when performing a firmware update. + * + * @param[in] obj_inst_id Object instance ID + * @param[in] cb A callback function to receive the block transfer data + */ +void lwm2m_firmware_set_write_cb_inst(uint16_t obj_inst_id, lwm2m_engine_set_data_cb_t cb); + +/** + * @brief Get the data callback for firmware block transfer writes. + * + * @param[in] obj_inst_id Object instance ID + * @return A registered callback function to receive the block transfer data + */ +lwm2m_engine_set_data_cb_t lwm2m_firmware_get_write_cb_inst(uint16_t obj_inst_id); + #if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT) /** * @brief Set data callback to handle firmware update execute events. @@ -388,6 +407,25 @@ void lwm2m_firmware_set_update_cb(lwm2m_engine_execute_cb_t cb); * @return A registered callback function to receive the execute event. */ lwm2m_engine_execute_cb_t lwm2m_firmware_get_update_cb(void); + +/** + * @brief Set data callback to handle firmware update execute events. + * + * LwM2M clients use this function to register a callback for receiving the + * update resource "execute" operation on the LwM2M Firmware Update object. + * + * @param[in] obj_inst_id Object instance ID + * @param[in] cb A callback function to receive the execute event. + */ +void lwm2m_firmware_set_update_cb_inst(uint16_t obj_inst_id, lwm2m_engine_execute_cb_t cb); + +/** + * @brief Get the event callback for firmware update execute events. + * + * @param[in] obj_inst_id Object instance ID + * @return A registered callback function to receive the execute event. + */ +lwm2m_engine_execute_cb_t lwm2m_firmware_get_update_cb_inst(uint16_t obj_inst_id); #endif #endif diff --git a/include/net/mqtt.h b/include/net/mqtt.h index a939be9f6b0..437fff18671 100644 --- a/include/net/mqtt.h +++ b/include/net/mqtt.h @@ -350,6 +350,9 @@ struct mqtt_sec_config { /** Indicates the list of security tags to be used for the session. */ sec_tag_t *sec_tag_list; + /** Indicates the preference for enabling TLS session caching. */ + int session_cache; + /** Peer hostname for ceritificate verification. * May be NULL to skip hostname verification. */ diff --git a/include/net/socket.h b/include/net/socket.h index 0663b19e84b..b11c1803975 100644 --- a/include/net/socket.h +++ b/include/net/socket.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #ifdef __cplusplus diff --git a/include/net/socket_ncs.h b/include/net/socket_ncs.h new file mode 100644 index 00000000000..3008ea1ccfd --- /dev/null +++ b/include/net/socket_ncs.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2021 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_NET_SOCKET_NCS_H_ +#define ZEPHYR_INCLUDE_NET_SOCKET_NCS_H_ + +/** + * @file + * @brief NCS specific additions to the BSD sockets API definitions + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* When CONFIG_NET_SOCKETS_OFFLOAD is enabled, offloaded sockets take precedence + * when creating a new socket. Combine this flag with a socket type when + * creating a socket, to enforce native socket creation (e. g. SOCK_STREAM | SOCK_NATIVE). + * If it's desired to create a native TLS socket, but still offload the + * underlying TCP/UDP socket, use e. g. SOCK_STREAM | SOCK_NATIVE_TLS. + */ +#define SOCK_NATIVE 0x80000000 +#define SOCK_NATIVE_TLS 0x40000000 + +/* NCS specific TLS options */ + +/** Socket option to control TLS session caching. Accepted values: + * - 0 - Disabled. + * - 1 - Enabled. + */ +#define TLS_SESSION_CACHE 10 +/** Socket option to purge session cache immediately. + * This option accepts any value. + */ +#define TLS_SESSION_CACHE_PURGE 11 +/** Socket option to set DTLS handshake timeout, specifically for nRF sockets. + * The option accepts an integer, indicating the total handshake timeout, + * including retransmissions, in seconds. + * Accepted values for the option are: 1, 3, 7, 15, 31, 63, 123. + */ +#define TLS_DTLS_HANDSHAKE_TIMEO 12 + +/* Valid values for TLS_SESSION_CACHE option */ +#define TLS_SESSION_CACHE_DISABLED 0 /**< Disable TLS session caching. */ +#define TLS_SESSION_CACHE_ENABLED 1 /**< Enable TLS session caching. */ + +/* Valid values for TLS_DTLS_HANDSHAKE_TIMEO option */ +#define TLS_DTLS_HANDSHAKE_TIMEO_1S 1 /**< 1 second */ +#define TLS_DTLS_HANDSHAKE_TIMEO_3S 3 /**< 1s + 2s */ +#define TLS_DTLS_HANDSHAKE_TIMEO_7S 7 /**< 1s + 2s + 4s */ +#define TLS_DTLS_HANDSHAKE_TIMEO_15S 15 /**< 1s + 2s + 4s + 8s */ +#define TLS_DTLS_HANDSHAKE_TIMEO_31S 31 /**< 1s + 2s + 4s + 8s + 16s */ +#define TLS_DTLS_HANDSHAKE_TIMEO_63S 63 /**< 1s + 2s + 4s + 8s + 16s + 32s */ +#define TLS_DTLS_HANDSHAKE_TIMEO_123S 123 /**< 1s + 2s + 4s + 8s + 16s + 32s + 60s */ + +/* NCS specific socket options */ + +/** sockopt: disable all replies to unexpected traffics */ +#define SO_SILENCE_ALL 30 +/** sockopt: disable IPv4 ICMP replies */ +#define SO_IP_ECHO_REPLY 31 +/** sockopt: disable IPv6 ICMP replies */ +#define SO_IPV6_ECHO_REPLY 32 +/** sockopt: Release Assistance Indication feature: This will indicate that the + * next call to send/sendto will be the last one for some time. + */ +#define SO_RAI_LAST 50 +/** sockopt: Release Assistance Indication feature: This will indicate that the + * application will not send any more data. + */ +#define SO_RAI_NO_DATA 51 +/** sockopt: Release Assistance Indication feature: This will indicate that + * after the next call to send/sendto, the application is expecting to receive + * one more data packet before this socket will not be used again for some time. + */ +#define SO_RAI_ONE_RESP 52 +/** sockopt: Release Assistance Indication feature: If a client application + * expects to use the socket more it can indicate that by setting this socket + * option before the next send call which will keep the network up longer. + */ +#define SO_RAI_ONGOING 53 +/** sockopt: Release Assistance Indication feature: If a server application + * expects to use the socket more it can indicate that by setting this socket + * option before the next send call. + */ +#define SO_RAI_WAIT_MORE 54 +/** sockopt: Configurable TCP server session timeout in minutes. + * Range is 0 to 135. 0 is no timeout and 135 is 2 h 15 min. Default is 0 (no timeout). + */ +#define SO_TCP_SRV_SESSTIMEO 55 + +/* NCS specific gettaddrinfo() flags */ + +/** Assume `service` contains a Packet Data Network (PDN) ID. + * When specified together with the AI_NUMERICSERV flag, + * `service` shall be formatted as follows: "port:pdn_id" + * where "port" is the port number and "pdn_id" is the PDN ID. + * Example: "8080:1", port 8080 PDN ID 1. + * Example: "42:0", port 42 PDN ID 0. + */ +#define AI_PDNSERV 0x1000 + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_NET_SOCKET_NCS_H_ */ diff --git a/include/storage/flash_map.h b/include/storage/flash_map.h index dda7f78a513..08eb4fcbfa5 100644 --- a/include/storage/flash_map.h +++ b/include/storage/flash_map.h @@ -256,6 +256,10 @@ const struct device *flash_area_get_device(const struct flash_area *fa); */ uint8_t flash_area_erased_val(const struct flash_area *fa); +#if USE_PARTITION_MANAGER +#include +#else + #define FLASH_AREA_LABEL_EXISTS(label) \ DT_HAS_FIXED_PARTITION_LABEL(label) @@ -281,6 +285,9 @@ uint8_t flash_area_erased_val(const struct flash_area *fa); #define FLASH_AREA_DEVICE(label) \ DEVICE_DT_GET(DT_MTD_FROM_FIXED_PARTITION(DT_NODE_BY_FIXED_PARTITION_LABEL(label))) + +#endif /* USE_PARTITION_MANAGER */ + #ifdef __cplusplus } #endif diff --git a/lib/libc/minimal/include/strings.h b/lib/libc/minimal/include/strings.h index db7670154aa..5c930194003 100644 --- a/lib/libc/minimal/include/strings.h +++ b/lib/libc/minimal/include/strings.h @@ -9,6 +9,8 @@ #ifndef ZEPHYR_LIB_LIBC_MINIMAL_INCLUDE_STRINGS_H_ #define ZEPHYR_LIB_LIBC_MINIMAL_INCLUDE_STRINGS_H_ +#include + #ifdef __cplusplus extern "C" { #endif diff --git a/modules/hal_nordic/nrf_802154/sl_opensource/platform/nrf_802154_irq_zephyr.c b/modules/hal_nordic/nrf_802154/sl_opensource/platform/nrf_802154_irq_zephyr.c index 1a3bf443724..9341d3b61ad 100644 --- a/modules/hal_nordic/nrf_802154/sl_opensource/platform/nrf_802154_irq_zephyr.c +++ b/modules/hal_nordic/nrf_802154/sl_opensource/platform/nrf_802154_irq_zephyr.c @@ -9,9 +9,16 @@ #include #include -void nrf_802154_irq_init(uint32_t irqn, uint32_t prio, nrf_802154_isr_t isr) +void nrf_802154_irq_init(uint32_t irqn, int32_t prio, nrf_802154_isr_t isr) { - irq_connect_dynamic(irqn, prio, isr, NULL, 0); + uint32_t flags = 0U; + + if (prio < 0) { + prio = 0; + flags |= IRQ_ZERO_LATENCY; + } + + irq_connect_dynamic(irqn, prio, isr, NULL, flags); } void nrf_802154_irq_enable(uint32_t irqn) diff --git a/modules/hal_nordic/nrfx/nrfx_glue.h b/modules/hal_nordic/nrfx/nrfx_glue.h index 6fef79ab101..af29ccc2538 100644 --- a/modules/hal_nordic/nrfx/nrfx_glue.h +++ b/modules/hal_nordic/nrfx/nrfx_glue.h @@ -275,11 +275,26 @@ void nrfx_busy_wait(uint32_t usec_to_wait); #define NRFX_GPIOTE_CHANNELS_USED NRFX_GPIOTE_CHANNELS_USED_BY_BT_CTLR #if defined(CONFIG_BT_CTLR) -#include <../subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_resources.h> +#if defined(CONFIG_BT_LL_SOFTDEVICE) +#include +#if defined(PPI_PRESENT) + /* PPI channels 17 - 31, for the nRF52 Series */ + #define PPI_CHANNELS_USED_BY_CTLR (BIT_MASK(15) << 17) +#else + /* DPPI channels 0 - 13, for the nRF53 Series */ + #define PPI_CHANNELS_USED_BY_CTLR BIT_MASK(14) +#endif +#define NRFX_PPI_CHANNELS_USED_BY_BT_CTLR (PPI_CHANNELS_USED_BY_CTLR | MPSL_RESERVED_PPI_CHANNELS) +#define NRFX_PPI_GROUPS_USED_BY_BT_CTLR 0 +#define NRFX_GPIOTE_CHANNELS_USED_BY_BT_CTLR 0 +#else +#include <../subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_resources.h> #define NRFX_PPI_CHANNELS_USED_BY_BT_CTLR BT_CTLR_USED_PPI_CHANNELS #define NRFX_PPI_GROUPS_USED_BY_BT_CTLR BT_CTLR_USED_PPI_GROUPS #define NRFX_GPIOTE_CHANNELS_USED_BY_BT_CTLR BT_CTLR_USED_GPIOTE_CHANNELS +#endif + #else #define NRFX_PPI_CHANNELS_USED_BY_BT_CTLR 0 #define NRFX_PPI_GROUPS_USED_BY_BT_CTLR 0 diff --git a/modules/mbedtls/Kconfig b/modules/mbedtls/Kconfig index 32aa000f1a9..2109afe072c 100644 --- a/modules/mbedtls/Kconfig +++ b/modules/mbedtls/Kconfig @@ -13,7 +13,6 @@ config MBEDTLS_PROMPTLESS mbed TLS menu prompt and instead handle the selection of MBEDTLS from dependent sub-configurations and thus preven stuck symbol behavior. - menuconfig MBEDTLS bool "mbed TLS Support" if !MBEDTLS_PROMPTLESS help @@ -27,6 +26,7 @@ choice MBEDTLS_IMPLEMENTATION config MBEDTLS_BUILTIN bool "Use Zephyr in-tree mbedTLS version" + depends on ! DISABLE_MBEDTLS_BUILTIN help Link with mbedTLS sources included with Zephyr distribution. Included mbedTLS version is well integrated with and supported @@ -40,6 +40,11 @@ config MBEDTLS_LIBRARY endchoice +# subsystems cannot deselect MBEDTLS_BUILTIN, but they can select +# DISABLE_MBEDTLS_BUILTIN. +config DISABLE_MBEDTLS_BUILTIN + bool + config CUSTOM_MBEDTLS_CFG_FILE bool "Custom mbed TLS configuration file" help @@ -167,4 +172,7 @@ config APP_LINK_WITH_MBEDTLS disabled if the include paths for MBEDTLS are causing aliasing issues for 'app'. +# Add PSA configurations +rsource "Kconfig.psa" + endif # MBEDTLS diff --git a/modules/mbedtls/Kconfig.psa b/modules/mbedtls/Kconfig.psa new file mode 100644 index 00000000000..80e6701e17f --- /dev/null +++ b/modules/mbedtls/Kconfig.psa @@ -0,0 +1,451 @@ +# +# Copyright (c) 2022 Nordic Semiconductor +# +# SPDX-License-Identifier: Apache-2.0 +# +menu "PSA RNG support" + +config PSA_PROMPTLESS + bool + +config PSA_DEFAULT_OFF + bool + +config PSA_WANT_ALG_CTR_DRBG + bool + prompt "PSA RNG using CTR_DRBG" + help + Provide CTR_DRBG as the random number generator. + Note: This configuration is currently not described and has no effect. + +config PSA_WANT_ALG_HMAC_DRBG + bool + prompt "PSA RNG using HMAC_DRBG" + help + Provide HMAC_DRBG as the random number generator. + Note: This configuration is currently not described and has no effect. + +endmenu # RNG support + +menu "PSA Key support" + +config PSA_HAS_KEY_SUPPORT + bool + default y + depends on PSA_WANT_KEY_TYPE_DERIVE || \ + PSA_WANT_KEY_TYPE_HMAC || \ + PSA_WANT_KEY_TYPE_AES || \ + PSA_WANT_KEY_TYPE_ARIA || \ + PSA_WANT_KEY_TYPE_CAMELLIA || \ + PSA_WANT_KEY_TYPE_CHACHA20 || \ + PSA_WANT_KEY_TYPE_DES || \ + PSA_WANT_KEY_TYPE_ECC_KEY_PAIR || \ + PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY || \ + PSA_WANT_KEY_TYPE_RSA_KEY_PAIR || \ + PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY + +config PSA_WANT_KEY_TYPE_DERIVE + bool + prompt "PSA Key derivation support" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF + +config PSA_WANT_KEY_TYPE_HMAC + bool + prompt "PSA Key type HMAC support" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF + depends on PSA_HAS_MAC_SUPPORT + +config PSA_WANT_KEY_TYPE_AES + bool + prompt "PSA Key Type AES support" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF + depends on PSA_HAS_CIPHER_SUPPORT || PSA_HAS_AEAD_SUPPORT + +config PSA_WANT_KEY_TYPE_ARIA + bool + default y if !PSA_DEFAULT_OFF + help + Currently not supported + +config PSA_WANT_KEY_TYPE_CAMELLIA + bool + depends on PSA_HAS_CIPHER_SUPPORT + help + Currently not supported + +config PSA_WANT_KEY_TYPE_CHACHA20 + bool + prompt "PSA Key type Chacha20 support" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF + depends on PSA_WANT_ALG_CHACHA20_POLY1305 + +config PSA_WANT_KEY_TYPE_DES + bool + depends on PSA_HAS_CIPHER_SUPPORT + help + Currently not supported + +config PSA_WANT_KEY_TYPE_ECC_KEY_PAIR + bool + prompt "PSA Key type ECC key pair support" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF + depends on PSA_HAS_ECC_SUPPORT + +config PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY + bool + prompt "PSA Key type ECC public key support" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF + depends on PSA_HAS_ECC_SUPPORT + +config PSA_WANT_KEY_TYPE_RAW_DATA + bool + prompt "PSA Key type RAW key support" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF + +config PSA_WANT_KEY_TYPE_RSA_KEY_PAIR + bool + prompt "PSA Key type RSA key pair support" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF + depends on PSA_HAS_RSA_SUPPORT + +config PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY + bool + prompt "PSA Key type RSA Public key support" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF + depends on PSA_HAS_RSA_SUPPORT + +endmenu # PSA_KEY_DERIVATION + +menu "PSA AEAD support" + +config PSA_HAS_AEAD_SUPPORT + bool + default y + depends on PSA_WANT_ALG_CCM || \ + PSA_WANT_ALG_GCM || \ + PSA_WANT_ALG_CHACHA20_POLY1305 + +config PSA_WANT_ALG_CCM + bool + prompt "PSA AES CCM support" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF + +config PSA_WANT_ALG_GCM + bool + prompt "PSA AES GCM support" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF + +config PSA_WANT_ALG_CHACHA20_POLY1305 + bool + prompt "PSA ChaCha20/Poly1305 support" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF + +endmenu # PSA AEAD support + + +menu "PSA Mac support" + +config PSA_HAS_MAC_SUPPORT + bool + default y + depends on PSA_WANT_ALG_CBC_MAC || \ + PSA_WANT_ALG_CMAC || \ + PSA_WANT_ALG_HMAC + help + Prompt-less configuration that states the PSA APIs enables + a configuration that adds the PSA mac module. + +config PSA_WANT_ALG_CBC_MAC + bool + help + CBC-MAC is not yet supported via the PSA API in Mbed TLS. + +config PSA_WANT_ALG_CMAC + bool + prompt "PSA AES CMAC support" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF + +config PSA_WANT_ALG_HMAC + bool + prompt "PSA HMAC support" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF + +endmenu # PSA Mac support + + +menu "PSA Hash support" + +config PSA_HAS_HASH_SUPPORT + bool + default y + depends on PSA_WANT_ALG_SHA_1 || \ + PSA_WANT_ALG_SHA_224 || \ + PSA_WANT_ALG_SHA_256 || \ + PSA_WANT_ALG_SHA_384 || \ + PSA_WANT_ALG_SHA_512 || \ + PSA_WANT_ALG_RIPEMD160 || \ + PSA_WANT_ALG_MD5 + +config PSA_WANT_ALG_SHA_1 + bool + prompt "PSA SHA1 support" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF + +config PSA_WANT_ALG_SHA_224 + bool + prompt "PSA SHA-224 support" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF + +config PSA_WANT_ALG_SHA_256 + bool + prompt "PSA SSH-256 support" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF + +config PSA_WANT_ALG_SHA_384 + bool + prompt "PSA SHA-384 support" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF + +config PSA_WANT_ALG_SHA_512 + bool + prompt "PSA SHA-512 support" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF + +config PSA_WANT_ALG_RIPEMD160 + bool + prompt "PSA RIPEMD160 support" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF + +config PSA_WANT_ALG_MD5 + bool + prompt "PSA MD5 support" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF + +endmenu # PSA Hash support + +menu "PSA Cipher support" + +config PSA_HAS_CIPHER_SUPPORT + bool + default y + depends on PSA_WANT_ALG_ECB_NO_PADDING || \ + PSA_WANT_ALG_CBC_NO_PADDING || \ + PSA_WANT_ALG_CBC_PKCS7 || \ + PSA_WANT_ALG_CFB || \ + PSA_WANT_ALG_CTR || \ + PSA_WANT_ALG_OFB || \ + PSA_WANT_ALG_CTR || \ + PSA_WANT_ALG_XTS + help + Prompt-less configuration that states the PSA APIs enables + a configuration that adds the PSA Cipher module. + +config PSA_WANT_ALG_ECB_NO_PADDING + bool + prompt "PSA AES ECB (no padding)" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF + +config PSA_WANT_ALG_CBC_NO_PADDING + bool + prompt "PSA CBC support (without padding)" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF + +config PSA_WANT_ALG_CBC_PKCS7 + bool + prompt "PSA CBC support (padded with PKCS#7)" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF + +config PSA_WANT_ALG_CFB + bool + prompt "PSA AES CFB support" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF + +config PSA_WANT_ALG_CTR + bool + prompt "PSA AES CTR mode support" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF + +config PSA_WANT_ALG_OFB + bool + prompt "PSA AES OFB mode support" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF + +config PSA_WANT_ALG_XTS + bool + help + AES XTS is currently not supported + +endmenu # PSA Cipher Support + + +menu "PSA Key derivation support" + +config PSA_HAS_KEY_DERIVATION + bool + default y + depends on PSA_WANT_ALG_HKDF || \ + PSA_WANT_ALG_PBKDF2_HMAC || \ + PSA_WANT_ALG_TLS12_PRF || \ + PSA_WANT_ALG_TLS12_PSK_TO_MS + help + Prompt-less configuration that states the PSA APIs enables + a configuration that adds the PSA key derivation module. + +config PSA_WANT_ALG_HKDF + bool + prompt "PSA HKFD support" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF + depends on PSA_WANT_ALG_HMAC + +config PSA_WANT_ALG_PBKDF2_HMAC + bool + depends on PSA_WANT_ALG_HMAC + help + PBKDF2-HMAC is not yet supported via the PSA APIs in Mbed TLS. + +config PSA_WANT_ALG_TLS12_PRF + bool + prompt "PSA PRF support (TLS1.2)" if !PSA_PROMPTLESS + +config PSA_WANT_ALG_TLS12_PSK_TO_MS + bool + prompt "PSA TLS 1.2 PSK to MS support" if !PSA_PROMPTLESS + +endmenu # PSA Key derivation support + + +menu "PSA Assymetric support" + +config PSA_HAS_ASYM_ENCRYPT_SUPPORT + bool + default y + depends on PSA_WANT_ALG_RSA_OAEP || \ + PSA_WANT_ALG_RSA_PKCS1V15_CRYPT + help + Prompt-less configuration that states the PSA APIs enables + a configuration that adds the PSA Assymetric encrypt module. + + +config PSA_HAS_ASYM_SIGN_SUPPORT + bool + default y + depends on PSA_WANT_ALG_ECDSA || \ + PSA_WANT_ALG_RSA_PKCS1V15_SIGN || \ + PSA_WANT_ALG_RSA_PSS + + help + Prompt-less configuration that states the PSA APIs enables + a configuration that adds the PSA Assymetric sign module. + +config PSA_HAS_ECC_SUPPORT + bool + depends on PSA_WANT_ALG_ECDH || PSA_WANT_ALG_ECDSA || PSA_WANT_ALG_DETERMINISTIC_ECDSA + default y + help + Prompt-less configuration that states the PSA APIs enables + a configuration that adds the PSA encrypt/sign module for ECC. + +config PSA_WANT_ALG_ECDH + bool + prompt "PSA ECDH support" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF + +config PSA_WANT_ALG_ECDSA + bool + prompt "PSA ECDSA support" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF + +config PSA_WANT_ALG_DETERMINISTIC_ECDSA + bool + prompt "PSA ECDSA support (deterministic mode)" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF + +menu "Elliptic Curve type support" + depends on PSA_HAS_ECC_SUPPORT + +config PSA_WANT_ECC_BRAINPOOL_P_R1_256 + bool + prompt "PSA ECC Brainpool256r1 support" + +config PSA_WANT_ECC_BRAINPOOL_P_R1_384 + bool "PSA ECC Brainpool384r1 support" + +config PSA_WANT_ECC_BRAINPOOL_P_R1_512 + bool "PSA ECC Brainpool512r1 support" + +config PSA_WANT_ECC_MONTGOMERY_255 + bool "PSA ECC Curve25519 support" + +config PSA_WANT_ECC_MONTGOMERY_448 + bool "PSA ECC Curve448 support" + default n + +config PSA_WANT_ECC_SECP_K1_192 + bool "PSA ECC secp192k1 support" + +config PSA_WANT_ECC_SECP_K1_224 + bool + help + SECP224K1 is buggy via the PSA API in Mbed TLS + See https://github.com/ARMmbed/mbedtls/issues/3541 + +config PSA_WANT_ECC_SECP_K1_256 + bool + prompt "PSA ECC secp256k1 support" if !PSA_PROMPTLESS + +config PSA_WANT_ECC_SECP_R1_192 + bool + prompt "PSA ECC secp192r1" if !PSA_PROMPTLESS + +config PSA_WANT_ECC_SECP_R1_224 + bool + prompt "PSA ECC secp224r1" if !PSA_PROMPTLESS + +config PSA_WANT_ECC_SECP_R1_256 + bool + prompt "PSA ECC secp256r1" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF + +config PSA_WANT_ECC_SECP_R1_384 + bool + prompt "PSA ECC secp384r1" if !PSA_PROMPTLESS + +config PSA_WANT_ECC_SECP_R1_521 + bool + prompt "PSA ECC secp521r1" if !PSA_PROMPTLESS + +endmenu # Elliptic Curve type support + +config PSA_HAS_RSA_SUPPORT + bool + depends on PSA_WANT_ALG_RSA_OAEP || \ + PSA_WANT_ALG_RSA_PKCS1V15_CRYPT || \ + PSA_WANT_ALG_RSA_PKCS1V15_SIGN || \ + PSA_WANT_ALG_RSA_PSS + default y + help + Prompt-less configuration that states the PSA APIs enables + a configuration that adds the PSA encrypt/sign module for RSA. + +config PSA_WANT_ALG_RSA_OAEP + bool + prompt "PSA RSA OAEP support" if !PSA_PROMPTLESS + +config PSA_WANT_ALG_RSA_PKCS1V15_CRYPT + bool + prompt "PSA RSA crypt support (PKCS1V15 mode)" if !PSA_PROMPTLESS + +config PSA_WANT_ALG_RSA_PKCS1V15_SIGN + bool + prompt "PSA RSA signature support (PKCS1V15 mode)" if !PSA_PROMPTLESS + +config PSA_WANT_ALG_RSA_PSS + bool + prompt "PSA RSA (PSS mode)" if !PSA_PROMPTLESS + +endmenu # PSA_ASSYMETRIC_SUPPORT + +config PSA_WANT_ALG_STREAM_CIPHER + bool + prompt "PSA stream cipher support" if !PSA_PROMPTLESS + default y if !PSA_DEFAULT_OFF diff --git a/modules/mbedtls/Kconfig.tls-generic b/modules/mbedtls/Kconfig.tls-generic index 7230efbd31c..a4af8966aed 100644 --- a/modules/mbedtls/Kconfig.tls-generic +++ b/modules/mbedtls/Kconfig.tls-generic @@ -9,6 +9,14 @@ menu "TLS configuration" menu "Supported TLS version" +config NRF_SECURITY + bool + +config NORDIC_SECURITY_BACKEND + bool + +if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) + config MBEDTLS_TLS_VERSION_1_0 bool "Enable support for TLS 1.0" select MBEDTLS_CIPHER @@ -33,6 +41,8 @@ config MBEDTLS_DTLS bool "Enable support for DTLS" depends on MBEDTLS_TLS_VERSION_1_1 || MBEDTLS_TLS_VERSION_1_2 +endif + config MBEDTLS_SSL_EXPORT_KEYS bool "Enable support for exporting SSL key block and master secret" depends on MBEDTLS_TLS_VERSION_1_0 || MBEDTLS_TLS_VERSION_1_1 || MBEDTLS_TLS_VERSION_1_2 @@ -47,6 +57,8 @@ menu "Ciphersuite configuration" comment "Supported key exchange modes" +if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) + config MBEDTLS_KEY_EXCHANGE_ALL_ENABLED bool "Enable all available ciphersuite modes" select MBEDTLS_KEY_EXCHANGE_PSK_ENABLED @@ -80,6 +92,8 @@ config MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED || \ MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED +endif + config MBEDTLS_PSK_MAX_LEN int "Max size of TLS pre-shared keys" default 32 @@ -87,6 +101,8 @@ config MBEDTLS_PSK_MAX_LEN help Max size of TLS pre-shared keys, in bytes. +if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) + config MBEDTLS_KEY_EXCHANGE_RSA_ENABLED bool "Enable the RSA-only based ciphersuite modes" default y if !NET_L2_OPENTHREAD @@ -119,8 +135,12 @@ if MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED || \ MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED || \ MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED +endif + comment "Supported elliptic curves" +if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) + config MBEDTLS_ECP_ALL_ENABLED bool "Enable all available elliptic curves" select MBEDTLS_ECP_DP_SECP192R1_ENABLED @@ -182,9 +202,12 @@ config MBEDTLS_ECP_NIST_OPTIM bool "Enable NSIT curves optimization" endif +endif comment "Supported cipher modes" +if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) + config MBEDTLS_CIPHER_ALL_ENABLED bool "Enable all available ciphers" select MBEDTLS_CIPHER_AES_ENABLED @@ -248,8 +271,12 @@ config MBEDTLS_CHACHAPOLY_AEAD_ENABLED bool "Enable the ChaCha20-Poly1305 AEAD algorithm" depends on MBEDTLS_CIPHER_CHACHA20_ENABLED || MBEDTLS_MAC_POLY1305_ENABLED +endif + comment "Supported message authentication methods" +if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) + config MBEDTLS_MAC_ALL_ENABLED bool "Enable all available MAC methods" select MBEDTLS_MAC_MD4_ENABLED @@ -293,10 +320,14 @@ config MBEDTLS_MAC_CMAC_ENABLED bool "Enable the CMAC (Cipher-based Message Authentication Code) mode for block ciphers." depends on MBEDTLS_CIPHER_AES_ENABLED || MBEDTLS_CIPHER_DES_ENABLED +endif + endmenu comment "Random number generators" +if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) + config MBEDTLS_CTR_DRBG_ENABLED bool "Enable the CTR_DRBG AES-256-based random generator" depends on MBEDTLS_CIPHER_AES_ENABLED @@ -306,14 +337,20 @@ config MBEDTLS_HMAC_DRBG_ENABLED bool "Enable the HMAC_DRBG random generator" select MBEDTLS_MD +endif + comment "Other configurations" config MBEDTLS_CIPHER bool "Enable the generic cipher layer." +if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) + config MBEDTLS_MD bool "Enable the generic message digest layer." +endif + config MBEDTLS_GENPRIME_ENABLED bool "Enable the prime-number generation code." @@ -331,10 +368,14 @@ config MBEDTLS_HAVE_ASM of asymmetric cryptography, however this might have an impact on the code size. +if !(NRF_SECURITY || NORDIC_SECURITY_BACKEND) + config MBEDTLS_ENTROPY_ENABLED bool "Enable mbedTLS generic entropy pool" depends on MBEDTLS_MAC_SHA256_ENABLED || MBEDTLS_MAC_SHA512_ENABLED +endif + config MBEDTLS_OPENTHREAD_OPTIMIZATIONS_ENABLED bool "Enable mbedTLS optimizations for OpenThread" depends on NET_L2_OPENTHREAD diff --git a/modules/mbedtls/configs/config-tls-generic.h b/modules/mbedtls/configs/config-tls-generic.h index b3b2b3b1f25..f7c1def23c3 100644 --- a/modules/mbedtls/configs/config-tls-generic.h +++ b/modules/mbedtls/configs/config-tls-generic.h @@ -438,6 +438,10 @@ #include CONFIG_MBEDTLS_USER_CONFIG_FILE #endif +#if defined(CONFIG_NRF_CC3XX_PLATFORM) +#define MBEDTLS_PLATFORM_ZEROIZE_ALT +#endif + #include "mbedtls/check_config.h" #endif /* MBEDTLS_CONFIG_H */ diff --git a/modules/trusted-firmware-m/CMakeLists.txt b/modules/trusted-firmware-m/CMakeLists.txt index 6723e1b5c2b..fc38df1f0cd 100644 --- a/modules/trusted-firmware-m/CMakeLists.txt +++ b/modules/trusted-firmware-m/CMakeLists.txt @@ -241,6 +241,7 @@ if (CONFIG_BUILD_WITH_TFM) -DCROSS_COMPILE=${TFM_TOOLCHAIN_PATH}/${TFM_TOOLCHAIN_PREFIX} -DCMAKE_BUILD_TYPE=${TFM_CMAKE_BUILD_TYPE} -DTFM_PLATFORM=${CONFIG_TFM_BOARD} + -DCRYPTO_HW_ACCELERATOR=True ${TFM_CMAKE_ARGS} $> -DTFM_TEST_REPO_PATH=${ZEPHYR_TF_M_TESTS_MODULE_DIR} @@ -321,7 +322,7 @@ if (CONFIG_BUILD_WITH_TFM) ) target_include_directories(tfm_api PRIVATE - ${ZEPHYR_TRUSTED_FIRMWARE_M_MODULE_DIR}/interface/include + ${TFM_BINARY_DIR}/install/interface/include ) zephyr_library_link_libraries( diff --git a/modules/trusted-firmware-m/Kconfig.tfm b/modules/trusted-firmware-m/Kconfig.tfm index e1c30796b4c..dffb1265686 100644 --- a/modules/trusted-firmware-m/Kconfig.tfm +++ b/modules/trusted-firmware-m/Kconfig.tfm @@ -169,9 +169,12 @@ config TFM_ITS_MAX_ASSET_SIZE config TFM_BL2 bool "Add MCUboot to TFM" default y + depends on !NORDIC_SECURITY_BACKEND help TFM is designed to run with MCUboot in a certain configuration. This config adds MCUboot to the build - built via TFM's build system. + We currently do not support builds with MCUboot and TF-M if the + Nordic Security backend is used. if TFM_BL2 diff --git a/modules/trusted-firmware-m/Kconfig.tfm.crypto_modules b/modules/trusted-firmware-m/Kconfig.tfm.crypto_modules index 1b4f7e1b17a..eb33b9101bd 100644 --- a/modules/trusted-firmware-m/Kconfig.tfm.crypto_modules +++ b/modules/trusted-firmware-m/Kconfig.tfm.crypto_modules @@ -17,6 +17,7 @@ config TFM_CRYPTO_RNG_MODULE_ENABLED config TFM_CRYPTO_KEY_MODULE_ENABLED bool "KEY crypto module" default y + depends on PSA_HAS_KEY_SUPPORT && NRF_SECURITY help Enables the KEY crypto module within the crypto partition. Unset this option if the functionality provided by 'crypto_key.c' @@ -25,6 +26,7 @@ config TFM_CRYPTO_KEY_MODULE_ENABLED config TFM_CRYPTO_AEAD_MODULE_ENABLED bool "AEAD crypto module" default y + depends on PSA_HAS_AEAD_SUPPORT && NRF_SECURITY help Enables the AEAD crypto module within the crypto partition. Unset this option if the functionality provided by 'crypto_aead.c' @@ -33,6 +35,7 @@ config TFM_CRYPTO_AEAD_MODULE_ENABLED config TFM_CRYPTO_MAC_MODULE_ENABLED bool "MAC crypto module" default y + depends on PSA_HAS_MAC_SUPPORT && NRF_SECURITY help Enables the MAC crypto module within the crypto partition. Unset this option if the functionality provided by 'crypto_mac.c' @@ -41,6 +44,7 @@ config TFM_CRYPTO_MAC_MODULE_ENABLED config TFM_CRYPTO_HASH_MODULE_ENABLED bool "HASH crypto module" default y + depends on PSA_HAS_HASH_SUPPORT && NRF_SECURITY help Enables the HASH crypto module within the crypto partition. Unset this option if the functionality provided by 'crypto_hash.c' @@ -49,6 +53,7 @@ config TFM_CRYPTO_HASH_MODULE_ENABLED config TFM_CRYPTO_CIPHER_MODULE_ENABLED bool "CIPHER crypto module" default y + depends on PSA_HAS_CIPHER_SUPPORT && NRF_SECURITY help Enables the CIPHER crypto module within the crypto partition. Unset this option if the functionality provided by 'crypto_cipher.c' @@ -57,6 +62,7 @@ config TFM_CRYPTO_CIPHER_MODULE_ENABLED config TFM_CRYPTO_ASYM_ENCRYPT_MODULE_ENABLED bool "ASYM ENCRYPT crypto module" default y + depends on PSA_HAS_ASYM_ENCRYPT_SUPPORT && NRF_SECURITY help Enables the ASYM ENCRYPT crypto module within the crypto partition. Unset this option if the encrypt functionality provided by 'crypto_asymmetric.c' @@ -65,6 +71,7 @@ config TFM_CRYPTO_ASYM_ENCRYPT_MODULE_ENABLED config TFM_CRYPTO_ASYM_SIGN_MODULE_ENABLED bool "ASYM SIGN crypto module" default y + depends on PSA_HAS_ASYM_SIGN_SUPPORT && NRF_SECURITY help Enables the ASYM SIGN crypto module within the crypto partition. Unset this option if the sign functionality provided by 'crypto_asymmetric.c' @@ -73,6 +80,7 @@ config TFM_CRYPTO_ASYM_SIGN_MODULE_ENABLED config TFM_CRYPTO_KEY_DERIVATION_MODULE_ENABLED bool "KEY DERIVATION crypto module" default y + depends on PSA_HAS_KEY_DERIVATION && NRF_SECURITY help Enables the KEY_DERIVATION crypto module within the crypto partition. Unset this option if the functionality provided by 'crypto_key_derivation.c' diff --git a/samples/bluetooth/direction_finding_central/CMakeLists.txt b/samples/bluetooth/direction_finding_central/CMakeLists.txt new file mode 100644 index 00000000000..a3f5cb8d0bf --- /dev/null +++ b/samples/bluetooth/direction_finding_central/CMakeLists.txt @@ -0,0 +1,14 @@ +# +# Copyright (c) 2022 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +project(direction_finding_central) + +target_sources(app PRIVATE + src/main.c +) diff --git a/samples/bluetooth/direction_finding_central/README.rst b/samples/bluetooth/direction_finding_central/README.rst new file mode 100644 index 00000000000..7c070ec2746 --- /dev/null +++ b/samples/bluetooth/direction_finding_central/README.rst @@ -0,0 +1,73 @@ +.. _bluetooth_direction_finding_central: + +Bluetooth: Direction Finding Central +#################################### + +Overview +******** + +A simple application demonstrating the BLE Direction Finding CTE reception in +connected mode by requesting transmission of a packet containing Constant +Tone Extension by connected peer device. + +Requirements +************ + +* Nordic nRF SoC based board with Direction Finding support (example boards: + :ref:`nrf52833dk_nrf52833`, :ref:`nrf52833dk_nrf52820`, :ref:`nrf5340dk_nrf5340`) +* Antenna matrix for AoA (optional) + +Check your SoC's product specification for Direction Finding support if you are +unsure. + +Building and Running +******************** + +By default the application supports Angle of Arrival and Angle of Departure mode. + +To use Angle of Departure mode only, build this application as follows, +changing ``nrf52833dk_nrf52833`` as needed for your board: + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/direction_finding_central + :host-os: unix + :board: nrf52833dk_nrf52833 + :gen-args: -DOVERLAY_CONFIG=overlay-aod.conf + :goals: build flash + :compact: + +To run the application on nRF5340DK, a Bluetooth controller application must +also run on the network core. The :ref:`bluetooth-hci-rpmsg-sample` sample +application may be used. To build this sample with direction finding support +enabled: + +* Copy + :zephyr_file:`samples/bluetooth/direction_finding_central/boards/nrf52833dk_nrf52833.overlay` + to a new file, + :file:`samples/bluetooth/hci_rpmsg/boards/nrf5340dk_nrf5340_cpunet.overlay`. +* Copy + :zephyr_file:`samples/bluetooth/direction_finding_central/boards/nrf52833dk_nrf52833.conf` + to a new file, + :file:`samples/bluetooth/hci_rpmsg/boards/nrf5340dk_nrf5340_cpunet.conf`. + +Antenna matrix configuration +**************************** + +To use this sample with Angle of Arrival enabled on Nordic SoCs, additional +configuration must be provided via :ref:`devicetree ` to enable +control of the antenna array. + +An example devicetree overlay is in +:zephyr_file:`samples/bluetooth/direction_finding_central/boards/nrf52833dk_nrf52833.overlay`. +You can customize this overlay when building for the same board, or create your +own board-specific overlay in the same directory for a different board. See +:dtcompatible:`nordic,nrf-radio` for documentation on the properties used in +this overlay. See :ref:`set-devicetree-overlays` for information on setting up +and using overlays. + +Note that antenna matrix configuration for the nRF5340 SoC is part of the +network core application. When :ref:`bluetooth-hci-rpmsg-sample` is used as the +network core application, the antenna matrix configuration should be stored in +the file +:file:`samples/bluetooth/hci_rpmsg/boards/nrf5340dk_nrf5340_cpunet.overlay` +instead. diff --git a/samples/bluetooth/direction_finding_central/boards/nrf52833dk_nrf52820.conf b/samples/bluetooth/direction_finding_central/boards/nrf52833dk_nrf52820.conf new file mode 100644 index 00000000000..93bd2a71c6d --- /dev/null +++ b/samples/bluetooth/direction_finding_central/boards/nrf52833dk_nrf52820.conf @@ -0,0 +1,23 @@ +# +# Copyright (c) 2022 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_BT_CTLR=y +CONFIG_BT_LL_SW_SPLIT=y + +# Enable new implementation of LLCPs +CONFIG_BT_LL_SW_LLCP=y + +# Enable Direction Finding Feature including AoA and AoD +CONFIG_BT_CTLR_DF=y + +CONFIG_BT_CTLR_DF_CTE_RX=y +CONFIG_BT_CTLR_DF_CONN_CTE_RX=y +CONFIG_BT_CTLR_DF_ANT_SWITCH_RX=y +CONFIG_BT_CTLR_DF_CONN_CTE_REQ=y + +# Ensure that there is enough control prcedure contexts to queue and execute all procedures +CONFIG_BT_CTLR_LLCP_PROC_CTX_BUF_NUM=6 +CONFIG_BT_CTLR_ADVANCED_FEATURES=y diff --git a/samples/bluetooth/direction_finding_central/boards/nrf52833dk_nrf52820.overlay b/samples/bluetooth/direction_finding_central/boards/nrf52833dk_nrf52820.overlay new file mode 100644 index 00000000000..918803762e9 --- /dev/null +++ b/samples/bluetooth/direction_finding_central/boards/nrf52833dk_nrf52820.overlay @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&radio { + status = "okay"; + /* This is an example number of antennas that may be available + * on antenna matrix board. + */ + dfe-antenna-num = <10>; + /* This is an example switch pattern that will be used to set an + * antenna for Tx PDU (period before start of Tx CTE). + */ + dfe-pdu-antenna = <0x1>; + + /* These are example GPIO pin numbers that are provided to + * Radio peripheral. The pins will be acquired by Radio to + * drive antenna switching when AoD is enabled. + */ + dfegpio0-gpios = <&gpio0 1 0>; + dfegpio1-gpios = <&gpio0 2 0>; + dfegpio2-gpios = <&gpio0 3 0>; + dfegpio3-gpios = <&gpio0 4 0>; +}; diff --git a/samples/bluetooth/direction_finding_central/boards/nrf52833dk_nrf52833.conf b/samples/bluetooth/direction_finding_central/boards/nrf52833dk_nrf52833.conf new file mode 100644 index 00000000000..93bd2a71c6d --- /dev/null +++ b/samples/bluetooth/direction_finding_central/boards/nrf52833dk_nrf52833.conf @@ -0,0 +1,23 @@ +# +# Copyright (c) 2022 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_BT_CTLR=y +CONFIG_BT_LL_SW_SPLIT=y + +# Enable new implementation of LLCPs +CONFIG_BT_LL_SW_LLCP=y + +# Enable Direction Finding Feature including AoA and AoD +CONFIG_BT_CTLR_DF=y + +CONFIG_BT_CTLR_DF_CTE_RX=y +CONFIG_BT_CTLR_DF_CONN_CTE_RX=y +CONFIG_BT_CTLR_DF_ANT_SWITCH_RX=y +CONFIG_BT_CTLR_DF_CONN_CTE_REQ=y + +# Ensure that there is enough control prcedure contexts to queue and execute all procedures +CONFIG_BT_CTLR_LLCP_PROC_CTX_BUF_NUM=6 +CONFIG_BT_CTLR_ADVANCED_FEATURES=y diff --git a/samples/bluetooth/direction_finding_central/boards/nrf52833dk_nrf52833.overlay b/samples/bluetooth/direction_finding_central/boards/nrf52833dk_nrf52833.overlay new file mode 100644 index 00000000000..8df796c6bbc --- /dev/null +++ b/samples/bluetooth/direction_finding_central/boards/nrf52833dk_nrf52833.overlay @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&radio { + status = "okay"; + /* This is a number of antennas that are available on antenna matrix + * designed by Nordic. For more information see README.rst. + */ + dfe-antenna-num = <12>; + /* This is a setting that enables antenna 12 (in antenna matrix designed + * by Nordic) for Rx PDU. For more information see README.rst. + */ + dfe-pdu-antenna = <0x0>; + + /* These are GPIO pin numbers that are provided to + * Radio peripheral. The pins will be acquired by Radio to + * drive antenna switching when AoA is enabled. + * Pin numbers are selected to drive switches on antenna matrix + * desinged by Nordic. For more information see README.rst. + */ + dfegpio0-gpios = <&gpio0 3 0>; + dfegpio1-gpios = <&gpio0 4 0>; + dfegpio2-gpios = <&gpio0 28 0>; + dfegpio3-gpios = <&gpio0 29 0>; +}; diff --git a/samples/bluetooth/direction_finding_central/overlay-aod.conf b/samples/bluetooth/direction_finding_central/overlay-aod.conf new file mode 100644 index 00000000000..7a78fdf6828 --- /dev/null +++ b/samples/bluetooth/direction_finding_central/overlay-aod.conf @@ -0,0 +1,8 @@ +# +# Copyright (c) 2022 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +# Disable AoA Feature (antenna switching) in Rx mode +CONFIG_BT_CTLR_DF_ANT_SWITCH_RX=n diff --git a/samples/bluetooth/direction_finding_central/prj.conf b/samples/bluetooth/direction_finding_central/prj.conf new file mode 100644 index 00000000000..03ef424c1b8 --- /dev/null +++ b/samples/bluetooth/direction_finding_central/prj.conf @@ -0,0 +1,18 @@ +# +# Copyright (c) 2022 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_BT=y +CONFIG_BT_DEBUG_LOG=y +CONFIG_BT_DEVICE_NAME="Direction Finding Central" + +CONFIG_BT_CENTRAL=y +CONFIG_BT_SMP=y +CONFIG_BT_GATT_CLIENT=y + +# Enable Direction Finding Feature RX in connected mode +CONFIG_BT_DF=y +CONFIG_BT_DF_CONNECTION_CTE_RX=y +CONFIG_BT_DF_CONNECTION_CTE_REQ=y diff --git a/samples/bluetooth/direction_finding_central/sample.yaml b/samples/bluetooth/direction_finding_central/sample.yaml new file mode 100644 index 00000000000..dcedc108958 --- /dev/null +++ b/samples/bluetooth/direction_finding_central/sample.yaml @@ -0,0 +1,17 @@ +sample: + name: Direction Finding Central + description: Sample application showing central role of Direction Finding in connected mode +tests: + sample.bluetooth.direction_finding_connectionless_rx: + harness: bluetooth + platform_allow: nrf52833dk_nrf52833 + tags: bluetooth + integration_platforms: + - nrf52833dk_nrf52833 + sample.bluetooth.direction_finding_connectionless_rx.aod: + extra_args: OVERLAY_CONFIG="overlay-aod.conf" + harness: bluetooth + platform_allow: nrf52833dk_nrf52833 + tags: bluetooth + integration_platforms: + - nrf52833dk_nrf52833 diff --git a/samples/bluetooth/direction_finding_central/src/main.c b/samples/bluetooth/direction_finding_central/src/main.c new file mode 100644 index 00000000000..bae4b73f4cf --- /dev/null +++ b/samples/bluetooth/direction_finding_central/src/main.c @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* Latency set to zero, to enforce PDU exchange every connection event */ +#define CONN_LATENCY 0U +/* Arbitrary selected timeout value */ +#define CONN_TIMEOUT 400U +/* Inteval used to run CTE request procedure periodically. + * Value is a number of connection events. + */ +#define CTE_REQ_INTERVAL (CONN_LATENCY + 10U) +/* Length of CTE in unit of 8 us */ +#define CTE_LEN (0x14U) + +#define DF_FEAT_ENABLED BIT64(BT_LE_FEAT_BIT_CONN_CTE_RESP) + +static struct bt_conn *default_conn; +static const struct bt_le_conn_param conn_params = BT_LE_CONN_PARAM_INIT( + BT_GAP_INIT_CONN_INT_MIN, BT_GAP_INIT_CONN_INT_MAX, CONN_LATENCY, CONN_TIMEOUT); + +#if defined(CONFIG_BT_DF_CTE_RX_AOA) +static const uint8_t ant_patterns[] = { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA }; +#endif /* CONFIG_BT_DF_CTE_RX_AOA */ + +static void start_scan(void); + +static const char *cte_type2str(uint8_t type) +{ + switch (type) { + case BT_DF_CTE_TYPE_AOA: + return "AOA"; + case BT_DF_CTE_TYPE_AOD_1US: + return "AOD 1 [us]"; + case BT_DF_CTE_TYPE_AOD_2US: + return "AOD 2 [us]"; + default: + return "Unknown"; + } +} + +static const char *packet_status2str(uint8_t status) +{ + switch (status) { + case BT_DF_CTE_CRC_OK: + return "CRC OK"; + case BT_DF_CTE_CRC_ERR_CTE_BASED_TIME: + return "CRC not OK, CTE Info OK"; + case BT_DF_CTE_CRC_ERR_CTE_BASED_OTHER: + return "CRC not OK, Sampled other way"; + case BT_DF_CTE_INSUFFICIENT_RESOURCES: + return "No resources"; + default: + return "Unknown"; + } +} + +static bool eir_found(struct bt_data *data, void *user_data) +{ + bt_addr_le_t *addr = user_data; + uint64_t u64 = 0U; + int err; + + printk("[AD]: %u data_len %u\n", data->type, data->data_len); + + switch (data->type) { + case BT_DATA_LE_SUPPORTED_FEATURES: + if (data->data_len > sizeof(u64)) { + return true; + } + + (void)memcpy(&u64, data->data, data->data_len); + + u64 = sys_le64_to_cpu(u64); + + if (!(u64 & DF_FEAT_ENABLED)) { + return true; + } + + err = bt_le_scan_stop(); + if (err) { + printk("Stop LE scan failed (err %d)\n", err); + return true; + } + + err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, &conn_params, &default_conn); + if (err) { + printk("Create conn failed (err %d)\n", err); + start_scan(); + } + return false; + } + + return true; +} + +static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, + struct net_buf_simple *ad) +{ + char dev[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(addr, dev, sizeof(dev)); + printk("[DEVICE]: %s, AD evt type %u, AD data len %u, RSSI %i\n", dev, type, ad->len, rssi); + + /* We're only interested in connectable events */ + if (type == BT_GAP_ADV_TYPE_ADV_IND || type == BT_GAP_ADV_TYPE_ADV_DIRECT_IND) { + bt_data_parse(ad, eir_found, (void *)addr); + } +} + +static void enable_cte_reqest(void) +{ + int err; + + const struct bt_df_conn_cte_rx_param cte_rx_params = { +#if defined(CONFIG_BT_DF_CTE_RX_AOA) + .cte_types = BT_DF_CTE_TYPE_ALL, + .slot_durations = 0x2, + .num_ant_ids = ARRAY_SIZE(ant_patterns), + .ant_ids = ant_patterns, +#else + .cte_types = BT_DF_CTE_TYPE_AOD_1US | BT_DF_CTE_TYPE_AOD_2US, +#endif /* CONFIG_BT_DF_CTE_RX_AOA */ + }; + + const struct bt_df_conn_cte_req_params cte_req_params = { + .interval = CTE_REQ_INTERVAL, + .cte_length = CTE_LEN, +#if defined(CONFIG_BT_DF_CTE_RX_AOA) + .cte_type = BT_DF_CTE_TYPE_AOA, +#else + .cte_type = BT_DF_CTE_TYPE_AOD_2US, +#endif /* CONFIG_BT_DF_CTE_RX_AOA */ + }; + + printk("Enable receiving of CTE...\n"); + err = bt_df_conn_cte_rx_enable(default_conn, &cte_rx_params); + if (err) { + printk("failed (err %d)\n", err); + return; + } + printk("success. CTE receive enabled.\n"); + + printk("Request CTE from peer device...\n"); + err = bt_df_conn_cte_req_enable(default_conn, &cte_req_params); + if (err) { + printk("failed (err %d)\n", err); + return; + } + printk("success. CTE request enabled.\n"); +} + +static void start_scan(void) +{ + int err; + + /* Use active scanning and disable duplicate filtering to handle any + * devices that might update their advertising data at runtime. + */ + struct bt_le_scan_param scan_param = { + .type = BT_LE_SCAN_TYPE_ACTIVE, + .options = BT_LE_SCAN_OPT_NONE, + .interval = BT_GAP_SCAN_FAST_INTERVAL, + .window = BT_GAP_SCAN_FAST_WINDOW, + }; + + err = bt_le_scan_start(&scan_param, device_found); + if (err) { + printk("Scanning failed to start (err %d)\n", err); + return; + } + + printk("Scanning successfully started\n"); +} + +static void connected(struct bt_conn *conn, uint8_t conn_err) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + if (conn_err) { + printk("Failed to connect to %s (%u)\n", addr, conn_err); + + bt_conn_unref(default_conn); + default_conn = NULL; + + start_scan(); + return; + } + + printk("Connected: %s\n", addr); + + if (conn == default_conn) { + enable_cte_reqest(); + } +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + printk("Disconnected: %s (reason 0x%02x)\n", addr, reason); + + if (default_conn != conn) { + return; + } + + bt_conn_unref(default_conn); + default_conn = NULL; + + start_scan(); +} + +static void cte_recv_cb(struct bt_conn *conn, struct bt_df_conn_iq_samples_report const *report) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + if (report->err == BT_DF_IQ_REPORT_ERR_SUCCESS) { + printk("CTE[%s]: samples count %d, cte type %s, slot durations: %u [us], " + "packet status %s, RSSI %i\n", + addr, report->sample_count, cte_type2str(report->cte_type), + report->slot_durations, packet_status2str(report->packet_status), + report->rssi); + } else { + printk("CTE[%s]: request failed, err %u\n", addr, report->err); + } +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .connected = connected, + .disconnected = disconnected, + .cte_report_cb = cte_recv_cb, +}; + +void main(void) +{ + int err; + + err = bt_enable(NULL); + if (err) { + printk("Bluetooth init failed (err %d)\n", err); + return; + } + + printk("Bluetooth initialized\n"); + + start_scan(); +} diff --git a/samples/bluetooth/direction_finding_connectionless_rx/src/main.c b/samples/bluetooth/direction_finding_connectionless_rx/src/main.c index 28a00525fe7..8c5c50ca4ac 100644 --- a/samples/bluetooth/direction_finding_connectionless_rx/src/main.c +++ b/samples/bluetooth/direction_finding_connectionless_rx/src/main.c @@ -13,12 +13,20 @@ #include #include +#include #include #define DEVICE_NAME CONFIG_BT_DEVICE_NAME #define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1) #define NAME_LEN 30 -#define TIMEOUT_SYNC_CREATE K_SECONDS(10) +#define PEER_NAME_LEN_MAX 30 +/* BT Core 5.3 Vol 6, Part B section 4.4.5.1 Periodic Advertising Trains allows controller to wait + * 6 periodic advertising events for synchronization establishment, hence timeout must be longer + * than that. + */ +#define SYNC_CREATE_TIMEOUT_INTERVAL_NUM 7 +/* Maximum length of advertising data represented in hexadecimal format */ +#define ADV_DATA_HEX_STR_LEN_MAX (BT_GAP_ADV_MAX_EXT_ADV_DATA_LEN * 2 + 1) static struct bt_le_per_adv_sync_param sync_create_param; static struct bt_le_per_adv_sync *sync; @@ -26,15 +34,16 @@ static bt_addr_le_t per_addr; static bool per_adv_found; static bool scan_enabled; static uint8_t per_sid; +static uint32_t sync_create_timeout_ms; static K_SEM_DEFINE(sem_per_adv, 0, 1); static K_SEM_DEFINE(sem_per_sync, 0, 1); static K_SEM_DEFINE(sem_per_sync_lost, 0, 1); -#if defined(CONFIG_BT_CTLR_DF_ANT_SWITCH_RX) +#if defined(CONFIG_BT_DF_CTE_RX_AOA) const static uint8_t ant_patterns[] = { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA }; -#endif /* CONFIG_BT_CTLR_DF_ANT_SWITCH_RX */ +#endif /* CONFIG_BT_DF_CTE_RX_AOA */ static bool data_cb(struct bt_data *data, void *user_data); static void create_sync(void); @@ -65,6 +74,11 @@ static struct bt_le_scan_cb scan_callbacks = { .recv = scan_recv, }; +static uint32_t sync_create_timeout_get(uint16_t interval) +{ + return BT_GAP_PER_ADV_INTERVAL_TO_MS(interval) * SYNC_CREATE_TIMEOUT_INTERVAL_NUM; +} + static const char *phy2str(uint8_t phy) { switch (phy) { @@ -147,8 +161,8 @@ static void recv_cb(struct bt_le_per_adv_sync *sync, const struct bt_le_per_adv_sync_recv_info *info, struct net_buf_simple *buf) { + static char data_str[ADV_DATA_HEX_STR_LEN_MAX]; char le_addr[BT_ADDR_LE_STR_LEN]; - char data_str[129]; bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr)); bin2hex(buf->data, buf->len, data_str, sizeof(data_str)); @@ -194,6 +208,7 @@ static void scan_recv(const struct bt_le_scan_recv_info *info, info->interval, info->interval * 5 / 4, info->sid); if (!per_adv_found && info->interval != 0) { + sync_create_timeout_ms = sync_create_timeout_get(info->interval); per_adv_found = true; per_sid = info->sid; bt_addr_le_copy(&per_addr, info->addr); @@ -242,14 +257,14 @@ static void enable_cte_rx(void) const struct bt_df_per_adv_sync_cte_rx_param cte_rx_params = { .max_cte_count = 5, -#if defined(CONFIG_BT_CTLR_DF_ANT_SWITCH_RX) +#if defined(CONFIG_BT_DF_CTE_RX_AOA) .cte_types = BT_DF_CTE_TYPE_ALL, .slot_durations = 0x2, .num_ant_ids = ARRAY_SIZE(ant_patterns), .ant_ids = ant_patterns, #else .cte_types = BT_DF_CTE_TYPE_AOD_1US | BT_DF_CTE_TYPE_AOD_2US, -#endif /* CONFIG_BT_CTLR_DF_ANT_SWITCH_RX */ +#endif /* CONFIG_BT_DF_CTE_RX_AOA */ }; printk("Enable receiving of CTE...\n"); @@ -344,7 +359,7 @@ void main(void) create_sync(); printk("Waiting for periodic sync...\n"); - err = k_sem_take(&sem_per_sync, TIMEOUT_SYNC_CREATE); + err = k_sem_take(&sem_per_sync, K_MSEC(sync_create_timeout_ms)); if (err != 0) { printk("failed (err %d)\n", err); err = delete_sync(); diff --git a/samples/bluetooth/direction_finding_connectionless_tx/prj.conf b/samples/bluetooth/direction_finding_connectionless_tx/prj.conf index a006af0993f..437ffbc4334 100644 --- a/samples/bluetooth/direction_finding_connectionless_tx/prj.conf +++ b/samples/bluetooth/direction_finding_connectionless_tx/prj.conf @@ -7,3 +7,4 @@ CONFIG_BT_BROADCASTER=y # Enable Direction Finding Feature including AoA and AoD CONFIG_BT_DF=y +CONFIG_BT_DF_CONNECTIONLESS_CTE_TX=y diff --git a/samples/bluetooth/direction_finding_connectionless_tx/src/main.c b/samples/bluetooth/direction_finding_connectionless_tx/src/main.c index 0f072d08834..5545c760afc 100644 --- a/samples/bluetooth/direction_finding_connectionless_tx/src/main.c +++ b/samples/bluetooth/direction_finding_connectionless_tx/src/main.c @@ -47,13 +47,13 @@ static struct bt_le_per_adv_param per_adv_param = { .options = BT_LE_ADV_OPT_USE_TX_POWER, }; -#if defined(CONFIG_BT_CTLR_DF_ANT_SWITCH_TX) +#if defined(CONFIG_BT_DF_CTE_TX_AOD) static uint8_t ant_patterns[] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA }; -#endif /* CONFIG_BT_CTLR_DF_ANT_SWITCH_TX */ +#endif /* CONFIG_BT_DF_CTE_TX_AOD */ struct bt_df_adv_cte_tx_param cte_params = { .cte_len = CTE_LEN, .cte_count = PER_ADV_EVENT_CTE_COUNT, -#if defined(CONFIG_BT_CTLR_DF_ANT_SWITCH_TX) +#if defined(CONFIG_BT_DF_CTE_TX_AOD) .cte_type = BT_DF_CTE_TYPE_AOD_2US, .num_ant_ids = ARRAY_SIZE(ant_patterns), .ant_ids = ant_patterns @@ -61,7 +61,7 @@ struct bt_df_adv_cte_tx_param cte_params = { .cte_len = CTE_LEN, .cte_type = BT_DF_CTE_TYPE_AOA, .num_ant_ids = 0, .ant_ids = NULL -#endif /* CONFIG_BT_CTLR_DF_ANT_SWITCH_TX */ +#endif /* CONFIG_BT_DF_CTE_TX_AOD */ }; static void adv_sent_cb(struct bt_le_ext_adv *adv, diff --git a/samples/bluetooth/direction_finding_peripheral/CMakeLists.txt b/samples/bluetooth/direction_finding_peripheral/CMakeLists.txt new file mode 100644 index 00000000000..57c340187f9 --- /dev/null +++ b/samples/bluetooth/direction_finding_peripheral/CMakeLists.txt @@ -0,0 +1,14 @@ +# +# Copyright (c) 2022 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +project(direction_finding_peripheral) + +target_sources(app PRIVATE + src/main.c +) diff --git a/samples/bluetooth/direction_finding_peripheral/README.rst b/samples/bluetooth/direction_finding_peripheral/README.rst new file mode 100644 index 00000000000..1a6c58fb258 --- /dev/null +++ b/samples/bluetooth/direction_finding_peripheral/README.rst @@ -0,0 +1,72 @@ +.. _bluetooth_direction_finding_peripheral: + +Bluetooth: Direction Finding Peripheral +####################################### + +Overview +******** + +A simple application demonstrating the BLE Direction Finding CTE transmission in +connected mode by response to a request received from connected peer device. + +Requirements +************ + +* Nordic nRF SoC based board with Direction Finding support (example boards: + :ref:`nrf52833dk_nrf52833`, :ref:`nrf52833dk_nrf52820`, :ref:`nrf5340dk_nrf5340`) +* Antenna matrix for AoA (optional) + +Check your SoC's product specification for Direction Finding support if you are +unsure. + +Building and Running +******************** + +By default the application supports Angle of Arrival and Angle of Departure mode. + +To use Angle of Arrival mode only, build this application as follows, +changing ``nrf52833dk_nrf52833`` as needed for your board: + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/direction_finding_peripheral + :host-os: unix + :board: nrf52833dk_nrf52833 + :gen-args: -DOVERLAY_CONFIG=overlay-aoa.conf + :goals: build flash + :compact: + +To run the application on nRF5340DK, a Bluetooth controller application must +also run on the network core. The :ref:`bluetooth-hci-rpmsg-sample` sample +application may be used. To build this sample with direction finding support +enabled: + +* Copy + :zephyr_file:`samples/bluetooth/direction_finding_peripheral/boards/nrf52833dk_nrf52833.overlay` + to a new file, + :file:`samples/bluetooth/hci_rpmsg/boards/nrf5340dk_nrf5340_cpunet.overlay`. +* Copy + :zephyr_file:`samples/bluetooth/direction_finding_peripheral/boards/nrf52833dk_nrf52833.conf` + to a new file, + :file:`samples/bluetooth/hci_rpmsg/boards/nrf5340dk_nrf5340_cpunet.conf`. + +Antenna matrix configuration +**************************** + +To use this sample with Angle of Departure enabled on Nordic SoCs, additional +configuration must be provided via :ref:`devicetree ` to enable +control of the antenna array. + +An example devicetree overlay is in +:zephyr_file:`samples/bluetooth/direction_finding_peripheral/boards/nrf52833dk_nrf52833.overlay`. +You can customize this overlay when building for the same board, or create your +own board-specific overlay in the same directory for a different board. See +:dtcompatible:`nordic,nrf-radio` for documentation on the properties used in +this overlay. See :ref:`set-devicetree-overlays` for information on setting up +and using overlays. + +Note that antenna matrix configuration for the nRF5340 SoC is part of the +network core application. When :ref:`bluetooth-hci-rpmsg-sample` is used as the +network core application, the antenna matrix configuration should be stored in +the file +:file:`samples/bluetooth/hci_rpmsg/boards/nrf5340dk_nrf5340_cpunet.overlay` +instead. diff --git a/samples/bluetooth/direction_finding_peripheral/boards/nrf52833dk_nrf52820.conf b/samples/bluetooth/direction_finding_peripheral/boards/nrf52833dk_nrf52820.conf new file mode 100644 index 00000000000..bb4952ac87f --- /dev/null +++ b/samples/bluetooth/direction_finding_peripheral/boards/nrf52833dk_nrf52820.conf @@ -0,0 +1,23 @@ +# +# Copyright (c) 2022 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_BT_CTLR=y +CONFIG_BT_LL_SW_SPLIT=y + +# Enable new implementation of LLCPs +CONFIG_BT_LL_SW_LLCP=y + +# Enable Direction Finding Feature including AoA and AoD +CONFIG_BT_CTLR_DF=y + +CONFIG_BT_CTLR_DF_CTE_TX=y +CONFIG_BT_CTLR_DF_CONN_CTE_TX=y +CONFIG_BT_CTLR_DF_ANT_SWITCH_TX=y +CONFIG_BT_CTLR_DF_CONN_CTE_RSP=y + +# Ensure that there is enough control prcedure contexts to queue and execute all procedures +CONFIG_BT_CTLR_ADVANCED_FEATURES=y +CONFIG_BT_CTLR_LLCP_PROC_CTX_BUF_NUM=6 diff --git a/samples/bluetooth/direction_finding_peripheral/boards/nrf52833dk_nrf52820.overlay b/samples/bluetooth/direction_finding_peripheral/boards/nrf52833dk_nrf52820.overlay new file mode 100644 index 00000000000..918803762e9 --- /dev/null +++ b/samples/bluetooth/direction_finding_peripheral/boards/nrf52833dk_nrf52820.overlay @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&radio { + status = "okay"; + /* This is an example number of antennas that may be available + * on antenna matrix board. + */ + dfe-antenna-num = <10>; + /* This is an example switch pattern that will be used to set an + * antenna for Tx PDU (period before start of Tx CTE). + */ + dfe-pdu-antenna = <0x1>; + + /* These are example GPIO pin numbers that are provided to + * Radio peripheral. The pins will be acquired by Radio to + * drive antenna switching when AoD is enabled. + */ + dfegpio0-gpios = <&gpio0 1 0>; + dfegpio1-gpios = <&gpio0 2 0>; + dfegpio2-gpios = <&gpio0 3 0>; + dfegpio3-gpios = <&gpio0 4 0>; +}; diff --git a/samples/bluetooth/direction_finding_peripheral/boards/nrf52833dk_nrf52833.conf b/samples/bluetooth/direction_finding_peripheral/boards/nrf52833dk_nrf52833.conf new file mode 100644 index 00000000000..bb4952ac87f --- /dev/null +++ b/samples/bluetooth/direction_finding_peripheral/boards/nrf52833dk_nrf52833.conf @@ -0,0 +1,23 @@ +# +# Copyright (c) 2022 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_BT_CTLR=y +CONFIG_BT_LL_SW_SPLIT=y + +# Enable new implementation of LLCPs +CONFIG_BT_LL_SW_LLCP=y + +# Enable Direction Finding Feature including AoA and AoD +CONFIG_BT_CTLR_DF=y + +CONFIG_BT_CTLR_DF_CTE_TX=y +CONFIG_BT_CTLR_DF_CONN_CTE_TX=y +CONFIG_BT_CTLR_DF_ANT_SWITCH_TX=y +CONFIG_BT_CTLR_DF_CONN_CTE_RSP=y + +# Ensure that there is enough control prcedure contexts to queue and execute all procedures +CONFIG_BT_CTLR_ADVANCED_FEATURES=y +CONFIG_BT_CTLR_LLCP_PROC_CTX_BUF_NUM=6 diff --git a/samples/bluetooth/direction_finding_peripheral/boards/nrf52833dk_nrf52833.overlay b/samples/bluetooth/direction_finding_peripheral/boards/nrf52833dk_nrf52833.overlay new file mode 100644 index 00000000000..8df796c6bbc --- /dev/null +++ b/samples/bluetooth/direction_finding_peripheral/boards/nrf52833dk_nrf52833.overlay @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&radio { + status = "okay"; + /* This is a number of antennas that are available on antenna matrix + * designed by Nordic. For more information see README.rst. + */ + dfe-antenna-num = <12>; + /* This is a setting that enables antenna 12 (in antenna matrix designed + * by Nordic) for Rx PDU. For more information see README.rst. + */ + dfe-pdu-antenna = <0x0>; + + /* These are GPIO pin numbers that are provided to + * Radio peripheral. The pins will be acquired by Radio to + * drive antenna switching when AoA is enabled. + * Pin numbers are selected to drive switches on antenna matrix + * desinged by Nordic. For more information see README.rst. + */ + dfegpio0-gpios = <&gpio0 3 0>; + dfegpio1-gpios = <&gpio0 4 0>; + dfegpio2-gpios = <&gpio0 28 0>; + dfegpio3-gpios = <&gpio0 29 0>; +}; diff --git a/samples/bluetooth/direction_finding_peripheral/overlay-aoa.conf b/samples/bluetooth/direction_finding_peripheral/overlay-aoa.conf new file mode 100644 index 00000000000..d13e82d3581 --- /dev/null +++ b/samples/bluetooth/direction_finding_peripheral/overlay-aoa.conf @@ -0,0 +1,8 @@ +# +# Copyright (c) 2022 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +# Disable AoD Feature (antenna switching) in Tx mode +CONFIG_BT_CTLR_DF_ANT_SWITCH_TX=n diff --git a/samples/bluetooth/direction_finding_peripheral/prj.conf b/samples/bluetooth/direction_finding_peripheral/prj.conf new file mode 100644 index 00000000000..b94ff0a4732 --- /dev/null +++ b/samples/bluetooth/direction_finding_peripheral/prj.conf @@ -0,0 +1,18 @@ +# +# Copyright (c) 2022 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_BT=y +CONFIG_BT_DEBUG_LOG=y +CONFIG_BT_DEVICE_NAME="DF Conn App" +CONFIG_BT_SMP=y + +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_DEVICE_APPEARANCE=833 + +# Enable Direction Finding Feature RX in connected mode +CONFIG_BT_DF=y +CONFIG_BT_DF_CONNECTION_CTE_TX=y +CONFIG_BT_DF_CONNECTION_CTE_RSP=y diff --git a/samples/bluetooth/direction_finding_peripheral/sample.yaml b/samples/bluetooth/direction_finding_peripheral/sample.yaml new file mode 100644 index 00000000000..208036b8964 --- /dev/null +++ b/samples/bluetooth/direction_finding_peripheral/sample.yaml @@ -0,0 +1,17 @@ +sample: + name: Direction Finding Peripheral + description: Sample application showing peripheral role of Direction Finding in connected mode +tests: + sample.bluetooth.direction_finding_connectionless_rx: + harness: bluetooth + platform_allow: nrf52833dk_nrf52833 + tags: bluetooth + integration_platforms: + - nrf52833dk_nrf52833 + sample.bluetooth.direction_finding_connectionless_rx.aod: + extra_args: OVERLAY_CONFIG="overlay-aoa.conf" + harness: bluetooth + platform_allow: nrf52833dk_nrf52833 + tags: bluetooth + integration_platforms: + - nrf52833dk_nrf52833 diff --git a/samples/bluetooth/direction_finding_peripheral/src/main.c b/samples/bluetooth/direction_finding_peripheral/src/main.c new file mode 100644 index 00000000000..e28f9e53782 --- /dev/null +++ b/samples/bluetooth/direction_finding_peripheral/src/main.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define DF_FEAT_ENABLED BIT64(BT_LE_FEAT_BIT_CONN_CTE_RESP) + +static const struct bt_data ad[] = { + BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), + BT_DATA_BYTES(BT_DATA_LE_SUPPORTED_FEATURES, BT_LE_SUPP_FEAT_24_ENCODE(DF_FEAT_ENABLED)), +}; + +/* Latency set to zero, to enforce PDU exchange every connection event */ +#define CONN_LATENCY 0U +/* Inteval used to run CTE request procedure periodically. + * Value is a number of connection events. + */ +#define CTE_REQ_INTERVAL (CONN_LATENCY + 10U) +/* Length of CTE in unit of 8 us */ +#define CTE_LEN (0x14U) + +#if defined(CONFIG_BT_DF_CTE_TX_AOD) +static const uint8_t ant_patterns[] = { 0x2, 0x0, 0x5, 0x6, 0x1, 0x4, 0xC, 0x9, 0xE, 0xD, 0x8 }; +#endif /* CONFIG_BT_DF_CTE_TX_AOD */ + +static void enable_cte_response(struct bt_conn *conn) +{ + int err; + + const struct bt_df_conn_cte_tx_param cte_tx_params = { +#if defined(CONFIG_BT_DF_CTE_TX_AOD) + .cte_types = BT_DF_CTE_TYPE_ALL, + .num_ant_ids = ARRAY_SIZE(ant_patterns), + .ant_ids = ant_patterns, +#else + .cte_types = BT_DF_CTE_TYPE_AOA, +#endif /* CONFIG_BT_DF_CTE_TX_AOD */ + }; + + printk("Set CTE transmission params..."); + err = bt_df_set_conn_cte_tx_param(conn, &cte_tx_params); + if (err) { + printk("failed (err %d)\n", err); + return; + } + printk("success.\n"); + + printk("Set CTE response enable..."); + err = bt_df_conn_cte_rsp_enable(conn); + if (err) { + printk("failed (err %d).\n", err); + return; + } + printk("success.\n"); +} + +static void connected(struct bt_conn *conn, uint8_t err) +{ + if (err) { + printk("Connection failed (err 0x%02x)\n", err); + } else { + printk("Connected\n"); + } + + enable_cte_response(conn); +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + printk("Disconnected (reason 0x%02x)\n", reason); +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .connected = connected, + .disconnected = disconnected, +}; + +static void bt_ready(void) +{ + int err; + + printk("Bluetooth initialized\n"); + + err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + if (err) { + printk("Advertising failed to start (err %d)\n", err); + return; + } + + printk("Advertising successfully started\n"); +} + +void main(void) +{ + int err; + + err = bt_enable(NULL); + if (err) { + printk("Bluetooth init failed (err %d)\n", err); + return; + } + + bt_ready(); +} diff --git a/samples/bluetooth/hci_pwr_ctrl/child_image/hci_rpmsg.conf b/samples/bluetooth/hci_pwr_ctrl/child_image/hci_rpmsg.conf new file mode 100644 index 00000000000..e6749ae6399 --- /dev/null +++ b/samples/bluetooth/hci_pwr_ctrl/child_image/hci_rpmsg.conf @@ -0,0 +1 @@ +CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL=y diff --git a/samples/bluetooth/ipsp/README.rst b/samples/bluetooth/ipsp/README.rst index 120e885ef1d..fef4dfdefe6 100644 --- a/samples/bluetooth/ipsp/README.rst +++ b/samples/bluetooth/ipsp/README.rst @@ -38,8 +38,8 @@ Building and Running for Linux kernels released before 4.12 For hosts using kernels released before 4.12, option :kconfig:`CONFIG_NET_L2_BT_ZEP1656` - must be selected. For more information, see `Zephyr issue #3111 - `_ + must be selected. For more information, see :github:`Zephyr issue #3111 + <3111>`. .. zephyr-app-commands:: :zephyr-app: samples/bluetooth/ipsp diff --git a/samples/net/sockets/echo_server/overlay-tfm.conf b/samples/net/sockets/echo_server/overlay-tfm.conf new file mode 100644 index 00000000000..44e2ab32b70 --- /dev/null +++ b/samples/net/sockets/echo_server/overlay-tfm.conf @@ -0,0 +1,7 @@ +# Kconfig fragment for building with TF-M and nRF Security +CONFIG_BUILD_WITH_TFM=y +CONFIG_NORDIC_SECURITY_BACKEND=y +CONFIG_MBEDTLS_PSA_CRYPTO_C=y + +CONFIG_MBEDTLS_ENABLE_HEAP=y +CONFIG_MBEDTLS_HEAP_SIZE=8192 diff --git a/samples/subsys/mgmt/mcumgr/smp_svr/overlay-bt.conf b/samples/subsys/mgmt/mcumgr/smp_svr/overlay-bt.conf index 401f06fe163..3c228eb5e3b 100644 --- a/samples/subsys/mgmt/mcumgr/smp_svr/overlay-bt.conf +++ b/samples/subsys/mgmt/mcumgr/smp_svr/overlay-bt.conf @@ -5,6 +5,7 @@ CONFIG_BT_BUF_ACL_RX_SIZE=256 # Enable the Bluetooth (unauthenticated) and shell mcumgr transports. CONFIG_MCUMGR_SMP_BT=y CONFIG_MCUMGR_SMP_BT_AUTHEN=n +CONFIG_MCUMGR_SMP_BT_CONN_PARAM_CONTROL=y CONFIG_MCUMGR_SMP_SHELL=y # Enable the LittleFS file system. diff --git a/samples/tfm_integration/psa_crypto/CMakeLists.txt b/samples/tfm_integration/psa_crypto/CMakeLists.txt index b4461a027de..17339b470b8 100644 --- a/samples/tfm_integration/psa_crypto/CMakeLists.txt +++ b/samples/tfm_integration/psa_crypto/CMakeLists.txt @@ -16,7 +16,7 @@ target_sources(app PRIVATE src/util_app_log.c) target_sources(app PRIVATE src/util_sformat.c) target_include_directories(app PRIVATE - ${ZEPHYR_TRUSTED_FIRMWARE_M_MODULE_DIR}/interface/include + $/install/interface/include ) # In TF-M, default value of CRYPTO_ENGINE_BUF_SIZE is 0x2080. It causes diff --git a/samples/tfm_integration/psa_protected_storage/CMakeLists.txt b/samples/tfm_integration/psa_protected_storage/CMakeLists.txt index 40bfae3263a..bbb8a2041fd 100644 --- a/samples/tfm_integration/psa_protected_storage/CMakeLists.txt +++ b/samples/tfm_integration/psa_protected_storage/CMakeLists.txt @@ -13,5 +13,5 @@ project(protected_storage) target_sources(app PRIVATE src/main.c) target_include_directories(app PRIVATE - ${ZEPHYR_TRUSTED_FIRMWARE_M_MODULE_DIR}/interface/include + $/install/interface/include ) diff --git a/samples/tfm_integration/tfm_ipc/CMakeLists.txt b/samples/tfm_integration/tfm_ipc/CMakeLists.txt index 0ac1e79b48f..f11b67af843 100644 --- a/samples/tfm_integration/tfm_ipc/CMakeLists.txt +++ b/samples/tfm_integration/tfm_ipc/CMakeLists.txt @@ -9,5 +9,5 @@ project(tfm_ipc) target_sources(app PRIVATE src/main.c) target_include_directories(app PRIVATE - ${ZEPHYR_TRUSTED_FIRMWARE_M_MODULE_DIR}/interface/include + $/install/interface/include ) diff --git a/samples/tfm_integration/tfm_psa_test/CMakeLists.txt b/samples/tfm_integration/tfm_psa_test/CMakeLists.txt index 080bfeb0231..9dcbf12ae64 100644 --- a/samples/tfm_integration/tfm_psa_test/CMakeLists.txt +++ b/samples/tfm_integration/tfm_psa_test/CMakeLists.txt @@ -13,5 +13,5 @@ project(tfm_psa_storage_test) target_sources(app PRIVATE src/main.c) target_include_directories(app PRIVATE - ${ZEPHYR_TRUSTED_FIRMWARE_M_MODULE_DIR}/interface/include + $/install/interface/include ) diff --git a/samples/tfm_integration/tfm_secure_partition/CMakeLists.txt b/samples/tfm_integration/tfm_secure_partition/CMakeLists.txt index 636ba5f1c19..262ac042c74 100644 --- a/samples/tfm_integration/tfm_secure_partition/CMakeLists.txt +++ b/samples/tfm_integration/tfm_secure_partition/CMakeLists.txt @@ -28,7 +28,7 @@ target_sources(app PRIVATE ) target_include_directories(app PRIVATE - ${ZEPHYR_TRUSTED_FIRMWARE_M_MODULE_DIR}/interface/include + $/install/interface/include ) target_compile_definitions(app diff --git a/scripts/ci/check_compliance.py b/scripts/ci/check_compliance.py index 7ddb20044b8..2dc7f68a928 100755 --- a/scripts/ci/check_compliance.py +++ b/scripts/ci/check_compliance.py @@ -257,6 +257,13 @@ def get_modules(self, modules_file): modules = [name for name in os.listdir(modules_dir) if os.path.exists(os.path.join(modules_dir, name, 'Kconfig'))] + nrf_modules_dir = ZEPHYR_BASE + '/../nrf/modules' + nrf_modules = [] + if os.path.exists(nrf_modules_dir): + nrf_modules = [name for name in os.listdir(nrf_modules_dir) if + os.path.exists(os.path.join(nrf_modules_dir, name, + 'Kconfig'))] + with open(modules_file, 'r') as fp_module_file: content = fp_module_file.read() @@ -266,6 +273,15 @@ def get_modules(self, modules_file): re.sub('[^a-zA-Z0-9]', '_', module).upper(), modules_dir + '/' + module + '/Kconfig' )) + for module in nrf_modules: + fp_module_file.write("ZEPHYR_{}_KCONFIG = {}\n".format( + re.sub('[^a-zA-Z0-9]', '_', module).upper(), + nrf_modules_dir + '/' + module + '/Kconfig' + )) + fp_module_file.write("NCS_{}_KCONFIG = {}\n".format( + re.sub('[^a-zA-Z0-9]', '_', module).upper(), + modules_dir + '/' + module + '/Kconfig' + )) fp_module_file.write(content) def parse_kconfig(self): diff --git a/scripts/kconfig/kconfiglib.py b/scripts/kconfig/kconfiglib.py index 14142c7b742..177f1c3fff0 100644 --- a/scripts/kconfig/kconfiglib.py +++ b/scripts/kconfig/kconfiglib.py @@ -556,6 +556,16 @@ def my_other_fn(kconf, name, arg_1, arg_2, ...): VERSION = (14, 1, 0) +# Bump the recursion limit from 1k to 5k. The limit was observed to be +# broken in NCS when gen_kconfig_rest.py was executed. Specifically, +# the function expr_str would indirectly invoke itself many times. It +# appeared that the expression that was too large was one that +# contained configs from many different SoC's. Perhaps SoC's should be +# moved into Zephyr modules in the future to reduce the size of the +# Kconfig tree. Or perhaps there is another optimization that could be +# done so we don't get thousands of recursions. +sys.setrecursionlimit(5000) + # File layout: # diff --git a/scripts/pylib/twister/twisterlib.py b/scripts/pylib/twister/twisterlib.py index 2f8fd7b3c88..af6a5a035f0 100755 --- a/scripts/pylib/twister/twisterlib.py +++ b/scripts/pylib/twister/twisterlib.py @@ -2149,9 +2149,9 @@ def run_cmake(self, args=[]): cmake_args = [ f'-B{self.build_dir}', f'-S{self.source_dir}', - f'-DEXTRA_CFLAGS="{cflags}"', - f'-DEXTRA_AFLAGS="{aflags}', - f'-DEXTRA_LDFLAGS="{ldflags}"', + f'-DEXTRA_CFLAGS={cflags}', + f'-DEXTRA_AFLAGS={aflags}', + f'-DEXTRA_LDFLAGS={ldflags}', f'-DEXTRA_GEN_DEFINES_ARGS={gen_defines_args}', f'-G{self.generator}' ] @@ -2790,6 +2790,9 @@ def __init__(self, board_root_list=[], testcase_roots=[], outdir=None): # run integration tests only self.integration = False + # used during creating shorter build paths + self.link_dir_counter = 0 + self.pipeline = None self.version = "NA" @@ -3876,6 +3879,48 @@ def verify_platforms_existence(self, platform_names_to_verify, log_info=""): else: logger.error(f"{log_info} - unrecognized platform - {platform}") + def create_build_dir_links(self): + """ + Iterate through all no-skipped instances in suite and create links + for each one build directories. Those links will be passed in the next + steps to the CMake command. + """ + + links_dir_name = "twister_links" # folder for all links + links_dir_path = os.path.join(self.outdir, links_dir_name) + if not os.path.exists(links_dir_path): + os.mkdir(links_dir_path) + + for instance in self.instances.values(): + if instance.status != "skipped": + self._create_build_dir_link(links_dir_path, instance) + + def _create_build_dir_link(self, links_dir_path, instance): + """ + Create build directory with original "long" path. Next take shorter + path and link them with original path - create link. At the end + replace build_dir to created link. This link will be passed to CMake + command. This action helps to limit path length which can be + significant during building by CMake on Windows OS. + """ + + os.makedirs(instance.build_dir, exist_ok=True) + + link_name = f"test_{self.link_dir_counter}" + link_path = os.path.join(links_dir_path, link_name) + + if os.name == "nt": # if OS is Windows + command = ["mklink", "/J", f"{link_path}", f"{instance.build_dir}"] + subprocess.call(command, shell=True) + else: # for Linux and MAC OS + os.symlink(instance.build_dir, link_path) + + # Here symbolic link is replaced with original build directory. It will + # be passed to CMake command + instance.build_dir = link_path + + self.link_dir_counter += 1 + class CoverageTool: """ Base class for every supported coverage tool diff --git a/scripts/requirements-doc.txt b/scripts/requirements-doc.txt index 650f55527ce..8a518a69dd3 100644 --- a/scripts/requirements-doc.txt +++ b/scripts/requirements-doc.txt @@ -1,6 +1,6 @@ # DOC: used to generate docs -breathe>=4.30 +breathe>=4.30,<4.33 # 4.33: disabled due to #803 and #805 issues sphinx~=4.0 sphinx_rtd_theme~=1.0 sphinx-tabs diff --git a/scripts/twister b/scripts/twister index d228abcfb7a..fd4808c2930 100755 --- a/scripts/twister +++ b/scripts/twister @@ -684,6 +684,15 @@ structure in the main Zephyr tree: boards///""") help="Execute time-consuming test cases that have been marked " "as 'slow' in testcase.yaml. Normally these are only built.") + parser.add_argument( + "--short-build-path", + action="store_true", + help="Create shorter build directory paths based on symbolic links. " + "The shortened build path will be used by CMake for generating " + "the build system and executing the build. Use this option if " + "you experience build failures related to path length, for " + "example on Windows OS.") + parser.add_argument( "--show-footprint", action="store_true", help="Show footprint statistics and deltas since last release." @@ -1236,6 +1245,9 @@ def main(): logger.info("Completed in %d seconds" % (duration)) return + if options.short_build_path: + suite.create_build_dir_links() + retries = options.retry_failed + 1 completed = 0 diff --git a/soc/arm/common/cortex_m/arm_mpu_regions.c b/soc/arm/common/cortex_m/arm_mpu_regions.c index 6ba05377ba5..f1bca61ef14 100644 --- a/soc/arm/common/cortex_m/arm_mpu_regions.c +++ b/soc/arm/common/cortex_m/arm_mpu_regions.c @@ -8,6 +8,9 @@ #include #include "arm_mpu_mem_cfg.h" +#if USE_PARTITION_MANAGER +#include +#endif static const struct arm_mpu_region mpu_regions[] = { /* Region 0 */ @@ -21,6 +24,14 @@ static const struct arm_mpu_region mpu_regions[] = { #endif /* Region 1 */ MPU_REGION_ENTRY("SRAM_0", +#if USE_PARTITION_MANAGER + PM_SRAM_ADDRESS, +#if defined(CONFIG_ARMV8_M_BASELINE) || defined(CONFIG_ARMV8_M_MAINLINE) + REGION_RAM_ATTR(PM_SRAM_ADDRESS, PM_SRAM_SIZE)), +#else + REGION_RAM_ATTR(REGION_SRAM_SIZE)), +#endif +#else CONFIG_SRAM_BASE_ADDRESS, #if defined(CONFIG_ARMV8_M_BASELINE) || defined(CONFIG_ARMV8_M_MAINLINE) REGION_RAM_ATTR(CONFIG_SRAM_BASE_ADDRESS, \ @@ -28,6 +39,9 @@ static const struct arm_mpu_region mpu_regions[] = { #else REGION_RAM_ATTR(REGION_SRAM_SIZE)), #endif + +#endif /* USE_PARTITION_MANAGER */ + }; const struct arm_mpu_config mpu_config = { diff --git a/soc/arm/nordic_nrf/nrf53/CMakeLists.txt b/soc/arm/nordic_nrf/nrf53/CMakeLists.txt index c9799cf9ae6..6d99e1ce016 100644 --- a/soc/arm/nordic_nrf/nrf53/CMakeLists.txt +++ b/soc/arm/nordic_nrf/nrf53/CMakeLists.txt @@ -7,3 +7,9 @@ zephyr_sources( zephyr_library_sources_ifdef(CONFIG_PM power.c ) + +if (CONFIG_BUILD_WITH_TFM) + zephyr_library_include_directories( + $/install/interface/include + ) +endif() diff --git a/soc/arm/nordic_nrf/nrf53/Kconfig.soc b/soc/arm/nordic_nrf/nrf53/Kconfig.soc index f1a2cbf71dc..b25a037aa5c 100644 --- a/soc/arm/nordic_nrf/nrf53/Kconfig.soc +++ b/soc/arm/nordic_nrf/nrf53/Kconfig.soc @@ -146,7 +146,7 @@ config SOC_DCDC_NRF53X_HV help Enable nRF53 series System on Chip High Voltage DC/DC converter. -if !TRUSTED_EXECUTION_NONSECURE +if !TRUSTED_EXECUTION_NONSECURE || BUILD_WITH_TFM config SOC_ENABLE_LFXO bool "Enable LFXO" @@ -208,14 +208,14 @@ config SOC_HFXO_CAP_INT_VALUE_X2 capacitance value for the two capacitors. Set it to 14 to get 7.0 pF for each capacitor, 15 to get 7.5 pF, and so on. -endif # !TRUSTED_EXECUTION_NONSECURE +endif # !TRUSTED_EXECUTION_NONSECURE || BUILD_WITH_TFM endif # SOC_NRF5340_CPUAPP config NRF_ENABLE_CACHE bool "Enable cache" - depends on (SOC_NRF5340_CPUAPP && !TRUSTED_EXECUTION_NONSECURE) \ + depends on (SOC_NRF5340_CPUAPP && (!TRUSTED_EXECUTION_NONSECURE || BUILD_WITH_TFM)) \ || SOC_NRF5340_CPUNET default y help @@ -224,3 +224,7 @@ config NRF_ENABLE_CACHE Instruction cache only (I-Cache) is available in nRF5340 CPUNET (Network MCU). + +config BUILD_WITH_TFM + # TF-M nRF53 platform enables the cache unconditionally. + select NRF_ENABLE_CACHE if SOC_NRF5340_CPUAPP diff --git a/soc/arm/nordic_nrf/nrf53/soc.c b/soc/arm/nordic_nrf/nrf53/soc.c index 7fd1bc9858a..ad01036b6ed 100644 --- a/soc/arm/nordic_nrf/nrf53/soc.c +++ b/soc/arm/nordic_nrf/nrf53/soc.c @@ -26,6 +26,7 @@ #elif defined(CONFIG_SOC_NRF5340_CPUNET) #include #endif +#include #define PIN_XL1 0 #define PIN_XL2 1 @@ -57,14 +58,18 @@ static int nordicsemi_nrf53_init(const struct device *arg) key = irq_lock(); #if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(CONFIG_NRF_ENABLE_CACHE) - /* Enable the instruction & data cache */ +#if !defined(CONFIG_BUILD_WITH_TFM) + /* Enable the instruction & data cache. + * This can only be done from secure code. + * This is handled by the TF-M platform so we skip it when TF-M is + * enabled. + */ nrf_cache_enable(NRF_CACHE); +#endif #elif defined(CONFIG_SOC_NRF5340_CPUNET) && defined(CONFIG_NRF_ENABLE_CACHE) nrf_nvmc_icache_config_set(NRF_NVMC, NRF_NVMC_ICACHE_ENABLE); #endif -#if defined(CONFIG_SOC_NRF5340_CPUAPP) && \ - !defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) #if defined(CONFIG_SOC_ENABLE_LFXO) nrf_oscillators_lfxo_cap_set(NRF_OSCILLATORS, IS_ENABLED(CONFIG_SOC_LFXO_CAP_INT_6PF) ? @@ -74,13 +79,18 @@ static int nordicsemi_nrf53_init(const struct device *arg) IS_ENABLED(CONFIG_SOC_LFXO_CAP_INT_9PF) ? NRF_OSCILLATORS_LFXO_CAP_9PF : NRF_OSCILLATORS_LFXO_CAP_EXTERNAL); - /* This can only be done from secure code. */ +#if !defined(CONFIG_BUILD_WITH_TFM) + /* This can only be done from secure code. + * This is handled by the TF-M platform so we skip it when TF-M is + * enabled. + */ nrf_gpio_pin_mcu_select(PIN_XL1, NRF_GPIO_PIN_MCUSEL_PERIPHERAL); nrf_gpio_pin_mcu_select(PIN_XL2, NRF_GPIO_PIN_MCUSEL_PERIPHERAL); -#endif +#endif /* !defined(CONFIG_BUILD_WITH_TFM) */ +#endif /* defined(CONFIG_SOC_ENABLE_LFXO) */ #if defined(CONFIG_SOC_HFXO_CAP_INTERNAL) /* This register is only accessible from secure code. */ - uint32_t xosc32mtrim = NRF_FICR->XOSC32MTRIM; + uint32_t xosc32mtrim = soc_secure_read_xosc32mtrim(); /* As specified in the nRF5340 PS: * CAPVALUE = (((FICR->XOSC32MTRIM.SLOPE+56)*(CAPACITANCE*2-14)) * +((FICR->XOSC32MTRIM.OFFSET-8)<<4)+32)>>6; @@ -99,7 +109,6 @@ static int nordicsemi_nrf53_init(const struct device *arg) #elif defined(CONFIG_SOC_HFXO_CAP_EXTERNAL) nrf_oscillators_hfxo_cap_set(NRF_OSCILLATORS, false, 0); #endif -#endif /* defined(CONFIG_SOC_NRF5340_CPUAPP) && ... */ #if defined(CONFIG_SOC_DCDC_NRF53X_APP) nrf_regulators_dcdcen_set(NRF_REGULATORS, true); diff --git a/soc/arm/nordic_nrf/nrf53/soc_secure.h b/soc/arm/nordic_nrf/nrf53/soc_secure.h new file mode 100644 index 00000000000..e6d9bce235b --- /dev/null +++ b/soc/arm/nordic_nrf/nrf53/soc_secure.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2019 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include + +#if defined(CONFIG_SOC_NRF5340_CPUAPP) +#if defined(CONFIG_BUILD_WITH_TFM) +/* Use TF-M platform services */ +#include "tfm_ioctl_api.h" +#include "hal/nrf_gpio.h" + +static inline void soc_secure_gpio_pin_mcu_select(uint32_t pin_number, nrf_gpio_pin_mcusel_t mcu) +{ + uint32_t result; + enum tfm_platform_err_t err; + + err = tfm_platform_gpio_pin_mcu_select(pin_number, mcu, &result); + __ASSERT(err == TFM_PLATFORM_ERR_SUCCESS, "TFM platform error (%d)", err); + __ASSERT(result == 0, "GPIO service error (%d)", result); +} + +#if defined(CONFIG_SOC_HFXO_CAP_INTERNAL) +static inline uint32_t soc_secure_read_xosc32mtrim(void) +{ + uintptr_t ptr = (uintptr_t)&NRF_FICR_S->XOSC32MTRIM; + enum tfm_platform_err_t err; + uint32_t result; + uint32_t xosc32mtrim; + + err = tfm_platform_mem_read(&xosc32mtrim, ptr, 4, &result); + __ASSERT(err == TFM_PLATFORM_ERR_SUCCESS, "TFM platform error (%d)", err); + __ASSERT(result == 0, "Read service error (%d)", result); + + return xosc32mtrim; +} +#endif /* defined(CONFIG_SOC_HFXO_CAP_INTERNAL) */ +#else +#include +/* Do this directly from secure processing environment. */ +static inline void soc_secure_gpio_pin_mcu_select(uint32_t pin_number, nrf_gpio_pin_mcusel_t mcu) +{ + nrf_gpio_pin_mcu_select(pin_number, mcu); +} + +static inline uint32_t soc_secure_read_xosc32mtrim(void) +{ + return NRF_FICR_S->XOSC32MTRIM; +} +#endif /* defined CONFIG_BUILD_WITH_TFM */ +#endif /* defined(CONFIG_SOC_NRF5340_CPUAPP) */ diff --git a/subsys/bluetooth/Kconfig.adv b/subsys/bluetooth/Kconfig.adv index b051935db37..dac03e6aa17 100644 --- a/subsys/bluetooth/Kconfig.adv +++ b/subsys/bluetooth/Kconfig.adv @@ -15,8 +15,7 @@ config BT_LIM_ADV_TIMEOUT than 180s. config BT_EXT_ADV - bool "Extended Advertising and Scanning support [EXPERIMENTAL]" - select EXPERIMENTAL + bool "Extended Advertising and Scanning support" help Select this to enable Extended Advertising API support. This enables support for advertising with multiple advertising sets, @@ -45,8 +44,7 @@ config BT_EXT_ADV_MAX_ADV_SET supported. config BT_PER_ADV - bool "Periodic Advertising and Scanning support [EXPERIMENTAL]" - select EXPERIMENTAL + bool "Periodic Advertising and Scanning support" help Select this to enable Periodic Advertising API support. This allows the device to send advertising data periodically at deterministic @@ -54,9 +52,8 @@ config BT_PER_ADV to periodically get the data. config BT_PER_ADV_SYNC - bool "Periodic advertising sync support [EXPERIMENTAL]" + bool "Periodic advertising sync support" depends on BT_OBSERVER - select EXPERIMENTAL help Select this to enable Periodic Advertising Sync API support. Syncing with a periodic advertiser allows the device to periodically diff --git a/subsys/bluetooth/common/Kconfig b/subsys/bluetooth/common/Kconfig index 83d668efd79..aaa9362ebe3 100644 --- a/subsys/bluetooth/common/Kconfig +++ b/subsys/bluetooth/common/Kconfig @@ -109,7 +109,7 @@ config BT_BUF_ACL_RX_COUNT config BT_BUF_EVT_RX_SIZE int "Maximum supported HCI Event buffer length" - default 255 if (BT_EXT_ADV && !(BT_BUF_EVT_DISCARDABLE_COUNT > 0)) || BT_PER_ADV + default 255 if (BT_EXT_ADV && BT_OBSERVER) || BT_PER_ADV_SYNC || BT_DF_CONNECTION_CTE_RX # LE Read Supported Commands command complete event. default 68 range 68 255 @@ -136,7 +136,7 @@ config BT_BUF_EVT_DISCARDABLE_SIZE int "Maximum supported discardable HCI Event buffer length" range 43 255 # LE Extended Advertising Report event - default 255 if BT_BREDR || BT_EXT_ADV + default 255 if BT_BREDR # Le Advertising Report event default 43 help diff --git a/subsys/bluetooth/controller/Kconfig b/subsys/bluetooth/controller/Kconfig index 4dcf8d4084c..840614cd19e 100644 --- a/subsys/bluetooth/controller/Kconfig +++ b/subsys/bluetooth/controller/Kconfig @@ -100,7 +100,8 @@ choice BT_LL_CHOICE Select the Bluetooth Link Layer to compile. config BT_LL_SW_SPLIT - bool "Software-based BLE Link Layer" + bool "Software-based BLE Link Layer [EXPERIMENTAL]" + select EXPERIMENTAL select BT_RECV_IS_RX_THREAD select ENTROPY_GENERATOR select NRF_HW_TIMER0_RESERVED @@ -198,6 +199,20 @@ config BT_CTLR_RX_BUFFERS connection interval and 2M PHY, maximum 18 packets with L2CAP payload size of 1 byte can be received. +config BT_CTLR_ISO_RX_BUFFERS + int "Number of Isochronous Rx buffers" + depends on BT_CTLR_SYNC_ISO || BT_CTLR_CONN_ISO + default 8 + range 1 30 + help + Set the number of Isochronous Rx PDUs to be buffered in the + controller. Number of required RX buffers would worst-case be + the number of RX nodes prepared in one ISO event for each + active ISO group. This depends on the number of bursts in an + ISO group and number of groups, and may need to be set lower + that the theoretical maximum. Default of 8 is for supporting + two groups of 4 payloads, e.g. 2 CIGs with 2 CISes of BN=2. + config BT_CTLR_ISO_TX_BUFFERS int "Number of Isochronous Tx buffers" depends on BT_CTLR_ADV_ISO || BT_CTLR_CONN_ISO @@ -216,6 +231,10 @@ config BT_CTLR_ISO_TX_BUFFER_SIZE Size of the Isochronous Tx buffers and the value returned in HCI LE Read Buffer Size V2 command response. +config BT_CTLR_ISO_VENDOR_DATA_PATH + bool "Enable vendor-specific ISO data path" + depends on BT_CTLR_SYNC_ISO || BT_CTLR_CONN_ISO + choice BT_CTLR_TX_PWR prompt "Tx Power" default BT_CTLR_TX_PWR_0 @@ -490,6 +509,13 @@ config BT_CTLR_ADV_EXT_RX_PDU_LEN_MAX help Maximum Advertising Extensions Receive PDU Length. +config BT_CTLR_SCAN_DATA_LEN_MAX + int "Maximum Extended Scanning Data Length" + depends on BT_OBSERVER + range 31 1650 + help + Maximum Extended Scanning Data Length. + config BT_CTLR_ADV_PERIODIC bool "LE Periodic Advertising in Advertising State" if !BT_LL_SW_SPLIT depends on BT_BROADCASTER && BT_CTLR_ADV_PERIODIC_SUPPORT diff --git a/subsys/bluetooth/controller/Kconfig.df b/subsys/bluetooth/controller/Kconfig.df index 9033e634737..5dbcfaf863d 100644 --- a/subsys/bluetooth/controller/Kconfig.df +++ b/subsys/bluetooth/controller/Kconfig.df @@ -97,7 +97,7 @@ config BT_CTLR_DF_CTE_RX config BT_CTLR_DF_CONN_CTE_REQ bool "Enable Connection CTE Request feature" - depends on BT_CTLR_DF_CTE_RX && BT_CONN + depends on BT_CTLR_DF_CONN_CTE_RX help Enable support for Bluetooth v5.1 Connection CTE Request feature in controller. @@ -134,13 +134,13 @@ config BT_CTLR_DF_CONN_CTE_TX Enable transmission of Constant Tone Extension in direction finding connected mode. -config BT_CTRL_DF_CONN_CTE_RX +config BT_CTLR_DF_CONN_CTE_RX bool "Enable Connection based CTE Receiver" depends on BT_CTLR_DF_CTE_RX && BT_CONN default y help - Enable reception and sampling of Constant Tone Extension in - direction finding connected mode. + Enable reception and sampling of Constant Tone Extension in direction + finding connected mode. config BT_CTLR_DF_SAMPLE_CTE_FOR_PDU_WITH_BAD_CRC bool "Enable sampling of CTE for PDUs with bad CRC" diff --git a/subsys/bluetooth/controller/Kconfig.ll_sw_split b/subsys/bluetooth/controller/Kconfig.ll_sw_split index e762f11d28c..646a4ee2315 100644 --- a/subsys/bluetooth/controller/Kconfig.ll_sw_split +++ b/subsys/bluetooth/controller/Kconfig.ll_sw_split @@ -534,8 +534,9 @@ config BT_CTLR_LLCP_COMMON_TX_CTRL_BUF_NUM config BT_CTLR_LLCP_PROC_CTX_BUF_NUM int "Number of control procedure contexts to be available across all connections" - default BT_CTLR_LLCP_CONN - range 1 255 + default 2 if BT_CTLR_LLCP_CONN = 1 + default BT_CTLR_LLCP_CONN if BT_CTLR_LLCP_CONN > 1 + range 2 255 help Set the number control procedure contexts that is to be available. This defines the size of the pool of control procedure contexts available diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c index a8262c5a06b..d9a39760d90 100644 --- a/subsys/bluetooth/controller/hci/hci.c +++ b/subsys/bluetooth/controller/hci/hci.c @@ -190,12 +190,6 @@ static uint32_t conn_count; static uint32_t cis_pending_count; #endif -#if !defined(CONFIG_BT_HCI_RAW) && defined(CONFIG_BT_BUF_EVT_DISCARDABLE_COUNT) -#define ADV_REPORT_EVT_MAX_LEN CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE -#else -#define ADV_REPORT_EVT_MAX_LEN CONFIG_BT_BUF_EVT_RX_SIZE -#endif - /* In HCI event PHY indices start at 1 compare to 0 indexed in aux_ptr field in * the Common Extended Payload Format in the PDUs. */ @@ -2794,19 +2788,21 @@ static void le_df_connectionless_iq_report(struct pdu_data *pdu_rx, } lll = iq_report->hdr.rx_ftr.param; + sync = HDR_LLL2ULL(lll); /* TX LL thread has higher priority than RX thread. It may happen that - * host succefully disables CTE sampling in the meantime. - * It should be verified here, to avoid reporint IQ samples after - * the functionality was disabled. + * host successfully disables CTE sampling in the meantime. + * It should be verified here, to avoid reporting IQ samples after + * the functionality was disabled or if sync was lost. */ - if (ull_df_sync_cfg_is_not_enabled(&lll->df_cfg)) { - /* Dropp further processing of the event. */ + if (ull_df_sync_cfg_is_not_enabled(&lll->df_cfg) || + !sync->timeout_reload) { + /* Drop further processing of the event. */ return; } /* If there are no IQ samples due to insufficient resources - * HCI event should inform about it by store single octet with + * HCI event should inform about it by storing single octet with * special I_sample and Q_sample data. */ samples_cnt = (!iq_report->sample_count ? 1 : iq_report->sample_count); @@ -2820,8 +2816,6 @@ static void le_df_connectionless_iq_report(struct pdu_data *pdu_rx, /* Get the sync handle corresponding to the LLL context passed in the * node rx footer field. */ - sync = HDR_LLL2ULL(lll); - sep->sync_handle = sys_cpu_to_le16(ull_sync_handle_get(sync)); sep->rssi = sys_cpu_to_le16(rssi); sep->rssi_ant_id = iq_report->rssi_ant_id; @@ -2846,8 +2840,8 @@ static void le_df_connectionless_iq_report(struct pdu_data *pdu_rx, sep->sample_count = 0U; } else { for (uint8_t idx = 0U; idx < samples_cnt; ++idx) { - sep->sample[idx].i = IQ_SHIFT_12_TO_8_BIT(iq_report->sample[idx].i); - sep->sample[idx].q = IQ_SHIFT_12_TO_8_BIT(iq_report->sample[idx].q); + sep->sample[idx].i = IQ_CONVERT_12_TO_8_BIT(iq_report->sample[idx].i); + sep->sample[idx].q = IQ_CONVERT_12_TO_8_BIT(iq_report->sample[idx].q); } sep->sample_count = samples_cnt; @@ -2878,7 +2872,7 @@ static void le_df_set_conn_cte_tx_params(struct net_buf *buf, } #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_TX */ -#if defined(CONFIG_BT_CTRL_DF_CONN_CTE_RX) +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) static void le_df_set_conn_cte_rx_params(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_le_set_conn_cte_rx_params *cmd = (void *)buf->data; @@ -2916,9 +2910,14 @@ static void le_df_connection_iq_report(struct node_rx_pdu *node_rx, struct net_b lll = iq_report->hdr.rx_ftr.param; +#if defined(CONFIG_BT_CTLR_PHY) phy_rx = lll->phy_rx; + /* Make sure the report is generated for connection on PHY UNCODED */ LL_ASSERT(phy_rx != PHY_CODED); +#else + phy_rx = PHY_1M; +#endif /* CONFIG_BT_CTLR_PHY */ /* TX LL thread has higher priority than RX thread. It may happen that host succefully * disables CTE sampling in the meantime. It should be verified here, to avoid reporing @@ -2964,13 +2963,13 @@ static void le_df_connection_iq_report(struct node_rx_pdu *node_rx, struct net_b sep->sample_count = 0U; } else { for (uint8_t idx = 0U; idx < samples_cnt; ++idx) { - sep->sample[idx].i = IQ_SHIFT_12_TO_8_BIT(iq_report->sample[idx].i); - sep->sample[idx].q = IQ_SHIFT_12_TO_8_BIT(iq_report->sample[idx].q); + sep->sample[idx].i = IQ_CONVERT_12_TO_8_BIT(iq_report->sample[idx].i); + sep->sample[idx].q = IQ_CONVERT_12_TO_8_BIT(iq_report->sample[idx].q); } sep->sample_count = samples_cnt; } } -#endif /* CONFIG_BT_CTRL_DF_CONN_CTE_RX */ +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */ #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) static void le_df_set_conn_cte_req_enable(struct net_buf *buf, struct net_buf **evt) @@ -2983,13 +2982,48 @@ static void le_df_set_conn_cte_req_enable(struct net_buf *buf, struct net_buf ** handle_le16 = cmd->handle; handle = sys_le16_to_cpu(handle_le16); - status = ll_df_set_conn_cte_req_enable(handle, cmd->enable, cmd->cte_request_interval, + status = ll_df_set_conn_cte_req_enable(handle, cmd->enable, + sys_le16_to_cpu(cmd->cte_request_interval), cmd->requested_cte_length, cmd->requested_cte_type); rp = hci_cmd_complete(evt, sizeof(*rp)); rp->status = status; rp->handle = handle_le16; } + +static void le_df_cte_req_failed(uint8_t error_code, uint16_t handle, struct net_buf *buf) +{ + struct bt_hci_evt_le_cte_req_failed *sep; + + if (!(event_mask & BT_EVT_MASK_LE_META_EVENT) || + !(le_event_mask & BT_EVT_MASK_LE_CTE_REQUEST_FAILED)) { + return; + } + + sep = meta_evt(buf, BT_HCI_EVT_LE_CTE_REQUEST_FAILED, sizeof(*sep)); + + sep->status = error_code; + sep->conn_handle = sys_cpu_to_le16(handle); +} +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ + +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) +static void le_df_set_conn_cte_rsp_enable(struct net_buf *buf, struct net_buf **evt) +{ + struct bt_hci_cp_le_conn_cte_rsp_enable *cmd = (void *)buf->data; + struct bt_hci_rp_le_conn_cte_rsp_enable *rp; + uint16_t handle, handle_le16; + uint8_t status; + + handle_le16 = cmd->handle; + handle = sys_le16_to_cpu(handle_le16); + + status = ll_df_set_conn_cte_rsp_enable(handle, cmd->enable); + rp = hci_cmd_complete(evt, sizeof(*rp)); + + rp->status = status; + rp->handle = handle_le16; +} #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */ static void le_df_read_ant_inf(struct net_buf *buf, struct net_buf **evt) @@ -4336,16 +4370,21 @@ static int controller_cmd_handle(uint16_t ocf, struct net_buf *cmd, le_df_set_conn_cte_tx_params(cmd, evt); break; #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_TX */ -#if defined(CONFIG_BT_CTRL_DF_CONN_CTE_RX) +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) case BT_OCF(BT_HCI_OP_LE_SET_CONN_CTE_RX_PARAMS): le_df_set_conn_cte_rx_params(cmd, evt); break; -#endif /* CONFIG_BT_CTRL_DF_CONN_CTE_RX */ +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */ #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) case BT_OCF(BT_HCI_OP_LE_CONN_CTE_REQ_ENABLE): le_df_set_conn_cte_req_enable(cmd, evt); break; #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) + case BT_OCF(BT_HCI_OP_LE_CONN_CTE_RSP_ENABLE): + le_df_set_conn_cte_rsp_enable(cmd, evt); + break; +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */ #endif /* CONFIG_BT_CTLR_DF */ #if defined(CONFIG_BT_CTLR_DTM_HCI) @@ -5701,6 +5740,7 @@ static void ext_adv_pdu_frag(uint8_t evt_type, uint8_t phy, uint8_t sec_phy, const uint8_t data_len_frag = MIN(*data_len, data_len_max); do { + /* Prepare a fragment of PDU data in a HCI event */ ext_adv_info_fill(evt_type, phy, sec_phy, adv_addr_type, adv_addr, direct_addr_type, direct_addr, rl_idx, tx_pwr, rssi, interval_le16, adi, @@ -5712,6 +5752,10 @@ static void ext_adv_pdu_frag(uint8_t evt_type, uint8_t phy, uint8_t sec_phy, *evt_buf = bt_buf_get_rx(BT_BUF_EVT, K_FOREVER); net_buf_frag_add(buf, *evt_buf); + + /* Continue to fragment until last partial PDU data fragment, + * remainder PDU data's HCI event will be prepare by caller. + */ } while (*data_len > data_len_max); } @@ -5731,15 +5775,24 @@ static void ext_adv_data_frag(const struct node_rx_pdu *node_rx_data, evt_type |= (BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_PARTIAL << 5); do { + /* Fragment the PDU data */ ext_adv_pdu_frag(evt_type, phy, *sec_phy, adv_addr_type, adv_addr, direct_addr_type, direct_addr, rl_idx, tx_pwr, rssi, interval_le16, adi, data_len_max, &data_len_total, data_len, data, buf, evt_buf); + /* Check if more PDUs in the list */ node_rx_data = node_rx_data->hdr.rx_ftr.extra; if (node_rx_data) { - if (*data_len) { + if (*data_len >= data_len_total) { + /* Last fragment restricted to maximum scan + * data length, caller will prepare the last + * HCI fragment event. + */ + break; + } else if (*data_len) { + /* Last fragment of current PDU data */ ext_adv_pdu_frag(evt_type, phy, *sec_phy, adv_addr_type, adv_addr, direct_addr_type, direct_addr, @@ -5749,9 +5802,20 @@ static void ext_adv_data_frag(const struct node_rx_pdu *node_rx_data, data_len, data, buf, evt_buf); } + /* Get next PDU data in list */ *data_len = ext_adv_data_get(node_rx_data, sec_phy, data); + + /* Restrict PDU data to maximum scan data length */ + if (*data_len > data_len_total) { + *data_len = data_len_total; + } } + + /* Continue to fragment if current PDU data length less than + * total data length or current PDU data length greater than + * HCI event max length. + */ } while ((*data_len < data_len_total) || (*data_len > data_len_max)); } @@ -6099,6 +6163,16 @@ static void le_ext_adv_report(struct pdu_data *pdu_data, } } + /* Restrict data length to maximum scan data length */ + if (data_len_total > CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX) { + data_len_total = CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX; + if (data_len > data_len_total) { + data_len = data_len_total; + } + + data_status = BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_INCOMPLETE; + } + /* Set directed advertising bit */ if (direct_addr) { evt_type |= BT_HCI_LE_ADV_EVT_TYPE_DIRECT; @@ -6106,11 +6180,14 @@ static void le_ext_adv_report(struct pdu_data *pdu_data, /* HCI fragment */ evt_buf = buf; - data_len_max = ADV_REPORT_EVT_MAX_LEN - + data_len_max = CONFIG_BT_BUF_EVT_RX_SIZE - sizeof(struct bt_hci_evt_le_meta_event) - sizeof(struct bt_hci_evt_le_ext_advertising_report) - sizeof(struct bt_hci_evt_le_ext_advertising_info); + /* If PDU data length less than total data length or PDU data length + * greater than maximum HCI event data length, then fragment. + */ if ((data_len < data_len_total) || (data_len > data_len_max)) { ext_adv_data_frag(node_rx_data, evt_type, phy, &sec_phy, adv_addr_type, adv_addr, direct_addr_type, @@ -6123,7 +6200,7 @@ static void le_ext_adv_report(struct pdu_data *pdu_data, /* Set data status bits */ evt_type |= (data_status << 5); - /* Start constructing the adv event */ + /* Start constructing the adv event for remainder of the PDU data */ ext_adv_info_fill(evt_type, phy, sec_phy, adv_addr_type, adv_addr, direct_addr_type, direct_addr, rl_idx, tx_pwr, rssi, interval_le16, adi, data_len, data, evt_buf); @@ -6135,6 +6212,16 @@ static void le_ext_adv_report(struct pdu_data *pdu_data, return; } + /* Restrict scan response data length to maximum scan data length */ + if (scan_data_len_total > CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX) { + scan_data_len_total = CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX; + if (scan_data_len > scan_data_len_total) { + scan_data_len = scan_data_len_total; + } + + scan_data_status = BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_INCOMPLETE; + } + /* Set scan response bit */ evt_type |= BT_HCI_LE_ADV_EVT_TYPE_SCAN_RSP; @@ -6147,6 +6234,9 @@ static void le_ext_adv_report(struct pdu_data *pdu_data, evt_buf = bt_buf_get_rx(BT_BUF_EVT, K_FOREVER); net_buf_frag_add(buf, evt_buf); + /* If PDU data length less than total data length or PDU data length + * greater than maximum HCI event data length, then fragment. + */ if ((scan_data_len < scan_data_len_total) || (scan_data_len > data_len_max)) { ext_adv_data_frag(node_rx_scan_data, evt_type, phy, @@ -6160,7 +6250,7 @@ static void le_ext_adv_report(struct pdu_data *pdu_data, /* set scan data status bits */ evt_type |= (scan_data_status << 5); - /* Start constructing the event */ + /* Start constructing the event for remainder of the PDU data */ ext_adv_info_fill(evt_type, phy, sec_phy_scan, adv_addr_type, adv_addr, direct_addr_type, direct_addr, rl_idx, tx_pwr, rssi, interval_le16, adi, scan_data_len, scan_data, @@ -6247,17 +6337,17 @@ static void le_per_adv_sync_established(struct pdu_data *pdu_data, scan = node_rx->hdr.rx_ftr.param; - dup_periodic_adv_reset(scan->per_scan.adv_addr_type, - scan->per_scan.adv_addr, - scan->per_scan.sid); + dup_periodic_adv_reset(scan->periodic.adv_addr_type, + scan->periodic.adv_addr, + scan->periodic.sid); sep->handle = sys_cpu_to_le16(node_rx->hdr.handle); /* Resolved address, if private, has been populated in ULL */ - sep->adv_addr.type = scan->per_scan.adv_addr_type; - memcpy(&sep->adv_addr.a.val[0], scan->per_scan.adv_addr, BDADDR_SIZE); + sep->adv_addr.type = scan->periodic.adv_addr_type; + (void)memcpy(sep->adv_addr.a.val, scan->periodic.adv_addr, BDADDR_SIZE); - sep->sid = scan->per_scan.sid; + sep->sid = scan->periodic.sid; sep->phy = find_lsb_set(se->phy); sep->interval = sys_cpu_to_le16(se->interval); sep->clock_accuracy = se->sca; @@ -6275,7 +6365,7 @@ static void le_per_adv_sync_report(struct pdu_data *pdu_data, uint8_t cte_type = BT_HCI_LE_NO_CTE; struct pdu_adv_com_ext_adv *p; struct pdu_adv_ext_hdr *h; - uint8_t data_status = 0U; + uint16_t data_len_total; struct net_buf *evt_buf; uint8_t data_len = 0U; uint8_t acad_len = 0U; @@ -6439,16 +6529,23 @@ static void le_per_adv_sync_report(struct pdu_data *pdu_data, accept = ftr->sync_rx_enabled; } - data_len_max = ADV_REPORT_EVT_MAX_LEN - + data_len_max = CONFIG_BT_BUF_EVT_RX_SIZE - sizeof(struct bt_hci_evt_le_meta_event) - sizeof(struct bt_hci_evt_le_per_advertising_report); + data_len_total = node_rx->hdr.rx_ftr.aux_data_len; evt_buf = buf; - if ((le_event_mask & BT_EVT_MASK_LE_PER_ADVERTISING_REPORT) && accept) { + if ((le_event_mask & BT_EVT_MASK_LE_PER_ADVERTISING_REPORT) && accept && + ((data_len_total - data_len) < CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX)) { + + data_len = MIN(data_len, (CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX + + data_len - data_len_total)); + do { struct bt_hci_evt_le_per_advertising_report *sep; uint8_t data_len_frag; + uint8_t data_status; data_len_frag = MIN(data_len, data_len_max); @@ -6457,17 +6554,30 @@ static void le_per_adv_sync_report(struct pdu_data *pdu_data, BT_HCI_EVT_LE_PER_ADVERTISING_REPORT, sizeof(*sep) + data_len_frag); + sep->handle = sys_cpu_to_le16(node_rx->hdr.handle); + sep->tx_power = tx_pwr; + sep->rssi = rssi; + sep->cte_type = cte_type; + sep->length = data_len_frag; memcpy(&sep->data[0], data, data_len_frag); + data += data_len_frag; data_len -= data_len_frag; if (data_len > 0) { /* Some data left in PDU, mark as partial data. */ data_status = BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_PARTIAL; - } else if (!aux_ptr) { + + evt_buf = bt_buf_get_rx(BT_BUF_EVT, K_FOREVER); + net_buf_frag_add(buf, evt_buf); + + tx_pwr = BT_HCI_LE_ADV_TX_POWER_NO_PREF; + } else if (!aux_ptr && + (data_len_total <= CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX)) { /* No data left, no AuxPtr, mark as complete data. */ data_status = BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_COMPLETE; - } else if (ftr->aux_w4next) { + } else if (ftr->aux_sched && + (data_len_total < CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX)) { /* No data left, but have AuxPtr and scheduled aux scan, * mark as partial data. */ @@ -6479,22 +6589,7 @@ static void le_per_adv_sync_report(struct pdu_data *pdu_data, data_status = BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_INCOMPLETE; } - sep->handle = sys_cpu_to_le16(node_rx->hdr.handle); - /* TODO: use actual TX power only on 1st report, subsequent - * reports can use 0x7F - */ - sep->tx_power = tx_pwr; - sep->rssi = rssi; - sep->cte_type = cte_type; sep->data_status = data_status; - sep->length = data_len_frag; - - if (data_len > 0) { - evt_buf = bt_buf_get_rx(BT_BUF_EVT, K_FOREVER); - net_buf_frag_add(buf, evt_buf); - - tx_pwr = BT_HCI_LE_ADV_TX_POWER_NO_PREF; - } } while (data_len > 0); evt_buf = NULL; @@ -7193,11 +7288,11 @@ static void encode_control(struct node_rx_pdu *node_rx, return; #endif /* CONFIG_BT_CTLR_CONN_ISO */ -#if defined(CONFIG_BT_CTRL_DF_CONN_CTE_RX) +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) case NODE_RX_TYPE_CONN_IQ_SAMPLE_REPORT: le_df_connection_iq_report(node_rx, buf); return; -#endif /* CONFIG_BT_CTRL_DF_CONN_CTE_RX */ +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */ #endif /* CONFIG_BT_CONN */ #if defined(CONFIG_BT_CTLR_ADV_INDICATION) @@ -7325,6 +7420,19 @@ static void le_unknown_rsp(struct pdu_data *pdu_data, uint16_t handle, } } +static void le_reject_ext_ind(struct pdu_data *pdu, uint16_t handle, struct net_buf *buf) +{ + switch (pdu->llctrl.reject_ext_ind.reject_opcode) { +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) + case PDU_DATA_LLCTRL_TYPE_CTE_REQ: + le_df_cte_req_failed(pdu->llctrl.reject_ext_ind.error_code, handle, buf); + break; +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ + default: + BT_WARN("reject opcode: 0x%02x", pdu->llctrl.reject_ext_ind.reject_opcode); + break; + } +} #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ) static void le_conn_param_req(struct pdu_data *pdu_data, uint16_t handle, struct net_buf *buf) @@ -7441,10 +7549,20 @@ static void encode_data_ctrl(struct node_rx_pdu *node_rx, break; #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) + case PDU_DATA_LLCTRL_TYPE_CTE_REQ: + le_df_cte_req_failed(BT_HCI_CTE_REQ_STATUS_RSP_WITHOUT_CTE, handle, buf); + break; +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ + case PDU_DATA_LLCTRL_TYPE_UNKNOWN_RSP: le_unknown_rsp(pdu_data, handle, buf); break; + case PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND: + le_reject_ext_ind(pdu_data, handle, buf); + break; + default: LL_ASSERT(0); return; @@ -7544,13 +7662,6 @@ uint8_t hci_get_class(struct node_rx_pdu *node_rx) defined(CONFIG_BT_CTLR_PROFILE_ISR) #if defined(CONFIG_BT_OBSERVER) case NODE_RX_TYPE_REPORT: - -#if defined(CONFIG_BT_CTLR_ADV_EXT) - __fallthrough; - case NODE_RX_TYPE_EXT_1M_REPORT: - case NODE_RX_TYPE_EXT_2M_REPORT: - case NODE_RX_TYPE_EXT_CODED_REPORT: -#endif /* CONFIG_BT_CTLR_ADV_EXT */ #endif /* CONFIG_BT_OBSERVER */ #if defined(CONFIG_BT_CTLR_SCAN_REQ_NOTIFY) @@ -7579,6 +7690,7 @@ uint8_t hci_get_class(struct node_rx_pdu *node_rx) #if defined(CONFIG_BT_CTLR_ADV_EXT) #if defined(CONFIG_BT_BROADCASTER) case NODE_RX_TYPE_EXT_ADV_TERMINATE: + #if defined(CONFIG_BT_CTLR_ADV_ISO) case NODE_RX_TYPE_BIG_COMPLETE: case NODE_RX_TYPE_BIG_TERMINATE: @@ -7586,11 +7698,12 @@ uint8_t hci_get_class(struct node_rx_pdu *node_rx) #endif /* CONFIG_BT_BROADCASTER */ #if defined(CONFIG_BT_OBSERVER) - __fallthrough; + case NODE_RX_TYPE_EXT_1M_REPORT: + case NODE_RX_TYPE_EXT_2M_REPORT: + case NODE_RX_TYPE_EXT_CODED_REPORT: case NODE_RX_TYPE_EXT_SCAN_TERMINATE: #if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) - __fallthrough; case NODE_RX_TYPE_SYNC: case NODE_RX_TYPE_SYNC_REPORT: case NODE_RX_TYPE_SYNC_LOST: @@ -7600,7 +7713,6 @@ uint8_t hci_get_class(struct node_rx_pdu *node_rx) #endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX */ #if defined(CONFIG_BT_CTLR_SYNC_ISO) - __fallthrough; case NODE_RX_TYPE_SYNC_ISO: case NODE_RX_TYPE_SYNC_ISO_LOST: #endif /* CONFIG_BT_CTLR_SYNC_ISO */ @@ -7620,9 +7732,11 @@ uint8_t hci_get_class(struct node_rx_pdu *node_rx) #if defined(CONFIG_BT_CTLR_CONN_ISO) case NODE_RX_TYPE_CIS_ESTABLISHED: #endif /* CONFIG_BT_CTLR_CONN_ISO */ -#if defined(CONFIG_BT_CTRL_DF_CONN_CTE_RX) + +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) case NODE_RX_TYPE_CONN_IQ_SAMPLE_REPORT: -#endif /* CONFIG_BT_CTRL_DF_CONN_CTE_RX */ +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */ + return HCI_CLASS_EVT_REQUIRED; case NODE_RX_TYPE_TERMINATE: @@ -7635,17 +7749,22 @@ uint8_t hci_get_class(struct node_rx_pdu *node_rx) #if defined(CONFIG_BT_CTLR_CONN_RSSI_EVENT) case NODE_RX_TYPE_RSSI: #endif /* CONFIG_BT_CTLR_CONN_RSSI_EVENT */ + #if defined(CONFIG_BT_CTLR_LE_PING) case NODE_RX_TYPE_APTO: #endif /* CONFIG_BT_CTLR_LE_PING */ + #if defined(CONFIG_BT_CTLR_CHAN_SEL_2) case NODE_RX_TYPE_CHAN_SEL_ALGO: #endif /* CONFIG_BT_CTLR_CHAN_SEL_2 */ + #if defined(CONFIG_BT_CTLR_PHY) case NODE_RX_TYPE_PHY_UPDATE: #endif /* CONFIG_BT_CTLR_PHY */ + return HCI_CLASS_EVT_CONNECTION; #endif /* CONFIG_BT_CONN */ + #if defined(CONFIG_BT_CTLR_SYNC_ISO) || defined(CONFIG_BT_CTLR_CONN_ISO) case NODE_RX_TYPE_ISO_PDU: return HCI_CLASS_ISO_DATA; diff --git a/subsys/bluetooth/controller/hci/hci_driver.c b/subsys/bluetooth/controller/hci/hci_driver.c index 149ba8515af..495030b69ba 100644 --- a/subsys/bluetooth/controller/hci/hci_driver.c +++ b/subsys/bluetooth/controller/hci/hci_driver.c @@ -49,7 +49,6 @@ #include "ll_sw/lll_sync_iso.h" #include "ll_sw/lll_conn.h" #include "ll_sw/lll_conn_iso.h" - #include "ll_sw/isoal.h" #include "ll_sw/ull_iso_types.h" @@ -229,9 +228,30 @@ static void prio_recv_thread(void *p1, void *p2, void *p3) while (1) { struct node_rx_pdu *node_rx; struct net_buf *buf; + bool iso_received; uint8_t num_cmplt; uint16_t handle; + iso_received = false; + +#if defined(CONFIG_BT_CTLR_ISO) + node_rx = ll_iso_rx_get(); + if (node_rx) { + ll_iso_rx_dequeue(); + + /* Find out and store the class for this node */ + node_rx->hdr.user_meta = hci_get_class(node_rx); + + /* Send the rx node up to Host thread, + * recv_thread() + */ + BT_DBG("ISO RX node enqueue"); + k_fifo_put(&recv_fifo, node_rx); + + iso_received = true; + } +#endif /* CONFIG_BT_CTLR_ISO */ + /* While there are completed rx nodes */ while ((num_cmplt = ll_rx_get((void *)&node_rx, &handle))) { #if defined(CONFIG_BT_CONN) @@ -280,13 +300,14 @@ static void prio_recv_thread(void *p1, void *p2, void *p3) BT_DBG("RX node enqueue"); k_fifo_put(&recv_fifo, node_rx); } + } + if (iso_received || node_rx) { /* There may still be completed nodes, continue * pushing all those up to Host before waiting * for ULL mayfly */ continue; - } BT_DBG("sem take..."); @@ -364,13 +385,24 @@ static inline struct net_buf *encode_node(struct node_rx_pdu *node_rx, isoal_status_t err; stream = ull_sync_iso_stream_get(node_rx->hdr.handle); - isoal_rx.meta = &node_rx->hdr.rx_iso_meta; - isoal_rx.pdu = (void *)node_rx->pdu; - err = isoal_rx_pdu_recombine(stream->dp->sink_hdl, &isoal_rx); - LL_ASSERT(err == ISOAL_STATUS_OK || - err == ISOAL_STATUS_ERR_SDU_ALLOC); + + /* Check validity of the data path sink. FIXME: A channel disconnect race + * may cause ISO data pending without valid data path. + */ + if (stream && stream->dp) { + isoal_rx.meta = &node_rx->hdr.rx_iso_meta; + isoal_rx.pdu = (void *)node_rx->pdu; + err = isoal_rx_pdu_recombine(stream->dp->sink_hdl, &isoal_rx); + + LL_ASSERT(err == ISOAL_STATUS_OK || + err == ISOAL_STATUS_ERR_SDU_ALLOC); + } #endif /* CONFIG_BT_CTLR_SYNC_ISO */ - break; + + node_rx->hdr.next = NULL; + ll_iso_rx_mem_release((void **)&node_rx); + + return buf; } #endif /* CONFIG_BT_CTLR_ISO */ diff --git a/subsys/bluetooth/controller/include/ll.h b/subsys/bluetooth/controller/include/ll.h index 36baeb2b987..d31e050c200 100644 --- a/subsys/bluetooth/controller/include/ll.h +++ b/subsys/bluetooth/controller/include/ll.h @@ -303,8 +303,11 @@ uint8_t ll_df_set_conn_cte_rx_params(uint16_t handle, uint8_t sampling_enable, uint8_t slot_durations, uint8_t switch_pattern_len, const uint8_t *ant_ids); /* Enables or disables CTE request control procedure in direction fingin connected mode. */ -uint8_t ll_df_set_conn_cte_req_enable(uint16_t handle, uint8_t enable, uint8_t cte_request_interval, - uint8_t requested_cte_length, uint8_t requested_cte_type); +uint8_t ll_df_set_conn_cte_req_enable(uint16_t handle, uint8_t enable, + uint16_t cte_request_interval, uint8_t requested_cte_length, + uint8_t requested_cte_type); +/* Enables or disables CTE response control procedure in direction fingin connected mode. */ +uint8_t ll_df_set_conn_cte_rsp_enable(uint16_t handle, uint8_t enable); /* Enables or disables CTE sampling in periodic advertising scan */ uint8_t ll_df_set_cl_iq_sampling_enable(uint16_t handle, uint8_t sampling_enable, @@ -327,6 +330,7 @@ int ll_tx_mem_enqueue(uint16_t handle, void *node_tx); uint8_t ll_rx_get(void **node_rx, uint16_t *handle); void ll_rx_dequeue(void); void ll_rx_mem_release(void **node_rx); +void ll_iso_rx_mem_release(void **node_rx); /* Downstream - ISO Data */ void *ll_iso_tx_mem_acquire(void); diff --git a/subsys/bluetooth/controller/include/ll_feat.h b/subsys/bluetooth/controller/include/ll_feat.h index b80a4574903..32ed99456a2 100644 --- a/subsys/bluetooth/controller/include/ll_feat.h +++ b/subsys/bluetooth/controller/include/ll_feat.h @@ -195,20 +195,31 @@ #define LL_BIS_OCTETS_RX_MAX 0 #endif /* !CONFIG_BT_CTLR_SYNC_ISO */ +#if defined(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT) || \ + defined(CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT) +#define LL_FEAT_BIT_PERIODIC_ADI_SUPPORT BIT64(BT_LE_FEAT_BIT_PER_ADV_ADI_SUPP) +#else /* !CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT && + * !CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT + */ +#define LL_FEAT_BIT_PERIODIC_ADI_SUPPORT 0U +#endif /* !CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT && + * !CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT + */ + /* All defined feature bits */ -#define LL_FEAT_BIT_MASK 0xFFFFFFFFFULL +#define LL_FEAT_BIT_MASK 0xFFFFFFFFFFULL /* * LL_FEAT_BIT_MASK_VALID is defined as per - * Core Spec V5.2 Volume 6, Part B, chapter 4.6 + * Core Spec V5.3 Volume 6, Part B, chapter 4.6 */ -#define LL_FEAT_BIT_MASK_VALID 0xFF787CF2FULL +#define LL_FEAT_BIT_MASK_VALID 0xEFF787CF2FULL /* Mask to filter away octet 0 for feature exchange */ #define LL_FEAT_FILTER_OCTET0 (LL_FEAT_BIT_MASK & ~0xFFULL) /* Mask for host controlled features */ -#define LL_FEAT_HOST_BIT_MASK 0x100000000ULL +#define LL_FEAT_HOST_BIT_MASK 0x4100000000ULL /* Feature bits of this controller */ #define LL_FEAT (LL_FEAT_BIT_ENC | \ @@ -237,4 +248,5 @@ LL_FEAT_BIT_CIS_CENTRAL | \ LL_FEAT_BIT_CIS_PERIPHERAL | \ LL_FEAT_BIT_ISO_BROADCASTER | \ - LL_FEAT_BIT_SYNC_RECEIVER) + LL_FEAT_BIT_SYNC_RECEIVER | \ + LL_FEAT_BIT_PERIODIC_ADI_SUPPORT) diff --git a/subsys/bluetooth/controller/ll_sw/lll.h b/subsys/bluetooth/controller/ll_sw/lll.h index 77c660664c2..1ff8369552a 100644 --- a/subsys/bluetooth/controller/ll_sw/lll.h +++ b/subsys/bluetooth/controller/ll_sw/lll.h @@ -327,21 +327,24 @@ struct node_rx_ftr { #endif /* CONFIG_BT_CTLR_EXT_SCAN_FP */ #if defined(CONFIG_BT_CTLR_ADV_EXT) && defined(CONFIG_BT_OBSERVER) + uint8_t phy_flags:1; + uint8_t scan_req:1; + uint8_t scan_rsp:1; + #if defined(CONFIG_BT_CTLR_PRIVACY) uint8_t direct_resolved:1; #endif /* CONFIG_BT_CTLR_PRIVACY */ - uint8_t aux_lll_sched:1; - uint8_t aux_w4next:1; - uint8_t aux_failed:1; #if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) uint8_t sync_status:2; uint8_t sync_rx_enabled:1; #endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */ - uint8_t phy_flags:1; - uint8_t scan_req:1; - uint8_t scan_rsp:1; + uint8_t aux_sched:1; + uint8_t aux_lll_sched:1; + uint8_t aux_failed:1; + + uint16_t aux_data_len; #endif /* CONFIG_BT_CTLR_ADV_EXT && CONFIG_BT_OBSERVER */ #if defined(CONFIG_BT_HCI_MESH_EXT) @@ -498,6 +501,15 @@ static inline void lll_hdr_init(void *lll, void *parent) #endif /* CONFIG_BT_CTLR_JIT_SCHEDULING */ } +/* If ISO vendor data path is not used, queue directly to ll_iso_rx */ +#if defined(CONFIG_BT_CTLR_ISO_VENDOR_DATA_PATH) +#define iso_rx_put(link, rx) ull_iso_rx_put(link, rx) +#define iso_rx_sched() ull_iso_rx_sched() +#else +#define iso_rx_put(link, rx) ll_iso_rx_put(link, rx) +#define iso_rx_sched() ll_rx_sched() +#endif /* CONFIG_BT_CTLR_ISO_VENDOR_DATA_PATH */ + void lll_done_score(void *param, uint8_t result); int lll_init(void); @@ -529,12 +541,13 @@ void *ull_pdu_rx_alloc_peek(uint8_t count); void *ull_pdu_rx_alloc_peek_iter(uint8_t *idx); void *ull_pdu_rx_alloc(void); void *ull_iso_pdu_rx_alloc_peek(uint8_t count); -void *ull_iso_pdu_rx_alloc_peek_iter(uint8_t *idx); void *ull_iso_pdu_rx_alloc(void); void ull_rx_put(memq_link_t *link, void *rx); void ull_rx_put_done(memq_link_t *link, void *done); void ull_rx_sched(void); void ull_rx_sched_done(void); +void ull_iso_rx_put(memq_link_t *link, void *rx); +void ull_iso_rx_sched(void); struct event_done_extra *ull_event_done_extra_get(void); struct event_done_extra *ull_done_extra_type_set(uint8_t type); void *ull_event_done(void *param); diff --git a/subsys/bluetooth/controller/ll_sw/lll_conn.h b/subsys/bluetooth/controller/ll_sw/lll_conn.h index 8b75670e6f8..ef4f9d3b9f3 100644 --- a/subsys/bluetooth/controller/ll_sw/lll_conn.h +++ b/subsys/bluetooth/controller/ll_sw/lll_conn.h @@ -148,9 +148,9 @@ struct lll_conn { int8_t tx_pwr_lvl; #endif -#if defined(CONFIG_BT_CTRL_DF_CONN_CTE_RX) +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) struct lll_df_conn_rx_cfg df_rx_cfg; -#endif /* CONFIG_BT_CTRL_DF_CONN_CTE_RX */ +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */ #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_TX) struct lll_df_conn_tx_cfg df_tx_cfg; #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_TX */ diff --git a/subsys/bluetooth/controller/ll_sw/lll_scan.h b/subsys/bluetooth/controller/ll_sw/lll_scan.h index 04894e5a7a8..5646d36773c 100644 --- a/subsys/bluetooth/controller/ll_sw/lll_scan.h +++ b/subsys/bluetooth/controller/ll_sw/lll_scan.h @@ -86,3 +86,4 @@ int lll_scan_reset(void); void lll_scan_prepare(void *param); extern uint8_t ull_scan_lll_handle_get(struct lll_scan *lll); +extern struct lll_scan *ull_scan_lll_is_valid_get(struct lll_scan *lll); diff --git a/subsys/bluetooth/controller/ll_sw/lll_sync.h b/subsys/bluetooth/controller/ll_sw/lll_sync.h index e77d32247d2..a1a4c86836f 100644 --- a/subsys/bluetooth/controller/ll_sw/lll_sync.h +++ b/subsys/bluetooth/controller/ll_sw/lll_sync.h @@ -51,7 +51,7 @@ struct lll_sync { uint32_t window_size_event_us; /* used to store lll_aux when chain is being scanned */ - struct lll_scan_aux *lll_aux; + struct lll_scan_aux *volatile lll_aux; #if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) struct lll_df_sync df_cfg; diff --git a/subsys/bluetooth/controller/ll_sw/lll_sync_iso.h b/subsys/bluetooth/controller/ll_sw/lll_sync_iso.h index d5fccaf9e9c..356461d665d 100644 --- a/subsys/bluetooth/controller/ll_sw/lll_sync_iso.h +++ b/subsys/bluetooth/controller/ll_sw/lll_sync_iso.h @@ -78,3 +78,5 @@ void lll_sync_iso_create_prepare(void *param); void lll_sync_iso_prepare(void *param); extern uint8_t ull_sync_iso_lll_handle_get(struct lll_sync_iso *lll); +extern void ll_iso_rx_put(memq_link_t *link, void *rx); +extern void ll_rx_sched(void); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/debug.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/debug.h index 711857ef1ef..72c0f153382 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/debug.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/debug.h @@ -8,6 +8,7 @@ #if defined(CONFIG_BT_CTLR_DEBUG_PINS) || \ defined(CONFIG_BT_CTLR_DEBUG_PINS_CPUAPP) #if defined(CONFIG_BOARD_NRF5340DK_NRF5340_CPUAPP) || \ + defined(CONFIG_BOARD_NRF5340DK_NRF5340_CPUAPP_NS) || \ defined(CONFIG_BOARD_NRF5340DK_NRF5340_CPUNET) #define DEBUG_PORT NRF_P1 #define DEBUG_PIN_IDX0 0 @@ -30,39 +31,20 @@ #define DEBUG_PIN7 BIT(DEBUG_PIN_IDX7) #define DEBUG_PIN8 BIT(DEBUG_PIN_IDX8) #define DEBUG_PIN9 BIT(DEBUG_PIN_IDX9) -#if defined(CONFIG_BOARD_NRF5340DK_NRF5340_CPUAPP) +#if defined(CONFIG_BOARD_NRF5340DK_NRF5340_CPUAPP) || \ + (defined(CONFIG_BOARD_NRF5340DK_NRF5340_CPUAPP_NS) && defined(CONFIG_BUILD_WITH_TFM)) #define DEBUG_SETUP() \ do { \ - DEBUG_PORT->PIN_CNF[DEBUG_PIN_IDX0] = \ - (GPIO_PIN_CNF_MCUSEL_NetworkMCU << \ - GPIO_PIN_CNF_MCUSEL_Pos); \ - DEBUG_PORT->PIN_CNF[DEBUG_PIN_IDX1] = \ - (GPIO_PIN_CNF_MCUSEL_NetworkMCU << \ - GPIO_PIN_CNF_MCUSEL_Pos); \ - DEBUG_PORT->PIN_CNF[DEBUG_PIN_IDX2] = \ - (GPIO_PIN_CNF_MCUSEL_NetworkMCU << \ - GPIO_PIN_CNF_MCUSEL_Pos); \ - DEBUG_PORT->PIN_CNF[DEBUG_PIN_IDX3] = \ - (GPIO_PIN_CNF_MCUSEL_NetworkMCU << \ - GPIO_PIN_CNF_MCUSEL_Pos); \ - DEBUG_PORT->PIN_CNF[DEBUG_PIN_IDX4] = \ - (GPIO_PIN_CNF_MCUSEL_NetworkMCU << \ - GPIO_PIN_CNF_MCUSEL_Pos); \ - DEBUG_PORT->PIN_CNF[DEBUG_PIN_IDX5] = \ - (GPIO_PIN_CNF_MCUSEL_NetworkMCU << \ - GPIO_PIN_CNF_MCUSEL_Pos); \ - DEBUG_PORT->PIN_CNF[DEBUG_PIN_IDX6] = \ - (GPIO_PIN_CNF_MCUSEL_NetworkMCU << \ - GPIO_PIN_CNF_MCUSEL_Pos); \ - DEBUG_PORT->PIN_CNF[DEBUG_PIN_IDX7] = \ - (GPIO_PIN_CNF_MCUSEL_NetworkMCU << \ - GPIO_PIN_CNF_MCUSEL_Pos); \ - DEBUG_PORT->PIN_CNF[DEBUG_PIN_IDX8] = \ - (GPIO_PIN_CNF_MCUSEL_NetworkMCU << \ - GPIO_PIN_CNF_MCUSEL_Pos); \ - DEBUG_PORT->PIN_CNF[DEBUG_PIN_IDX9] = \ - (GPIO_PIN_CNF_MCUSEL_NetworkMCU << \ - GPIO_PIN_CNF_MCUSEL_Pos); \ + soc_secure_gpio_pin_mcu_select(32 + DEBUG_PIN_IDX0, NRF_GPIO_PIN_MCUSEL_NETWORK); + soc_secure_gpio_pin_mcu_select(32 + DEBUG_PIN_IDX1, NRF_GPIO_PIN_MCUSEL_NETWORK); + soc_secure_gpio_pin_mcu_select(32 + DEBUG_PIN_IDX2, NRF_GPIO_PIN_MCUSEL_NETWORK); + soc_secure_gpio_pin_mcu_select(32 + DEBUG_PIN_IDX3, NRF_GPIO_PIN_MCUSEL_NETWORK); + soc_secure_gpio_pin_mcu_select(32 + DEBUG_PIN_IDX4, NRF_GPIO_PIN_MCUSEL_NETWORK); + soc_secure_gpio_pin_mcu_select(32 + DEBUG_PIN_IDX5, NRF_GPIO_PIN_MCUSEL_NETWORK); + soc_secure_gpio_pin_mcu_select(32 + DEBUG_PIN_IDX6, NRF_GPIO_PIN_MCUSEL_NETWORK); + soc_secure_gpio_pin_mcu_select(32 + DEBUG_PIN_IDX7, NRF_GPIO_PIN_MCUSEL_NETWORK); + soc_secure_gpio_pin_mcu_select(32 + DEBUG_PIN_IDX8, NRF_GPIO_PIN_MCUSEL_NETWORK); + soc_secure_gpio_pin_mcu_select(32 + DEBUG_PIN_IDX9, NRF_GPIO_PIN_MCUSEL_NETWORK); } while (0) #endif /* CONFIG_BOARD_NRF5340DK_NRF5340_CPUAPP */ #elif defined(CONFIG_BOARD_NRF52840DK_NRF52840) || \ diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.h index 9776dd195f8..844bc7aefda 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.h @@ -11,16 +11,16 @@ #define RADIO_PKT_CONF_PDU_TYPE_MSK BIT(RADIO_PKT_CONF_PDU_TYPE_POS) #define RADIO_PKT_CONF_PDU_TYPE_AC (0U) #define RADIO_PKT_CONF_PDU_TYPE_DC (1U) -/* PHY type, two bit field */ +/* PHY type, three bit field */ #define RADIO_PKT_CONF_PHY_POS (1U) -#define RADIO_PKT_CONF_PHY_MSK (BIT_MASK(2U) << RADIO_PKT_CONF_PHY_POS) +#define RADIO_PKT_CONF_PHY_MSK (BIT_MASK(3U)) #define RADIO_PKT_CONF_PHY_LEGACY (0U) -#define RADIO_PKT_CONF_PHY_1M (1U) -#define RADIO_PKT_CONF_PHY_2M (2U) -#define RADIO_PKT_CONF_PHY_CODED (3U) +#define RADIO_PKT_CONF_PHY_1M (BIT(0U)) +#define RADIO_PKT_CONF_PHY_2M (BIT(1U)) +#define RADIO_PKT_CONF_PHY_CODED (BIT(2U)) /* CTE enabled, 1 bit field */ -#define RADIO_PKT_CONF_CTE_POS (3U) -#define RADIO_PKT_CONF_CTE_MSK BIT(RADIO_PKT_CONF_PDU_TYPE_POS) +#define RADIO_PKT_CONF_CTE_POS (4U) +#define RADIO_PKT_CONF_CTE_MSK BIT(0) #define RADIO_PKT_CONF_CTE_DISABLED (0U) #define RADIO_PKT_CONF_CTE_ENABLED (1U) diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c index e0cc6de53a3..c206ab810c7 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c @@ -375,9 +375,14 @@ void lll_done_ull_inc(void) } #endif /* CONFIG_BT_CTLR_LOW_LAT_ULL_DONE */ -bool lll_is_done(void *param) +bool lll_is_done(void *param, bool *is_resume) { - /* FIXME: use param to check */ + /* NOTE: Current radio event when preempted could put itself in resume + * into the prepare pipeline in which case event.curr.param would + * be set to NULL. + */ + *is_resume = (param != event.curr.param); + return !event.curr.abort_cb; } @@ -731,6 +736,10 @@ static struct lll_event *resume_enqueue(lll_prepare_cb_t resume_cb) { struct lll_prepare_param prepare_param = {0}; + /* Enqueue into prepare pipeline as resume radio event, and remove + * parameter assignment from currently active radio event so that + * done event is not generated. + */ prepare_param.param = event.curr.param; event.curr.param = NULL; diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c index 32e98d44abc..ae93d280ae4 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c @@ -472,8 +472,7 @@ struct pdu_adv *lll_adv_pdu_latest_get(struct lll_adv_pdu *pdu, * switch attempt (on next event). */ if (!MFIFO_ENQUEUE_IDX_GET(pdu_free, &free_idx)) { - pdu->pdu[pdu_idx] = p; - return NULL; + break; } #if defined(CONFIG_BT_CTLR_ADV_PDU_LINK) @@ -488,16 +487,19 @@ struct pdu_adv *lll_adv_pdu_latest_get(struct lll_adv_pdu *pdu, p = next; } while (p); - pdu->pdu[pdu_idx] = NULL; + /* If not all PDUs where released into mfifo, keep the list in + * current data index, to be released on the next switch + * attempt. + */ + pdu->pdu[pdu_idx] = p; + /* Progress to next data index */ first += 1U; if (first == DOUBLE_BUFFER_SIZE) { first = 0U; } pdu->first = first; *is_modified = 1U; - - pdu->pdu[pdu_idx] = NULL; } return (void *)pdu->pdu[first]; diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c index 7734d1b93e2..d87410bf0d7 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c @@ -44,12 +44,6 @@ #include "common/log.h" #include "hal/debug.h" -#if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK) -#define ADV_SYNC_PDU_B2B_AFS (CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK_AFS) -#else -#define ADV_SYNC_PDU_B2B_AFS 0 -#endif - static int init_reset(void); static int prepare_cb(struct lll_prepare_param *p); static void abort_cb(struct lll_prepare_param *prepare_param, void *param); @@ -204,7 +198,7 @@ static int prepare_cb(struct lll_prepare_param *p) lll->last_pdu = pdu; radio_isr_set(isr_tx, lll); - radio_tmr_tifs_set(ADV_SYNC_PDU_B2B_AFS); + radio_tmr_tifs_set(EVENT_SYNC_B2B_MAFS_US); switch_radio_complete_and_b2b_tx(lll, phy_s); } else #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK */ @@ -223,6 +217,26 @@ static int prepare_cb(struct lll_prepare_param *p) remainder = p->remainder; start_us = radio_tmr_start(1, ticks_at_start, remainder); +#if defined(CONFIG_BT_CTLR_PROFILE_ISR) || \ + defined(HAL_RADIO_GPIO_HAVE_PA_PIN) + /* capture end of AUX_SYNC_IND/AUX_CHAIN_IND PDU, used for calculating + * next PDU timestamp. + * + * In Periodic Advertising without chaining there is no need for LLL to + * get the end time from radio, hence there is no call to + * radio_tmr_end_capture() to capture the radio end time. + * + * With chaining the sw_switch used PPI/DPPI for back to back Tx, no + * radio end time capture is needed there either. + * + * For PA LNA (and ISR profiling), the radio end time is required to + * setup the GPIOTE using radio_gpio_pa_lna_enable which needs call to + * radio_tmr_tifs_base_get(), both PA/LNA and ISR profiling call + * radio_tmr_end_get(). + */ + radio_tmr_end_capture(); +#endif /* CONFIG_BT_CTLR_PROFILE_ISR */ + #if defined(HAL_RADIO_GPIO_HAVE_PA_PIN) radio_gpio_pa_setup(); @@ -350,7 +364,7 @@ static void isr_tx(void *param) /* setup tIFS switching */ if (pdu->adv_ext_ind.ext_hdr_len && pdu->adv_ext_ind.ext_hdr.aux_ptr) { - radio_tmr_tifs_set(ADV_SYNC_PDU_B2B_AFS); + radio_tmr_tifs_set(EVENT_SYNC_B2B_MAFS_US); radio_isr_set(isr_tx, lll_sync); switch_radio_complete_and_b2b_tx(lll_sync, lll->phy_s); } else { @@ -367,12 +381,15 @@ static void isr_tx(void *param) lll_prof_cputime_capture(); } +#if defined(CONFIG_BT_CTLR_PROFILE_ISR) || \ + defined(HAL_RADIO_GPIO_HAVE_PA_PIN) /* capture end of AUX_SYNC_IND/AUX_CHAIN_IND PDU, used for calculating * next PDU timestamp. */ radio_tmr_end_capture(); +#endif /* CONFIG_BT_CTLR_PROFILE_ISR */ -#if defined(HAL_RADIO_GPIO_HAVE_LNA_PIN) +#if defined(HAL_RADIO_GPIO_HAVE_PA_PIN) if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) { /* PA/LNA enable is overwriting packet end used in ISR * profiling, hence back it up for later use. @@ -380,11 +397,13 @@ static void isr_tx(void *param) lll_prof_radio_end_backup(); } - radio_gpio_lna_setup(); - radio_gpio_pa_lna_enable(radio_tmr_tifs_base_get() + ADV_SYNC_PDU_B2B_AFS - 4 + cte_len_us - + radio_gpio_pa_setup(); + radio_gpio_pa_lna_enable(radio_tmr_tifs_base_get() + + EVENT_SYNC_B2B_MAFS_US - + (EVENT_CLOCK_JITTER_US << 1) + cte_len_us - radio_tx_chain_delay_get(lll->phy_s, 0) - - HAL_RADIO_GPIO_LNA_OFFSET); -#endif /* HAL_RADIO_GPIO_HAVE_LNA_PIN */ + HAL_RADIO_GPIO_PA_OFFSET); +#endif /* HAL_RADIO_GPIO_HAVE_PA_PIN */ if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) { lll_prof_send(); @@ -396,7 +415,7 @@ static void pdu_b2b_update(struct lll_adv_sync *lll, struct pdu_adv *pdu, uint32 while (pdu) { /* FIXME: Use implementation defined channel index */ pdu_b2b_aux_ptr_update(pdu, lll->adv->phy_s, lll->adv->phy_flags, 0, - ADV_SYNC_PDU_B2B_AFS, cte_len_us); + EVENT_SYNC_B2B_MAFS_US, cte_len_us); pdu = lll_adv_pdu_linked_next_get(pdu); } } diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central.c index 8ef6ba1315c..0caf0d62487 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central.c @@ -88,10 +88,10 @@ static int init_reset(void) static int prepare_cb(struct lll_prepare_param *p) { -#if defined(CONFIG_BT_CTRL_DF_CONN_CTE_RX) +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) struct lll_df_conn_rx_params *df_rx_params; struct lll_df_conn_rx_cfg *df_rx_cfg; -#endif /* CONFIG_BT_CTRL_DF_CONN_CTE_RX */ +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */ struct pdu_data *pdu_data_tx; uint32_t ticks_at_event; uint32_t ticks_at_start; @@ -158,9 +158,10 @@ static int prepare_cb(struct lll_prepare_param *p) #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_TX) if (pdu_data_tx->cp) { - lll_df_conn_cte_tx_enable(&lll->df_tx_cfg); - cte_len = CTE_LEN_US(pdu_data_tx->cte_info.time); + + lll_df_cte_tx_configure(pdu_data_tx->cte_info.type, pdu_data_tx->cte_info.time, + lll->df_tx_cfg.ant_sw_len, lll->df_tx_cfg.ant_ids); } else #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_TX */ { @@ -184,7 +185,7 @@ static int prepare_cb(struct lll_prepare_param *p) radio_tmr_tifs_set(EVENT_IFS_US); -#if defined(CONFIG_BT_CTRL_DF_CONN_CTE_RX) +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) /* If CTE RX is enabled and the PHY is not CODED, store channel used for * the connection event to report it with collected IQ samples. * The configuration of the CTE receive may not change during the event, @@ -198,7 +199,7 @@ static int prepare_cb(struct lll_prepare_param *p) lll->df_rx_cfg.chan = data_chan_use; } } -#endif /* CONFIG_BT_CTRL_DF_CONN_CTE_RX */ +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */ #if defined(CONFIG_BT_CTLR_PHY) radio_switch_complete_and_rx(lll->phy_rx); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_conn.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_conn.c index 68eb2d61cb8..903a4b2e549 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_conn.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_conn.c @@ -48,10 +48,10 @@ static inline int isr_rx_pdu(struct lll_conn *lll, struct pdu_data *pdu_data_rx, uint8_t *is_rx_enqueue, struct node_tx **tx_release, uint8_t *is_done); static void empty_tx_init(void); -#if defined(CONFIG_BT_CTRL_DF_CONN_CTE_RX) +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) static inline bool create_iq_report(struct lll_conn *lll, uint8_t rssi_ready, uint8_t packet_status); -#endif /* CONFIG_BT_CTRL_DF_CONN_CTE_RX */ +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */ #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_TX) static struct pdu_data *get_last_tx_pdu(struct lll_conn *lll); #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_TX */ @@ -195,9 +195,9 @@ void lll_conn_isr_rx(void *param) uint8_t is_done; uint8_t cte_len; uint8_t crc_ok; -#if defined(CONFIG_BT_CTRL_DF_CONN_CTE_RX) +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) bool cte_ready; -#endif /* CONFIG_BT_CTRL_DF_CONN_CTE_RX */ +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */ if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) { lll_prof_latency_capture(); @@ -208,15 +208,15 @@ void lll_conn_isr_rx(void *param) if (trx_done) { crc_ok = radio_crc_is_valid(); rssi_ready = radio_rssi_is_ready(); -#if defined(CONFIG_BT_CTRL_DF_CONN_CTE_RX) +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) cte_ready = radio_df_cte_ready(); -#endif /* CONFIG_BT_CTRL_DF_CONN_CTE_RX */ +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */ } else { crc_ok = rssi_ready = 0U; -#if defined(CONFIG_BT_CTRL_DF_CONN_CTE_RX) +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) cte_ready = 0U; -#endif /* CONFIG_BT_CTRL_DF_CONN_CTE_RX */ +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */ } /* Clear radio rx status and events */ @@ -274,9 +274,10 @@ void lll_conn_isr_rx(void *param) #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_TX) if (pdu_data_tx->cp) { - lll_df_conn_cte_tx_enable(&lll->df_tx_cfg); - cte_len = CTE_LEN_US(pdu_data_tx->cte_info.time); + + lll_df_cte_tx_configure(pdu_data_tx->cte_info.type, pdu_data_tx->cte_info.time, + lll->df_tx_cfg.ant_sw_len, lll->df_tx_cfg.ant_ids); } else #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_TX */ { @@ -406,7 +407,7 @@ void lll_conn_isr_rx(void *param) is_ull_rx = 1U; } -#if defined(CONFIG_BT_CTRL_DF_CONN_CTE_RX) +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) if (cte_ready) { is_iq_report = create_iq_report(lll, rssi_ready, @@ -415,7 +416,7 @@ void lll_conn_isr_rx(void *param) } else { #else if (1) { -#endif /* CONFIG_BT_CTRL_DF_CONN_CTE_RX */ +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */ is_iq_report = false; } @@ -467,12 +468,16 @@ void lll_conn_isr_tx(void *param) lll = param; -#if defined(CONFIG_BT_CTRL_DF_CONN_CTE_RX) +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) #if defined(CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE) enum radio_end_evt_delay_state end_evt_delay; #endif /* CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE */ +#if defined(CONFIG_BT_CTLR_PHY) if (lll->phy_rx != PHY_CODED) { +#else + if (1) { +#endif /* CONFIG_BT_CTLR_PHY */ struct lll_df_conn_rx_params *df_rx_params; struct lll_df_conn_rx_cfg *df_rx_cfg; @@ -506,7 +511,7 @@ void lll_conn_isr_tx(void *param) #endif /* !CONFIG_BT_CTLR_PHY */ #endif /* CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE */ -#endif /* CONFIG_BT_CTRL_DF_CONN_CTE_RX */ +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */ /* Use regular API for cases when: * - CTE RX is not enabled, @@ -554,13 +559,13 @@ void lll_conn_isr_tx(void *param) radio_tmr_hcto_configure(hcto); -#if defined(CONFIG_BT_CTRL_DF_CONN_CTE_RX) +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) if (true) { #elif defined(CONFIG_BT_CENTRAL) && defined(CONFIG_BT_CTLR_CONN_RSSI) if (!trx_cnt && !lll->role) { #else if (false) { -#endif /* CONFIG_BT_CTRL_DF_CONN_CTE_RX */ +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */ radio_rssi_measure(); } @@ -721,6 +726,16 @@ void lll_conn_pdu_tx_prep(struct lll_conn *lll, struct pdu_data **pdu_data_tx) if (lll->packet_tx_head_offset) { p->ll_id = PDU_DATA_LLID_DATA_CONTINUE; + +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_TX) || defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) + /* BT 5.3 Core Spec does not define handling of CP bit + * for PDUs fragmented by Controller, hence the CP bit + * is set to zero. The CTE should not be transmitted + * with CONTINUE PDUs if fragmentation is performed. + */ + p->cp = 0U; + p->resv = 0U; +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_TX || CONFIG_BT_CTLR_DF_CONN_CTE_RX */ } p->len = lll->packet_tx_head_len - lll->packet_tx_head_offset; @@ -738,6 +753,12 @@ void lll_conn_pdu_tx_prep(struct lll_conn *lll, struct pdu_data **pdu_data_tx) } p->rfu = 0U; + +#if !defined(CONFIG_BT_CTLR_DATA_LENGTH_CLEAR) +#if !defined(CONFIG_BT_CTLR_DF_CONN_CTE_TX) && !defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) + p->resv = 0U; +#endif /* !CONFIG_BT_CTLR_DF_CONN_CTE_TX && !CONFIG_BT_CTLR_DF_CONN_CTE_RX */ +#endif /* CONFIG_BT_CTLR_DATA_LENGTH_CLEAR */ } *pdu_data_tx = p; @@ -991,21 +1012,24 @@ static void empty_tx_init(void) p = (void *)radio_pkt_empty_get(); p->ll_id = PDU_DATA_LLID_DATA_CONTINUE; - p->cp = false; -#if !defined(CONFIG_BT_CTLR_DATA_LENGTH_CLEAR) - p->resv = 0U; -#endif /* CONFIG_BT_CTLR_DATA_LENGTH_CLEAR */ + + /* cp, rfu, and resv fields in the empty PDU buffer is statically + * zero initialized at power up and these values in this buffer are + * not modified at runtime. + */ } -#if defined(CONFIG_BT_CTRL_DF_CONN_CTE_RX) +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) static inline bool create_iq_report(struct lll_conn *lll, uint8_t rssi_ready, uint8_t packet_status) { struct lll_df_conn_rx_params *rx_params; struct lll_df_conn_rx_cfg *rx_cfg; +#if defined(CONFIG_BT_CTLR_PHY) if (lll->phy_rx == PHY_CODED) { return false; } +#endif /* CONFIG_BT_CTLR_PHY */ rx_cfg = &lll->df_rx_cfg; @@ -1040,7 +1064,7 @@ static inline bool create_iq_report(struct lll_conn *lll, uint8_t rssi_ready, ui return false; } -#endif /* CONFIG_BT_CTRL_DF_CONN_CTE_RX */ +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */ #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_TX) /** diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_df.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_df.c index 8e58773e5d3..ca8afcf8522 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_df.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_df.c @@ -43,10 +43,7 @@ #define DF_MIN_ANT_NUM_REQUIRED 2 static int init_reset(void); -#if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX) || defined(CONFIG_BT_CTLR_DF_CONN_CTE_TX) -static void df_cte_tx_configure(uint8_t cte_type, uint8_t cte_length, uint8_t ant_ids_len, - const uint8_t *ant_ids); -#endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX || CONFIG_BT_CTLR_DF_CONN_CTE_TX */ + /* @brief Function performs Direction Finding initialization * * @return Zero in case of success, other value in case of failure. @@ -79,20 +76,6 @@ uint8_t lll_df_ant_num_get(void) return radio_df_ant_num_get(); } -#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_TX) -/** - * @brief Function enables transmission of Constant Tone Extension by radio peripheral in connected - * mode. - * - * @param df_cfg Pointer to configuration of the CTE. - */ -void lll_df_conn_cte_tx_enable(const struct lll_df_conn_tx_cfg *df_cfg) -{ - df_cte_tx_configure(df_cfg->cte_type, df_cfg->cte_length, df_cfg->ant_sw_len, - df_cfg->ant_ids); -} -#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_TX */ - #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX) /* @brief Function enables transmission of Constant Tone Extension. * @@ -121,8 +104,8 @@ void lll_df_cte_tx_enable(struct lll_adv_sync *lll_sync, const struct pdu_adv *p df_cfg = lll_adv_sync_extra_data_curr_get(lll_sync); LL_ASSERT(df_cfg); - df_cte_tx_configure(df_cfg->cte_type, df_cfg->cte_length, - df_cfg->ant_sw_len, df_cfg->ant_ids); + lll_df_cte_tx_configure(df_cfg->cte_type, df_cfg->cte_length, + df_cfg->ant_sw_len, df_cfg->ant_ids); lll_sync->cte_started = 1U; *cte_len_us = CTE_LEN_US(df_cfg->cte_length); @@ -225,7 +208,7 @@ struct lll_df_sync_cfg *lll_df_sync_cfg_latest_get(struct lll_df_sync *df_cfg, } #endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX */ -#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) || defined(CONFIG_BT_CTRL_DF_CONN_CTE_RX) +#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) || defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) /* @brief Function initializes reception of Constant Tone Extension. * * @param slot_duration Switching and sampling slots duration (1us or 2us). @@ -264,9 +247,9 @@ void lll_df_conf_cte_rx_enable(uint8_t slot_duration, uint8_t ant_num, const uin radio_df_iq_data_packet_set(node_rx->pdu, IQ_SAMPLE_TOTAL_CNT); node_rx->chan_idx = chan_idx; } -#endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX || CONFIG_BT_CTRL_DF_CONN_CTE_RX */ +#endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX || CONFIG_BT_CTLR_DF_CONN_CTE_RX */ -#if defined(CONFIG_BT_CTRL_DF_CONN_CTE_RX) +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) /** * @brief Function initializes parsing of received PDU for CTEInfo. * @@ -293,7 +276,7 @@ void lll_df_conf_cte_info_parsing_enable(void) /* Do not set storage for IQ samples, it is irrelevant for parsing of a PDU for CTEInfo. */ radio_df_iq_data_packet_set(NULL, 0); } -#endif /* CONFIG_BT_CTRL_DF_CONN_CTE_RX */ +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */ /* @brief Function performs common steps for initialization and reset * of Direction Finding LLL module. @@ -307,17 +290,17 @@ static int init_reset(void) #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX) || defined(CONFIG_BT_CTLR_DF_CONN_CTE_TX) /** - * @brief Function initializes transmission of Constant Tone Extension. + * @brief Function configures transmission of Constant Tone Extension. * - * @param cte_type Type of the CTE - * @param cte_length Length of CTE in units of 8 us - * @param ant_ids_len Length of antenna identifiers array - * @param ant_ids Pointer to antenna identifiers array + * @param cte_type Type of the CTE + * @param cte_length Length of CTE in units of 8 us + * @param num_ant_ids Length of @p ant_ids + * @param ant_ids Pointer to antenna identifiers array * * In case of AoA mode ant_sw_len and ant_ids members are not used. */ -static void df_cte_tx_configure(uint8_t cte_type, uint8_t cte_length, uint8_t ant_ids_len, - const uint8_t *ant_ids) +void lll_df_cte_tx_configure(uint8_t cte_type, uint8_t cte_length, uint8_t num_ant_ids, + const uint8_t *ant_ids) { if (cte_type == BT_HCI_LE_AOA_CTE) { radio_df_mode_set_aoa(); @@ -335,7 +318,7 @@ static void df_cte_tx_configure(uint8_t cte_type, uint8_t cte_length, uint8_t an radio_df_ant_switching_pin_sel_cfg(); radio_df_ant_switch_pattern_clear(); - radio_df_ant_switch_pattern_set(ant_ids, ant_ids_len); + radio_df_ant_switch_pattern_set(ant_ids, num_ant_ids); } #endif /* CONFIG_BT_CTLR_DF_ANT_SWITCH_TX */ } diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_df_internal.h b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_df_internal.h index 83889ea31ce..7c7f0730c29 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_df_internal.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_df_internal.h @@ -59,8 +59,9 @@ static inline uint8_t lll_df_sync_cfg_is_modified(struct lll_df_sync *df_cfg) void lll_df_conf_cte_rx_enable(uint8_t slot_duration, uint8_t ant_num, const uint8_t *ant_ids, uint8_t chan_idx, bool cte_info_in_s1); -/* Enable CTE transmission according to provided configuration */ -void lll_df_conn_cte_tx_enable(const struct lll_df_conn_tx_cfg *df_cfg); +/* Configure CTE transmission */ +void lll_df_cte_tx_configure(uint8_t cte_type, uint8_t cte_length, uint8_t num_ant_ids, + const uint8_t *ant_ids); /* Enabled parsing of a PDU for CTEInfo */ void lll_df_conf_cte_info_parsing_enable(void); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_df_types.h b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_df_types.h index b19d3b19788..e58d4450eff 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_df_types.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_df_types.h @@ -66,8 +66,22 @@ struct lll_df_adv_cfg { #define IQ_SAMPLE_CNT (PDU_DC_LL_HEADER_SIZE + LL_LENGTH_OCTETS_RX_MAX) #define RSSI_DBM_TO_DECI_DBM(x) (-(x) * 10) -#define IQ_SHIFT_12_TO_8_BIT(x) ((int8_t)((x) >> 4)) +/* Macro that represents out of range IQ sample (saturated). Value provided by Radio specifications. + * It is not defined by Bluetooth Core specification. This is the vendor specific value. + * + * Nordic Semiconductor Radio peripheral provides 16 bit wide IQ samples. + * BT 5.3 Core specification Vol 4, Part E sectons 7.7.65.21 and 7.7.65.22 limit size of + * IQ samples to 8 bits. + * To mitigate the limited accuratcy and losing information about saturated IQ samples a 0x80 value + * is selected to serve the purpose. + */ +#define IQ_SAMPLE_STATURATED_16_BIT 0x8000 +#define IQ_SAMPLE_STATURATED_8_BIT 0x80 +#define IQ_SHIFT_12_TO_8_BIT(x) ((int8_t)((x) >> 4)) +#define IQ_CONVERT_12_TO_8_BIT(x) \ + (((x) == IQ_SAMPLE_STATURATED_16_BIT) ? IQ_SAMPLE_STATURATED_8_BIT : \ + IQ_SHIFT_12_TO_8_BIT((x))) /* Structure to store an single IQ sample */ struct iq_sample { int16_t i; @@ -108,11 +122,6 @@ struct lll_df_sync { struct lll_df_sync_cfg cfg[DOUBLE_BUFFER_SIZE]; }; -/* Names for allowed states for CTE transmit parameters in connected mode */ -enum df_cte_tx_state { - DF_CTE_CONN_TX_PARAMS_UNINITIALIZED, - DF_CTE_CONN_TX_PARAMS_SET, -}; /* Parameters for reception of Constant Tone Extension in connected mode */ struct lll_df_conn_rx_params { uint8_t is_enabled:1; @@ -154,10 +163,12 @@ struct cte_conn_iq_report { /* Configuration for transmission of Constant Tone Extension in connected mode */ struct lll_df_conn_tx_cfg { - uint8_t state:1; + /* Stores information if the TX configuration was set at least once. + * It is required for handling HCI_LE_Connection_CTE_Response_Enable HCI command. + * See BT 5.3 Core specification Vol 4, Part E, sec. 7.8.86. + */ + uint8_t is_initialized:1; uint8_t ant_sw_len:7; - uint8_t cte_type:2; - uint8_t cte_length:6; /* Length of CTE in 8us units */ uint8_t cte_rsp_en:1; /* CTE response is enabled */ uint8_t cte_types_allowed:3; /* Bitfield with allowed CTE types */ uint8_t ant_ids[BT_CTLR_DF_MAX_ANT_SW_PATTERN_LEN]; diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_internal.h b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_internal.h index 6fdf3b74c74..032ca508148 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_internal.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_internal.h @@ -6,7 +6,7 @@ int lll_prepare_done(void *param); int lll_done(void *param); -bool lll_is_done(void *param); +bool lll_is_done(void *param, bool *is_resume); int lll_is_abort_cb(void *next, void *curr, lll_prepare_cb_t *resume_cb); void lll_abort_cb(struct lll_prepare_param *prepare_param, void *param); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral.c index 7587ff17d6c..4c89cdf2d24 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral.c @@ -101,10 +101,10 @@ static int init_reset(void) static int prepare_cb(struct lll_prepare_param *p) { -#if defined(CONFIG_BT_CTRL_DF_CONN_CTE_RX) +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) struct lll_df_conn_rx_params *df_rx_params; struct lll_df_conn_rx_cfg *df_rx_cfg; -#endif /* CONFIG_BT_CTRL_DF_CONN_CTE_RX */ +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */ uint32_t ticks_at_event; uint32_t ticks_at_start; uint16_t event_counter; @@ -213,12 +213,16 @@ static int prepare_cb(struct lll_prepare_param *p) radio_tmr_tifs_set(EVENT_IFS_US); -#if defined(CONFIG_BT_CTRL_DF_CONN_CTE_RX) +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) #if defined(CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE) enum radio_end_evt_delay_state end_evt_delay; #endif /* CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE */ +#if defined(CONFIG_BT_CTLR_PHY) if (lll->phy_rx != PHY_CODED) { +#else + if (1) { +#endif /* CONFIG_BT_CTLR_PHY */ df_rx_cfg = &lll->df_rx_cfg; df_rx_params = dbuf_latest_get(&df_rx_cfg->hdr, NULL); @@ -247,7 +251,7 @@ static int prepare_cb(struct lll_prepare_param *p) #endif /* !CONFIG_BT_CTLR_PHY */ #endif /* CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE */ -#endif /* CONFIG_BT_CTRL_DF_CONN_CTE_RX */ +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */ /* Use regular API for cases when: * - CTE RX is not enabled, diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c index ecebaf9a65e..4f8308455e5 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c @@ -79,7 +79,6 @@ static void isr_abort(void *param); * (EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US) */ static void isr_done_cleanup(void *param); -static void isr_cleanup(void *param); static inline int isr_rx_pdu(struct lll_scan *lll, struct pdu_adv *pdu_adv_rx, uint8_t devmatch_ok, uint8_t devmatch_id, @@ -620,11 +619,8 @@ static void abort_cb(struct lll_prepare_param *prepare_param, void *param) cpu_sleep(); } #endif /* CONFIG_BT_CENTRAL */ - } else if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) { - radio_isr_set(isr_done_cleanup, param); - radio_disable(); } else { - radio_isr_set(isr_cleanup, param); + radio_isr_set(isr_done_cleanup, param); radio_disable(); } return; @@ -640,10 +636,17 @@ static void abort_cb(struct lll_prepare_param *prepare_param, void *param) } static void ticker_stop_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, - uint32_t remainder, uint16_t lazy, uint8_t force, void *param) + uint32_t remainder, uint16_t lazy, uint8_t force, + void *param) { - radio_isr_set(isr_done_cleanup, param); - radio_disable(); + static memq_link_t link; + static struct mayfly mfy = {0, 0, &link, NULL, lll_disable}; + uint32_t ret; + + mfy.param = param; + ret = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH, TICKER_USER_ID_LLL, 0, + &mfy); + LL_ASSERT(!ret); } static void ticker_op_start_cb(uint32_t status, void *param) @@ -982,6 +985,7 @@ static void isr_abort(void *param) static void isr_done_cleanup(void *param) { struct lll_scan *lll; + bool is_resume; /* Clear radio status and events */ lll_isr_status_reset(); @@ -989,7 +993,7 @@ static void isr_done_cleanup(void *param) /* Under race between duration expire, is_stop is set in this function, * and event preemption, prevent generating duplicate scan done events. */ - if (lll_is_done(param)) { + if (lll_is_done(param, &is_resume)) { return; } @@ -1009,28 +1013,47 @@ static void isr_done_cleanup(void *param) ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_LLL, TICKER_ID_SCAN_STOP, NULL, NULL); -#if defined(CONFIG_BT_CTLR_ADV_EXT) - struct event_done_extra *extra; - - if (lll->is_aux_sched) { - struct node_rx_pdu *node_rx; - - node_rx = ull_pdu_rx_alloc(); - LL_ASSERT(node_rx); +#if defined(CONFIG_BT_CTLR_SCAN_INDICATION) + struct node_rx_hdr *node_rx; - node_rx->hdr.type = NODE_RX_TYPE_EXT_AUX_RELEASE; + /* Check if there are enough free node rx available: + * 1. For generating this scan indication + * 2. Keep one available free for reception of ACL connection Rx data + * 3. Keep one available free for reception on ACL connection to NACK + * the PDU + */ + node_rx = ull_pdu_rx_alloc_peek(3); + if (node_rx) { + ull_pdu_rx_alloc(); - node_rx->hdr.rx_ftr.param = lll; + /* TODO: add other info by defining a payload struct */ + node_rx->type = NODE_RX_TYPE_SCAN_INDICATION; - ull_rx_put(node_rx->hdr.link, node_rx); + ull_rx_put(node_rx->link, node_rx); ull_rx_sched(); } +#endif /* CONFIG_BT_CTLR_SCAN_INDICATION */ - /* Generate Scan done events so that duration and max expiry is - * detected in ULL. +#if defined(CONFIG_BT_HCI_MESH_EXT) + if (_radio.advertiser.is_enabled && _radio.advertiser.is_mesh && + !_radio.advertiser.retry) { + mayfly_mesh_stop(NULL); + } +#endif /* CONFIG_BT_HCI_MESH_EXT */ + +#if defined(CONFIG_BT_CTLR_ADV_EXT) + /* If continuous scan then do not generate scan done when radio event + * has been placed into prepare pipeline as a resume radio event. */ - extra = ull_done_extra_type_set(EVENT_DONE_EXTRA_TYPE_SCAN); - LL_ASSERT(extra); + if (!is_resume) { + struct event_done_extra *extra; + + /* Generate Scan done events so that duration and max expiry is + * detected in ULL. + */ + extra = ull_done_extra_type_set(EVENT_DONE_EXTRA_TYPE_SCAN); + LL_ASSERT(extra); + } /* Prevent scan events in pipeline from being scheduled if duration has * expired. @@ -1038,62 +1061,22 @@ static void isr_done_cleanup(void *param) if (unlikely(lll->duration_reload && !lll->duration_expire)) { lll->is_stop = 1U; } -#endif /* CONFIG_BT_CTLR_ADV_EXT */ - - lll_isr_cleanup(param); -} - -static void isr_cleanup(void *param) -{ - /* Clear radio status and events */ - lll_isr_status_reset(); - - /* Do not generate done event for connection initiation, ULL will - * disable the event when establishing/setting up the connection. - * Also, do not generate done event when duration expire, as ULL - * will disable the event. - * As it was transmission of CONNECT_IND, there is not filters to - * disable either. - */ - if (lll_is_done(param)) { - return; - } - /* Disable Rx filters, if cleanup after being in Rx state */ - radio_filter_disable(); + if (lll->is_aux_sched) { + struct node_rx_pdu *node_rx; - /* Scanner stop can expire while here in this ISR. - * Deferred attempt to stop can fail as it would have - * expired, hence ignore failure. - */ - ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_LLL, - TICKER_ID_SCAN_STOP, NULL, NULL); + lll->is_aux_sched = 0U; -#if defined(CONFIG_BT_HCI_MESH_EXT) - if (_radio.advertiser.is_enabled && _radio.advertiser.is_mesh && - !_radio.advertiser.retry) { - mayfly_mesh_stop(NULL); - } -#endif /* CONFIG_BT_HCI_MESH_EXT */ - -#if defined(CONFIG_BT_CTLR_SCAN_INDICATION) - struct node_rx_hdr *node_rx = ull_pdu_rx_alloc_peek(3); + node_rx = ull_pdu_rx_alloc(); + LL_ASSERT(node_rx); - if (node_rx) { - ull_pdu_rx_alloc(); + node_rx->hdr.type = NODE_RX_TYPE_EXT_AUX_RELEASE; - /* TODO: add other info by defining a payload struct */ - node_rx->type = NODE_RX_TYPE_SCAN_INDICATION; + node_rx->hdr.rx_ftr.param = lll; - ull_rx_put(node_rx->link, node_rx); + ull_rx_put(node_rx->hdr.link, node_rx); ull_rx_sched(); } -#endif /* CONFIG_BT_CTLR_SCAN_INDICATION */ - -#if defined(CONFIG_BT_CTLR_ADV_EXT) - struct lll_scan *lll = param; - - lll->is_aux_sched = 0U; #endif /* CONFIG_BT_CTLR_ADV_EXT */ lll_isr_cleanup(param); @@ -1189,7 +1172,7 @@ static inline int isr_rx_pdu(struct lll_scan *lll, struct pdu_adv *pdu_adv_rx, lll_prof_cputime_capture(); } - radio_isr_set(isr_cleanup, lll); + radio_isr_set(isr_done_cleanup, lll); #if defined(HAL_RADIO_GPIO_HAVE_PA_PIN) if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) { diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c index 328f4000b8b..55e6abe3105 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c @@ -53,6 +53,7 @@ static int init_reset(void); static int prepare_cb(struct lll_prepare_param *p); +static int is_abort_cb(void *next, void *curr, lll_prepare_cb_t *resume_cb); static void abort_cb(struct lll_prepare_param *prepare_param, void *param); static void isr_done(void *param); static void isr_rx_ull_schedule(void *param); @@ -110,7 +111,7 @@ void lll_scan_aux_prepare(void *param) err = lll_hfclock_on(); LL_ASSERT(err >= 0); - err = lll_prepare(lll_is_abort_cb, abort_cb, prepare_cb, 0, param); + err = lll_prepare(is_abort_cb, abort_cb, prepare_cb, 0, param); LL_ASSERT(!err || err == -EINPROGRESS); } @@ -135,6 +136,11 @@ uint8_t lll_scan_aux_setup(struct pdu_adv *pdu, uint8_t pdu_phy, /* Get reference to extended header */ pri_com_hdr = (void *)&pdu->adv_ext_ind; + if (!pdu->len || !pri_com_hdr->ext_hdr_len) { + return 0U; + } + + /* Get reference to flags and contents */ pri_hdr = (void *)pri_com_hdr->ext_hdr_adv_data; pri_dptr = pri_hdr->data; @@ -424,16 +430,14 @@ static int prepare_cb(struct lll_prepare_param *p) lll_aux = p->param; lll = ull_scan_aux_lll_parent_get(lll_aux, &is_lll_scan); -#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) /* Check if this aux scan is for periodic advertising train */ - if (!is_lll_scan) { + if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) && !is_lll_scan) { lll_sync_aux_prepare_cb((void *)lll, lll_aux); lll = NULL; goto sync_aux_prepare_done; } -#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */ #if defined(CONFIG_BT_CENTRAL) /* Check if stopped (on connection establishment race between @@ -514,9 +518,7 @@ static int prepare_cb(struct lll_prepare_param *p) (uint8_t *)fal->bdaddr); } -#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) sync_aux_prepare_done: -#endif /* Calculate event timings, coarse and fine */ ticks_at_event = p->ticks_at_expire; ull = HDR_LLL2ULL(lll_aux); @@ -595,6 +597,32 @@ static int prepare_cb(struct lll_prepare_param *p) return 0; } +static int is_abort_cb(void *next, void *curr, lll_prepare_cb_t *resume_cb) +{ + struct lll_scan *lll; + + /* Auxiliary context shall not resume when being preempted, i.e. they + * shall not use -EAGAIN as return value. + */ + ARG_UNUSED(resume_cb); + + /* Auxiliary event shall not overlap as they are not periodically + * scheduled. + */ + LL_ASSERT(next != curr); + + lll = ull_scan_lll_is_valid_get(next); + if (lll) { + /* Next event is scan context, let the current auxiliary scan + * continue. + */ + return 0; + } + + /* Yield current auxiliary event to other than scan events */ + return -ECANCELED; +} + static void abort_cb(struct lll_prepare_param *prepare_param, void *param) { int err; @@ -621,11 +649,38 @@ static void abort_cb(struct lll_prepare_param *prepare_param, void *param) static void isr_done(void *param) { - struct event_done_extra *e; + struct lll_sync *lll; + uint8_t is_lll_scan; lll_isr_status_reset(); - if (!trx_cnt) { + if (param) { + lll = ull_scan_aux_lll_parent_get(param, &is_lll_scan); + } else { + lll = NULL; + } + + /* Check if this aux scan is for periodic advertising train */ + if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) && lll && !is_lll_scan) { + struct node_rx_pdu *node_rx; + + /* Generate message to release aux context and flag the report + * generated thereafter by HCI as incomplete. + */ + node_rx = ull_pdu_rx_alloc(); + LL_ASSERT(node_rx); + + node_rx->hdr.type = NODE_RX_TYPE_EXT_AUX_RELEASE; + + node_rx->hdr.rx_ftr.param = lll; + node_rx->hdr.rx_ftr.aux_failed = 1U; + + ull_rx_put(node_rx->hdr.link, node_rx); + ull_rx_sched(); + + } else if (!trx_cnt) { + struct event_done_extra *e; + e = ull_done_extra_type_set(EVENT_DONE_EXTRA_TYPE_SCAN_AUX); LL_ASSERT(e); } @@ -768,7 +823,7 @@ static void isr_rx(struct lll_scan *lll, struct lll_scan_aux *lll_aux, radio_isr_set(isr_done, NULL); } else { /* Send message to flush Auxiliary PDU list */ - if (err != -ECANCELED) { + if (lll->is_aux_sched && err != -ECANCELED) { struct node_rx_pdu *node_rx; node_rx = ull_pdu_rx_alloc(); @@ -795,6 +850,8 @@ static void isr_rx(struct lll_scan *lll, struct lll_scan_aux *lll_aux, * context or auxiliary PDU reception by aux context */ if (lll->is_aux_sched) { + lll->is_aux_sched = 0U; + /* Go back to resuming primary channel scanning */ radio_isr_set(lll_scan_isr_resume, lll); } else { @@ -1159,11 +1216,6 @@ static int isr_rx_pdu(struct lll_scan *lll, struct lll_scan_aux *lll_aux, ftr->param = lll; ftr->scan_rsp = lll->lll_aux->state; - /* Auxiliary PDU received by LLL scheduling by scan - * context. - */ - lll->is_aux_sched = 1U; - /* Further auxiliary PDU reception will be chain PDUs */ lll->lll_aux->is_chain_sched = 1U; } else { @@ -1211,18 +1263,22 @@ static int isr_rx_pdu(struct lll_scan *lll, struct lll_scan_aux *lll_aux, ull_rx_sched(); - /* Increase trx count so as to not generate done extra event - * as a valid Auxiliary PDU node rx is being reported to ULL. - */ - trx_cnt++; - /* Next aux scan is scheduled from LLL, we already handled radio * disable so prevent caller from doing it again. */ if (ftr->aux_lll_sched) { + if (!lll_aux) { + lll->is_aux_sched = 1U; + } + return 0; } + /* Increase trx count so as to not generate done extra event + * as a valid Auxiliary PDU node rx is being reported to ULL. + */ + trx_cnt++; + return -ECANCELED; } @@ -1420,12 +1476,21 @@ static void isr_rx_connect_rsp(void *param) struct lll_conn *conn_lll = lll->conn; #if defined(CONFIG_BT_CTLR_DATA_LENGTH) +#if defined(CONFIG_BT_LL_SW_LLCP_LEGACY) conn_lll->max_tx_time = MAX(conn_lll->max_tx_time, PDU_DC_MAX_US(PDU_DC_PAYLOAD_SIZE_MIN, lll_aux->phy)); conn_lll->max_rx_time = MAX(conn_lll->max_rx_time, PDU_DC_MAX_US(PDU_DC_PAYLOAD_SIZE_MIN, lll_aux->phy)); +#else + conn_lll->dle.eff.max_tx_time = MAX(conn_lll->dle.eff.max_tx_time, + PDU_DC_MAX_US(PDU_DC_PAYLOAD_SIZE_MIN, + lll_aux->phy)); + conn_lll->dle.eff.max_rx_time = MAX(conn_lll->dle.eff.max_rx_time, + PDU_DC_MAX_US(PDU_DC_PAYLOAD_SIZE_MIN, + lll_aux->phy)); +#endif /* CONFIG_BT_LL_SW_LLCP_LEGACY */ #endif /* CONFIG_BT_CTLR_DATA_LENGTH*/ conn_lll->phy_tx = lll_aux->phy; @@ -1468,7 +1533,7 @@ static void isr_rx_connect_rsp(void *param) radio_isr_set(lll_scan_isr_resume, lll); } else { - radio_isr_set(isr_done, lll_aux); + radio_isr_set(isr_done, NULL); } radio_disable(); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c index 0f83aee86a3..b18726192f5 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c @@ -49,6 +49,7 @@ static void prepare(void *param); static int create_prepare_cb(struct lll_prepare_param *p); static int prepare_cb(struct lll_prepare_param *p); static int prepare_cb_common(struct lll_prepare_param *p, uint8_t chan_idx); +static int is_abort_cb(void *next, void *curr, lll_prepare_cb_t *resume_cb); static void abort_cb(struct lll_prepare_param *prepare_param, void *param); static int isr_rx(struct lll_sync *lll, uint8_t node_type, uint8_t crc_ok, uint8_t rssi_ready, enum sync_status status); @@ -98,7 +99,7 @@ void lll_sync_create_prepare(void *param) prepare(param); /* Invoke common pipeline handling of prepare */ - err = lll_prepare(lll_is_abort_cb, abort_cb, create_prepare_cb, 0, param); + err = lll_prepare(is_abort_cb, abort_cb, create_prepare_cb, 0, param); LL_ASSERT(!err || err == -EINPROGRESS); } @@ -109,7 +110,7 @@ void lll_sync_prepare(void *param) prepare(param); /* Invoke common pipeline handling of prepare */ - err = lll_prepare(lll_is_abort_cb, abort_cb, prepare_cb, 0, param); + err = lll_prepare(is_abort_cb, abort_cb, prepare_cb, 0, param); LL_ASSERT(!err || err == -EINPROGRESS); } @@ -455,6 +456,32 @@ static int prepare_cb_common(struct lll_prepare_param *p, uint8_t chan_idx) return 0; } +static int is_abort_cb(void *next, void *curr, lll_prepare_cb_t *resume_cb) +{ + /* Sync context shall not resume when being preempted, i.e. they + * shall not use -EAGAIN as return value. + */ + ARG_UNUSED(resume_cb); + + /* Different radio event overlap */ + if (next != curr) { + struct lll_scan *lll; + + lll = ull_scan_lll_is_valid_get(next); + if (!lll) { + /* Abort current event as next event is not a scan + * event. + */ + return -ECANCELED; + } + } + + /* Do not abort if current periodic sync event overlaps next interval + * or next event is a scan event. + */ + return 0; +} + static void abort_cb(struct lll_prepare_param *prepare_param, void *param) { struct lll_sync *lll; @@ -606,7 +633,13 @@ static int isr_rx(struct lll_sync *lll, uint8_t node_type, uint8_t crc_ok, uint8 if (crc_ok) { struct node_rx_pdu *node_rx; - node_rx = ull_pdu_rx_alloc_peek(3); + /* Verify if there are free RX buffers for: + * - reporting just received PDU + * - allocating an extra node_rx for periodic report incomplete + * - a buffer for receiving data in a connection + * - a buffer for receiving empty PDU + */ + node_rx = ull_pdu_rx_alloc_peek(4); if (node_rx) { struct node_rx_ftr *ftr; struct pdu_adv *pdu; @@ -627,6 +660,10 @@ static int isr_rx(struct lll_sync *lll, uint8_t node_type, uint8_t crc_ok, uint8 ftr->sync_status = status; ftr->sync_rx_enabled = lll->is_rx_enabled; + if (node_type != NODE_RX_TYPE_EXT_AUX_REPORT) { + ftr->extra = ull_pdu_rx_alloc(); + } + pdu = (void *)node_rx->pdu; ftr->aux_lll_sched = lll_scan_aux_setup(pdu, lll->phy, @@ -634,7 +671,10 @@ static int isr_rx(struct lll_sync *lll, uint8_t node_type, uint8_t crc_ok, uint8 isr_aux_setup, lll); if (ftr->aux_lll_sched) { - lll->is_aux_sched = 1U; + if (node_type != NODE_RX_TYPE_EXT_AUX_REPORT) { + lll->is_aux_sched = 1U; + } + err = -EBUSY; } else { err = 0; @@ -643,6 +683,8 @@ static int isr_rx(struct lll_sync *lll, uint8_t node_type, uint8_t crc_ok, uint8 ull_rx_put(node_rx->hdr.link, node_rx); sched = true; + } else if (node_type == NODE_RX_TYPE_EXT_AUX_REPORT) { + err = -ENOMEM; } else { err = 0; } @@ -821,6 +863,7 @@ static void isr_rx_aux_chain(void *param) lll_isr_status_reset(); crc_ok = 0U; + err = 0; goto isr_rx_aux_chain_done; } @@ -841,6 +884,9 @@ static void isr_rx_aux_chain(void *param) if (!trx_done) { /* TODO: Combine the early exit with above if-then-else block */ + + err = 0; + goto isr_rx_aux_chain_done; } @@ -856,9 +902,12 @@ static void isr_rx_aux_chain(void *param) } isr_rx_aux_chain_done: - if (!crc_ok) { + if (!crc_ok || err) { struct node_rx_pdu *node_rx; + /* Generate message to release aux context and flag the report + * generated thereafter by HCI as incomplete. + */ node_rx = ull_pdu_rx_alloc(); LL_ASSERT(node_rx); @@ -876,7 +925,7 @@ static void isr_rx_aux_chain(void *param) isr_rx_done_cleanup(lll, 1U, false); } else { - lll_isr_cleanup(lll); + lll_isr_cleanup(lll_aux); } } @@ -911,7 +960,36 @@ static void isr_rx_done_cleanup(struct lll_sync *lll, uint8_t crc_ok, bool sync_ static void isr_done(void *param) { + struct lll_sync *lll; + lll_isr_status_reset(); + + /* Generate incomplete data status and release aux context when + * sync event is using LLL scheduling. + */ + lll = param; + + /* LLL scheduling used for chain PDU reception is aborted/preempted */ + if (lll->is_aux_sched) { + struct node_rx_pdu *node_rx; + + lll->is_aux_sched = 0U; + + /* Generate message to release aux context and flag the report + * generated thereafter by HCI as incomplete. + */ + node_rx = ull_pdu_rx_alloc(); + LL_ASSERT(node_rx); + + node_rx->hdr.type = NODE_RX_TYPE_EXT_AUX_RELEASE; + + node_rx->hdr.rx_ftr.param = lll; + node_rx->hdr.rx_ftr.aux_failed = 1U; + + ull_rx_put(node_rx->hdr.link, node_rx); + ull_rx_sched(); + } + isr_rx_done_cleanup(param, ((trx_cnt) ? 1U : 0U), false); } @@ -939,6 +1017,7 @@ static inline int create_iq_report(struct lll_sync *lll, uint8_t rssi_ready, cte_info = radio_df_cte_status_get(); ant = radio_df_pdu_antenna_switch_pattern_get(); iq_report = ull_df_iq_report_alloc(); + LL_ASSERT(iq_report); iq_report->hdr.type = NODE_RX_TYPE_SYNC_IQ_SAMPLE_REPORT; iq_report->sample_count = sample_cnt; diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c index 8ae4c7fc000..db259789603 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.c @@ -263,7 +263,7 @@ static int prepare_cb_common(struct lll_prepare_param *p) radio_crc_configure(PDU_CRC_POLYNOMIAL, sys_get_le24(crc_init)); lll_chan_set(data_chan_use); - node_rx = ull_pdu_rx_alloc_peek(1U); + node_rx = ull_iso_pdu_rx_alloc_peek(1U); LL_ASSERT(node_rx); radio_pkt_rx_set(node_rx->pdu); @@ -437,7 +437,7 @@ static void isr_rx(void *param) lll->ctrl) { lll->cssn_curr = lll->cssn_next; - node_rx = ull_pdu_rx_alloc_peek(1U); + node_rx = ull_iso_pdu_rx_alloc_peek(1U); LL_ASSERT(node_rx); pdu = (void *)node_rx->pdu; @@ -455,7 +455,7 @@ static void isr_rx(void *param) } } } else { - node_rx = ull_pdu_rx_alloc_peek(3U); + node_rx = ull_iso_pdu_rx_alloc_peek(3U); if (!node_rx) { goto isr_rx_done; } @@ -480,7 +480,7 @@ static void isr_rx(void *param) (payload_index < lll->payload_head))) { struct node_rx_iso_meta *iso_meta; - ull_pdu_rx_alloc(); + ull_iso_pdu_rx_alloc(); node_rx->hdr.type = NODE_RX_TYPE_ISO_PDU; node_rx->hdr.handle = lll->stream_handle[bis_idx]; @@ -601,7 +601,7 @@ static void isr_rx(void *param) node_rx = lll->payload[bis_idx][payload_tail]; lll->payload[bis_idx][payload_tail] = NULL; - ull_rx_put(node_rx->hdr.link, node_rx); + iso_rx_put(node_rx->hdr.link, node_rx); } payload_index = payload_tail + 1U; @@ -615,7 +615,7 @@ static void isr_rx(void *param) #if !defined(CONFIG_BT_CTLR_LOW_LAT_ULL) if (node_rx) { - ull_rx_sched(); + iso_rx_sched(); } #endif /* CONFIG_BT_CTLR_LOW_LAT_ULL */ @@ -681,7 +681,7 @@ static void isr_rx(void *param) } lll_chan_set(data_chan_use); - node_rx = ull_pdu_rx_alloc_peek(1U); + node_rx = ull_iso_pdu_rx_alloc_peek(1U); LL_ASSERT(node_rx); radio_pkt_rx_set(node_rx->pdu); diff --git a/subsys/bluetooth/controller/ll_sw/pdu.h b/subsys/bluetooth/controller/ll_sw/pdu.h index 6bdb35053d5..afc124f5027 100644 --- a/subsys/bluetooth/controller/ll_sw/pdu.h +++ b/subsys/bluetooth/controller/ll_sw/pdu.h @@ -99,8 +99,10 @@ #define EVENT_MAFS_US 300 /* Standard allows 2 us timing uncertainty inside the event */ #define EVENT_MAFS_MAX_US (EVENT_MAFS_US + EVENT_CLOCK_JITTER_US) -/* Controller defined back to back transmit MAFS */ +/* Controller defined back to back transmit MAFS for extended advertising */ #define EVENT_B2B_MAFS_US (CONFIG_BT_CTLR_ADV_PDU_BACK2BACK_AFS) +/* Controller defined back to back transmit MAFS for periodic advertising */ +#define EVENT_SYNC_B2B_MAFS_US (CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK_AFS) /* Minimum Subevent Space timings */ #define EVENT_MSS_US 150 /* Standard allows 2 us timing uncertainty inside the event */ @@ -124,7 +126,7 @@ #define OFFS_UNIT_VALUE_30_US 0 #define OFFS_UNIT_VALUE_300_US 1 /* Value specified in BT Spec. Vol 6, Part B, section 2.3.4.6 */ -#define OFFS_ADJUST_US 245760 +#define OFFS_ADJUST_US 2457600UL /* Advertiser's Sleep Clock Accuracy Value */ #define SCA_500_PPM 500 /* 51 ppm to 500 ppm */ @@ -809,11 +811,19 @@ struct pdu_data { uint8_t nesn:1; uint8_t sn:1; uint8_t md:1; +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_TX) || defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) uint8_t cp:1; uint8_t rfu:2; +#else + uint8_t rfu:3; +#endif #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_TX) || defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) uint8_t rfu:2; uint8_t cp:1; +#else + uint8_t rfu:3; +#endif uint8_t md:1; uint8_t sn:1; uint8_t nesn:1; diff --git a/subsys/bluetooth/controller/ll_sw/ull.c b/subsys/bluetooth/controller/ll_sw/ull.c index 60b991c47bf..a61b6ef5191 100644 --- a/subsys/bluetooth/controller/ll_sw/ull.c +++ b/subsys/bluetooth/controller/ll_sw/ull.c @@ -353,15 +353,21 @@ static RXFIFO_DEFINE(done, sizeof(struct node_rx_event_done), * Increasing this by times the max. simultaneous connection count will permit * simultaneous parallel PHY update or Connection Update procedures amongst * active connections. - * Minimum node rx of 2 that can be reserved happens when local central - * initiated PHY Update reserves 2 node rx, one for PHY update complete and - * another for Data Length Update complete notification. Otherwise, a - * peripheral only needs 1 additional node rx to generate Data Length Update - * complete when PHY Update completes; node rx for PHY update complete is - * reserved as the received PHY Update Ind PDU. + * Minimum node rx of 2 that can be reserved happens when: + * - for legacy LLCPs: + * Local central initiated PHY Update reserves 2 node rx, + * one for PHY update complete and another for Data Length Update complete + * notification. Otherwise, a peripheral only needs 1 additional node rx to + * generate Data Length Update complete when PHY Update completes; node rx for + * PHY update complete is reserved as the received PHY Update Ind PDU. + * - for new LLCPs: + * Central and peripheral always use two new nodes for handling completion + * notification one for PHY update complete and another for Data Length Update + * complete. */ -#if defined(CONFIG_BT_CENTRAL) && defined(CONFIG_BT_CTLR_PHY) && \ - defined(CONFIG_BT_CTLR_DATA_LENGTH) +#if defined(CONFIG_BT_CTLR_DATA_LENGTH) && defined(CONFIG_BT_CTLR_PHY) && \ + (defined(CONFIG_BT_LL_SW_LLCP_LEGACY) && defined(CONFIG_BT_CENTRAL) || \ + !defined(CONFIG_BT_LL_SW_LLCP_LEGACY)) #define LL_PDU_RX_CNT (2 * (CONFIG_BT_CTLR_LLCP_CONN)) #elif defined(CONFIG_BT_CONN) #define LL_PDU_RX_CNT (CONFIG_BT_CTLR_LLCP_CONN) @@ -1198,17 +1204,13 @@ void ll_rx_dequeue(void) case NODE_RX_TYPE_CIS_ESTABLISHED: #endif /* CONFIG_BT_CTLR_CONN_ISO */ -#if defined(CONFIG_BT_CTLR_ISO) - case NODE_RX_TYPE_ISO_PDU: -#endif - #if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) case NODE_RX_TYPE_SYNC_IQ_SAMPLE_REPORT: #endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX */ -#if defined(CONFIG_BT_CTRL_DF_CONN_CTE_RX) +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) case NODE_RX_TYPE_CONN_IQ_SAMPLE_REPORT: -#endif /* CONFIG_BT_CTRL_DF_CONN_CTE_RX */ +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */ /* Ensure that at least one 'case' statement is present for this * code block. @@ -1432,11 +1434,17 @@ void ll_rx_mem_release(void **node_rx) /* pick the sync context before scan context * is cleanup of sync context association. */ - sync = scan->per_scan.sync; + sync = scan->periodic.sync; ull_sync_setup_complete(scan); if (status != BT_HCI_ERR_SUCCESS) { + memq_link_t *link_sync_lost; + + link_sync_lost = + sync->node_rx_lost.hdr.link; + ll_rx_link_release(link_sync_lost); + ull_sync_release(sync); } @@ -1483,7 +1491,7 @@ void ll_rx_mem_release(void **node_rx) #endif /* CONFIG_BT_CTLR_SYNC_ISO */ #endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */ -#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) || defined(CONFIG_BT_CTRL_DF_CONN_CTE_RX) +#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) || defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) case NODE_RX_TYPE_SYNC_IQ_SAMPLE_REPORT: case NODE_RX_TYPE_CONN_IQ_SAMPLE_REPORT: { @@ -1494,7 +1502,7 @@ void ll_rx_mem_release(void **node_rx) ull_df_rx_iq_report_alloc(report_cnt); } break; -#endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX || CONFIG_BT_CTRL_DF_CONN_CTE_RX */ +#endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX || CONFIG_BT_CTLR_DF_CONN_CTE_RX */ #if defined(CONFIG_BT_CONN) || defined(CONFIG_BT_CTLR_CONN_ISO) case NODE_RX_TYPE_TERMINATE: @@ -1694,6 +1702,7 @@ int ull_ticker_stop_with_mark(uint8_t ticker_handle, void *param, uint32_t volatile ret_cb; uint32_t ret; void *mark; + int err; mark = ull_disable_mark(param); if (mark != param) { @@ -1714,16 +1723,17 @@ int ull_ticker_stop_with_mark(uint8_t ticker_handle, void *param, return -EALREADY; } - ret = ull_disable(lll_disable); - if (ret) { - return -EBUSY; - } + err = ull_disable(lll_disable); mark = ull_disable_unmark(param); if (mark != param) { return -ENOLCK; } + if (err && (err != -EALREADY)) { + return err; + } + return 0; } @@ -1753,8 +1763,8 @@ int ull_disable(void *lll) uint32_t ret; hdr = HDR_LLL2ULL(lll); - if (!hdr || !ull_ref_get(hdr)) { - return 0; + if (!ull_ref_get(hdr)) { + return -EALREADY; } k_sem_init(&sem, 0, 1); @@ -1772,7 +1782,7 @@ int ull_disable(void *lll) * care. */ if (!ull_ref_get(hdr)) { - return 0; + return -EALREADY; } mfy.param = lll; @@ -2445,7 +2455,7 @@ static inline int rx_demux_rx(memq_link_t *link, struct node_rx_hdr *rx) #endif /* CONFIG_BT_CTLR_ADV_EXT */ #endif /* CONFIG_BT_OBSERVER */ -#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) || defined(CONFIG_BT_CTRL_DF_CONN_CTE_RX) +#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) || defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) case NODE_RX_TYPE_SYNC_IQ_SAMPLE_REPORT: case NODE_RX_TYPE_CONN_IQ_SAMPLE_REPORT: { @@ -2454,7 +2464,7 @@ static inline int rx_demux_rx(memq_link_t *link, struct node_rx_hdr *rx) ll_rx_sched(); } break; -#endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX || CONFIG_BT_CTRL_DF_CONN_CTE_RX */ +#endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX || CONFIG_BT_CTLR_DF_CONN_CTE_RX */ #if defined(CONFIG_BT_CONN) case NODE_RX_TYPE_CONNECTION: @@ -2539,44 +2549,6 @@ static inline int rx_demux_rx(memq_link_t *link, struct node_rx_hdr *rx) * CONFIG_BT_CONN */ -#if defined(CONFIG_BT_CTLR_ISO) - case NODE_RX_TYPE_ISO_PDU: - { - /* Remove from receive-queue; ULL has received this now */ - (void)memq_dequeue(memq_ull_rx.tail, &memq_ull_rx.head, NULL); - -#if defined(CONFIG_BT_CTLR_CONN_ISO) - struct node_rx_pdu *rx_pdu = (struct node_rx_pdu *)rx; - struct ll_conn_iso_stream *cis = - ll_conn_iso_stream_get(rx_pdu->hdr.handle); - struct ll_iso_datapath *dp = cis->hdr.datapath_out; - isoal_sink_handle_t sink = dp->sink_hdl; - - if (dp->path_id != BT_HCI_DATAPATH_ID_HCI) { - /* If vendor specific datapath pass to ISO AL here, - * in case of HCI destination it will be passed in - * HCI context. - */ - struct isoal_pdu_rx pckt_meta = { - .meta = &rx_pdu->hdr.rx_iso_meta, - .pdu = (struct pdu_iso *) &rx_pdu->pdu[0] - }; - - /* Pass the ISO PDU through ISO-AL */ - isoal_status_t err = - isoal_rx_pdu_recombine(sink, &pckt_meta); - - LL_ASSERT(err == ISOAL_STATUS_OK); /* TODO handle err */ - } -#endif - - /* Let ISO PDU start its long journey upwards */ - ll_rx_put(link, rx); - ll_rx_sched(); - } - break; -#endif - default: { #if defined(CONFIG_BT_CTLR_USER_EXT) diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv.c b/subsys/bluetooth/controller/ll_sw/ull_adv.c index 88c31505f63..875f54b6e55 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv.c @@ -1025,10 +1025,14 @@ uint8_t ll_adv_enable(uint8_t enable) #if defined(CONFIG_BT_CTLR_CONN_META) memset(&conn_lll->conn_meta, 0, sizeof(conn_lll->conn_meta)); #endif /* CONFIG_BT_CTLR_CONN_META */ -#if defined(CONFIG_BT_CTRL_DF_CONN_CTE_RX) +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) + conn_lll->df_rx_cfg.is_initialized = 0U; conn_lll->df_rx_cfg.hdr.elem_size = sizeof(struct lll_df_conn_rx_params); -#endif /* CONFIG_BT_CTRL_DF_CONN_CTE_RX */ - +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */ +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_TX) + conn_lll->df_tx_cfg.is_initialized = 0U; + conn_lll->df_tx_cfg.cte_rsp_en = 0U; +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_TX */ conn->connect_expire = 6; conn->supervision_expire = 0; conn->procedure_expire = 0; @@ -2519,8 +2523,9 @@ static inline uint8_t disable(uint8_t handle) { uint32_t volatile ret_cb; struct ll_adv_set *adv; - void *mark; uint32_t ret; + void *mark; + int err; adv = ull_adv_is_enabled_get(handle); if (!adv) { @@ -2581,8 +2586,8 @@ static inline uint8_t disable(uint8_t handle) return BT_HCI_ERR_CMD_DISALLOWED; } - ret = ull_disable(&adv->lll); - LL_ASSERT(!ret); + err = ull_disable(&adv->lll); + LL_ASSERT(!err || (err == -EALREADY)); mark = ull_disable_unmark(adv); LL_ASSERT(mark == adv); @@ -2592,13 +2597,12 @@ static inline uint8_t disable(uint8_t handle) if (lll_aux) { struct ll_adv_aux_set *aux; - uint8_t err; aux = HDR_LLL2ULL(lll_aux); err = ull_adv_aux_stop(aux); - if (err) { - return err; + if (err && (err != -EALREADY)) { + return BT_HCI_ERR_CMD_DISALLOWED; } } #endif /* CONFIG_BT_CTLR_ADV_EXT && (CONFIG_BT_CTLR_ADV_AUX_SET > 0) */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_aux.c b/subsys/bluetooth/controller/ll_sw/ull_adv_aux.c index f159ed0926b..81da55191d8 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_aux.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_aux.c @@ -1073,7 +1073,7 @@ uint32_t ull_adv_aux_start(struct ll_adv_aux_set *aux, uint32_t ticks_anchor, return ret; } -uint8_t ull_adv_aux_stop(struct ll_adv_aux_set *aux) +int ull_adv_aux_stop(struct ll_adv_aux_set *aux) { uint8_t aux_handle; int err; @@ -1084,7 +1084,7 @@ uint8_t ull_adv_aux_stop(struct ll_adv_aux_set *aux) aux, &aux->lll); LL_ASSERT(err == 0 || err == -EALREADY); if (err) { - return BT_HCI_ERR_CMD_DISALLOWED; + return err; } aux->is_started = 0U; diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_internal.h b/subsys/bluetooth/controller/ll_sw/ull_adv_internal.h index f1b7982b564..93b567139c7 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_internal.h @@ -83,7 +83,7 @@ uint32_t ull_adv_aux_start(struct ll_adv_aux_set *aux, uint32_t ticks_anchor, uint32_t ticks_slot_overhead); /* helper function to stop auxiliary advertising */ -uint8_t ull_adv_aux_stop(struct ll_adv_aux_set *aux); +int ull_adv_aux_stop(struct ll_adv_aux_set *aux); /* helper function to acquire and initialize auxiliary advertising instance */ struct ll_adv_aux_set *ull_adv_aux_acquire(struct lll_adv *lll); diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c b/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c index 1e51e514706..1860e05e9a5 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c @@ -1734,6 +1734,12 @@ static inline void sync_info_offset_fill(struct pdu_adv_sync_info *si, uint32_t offs; offs = HAL_TICKER_TICKS_TO_US(ticks_offset) - start_us; + + if (offs >= OFFS_ADJUST_US) { + offs -= OFFS_ADJUST_US; + si->offs_adjust = 1U; + } + offs = offs / OFFS_UNIT_30_US; if (!!(offs >> OFFS_UNIT_BITS)) { si->offs = sys_cpu_to_le16(offs / (OFFS_UNIT_300_US / diff --git a/subsys/bluetooth/controller/ll_sw/ull_central.c b/subsys/bluetooth/controller/ll_sw/ull_central.c index c5a3b590dd2..1f98a6e6d57 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_central.c +++ b/subsys/bluetooth/controller/ll_sw/ull_central.c @@ -270,10 +270,14 @@ uint8_t ll_create_connection(uint16_t scan_interval, uint16_t scan_window, memset(&conn_lll->conn_meta, 0, sizeof(conn_lll->conn_meta)); #endif /* CONFIG_BT_CTLR_CONN_META */ -#if defined(CONFIG_BT_CTRL_DF_CONN_CTE_RX) - conn_lll->df_rx_cfg.is_initialized = false; +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) + conn_lll->df_rx_cfg.is_initialized = 0U; conn_lll->df_rx_cfg.hdr.elem_size = sizeof(struct lll_df_conn_rx_params); -#endif /* CONFIG_BT_CTRL_DF_CONN_CTE_RX */ +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */ +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_TX) + conn_lll->df_tx_cfg.is_initialized = 0U; + conn_lll->df_tx_cfg.cte_rsp_en = 0U; +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_TX */ conn->connect_expire = CONN_ESTAB_COUNTDOWN; conn->supervision_expire = 0U; diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn.c b/subsys/bluetooth/controller/ll_sw/ull_conn.c index 95eb2aaea14..75b1858bf34 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn.c +++ b/subsys/bluetooth/controller/ll_sw/ull_conn.c @@ -1649,6 +1649,33 @@ void ull_conn_done(struct node_rx_event_done *done) } #endif /* CONFIG_BT_CTLR_LE_PING */ +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) + if (conn->llcp.cte_req.req_expire != 0U) { + if (conn->llcp.cte_req.req_expire > elapsed_event) { + conn->llcp.cte_req.req_expire -= elapsed_event; + } else { + uint8_t err; + + conn->llcp.cte_req.req_expire = 0U; + + err = ull_cp_cte_req(conn, conn->llcp.cte_req.min_cte_len, + conn->llcp.cte_req.cte_type); + + if (err == BT_HCI_ERR_CMD_DISALLOWED) { + /* Conditions has changed e.g. PHY was changed to CODED. + * New CTE REQ is not possible. Disable the periodic requests. + * + * If the CTE REQ is in active state, let it complete and disable + * in regular control procedure way. + */ + if (!conn->llcp.cte_req.is_active) { + ull_cp_cte_req_set_disable(conn); + } + } + } + } +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ + #if defined(CONFIG_BT_CTLR_CONN_RSSI_EVENT) /* generate RSSI event */ if (lll->rssi_sample_count == 0U) { @@ -2052,20 +2079,17 @@ uint16_t ull_conn_lll_max_tx_octets_get(struct lll_conn *lll) /** * @brief Initialize pdu_data members that are read only in lower link layer. + * Fields that are modified after static initialization are only + * re-initialized. * - * @param pdu_tx Pointer to pdu_data object to be initialized + * @param pdu Pointer to pdu_data object to be initialized */ -void ull_pdu_data_init(struct pdu_data *pdu_tx) +void ull_pdu_data_init(struct pdu_data *pdu) { - LL_ASSERT(pdu_tx); - - pdu_tx->cp = false; - pdu_tx->rfu = 0U; -#if !defined(CONFIG_SOC_OPENISA_RV32M1_RISCV32) -#if !defined(CONFIG_BT_CTLR_DATA_LENGTH_CLEAR) - pdu_tx->resv = 0U; -#endif /* CONFIG_BT_CTLR_DATA_LENGTH_CLEAR */ -#endif /* !CONFIG_SOC_OPENISA_RV32M1_RISCV32 */ +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_TX) || defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) + pdu->cp = 0U; + pdu->resv = 0U; +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_TX || CONFIG_BT_CTLR_DF_CONN_CTE_RX */ } static int init_reset(void) @@ -2303,6 +2327,7 @@ static void conn_cleanup_finalize(struct ll_conn *conn) } #else /* CONFIG_BT_LL_SW_LLCP_LEGACY */ ARG_UNUSED(rx); + ull_cp_state_set(conn, ULL_CP_DISCONNECTED); #endif /* CONFIG_BT_LL_SW_LLCP_LEGACY */ /* flush demux-ed Tx buffer still in ULL context */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn_internal.h b/subsys/bluetooth/controller/ll_sw/ull_conn_internal.h index 381a8e36768..a2def1b4246 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_conn_internal.h @@ -37,7 +37,7 @@ void *ull_conn_ack_dequeue(void); void ull_conn_tx_ack(uint16_t handle, memq_link_t *link, struct node_tx *tx); uint8_t ull_conn_llcp_req(void *conn); -void ull_pdu_data_init(struct pdu_data *pdu_tx); +void ull_pdu_data_init(struct pdu_data *pdu); #if !defined(CONFIG_BT_LL_SW_LLCP_LEGACY) diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn_types.h b/subsys/bluetooth/controller/ll_sw/ull_conn_types.h index 62f7da3c625..1e7194ea56b 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn_types.h +++ b/subsys/bluetooth/controller/ll_sw/ull_conn_types.h @@ -367,6 +367,9 @@ struct llcp_struct { uint8_t collision; uint8_t incompat; uint8_t reject_opcode; +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) || defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) + uint8_t paused_cmd; +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP || CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ } remote; /* Prepare parameters */ @@ -417,26 +420,29 @@ struct llcp_struct { /* Procedure may be active periodically, active state must be stored. * If procedure is active, request parameters update may not be issued. */ - uint8_t is_enabled; + uint8_t is_enabled:1; + uint8_t is_active:1; uint8_t cte_type; /* Minimum requested CTE length in 8us units */ uint8_t min_cte_len; uint16_t req_interval; + uint16_t req_expire; + void *disable_param; + void (*disable_cb)(void *param); } cte_req; #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ + #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) - /* TODO (ppryga): Consided move of the type of structure to ull_df_types.h or - * lll_df_types.h. To have single definition of the type and share it wish LLL. - */ struct llcp_df_rsp_cfg { - uint8_t is_enabled; + uint8_t is_enabled:1; + uint8_t is_active:1; uint8_t cte_types; uint8_t max_cte_len; - uint8_t ant_sw_len; - /* TODO (ppryga): Update to use the same macro as in lll_df_types.h */ - uint8_t ant_ids[CONFIG_BT_CTLR_DF_MAX_ANT_SW_PATTERN_LEN]; + void *disable_param; + void (*disable_cb)(void *param); } cte_rsp; #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */ + #if (CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM > 0) &&\ (CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM <\ CONFIG_BT_CTLR_LLCP_TX_PER_CONN_TX_CTRL_BUF_NUM_MAX) @@ -472,8 +478,16 @@ struct ll_conn { * and/or needs to be properly integrated in the control procedures */ union { + struct { +#if defined(CONFIG_BT_CTLR_CONN_META) + uint8_t is_must_expire:1; +#endif /* CONFIG_BT_CTLR_CONN_META */ + } common; #if defined(CONFIG_BT_PERIPHERAL) struct { +#if defined(CONFIG_BT_CTLR_CONN_META) + uint8_t is_must_expire:1; +#endif /* CONFIG_BT_CTLR_CONN_META */ uint8_t latency_cancel:1; uint8_t sca:3; uint32_t force; @@ -483,6 +497,9 @@ struct ll_conn { #if defined(CONFIG_BT_CENTRAL) struct { +#if defined(CONFIG_BT_CTLR_CONN_META) + uint8_t is_must_expire:1; +#endif /* CONFIG_BT_CTLR_CONN_META */ uint8_t terminate_ack:1; } central; #endif /* CONFIG_BT_CENTRAL */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_df.c b/subsys/bluetooth/controller/ll_sw/ull_df.c index c2675d7bec0..37320c3ffa6 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_df.c +++ b/subsys/bluetooth/controller/ll_sw/ull_df.c @@ -36,10 +36,12 @@ #include "ull_sync_types.h" #include "ull_sync_internal.h" #include "ull_adv_types.h" +#include "ull_tx_queue.h" #include "ull_conn_types.h" #include "ull_conn_internal.h" #include "ull_df_types.h" #include "ull_df_internal.h" +#include "ull_llcp.h" #include "ull_adv_internal.h" #include "ull_internal.h" @@ -51,7 +53,7 @@ #include "common/log.h" #include "hal/debug.h" -#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) || defined(CONFIG_BT_CTRL_DF_CONN_CTE_RX) +#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) || defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) #define CTE_LEN_MAX_US 160U @@ -74,7 +76,7 @@ static MFIFO_DEFINE(iq_report_free, sizeof(void *), IQ_REPORT_CNT); /* Number of available instance of linked list to be used for node_rx_iq_reports. */ static uint8_t mem_link_iq_report_quota_pdu; -#endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX || CONFIG_BT_CTRL_DF_CONN_CTE_RX*/ +#endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX || CONFIG_BT_CTLR_DF_CONN_CTE_RX*/ /* ToDo: * - Add release of df_adv_cfg when adv_sync is released. @@ -166,7 +168,7 @@ static int init_reset(void) &df_adv_cfg_free); #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */ -#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) || defined(CONFIG_BT_CTRL_DF_CONN_CTE_RX) +#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) || defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) /* Re-initialize the free IQ report mfifo */ MFIFO_INIT(iq_report_free); @@ -178,7 +180,7 @@ static int init_reset(void) /* Allocate free IQ report node rx */ mem_link_iq_report_quota_pdu = IQ_REPORT_CNT; ull_df_rx_iq_report_alloc(UINT8_MAX); -#endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX || CONFIG_BT_CTRL_DF_CONN_CTE_RX */ +#endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX || CONFIG_BT_CTLR_DF_CONN_CTE_RX */ return 0; } @@ -497,7 +499,7 @@ bool ull_df_sync_cfg_is_not_enabled(struct lll_df_sync *df_cfg) } #endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX */ -#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) || defined(CONFIG_BT_CTRL_DF_CONN_CTE_RX) +#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) || defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) void *ull_df_iq_report_alloc_peek(uint8_t count) { if (count > MFIFO_AVAIL_COUNT_GET(iq_report_free)) { @@ -558,9 +560,9 @@ void ull_df_rx_iq_report_alloc(uint8_t max) ull_iq_report_link_inc_quota(-1); } } -#endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX || CONFIG_BT_CTRL_DF_CONN_CTE_RX */ +#endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX || CONFIG_BT_CTLR_DF_CONN_CTE_RX */ -#if defined(CONFIG_BT_CTRL_DF_CONN_CTE_RX) +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) bool ull_df_conn_cfg_is_not_enabled(struct lll_df_conn_rx_cfg *rx_cfg) { struct lll_df_conn_rx_params *rx_params; @@ -580,7 +582,7 @@ bool ull_df_conn_cfg_is_not_enabled(struct lll_df_conn_rx_cfg *rx_cfg) return !rx_params->is_enabled; } -#endif /* CONFIG_BT_CTRL_DF_CONN_CTE_RX */ +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */ #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX) /* @brief Function releases unused memory for DF advertising configuration. @@ -1041,13 +1043,13 @@ uint8_t ll_df_set_conn_cte_tx_params(uint16_t handle, uint8_t cte_types, uint8_t df_tx_cfg->ant_sw_len = switch_pattern_len; df_tx_cfg->cte_types_allowed = cte_types; - df_tx_cfg->state = DF_CTE_CONN_TX_PARAMS_SET; + df_tx_cfg->is_initialized = 1U; return BT_HCI_ERR_SUCCESS; } #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_TX */ -#if defined(CONFIG_BT_CTRL_DF_CONN_CTE_RX) +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) /** * @brief Function sets CTE reception parameters for a connection. * @@ -1085,7 +1087,7 @@ uint8_t ll_df_set_conn_cte_rx_params(uint16_t handle, uint8_t sampling_enable, /* This is an information for HCI_LE_Connection_CTE_Request_Enable that * HCI_LE_Set_Connection_CTE_Receive_Parameters was called at least once. */ - cfg_rx->is_initialized = true; + cfg_rx->is_initialized = 1U; params_buf_hdr = &cfg_rx->hdr; params_rx = dbuf_alloc(params_buf_hdr, ¶ms_idx); @@ -1116,7 +1118,14 @@ uint8_t ll_df_set_conn_cte_rx_params(uint16_t handle, uint8_t sampling_enable, return BT_HCI_ERR_SUCCESS; } -#endif /* CONFIG_BT_CTRL_DF_CONN_CTE_RX */ +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */ + +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) || defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) +static void df_conn_cte_req_disable(void *param) +{ + k_sem_give(param); +} +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ || CONFIG_BT_CTLR_DF_CONN_CTE_RSP */ #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) /* @brief Function enables or disables CTE request control procedure for a connection. @@ -1139,8 +1148,9 @@ uint8_t ll_df_set_conn_cte_rx_params(uint16_t handle, uint8_t sampling_enable, * * @return HCI Status of command completion. */ -uint8_t ll_df_set_conn_cte_req_enable(uint16_t handle, uint8_t enable, uint8_t cte_request_interval, - uint8_t requested_cte_length, uint8_t requested_cte_type) +uint8_t ll_df_set_conn_cte_req_enable(uint16_t handle, uint8_t enable, + uint16_t cte_request_interval, uint8_t requested_cte_length, + uint8_t requested_cte_type) { struct ll_conn *conn; @@ -1150,23 +1160,33 @@ uint8_t ll_df_set_conn_cte_req_enable(uint16_t handle, uint8_t enable, uint8_t c } if (!enable) { - /* There is no parameter validation for disable operation. */ + ull_cp_cte_req_set_disable(conn); - /* TODO: Add missing implementation of disable CTE reques. - * Requires refactored LLCPs. - */ + if (conn->llcp.cte_req.is_active) { + struct k_sem sem; + + k_sem_init(&sem, 0U, 1U); + conn->llcp.cte_req.disable_param = &sem; + conn->llcp.cte_req.disable_cb = df_conn_cte_req_disable; + + if (!conn->llcp.cte_req.is_active) { + k_sem_take(&sem, K_FOREVER); + } + } + + return BT_HCI_ERR_SUCCESS; } else { - if (!conn->df_rx_params.is_enabled) { + if (!conn->lll.df_rx_cfg.is_initialized) { return BT_HCI_ERR_CMD_DISALLOWED; } - /* TODO: check if CTE_REQ LLCP is active. Add when merged with refactored LLCPs */ + if (conn->llcp.cte_req.is_enabled) { + return BT_HCI_ERR_CMD_DISALLOWED; + } #if defined(CONFIG_BT_CTLR_PHY) - /* Phy may be changed to CODED only if PHY update procedure is supproted. In other - * case the mandatory PHY1M is used (that supports CTE). - */ - if (conn->lll.phy_tx == PHY_CODED) { + /* CTE request may be enabled only in case the receiver PHY is not CODED */ + if (conn->lll.phy_rx == PHY_CODED) { return BT_HCI_ERR_CMD_DISALLOWED; } #endif /* CONFIG_BT_CTLR_PHY */ @@ -1189,22 +1209,78 @@ uint8_t ll_df_set_conn_cte_req_enable(uint16_t handle, uint8_t enable, uint8_t c /* If controller is aware of features supported by peer device then check * whether required features are enabled. */ - if (conn->common.fex_valid && - (!(conn->llcp_feature.features_peer & BIT64(BT_LE_FEAT_BIT_CONN_CTE_RESP)) || + if (conn->llcp.fex.valid && + (!(conn->llcp.fex.features_peer & BIT64(BT_LE_FEAT_BIT_CONN_CTE_RESP)) || ((requested_cte_type == BT_HCI_LE_AOD_CTE_1US || requested_cte_type == BT_HCI_LE_AOD_CTE_2US) && - !(conn->llcp_feature.features_peer & + !(conn->llcp.fex.features_peer & BIT64(BT_LE_FEAT_BIT_ANT_SWITCH_TX_AOD))))) { return BT_HCI_ERR_UNSUPP_REMOTE_FEATURE; } - } - /* TODO: implement disable of the CTE if PHY is changed to coded */ + conn->llcp.cte_req.is_enabled = 1U; + conn->llcp.cte_req.req_interval = cte_request_interval; + conn->llcp.cte_req.cte_type = requested_cte_type; + conn->llcp.cte_req.min_cte_len = requested_cte_length; + } - return BT_HCI_ERR_CMD_DISALLOWED; + return ull_cp_cte_req(conn, requested_cte_length, requested_cte_type); } #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) +/** + * @brief Function enables or disables CTE response control procedure for a connection. + * + * @param handle Connection handle. + * @param enable Enable or disable CTE response. + * + * @return HCI Status of command completion. + */ +uint8_t ll_df_set_conn_cte_rsp_enable(uint16_t handle, uint8_t enable) +{ + struct ll_conn *conn; + + conn = ll_connected_get(handle); + if (!conn) { + return BT_HCI_ERR_UNKNOWN_CONN_ID; + } + + if (enable) { + if (!conn->lll.df_tx_cfg.is_initialized) { + return BT_HCI_ERR_CMD_DISALLOWED; + } + +#if defined(CONFIG_BT_CTLR_PHY) + /* CTE may not be send over CODED PHY */ + if (conn->lll.phy_tx == PHY_CODED) { + return BT_HCI_ERR_CMD_DISALLOWED; + } +#endif /* CONFIG_BT_CTLR_PHY */ + conn->lll.df_tx_cfg.cte_rsp_en = 1U; + + ull_cp_cte_rsp_enable(conn, enable, LLL_DF_MAX_CTE_LEN, + conn->lll.df_tx_cfg.cte_types_allowed); + } else { + conn->lll.df_tx_cfg.cte_rsp_en = false; + + if (conn->llcp.cte_rsp.is_active) { + struct k_sem sem; + + k_sem_init(&sem, 0U, 1U); + conn->llcp.cte_rsp.disable_param = &sem; + conn->llcp.cte_rsp.disable_cb = df_conn_cte_req_disable; + + if (!conn->llcp.cte_rsp.is_active) { + k_sem_take(&sem, K_FOREVER); + } + } + } + + return BT_HCI_ERR_SUCCESS; +} +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */ + /* @brief Function provides information about Direction Finding * antennas switching and sampling related settings. * diff --git a/subsys/bluetooth/controller/ll_sw/ull_df_types.h b/subsys/bluetooth/controller/ll_sw/ull_df_types.h index 42f669daf20..d7a38eda5a1 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_df_types.h +++ b/subsys/bluetooth/controller/ll_sw/ull_df_types.h @@ -33,7 +33,7 @@ enum df_switch_sample_support { #define SYNC_IQ_REPORT_CNT 0U #endif -#if defined(CONFIG_BT_MAX_CONN) && defined(CONFIG_BT_CTRL_DF_CONN_CTE_RX) +#if defined(CONFIG_BT_MAX_CONN) && defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) #define CONN_IQ_REPORT_CNT (CONFIG_BT_MAX_CONN * 2) #else #define CONN_IQ_REPORT_CNT 0U diff --git a/subsys/bluetooth/controller/ll_sw/ull_iso.c b/subsys/bluetooth/controller/ll_sw/ull_iso.c index 1a2aa1bc617..ea27fd2aabb 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_iso.c @@ -14,6 +14,7 @@ #include "util/memq.h" #include "util/mem.h" #include "util/mfifo.h" +#include "util/mayfly.h" #include "pdu.h" @@ -60,8 +61,32 @@ static int init_reset(void); #if BT_CTLR_ISO_STREAMS static struct ll_iso_datapath datapath_pool[BT_CTLR_ISO_STREAMS]; #endif + static void *datapath_free; +#if defined(CONFIG_BT_CTLR_SYNC_ISO) || defined(CONFIG_BT_CTLR_CONN_ISO) +#define NODE_RX_HEADER_SIZE (offsetof(struct node_rx_pdu, pdu)) +/* ISO LL conformance tests require a PDU size of maximum 251 bytes + header */ +#define ISO_RX_BUFFER_SIZE (2 + 251) + +/* Declare the ISO rx node RXFIFO. This is a composite pool-backed MFIFO for + * rx_nodes. The declaration constructs the following data structures: + * - mfifo_iso_rx: FIFO with pointers to PDU buffers + * - mem_iso_rx: Backing data pool for PDU buffer elements + * - mem_link_iso_rx: Pool of memq_link_t elements + * + * Two extra links are reserved for use by the ll_iso_rx and ull_iso_rx memq. + */ +static RXFIFO_DEFINE(iso_rx, NODE_RX_HEADER_SIZE + ISO_RX_BUFFER_SIZE, + CONFIG_BT_CTLR_ISO_RX_BUFFERS, 2); + +static MEMQ_DECLARE(ll_iso_rx); +#if defined(CONFIG_BT_CTLR_ISO_VENDOR_DATA_PATH) +static MEMQ_DECLARE(ull_iso_rx); +static void iso_rx_demux(void *param); +#endif /* CONFIG_BT_CTLR_ISO_VENDOR_DATA_PATH */ +#endif /* CONFIG_BT_CTLR_SYNC_ISO) || CONFIG_BT_CTLR_CONN_ISO */ + #if defined(CONFIG_BT_CTLR_ADV_ISO) || defined(CONFIG_BT_CTLR_CONN_ISO) static MFIFO_DEFINE(iso_tx, sizeof(struct lll_tx), CONFIG_BT_CTLR_ISO_TX_BUFFERS); @@ -213,7 +238,7 @@ uint8_t ll_setup_iso_path(uint16_t handle, uint8_t path_dir, uint8_t path_id, stream_handle = handle - BT_CTLR_SYNC_ISO_STREAM_HANDLE_BASE; stream = ull_sync_iso_stream_get(stream_handle); - if (stream->dp) { + if (!stream || stream->dp) { return BT_HCI_ERR_CMD_DISALLOWED; } #endif /* CONFIG_BT_CTLR_CONN_ISO */ @@ -381,6 +406,10 @@ uint8_t ll_remove_iso_path(uint16_t handle, uint8_t path_dir) stream_handle = handle - BT_CTLR_SYNC_ISO_STREAM_HANDLE_BASE; stream = ull_sync_iso_stream_get(stream_handle); + if (!stream) { + return BT_HCI_ERR_CMD_DISALLOWED; + } + dp = stream->dp; if (dp) { stream->dp = NULL; @@ -522,6 +551,182 @@ int ull_iso_reset(void) return 0; } +#if defined(CONFIG_BT_CTLR_SYNC_ISO) || defined(CONFIG_BT_CTLR_CONN_ISO) +void *ull_iso_pdu_rx_alloc_peek(uint8_t count) +{ + if (count > MFIFO_AVAIL_COUNT_GET(iso_rx)) { + return NULL; + } + + return MFIFO_DEQUEUE_PEEK(iso_rx); +} + +void *ull_iso_pdu_rx_alloc(void) +{ + return MFIFO_DEQUEUE(iso_rx); +} + +#if defined(CONFIG_BT_CTLR_ISO_VENDOR_DATA_PATH) +void ull_iso_rx_put(memq_link_t *link, void *rx) +{ + /* Enqueue the Rx object */ + memq_enqueue(link, rx, &memq_ull_iso_rx.tail); +} + +void ull_iso_rx_sched(void) +{ + static memq_link_t link; + static struct mayfly mfy = {0, 0, &link, NULL, iso_rx_demux}; + + /* Kick the ULL (using the mayfly, tailchain it) */ + mayfly_enqueue(TICKER_USER_ID_LLL, TICKER_USER_ID_ULL_HIGH, 1, &mfy); +} + +static void iso_rx_demux(void *param) +{ + struct ll_conn_iso_stream *cis; + struct ll_iso_datapath *dp; + struct node_rx_pdu *rx_pdu; + isoal_sink_handle_t sink; + struct node_rx_hdr *rx; + memq_link_t *link; + + do { + link = memq_peek(memq_ull_iso_rx.head, memq_ull_iso_rx.tail, + (void **)&rx); + if (link) { + /* Demux Rx objects */ + switch (rx->type) { + case NODE_RX_TYPE_RELEASE: + (void)memq_dequeue(memq_ull_iso_rx.tail, + &memq_ull_iso_rx.head, NULL); + ll_iso_rx_put(link, rx); + ll_rx_sched(); + break; + + case NODE_RX_TYPE_ISO_PDU: + /* Remove from receive-queue; ULL has received this now */ + (void)memq_dequeue(memq_ull_iso_rx.tail, &memq_ull_iso_rx.head, + NULL); + +#if defined(CONFIG_BT_CTLR_CONN_ISO) + rx_pdu = (struct node_rx_pdu *)rx; + cis = ll_conn_iso_stream_get(rx_pdu->hdr.handle); + dp = cis->hdr.datapath_out; + sink = dp->sink_hdl; + + if (dp->path_id != BT_HCI_DATAPATH_ID_HCI) { + /* If vendor specific datapath pass to ISO AL here, + * in case of HCI destination it will be passed in + * HCI context. + */ + struct isoal_pdu_rx pckt_meta = { + .meta = &rx_pdu->hdr.rx_iso_meta, + .pdu = (struct pdu_iso *)&rx_pdu->pdu[0] + }; + + /* Pass the ISO PDU through ISO-AL */ + const isoal_status_t err = + isoal_rx_pdu_recombine(sink, &pckt_meta); + + LL_ASSERT(err == ISOAL_STATUS_OK); /* TODO handle err */ + } +#endif /* CONFIG_BT_CTLR_CONN_ISO */ + + /* Let ISO PDU start its long journey upwards */ + ll_iso_rx_put(link, rx); + ll_rx_sched(); + break; + + default: + LL_ASSERT(0); + break; + } + } + } while (link); +} +#endif /* CONFIG_BT_CTLR_ISO_VENDOR_DATA_PATH */ + +void ll_iso_rx_put(memq_link_t *link, void *rx) +{ + /* Enqueue the Rx object */ + memq_enqueue(link, rx, &memq_ll_iso_rx.tail); +} + +void *ll_iso_rx_get(void) +{ + struct node_rx_hdr *rx; + memq_link_t *link; + + link = memq_peek(memq_ll_iso_rx.head, memq_ll_iso_rx.tail, (void **)&rx); + while (link) { + /* Do not send up buffers to Host thread that are + * marked for release + */ + if (rx->type == NODE_RX_TYPE_RELEASE) { + (void)memq_dequeue(memq_ll_iso_rx.tail, + &memq_ll_iso_rx.head, NULL); + mem_release(link, &mem_link_iso_rx.free); + mem_release(rx, &mem_iso_rx.free); + RXFIFO_ALLOC(iso_rx, 1); + + link = memq_peek(memq_ll_iso_rx.head, memq_ll_iso_rx.tail, (void **)&rx); + continue; + } + return rx; + } + + return NULL; +} + +void ll_iso_rx_dequeue(void) +{ + struct node_rx_hdr *rx = NULL; + memq_link_t *link; + + link = memq_dequeue(memq_ll_iso_rx.tail, &memq_ll_iso_rx.head, + (void **)&rx); + LL_ASSERT(link); + + mem_release(link, &mem_link_iso_rx.free); + + /* Handle object specific clean up */ + switch (rx->type) { + case NODE_RX_TYPE_ISO_PDU: + break; + default: + LL_ASSERT(0); + break; + } +} + +void ll_iso_rx_mem_release(void **node_rx) +{ + struct node_rx_hdr *rx; + + rx = *node_rx; + while (rx) { + struct node_rx_hdr *rx_free; + + rx_free = rx; + rx = rx->next; + + switch (rx_free->type) { + case NODE_RX_TYPE_ISO_PDU: + mem_release(rx_free, &mem_iso_rx.free); + break; + default: + LL_ASSERT(0); + break; + } + } + + *node_rx = rx; + + RXFIFO_ALLOC(iso_rx, UINT8_MAX); +} +#endif /* CONFIG_BT_CTLR_SYNC_ISO) || CONFIG_BT_CTLR_CONN_ISO */ + void ull_iso_datapath_release(struct ll_iso_datapath *dp) { mem_release(dp, &datapath_free); @@ -529,6 +734,30 @@ void ull_iso_datapath_release(struct ll_iso_datapath *dp) static int init_reset(void) { +#if defined(CONFIG_BT_CTLR_SYNC_ISO) || defined(CONFIG_BT_CTLR_CONN_ISO) + memq_link_t *link; + + RXFIFO_INIT(iso_rx); + + /* Acquire a link to initialize ull rx memq */ + link = mem_acquire(&mem_link_iso_rx.free); + LL_ASSERT(link); + +#if defined(CONFIG_BT_CTLR_ISO_VENDOR_DATA_PATH) + /* Initialize ull rx memq */ + MEMQ_INIT(ull_iso_rx, link); +#endif /* CONFIG_BT_CTLR_ISO_VENDOR_DATA_PATH */ + + /* Acquire a link to initialize ll_iso_rx memq */ + link = mem_acquire(&mem_link_iso_rx.free); + LL_ASSERT(link); + + /* Initialize ll_iso_rx memq */ + MEMQ_INIT(ll_iso_rx, link); + + RXFIFO_ALLOC(iso_rx, UINT8_MAX); +#endif /* CONFIG_BT_CTLR_SYNC_ISO) || CONFIG_BT_CTLR_CONN_ISO */ + #if defined(CONFIG_BT_CTLR_ADV_ISO) || defined(CONFIG_BT_CTLR_CONN_ISO) /* Initialize tx pool. */ mem_init(mem_iso_tx.pool, CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE, diff --git a/subsys/bluetooth/controller/ll_sw/ull_iso_internal.h b/subsys/bluetooth/controller/ll_sw/ull_iso_internal.h index 4b5136bd4ce..78e45275ea6 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_iso_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_iso_internal.h @@ -7,3 +7,6 @@ int ull_iso_init(void); int ull_iso_reset(void); void ull_iso_datapath_release(struct ll_iso_datapath *dp); +void ll_iso_rx_put(memq_link_t *link, void *rx); +void *ll_iso_rx_get(void); +void ll_iso_rx_dequeue(void); diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp.c b/subsys/bluetooth/controller/ll_sw/ull_llcp.c index 2b1a133a6ad..71dbeb6e1ae 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp.c @@ -188,10 +188,15 @@ void llcp_tx_alloc_unpeek(struct proc_ctx *ctx) struct node_tx *llcp_tx_alloc(struct ll_conn *conn, struct proc_ctx *ctx) { + struct pdu_data *pdu; struct node_tx *tx; ARG_UNUSED(conn); tx = (struct node_tx *)mem_acquire(&mem_tx.free); + + pdu = (struct pdu_data *)tx->pdu; + ull_pdu_data_init(pdu); + return tx; } #endif /* LLCP_TX_CTRL_BUF_QUEUE_ENABLE */ @@ -391,7 +396,7 @@ struct proc_ctx *llcp_create_remote_procedure(enum llcp_proc proc) llcp_rp_comm_init_proc(ctx); break; #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ -#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) case PROC_CTE_REQ: llcp_rp_comm_init_proc(ctx); break; @@ -433,6 +438,9 @@ void ull_llcp_init(struct ll_conn *conn) sys_slist_init(&conn->llcp.remote.pend_proc_list); conn->llcp.remote.incompat = INCOMPAT_NO_COLLISION; conn->llcp.remote.collision = 0U; +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) + conn->llcp.remote.paused_cmd = PROC_NONE; +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */ /* Reset the cached version Information (PROC_VERSION_EXCHANGE) */ memset(&conn->llcp.vex, 0, sizeof(conn->llcp.vex)); @@ -452,6 +460,20 @@ void ull_llcp_init(struct ll_conn *conn) conn->lll.enc_rx = 0U; #endif /* CONFIG_BT_CTLR_LE_ENC */ +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) + conn->llcp.cte_req.is_enabled = 0U; + conn->llcp.cte_req.req_expire = 0U; + conn->llcp.cte_req.is_active = 0U; + conn->llcp.cte_req.disable_param = NULL; + conn->llcp.cte_req.disable_cb = NULL; +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) + conn->llcp.cte_rsp.is_enabled = 0U; + conn->llcp.cte_rsp.is_active = 0U; + conn->llcp.cte_rsp.disable_param = NULL; + conn->llcp.cte_rsp.disable_cb = NULL; +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */ + #if defined(LLCP_TX_CTRL_BUF_QUEUE_ENABLE) #if (CONFIG_BT_CTLR_LLCP_PER_CONN_TX_CTRL_BUF_NUM > 0) conn->llcp.tx_buffer_alloc = 0; @@ -886,16 +908,36 @@ uint8_t ull_cp_cte_req(struct ll_conn *conn, uint8_t min_cte_len, uint8_t cte_ty { struct proc_ctx *ctx; - ctx = llcp_create_local_procedure(PROC_CTE_REQ); - if (!ctx) { - return BT_HCI_ERR_CMD_DISALLOWED; + /* The request may be started by periodic CTE request procedure, so it skips earlier + * verification of PHY. In case the PHY has changed to CODE the request should be stopped. + */ +#if defined(CONFIG_BT_CTLR_PHY) + if (conn->lll.phy_rx != PHY_CODED) { +#else + if (1) { +#endif /* CONFIG_BT_CTLR_PHY */ + ctx = llcp_create_local_procedure(PROC_CTE_REQ); + if (!ctx) { + return BT_HCI_ERR_CMD_DISALLOWED; + } + + ctx->data.cte_req.min_len = min_cte_len; + ctx->data.cte_req.type = cte_type; + + conn->llcp.cte_req.is_active = 1U; + + llcp_lr_enqueue(conn, ctx); + + return BT_HCI_ERR_SUCCESS; } - ctx->data.cte_req.min_len = min_cte_len; - ctx->data.cte_req.type = cte_type; - llcp_lr_enqueue(conn, ctx); + return BT_HCI_ERR_CMD_DISALLOWED; +} - return BT_HCI_ERR_SUCCESS; +void ull_cp_cte_req_set_disable(struct ll_conn *conn) +{ + conn->llcp.cte_req.is_enabled = 0U; + conn->llcp.cte_req.req_interval = 0U; } #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp.h b/subsys/bluetooth/controller/ll_sw/ull_llcp.h index c7cf75ee514..2842d1b1fe4 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp.h +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp.h @@ -153,6 +153,11 @@ uint8_t ull_cp_data_length_update(struct ll_conn *conn, uint16_t max_tx_octets, */ uint8_t ull_cp_cte_req(struct ll_conn *conn, uint8_t min_cte_len, uint8_t cte_type); +/** + * @brief Set a CTE Request Procedure disabled. + */ +void ull_cp_cte_req_set_disable(struct ll_conn *conn); + /** * @brief Enable or disable response to CTE Request Procedure. */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_chmu.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_chmu.c index f0955b0936b..50800caa980 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_chmu.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_chmu.c @@ -114,7 +114,7 @@ static void lp_chmu_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t static void lp_chmu_send_channel_map_update_ind(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { - if (llcp_rr_get_collision(conn) || !llcp_tx_alloc_peek(conn, ctx)) { + if (ctx->pause || llcp_rr_get_collision(conn) || !llcp_tx_alloc_peek(conn, ctx)) { ctx->state = LP_CHMU_STATE_WAIT_TX_CHAN_MAP_IND; } else { llcp_rr_set_incompat(conn, INCOMPAT_RESOLVABLE); diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c index 619c2045f02..6a192a6bce7 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c @@ -208,17 +208,31 @@ static void lp_comm_ntf_length_change(struct ll_conn *conn, struct proc_ctx *ctx #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) -static void lp_comm_ntf_cte_req(struct ll_conn *conn, struct proc_ctx *ctx, struct pdu_data *pdu) + +static void lp_comm_complete_cte_req_finalize(struct ll_conn *conn) { - /* TODO (ppryga): pack IQ samples and send them to host */ - /* TODO (ppryga): procedure may be re-triggered periodically by controller itself. - * Add periodicy handling code. It should be executed after receive - * notification about end of current procedure run. + llcp_rr_set_paused_cmd(conn, PROC_NONE); + llcp_lr_complete(conn); + + conn->llcp.cte_req.is_active = 0U; + + /* If disable_cb is not NULL then there is waiting CTE REQ disable request + * from host. Execute the callback to notify waiting thread that the + * procedure is inactive. */ - /* TODO (ppryga): Add handling of rejections in HCI: HCI_LE_CTE_Request_Failed. */ + if (conn->llcp.cte_req.disable_cb) { + conn->llcp.cte_req.disable_cb(conn->llcp.cte_req.disable_param); + } +} + +static void lp_comm_ntf_cte_req(struct ll_conn *conn, struct proc_ctx *ctx, struct pdu_data *pdu) +{ switch (ctx->response_opcode) { case PDU_DATA_LLCTRL_TYPE_CTE_RSP: - llcp_ntf_encode_cte_req(conn, pdu); + /* Notify host that received LL_CTE_RSP does not have CTE */ + if (!ctx->data.cte_remote_rsp.has_cte) { + llcp_ntf_encode_cte_req(pdu); + } break; case PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND: llcp_ntf_encode_reject_ext_ind(ctx, pdu); @@ -351,13 +365,40 @@ static void lp_comm_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) case PROC_CTE_REQ: - if (ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_CTE_RSP || - (ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND && - ctx->reject_ext_ind.reject_opcode == PDU_DATA_LLCTRL_TYPE_CTE_REQ)) { - lp_comm_ntf(conn, ctx); - llcp_lr_complete(conn); + if (ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_CTE_RSP) { + if (ctx->data.cte_remote_rsp.has_cte && + conn->llcp.cte_req.req_interval != 0U) { + conn->llcp.cte_req.req_expire = conn->llcp.cte_req.req_interval; + ctx->state = LP_COMMON_STATE_IDLE; + } else if (llcp_ntf_alloc_is_available()) { + lp_comm_ntf(conn, ctx); + ull_cp_cte_req_set_disable(conn); + ctx->state = LP_COMMON_STATE_IDLE; + } else { + ctx->state = LP_COMMON_STATE_WAIT_NTF; + } + } else if (ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND && + ctx->reject_ext_ind.reject_opcode == PDU_DATA_LLCTRL_TYPE_CTE_REQ) { + if (llcp_ntf_alloc_is_available()) { + lp_comm_ntf(conn, ctx); + ull_cp_cte_req_set_disable(conn); + ctx->state = LP_COMMON_STATE_IDLE; + } else { + ctx->state = LP_COMMON_STATE_WAIT_NTF; + } + } else if (ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_UNUSED) { + /* This path is related with handling disable the CTE REQ when PHY + * has been changed to CODED PHY. BT 5.3 Core Vol 4 Part E 7.8.85 + * says CTE REQ has to be automatically disabled as if it had been requested + * by Host. There is no notification send to Host. + */ + ull_cp_cte_req_set_disable(conn); ctx->state = LP_COMMON_STATE_IDLE; } + + if (ctx->state == LP_COMMON_STATE_IDLE) { + lp_comm_complete_cte_req_finalize(conn); + } break; #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ default: @@ -416,7 +457,7 @@ static void lp_comm_send_req(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t } break; case PROC_TERMINATE: - if (ctx->pause || !llcp_tx_alloc_peek(conn, ctx)) { + if (!llcp_tx_alloc_peek(conn, ctx)) { ctx->state = LP_COMMON_STATE_WAIT_TX; } else { lp_comm_tx(conn, ctx); @@ -449,11 +490,30 @@ static void lp_comm_send_req(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) case PROC_CTE_REQ: - if (ctx->pause || !llcp_tx_alloc_peek(conn, ctx)) { - ctx->state = LP_COMMON_STATE_WAIT_TX; +#if defined(CONFIG_BT_CTLR_PHY) + if (conn->lll.phy_rx != PHY_CODED) { +#else + if (1) { +#endif /* CONFIG_BT_CTLR_PHY */ + if (ctx->pause || !llcp_tx_alloc_peek(conn, ctx) || + (llcp_rr_get_paused_cmd(conn) == PROC_CTE_REQ)) { + ctx->state = LP_COMMON_STATE_WAIT_TX; + } else { + lp_comm_tx(conn, ctx); + ctx->state = LP_COMMON_STATE_WAIT_RX; + } } else { - lp_comm_tx(conn, ctx); - ctx->state = LP_COMMON_STATE_WAIT_RX; + /* The PHY was changed to CODED when the request was waiting in a local + * request queue. + * + * Use of pair: proc PROC_CTE_REQ and rx_opcode PDU_DATA_LLCTRL_TYPE_UNUSED + * to complete the procedure before sending a request to peer. + * This is a special complete execution path to disable the procedure + * due to change of RX PHY to CODED. + */ + ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED; + ctx->state = LP_COMMON_STATE_IDLE; + llcp_lr_complete(conn); } break; #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ @@ -552,9 +612,11 @@ static void lp_comm_rx_decode(struct ll_conn *conn, struct proc_ctx *ctx, struct llcp_pdu_decode_length_rsp(conn, pdu); break; #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) case PDU_DATA_LLCTRL_TYPE_CTE_RSP: - /* CTE Response PDU had no data */ + llcp_pdu_decode_cte_rsp(ctx, pdu); break; +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ case PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND: llcp_pdu_decode_reject_ext_ind(ctx, pdu); break; @@ -595,6 +657,15 @@ static void lp_comm_st_wait_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint ctx->state = LP_COMMON_STATE_IDLE; } break; +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) + case PROC_CTE_REQ: + if (llcp_ntf_alloc_is_available()) { + lp_comm_ntf(conn, ctx); + ctx->state = LP_COMMON_STATE_IDLE; + lp_comm_complete_cte_req_finalize(conn); + } + break; +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ default: break; } @@ -692,11 +763,11 @@ static void rp_comm_rx_decode(struct ll_conn *conn, struct proc_ctx *ctx, struct llcp_tx_pause_data(conn); break; #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ -#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) case PDU_DATA_LLCTRL_TYPE_CTE_REQ: - llcp_pdu_decode_cte_req(conn, pdu); + llcp_pdu_decode_cte_req(ctx, pdu); break; -#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */ default: /* Unknown opcode */ LL_ASSERT(0); @@ -737,36 +808,40 @@ static void rp_comm_tx(struct ll_conn *conn, struct proc_ctx *ctx) ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_LENGTH_RSP; break; #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ -#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) case PROC_CTE_REQ: { uint8_t err_code = 0; if (conn->llcp.cte_rsp.is_enabled == 0) { err_code = BT_HCI_ERR_UNSUPP_LL_PARAM_VAL; } + #if defined(CONFIG_BT_PHY_UPDATE) /* If the PHY update is not possible, then PHY1M is used. * CTE is supported for PHY1M. */ - if (conn->lll.phy_tx != PHY_CODED) { + if (conn->lll.phy_tx == PHY_CODED) { err_code = BT_HCI_ERR_INVALID_LL_PARAM; } #endif /* CONFIG_BT_PHY_UPDATE */ - if (!(conn->llcp.cte_rsp.cte_types & BIT(conn->llcp.cte_req.cte_type)) && - conn->llcp.cte_rsp.max_cte_len >= conn->llcp.cte_req.min_cte_len) { + if (!(conn->llcp.cte_rsp.cte_types & BIT(ctx->data.cte_remote_req.cte_type)) || + conn->llcp.cte_rsp.max_cte_len < ctx->data.cte_remote_req.min_cte_len) { err_code = BT_HCI_ERR_UNSUPP_LL_PARAM_VAL; } if (!err_code) { - llcp_pdu_encode_cte_rsp(pdu); + llcp_pdu_encode_cte_rsp(ctx, pdu); ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_CTE_RSP; } else { llcp_pdu_encode_reject_ext_ind(pdu, PDU_DATA_LLCTRL_TYPE_CTE_REQ, err_code); ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND; } + + ctx->tx_ack = tx; + break; } -#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */ default: /* Unknown procedure */ LL_ASSERT(0); @@ -920,17 +995,18 @@ static void rp_comm_send_rsp(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t } break; #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ -#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) case PROC_CTE_REQ: - if (ctx->pause || !llcp_tx_alloc_peek(conn, ctx)) { + if (ctx->pause || !llcp_tx_alloc_peek(conn, ctx) || + (llcp_rr_get_paused_cmd(conn) == PROC_CTE_REQ)) { ctx->state = RP_COMMON_STATE_WAIT_TX; } else { + llcp_rr_set_paused_cmd(conn, PROC_PHY_UPDATE); rp_comm_tx(conn, ctx); - llcp_rr_complete(conn); - ctx->state = RP_COMMON_STATE_IDLE; + ctx->state = RP_COMMON_STATE_WAIT_TX_ACK; } break; -#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */ default: /* Unknown procedure */ LL_ASSERT(0); @@ -962,13 +1038,13 @@ static void rp_comm_st_wait_tx(struct ll_conn *conn, struct proc_ctx *ctx, uint8 } } -#if defined(CONFIG_BT_CTLR_DATA_LENGTH) static void rp_comm_st_wait_tx_ack(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { switch (evt) { case RP_COMMON_EVT_ACK: switch (ctx->proc) { +#if defined(CONFIG_BT_CTLR_DATA_LENGTH) case PROC_DATA_LENGTH_UPDATE: { /* Apply changes in data lengths/times */ uint8_t dle_changed = ull_dle_update_eff(conn); @@ -986,6 +1062,16 @@ static void rp_comm_st_wait_tx_ack(struct ll_conn *conn, struct proc_ctx *ctx, u } break; } +#endif /* CONFIG_BT_CTLR_DATA_LENGTH */ +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) + case PROC_CTE_REQ: { + /* add PHY update pause = false here */ + ctx->tx_ack = NULL; + llcp_rr_set_paused_cmd(conn, PROC_NONE); + llcp_rr_complete(conn); + ctx->state = RP_COMMON_STATE_IDLE; + } +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */ default: /* Ignore other procedures */ break; @@ -997,6 +1083,7 @@ static void rp_comm_st_wait_tx_ack(struct ll_conn *conn, struct proc_ctx *ctx, u } } +#if defined(CONFIG_BT_CTLR_DATA_LENGTH) static void rp_comm_st_wait_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { @@ -1021,10 +1108,10 @@ static void rp_comm_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint case RP_COMMON_STATE_WAIT_TX: rp_comm_st_wait_tx(conn, ctx, evt, param); break; -#if defined(CONFIG_BT_CTLR_DATA_LENGTH) case RP_COMMON_STATE_WAIT_TX_ACK: rp_comm_st_wait_tx_ack(conn, ctx, evt, param); break; +#if defined(CONFIG_BT_CTLR_DATA_LENGTH) case RP_COMMON_STATE_WAIT_NTF: rp_comm_st_wait_ntf(conn, ctx, evt, param); break; diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_conn_upd.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_conn_upd.c index cb194bd92cf..7773d6cd958 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_conn_upd.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_conn_upd.c @@ -217,7 +217,7 @@ static void lp_cu_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t e static void lp_cu_send_conn_param_req(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { - if (llcp_rr_get_collision(conn) || !llcp_tx_alloc_peek(conn, ctx)) { + if (ctx->pause || llcp_rr_get_collision(conn) || !llcp_tx_alloc_peek(conn, ctx)) { ctx->state = LP_CU_STATE_WAIT_TX_CONN_PARAM_REQ; } else { uint16_t event_counter = ull_conn_event_counter(conn); @@ -261,7 +261,7 @@ static void lp_cu_send_conn_param_req(struct ll_conn *conn, struct proc_ctx *ctx static void lp_cu_send_conn_update_ind(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { - if (!llcp_tx_alloc_peek(conn, ctx)) { + if (ctx->pause || !llcp_tx_alloc_peek(conn, ctx)) { ctx->state = LP_CU_STATE_WAIT_TX_CONN_UPDATE_IND; } else { ctx->data.cu.win_size = 1U; @@ -626,7 +626,7 @@ static void rp_cu_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t e static void rp_cu_send_conn_update_ind(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { - if (!llcp_tx_alloc_peek(conn, ctx)) { + if (ctx->pause || !llcp_tx_alloc_peek(conn, ctx)) { ctx->state = RP_CU_STATE_WAIT_TX_CONN_UPDATE_IND; } else { ctx->data.cu.win_size = 1U; @@ -643,7 +643,7 @@ static void rp_cu_send_conn_update_ind(struct ll_conn *conn, struct proc_ctx *ct static void rp_cu_send_reject_ext_ind(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { - if (!llcp_tx_alloc_peek(conn, ctx)) { + if (ctx->pause || !llcp_tx_alloc_peek(conn, ctx)) { ctx->state = RP_CU_STATE_WAIT_TX_REJECT_EXT_IND; } else { rp_cu_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND); @@ -655,7 +655,7 @@ static void rp_cu_send_reject_ext_ind(struct ll_conn *conn, struct proc_ctx *ctx static void rp_cu_send_conn_param_rsp(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { - if (!llcp_tx_alloc_peek(conn, ctx)) { + if (ctx->pause || !llcp_tx_alloc_peek(conn, ctx)) { ctx->state = RP_CU_STATE_WAIT_TX_CONN_PARAM_RSP; } else { rp_cu_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_CONN_PARAM_RSP); @@ -679,7 +679,7 @@ static void rp_cu_send_conn_param_req_ntf(struct ll_conn *conn, struct proc_ctx static void rp_cu_send_unknown_rsp(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { - if (!llcp_tx_alloc_peek(conn, ctx)) { + if (ctx->pause || !llcp_tx_alloc_peek(conn, ctx)) { ctx->state = RP_CU_STATE_WAIT_TX_UNKNOWN_RSP; } else { rp_cu_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_UNKNOWN_RSP); diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_enc.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_enc.c index bba4fea04a1..11fb731f218 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_enc.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_enc.c @@ -250,6 +250,10 @@ static void lp_enc_send_enc_req(struct ll_conn *conn, struct proc_ctx *ctx, uint /* Wait for the LL_ENC_RSP */ ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_ENC_RSP; ctx->state = LP_ENC_STATE_WAIT_RX_ENC_RSP; + + /* Pause possibly ongoing remote procedure */ + llcp_rr_pause(conn); + } } @@ -410,6 +414,9 @@ static void lp_enc_st_wait_rx_start_enc_req(struct ll_conn *conn, struct proc_ct ctx->data.enc.error = (pdu->llctrl.opcode == PDU_DATA_LLCTRL_TYPE_REJECT_IND) ? pdu->llctrl.reject_ind.error_code : pdu->llctrl.reject_ext_ind.error_code; + /* Resume possibly paused remote procedure */ + llcp_rr_resume(conn); + lp_enc_complete(conn, ctx, evt, param); break; default: @@ -441,6 +448,10 @@ static void lp_enc_st_wait_rx_start_enc_rsp(struct ll_conn *conn, struct proc_ct /* Resume Rx data */ ull_conn_resume_rx_data(conn); ctx->data.enc.error = BT_HCI_ERR_SUCCESS; + + /* Resume possibly paused remote procedure */ + llcp_rr_resume(conn); + lp_enc_complete(conn, ctx, evt, param); break; default: @@ -817,6 +828,8 @@ static void rp_enc_send_reject_ind(struct ll_conn *conn, struct proc_ctx *ctx, u llcp_tx_resume_data(conn); /* Resume Rx data */ ull_conn_resume_rx_data(conn); + /* Resume possibly paused local procedure */ + llcp_lr_resume(conn); } } @@ -835,6 +848,9 @@ static void rp_enc_send_start_enc_rsp(struct ll_conn *conn, struct proc_ctx *ctx /* Resume Rx data */ ull_conn_resume_rx_data(conn); + /* Resume possibly paused local procedure */ + llcp_lr_resume(conn); + /* Tx Encryption enabled */ conn->lll.enc_tx = 1U; } @@ -898,6 +914,10 @@ static void rp_enc_state_wait_rx_enc_req(struct ll_conn *conn, struct proc_ctx * llcp_tx_flush(conn); /* Pause Rx data */ ull_conn_pause_rx_data(conn); + + /* Pause possibly paused local procedure */ + llcp_lr_pause(conn); + rp_enc_store_m(conn, ctx, param); rp_enc_send_enc_rsp(conn, ctx, evt, param); break; diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h b/subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h index 10cf74c3b34..cab97dcb05d 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h @@ -20,6 +20,8 @@ enum llcp_proc { PROC_CHAN_MAP_UPDATE, PROC_DATA_LENGTH_UPDATE, PROC_CTE_REQ, + /* A helper enum entry, to use in pause prcedure context */ + PROC_NONE = 0x0, }; #if ((CONFIG_BT_CTLR_LLCP_COMMON_TX_CTRL_BUF_NUM <\ (CONFIG_BT_CTLR_LLCP_TX_PER_CONN_TX_CTRL_BUF_NUM_MAX *\ @@ -220,7 +222,21 @@ struct proc_ctx { uint8_t type:2; uint8_t min_len:5; } cte_req; + + struct llcp_df_cte_remote_rsp { + /* Storage for information that received LL_CTE_RSP PDU includes CTE */ + uint8_t has_cte; + } cte_remote_rsp; #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ + +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) + /* Use by CTE Response Procedure */ + struct llcp_df_cte_remote_req { + uint8_t cte_type; + uint8_t min_cte_len; + } cte_remote_req; +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */ + } data; struct { @@ -415,6 +431,8 @@ void llcp_pdu_decode_terminate_ind(struct proc_ctx *ctx, struct pdu_data *pdu); * LLCP Local Request */ struct proc_ctx *llcp_lr_peek(struct ll_conn *conn); +void llcp_lr_pause(struct ll_conn *conn); +void llcp_lr_resume(struct ll_conn *conn); void llcp_lr_tx_ack(struct ll_conn *conn, struct proc_ctx *ctx, struct node_tx *tx); void llcp_lr_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pdu *rx); void llcp_lr_enqueue(struct ll_conn *conn, struct proc_ctx *ctx); @@ -430,7 +448,11 @@ void llcp_lr_abort(struct ll_conn *conn); */ void llcp_rr_set_incompat(struct ll_conn *conn, enum proc_incompat incompat); bool llcp_rr_get_collision(struct ll_conn *conn); +void llcp_rr_set_paused_cmd(struct ll_conn *conn, enum llcp_proc); +enum llcp_proc llcp_rr_get_paused_cmd(struct ll_conn *conn); struct proc_ctx *llcp_rr_peek(struct ll_conn *conn); +void llcp_rr_pause(struct ll_conn *conn); +void llcp_rr_resume(struct ll_conn *conn); void llcp_rr_tx_ack(struct ll_conn *conn, struct proc_ctx *ctx, struct node_tx *tx); void llcp_rr_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pdu *rx); void llcp_rr_init(struct ll_conn *conn); @@ -578,11 +600,18 @@ void llcp_ntf_encode_length_change(struct ll_conn *conn, * Constant Tone Request Procedure Helper */ void llcp_pdu_encode_cte_req(struct proc_ctx *ctx, struct pdu_data *pdu); -void llcp_ntf_encode_cte_req(struct ll_conn *conn, struct pdu_data *pdu); -void llcp_pdu_decode_cte_req(struct ll_conn *conn, struct pdu_data *pdu); -void llcp_pdu_encode_cte_rsp(struct pdu_data *pdu); +void llcp_pdu_decode_cte_rsp(struct proc_ctx *ctx, const struct pdu_data *pdu); +void llcp_ntf_encode_cte_req(struct pdu_data *pdu); #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) +/* + * Constant Tone Response Procedure Helper + */ +void llcp_pdu_decode_cte_req(struct proc_ctx *ctx, struct pdu_data *pdu); +void llcp_pdu_encode_cte_rsp(const struct proc_ctx *ctx, struct pdu_data *pdu); +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */ + #ifdef ZTEST_UNITTEST bool lr_is_disconnected(struct ll_conn *conn); bool lr_is_idle(struct ll_conn *conn); diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_local.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_local.c index e142dd192e6..2b0c012b217 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_local.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_local.c @@ -112,6 +112,26 @@ struct proc_ctx *llcp_lr_peek(struct ll_conn *conn) return ctx; } +void llcp_lr_pause(struct ll_conn *conn) +{ + struct proc_ctx *ctx; + + ctx = (struct proc_ctx *)sys_slist_peek_head(&conn->llcp.local.pend_proc_list); + if (ctx) { + ctx->pause = 1; + } +} + +void llcp_lr_resume(struct ll_conn *conn) +{ + struct proc_ctx *ctx; + + ctx = (struct proc_ctx *)sys_slist_peek_head(&conn->llcp.local.pend_proc_list); + if (ctx) { + ctx->pause = 0; + } +} + void llcp_lr_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pdu *rx) { switch (ctx->proc) { @@ -326,6 +346,12 @@ static void lr_st_idle(struct ll_conn *conn, uint8_t evt, void *param) lr_act_disconnect(conn); lr_set_state(conn, LR_STATE_DISCONNECT); break; + case LR_EVT_COMPLETE: + /* Some procedures like CTE request may be completed without actual run due to + * change in conditions while the procedure was waiting in a queue. + */ + lr_act_complete(conn); + break; default: /* Ignore other evts */ break; diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_pdu.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_pdu.c index 60f0a0e7328..54c56a713e5 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_pdu.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_pdu.c @@ -727,27 +727,46 @@ void llcp_pdu_encode_cte_req(struct proc_ctx *ctx, struct pdu_data *pdu) p->cte_type_req = ctx->data.cte_req.type; } -void llcp_ntf_encode_cte_req(struct ll_conn *conn, struct pdu_data *pdu) +void llcp_pdu_decode_cte_rsp(struct proc_ctx *ctx, const struct pdu_data *pdu) +{ + if (pdu->cp == 0U || pdu->cte_info.time == 0U) { + ctx->data.cte_remote_rsp.has_cte = false; + } else { + ctx->data.cte_remote_rsp.has_cte = true; + } +} + +void llcp_ntf_encode_cte_req(struct pdu_data *pdu) { pdu->ll_id = PDU_DATA_LLID_CTRL; pdu->len = offsetof(struct pdu_data_llctrl, cte_rsp) + sizeof(struct pdu_data_llctrl_cte_rsp); pdu->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_CTE_RSP; - /* TODO add handling of IQ samples forwarding */ + /* Received LL_CTE_RSP PDU didn't have CTE */ + pdu->cp = 0U; } +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ -void llcp_pdu_decode_cte_req(struct ll_conn *conn, struct pdu_data *pdu) +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) +void llcp_pdu_decode_cte_req(struct proc_ctx *ctx, struct pdu_data *pdu) { - conn->llcp.cte_req.min_cte_len = pdu->llctrl.cte_req.min_cte_len_req; - conn->llcp.cte_req.cte_type = pdu->llctrl.cte_req.cte_type_req; + ctx->data.cte_remote_req.min_cte_len = pdu->llctrl.cte_req.min_cte_len_req; + ctx->data.cte_remote_req.cte_type = pdu->llctrl.cte_req.cte_type_req; } -void llcp_pdu_encode_cte_rsp(struct pdu_data *pdu) +void llcp_pdu_encode_cte_rsp(const struct proc_ctx *ctx, struct pdu_data *pdu) { pdu->ll_id = PDU_DATA_LLID_CTRL; pdu->len = - offsetof(struct pdu_data_llctrl, cte_rsp) + sizeof(struct pdu_data_llctrl_cte_rsp); + offsetof(struct pdu_data_llctrl, cte_rsp) + sizeof(struct pdu_data_llctrl_cte_rsp); pdu->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_CTE_RSP; + + /* Set content of a PDU header first byte, that is not changed by LLL */ + pdu->cp = 1U; + pdu->rfu = 0U; + + pdu->cte_info.time = ctx->data.cte_remote_req.min_cte_len; + pdu->cte_info.type = ctx->data.cte_remote_req.cte_type; } -#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_phy.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_phy.c index 021b2a35cc3..46f90c732c2 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_phy.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_phy.c @@ -435,15 +435,18 @@ static void lp_pu_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t e #endif llcp_lr_complete(conn); ctx->state = LP_PU_STATE_IDLE; + llcp_rr_set_paused_cmd(conn, PROC_NONE); } } static void lp_pu_send_phy_req(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { - if (llcp_rr_get_collision(conn) || !llcp_tx_alloc_peek(conn, ctx)) { + if (ctx->pause || llcp_rr_get_collision(conn) || !llcp_tx_alloc_peek(conn, ctx) || + (llcp_rr_get_paused_cmd(conn) == PROC_PHY_UPDATE)) { ctx->state = LP_PU_STATE_WAIT_TX_PHY_REQ; } else { llcp_rr_set_incompat(conn, INCOMPAT_RESOLVABLE); + llcp_rr_set_paused_cmd(conn, PROC_CTE_REQ); lp_pu_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_PHY_REQ); llcp_tx_pause_data(conn); ctx->state = LP_PU_STATE_WAIT_TX_ACK_PHY_REQ; @@ -454,7 +457,7 @@ static void lp_pu_send_phy_req(struct ll_conn *conn, struct proc_ctx *ctx, uint8 static void lp_pu_send_phy_update_ind(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { - if (!llcp_tx_alloc_peek(conn, ctx)) { + if (ctx->pause || !llcp_tx_alloc_peek(conn, ctx)) { ctx->state = LP_PU_STATE_WAIT_TX_PHY_UPDATE_IND; } else { ctx->data.pu.instant = pu_event_counter(conn) + PHY_UPDATE_INSTANT_DELTA; @@ -832,6 +835,7 @@ static void rp_pu_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t e pu_dle_ntf(conn, ctx); } #endif + llcp_rr_set_paused_cmd(conn, PROC_NONE); llcp_rr_complete(conn); ctx->state = RP_PU_STATE_IDLE; } @@ -841,9 +845,11 @@ static void rp_pu_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t e static void rp_pu_send_phy_update_ind(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { - if (!llcp_tx_alloc_peek(conn, ctx)) { + if (ctx->pause || !llcp_tx_alloc_peek(conn, ctx) || + (llcp_rr_get_paused_cmd(conn) == PROC_PHY_UPDATE)) { ctx->state = RP_PU_STATE_WAIT_TX_PHY_UPDATE_IND; } else { + llcp_rr_set_paused_cmd(conn, PROC_CTE_REQ); ctx->data.pu.instant = pu_event_counter(conn) + PHY_UPDATE_INSTANT_DELTA; rp_pu_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_PHY_UPD_IND); ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED; @@ -855,9 +861,11 @@ static void rp_pu_send_phy_update_ind(struct ll_conn *conn, struct proc_ctx *ctx #if defined(CONFIG_BT_PERIPHERAL) static void rp_pu_send_phy_rsp(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param) { - if (!llcp_tx_alloc_peek(conn, ctx)) { + if (ctx->pause || !llcp_tx_alloc_peek(conn, ctx) || + (llcp_rr_get_paused_cmd(conn) == PROC_PHY_UPDATE)) { ctx->state = RP_PU_STATE_WAIT_TX_PHY_RSP; } else { + llcp_rr_set_paused_cmd(conn, PROC_CTE_REQ); rp_pu_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_PHY_RSP); ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_PHY_UPD_IND; ctx->state = RP_PU_STATE_WAIT_TX_ACK_PHY_RSP; diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_remote.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_remote.c index 9f2ea5e3bea..927607ef9ac 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_remote.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_remote.c @@ -136,6 +136,22 @@ void llcp_rr_set_incompat(struct ll_conn *conn, enum proc_incompat incompat) conn->llcp.remote.incompat = incompat; } +void llcp_rr_set_paused_cmd(struct ll_conn *conn, enum llcp_proc proc) +{ +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) || defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) + conn->llcp.remote.paused_cmd = proc; +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP || CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ +} + +enum llcp_proc llcp_rr_get_paused_cmd(struct ll_conn *conn) +{ +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) || defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) + return conn->llcp.remote.paused_cmd; +#else + return PROC_NONE; +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP || CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ +} + static enum proc_incompat rr_get_incompat(struct ll_conn *conn) { return conn->llcp.remote.incompat; @@ -172,6 +188,27 @@ struct proc_ctx *llcp_rr_peek(struct ll_conn *conn) return ctx; } +void llcp_rr_pause(struct ll_conn *conn) +{ + struct proc_ctx *ctx; + + ctx = (struct proc_ctx *)sys_slist_peek_head(&conn->llcp.remote.pend_proc_list); + if (ctx) { + ctx->pause = 1; + } +} + +void llcp_rr_resume(struct ll_conn *conn) +{ + struct proc_ctx *ctx; + + ctx = (struct proc_ctx *)sys_slist_peek_head(&conn->llcp.remote.pend_proc_list); + if (ctx) { + ctx->pause = 0; + } +} + + void llcp_rr_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pdu *rx) { switch (ctx->proc) { @@ -219,11 +256,11 @@ void llcp_rr_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pdu * llcp_rp_comm_rx(conn, ctx, rx); break; #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ -#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) case PROC_CTE_REQ: llcp_rp_comm_rx(conn, ctx, rx); break; -#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */ default: /* Unknown procedure */ LL_ASSERT(0); @@ -245,6 +282,11 @@ void llcp_rr_tx_ack(struct ll_conn *conn, struct proc_ctx *ctx, struct node_tx * llcp_rp_pu_tx_ack(conn, ctx, tx); break; #endif /* CONFIG_BT_CTLR_PHY */ +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) + case PROC_CTE_REQ: + llcp_rp_comm_tx_ack(conn, ctx, tx); + break; +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */ default: /* Ignore tx_ack */ break; @@ -304,11 +346,11 @@ static void rr_act_run(struct ll_conn *conn) llcp_rp_comm_run(conn, ctx, NULL); break; #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ -#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) case PROC_CTE_REQ: llcp_rp_comm_run(conn, ctx, NULL); break; -#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RSP */ default: /* Unknown procedure */ LL_ASSERT(0); @@ -352,7 +394,7 @@ static void rr_act_reject(struct ll_conn *conn) LL_ASSERT(ctx != NULL); - if (!llcp_tx_alloc_peek(conn, ctx)) { + if (ctx->pause || !llcp_tx_alloc_peek(conn, ctx)) { rr_set_state(conn, RR_STATE_REJECT); } else { rr_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_REJECT_IND); @@ -429,7 +471,7 @@ static void rr_st_idle(struct ll_conn *conn, uint8_t evt, void *param) /* Run remote procedure */ rr_act_run(conn); rr_set_state(conn, RR_STATE_TERMINATE); - } else if (incompat == INCOMPAT_NO_COLLISION) { + } else if (!with_instant || incompat == INCOMPAT_NO_COLLISION) { /* No collision * => Run procedure * @@ -465,6 +507,12 @@ static void rr_st_idle(struct ll_conn *conn, uint8_t evt, void *param) conn->llcp.remote.reject_opcode = pdu->llctrl.opcode; rr_act_reject(conn); + } else if (!with_instant && central && incompat == INCOMPAT_RESOLVABLE) { + /* No collision with procedure without instant + * => Run procedure + */ + rr_act_run(conn); + rr_set_state(conn, RR_STATE_ACTIVE); } else if (with_instant && incompat == INCOMPAT_RESERVED) { /* Protocol violation. * => Disconnect diff --git a/subsys/bluetooth/controller/ll_sw/ull_scan.c b/subsys/bluetooth/controller/ll_sw/ull_scan.c index 93fad1907f6..62ce791de4d 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_scan.c +++ b/subsys/bluetooth/controller/ll_sw/ull_scan.c @@ -355,13 +355,20 @@ void ull_scan_params_set(struct lll_scan *lll, uint8_t type, uint16_t interval, uint8_t ull_scan_enable(struct ll_scan_set *scan) { - struct lll_scan *lll = &scan->lll; uint32_t ticks_slot_overhead; uint32_t volatile ret_cb; uint32_t ticks_interval; uint32_t ticks_anchor; + struct lll_scan *lll; uint32_t ret; +#if defined(CONFIG_BT_CTLR_ADV_EXT) + /* Initialize extend scan stop request */ + scan->is_stop = 0U; +#endif /* CONFIG_BT_CTLR_ADV_EXT */ + + /* Initialize LLL scan context */ + lll = &scan->lll; lll->init_addr_type = scan->own_addr_type; (void)ll_addr_read(lll->init_addr_type, lll->init_addr); lll->chan = 0U; @@ -462,6 +469,12 @@ uint8_t ull_scan_disable(uint8_t handle, struct ll_scan_set *scan) { int err; +#if defined(CONFIG_BT_CTLR_ADV_EXT) + /* Request Extended Scan stop */ + scan->is_stop = 1U; + cpu_dmb(); +#endif /* CONFIG_BT_CTLR_ADV_EXT */ + err = ull_ticker_stop_with_mark(TICKER_ID_SCAN_BASE + handle, scan, &scan->lll); LL_ASSERT(err == 0 || err == -EALREADY); @@ -469,6 +482,30 @@ uint8_t ull_scan_disable(uint8_t handle, struct ll_scan_set *scan) return BT_HCI_ERR_CMD_DISALLOWED; } +#if defined(CONFIG_BT_CTLR_ADV_EXT) + /* Find and stop associated auxiliary scan contexts */ + for (uint8_t aux_handle = 0; aux_handle < CONFIG_BT_CTLR_SCAN_AUX_SET; + aux_handle++) { + struct lll_scan_aux *aux_scan_lll; + struct ll_scan_set *aux_scan; + struct ll_scan_aux_set *aux; + + aux = ull_scan_aux_set_get(aux_handle); + aux_scan_lll = aux->parent; + if (!aux_scan_lll) { + continue; + } + + aux_scan = HDR_LLL2ULL(aux_scan_lll); + if (aux_scan == scan) { + err = ull_scan_aux_stop(aux); + if (err && (err != -EALREADY)) { + return BT_HCI_ERR_CMD_DISALLOWED; + } + } + } +#endif /* CONFIG_BT_CTLR_ADV_EXT */ + return 0; } @@ -588,6 +625,19 @@ struct ll_scan_set *ull_scan_is_valid_get(struct ll_scan_set *scan) return scan; } +struct lll_scan *ull_scan_lll_is_valid_get(struct lll_scan *lll) +{ + struct ll_scan_set *scan; + + scan = HDR_LLL2ULL(lll); + scan = ull_scan_is_valid_get(scan); + if (scan) { + return &scan->lll; + } + + return NULL; +} + struct ll_scan_set *ull_scan_is_enabled_get(uint8_t handle) { struct ll_scan_set *scan; @@ -621,7 +671,7 @@ uint32_t ull_scan_is_enabled(uint8_t handle) #if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) scan = ull_scan_set_get(handle); - return scan->per_scan.sync ? ULL_SCAN_IS_SYNC : 0U; + return scan->periodic.sync ? ULL_SCAN_IS_SYNC : 0U; #else return 0U; #endif @@ -632,7 +682,7 @@ uint32_t ull_scan_is_enabled(uint8_t handle) (scan->lll.conn ? ULL_SCAN_IS_INITIATOR : 0U) | #endif #if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) - (scan->per_scan.sync ? ULL_SCAN_IS_SYNC : 0U) | + (scan->periodic.sync ? ULL_SCAN_IS_SYNC : 0U) | #endif 0U); } diff --git a/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c b/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c index fa984ec7b83..720a7d0cd80 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c +++ b/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c @@ -50,14 +50,20 @@ static inline uint8_t aux_handle_get(struct ll_scan_aux_set *aux); static inline struct ll_sync_set *sync_create_get(struct ll_scan_set *scan); static inline struct ll_sync_iso_set * sync_iso_create_get(struct ll_sync_set *sync); -static void last_disabled_cb(void *param); static void done_disabled_cb(void *param); static void flush(void *param); +static void rx_release_put(struct node_rx_hdr *rx); +static void aux_sync_incomplete(void *param); static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, uint32_t remainder, uint16_t lazy, uint8_t force, void *param); static void ticker_op_cb(uint32_t status, void *param); +/* Auxiliary context pool used for reception of PDUs at aux offsets, common for + * both Extended Advertising and Periodic Advertising. + * Increasing the count allows simultaneous reception of interleaved chain PDUs + * from multiple advertisers. + */ static struct ll_scan_aux_set ll_scan_aux_pool[CONFIG_BT_CTLR_SCAN_AUX_SET]; static void *scan_aux_free; @@ -87,6 +93,7 @@ int ull_scan_aux_reset(void) void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) { + struct node_rx_hdr *rx_incomplete; struct ll_sync_iso_set *sync_iso; struct pdu_adv_aux_ptr *aux_ptr; struct pdu_adv_com_ext_adv *p; @@ -107,9 +114,11 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) uint32_t ticker_status; struct lll_scan *lll; struct pdu_adv *pdu; + uint8_t hdr_buf_len; uint8_t aux_handle; bool is_scan_req; uint8_t acad_len; + uint8_t data_len; uint8_t hdr_len; uint8_t *ptr; uint8_t phy; @@ -117,14 +126,17 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) is_scan_req = false; ftr = &rx->rx_ftr; - sync_lll = NULL; - switch (rx->type) { case NODE_RX_TYPE_EXT_1M_REPORT: lll_aux = NULL; aux = NULL; + sync_lll = NULL; sync_iso = NULL; + rx_incomplete = NULL; + lll = ftr->param; + LL_ASSERT(!lll->lll_aux); + scan = HDR_LLL2ULL(lll); sync = sync_create_get(scan); phy = BT_HCI_LE_EXT_SCAN_PHY_1M; @@ -132,15 +144,23 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) case NODE_RX_TYPE_EXT_CODED_REPORT: lll_aux = NULL; aux = NULL; + sync_lll = NULL; sync_iso = NULL; + rx_incomplete = NULL; + lll = ftr->param; + LL_ASSERT(!lll->lll_aux); + scan = HDR_LLL2ULL(lll); sync = sync_create_get(scan); phy = BT_HCI_LE_EXT_SCAN_PHY_CODED; break; case NODE_RX_TYPE_EXT_AUX_REPORT: sync_iso = NULL; + rx_incomplete = NULL; if (ull_scan_aux_is_valid_get(HDR_LLL2ULL(ftr->param))) { + sync_lll = NULL; + /* Node has valid aux context so its scan was scheduled * from ULL. */ @@ -149,7 +169,12 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) /* aux parent will be NULL for periodic sync */ lll = aux->parent; - } else if (ull_scan_is_valid_get(HDR_LLL2ULL(ftr->param))) { + LL_ASSERT(lll); + + } else if (!IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) || + ull_scan_is_valid_get(HDR_LLL2ULL(ftr->param))) { + sync_lll = NULL; + /* Node that does not have valid aux context but has * valid scan set was scheduled from LLL. We can * retrieve aux context from lll_scan as it was stored @@ -162,17 +187,22 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) aux = HDR_LLL2ULL(lll_aux); LL_ASSERT(lll == aux->parent); + } else { + lll = NULL; + /* If none of the above, node is part of sync scanning */ - lll = NULL; sync_lll = ftr->param; lll_aux = sync_lll->lll_aux; + LL_ASSERT(lll_aux); + aux = HDR_LLL2ULL(lll_aux); + LL_ASSERT(sync_lll == aux->parent); } - if (lll) { + if (!IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) || lll) { scan = HDR_LLL2ULL(lll); sync = (void *)scan; scan = ull_scan_is_valid_get(scan); @@ -185,7 +215,7 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) } phy = lll_aux->phy; - if (scan) { + if (!IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) || scan) { /* Here we are scanner context */ sync = sync_create_get(scan); @@ -217,8 +247,6 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) rx->type = NODE_RX_TYPE_SYNC_REPORT; rx->handle = ull_sync_handle_get(sync); - sync_lll = &sync->lll; - /* Check if we need to create BIG sync */ sync_iso = sync_iso_create_get(sync); @@ -238,6 +266,8 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) * passed in the node rx footer field. */ sync_lll = ftr->param; + LL_ASSERT(!sync_lll->lll_aux); + ull_sync = HDR_LLL2ULL(sync_lll); rx->handle = ull_sync_handle_get(ull_sync); @@ -254,6 +284,11 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) scan = NULL; sync = NULL; phy = sync_lll->phy; + + /* backup extra node_rx supplied for generating + * incomplete report + */ + rx_incomplete = ftr->extra; #endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */ } @@ -266,11 +301,30 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) rx->link = link; ftr->extra = NULL; - ftr->aux_w4next = 0; + ftr->aux_sched = 0U; pdu = (void *)((struct node_rx_pdu *)rx)->pdu; p = (void *)&pdu->adv_ext_ind; - if (!p->ext_hdr_len) { + if (!pdu->len || !p->ext_hdr_len) { + if (pdu->len) { + data_len = pdu->len - PDU_AC_EXT_HEADER_SIZE_MIN; + } else { + data_len = 0U; + } + + if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) && sync_lll) { + struct ll_sync_set *sync; + + sync = HDR_LLL2ULL(sync_lll); + ftr->aux_data_len = sync->data_len + data_len; + sync->data_len = 0U; + } else if (aux) { + aux->data_len += data_len; + ftr->aux_data_len = aux->data_len; + } else { + ftr->aux_data_len = data_len; + } + goto ull_scan_aux_rx_flush; } @@ -290,7 +344,7 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) #if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) /* Check if Periodic Advertising Synchronization to be created */ - if (sync && (scan->per_scan.state != LL_SYNC_STATE_CREATED)) { + if (sync && (scan->periodic.state != LL_SYNC_STATE_CREATED)) { /* Check address and update internal state */ #if defined(CONFIG_BT_CTLR_PRIVACY) ull_sync_setup_addr_check(scan, pdu->tx_addr, ptr, @@ -331,15 +385,14 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) si = (void *)ptr; ptr += sizeof(*si); -#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) /* Check if Periodic Advertising Synchronization to be created. * Setup synchronization if address and SID match in the * Periodic Advertiser List or with the explicitly supplied. */ - if (sync && adi && ull_sync_setup_sid_match(scan, adi->sid)) { + if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) && sync && adi && + ull_sync_setup_sid_match(scan, adi->sid)) { ull_sync_setup(scan, aux, rx, si); } -#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */ } if (h->tx_pwr) { @@ -348,14 +401,20 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) /* Calculate ACAD Len */ hdr_len = ptr - (uint8_t *)p; - if (hdr_len <= (p->ext_hdr_len + offsetof(struct pdu_adv_com_ext_adv, - ext_hdr_adv_data))) { - acad_len = p->ext_hdr_len + - offsetof(struct pdu_adv_com_ext_adv, - ext_hdr_adv_data) - - hdr_len; - } else { + hdr_buf_len = PDU_AC_EXT_HEADER_SIZE_MIN + p->ext_hdr_len; + if (hdr_len > hdr_buf_len) { + /* FIXME: Handle invalid header length */ acad_len = 0U; + } else { + acad_len = hdr_buf_len - hdr_len; + hdr_len += acad_len; + } + + /* calculate total data length */ + if (hdr_len < pdu->len) { + data_len = pdu->len - hdr_len; + } else { + data_len = 0U; } /* Periodic Advertising Channel Map Indication and/or Broadcast ISO @@ -379,6 +438,19 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) */ if (!aux_ptr || !aux_ptr->offs || is_scan_req || (aux_ptr->phy > EXT_ADV_AUX_PHY_LE_CODED)) { + if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) && sync_lll) { + struct ll_sync_set *sync; + + sync = HDR_LLL2ULL(sync_lll); + ftr->aux_data_len = sync->data_len + data_len; + sync->data_len = 0U; + } else if (aux) { + aux->data_len += data_len; + ftr->aux_data_len = aux->data_len; + } else { + ftr->aux_data_len = data_len; + } + if (is_scan_req) { LL_ASSERT(aux && aux->rx_last); @@ -394,10 +466,32 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) if (!aux) { aux = aux_acquire(); if (!aux) { + /* As LLL scheduling has been used and will fail due to + * non-allocation of aux context, a sync report with + * aux_failed flag set will be generated. Let the + * current sync report be set as partial, and the + * sync report corresponding to ull_scan_aux_release + * have the incomplete data status. + */ + if (ftr->aux_lll_sched) { + ftr->aux_sched = 1U; + } + + if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) && + sync_lll) { + struct ll_sync_set *sync; + + sync = HDR_LLL2ULL(sync_lll); + ftr->aux_data_len = sync->data_len + data_len; + sync->data_len = 0U; + + } + goto ull_scan_aux_rx_flush; } aux->rx_head = aux->rx_last = NULL; + aux->data_len = data_len; lll_aux = &aux->lll; lll_aux->is_chain_sched = 0U; @@ -405,17 +499,25 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) lll_hdr_init(lll_aux, aux); aux->parent = lll ? (void *)lll : (void *)sync_lll; + +#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) + aux->rx_incomplete = rx_incomplete; + rx_incomplete = NULL; +#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */ + + } else { + aux->data_len += data_len; } /* In sync context we can dispatch rx immediately, in scan context we * enqueue rx in aux context and will flush them after scan is complete. */ - if (0) { -#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) - } else if (sync_lll) { - ll_rx_put(link, rx); - ll_rx_sched(); -#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */ + if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) && sync_lll) { + struct ll_sync_set *sync; + + sync = HDR_LLL2ULL(sync_lll); + sync->data_len += data_len; + ftr->aux_data_len = sync->data_len; } else { if (aux->rx_last) { aux->rx_last->rx_ftr.extra = rx; @@ -423,23 +525,29 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) aux->rx_head = rx; } aux->rx_last = rx; + + ftr->aux_data_len = aux->data_len; } + /* Initialize the channel index and PHY for the Auxiliary PDU reception. + */ lll_aux->chan = aux_ptr->chan_idx; lll_aux->phy = BIT(aux_ptr->phy); - ftr->aux_w4next = 1; - /* See if this was already scheduled from LLL. If so, store aux context * in global scan struct so we can pick it when scanned node is received * with a valid context. */ if (ftr->aux_lll_sched) { - if (0) { -#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) - } else if (sync_lll) { + /* AUX_ADV_IND/AUX_CHAIN_IND PDU reception is being setup */ + ftr->aux_sched = 1U; + + if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) && sync_lll) { sync_lll->lll_aux = lll_aux; -#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */ + + /* In sync context, dispatch immediately */ + ll_rx_put(link, rx); + ll_rx_sched(); } else { lll->lll_aux = lll_aux; } @@ -453,12 +561,35 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) } /* Switching to ULL scheduling to receive auxiliary PDUs */ - if (lll) { + if (!IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) || lll) { + /* Do not ULL schedule if scan disable requested */ + if (unlikely(scan->is_stop)) { + goto ull_scan_aux_rx_flush; + } + + /* Remove auxiliary context association with scan context so + * that LLL can differentiate it to being ULL scheduling. + */ lll->lll_aux = NULL; } else { + struct ll_sync_set *sync; + LL_ASSERT(sync_lll && (!sync_lll->lll_aux || sync_lll->lll_aux == lll_aux)); + + /* Do not ULL schedule if sync terminate requested */ + sync = HDR_LLL2ULL(sync_lll); + if (unlikely(sync->is_stop)) { + goto ull_scan_aux_rx_flush; + } + + /* Associate the auxiliary context with sync context */ sync_lll->lll_aux = lll_aux; + + /* Backup the node rx to be dispatch on successfully ULL + * scheduling setup. + */ + aux->rx_head = rx; } /* Determine the window size */ @@ -553,21 +684,24 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) ull_scan_aux_rx_flush: #if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) - if (sync && (scan->per_scan.state != LL_SYNC_STATE_CREATED)) { - scan->per_scan.state = LL_SYNC_STATE_IDLE; + if (sync && (scan->periodic.state != LL_SYNC_STATE_CREATED)) { + scan->periodic.state = LL_SYNC_STATE_IDLE; } #endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */ if (aux) { struct ull_hdr *hdr; + uint8_t ref; /* Enqueue last rx in aux context if possible, otherwise send * immediately since we are in sync context. */ - if (aux->rx_last) { + if (!IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) || aux->rx_last) { aux->rx_last->rx_ftr.extra = rx; + aux->rx_last = rx; } else { LL_ASSERT(sync_lll); + ll_rx_put(link, rx); ll_rx_sched(); } @@ -582,75 +716,109 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) * ull_hdr before done event was processed. */ hdr = &aux->ull; - LL_ASSERT(ull_ref_get(hdr) < 2); - if (ull_ref_get(hdr) == 0) { + ref = ull_ref_get(hdr); + if (ref == 0) { flush(aux); } else { - LL_ASSERT(!hdr->disabled_cb); + /* A specific single shot scheduled aux context cannot + * overlap, i.e. ULL reference count shall be less than + * 2. + */ + LL_ASSERT(ref < 2); + LL_ASSERT(!hdr->disabled_cb); hdr->disabled_param = aux; - hdr->disabled_cb = last_disabled_cb; + hdr->disabled_cb = done_disabled_cb; } return; } ll_rx_put(link, rx); + + if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) && rx_incomplete) { + rx_release_put(rx_incomplete); + } + ll_rx_sched(); } void ull_scan_aux_done(struct node_rx_event_done *done) { struct ll_scan_aux_set *aux; - struct ull_hdr *hdr; /* Get reference to ULL context */ aux = CONTAINER_OF(done->param, struct ll_scan_aux_set, ull); - if (0) { -#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) - } else if (!ull_scan_aux_is_valid_get(aux)) { + if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) && + !ull_scan_aux_is_valid_get(aux)) { struct ll_sync_set *sync; sync = CONTAINER_OF(done->param, struct ll_sync_set, ull); LL_ASSERT(ull_sync_is_valid_get(sync)); - hdr = &sync->ull; - if (!sync->lll.lll_aux) { + /* Auxiliary context will be flushed by ull_scan_aux_stop() */ + if (unlikely(sync->is_stop) || !sync->lll.lll_aux) { return; } aux = HDR_LLL2ULL(sync->lll.lll_aux); -#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */ } else { - /* Setup the disabled callback to flush the auxiliary PDUs */ - hdr = &aux->ull; + struct ll_scan_set *scan; + struct lll_scan *lll; + + lll = aux->parent; + LL_ASSERT(lll); + + scan = HDR_LLL2ULL(lll); + LL_ASSERT(ull_scan_is_valid_get(scan)); + + /* Auxiliary context will be flushed by ull_scan_aux_stop() */ + if (unlikely(scan->is_stop)) { + return; + } } - LL_ASSERT(!hdr->disabled_cb); - hdr->disabled_param = aux; - hdr->disabled_cb = done_disabled_cb; + flush(aux); +} + +struct ll_scan_aux_set *ull_scan_aux_set_get(uint8_t handle) +{ + if (handle >= CONFIG_BT_CTLR_SCAN_AUX_SET) { + return NULL; + } + + return &ll_scan_aux_pool[handle]; } uint8_t ull_scan_aux_lll_handle_get(struct lll_scan_aux *lll) { - return aux_handle_get((void *)lll->hdr.parent); + struct ll_scan_aux_set *aux; + + aux = HDR_LLL2ULL(lll); + + return aux_handle_get(aux); } void *ull_scan_aux_lll_parent_get(struct lll_scan_aux *lll, uint8_t *is_lll_scan) { - struct ll_scan_aux_set *aux_set; - struct ll_scan_set *scan_set; + struct ll_scan_aux_set *aux; - aux_set = HDR_LLL2ULL(lll); - scan_set = HDR_LLL2ULL(aux_set->parent); + aux = HDR_LLL2ULL(lll); if (is_lll_scan) { - *is_lll_scan = !!ull_scan_is_valid_get(scan_set); + struct ll_scan_set *scan; + struct lll_scan *lll; + + lll = aux->parent; + LL_ASSERT(lll); + + scan = HDR_LLL2ULL(lll); + *is_lll_scan = !!ull_scan_is_valid_get(scan); } - return aux_set->parent; + return aux->parent; } struct ll_scan_aux_set *ull_scan_aux_is_valid_get(struct ll_scan_aux_set *aux) @@ -680,15 +848,23 @@ void ull_scan_aux_release(memq_link_t *link, struct node_rx_hdr *rx) lll = rx->rx_ftr.param; lll_aux = lll->lll_aux; - } else if (ull_scan_aux_is_valid_get(param_ull)) { + + } else if (!IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) || + ull_scan_aux_is_valid_get(param_ull)) { /* Mark for buffer for release */ rx->type = NODE_RX_TYPE_RELEASE; lll_aux = rx->rx_ftr.param; -#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) + } else if (ull_sync_is_valid_get(param_ull)) { + struct ll_sync_set *sync; struct lll_sync *lll; + sync = param_ull; + + /* reset data len total */ + sync->data_len = 0U; + lll = rx->rx_ftr.param; lll_aux = lll->lll_aux; @@ -696,13 +872,13 @@ void ull_scan_aux_release(memq_link_t *link, struct node_rx_hdr *rx) * data properly. */ rx->type = NODE_RX_TYPE_SYNC_REPORT; - rx->handle = ull_sync_handle_get(param_ull); + rx->handle = ull_sync_handle_get(sync); /* Dequeue will try releasing list of node rx, set the extra * pointer to NULL. */ rx->rx_ftr.extra = NULL; -#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */ + } else { LL_ASSERT(0); lll_aux = NULL; @@ -710,21 +886,63 @@ void ull_scan_aux_release(memq_link_t *link, struct node_rx_hdr *rx) if (lll_aux) { struct ll_scan_aux_set *aux; + struct ll_scan_set *scan; + struct lll_scan *lll; struct ull_hdr *hdr; + uint8_t is_stop; aux = HDR_LLL2ULL(lll_aux); - hdr = &aux->ull; + lll = aux->parent; + LL_ASSERT(lll); - LL_ASSERT(ull_ref_get(hdr) < 2); + scan = HDR_LLL2ULL(lll); + scan = ull_scan_is_valid_get(scan); + if (scan) { + is_stop = scan->is_stop; + } else { + struct lll_sync *sync_lll; + struct ll_sync_set *sync; - /* Flush from here of from done event, if one is pending */ - if (ull_ref_get(hdr) == 0) { - flush(aux); + sync_lll = (void *)lll; + sync = HDR_LLL2ULL(sync_lll); + is_stop = sync->is_stop; + } + + if (!is_stop) { + uint8_t ref; + + /* Flush from here or from done event, if one is + * pending. + */ + hdr = &aux->ull; + ref = ull_ref_get(hdr); + if (ref == 0) { + flush(aux); + } else { + /* A specific single shot scheduled aux context + * cannot overlap, i.e. ULL reference count + * shall be less than 2. + */ + LL_ASSERT(ref < 2); + + LL_ASSERT(!hdr->disabled_cb); + hdr->disabled_param = aux; + hdr->disabled_cb = done_disabled_cb; + } } else { - LL_ASSERT(!hdr->disabled_cb); + /* Sync terminate requested, enqueue node rx that will + * be flushed by the disabled_cb setup by the + * terminate. + */ + rx->link = link; + if (aux->rx_last) { + aux->rx_last->rx_ftr.extra = rx; + } else { + aux->rx_head = rx; + } + aux->rx_last = rx; - hdr->disabled_param = aux; - hdr->disabled_cb = last_disabled_cb; + return; } } @@ -735,7 +953,7 @@ void ull_scan_aux_release(memq_link_t *link, struct node_rx_hdr *rx) int ull_scan_aux_stop(struct ll_scan_aux_set *aux) { static memq_link_t link; - static struct mayfly mfy = {0, 0, &link, NULL, flush}; + static struct mayfly mfy = {0, 0, &link, NULL, NULL}; uint8_t aux_handle; uint32_t ret; int err; @@ -750,9 +968,38 @@ int ull_scan_aux_stop(struct ll_scan_aux_set *aux) /* Abort LLL event if ULL scheduling not used or already in prepare */ if (err == -EALREADY) { - ret = ull_disable(&aux->lll); - if (ret) { - return -EBUSY; + err = ull_disable(&aux->lll); + if (err) { + return err; + } + + mfy.fp = flush; + + } else if (!IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC)) { + /* ULL scan auxiliary PDU reception scheduling stopped + * before prepare. + */ + mfy.fp = flush; + + } else { + struct ll_scan_set *scan; + struct lll_scan *lll; + + lll = aux->parent; + LL_ASSERT(lll); + + scan = HDR_LLL2ULL(lll); + scan = ull_scan_is_valid_get(scan); + if (scan) { + /* ULL scan auxiliary PDU reception scheduling stopped + * before prepare. + */ + mfy.fp = flush; + } else { + /* ULL sync chain reception scheduling stopped before + * prepare. + */ + mfy.fp = aux_sync_incomplete; } } @@ -782,6 +1029,12 @@ static inline struct ll_scan_aux_set *aux_acquire(void) static inline void aux_release(struct ll_scan_aux_set *aux) { + /* Clear the parent so that when scan is being disabled then this + * auxiliary context shall not associate itself from being disable. + */ + LL_ASSERT(aux->parent); + aux->parent = NULL; + mem_release(aux, &scan_aux_free); } @@ -794,7 +1047,7 @@ static inline uint8_t aux_handle_get(struct ll_scan_aux_set *aux) static inline struct ll_sync_set *sync_create_get(struct ll_scan_set *scan) { #if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) - return scan->per_scan.sync; + return (!scan->periodic.cancelled) ? scan->periodic.sync : NULL; #else /* !CONFIG_BT_CTLR_SYNC_PERIODIC */ return NULL; #endif /* !CONFIG_BT_CTLR_SYNC_PERIODIC */ @@ -810,57 +1063,131 @@ static inline struct ll_sync_iso_set * #endif /* !CONFIG_BT_CTLR_SYNC_ISO */ } -static void last_disabled_cb(void *param) +static void done_disabled_cb(void *param) { flush(param); } -static void done_disabled_cb(void *param) +static void flush(void *param) { struct ll_scan_aux_set *aux; + struct ll_scan_set *scan; + struct node_rx_hdr *rx; + struct lll_scan *lll; + bool sched = false; + /* Debug check that parent was assigned when allocated for reception of + * auxiliary channel PDUs. + */ aux = param; - LL_ASSERT(ull_scan_aux_is_valid_get(aux)); + LL_ASSERT(aux->parent); + + rx = aux->rx_head; + if (rx) { + ll_rx_put(rx->link, rx); + sched = true; + } - aux = ull_scan_aux_is_valid_get(aux); #if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) - if (!aux) { + if (aux->rx_incomplete) { + rx_release_put(aux->rx_incomplete); + sched = true; + } +#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */ + + if (sched) { + ll_rx_sched(); + } + + lll = aux->parent; + scan = HDR_LLL2ULL(lll); + scan = ull_scan_is_valid_get(scan); + if (!IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) || scan) { + lll->lll_aux = NULL; + } else { struct lll_sync *sync_lll; + struct ll_sync_set *sync; + + sync_lll = aux->parent; + sync = HDR_LLL2ULL(sync_lll); - sync_lll = param; - LL_ASSERT(sync_lll->lll_aux); - aux = HDR_LLL2ULL(sync_lll->lll_aux); + LL_ASSERT(sync->is_stop || sync_lll->lll_aux); + sync_lll->lll_aux = NULL; } -#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */ - flush(aux); + aux_release(aux); } -static void flush(void *param) +static void rx_release_put(struct node_rx_hdr *rx) +{ + rx->type = NODE_RX_TYPE_RELEASE; + + ll_rx_put(rx->link, rx); +} + +static void aux_sync_partial(void *param) { struct ll_scan_aux_set *aux; struct node_rx_hdr *rx; - /* Nodes are enqueued only in scan context so need to send them now */ aux = param; rx = aux->rx_head; - if (rx) { - struct lll_scan *lll; + aux->rx_head = NULL; - lll = aux->parent; - lll->lll_aux = NULL; + rx->rx_ftr.aux_sched = 1U; - ll_rx_put(rx->link, rx); - ll_rx_sched(); - } else { + ll_rx_put(rx->link, rx); + ll_rx_sched(); +} + +static void aux_sync_incomplete(void *param) +{ +#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) + struct ll_scan_aux_set *aux; + + aux = param; + + /* ULL scheduling succeeded hence no backup node rx present, use the + * extra node rx reserved for incomplete data status generation. + */ + if (!aux->rx_head) { + struct ll_sync_set *sync; + struct node_rx_hdr *rx; struct lll_sync *lll; + /* get reference to sync context */ lll = aux->parent; - LL_ASSERT(lll->lll_aux); - lll->lll_aux = NULL; + LL_ASSERT(lll); + sync = HDR_LLL2ULL(lll); + + /* reset data len total */ + sync->data_len = 0U; + + /* pick extra node rx stored in aux context */ + rx = aux->rx_incomplete; + LL_ASSERT(rx); + aux->rx_incomplete = NULL; + + /* prepare sync report with failure */ + rx->type = NODE_RX_TYPE_SYNC_REPORT; + rx->handle = ull_sync_handle_get(sync); + + /* flag chain reception failure */ + rx->rx_ftr.aux_failed = 1U; + + /* Dequeue will try releasing list of node rx, + * set the extra pointer to NULL. + */ + rx->rx_ftr.extra = NULL; + + /* add to rx list, will be flushed */ + aux->rx_head = rx; } - aux_release(aux); + LL_ASSERT(!ull_ref_get(&aux->ull)); + + flush(aux); +#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */ } static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, @@ -899,11 +1226,36 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, static void ticker_op_cb(uint32_t status, void *param) { static memq_link_t link; - static struct mayfly mfy = {0, 0, &link, NULL, flush}; + static struct mayfly mfy = {0, 0, &link, NULL, NULL}; + struct ll_sync_set *sync; uint32_t ret; + if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC)) { + struct ll_scan_aux_set *aux; + struct lll_sync *sync_lll; + + aux = param; + sync_lll = aux->parent; + LL_ASSERT(sync_lll); + + sync = HDR_LLL2ULL(sync_lll); + sync = ull_sync_is_valid_get(sync); + } else { + sync = NULL; + } + if (status == TICKER_STATUS_SUCCESS) { - return; + if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) && sync) { + mfy.fp = aux_sync_partial; + } else { + return; + } + } else { + if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) && sync) { + mfy.fp = aux_sync_incomplete; + } else { + mfy.fp = flush; + } } mfy.param = param; diff --git a/subsys/bluetooth/controller/ll_sw/ull_scan_internal.h b/subsys/bluetooth/controller/ll_sw/ull_scan_internal.h index e664ae13781..a90aac5527e 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_scan_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_scan_internal.h @@ -80,6 +80,9 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx); /* Helper to clean up auxiliary channel scanning */ void ull_scan_aux_done(struct node_rx_event_done *done); +/* Return the scan aux set instance given the handle */ +struct ll_scan_aux_set *ull_scan_aux_set_get(uint8_t handle); + /* Helper function to check and return if a valid aux scan context */ struct ll_scan_aux_set *ull_scan_aux_is_valid_get(struct ll_scan_aux_set *aux); diff --git a/subsys/bluetooth/controller/ll_sw/ull_scan_types.h b/subsys/bluetooth/controller/ll_sw/ull_scan_types.h index 7ee46c86d75..969f6fa9106 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_scan_types.h +++ b/subsys/bluetooth/controller/ll_sw/ull_scan_types.h @@ -11,6 +11,8 @@ struct ll_scan_set { #if defined(CONFIG_BT_CTLR_ADV_EXT) uint16_t duration_lazy; struct node_rx_hdr *node_rx_scan_term; + + uint8_t is_stop:1; #endif /* CONFIG_BT_CTLR_ADV_EXT */ uint8_t is_enabled:1; @@ -22,6 +24,7 @@ struct ll_scan_set { uint8_t adv_addr_type:1; uint8_t filter_policy:1; + uint8_t cancelled:1; uint8_t state:2; uint8_t adv_addr[BDADDR_SIZE]; @@ -31,7 +34,7 @@ struct ll_scan_set { * cancelling sync create, hence the volatile keyword. */ struct ll_sync_set *volatile sync; - } per_scan; + } periodic; #endif }; @@ -44,4 +47,10 @@ struct ll_scan_aux_set { struct node_rx_hdr *rx_head; struct node_rx_hdr *rx_last; + + uint16_t data_len; + +#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC) + struct node_rx_hdr *rx_incomplete; +#endif }; diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync.c b/subsys/bluetooth/controller/ll_sw/ull_sync.c index b0f34eb85ed..20af75c0418 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sync.c @@ -86,9 +86,6 @@ static void *sync_free; static struct k_sem sem_ticker_cb; #endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX */ -static memq_link_t link_lll_prepare; -static struct mayfly mfy_lll_prepare = { 0, 0, &link_lll_prepare, NULL, lll_sync_prepare }; - uint8_t ll_sync_create(uint8_t options, uint8_t sid, uint8_t adv_addr_type, uint8_t *adv_addr, uint16_t skip, uint16_t sync_timeout, uint8_t sync_cte_type) @@ -102,10 +99,17 @@ uint8_t ll_sync_create(uint8_t options, uint8_t sid, uint8_t adv_addr_type, struct ll_sync_set *sync; scan = ull_scan_set_get(SCAN_HANDLE_1M); - if (!scan || scan->per_scan.sync) { + if (!scan || scan->periodic.sync) { return BT_HCI_ERR_CMD_DISALLOWED; } + if (IS_ENABLED(CONFIG_BT_CTLR_PHY_CODED)) { + scan_coded = ull_scan_set_get(SCAN_HANDLE_PHY_CODED); + if (!scan_coded || scan_coded->periodic.sync) { + return BT_HCI_ERR_CMD_DISALLOWED; + } + } + #if defined(CONFIG_BT_CTLR_CHECK_SAME_PEER_SYNC) /* Do not sync twice to the same peer and same SID */ if (((options & BT_HCI_LE_PER_ADV_CREATE_SYNC_FP_USE_LIST) == 0U) && @@ -114,15 +118,6 @@ uint8_t ll_sync_create(uint8_t options, uint8_t sid, uint8_t adv_addr_type, } #endif /* CONFIG_BT_CTLR_CHECK_SAME_PEER_SYNC */ - if (IS_ENABLED(CONFIG_BT_CTLR_PHY_CODED)) { - scan_coded = ull_scan_set_get(SCAN_HANDLE_PHY_CODED); - if (!scan_coded || scan_coded->per_scan.sync) { - return BT_HCI_ERR_CMD_DISALLOWED; - } - } - - /* FIXME: Check for already synchronized to same peer */ - link_sync_estab = ll_rx_link_alloc(); if (!link_sync_estab) { return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED; @@ -152,26 +147,28 @@ uint8_t ll_sync_create(uint8_t options, uint8_t sid, uint8_t adv_addr_type, return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED; } - scan->per_scan.state = LL_SYNC_STATE_IDLE; - scan->per_scan.filter_policy = + scan->periodic.cancelled = 0U; + scan->periodic.state = LL_SYNC_STATE_IDLE; + scan->periodic.filter_policy = options & BT_HCI_LE_PER_ADV_CREATE_SYNC_FP_USE_LIST; if (IS_ENABLED(CONFIG_BT_CTLR_PHY_CODED)) { - scan_coded->per_scan.state = LL_SYNC_STATE_IDLE; - scan_coded->per_scan.filter_policy = - scan->per_scan.filter_policy; + scan_coded->periodic.cancelled = 0U; + scan_coded->periodic.state = LL_SYNC_STATE_IDLE; + scan_coded->periodic.filter_policy = + scan->periodic.filter_policy; } - if (!scan->per_scan.filter_policy) { - scan->per_scan.sid = sid; - scan->per_scan.adv_addr_type = adv_addr_type; - memcpy(scan->per_scan.adv_addr, adv_addr, BDADDR_SIZE); + if (!scan->periodic.filter_policy) { + scan->periodic.sid = sid; + scan->periodic.adv_addr_type = adv_addr_type; + (void)memcpy(scan->periodic.adv_addr, adv_addr, BDADDR_SIZE); if (IS_ENABLED(CONFIG_BT_CTLR_PHY_CODED)) { - scan_coded->per_scan.sid = scan->per_scan.sid; - scan_coded->per_scan.adv_addr_type = - scan->per_scan.adv_addr_type; - memcpy(scan_coded->per_scan.adv_addr, - scan->per_scan.adv_addr, BDADDR_SIZE); + scan_coded->periodic.sid = scan->periodic.sid; + scan_coded->periodic.adv_addr_type = + scan->periodic.adv_addr_type; + (void)memcpy(scan_coded->periodic.adv_addr, + scan->periodic.adv_addr, BDADDR_SIZE); } } @@ -190,6 +187,7 @@ uint8_t ll_sync_create(uint8_t options, uint8_t sid, uint8_t adv_addr_type, 1U : 0U; #endif sync->skip = skip; + sync->is_stop = 0U; /* NOTE: Use timeout not zero to represent sync context used for sync * create. @@ -223,6 +221,7 @@ uint8_t ll_sync_create(uint8_t options, uint8_t sid, uint8_t adv_addr_type, /* Initialize sync LLL context */ lll_sync = &sync->lll; + lll_sync->lll_aux = NULL; lll_sync->is_rx_enabled = sync->rx_enable; lll_sync->skip_prepare = 0U; lll_sync->skip_event = 0U; @@ -230,7 +229,7 @@ uint8_t ll_sync_create(uint8_t options, uint8_t sid, uint8_t adv_addr_type, lll_sync->window_widening_event_us = 0U; #if defined(CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING) lll_sync->cte_type = sync_cte_type; - lll_sync->filter_policy = scan->per_scan.filter_policy; + lll_sync->filter_policy = scan->periodic.filter_policy; #endif /* CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING */ #if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX) @@ -242,9 +241,9 @@ uint8_t ll_sync_create(uint8_t options, uint8_t sid, uint8_t adv_addr_type, lll_hdr_init(lll_sync, sync); /* Enable scanner to create sync */ - scan->per_scan.sync = sync; + scan->periodic.sync = sync; if (IS_ENABLED(CONFIG_BT_CTLR_PHY_CODED)) { - scan_coded->per_scan.sync = sync; + scan_coded->periodic.sync = sync; } return 0; @@ -261,35 +260,44 @@ uint8_t ll_sync_create_cancel(void **rx) struct node_rx_sync *se; scan = ull_scan_set_get(SCAN_HANDLE_1M); - if (!scan || !scan->per_scan.sync) { + if (!scan || !scan->periodic.sync) { return BT_HCI_ERR_CMD_DISALLOWED; } if (IS_ENABLED(CONFIG_BT_CTLR_PHY_CODED)) { scan_coded = ull_scan_set_get(SCAN_HANDLE_PHY_CODED); - if (!scan_coded || !scan_coded->per_scan.sync) { + if (!scan_coded || !scan_coded->periodic.sync) { return BT_HCI_ERR_CMD_DISALLOWED; } } /* Check for race condition where in sync is established when sync - * context was set to NULL. + * create cancel is invoked. * - * Setting `scan->per_scan.sync` to NULL represents cancellation - * requested in the thread context. Checking `sync->timeout_reload` - * confirms if synchronization was established before - * `scan->per_scan.sync` was set to NULL. + * Setting `scan->periodic.cancelled` to represent cancellation + * requested in the thread context. Checking `scan->periodic.sync` for + * NULL confirms if synchronization was established before + * `scan->periodic.cancelled` was set to 1U. */ - sync = scan->per_scan.sync; - scan->per_scan.sync = NULL; + scan->periodic.cancelled = 1U; if (IS_ENABLED(CONFIG_BT_CTLR_PHY_CODED)) { - scan_coded->per_scan.sync = NULL; + scan_coded->periodic.cancelled = 1U; } cpu_dmb(); + sync = scan->periodic.sync; if (!sync || sync->timeout_reload) { + /* FIXME: sync establishment in progress looking for first + * AUX_SYNC_IND. Cleanup by stopping ticker and disabling + * LLL events. + */ return BT_HCI_ERR_CMD_DISALLOWED; } + /* It is safe to remove association with scanner as cancelled flag is + * set and sync has not been established. + */ + scan->periodic.sync = NULL; + /* Mark the sync context as sync create cancelled */ if (IS_ENABLED(CONFIG_BT_CTLR_CHECK_SAME_PEER_SYNC)) { sync->timeout = 0U; @@ -335,6 +343,11 @@ uint8_t ll_sync_terminate(uint16_t handle) return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER; } + /* Request terminate, no new ULL scheduling to be setup */ + sync->is_stop = 1U; + cpu_dmb(); + + /* Stop periodic sync ticker timeouts */ err = ull_ticker_stop_with_mark(TICKER_ID_SCAN_SYNC_BASE + handle, sync, &sync->lll); LL_ASSERT(err == 0 || err == -EALREADY); @@ -342,6 +355,7 @@ uint8_t ll_sync_terminate(uint16_t handle) return BT_HCI_ERR_CMD_DISALLOWED; } + /* Check and stop any auxiliary PDU receptions */ lll_aux = sync->lll.lll_aux; if (lll_aux) { struct ll_scan_aux_set *aux; @@ -356,6 +370,9 @@ uint8_t ll_sync_terminate(uint16_t handle) link_sync_lost = sync->node_rx_lost.hdr.link; ll_rx_link_release(link_sync_lost); + /* Mark sync context not sync established */ + sync->timeout_reload = 0U; + ull_sync_release(sync); return 0; @@ -474,8 +491,8 @@ void ull_sync_release(struct ll_sync_set *sync) sync->timeout = 0U; } - /* Mark sync context not sync established */ - sync->timeout_reload = 0U; + /* reset accumulated data len */ + sync->data_len = 0U; mem_release(sync, &sync_free); } @@ -485,59 +502,59 @@ void ull_sync_setup_addr_check(struct ll_scan_set *scan, uint8_t addr_type, { /* Check if Periodic Advertiser list to be used */ if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC_ADV_LIST) && - scan->per_scan.filter_policy) { + scan->periodic.filter_policy) { /* Check in Periodic Advertiser List */ if (ull_filter_ull_pal_addr_match(addr_type, addr)) { /* Remember the address, to check with * SID in Sync Info */ - scan->per_scan.adv_addr_type = addr_type; - (void)memcpy(scan->per_scan.adv_addr, addr, + scan->periodic.adv_addr_type = addr_type; + (void)memcpy(scan->periodic.adv_addr, addr, BDADDR_SIZE); /* Address matched */ - scan->per_scan.state = LL_SYNC_STATE_ADDR_MATCH; + scan->periodic.state = LL_SYNC_STATE_ADDR_MATCH; /* Check in Resolving List */ } else if (IS_ENABLED(CONFIG_BT_CTLR_PRIVACY) && ull_filter_ull_pal_listed(rl_idx, &addr_type, - scan->per_scan.adv_addr)) { + scan->periodic.adv_addr)) { /* Remember the address, to check with the * SID in Sync Info */ - scan->per_scan.adv_addr_type = addr_type; + scan->periodic.adv_addr_type = addr_type; /* Address matched */ - scan->per_scan.state = LL_SYNC_STATE_ADDR_MATCH; + scan->periodic.state = LL_SYNC_STATE_ADDR_MATCH; } /* Check with explicitly supplied address */ - } else if ((addr_type == scan->per_scan.adv_addr_type) && - !memcmp(addr, scan->per_scan.adv_addr, BDADDR_SIZE)) { + } else if ((addr_type == scan->periodic.adv_addr_type) && + !memcmp(addr, scan->periodic.adv_addr, BDADDR_SIZE)) { /* Address matched */ - scan->per_scan.state = LL_SYNC_STATE_ADDR_MATCH; + scan->periodic.state = LL_SYNC_STATE_ADDR_MATCH; /* Check identity address with explicitly supplied address */ } else if (IS_ENABLED(CONFIG_BT_CTLR_PRIVACY) && (rl_idx < ll_rl_size_get())) { ll_rl_id_addr_get(rl_idx, &addr_type, addr); - if ((addr_type == scan->per_scan.adv_addr_type) && - !memcmp(addr, scan->per_scan.adv_addr, BDADDR_SIZE)) { + if ((addr_type == scan->periodic.adv_addr_type) && + !memcmp(addr, scan->periodic.adv_addr, BDADDR_SIZE)) { /* Identity address matched */ - scan->per_scan.state = LL_SYNC_STATE_ADDR_MATCH; + scan->periodic.state = LL_SYNC_STATE_ADDR_MATCH; } } } bool ull_sync_setup_sid_match(struct ll_scan_set *scan, uint8_t sid) { - return (scan->per_scan.state == LL_SYNC_STATE_ADDR_MATCH) && + return (scan->periodic.state == LL_SYNC_STATE_ADDR_MATCH) && ((IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC_ADV_LIST) && - scan->per_scan.filter_policy && - ull_filter_ull_pal_match(scan->per_scan.adv_addr_type, - scan->per_scan.adv_addr, sid)) || - (!scan->per_scan.filter_policy && - (sid == scan->per_scan.sid))); + scan->periodic.filter_policy && + ull_filter_ull_pal_match(scan->periodic.adv_addr_type, + scan->periodic.adv_addr, sid)) || + (!scan->periodic.filter_policy && + (sid == scan->periodic.sid))); } void ull_sync_setup(struct ll_scan_set *scan, struct ll_scan_aux_set *aux, @@ -562,7 +579,7 @@ void ull_sync_setup(struct ll_scan_set *scan, struct ll_scan_aux_set *aux, uint8_t sca; /* Populate the LLL context */ - sync = scan->per_scan.sync; + sync = scan->periodic.sync; lll = &sync->lll; /* Copy channel map from sca_chm field in sync_info structure, and @@ -588,8 +605,8 @@ void ull_sync_setup(struct ll_scan_set *scan, struct ll_scan_aux_set *aux, /* Remember the peer address. * NOTE: Peer identity address is copied here when privacy is enable. */ - sync->peer_id_addr_type = scan->per_scan.adv_addr_type; - (void)memcpy(sync->peer_id_addr, scan->per_scan.adv_addr, + sync->peer_id_addr_type = scan->periodic.adv_addr_type; + (void)memcpy(sync->peer_id_addr, scan->periodic.adv_addr, sizeof(sync->peer_id_addr)); #endif /* CONFIG_BT_CTLR_CHECK_SAME_PEER_SYNC || * CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT @@ -633,7 +650,7 @@ void ull_sync_setup(struct ll_scan_set *scan, struct ll_scan_aux_set *aux, } /* Set the state to sync create */ - scan->per_scan.state = LL_SYNC_STATE_CREATED; + scan->periodic.state = LL_SYNC_STATE_CREATED; if (IS_ENABLED(CONFIG_BT_CTLR_PHY_CODED)) { struct ll_scan_set *scan_1m; @@ -642,9 +659,9 @@ void ull_sync_setup(struct ll_scan_set *scan, struct ll_scan_aux_set *aux, struct ll_scan_set *scan_coded; scan_coded = ull_scan_set_get(SCAN_HANDLE_PHY_CODED); - scan_coded->per_scan.state = LL_SYNC_STATE_CREATED; + scan_coded->periodic.state = LL_SYNC_STATE_CREATED; } else { - scan_1m->per_scan.state = LL_SYNC_STATE_CREATED; + scan_1m->periodic.state = LL_SYNC_STATE_CREATED; } } @@ -700,7 +717,7 @@ void ull_sync_setup(struct ll_scan_set *scan, struct ll_scan_aux_set *aux, } ticks_slot_offset += HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_START_US); - mfy_lll_prepare.fp = lll_sync_create_prepare; + sync->lll_sync_prepare = lll_sync_create_prepare; ret = ticker_start(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_ULL_HIGH, (TICKER_ID_SCAN_SYNC_BASE + sync_handle), @@ -719,7 +736,7 @@ void ull_sync_setup(struct ll_scan_set *scan, struct ll_scan_aux_set *aux, void ull_sync_setup_complete(struct ll_scan_set *scan) { /* Remove the sync context from being associated with scan contexts */ - scan->per_scan.sync = NULL; + scan->periodic.sync = NULL; if (IS_ENABLED(CONFIG_BT_CTLR_PHY_CODED)) { struct ll_scan_set *scan_1m; @@ -728,9 +745,9 @@ void ull_sync_setup_complete(struct ll_scan_set *scan) struct ll_scan_set *scan_coded; scan_coded = ull_scan_set_get(SCAN_HANDLE_PHY_CODED); - scan_coded->per_scan.sync = NULL; + scan_coded->periodic.sync = NULL; } else { - scan_1m->per_scan.sync = NULL; + scan_1m->periodic.sync = NULL; } } } @@ -738,12 +755,14 @@ void ull_sync_setup_complete(struct ll_scan_set *scan) void ull_sync_established_report(memq_link_t *link, struct node_rx_hdr *rx) { struct node_rx_pdu *rx_establ; - struct ll_sync_set *ull_sync; + struct ll_sync_set *sync; struct node_rx_ftr *ftr; struct node_rx_sync *se; struct lll_sync *lll; ftr = &rx->rx_ftr; + lll = ftr->param; + sync = HDR_LLL2ULL(lll); #if defined(CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING) enum sync_status sync_status; @@ -753,8 +772,6 @@ void ull_sync_established_report(memq_link_t *link, struct node_rx_hdr *rx) #else struct pdu_cte_info *rx_cte_info; - lll = ftr->param; - rx_cte_info = pdu_cte_info_get((struct pdu_adv *)((struct node_rx_pdu *)rx)->pdu); if (rx_cte_info != NULL) { sync_status = lll_sync_cte_is_allowed(lll->cte_type, lll->filter_policy, @@ -774,15 +791,10 @@ void ull_sync_established_report(memq_link_t *link, struct node_rx_hdr *rx) if (1) { #endif /* !CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING */ - /* Set the sync handle corresponding to the LLL context passed in the node rx - * footer field. - */ - lll = ftr->param; - ull_sync = HDR_LLL2ULL(lll); - /* Prepare and dispatch sync notification */ - rx_establ = (void *)ull_sync->node_rx_sync_estab; + rx_establ = (void *)sync->node_rx_sync_estab; rx_establ->hdr.type = NODE_RX_TYPE_SYNC; + rx_establ->hdr.handle = ull_sync_handle_get(sync); se = (void *)rx_establ->pdu; #if defined(CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING) @@ -792,7 +804,7 @@ void ull_sync_established_report(memq_link_t *link, struct node_rx_hdr *rx) #if !defined(CONFIG_BT_CTLR_CTEINLINE_SUPPORT) /* Notify done event handler to terminate sync scan if required. */ - ull_sync->sync_term = sync_status == SYNC_STAT_TERM; + sync->is_term = (sync_status == SYNC_STAT_TERM); #endif /* !CONFIG_BT_CTLR_CTEINLINE_SUPPORT */ #else se->status = BT_HCI_ERR_SUCCESS; @@ -816,8 +828,9 @@ void ull_sync_established_report(memq_link_t *link, struct node_rx_hdr *rx) if (1) { #endif /* !CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING */ + /* Switch sync event prepare function to one reposnsible for regular PDUs receive */ - mfy_lll_prepare.fp = lll_sync_prepare; + sync->lll_sync_prepare = lll_sync_prepare; /* Change node type to appropriately handle periodic * advertising PDU report. @@ -833,26 +846,33 @@ void ull_sync_done(struct node_rx_event_done *done) uint32_t ticks_drift_plus; struct ll_sync_set *sync; uint16_t elapsed_event; - struct lll_sync *lll; uint16_t skip_event; uint16_t lazy; uint8_t force; /* Get reference to ULL context */ sync = CONTAINER_OF(done->param, struct ll_sync_set, ull); - lll = &sync->lll; + + /* Do nothing if local terminate requested or sync lost */ + if (unlikely(sync->is_stop || !sync->timeout_reload)) { + return; + } #if defined(CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING) #if defined(CONFIG_BT_CTLR_CTEINLINE_SUPPORT) if (done->extra.sync_term) { #else - if (sync->sync_term) { + if (sync->is_term) { #endif /* CONFIG_BT_CTLR_CTEINLINE_SUPPORT */ /* Stop periodic advertising scan ticker */ sync_ticker_cleanup(sync, NULL); } else #endif /* CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING */ { + struct lll_sync *lll; + + lll = &sync->lll; + /* Events elapsed used in timeout checks below */ skip_event = lll->skip_event; elapsed_event = skip_event + 1; @@ -1095,12 +1115,18 @@ static void sync_ticker_cleanup(struct ll_sync_set *sync, ticker_op_func stop_op TICKER_ID_SCAN_SYNC_BASE + sync_handle, stop_op_cb, (void *)sync); LL_ASSERT((ret == TICKER_STATUS_SUCCESS) || (ret == TICKER_STATUS_BUSY)); + + /* Mark sync context not sync established */ + sync->timeout_reload = 0U; } static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, uint32_t remainder, uint16_t lazy, uint8_t force, void *param) { + static memq_link_t link_lll_prepare; + static struct mayfly mfy_lll_prepare = { + 0, 0, &link_lll_prepare, NULL, NULL}; static struct lll_prepare_param p; struct ll_sync_set *sync = param; struct lll_sync *lll; @@ -1125,9 +1151,11 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, p.force = force; p.param = lll; mfy_lll_prepare.param = &p; + mfy_lll_prepare.fp = sync->lll_sync_prepare; /* Kick LLL prepare */ - ret = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH, TICKER_USER_ID_LLL, 0, &mfy_lll_prepare); + ret = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH, TICKER_USER_ID_LLL, 0, + &mfy_lll_prepare); LL_ASSERT(!ret); DEBUG_RADIO_PREPARE_O(1); @@ -1190,7 +1218,14 @@ static void ticker_stop_sync_lost_op_cb(uint32_t status, void *param) static memq_link_t link; static struct mayfly mfy = {0, 0, &link, NULL, sync_lost}; - LL_ASSERT(status == TICKER_STATUS_SUCCESS); + /* When in race between terminate requested in thread context and + * sync lost scenario, do not generate the sync lost node rx from here + */ + if (status != TICKER_STATUS_SUCCESS) { + LL_ASSERT(param == ull_disable_mark_get()); + + return; + } mfy.param = param; @@ -1201,9 +1236,17 @@ static void ticker_stop_sync_lost_op_cb(uint32_t status, void *param) static void sync_lost(void *param) { - struct ll_sync_set *sync = param; + struct ll_sync_set *sync; struct node_rx_pdu *rx; + /* sync established was not generated yet, no free node rx */ + sync = param; + if (sync->lll_sync_prepare != lll_sync_prepare) { + sync_expire(param); + + return; + } + /* Generate Periodic advertising sync lost */ rx = (void *)&sync->node_rx_lost; rx->hdr.handle = ull_sync_handle_get(sync); diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c b/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c index 6b85b567d1d..93584dd8b22 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c @@ -268,7 +268,11 @@ struct ll_sync_iso_set *ull_sync_iso_by_stream_get(uint16_t handle) struct lll_sync_iso_stream *ull_sync_iso_stream_get(uint16_t handle) { - if (handle >= CONFIG_BT_CTLR_SYNC_ISO_STREAM_COUNT) { + struct ll_sync_iso_set *sync_iso; + + /* Get the BIG Sync context and check for not being terminated */ + sync_iso = ull_sync_iso_by_stream_get(handle); + if (!sync_iso || !sync_iso->sync) { return NULL; } @@ -287,6 +291,7 @@ void ull_sync_iso_stream_release(struct ll_sync_iso_set *sync_iso) handle = lll->stream_handle[lll->stream_count]; stream = ull_sync_iso_stream_get(handle); + LL_ASSERT(stream); dp = stream->dp; if (dp) { diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync_types.h b/subsys/bluetooth/controller/ll_sw/ull_sync_types.h index cdffc5eb093..8b2288c45b8 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync_types.h +++ b/subsys/bluetooth/controller/ll_sw/ull_sync_types.h @@ -21,6 +21,12 @@ struct ll_sync_set { uint16_t volatile timeout_reload; /* Non-zero when sync established */ uint16_t timeout_expire; + /* Member to store periodic advertising sync prepare. + * Also serves as a flag to inform if sync established was + * already generated. + */ + void (*lll_sync_prepare)(void *param); + #if defined(CONFIG_BT_CTLR_CHECK_SAME_PEER_SYNC) || \ defined(CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT) uint8_t peer_id_addr[BDADDR_SIZE]; @@ -40,9 +46,10 @@ struct ll_sync_set { /* Member used to notify event done handler to terminate sync scanning. * Used only when no HW support for parsing PDU for CTEInfo. */ - uint8_t sync_term:1; + uint8_t is_term:1; #endif /* CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING && !CONFIG_BT_CTLR_CTEINLINE_SUPPORT */ + uint8_t is_stop:1; /* sync terminate requested */ uint8_t sync_expire:3; /* countdown of 6 before fail to establish */ #if defined(CONFIG_BT_CTLR_CHECK_SAME_PEER_SYNC) @@ -74,6 +81,8 @@ struct ll_sync_set { struct ll_sync_iso_set *volatile sync_iso; } iso; #endif /* CONFIG_BT_CTLR_SYNC_ISO */ + + uint16_t data_len; }; struct node_rx_sync { diff --git a/subsys/bluetooth/controller/ll_sw/ull_tx_queue.c b/subsys/bluetooth/controller/ll_sw/ull_tx_queue.c index 339771dd650..b0914e4382f 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_tx_queue.c +++ b/subsys/bluetooth/controller/ll_sw/ull_tx_queue.c @@ -15,15 +15,19 @@ void ull_tx_q_init(struct ull_tx_q *queue) void ull_tx_q_pause_data(struct ull_tx_q *queue) { - queue->pause_data = 1U; + queue->pause_data++; } void ull_tx_q_resume_data(struct ull_tx_q *queue) { - queue->pause_data = 0U; + if (queue->pause_data > 0) { + queue->pause_data--; + } - /* move all paused data to the tail of tx list */ - sys_slist_merge_slist(&queue->tx_list, &queue->data_list); + /* move all paused data to the tail of tx list, only if not empty and no longer paused */ + if (!queue->pause_data && !sys_slist_is_empty(&queue->data_list)) { + sys_slist_merge_slist(&queue->tx_list, &queue->data_list); + } } void ull_tx_q_enqueue_data(struct ull_tx_q *queue, struct node_tx *tx) diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig index 3468a6d462d..63048586b8d 100644 --- a/subsys/bluetooth/host/Kconfig +++ b/subsys/bluetooth/host/Kconfig @@ -485,6 +485,17 @@ config BT_BACKGROUND_SCAN_WINDOW int "Scan window used for background scanning in 0.625 ms units" default 18 range 4 16384 + +config BT_EXT_SCAN_BUF_SIZE + int "Maximum advertisement report size" + depends on BT_EXT_ADV + range 1 1650 + default 229 + help + Maximum size of an advertisement report in octets. If the advertisement + provided by the controller is larger than this buffer size, + the remaining data will be discarded. + endif # BT_OBSERVER config BT_SCAN_WITH_IDENTITY @@ -554,6 +565,12 @@ config BT_DF_CONNECTIONLESS_CTE_RX Enable support for reception and sampling of Constant Tone Extension in connectionless mode. +config BT_DF_CONNECTIONLESS_CTE_TX + bool "Enable support for transmission of CTE in connectionless mode" + help + Enable support for transmission of Constant Tone Extension in + connectionless mode. + config BT_DF_CONNECTION_CTE_RX bool "Enable support for receive of CTE in connection mode" help @@ -580,6 +597,22 @@ config BT_DF_CONNECTION_CTE_RSP Enable support for request of Constant Tone Extension in connection mode. +config BT_DF_CTE_RX_AOA + bool "Enable antenna switching during CTE reception (AoA) feature" + depends on BT_DF_CONNECTIONLESS_CTE_RX || BT_DF_CONNECTION_CTE_RX + default y + help + Enable support for antenna switching during CTE reception. + Also known as Angle of Arrival mode. + +config BT_DF_CTE_TX_AOD + bool "Enable antenna switching during CTE transmission (AoD) feature" + depends on BT_DF_CONNECTIONLESS_CTE_TX || BT_DF_CONNECTION_CTE_TX + default y + help + Enable support for antenna switching during CTE transmission. + Also known as Angle of Departure mode. + config BT_DEBUG_DF bool "Bluetooth Direction Finding debug" help diff --git a/subsys/bluetooth/host/Kconfig.l2cap b/subsys/bluetooth/host/Kconfig.l2cap index 514e5bf31c1..dc94fbf5c9a 100644 --- a/subsys/bluetooth/host/Kconfig.l2cap +++ b/subsys/bluetooth/host/Kconfig.l2cap @@ -46,7 +46,8 @@ config BT_L2CAP_DYNAMIC_CHANNEL allowing the creation of dynamic L2CAP Channels. config BT_L2CAP_ECRED - bool "L2CAP Enhanced Credit Based Flow Control support" + bool "L2CAP Enhanced Credit Based Flow Control support [EXPERIMENTAL]" + select EXPERIMENTAL depends on BT_L2CAP_DYNAMIC_CHANNEL help This option enables support for LE Connection oriented Channels with diff --git a/subsys/bluetooth/host/adv.c b/subsys/bluetooth/host/adv.c index c1b24c4fa00..ecd0de33716 100644 --- a/subsys/bluetooth/host/adv.c +++ b/subsys/bluetooth/host/adv.c @@ -27,6 +27,128 @@ enum adv_name_type { ADV_NAME_TYPE_SD, }; +struct bt_ad { + /* Pointer to an LTV structure */ + const struct bt_data *data; + /* Number of elements in @p data */ + size_t len; +}; + +struct ad_stream { + /* ad is a two dimensional array of struct bt_data elements. */ + const struct bt_ad *ad; + /* The number of struct bt_ad elements. */ + size_t ad_len; + + /* The current index in the array of struct bt_ad elements */ + size_t ad_index; + /* The current index in the array of ad.data elements */ + size_t data_index; + + /* Current LTV offset contains the data offset in the ad[x].data[y].data value array + * The length and type are included in this offset. + */ + uint16_t current_ltv_offset; +}; + +static void ad_stream_new(struct ad_stream *stream, const struct bt_ad *ad, size_t ad_len) +{ + (void)memset(stream, 0, sizeof(*stream)); + stream->ad = ad; + stream->ad_len = ad_len; +} + +/** + * @brief Returns true if the current stream is empty. + * + * @param stream AD stream, @ref ad_stream_new + * + * @returns true if the stream is now empty. + */ +static bool ad_stream_is_empty(const struct ad_stream *stream) +{ + /* If ad_index == ad_len, then we are past the last element in the ad array */ + return stream->ad_index == stream->ad_len; +} + +/** + * @brief Returns the bt_data structure that is currently being read + * + * If the structure has been fully read, the function iterates to the next + * + * @param stream AD stream, @ref ad_stream_new + * + * @returns The current LTV structure or NULL if there are no left. + */ +static const struct bt_data *ad_stream_current_ltv_update(struct ad_stream *stream) +{ + const struct bt_data *current_ltv = &stream->ad[stream->ad_index].data[stream->data_index]; + const bool done_reading_ltv = (stream->current_ltv_offset == current_ltv->data_len + 2); + + if (done_reading_ltv) { + stream->current_ltv_offset = 0; + + if (stream->data_index + 1 == stream->ad[stream->ad_index].len) { + stream->data_index = 0; + stream->ad_index++; + } else { + stream->data_index++; + } + } + + if (ad_stream_is_empty(stream)) { + return NULL; + } else { + return &stream->ad[stream->ad_index].data[stream->data_index]; + } +} + +/** + * @brief Read at max buf_len data from the flattened AD stream. + * + * The read data can contain multiple LTV AD structures. + * + * @param stream AD stream, @ref ad_stream_new + * @param buf Buffer where the data will be put + * @param buf_len Buffer length + * + * @returns The number of bytes read from the stream written to the provided buffer + */ +static uint8_t ad_stream_read(struct ad_stream *stream, uint8_t *buf, uint8_t buf_len) +{ + uint8_t read_len = 0; + + while (read_len < buf_len) { + const struct bt_data *current_ltv = ad_stream_current_ltv_update(stream); + + if (!current_ltv) { + break; + } + + if (stream->current_ltv_offset == 0) { + buf[read_len] = current_ltv->data_len + 1; + stream->current_ltv_offset++; + read_len++; + } else if (stream->current_ltv_offset == 1) { + buf[read_len] = current_ltv->type; + stream->current_ltv_offset++; + read_len++; + } else { + const size_t remaining_data_len = + current_ltv->data_len - stream->current_ltv_offset + 2; + const size_t size_to_copy = MIN(buf_len - read_len, remaining_data_len); + + (void)memcpy(&buf[read_len], + ¤t_ltv->data[stream->current_ltv_offset - 2], + size_to_copy); + stream->current_ltv_offset += size_to_copy; + read_len += size_to_copy; + } + } + + return read_len; +} + enum adv_name_type get_adv_name_type(const struct bt_le_ext_adv *adv) { if (atomic_test_bit(adv->flags, BT_ADV_INCLUDE_NAME_SD)) { @@ -338,12 +460,6 @@ static bool valid_adv_param(const struct bt_le_adv_param *param) return valid_adv_ext_param(param); } - -struct bt_ad { - const struct bt_data *data; - size_t len; -}; - static int set_data_add_complete(uint8_t *set_data, uint8_t set_data_len_max, const struct bt_ad *ad, size_t ad_len, uint8_t *data_len) { @@ -447,85 +563,44 @@ static int hci_set_adv_ext_complete(struct bt_le_ext_adv *adv, uint16_t hci_op, static int hci_set_adv_ext_fragmented(struct bt_le_ext_adv *adv, uint16_t hci_op, const struct bt_ad *ad, size_t ad_len) { - struct bt_hci_cp_le_set_ext_adv_data *set_data; - struct net_buf *buf; - int err; + struct ad_stream stream; - for (size_t i = 0; i < ad_len; i++) { - - const struct bt_data *data = ad[i].data; + ad_stream_new(&stream, ad, ad_len); - for (size_t j = 0; j < ad[i].len; j++) { - size_t len = data[j].data_len; - uint8_t type = data[j].type; - size_t offset = 0; + bool is_first_iteration = true; - /* We can't necessarily set one AD field in a single step. */ - while (offset < data[j].data_len) { - buf = bt_hci_cmd_create(hci_op, sizeof(*set_data)); - if (!buf) { - return -ENOBUFS; - } + while (!ad_stream_is_empty(&stream)) { + struct bt_hci_cp_le_set_ext_adv_data *set_data; + struct net_buf *buf; + int err; - set_data = net_buf_add(buf, sizeof(*set_data)); - (void)memset(set_data, 0, sizeof(*set_data)); - - set_data->handle = adv->handle; - set_data->frag_pref = BT_HCI_LE_EXT_ADV_FRAG_DISABLED; - - /* Determine the operation parameter value. */ - if ((i == 0) && (j == 0) && (offset == 0)) { - set_data->op = BT_HCI_LE_EXT_ADV_OP_FIRST_FRAG; - } else if ((i == ad_len - 1) && (j == ad[i].len - 1)) { - /* The last AD field may be split into - * one or two commands. - */ - if (offset != 0) { - /* We can always set the data in two operations - * Therefore, we know that this is the last. - */ - set_data->op = BT_HCI_LE_EXT_ADV_OP_LAST_FRAG; - } else if (len + 2 <= BT_HCI_LE_EXT_ADV_FRAG_MAX_LEN) { - /* First part fits. */ - set_data->op = BT_HCI_LE_EXT_ADV_OP_LAST_FRAG; - } else { - /* The data must be split into two - * commands. - */ - set_data->op = BT_HCI_LE_EXT_ADV_OP_INTERM_FRAG; - } - } else { - set_data->op = BT_HCI_LE_EXT_ADV_OP_INTERM_FRAG; - } + buf = bt_hci_cmd_create(hci_op, sizeof(*set_data)); + if (!buf) { + return -ENOBUFS; + } - if (offset == 0) { - set_data->len = MIN(len + 2, - BT_HCI_LE_EXT_ADV_FRAG_MAX_LEN); - } else { - /* No need to take min operation here, - * as we can always fit the second part. - */ - set_data->len = len - offset; - } + set_data = net_buf_add(buf, sizeof(*set_data)); - if (offset == 0) { - set_data->data[0] = len + 1; - set_data->data[1] = type; - memcpy(&set_data->data[2], data[j].data, set_data->len - 2); - offset += set_data->len - 2; - } else { - memcpy(&set_data->data[0], &data[j].data[offset], - set_data->len); - offset += set_data->len; - } + set_data->handle = adv->handle; + set_data->frag_pref = BT_HCI_LE_EXT_ADV_FRAG_ENABLED; + set_data->len = ad_stream_read(&stream, set_data->data, sizeof(set_data->data)); - err = bt_hci_cmd_send_sync(hci_op, buf, NULL); - if (err) { - return err; - } - } + if (is_first_iteration && ad_stream_is_empty(&stream)) { + set_data->op = BT_HCI_LE_EXT_ADV_OP_COMPLETE_DATA; + } else if (is_first_iteration) { + set_data->op = BT_HCI_LE_EXT_ADV_OP_FIRST_FRAG; + } else if (ad_stream_is_empty(&stream)) { + set_data->op = BT_HCI_LE_EXT_ADV_OP_LAST_FRAG; + } else { + set_data->op = BT_HCI_LE_EXT_ADV_OP_INTERM_FRAG; + } + err = bt_hci_cmd_send_sync(hci_op, buf, NULL); + if (err) { + return err; } + + is_first_iteration = false; } return 0; @@ -586,6 +661,54 @@ static int set_sd(struct bt_le_ext_adv *adv, const struct bt_ad *sd, return hci_set_ad(BT_HCI_OP_LE_SET_SCAN_RSP_DATA, sd, sd_len); } +#if defined(CONFIG_BT_PER_ADV) +static int hci_set_per_adv_data(const struct bt_le_ext_adv *adv, + const struct bt_data *ad, size_t ad_len) +{ + struct ad_stream stream; + struct bt_ad d = { .data = ad, .len = ad_len }; + bool is_first_iteration = true; + + ad_stream_new(&stream, &d, 1); + + while (!ad_stream_is_empty(&stream)) { + struct bt_hci_cp_le_set_per_adv_data *set_data; + struct net_buf *buf; + int err; + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_PER_ADV_DATA, sizeof(*set_data)); + if (!buf) { + return -ENOBUFS; + } + + set_data = net_buf_add(buf, sizeof(*set_data)); + (void)memset(set_data, 0, sizeof(*set_data)); + + set_data->handle = adv->handle; + set_data->len = ad_stream_read(&stream, set_data->data, sizeof(set_data->data)); + + if (is_first_iteration && ad_stream_is_empty(&stream)) { + set_data->op = BT_HCI_LE_EXT_ADV_OP_COMPLETE_DATA; + } else if (is_first_iteration) { + set_data->op = BT_HCI_LE_EXT_ADV_OP_FIRST_FRAG; + } else if (ad_stream_is_empty(&stream)) { + set_data->op = BT_HCI_LE_EXT_ADV_OP_LAST_FRAG; + } else { + set_data->op = BT_HCI_LE_EXT_ADV_OP_INTERM_FRAG; + } + + err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_PER_ADV_DATA, buf, NULL); + if (err) { + return err; + } + + is_first_iteration = false; + } + + return 0; +} +#endif /* CONFIG_BT_PER_ADV */ + static inline bool ad_has_name(const struct bt_data *ad, size_t ad_len) { size_t i; @@ -1613,10 +1736,7 @@ int bt_le_per_adv_set_param(struct bt_le_ext_adv *adv, int bt_le_per_adv_set_data(const struct bt_le_ext_adv *adv, const struct bt_data *ad, size_t ad_len) { - struct bt_hci_cp_le_set_per_adv_data *cp; - struct net_buf *buf; - struct bt_ad d = { .data = ad, .len = ad_len }; - int err; + size_t total_len_bytes = 0; if (!BT_FEAT_LE_EXT_PER_ADV(bt_dev.le.features)) { return -ENOTSUP; @@ -1630,38 +1750,19 @@ int bt_le_per_adv_set_data(const struct bt_le_ext_adv *adv, return -EINVAL; } - if (ad_len > BT_HCI_LE_PER_ADV_FRAG_MAX_LEN) { - return -EINVAL; - } - - - buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_PER_ADV_DATA, sizeof(*cp)); - if (!buf) { - return -ENOBUFS; - } - - cp = net_buf_add(buf, sizeof(*cp)); - (void)memset(cp, 0, sizeof(*cp)); - - cp->handle = adv->handle; - - /* TODO: If data is longer than what the controller can manage, - * split the data. Read size from controller on boot. - */ - cp->op = BT_HCI_LE_PER_ADV_OP_COMPLETE_DATA; - - err = set_data_add_complete(cp->data, BT_HCI_LE_PER_ADV_FRAG_MAX_LEN, &d, 1, - &cp->len); - if (err) { - return err; + for (size_t i = 0; i < ad_len; i++) { + total_len_bytes += ad[i].data_len + 2; } - err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_PER_ADV_DATA, buf, NULL); - if (err) { - return err; + if ((total_len_bytes > BT_HCI_LE_PER_ADV_FRAG_MAX_LEN) && + atomic_test_bit(adv->flags, BT_PER_ADV_ENABLED)) { + /* It is not allowed to set periodic advertising data + * in multiple operations while it is running. + */ + return -EINVAL; } - return 0; + return hci_set_per_adv_data(adv, ad, ad_len); } static int bt_le_per_adv_enable(struct bt_le_ext_adv *adv, bool enable) diff --git a/subsys/bluetooth/host/att.c b/subsys/bluetooth/host/att.c index 5cbbd44fc10..532257429ac 100644 --- a/subsys/bluetooth/host/att.c +++ b/subsys/bluetooth/host/att.c @@ -2622,8 +2622,6 @@ static void att_reset(struct bt_att *att) net_buf_unref(buf); } - att->conn = NULL; - /* Notify pending requests */ while (!sys_slist_is_empty(&att->reqs)) { struct bt_att_req *req; @@ -2632,13 +2630,17 @@ static void att_reset(struct bt_att *att) node = sys_slist_get_not_empty(&att->reqs); req = CONTAINER_OF(node, struct bt_att_req, node); if (req->func) { - req->func(NULL, BT_ATT_ERR_UNLIKELY, NULL, 0, + req->func(att->conn, BT_ATT_ERR_UNLIKELY, NULL, 0, req->user_data); } bt_att_req_free(req); } + /* FIXME: `att->conn` is not reference counted. Consider using `bt_conn_ref` + * and `bt_conn_unref` to follow convention. + */ + att->conn = NULL; k_mem_slab_free(&att_slab, (void **)&att); } diff --git a/subsys/bluetooth/host/conn.c b/subsys/bluetooth/host/conn.c index a27ef52d74e..6ead16ad0db 100644 --- a/subsys/bluetooth/host/conn.c +++ b/subsys/bluetooth/host/conn.c @@ -2949,7 +2949,40 @@ void bt_hci_le_df_connection_iq_report(struct net_buf *buf) cb->cte_report_cb(conn, &iq_report); } } + + bt_conn_unref(conn); } #endif /* CONFIG_BT_DF_CONNECTION_CTE_RX */ +#if defined(CONFIG_BT_DF_CONNECTION_CTE_REQ) +void bt_hci_le_df_cte_req_failed(struct net_buf *buf) +{ + struct bt_df_conn_iq_samples_report iq_report; + struct bt_conn *conn; + struct bt_conn_cb *cb; + int err; + + err = hci_df_prepare_conn_cte_req_failed(buf, &iq_report, &conn); + if (err) { + BT_ERR("Prepare CTE REQ failed IQ report failed %d", err); + return; + } + + for (cb = callback_list; cb; cb = cb->_next) { + if (cb->cte_report_cb) { + cb->cte_report_cb(conn, &iq_report); + } + } + + STRUCT_SECTION_FOREACH(bt_conn_cb, cb) + { + if (cb->cte_report_cb) { + cb->cte_report_cb(conn, &iq_report); + } + } + + bt_conn_unref(conn); +} +#endif /* CONFIG_BT_DF_CONNECTION_CTE_REQ */ + #endif /* CONFIG_BT_CONN */ diff --git a/subsys/bluetooth/host/direction.c b/subsys/bluetooth/host/direction.c index bb02cee70cc..4a6c01b7e52 100644 --- a/subsys/bluetooth/host/direction.c +++ b/subsys/bluetooth/host/direction.c @@ -53,8 +53,8 @@ static bool valid_cte_rx_common_params(uint8_t cte_types, uint8_t slot_durations #if defined(CONFIG_BT_DF_CONNECTIONLESS_CTE_RX) static bool valid_cl_cte_rx_params(const struct bt_df_per_adv_sync_cte_rx_param *params); -static void -prepare_cl_cte_rx_enable_cmd_params(struct net_buf *buf, struct bt_le_per_adv_sync *sync, +static int +prepare_cl_cte_rx_enable_cmd_params(struct net_buf **buf, struct bt_le_per_adv_sync *sync, const struct bt_df_per_adv_sync_cte_rx_param *params, bool enable); static int hci_df_set_cl_cte_rx_enable(struct bt_le_per_adv_sync *sync, bool enable, @@ -62,9 +62,9 @@ static int hci_df_set_cl_cte_rx_enable(struct bt_le_per_adv_sync *sync, bool ena #endif /* CONFIG_BT_DF_CONNECTIONLESS_CTE_RX */ #if defined(CONFIG_BT_DF_CONNECTION_CTE_RX) -static void prepare_conn_cte_rx_enable_cmd_params(struct net_buf *buf, struct bt_conn *conn, - const struct bt_df_conn_cte_rx_param *params, - bool enable); +static int prepare_conn_cte_rx_enable_cmd_params(struct net_buf **buf, struct bt_conn *conn, + const struct bt_df_conn_cte_rx_param *params, + bool enable); static int hci_df_set_conn_cte_rx_enable(struct bt_conn *conn, bool enable, const struct bt_df_conn_cte_rx_param *params); #endif /* CONFIG_BT_DF_CONNECTION_CTE_RX */ @@ -273,28 +273,44 @@ static bool valid_cl_cte_rx_params(const struct bt_df_per_adv_sync_cte_rx_param return true; } -static void -prepare_cl_cte_rx_enable_cmd_params(struct net_buf *buf, struct bt_le_per_adv_sync *sync, +static int +prepare_cl_cte_rx_enable_cmd_params(struct net_buf **buf, struct bt_le_per_adv_sync *sync, const struct bt_df_per_adv_sync_cte_rx_param *params, bool enable) { struct bt_hci_cp_le_set_cl_cte_sampling_enable *cp; - const uint8_t *ant_ids; + uint8_t switch_pattern_len; - cp = net_buf_add(buf, sizeof(*cp)); + if (params->cte_types & BT_DF_CTE_TYPE_AOA) { + switch_pattern_len = params->num_ant_ids; + } else { + switch_pattern_len = ARRAY_SIZE(df_dummy_switch_pattern); + } + + /* If CTE Rx is enabled, command parameters total length must include + * antenna ids, so command size if extended by num_and_ids. + */ + *buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_CL_CTE_SAMPLING_ENABLE, + (sizeof(struct bt_hci_cp_le_set_cl_cte_sampling_enable) + + (enable ? switch_pattern_len : 0))); + if (!(*buf)) { + return -ENOBUFS; + } + + cp = net_buf_add(*buf, sizeof(*cp)); (void)memset(cp, 0, sizeof(*cp)); cp->sync_handle = sys_cpu_to_le16(sync->handle); cp->sampling_enable = enable ? 1 : 0; if (enable) { + const uint8_t *ant_ids; uint8_t *dest_ant_ids; cp->max_sampled_cte = params->max_cte_count; if (params->cte_types & BT_DF_CTE_TYPE_AOA) { cp->slot_durations = params->slot_durations; - cp->switch_pattern_len = params->num_ant_ids; ant_ids = params->ant_ids; } else { /* Those values are put here due to constraints from HCI command @@ -303,13 +319,15 @@ prepare_cl_cte_rx_enable_cmd_params(struct net_buf *buf, struct bt_le_per_adv_sy * receive for AoD mode (e.g. device equipped with single antenna). */ cp->slot_durations = BT_HCI_LE_ANTENNA_SWITCHING_SLOT_2US; - cp->switch_pattern_len = ARRAY_SIZE(df_dummy_switch_pattern); ant_ids = &df_dummy_switch_pattern[0]; } - dest_ant_ids = net_buf_add(buf, params->num_ant_ids); + cp->switch_pattern_len = switch_pattern_len; + dest_ant_ids = net_buf_add(*buf, params->num_ant_ids); memcpy(dest_ant_ids, ant_ids, cp->switch_pattern_len); } + + return 0; } static int hci_df_set_cl_cte_rx_enable(struct bt_le_per_adv_sync *sync, bool enable, @@ -326,18 +344,11 @@ static int hci_df_set_cl_cte_rx_enable(struct bt_le_per_adv_sync *sync, bool ena } } - /* If CTE Rx is enabled, command parameters total length must include - * antenna ids, so command size if extended by num_and_ids. - */ - buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_CL_CTE_SAMPLING_ENABLE, - (sizeof(struct bt_hci_cp_le_set_cl_cte_sampling_enable) + - (enable ? params->num_ant_ids : 0))); - if (!buf) { - return -ENOBUFS; + err = prepare_cl_cte_rx_enable_cmd_params(&buf, sync, params, enable); + if (err) { + return err; } - prepare_cl_cte_rx_enable_cmd_params(buf, sync, params, enable); - bt_hci_cmd_state_set_init(buf, &state, sync->flags, BT_PER_ADV_SYNC_CTE_ENABLED, enable); err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_CL_CTE_SAMPLING_ENABLE, buf, &rsp); @@ -503,40 +514,60 @@ static int hci_df_set_conn_cte_tx_param(struct bt_conn *conn, #endif /* CONFIG_BT_DF_CONNECTION_CTE_TX */ #if defined(CONFIG_BT_DF_CONNECTION_CTE_RX) -static void prepare_conn_cte_rx_enable_cmd_params(struct net_buf *buf, struct bt_conn *conn, - const struct bt_df_conn_cte_rx_param *params, - bool enable) +static int prepare_conn_cte_rx_enable_cmd_params(struct net_buf **buf, struct bt_conn *conn, + const struct bt_df_conn_cte_rx_param *params, + bool enable) { struct bt_hci_cp_le_set_conn_cte_rx_params *cp; - const uint8_t *ant_ids; + uint8_t switch_pattern_len; - cp = net_buf_add(buf, sizeof(*cp)); + if (params->cte_types & BT_DF_CTE_TYPE_AOA) { + switch_pattern_len = params->num_ant_ids; + } else { + switch_pattern_len = ARRAY_SIZE(df_dummy_switch_pattern); + } + + /* If CTE Rx is enabled, command parameters total length must include + * antenna ids, so command size if extended by num_and_ids. + */ + *buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_CONN_CTE_RX_PARAMS, + (sizeof(struct bt_hci_cp_le_set_conn_cte_rx_params) + + (enable ? switch_pattern_len : 0))); + if (!(*buf)) { + return -ENOBUFS; + } + + cp = net_buf_add(*buf, sizeof(*cp)); (void)memset(cp, 0, sizeof(*cp)); cp->handle = sys_cpu_to_le16(conn->handle); cp->sampling_enable = enable ? 1 : 0; if (enable) { + const uint8_t *ant_ids; uint8_t *dest_ant_ids; if (params->cte_types & BT_DF_CTE_TYPE_AOA) { cp->slot_durations = params->slot_durations; - cp->switch_pattern_len = params->num_ant_ids; ant_ids = params->ant_ids; } else { /* Those values are put here due to constraints from HCI command * specification: Bluetooth Core Spec. 5.3 Vol 4,Part E, sec 7.8.85. * There is no right way to successfully send the command to enable CTE * receive for AoD mode (e.g. device equipped with single antenna). + * There is no CTE type in the parameters list, so controller is forced + * to check correctness of all parameters always. */ cp->slot_durations = BT_HCI_LE_ANTENNA_SWITCHING_SLOT_2US; - cp->switch_pattern_len = ARRAY_SIZE(df_dummy_switch_pattern); ant_ids = &df_dummy_switch_pattern[0]; } - dest_ant_ids = net_buf_add(buf, params->num_ant_ids); + cp->switch_pattern_len = switch_pattern_len; + dest_ant_ids = net_buf_add(*buf, cp->switch_pattern_len); (void)memcpy(dest_ant_ids, ant_ids, cp->switch_pattern_len); } + + return 0; } static int hci_df_set_conn_cte_rx_enable(struct bt_conn *conn, bool enable, @@ -554,18 +585,11 @@ static int hci_df_set_conn_cte_rx_enable(struct bt_conn *conn, bool enable, } } - /* If CTE Rx is enabled, command parameters total length must include - * antenna ids, so command size if extended by num_and_ids. - */ - buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_CONN_CTE_RX_PARAMS, - (sizeof(struct bt_hci_rp_le_set_conn_cte_rx_params) + - (enable ? params->num_ant_ids : 0))); - if (!buf) { - return -ENOBUFS; + err = prepare_conn_cte_rx_enable_cmd_params(&buf, conn, params, enable); + if (err) { + return err; } - prepare_conn_cte_rx_enable_cmd_params(buf, conn, params, enable); - bt_hci_cmd_state_set_init(buf, &state, conn->flags, BT_CONN_CTE_RX_ENABLED, enable); err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_CONN_CTE_RX_PARAMS, buf, &rsp); @@ -605,7 +629,6 @@ int hci_df_prepare_connection_iq_report(struct net_buf *buf, evt = net_buf_pull_mem(buf, sizeof(*evt)); conn = bt_conn_lookup_handle(sys_le16_to_cpu(evt->conn_handle)); - if (!conn) { BT_ERR("Unknown conn handle 0x%04X for iq samples report", sys_le16_to_cpu(evt->conn_handle)); @@ -622,6 +645,7 @@ int hci_df_prepare_connection_iq_report(struct net_buf *buf, return -EINVAL; } + report->err = BT_DF_IQ_REPORT_ERR_SUCCESS; report->chan_idx = evt->data_chan_idx; report->rx_phy = evt->rx_phy; report->chan_idx = evt->data_chan_idx; @@ -669,7 +693,7 @@ static void prepare_conn_cte_req_enable_cmd_params(struct net_buf *buf, const st if (enable) { cp->cte_request_interval = params->interval; - cp->requested_cte_length = params->cte_length; + cp->requested_cte_length = sys_cpu_to_le16(params->cte_length); cp->requested_cte_type = get_hci_cte_type(params->cte_type); } } @@ -682,7 +706,7 @@ static int hci_df_set_conn_cte_req_enable(struct bt_conn *conn, bool enable, struct net_buf *buf, *rsp; int err; - if (enable && !valid_cte_req_params(conn, params->cte_length, params->cte_type)) { + if (enable && !valid_cte_req_params(conn, params->cte_type, params->cte_length)) { return -EINVAL; } @@ -710,6 +734,45 @@ static int hci_df_set_conn_cte_req_enable(struct bt_conn *conn, bool enable, return err; } + +int hci_df_prepare_conn_cte_req_failed(struct net_buf *buf, + struct bt_df_conn_iq_samples_report *report, + struct bt_conn **conn_to_report) +{ + struct bt_hci_evt_le_cte_req_failed *evt; + struct bt_conn *conn; + + if (buf->len < sizeof(*evt)) { + BT_ERR("Unexpected end of buffer"); + return -EINVAL; + } + + evt = net_buf_pull_mem(buf, sizeof(*evt)); + + conn = bt_conn_lookup_handle(sys_le16_to_cpu(evt->conn_handle)); + if (!conn) { + BT_ERR("Unknown conn handle 0x%04X for iq samples report", + sys_le16_to_cpu(evt->conn_handle)); + return -EINVAL; + } + + if (!atomic_test_bit(conn->flags, BT_CONN_CTE_REQ_ENABLED)) { + BT_ERR("Received conn CTE request notification when CTE REQ disabled"); + return -EINVAL; + } + + (void)memset(report, 0U, sizeof(*report)); + + if (evt->status == BT_HCI_CTE_REQ_STATUS_RSP_WITHOUT_CTE) { + report->err = BT_DF_IQ_REPORT_ERR_NO_CTE; + } else { + report->err = BT_DF_IQ_REPORT_ERR_PEER_REJECTED; + } + + *conn_to_report = conn; + + return 0; +} #endif /* CONFIG_BT_DF_CONNECTION_CTE_REQ */ #if defined(CONFIG_BT_DF_CONNECTION_CTE_RSP) diff --git a/subsys/bluetooth/host/direction_internal.h b/subsys/bluetooth/host/direction_internal.h index 424bc536df6..0fb8d89ab3d 100644 --- a/subsys/bluetooth/host/direction_internal.h +++ b/subsys/bluetooth/host/direction_internal.h @@ -13,3 +13,6 @@ void hci_df_prepare_connectionless_iq_report(struct net_buf *buf, int hci_df_prepare_connection_iq_report(struct net_buf *buf, struct bt_df_conn_iq_samples_report *report, struct bt_conn **conn_to_report); +int hci_df_prepare_conn_cte_req_failed(struct net_buf *buf, + struct bt_df_conn_iq_samples_report *report, + struct bt_conn **conn_to_report); diff --git a/subsys/bluetooth/host/gatt.c b/subsys/bluetooth/host/gatt.c index 448c05885b3..dae58bc6f16 100644 --- a/subsys/bluetooth/host/gatt.c +++ b/subsys/bluetooth/host/gatt.c @@ -142,6 +142,9 @@ BUILD_ASSERT(!(CONFIG_BT_PERIPHERAL_PREF_TIMEOUT > 3200 && BUILD_ASSERT((CONFIG_BT_PERIPHERAL_PREF_MIN_INT == 0xffff) || (CONFIG_BT_PERIPHERAL_PREF_MIN_INT <= CONFIG_BT_PERIPHERAL_PREF_MAX_INT)); +BUILD_ASSERT((CONFIG_BT_PERIPHERAL_PREF_TIMEOUT * 4U) > + ((1U + CONFIG_BT_PERIPHERAL_PREF_LATENCY) * + CONFIG_BT_PERIPHERAL_PREF_MAX_INT)); static ssize_t read_ppcp(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) @@ -4905,6 +4908,8 @@ void bt_gatt_connected(struct bt_conn *conn) settings_load_subtree_direct(key, ccc_set_direct, (void *)key); } + bt_gatt_foreach_attr(0x0001, 0xffff, update_ccc, &data); + /* BLUETOOTH CORE SPECIFICATION Version 5.1 | Vol 3, Part C page 2192: * * 10.3.1.1 Handling of GATT indications and notifications diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index 617ba3cc38b..033f695ae22 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -2229,6 +2229,11 @@ static const struct event_handler meta_events[] = { EVENT_HANDLER(BT_HCI_EVT_LE_CONNECTION_IQ_REPORT, bt_hci_le_df_connection_iq_report, sizeof(struct bt_hci_evt_le_connection_iq_report)), #endif /* CONFIG_BT_DF_CONNECTION_CTE_RX */ +#if defined(CONFIG_BT_DF_CONNECTION_CTE_REQ) + EVENT_HANDLER(BT_HCI_EVT_LE_CTE_REQUEST_FAILED, bt_hci_le_df_cte_req_failed, + sizeof(struct bt_hci_evt_le_cte_req_failed)), +#endif /* CONFIG_BT_DF_CONNECTION_CTE_REQ */ + }; static void hci_le_meta_event(struct net_buf *buf) diff --git a/subsys/bluetooth/host/hci_core.h b/subsys/bluetooth/host/hci_core.h index 412da9c2639..c265eec1078 100644 --- a/subsys/bluetooth/host/hci_core.h +++ b/subsys/bluetooth/host/hci_core.h @@ -469,3 +469,4 @@ void bt_hci_role_change(struct net_buf *buf); void bt_hci_synchronous_conn_complete(struct net_buf *buf); void bt_hci_le_df_connection_iq_report(struct net_buf *buf); +void bt_hci_le_df_cte_req_failed(struct net_buf *buf); diff --git a/subsys/bluetooth/host/iso.c b/subsys/bluetooth/host/iso.c index fe42c6a37bf..fa9771798c6 100644 --- a/subsys/bluetooth/host/iso.c +++ b/subsys/bluetooth/host/iso.c @@ -442,15 +442,16 @@ static void bt_iso_chan_disconnected(struct bt_iso_chan *chan, uint8_t reason) #if defined(CONFIG_BT_ISO_UNICAST) bool is_chan_connected; struct bt_iso_cig *cig; + struct bt_iso_chan *cis_chan; /* Update CIG state */ cig = get_cig(chan); __ASSERT(cig != NULL, "CIG was NULL"); is_chan_connected = false; - SYS_SLIST_FOR_EACH_CONTAINER(&cig->cis_channels, chan, node) { - if (chan->state == BT_ISO_CONNECTED || - chan->state == BT_ISO_CONNECT) { + SYS_SLIST_FOR_EACH_CONTAINER(&cig->cis_channels, cis_chan, node) { + if (cis_chan->state == BT_ISO_CONNECTED || + cis_chan->state == BT_ISO_CONNECT) { is_chan_connected = true; break; } diff --git a/subsys/bluetooth/host/l2cap.c b/subsys/bluetooth/host/l2cap.c index 5aa608ccf7e..54bdf674e5f 100644 --- a/subsys/bluetooth/host/l2cap.c +++ b/subsys/bluetooth/host/l2cap.c @@ -1053,9 +1053,9 @@ static uint16_t l2cap_check_security(struct bt_conn *conn, if (keys) { if (conn->role == BT_HCI_ROLE_CENTRAL) { - ltk_present = keys->id & (BT_KEYS_LTK_P256 | BT_KEYS_PERIPH_LTK); + ltk_present = keys->keys & (BT_KEYS_LTK_P256 | BT_KEYS_PERIPH_LTK); } else { - ltk_present = keys->id & (BT_KEYS_LTK_P256 | BT_KEYS_LTK); + ltk_present = keys->keys & (BT_KEYS_LTK_P256 | BT_KEYS_LTK); } } else { ltk_present = false; diff --git a/subsys/bluetooth/host/scan.c b/subsys/bluetooth/host/scan.c index 033c9ca9cad..bdb690754f9 100644 --- a/subsys/bluetooth/host/scan.c +++ b/subsys/bluetooth/host/scan.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "hci_core.h" #include "conn_internal.h" @@ -27,6 +28,42 @@ static bt_le_scan_cb_t *scan_dev_found_cb; static sys_slist_t scan_cbs = SYS_SLIST_STATIC_INIT(&scan_cbs); #if defined(CONFIG_BT_EXT_ADV) +/* A buffer used to reassemble advertisement data from the controller. */ +NET_BUF_SIMPLE_DEFINE(ext_scan_buf, CONFIG_BT_EXT_SCAN_BUF_SIZE); + +struct fragmented_advertiser { + bt_addr_le_t addr; + uint8_t sid; + enum { + FRAG_ADV_INACTIVE, + FRAG_ADV_REASSEMBLING, + FRAG_ADV_DISCARDING, + } state; +}; + +static struct fragmented_advertiser reassembling_advertiser; + +static bool fragmented_advertisers_equal(const struct fragmented_advertiser *a, + const bt_addr_le_t *addr, uint8_t sid) +{ + /* Two advertisers are equal if they are the same adv set from the same device */ + return a->sid == sid && bt_addr_le_cmp(&a->addr, addr) == 0; +} + +/* Sets the address and sid of the advertiser to be reassembled. */ +static void init_reassembling_advertiser(const bt_addr_le_t *addr, uint8_t sid) +{ + bt_addr_le_copy(&reassembling_advertiser.addr, addr); + reassembling_advertiser.sid = sid; + reassembling_advertiser.state = FRAG_ADV_REASSEMBLING; +} + +static void reset_reassembling_advertiser(void) +{ + net_buf_simple_reset(&ext_scan_buf); + reassembling_advertiser.state = FRAG_ADV_INACTIVE; +} + #if defined(CONFIG_BT_PER_ADV_SYNC) static struct bt_le_per_adv_sync *get_pending_per_adv_sync(void); static struct bt_le_per_adv_sync per_adv_sync_pool[CONFIG_BT_PER_ADV_SYNC_MAX]; @@ -37,6 +74,9 @@ static sys_slist_t pa_sync_cbs = SYS_SLIST_STATIC_INIT(&pa_sync_cbs); void bt_scan_reset(void) { scan_dev_found_cb = NULL; +#if defined(CONFIG_BT_EXT_ADV) + reset_reassembling_advertiser(); +#endif } static int set_le_ext_scan_enable(uint8_t enable, uint16_t duration) @@ -361,7 +401,7 @@ static void check_pending_conn(const bt_addr_le_t *id_addr, #endif /* CONFIG_BT_CENTRAL */ /* Convert Legacy adv report evt_type field to adv props */ -static uint8_t get_adv_props(uint8_t evt_type) +static uint8_t get_adv_props_legacy(uint8_t evt_type) { switch (evt_type) { case BT_GAP_ADV_TYPE_ADV_IND: @@ -392,7 +432,7 @@ static uint8_t get_adv_props(uint8_t evt_type) } static void le_adv_recv(bt_addr_le_t *addr, struct bt_le_scan_recv_info *info, - struct net_buf *buf, uint8_t len) + struct net_buf_simple *buf, uint16_t len) { struct bt_le_scan_cb *listener, *next; struct net_buf_simple_state state; @@ -423,23 +463,22 @@ static void le_adv_recv(bt_addr_le_t *addr, struct bt_le_scan_recv_info *info, info->addr = &id_addr; if (scan_dev_found_cb) { - net_buf_simple_save(&buf->b, &state); + net_buf_simple_save(buf, &state); buf->len = len; - scan_dev_found_cb(&id_addr, info->rssi, info->adv_type, - &buf->b); + scan_dev_found_cb(&id_addr, info->rssi, info->adv_type, buf); - net_buf_simple_restore(&buf->b, &state); + net_buf_simple_restore(buf, &state); } SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&scan_cbs, listener, next, node) { if (listener->recv) { - net_buf_simple_save(&buf->b, &state); + net_buf_simple_save(buf, &state); buf->len = len; - listener->recv(info, &buf->b); + listener->recv(info, buf); - net_buf_simple_restore(&buf->b, &state); + net_buf_simple_restore(buf, &state); } } @@ -507,15 +546,43 @@ static uint8_t get_adv_type(uint8_t evt_type) } } +/* Convert extended adv report evt_type field to adv props */ +static uint16_t get_adv_props_extended(uint16_t evt_type) +{ + /* Converts from BT_HCI_LE_ADV_EVT_TYPE_* to BT_GAP_ADV_PROP_* + * The first 4 bits are the same (conn, scan, direct, scan_rsp). + * Bit 4 must be flipped as the meaning of 1 is opposite (legacy -> extended) + * The rest of the bits are zeroed out. + */ + return (evt_type ^ BT_HCI_LE_ADV_EVT_TYPE_LEGACY) & BIT_MASK(5); +} + +static void create_ext_adv_info(struct bt_hci_evt_le_ext_advertising_info const *const evt, + struct bt_le_scan_recv_info *const scan_info) +{ + scan_info->primary_phy = bt_get_phy(evt->prim_phy); + scan_info->secondary_phy = bt_get_phy(evt->sec_phy); + scan_info->tx_power = evt->tx_power; + scan_info->rssi = evt->rssi; + scan_info->sid = evt->sid; + scan_info->interval = sys_le16_to_cpu(evt->interval); + scan_info->adv_type = get_adv_type(evt->evt_type); + scan_info->adv_props = get_adv_props_extended(evt->evt_type); +} + void bt_hci_le_adv_ext_report(struct net_buf *buf) { uint8_t num_reports = net_buf_pull_u8(buf); - BT_DBG("Adv number of reports %u", num_reports); + BT_DBG("Adv number of reports %u", num_reports); while (num_reports--) { struct bt_hci_evt_le_ext_advertising_info *evt; - struct bt_le_scan_recv_info adv_info; + struct bt_le_scan_recv_info scan_info; + uint16_t data_status; + bool is_report_complete; + bool more_to_come; + bool is_new_advertiser; if (buf->len < sizeof(*evt)) { BT_ERR("Unexpected end of buffer"); @@ -523,34 +590,99 @@ void bt_hci_le_adv_ext_report(struct net_buf *buf) } evt = net_buf_pull_mem(buf, sizeof(*evt)); + data_status = BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS(evt->evt_type); + is_report_complete = data_status == BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_COMPLETE; + more_to_come = data_status == BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_PARTIAL; - adv_info.primary_phy = bt_get_phy(evt->prim_phy); - adv_info.secondary_phy = bt_get_phy(evt->sec_phy); - adv_info.tx_power = evt->tx_power; - adv_info.rssi = evt->rssi; - adv_info.sid = evt->sid; - adv_info.interval = sys_le16_to_cpu(evt->interval); - - adv_info.adv_type = get_adv_type(evt->evt_type); - /* Convert "Legacy" property to Extended property. */ - adv_info.adv_props = evt->evt_type ^ BT_HCI_LE_ADV_PROP_LEGACY; - - if (BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS(evt->evt_type) == - BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_PARTIAL) { - /* Handling of incomplete reports is currently not - * handled in the host. The remaining advertising - * reports may therefore contain partial data. + if (evt->evt_type & BT_HCI_LE_ADV_EVT_TYPE_LEGACY) { + /* Legacy advertising reports are complete. + * Create event immediately. */ - BT_WARN("Incomplete adv report"); + create_ext_adv_info(evt, &scan_info); + le_adv_recv(&evt->addr, &scan_info, &buf->b, evt->length); + continue; } - le_adv_recv(&evt->addr, &adv_info, buf, evt->length); + is_new_advertiser = reassembling_advertiser.state == FRAG_ADV_INACTIVE || + !fragmented_advertisers_equal(&reassembling_advertiser, + &evt->addr, evt->sid); + + if (is_new_advertiser && is_report_complete) { + /* Only advertising report from this advertiser. + * Create event immediately. + */ + create_ext_adv_info(evt, &scan_info); + le_adv_recv(&evt->addr, &scan_info, &buf->b, evt->length); + continue; + } + + if (is_new_advertiser && reassembling_advertiser.state == FRAG_ADV_REASSEMBLING) { + BT_WARN("Received an incomplete advertising report while reassembling " + "advertising reports from a different advertiser. The advertising " + "report is discarded and future scan results may be incomplete. " + "Interleaving of fragmented advertising reports from different " + "advertisers is not yet supported."); + (void)net_buf_pull_mem(buf, evt->length); + continue; + } + + if (data_status == BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_INCOMPLETE) { + /* Controller truncated, no more data will come. + * We do not need to keep track of this advertiser. + * Discard this report. + */ + (void)net_buf_pull_mem(buf, evt->length); + reset_reassembling_advertiser(); + continue; + } + + if (is_new_advertiser) { + /* We are not reassembling reports from an advertiser and + * this is the first report from the new advertiser. + * Initialize the new advertiser. + */ + __ASSERT_NO_MSG(reassembling_advertiser.state == FRAG_ADV_INACTIVE); + init_reassembling_advertiser(&evt->addr, evt->sid); + } + + if (evt->length + ext_scan_buf.len > ext_scan_buf.size) { + /* The report does not fit in the reassemby buffer + * Discard this and future reports from the advertiser. + */ + reassembling_advertiser.state = FRAG_ADV_DISCARDING; + } + + if (reassembling_advertiser.state == FRAG_ADV_DISCARDING) { + (void)net_buf_pull_mem(buf, evt->length); + if (!more_to_come) { + /* We do no longer need to keep track of this advertiser as + * all the expected data is received. + */ + reset_reassembling_advertiser(); + } + continue; + } + + net_buf_simple_add_mem(&ext_scan_buf, buf->data, evt->length); + if (more_to_come) { + /* The controller will send additional reports to be reassembled */ + continue; + } + + /* No more data coming from the controller. + * Create event. + */ + __ASSERT_NO_MSG(is_report_complete); + create_ext_adv_info(evt, &scan_info); + le_adv_recv(&evt->addr, &scan_info, &ext_scan_buf, ext_scan_buf.len); + + /* We do no longer need to keep track of this advertiser. */ + reset_reassembling_advertiser(); net_buf_pull(buf, evt->length); } } - #if defined(CONFIG_BT_PER_ADV_SYNC) static void per_adv_sync_delete(struct bt_le_per_adv_sync *per_adv_sync) { @@ -803,6 +935,14 @@ void bt_hci_le_per_adv_sync_established(struct net_buf *buf) memset(&sync_info, 0, sizeof(sync_info)); sync_info.interval = pending_per_adv_sync->interval; sync_info.phy = bt_get_phy(pending_per_adv_sync->phy); + + if (atomic_test_bit(pending_per_adv_sync->flags, + BT_PER_ADV_SYNC_SYNCING_USE_LIST)) { + /* Now we know which address and SID we synchronized to. */ + bt_addr_le_copy(&pending_per_adv_sync->addr, &evt->adv_addr); + pending_per_adv_sync->sid = evt->sid; + } + sync_info.addr = &pending_per_adv_sync->addr; sync_info.sid = pending_per_adv_sync->sid; @@ -989,9 +1129,9 @@ void bt_hci_le_adv_report(struct net_buf *buf) adv_info.interval = 0U; adv_info.adv_type = evt->evt_type; - adv_info.adv_props = get_adv_props(evt->evt_type); + adv_info.adv_props = get_adv_props_legacy(evt->evt_type); - le_adv_recv(&evt->addr, &adv_info, buf, evt->length); + le_adv_recv(&evt->addr, &adv_info, &buf->b, evt->length); net_buf_pull(buf, evt->length + sizeof(adv_info.rssi)); } @@ -1122,7 +1262,7 @@ int bt_le_scan_stop(void) return -EALREADY; } - scan_dev_found_cb = NULL; + bt_scan_reset(); if (IS_ENABLED(CONFIG_BT_EXT_ADV) && atomic_test_and_clear_bit(bt_dev.flags, BT_DEV_SCAN_LIMITED)) { diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index 5f97d60fb9f..9eeba460688 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -4,7 +4,8 @@ # SPDX-License-Identifier: Apache-2.0 menuconfig BT_MESH - bool "Bluetooth mesh support" + bool "Bluetooth mesh support [EXPERIMENTAL]" + select EXPERIMENTAL select TINYCRYPT select TINYCRYPT_AES select TINYCRYPT_AES_CMAC diff --git a/subsys/fs/littlefs_fs.c b/subsys/fs/littlefs_fs.c index f9b2bb621bd..85718d5983f 100644 --- a/subsys/fs/littlefs_fs.c +++ b/subsys/fs/littlefs_fs.c @@ -775,6 +775,12 @@ static const struct fs_file_system_t littlefs_fs = { .statvfs = littlefs_statvfs, }; +#ifdef USE_PARTITION_MANAGER +#define _LFS_USE_NCS_PM 1 +#else +#define _LFS_USE_NCS_PM 0 +#endif + #define DT_DRV_COMPAT zephyr_fstab_littlefs #define FS_PARTITION(inst) DT_PHANDLE_BY_IDX(DT_DRV_INST(inst), partition, 0) @@ -809,7 +815,11 @@ struct fs_mount_t FS_FSTAB_ENTRY(DT_DRV_INST(inst)) = { \ .type = FS_LITTLEFS, \ .mnt_point = DT_INST_PROP(inst, mount_point), \ .fs_data = &fs_data_##inst, \ - .storage_dev = (void *)DT_FIXED_PARTITION_ID(FS_PARTITION(inst)), \ + .storage_dev = (void *) (_LFS_USE_NCS_PM ?\ + COND_CODE_1(FLASH_AREA_LABEL_EXISTS(littlefs_storage), \ + (FLASH_AREA_ID(littlefs_storage)), \ + (FLASH_AREA_ID(storage))) :\ + DT_FIXED_PARTITION_ID(FS_PARTITION(inst))), \ .flags = FSTAB_ENTRY_DT_MOUNT_FLAGS(DT_DRV_INST(inst)), \ }; diff --git a/subsys/ipc/rpmsg_service/rpmsg_backend.h b/subsys/ipc/rpmsg_service/rpmsg_backend.h index ab5df7c4297..b4adec43445 100644 --- a/subsys/ipc/rpmsg_service/rpmsg_backend.h +++ b/subsys/ipc/rpmsg_service/rpmsg_backend.h @@ -13,8 +13,35 @@ extern "C" { #endif +#if CONFIG_PARTITION_MANAGER_ENABLED + +#include "pm_config.h" + +#if defined(PM_RPMSG_NRF53_SRAM_ADDRESS) || defined(PM__RPMSG_NRF53_SRAM_ADDRESS) + +#if defined(PM_RPMSG_NRF53_SRAM_ADDRESS) +#define VDEV_START_ADDR PM_RPMSG_NRF53_SRAM_ADDRESS +#define VDEV_SIZE PM_RPMSG_NRF53_SRAM_SIZE +#else +/* The current image is a child image in a different domain than the image + * which defined the required values. To reach the values of the parent domain + * we use the 'PM__' variant of the define. + */ +#define VDEV_START_ADDR PM__RPMSG_NRF53_SRAM_ADDRESS +#define VDEV_SIZE PM__RPMSG_NRF53_SRAM_SIZE +#endif /* defined(PM_RPMSG_NRF53_SRAM_ADDRESS) */ + +#else #define VDEV_START_ADDR CONFIG_RPMSG_SERVICE_SHM_BASE_ADDRESS #define VDEV_SIZE CONFIG_RPMSG_SERVICE_SHM_SIZE +#endif /* defined(PM_RPMSG_NRF53_SRAM_ADDRESS) || defined(PM__RPMSG_NRF53_SRAM_ADDRESS) */ + +#else + +#define VDEV_START_ADDR CONFIG_RPMSG_SERVICE_SHM_BASE_ADDRESS +#define VDEV_SIZE CONFIG_RPMSG_SERVICE_SHM_SIZE + +#endif /* CONFIG_PARTITION_MANAGER_ENABLED */ #define VDEV_STATUS_ADDR VDEV_START_ADDR #define VDEV_STATUS_SIZE 0x400 diff --git a/subsys/logging/log_core.c b/subsys/logging/log_core.c index 38308157afd..cbbf4959318 100644 --- a/subsys/logging/log_core.c +++ b/subsys/logging/log_core.c @@ -226,16 +226,17 @@ static void detect_missed_strdup(struct log_msg *msg) static void z_log_msg_post_finalize(void) { - atomic_inc(&buffered_cnt); + atomic_val_t cnt = atomic_inc(&buffered_cnt); + if (panic_mode) { unsigned int key = irq_lock(); (void)log_process(false); irq_unlock(key); - } else if (proc_tid != NULL && buffered_cnt == 1) { + } else if (proc_tid != NULL && cnt == 0) { k_timer_start(&log_process_thread_timer, K_MSEC(CONFIG_LOG_PROCESS_THREAD_SLEEP_MS), K_NO_WAIT); } else if (CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD) { - if ((buffered_cnt == CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD) && + if ((cnt == CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD) && (proc_tid != NULL)) { k_timer_stop(&log_process_thread_timer); k_sem_give(&log_process_thread_sem); @@ -816,7 +817,9 @@ bool z_impl_log_process(bool bypass) msg = get_msg(); if (msg.msg) { - atomic_dec(&buffered_cnt); + if (!bypass) { + atomic_dec(&buffered_cnt); + } msg_process(msg, bypass); } diff --git a/subsys/mgmt/mcumgr/Kconfig b/subsys/mgmt/mcumgr/Kconfig index 98ac7ed7373..9f0de718b53 100644 --- a/subsys/mgmt/mcumgr/Kconfig +++ b/subsys/mgmt/mcumgr/Kconfig @@ -315,51 +315,64 @@ config MCUMGR_SMP_BT_AUTHEN Enables encrypted and authenticated connection requirement to Bluetooth SMP transport. -config MCUMGR_SMP_BT_LATENCY_CONTROL - bool "Request low latency connection when handling SMP commands" +config MCUMGR_SMP_BT_CONN_PARAM_CONTROL + bool "Request specific connection parameters for SMP packet exchange" depends on SYSTEM_WORKQUEUE_PRIORITY < 0 + depends on BT_GAP_PERIPHERAL_PREF_PARAMS help - Enables support for requesting low latency connection parameter when + Enables support for requesting specific connection parameters when SMP commands are handled. This option allows to speed up the command exchange process. Its recommended to enable this if SMP is used for DFU. -config MCUMGR_SMP_BT_LATENCY_CONTROL_DEFAULT_LATENCY - int "Default value for connection latency" - depends on MCUMGR_SMP_BT_LATENCY_CONTROL - default BT_PERIPHERAL_PREF_LATENCY if BT_GAP_PERIPHERAL_PREF_PARAMS - default 99 +if MCUMGR_SMP_BT_CONN_PARAM_CONTROL + +config MCUMGR_SMP_BT_CONN_PARAM_CONTROL_MIN_INT + int "Minimum connection interval for SMP packet exchange" + default 6 + range 6 3200 + help + Minimum connection interval in 1.25ms units used during the exchange of SMP packets. + +config MCUMGR_SMP_BT_CONN_PARAM_CONTROL_MAX_INT + int "Maximum connection interval for SMP packet exchange" + default 9 + range MCUMGR_SMP_BT_CONN_PARAM_CONTROL_MIN_INT 3200 + help + Maximum connection interval in 1.25ms units used during the exchange of SMP packets. + +config MCUMGR_SMP_BT_CONN_PARAM_CONTROL_LATENCY + int "Peripheral latency for SMP packet exchange" + default 0 range 0 499 help - The value is a default connection latency that is used when restoring - from low latency mode. + Peripheral latency in Connection Intervals used during the exchange of SMP packets. -config MCUMGR_SMP_BT_LATENCY_CONTROL_RESTORE_TIME - int "Connection latency restore time in milliseconds" - depends on MCUMGR_SMP_BT_LATENCY_CONTROL +config MCUMGR_SMP_BT_CONN_PARAM_CONTROL_TIMEOUT + int "Supervision timeout for SMP packet exchange" + default 42 + range 10 3200 + help + Supervision timeout in 10ms used during the exchange of SMP packets. + +config MCUMGR_SMP_BT_CONN_PARAM_CONTROL_RESTORE_TIME + int "Connection parameters restore time in milliseconds" default 5000 - range 1 65535 - help - The value is a time after which connection latency is restored - to default value - (:kconfig:`MCUMGR_SMP_BT_LATENCY_CONTROL_DEFAULT_LATENCY`). Latency - restoration time could take up to twice as long as specified time. - This is because of limiting CPU time needed to support this feature. - The implementation periodically checks if the low latency is still - needed every :kconfig:`MCUMGR_SMP_BT_LATENCY_CONTROL_RESTORE_TIME`. - The default latency is restored during check only if there was no SMP - command exchanged in period before the check - -config MCUMGR_SMP_BT_LATENCY_CONTROL_RESTORE_RETRY_TIME - int "Connection latency restore retry time in milliseconds" - depends on MCUMGR_SMP_BT_LATENCY_CONTROL + range 1000 65535 + help + The value is a time of inactivity on the SMP characteristic after which + connection parameters are restored to peripheral preferred values + (:kconfig:`BT_GAP_PERIPHERAL_PREF_PARAMS`). + +config MCUMGR_SMP_BT_CONN_PARAM_CONTROL_RETRY_TIME + int "Connection parameters update retry time in milliseconds" default 1000 range 1 5000 help - In case connection latency restoration fails due to an error, this - option specifies the time after retry to set the default latency - (:kconfig:`MCUMGR_SMP_BT_LATENCY_CONTROL_DEFAULT_LATENCY`) would be - executed. + In case connection parameters update fails due to an error, this + option specifies the time of the next update attempt. + +endif # MCUMGR_SMP_BT_CONN_PARAM_CONTROL endif # MCUMGR_SMP_BT diff --git a/subsys/mgmt/mcumgr/smp_bt.c b/subsys/mgmt/mcumgr/smp_bt.c index 84ff096bc8e..55835eb83f5 100644 --- a/subsys/mgmt/mcumgr/smp_bt.c +++ b/subsys/mgmt/mcumgr/smp_bt.c @@ -21,27 +21,48 @@ #include -#define RESTORE_TIME COND_CODE_1(CONFIG_MCUMGR_SMP_BT_LATENCY_CONTROL, \ - (CONFIG_MCUMGR_SMP_BT_LATENCY_CONTROL_RESTORE_TIME), (0)) -#define RESTORE_RETRY_TIME COND_CODE_1(CONFIG_MCUMGR_SMP_BT_LATENCY_CONTROL, \ - (CONFIG_MCUMGR_SMP_BT_LATENCY_CONTROL_RESTORE_RETRY_TIME), (0)) -#define DEFAULT_LATENCY COND_CODE_1(CONFIG_MCUMGR_SMP_BT_LATENCY_CONTROL, \ - (CONFIG_MCUMGR_SMP_BT_LATENCY_CONTROL_DEFAULT_LATENCY), (0)) - +#define RESTORE_TIME COND_CODE_1(CONFIG_MCUMGR_SMP_BT_CONN_PARAM_CONTROL, \ + (CONFIG_MCUMGR_SMP_BT_CONN_PARAM_CONTROL_RESTORE_TIME), \ + (0)) +#define RETRY_TIME COND_CODE_1(CONFIG_MCUMGR_SMP_BT_CONN_PARAM_CONTROL, \ + (CONFIG_MCUMGR_SMP_BT_CONN_PARAM_CONTROL_RETRY_TIME), \ + (0)) + +#define CONN_PARAM_SMP COND_CODE_1(CONFIG_MCUMGR_SMP_BT_CONN_PARAM_CONTROL, \ + BT_LE_CONN_PARAM( \ + CONFIG_MCUMGR_SMP_BT_CONN_PARAM_CONTROL_MIN_INT, \ + CONFIG_MCUMGR_SMP_BT_CONN_PARAM_CONTROL_MAX_INT, \ + CONFIG_MCUMGR_SMP_BT_CONN_PARAM_CONTROL_LATENCY, \ + CONFIG_MCUMGR_SMP_BT_CONN_PARAM_CONTROL_TIMEOUT), \ + (NULL)) +#define CONN_PARAM_PREF COND_CODE_1(CONFIG_MCUMGR_SMP_BT_CONN_PARAM_CONTROL, \ + BT_LE_CONN_PARAM( \ + CONFIG_BT_PERIPHERAL_PREF_MIN_INT, \ + CONFIG_BT_PERIPHERAL_PREF_MAX_INT, \ + CONFIG_BT_PERIPHERAL_PREF_LATENCY, \ + CONFIG_BT_PERIPHERAL_PREF_TIMEOUT), \ + (NULL)) + +#ifdef CONFIG_MCUMGR_SMP_BT_CONN_PARAM_CONTROL +/* Verification of SMP Connection Parameters configuration that is not possible in the Kconfig. */ +BUILD_ASSERT((CONFIG_MCUMGR_SMP_BT_CONN_PARAM_CONTROL_TIMEOUT * 4U) > + ((1U + CONFIG_MCUMGR_SMP_BT_CONN_PARAM_CONTROL_LATENCY) * + CONFIG_MCUMGR_SMP_BT_CONN_PARAM_CONTROL_MAX_INT)); +#endif struct smp_bt_user_data { struct bt_conn *conn; }; enum { - CONN_LOW_LATENCY_ENABLED = BIT(0), - CONN_LOW_LATENCY_REQUIRED = BIT(1), + CONN_PARAM_SMP_REQUESTED = BIT(0), }; struct conn_param_data { struct bt_conn *conn; struct k_work_delayable dwork; - uint8_t latency_state; + struct k_work_delayable ework; + uint8_t state; }; static struct zephyr_smp_transport smp_bt_transport; @@ -60,7 +81,7 @@ static struct bt_uuid_128 smp_bt_chr_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0xda2e7828, 0xfbce, 0x4e01, 0xae9e, 0x261174997c48)); /* Helper function that allocates conn_param_data for a conn. */ -static struct conn_param_data *alloc_conn_param_data(struct bt_conn *conn) +static struct conn_param_data *conn_param_data_alloc(struct bt_conn *conn) { for (size_t i = 0; i < ARRAY_SIZE(conn_data); i++) { if (conn_data[i].conn == NULL) { @@ -75,7 +96,7 @@ static struct conn_param_data *alloc_conn_param_data(struct bt_conn *conn) } /* Helper function that returns conn_param_data associated with a conn. */ -static struct conn_param_data *get_conn_param_data(const struct bt_conn *conn) +static struct conn_param_data *conn_param_data_get(const struct bt_conn *conn) { for (size_t i = 0; i < ARRAY_SIZE(conn_data); i++) { if (conn_data[i].conn == conn) { @@ -89,63 +110,51 @@ static struct conn_param_data *get_conn_param_data(const struct bt_conn *conn) } /* Sets connection parameters for a given conn. */ -static void set_conn_latency(struct bt_conn *conn, bool low_latency) +static void conn_param_set(struct bt_conn *conn, struct bt_le_conn_param *param) { - struct bt_le_conn_param params; - struct conn_param_data *cpd; - struct bt_conn_info info; int ret = 0; + struct conn_param_data *cpd = conn_param_data_get(conn); - cpd = get_conn_param_data(conn); - - ret = bt_conn_get_info(conn, &info); - __ASSERT_NO_MSG(!ret); - - if ((low_latency && (info.le.latency == 0)) || - ((!low_latency) && (info.le.latency == DEFAULT_LATENCY))) { - /* Already updated. */ - return; - } - - params.interval_min = info.le.interval; - params.interval_max = info.le.interval; - params.latency = (low_latency) ? (0) : (DEFAULT_LATENCY); - params.timeout = info.le.timeout; - - ret = bt_conn_le_param_update(cpd->conn, ¶ms); + ret = bt_conn_le_param_update(conn, param); if (ret && (ret != -EALREADY)) { - if (!low_latency) { - /* Try again to avoid stucking in low latency. */ - (void)k_work_reschedule(&cpd->dwork, K_MSEC(RESTORE_RETRY_TIME)); - } + /* Try again to avoid being stuck with incorrect connection parameters. */ + (void)k_work_reschedule(&cpd->ework, K_MSEC(RETRY_TIME)); + } else { + (void)k_work_cancel_delayable(&cpd->ework); } } -/* Work handler function for restoring the default latency for the connection. */ -static void restore_default_latency(struct k_work *work) +/* Work handler function for restoring the preferred connection parameters for the connection. */ +static void conn_param_on_pref_restore(struct k_work *work) { - struct conn_param_data *cpd; + struct conn_param_data *cpd = CONTAINER_OF(work, struct conn_param_data, dwork); - cpd = CONTAINER_OF(work, struct conn_param_data, dwork); + conn_param_set(cpd->conn, CONN_PARAM_PREF); + cpd->state &= ~CONN_PARAM_SMP_REQUESTED; +} - if (cpd->latency_state & CONN_LOW_LATENCY_REQUIRED) { - cpd->latency_state &= ~CONN_LOW_LATENCY_REQUIRED; - (void)k_work_reschedule(&cpd->dwork, K_MSEC(RESTORE_TIME)); - } else { - set_conn_latency(cpd->conn, false); - } +/* Work handler function for retrying on conn negotiation API error. */ +static void conn_param_on_error_retry(struct k_work *work) +{ + struct conn_param_data *cpd = CONTAINER_OF(work, struct conn_param_data, ework); + struct bt_le_conn_param *param = (cpd->state & CONN_PARAM_SMP_REQUESTED) ? + CONN_PARAM_SMP : CONN_PARAM_PREF; + + conn_param_set(cpd->conn, param); } -static void enable_low_latency(struct bt_conn *conn) +static void conn_param_smp_enable(struct bt_conn *conn) { - struct conn_param_data *cpd = get_conn_param_data(conn); + struct conn_param_data *cpd = conn_param_data_get(conn); - if (cpd->latency_state & CONN_LOW_LATENCY_ENABLED) { - cpd->latency_state |= CONN_LOW_LATENCY_REQUIRED; - } else { - set_conn_latency(conn, true); + if (!(cpd->state & CONN_PARAM_SMP_REQUESTED)) { + conn_param_set(conn, CONN_PARAM_SMP); + cpd->state |= CONN_PARAM_SMP_REQUESTED; } + + /* SMP characteristic in use; refresh the restore timeout. */ + (void)k_work_reschedule(&cpd->dwork, K_MSEC(RESTORE_TIME)); } /** @@ -168,8 +177,8 @@ static ssize_t smp_bt_chr_write(struct bt_conn *conn, ud = net_buf_user_data(nb); ud->conn = bt_conn_ref(conn); - if (IS_ENABLED(CONFIG_MCUMGR_SMP_BT_LATENCY_CONTROL)) { - enable_low_latency(conn); + if (IS_ENABLED(CONFIG_MCUMGR_SMP_BT_CONN_PARAM_CONTROL)) { + conn_param_smp_enable(conn); } zephyr_smp_rx_req(&smp_bt_transport, nb); @@ -303,51 +312,36 @@ int smp_bt_unregister(void) static void connected(struct bt_conn *conn, uint8_t err) { if (err == 0) { - alloc_conn_param_data(conn); + conn_param_data_alloc(conn); } } /* BT disconnected callback. */ static void disconnected(struct bt_conn *conn, uint8_t reason) { - struct conn_param_data *cpd = get_conn_param_data(conn); + struct conn_param_data *cpd = conn_param_data_get(conn); /* Cancel work if ongoing. */ (void)k_work_cancel_delayable(&cpd->dwork); + (void)k_work_cancel_delayable(&cpd->ework); /* Clear cpd. */ - cpd->latency_state = 0; + cpd->state = 0; cpd->conn = NULL; } -/* BT LE connection parameters updated callback. */ -static void le_param_updated(struct bt_conn *conn, uint16_t interval, - uint16_t latency, uint16_t timeout) -{ - struct conn_param_data *cpd = get_conn_param_data(conn); - - if (latency == 0) { - cpd->latency_state |= CONN_LOW_LATENCY_ENABLED; - cpd->latency_state &= ~CONN_LOW_LATENCY_REQUIRED; - (void)k_work_reschedule(&cpd->dwork, K_MSEC(RESTORE_TIME)); - } else { - cpd->latency_state &= ~CONN_LOW_LATENCY_ENABLED; - (void)k_work_cancel_delayable(&cpd->dwork); - } -} - -static void init_latency_control_support(void) +static void conn_param_control_init(void) { /* Register BT callbacks */ static struct bt_conn_cb conn_callbacks = { .connected = connected, .disconnected = disconnected, - .le_param_updated = le_param_updated, }; bt_conn_cb_register(&conn_callbacks); for (size_t i = 0; i < ARRAY_SIZE(conn_data); i++) { - k_work_init_delayable(&conn_data[i].dwork, restore_default_latency); + k_work_init_delayable(&conn_data[i].dwork, conn_param_on_pref_restore); + k_work_init_delayable(&conn_data[i].ework, conn_param_on_error_retry); } } @@ -355,8 +349,8 @@ static int smp_bt_init(const struct device *dev) { ARG_UNUSED(dev); - if (IS_ENABLED(CONFIG_MCUMGR_SMP_BT_LATENCY_CONTROL)) { - init_latency_control_support(); + if (IS_ENABLED(CONFIG_MCUMGR_SMP_BT_CONN_PARAM_CONTROL)) { + conn_param_control_init(); } zephyr_smp_transport_init(&smp_bt_transport, smp_bt_tx_pkt, diff --git a/subsys/net/l2/openthread/Kconfig.features b/subsys/net/l2/openthread/Kconfig.features index c058644e626..50f2eed83f6 100644 --- a/subsys/net/l2/openthread/Kconfig.features +++ b/subsys/net/l2/openthread/Kconfig.features @@ -29,6 +29,9 @@ config OPENTHREAD_BORDER_AGENT config OPENTHREAD_BORDER_ROUTER bool "Enable Border Router support" +config OPENTHREAD_BORDER_ROUTING_NAT64 + bool "Enable border routing NAT64 support" + config OPENTHREAD_COAP bool "Enable OpenThread CoAP support" help @@ -81,6 +84,9 @@ config OPENTHREAD_DIAG config OPENTHREAD_DNS_CLIENT bool "Enable DNS client support" +config OPENTHREAD_DNS_DSO + bool "Enable DNS Stateful Operations (DSO) support" + config OPENTHREAD_DNSSD_SERVER bool "Enable DNS-SD server support" @@ -95,6 +101,9 @@ config OPENTHREAD_LOG_LEVEL_DYNAMIC config OPENTHREAD_ECDSA bool "Enable ECDSA support" +config OPENTHREAD_EXCLUDE_TCPLP_LIB + bool "Exclude TCPlp library from build" + config OPENTHREAD_EXTERNAL_HEAP bool "Enable external heap support" diff --git a/subsys/net/l2/openthread/Kconfig.thread b/subsys/net/l2/openthread/Kconfig.thread index c9aad6a816d..dc1fd366d82 100644 --- a/subsys/net/l2/openthread/Kconfig.thread +++ b/subsys/net/l2/openthread/Kconfig.thread @@ -100,6 +100,12 @@ config OPENTHREAD_CSL_MIN_RECEIVE_ON help The minimum CSL receive window (in microseconds) required to receive a full IEEE 802.15.4 frame +config OPENTHREAD_PLATFORM_CSL_UNCERT + int "CSL clock uncertainty" + default 255 + help + The Uncertainty of the scheduling CSL of transmission by the parent, in ±10 us units. + config OPENTHREAD_MAC_SOFTWARE_TX_SECURITY_ENABLE bool "Enable software transmission security logic" default y if OPENTHREAD_THREAD_VERSION_1_2 diff --git a/subsys/net/l2/openthread/openthread.c b/subsys/net/l2/openthread/openthread.c index 04aa8c51437..12765193075 100644 --- a/subsys/net/l2/openthread/openthread.c +++ b/subsys/net/l2/openthread/openthread.c @@ -297,8 +297,20 @@ static void openthread_process(struct k_work *work) openthread_api_mutex_unlock(ot_context); } -static enum net_verdict openthread_recv(struct net_if *iface, - struct net_pkt *pkt) +static bool is_ipv6_frag(struct net_pkt *pkt) +{ + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ipv6_access, struct net_ipv6_hdr); + struct net_ipv6_hdr *hdr; + + hdr = (struct net_ipv6_hdr *)net_pkt_get_data(pkt, &ipv6_access); + if (!hdr) { + return false; + } + + return hdr->nexthdr == NET_IPV6_NEXTHDR_FRAG ? true : false; +} + +static enum net_verdict openthread_recv(struct net_if *iface, struct net_pkt *pkt) { struct openthread_context *ot_context = net_if_l2_data(iface); @@ -310,6 +322,10 @@ static enum net_verdict openthread_recv(struct net_if *iface, net_pkt_hexdump(pkt, "Injected IPv6 packet"); } + if (IS_ENABLED(CONFIG_OPENTHREAD_IP6_FRAGM) && is_ipv6_frag(pkt)) { + return NET_DROP; + } + return NET_CONTINUE; } diff --git a/subsys/net/lib/lwm2m/Kconfig b/subsys/net/lib/lwm2m/Kconfig index 4c3b137b371..4b97fa24e40 100644 --- a/subsys/net/lib/lwm2m/Kconfig +++ b/subsys/net/lib/lwm2m/Kconfig @@ -310,6 +310,21 @@ config LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT help Include support for LWM2M Firmware Update Object (ID 5) +config LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT_MULTIPLE + bool "Support multiple firmware update objects [EXPERIMENTAL]" + depends on LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT + select EXPERIMENTAL + help + Support multiple instances of LWM2M Firwmare Update Object (ID 5) + +config LWM2M_FIRMWARE_UPDATE_OBJ_INSTANCE_COUNT + int "Maximum # of LWM2M Firmware update object instances" + default 1 + depends on LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT_MULTIPLE + help + This setting establishes the total count of LWM2M Firmware update + object instances available to the client. + config LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT bool "Firmware Update object pull support" default y diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.h b/subsys/net/lib/lwm2m/lwm2m_engine.h index 8ad786dd345..e33b307cb35 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.h +++ b/subsys/net/lib/lwm2m/lwm2m_engine.h @@ -128,9 +128,13 @@ int32_t lwm2m_server_get_pmax(uint16_t obj_inst_id); int lwm2m_server_short_id_to_inst(uint16_t short_id); #if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT) -uint8_t lwm2m_firmware_get_update_state(void); +void lwm2m_firmware_set_update_state_inst(uint16_t obj_inst_id, uint8_t state); +void lwm2m_firmware_set_update_result_inst(uint16_t obj_inst_id, uint8_t result); void lwm2m_firmware_set_update_state(uint8_t state); void lwm2m_firmware_set_update_result(uint8_t result); +uint8_t lwm2m_firmware_get_update_state_inst(uint16_t obj_inst_id); +uint8_t lwm2m_firmware_get_update_state(void); +uint8_t lwm2m_firmware_get_update_result_inst(uint16_t obj_inst_id); uint8_t lwm2m_firmware_get_update_result(void); #endif diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c b/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c index 980bd507361..7f3c26a4ea7 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c @@ -12,6 +12,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include +#include #include #include "lwm2m_object.h" @@ -20,6 +21,12 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #define FIRMWARE_VERSION_MAJOR 1 #define FIRMWARE_VERSION_MINOR 0 +#if defined(LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT_MULTIPLE) +#define MAX_INSTANCE_COUNT LWM2M_FIRMWARE_UPDATE_OBJ_INSTANCE_COUNT +#else +#define MAX_INSTANCE_COUNT 1 +#endif + /* Firmware resource IDs */ #define FIRMWARE_PACKAGE_ID 0 #define FIRMWARE_PACKAGE_URI_ID 1 @@ -47,12 +54,12 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #define RESOURCE_INSTANCE_COUNT (FIRMWARE_MAX_ID - 1) /* resource state variables */ -static uint8_t update_state; -static uint8_t update_result; -static uint8_t delivery_method; -static char package_uri[PACKAGE_URI_LEN]; +static uint8_t update_state[MAX_INSTANCE_COUNT]; +static uint8_t update_result[MAX_INSTANCE_COUNT]; +static uint8_t delivery_method[MAX_INSTANCE_COUNT]; +static char package_uri[MAX_INSTANCE_COUNT][PACKAGE_URI_LEN]; -/* only 1 instance of firmware object exists */ +/* A varying number of firmware object exists */ static struct lwm2m_engine_obj firmware; static struct lwm2m_engine_obj_field fields[] = { OBJ_FIELD_DATA(FIRMWARE_PACKAGE_ID, W, OPAQUE), @@ -66,41 +73,47 @@ static struct lwm2m_engine_obj_field fields[] = { OBJ_FIELD_DATA(FIRMWARE_UPDATE_DELIV_METHOD_ID, R, U8) }; -static struct lwm2m_engine_obj_inst inst; -static struct lwm2m_engine_res res[FIRMWARE_MAX_ID]; -static struct lwm2m_engine_res_inst res_inst[RESOURCE_INSTANCE_COUNT]; +static struct lwm2m_engine_obj_inst inst[MAX_INSTANCE_COUNT]; +static struct lwm2m_engine_res res[MAX_INSTANCE_COUNT][FIRMWARE_MAX_ID]; +static struct lwm2m_engine_res_inst res_inst[MAX_INSTANCE_COUNT][RESOURCE_INSTANCE_COUNT]; -static lwm2m_engine_set_data_cb_t write_cb; -static lwm2m_engine_execute_cb_t update_cb; +static lwm2m_engine_set_data_cb_t write_cb[MAX_INSTANCE_COUNT]; +static lwm2m_engine_execute_cb_t update_cb[MAX_INSTANCE_COUNT]; #ifdef CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT -extern int lwm2m_firmware_start_transfer(char *package_uri); +extern int lwm2m_firmware_start_transfer(uint16_t obj_inst_id, char *package_uri); #endif +uint8_t lwm2m_firmware_get_update_state_inst(uint16_t obj_inst_id) +{ + return update_state[obj_inst_id]; +} + uint8_t lwm2m_firmware_get_update_state(void) { - return update_state; + return lwm2m_firmware_get_update_state_inst(0); } -void lwm2m_firmware_set_update_state(uint8_t state) +void lwm2m_firmware_set_update_state_inst(uint16_t obj_inst_id, uint8_t state) { bool error = false; + char path[sizeof("5/65535/3")]; /* Check LWM2M SPEC appendix E.6.1 */ switch (state) { case STATE_DOWNLOADING: - if (update_state != STATE_IDLE) { + if (update_state[obj_inst_id] != STATE_IDLE) { error = true; } break; case STATE_DOWNLOADED: - if (update_state != STATE_DOWNLOADING && - update_state != STATE_UPDATING) { + if (update_state[obj_inst_id] != STATE_DOWNLOADING && + update_state[obj_inst_id] != STATE_UPDATING) { error = true; } break; case STATE_UPDATING: - if (update_state != STATE_DOWNLOADED) { + if (update_state[obj_inst_id] != STATE_DOWNLOADED) { error = true; } break; @@ -113,36 +126,49 @@ void lwm2m_firmware_set_update_state(uint8_t state) if (error) { LOG_ERR("Invalid state transition: %u -> %u", - update_state, state); + update_state[obj_inst_id], state); } - update_state = state; - NOTIFY_OBSERVER(LWM2M_OBJECT_FIRMWARE_ID, 0, FIRMWARE_STATE_ID); - LOG_DBG("Update state = %d", update_state); + snprintk(path, sizeof(path), "5/%" PRIu16 "/3", obj_inst_id); + + lwm2m_engine_set_u8(path, state); + + LOG_DBG("Update state = %d", state); +} + +void lwm2m_firmware_set_update_state(uint8_t state) +{ + lwm2m_firmware_set_update_state_inst(0, state); +} + +uint8_t lwm2m_firmware_get_update_result_inst(uint16_t obj_inst_id) +{ + return update_result[obj_inst_id]; } uint8_t lwm2m_firmware_get_update_result(void) { - return update_result; + return lwm2m_firmware_get_update_result_inst(0); } -void lwm2m_firmware_set_update_result(uint8_t result) +void lwm2m_firmware_set_update_result_inst(uint16_t obj_inst_id, uint8_t result) { uint8_t state; bool error = false; + char path[sizeof("5/65535/5")]; /* Check LWM2M SPEC appendix E.6.1 */ switch (result) { case RESULT_DEFAULT: - lwm2m_firmware_set_update_state(STATE_IDLE); + lwm2m_firmware_set_update_state_inst(obj_inst_id, STATE_IDLE); break; case RESULT_SUCCESS: - if (update_state != STATE_UPDATING) { + if (update_state[obj_inst_id] != STATE_UPDATING) { error = true; - state = update_state; + state = update_state[obj_inst_id]; } - lwm2m_firmware_set_update_state(STATE_IDLE); + lwm2m_firmware_set_update_state_inst(obj_inst_id, STATE_IDLE); break; case RESULT_NO_STORAGE: case RESULT_OUT_OF_MEM: @@ -150,30 +176,30 @@ void lwm2m_firmware_set_update_result(uint8_t result) case RESULT_UNSUP_FW: case RESULT_INVALID_URI: case RESULT_UNSUP_PROTO: - if (update_state != STATE_DOWNLOADING) { + if (update_state[obj_inst_id] != STATE_DOWNLOADING) { error = true; - state = update_state; + state = update_state[obj_inst_id]; } - lwm2m_firmware_set_update_state(STATE_IDLE); + lwm2m_firmware_set_update_state_inst(obj_inst_id, STATE_IDLE); break; case RESULT_INTEGRITY_FAILED: - if (update_state != STATE_DOWNLOADING && - update_state != STATE_UPDATING) { + if (update_state[obj_inst_id] != STATE_DOWNLOADING && + update_state[obj_inst_id] != STATE_UPDATING) { error = true; - state = update_state; + state = update_state[obj_inst_id]; } - lwm2m_firmware_set_update_state(STATE_IDLE); + lwm2m_firmware_set_update_state_inst(obj_inst_id, STATE_IDLE); break; case RESULT_UPDATE_FAILED: - if (update_state != STATE_DOWNLOADING && - update_state != STATE_UPDATING) { + if (update_state[obj_inst_id] != STATE_DOWNLOADING && + update_state[obj_inst_id] != STATE_UPDATING) { error = true; - state = update_state; + state = update_state[obj_inst_id]; } - lwm2m_firmware_set_update_state(STATE_IDLE); + lwm2m_firmware_set_update_state_inst(obj_inst_id, STATE_IDLE); break; default: LOG_ERR("Unhandled result: %u", result); @@ -185,9 +211,16 @@ void lwm2m_firmware_set_update_result(uint8_t result) result, state); } - update_result = result; - NOTIFY_OBSERVER(LWM2M_OBJECT_FIRMWARE_ID, 0, FIRMWARE_UPDATE_RESULT_ID); - LOG_DBG("Update result = %d", update_result); + snprintk(path, sizeof(path), "5/%" PRIu16 "/5", obj_inst_id); + + lwm2m_engine_set_u8(path, result); + + LOG_DBG("Update result = %d", result); +} + +void lwm2m_firmware_set_update_result(uint8_t result) +{ + lwm2m_firmware_set_update_result_inst(0, result); } static int package_write_cb(uint16_t obj_inst_id, uint16_t res_id, @@ -195,18 +228,19 @@ static int package_write_cb(uint16_t obj_inst_id, uint16_t res_id, bool last_block, size_t total_size) { uint8_t state; - int ret; + int ret = 0; + lwm2m_engine_set_data_cb_t callback; - state = lwm2m_firmware_get_update_state(); + state = lwm2m_firmware_get_update_state_inst(obj_inst_id); if (state == STATE_IDLE) { /* TODO: setup timer to check download status, * make sure it fail after timeout */ - lwm2m_firmware_set_update_state(STATE_DOWNLOADING); + lwm2m_firmware_set_update_state_inst(obj_inst_id, STATE_DOWNLOADING); } else if (state != STATE_DOWNLOADING) { if (data_len == 0U && state == STATE_DOWNLOADED) { /* reset to state idle and result default */ - lwm2m_firmware_set_update_result(RESULT_DEFAULT); + lwm2m_firmware_set_update_result_inst(obj_inst_id, RESULT_DEFAULT); return 0; } @@ -214,26 +248,31 @@ static int package_write_cb(uint16_t obj_inst_id, uint16_t res_id, return -EPERM; } - ret = write_cb ? write_cb(obj_inst_id, res_id, res_inst_id, - data, data_len, - last_block, total_size) : 0; + callback = lwm2m_firmware_get_write_cb_inst(obj_inst_id); + if (callback) { + ret = callback(obj_inst_id, res_id, res_inst_id, + data, data_len, last_block, total_size); + } + if (ret >= 0) { if (last_block) { - lwm2m_firmware_set_update_state(STATE_DOWNLOADED); + lwm2m_firmware_set_update_state_inst(obj_inst_id, STATE_DOWNLOADED); } return 0; } else if (ret == -ENOMEM) { - lwm2m_firmware_set_update_result(RESULT_OUT_OF_MEM); + lwm2m_firmware_set_update_result_inst(obj_inst_id, RESULT_OUT_OF_MEM); } else if (ret == -ENOSPC) { - lwm2m_firmware_set_update_result(RESULT_NO_STORAGE); + lwm2m_firmware_set_update_result_inst(obj_inst_id, RESULT_NO_STORAGE); /* Response 4.13 (RFC7959, section 2.9.3) */ /* TODO: should include size1 option to indicate max size */ ret = -EFBIG; } else if (ret == -EFAULT) { - lwm2m_firmware_set_update_result(RESULT_INTEGRITY_FAILED); + lwm2m_firmware_set_update_result_inst(obj_inst_id, RESULT_INTEGRITY_FAILED); + } else if (ret == -ENOMSG) { + lwm2m_firmware_set_update_result_inst(obj_inst_id, RESULT_UNSUP_FW); } else { - lwm2m_firmware_set_update_result(RESULT_UPDATE_FAILED); + lwm2m_firmware_set_update_result_inst(obj_inst_id, RESULT_UPDATE_FAILED); } return ret; @@ -243,20 +282,20 @@ static int package_uri_write_cb(uint16_t obj_inst_id, uint16_t res_id, uint16_t res_inst_id, uint8_t *data, uint16_t data_len, bool last_block, size_t total_size) { - LOG_DBG("PACKAGE_URI WRITE: %s", log_strdup(package_uri)); + LOG_DBG("PACKAGE_URI WRITE: %s", log_strdup(package_uri[obj_inst_id])); #ifdef CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT - uint8_t state = lwm2m_firmware_get_update_state(); + uint8_t state = lwm2m_firmware_get_update_state_inst(obj_inst_id); if (state == STATE_IDLE) { - lwm2m_firmware_set_update_result(RESULT_DEFAULT); + lwm2m_firmware_set_update_result_inst(obj_inst_id, RESULT_DEFAULT); if (data_len > 0) { - lwm2m_firmware_start_transfer(package_uri); + lwm2m_firmware_start_transfer(obj_inst_id, package_uri[obj_inst_id]); } } else if (state == STATE_DOWNLOADED && data_len == 0U) { /* reset to state idle and result default */ - lwm2m_firmware_set_update_result(RESULT_DEFAULT); + lwm2m_firmware_set_update_result_inst(obj_inst_id, RESULT_DEFAULT); } return 0; @@ -267,22 +306,42 @@ static int package_uri_write_cb(uint16_t obj_inst_id, uint16_t res_id, void lwm2m_firmware_set_write_cb(lwm2m_engine_set_data_cb_t cb) { - write_cb = cb; + lwm2m_firmware_set_write_cb_inst(0, cb); } lwm2m_engine_set_data_cb_t lwm2m_firmware_get_write_cb(void) { - return write_cb; + return lwm2m_firmware_get_write_cb_inst(0); } void lwm2m_firmware_set_update_cb(lwm2m_engine_execute_cb_t cb) { - update_cb = cb; + lwm2m_firmware_set_update_cb_inst(0, cb); } lwm2m_engine_execute_cb_t lwm2m_firmware_get_update_cb(void) { - return update_cb; + return lwm2m_firmware_get_update_cb_inst(0); +} + +void lwm2m_firmware_set_write_cb_inst(uint16_t obj_inst_id, lwm2m_engine_set_data_cb_t cb) +{ + write_cb[obj_inst_id] = cb; +} + +lwm2m_engine_set_data_cb_t lwm2m_firmware_get_write_cb_inst(uint16_t obj_inst_id) +{ + return write_cb[obj_inst_id]; +} + +void lwm2m_firmware_set_update_cb_inst(uint16_t obj_inst_id, lwm2m_engine_execute_cb_t cb) +{ + update_cb[obj_inst_id] = cb; +} + +lwm2m_engine_execute_cb_t lwm2m_firmware_get_update_cb_inst(uint16_t obj_inst_id) +{ + return update_cb[obj_inst_id]; } static int firmware_update_cb(uint16_t obj_inst_id, @@ -292,20 +351,20 @@ static int firmware_update_cb(uint16_t obj_inst_id, uint8_t state; int ret; - state = lwm2m_firmware_get_update_state(); + state = lwm2m_firmware_get_update_state_inst(obj_inst_id); if (state != STATE_DOWNLOADED) { LOG_ERR("State other than downloaded: %d", state); return -EPERM; } - lwm2m_firmware_set_update_state(STATE_UPDATING); + lwm2m_firmware_set_update_state_inst(obj_inst_id, STATE_UPDATING); - callback = lwm2m_firmware_get_update_cb(); + callback = lwm2m_firmware_get_update_cb_inst(obj_inst_id); if (callback) { ret = callback(obj_inst_id, args, args_len); if (ret < 0) { LOG_ERR("Failed to update firmware: %d", ret); - lwm2m_firmware_set_update_result( + lwm2m_firmware_set_update_result_inst(obj_inst_id, ret == -EINVAL ? RESULT_INTEGRITY_FAILED : RESULT_UPDATE_FAILED); return 0; @@ -319,31 +378,32 @@ static struct lwm2m_engine_obj_inst *firmware_create(uint16_t obj_inst_id) { int i = 0, j = 0; - init_res_instance(res_inst, ARRAY_SIZE(res_inst)); + init_res_instance(res_inst[obj_inst_id], ARRAY_SIZE(res_inst[obj_inst_id])); /* initialize instance resource data */ - INIT_OBJ_RES_OPT(FIRMWARE_PACKAGE_ID, res, i, res_inst, j, 1, false, - true, NULL, NULL, NULL, package_write_cb, NULL); - INIT_OBJ_RES(FIRMWARE_PACKAGE_URI_ID, res, i, res_inst, j, 1, false, - true, package_uri, PACKAGE_URI_LEN, - NULL, NULL, NULL, package_uri_write_cb, NULL); - INIT_OBJ_RES_EXECUTE(FIRMWARE_UPDATE_ID, res, i, firmware_update_cb); - INIT_OBJ_RES_DATA(FIRMWARE_STATE_ID, res, i, res_inst, j, - &update_state, sizeof(update_state)); - INIT_OBJ_RES_DATA(FIRMWARE_UPDATE_RESULT_ID, res, i, res_inst, j, - &update_result, sizeof(update_result)); - INIT_OBJ_RES_OPTDATA(FIRMWARE_PACKAGE_NAME_ID, res, i, res_inst, j); - INIT_OBJ_RES_OPTDATA(FIRMWARE_PACKAGE_VERSION_ID, res, i, res_inst, j); - INIT_OBJ_RES_MULTI_OPTDATA(FIRMWARE_UPDATE_PROTO_SUPPORT_ID, res, i, - res_inst, j, 1, false); - INIT_OBJ_RES_DATA(FIRMWARE_UPDATE_DELIV_METHOD_ID, res, i, res_inst, j, - &delivery_method, sizeof(delivery_method)); - - inst.resources = res; - inst.resource_count = i; + INIT_OBJ_RES_OPT(FIRMWARE_PACKAGE_ID, res[obj_inst_id], i, res_inst[obj_inst_id], j, 1, + false, true, NULL, NULL, NULL, package_write_cb, NULL); + INIT_OBJ_RES(FIRMWARE_PACKAGE_URI_ID, res[obj_inst_id], i, res_inst[obj_inst_id], j, 1, + false, true, package_uri[obj_inst_id], PACKAGE_URI_LEN, NULL, NULL, NULL, + package_uri_write_cb, NULL); + INIT_OBJ_RES_EXECUTE(FIRMWARE_UPDATE_ID, res[obj_inst_id], i, firmware_update_cb); + INIT_OBJ_RES_DATA(FIRMWARE_STATE_ID, res[obj_inst_id], i, res_inst[obj_inst_id], j, + &(update_state[obj_inst_id]), sizeof(update_state[obj_inst_id])); + INIT_OBJ_RES_DATA(FIRMWARE_UPDATE_RESULT_ID, res[obj_inst_id], i, res_inst[obj_inst_id], j, + &(update_result[obj_inst_id]), sizeof(update_result[obj_inst_id])); + INIT_OBJ_RES_OPTDATA(FIRMWARE_PACKAGE_NAME_ID, res[obj_inst_id], i, + res_inst[obj_inst_id], j); + INIT_OBJ_RES_OPTDATA(FIRMWARE_PACKAGE_VERSION_ID, res[obj_inst_id], i, + res_inst[obj_inst_id], j); + INIT_OBJ_RES_DATA(FIRMWARE_UPDATE_DELIV_METHOD_ID, res[obj_inst_id], i, + res_inst[obj_inst_id], j, &(delivery_method[obj_inst_id]), + sizeof(delivery_method[obj_inst_id])); + + inst[obj_inst_id].resources = res[obj_inst_id]; + inst[obj_inst_id].resource_count = i; LOG_DBG("Create LWM2M firmware instance: %d", obj_inst_id); - return &inst; + return &inst[obj_inst_id]; } static int lwm2m_firmware_init(const struct device *dev) @@ -352,31 +412,34 @@ static int lwm2m_firmware_init(const struct device *dev) int ret = 0; /* Set default values */ - package_uri[0] = '\0'; - /* Initialize state machine */ - /* TODO: should be restored from the permanent storage */ - update_state = STATE_IDLE; - update_result = RESULT_DEFAULT; -#ifdef CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT - delivery_method = DELIVERY_METHOD_BOTH; -#else - delivery_method = DELIVERY_METHOD_PUSH_ONLY; -#endif - firmware.obj_id = LWM2M_OBJECT_FIRMWARE_ID; firmware.version_major = FIRMWARE_VERSION_MAJOR; firmware.version_minor = FIRMWARE_VERSION_MINOR; firmware.is_core = true; firmware.fields = fields; firmware.field_count = ARRAY_SIZE(fields); - firmware.max_instance_count = 1U; + firmware.max_instance_count = MAX_INSTANCE_COUNT; firmware.create_cb = firmware_create; lwm2m_register_obj(&firmware); - /* auto create the only instance */ - ret = lwm2m_create_obj_inst(LWM2M_OBJECT_FIRMWARE_ID, 0, &obj_inst); - if (ret < 0) { - LOG_DBG("Create LWM2M instance 0 error: %d", ret); + + for (int idx = 0; idx < MAX_INSTANCE_COUNT; idx++) { + package_uri[idx][0] = '\0'; + + /* Initialize state machine */ + /* TODO: should be restored from the permanent storage */ + update_state[idx] = STATE_IDLE; + update_result[idx] = RESULT_DEFAULT; +#ifdef CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT + delivery_method[idx] = DELIVERY_METHOD_BOTH; +#else + delivery_method[idx] = DELIVERY_METHOD_PUSH_ONLY; +#endif + ret = lwm2m_create_obj_inst(LWM2M_OBJECT_FIRMWARE_ID, idx, &obj_inst); + if (ret < 0) { + LOG_DBG("Create LWM2M instance %d error: %d", idx, ret); + break; + } } return ret; diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c b/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c index c206365ec87..ee685bfb3a7 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c @@ -21,7 +21,7 @@ static void set_update_result(uint16_t obj_inst_id, int error_code) int result; if (!error_code) { - lwm2m_firmware_set_update_state(STATE_DOWNLOADED); + lwm2m_firmware_set_update_state_inst(obj_inst_id, STATE_DOWNLOADED); return; } @@ -65,7 +65,7 @@ int lwm2m_firmware_cancel_transfer(void) return 0; } -int lwm2m_firmware_start_transfer(char *package_uri) +int lwm2m_firmware_start_transfer(uint16_t obj_inst_id, char *package_uri) { int error_code; @@ -78,7 +78,7 @@ int lwm2m_firmware_start_transfer(char *package_uri) return error_code; } - lwm2m_firmware_set_update_state(STATE_DOWNLOADING); + lwm2m_firmware_set_update_state_inst(obj_inst_id, STATE_DOWNLOADING); return 0; } diff --git a/subsys/net/lib/mqtt/mqtt_transport_socket_tls.c b/subsys/net/lib/mqtt/mqtt_transport_socket_tls.c index d418d24f9c0..a7c8dbf95ed 100644 --- a/subsys/net/lib/mqtt/mqtt_transport_socket_tls.c +++ b/subsys/net/lib/mqtt/mqtt_transport_socket_tls.c @@ -78,6 +78,16 @@ int mqtt_client_tls_connect(struct mqtt_client *client) } } + if (tls_config->session_cache == TLS_SESSION_CACHE_ENABLED) { + ret = zsock_setsockopt(client->transport.tls.sock, SOL_TLS, + TLS_SESSION_CACHE, + &tls_config->session_cache, + sizeof(tls_config->session_cache)); + if (ret < 0) { + goto error; + } + } + if (tls_config->cert_nocopy != TLS_CERT_NOCOPY_NONE) { ret = zsock_setsockopt(client->transport.tls.sock, SOL_TLS, TLS_CERT_NOCOPY, &tls_config->cert_nocopy, diff --git a/subsys/net/lib/openthread/platform/crypto_psa.c b/subsys/net/lib/openthread/platform/crypto_psa.c index f581ec0a572..00eb217336a 100644 --- a/subsys/net/lib/openthread/platform/crypto_psa.c +++ b/subsys/net/lib/openthread/platform/crypto_psa.c @@ -115,9 +115,9 @@ static void ensureKeyIsLoaded(otCryptoKeyRef aKeyRef) psa_reset_key_attributes(&attributes); } -otError otPlatCryptoInit(void) +void otPlatCryptoInit(void) { - return psaToOtError(psa_crypto_init()); + psa_crypto_init(); } otError otPlatCryptoImportKey(otCryptoKeyRef *aKeyRef, @@ -405,3 +405,16 @@ otError otPlatCryptoSha256Finish(otCryptoContext *aContext, uint8_t *aHash, uint return psaToOtError(psa_hash_finish(operation, aHash, aHashSize, &hash_size)); } + +void otPlatCryptoRandomInit(void) +{ +} + +void otPlatCryptoRandomDeinit(void) +{ +} + +otError otPlatCryptoRandomGet(uint8_t *aBuffer, uint16_t aSize) +{ + return psaToOtError(psa_generate_random(aBuffer, aSize)); +} diff --git a/subsys/net/lib/openthread/platform/logging.c b/subsys/net/lib/openthread/platform/logging.c index 5788eb95aa5..7569b3b7f8a 100644 --- a/subsys/net/lib/openthread/platform/logging.c +++ b/subsys/net/lib/openthread/platform/logging.c @@ -39,35 +39,36 @@ static inline int log_translate(otLogLevel aLogLevel) return -1; } -void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, - const char *aFormat, ...) +#if defined(CONFIG_LOG) +static uint32_t count_args(const char *fmt) { - /* - * The following speed optimization have been used: - * - arguments are counted at compile time - * - for none arguments aFormat is not checked for %s - * - for up to three arguments program uses fast path - * - time consuming string formatting is posponed to idle time - * TODO : add support for ll (problem for 32 bit processors) - */ - + uint32_t args = 0U; + bool prev = false; /* if previous char was a modificator. */ -#ifdef OPENTHREAD_CONFIG_PLAT_LOG_MACRO_NAME__COUNT_ARGS - /* The arguments number has been counted by macro at compile time, - * and the value has been passed in unused (now) aLogRegion. - * If LogRegion value from OT is needed, rewrite macro - * OPENTHREAD_CONFIG_PLAT_LOG_MACRO_NAME__COUNT_ARGS and use higher - * bits to pass args_num. - */ - uint32_t args_num = (uint32_t) aLogRegion; -#else - ARG_UNUSED(aLogRegion); + while (*fmt != '\0') { + if (*fmt == '%') { + prev = !prev; + } else if (prev) { + args++; + prev = false; + } else { + ; /* standard character, continue walk */ + } + fmt++; + } - uint32_t args_num = log_count_args(aFormat); + return args; +} #endif - va_list param_list; +void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat, ...) +{ + ARG_UNUSED(aLogRegion); + +#if defined(CONFIG_LOG) int level = log_translate(aLogLevel); + uint32_t args_num = count_args(aFormat); + va_list param_list; if (level < 0) { return; @@ -82,4 +83,9 @@ void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, */ Z_LOG_VA(level, aFormat, param_list, args_num, LOG_STRDUP_EXEC); va_end(param_list); +#else + ARG_UNUSED(aLogLevel); + ARG_UNUSED(aFormat); +#endif + } diff --git a/subsys/net/lib/openthread/platform/openthread-core-zephyr-config.h b/subsys/net/lib/openthread/platform/openthread-core-zephyr-config.h index dfa753f2744..8855fd123cb 100644 --- a/subsys/net/lib/openthread/platform/openthread-core-zephyr-config.h +++ b/subsys/net/lib/openthread/platform/openthread-core-zephyr-config.h @@ -272,38 +272,6 @@ */ #define RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM 0 -/** - * @def OPENTHREAD_CONFIG_PLAT_LOG_MACRO_NAME - * - * The platform logging function for openthread. - * - */ -#define _OT_CONF_PLAT_LOG_FUN_NARGS__IMPL( \ - _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10,\ - _11, _12, _13, _14, N, ...) N - -#define _OT_CONF_PLAT_LOG_FUN_NARGS__GET(...) \ - _OT_CONF_PLAT_LOG_FUN_NARGS__IMPL(__VA_ARGS__,\ - 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, ~) - -#define OPENTHREAD_CONFIG_PLAT_LOG_MACRO_NAME__COUNT_ARGS(aLogLevel, unused, \ - aFormat, ...) \ - do { \ - ARG_UNUSED(unused); \ - otPlatLog( \ - aLogLevel, \ - (otLogRegion)_OT_CONF_PLAT_LOG_FUN_NARGS__GET(__VA_ARGS__),\ - aFormat, ##__VA_ARGS__); \ - } while (false) - -#ifdef OPENTHREAD_CONFIG_PLAT_LOG_MACRO_NAME -#error OPENTHREAD_CONFIG_PLAT_LOG_MACRO_NAME \ - "OPENTHREAD_CONFIG_PLAT_LOG_MACRO_NAME mustn't be defined before" -#endif - -#define OPENTHREAD_CONFIG_PLAT_LOG_MACRO_NAME \ - OPENTHREAD_CONFIG_PLAT_LOG_MACRO_NAME__COUNT_ARGS - /** * @def OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE * @@ -360,6 +328,16 @@ #define OPENTHREAD_CONFIG_CSL_MIN_RECEIVE_ON CONFIG_OPENTHREAD_CSL_MIN_RECEIVE_ON #endif /* CONFIG_OPENTHREAD_CSL_MIN_RECEIVE_ON */ +/** + * @def OPENTHREAD_CONFIG_PLATFORM_CSL_UNCERT + * + * The Uncertainty of the scheduling CSL of transmission by the parent, in ±10 us units. + */ + +#ifdef CONFIG_OPENTHREAD_PLATFORM_CSL_UNCERT +#define OPENTHREAD_CONFIG_PLATFORM_CSL_UNCERT CONFIG_OPENTHREAD_PLATFORM_CSL_UNCERT +#endif /* CONFIG_OPENTHREAD_PLATFORM_CSL_UNCERT */ + /** * @def OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_SECURITY_ENABLE * @@ -381,6 +359,17 @@ #define OPENTHREAD_CONFIG_CLI_MAX_LINE_LENGTH CONFIG_OPENTHREAD_CLI_MAX_LINE_LENGTH #endif /* CONFIG_OPENTHREAD_CLI_MAX_LINE_LENGTH */ +/** + * @def OPENTHREAD_CONFIG_CLI_PROMPT_ENABLE + * + * Enable CLI prompt. + * + * When enabled, the CLI will print prompt on the output after processing a command. + * Otherwise, no prompt is added to the output. + * + */ +#define OPENTHREAD_CONFIG_CLI_PROMPT_ENABLE 0 + /** * @def OPENTHREAD_CONFIG_IP6_MAX_EXT_UCAST_ADDRS * diff --git a/subsys/net/lib/openthread/platform/radio.c b/subsys/net/lib/openthread/platform/radio.c index 07421c3a7eb..2fef0f2648f 100644 --- a/subsys/net/lib/openthread/platform/radio.c +++ b/subsys/net/lib/openthread/platform/radio.c @@ -336,18 +336,8 @@ static inline void handle_tx_done(otInstance *aInstance) if (IS_ENABLED(CONFIG_OPENTHREAD_DIAG) && otPlatDiagModeGet()) { otPlatDiagRadioTransmitDone(aInstance, &sTransmitFrame, tx_result); } else { - if (sTransmitFrame.mPsdu[0] & IEEE802154_AR_FLAG_SET) { - if (ack_frame.mLength == 0) { - LOG_DBG("No ACK received."); - otPlatRadioTxDone(aInstance, &sTransmitFrame, - NULL, OT_ERROR_NO_ACK); - } else { - otPlatRadioTxDone(aInstance, &sTransmitFrame, - &ack_frame, tx_result); - } - } else { - otPlatRadioTxDone(aInstance, &sTransmitFrame, NULL, tx_result); - } + otPlatRadioTxDone(aInstance, &sTransmitFrame, ack_frame.mLength ? &ack_frame : NULL, + tx_result); ack_frame.mLength = 0; } } @@ -356,6 +346,7 @@ static void openthread_handle_received_frame(otInstance *instance, struct net_pkt *pkt) { otRadioFrame recv_frame; + memset(&recv_frame, 0, sizeof(otRadioFrame)); recv_frame.mPsdu = net_buf_frag_last(pkt->buffer)->data; /* Length inc. CRC. */ diff --git a/subsys/net/lib/openthread/platform/shell.c b/subsys/net/lib/openthread/platform/shell.c index cf34887a778..e72fd34a6e6 100644 --- a/subsys/net/lib/openthread/platform/shell.c +++ b/subsys/net/lib/openthread/platform/shell.c @@ -25,19 +25,8 @@ static bool is_shell_initialized; static int ot_console_cb(void *context, const char *format, va_list arg) { - char prompt_check[4]; - ARG_UNUSED(context); - /* A temporary workaround to avoid printing OT prompt in Zehyr shell. - * Eventually, OT should add an option which would allow to disable - * prompt on the CLI output. - */ - vsnprintf(prompt_check, sizeof(prompt_check), format, arg); - if (strcmp(prompt_check, "> ") == 0) { - return 0; - } - if (shell_p == NULL) { return 0; } diff --git a/subsys/net/lib/sockets/sockets.c b/subsys/net/lib/sockets/sockets.c index 0b048fcecd8..238c339e6d5 100644 --- a/subsys/net/lib/sockets/sockets.c +++ b/subsys/net/lib/sockets/sockets.c @@ -1364,6 +1364,10 @@ static int zsock_poll_update_ctx(struct net_context *ctx, (*pev)++; } + if (sock_is_eof(ctx)) { + pfd->revents |= ZSOCK_POLLHUP; + } + return 0; } diff --git a/subsys/net/lib/sockets/sockets_tls.c b/subsys/net/lib/sockets/sockets_tls.c index 2f7370e1425..0bbebfb7f97 100644 --- a/subsys/net/lib/sockets/sockets_tls.c +++ b/subsys/net/lib/sockets/sockets_tls.c @@ -2176,8 +2176,6 @@ static int ztls_socket_data_check(struct tls_context *ctx) /* Treat any other error as fatal. */ return -EIO; - } else if (ret == 0 && ctx->type == SOCK_STREAM) { - return -ENOTCONN; } return mbedtls_ssl_get_bytes_avail(&ctx->ssl); @@ -2206,7 +2204,7 @@ static int ztls_poll_update_pollin(int fd, struct tls_context *ctx, } ret = ztls_socket_data_check(ctx); - if (ret == -ENOTCONN) { + if (ret == -ENOTCONN || (pfd->revents & ZSOCK_POLLHUP)) { /* Datagram does not return 0 on consecutive recv, but an error * code, hence clear POLLIN. */ diff --git a/tests/arch/arm/arm_thread_swap_tz/CMakeLists.txt b/tests/arch/arm/arm_thread_swap_tz/CMakeLists.txt index 56231233c97..93e91deafcb 100644 --- a/tests/arch/arm/arm_thread_swap_tz/CMakeLists.txt +++ b/tests/arch/arm/arm_thread_swap_tz/CMakeLists.txt @@ -12,6 +12,8 @@ project(NONE) FILE(GLOB app_sources src/*.c) target_sources(app PRIVATE ${app_sources}) -target_include_directories(app PRIVATE - ${ZEPHYR_TRUSTED_FIRMWARE_M_MODULE_DIR}/interface/include -) +if (CONFIG_BUILD_WITH_TFM) + target_include_directories(app PRIVATE + $/install/interface/include + ) +endif() diff --git a/tests/bluetooth/bsim_bt/bsim_test_iso/src/main.c b/tests/bluetooth/bsim_bt/bsim_test_iso/src/main.c index 3114ff6f208..c3814cad71d 100644 --- a/tests/bluetooth/bsim_bt/bsim_test_iso/src/main.c +++ b/tests/bluetooth/bsim_bt/bsim_test_iso/src/main.c @@ -646,7 +646,7 @@ static void test_iso_recv_main(void) uint8_t check_countdown = 3; printk("Waiting for remote BIG terminate by checking for missing " - "%u BIG Info report...", check_countdown); + "%u BIG Info report...\n", check_countdown); do { is_sync_recv = false; is_big_info = false; diff --git a/tests/bluetooth/controller/ctrl_cte_req/src/main.c b/tests/bluetooth/controller/ctrl_cte_req/src/main.c index 66911c49392..653bd8c71ff 100644 --- a/tests/bluetooth/controller/ctrl_cte_req/src/main.c +++ b/tests/bluetooth/controller/ctrl_cte_req/src/main.c @@ -237,6 +237,9 @@ void test_cte_req_central_remote(void) lt_rx(LL_CTE_RSP, &conn, &tx, &remote_cte_rsp); lt_rx_q_is_empty(&conn); + /* TX Ack */ + event_tx_ack(&conn, tx); + /* Done */ event_done(&conn); @@ -303,6 +306,9 @@ void test_cte_req_peripheral_remote(void) lt_rx(LL_CTE_RSP, &conn, &tx, &remote_cte_rsp); lt_rx_q_is_empty(&conn); + /* TX Ack */ + event_tx_ack(&conn, tx); + /* Done */ event_done(&conn); @@ -504,7 +510,7 @@ void test_cte_req_reject_inv_ll_param_central_remote(void) /* Enable response for CTE request */ ull_cp_cte_rsp_enable(&conn, true, BT_HCI_LE_CTE_LEN_MAX, - (BT_HCI_LE_AOA_CTE | BT_HCI_LE_AOD_CTE_1US)); + (BT_HCI_LE_AOA_CTE_RSP | BT_HCI_LE_AOD_CTE_RSP_1US)); /* Prepare */ event_prepare(&conn); @@ -522,6 +528,9 @@ void test_cte_req_reject_inv_ll_param_central_remote(void) lt_rx(LL_REJECT_EXT_IND, &conn, &tx, &remote_reject_ext_ind); lt_rx_q_is_empty(&conn); + /* TX Ack */ + event_tx_ack(&conn, tx); + /* Done */ event_done(&conn); @@ -591,6 +600,9 @@ void test_cte_req_reject_inv_ll_param_peripheral_remote(void) lt_rx(LL_REJECT_EXT_IND, &conn, &tx, &remote_reject_ext_ind); lt_rx_q_is_empty(&conn); + /* TX Ack */ + event_tx_ack(&conn, tx); + /* Done */ event_done(&conn); @@ -604,6 +616,749 @@ void test_cte_req_reject_inv_ll_param_peripheral_remote(void) "Free CTX buffers %d", ctx_buffers_free()); } +/* Tests related with PHY update procedure and CTE request procedure "collision" */ + +#define PREFER_S2_CODING 0U +#define HOST_INITIATED 1U +#define PHY_UPDATE_INSTANT_DELTA 6U +#define PHY_PREFER_ANY (PHY_1M | PHY_2M | PHY_CODED) +/* Arbitrary value used for setting effective maximum number of TX/RX octets */ +#define PDU_PDU_MAX_OCTETS (PDU_DC_PAYLOAD_SIZE_MIN * 3) + +static void check_pref_phy_state(const struct ll_conn *conn, uint8_t phy_tx, uint8_t phy_rx) +{ + zassert_equal(conn->phy_pref_rx, phy_rx, + "Preferred RX PHY mismatch %d (actual) != %d (expected)", conn->phy_pref_rx, + phy_rx); + zassert_equal(conn->phy_pref_tx, phy_tx, + "Preferred TX PHY mismatch %d (actual) != %d (expected)", conn->phy_pref_tx, + phy_tx); +} + +static void check_current_phy_state(const struct ll_conn *conn, uint8_t phy_tx, uint8_t flags, + uint8_t phy_rx) +{ + zassert_equal(conn->lll.phy_rx, phy_rx, + "Current RX PHY mismatch %d (actual) != %d (expected)", conn->lll.phy_rx, + phy_rx); + zassert_equal(conn->lll.phy_tx, phy_tx, + "Current TX PHY mismatch %d (actual) != %d (expected)", conn->lll.phy_tx, + phy_tx); + zassert_equal(conn->lll.phy_flags, flags, + "Current Flags mismatch %d (actual) != %d (expected)", conn->lll.phy_flags, + flags); +} + +static bool is_instant_reached(struct ll_conn *conn, uint16_t instant) +{ + /* Check if instant is in the past. + * + * NOTE: If conn_event > instant then subtract operation will result in value greather than + * 0x7FFF for uint16_t type. This is based on modulo 65536 math. The 0x7FFF is + * maximum positive difference between actual value of connection event counter and + * instant. + */ + return (uint16_t)(event_counter(conn) - instant) <= (uint16_t)0x7FFF; +} + +static uint16_t pu_event_counter(struct ll_conn *conn) +{ + struct lll_conn *lll; + uint16_t event_counter; + + lll = &conn->lll; + + /* Calculate current event counter */ + event_counter = lll->event_counter + lll->latency_prepare; + + return event_counter; +} + +static void phy_update_setup(void) +{ + test_setup(&conn); + + /* Emulate initial conn state */ + conn.phy_pref_rx = PHY_PREFER_ANY; + conn.phy_pref_tx = PHY_PREFER_ANY; + conn.lll.phy_flags = PREFER_S2_CODING; + conn.lll.phy_tx_time = PHY_1M; + conn.lll.phy_rx = PHY_1M; + conn.lll.phy_tx = PHY_1M; + + /* Init DLE data */ + ull_conn_default_tx_octets_set(251); + ull_conn_default_tx_time_set(2120); + ull_dle_init(&conn, PHY_1M); + /* Emulate different remote numbers to trigger update of effective max TX octets and time. + * Numbers are taken arbitrary. + */ + conn.lll.dle.remote.max_tx_octets = PDU_PDU_MAX_OCTETS; + conn.lll.dle.remote.max_rx_octets = PDU_PDU_MAX_OCTETS; + conn.lll.dle.remote.max_tx_time = PDU_DC_MAX_US(conn.lll.dle.remote.max_tx_octets, PHY_1M); + conn.lll.dle.remote.max_rx_time = PDU_DC_MAX_US(conn.lll.dle.remote.max_rx_octets, PHY_1M); + ull_dle_update_eff(&conn); +} + +static void run_local_cte_req(struct pdu_data_llctrl_cte_req *cte_req) +{ + struct pdu_data_llctrl_cte_rsp remote_cte_rsp = {}; + struct node_tx *tx = NULL; + struct node_rx_pdu *ntf; + + /* The CTE request should already be in local control procedures queue */ + + /* Prepare */ + event_prepare(&conn); + + /* Tx Queue should have one LL Control PDU */ + lt_rx(LL_CTE_REQ, &conn, &tx, cte_req); + lt_rx_q_is_empty(&conn); + + /* Rx */ + lt_tx(LL_CTE_RSP, &conn, &remote_cte_rsp); + + /* Done */ + event_done(&conn); + + /* Receive notification of sampled CTE response */ + ut_rx_pdu(LL_CTE_RSP, &ntf, &remote_cte_rsp); + + /* There should not be a host notifications */ + ut_rx_q_is_empty(); + + /* Release tx node */ + ull_cp_release_tx(&conn, tx); +} + +void wait_for_phy_update_instant(uint8_t instant) +{ + /* */ + while (!is_instant_reached(&conn, instant)) { + /* Prepare */ + event_prepare(&conn); + + /* Tx Queue should NOT have a LL Control PDU */ + lt_rx_q_is_empty(&conn); + + /* Done */ + event_done(&conn); + + check_current_phy_state(&conn, PHY_1M, PREFER_S2_CODING, PHY_1M); + + /* There should NOT be a host notification */ + ut_rx_q_is_empty(); + } +} + +void check_phy_update_and_cte_req_complete(bool is_local, struct pdu_data_llctrl_cte_req *cte_req, + struct pdu_data_llctrl_phy_req *phy_req, + uint8_t ctx_num_at_end) +{ + struct pdu_data_llctrl_length_rsp length_ntf = { + PDU_PDU_MAX_OCTETS, PDU_DC_MAX_US(PDU_PDU_MAX_OCTETS, phy_req->tx_phys), + PDU_PDU_MAX_OCTETS, PDU_DC_MAX_US(PDU_PDU_MAX_OCTETS, phy_req->rx_phys) + }; + struct node_rx_pu pu = { .status = BT_HCI_ERR_SUCCESS }; + struct pdu_data_llctrl_cte_rsp remote_cte_rsp = {}; + struct node_tx *tx = NULL; + struct node_rx_pdu *ntf; + + /* Prepare */ + event_prepare(&conn); + + if (!is_local && cte_req != NULL) { + /* Handle remote PHY update request completion and local CTE reques in the same + * event. + */ + + /* Tx Queue should have one LL Control PDU */ + lt_rx(LL_CTE_REQ, &conn, &tx, cte_req); + lt_rx_q_is_empty(&conn); + + /* Rx */ + lt_tx(LL_CTE_RSP, &conn, &remote_cte_rsp); + } else { + /* Tx Queue should NOT have a LL Control PDU */ + lt_rx_q_is_empty(&conn); + } + + /* Done */ + event_done(&conn); + + /* There should be two host notifications, one pu and one dle */ + ut_rx_node(NODE_PHY_UPDATE, &ntf, &pu); + ut_rx_pdu(LL_LENGTH_RSP, &ntf, &length_ntf); + + /* Release Ntf */ + ull_cp_release_ntf(ntf); + + if (!is_local && cte_req != NULL) { + /* Receive notification of sampled CTE response */ + ut_rx_pdu(LL_CTE_RSP, &ntf, &remote_cte_rsp); + + /* Release Ntf */ + ull_cp_release_ntf(ntf); + + /* Release tx node */ + ull_cp_release_tx(&conn, tx); + } + + /* There should not be a host notifications */ + ut_rx_q_is_empty(); + + check_current_phy_state(&conn, phy_req->tx_phys, PREFER_S2_CODING, phy_req->tx_phys); + if (is_local) { + check_pref_phy_state(&conn, phy_req->rx_phys, phy_req->tx_phys); + } else { + check_pref_phy_state(&conn, PHY_PREFER_ANY, PHY_PREFER_ANY); + } + + /* There is still queued CTE REQ so number of contexts is smaller by 1 than max */ + zassert_equal(ctx_buffers_free(), ctx_num_at_end, "Free CTX buffers %d", + ctx_buffers_free()); +} + +/** + * @brief The function executes PHY update procedure in central role. + * + * The main goal for the function is to run and evaluate the PHY update control procedure. + * In case the PHY request is remote request and there is a local CTE request then + * after PHY update completion CTE request is executed in the same event. + * In this situation the function processes verification of CTE request completion also. + * + * @param is_local Flag informing if PHY request is local or remote. + * @param cte_req Parameters of CTE request procedure. If it is NULL there were no CTE + * request. + * @param phy_req Parameters of PHY update reques. + * @param events_at_start Number of connection events at function start. + * @param ctx_num_at_end Expected number of free procedure contexts at function end. + */ +static void run_phy_update_central(bool is_local, struct pdu_data_llctrl_cte_req *cte_req, + struct pdu_data_llctrl_phy_req *phy_req, uint8_t events_at_start, + uint8_t ctx_num_at_end) +{ + struct pdu_data_llctrl_phy_req rsp = { .rx_phys = PHY_PREFER_ANY, + .tx_phys = PHY_PREFER_ANY }; + struct pdu_data_llctrl_phy_upd_ind ind = { .instant = events_at_start + + PHY_UPDATE_INSTANT_DELTA, + .c_to_p_phy = phy_req->tx_phys, + .p_to_c_phy = phy_req->rx_phys }; + struct node_tx *tx = NULL; + struct pdu_data *pdu; + uint16_t instant; + + /* Prepare */ + event_prepare(&conn); + + if (is_local) { + /* Tx Queue should have one LL Control PDU */ + lt_rx(LL_PHY_REQ, &conn, &tx, phy_req); + lt_rx_q_is_empty(&conn); + + /* TX Ack */ + event_tx_ack(&conn, tx); + + /* Rx */ + lt_tx(LL_PHY_RSP, &conn, &rsp); + + ind.instant += 1; + } + + /* Done */ + event_done(&conn); + + /* Check that data tx was paused */ + zassert_equal(conn.tx_q.pause_data, 1U, "Data tx is not paused"); + + if (tx != NULL) { + /* Release Tx */ + ull_cp_release_tx(&conn, tx); + } + /* Prepare */ + event_prepare(&conn); + + /* Tx Queue should have one LL Control PDU */ + lt_rx(LL_PHY_UPDATE_IND, &conn, &tx, &ind); + lt_rx_q_is_empty(&conn); + + /* TX Ack */ + event_tx_ack(&conn, tx); + + /* Check that data tx is no lonnger paused */ + zassert_equal(conn.tx_q.pause_data, 0U, "Data tx is paused"); + + /* Done */ + event_done(&conn); + + /* Save Instant */ + pdu = (struct pdu_data *)tx->pdu; + instant = sys_le16_to_cpu(pdu->llctrl.phy_upd_ind.instant); + + /* Release Tx */ + ull_cp_release_tx(&conn, tx); + + wait_for_phy_update_instant(instant); + + check_phy_update_and_cte_req_complete(is_local, cte_req, phy_req, ctx_num_at_end); +} + +/** + * @brief The function executes PHY update procedure in peripheral role. + * + * The main goal for the function is to run and evaluate the PHY update control procedure. + * In case the PHY request is remote request and there is a local CTE request then + * after PHY update completion CTE request is executed in the same event. + * In this situation the function processes verification of CTE request completion also. + * + * @param is_local Flag informing if PHY request is local or remote. + * @param cte_req Parameters of CTE request procedure. If it is NULL there were no CTE + * request. + * @param phy_req Parameters of PHY update reques. + * @param events_at_start Number of connection events at function start. + * @param ctx_num_at_end Expected number of free procedure contexts at function end. + */ +static void run_phy_update_peripheral(bool is_local, struct pdu_data_llctrl_cte_req *cte_req, + struct pdu_data_llctrl_phy_req *phy_req, + uint8_t events_at_start, uint8_t ctx_num_at_end) +{ + struct pdu_data_llctrl_phy_req rsp = { .rx_phys = PHY_PREFER_ANY, + .tx_phys = PHY_PREFER_ANY }; + struct pdu_data_llctrl_phy_upd_ind ind = { .c_to_p_phy = phy_req->rx_phys, + .p_to_c_phy = phy_req->tx_phys }; + struct node_tx *tx; + uint16_t instant; + + /* Prepare */ + event_prepare(&conn); + + if (is_local) { + /* Tx Queue should have one LL Control PDU */ + lt_rx(LL_PHY_REQ, &conn, &tx, phy_req); + lt_rx_q_is_empty(&conn); + + /* TX Ack */ + event_tx_ack(&conn, tx); + } + + /* Done */ + event_done(&conn); + + if (is_local) { + /* Release Tx */ + ull_cp_release_tx(&conn, tx); + } else { + /* Check that data tx was paused */ + zassert_equal(conn.tx_q.pause_data, 1U, "Data tx is not paused"); + } + + /* Prepare */ + event_prepare(&conn); + + instant = event_counter(&conn) + PHY_UPDATE_INSTANT_DELTA; + ind.instant = instant; + + if (is_local) { + /* Tx Queue should NOT have a LL Control PDU */ + lt_rx_q_is_empty(&conn); + + /* Tx Queue should have one LL Control PDU */ + lt_tx(LL_PHY_UPDATE_IND, &conn, &ind); + } else { + /* Tx Queue should have one LL Control PDU */ + lt_rx(LL_PHY_RSP, &conn, &tx, &rsp); + lt_rx_q_is_empty(&conn); + + /* Rx */ + lt_tx(LL_PHY_UPDATE_IND, &conn, &ind); + + /* We are sending RSP, so data tx should be paused until after tx ack */ + zassert_equal(conn.tx_q.pause_data, 1U, "Data tx is not paused"); + + /* TX Ack */ + event_tx_ack(&conn, tx); + + /* Check that data tx is no longer paused */ + zassert_equal(conn.tx_q.pause_data, 0U, "Data tx is paused"); + } + + /* Done */ + event_done(&conn); + + if (!is_local) { + /* Release Tx */ + ull_cp_release_tx(&conn, tx); + } + + wait_for_phy_update_instant(instant); + + check_phy_update_and_cte_req_complete(is_local, cte_req, phy_req, ctx_num_at_end); +} + +static void test_local_cte_req_wait_for_phy_update_complete_and_disable(uint8_t role) +{ + uint8_t err; + + struct pdu_data_llctrl_cte_req local_cte_req = { + .cte_type_req = BT_HCI_LE_AOA_CTE, + .min_cte_len_req = BT_HCI_LE_CTE_LEN_MIN, + }; + struct pdu_data_llctrl_phy_req phy_req = { .rx_phys = PHY_CODED, .tx_phys = PHY_CODED }; + + phy_update_setup(); + + /* Role */ + test_set_role(&conn, role); + + /* Connect */ + ull_cp_state_set(&conn, ULL_CP_CONNECTED); + + /* Initiate an PHY Update Procedure */ + err = ull_cp_phy_update(&conn, PHY_CODED, PREFER_S2_CODING, PHY_CODED, HOST_INITIATED); + zassert_equal(err, BT_HCI_ERR_SUCCESS, NULL); + + /* Initiate an CTE Request Procedure */ + err = ull_cp_cte_req(&conn, local_cte_req.min_cte_len_req, local_cte_req.cte_type_req); + zassert_equal(err, BT_HCI_ERR_SUCCESS, NULL); + + if (role == BT_HCI_ROLE_CENTRAL) { + run_phy_update_central(true, NULL, &phy_req, pu_event_counter(&conn), + CONFIG_BT_CTLR_LLCP_PROC_CTX_BUF_NUM - 1); + } else { + run_phy_update_peripheral(true, NULL, &phy_req, pu_event_counter(&conn), + CONFIG_BT_CTLR_LLCP_PROC_CTX_BUF_NUM - 1); + } + + /* In this test CTE request is local procedure. Local procedures are handled after remote + * procedures, hence PHY update will be handled one event after completion of CTE request. + */ + + /* Prepare */ + event_prepare(&conn); + + /* Tx Queue should not have any LL Control PDU */ + lt_rx_q_is_empty(&conn); + + /* Done */ + event_done(&conn); + + /* There should not be a host notifications */ + ut_rx_q_is_empty(); + + zassert_equal(ctx_buffers_free(), CONFIG_BT_CTLR_LLCP_PROC_CTX_BUF_NUM, + "Free CTX buffers %d", ctx_buffers_free()); +} + +void test_central_local_cte_req_wait_for_phy_update_complete_and_disable(void) +{ + test_local_cte_req_wait_for_phy_update_complete_and_disable(BT_HCI_ROLE_CENTRAL); +} + +void test_peripheral_local_cte_req_wait_for_phy_update_complete_and_disable(void) +{ + test_local_cte_req_wait_for_phy_update_complete_and_disable(BT_HCI_ROLE_PERIPHERAL); +} + +static void test_local_cte_req_wait_for_phy_update_complete(uint8_t role) +{ + struct pdu_data_llctrl_cte_req local_cte_req = { + .cte_type_req = BT_HCI_LE_AOA_CTE, + .min_cte_len_req = BT_HCI_LE_CTE_LEN_MIN, + }; + struct pdu_data_llctrl_phy_req phy_req = { .rx_phys = PHY_2M, .tx_phys = PHY_2M }; + + uint8_t err; + + phy_update_setup(); + + /* Role */ + test_set_role(&conn, role); + + /* Connect */ + ull_cp_state_set(&conn, ULL_CP_CONNECTED); + + /* Initiate an PHY Update Procedure */ + err = ull_cp_phy_update(&conn, phy_req.rx_phys, PREFER_S2_CODING, phy_req.tx_phys, + HOST_INITIATED); + zassert_equal(err, BT_HCI_ERR_SUCCESS, NULL); + + /* Initiate an CTE Request Procedure */ + err = ull_cp_cte_req(&conn, local_cte_req.min_cte_len_req, local_cte_req.cte_type_req); + zassert_equal(err, BT_HCI_ERR_SUCCESS, NULL); + + if (role == BT_HCI_ROLE_CENTRAL) { + run_phy_update_central(true, &local_cte_req, &phy_req, pu_event_counter(&conn), + CONFIG_BT_CTLR_LLCP_PROC_CTX_BUF_NUM - 1); + } else { + run_phy_update_peripheral(true, &local_cte_req, &phy_req, pu_event_counter(&conn), + CONFIG_BT_CTLR_LLCP_PROC_CTX_BUF_NUM - 1); + } + + /* PHY update was completed. Handle CTE request */ + run_local_cte_req(&local_cte_req); + + zassert_equal(ctx_buffers_free(), CONFIG_BT_CTLR_LLCP_PROC_CTX_BUF_NUM, + "Free CTX buffers %d", ctx_buffers_free()); +} + +void test_central_local_cte_req_wait_for_phy_update_complete(void) +{ + test_local_cte_req_wait_for_phy_update_complete(BT_HCI_ROLE_CENTRAL); +} + +void test_peripheral_local_cte_req_wait_for_phy_update_complete(void) +{ + test_local_cte_req_wait_for_phy_update_complete(BT_HCI_ROLE_PERIPHERAL); +} + +static void test_local_phy_update_wait_for_cte_req_complete(uint8_t role) +{ + struct pdu_data_llctrl_phy_req phy_req = { .rx_phys = PHY_CODED, .tx_phys = PHY_CODED }; + struct pdu_data_llctrl_cte_req local_cte_req = { + .cte_type_req = BT_HCI_LE_AOA_CTE, + .min_cte_len_req = BT_HCI_LE_CTE_LEN_MIN, + }; + uint8_t err; + + phy_update_setup(); + + /* Role */ + test_set_role(&conn, role); + + /* Connect */ + ull_cp_state_set(&conn, ULL_CP_CONNECTED); + + /* Initiate an CTE Request Procedure */ + err = ull_cp_cte_req(&conn, local_cte_req.min_cte_len_req, local_cte_req.cte_type_req); + zassert_equal(err, BT_HCI_ERR_SUCCESS, NULL); + + /* Initiate an PHY Update Procedure */ + err = ull_cp_phy_update(&conn, PHY_CODED, PREFER_S2_CODING, PHY_CODED, HOST_INITIATED); + zassert_equal(err, BT_HCI_ERR_SUCCESS, NULL); + + /* Handle CTE request */ + run_local_cte_req(&local_cte_req); + + zassert_equal(ctx_buffers_free(), CONFIG_BT_CTLR_LLCP_PROC_CTX_BUF_NUM - 1, + "Free CTX buffers %d", ctx_buffers_free()); + + if (role == BT_HCI_ROLE_CENTRAL) { + run_phy_update_central(true, NULL, &phy_req, pu_event_counter(&conn), + CONFIG_BT_CTLR_LLCP_PROC_CTX_BUF_NUM); + } else { + run_phy_update_peripheral(true, NULL, &phy_req, pu_event_counter(&conn), + CONFIG_BT_CTLR_LLCP_PROC_CTX_BUF_NUM); + } +} + +void test_central_local_phy_update_wait_for_cte_req_complete(void) +{ + test_local_phy_update_wait_for_cte_req_complete(BT_HCI_ROLE_CENTRAL); +} + +void test_peripheral_local_phy_update_wait_for_cte_req_complete(void) +{ + test_local_phy_update_wait_for_cte_req_complete(BT_HCI_ROLE_PERIPHERAL); +} + +static void run_remote_cte_req(struct pdu_data_llctrl_cte_req *cte_req) +{ + struct pdu_data_llctrl_cte_rsp remote_cte_rsp = {}; + struct node_tx *tx; + + /* The CTE response should already be enabled and request PDU should already be + * received. + */ + + /* Prepare */ + event_prepare(&conn); + + /* Tx Queue should have one LL Control PDU */ + lt_rx(LL_CTE_RSP, &conn, &tx, &remote_cte_rsp); + lt_rx_q_is_empty(&conn); + + /* TX Ack */ + event_tx_ack(&conn, tx); + + /* Done */ + event_done(&conn); + + /* Release tx node */ + ull_cp_release_tx(&conn, tx); + + /* There should not be a host notifications */ + ut_rx_q_is_empty(); +} + +static void test_phy_update_wait_for_remote_cte_req_complete(uint8_t role) +{ + struct pdu_data_llctrl_cte_req local_cte_req = { + .cte_type_req = BT_HCI_LE_AOA_CTE, + .min_cte_len_req = BT_HCI_LE_CTE_LEN_MIN, + }; + struct pdu_data_llctrl_phy_req phy_req = { .rx_phys = PHY_CODED, .tx_phys = PHY_CODED }; + uint8_t err; + + phy_update_setup(); + + /* Role */ + test_set_role(&conn, role); + + /* Connect */ + ull_cp_state_set(&conn, ULL_CP_CONNECTED); + + /* Enable response for CTE request */ + ull_cp_cte_rsp_enable(&conn, true, BT_HCI_LE_CTE_LEN_MAX, + (BT_HCI_LE_AOA_CTE | BT_HCI_LE_AOD_CTE_1US | BT_HCI_LE_AOD_CTE_2US)); + + /* Prepare */ + event_prepare(&conn); + + /* Tx */ + lt_tx(LL_CTE_REQ, &conn, &local_cte_req); + + /* Done */ + event_done(&conn); + + /* Initiate an PHY Update Procedure */ + err = ull_cp_phy_update(&conn, PHY_CODED, PREFER_S2_CODING, PHY_CODED, HOST_INITIATED); + zassert_equal(err, BT_HCI_ERR_SUCCESS, NULL); + + run_remote_cte_req(&local_cte_req); + + /* There should not be a host notifications */ + ut_rx_q_is_empty(); + + zassert_equal(ctx_buffers_free(), CONFIG_BT_CTLR_LLCP_PROC_CTX_BUF_NUM - 1, + "Free CTX buffers %d", ctx_buffers_free()); + + if (role == BT_HCI_ROLE_CENTRAL) { + run_phy_update_central(true, NULL, &phy_req, pu_event_counter(&conn), + CONFIG_BT_CTLR_LLCP_PROC_CTX_BUF_NUM); + } else { + run_phy_update_peripheral(true, NULL, &phy_req, pu_event_counter(&conn), + CONFIG_BT_CTLR_LLCP_PROC_CTX_BUF_NUM); + } +} + +void test_central_phy_update_wait_for_remote_cte_req_complete(void) +{ + test_phy_update_wait_for_remote_cte_req_complete(BT_HCI_ROLE_CENTRAL); +} + +void test_peripheral_phy_update_wait_for_remote_cte_req_complete(void) +{ + test_phy_update_wait_for_remote_cte_req_complete(BT_HCI_ROLE_PERIPHERAL); +} + +static void test_cte_req_wait_for_remote_phy_update_complete_and_disable(uint8_t role) +{ + uint8_t err; + + struct pdu_data_llctrl_cte_req local_cte_req = { + .cte_type_req = BT_HCI_LE_AOA_CTE, + .min_cte_len_req = BT_HCI_LE_CTE_LEN_MIN, + }; + struct pdu_data_llctrl_phy_req phy_req = { .rx_phys = PHY_CODED, .tx_phys = PHY_CODED }; + + phy_update_setup(); + + /* Role */ + test_set_role(&conn, role); + + /* Connect */ + ull_cp_state_set(&conn, ULL_CP_CONNECTED); + + /* Prepare */ + event_prepare(&conn); + + /* Tx */ + lt_tx(LL_PHY_REQ, &conn, &phy_req); + + /* Done */ + event_done(&conn); + + /* Initiate an CTE Request Procedure */ + err = ull_cp_cte_req(&conn, local_cte_req.min_cte_len_req, local_cte_req.cte_type_req); + zassert_equal(err, BT_HCI_ERR_SUCCESS, NULL); + + if (role == BT_HCI_ROLE_CENTRAL) { + run_phy_update_central(false, NULL, &phy_req, pu_event_counter(&conn), + CONFIG_BT_CTLR_LLCP_PROC_CTX_BUF_NUM); + } else { + run_phy_update_peripheral(false, NULL, &phy_req, pu_event_counter(&conn), + CONFIG_BT_CTLR_LLCP_PROC_CTX_BUF_NUM); + } + + /* There is no special handling of CTE REQ completion. It is done when instant happens just + * after remote PHY update completes. + */ +} + +void test_central_cte_req_wait_for_remote_phy_update_complete_and_disable(void) +{ + test_cte_req_wait_for_remote_phy_update_complete_and_disable(BT_HCI_ROLE_CENTRAL); +} + +void test_peripheral_cte_req_wait_for_remote_phy_update_complete_and_disable(void) +{ + test_cte_req_wait_for_remote_phy_update_complete_and_disable(BT_HCI_ROLE_PERIPHERAL); +} + +static void test_cte_req_wait_for_remote_phy_update_complete(uint8_t role) +{ + uint8_t err; + + struct pdu_data_llctrl_cte_req local_cte_req = { + .cte_type_req = BT_HCI_LE_AOA_CTE, + .min_cte_len_req = BT_HCI_LE_CTE_LEN_MIN, + }; + struct pdu_data_llctrl_phy_req phy_req = { .rx_phys = PHY_2M, .tx_phys = PHY_2M }; + + phy_update_setup(); + + /* Role */ + test_set_role(&conn, role); + + /* Connect */ + ull_cp_state_set(&conn, ULL_CP_CONNECTED); + + /* Prepare */ + event_prepare(&conn); + + /* Tx */ + lt_tx(LL_PHY_REQ, &conn, &phy_req); + + /* Done */ + event_done(&conn); + + /* Initiate an CTE Request Procedure */ + err = ull_cp_cte_req(&conn, local_cte_req.min_cte_len_req, local_cte_req.cte_type_req); + zassert_equal(err, BT_HCI_ERR_SUCCESS, NULL); + + if (role == BT_HCI_ROLE_CENTRAL) { + run_phy_update_central(false, &local_cte_req, &phy_req, pu_event_counter(&conn), + CONFIG_BT_CTLR_LLCP_PROC_CTX_BUF_NUM); + } else { + run_phy_update_peripheral(false, &local_cte_req, &phy_req, pu_event_counter(&conn), + CONFIG_BT_CTLR_LLCP_PROC_CTX_BUF_NUM); + } + + /* There is no special handling of CTE REQ completion here. It is done when instant happens + * just after remote PHY update completes. + */ +} + +void test_central_cte_req_wait_for_remote_phy_update_complete(void) +{ + test_cte_req_wait_for_remote_phy_update_complete(BT_HCI_ROLE_CENTRAL); +} + +void test_peripheral_cte_req_wait_for_remote_phy_update_complete(void) +{ + test_cte_req_wait_for_remote_phy_update_complete(BT_HCI_ROLE_PERIPHERAL); +} + void test_main(void) { ztest_test_suite( @@ -621,7 +1376,42 @@ void test_main(void) ztest_unit_test_setup_teardown(test_cte_req_reject_inv_ll_param_central_remote, setup, unit_test_noop), ztest_unit_test_setup_teardown(test_cte_req_reject_inv_ll_param_peripheral_remote, - setup, unit_test_noop)); - + setup, unit_test_noop), + ztest_unit_test_setup_teardown( + test_central_local_cte_req_wait_for_phy_update_complete_and_disable, setup, + unit_test_noop), + ztest_unit_test_setup_teardown( + test_central_local_cte_req_wait_for_phy_update_complete_and_disable, setup, + unit_test_noop), + ztest_unit_test_setup_teardown( + test_peripheral_local_cte_req_wait_for_phy_update_complete, setup, + unit_test_noop), + ztest_unit_test_setup_teardown( + test_central_local_phy_update_wait_for_cte_req_complete, setup, + unit_test_noop), + ztest_unit_test_setup_teardown( + test_peripheral_local_phy_update_wait_for_cte_req_complete, setup, + unit_test_noop), + ztest_unit_test_setup_teardown( + test_peripheral_local_cte_req_wait_for_phy_update_complete, setup, + unit_test_noop), + ztest_unit_test_setup_teardown( + test_central_phy_update_wait_for_remote_cte_req_complete, setup, + unit_test_noop), + ztest_unit_test_setup_teardown( + test_peripheral_phy_update_wait_for_remote_cte_req_complete, setup, + unit_test_noop), + ztest_unit_test_setup_teardown( + test_central_cte_req_wait_for_remote_phy_update_complete_and_disable, setup, + unit_test_noop), + ztest_unit_test_setup_teardown( + test_peripheral_cte_req_wait_for_remote_phy_update_complete_and_disable, + setup, unit_test_noop), + ztest_unit_test_setup_teardown( + test_central_cte_req_wait_for_remote_phy_update_complete, setup, + unit_test_noop), + ztest_unit_test_setup_teardown( + test_peripheral_cte_req_wait_for_remote_phy_update_complete, setup, + unit_test_noop)); ztest_run_test_suite(cte_req); } diff --git a/tests/bluetooth/controller/ctrl_version/src/main.c b/tests/bluetooth/controller/ctrl_version/src/main.c index 2925649cbbd..6aa488ef460 100644 --- a/tests/bluetooth/controller/ctrl_version/src/main.c +++ b/tests/bluetooth/controller/ctrl_version/src/main.c @@ -346,8 +346,10 @@ void test_version_exchange_mas_loc_twice(void) ut_rx_pdu(LL_VERSION_IND, &ntf, &remote_version_ind); ut_rx_q_is_empty(); - /* Note that one context buffer is not freed for this test */ - zassert_equal(ctx_buffers_free(), CONFIG_BT_CTLR_LLCP_PROC_CTX_BUF_NUM - 1, + /* Second attempt to run the version exchange completes immediately in idle state. + * The context is released just after that. + */ + zassert_equal(ctx_buffers_free(), CONFIG_BT_CTLR_LLCP_PROC_CTX_BUF_NUM, "Free CTX buffers %d", ctx_buffers_free()); } diff --git a/tests/bluetooth/controller/mock_ctrl/include/kconfig.h b/tests/bluetooth/controller/mock_ctrl/include/kconfig.h index 2c24b121b34..f5222e7e29a 100644 --- a/tests/bluetooth/controller/mock_ctrl/include/kconfig.h +++ b/tests/bluetooth/controller/mock_ctrl/include/kconfig.h @@ -119,6 +119,14 @@ #endif /* Direction finding LE Features configs */ +#ifndef CONFIG_BT_CTLR_DF_CONN_CTE_RX +#define CONFIG_BT_CTLR_DF_CONN_CTE_RX y +#endif + +#ifndef CONFIG_BT_CTLR_DF_CONN_CTE_TX +#define CONFIG_BT_CTLR_DF_CONN_CTE_TX y +#endif + #ifndef CONFIG_BT_CTLR_DF_CONN_CTE_REQ #define CONFIG_BT_CTLR_DF_CONN_CTE_REQ y #endif diff --git a/tests/bluetooth/df/common/src/bt_conn_common.c b/tests/bluetooth/df/common/src/bt_conn_common.c index 02e31ad5432..46955669a12 100644 --- a/tests/bluetooth/df/common/src/bt_conn_common.c +++ b/tests/bluetooth/df/common/src/bt_conn_common.c @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -34,6 +35,14 @@ uint16_t ut_bt_create_connection(void) conn->lll.latency = 0; conn->lll.handle = ll_conn_handle_get(conn); +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX) + conn->lll.df_rx_cfg.is_initialized = 0U; +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */ + +#if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) + conn->llcp.cte_req.is_enabled = 0U; +#endif /* CONFIG_BT_CTLR_DF_CONN_CTE_REQ */ + return conn->lll.handle; } @@ -54,8 +63,8 @@ void ut_bt_set_peer_features(uint16_t conn_handle, uint64_t features) conn = ll_conn_get(conn_handle); zassert_not_equal(conn, NULL, "Failed ll_conn instance for given handle"); - conn->common.fex_valid = PEER_FEATURES_ARE_VALID; - conn->llcp_feature.features_peer = features; + conn->llcp.fex.valid = PEER_FEATURES_ARE_VALID; + conn->llcp.fex.features_peer = features; } void ut_bt_set_periph_latency(uint16_t conn_handle, uint16_t periph_latency) diff --git a/tests/bluetooth/df/connection_cte_req/prj.conf b/tests/bluetooth/df/connection_cte_req/prj.conf index 6a3efb55fb1..6280ed8e699 100644 --- a/tests/bluetooth/df/connection_cte_req/prj.conf +++ b/tests/bluetooth/df/connection_cte_req/prj.conf @@ -10,13 +10,22 @@ CONFIG_BT_GATT_CLIENT=y CONFIG_BT_CTLR=y CONFIG_BT_LL_SW_SPLIT=y +# Enable new implementation of LLCP +CONFIG_BT_LL_SW_LLCP=y + # Enable Direction Finding Feature including AoA and AoD CONFIG_BT_DF=y -CONFIG_BT_DF_CONNECTION_CTE_RX=y +CONFIG_BT_CTLR_DF_CTE_RX=y +CONFIG_BT_DF_CONNECTION_CTE_REQ=y CONFIG_BT_CTLR_DF=y CONFIG_BT_CTLR_DF_CONN_CTE_REQ=y +CONFIG_BT_CTLR_DF_CONN_CTE_REQ=y +CONFIG_BT_DF_CONNECTION_CTE_TX=y +CONFIG_BT_DF_CONNECTION_CTE_RX=y +CONFIG_BT_DF_CONNECTION_CTE_RSP=y +CONFIG_BT_DF_CONNECTION_CTE_REQ=y -# set antenna switch pattern to max allowed value +# Set antenna switch pattern to max allowed value CONFIG_BT_CTLR_DF_MAX_ANT_SW_PATTERN_LEN=39 diff --git a/tests/bluetooth/df/connection_cte_req/src/test_cte_req_enable.c b/tests/bluetooth/df/connection_cte_req/src/test_cte_req_enable.c index 1b0839d31df..3db45d573ba 100644 --- a/tests/bluetooth/df/connection_cte_req/src/test_cte_req_enable.c +++ b/tests/bluetooth/df/connection_cte_req/src/test_cte_req_enable.c @@ -63,8 +63,6 @@ int send_conn_cte_req_enable(uint16_t conn_handle, struct bt_hci_cp_le_conn_cte_req_enable *cp; struct net_buf *buf; - zassert_not_equal(data, NULL, "Unexpected data pointer with null value."); - buf = bt_hci_cmd_create(BT_HCI_OP_LE_CONN_CTE_REQ_ENABLE, sizeof(*cp)); if (!buf) { return -ENOBUFS; @@ -74,9 +72,11 @@ int send_conn_cte_req_enable(uint16_t conn_handle, (void)memset(cp, 0, sizeof(*cp)); cp->handle = sys_cpu_to_le16(conn_handle); cp->enable = enable ? 1 : 0; - cp->cte_request_interval = data->cte_request_interval; - cp->requested_cte_length = data->requested_cte_length; - cp->requested_cte_type = data->requested_cte_type; + if (data != NULL) { + cp->cte_request_interval = data->cte_request_interval; + cp->requested_cte_length = data->requested_cte_length; + cp->requested_cte_type = data->requested_cte_type; + } return bt_hci_cmd_send_sync(BT_HCI_OP_LE_CONN_CTE_REQ_ENABLE, buf, NULL); } @@ -146,11 +146,31 @@ void test_set_conn_cte_req_enable_with_invalid_cte_type(void) "Unexpected error value for CTE request enable with invalid CTE type"); } -static void connection_setup(void) +void test_set_conn_cte_req_enable(void) +{ + int err; + + err = send_conn_cte_req_enable(g_conn_handle, &g_data, true); + zassert_equal(err, 0, "Unexpected error value for CTE request enable"); +} + +void test_set_conn_cte_req_disable(void) +{ + int err; + + err = send_conn_cte_req_enable(g_conn_handle, NULL, false); + zassert_equal(err, 0, "Unexpected error value for CTE request disable"); +} +static void cte_req_params_set(void) { g_data.cte_request_interval = REQUEST_INTERVAL_OK; g_data.requested_cte_length = BT_HCI_LE_CTE_LEN_MAX; g_data.requested_cte_type = BT_HCI_LE_AOD_CTE_2US; +} + +static void connection_setup(void) +{ + cte_req_params_set(); g_conn_handle = ut_bt_create_connection(); } @@ -172,12 +192,21 @@ static void cte_rx_param_setup(void) .ant_ids = ant_ids }; + cte_req_params_set(); + ut_bt_create_connection(); - ut_bt_set_periph_latency(g_conn_handle, REQUEST_INTERVAL_TOO_LOW); + ut_bt_set_periph_latency(g_conn_handle, CONN_PERIPH_LATENCY); send_set_conn_cte_rx_params(g_conn_handle, &cte_rx_params, true); } +static void cte_req_setup(void) +{ + cte_rx_param_setup(); + + send_conn_cte_req_enable(g_conn_handle, &g_data, true); +} + static void cte_rx_param_teardown(void) { connection_teardown(); @@ -185,6 +214,13 @@ static void cte_rx_param_teardown(void) send_set_conn_cte_rx_params(g_conn_handle, NULL, false); } +static void cte_req_teardown(void) +{ + send_conn_cte_req_enable(g_conn_handle, NULL, false); + + cte_rx_param_teardown(); +} + void run_cte_request_enable_tests(void) { ztest_test_suite( @@ -199,7 +235,11 @@ void run_cte_request_enable_tests(void) cte_rx_param_setup, cte_rx_param_teardown), ztest_unit_test_setup_teardown( test_set_conn_cte_req_enable_with_too_long_requested_length, - cte_rx_param_setup, cte_rx_param_teardown)); + cte_rx_param_setup, cte_rx_param_teardown), + ztest_unit_test_setup_teardown(test_set_conn_cte_req_enable, cte_rx_param_setup, + cte_rx_param_teardown), + ztest_unit_test_setup_teardown(test_set_conn_cte_req_disable, cte_req_setup, + cte_req_teardown)); ztest_run_test_suite(test_hci_set_conn_cte_rx_params); /* TODO: Add tests cases that verify positive behavior of the function diff --git a/tests/bluetooth/host_long_adv_recv/CMakeLists.txt b/tests/bluetooth/host_long_adv_recv/CMakeLists.txt new file mode 100644 index 00000000000..da5b449c986 --- /dev/null +++ b/tests/bluetooth/host_long_adv_recv/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(host_long_adv_recv) + +target_sources(app PRIVATE src/main.c) diff --git a/tests/bluetooth/host_long_adv_recv/prj.conf b/tests/bluetooth/host_long_adv_recv/prj.conf new file mode 100644 index 00000000000..c7b3600e999 --- /dev/null +++ b/tests/bluetooth/host_long_adv_recv/prj.conf @@ -0,0 +1,19 @@ +CONFIG_TEST=y +CONFIG_ZTEST=y +CONFIG_ZTEST_MOCKING=y + +CONFIG_BT=y +CONFIG_BT_CTLR=n +CONFIG_BT_HCI=n +CONFIG_BT_HCI_RAW=n +CONFIG_BT_OBSERVER=y +CONFIG_BT_NO_DRIVER=y +CONFIG_BT_RECV_IS_RX_THREAD=y +CONFIG_BT_EXT_ADV=y + +CONFIG_BT_DEBUG_LOG=y +CONFIG_BT_DEBUG_HCI_CORE=n +CONFIG_BT_DEBUG_HCI_DRIVER=n +CONFIG_BT_LOG_LEVEL_DBG=y + +CONFIG_BT_EXT_SCAN_BUF_SIZE=91 diff --git a/tests/bluetooth/host_long_adv_recv/src/main.c b/tests/bluetooth/host_long_adv_recv/src/main.c new file mode 100644 index 00000000000..14164705f7d --- /dev/null +++ b/tests/bluetooth/host_long_adv_recv/src/main.c @@ -0,0 +1,493 @@ +/* main.c - Host long advertising receive */ + +/* + * Copyright (c) 2021 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#define LOG_LEVEL CONFIG_BT_LOG_LEVEL +#include +LOG_MODULE_REGISTER(host_test_app); + +struct test_adv_report { + uint8_t data[CONFIG_BT_EXT_SCAN_BUF_SIZE]; + uint8_t length; + uint16_t evt_prop; + bt_addr_le_t addr; +}; + +#define COMPLETE BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_COMPLETE << 5 +#define MORE_TO_COME BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_PARTIAL << 5 +#define TRUNCATED BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_INCOMPLETE << 5 + +/* Command handler structure for cmd_handle(). */ +struct cmd_handler { + uint16_t opcode; /* HCI command opcode */ + uint8_t len; /* HCI command response length */ + void (*handler)(struct net_buf *buf, struct net_buf **evt, uint8_t len, uint16_t opcode); +}; + +/* Add event to net_buf. */ +static void evt_create(struct net_buf *buf, uint8_t evt, uint8_t len) +{ + struct bt_hci_evt_hdr *hdr; + + hdr = net_buf_add(buf, sizeof(*hdr)); + hdr->evt = evt; + hdr->len = len; +} + +static void le_meta_evt_create(struct bt_hci_evt_le_meta_event *evt, uint8_t subevent) +{ + evt->subevent = subevent; +} + +static void adv_info_create(struct bt_hci_evt_le_ext_advertising_info *evt, uint16_t evt_type, + const bt_addr_le_t *const addr, uint8_t length) +{ + evt->evt_type = evt_type; + bt_addr_le_copy(&evt->addr, addr); + evt->prim_phy = 0; + evt->sec_phy = 0; + evt->sid = 0; + evt->tx_power = 0; + evt->rssi = 0; + evt->interval = 0; + bt_addr_le_copy(&evt->direct_addr, BT_ADDR_LE_NONE); + evt->length = length; +} + +/* Create a command complete event. */ +static void *cmd_complete(struct net_buf **buf, uint8_t plen, uint16_t opcode) +{ + struct bt_hci_evt_cmd_complete *cc; + + *buf = bt_buf_get_evt(BT_HCI_EVT_CMD_COMPLETE, false, K_FOREVER); + evt_create(*buf, BT_HCI_EVT_CMD_COMPLETE, sizeof(*cc) + plen); + cc = net_buf_add(*buf, sizeof(*cc)); + cc->ncmd = 1U; + cc->opcode = sys_cpu_to_le16(opcode); + + return net_buf_add(*buf, plen); +} + +/* Loop over handlers to try to handle the command given by opcode. */ +static int cmd_handle_helper(uint16_t opcode, struct net_buf *cmd, struct net_buf **evt, + const struct cmd_handler *handlers, size_t num_handlers) +{ + for (size_t i = 0; i < num_handlers; i++) { + const struct cmd_handler *handler = &handlers[i]; + + if (handler->opcode != opcode) { + continue; + } + + if (handler->handler) { + handler->handler(cmd, evt, handler->len, opcode); + + return 0; + } + } + + zassert_unreachable("opcode %X failed", opcode); + + return -EINVAL; +} + +/* Lookup the command opcode and invoke handler. */ +static int cmd_handle(struct net_buf *cmd, const struct cmd_handler *handlers, size_t num_handlers) +{ + struct net_buf *evt = NULL; + struct bt_hci_evt_cc_status *ccst; + struct bt_hci_cmd_hdr *chdr; + uint16_t opcode; + int err; + + chdr = net_buf_pull_mem(cmd, sizeof(*chdr)); + opcode = sys_le16_to_cpu(chdr->opcode); + + err = cmd_handle_helper(opcode, cmd, &evt, handlers, num_handlers); + + if (err == -EINVAL) { + ccst = cmd_complete(&evt, sizeof(*ccst), opcode); + ccst->status = BT_HCI_ERR_UNKNOWN_CMD; + } + + if (evt) { + bt_recv_prio(evt); + } + + return err; +} + +/* Generic command complete with success status. */ +static void generic_success(struct net_buf *buf, struct net_buf **evt, uint8_t len, uint16_t opcode) +{ + struct bt_hci_evt_cc_status *ccst; + + ccst = cmd_complete(evt, len, opcode); + + /* Fill any event parameters with zero */ + (void)memset(ccst, 0, len); + + ccst->status = BT_HCI_ERR_SUCCESS; +} + +/* Bogus handler for BT_HCI_OP_READ_LOCAL_FEATURES. */ +static void read_local_features(struct net_buf *buf, struct net_buf **evt, uint8_t len, + uint16_t opcode) +{ + struct bt_hci_rp_read_local_features *rp; + + rp = cmd_complete(evt, sizeof(*rp), opcode); + rp->status = 0x00; + (void)memset(rp->features, 0xFF, sizeof(rp->features)); +} + +/* Bogus handler for BT_HCI_OP_READ_SUPPORTED_COMMANDS. */ +static void read_supported_commands(struct net_buf *buf, struct net_buf **evt, uint8_t len, + uint16_t opcode) +{ + struct bt_hci_rp_read_supported_commands *rp; + + rp = cmd_complete(evt, sizeof(*rp), opcode); + (void)memset(rp->commands, 0xFF, sizeof(rp->commands)); + rp->status = 0x00; +} + +/* Bogus handler for BT_HCI_OP_LE_READ_LOCAL_FEATURES. */ +static void le_read_local_features(struct net_buf *buf, struct net_buf **evt, uint8_t len, + uint16_t opcode) +{ + struct bt_hci_rp_le_read_local_features *rp; + + rp = cmd_complete(evt, sizeof(*rp), opcode); + rp->status = 0x00; + (void)memset(rp->features, 0xFF, sizeof(rp->features)); +} + +/* Bogus handler for BT_HCI_OP_LE_READ_SUPP_STATES. */ +static void le_read_supp_states(struct net_buf *buf, struct net_buf **evt, uint8_t len, + uint16_t opcode) +{ + struct bt_hci_rp_le_read_supp_states *rp; + + rp = cmd_complete(evt, sizeof(*rp), opcode); + rp->status = 0x00; + (void)memset(&rp->le_states, 0xFF, sizeof(rp->le_states)); +} + +/* Setup handlers needed for bt_enable to function. */ +static const struct cmd_handler cmds[] = { + { BT_HCI_OP_READ_LOCAL_VERSION_INFO, sizeof(struct bt_hci_rp_read_local_version_info), + generic_success }, + { BT_HCI_OP_READ_SUPPORTED_COMMANDS, sizeof(struct bt_hci_rp_read_supported_commands), + read_supported_commands }, + { BT_HCI_OP_READ_LOCAL_FEATURES, sizeof(struct bt_hci_rp_read_local_features), + read_local_features }, + { BT_HCI_OP_READ_BD_ADDR, sizeof(struct bt_hci_rp_read_bd_addr), generic_success }, + { BT_HCI_OP_SET_EVENT_MASK, sizeof(struct bt_hci_evt_cc_status), generic_success }, + { BT_HCI_OP_LE_SET_EVENT_MASK, sizeof(struct bt_hci_evt_cc_status), generic_success }, + { BT_HCI_OP_LE_READ_LOCAL_FEATURES, sizeof(struct bt_hci_rp_le_read_local_features), + le_read_local_features }, + { BT_HCI_OP_LE_READ_SUPP_STATES, sizeof(struct bt_hci_rp_le_read_supp_states), + le_read_supp_states }, + { BT_HCI_OP_LE_RAND, sizeof(struct bt_hci_rp_le_rand), generic_success }, + { BT_HCI_OP_LE_SET_RANDOM_ADDRESS, sizeof(struct bt_hci_cp_le_set_random_address), + generic_success }, + { BT_HCI_OP_RESET, 0, generic_success }, +}; + +/* HCI driver open. */ +static int driver_open(void) +{ + return 0; +} + +/* HCI driver send. */ +static int driver_send(struct net_buf *buf) +{ + zassert_true(cmd_handle(buf, cmds, ARRAY_SIZE(cmds)) == 0, "Unknown HCI command"); + + net_buf_unref(buf); + + return 0; +} + +/* HCI driver structure. */ +static const struct bt_hci_driver drv = { + .name = "test", + .bus = BT_HCI_DRIVER_BUS_VIRTUAL, + .open = driver_open, + .send = driver_send, + .quirks = 0, +}; + +struct bt_recv_job_data { + struct k_work work; /* Work item */ + struct k_sem *sync; /* Semaphore to synchronize with */ + struct net_buf *buf; /* Net buffer to be passed to bt_recv() */ +} job_data[CONFIG_BT_BUF_EVT_RX_COUNT]; + +#define job(buf) (&job_data[net_buf_id(buf)]) + +/* Work item handler for bt_recv() jobs. */ +static void bt_recv_job_cb(struct k_work *item) +{ + struct bt_recv_job_data *data = CONTAINER_OF(item, struct bt_recv_job_data, work); + + /* Send net buffer to host */ + bt_recv(data->buf); + + /* Wake up bt_recv_job_submit */ + k_sem_give(job(data->buf)->sync); +} + +/* Prepare a job to call bt_recv() to be submitted to the system workqueue. */ +static void bt_recv_job_submit(struct net_buf *buf) +{ + struct k_sem sync_sem; + + /* Store the net buffer to be passed to bt_recv */ + job(buf)->buf = buf; + + /* Initialize job work item/semaphore */ + k_work_init(&job(buf)->work, bt_recv_job_cb); + k_sem_init(&sync_sem, 0, 1); + job(buf)->sync = &sync_sem; + + /* Make sure the buffer stays around until the command completes */ + buf = net_buf_ref(buf); + + /* Submit the work item */ + k_work_submit(&job(buf)->work); + + /* Wait for bt_recv_job_cb to be done */ + k_sem_take(&sync_sem, K_FOREVER); + + net_buf_unref(buf); +} + +/* Semaphore to test if the prop callback was called. */ +static K_SEM_DEFINE(prop_cb_sem, 0, 1); + +static void *adv_report_evt(struct net_buf *buf, uint8_t data_len, uint16_t evt_type, + const bt_addr_le_t *const addr) +{ + struct bt_hci_evt_le_meta_event *meta_evt; + struct bt_hci_evt_le_ext_advertising_info *evt; + + evt_create(buf, BT_HCI_EVT_LE_META_EVENT, sizeof(*meta_evt) + sizeof(*evt) + data_len + 1); + meta_evt = net_buf_add(buf, sizeof(*meta_evt)); + le_meta_evt_create(meta_evt, BT_HCI_EVT_LE_EXT_ADVERTISING_REPORT); + net_buf_add_u8(buf, 1); /* Number of reports */ + evt = net_buf_add(buf, sizeof(*evt)); + adv_info_create(evt, evt_type, addr, data_len); + + return net_buf_add(buf, data_len); +} + +/* Send a prop event report wit the given data. */ +static void send_adv_report(const struct test_adv_report *report) +{ + LOG_DBG("Sending adv report"); + struct net_buf *buf; + uint8_t *adv_data; + + buf = bt_buf_get_rx(BT_BUF_EVT, K_FOREVER); + adv_data = adv_report_evt(buf, report->length, report->evt_prop, &report->addr); + memcpy(adv_data, &report->data, report->length); + + /* Submit job */ + bt_recv_job_submit(buf); +} + +static uint16_t get_expected_length(void) +{ + return ztest_get_return_value(); +} + +static uint8_t *get_expected_data(void) +{ + return ztest_get_return_value_ptr(); +} + +static void scan_recv_cb(const struct bt_le_scan_recv_info *info, struct net_buf_simple *buf) +{ + ARG_UNUSED(info); + + LOG_DBG("Received event with length %u", buf->len); + + const uint16_t expected_length = get_expected_length(); + const uint8_t *expected_data = get_expected_data(); + + zassert_equal(buf->len, expected_length, "Lengths should be equal"); + zassert_mem_equal(buf->data, expected_data, buf->len, "Data should be equal"); +} + +static void scan_timeout_cb(void) +{ + zassert_unreachable("Timeout should not happen"); +} + +static void generate_sequence(uint8_t *dest, uint16_t len, uint8_t range_start, uint8_t range_end) +{ + uint16_t written = 0; + uint8_t value = range_start; + + while (written < len) { + *dest++ = value++; + written++; + if (value > range_end) { + value = range_start; + } + } +} + +/* Test. */ +static void test_host_long_adv_recv(void) +{ + /* Register the test HCI driver */ + bt_hci_driver_register(&drv); + + /* Go! Wait until Bluetooth initialization is done */ + zassert_true((bt_enable(NULL) == 0), "bt_enable failed"); + + static struct bt_le_scan_cb scan_callbacks = { .recv = scan_recv_cb, + .timeout = scan_timeout_cb }; + bt_le_scan_cb_register(&scan_callbacks); + bt_addr_le_t addr_a; + bt_addr_le_t addr_b; + bt_addr_le_t addr_c; + bt_addr_le_t addr_d; + + bt_addr_le_create_static(&addr_a); + bt_addr_le_create_static(&addr_b); + bt_addr_le_create_static(&addr_c); + bt_addr_le_create_static(&addr_d); + + struct test_adv_report report_a_1 = { .length = 30, .evt_prop = MORE_TO_COME }; + struct test_adv_report report_a_2 = { .length = 30, .evt_prop = COMPLETE }; + + bt_addr_le_copy(&report_a_1.addr, &addr_a); + bt_addr_le_copy(&report_a_2.addr, &addr_a); + + struct test_adv_report report_b_1 = { .length = 30, .evt_prop = MORE_TO_COME }; + struct test_adv_report report_b_2 = { .length = 30, .evt_prop = COMPLETE }; + + bt_addr_le_copy(&report_b_1.addr, &addr_b); + bt_addr_le_copy(&report_b_2.addr, &addr_b); + + struct test_adv_report report_c = { .length = 30, + .evt_prop = COMPLETE | BT_HCI_LE_ADV_EVT_TYPE_LEGACY }; + + bt_addr_le_copy(&report_c.addr, &addr_c); + + struct test_adv_report report_d = { .length = 30, .evt_prop = TRUNCATED }; + + bt_addr_le_copy(&report_c.addr, &addr_c); + + struct test_adv_report report_a_combined = { .length = report_a_1.length + + report_a_2.length }; + + struct test_adv_report report_a_1_repeated = { .length = CONFIG_BT_EXT_SCAN_BUF_SIZE }; + + struct test_adv_report report_b_combined = { .length = report_b_1.length + + report_b_2.length }; + + generate_sequence(report_a_combined.data, report_a_combined.length, 'A', 'Z'); + generate_sequence(report_b_combined.data, report_b_combined.length, 'a', 'z'); + generate_sequence(report_c.data, report_c.length, '0', '9'); + + (void)memcpy(report_a_1.data, report_a_combined.data, report_a_1.length); + (void)memcpy(report_a_2.data, &report_a_combined.data[report_a_1.length], + report_a_2.length); + + for (int i = 0; i < report_a_1_repeated.length; i += report_a_1.length) { + memcpy(&report_a_1_repeated.data[i], report_a_1.data, + MIN(report_a_1.length, (report_a_1_repeated.length - i))); + } + + (void)memcpy(report_b_1.data, report_b_combined.data, report_b_1.length); + (void)memcpy(report_b_2.data, &report_b_combined.data[report_b_1.length], + report_b_2.length); + + /* Check that non-interleaved fragmented adv reports work */ + ztest_returns_value(get_expected_data, report_a_combined.data); + ztest_returns_value(get_expected_length, report_a_combined.length); /* Expect a */ + ztest_returns_value(get_expected_data, report_b_combined.data); + ztest_returns_value(get_expected_length, report_b_combined.length); /* Then b */ + send_adv_report(&report_a_1); + send_adv_report(&report_a_2); + send_adv_report(&report_b_1); + send_adv_report(&report_b_2); + + /* Check that legacy adv reports interleaved with fragmented adv reports work */ + ztest_returns_value(get_expected_data, report_c.data); + ztest_returns_value(get_expected_length, report_c.length); /* Expect c */ + ztest_returns_value(get_expected_data, report_a_combined.data); + ztest_returns_value(get_expected_length, report_a_combined.length); /* Then a */ + send_adv_report(&report_a_1); + send_adv_report(&report_c); /* Interleaved legacy adv report */ + send_adv_report(&report_a_2); + + /* Check that complete adv reports interleaved with fragmented adv reports work */ + ztest_returns_value(get_expected_data, report_b_2.data); + ztest_returns_value(get_expected_length, report_b_2.length); /* Expect b */ + ztest_returns_value(get_expected_data, report_a_combined.data); + ztest_returns_value(get_expected_length, report_a_combined.length); /* Then a */ + send_adv_report(&report_a_1); + send_adv_report(&report_b_2); /* Interleaved short extended adv report */ + send_adv_report(&report_a_2); + + /* Check that fragmented adv reports from one peer are received, + * and that interleaved fragmented adv reports from other peers are discarded + */ + ztest_returns_value(get_expected_data, report_a_combined.data); + ztest_returns_value(get_expected_length, report_a_combined.length); /* Expect a */ + ztest_returns_value(get_expected_data, report_b_2.data); + ztest_returns_value(get_expected_length, + report_b_2.length); /* Then b, INCOMPLETE REPORT */ + send_adv_report(&report_a_1); + send_adv_report(&report_b_1); /* Interleaved fragmented adv report, NOT SUPPORTED */ + send_adv_report(&report_a_2); + send_adv_report(&report_b_2); + + /* Check that host discards the data if the controller keeps sending + * incomplete packets. + */ + for (int i = 0; i < (2 + (CONFIG_BT_EXT_SCAN_BUF_SIZE / report_a_1.length)); i++) { + send_adv_report(&report_a_1); + } + send_adv_report(&report_a_2); + + /* Check that controller truncated reports do not generate events */ + send_adv_report(&report_d); + + /* Check that reports from a different advertiser works after truncation */ + ztest_returns_value(get_expected_data, report_b_combined.data); + ztest_returns_value(get_expected_length, report_b_combined.length); /* Expect b */ + send_adv_report(&report_b_1); + send_adv_report(&report_b_2); +} + +/* test case main entry */ +void test_main(void) +{ + ztest_test_suite(test_host_long_adv_recv, ztest_unit_test(test_host_long_adv_recv)); + + ztest_run_test_suite(test_host_long_adv_recv); +} diff --git a/tests/bluetooth/host_long_adv_recv/testcase.yaml b/tests/bluetooth/host_long_adv_recv/testcase.yaml new file mode 100644 index 00000000000..54f11d81b09 --- /dev/null +++ b/tests/bluetooth/host_long_adv_recv/testcase.yaml @@ -0,0 +1,4 @@ +tests: + bluetooth.host_long_adv_recv: + platform_allow: native_posix native_posix_64 + tags: bluetooth host diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index 052ec758364..1b2fe44f0a8 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -154,6 +154,18 @@ test_i2c_mpu9150: mpu9150@16 { reg = <0x16>; }; +test_i2c_mpu9250: mpu9250@1e { + compatible = "invensense,mpu9250"; + reg = <0x1e>; + irq-gpios = <&test_gpio 0 0>; + gyro-sr-div = <10>; + gyro-dlpf = <5>; + gyro-fs = <250>; + accel-fs = <2>; + accel-dlpf="5.05"; + label = "MPU9250"; +}; + test_i2c_ina219: ina219@40 { compatible = "ti,ina219"; label = "INA219"; diff --git a/tests/drivers/build_all/sensor/prj.conf b/tests/drivers/build_all/sensor/prj.conf index ef269aaf698..f2ac144eb7e 100644 --- a/tests/drivers/build_all/sensor/prj.conf +++ b/tests/drivers/build_all/sensor/prj.conf @@ -72,6 +72,7 @@ CONFIG_MAX6675=y CONFIG_MCP9808=y CONFIG_MPR=y CONFIG_MPU6050=y +CONFIG_MPU9250=y CONFIG_MS5607=y CONFIG_MS5837=y CONFIG_OPT3001=y diff --git a/tests/drivers/build_all/sensor/sensors_trigger_own.conf b/tests/drivers/build_all/sensor/sensors_trigger_own.conf index 28a05c164b8..7c77279dcda 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_own.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_own.conf @@ -30,6 +30,7 @@ CONFIG_LSM9DS0_GYRO_TRIGGER_DRDY=y CONFIG_LSM9DS0_GYRO_TRIGGERS=y CONFIG_MCP9808_TRIGGER_OWN_THREAD=y CONFIG_MPU6050_TRIGGER_OWN_THREAD=y +CONFIG_MPU9250_TRIGGER_OWN_THREAD=y CONFIG_SHT3XD_TRIGGER_OWN_THREAD=y CONFIG_SM351LT_TRIGGER_OWN_THREAD=y CONFIG_STTS751_TRIGGER_OWN_THREAD=y diff --git a/tests/drivers/uart/uart_async_api/boards/nrf52840dk_nrf52840.overlay b/tests/drivers/uart/uart_async_api/boards/nrf52840dk_nrf52840.overlay index 6762dce267a..f9408f65f86 100644 --- a/tests/drivers/uart/uart_async_api/boards/nrf52840dk_nrf52840.overlay +++ b/tests/drivers/uart/uart_async_api/boards/nrf52840dk_nrf52840.overlay @@ -16,7 +16,7 @@ }; &uart0 { - compatible = "nordic,nrf-uart"; + compatible = "nordic,nrf-uarte"; current-speed = <115200>; status = "okay"; tx-pin = <33>; diff --git a/tests/drivers/uart/uart_async_api/boards/nrf9160dk_nrf9160.conf b/tests/drivers/uart/uart_async_api/boards/nrf9160dk_nrf9160.conf index b695c18ab28..3bf0d47364b 100644 --- a/tests/drivers/uart/uart_async_api/boards/nrf9160dk_nrf9160.conf +++ b/tests/drivers/uart/uart_async_api/boards/nrf9160dk_nrf9160.conf @@ -1 +1,3 @@ CONFIG_ARM_MPU=n +CONFIG_UART_1_NRF_HW_ASYNC=y +CONFIG_UART_1_NRF_HW_ASYNC_TIMER=2 diff --git a/tests/drivers/uart/uart_async_api/boards/nrf_uart.overlay b/tests/drivers/uart/uart_async_api/boards/nrf_uart.overlay new file mode 100644 index 00000000000..936a3ea2437 --- /dev/null +++ b/tests/drivers/uart/uart_async_api/boards/nrf_uart.overlay @@ -0,0 +1,5 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +&uart0 { + compatible = "nordic,nrf-uart"; +}; diff --git a/tests/drivers/uart/uart_async_api/src/main.c b/tests/drivers/uart/uart_async_api/src/main.c index d09b75725f7..b1a4b3c6f62 100644 --- a/tests/drivers/uart/uart_async_api/src/main.c +++ b/tests/drivers/uart/uart_async_api/src/main.c @@ -24,6 +24,8 @@ void test_main(void) ztest_test_suite(uart_async_test, ztest_unit_test(test_single_read_setup), ztest_user_unit_test(test_single_read), + ztest_unit_test(test_multiple_rx_enable_setup), + ztest_user_unit_test(test_multiple_rx_enable), ztest_unit_test(test_chained_read_setup), ztest_user_unit_test(test_chained_read), ztest_unit_test(test_double_buffer_setup), diff --git a/tests/drivers/uart/uart_async_api/src/test_uart.h b/tests/drivers/uart/uart_async_api/src/test_uart.h index 5bb65ff1849..c534c5d5b71 100644 --- a/tests/drivers/uart/uart_async_api/src/test_uart.h +++ b/tests/drivers/uart/uart_async_api/src/test_uart.h @@ -54,6 +54,7 @@ void init_test(void); void test_single_read(void); +void test_multiple_rx_enable(void); void test_chained_read(void); void test_double_buffer(void); void test_read_abort(void); @@ -63,6 +64,7 @@ void test_long_buffers(void); void test_chained_write(void); void test_single_read_setup(void); +void test_multiple_rx_enable_setup(void); void test_chained_read_setup(void); void test_double_buffer_setup(void); void test_read_abort_setup(void); diff --git a/tests/drivers/uart/uart_async_api/src/test_uart_async.c b/tests/drivers/uart/uart_async_api/src/test_uart_async.c index 8e120370286..7178de985e1 100644 --- a/tests/drivers/uart/uart_async_api/src/test_uart_async.c +++ b/tests/drivers/uart/uart_async_api/src/test_uart_async.c @@ -68,7 +68,9 @@ void test_single_read_setup(void) void test_single_read(void) { uint8_t rx_buf[10] = {0}; - uint8_t tx_buf[5] = "test"; + + /* Check also if sending from read only memory (e.g. flash) works. */ + static const uint8_t tx_buf[5] = "test"; zassert_not_equal(memcmp(tx_buf, rx_buf, 5), 0, "Initial buffer check failed"); @@ -101,6 +103,104 @@ void test_single_read(void) zassert_equal(tx_aborted_count, 0, "TX aborted triggered"); } +void test_multiple_rx_enable_setup(void) +{ + tx_aborted_count = 0; + + /* Reuse the callback from the single_read test case, as this test case + * does not need anything extra in this regard. + */ + uart_callback_set(uart_dev, + test_single_read_callback, + (void *)&tx_aborted_count); + + k_sem_reset(&rx_rdy); + k_sem_reset(&rx_buf_released); + k_sem_reset(&rx_disabled); + k_sem_reset(&tx_done); +} + +void test_multiple_rx_enable(void) +{ + /* Check also if sending from read only memory (e.g. flash) works. */ + static const uint8_t tx_buf[] = "test"; + uint8_t rx_buf[sizeof(tx_buf)] = {0}; + int ret; + + /* Enable RX without a timeout. */ + ret = uart_rx_enable(uart_dev, rx_buf, sizeof(rx_buf), SYS_FOREVER_US); + zassert_equal(ret, 0, "uart_rx_enable failed"); + zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), -EAGAIN, + "RX_RDY not expected at this point"); + zassert_equal(k_sem_take(&rx_disabled, K_MSEC(100)), -EAGAIN, + "RX_DISABLED not expected at this point"); + + /* Disable RX before any data has been received. */ + ret = uart_rx_disable(uart_dev); + zassert_equal(ret, 0, "uart_rx_disable failed"); + zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), -EAGAIN, + "RX_RDY not expected at this point"); + zassert_equal(k_sem_take(&rx_buf_released, K_MSEC(100)), 0, + "RX_BUF_RELEASED timeout"); + zassert_equal(k_sem_take(&rx_disabled, K_MSEC(100)), 0, + "RX_DISABLED timeout"); + + k_sem_reset(&rx_buf_released); + k_sem_reset(&rx_disabled); + + /* Check that RX can be reenabled after "manual" disabling. */ + ret = uart_rx_enable(uart_dev, rx_buf, sizeof(rx_buf), + 50 * USEC_PER_MSEC); + zassert_equal(ret, 0, "uart_rx_enable failed"); + zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), -EAGAIN, + "RX_RDY not expected at this point"); + + /* Send enough data to completely fill RX buffer, so that RX ends. */ + ret = uart_tx(uart_dev, tx_buf, sizeof(tx_buf), 100 * USEC_PER_MSEC); + zassert_equal(ret, 0, "uart_tx failed"); + zassert_equal(k_sem_take(&tx_done, K_MSEC(100)), 0, "TX_DONE timeout"); + zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), 0, "RX_RDY timeout"); + zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), -EAGAIN, + "Extra RX_RDY received"); + zassert_equal(k_sem_take(&rx_buf_released, K_MSEC(100)), 0, + "RX_BUF_RELEASED timeout"); + zassert_equal(k_sem_take(&rx_disabled, K_MSEC(100)), 0, + "RX_DISABLED timeout"); + zassert_equal(tx_aborted_count, 0, "Unexpected TX abort"); + + zassert_equal(memcmp(tx_buf, rx_buf, sizeof(tx_buf)), 0, + "Buffers not equal"); + + k_sem_reset(&rx_rdy); + k_sem_reset(&rx_buf_released); + k_sem_reset(&rx_disabled); + k_sem_reset(&tx_done); + memset(rx_buf, 0, sizeof(rx_buf)); + + /* Check that RX can be reenabled after automatic disabling. */ + ret = uart_rx_enable(uart_dev, rx_buf, sizeof(rx_buf), + 50 * USEC_PER_MSEC); + zassert_equal(ret, 0, "uart_rx_enable failed"); + zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), -EAGAIN, + "RX_RDY not expected at this point"); + + /* Fill RX buffer again to confirm that RX still works properly. */ + ret = uart_tx(uart_dev, tx_buf, sizeof(tx_buf), 100 * USEC_PER_MSEC); + zassert_equal(ret, 0, "uart_tx failed"); + zassert_equal(k_sem_take(&tx_done, K_MSEC(100)), 0, "TX_DONE timeout"); + zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), 0, "RX_RDY timeout"); + zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), -EAGAIN, + "Extra RX_RDY received"); + zassert_equal(k_sem_take(&rx_buf_released, K_MSEC(100)), 0, + "RX_BUF_RELEASED timeout"); + zassert_equal(k_sem_take(&rx_disabled, K_MSEC(100)), 0, + "RX_DISABLED timeout"); + zassert_equal(tx_aborted_count, 0, "Unexpected TX abort"); + + zassert_equal(memcmp(tx_buf, rx_buf, sizeof(tx_buf)), 0, + "Buffers not equal"); +} + ZTEST_BMEM uint8_t chained_read_buf0[10]; ZTEST_BMEM uint8_t chained_read_buf1[20]; ZTEST_BMEM uint8_t chained_read_buf2[30]; diff --git a/tests/drivers/uart/uart_async_api/testcase.yaml b/tests/drivers/uart/uart_async_api/testcase.yaml index feee2d965f4..d91a8c7086b 100644 --- a/tests/drivers/uart/uart_async_api/testcase.yaml +++ b/tests/drivers/uart/uart_async_api/testcase.yaml @@ -10,6 +10,14 @@ tests: harness: ztest harness_config: fixture: gpio_loopback + drivers.uart.uart_async_api.nrf_uart: + tags: drivers + filter: CONFIG_UART_CONSOLE and CONFIG_SERIAL_SUPPORT_ASYNC + harness: ztest + platform_allow: nrf52840dk_nrf52840 + harness_config: + fixture: gpio_loopback + extra_args: DTC_OVERLAY_FILE="boards/nrf52840dk_nrf52840.overlay;boards/nrf_uart.overlay" drivers.uart.uart_async_api.rtt: tags: drivers filter: CONFIG_UART_CONSOLE and CONFIG_SERIAL_SUPPORT_ASYNC and CONFIG_HAS_SEGGER_RTT diff --git a/tests/drivers/uart/uart_mix_fifo_poll/src/main.c b/tests/drivers/uart/uart_mix_fifo_poll/src/main.c index 3cad674940f..20224fab244 100644 --- a/tests/drivers/uart/uart_mix_fifo_poll/src/main.c +++ b/tests/drivers/uart/uart_mix_fifo_poll/src/main.c @@ -36,16 +36,29 @@ struct rx_source { uint8_t prev; }; +#define BUF_SIZE 16 + +/* Buffer used for polling. */ +static uint8_t txbuf[3][BUF_SIZE]; + +/* Buffer used for async or interrupt driven apis. + * One of test configurations checks if RO buffer works with the driver. + */ +static IF_ENABLED(TEST_CONST_BUFFER, (const)) uint8_t txbuf3[16] = { + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f +}; + struct test_data { - uint8_t buf[16]; + const uint8_t *buf; volatile int cnt; int max; struct k_sem sem; }; static struct rx_source source[4]; -static struct test_data test_data[4]; -static struct test_data *int_async_data; +static struct test_data test_data[3]; +static struct test_data int_async_data; static const struct device *counter_dev; static const struct device *uart_dev; @@ -152,7 +165,7 @@ static void rx_isr(void) int len; do { - len = uart_fifo_read(uart_dev, buf, sizeof(buf)); + len = uart_fifo_read(uart_dev, buf, BUF_SIZE); for (int i = 0; i < len; i++) { process_byte(buf[i]); } @@ -161,10 +174,10 @@ static void rx_isr(void) static void tx_isr(void) { - uint8_t *buf = &int_async_data->buf[int_async_data->cnt & 0xF]; + const uint8_t *buf = &int_async_data.buf[int_async_data.cnt & 0xF]; int len = uart_fifo_fill(uart_dev, buf, 1); - int_async_data->cnt += len; + int_async_data.cnt += len; k_busy_wait(len ? 4 : 2); uart_irq_tx_disable(uart_dev); @@ -208,7 +221,7 @@ static void bulk_poll_out(struct test_data *data, int wait_base, int wait_range) for (int i = 0; i < data->max; i++) { data->cnt++; - uart_poll_out(uart_dev, data->buf[i % sizeof(data->buf)]); + uart_poll_out(uart_dev, data->buf[i % BUF_SIZE]); if (wait_base) { int r = sys_rand32_get(); @@ -240,15 +253,17 @@ static void int_async_thread_func(void *p_data, void *base, void *range) while (data->cnt < data->max) { if (async) { - uint8_t *buf; int err; err = k_sem_take(&async_tx_sem, K_MSEC(1000)); zassert_true(err >= 0, NULL); - buf = &int_async_data->buf[data->cnt & 0xF]; - data->cnt++; - err = uart_tx(uart_dev, buf, 1, 1000 * USEC_PER_MSEC); + int idx = data->cnt & 0xF; + size_t len = (idx < BUF_SIZE / 2) ? 5 : 1; /* Try various lengths */ + + data->cnt += len; + err = uart_tx(uart_dev, &int_async_data.buf[idx], + len, 1000 * USEC_PER_MSEC); zassert_true(err >= 0, "Unexpected err:%d", err); } else { @@ -267,7 +282,7 @@ static void poll_out_timer_handler(struct k_timer *timer) { struct test_data *data = k_timer_user_data_get(timer); - uart_poll_out(uart_dev, data->buf[data->cnt % sizeof(data->buf)]); + uart_poll_out(uart_dev, data->buf[data->cnt % BUF_SIZE]); data->cnt++; if (data->cnt == data->max) { @@ -288,10 +303,10 @@ static void init_buf(uint8_t *buf, int len, int idx) } } -static void init_test_data(struct test_data *data, int id, int repeat) +static void init_test_data(struct test_data *data, const uint8_t *buf, int repeat) { k_sem_init(&data->sem, 0, 1); - init_buf(data->buf, sizeof(data->buf), id); + data->buf = buf; data->cnt = 0; data->max = repeat; } @@ -303,7 +318,8 @@ static void test_mixed_uart_access(void) int num_of_contexts = ARRAY_SIZE(test_data); for (int i = 0; i < ARRAY_SIZE(test_data); i++) { - init_test_data(&test_data[i], i, repeat); + init_buf(txbuf[i], sizeof(txbuf[i]), i); + init_test_data(&test_data[i], txbuf[i], repeat); } (void)k_thread_create(&high_poll_out_thread, high_poll_out_thread_stack, 1024, @@ -312,15 +328,12 @@ static void test_mixed_uart_access(void) if (async || int_driven) { - int_async_data = &test_data[3]; + init_test_data(&int_async_data, txbuf3, repeat); (void)k_thread_create(&int_async_thread, int_async_thread_stack, 1024, int_async_thread_func, - int_async_data, (void *)300, (void *)400, + &int_async_data, (void *)300, (void *)400, 2, 0, K_NO_WAIT); - } else { - /* async/int driven context not used. */ - num_of_contexts--; } k_timer_user_data_set(&poll_out_timer, &test_data[1]); @@ -333,18 +346,20 @@ static void test_mixed_uart_access(void) for (int i = 0; i < num_of_contexts; i++) { err = k_sem_take(&test_data[i].sem, K_MSEC(10000)); zassert_equal(err, 0, NULL); + } + if (async || int_driven) { + err = k_sem_take(&int_async_data.sem, K_MSEC(10000)); + zassert_equal(err, 0, NULL); } k_msleep(10); - for (int i = 0; i < num_of_contexts; i++) { + for (int i = 0; i < (num_of_contexts + (async || int_driven ? 1 : 0)); i++) { zassert_equal(source[i].cnt, repeat, "%d: Unexpected rx bytes count (%d/%d)", i, source[i].cnt, repeat); - } - } void test_main(void) diff --git a/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml b/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml index 3114aaf0726..0ad912c7eda 100644 --- a/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml +++ b/tests/drivers/uart/uart_mix_fifo_poll/testcase.yaml @@ -31,6 +31,20 @@ tests: - CONFIG_NRFX_TIMER2=y - CONFIG_UART_0_ENHANCED_POLL_OUT=n + drivers.uart.uart_mix_poll_async_api_const: + tags: drivers + platform_allow: nrf52840dk_nrf52840 nrf9160dk_nrf9160 + extra_args: TEST_CONST_BUFFER=1 + extra_configs: + - CONFIG_UART_ASYNC_API=y + - CONFIG_UART_0_INTERRUPT_DRIVEN=n + - CONFIG_UART_0_ASYNC=y + - CONFIG_UART_0_NRF_HW_ASYNC=y + - CONFIG_UART_0_NRF_HW_ASYNC_TIMER=2 + - CONFIG_NRFX_TIMER2=y + - CONFIG_UART_0_ENHANCED_POLL_OUT=n + - CONFIG_UART_ASYNC_TX_CACHE_SIZE=2 + drivers.uart.uart_mix_poll_async_api_low_power: tags: drivers platform_allow: nrf52840dk_nrf52840 nrf9160dk_nrf9160 diff --git a/tests/subsys/openthread/radio_test.c b/tests/subsys/openthread/radio_test.c index 38e8a3f7e25..aea465d9576 100644 --- a/tests/subsys/openthread/radio_test.c +++ b/tests/subsys/openthread/radio_test.c @@ -430,8 +430,7 @@ static void test_tx_test(void) ztest_expect_value(set_channel_mock, channel, chan); ztest_expect_value(set_txpower_mock, dbm, power); ztest_expect_value(start_mock, dev, &radio); - zassert_equal(otPlatRadioReceive(ot, chan), OT_ERROR_NONE, - "Failed to receive."); + zassert_equal(otPlatRadioReceive(ot, chan), OT_ERROR_NONE, "Failed to receive."); /* ACKed frame */ frm->mChannel = chan2; @@ -442,8 +441,7 @@ static void test_tx_test(void) ztest_expect_value(cca_mock, dev, &radio); ztest_expect_value(tx_mock, frag->data, frm->mPsdu); ztest_expect_value(set_txpower_mock, dbm, power); - zassert_equal(otPlatRadioTransmit(ot, frm), OT_ERROR_NONE, - "Transmit failed."); + zassert_equal(otPlatRadioTransmit(ot, frm), OT_ERROR_NONE, "Transmit failed."); create_ack_frame(); make_sure_sem_set(Z_TIMEOUT_MS(100)); @@ -460,27 +458,10 @@ static void test_tx_test(void) ztest_expect_value(set_channel_mock, channel, chan2); ztest_expect_value(tx_mock, frag->data, frm->mPsdu); ztest_expect_value(set_txpower_mock, dbm, power); - zassert_equal(otPlatRadioTransmit(ot, frm), OT_ERROR_NONE, - "Transmit failed."); + zassert_equal(otPlatRadioTransmit(ot, frm), OT_ERROR_NONE, "Transmit failed."); make_sure_sem_set(Z_TIMEOUT_MS(100)); ztest_expect_value(otPlatRadioTxDone, aError, OT_ERROR_NONE); platformRadioProcess(ot); - - /* ACKed frame, no ACK */ - frm->mChannel = --chan2; - frm->mInfo.mTxInfo.mCsmaCaEnabled = false; - frm->mPsdu[0] = IEEE802154_AR_FLAG_SET; - - ztest_returns_value(set_channel_mock, 0); - ztest_expect_value(set_channel_mock, channel, chan2); - ztest_expect_value(tx_mock, frag->data, frm->mPsdu); - ztest_expect_value(set_txpower_mock, dbm, power); - zassert_equal(otPlatRadioTransmit(ot, frm), OT_ERROR_NONE, - "Transmit failed."); - make_sure_sem_set(Z_TIMEOUT_MS(100)); - - ztest_expect_value(otPlatRadioTxDone, aError, OT_ERROR_NO_ACK); - platformRadioProcess(ot); } /** diff --git a/tests/subsys/storage/stream/stream_flash/src/main.c b/tests/subsys/storage/stream/stream_flash/src/main.c index 93d803e6db6..0ea9fa177bc 100644 --- a/tests/subsys/storage/stream/stream_flash/src/main.c +++ b/tests/subsys/storage/stream/stream_flash/src/main.c @@ -22,7 +22,7 @@ #define FLASH_NAME DT_CHOSEN_ZEPHYR_FLASH_CONTROLLER_LABEL /* so that we don't overwrite the application when running on hw */ -#define FLASH_BASE (64*1024) +#define FLASH_BASE (128*1024) #define FLASH_AVAILABLE (FLASH_SIZE-FLASH_BASE) static const struct device *fdev; diff --git a/west.yml b/west.yml index 282997c1c25..dec5d99d0a9 100644 --- a/west.yml +++ b/west.yml @@ -88,7 +88,7 @@ manifest: groups: - hal - name: hal_nordic - revision: a42b016d7c7610489f5f8c79773fedc05ba352ee + revision: b1db86f188c3c5864985e1bd18a849d53f1c0a2d path: modules/hal/nordic groups: - hal @@ -190,7 +190,7 @@ manifest: revision: cfd050ff38a9d028dc211690b2ec35971128e45e path: modules/lib/open-amp - name: openthread - revision: 41bc49da49736fbdfdfa231f7b2311f29dcc4979 + revision: b7aa7686d3f4e326bd25abc234b209159977c26d path: modules/lib/openthread - name: segger revision: 3a52ab222133193802d3c3b4d21730b9b1f1d2f6 @@ -218,7 +218,7 @@ manifest: groups: - debug - name: trusted-firmware-m - revision: c8134809a9439571c54d36ef39210270dbee8f67 + revision: 5d32c3e64b3d589548e881eeeeb37d84944c90af path: modules/tee/tf-m/trusted-firmware-m groups: - tee @@ -228,7 +228,7 @@ manifest: groups: - tee - name: psa-arch-tests - revision: 186cba2543dff73d0cda5509d26f02a0b39ee66e + revision: 0aab24602cbef30f6422e7ef1066a8473073e586 path: modules/tee/tf-m/psa-arch-tests groups: - tee