diff --git a/.github/test-spec.yml b/.github/test-spec.yml index c29b7ea2eb5c..91543c5eaa14 100644 --- a/.github/test-spec.yml +++ b/.github/test-spec.yml @@ -267,6 +267,7 @@ - "include/bluetooth/mesh/**/*" - "tests/subsys/bluetooth/mesh/**/*" - "samples/bluetooth/mesh/**/*" + - "scripts/requirements-fixed.txt" "CI-thingy91-test": - "modules/cjson/**/*" diff --git a/.github/workflows/codeowners-reviewers.yml b/.github/workflows/codeowners-reviewers.yml new file mode 100644 index 000000000000..5b063b87856b --- /dev/null +++ b/.github/workflows/codeowners-reviewers.yml @@ -0,0 +1,19 @@ +name: Assign reviewers from CODEOWNERS + +on: + pull_request_target: + types: [opened, reopened, synchronize] + +permissions: + contents: read + pull-requests: write + +jobs: + contribs: + runs-on: ubuntu-24.04 + name: Assign Reviewers from CODEOWNERS + steps: + - name: Assign + uses: nrfconnect/action-codeowners-reviewers@e00a792221daf9f7ec21c658400dc62739b3bfe5 + with: + github_token: ${{ secrets.NCS_NORDICBUILDER_ACTION_TOKEN }} diff --git a/.github/workflows/matter-validation.yml b/.github/workflows/matter-validation.yml new file mode 100644 index 000000000000..20a34009254c --- /dev/null +++ b/.github/workflows/matter-validation.yml @@ -0,0 +1,68 @@ +name: Matter Validation + +on: + pull_request: + branches: + - main + - 'v*-branch' + + paths: + - 'samples/matter/**' + - 'applications/matter_bridge/**' + - 'applications/matter_weather_station/**' + +permissions: + contents: read + +jobs: + matter-validation: + runs-on: ubuntu-24.04 + steps: + - name: Checkout the code + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: 0 + path: ncs/nrf + + - name: Rebase + if: github.event_name == 'pull_request' + continue-on-error: true + env: + BASE_REF: ${{ github.base_ref }} + PR_HEAD: ${{ github.event.pull_request.head.sha }} + working-directory: ncs/nrf + run: | + git config --global user.email "actions@zephyrproject.org" + git config --global user.name "Github Actions" + rm -fr ".git/rebase-apply" + rm -fr ".git/rebase-merge" + git rebase origin/${BASE_REF} + git clean -f -d + git log --graph --oneline HEAD...${PR_HEAD} + + - name: Set up Python + uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 + with: + python-version: 3.12 + cache: pip + cache-dependency-path: ncs/nrf/scripts/requirements.txt + + - name: Install packages + working-directory: ncs/nrf + run: | + sudo apt update + sudo apt-get install -y wget python3-pip git + pip install -r scripts/requirements.txt + + - name: Checkout Matter repository + working-directory: ncs + run: | + git clone https://github.com/nrfconnect/sdk-connectedhomeip modules/lib/matter + cd modules/lib/matter + git checkout master + + - name: validate Matter samples and documentation + working-directory: ncs + run: | + python nrf/scripts/matter/matter_sample_checker/matter_sample_checker.py --samples-zap-yaml nrf/samples/matter/common/src/zap_samples.yml --base nrf diff --git a/CODEOWNERS b/CODEOWNERS index a24ab38fdd29..0dfb1eb9316e 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -72,15 +72,18 @@ /doc/_zoomin/ @nrfconnect/ncs-co-doc @nrfconnect/ncs-doc-leads /doc/kconfig/ @nrfconnect/ncs-doc-leads /doc/matter/ @nrfconnect/ncs-matter-doc -/doc/mcuboot/ @nrfconnect/ncs-pluto-doc +/doc/mcuboot/ @nrfconnect/ncs-eris-doc /doc/nrf/*.rst @nrfconnect/ncs-doc-leads /doc/nrf/app_dev/ @nrfconnect/ncs-doc-leads @nrfconnect/ncs-vestavind-doc -/doc/nrf/app_dev/bootloaders_dfu/ @nrfconnect/ncs-pluto-doc +/doc/nrf/app_dev/bootloaders_dfu/ @nrfconnect/ncs-eris-doc /doc/nrf/app_dev/device_guides/fem/ @nrfconnect/ncs-doc-leads /doc/nrf/app_dev/device_guides/nrf52/ @nrfconnect/ncs-doc-leads /doc/nrf/app_dev/device_guides/nrf53/ @nrfconnect/ncs-doc-leads -/doc/nrf/app_dev/device_guides/nrf53/qspi_xip_guide_nrf5340.rst @nrfconnect/ncs-pluto-doc +/doc/nrf/app_dev/device_guides/nrf53/qspi_xip_guide_nrf5340.rst @nrfconnect/ncs-eris-doc /doc/nrf/app_dev/device_guides/nrf54l/ @annwoj +/doc/nrf/app_dev/device_guides/nrf54l/cryptography.rst @nrfconnect/ncs-aegir-doc +/doc/nrf/app_dev/device_guides/nrf54l/kmu_basics.rst @nrfconnect/ncs-aegir-doc +/doc/nrf/app_dev/device_guides/nrf54l/kmu_provision.rst @nrfconnect/ncs-aegir-doc /doc/nrf/app_dev/device_guides/nrf70/ @nrfconnect/ncs-wifi-doc /doc/nrf/app_dev/device_guides/nrf91/ @nrfconnect/ncs-modem-doc /doc/nrf/app_dev/device_guides/nrf91/nrf91_snippet.rst @nrfconnect/ncs-cia-doc @@ -104,7 +107,7 @@ /doc/nrf/drivers/uart_nrf_sw_lpuart.rst @nrfconnect/ncs-doc-leads /doc/nrf/external_comp/avsystem.rst @nrfconnect/ncs-iot-oulu-tampere-doc /doc/nrf/external_comp/bt_fast_pair/ @nrfconnect/ncs-si-bluebagel-doc -/doc/nrf/external_comp/coremark.rst @nrfconnect/ncs-si-bluebagel-doc +/doc/nrf/external_comp/coremark.rst @nrfconnect/ncs-si-muffin-doc /doc/nrf/external_comp/dult.rst @nrfconnect/ncs-si-bluebagel-doc /doc/nrf/external_comp/edge_impulse.rst @nrfconnect/ncs-si-muffin-doc /doc/nrf/external_comp/memfault.rst @nrfconnect/ncs-cia-doc @@ -127,7 +130,7 @@ /doc/nrf/libraries/debug/index.rst @nrfconnect/ncs-doc-leads /doc/nrf/libraries/debug/memfault_ncs.rst @nrfconnect/ncs-cia-doc /doc/nrf/libraries/debug/ppi_trace.rst @nrfconnect/ncs-doc-leads -/doc/nrf/libraries/dfu/ @nrfconnect/ncs-pluto-doc +/doc/nrf/libraries/dfu/ @nrfconnect/ncs-eris-doc /doc/nrf/libraries/gazell/ @nrfconnect/ncs-si-muffin-doc /doc/nrf/libraries/modem/nrf_modem_lib/ @nrfconnect/ncs-modem-doc /doc/nrf/libraries/modem/at_cmd_custom.rst @nrfconnect/ncs-modem-doc @@ -156,9 +159,8 @@ /doc/nrf/libraries/networking/aws_*.rst @nrfconnect/ncs-cia-doc /doc/nrf/libraries/networking/azure_*.rst @nrfconnect/ncs-cia-doc /doc/nrf/libraries/networking/coap_utils.rst @nrfconnect/ncs-terahertz-doc -/doc/nrf/libraries/networking/download_client.rst @nrfconnect/ncs-modem-doc /doc/nrf/libraries/networking/downloader.rst @nrfconnect/ncs-modem-doc -/doc/nrf/libraries/networking/fota_download.rst @nrfconnect/ncs-pluto-doc +/doc/nrf/libraries/networking/fota_download.rst @nrfconnect/ncs-eris-doc /doc/nrf/libraries/networking/ftp_client.rst @nrfconnect/ncs-iot-oulu-tampere-doc /doc/nrf/libraries/networking/icalendar_parser.rst @nrfconnect/ncs-doc-leads /doc/nrf/libraries/networking/index.rst @nrfconnect/ncs-doc-leads @@ -195,7 +197,7 @@ /doc/nrf/libraries/others/esb.rst @nrfconnect/ncs-si-muffin-doc /doc/nrf/libraries/others/event_manager_proxy.rst @nrfconnect/ncs-si-muffin-doc /doc/nrf/libraries/others/fem_al.rst @nrfconnect/ncs-si-muffin-doc -/doc/nrf/libraries/others/flash_map_pm.rst @nrfconnect/ncs-pluto-doc +/doc/nrf/libraries/others/flash_map_pm.rst @nrfconnect/ncs-eris-doc /doc/nrf/libraries/others/hw_id.rst @nrfconnect/ncs-cia-doc /doc/nrf/libraries/others/index.rst @nrfconnect/ncs-doc-leads /doc/nrf/libraries/others/log_rpc.rst @nrfconnect/ncs-terahertz-doc @@ -212,7 +214,7 @@ /doc/nrf/libraries/others/tone.rst @nrfconnect/ncs-audio-doc /doc/nrf/libraries/others/uart_async_adapter.rst @nrfconnect/ncs-si-muffin-doc /doc/nrf/libraries/others/wave_gen.rst @nrfconnect/ncs-si-bluebagel-doc -/doc/nrf/libraries/security/bootloader/ @nrfconnect/ncs-pluto-doc +/doc/nrf/libraries/security/bootloader/ @nrfconnect/ncs-eris-doc /doc/nrf/libraries/security/nrf_security/ @nrfconnect/ncs-aegir-doc /doc/nrf/libraries/security/tfm/ @nrfconnect/ncs-aegir-doc /doc/nrf/libraries/security/fatal_error.rst @nrfconnect/ncs-doc-leads @@ -245,7 +247,7 @@ /doc/nrf/samples/crypto.rst @nrfconnect/ncs-aegir-doc /doc/nrf/samples/debug.rst @nrfconnect/ncs-cia-doc /doc/nrf/samples/dect.rst @nrfconnect/ncs-modem-doc -/doc/nrf/samples/dfu.rst @nrfconnect/ncs-charon-doc +/doc/nrf/samples/dfu.rst @nrfconnect/ncs-eris-doc /doc/nrf/samples/edge.rst @nrfconnect/ncs-si-muffin-doc /doc/nrf/samples/esb.rst @nrfconnect/ncs-si-muffin-doc /doc/nrf/samples/fast_pair.rst @nrfconnect/ncs-si-bluebagel-doc @@ -343,12 +345,11 @@ /include/fem_al/ @nrfconnect/ncs-dragoon /include/hpf/ @nrfconnect/ncs-ll-ursus /include/logging/ @nrfconnect/ncs-protocols-serialization -/include/mgmt/ @nrfconnect/ncs-pluto +/include/mgmt/ @nrfconnect/ncs-eris /include/modem/ @nrfconnect/ncs-modem @nrfconnect/ncs-modem-tre /include/mpsl/ @nrfconnect/ncs-dragoon /include/net/ @nrfconnect/ncs-co-networking /include/net/azure_* @nrfconnect/ncs-cia -/include/net/download_client* @nrfconnect/ncs-modem /include/net/downloader* @nrfconnect/ncs-modem /include/net/nrf_cloud_* @nrfconnect/ncs-nrf-cloud /include/nfc/ @nrfconnect/ncs-co-drivers @nrfconnect/ncs-si-muffin @@ -379,8 +380,8 @@ /lib/edge_impulse/ @nrfconnect/ncs-si-muffin /lib/fatal_error/ @nordic-krch /lib/fem_al/ @nrfconnect/ncs-si-muffin -/lib/flash_patch/ @nrfconnect/ncs-pluto -/lib/fprotect/ @nrfconnect/ncs-pluto +/lib/flash_patch/ @nrfconnect/ncs-eris +/lib/fprotect/ @nrfconnect/ncs-eris /lib/gcf_sms/ @nrfconnect/ncs-modem /lib/hw_id/ @nrfconnect/ncs-cia /lib/hw_unique_key/ @nrfconnect/ncs-aegir @@ -413,8 +414,8 @@ # Modules /modules/azure-sdk-for-c/ @nrfconnect/ncs-cia /modules/cjson/ @nrfconnect/ncs-cia @nrfconnect/ncs-nrf-cloud -/modules/coremark/ @nrfconnect/ncs-si-bluebagel -/modules/mcuboot/ @nrfconnect/ncs-pluto +/modules/coremark/ @nrfconnect/ncs-si-muffin +/modules/mcuboot/ @nrfconnect/ncs-eris /modules/memfault-firmware-sdk/ @nrfconnect/ncs-cia @nrfconnect/ncs-memfault /modules/nrfxlib/ @nrfconnect/ncs-code-owners /modules/openthread/ @nrfconnect/ncs-thread @@ -427,7 +428,7 @@ /samples/app_event_manager/ @nrfconnect/ncs-si-muffin @nrfconnect/ncs-si-bluebagel /samples/app_event_manager_profiler_tracer/ @nrfconnect/ncs-si-muffin @nrfconnect/ncs-si-bluebagel /samples/app_jwt/ @nrfconnect/ncs-modem @ayla-nordicsemi -/samples/benchmarks/coremark/ @nrfconnect/ncs-si-bluebagel +/samples/benchmarks/coremark/ @nrfconnect/ncs-si-muffin /samples/bluetooth/nrf_auraconfig/ @nrfconnect/ncs-audio /samples/bluetooth/central_and_peripheral_hr/ @nrfconnect/ncs-si-muffin /samples/bluetooth/central_bas/ @nrfconnect/ncs-si-muffin @@ -478,7 +479,7 @@ /samples/bluetooth/shell_bt_nus/ @nrfconnect/ncs-si-muffin /samples/bluetooth/subrating/ @nrfconnect/ncs-dragoon /samples/bluetooth/throughput/ @nrfconnect/ncs-si-muffin -/samples/bootloader/ @nrfconnect/ncs-pluto +/samples/bootloader/ @nrfconnect/ncs-eris /samples/caf/ @nrfconnect/ncs-si-muffin @nrfconnect/ncs-si-bluebagel /samples/caf_sensor_manager/ @nrfconnect/ncs-si-muffin @nrfconnect/ncs-si-bluebagel /samples/cellular/ @nrfconnect/ncs-co-networking @nrfconnect/ncs-modem @@ -502,9 +503,9 @@ /samples/debug/ppi_trace/ @nordic-krch /samples/dect/dect_phy/dect_shell/ @nrfconnect/ncs-modem-tre /samples/dect/dect_phy/hello_dect/ @nrfconnect/ncs-modem -/samples/dfu/ab/ @nrfconnect/ncs-charon -/samples/dfu/dfu_target/ @nrfconnect/ncs-charon -/samples/dfu/dfu_multi_image/ @nrfconnect/ncs-charon +/samples/dfu/ab/ @nrfconnect/ncs-eris +/samples/dfu/dfu_target/ @nrfconnect/ncs-eris +/samples/dfu/dfu_multi_image/ @nrfconnect/ncs-eris /samples/edge_impulse/ @nrfconnect/ncs-si-muffin /samples/esb/ @nrfconnect/ncs-si-muffin /samples/event_manager_proxy/ @nrfconnect/ncs-si-muffin @@ -513,18 +514,19 @@ /samples/ipc/ipc_service/ @nrfconnect/ncs-si-muffin /samples/keys/ @nrfconnect/ncs-aegir /samples/matter/ @nrfconnect/ncs-matter -/samples/mcuboot/ @nrfconnect/ncs-pluto +/samples/mcuboot/ @nrfconnect/ncs-eris /samples/mpsl/ @nrfconnect/ncs-dragoon /samples/net/ @nrfconnect/ncs-cia @nrfconnect/ncs-modem /samples/nfc/ @nrfconnect/ncs-si-muffin -/samples/nrf5340/netboot/ @nrfconnect/ncs-pluto -/samples/nrf5340/extxip_smp_svr/ @nrfconnect/ncs-pluto +/samples/nrf5340/netboot/ @nrfconnect/ncs-eris +/samples/nrf5340/extxip_smp_svr/ @nrfconnect/ncs-eris /samples/nrf_rpc/ @nrfconnect/ncs-si-muffin /samples/sensor/bh1749/ @nrfconnect/ncs-cia /samples/sensor/bme68x_iaq/ @nrfconnect/ncs-cia /samples/nrf5340/empty_app_core/ @nrfconnect/ncs-si-muffin -/samples/nrf5340/extxip_smp_svr/ @nrfconnect/ncs-pluto +/samples/nrf5340/extxip_smp_svr/ @nrfconnect/ncs-eris /samples/nrf54h20/empty_app_core/ @nrfconnect/ncs-aurora +/samples/ironside_se/ @nrfconnect/ncs-aurora /samples/nrf_compress/ @nordicjm /samples/nrf_profiler/ @nrfconnect/ncs-si-bluebagel /samples/nrf_rpc/protocols_serialization/ @nrfconnect/ncs-protocols-serialization @@ -558,7 +560,7 @@ /samples/app_event_manager/*.rst @nrfconnect/ncs-si-muffin-doc @nrfconnect/ncs-si-bluebagel-doc /samples/app_event_manager_profiler_tracer/*.rst @nrfconnect/ncs-si-muffin-doc /samples/app_jwt/*.rst @nrfconnect/ncs-modem-doc @ayla-nordicsemi -/samples/benchmarks/coremark/*.rst @nrfconnect/ncs-si-bluebagel-doc +/samples/benchmarks/coremark/*.rst @nrfconnect/ncs-si-muffin-doc /samples/bluetooth/**/*.rst @nrfconnect/ncs-si-bluebagel-doc @nrfconnect/ncs-si-muffin-doc /samples/bluetooth/central_and_peripheral_hr/*.rst @nrfconnect/ncs-si-muffin-doc /samples/bluetooth/central_bas/*.rst @nrfconnect/ncs-si-muffin-doc @@ -610,7 +612,7 @@ /samples/bluetooth/shell_bt_nus/*.rst @nrfconnect/ncs-si-muffin-doc /samples/bluetooth/subrating/*.rst @nrfconnect/ncs-dragoon-doc /samples/bluetooth/throughput/*.rst @nrfconnect/ncs-si-muffin-doc -/samples/bootloader/*.rst @nrfconnect/ncs-pluto-doc +/samples/bootloader/*.rst @nrfconnect/ncs-eris-doc /samples/caf/*.rst @nrfconnect/ncs-si-muffin-doc @nrfconnect/ncs-si-bluebagel-doc /samples/caf_sensor_manager/*.rst @nrfconnect/ncs-si-muffin-doc @nrfconnect/ncs-si-bluebagel-doc /samples/cellular/**/*.rst @nrfconnect/ncs-modem-doc @@ -628,14 +630,15 @@ /samples/debug/ppi_trace/*.rst @nrfconnect/ncs-doc-leads /samples/dect/dect_phy/dect_shell/*.rst @nrfconnect/ncs-iot-positioning-doc /samples/dect/dect_phy/hello_dect/*.rst @nrfconnect/ncs-modem-doc -/samples/dfu/ab/*.rst @nrfconnect/ncs-charon-doc -/samples/dfu/dfu_target/*.rst @nrfconnect/ncs-charon-doc -/samples/dfu/dfu_multi_image/*.rst @nrfconnect/ncs-charon-doc +/samples/dfu/ab/*.rst @nrfconnect/ncs-eris-doc +/samples/dfu/dfu_target/*.rst @nrfconnect/ncs-eris-doc +/samples/dfu/dfu_multi_image/*.rst @nrfconnect/ncs-eris-doc /samples/esb/**/*.rst @nrfconnect/ncs-si-muffin-doc /samples/edge_impulse/**/*.rst @nrfconnect/ncs-si-muffin-doc /samples/event_manager_proxy/*.rst @nrfconnect/ncs-si-muffin-doc /samples/gazell/**/*.rst @nrfconnect/ncs-si-muffin-doc /samples/hw_id/*.rst @nrfconnect/ncs-cia-doc +/samples/ironside_se/**/*.rst @nrfconnect/ncs-aurora-doc /samples/ipc/ipc_service/*.rst @nrfconnect/ncs-si-muffin-doc /samples/keys/**/*.rst @nrfconnect/ncs-aegir-doc /samples/matter/**/*.rst @nrfconnect/ncs-matter-doc @@ -645,8 +648,8 @@ /samples/nfc/**/*.rst @nrfconnect/ncs-si-muffin-doc /samples/nrf5340/empty_app_core/*.rst @nrfconnect/ncs-si-muffin-doc /samples/nrf5340/empty_net_core/*.rst @nrfconnect/ncs-si-bluebagel-doc -/samples/nrf5340/extxip_smp_svr/*.rst @nrfconnect/ncs-pluto-doc -/samples/nrf5340/netboot/*.rst @nrfconnect/ncs-pluto-doc +/samples/nrf5340/extxip_smp_svr/*.rst @nrfconnect/ncs-eris-doc +/samples/nrf5340/netboot/*.rst @nrfconnect/ncs-eris-doc /samples/nrf5340/remote_shell/*.rst @nrfconnect/ncs-si-muffin-doc /samples/nrf_compress/mcuboot_update/*.rst @nrfconnect/ncs-vestavind-doc /samples/nrf_profiler/*.rst @nrfconnect/ncs-si-bluebagel-doc @@ -678,9 +681,9 @@ /samples/zephyr/sensor/accel_polling/ @nrfconnect/ncs-low-level-test /samples/zephyr/sensor/bme680/ @nrfconnect/ncs-low-level-test /samples/zephyr/sensor/qdec/ @nrfconnect/ncs-low-level-test -/samples/zephyr/smp_svr_mini_boot/ @nrfconnect/ncs-pluto @nrfconnect/ncs-charon +/samples/zephyr/smp_svr_mini_boot/ @nrfconnect/ncs-eris /samples/zephyr/subsys/ipc/ @nrfconnect/ncs-low-level-test -/samples/zephyr/subsys/mgmt/mcumgr/smp_svr/ @nrfconnect/ncs-charon +/samples/zephyr/subsys/mgmt/mcumgr/smp_svr/ @nrfconnect/ncs-eris /samples/zephyr/subsys/settings/ @nrfconnect/ncs-low-level-test /samples/zephyr/subsys/usb/ @nrfconnect/ncs-low-level-test /samples/zephyr/sysbuild/ @nrfconnect/ncs-low-level-test @@ -707,15 +710,15 @@ /scripts/west_commands/sbom/ @nrfconnect/ncs-co-scripts /scripts/west_commands/thingy91x_dfu.py @nrfconnect/ncs-cia /scripts/west_commands/ncs_ironside_se_update.py @nrfconnect/ncs-aurora -/scripts/west_commands/ncs_provision.py @nrfconnect/ncs-pluto -/scripts/bootloader/ @nrfconnect/ncs-pluto -/scripts/reglock.py @nrfconnect/ncs-pluto +/scripts/west_commands/ncs_provision.py @nrfconnect/ncs-eris +/scripts/bootloader/ @nrfconnect/ncs-eris +/scripts/reglock.py @nrfconnect/ncs-eris /scripts/ncs-docker-version.txt @nrfconnect/ncs-ci /scripts/print_docker_image.sh @nrfconnect/ncs-ci /scripts/print_toolchain_checksum.sh @nrfconnect/ncs-ci /scripts/hpf/ @nrfconnect/ncs-ll-ursus /scripts/generate_psa_key_attributes.py @nrfconnect/ncs-aegir -/scripts/tests/ @nrfconnect/ncs-pluto @fundakol +/scripts/tests/ @nrfconnect/ncs-eris @fundakol /scripts/vale/ @francescoser /scripts/esb_sniffer/ @nrfconnect/ncs-si-muffin @@ -780,23 +783,23 @@ /subsys/bluetooth/services/ras/ @nrfconnect/ncs-dragoon /subsys/bluetooth/services/wifi_prov/ @wentong-li @bama-nordic /subsys/bluetooth/services/hids.c @nrfconnect/ncs-si-bluebagel -/subsys/bootloader/ @nrfconnect/ncs-pluto +/subsys/bootloader/ @nrfconnect/ncs-eris /subsys/caf/ @nrfconnect/ncs-si-muffin @nrfconnect/ncs-si-bluebagel /subsys/debug/ @nordic-krch /subsys/debug/coredump/ @nrfconnect/ncs-protocols-serialization -/subsys/dfu/ @nrfconnect/ncs-pluto -/subsys/dfu/dfu_target/ @nrfconnect/ncs-pluto @nrfconnect/ncs-charon -/subsys/dfu/dfu_multi_image/ @Damian-Nordic @nrfconnect/ncs-charon +/subsys/dfu/ @nrfconnect/ncs-eris +/subsys/dfu/dfu_target/ @nrfconnect/ncs-eris +/subsys/dfu/dfu_multi_image/ @Damian-Nordic @nrfconnect/ncs-eris /subsys/dm/ @nrfconnect/ncs-si-muffin /subsys/dult/ @nrfconnect/ncs-si-bluebagel /subsys/emds/ @balaklaka @nrfconnect/ncs-paladin /subsys/esb/ @nrfconnect/ncs-si-muffin /subsys/event_manager_proxy/ @nrfconnect/ncs-si-muffin -/subsys/fw_info/ @nrfconnect/ncs-pluto +/subsys/fw_info/ @nrfconnect/ncs-eris /subsys/gazell/ @leewkb4567 /subsys/logging/ @nrfconnect/ncs-protocols-serialization -/subsys/mcuboot/ @nrfconnect/ncs-charon -/subsys/mgmt/ @nrfconnect/ncs-pluto +/subsys/mcuboot/ @nrfconnect/ncs-eris +/subsys/mgmt/ @nrfconnect/ncs-eris /subsys/mpsl/ @nrfconnect/ncs-dragoon /subsys/mpsl/cx/ @nrfconnect/ncs-radio-sw /subsys/mpsl/fem/ @nrfconnect/ncs-radio-sw @@ -804,7 +807,6 @@ /subsys/net/lib/mqtt_helper/ @nrfconnect/ncs-cia /subsys/net/lib/azure_* @nrfconnect/ncs-cia /subsys/net/lib/aws_* @nrfconnect/ncs-cia -/subsys/net/lib/download_client* @nrfconnect/ncs-modem /subsys/net/lib/downloader/ @nrfconnect/ncs-modem /subsys/net/lib/ftp_client/ @nrfconnect/ncs-iot-oulu /subsys/net/lib/hostap_crypto/ @krish2718 @jukkar @@ -825,9 +827,9 @@ /subsys/nrf_rpc/ @nrfconnect/ncs-si-muffin @nrfconnect/ncs-protocols-serialization /subsys/nrf_security/ @nrfconnect/ncs-aegir /subsys/partition_manager/ @nordicjm @tejlmand -/subsys/pcd/ @nrfconnect/ncs-pluto +/subsys/pcd/ @nrfconnect/ncs-eris /subsys/secure_storage/ @nrfconnect/ncs-aegir -/subsys/settings/ @nrfconnect/ncs-pluto @rghaddab +/subsys/settings/ @nrfconnect/ncs-eris @rghaddab /subsys/shell/ @nordic-krch /subsys/trusted_storage/ @nrfconnect/ncs-aegir /subsys/uart_async_adapter/ @nrfconnect/ncs-si-muffin @@ -847,9 +849,9 @@ /tests/bluetooth/tester/ @carlescufi @nrfconnect/ncs-paladin /tests/crypto/ @magnev /tests/drivers/audio/ @nrfconnect/ncs-low-level-test -/tests/drivers/flash/flash_rpc/ @nrfconnect/ncs-pluto -/tests/drivers/flash_patch/ @nrfconnect/ncs-pluto -/tests/drivers/fprotect/ @nrfconnect/ncs-pluto +/tests/drivers/flash/flash_rpc/ @nrfconnect/ncs-eris +/tests/drivers/flash_patch/ @nrfconnect/ncs-eris +/tests/drivers/fprotect/ @nrfconnect/ncs-eris /tests/drivers/gpio/ @nrfconnect/ncs-low-level-test @nrfconnect/ncs-ll-ursus /tests/drivers/grtc/ @nrfconnect/ncs-low-level-test /tests/drivers/i2c/ @nrfconnect/ncs-low-level-test @@ -901,8 +903,8 @@ /tests/lib/app_jwt/ @nrfconnect/ncs-modem /tests/mocks/nrf_rpc/ @nrfconnect/ncs-protocols-serialization /tests/modules/lib/zcbor/ @oyvindronningstad -/tests/modules/mcuboot/direct_xip/ @nrfconnect/ncs-pluto -/tests/modules/mcuboot/external_flash/ @nrfconnect/ncs-pluto +/tests/modules/mcuboot/direct_xip/ @nrfconnect/ncs-eris +/tests/modules/mcuboot/external_flash/ @nrfconnect/ncs-eris /tests/nrf5340_audio/ @nrfconnect/ncs-audio @nordic-auko /tests/psa_crypto/ @nrfconnect/ncs-aegir /tests/subsys/app_event_manager/ @nrfconnect/ncs-si-muffin @nrfconnect/ncs-si-bluebagel @@ -913,21 +915,20 @@ /tests/subsys/bluetooth/enocean/ @nrfconnect/ncs-paladin /tests/subsys/bluetooth/fast_pair/ @nrfconnect/ncs-si-bluebagel /tests/subsys/bluetooth/mesh/ @nrfconnect/ncs-paladin -/tests/subsys/bootloader/ @nrfconnect/ncs-pluto +/tests/subsys/bootloader/ @nrfconnect/ncs-eris /tests/subsys/caf/ @nrfconnect/ncs-si-muffin @nrfconnect/ncs-si-bluebagel /tests/subsys/debug/cpu_load/ @nordic-krch -/tests/subsys/dfu/ @nrfconnect/ncs-pluto +/tests/subsys/dfu/ @nrfconnect/ncs-eris /tests/subsys/dfu/dfu_multi_image/ @Damian-Nordic /tests/subsys/emds/ @balaklaka @nrfconnect/ncs-paladin /tests/subsys/event_manager_proxy/ @nrfconnect/ncs-si-muffin -/tests/subsys/fw_info/ @nrfconnect/ncs-pluto -/tests/subsys/kmu/ @nrfconnect/ncs-pluto +/tests/subsys/fw_info/ @nrfconnect/ncs-eris +/tests/subsys/kmu/ @nrfconnect/ncs-eris /tests/subsys/mpsl/ @nrfconnect/ncs-dragoon /tests/subsys/net/lib/aws_*/ @nrfconnect/ncs-cia /tests/subsys/net/lib/azure_iot_hub/ @nrfconnect/ncs-cia /tests/subsys/net/lib/downloader/ @nrfconnect/ncs-modem -/tests/subsys/net/lib/download_client/ @nrfconnect/ncs-modem -/tests/subsys/net/lib/fota_download/ @nrfconnect/ncs-pluto +/tests/subsys/net/lib/fota_download/ @nrfconnect/ncs-eris /tests/subsys/net/lib/lwm2m_*/ @nrfconnect/ncs-iot-oulu /tests/subsys/net/lib/mqtt_helper/ @nrfconnect/ncs-cia /tests/subsys/net/lib/nrf_cloud/ @nrfconnect/ncs-nrf-cloud @@ -941,7 +942,7 @@ /tests/subsys/nrf_security/psa_core_lite/ @nrfconnect/ncs-aegir /tests/subsys/partition_manager/region/ @nordicjm @tejlmand /tests/subsys/partition_manager/static_pm_file/ @nordicjm @tejlmand -/tests/subsys/pcd/ @nrfconnect/ncs-pluto +/tests/subsys/pcd/ @nrfconnect/ncs-eris /tests/subsys/rtt/ @nrfconnect/ncs-low-level-test /tests/subsys/swo/ @nrfconnect/ncs-low-level-test /tests/subsys/usb/negotiated_speed/ @nrfconnect/ncs-low-level-test @@ -971,7 +972,7 @@ /tests/zephyr/drivers/watchdog/ @nrfconnect/ncs-low-level-test /tests/zephyr/kernel/timer/timer_behavior/ @nrfconnect/ncs-low-level-test /tests/zephyr/subsys/secure_storage/ @nrfconnect/ncs-aegir -/tests/zephyr/subsys/settings/performance/ @nrfconnect/ncs-pluto @rghaddab +/tests/zephyr/subsys/settings/performance/ @nrfconnect/ncs-eris @rghaddab /tests/benchmarks/multicore/idle/*.rst @nrfconnect/ncs-si-bluebagel-doc /tests/benchmarks/multicore/idle_gpio/*.rst @nrfconnect/ncs-si-bluebagel-doc diff --git a/applications/matter_bridge/Kconfig b/applications/matter_bridge/Kconfig index c5d19e92783d..ff1bf2167597 100644 --- a/applications/matter_bridge/Kconfig +++ b/applications/matter_bridge/Kconfig @@ -176,6 +176,9 @@ endchoice endif # OPENTHREAD +config CHIP_WIFI + default y if BOARD_NRF7002DK_NRF5340_CPUAPP || SHIELD_NRF7002EK + # Dummy Kconfig just to select experimental for some of the configurations. config BRIDGE_EXPERIMENTAL bool diff --git a/applications/matter_weather_station/Kconfig b/applications/matter_weather_station/Kconfig index 8335b3374f66..a121ae645b3c 100644 --- a/applications/matter_weather_station/Kconfig +++ b/applications/matter_weather_station/Kconfig @@ -32,12 +32,15 @@ config CHIP_ENABLE_ICD_SUPPORT endif # OPENTHREAD -if CHIP_WIFI +if SHIELD_NRF7002EB + +config CHIP_WIFI + default y config NRF_WIFI_LOW_POWER default y -endif # CHIP_WIFI +endif # SHIELD_NRF7002EB source "$(ZEPHYR_CONNECTEDHOMEIP_MODULE_DIR)/config/nrfconnect/chip-module/Kconfig.features" source "$(ZEPHYR_CONNECTEDHOMEIP_MODULE_DIR)/config/nrfconnect/chip-module/Kconfig.defaults" diff --git a/applications/nrf5340_audio/broadcast_source/overlay-broadcast_source.conf b/applications/nrf5340_audio/broadcast_source/overlay-broadcast_source.conf index ecf85eda245e..2f60f0510e03 100644 --- a/applications/nrf5340_audio/broadcast_source/overlay-broadcast_source.conf +++ b/applications/nrf5340_audio/broadcast_source/overlay-broadcast_source.conf @@ -26,3 +26,7 @@ CONFIG_BT_EXT_ADV_MAX_ADV_SET=2 CONFIG_LC3_ENC_CHAN_MAX=2 CONFIG_AUDIO_ENCODE_CHANNELS_MAX=2 CONFIG_ENTROPY_GENERATOR=y + + +CONFIG_DEVICE_LOCATION_SET_COMPILE_TIME=y +CONFIG_DEVICE_LOCATION_AT_COMPILE_TIME=3 diff --git a/applications/nrf5340_audio/src/audio/Kconfig b/applications/nrf5340_audio/src/audio/Kconfig index 7fdbfe948565..26c40bce58ca 100644 --- a/applications/nrf5340_audio/src/audio/Kconfig +++ b/applications/nrf5340_audio/src/audio/Kconfig @@ -124,16 +124,22 @@ config AUDIO_ENCODE_CHANNELS_MAX Maximum number of audio channels that can be encoded. This number may have a large impact on memory and CPU usage. -config AUDIO_INPUT_CHANNELS_MAX - int "Maximum number of simoultaneus audio input channels" - default 2 +config AUDIO_INPUT_CHANNELS + int "Maximum number of simultaneous audio input channels" + default 2 if AUDIO_SOURCE_I2S + default 2 if AUDIO_SOURCE_USB + default 1 + range 1 2 help Maximum number of audio channels that can be physically input. This is dependent on the HW itself. -config AUDIO_OUTPUT_CHANNELS_MAX - int "Maximum number of simoultaneus audio output channels" - default 2 +config AUDIO_OUTPUT_CHANNELS + int "Maximum number of simultaneous audio output channels" + default 2 if AUDIO_SOURCE_I2S + default 2 if AUDIO_SOURCE_USB + default 1 + range 1 2 help Maximum number of audio channels that can be physically output. This is dependent on the HW itself. diff --git a/applications/nrf5340_audio/src/audio/audio_datapath.c b/applications/nrf5340_audio/src/audio/audio_datapath.c index 7cca9f12eeb2..bf5f48559113 100644 --- a/applications/nrf5340_audio/src/audio/audio_datapath.c +++ b/applications/nrf5340_audio/src/audio/audio_datapath.c @@ -41,13 +41,15 @@ LOG_MODULE_REGISTER(audio_datapath, CONFIG_AUDIO_DATAPATH_LOG_LEVEL); #define BLK_PERIOD_US 1000 /* Total sample FIFO period in microseconds */ -#define FIFO_SMPL_PERIOD_US (CONFIG_AUDIO_MAX_PRES_DLY_US * 2) +#define FIFO_CHANNELS_MAX MAX(CONFIG_AUDIO_INPUT_CHANNELS, CONFIG_AUDIO_OUTPUT_CHANNELS) +#define FIFO_SMPL_PERIOD_US (CONFIG_AUDIO_MAX_PRES_DLY_US * FIFO_CHANNELS_MAX) #define FIFO_NUM_BLKS NUM_BLKS(FIFO_SMPL_PERIOD_US) -#define MAX_FIFO_SIZE (FIFO_NUM_BLKS * BLK_SIZE_SAMPLES(CONFIG_AUDIO_SAMPLE_RATE_HZ) * 2) +#define MAX_FIFO_SIZE \ + (FIFO_NUM_BLKS * BLK_SIZE_SAMPLES(CONFIG_AUDIO_SAMPLE_RATE_HZ) * FIFO_CHANNELS_MAX) /* Number of audio blocks given a duration */ #define NUM_BLKS(d) ((d) / BLK_PERIOD_US) -/* Single audio block size in number of samples (stereo) */ +/* Single audio block size in number of samples */ /* clang-format off */ #define BLK_SIZE_SAMPLES(r) (((r)*BLK_PERIOD_US) / 1000000) /* clang-format on */ @@ -56,17 +58,23 @@ LOG_MODULE_REGISTER(audio_datapath, CONFIG_AUDIO_DATAPATH_LOG_LEVEL); /* Decrement sample FIFO index by one block */ #define PREV_IDX(i) (((i) > 0) ? ((i) - 1) : (FIFO_NUM_BLKS - 1)) -#define NUM_BLKS_IN_FRAME NUM_BLKS(CONFIG_AUDIO_FRAME_DURATION_US) -#define BLK_MONO_NUM_SAMPS BLK_SIZE_SAMPLES(CONFIG_AUDIO_SAMPLE_RATE_HZ) -#define BLK_STEREO_NUM_SAMPS (BLK_MONO_NUM_SAMPS * 2) +#define NUM_BLKS_IN_FRAME NUM_BLKS(CONFIG_AUDIO_FRAME_DURATION_US) +#define BLK_MONO_NUM_SAMPS BLK_SIZE_SAMPLES(CONFIG_AUDIO_SAMPLE_RATE_HZ) +#define BLK_MULTI_CHAN_NUM_SAMPS (BLK_MONO_NUM_SAMPS * CONFIG_AUDIO_OUTPUT_CHANNELS) /* Number of octets in a single audio block */ -#define BLK_MONO_SIZE_OCTETS (BLK_MONO_NUM_SAMPS * CONFIG_AUDIO_BIT_DEPTH_OCTETS) -#define BLK_STEREO_SIZE_OCTETS (BLK_MONO_SIZE_OCTETS * 2) +#define BLK_MONO_SIZE_OCTETS (BLK_MONO_NUM_SAMPS * CONFIG_AUDIO_BIT_DEPTH_OCTETS) +#define BLK_MULTI_CHAN_SIZE_OCTETS (BLK_MULTI_CHAN_NUM_SAMPS * CONFIG_AUDIO_BIT_DEPTH_OCTETS) + +/* Number of decoder buffers. */ +#define FIFO_NUM_BUFS 2 + /* How many function calls before moving on with drift compensation */ #define DRIFT_COMP_WAITING_CNT (DRIFT_MEAS_PERIOD_US / BLK_PERIOD_US) /* How much data to be collected before moving on with presentation compensation */ #define PRES_COMP_NUM_DATA_PTS (DRIFT_MEAS_PERIOD_US / CONFIG_AUDIO_FRAME_DURATION_US) -/* How many microseconds two timestamps can be apart before they are considered non-consecutive */ +/* How many microseconds two timestamps can be apart before they are considered + * non-consecutive + */ #define CONSECUTIVE_TS_LIMIT_US \ (CONFIG_AUDIO_FRAME_DURATION_US + (CONFIG_AUDIO_FRAME_DURATION_US / 2)) @@ -92,7 +100,9 @@ LOG_MODULE_REGISTER(audio_datapath, CONFIG_AUDIO_DATAPATH_LOG_LEVEL); /* How often to print under-run warning */ #define LOG_INTERVAL_BLKS 5000 -NET_BUF_POOL_FIXED_DEFINE(pool_i2s_rx, FIFO_NUM_BLKS, BLK_STEREO_SIZE_OCTETS, +NET_BUF_POOL_FIXED_DEFINE(pool_i2s_rx, FIFO_NUM_BLKS, BLK_MULTI_CHAN_SIZE_OCTETS, + sizeof(struct audio_metadata), NULL); +NET_BUF_POOL_FIXED_DEFINE(audio_pcm_pool, FIFO_NUM_BUFS, PCM_NUM_BYTES_MULTI_CHAN, sizeof(struct audio_metadata), NULL); enum drift_comp_state { @@ -180,6 +190,17 @@ static int filled_blocks_get(void) } } +static struct audio_metadata i2s_meta = {.data_coding = PCM, + .data_len_us = 1000, + .sample_rate_hz = CONFIG_AUDIO_SAMPLE_RATE_HZ, + .bits_per_sample = CONFIG_AUDIO_BIT_DEPTH_BITS, + .carried_bits_per_sample = CONFIG_AUDIO_BIT_DEPTH_BITS, + .bytes_per_location = BLK_MONO_SIZE_OCTETS, + .interleaved = true, + .locations = BT_AUDIO_LOCATION_FRONT_LEFT | + BT_AUDIO_LOCATION_FRONT_RIGHT, + .bad_data = 0}; + static bool tone_active; /* Buffer which can hold max 1 period test tone at 100 Hz */ static uint16_t test_tone_buf[CONFIG_AUDIO_SAMPLE_RATE_HZ / 100]; @@ -201,7 +222,9 @@ static int32_t err_us_calculate(uint32_t sdu_ref_us, uint32_t frame_start_ts_us) int64_t total_err = ((int64_t)sdu_ref_us - (int64_t)frame_start_ts_us); - /* Store sign for later use, since remainder operation is undefined for negatives */ + /* Store sign for later use, since remainder operation is undefined for + * negatives + */ if (total_err < 0) { err_neg = true; total_err *= -1; @@ -253,8 +276,8 @@ static void drift_comp_state_set(enum drift_comp_state new_state) static inline void audio_datapath_drift_compensation(uint32_t frame_start_ts_us) { if (CONFIG_AUDIO_DEV == HEADSET) { - /** For headsets we do not use the timestamp gotten from hci_tx_sync_get to adjust - * for drift + /** For headsets we do not use the timestamp gotten from hci_tx_sync_get to + * adjust for drift */ ctrl_blk.prev_drift_sdu_ref_us = ctrl_blk.prev_pres_sdu_ref_us; } @@ -373,8 +396,8 @@ static void pres_comp_state_set(enum pres_comp_state new_state) * * @param recv_frame_ts_us Timestamp of when frame was received. * @param sdu_ref_us ISO timestamp reference from Bluetooth LE controller. - * @param sdu_ref_not_consecutive True if sdu_ref_us and the previous sdu_ref_us - * originate from non-consecutive frames. + * @param sdu_ref_not_consecutive True if sdu_ref_us and the previous sdu_ref_us originate + * from non-consecutive frames. */ static void audio_datapath_presentation_compensation(uint32_t recv_frame_ts_us, uint32_t sdu_ref_us, bool sdu_ref_not_consecutive) @@ -437,8 +460,8 @@ static void audio_datapath_presentation_compensation(uint32_t recv_frame_ts_us, case PRES_STATE_LOCKED: { /* * Presentation delay compensation moves into PRES_STATE_WAIT if sdu_ref_us - * and the previous sdu_ref_us originate from non-consecutive frames, or into - * PRES_STATE_INIT if drift compensation unlocks. + * and the previous sdu_ref_us originate from non-consecutive frames, or + * into PRES_STATE_INIT if drift compensation unlocks. */ break; @@ -480,8 +503,9 @@ static void audio_datapath_presentation_compensation(uint32_t recv_frame_ts_us, /* Increase presentation delay */ for (int i = 0; i < pres_adj_blks; i++) { /* Mute audio block */ - memset(&ctrl_blk.out.fifo[ctrl_blk.out.prod_blk_idx * BLK_STEREO_NUM_SAMPS], - 0, BLK_STEREO_SIZE_OCTETS); + memset(&ctrl_blk.out + .fifo[ctrl_blk.out.prod_blk_idx * BLK_MULTI_CHAN_NUM_SAMPS], + 0, BLK_MULTI_CHAN_SIZE_OCTETS); /* Record producer block start reference */ ctrl_blk.out.prod_blk_ts[ctrl_blk.out.prod_blk_idx] = @@ -560,7 +584,7 @@ static void tone_mix(uint8_t *tx_buf) test_tone_size, &finite_pos); ERR_CHK(ret); - ret = pcm_mix(tx_buf, BLK_STEREO_SIZE_OCTETS, tone_buf_continuous, BLK_MONO_SIZE_OCTETS, + ret = pcm_mix(tx_buf, BLK_MULTI_CHAN_SIZE_OCTETS, tone_buf_continuous, BLK_MONO_SIZE_OCTETS, B_MONO_INTO_A_STEREO_L); ERR_CHK(ret); } @@ -569,8 +593,8 @@ static void tone_mix(uint8_t *tx_buf) * Used interchangeably by I2S. */ static struct { - uint8_t __aligned(WB_UP(1)) buf_0[BLK_STEREO_SIZE_OCTETS]; - uint8_t __aligned(WB_UP(1)) buf_1[BLK_STEREO_SIZE_OCTETS]; + uint8_t __aligned(WB_UP(1)) buf_0[BLK_MULTI_CHAN_SIZE_OCTETS]; + uint8_t __aligned(WB_UP(1)) buf_1[BLK_MULTI_CHAN_SIZE_OCTETS]; bool buf_0_in_use; bool buf_1_in_use; } alt; @@ -622,14 +646,6 @@ static void alt_buffer_free_both(void) alt.buf_1_in_use = false; } -static struct audio_metadata i2s_meta = {.data_coding = PCM, - .data_len_us = 1000, - .sample_rate_hz = CONFIG_AUDIO_SAMPLE_RATE_HZ, - .bits_per_sample = CONFIG_AUDIO_BIT_DEPTH_BITS, - .carried_bits_per_sample = CONFIG_AUDIO_BIT_DEPTH_BITS, - .locations = BT_AUDIO_LOCATION_FRONT_LEFT | - BT_AUDIO_LOCATION_FRONT_RIGHT, - .bad_data = false}; /* * This handler function is called every time I2S needs new buffers for * TX and RX data. @@ -677,7 +693,7 @@ static void audio_datapath_i2s_blk_complete(uint32_t frame_start_ts_us, uint32_t } tx_buf = (uint8_t *)&ctrl_blk.out - .fifo[next_out_blk_idx * BLK_STEREO_NUM_SAMPS]; + .fifo[next_out_blk_idx * BLK_MULTI_CHAN_NUM_SAMPS]; } else { if (stream_state_get() == STATE_STREAMING) { @@ -697,7 +713,7 @@ static void audio_datapath_i2s_blk_complete(uint32_t frame_start_ts_us, uint32_t ret = alt_buffer_get((void **)&tx_buf); ERR_CHK(ret); - memset(tx_buf, 0, BLK_STEREO_SIZE_OCTETS); + memset(tx_buf, 0, BLK_MULTI_CHAN_SIZE_OCTETS); } if (tone_active) { @@ -719,6 +735,7 @@ static void audio_datapath_i2s_blk_complete(uint32_t frame_start_ts_us, uint32_t /* If RX FIFO is filled up */ num_overruns++; struct net_buf *stale_i2s_data; + ret = k_msgq_get(ctrl_blk.in.audio_q, (void *)&stale_i2s_data, K_NO_WAIT); ERR_CHK(ret); /* Discard data */ @@ -737,11 +754,11 @@ static void audio_datapath_i2s_blk_complete(uint32_t frame_start_ts_us, uint32_t } /* Store RX buffer in net_buf */ - net_buf_add_mem(rx_audio_block, rx_buf_released, BLK_STEREO_SIZE_OCTETS); + net_buf_add_mem(rx_audio_block, rx_buf_released, BLK_MULTI_CHAN_SIZE_OCTETS); /* Store I2S related metadata */ - struct audio_metadata *meta = net_buf_user_data(rx_audio_block); - *meta = i2s_meta; + struct audio_metadata *meta_rx = net_buf_user_data(rx_audio_block); + *meta_rx = i2s_meta; ret = k_msgq_put(ctrl_blk.in.audio_q, (void *)&rx_audio_block, K_NO_WAIT); ERR_CHK_MSG(ret, "Unable to put RX audio block into queue"); @@ -763,18 +780,18 @@ static void audio_datapath_i2s_start(void) uint8_t *tx_buf_1 = NULL; /* Buffers used for I2S RX. Used interchangeably by I2S. */ - static uint32_t rx_buf_0[BLK_STEREO_SIZE_OCTETS]; - static uint32_t rx_buf_1[BLK_STEREO_SIZE_OCTETS]; + static uint32_t rx_buf_0[BLK_MULTI_CHAN_SIZE_OCTETS]; + static uint32_t rx_buf_1[BLK_MULTI_CHAN_SIZE_OCTETS]; /* TX */ if (IS_ENABLED(CONFIG_STREAM_BIDIRECTIONAL) || (CONFIG_AUDIO_DEV == HEADSET)) { ctrl_blk.out.cons_blk_idx = PREV_IDX(ctrl_blk.out.cons_blk_idx); tx_buf_0 = (uint8_t *)&ctrl_blk.out - .fifo[ctrl_blk.out.cons_blk_idx * BLK_STEREO_NUM_SAMPS]; + .fifo[ctrl_blk.out.cons_blk_idx * BLK_MULTI_CHAN_NUM_SAMPS]; ctrl_blk.out.cons_blk_idx = PREV_IDX(ctrl_blk.out.cons_blk_idx); tx_buf_1 = (uint8_t *)&ctrl_blk.out - .fifo[ctrl_blk.out.cons_blk_idx * BLK_STEREO_NUM_SAMPS]; + .fifo[ctrl_blk.out.cons_blk_idx * BLK_MULTI_CHAN_NUM_SAMPS]; } /* Start I2S */ @@ -791,8 +808,8 @@ static void audio_datapath_i2s_stop(void) /** * @brief Adjust timing to make sure audio data is sent just in time for Bluetooth LE event. * - * @note The time from last anchor point is checked and then blocks of 1 ms can be dropped - * to allow the sending of encoded data to be sent just before the connection interval + * @note The time from last anchor point is checked and then blocks of 1 ms can be dropped to + * allow the sending of encoded data to be sent just before the connection interval * opens up. This is done to reduce overall latency. * * @param[in] tx_sync_ts_us The timestamp from get_tx_sync. @@ -808,9 +825,10 @@ static void audio_datapath_just_in_time_check_and_adjust(uint32_t tx_sync_ts_us, diff = (int64_t)tx_sync_ts_us - curr_ts_us; /* - * The diff should always be positive. If diff is a large negative number, it is likely - * that wrapping has occurred. A small negative value however, may point to the application - * sending data too late, and we need to drop data to get back in sync with the controller. + * The diff should always be positive. If diff is a large negative number, it + * is likely that wrapping has occurred. A small negative value however, may + * point to the application sending data too late, and we need to drop data to + * get back in sync with the controller. */ if (diff < -((int64_t)UINT32_MAX / 2)) { LOG_DBG("Timestamp wrap. diff: %lld", diff); @@ -842,11 +860,11 @@ static void audio_datapath_just_in_time_check_and_adjust(uint32_t tx_sync_ts_us, /** * @brief Update sdu_ref_us so that drift compensation can work correctly. * - * @note This function is only valid for gateway using I2S as audio source - * and unidirectional audio stream (gateway to one or more headsets). + * @note This function is only valid for gateway using I2S as audio + * source and unidirectional audio stream (gateway to one or more headsets). * - * @param sdu_ref_us ISO timestamp reference from Bluetooth LE controller. - * @param adjust Indicate if the sdu_ref should be used to adjust timing. + * @param sdu_ref_us ISO timestamp reference from Bluetooth LE controller. + * @param adjust Indicate if the sdu_ref should be used to adjust timing. */ static void audio_datapath_sdu_ref_update(const struct zbus_channel *chan) { @@ -896,11 +914,11 @@ void audio_datapath_pres_delay_us_get(uint32_t *delay_us) *delay_us = ctrl_blk.pres_comp.pres_delay_us; } -void audio_datapath_stream_out(struct net_buf *audio_frame) +void audio_datapath_stream_out(struct net_buf *audio_frame_in) { - /* Upon first received audio frame, the delta will be invalid (as there is no previous value - * to compare it to). Hence, this function only prints LOG_ERR if there are consecutive - * errors. + /* Upon first received audio frame, the delta will be invalid (as there is no + * previous value to compare it to). Hence, this function only prints LOG_ERR + * if there are consecutive errors. */ static uint32_t consec_invalid_ts_deltas; bool sdu_ref_not_consecutive = false; @@ -910,23 +928,24 @@ void audio_datapath_stream_out(struct net_buf *audio_frame) return; } - if (audio_frame == NULL) { - LOG_ERR("Buffer pointer is NULL"); + if (audio_frame_in == NULL) { + LOG_ERR("Audio frame is NULL"); + return; } /*** Check incoming data ***/ - struct audio_metadata *meta = net_buf_user_data(audio_frame); + struct audio_metadata *meta_in = net_buf_user_data(audio_frame_in); - if (meta->ref_ts_us == ctrl_blk.prev_pres_sdu_ref_us && meta->ref_ts_us != 0) { - LOG_ERR("Duplicate sdu_ref_us (%d) - Dropping audio frame", meta->ref_ts_us); + if (meta_in->ref_ts_us == ctrl_blk.prev_pres_sdu_ref_us && meta_in->ref_ts_us != 0) { + LOG_WRN("Duplicate sdu_ref_us (%d) - Dropping audio frame", meta_in->ref_ts_us); return; } - uint32_t sdu_ref_delta_us = meta->ref_ts_us - ctrl_blk.prev_pres_sdu_ref_us; + uint32_t sdu_ref_delta_us = meta_in->ref_ts_us - ctrl_blk.prev_pres_sdu_ref_us; - if (meta->ref_ts_us == 0 && ctrl_blk.prev_pres_sdu_ref_us == 0) { + if (meta_in->ref_ts_us == 0 && ctrl_blk.prev_pres_sdu_ref_us == 0) { /* Timestamp not received yet */ - ctrl_blk.prev_pres_sdu_ref_us = meta->ref_ts_us; + ctrl_blk.prev_pres_sdu_ref_us = meta_in->ref_ts_us; sdu_ref_not_consecutive = true; } else if (sdu_ref_delta_us > CONSECUTIVE_TS_LIMIT_US) { @@ -940,30 +959,31 @@ void audio_datapath_stream_out(struct net_buf *audio_frame) } sdu_ref_not_consecutive = true; - ctrl_blk.prev_pres_sdu_ref_us = meta->ref_ts_us; + ctrl_blk.prev_pres_sdu_ref_us = meta_in->ref_ts_us; consec_invalid_ts_deltas++; } else if (!IN_RANGE(sdu_ref_delta_us, CONFIG_AUDIO_FRAME_DURATION_US - SDU_REF_CH_DELTA_MAX_US, CONFIG_AUDIO_FRAME_DURATION_US + SDU_REF_CH_DELTA_MAX_US)) { - /* If timestamp is consecutive but has invalid delta: Estimate the timestamp */ + /* If timestamp is consecutive but has invalid delta: Estimate the timestamp + */ if (consec_invalid_ts_deltas) { - LOG_ERR("Invalid sdu_ref_us delta (%d) meta->ref_ts_us %d us. " + LOG_ERR("Invalid sdu_ref_us delta (%d) meta_in->ref_ts_us %d us. " "Estimating.", - sdu_ref_delta_us, meta->ref_ts_us); + sdu_ref_delta_us, meta_in->ref_ts_us); } else { - LOG_DBG("Invalid sdu_ref_us delta (%d) meta->ref_ts_us %d us. " + LOG_DBG("Invalid sdu_ref_us delta (%d) meta_in->ref_ts_us %d us. " "Estimating.", - sdu_ref_delta_us, meta->ref_ts_us); + sdu_ref_delta_us, meta_in->ref_ts_us); } /* Estimate ref_ts_us. * If the SDU ref was estimated, we don't update the previous reference with * the estimated value. This is to avoid an infinite loop of estimations. */ - uint32_t ref_ts_temp_us = meta->ref_ts_us; + uint32_t ref_ts_temp_us = meta_in->ref_ts_us; - meta->ref_ts_us = ctrl_blk.prev_pres_sdu_ref_us + CONFIG_AUDIO_FRAME_DURATION_US; + meta_in->ref_ts_us = ctrl_blk.prev_pres_sdu_ref_us + CONFIG_AUDIO_FRAME_DURATION_US; ctrl_blk.prev_pres_sdu_ref_us = ref_ts_temp_us; consec_invalid_ts_deltas++; @@ -971,36 +991,53 @@ void audio_datapath_stream_out(struct net_buf *audio_frame) /* The new timestamp is valid. It is consecutive and * within the expected range compared to the last timestamp. */ - ctrl_blk.prev_pres_sdu_ref_us = meta->ref_ts_us; + ctrl_blk.prev_pres_sdu_ref_us = meta_in->ref_ts_us; consec_invalid_ts_deltas = 0; } /*** Presentation compensation ***/ if (ctrl_blk.pres_comp.enabled) { - audio_datapath_presentation_compensation(meta->data_rx_ts_us, meta->ref_ts_us, + audio_datapath_presentation_compensation(meta_in->data_rx_ts_us, meta_in->ref_ts_us, sdu_ref_not_consecutive); } /*** Decode ***/ int ret; - size_t pcm_size; + struct net_buf *audio_frame_out = net_buf_alloc(&audio_pcm_pool, K_NO_WAIT); - ret = sw_codec_decode(audio_frame, &ctrl_blk.decoded_data, &pcm_size); + if (audio_frame_out == NULL) { + LOG_ERR("Out of I2S PCM TX buffers."); + return; + } + + /* Output I2S related metadata */ + struct audio_metadata *meta_out = net_buf_user_data(audio_frame_out); + *meta_out = i2s_meta; + meta_out->data_len_us = meta_in->data_len_us; + meta_out->ref_ts_us = meta_in->ref_ts_us; + meta_out->data_rx_ts_us = meta_in->data_rx_ts_us; + meta_out->bad_data = meta_in->bad_data; + + ret = sw_codec_decode(audio_frame_in, audio_frame_out); if (ret) { + net_buf_unref(audio_frame_out); LOG_WRN("SW codec decode error: %d", ret); + return; } if (IS_ENABLED(CONFIG_SD_CARD_PLAYBACK)) { if (sd_card_playback_is_active()) { - sd_card_playback_mix_with_stream(ctrl_blk.decoded_data, pcm_size); + sd_card_playback_mix_with_stream((void *const)audio_frame_out->data, + audio_frame_out->len); } } - if (pcm_size != (BLK_STEREO_SIZE_OCTETS * NUM_BLKS_IN_FRAME)) { - LOG_WRN("Decoded audio has wrong size: %d. Expected: %d", pcm_size, - (BLK_STEREO_SIZE_OCTETS * NUM_BLKS_IN_FRAME)); + if (audio_frame_out->len != PCM_NUM_BYTES_MONO * CONFIG_AUDIO_OUTPUT_CHANNELS) { + LOG_WRN("Decoded audio has wrong size: %d. Expected: %d", audio_frame_out->len, + PCM_NUM_BYTES_MONO * CONFIG_AUDIO_OUTPUT_CHANNELS); /* Discard frame */ + net_buf_unref(audio_frame_out); return; } @@ -1011,6 +1048,7 @@ void audio_datapath_stream_out(struct net_buf *audio_frame) LOG_WRN("Output audio stream overrun - Discarding audio frame"); /* Discard frame to allow consumer to catch up */ + net_buf_unref(audio_frame_out); return; } @@ -1018,22 +1056,26 @@ void audio_datapath_stream_out(struct net_buf *audio_frame) for (uint32_t i = 0; i < NUM_BLKS_IN_FRAME; i++) { if (IS_ENABLED(CONFIG_AUDIO_BIT_DEPTH_16)) { - memcpy(&ctrl_blk.out.fifo[out_blk_idx * BLK_STEREO_NUM_SAMPS], - &((int16_t *)ctrl_blk.decoded_data)[i * BLK_STEREO_NUM_SAMPS], - BLK_STEREO_SIZE_OCTETS); + memcpy(&ctrl_blk.out.fifo[out_blk_idx * BLK_MULTI_CHAN_NUM_SAMPS], + (int16_t *)audio_frame_out->data, BLK_MULTI_CHAN_SIZE_OCTETS); } else if (IS_ENABLED(CONFIG_AUDIO_BIT_DEPTH_32)) { - memcpy(&ctrl_blk.out.fifo[out_blk_idx * BLK_STEREO_NUM_SAMPS], - &((int32_t *)ctrl_blk.decoded_data)[i * BLK_STEREO_NUM_SAMPS], - BLK_STEREO_SIZE_OCTETS); + memcpy(&ctrl_blk.out.fifo[out_blk_idx * BLK_MULTI_CHAN_NUM_SAMPS], + (int32_t *)audio_frame_out->data, BLK_MULTI_CHAN_SIZE_OCTETS); } + /* Remove consumed data from net buffer */ + net_buf_pull(audio_frame_out, BLK_MULTI_CHAN_SIZE_OCTETS); + /* Record producer block start reference */ - ctrl_blk.out.prod_blk_ts[out_blk_idx] = meta->data_rx_ts_us + (i * BLK_PERIOD_US); + ctrl_blk.out.prod_blk_ts[out_blk_idx] = + meta_in->data_rx_ts_us + (i * BLK_PERIOD_US); out_blk_idx = NEXT_IDX(out_blk_idx); } ctrl_blk.out.prod_blk_idx = out_blk_idx; + + net_buf_unref(audio_frame_out); } int audio_datapath_start(struct k_msgq *audio_q_rx) @@ -1086,9 +1128,9 @@ int audio_datapath_init(void) ctrl_blk.pres_comp.enabled = true; if (IS_ENABLED(CONFIG_STREAM_BIDIRECTIONAL) && (CONFIG_AUDIO_DEV == GATEWAY)) { - /* Disable presentation compensation feature for microphone return on gateway, - * since there's only one stream output from gateway for now, so no need to - * qhave presentation compensation. + /* Disable presentation compensation feature for microphone return on + * gateway, since there's only one stream output from gateway for now, so no + * need to qhave presentation compensation. */ ctrl_blk.pres_comp.enabled = false; } else { @@ -1108,9 +1150,8 @@ static int cmd_i2s_tone_play(const struct shell *shell, size_t argc, const char float amplitude; if (argc != 4) { - shell_error( - shell, - "3 arguments (freq [Hz], dur [ms], and amplitude [0-1.0] must be provided"); + shell_error(shell, "3 arguments (freq [Hz], dur [ms], and amplitude " + "[0-1.0] must be provided"); return -EINVAL; } diff --git a/applications/nrf5340_audio/src/audio/audio_datapath.h b/applications/nrf5340_audio/src/audio/audio_datapath.h index 5b6fa44801d0..0a6fd43e28e0 100644 --- a/applications/nrf5340_audio/src/audio/audio_datapath.h +++ b/applications/nrf5340_audio/src/audio/audio_datapath.h @@ -65,9 +65,9 @@ void audio_datapath_pres_delay_us_get(uint32_t *delay_us); * and processed before being outputted over I2S. The audio is synchronized * using sdu_ref_us. * - * @param audio_frame Pointer to the audio buffer. + * @param audio_frame_in Pointer to the coded audio input buffer. */ -void audio_datapath_stream_out(struct net_buf *audio_frame); +void audio_datapath_stream_out(struct net_buf *audio_frame_in); /** * @brief Start the audio datapath module. diff --git a/applications/nrf5340_audio/src/audio/audio_system.c b/applications/nrf5340_audio/src/audio/audio_system.c index 3fe921267c11..a3b4b1d29a40 100644 --- a/applications/nrf5340_audio/src/audio/audio_system.c +++ b/applications/nrf5340_audio/src/audio/audio_system.c @@ -26,6 +26,12 @@ LOG_MODULE_REGISTER(audio_system, CONFIG_AUDIO_SYSTEM_LOG_LEVEL); #define FIFO_TX_BLOCK_COUNT (CONFIG_FIFO_FRAME_SPLIT_NUM * CONFIG_FIFO_TX_FRAME_COUNT) #define FIFO_RX_BLOCK_COUNT (CONFIG_FIFO_FRAME_SPLIT_NUM * CONFIG_FIFO_RX_FRAME_COUNT) +/* Size these to fit the use case as part of optimization (e.g. increase decoder pool when it is + * wrapped in a thread). + */ +#define FIFO_ENC_POOL_BLK_COUNT 2 +#define FIFO_DEC_POOL_BLK_COUNT 1 + #define DEBUG_INTERVAL_NUM 1000 #define TEST_TONE_BASE_FREQ_HZ 1000 @@ -36,7 +42,11 @@ K_MSGQ_DEFINE(audio_q_rx, sizeof(struct net_buf *), FIFO_RX_BLOCK_COUNT, sizeof( NET_BUF_POOL_FIXED_DEFINE(audio_q_rx_pool, FIFO_RX_BLOCK_COUNT, FRAME_SIZE_BYTES, sizeof(struct audio_metadata), NULL); -NET_BUF_POOL_FIXED_DEFINE(audio_q_tx_pool, FIFO_TX_BLOCK_COUNT, USB_BLOCK_SIZE_STEREO, +NET_BUF_POOL_FIXED_DEFINE(audio_q_enc_pool, FIFO_ENC_POOL_BLK_COUNT, ENC_MULTI_CHAN_MAX_FRAME_SIZE, + sizeof(struct audio_metadata), NULL); +NET_BUF_POOL_FIXED_DEFINE(audio_q_dec_pool, FIFO_DEC_POOL_BLK_COUNT, PCM_NUM_BYTES_MULTI_CHAN, + sizeof(struct audio_metadata), NULL); +NET_BUF_POOL_FIXED_DEFINE(audio_q_tx_pool, FIFO_TX_BLOCK_COUNT, USB_BLOCK_SIZE_MULTI_CHAN, sizeof(struct audio_metadata), NULL); static K_SEM_DEFINE(sem_encoder_start, 0, 1); @@ -54,7 +64,21 @@ static struct sw_codec_config sw_codec_cfg; static int16_t test_tone_buf[CONFIG_AUDIO_SAMPLE_RATE_HZ / 1000]; static size_t test_tone_size; -static bool sample_rate_valid(uint32_t sample_rate_hz) +/* The meta data for the decoder and the expected format of the USB. + * An improvement would be to have the USB convert incoming data to the format it requires. + */ +static struct audio_metadata decoder_meta = {.data_coding = PCM, + .data_len_us = CONFIG_AUDIO_FRAME_DURATION_US, + .sample_rate_hz = CONFIG_AUDIO_SAMPLE_RATE_48000_HZ, + .bits_per_sample = CONFIG_AUDIO_BIT_DEPTH_BITS, + .carried_bits_per_sample = CONFIG_AUDIO_BIT_DEPTH_BITS, + .bytes_per_location = PCM_NUM_BYTES_MONO, + .interleaved = true, + .locations = BT_AUDIO_LOCATION_FRONT_LEFT | + BT_AUDIO_LOCATION_FRONT_RIGHT, + .bad_data = 0}; + +bool sample_rate_valid(uint32_t sample_rate_hz) { if (sample_rate_hz == 16000 || sample_rate_hz == 24000 || sample_rate_hz == 48000) { return true; @@ -71,20 +95,28 @@ static void audio_gateway_configure(void) ERR_CHK_MSG(-EINVAL, "No codec selected"); } -#if (CONFIG_STREAM_BIDIRECTIONAL) - sw_codec_cfg.decoder.audio_ch = DEVICE_LOCATION_DEFAULT; - sw_codec_cfg.decoder.num_ch = 1; - sw_codec_cfg.decoder.channel_mode = SW_CODEC_MONO; -#endif /* (CONFIG_STREAM_BIDIRECTIONAL) */ + if (IS_ENABLED(CONFIG_STREAM_BIDIRECTIONAL)) { + sw_codec_cfg.decoder.audio_loc = BT_AUDIO_LOCATION_MONO_AUDIO; + sw_codec_cfg.decoder.num_ch = 1; + sw_codec_cfg.decoder.channel_mode = SW_CODEC_MONO; + } + + device_location_get(&sw_codec_cfg.encoder.audio_loc); if (IS_ENABLED(CONFIG_MONO_TO_ALL_RECEIVERS)) { + sw_codec_cfg.encoder.audio_loc = BT_AUDIO_LOCATION_MONO_AUDIO; + } + + if (sw_codec_cfg.encoder.audio_loc == BT_AUDIO_LOCATION_MONO_AUDIO || + (POPCOUNT(sw_codec_cfg.encoder.audio_loc) == 1)) { sw_codec_cfg.encoder.num_ch = 1; - } else { - sw_codec_cfg.encoder.num_ch = 2; + sw_codec_cfg.encoder.channel_mode = SW_CODEC_MONO; + + return; } - sw_codec_cfg.encoder.channel_mode = - (sw_codec_cfg.encoder.num_ch == 1) ? SW_CODEC_MONO : SW_CODEC_STEREO; + sw_codec_cfg.encoder.num_ch = POPCOUNT(sw_codec_cfg.encoder.audio_loc); + sw_codec_cfg.encoder.channel_mode = SW_CODEC_MULTICHANNEL; } static void audio_headset_configure(void) @@ -95,31 +127,30 @@ static void audio_headset_configure(void) ERR_CHK_MSG(-EINVAL, "No codec selected"); } -#if (CONFIG_STREAM_BIDIRECTIONAL) - sw_codec_cfg.encoder.audio_ch = 0; - sw_codec_cfg.encoder.num_ch = 1; - sw_codec_cfg.encoder.channel_mode = SW_CODEC_MONO; -#endif /* (CONFIG_STREAM_BIDIRECTIONAL) */ - - enum bt_audio_location device_location; + if (IS_ENABLED(CONFIG_STREAM_BIDIRECTIONAL)) { + sw_codec_cfg.encoder.audio_loc = BT_AUDIO_LOCATION_MONO_AUDIO; + sw_codec_cfg.encoder.num_ch = 1; + sw_codec_cfg.encoder.channel_mode = SW_CODEC_MONO; + } - device_location_get(&device_location); + device_location_get(&sw_codec_cfg.decoder.audio_loc); + if (sw_codec_cfg.decoder.audio_loc == BT_AUDIO_LOCATION_MONO_AUDIO) { + sw_codec_cfg.decoder.num_ch = 1; + } else { + sw_codec_cfg.decoder.num_ch = POPCOUNT(sw_codec_cfg.decoder.audio_loc); + } - sw_codec_cfg.decoder.num_ch = POPCOUNT(device_location); - switch ((uint32_t)device_location) { + switch ((uint32_t)sw_codec_cfg.decoder.audio_loc) { + case BT_AUDIO_LOCATION_MONO_AUDIO: case BT_AUDIO_LOCATION_FRONT_LEFT: - sw_codec_cfg.decoder.audio_ch = 0; - sw_codec_cfg.decoder.channel_mode = SW_CODEC_MONO; - break; case BT_AUDIO_LOCATION_FRONT_RIGHT: - sw_codec_cfg.decoder.audio_ch = 1; sw_codec_cfg.decoder.channel_mode = SW_CODEC_MONO; break; case (BT_AUDIO_LOCATION_FRONT_LEFT | BT_AUDIO_LOCATION_FRONT_RIGHT): - sw_codec_cfg.decoder.channel_mode = SW_CODEC_STEREO; + sw_codec_cfg.decoder.channel_mode = SW_CODEC_MULTICHANNEL; break; default: - LOG_ERR("Unsupported device location: 0x%08x", device_location); + LOG_ERR("Unsupported device location: 0x%08x", sw_codec_cfg.decoder.audio_loc); ERR_CHK(-EINVAL); break; }; @@ -135,14 +166,17 @@ static void encoder_thread(void *arg1, void *arg2, void *arg3) int ret; uint32_t audio_q_num_used; static uint32_t test_tone_finite_pos; + struct net_buf *audio_frame_out = NULL; + struct audio_metadata *meta_blk; + struct audio_metadata *meta_in; int debug_trans_count = 0; while (1) { /* Don't start encoding until the stream needing it has started */ ret = k_poll(&encoder_evt, 1, K_FOREVER); - struct net_buf *audio_frame = net_buf_alloc(&audio_q_rx_pool, K_NO_WAIT); + struct net_buf *audio_frame_in = net_buf_alloc(&audio_q_rx_pool, K_NO_WAIT); - if (audio_frame == NULL) { + if (audio_frame_in == NULL) { LOG_ERR("Out of RX buffers"); continue; } @@ -160,32 +194,54 @@ static void encoder_thread(void *arg1, void *arg2, void *arg3) ERR_CHK_MSG(ret, "Failed to get audio block from RX queue"); /* Copy metadata from the first block */ - ret = net_buf_user_data_copy(audio_frame, audio_block); + ret = net_buf_user_data_copy(audio_frame_in, audio_block); ERR_CHK_MSG(ret, "Failed to copy user data"); /* Extract the data from the block */ - net_buf_add_mem(audio_frame, audio_block->data, audio_block->len); + net_buf_add_mem(audio_frame_in, audio_block->data, audio_block->len); + + meta_in = net_buf_user_data(audio_frame_in); /* Free the block */ net_buf_unref(audio_block); - struct audio_metadata *meta = net_buf_user_data(audio_frame); /* Loop until we have a full frame */ - while (meta->data_len_us < CONFIG_AUDIO_FRAME_DURATION_US) { + while (meta_in->data_len_us < CONFIG_AUDIO_FRAME_DURATION_US) { ret = k_msgq_get(&audio_q_rx, (void *)&audio_block, K_FOREVER); ERR_CHK_MSG(ret, "Failed to get audio block from RX queue"); - struct audio_metadata *block_meta = net_buf_user_data(audio_block); + meta_blk = net_buf_user_data(audio_block); /* Extract the data from the block */ - net_buf_add_mem(audio_frame, audio_block->data, audio_block->len); - meta->data_len_us += block_meta->data_len_us; + net_buf_add_mem(audio_frame_in, audio_block->data, audio_block->len); + meta_in->data_len_us += meta_blk->data_len_us; + meta_in->bytes_per_location += meta_blk->bytes_per_location; /* Free the block */ net_buf_unref(audio_block); } if (sw_codec_cfg.encoder.enabled) { + audio_frame_out = net_buf_alloc(&audio_q_enc_pool, K_NO_WAIT); + + if (audio_frame_out == NULL) { + LOG_WRN("Out of encoder buffers"); + net_buf_unref(audio_frame_in); + continue; + } + + /* Configure the meta data */ + struct audio_metadata *meta_out = net_buf_user_data(audio_frame_out); + + net_buf_user_data_copy(audio_frame_out, audio_frame_in); + meta_out->data_coding = LC3; + meta_out->sample_rate_hz = sw_codec_cfg.encoder.sample_rate_hz; + meta_out->bitrate_bps = sw_codec_cfg.encoder.bitrate; + meta_out->bytes_per_location = + (meta_out->bitrate_bps * meta_out->data_len_us) / 8000000; + meta_out->interleaved = false; + meta_out->locations = sw_codec_cfg.encoder.audio_loc; + if (test_tone_size) { /* Test tone takes over audio stream */ uint32_t num_bytes = 0; @@ -196,17 +252,20 @@ static void encoder_thread(void *arg1, void *arg2, void *arg3) ERR_CHK(ret); ret = pscm_copy_pad(tmp, FRAME_SIZE_BYTES / 2, - CONFIG_AUDIO_BIT_DEPTH_BITS, audio_frame->data, - &num_bytes); + CONFIG_AUDIO_BIT_DEPTH_BITS, + audio_frame_in->data, &num_bytes); ERR_CHK(ret); - if (audio_frame->len != num_bytes) { - LOG_ERR("Tone wrong size: %u", num_bytes); + if (audio_frame_in->len != num_bytes) { + LOG_ERR("Audio frame and tone length mismatch: %u != %u", + audio_frame_in->len, num_bytes); } } - ret = sw_codec_encode(audio_frame); + ret = sw_codec_encode(audio_frame_in, audio_frame_out); ERR_CHK_MSG(ret, "Encode failed"); + + net_buf_unref(audio_frame_in); } /* Print block usage */ @@ -220,8 +279,8 @@ static void encoder_thread(void *arg1, void *arg2, void *arg3) } if (sw_codec_cfg.encoder.enabled) { - streamctrl_send(audio_frame); - net_buf_unref(audio_frame); + streamctrl_send(audio_frame_out); + net_buf_unref(audio_frame_out); } STACK_USAGE_PRINT("encoder_thread", &encoder_thread_data); } @@ -323,12 +382,10 @@ int audio_system_config_set(uint32_t encoder_sample_rate_hz, uint32_t encoder_bi } /* This function is only used on gateway using USB as audio source and bidirectional stream */ -int audio_system_decode(struct net_buf *audio_frame) +int audio_system_decode(struct net_buf *audio_frame_in) { int ret; static int debug_trans_count; - static void *pcm_raw_data; - size_t pcm_block_size; if (!sw_codec_cfg.initialized) { /* Throw away data */ @@ -339,9 +396,32 @@ int audio_system_decode(struct net_buf *audio_frame) return -EPERM; } - ret = sw_codec_decode(audio_frame, &pcm_raw_data, &pcm_block_size); + if (audio_frame_in == NULL) { + LOG_ERR("Buffer pointer is NULL"); + return -EINVAL; + } + + struct net_buf *audio_frame_out = net_buf_alloc(&audio_q_dec_pool, K_NO_WAIT); + + if (audio_frame_out == NULL) { + LOG_WRN("Out of PCM buffers"); + return -ENOSPC; + } + + /* Configure the meta data */ + struct audio_metadata *meta_in = net_buf_user_data(audio_frame_in); + struct audio_metadata *meta_out = net_buf_user_data(audio_frame_out); + + *meta_out = decoder_meta; + meta_out->data_len_us = meta_in->data_len_us; + meta_out->ref_ts_us = meta_in->ref_ts_us; + meta_out->data_rx_ts_us = meta_in->data_rx_ts_us; + meta_out->bad_data = meta_in->bad_data; + + ret = sw_codec_decode(audio_frame_in, audio_frame_out); if (ret) { LOG_ERR("Failed to decode"); + net_buf_unref(audio_frame_out); return ret; } @@ -364,19 +444,29 @@ int audio_system_decode(struct net_buf *audio_frame) if (audio_block == NULL) { LOG_ERR("Out of TX buffers"); + net_buf_unref(audio_frame_out); return -ENOMEM; } - net_buf_add_mem(audio_block, (char *)pcm_raw_data + (i * (BLOCK_SIZE_BYTES)), + struct audio_metadata *meta_blk = net_buf_user_data(audio_block); + + net_buf_add_mem(audio_block, + (char *)audio_frame_out->data + (i * (BLOCK_SIZE_BYTES)), BLOCK_SIZE_BYTES); + net_buf_user_data_copy(audio_block, audio_frame_out); + + meta_blk->data_len_us = meta_out->data_len_us / CONFIG_FIFO_FRAME_SPLIT_NUM; + meta_blk->bytes_per_location = BLOCK_SIZE_BYTES; ret = k_msgq_put(&audio_q_tx, (void *)&audio_block, K_NO_WAIT); if (ret) { LOG_ERR("Failed to put block onto queue"); net_buf_unref(audio_block); + net_buf_unref(audio_frame_out); return ret; } } + if (debug_trans_count == DEBUG_INTERVAL_NUM) { uint32_t audio_q_num_used = k_msgq_num_used_get(&audio_q_tx); @@ -387,6 +477,8 @@ int audio_system_decode(struct net_buf *audio_frame) debug_trans_count++; } + net_buf_unref(audio_frame_out); + return 0; } diff --git a/applications/nrf5340_audio/src/audio/le_audio_rx.c b/applications/nrf5340_audio/src/audio/le_audio_rx.c index bd9fe44665a9..4b1c1a968d4b 100644 --- a/applications/nrf5340_audio/src/audio/le_audio_rx.c +++ b/applications/nrf5340_audio/src/audio/le_audio_rx.c @@ -43,7 +43,8 @@ static void audio_frame_add(struct net_buf *audio_frame, struct net_buf *audio_f net_buf_add_mem(audio_frame, audio_frame_rx->data, audio_frame_rx->len); } else { /* Increment len to account for bad_data */ - net_buf_add(audio_frame, meta->bytes_per_location * metadata_num_ch_get(meta)); + net_buf_add(audio_frame, + meta->bytes_per_location * audio_metadata_num_ch_get(meta)); } } @@ -157,8 +158,9 @@ void le_audio_rx_data_handler(struct net_buf *audio_frame_rx, struct audio_metad /* Check if we have received all frames, send if we have */ check_send: - if (le_audio_concurrent_sync_num_get() == - metadata_num_ch_get(net_buf_user_data(audio_frame))) { + struct audio_metadata *existing_meta = net_buf_user_data(audio_frame); + + if (le_audio_concurrent_sync_num_get() == audio_metadata_num_ch_get(existing_meta)) { /* We have received all frames we are waiting for, pass data on to * the next module */ diff --git a/applications/nrf5340_audio/src/audio/sw_codec_select.c b/applications/nrf5340_audio/src/audio/sw_codec_select.c index f73c50041c87..8123ca4133b7 100644 --- a/applications/nrf5340_audio/src/audio/sw_codec_select.c +++ b/applications/nrf5340_audio/src/audio/sw_codec_select.c @@ -12,6 +12,8 @@ #include #include +#include "macros_common.h" + #if (CONFIG_SW_CODEC_LC3) #include "sw_codec_lc3.h" #endif /* (CONFIG_SW_CODEC_LC3) */ @@ -87,116 +89,133 @@ bool sw_codec_is_initialized(void) return m_config.initialized; } -int sw_codec_encode(struct net_buf *audio_frame) +int sw_codec_encode(struct net_buf *audio_frame_in, struct net_buf *audio_frame_out) { - int ret; - - /* Temp storage for PCM */ - char pcm_data_mono_system_sample_rate - [CONFIG_AUDIO_ENCODE_CHANNELS_MAX][PCM_NUM_BYTES_MONO] = {0}; - /* Make sure we have enough space for two frames (stereo) */ - uint8_t m_encoded_data[ENC_MAX_FRAME_SIZE * CONFIG_AUDIO_ENCODE_CHANNELS_MAX]; - - char pcm_data_mono_converted_buf[CONFIG_AUDIO_ENCODE_CHANNELS_MAX] - [PCM_NUM_BYTES_MONO] = {0}; - - size_t pcm_block_size_mono_system_sample_rate; - size_t pcm_block_size_mono; - - struct audio_metadata *meta = net_buf_user_data(audio_frame); - if (!m_config.encoder.enabled) { LOG_ERR("Encoder has not been initialized"); return -ENXIO; } + if (audio_frame_in == NULL || audio_frame_out == NULL) { + LOG_ERR("LC3 encoder input parameter error"); + return -EINVAL; + } + + int ret; + struct audio_metadata *meta_in = net_buf_user_data(audio_frame_in); + struct audio_metadata *meta_out = net_buf_user_data(audio_frame_out); + switch (m_config.sw_codec) { case SW_CODEC_LC3: { #if (CONFIG_SW_CODEC_LC3) - uint16_t encoded_bytes_written; - char *pcm_data_mono_ptrs[m_config.encoder.channel_mode]; + uint8_t inter_buf[PCM_NUM_BYTES_MONO]; + uint8_t src_buf[PCM_NUM_BYTES_MONO]; + uint8_t chan_in_num, chan_out_num; + uint8_t chan_out = 0; + uint8_t *inter_out; + uint8_t *enc_in = audio_frame_in->data; + uint8_t *enc_out = audio_frame_out->data; + size_t enc_in_size = 0; + uint16_t bytes_written; + uint32_t loc_in, loc_out; + + LOG_DBG("LC3 encoder module"); + + if ((meta_in->data_coding != PCM) || (meta_out->data_coding != LC3)) { + LOG_ERR("LC3 encoder module has incorrect input or output data type: in = " + "%d out = %d", + meta_in->data_coding, meta_out->data_coding); + return -EINVAL; + } - /* Since LC3 is a single channel codec, we must split the - * stereo PCM stream - */ - ret = pscm_two_channel_split(audio_frame->data, audio_frame->len, - CONFIG_AUDIO_BIT_DEPTH_BITS, - pcm_data_mono_system_sample_rate[0], - pcm_data_mono_system_sample_rate[1], - &pcm_block_size_mono_system_sample_rate); - if (ret) { - return ret; + chan_in_num = audio_metadata_num_ch_get(meta_in); + if (audio_frame_in->len < (meta_in->bytes_per_location * chan_in_num)) { + LOG_ERR("Encoder input buffer too small: %d (>=%d)", audio_frame_in->len, + meta_in->bytes_per_location * chan_in_num); + return -EINVAL; } - for (int i = 0; i < m_config.encoder.channel_mode; ++i) { - ret = sw_codec_sample_rate_convert( - &encoder_converters[i], CONFIG_AUDIO_SAMPLE_RATE_HZ, - m_config.encoder.sample_rate_hz, - pcm_data_mono_system_sample_rate[i], - pcm_block_size_mono_system_sample_rate, - pcm_data_mono_converted_buf[i], &pcm_data_mono_ptrs[i], - &pcm_block_size_mono); - if (ret) { - LOG_ERR("Sample rate conversion failed for channel %d: %d", i, ret); - return ret; - } + chan_out_num = audio_metadata_num_ch_get(meta_out); + if (audio_frame_out->size < (meta_out->bytes_per_location * chan_out_num)) { + LOG_ERR("Encoder output buffer too small: %d (>=%d)", audio_frame_out->size, + meta_out->bytes_per_location * chan_out_num); + return -EINVAL; } - switch (m_config.encoder.channel_mode) { - case SW_CODEC_MONO: { - ret = sw_codec_lc3_enc_run(pcm_data_mono_ptrs[0], - pcm_block_size_mono, LC3_USE_BITRATE_FROM_INIT, - 0, sizeof(m_encoded_data), m_encoded_data, - &encoded_bytes_written); - if (ret) { - return ret; - } - meta->locations = BT_AUDIO_LOCATION_FRONT_LEFT; - break; + if (meta_out->locations == BT_AUDIO_LOCATION_MONO_AUDIO && + meta_in->locations == BT_AUDIO_LOCATION_MONO_AUDIO) { + loc_in = 1; + loc_out = 1; + } else if (meta_out->locations & meta_in->locations) { + loc_in = meta_in->locations; + loc_out = meta_out->locations; + } else { + LOG_ERR("No common output location with input"); + return -EINVAL; } - case SW_CODEC_STEREO: { - ret = sw_codec_lc3_enc_run(pcm_data_mono_ptrs[0], - pcm_block_size_mono, LC3_USE_BITRATE_FROM_INIT, - 0, sizeof(m_encoded_data), - m_encoded_data, &encoded_bytes_written); - if (ret) { - return ret; - } - ret = sw_codec_lc3_enc_run( - pcm_data_mono_ptrs[1], pcm_block_size_mono, - LC3_USE_BITRATE_FROM_INIT, 1, - sizeof(m_encoded_data) - encoded_bytes_written, - m_encoded_data + encoded_bytes_written, &encoded_bytes_written); - if (ret) { - return ret; + /* Clear all output locations to ensure any unused locations are zero */ + memset(audio_frame_out->data, 0, audio_frame_out->size); + + /* Encode only the common channel(s) between the input and output locations. */ + while (loc_out && loc_in) { + if (loc_out & loc_in & 0x01) { + if (meta_in->interleaved) { + ret = pscm_deinterleave(audio_frame_in->data, + audio_frame_in->len, chan_in_num, + chan_out, + meta_in->carried_bits_per_sample, + inter_buf, sizeof(inter_buf)); + ERR_CHK_MSG(ret, "Encode: Failed de-interleaving"); + + inter_out = inter_buf; + } else { + inter_out = (uint8_t *)audio_frame_in->data + + (meta_in->bytes_per_location * chan_out); + } + + ret = sw_codec_sample_rate_convert( + &encoder_converters[chan_out], meta_in->sample_rate_hz, + meta_out->sample_rate_hz, inter_out, + meta_in->bytes_per_location, src_buf, (char **)&enc_in, + &enc_in_size); + ERR_CHK_MSG(ret, "Encode: Sample rate conversion failed"); + + ret = sw_codec_lc3_enc_run( + enc_in, enc_in_size, meta_out->bitrate_bps, chan_out, + meta_in->bytes_per_location, enc_out, &bytes_written); + ERR_CHK_MSG(ret, "Encode failed"); + + enc_out += bytes_written; + + LOG_DBG("Completed LC3 encode of ch: %d", chan_out); } - encoded_bytes_written += encoded_bytes_written; - break; - } - default: - LOG_ERR("Unsupported channel mode for encoder: %d", - m_config.encoder.channel_mode); - return -ENODEV; + + chan_out += loc_out & 0x01; + + loc_in >>= 1; + loc_out >>= 1; } - meta->data_coding = LC3; + meta_out->bytes_per_location = bytes_written; + meta_out->locations &= meta_in->locations; + net_buf_add(audio_frame_out, + meta_out->bytes_per_location * audio_metadata_num_ch_get(meta_out)); - net_buf_remove_mem(audio_frame, audio_frame->len); - net_buf_add_mem(audio_frame, m_encoded_data, encoded_bytes_written); + return 0; #endif /* (CONFIG_SW_CODEC_LC3) */ break; } default: - LOG_ERR("Unsupported codec: %d", m_config.sw_codec); + LOG_ERR("Unsupported codec: %d", meta_out->data_coding); return -ENODEV; } return 0; } -int sw_codec_decode(struct net_buf const *const audio_frame, void **decoded_data, - size_t *decoded_size) +int sw_codec_decode(struct net_buf const *const audio_frame_in, + struct net_buf *const audio_frame_out) { if (!m_config.decoder.enabled) { LOG_ERR("Decoder has not been initialized"); @@ -204,147 +223,134 @@ int sw_codec_decode(struct net_buf const *const audio_frame, void **decoded_data } int ret; - - static char pcm_data_stereo[PCM_NUM_BYTES_STEREO]; - - char decoded_data_mono - [CONFIG_AUDIO_DECODE_CHANNELS_MAX][PCM_NUM_BYTES_MONO] = {0}; - char decoded_data_mono_system_sample_rate - [CONFIG_AUDIO_DECODE_CHANNELS_MAX][PCM_NUM_BYTES_MONO] = {0}; - - size_t pcm_size_stereo = 0; - size_t pcm_size_mono = 0; - size_t decoded_data_size = 0; - - struct audio_metadata *meta = net_buf_user_data(audio_frame); + struct audio_metadata *meta_in = net_buf_user_data(audio_frame_in); + struct audio_metadata *meta_out = net_buf_user_data(audio_frame_out); switch (m_config.sw_codec) { case SW_CODEC_LC3: { #if (CONFIG_SW_CODEC_LC3) - char *pcm_in_data_ptrs[m_config.decoder.channel_mode]; + uint8_t dec_out_buf[PCM_NUM_BYTES_MONO]; + uint8_t src_buf[PCM_NUM_BYTES_MONO]; + uint8_t *data_in; + uint8_t *dec_out = dec_out_buf; + uint8_t *src_out = src_buf; + uint8_t chan_in, chan_out; + uint8_t chans_out_num; + uint8_t *inter_in = dec_out_buf; + uint16_t bytes_written; + uint32_t loc_in, loc_out; + uint32_t bad_data_mask; + size_t inter_in_size = 0; + + if (meta_in->data_coding != LC3 || meta_out->data_coding != PCM) { + LOG_ERR("LC3 decoder module has incorrect input or output data type: in = " + "%d out = %d", + meta_in->data_coding, meta_out->data_coding); + return -EINVAL; + } - switch (m_config.decoder.channel_mode) { - case SW_CODEC_MONO: { - if (meta->bad_data && SW_CODEC_OVERRIDE_PLC) { - memset(decoded_data_mono[0], 0, PCM_NUM_BYTES_MONO); - decoded_data_size = PCM_NUM_BYTES_MONO; - } else { - ret = sw_codec_lc3_dec_run( - audio_frame->data, audio_frame->len, LC3_PCM_NUM_BYTES_MONO, - 0, decoded_data_mono[0], - (uint16_t *)&decoded_data_size, meta->bad_data); - if (ret) { - return ret; - } + if (audio_frame_in->len < + meta_in->bytes_per_location * audio_metadata_num_ch_get(meta_in)) { + LOG_ERR("Decoder input frame too small: %d (< %d)", audio_frame_in->len, + (meta_in->bytes_per_location * audio_metadata_num_ch_get(meta_in))); + return -EINVAL; + } - ret = sw_codec_sample_rate_convert( - &decoder_converters[0], - m_config.decoder.sample_rate_hz, - CONFIG_AUDIO_SAMPLE_RATE_HZ, decoded_data_mono[0], - decoded_data_size, - decoded_data_mono_system_sample_rate[0], - &pcm_in_data_ptrs[0], &pcm_size_mono); - if (ret) { - LOG_ERR("Sample rate conversion failed for mono: %d", ret); - return ret; - } - } + chans_out_num = audio_metadata_num_ch_get(meta_out); + if (audio_frame_out->size < meta_out->bytes_per_location * chans_out_num) { + LOG_ERR("Decoder output buffer too small: %d (<%d for %d channel(s))", + audio_frame_out->size, + (meta_out->bytes_per_location * chans_out_num), chans_out_num); + return -EINVAL; + } - if (IS_ENABLED(CONFIG_STREAM_BIDIRECTIONAL) && - (CONFIG_AUDIO_DEV == GATEWAY)) { - /* If we are receieving mono audio on the gateway, we send it out - * as stereo, so we need to pad the mono data to stereo. - */ - ret = pscm_copy_pad(pcm_in_data_ptrs[0], pcm_size_mono, - CONFIG_AUDIO_BIT_DEPTH_BITS, pcm_data_stereo, - &pcm_size_stereo); - if (ret) { - LOG_ERR("Failed to copy pad mono to stereo: %d", ret); - return ret; - } + if (meta_out->locations == BT_AUDIO_LOCATION_MONO_AUDIO && + meta_in->locations == BT_AUDIO_LOCATION_MONO_AUDIO) { + loc_in = 1; + loc_out = 1; + } else if (meta_out->locations & meta_in->locations) { + loc_in = meta_in->locations; + loc_out = meta_out->locations; + } else { + LOG_ERR("No common output location with input"); + return -EINVAL; + } + + if (!meta_out->interleaved) { + if (IS_ENABLED(CONFIG_SAMPLE_RATE_CONVERTER) && + meta_in->sample_rate_hz != meta_out->sample_rate_hz) { + src_out = (uint8_t *)audio_frame_out->data; } else { - /* For now, i2s is only stereo, so in order to send - * just one channel, we need to insert 0 for the - * other channel - */ - ret = pscm_zero_pad(pcm_in_data_ptrs[0], pcm_size_mono, - m_config.decoder.audio_ch, - CONFIG_AUDIO_BIT_DEPTH_BITS, pcm_data_stereo, - &pcm_size_stereo); - if (ret) { - return ret; - } + dec_out = (uint8_t *)audio_frame_out->data; } - break; } - case SW_CODEC_STEREO: { - if (meta->bad_data && SW_CODEC_OVERRIDE_PLC) { - memset(decoded_data_mono[0], 0, PCM_NUM_BYTES_MONO); - memset(decoded_data_mono[1], 0, PCM_NUM_BYTES_MONO); - decoded_data_size = PCM_NUM_BYTES_MONO; - } else { - /* Decode left channel */ - ret = sw_codec_lc3_dec_run( - audio_frame->data, (audio_frame->len / 2), - LC3_PCM_NUM_BYTES_MONO, 0, - decoded_data_mono[0], - (uint16_t *)&decoded_data_size, meta->bad_data); - if (ret) { - return ret; - } + /* Clear all output channels to ensure any unused are zero */ + memset(audio_frame_out->data, 0, audio_frame_out->size); - /* Decode right channel */ - ret = sw_codec_lc3_dec_run( - (audio_frame->data + (audio_frame->len / 2)), - (audio_frame->len / 2), LC3_PCM_NUM_BYTES_MONO, 1, - decoded_data_mono[1], - (uint16_t *)&decoded_data_size, meta->bad_data); - if (ret) { - return ret; - } + chan_in = 0; + chan_out = 0; + bad_data_mask = 0x01; + + /* Decode only the channel(s) common between the input and output locations. + * These will be put in the first channel or channels and the location + * will indicate which channel(s) they are. Prior to playout (I2S or TDM) + * all other channels can be zeroed. + */ + while (loc_in && loc_out) { + if (loc_out & loc_in & 0x01) { + data_in = (uint8_t *)audio_frame_in->data + + (meta_in->bytes_per_location * chan_in); + + ret = sw_codec_lc3_dec_run(data_in, meta_in->bytes_per_location, + audio_frame_out->size, chan_in, dec_out, + &bytes_written, + (meta_in->bad_data & bad_data_mask)); + ERR_CHK_MSG(ret, "Decode failed"); - for (int i = 0; i < m_config.decoder.channel_mode; ++i) { - ret = sw_codec_sample_rate_convert( - &decoder_converters[i], - m_config.decoder.sample_rate_hz, - CONFIG_AUDIO_SAMPLE_RATE_HZ, decoded_data_mono[i], - decoded_data_size, - decoded_data_mono_system_sample_rate[i], - &pcm_in_data_ptrs[i], &pcm_size_mono); - if (ret) { - LOG_ERR("Sample rate conversion failed for channel " - "%d : %d", - i, ret); - return ret; + ret = sw_codec_sample_rate_convert( + &decoder_converters[chan_in], meta_in->sample_rate_hz, + meta_out->sample_rate_hz, dec_out, bytes_written, src_out, + (char **)&inter_in, &inter_in_size); + ERR_CHK_MSG(ret, "Decode: Sample rate converter failed"); + + if (meta_out->interleaved) { + ret = pscm_interleave(inter_in, inter_in_size, chan_out, + meta_out->carried_bits_per_sample, + audio_frame_out->data, + audio_frame_out->size, chans_out_num); + ERR_CHK_MSG(ret, "Decode: Interleave failed"); + } else { + if (IS_ENABLED(CONFIG_SAMPLE_RATE_CONVERTER) && + meta_in->sample_rate_hz != meta_out->sample_rate_hz) { + src_out += inter_in_size; + } else { + dec_out += inter_in_size; } } } - ret = pscm_combine(pcm_in_data_ptrs[0], - pcm_in_data_ptrs[1], pcm_size_mono, - CONFIG_AUDIO_BIT_DEPTH_BITS, pcm_data_stereo, - &pcm_size_stereo); - if (ret) { - return ret; - } - break; - } - default: - LOG_ERR("Unsupported channel mode for decoder: %d", - m_config.decoder.channel_mode); - return -ENODEV; + bad_data_mask <<= 1; + + chan_in += loc_in & 0x01; + chan_out += loc_out & 0x01; + + loc_in >>= 1; + loc_out >>= 1; } - *decoded_size = pcm_size_stereo; - *decoded_data = pcm_data_stereo; + meta_out->bytes_per_location = inter_in_size; + net_buf_add(audio_frame_out, + meta_out->bytes_per_location * audio_metadata_num_ch_get(meta_out)); + #endif /* (CONFIG_SW_CODEC_LC3) */ break; } default: - LOG_ERR("Unsupported codec: %d", m_config.sw_codec); + LOG_ERR("Unsupported codec: %d", meta_in->data_coding); return -ENODEV; } + return 0; } @@ -428,7 +434,6 @@ int sw_codec_init(struct sw_codec_config sw_codec_cfg) sw_codec_cfg.encoder.sample_rate_hz, CONFIG_AUDIO_BIT_DEPTH_BITS, CONFIG_AUDIO_FRAME_DURATION_US, sw_codec_cfg.encoder.bitrate, sw_codec_cfg.encoder.num_ch, &pcm_bytes_req_enc); - if (ret) { return ret; } @@ -447,7 +452,6 @@ int sw_codec_init(struct sw_codec_config sw_codec_cfg) ret = sw_codec_lc3_dec_init( sw_codec_cfg.decoder.sample_rate_hz, CONFIG_AUDIO_BIT_DEPTH_BITS, CONFIG_AUDIO_FRAME_DURATION_US, sw_codec_cfg.decoder.num_ch); - if (ret) { return ret; } @@ -465,25 +469,23 @@ int sw_codec_init(struct sw_codec_config sw_codec_cfg) return false; } - if (sw_codec_cfg.encoder.enabled && IS_ENABLED(SAMPLE_RATE_CONVERTER)) { + if (sw_codec_cfg.encoder.enabled && IS_ENABLED(CONFIG_SAMPLE_RATE_CONVERTER)) { for (int i = 0; i < sw_codec_cfg.encoder.channel_mode; i++) { ret = sample_rate_converter_open(&encoder_converters[i]); if (ret) { LOG_ERR("Failed to initialize the sample rate converter for " - "encoding channel %d: %d", - i, ret); + "encoding channel %d: %d", i, ret); return ret; } } } - if (sw_codec_cfg.decoder.enabled && IS_ENABLED(SAMPLE_RATE_CONVERTER)) { + if (sw_codec_cfg.decoder.enabled && IS_ENABLED(CONFIG_SAMPLE_RATE_CONVERTER)) { for (int i = 0; i < sw_codec_cfg.decoder.channel_mode; i++) { ret = sample_rate_converter_open(&decoder_converters[i]); if (ret) { LOG_ERR("Failed to initialize the sample rate converter for " - "decoding channel %d: %d", - i, ret); + "decoding channel %d: %d", i, ret); return ret; } } diff --git a/applications/nrf5340_audio/src/audio/sw_codec_select.h b/applications/nrf5340_audio/src/audio/sw_codec_select.h index 231493fd9ef6..cda782f39758 100644 --- a/applications/nrf5340_audio/src/audio/sw_codec_select.h +++ b/applications/nrf5340_audio/src/audio/sw_codec_select.h @@ -27,46 +27,56 @@ #if (CONFIG_SW_CODEC_LC3) #define LC3_MAX_FRAME_SIZE_MS 10 #define LC3_ENC_MONO_FRAME_SIZE (CONFIG_LC3_BITRATE_MAX * LC3_MAX_FRAME_SIZE_MS / (8 * 1000)) - #define LC3_PCM_NUM_BYTES_MONO \ (CONFIG_AUDIO_SAMPLE_RATE_HZ * CONFIG_AUDIO_BIT_DEPTH_OCTETS * LC3_MAX_FRAME_SIZE_MS / 1000) #define LC3_ENC_TIME_US 3000 #define LC3_DEC_TIME_US 1500 #else - #define LC3_ENC_MONO_FRAME_SIZE 0 - #define LC3_PCM_NUM_BYTES_MONO 0 - #define LC3_ENC_TIME_US 0 - #define LC3_DEC_TIME_US 0 #endif /* CONFIG_SW_CODEC_LC3 */ -#define ENC_MAX_FRAME_SIZE MAX(LC3_ENC_MONO_FRAME_SIZE, 0) - -#define ENC_TIME_US MAX(LC3_ENC_TIME_US, 0) - -#define DEC_TIME_US MAX(LC3_DEC_TIME_US, 0) - -#define PCM_NUM_BYTES_MONO MAX(LC3_PCM_NUM_BYTES_MONO, 0) - -#define PCM_NUM_BYTES_STEREO (PCM_NUM_BYTES_MONO * 2) +/* Max will be used when multiple codecs are supported */ +#define ENC_MAX_FRAME_SIZE MAX(LC3_ENC_MONO_FRAME_SIZE, 0) +#define ENC_MULTI_CHAN_MAX_FRAME_SIZE (LC3_ENC_MONO_FRAME_SIZE * CONFIG_AUDIO_ENCODE_CHANNELS_MAX) +#define ENC_TIME_US MAX(LC3_ENC_TIME_US, 0) +#define DEC_TIME_US MAX(LC3_DEC_TIME_US, 0) +#define PCM_NUM_BYTES_MONO MAX(LC3_PCM_NUM_BYTES_MONO, 0) +#define PCM_NUM_BYTES_MULTI_CHAN \ + (PCM_NUM_BYTES_MONO * MAX(CONFIG_AUDIO_DECODE_CHANNELS_MAX, CONFIG_AUDIO_OUTPUT_CHANNELS)) /** * @brief Software codec selection enumeration. */ enum sw_codec_select { - SW_CODEC_NONE, /**< No codec selected */ - SW_CODEC_LC3, /**< Low Complexity Communication Codec */ + SW_CODEC_NONE, /**< No codec selected */ + SW_CODEC_LC3, /**< Low Complexity Communication Codec */ }; /** * @brief Software codec channel mode enumeration. */ enum sw_codec_channel_mode { - SW_CODEC_MONO = 1, /**< Mono channel mode (single channel) */ - SW_CODEC_STEREO, /**< Stereo channel mode (dual channels) */ + SW_CODEC_MONO = 1, + SW_CODEC_MULTICHANNEL, +}; + +/** + * @brief Private encoder context. + */ +struct lc3_encoder_context { + /* Array of encoder channel handles. */ + struct lc3_encoder_handle *lc3_enc_channel[CONFIG_AUDIO_ENCODE_CHANNELS_MAX]; +}; + +/** + * @brief Private decoder context. + */ +struct lc3_decoder_context { + /* Array of decoder channel handles. */ + struct lc3_decoder_handle *lc3_dec_channel[CONFIG_AUDIO_DECODE_CHANNELS_MAX]; }; /** @@ -77,8 +87,9 @@ struct sw_codec_encoder { int bitrate; enum sw_codec_channel_mode channel_mode; uint8_t num_ch; - enum audio_channel audio_ch; + enum bt_audio_location audio_loc; uint32_t sample_rate_hz; + struct lc3_encoder_context lc3_ctx; }; /** @@ -88,8 +99,9 @@ struct sw_codec_decoder { bool enabled; enum sw_codec_channel_mode channel_mode; uint8_t num_ch; - enum audio_channel audio_ch; + enum bt_audio_location audio_loc; uint32_t sample_rate_hz; + struct lc3_decoder_context lc3_ctx; }; /** @@ -113,25 +125,29 @@ bool sw_codec_is_initialized(void); /** * @brief Encode PCM data and output encoded data. * - * @note Takes in stereo PCM stream, will encode either one or two + * @note Takes in a PCM stream, will encode either one or multiple * channels, based on channel_mode set during init. * - * @param[in] audio_frame Pointer to the audio buffer. + * @param[in] audio_frame_in Pointer to the audio PCM buffer. + * @param[out] audio_frame_out Pointer to the audio encoded buffer. * * @return 0 if success, error codes depends on sw_codec selected. */ -int sw_codec_encode(struct net_buf *audio_frame); +int sw_codec_encode(struct net_buf *audio_frame_in, struct net_buf *audio_frame_out); /** * @brief Decode encoded data and output PCM data. * - * @param[in] audio_frame Pointer to the audio buffer. - * @param[out] pcm_data Pointer to the buffer to store the decoded PCM data. - * @param[out] pcm_size Size of decoded data. + * @note Takes in a coded bitstream, will decode either one or multiple + * channels, based on channel_mode set during init. + * + * @param[in] audio_frame_in Pointer to the audio input buffer. + * @param[out] audio_frame_out Pointer to the audio output buffer. * * @return 0 if success, error codes depends on sw_codec selected. */ -int sw_codec_decode(struct net_buf const *const audio_frame, void **pcm_data, size_t *pcm_size); +int sw_codec_decode(struct net_buf const *const audio_frame_in, + struct net_buf *const audio_frame_out); /** * @brief Uninitialize the software codec and free the allocated space. diff --git a/applications/nrf5340_audio/src/bluetooth/bt_stream/bt_le_audio_tx/bt_le_audio_tx.c b/applications/nrf5340_audio/src/bluetooth/bt_stream/bt_le_audio_tx/bt_le_audio_tx.c index 193d2d774c3c..8c6d850ff04b 100644 --- a/applications/nrf5340_audio/src/bluetooth/bt_stream/bt_le_audio_tx/bt_le_audio_tx.c +++ b/applications/nrf5340_audio/src/bluetooth/bt_stream/bt_le_audio_tx/bt_le_audio_tx.c @@ -204,7 +204,7 @@ int bt_le_audio_tx_send(struct net_buf const *const audio_frame, struct le_audio /* Get number of channels in the audio frame */ struct audio_metadata *meta = net_buf_user_data(audio_frame); - uint8_t num_ch = metadata_num_ch_get(meta); + uint8_t num_ch = audio_metadata_num_ch_get(meta); if (num_ch == 0 || (audio_frame->len % num_ch != 0)) { LOG_ERR("Invalid number (%d) of channels in audio frame (%d)", num_ch, diff --git a/applications/nrf5340_audio/src/bluetooth/bt_stream/le_audio.c b/applications/nrf5340_audio/src/bluetooth/bt_stream/le_audio.c index 5ca50c624901..1e76a2c43ea0 100644 --- a/applications/nrf5340_audio/src/bluetooth/bt_stream/le_audio.c +++ b/applications/nrf5340_audio/src/bluetooth/bt_stream/le_audio.c @@ -38,7 +38,7 @@ int le_audio_metadata_populate(struct audio_metadata *meta, const struct bt_bap_ return ret; } - meta->bytes_per_location = octets_per_frame / metadata_num_ch_get(meta); + meta->bytes_per_location = octets_per_frame / audio_metadata_num_ch_get(meta); if (meta->bytes_per_location == 0) { LOG_ERR("Failed to get bytes per location"); return -EINVAL; diff --git a/applications/nrf5340_audio/src/modules/audio_i2s.h b/applications/nrf5340_audio/src/modules/audio_i2s.h index 32719f8b8fbb..0a989581699c 100644 --- a/applications/nrf5340_audio/src/modules/audio_i2s.h +++ b/applications/nrf5340_audio/src/modules/audio_i2s.h @@ -48,8 +48,8 @@ ((CONFIG_I2S_LRCK_FREQ_HZ / 1000 * 10) * CONFIG_I2S_CH_NUM * CONFIG_AUDIO_BIT_DEPTH_OCTETS) #endif /* ((CONFIG_AUDIO_FRAME_DURATION_US == 7500) && CONFIG_SW_CODEC_LC3) */ -/** Calculate block size in bytes for I2S FIFO frame splitting. */ -#define BLOCK_SIZE_BYTES (FRAME_SIZE_BYTES / CONFIG_FIFO_FRAME_SPLIT_NUM) +#define FRAME_SIZE_MONO_BYTES (FRAME_SIZE_BYTES / CONFIG_I2S_CH_NUM) +#define BLOCK_SIZE_BYTES (FRAME_SIZE_BYTES / CONFIG_FIFO_FRAME_SPLIT_NUM) /** * @brief Calculate number of samples per I2S block. diff --git a/applications/nrf5340_audio/src/modules/audio_usb.c b/applications/nrf5340_audio/src/modules/audio_usb.c index 68edbfc9cd9b..98d60d6d4024 100644 --- a/applications/nrf5340_audio/src/modules/audio_usb.c +++ b/applications/nrf5340_audio/src/modules/audio_usb.c @@ -13,6 +13,7 @@ #include #include "macros_common.h" +#include "device_location.h" #include LOG_MODULE_REGISTER(audio_usb, CONFIG_MODULE_AUDIO_USB_LOG_LEVEL); @@ -20,13 +21,25 @@ LOG_MODULE_REGISTER(audio_usb, CONFIG_MODULE_AUDIO_USB_LOG_LEVEL); static struct k_msgq *audio_q_tx; static struct k_msgq *audio_q_rx; -NET_BUF_POOL_FIXED_DEFINE(pool_in, CONFIG_FIFO_FRAME_SPLIT_NUM, USB_BLOCK_SIZE_STEREO, +NET_BUF_POOL_FIXED_DEFINE(pool_in, CONFIG_FIFO_FRAME_SPLIT_NUM, USB_BLOCK_SIZE_MULTI_CHAN, sizeof(struct audio_metadata), NULL); static uint32_t rx_num_overruns; static bool rx_first_data; static bool tx_first_data; +/* The meta data for the USB and that required for the following audio system. */ +struct audio_metadata usb_in_meta = {.data_coding = PCM, + .data_len_us = 1000, + .sample_rate_hz = CONFIG_AUDIO_SAMPLE_RATE_HZ, + .bits_per_sample = CONFIG_AUDIO_BIT_DEPTH_BITS, + .carried_bits_per_sample = CONFIG_AUDIO_BIT_DEPTH_BITS, + .bytes_per_location = USB_BLOCK_SIZE_MULTI_CHAN / 2, + .interleaved = true, + .locations = BT_AUDIO_LOCATION_FRONT_LEFT | + BT_AUDIO_LOCATION_FRONT_RIGHT, + .bad_data = 0}; + #if (CONFIG_STREAM_BIDIRECTIONAL) static uint32_t tx_num_underruns; @@ -89,8 +102,8 @@ static void data_received(const struct device *dev, struct net_buf *buffer, size } /* Receive data from USB */ - if (size != USB_BLOCK_SIZE_STEREO) { - LOG_WRN("Wrong length: %d", size); + if (size != USB_BLOCK_SIZE_MULTI_CHAN) { + LOG_WRN("Incorrect buffer size: %d (%u)", size, USB_BLOCK_SIZE_MULTI_CHAN); net_buf_unref(buffer); return; } @@ -126,16 +139,9 @@ static void data_received(const struct device *dev, struct net_buf *buffer, size /* Send USB buffer back to USB stack */ net_buf_unref(buffer); - /* Add meta data */ + /* Store USB related metadata */ struct audio_metadata *meta = net_buf_user_data(audio_block); - - meta->data_coding = PCM; - meta->data_len_us = 1000; - meta->sample_rate_hz = CONFIG_AUDIO_SAMPLE_RATE_HZ; - meta->bits_per_sample = CONFIG_AUDIO_BIT_DEPTH_BITS; - meta->carried_bits_per_sample = CONFIG_AUDIO_BIT_DEPTH_BITS; - meta->locations = BT_AUDIO_LOCATION_FRONT_LEFT | BT_AUDIO_LOCATION_FRONT_RIGHT; - meta->bad_data = false; + *meta = usb_in_meta; /* Put the block into RX queue */ ret = k_msgq_put(audio_q_rx, (void *)&audio_block, K_NO_WAIT); diff --git a/applications/nrf5340_audio/src/modules/audio_usb.h b/applications/nrf5340_audio/src/modules/audio_usb.h index 8806fb6501ca..6cfc1fa833b4 100644 --- a/applications/nrf5340_audio/src/modules/audio_usb.h +++ b/applications/nrf5340_audio/src/modules/audio_usb.h @@ -18,14 +18,15 @@ #include -#if (CONFIG_AUDIO_SOURCE_USB && !CONFIG_AUDIO_SAMPLE_RATE_48000_HZ) -/* Only 48kHz is supported when using USB */ -#error USB only supports 48kHz +#if (CONFIG_AUDIO_SOURCE_USB && !CONFIG_AUDIO_SAMPLE_RATE_48000_HZ && \ + MAX(CONFIG_AUDIO_INPUT_CHANNELS, CONFIG_AUDIO_OUTPUT_CHANNELS) != 2) +/* Only 48kHz stereo is supported when using USB */ +#error USB only supports 48kHz stereo #endif /* (CONFIG_AUDIO_SOURCE_USB && !CONFIG_AUDIO_SAMPLE_RATE_48000_HZ) */ -/** Calculate USB block size for stereo audio in bytes. */ -#define USB_BLOCK_SIZE_STEREO \ - (((CONFIG_AUDIO_SAMPLE_RATE_HZ * CONFIG_AUDIO_BIT_DEPTH_OCTETS) / 1000) * 2) +#define USB_BLOCK_SIZE_MULTI_CHAN \ + (((CONFIG_AUDIO_SAMPLE_RATE_HZ * CONFIG_AUDIO_BIT_DEPTH_OCTETS) / 1000) * \ + MAX(CONFIG_AUDIO_INPUT_CHANNELS, CONFIG_AUDIO_OUTPUT_CHANNELS)) /** * @brief Set pointers to the queues to be used by the USB module and start sending/receiving data. diff --git a/applications/nrf5340_audio/src/utils/fw_info_app.c.in b/applications/nrf5340_audio/src/utils/fw_info_app.c.in index ceef6ebeef55..55d01109d096 100644 --- a/applications/nrf5340_audio/src/utils/fw_info_app.c.in +++ b/applications/nrf5340_audio/src/utils/fw_info_app.c.in @@ -31,25 +31,18 @@ int fw_info_app_print(void) #if (CONFIG_DEBUG) int ret; - - LOG_INF("------- DEBUG BUILD -------"); - -#if (CONFIG_AUDIO_DEV == HEADSET) enum bt_audio_location location; device_location_get(&location); + LOG_INF("------- DEBUG BUILD -------"); + +#if (CONFIG_AUDIO_DEV == HEADSET) if (location == BT_AUDIO_LOCATION_MONO_AUDIO){ LOG_ERR("HEADSET location %s is not supported", bt_audio_location_bit_to_str(location)); return -EINVAL; } - for (int i = 0; i < (CHAR_BIT * sizeof(enum bt_audio_location)); i++) { - if (location & BIT(i)) { - LOG_INF(COLOR_CYAN "HEADSET location: %s" COLOR_RESET, bt_audio_location_bit_to_str(BIT(i))); - } - } - if (location == BT_AUDIO_LOCATION_FRONT_LEFT) { ret = log_set_tag(HS_LOC_L_TAG); } else if (location == BT_AUDIO_LOCATION_FRONT_RIGHT) { @@ -69,9 +62,19 @@ int fw_info_app_print(void) if (ret) { return ret; } - LOG_INF(COLOR_CYAN "GATEWAY device" COLOR_RESET); +#else + /* Make sure that we have the correct device */ + BUILD_ASSERT(0, "Unrecognized audio device"); #endif /* (CONFIG_AUDIO_DEV == HEADSET) */ + + for (int i = 0; i < (CHAR_BIT * sizeof(enum bt_audio_location)); i++) { + if (location & BIT(i)) { + LOG_INF(COLOR_CYAN "%s location: %s" COLOR_RESET, CONFIG_AUDIO_DEV == HEADSET ? "HEADSET" : "GATEWAY", bt_audio_location_bit_to_str(BIT(i))); + } + } + #endif /* (CONFIG_DEBUG) */ + return 0; } \ No newline at end of file diff --git a/applications/nrf5340_audio/tools/buildprog/nrf5340_audio_dk_devices.py b/applications/nrf5340_audio/tools/buildprog/nrf5340_audio_dk_devices.py index bc76f58d56c8..f22a9ca09cdb 100644 --- a/applications/nrf5340_audio/tools/buildprog/nrf5340_audio_dk_devices.py +++ b/applications/nrf5340_audio/tools/buildprog/nrf5340_audio_dk_devices.py @@ -131,12 +131,11 @@ def __post_init__( def __str__(self): result = f"{self.nrf5340_audio_dk_snr} {self.nrf5340_audio_dk_dev.name}" - if self.nrf5340_audio_dk_dev == AudioDevice.headset: - # Print all location labels if multiple - if isinstance(self.location, list): - result += " " + "+".join([loc.label for loc in self.location]) - else: - result += f" {self.location.name}" + # Print all location labels if multiple + if isinstance(self.location, list): + result += " " + "+".join([loc.label for loc in self.location]) + else: + result += f" {self.location.name}" return result diff --git a/applications/nrf5340_audio/tools/buildprog/program.py b/applications/nrf5340_audio/tools/buildprog/program.py index 5a98dc6b503a..a6abac994ce1 100644 --- a/applications/nrf5340_audio/tools/buildprog/program.py +++ b/applications/nrf5340_audio/tools/buildprog/program.py @@ -9,7 +9,7 @@ from threading import Thread from os import system, path from typing import List -from nrf5340_audio_dk_devices import DeviceConf, SelectFlags, AudioDevice, Location +from nrf5340_audio_dk_devices import DeviceConf, SelectFlags, Location MEM_ADDR_UICR_SNR = 0x00FF80F0 MEM_ADDR_UICR_CH = 0x00FF80F4 @@ -28,15 +28,13 @@ def locations_to_bitfield(locations: List[Location]) -> int: def __populate_uicr(dev): """Program UICR in device with information from JSON file""" - if dev.nrf5340_audio_dk_dev == AudioDevice.headset: - print("Writing UICR with location value: " + str(locations_to_bitfield(dev.location))) - cmd = f"nrfutil device write --serial-number {dev.nrf5340_audio_dk_snr} --address {MEM_ADDR_UICR_CH} --value {locations_to_bitfield(dev.location)}" - # Write location information to UICR - print_location_labels(dev.location) - ret_val = system(cmd) + print("Writing UICR " + str(dev.nrf5340_audio_dk_snr) + " with location value: " + str(locations_to_bitfield(dev.location))) + cmd = f"nrfutil device write --serial-number {dev.nrf5340_audio_dk_snr} --address {MEM_ADDR_UICR_CH} --value {locations_to_bitfield(dev.location)}" + # Write location information to UICR + ret_val = system(cmd) + if ret_val: + return False - if ret_val: - return False cmd = f"nrfutil device write --serial-number {dev.nrf5340_audio_dk_snr} --address {MEM_ADDR_UICR_SNR} --value {dev.nrf5340_audio_dk_snr}" # Write segger nr to UICR diff --git a/applications/nrf5340_audio/unicast_client/overlay-unicast_client.conf b/applications/nrf5340_audio/unicast_client/overlay-unicast_client.conf index f9087c70505f..109b06e68885 100644 --- a/applications/nrf5340_audio/unicast_client/overlay-unicast_client.conf +++ b/applications/nrf5340_audio/unicast_client/overlay-unicast_client.conf @@ -36,3 +36,6 @@ CONFIG_LC3_DEC_CHAN_MAX=1 CONFIG_AUDIO_ENCODE_CHANNELS_MAX=2 CONFIG_MBEDTLS_ENABLE_HEAP=y CONFIG_MBEDTLS_HEAP_SIZE=2048 + +CONFIG_DEVICE_LOCATION_SET_COMPILE_TIME=y +CONFIG_DEVICE_LOCATION_AT_COMPILE_TIME=3 diff --git a/applications/nrf_desktop/api.rst b/applications/nrf_desktop/api.rst index cc837f658078..184426954add 100644 --- a/applications/nrf_desktop/api.rst +++ b/applications/nrf_desktop/api.rst @@ -33,6 +33,14 @@ LED states .. doxygengroup:: nrf_desktop_led_state +Motion events +************* + +| Header file: :file:`applications/nrf_desktop/src/events/motion_event.h` +| Source file: :file:`applications/nrf_desktop/src/events/motion_event.c` + +.. doxygengroup:: nrf_desktop_motion_event + USB events ********** diff --git a/applications/nrf_desktop/configuration/nrf54h20dk_nrf54h20_cpuapp/images/mcuboot/prj.conf b/applications/nrf_desktop/configuration/nrf54h20dk_nrf54h20_cpuapp/images/mcuboot/prj.conf index 4908d11f489c..fa19a3075cc6 100644 --- a/applications/nrf_desktop/configuration/nrf54h20dk_nrf54h20_cpuapp/images/mcuboot/prj.conf +++ b/applications/nrf_desktop/configuration/nrf54h20dk_nrf54h20_cpuapp/images/mcuboot/prj.conf @@ -17,13 +17,7 @@ CONFIG_FLASH=y # Configure support for resuming the application execution after suspend to RAM (S2RAM) # that is requested by the application. MCUboot does not support S2RAM itself, but serves # as an immediate actor while waking up from suspension. -CONFIG_PM=y -CONFIG_PM_S2RAM=y -CONFIG_PM_S2RAM_CUSTOM_MARKING=y -CONFIG_SOC_NRF54H20_PM_S2RAM_OVERRIDE=y - -# Disable device power management as it is not used by the bootloader -CONFIG_PM_DEVICE=n +CONFIG_SOC_EARLY_RESET_HOOK=y # Power domains forced on by default on boot, no need to manage them in bootloader CONFIG_POWER_DOMAIN=n diff --git a/applications/nrf_desktop/configuration/nrf54h20dk_nrf54h20_cpuapp/images/mcuboot/prj_dongle.conf b/applications/nrf_desktop/configuration/nrf54h20dk_nrf54h20_cpuapp/images/mcuboot/prj_dongle.conf index 4908d11f489c..fa19a3075cc6 100644 --- a/applications/nrf_desktop/configuration/nrf54h20dk_nrf54h20_cpuapp/images/mcuboot/prj_dongle.conf +++ b/applications/nrf_desktop/configuration/nrf54h20dk_nrf54h20_cpuapp/images/mcuboot/prj_dongle.conf @@ -17,13 +17,7 @@ CONFIG_FLASH=y # Configure support for resuming the application execution after suspend to RAM (S2RAM) # that is requested by the application. MCUboot does not support S2RAM itself, but serves # as an immediate actor while waking up from suspension. -CONFIG_PM=y -CONFIG_PM_S2RAM=y -CONFIG_PM_S2RAM_CUSTOM_MARKING=y -CONFIG_SOC_NRF54H20_PM_S2RAM_OVERRIDE=y - -# Disable device power management as it is not used by the bootloader -CONFIG_PM_DEVICE=n +CONFIG_SOC_EARLY_RESET_HOOK=y # Power domains forced on by default on boot, no need to manage them in bootloader CONFIG_POWER_DOMAIN=n diff --git a/applications/nrf_desktop/configuration/nrf54h20dk_nrf54h20_cpuapp/images/mcuboot/prj_release.conf b/applications/nrf_desktop/configuration/nrf54h20dk_nrf54h20_cpuapp/images/mcuboot/prj_release.conf index fd4e8471b6c1..7ea38048f75e 100644 --- a/applications/nrf_desktop/configuration/nrf54h20dk_nrf54h20_cpuapp/images/mcuboot/prj_release.conf +++ b/applications/nrf_desktop/configuration/nrf54h20dk_nrf54h20_cpuapp/images/mcuboot/prj_release.conf @@ -19,13 +19,7 @@ CONFIG_RESET_ON_FATAL_ERROR=y # Configure support for resuming the application execution after suspend to RAM (S2RAM) # that is requested by the application. MCUboot does not support S2RAM itself, but serves # as an immediate actor while waking up from suspension. -CONFIG_PM=y -CONFIG_PM_S2RAM=y -CONFIG_PM_S2RAM_CUSTOM_MARKING=y -CONFIG_SOC_NRF54H20_PM_S2RAM_OVERRIDE=y - -# Disable device power management as it is not used by the bootloader -CONFIG_PM_DEVICE=n +CONFIG_SOC_EARLY_RESET_HOOK=y # Power domains forced on by default on boot, no need to manage them in bootloader CONFIG_POWER_DOMAIN=n diff --git a/applications/nrf_desktop/configuration/nrf54h20dk_nrf54h20_cpuapp/images/mcuboot/prj_release_dongle.conf b/applications/nrf_desktop/configuration/nrf54h20dk_nrf54h20_cpuapp/images/mcuboot/prj_release_dongle.conf index fd4e8471b6c1..7ea38048f75e 100644 --- a/applications/nrf_desktop/configuration/nrf54h20dk_nrf54h20_cpuapp/images/mcuboot/prj_release_dongle.conf +++ b/applications/nrf_desktop/configuration/nrf54h20dk_nrf54h20_cpuapp/images/mcuboot/prj_release_dongle.conf @@ -19,13 +19,7 @@ CONFIG_RESET_ON_FATAL_ERROR=y # Configure support for resuming the application execution after suspend to RAM (S2RAM) # that is requested by the application. MCUboot does not support S2RAM itself, but serves # as an immediate actor while waking up from suspension. -CONFIG_PM=y -CONFIG_PM_S2RAM=y -CONFIG_PM_S2RAM_CUSTOM_MARKING=y -CONFIG_SOC_NRF54H20_PM_S2RAM_OVERRIDE=y - -# Disable device power management as it is not used by the bootloader -CONFIG_PM_DEVICE=n +CONFIG_SOC_EARLY_RESET_HOOK=y # Power domains forced on by default on boot, no need to manage them in bootloader CONFIG_POWER_DOMAIN=n diff --git a/applications/nrf_desktop/description.rst b/applications/nrf_desktop/description.rst index ef0a206ba7b7..5cda0720fd99 100644 --- a/applications/nrf_desktop/description.rst +++ b/applications/nrf_desktop/description.rst @@ -1091,7 +1091,7 @@ After building the application with or without :ref:`specifying the build type < .. note:: When a :ref:`configuration with debug features ` is enabled, for example logger and assertions, the gaming mouse report rate can be significantly lower. - Make sure that you use the ``release``configurations before testing the mouse report rate. + Make sure that you use the ``release`` configurations before testing the mouse report rate. For the ``release`` configurations, you should observe a 500-Hz report rate when both the mouse and the keyboard are connected and a 1000-Hz rate when only the mouse is connected. #. Switch the Bluetooth peer on the gaming mouse by pressing the **Precise Aim** button (see `User interface`_). diff --git a/applications/nrf_desktop/doc/hid_provider_mouse.rst b/applications/nrf_desktop/doc/hid_provider_mouse.rst index 3ffe723024af..4ebff8ba846e 100644 --- a/applications/nrf_desktop/doc/hid_provider_mouse.rst +++ b/applications/nrf_desktop/doc/hid_provider_mouse.rst @@ -91,6 +91,8 @@ The HID provider mouse module tracks the number of HID reports in flight and mai * If the number of HID reports in flight is lower than the pipeline size, the module provides additional HID reports to generate the HID report pipeline on user input. * If the number of HID reports in flight is greater than or equal to the pipeline size, the module buffers user input internally and delays providing subsequent HID input reports until previously submitted reports are sent to the HID host. + Apart from this, after a HID input report handled by the module is sent, the module waits for a subsequent :c:struct:`motion_event` before submitting a subsequent HID input report. + This is done to ensure that the recent value of motion will be included in the subsequent HID input report. See the :ref:`nrf_desktop_hid_mouse_report_handling` section for an overview of handling HID mouse input reports in the nRF Desktop. The section focuses on interactions between application modules. diff --git a/applications/nrf_desktop/doc/hid_state_pm.rst b/applications/nrf_desktop/doc/hid_state_pm.rst index 90fec77e86a5..d7265e18a4c6 100644 --- a/applications/nrf_desktop/doc/hid_state_pm.rst +++ b/applications/nrf_desktop/doc/hid_state_pm.rst @@ -24,14 +24,22 @@ Configuration The module is enabled by :ref:`CONFIG_DESKTOP_HID_STATE_PM_ENABLE ` Kconfig option. The option depends on the :kconfig:option:`CONFIG_CAF_POWER_MANAGER` and :ref:`CONFIG_DESKTOP_HID_STATE_ENABLE ` Kconfig options. +It selects the :kconfig:option:`CONFIG_CAF_KEEP_ALIVE_EVENTS` Kconfig option to enable support for the :c:struct:`keep_alive_event`. The option is enabled by default. Implementation details ********************** The module relies on :c:struct:`hid_report_event` to detect HID report exchange. +The module submits a :c:struct:`keep_alive_event` on the HID report exchange to prevent application power down. .. note:: In the nRF Desktop application, most of the HID reports are broadcasted as :c:struct:`hid_report_event`, but there are exceptions. For example, the :ref:`nrf_desktop_config_channel` uses HID feature reports or HID output reports as transport and the configuration channel data is broadcasted using :c:struct:`config_event` in the application. Hence, the |hid_state_pm| does not prevent suspending the device when the configuration channel is in use. + +Tracking power manager restrictions +=================================== + +If the power manager events are supported (:kconfig:option:`CONFIG_CAF_POWER_MANAGER_EVENTS`), the HID state power manager module subscribes to the :c:struct:`power_manager_restrict_event` to track the maximum allowed power level. +If the :c:enum:`POWER_MANAGER_LEVEL_ALIVE` power level is enforced by any application module, the module skips submitting the :c:struct:`keep_alive_event` to reduce the number of performed operations and improve performance. diff --git a/applications/nrf_desktop/doc/motion.rst b/applications/nrf_desktop/doc/motion.rst index 55ced17ab64e..198be09d2ca4 100644 --- a/applications/nrf_desktop/doc/motion.rst +++ b/applications/nrf_desktop/doc/motion.rst @@ -100,10 +100,10 @@ Shell integration If the Zephyr shell is enabled (meaning the :kconfig:option:`CONFIG_SHELL` Kconfig option is set), the motion module registers a ``motion_sim`` shell module and links to it two commands: -* ``start`` - Start sending simulated movement data to the HID subscriber. -* ``stop``- Stop sending simulated movement data to the HID subscriber. +* ``start`` - Start generating simulated movement data. +* ``stop``- Stop generating simulated movement data. -If the shell is enabled, motion generation no longer starts automatically when the HID subscriber connects and after system wakeup (when :c:struct:`wake_up_event` is received). +If the shell is enabled, the module no longer starts generating motion automatically after boot. The simulated movement data generation needs to be triggered using a shell command. Configuration channel diff --git a/applications/nrf_desktop/src/events/motion_event.c b/applications/nrf_desktop/src/events/motion_event.c index 3de6cbc1aa5e..9fee1a001afc 100644 --- a/applications/nrf_desktop/src/events/motion_event.c +++ b/applications/nrf_desktop/src/events/motion_event.c @@ -12,7 +12,8 @@ static void log_motion_event(const struct app_event_header *aeh) { const struct motion_event *event = cast_motion_event(aeh); - APP_EVENT_MANAGER_LOG(aeh, "dx=%d, dy=%d", event->dx, event->dy); + APP_EVENT_MANAGER_LOG(aeh, "dx=%d, dy=%d, %sactive", event->dx, event->dy, + event->active ? "" : "in"); } static void profile_motion_event(struct log_event_buf *buf, @@ -22,11 +23,12 @@ static void profile_motion_event(struct log_event_buf *buf, nrf_profiler_log_encode_int16(buf, event->dx); nrf_profiler_log_encode_int16(buf, event->dy); + nrf_profiler_log_encode_uint8(buf, event->active ? (1) : (0)); } APP_EVENT_INFO_DEFINE(motion_event, - ENCODE(NRF_PROFILER_ARG_S16, NRF_PROFILER_ARG_S16), - ENCODE("dx", "dy"), + ENCODE(NRF_PROFILER_ARG_S16, NRF_PROFILER_ARG_S16, NRF_PROFILER_ARG_U8), + ENCODE("dx", "dy", "active"), profile_motion_event); APP_EVENT_TYPE_DEFINE(motion_event, diff --git a/applications/nrf_desktop/src/events/motion_event.h b/applications/nrf_desktop/src/events/motion_event.h index 37dd05dd2f6e..7b6235597b00 100644 --- a/applications/nrf_desktop/src/events/motion_event.h +++ b/applications/nrf_desktop/src/events/motion_event.h @@ -7,24 +7,41 @@ #ifndef _MOTION_EVENT_H_ #define _MOTION_EVENT_H_ +#include +#include + /** * @brief Motion Event - * @defgroup motion_event Motion Event + * @defgroup nrf_desktop_motion_event Motion Event + * + * The @ref motion_event is used to propagate information about user input (motion sensor samples). + * * @{ */ -#include -#include - #ifdef __cplusplus extern "C" { #endif +/** @brief Motion event. */ struct motion_event { + /** Event header. */ struct app_event_header header; + /** Relative motion over the X axis. */ int16_t dx; + + /** Relative motion over the Y axis. */ int16_t dy; + + /** Information if motion source is still active (fetching) or goes to idle state. + * + * Once HID input report subscription is enabled, an active motion source keeps providing + * motion samples for subsequent HID input reports. The active motion source goes to idle + * state when no motion is detected for some time. The motion source in idle state becomes + * active when motion is detected. + */ + bool active; }; APP_EVENT_TYPE_DECLARE(motion_event); diff --git a/applications/nrf_desktop/src/hw_interface/motion_buttons.c b/applications/nrf_desktop/src/hw_interface/motion_buttons.c index 57c9b3de3c82..a43d0a00b2de 100644 --- a/applications/nrf_desktop/src/hw_interface/motion_buttons.c +++ b/applications/nrf_desktop/src/hw_interface/motion_buttons.c @@ -61,12 +61,13 @@ static motion_ts get_timestamp(void) } } -static void motion_event_send(int16_t dx, int16_t dy) +static void motion_event_send(int16_t dx, int16_t dy, bool active) { struct motion_event *event = new_motion_event(); event->dx = dx; event->dy = dy; + event->active = active; APP_EVENT_SUBMIT(event); } @@ -98,6 +99,11 @@ static enum dir key_to_dir(uint16_t key_id) return dir; } +static bool is_motion_active(void) +{ + return active_dir_bm != 0; +} + static int16_t ts_diff_to_motion(int64_t diff, int32_t *reminder) { int64_t res = diff * CONFIG_DESKTOP_MOTION_BUTTONS_MOTION_PER_SEC + *reminder; @@ -157,7 +163,7 @@ static void send_motion(void) int16_t y; generate_motion(&x, &y); - motion_event_send(x, y); + motion_event_send(x, y, is_motion_active()); } static bool handle_button_event(const struct button_event *event) @@ -196,10 +202,6 @@ static bool handle_module_state_event(const struct module_state_event *event) return false; } -static bool is_motion_active(void) -{ - return active_dir_bm != 0; -} static bool handle_hid_report_sent_event(const struct hid_report_sent_event *event) { diff --git a/applications/nrf_desktop/src/hw_interface/motion_sensor.c b/applications/nrf_desktop/src/hw_interface/motion_sensor.c index f669488684b9..caa6d673e542 100644 --- a/applications/nrf_desktop/src/hw_interface/motion_sensor.c +++ b/applications/nrf_desktop/src/hw_interface/motion_sensor.c @@ -223,7 +223,7 @@ static void data_ready_handler(const struct device *dev, const struct sensor_tri k_spin_unlock(&state.lock, key); } -static int motion_read(bool send_event) +static int motion_read(int16_t *dx, int16_t *dy) { struct sensor_value value_x; struct sensor_value value_y; @@ -239,29 +239,11 @@ static int motion_read(bool send_event) &value_y); } - if (err || !send_event) { - return err; - } - - static unsigned int nodata; - if (!value_x.val1 && !value_y.val1) { - if (nodata < NODATA_LIMIT) { - nodata++; - } else { - nodata = 0; - - return -ENODATA; - } - } else { - nodata = 0; + if (!err) { + *dx = value_x.val1; + *dy = value_y.val1; } - struct motion_event *event = new_motion_event(); - - event->dx = value_x.val1; - event->dy = value_y.val1; - APP_EVENT_SUBMIT(event); - return err; } @@ -472,15 +454,24 @@ static void write_config(void) static void motion_thread_fn(void) { + unsigned int nodata = 0; + struct motion_event *event = NULL; int err = init(); if (!err) { module_set_state(MODULE_STATE_READY); + } else { + /* This thread is supposed to run forever. */ + module_set_state(MODULE_STATE_ERROR); + return; } - while (!err) { + while (true) { bool send_event; uint32_t option_bm; + int16_t dx; + int16_t dy; + bool no_motion = false; k_sem_take(&sem, K_FOREVER); @@ -490,23 +481,50 @@ static void motion_thread_fn(void) option_bm = state.option_mask; k_spin_unlock(&state.lock, key); - err = motion_read(send_event); + err = motion_read(&dx, &dy); + if (err) { + break; + } + + if (send_event) { + if ((dx == 0) && (dy == 0)) { + if (nodata < NODATA_LIMIT) { + nodata++; + } else { + nodata = 0; + no_motion = true; + } + } else { + nodata = 0; + } - bool no_motion = (err == -ENODATA); - if (unlikely(no_motion)) { - err = 0; + if (!event) { + event = new_motion_event(); + } + event->dx = dx; + event->dy = dy; + event->active = !no_motion; } - if (IS_ENABLED(CONFIG_DESKTOP_CONFIG_CHANNEL_ENABLE) && - !err && unlikely(option_bm)) { + if (IS_ENABLED(CONFIG_DESKTOP_CONFIG_CHANNEL_ENABLE) && unlikely(option_bm)) { write_config(); } key = k_spin_lock(&state.lock); - if ((state.state == STATE_FETCHING) && no_motion) { - state.state = STATE_IDLE; + if (state.state == STATE_FETCHING) { + if (send_event) { + __ASSERT_NO_MSG(event); + APP_EVENT_SUBMIT(event); + event = NULL; + + if (no_motion) { + state.state = STATE_IDLE; + } + } } + if (state.state != STATE_FETCHING) { + nodata = 0; enable_trigger(); } k_spin_unlock(&state.lock, key); @@ -534,6 +552,17 @@ static bool handle_usb_state_event(const struct usb_state_event *event) return false; } +static void send_empty_motion_event(void) +{ + struct motion_event *event = new_motion_event(); + + event->dx = 0; + event->dy = 0; + event->active = false; + + APP_EVENT_SUBMIT(event); +} + static bool app_event_handler(const struct app_event_header *aeh) { if (is_hid_report_sent_event(aeh)) { @@ -661,6 +690,10 @@ static bool app_event_handler(const struct app_event_header *aeh) switch (state.state) { case STATE_FETCHING: + /* Send a motion_event to inform about leaving fetching state. */ + send_empty_motion_event(); + /* Fall-through */ + case STATE_IDLE: case STATE_DISCONNECTED: enable_trigger(); diff --git a/applications/nrf_desktop/src/hw_interface/motion_simulated.c b/applications/nrf_desktop/src/hw_interface/motion_simulated.c index 9cb651fed08e..0639e60e4b2e 100644 --- a/applications/nrf_desktop/src/hw_interface/motion_simulated.c +++ b/applications/nrf_desktop/src/hw_interface/motion_simulated.c @@ -57,12 +57,14 @@ static enum state state; static bool generating_motion = !IS_ENABLED(CONFIG_SHELL); -static void motion_event_send(int16_t dx, int16_t dy) +static void motion_event_send(int16_t dx, int16_t dy, bool active) { struct motion_event *event = new_motion_event(); event->dx = dx; event->dy = dy; + event->active = active; + APP_EVENT_SUBMIT(event); } @@ -108,7 +110,7 @@ static void generate_motion_event(void) generate_new_position(&x_new, &y_new); - motion_event_send(x_new - x_cur, y_new - y_cur); + motion_event_send(x_new - x_cur, y_new - y_cur, generating_motion); x_cur = x_new; y_cur = y_new; @@ -194,6 +196,11 @@ static bool app_event_handler(const struct app_event_header *aeh) if (state == STATE_DISCONNECTED) { state = STATE_SUSPENDED_DISCONNECTED; } else if ((state == STATE_IDLE) || (state == STATE_FETCHING)) { + if (state == STATE_FETCHING) { + /* Send a motion_event to inform about leaving fetching state. */ + motion_event_send(0, 0, false); + } + state = STATE_SUSPENDED; } diff --git a/applications/nrf_desktop/src/modules/hid_provider_mouse.c b/applications/nrf_desktop/src/modules/hid_provider_mouse.c index 7fff6856c579..5c7bfbc486d7 100644 --- a/applications/nrf_desktop/src/modules/hid_provider_mouse.c +++ b/applications/nrf_desktop/src/modules/hid_provider_mouse.c @@ -29,12 +29,18 @@ LOG_MODULE_REGISTER(MODULE, CONFIG_DESKTOP_HID_REPORT_PROVIDER_MOUSE_LOG_LEVEL); /* Make sure that mouse buttons would fit in button bitmask. */ BUILD_ASSERT(MOUSE_REPORT_BUTTON_COUNT_MAX <= BITS_PER_BYTE); +enum SYNC_DATA { + SYNC_DATA_MOTION, +}; + struct report_data { uint8_t button_bm; /* Bitmask of pressed mouse buttons. */ int16_t axes[MOUSE_REPORT_AXIS_COUNT]; /* Array of axes (motion X, motion Y, wheel). */ bool update_needed; uint8_t pipeline_cnt; uint8_t pipeline_size; + uint8_t sync_data_active_bm; + uint8_t sync_data_wait_bm; }; static const void *active_sub; @@ -53,6 +59,8 @@ static void clear_report_data(struct report_data *rd) rd->update_needed = false; rd->pipeline_cnt = 0; rd->pipeline_size = 0; + rd->sync_data_active_bm = 0; + rd->sync_data_wait_bm = 0; } static void send_empty_report(uint8_t report_id, const void *subscriber) @@ -88,6 +96,9 @@ static bool send_report_mouse(uint8_t report_id, bool force) } else if (rd->pipeline_cnt >= rd->pipeline_size) { /* Buffer HID data internally until previously submitted reports are sent. */ return false; + } else if (rd->sync_data_wait_bm != 0) { + /* Wait for data from synchronously sampled sensors. */ + return false; } else if (!rd->update_needed) { /* Nothing to send. */ return false; @@ -168,6 +179,9 @@ static bool send_report_boot_mouse(uint8_t report_id, bool force) } else if (rd->pipeline_cnt >= rd->pipeline_size) { /* Buffer HID data internally until previously submitted reports are sent. */ return false; + } else if (rd->sync_data_wait_bm != 0) { + /* Wait for data from synchronously sampled sensors. */ + return false; } else if (!rd->update_needed) { /* Nothing to send. */ return false; @@ -259,6 +273,13 @@ static void mouse_report_sent(uint8_t report_id, bool error) __ASSERT_NO_MSG(((report_id == REPORT_ID_MOUSE) && !boot_mode) || ((report_id == REPORT_ID_BOOT_MOUSE) && boot_mode)); + /* Wait for the synchronously sampled sensors before providing subsequent HID report. + * The sensors are sampled on hid_report_sent_event. + */ + if (report_data.pipeline_cnt >= report_data.pipeline_size) { + report_data.sync_data_wait_bm = report_data.sync_data_active_bm; + } + __ASSERT_NO_MSG(report_data.pipeline_cnt > 0); report_data.pipeline_cnt--; @@ -276,7 +297,10 @@ static void trigger_report_transmission(void) /* Mark that update is needed. */ report_data.update_needed = true; - if (active_sub) { + /* Trigger instant report transmission only if the module does not wait for any data coming + * from a synchronized sensor. Otherwise the module needs to wait for the sensor. + */ + if (active_sub && (report_data.sync_data_wait_bm == 0)) { __ASSERT_NO_MSG(hid_state_api); (void)hid_state_api->trigger_report_send(boot_mode ? REPORT_ID_BOOT_MOUSE : REPORT_ID_MOUSE); @@ -340,7 +364,13 @@ static bool handle_motion_event(const struct motion_event *event) report_data.axes[MOUSE_REPORT_AXIS_X] += event->dx; report_data.axes[MOUSE_REPORT_AXIS_Y] += event->dy; - trigger_report_transmission(); + WRITE_BIT(report_data.sync_data_wait_bm, SYNC_DATA_MOTION, 0); + WRITE_BIT(report_data.sync_data_active_bm, SYNC_DATA_MOTION, event->active); + + /* Skip HID report transmission if motion sensor reports no motion and becomes inactive. */ + if (event->active || (event->dx != 0) || (event->dy != 0)) { + trigger_report_transmission(); + } return false; } diff --git a/applications/nrf_desktop/src/modules/hid_state_pm.c b/applications/nrf_desktop/src/modules/hid_state_pm.c index 22599de259f8..27b12319e070 100644 --- a/applications/nrf_desktop/src/modules/hid_state_pm.c +++ b/applications/nrf_desktop/src/modules/hid_state_pm.c @@ -11,14 +11,40 @@ #define MODULE hid_state_pm #include #include +#include + +static struct module_flags pm_alive_restrict_flags; +static bool pm_alive_enforced; static bool app_event_handler(const struct app_event_header *aeh) { - __ASSERT_NO_MSG(is_hid_report_event(aeh)); - keep_alive(); + if (is_hid_report_event(aeh)) { + if (!pm_alive_enforced) { + keep_alive(); + } + return false; + } + + if (IS_ENABLED(CONFIG_CAF_POWER_MANAGER_EVENTS) && + is_power_manager_restrict_event(aeh)) { + const struct power_manager_restrict_event *event = + cast_power_manager_restrict_event(aeh); + + module_flags_set_bit_to(&pm_alive_restrict_flags, + event->module_idx, + event->level == POWER_MANAGER_LEVEL_ALIVE); + /* Cache the result to improve performance. */ + pm_alive_enforced = !module_flags_check_zero(&pm_alive_restrict_flags); + + return false; + } + return false; } APP_EVENT_LISTENER(MODULE, app_event_handler); APP_EVENT_SUBSCRIBE(MODULE, hid_report_event); +#if CONFIG_CAF_POWER_MANAGER_EVENTS +APP_EVENT_SUBSCRIBE_EARLY(MODULE, power_manager_restrict_event); +#endif /* CONFIG_CAF_POWER_MANAGER_EVENTS */ diff --git a/applications/nrf_desktop/src/modules/hids.c b/applications/nrf_desktop/src/modules/hids.c index 317b7b195860..1287fb8d335a 100644 --- a/applications/nrf_desktop/src/modules/hids.c +++ b/applications/nrf_desktop/src/modules/hids.c @@ -683,7 +683,7 @@ static bool app_event_handler(const struct app_event_header *aeh) return false; } APP_EVENT_LISTENER(MODULE, app_event_handler); -APP_EVENT_SUBSCRIBE(MODULE, hid_report_event); +APP_EVENT_SUBSCRIBE_EARLY(MODULE, hid_report_event); APP_EVENT_SUBSCRIBE(MODULE, hid_notification_event); /* The module is initialized before CAF BLE state module to make sure that the GATT HIDS is * registered before Bluetooth is enabled. This is done to avoid submitting works related to Service diff --git a/applications/nrf_desktop/src/modules/usb_state.c b/applications/nrf_desktop/src/modules/usb_state.c index 32ed8f492357..56c905a82ca9 100644 --- a/applications/nrf_desktop/src/modules/usb_state.c +++ b/applications/nrf_desktop/src/modules/usb_state.c @@ -1567,7 +1567,7 @@ static bool app_event_handler(const struct app_event_header *aeh) } APP_EVENT_LISTENER(MODULE, app_event_handler); APP_EVENT_SUBSCRIBE(MODULE, module_state_event); -APP_EVENT_SUBSCRIBE(MODULE, hid_report_event); +APP_EVENT_SUBSCRIBE_EARLY(MODULE, hid_report_event); #if CONFIG_DESKTOP_CONFIG_CHANNEL_ENABLE APP_EVENT_SUBSCRIBE(MODULE, config_event); #endif diff --git a/boards/nordic/nrf54lv10dk/board.yml b/boards/nordic/nrf54lv10dk/board.yml index 3bde6f7f135e..bf94e3c28677 100644 --- a/boards/nordic/nrf54lv10dk/board.yml +++ b/boards/nordic/nrf54lv10dk/board.yml @@ -13,3 +13,4 @@ board: revisions: - name: "0.0.0" - name: "0.2.0" + - name: "0.7.0" diff --git a/boards/nordic/nrf54lv10dk/nrf54lv10a_cpuapp_common.dtsi b/boards/nordic/nrf54lv10dk/nrf54lv10a_cpuapp_common.dtsi index 24d467118f18..e8eb731c209f 100644 --- a/boards/nordic/nrf54lv10dk/nrf54lv10a_cpuapp_common.dtsi +++ b/boards/nordic/nrf54lv10dk/nrf54lv10a_cpuapp_common.dtsi @@ -21,6 +21,11 @@ zephyr,bt-hci = &bt_hci_sdc; zephyr,ieee802154 = &ieee802154; }; + + aliases { + mcuboot-button0 = &button0; + mcuboot-led0 = &led0; + }; }; &cpuapp_sram { diff --git a/boards/nordic/nrf54lv10dk/nrf54lv10dk_nrf54lv10a_cpuapp_0_7_0.overlay b/boards/nordic/nrf54lv10dk/nrf54lv10dk_nrf54lv10a_cpuapp_0_7_0.overlay new file mode 100644 index 000000000000..d9658327f5d5 --- /dev/null +++ b/boards/nordic/nrf54lv10dk/nrf54lv10dk_nrf54lv10a_cpuapp_0_7_0.overlay @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +/ { + leds { + compatible = "gpio-leds"; + + led0: led_0 { + gpios = <&gpio1 24 GPIO_ACTIVE_HIGH>; + }; + + led1: led_1 { + gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; + }; + + led2: led_2 { + gpios = <&gpio1 25 GPIO_ACTIVE_HIGH>; + }; + + led3: led_3 { + gpios = <&gpio1 22 GPIO_ACTIVE_HIGH>; + }; + }; + + buttons { + compatible = "gpio-keys"; + + button0: button_0 { + gpios = <&gpio1 21 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + }; + + button1: button_1 { + gpios = <&gpio1 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + }; + + button2: button_2 { + gpios = <&gpio1 8 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + }; + + button3: button_3 { + gpios = <&gpio0 4 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + }; + }; +}; diff --git a/boards/nordic/nrf54lv10dk/nrf54lv10dk_nrf54lv10a_cpuapp_0_7_0.yaml b/boards/nordic/nrf54lv10dk/nrf54lv10dk_nrf54lv10a_cpuapp_0_7_0.yaml new file mode 100644 index 000000000000..1fc01fa7bc60 --- /dev/null +++ b/boards/nordic/nrf54lv10dk/nrf54lv10dk_nrf54lv10a_cpuapp_0_7_0.yaml @@ -0,0 +1,20 @@ +# Copyright (c) 2025 Nordic Semiconductor ASA +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + +identifier: nrf54lv10dk@0.7.0/nrf54lv10a/cpuapp +name: nRF54LV10-DK-nRF54LV10A-Application (rev. 0.7.0) +type: mcu +arch: arm +toolchain: + - gnuarmemb + - zephyr +sysbuild: true +ram: 191 +flash: 212 +supported: + - adc + - counter + - gpio + - i2c + - spi + - watchdog diff --git a/boards/nordic/nrf54lv10dk/nrf54lv10dk_nrf54lv10a_cpuflpr_0_2_0.yaml b/boards/nordic/nrf54lv10dk/nrf54lv10dk_nrf54lv10a_cpuflpr_0_2_0.yaml index fa049c360a89..ba0660aed0fc 100644 --- a/boards/nordic/nrf54lv10dk/nrf54lv10dk_nrf54lv10a_cpuflpr_0_2_0.yaml +++ b/boards/nordic/nrf54lv10dk/nrf54lv10dk_nrf54lv10a_cpuflpr_0_2_0.yaml @@ -2,7 +2,7 @@ # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause identifier: nrf54lv10dk@0.2.0/nrf54lv10a/cpuflpr -name: nRF54Lv10-DK-nRF54Lv10a-Fast-Lightweight-Peripheral-Processor (rev. 0.2.0) +name: nRF54LV10-DK-nRF54LV10a-Fast-Lightweight-Peripheral-Processor (rev. 0.2.0) type: mcu arch: riscv toolchain: diff --git a/boards/nordic/nrf54lv10dk/nrf54lv10dk_nrf54lv10a_cpuflpr_0_7_0.overlay b/boards/nordic/nrf54lv10dk/nrf54lv10dk_nrf54lv10a_cpuflpr_0_7_0.overlay new file mode 100644 index 000000000000..d9658327f5d5 --- /dev/null +++ b/boards/nordic/nrf54lv10dk/nrf54lv10dk_nrf54lv10a_cpuflpr_0_7_0.overlay @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +/ { + leds { + compatible = "gpio-leds"; + + led0: led_0 { + gpios = <&gpio1 24 GPIO_ACTIVE_HIGH>; + }; + + led1: led_1 { + gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; + }; + + led2: led_2 { + gpios = <&gpio1 25 GPIO_ACTIVE_HIGH>; + }; + + led3: led_3 { + gpios = <&gpio1 22 GPIO_ACTIVE_HIGH>; + }; + }; + + buttons { + compatible = "gpio-keys"; + + button0: button_0 { + gpios = <&gpio1 21 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + }; + + button1: button_1 { + gpios = <&gpio1 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + }; + + button2: button_2 { + gpios = <&gpio1 8 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + }; + + button3: button_3 { + gpios = <&gpio0 4 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + }; + }; +}; diff --git a/boards/nordic/nrf54lv10dk/nrf54lv10dk_nrf54lv10a_cpuflpr_0_7_0.yaml b/boards/nordic/nrf54lv10dk/nrf54lv10dk_nrf54lv10a_cpuflpr_0_7_0.yaml new file mode 100644 index 000000000000..d4daa2e66a82 --- /dev/null +++ b/boards/nordic/nrf54lv10dk/nrf54lv10dk_nrf54lv10a_cpuflpr_0_7_0.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2025 Nordic Semiconductor ASA +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + +identifier: nrf54lv10dk@0.7.0/nrf54lv10a/cpuflpr +name: nRF54LV10-DK-nRF54LV10a-Fast-Lightweight-Peripheral-Processor (rev. 0.7.0) +type: mcu +arch: riscv +toolchain: + - zephyr +sysbuild: true +ram: 64 +flash: 64 +supported: + - counter + - gpio diff --git a/boards/shields/coverage_support/boards/nrf54lv10dk_nrf54lv10a_cpuapp.overlay b/boards/shields/coverage_support/boards/nrf54lv10dk_nrf54lv10a_cpuapp.overlay index 08c44f11212d..8582ed231a1b 100644 --- a/boards/shields/coverage_support/boards/nrf54lv10dk_nrf54lv10a_cpuapp.overlay +++ b/boards/shields/coverage_support/boards/nrf54lv10dk_nrf54lv10a_cpuapp.overlay @@ -14,6 +14,10 @@ }; }; +&prng { + status = "okay"; +}; + &psa_rng { status = "disabled"; }; diff --git a/cmake/modules/kconfig.cmake b/cmake/modules/kconfig.cmake index fd5fd5e28803..b84cef0a9fcd 100644 --- a/cmake/modules/kconfig.cmake +++ b/cmake/modules/kconfig.cmake @@ -27,8 +27,10 @@ if(CONFIG_NCS_IS_VARIANT_IMAGE) import_kconfig("CONFIG" ${DOTCONFIG}) else() + include(${ZEPHYR_NRF_MODULE_DIR}/cmake/sysbuild/bootloader_dts_utils.cmake) + dt_chosen(code_partition PROPERTY "zephyr,code-partition") - dt_reg_addr(code_partition_offset PATH "${code_partition}" REQUIRED) + dt_partition_addr(code_partition_offset PATH "${code_partition}" REQUIRED) dt_reg_size(code_partition_size PATH "${code_partition}" REQUIRED) set(preload_autoconf_h ${PRELOAD_BINARY_DIR}/zephyr/include/generated/zephyr/autoconf.h) diff --git a/cmake/sysbuild/bootloader_dts_utils.cmake b/cmake/sysbuild/bootloader_dts_utils.cmake index 9567120a60b4..c519768edaba 100644 --- a/cmake/sysbuild/bootloader_dts_utils.cmake +++ b/cmake/sysbuild/bootloader_dts_utils.cmake @@ -5,20 +5,115 @@ # data coming from the devicetree for configurations using # a bootloader. -function(get_address_from_dt_partition_nodelabel label address) - dt_nodelabel(partition_node TARGET ${DEFAULT_IMAGE} NODELABEL ${label} REQUIRED) - dt_reg_addr(partition_offset TARGET ${DEFAULT_IMAGE} PATH ${partition_node}) +function(dt_get_parent node) + string(FIND "${${node}}" "/" pos REVERSE) + + if(pos EQUAL -1) + message(FATAL_ERROR "Unable to get parent of node: ${${node}}") + endif() + + string(SUBSTRING "${${node}}" 0 ${pos} ${node}) + set(${node} "${${node}}" PARENT_SCOPE) +endfunction() + +# Usage: +# dt_partition_addr( [LABEL