From 8d2772093217b0f97623da3abc6b86ab12d203ff Mon Sep 17 00:00:00 2001 From: Mason Tran Date: Mon, 29 Jul 2024 16:29:15 -0400 Subject: [PATCH] [sdk] update to Simplicity SDK v2024.6.0 (#918) * [sdk] add Simplicity SDK for Series 2+ parts Update PAL * [slc] remove usage of daemon mode Using daemon mode causes issues when developing SLC components * [slc] add `ot_efr32` version of `ot_headers` As part of SBOM work, openthread headers were pulled out of SLC components which referenced mostly Silabs code and consolidated into the `ot_headers` component. A requirement for `ot_headers` was then added to affected components. This requirement causes ALL OpenThread headers to be added to any component which previously only required a subset of the headers. In the context of ot-efr32 builds, this causes SLC generation failures as the CMake platform library definitions will now reference all openthread headers in `ot_headers`, which may or may not match up (ex. deleted) with the version of OpenThread checked out in the `openthread` submodule in ot-efr32. This commit adds an ot-efr32 version of `ot_headers` which fixes the issue by pulling in only required headers instead of all headers in the `simplicity_sdk` version of `ot_headers`. * [script] misc. script improvements --- .github/workflows/build.yml | 16 +- .gitmodules | 6 +- README.md | 2 +- .../example_vendor.slce | 6 +- .../projects/example-vendor-rcp-uart.slcp | 2 + ot-efr32.slce | 6 +- ot-efr32.slsdk | 2 +- script/build | 137 +- script/build_example_apps | 7 +- script/efr32-definitions | 89 +- script/generate | 16 +- script/generate_cmake.py | 16 +- script/test | 28 +- src/README.md | 10 +- src/efr32mg12/arm-none-eabi.cmake | 52 - .../PHY_IEEE802154_915MHZ_2GFSK_EFR32XG12.c | 225 --- .../PHY_IEEE802154_915MHZ_OQPSK_EFR32XG12.c | 211 --- src/efr32mg13/arm-none-eabi.cmake | 52 - .../arm-none-eabi.cmake | 2 +- src/src/CMakeLists.txt | 2 +- src/src/alarm.c | 183 ++- src/src/alarm.h | 69 + src/src/crypto.c | 22 +- src/src/flash.c | 50 +- src/src/ieee802154-packet-utils.cpp | 12 +- src/src/memory.c | 4 +- src/src/misc.c | 40 +- src/src/openthread-core-efr32-config-check.h | 6 +- src/src/openthread-core-efr32-config.h | 38 +- src/src/platform-efr32.h | 39 +- src/src/radio.c | 1324 +++++++-------- src/src/radio_coex.c | 189 +++ src/src/radio_power_manager.c | 290 ++++ src/src/sl_gp_interface.c | 335 ++++ ...l_rcp_gp_interface.h => sl_gp_interface.h} | 44 +- src/src/sl_multipan.h | 90 ++ src/src/sl_openthread.h | 2 +- src/src/sl_packet_utils.h | 20 +- src/src/sl_rcp_gp_interface.c | 275 ---- src/src/sleep.c | 7 +- src/src/soft_source_match_table.c | 101 +- src/src/spidrv_usart.c | 8 +- src/src/system.c | 133 +- src/src/uartdrv_uart.c | 99 +- third_party/silabs/cmake/utility.cmake | 8 +- third_party/silabs/gecko_sdk | 1 - third_party/silabs/simplicity_sdk | 1 + .../component/ot_core_vendor_extension.slcc | 5 + .../slc/component/ot_crash_handler.slcc | 63 - .../silabs/slc/component/ot_headers.slcc | 59 + .../component/ot_stack_features_config.slcc | 6 +- .../platform_library/CMakeLists.txt.jinja | 16 +- .../platform_library/mbedtls.cmake.jinja | 2 +- .../openthread-efr32-rcp-spi.slcp | 10 +- .../openthread-efr32-rcp-uart.slcp | 10 +- ...32-soc-with-buttons-power-manager-csl.slcp | 12 +- ...-efr32-soc-with-buttons-power-manager.slcp | 12 +- .../openthread-efr32-soc-with-buttons.slcp | 12 +- .../openthread-efr32-soc.slcp | 12 +- .../silabs/src/legacy_hal/diagnostic.c | 1422 ----------------- 60 files changed, 2438 insertions(+), 3480 deletions(-) delete mode 100644 src/efr32mg12/arm-none-eabi.cmake delete mode 100644 src/efr32mg12/phy/PHY_IEEE802154_915MHZ_2GFSK_EFR32XG12.c delete mode 100644 src/efr32mg12/phy/PHY_IEEE802154_915MHZ_OQPSK_EFR32XG12.c delete mode 100644 src/efr32mg13/arm-none-eabi.cmake rename src/{efr32mg1 => efr32mg26}/arm-none-eabi.cmake (94%) create mode 100644 src/src/alarm.h create mode 100644 src/src/radio_coex.c create mode 100644 src/src/radio_power_manager.c create mode 100644 src/src/sl_gp_interface.c rename src/src/{sl_rcp_gp_interface.h => sl_gp_interface.h} (80%) create mode 100644 src/src/sl_multipan.h delete mode 100644 src/src/sl_rcp_gp_interface.c delete mode 160000 third_party/silabs/gecko_sdk create mode 160000 third_party/silabs/simplicity_sdk delete mode 100644 third_party/silabs/slc/component/ot_crash_handler.slcc create mode 100644 third_party/silabs/slc/component/ot_headers.slcc delete mode 100644 third_party/silabs/src/legacy_hal/diagnostic.c diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 024785fb..12051c51 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -106,23 +106,23 @@ jobs: -v $PWD:/ot-efr32 -w /ot-efr32\ ${{ env.DOCKER_IMAGE_SHA_TAG }} - - name: Append LFS include config to GSDK .lfsconfig + - name: Append LFS include config to simplicity_sdk .lfsconfig run: | - git -C third_party/silabs/gecko_sdk checkout -- .lfsconfig - echo 'fetchinclude = "platform/emdrv/nvm3/lib/libnvm3_*_gcc.a,platform/radio/rail_lib/autogen/librail_release/librail_config_mgm*_gcc.a,platform/radio/rail_lib/autogen/librail_release/*efr32xg*_gcc_release.a"' >> third_party/silabs/gecko_sdk/.lfsconfig + git -C third_party/silabs/simplicity_sdk checkout -- .lfsconfig + echo 'fetchinclude = "platform/emdrv/nvm3/lib/libnvm3_*_gcc.a,platform/radio/rail_lib/autogen/librail_release/librail_config_mgm*_gcc.a,platform/radio/rail_lib/autogen/librail_release/*efr32xg*_gcc_release.a"' >> third_party/silabs/simplicity_sdk/.lfsconfig - name: Create LFS file hash list - run: git -C third_party/silabs/gecko_sdk lfs ls-files -l | cut -d' ' -f1 | sort > .lfs-assets-id + run: git -C third_party/silabs/simplicity_sdk lfs ls-files -l | cut -d' ' -f1 | sort > .lfs-assets-id - - name: Restore gecko_sdk LFS cache + - name: Restore simplicity_sdk LFS cache uses: actions/cache@v4 - id: lfs-cache-gecko_gsdk + id: lfs-cache-simplicity_sdk with: - path: .git/modules/third_party/silabs/gecko_sdk/lfs + path: .git/modules/third_party/silabs/simplicity_sdk/lfs key: lfs-${{ hashFiles('.lfs-assets-id') }} - name: Git LFS Pull - run: git -C third_party/silabs/gecko_sdk lfs pull + run: git -C third_party/silabs/simplicity_sdk lfs pull - name: Build run: docker exec ot-efr32-dev bash -c 'PATH=${{ env.TOOLCHAIN_DIR }}/${{ matrix.gcc_extract_dir }}/bin:$PATH script/test' diff --git a/.gitmodules b/.gitmodules index 611db35a..dc5557cf 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "openthread"] path = openthread url = https://github.com/openthread/openthread.git -[submodule "third_party/silabs/gecko_sdk"] - path = third_party/silabs/gecko_sdk - url = https://github.com/SiliconLabs/gecko_sdk.git +[submodule "third_party/silabs/simplicity_sdk"] + path = third_party/silabs/simplicity_sdk + url = https://github.com/SiliconLabs/simplicity_sdk.git diff --git a/README.md b/README.md index ab3b43d5..5d76b3db 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ The example platform drivers are intended to present the minimal code necessary When using this repo to generate a solution that requires two different projects, such as an RCP & OTBR, make sure they are relying on the same OpenThread version to ensure maximum compatibility. You can check which commit this repo relies upon in the "openthread" submodule. -If your OTBR project was generated using the Silabs GSDK / Simplicity Studio, we recommend to also use it to generate the RCP project and not this repo. This will mitigate potential incompatibility issues due to mismatched OpenThread versions. +If your OTBR project was generated using the Silabs SiSDK / Simplicity Studio, we recommend to also use it to generate the RCP project and not this repo. This will mitigate potential incompatibility issues due to mismatched OpenThread versions. To learn more about building and running the examples please check: diff --git a/examples/example_vendor_slc_extension/example_vendor.slce b/examples/example_vendor_slc_extension/example_vendor.slce index 8ab63d12..1547f2b6 100644 --- a/examples/example_vendor_slc_extension/example_vendor.slce +++ b/examples/example_vendor_slc_extension/example_vendor.slce @@ -37,10 +37,10 @@ id: example_vendor version: 0.0.1 -description: "example_vendor extension for Gecko SDK Suite" +description: "example_vendor extension for Simplicity SDK Suite" label: "Example Vendor extension" sdk: - id: gecko_sdk - version: 4.2.1 + id: simplicity_sdk + version: 2024.6.0 component_path: - path: component diff --git a/examples/example_vendor_slc_extension/projects/example-vendor-rcp-uart.slcp b/examples/example_vendor_slc_extension/projects/example-vendor-rcp-uart.slcp index d49e8336..69de20bb 100644 --- a/examples/example_vendor_slc_extension/projects/example-vendor-rcp-uart.slcp +++ b/examples/example_vendor_slc_extension/projects/example-vendor-rcp-uart.slcp @@ -35,6 +35,8 @@ quality: production component: - id: ot_platform_abstraction_core + - id: ot_headers + from: ot-efr32 - id: ot_mbedtls - id: ot_stack_features_config from: ot-efr32 diff --git a/ot-efr32.slce b/ot-efr32.slce index 580461f1..3ea5fc2e 100644 --- a/ot-efr32.slce +++ b/ot-efr32.slce @@ -1,9 +1,9 @@ id: ot-efr32 version: 0.0.1 -description: "ot-efr32 extension for Gecko SDK Suite" +description: "ot-efr32 extension for Simplicity SDK Suite" label: "Silicon Labs OpenThread" sdk: - id: gecko_sdk - version: 4.4.0 + id: simplicity_sdk + version: 2024.6.0 component_path: - path: third_party/silabs/slc/component diff --git a/ot-efr32.slsdk b/ot-efr32.slsdk index 77d4c64d..6462b291 100644 --- a/ot-efr32.slsdk +++ b/ot-efr32.slsdk @@ -4,6 +4,6 @@ id=com.silabs.sdk.ot-efr32 version=0.0.1 label=Silicon Labs ot-efr32 -description=ot-efr32 extension for Gecko SDK Suite +description=ot-efr32 extension for Simplicity SDK Suite prop.subLabel=Silicon Labs ot-efr32\\ 0.0.1-1.0 diff --git a/script/build b/script/build index 61b91793..2e020a18 100755 --- a/script/build +++ b/script/build @@ -29,7 +29,7 @@ # ============================================================================== # Bash definitions - +# ============================================================================== if [[ -n ${BASH_SOURCE[0]} ]]; then script_path="${BASH_SOURCE[0]}" else @@ -37,52 +37,11 @@ else fi script_dir="$(realpath "$(dirname "${script_path}")")" repo_dir="$(dirname "${script_dir}")" -gsdk_dir="${repo_dir}/third_party/silabs/gecko_sdk" - -# shellcheck source=script/efr32-definitions -source "${repo_dir}/script/efr32-definitions" - -# shellcheck source=script/util -source "${repo_dir}/script/util" - -set -euxo pipefail - -# ============================================================================== -# Pre-build checks - -set +x -echo "=========================================================================================================" -echo "Check if the Git LFS package is installed" -echo "=========================================================================================================" -set -x -if ! git lfs >/dev/null; then - set +x - echo "ERROR: Git LFS is not installed" - echo - echo "Please run './script/bootstrap packages'" to install it - exit 3 -fi - -set +x -echo "=========================================================================================================" -echo "Ensure Git LFS has been initialized for the GSDK" -echo "=========================================================================================================" -set -x -if [ ! -f "$(git -C "${gsdk_dir}" rev-parse --git-dir)/hooks/pre-push" ]; then - git -C "${gsdk_dir}" lfs install -fi - -set +x -echo "=========================================================================================================" -echo "Ensure GSDK submodule has been initialized and LFS objects have been pulled" -echo "=========================================================================================================" -set -x -git submodule update --init "${gsdk_dir}" -git -C "${gsdk_dir}" lfs pull -# ============================================================================== +# CMake Build targets OT_CMAKE_NINJA_TARGET=${OT_CMAKE_NINJA_TARGET-} +# CMake Build options OT_OPTIONS=( "-DCMAKE_BUILD_TYPE=Release" "-DOT_DIAGNOSTIC=ON" @@ -97,6 +56,72 @@ if command -v ccache >/dev/null; then fi readonly OT_OPTIONS +# ============================================================================== +# shellcheck source=script/efr32-definitions +source "${repo_dir}/script/efr32-definitions" + +# shellcheck source=script/slc_cli +source "${repo_dir}/script/slc_cli" + +# shellcheck source=script/util +source "${repo_dir}/script/util" + +set -euxo pipefail + +# ============================================================================== +# Pre-build checks +# ============================================================================== +# Initialize the Silicon Labs SDK +# This function initializes the Silicon Labs SDK submodule and checks if the platform is supported +# Arguments: +# $1: The board name +# Returns: +# None +init_silabs_sdk() +{ + set +x + echo "=========================================================================================================" + echo "Ensure SDK submodule has been initialized" + echo "=========================================================================================================" + set -x + # Skip LFS files for now. They will be pulled in init_silabs_sdk_lfs() + GIT_LFS_SKIP_SMUDGE=true git submodule update --init "${sdk_dir}" + + set +x + echo "=========================================================================================================" + echo "Check if the Git LFS package is installed" + echo "=========================================================================================================" + set -x + if ! git lfs >/dev/null; then + set +x + echo "ERROR: Git LFS is not installed" + echo + echo "Please run './script/bootstrap packages'" to install it + exit 3 + fi + + set +x + echo "=========================================================================================================" + echo "Ensure Git LFS has been initialized for the SDK" + echo "=========================================================================================================" + set -x + if [ ! -f "$(git -C "${sdk_dir}" rev-parse --git-dir)/hooks/pre-push" ]; then + git -C "${sdk_dir}" lfs install + fi + + set +x + echo "=========================================================================================================" + echo "Ensure LFS objects have been pulled" + echo "=========================================================================================================" + set -x + + # TODO: Add .lfsconfig lines to only fetch the necessary files + git -C "${sdk_dir}" lfs pull +} + +# ============================================================================== +# Build functions +# ============================================================================== generate() { if [ "${skip_generation}" = true ]; then @@ -234,6 +259,7 @@ build_soc() cd "${repo_dir}" } +# ============================================================================== main() { local usage="usage: $0 [-h] [--skip-silabs-apps] [-D -D]" @@ -281,20 +307,28 @@ main() shift fi - platform=$(efr32_get_platform "${board}") + # Check if a platform can be found for a given board in Simplicity SDK + platform=$(efr32_get_platform "${board}" "${sisdk_dir}") + + # Check if the platform is supported efr32_check_platform "${platform}" || die "Unsupported platform ${platform}" + set +x + echo "=========================================================================================================" + echo "Using Simplicity SDK for board ${board} (${platform})" + echo "=========================================================================================================" + set -x + # Initialize the SDK + init_silabs_sdk "${board}" + local options=("${OT_OPTIONS[@]}") options+=("-DCMAKE_TOOLCHAIN_FILE=src/${platform}/arm-none-eabi.cmake") + # Set default OT_CMAKE_NINJA_TARGET based on platform if [ -z "${OT_CMAKE_NINJA_TARGET}" ]; then case "${platform}" in - efr32mg1) - OT_CMAKE_NINJA_TARGET=("ot-rcp-uart") - skip_silabs_apps=true - ;; - efr32mg12 | efr32mg13 | efr32mg21 | efr32mg24) + efr32mg2*) OT_CMAKE_NINJA_TARGET=("ot-rcp-uart" "ot-rcp-spi" "ot-cli-ftd" "ot-cli-mtd" "ot-ncp-ftd" "ot-ncp-mtd") ;; esac @@ -333,7 +367,7 @@ main() fi # Build silabs apps - if [ "${skip_silabs_apps}" = false ]; then + if [ -z ${OT_CMAKE_NINJA_TARGET+x} ] && [ "${skip_silabs_apps}" = false ]; then local before_flags=() local after_flags=() @@ -342,7 +376,6 @@ main() fi "${repo_dir}"/script/build_example_apps "${before_flags[@]-}" "${board}" "${after_flags[@]-}" "$@" - fi ls -alh "${OT_CMAKE_BUILD_DIR}"/openthread/*/bin/* diff --git a/script/build_example_apps b/script/build_example_apps index 75c92a8e..7f5ac146 100755 --- a/script/build_example_apps +++ b/script/build_example_apps @@ -40,12 +40,10 @@ fi script_dir="$(realpath "$(dirname "${script_path}")")" repo_dir="$(dirname "${script_dir}")" +# ============================================================================== # shellcheck source=script/efr32-definitions source "${repo_dir}/script/efr32-definitions" -# shellcheck source=script/slc_cli -source "${repo_dir}/script/slc_cli" - # shellcheck source=script/util source "${repo_dir}/script/util" @@ -245,9 +243,6 @@ main() options+=("-DCMAKE_TOOLCHAIN_FILE=src/${platform}/arm-none-eabi.cmake") - # Find slc-cli installation - slc_init - options+=("$@") export OT_CMAKE_BUILD_DIR="$repo_dir/build/${board}" slc_generated_projects_dir="${OT_CMAKE_BUILD_DIR}"/slc diff --git a/script/efr32-definitions b/script/efr32-definitions index 8dd7499d..263f2528 100755 --- a/script/efr32-definitions +++ b/script/efr32-definitions @@ -29,6 +29,7 @@ # ============================================================================== # Bash definitions +# ============================================================================== if [[ -n ${BASH_SOURCE[0]} ]]; then script_path="${BASH_SOURCE[0]}" @@ -41,42 +42,54 @@ if [ -z ${repo_dir+x} ]; then script_dir="$(realpath "$(dirname "${script_path}")")" repo_dir="$(dirname "${script_dir}")" fi -# Check if gsdk_dir is defined -if [ -z ${gsdk_dir+x} ]; then - gsdk_dir="${repo_dir}/third_party/silabs/gecko_sdk" -fi -efr32_device_regex="" -efr32_device_regex+="\(efr32\)*" # Group 1 - efr32 (optional) -efr32_device_regex+="\([[:alpha:]]\{2\}\)" # Group 2 - mg, bg, xg (product line) -efr32_device_regex+="\(m*\)" # Group 3 - m (optional, modules only) -efr32_device_regex+="\([[:digit:]]\{1,2\}\)[[:digit:]]\{0,1\}" # Group 4 - 1, 12, 13, 21, 24, 210, 240 etc (series and configuration) -efr32_device_regex+="\([[:alpha:]]\{1\}\)" # Group 5 - a, b, c, p, v (revision) -efr32_device_regex+="\([[:alpha:]]\{0,1\}[[:digit:]]\{1,3\}\)" # Group 6 - xxx, a32, 032 -efr32_device_regex+="\(f[[:digit:]]\{1,\}\)*" # Group 7 - fXXX (flash size) -efr32_device_regex+="\([[:alpha:]]\{2,3\}\)*" # Group 8 - im, gl, gm, jia, vna, etc -efr32_device_regex+="\(f[[:digit:]]\{1,\}\)*" # Group 9 - 32, 40, 48, 68, 125 -efr32_device_regex+=".*" # Rest of line -readonly efr32_device_regex +# Define the regex for efr32 devices if not already defined +if [ -z ${efr32_device_regex+x} ]; then + efr32_device_regex="" + efr32_device_regex+="\(efr32\)*" # Group 1 - efr32 (optional) + efr32_device_regex+="\([[:alpha:]]\{2\}\)" # Group 2 - mg, bg, xg (product line) + efr32_device_regex+="\(m*\)" # Group 3 - m (optional, modules only) + efr32_device_regex+="\([[:digit:]]\{1,2\}\)[[:digit:]]\{0,1\}" # Group 4 - 1, 12, 13, 21, 24, 210, 240 etc (series and configuration) + efr32_device_regex+="\([[:alpha:]]\{1\}\)" # Group 5 - a, b, c, p, v (revision) + efr32_device_regex+="\([[:alpha:]]\{0,1\}[[:digit:]]\{1,3\}\)" # Group 6 - xxx, a32, 032 + efr32_device_regex+="\(f[[:digit:]]\{1,\}\)*" # Group 7 - fXXX (flash size) + efr32_device_regex+="\([[:alpha:]]\{2,3\}\)*" # Group 8 - im, gl, gm, jia, vna, etc + efr32_device_regex+="\(f[[:digit:]]\{1,\}\)*" # Group 9 - 32, 40, 48, 68, 125 + efr32_device_regex+=".*" # Rest of line + readonly efr32_device_regex +fi # ============================================================================== +# SDKs +# ============================================================================== +# Simplicity SDK +sisdk_dir="${repo_dir}/third_party/silabs/simplicity_sdk" +readonly sisdk_dir + +# SDK directory to use +sdk_dir="${sisdk_dir}" +# ============================================================================== efr32_get_board_slcc() { local -r \ doc="Gets the latest revision .slcc file for a efr32 board" # - # Arg $1 -- efr32 board - if [ $# -ne 1 ] || [ -z "$1" ]; then - printf "%s\n\nUsage:\n\t%s \n" "${doc}" "${FUNCNAME[0]}" >&2 + # Arg $1 -- efr32 board (optional) (default: $board) + # Arg $2 -- SDK directory (optional) (default: $sdk_dir) + if [ $# -lt 1 ] || [ -z "$1" ]; then + printf "%s\n\nUsage:\n\t%s [efr32_board] \n" "${doc}" "${FUNCNAME[0]}" >&2 return 1 fi - local board=$1 + + # Default to existing values if not provided as arguments + local board=${1:-${board:?}} + local sdk_dir=${2:-${sdk_dir:?}} # Find component file for latest revision of board local board_slcc board_slcc=$( - find "${gsdk_dir}"/hardware/board/component -type f \( -name "${board}*" ! -name '*_support.slcc' \) \ + find "${sdk_dir}"/hardware/board/component -type f \( -name "${board}*" ! -name '*_support.slcc' \) \ | sort --version-sort \ | tail -n 1 ) @@ -85,7 +98,19 @@ efr32_get_board_slcc() efr32_get_platform() { - local board=${board-$1} + local -r \ + doc="Gets the platform for a efr32 board" + # + # Arg $1 -- efr32 board (optional) (default: $board) + # Arg $2 -- SDK directory (optional) (default: $sdk_dir) + if [ $# -gt 2 ]; then + printf "%s\n\nUsage:\n\t%s \n" "${doc}" "${FUNCNAME[0]}" >&2 + return 1 + fi + + # Default to existing values if not provided as arguments + local board=${1:-${board:?}} + local sdk_dir=${2:-${sdk_dir:?}} # Find component file for latest revision of board local board_slcc @@ -99,11 +124,6 @@ efr32_get_platform() | head -n 1 ) - if [ -z "${platform}" ]; then - echo "Error parsing platform" - exit 3 - fi - echo "${platform}" } @@ -115,9 +135,15 @@ efr32_get_platforms() efr32_check_platform() { - # Checks if a value is a valid efr32 platform + local -r \ + doc="Checks if a value is a valid efr32 platform" # - # Arg $1 -- value + # Arg $1 -- platform + if [ $# -ne 1 ]; then + printf "%s\n\nUsage:\n\t%s \n" "${doc}" "${FUNCNAME[0]}" >&2 + return 1 + fi + local match=false local platform="${1?}" @@ -128,10 +154,11 @@ efr32_check_platform() fi done + # if no match, print error message if ! $match; then set +x - printf "\n\nERROR: Invalid platform\n" >&2 - printf "Valid platforms:\n" >&2 + printf "\n\nERROR: Unsupported platform\n" >&2 + printf "Supported platforms:\n" >&2 for platform in $(efr32_get_platforms); do printf " - %s\n" "${platform}" >&2 done diff --git a/script/generate b/script/generate index e6f3b6bd..383195a8 100755 --- a/script/generate +++ b/script/generate @@ -39,7 +39,7 @@ else fi script_dir="$(realpath "$(dirname "${script_path}")")" repo_dir="$(dirname "${script_dir}")" -sdk_dir="${repo_dir}/third_party/silabs/gecko_sdk" +sdk_dir="${repo_dir}/third_party/silabs/simplicity_sdk" # shellcheck source=script/slc_cli source "${repo_dir}/script/slc_cli" @@ -86,14 +86,14 @@ trust_sdk_and_extensions() set +x echo "======================================================================" - echo "Trusting Gecko SDK :'${sdk_dir}':" + echo "Trusting Simplicity SDK :'${sdk_dir}':" echo "======================================================================" set -x - # Trust the Gecko SDK submodule - run_slc --daemon -v 1 signature trust --sdk "${sdk_dir}" -data "${openthread_slc_data}" + # Trust the Simplicity SDK submodule + run_slc -v 1 signature trust --sdk "${sdk_dir}" -data "${openthread_slc_data}" - # Ensure GSDK extension folder exists + # Ensure SDK extension folder exists mkdir -p "${sdk_dir}/extension" set +x @@ -138,7 +138,7 @@ trust_sdk_and_extensions() fi # Trust the extension - run_slc --daemon -v 1 signature trust --sdk "${sdk_dir}" -extpath "${extension_symlink}" -data "${openthread_slc_data}" + run_slc -v 1 signature trust --sdk "${sdk_dir}" -extpath "${extension_symlink}" -data "${openthread_slc_data}" done ls -alh "${sdk_dir}/extension" @@ -215,9 +215,11 @@ generate() echo "======================================================================" set -x - run_slc --daemon -v 1 generate \ + run_slc -v 1 generate \ -data "${openthread_slc_data?}" \ + --cache-home "${build_dir}/slc/slcc_components.cache" \ --sdk="${sdk_dir?}" \ + --clear-cache \ --project-file="${slcp}" \ --project-name="${project_name}" \ --output-type=makefile \ diff --git a/script/generate_cmake.py b/script/generate_cmake.py index 754ab9d6..02903b24 100755 --- a/script/generate_cmake.py +++ b/script/generate_cmake.py @@ -53,14 +53,14 @@ def prepare_path(path: str) -> str: if path.startswith('"') and path.endswith('"'): path = path.strip('"') - # Replace SDK_PATH with SILABS_GSDK_DIR - path = path.replace('(SDK_PATH)', '{SILABS_GSDK_DIR}') + # Replace SDK_PATH with SILABS_SDK_DIR + path = path.replace('(SDK_PATH)', '{SILABS_SDK_DIR}') # Redirect OpenThread stack sources to the ot-efr32 openthread submodule #} - path = path.replace('${SILABS_GSDK_DIR}/util/third_party/openthread', '${PROJECT_SOURCE_DIR}/openthread') + path = path.replace('${SILABS_SDK_DIR}/util/third_party/openthread', '${PROJECT_SOURCE_DIR}/openthread') # Redirect PAL sources to the ot-efr32 PAL - path = path.replace('${SILABS_GSDK_DIR}/protocol/openthread/platform-abstraction/efr32', + path = path.replace('${SILABS_SDK_DIR}/protocol/openthread/platform-abstraction/efr32', '${PROJECT_SOURCE_DIR}/src/src') return path @@ -68,7 +68,7 @@ def prepare_path(path: str) -> str: def is_mbedtls_source(source: str) -> bool: r: bool = False - r |= '${SILABS_GSDK_DIR}/util/third_party/mbedtls' in source + r |= '${SILABS_SDK_DIR}/util/third_party/mbedtls' in source return r @@ -107,9 +107,9 @@ def filter_mbedtls_lib_vars(slc_vars: dict) -> dict: def f(include: str) -> bool: keep: bool = False keep |= (include == '"autogen"') or (include == '"config"') - keep |= '${SILABS_GSDK_DIR}/hardware' in include - keep |= '${SILABS_GSDK_DIR}/platform' in include - keep |= '${SILABS_GSDK_DIR}/util/third_party/crypto' in include + keep |= '${SILABS_SDK_DIR}/hardware' in include + keep |= '${SILABS_SDK_DIR}/platform' in include + keep |= '${SILABS_SDK_DIR}/util/third_party/crypto' in include if not keep: pass return keep diff --git a/script/test b/script/test index f3b54736..0e2bd114 100755 --- a/script/test +++ b/script/test @@ -61,22 +61,6 @@ readonly OT_OPTIONS=( ) # List of boards to test -readonly MG1_BOARDS=( - brd4151a -) - -readonly MG12_BOARDS=( - brd4161a - brd4164a - brd4166a - brd4170a - brd4304a -) - -readonly MG13_BOARDS=( - brd4168a -) - readonly MG21_BOARDS=( brd4180a brd4180b @@ -88,6 +72,10 @@ readonly MG24_BOARDS=( brd4187c ) +readonly MG26_BOARDS=( + brd4116a +) + # ============================================================================== main() @@ -123,19 +111,15 @@ main() BOARDS=() if [ "${all_boards}" = true ]; then BOARDS+=( - "${MG1_BOARDS[@]}" - "${MG12_BOARDS[@]}" - "${MG13_BOARDS[@]}" "${MG21_BOARDS[@]}" "${MG24_BOARDS[@]}" + "${MG26_BOARDS[@]}" ) else BOARDS+=( - "${MG1_BOARDS[0]}" - "${MG12_BOARDS[0]}" - "${MG13_BOARDS[0]}" "${MG21_BOARDS[0]}" "${MG24_BOARDS[0]}" + "${MG26_BOARDS[0]}" ) fi diff --git a/src/README.md b/src/README.md index 18912df3..3e44e72a 100644 --- a/src/README.md +++ b/src/README.md @@ -38,7 +38,7 @@ See [EFR32 Sleepy Demo Example](../examples/sleepy-demo/README.md) for instructi When using this repo to generate a solution that requires two different projects, such as an RCP & OTBR, make sure they are relying on the same OpenThread version to ensure maximum compatibility. You can check which commit this repo relies upon in the "openthread" submodule (in the root of this repo). -If your OTBR project was generated using the Silabs GSDK / Simplicity Studio, we recommend to also use it to generate the RCP project and not this repo. This will mitigate potential incompatibility issues due to mismatched OpenThread versions. +If your OTBR project was generated using the Silabs SiSDK / Simplicity Studio, we recommend to also use it to generate the RCP project and not this repo. This will mitigate potential incompatibility issues due to mismatched OpenThread versions. @@ -122,7 +122,7 @@ Simplicity Commander provides command line and graphical interfaces for J-Link C - [Mac](https://www.silabs.com/documents/public/software/SimplicityCommander-Mac.zip) - [Windows](https://www.silabs.com/documents/public/software/SimplicityCommander-Windows.zip) -For Windows and Linux, the Simplicity Commander executable can be found in the location that the package is extracted. +For Windows and Linux, the Simplicity Commander executable can be found in the location that the package is extracted. On MacOS, the executable can be found at the following directory: ```bash @@ -142,7 +142,7 @@ Launch the Simplicity Commander executable `commander` at the path stated above #### Commander CLI -The Simplicity Commander CLI provides another method of flashing binaries to a device without opening a GUI. +The Simplicity Commander CLI provides another method of flashing binaries to a device without opening a GUI. When using Simplicity Commander in CLI mode, it is highly recommended to add the directory of the executable to your environment's `PATH` variable. This can be done with the following command: ```bash @@ -349,6 +349,6 @@ The following toolchain has been used for testing and verification: - gcc version 7.3.1 -The EFR32 example has been verified with following Silicon Labs Gecko SDK Library version: +The EFR32 example has been verified with following Silicon Labs Simplicity SDK Library version: -- Silicon Labs Gecko SDK v4.1.x +- Silicon Labs Simplicity SDK v4.1.x diff --git a/src/efr32mg12/arm-none-eabi.cmake b/src/efr32mg12/arm-none-eabi.cmake deleted file mode 100644 index 543c7ac4..00000000 --- a/src/efr32mg12/arm-none-eabi.cmake +++ /dev/null @@ -1,52 +0,0 @@ -# -# Copyright (c) 2021, The OpenThread Authors. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. Neither the name of the copyright holder nor the -# names of its contributors may be used to endorse or promote products -# derived from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# - -set(CMAKE_SYSTEM_NAME Generic) -set(CMAKE_SYSTEM_PROCESSOR ARM) - -set(CMAKE_C_COMPILER arm-none-eabi-gcc) -set(CMAKE_CXX_COMPILER arm-none-eabi-g++) -set(CMAKE_ASM_COMPILER arm-none-eabi-gcc) -set(CMAKE_RANLIB arm-none-eabi-ranlib) - -execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE COMPILER_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) - -set(COMMON_C_FLAGS "-mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -mthumb -fdata-sections -ffunction-sections") - -set(CMAKE_C_FLAGS_INIT "${COMMON_C_FLAGS} -std=c99") -set(CMAKE_CXX_FLAGS_INIT "${COMMON_C_FLAGS} -fno-exceptions -fno-rtti") -set(CMAKE_ASM_FLAGS_INIT "${CMAKE_C_FLAGS_INIT} -x assembler-with-cpp") -set(CMAKE_EXE_LINKER_FLAGS_INIT "${COMMON_C_FLAGS} -specs=nano.specs -specs=nosys.specs") - -set(CMAKE_C_FLAGS_DEBUG "-Og -g") -set(CMAKE_CXX_FLAGS_DEBUG "-Og -g") -set(CMAKE_ASM_FLAGS_DEBUG "-g") - -set(CMAKE_C_FLAGS_RELEASE "-Os") -set(CMAKE_CXX_FLAGS_RELEASE "-Os") -set(CMAKE_ASM_FLAGS_RELEASE "") diff --git a/src/efr32mg12/phy/PHY_IEEE802154_915MHZ_2GFSK_EFR32XG12.c b/src/efr32mg12/phy/PHY_IEEE802154_915MHZ_2GFSK_EFR32XG12.c deleted file mode 100644 index 76df956d..00000000 --- a/src/efr32mg12/phy/PHY_IEEE802154_915MHZ_2GFSK_EFR32XG12.c +++ /dev/null @@ -1,225 +0,0 @@ -/***************************************************************************/ -/** - * @brief RAIL Configuration - * @details - * WARNING: Auto-Generated Radio Config - * - DO NOT EDIT Radio Configurator - * Version: 2021.3.1 RAIL Adapter - * Version: 2.4.14 RAIL Compatibility: 2.x - ******************************************************************************* - * # License - * Copyright 2019 Silicon Laboratories Inc. www.silabs.com - ******************************************************************************* - * - * SPDX-License-Identifier: Zlib - * - * The licensor of this software is Silicon Laboratories Inc. - * - * This software is provided 'as-is', without any express or implied warranty. - * In no event will the authors be held liable for any damages arising from the - * use of this software. - * - * Permission is granted to anyone to use this software for any purpose, including - * commercial applications, and to alter it and redistribute it freely, subject to - * the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not claim - * that you wrote the original software. If you use this software in a product, an - * acknowledgment in the product documentation would be appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - * - ******************************************************************************/ -#include "em_device.h" -#include "rail_config.h" - -#if RADIO_CONFIG_915MHZ_2GFSK_SUPPORT - -uint32_t RAILCb_CalcSymbolRate(RAIL_Handle_t railHandle) -{ - (void)railHandle; - return 0U; -} - -uint32_t RAILCb_CalcBitRate(RAIL_Handle_t railHandle) -{ - (void)railHandle; - return 0U; -} - -void RAILCb_ConfigFrameTypeLength(RAIL_Handle_t railHandle, const RAIL_FrameType_t *frameType) -{ - (void)railHandle; - (void)frameType; -} - -static const uint8_t generated_irCalConfig[] = {25, 71, 3, 6, 4, 16, 0, 1, 1, 3, 1, 6, 0, - 16, 39, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0}; - -static const uint32_t generated_phyInfo[] = { - 5UL, - 0x00999999UL, // 153.60000000000002 - (uint32_t)NULL, - (uint32_t)generated_irCalConfig, -#ifdef RADIO_CONFIG_ENABLE_TIMING - (uint32_t)&generated_timing, -#else - (uint32_t)NULL, -#endif - 0x00000000UL, - 7040000UL, - 32000000UL, - 500000UL, - (1UL << 8) | 1UL, - 0x06005C8FUL, -}; - -const uint32_t generated[] = { - 0x01041FF0UL, - 0x003F003FUL, - /* 1FF4 */ 0x00000000UL, - /* 1FF8 */ (uint32_t)&generated_phyInfo, - /* 1FFC */ 0x00000000UL, - 0x00020004UL, - 0x0016B10CUL, - /* 0008 */ 0x00000080UL, - 0x00020018UL, - 0x00000000UL, - /* 001C */ 0x00000000UL, - 0x00070028UL, - 0x00000825UL, - /* 002C */ 0x00000100UL, - /* 0030 */ 0x000001FFUL, - /* 0034 */ 0x00000001UL, - /* 0038 */ 0x00000000UL, - /* 003C */ 0x00000000UL, - /* 0040 */ 0x000007A0UL, - 0x00010048UL, - 0x00000000UL, - 0x00020054UL, - 0x00000000UL, - /* 0058 */ 0x00000000UL, - 0x000400A0UL, - 0x00004001UL, - /* 00A4 */ 0x00000CFFUL, - /* 00A8 */ 0x00004101UL, - /* 00AC */ 0x00000DFFUL, - 0x00012000UL, - 0x00000704UL, - 0x00012010UL, - 0x00000000UL, - 0x00012018UL, - 0x00008408UL, - 0x00013008UL, - 0x0100AC13UL, - 0x00023030UL, - 0x00105C8FUL, - /* 3034 */ 0x00000003UL, - 0x00013040UL, - 0x00000000UL, - 0x000140A0UL, - 0x0F0027AAUL, - 0x000140B8UL, - 0x0093C000UL, - 0x000140F4UL, - 0x00001020UL, - 0x00024134UL, - 0x00000880UL, - /* 4138 */ 0x000087F6UL, - 0x00024140UL, - 0x008800A3UL, - /* 4144 */ 0x4D52E6C1UL, - 0x00044160UL, - 0x00000000UL, - /* 4164 */ 0x00000000UL, - /* 4168 */ 0x00000006UL, - /* 416C */ 0x00000006UL, - 0x00086014UL, - 0x00000010UL, - /* 6018 */ 0x04000000UL, - /* 601C */ 0x0007000FUL, - /* 6020 */ 0x00006000UL, - /* 6024 */ 0x000C5000UL, - /* 6028 */ 0x03000000UL, - /* 602C */ 0x00000000UL, - /* 6030 */ 0x00000000UL, - 0x00066050UL, - 0x00FF0990UL, - /* 6054 */ 0x00001040UL, - /* 6058 */ 0x0000000AUL, - /* 605C */ 0x00200092UL, - /* 6060 */ 0x00007209UL, - /* 6064 */ 0x00000000UL, - 0x000C6078UL, - 0x08E02714UL, - /* 607C */ 0x00000000UL, - /* 6080 */ 0x002A03F3UL, - /* 6084 */ 0x019890E1UL, - /* 6088 */ 0x00000CB7UL, - /* 608C */ 0x22140A04UL, - /* 6090 */ 0x4F4A4132UL, - /* 6094 */ 0x00000000UL, - /* 6098 */ 0x00000000UL, - /* 609C */ 0x00000000UL, - /* 60A0 */ 0x00000000UL, - /* 60A4 */ 0x00000000UL, - 0x000760E4UL, - 0xCC7C0889UL, - /* 60E8 */ 0x00000000UL, - /* 60EC */ 0x07830464UL, - /* 60F0 */ 0x3AC81388UL, - /* 60F4 */ 0x0006209CUL, - /* 60F8 */ 0x00206100UL, - /* 60FC */ 0x208556B7UL, - 0x00036104UL, - 0x0010F6D2UL, - /* 6108 */ 0x00003020UL, - /* 610C */ 0x0000BB88UL, - 0x00016120UL, - 0x00000000UL, - 0x00077014UL, - 0x000270F8UL, - /* 7018 */ 0x00000300UL, - /* 701C */ 0x844A0060UL, - /* 7020 */ 0x00000000UL, - /* 7024 */ 0x00000082UL, - /* 7028 */ 0x00000000UL, - /* 702C */ 0x000000D5UL, - 0x00027048UL, - 0x0000383EUL, - /* 704C */ 0x000025BCUL, - 0x00037070UL, - 0x00120105UL, - /* 7074 */ 0x00083018UL, - /* 7078 */ 0x006D8480UL, - - 0xFFFFFFFFUL, -}; - -RAIL_ChannelConfigEntryAttr_t generated_entryAttr = {{0xFFFFFFFFUL}}; - -const RAIL_ChannelConfigEntry_t generated_channels[] = { - {.phyConfigDeltaAdd = NULL, - .baseFrequency = 903000000, - .channelSpacing = 1000000, - .physicalChannelOffset = 0, - .channelNumberStart = 0, - .channelNumberEnd = 24, - .maxPower = RAIL_TX_POWER_MAX, - .attr = &generated_entryAttr}, -}; - -const RAIL_ChannelConfig_t generated_channelConfig = { - .phyConfigBase = generated, - .phyConfigDeltaSubtract = NULL, - .configs = generated_channels, - .length = 1, - .signature = 0U, -}; - -const RAIL_ChannelConfig_t *channelConfigs[] = { - &generated_channelConfig, -}; - -#endif // RADIO_CONFIG_915MHZ_2GFSK_SUPPORT diff --git a/src/efr32mg12/phy/PHY_IEEE802154_915MHZ_OQPSK_EFR32XG12.c b/src/efr32mg12/phy/PHY_IEEE802154_915MHZ_OQPSK_EFR32XG12.c deleted file mode 100644 index 07758166..00000000 --- a/src/efr32mg12/phy/PHY_IEEE802154_915MHZ_OQPSK_EFR32XG12.c +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright 2018 Silicon Laboratories, Inc. -// -// - -/// @file rail_config.c -/// @brief RAIL Configuration -/// @copyright Copyright 2015 Silicon Laboratories, Inc. http://www.silabs.com -// ============================================================================= -// -// WARNING: Auto-Generated Radio Config - DO NOT EDIT -// Radio Configurator Version: 3.8.0 -// RAIL Adapter Version: 2.2.5 -// RAIL Compatibility: 2.x -// -// ============================================================================= -#include "em_common.h" -#include "rail_config.h" - -#if RADIO_CONFIG_915MHZ_OQPSK_SUPPORT - -uint32_t RAILCb_CalcSymbolRate(RAIL_Handle_t railHandle) -{ - (void)railHandle; - return 0U; -} - -uint32_t RAILCb_CalcBitRate(RAIL_Handle_t railHandle) -{ - (void)railHandle; - return 0U; -} - -void RAILCb_ConfigFrameTypeLength(RAIL_Handle_t railHandle, const RAIL_FrameType_t *frameType) -{ - (void)railHandle; - (void)frameType; -} - -static const uint8_t generated_irCalConfig[] = {24, 71, 3, 6, 4, 16, 0, 1, 1, 3, 1, 6, 0, - 16, 39, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0}; - -static const uint32_t generated_phyInfo[] = { - 3UL, - 0x00924924UL, // 146.285714286 - (uint32_t)NULL, - (uint32_t)generated_irCalConfig, -#ifdef RADIO_CONFIG_ENABLE_TIMING - (uint32_t)&generated_timing, -#else - (uint32_t)NULL, -#endif - 0x00000000UL, - 7500000UL, - 42000000UL, - 1000000UL, - (16UL << 8) | 4UL, -}; - -const uint32_t generated[] = { - 0x01031FF0UL, - 0x003F003FUL, - /* 1FF4 */ 0x00000000UL, - /* 1FF8 */ (uint32_t)&generated_phyInfo, - 0x00020004UL, - 0x00157001UL, - /* 0008 */ 0x0000007FUL, - 0x00020018UL, - 0x00000000UL, - /* 001C */ 0x00000000UL, - 0x00070028UL, - 0x00000000UL, - /* 002C */ 0x00000000UL, - /* 0030 */ 0x00000000UL, - /* 0034 */ 0x00000000UL, - /* 0038 */ 0x00000000UL, - /* 003C */ 0x00000000UL, - /* 0040 */ 0x000007A0UL, - 0x00010048UL, - 0x00000000UL, - 0x00020054UL, - 0x00000000UL, - /* 0058 */ 0x00000000UL, - 0x000400A0UL, - 0x00004000UL, - /* 00A4 */ 0x00004CFFUL, - /* 00A8 */ 0x00004100UL, - /* 00AC */ 0x00004DFFUL, - 0x00012000UL, - 0x000007C4UL, - 0x00012010UL, - 0x00000000UL, - 0x00012018UL, - 0x00008408UL, - 0x00013008UL, - 0x0100AC13UL, - 0x00023030UL, - 0x00107800UL, - /* 3034 */ 0x00000003UL, - 0x00013040UL, - 0x00000000UL, - 0x000140A0UL, - 0x0F0027AAUL, - 0x000140B8UL, - 0x00B3C000UL, - 0x000140F4UL, - 0x00001020UL, - 0x00024134UL, - 0x00000880UL, - /* 4138 */ 0x000087F6UL, - 0x00024140UL, - 0x00880086UL, - /* 4144 */ 0x4D52E6C0UL, - 0x00044160UL, - 0x00000000UL, - /* 4164 */ 0x00000000UL, - /* 4168 */ 0x00000006UL, - /* 416C */ 0x00000006UL, - 0x00086014UL, - 0x00000010UL, - /* 6018 */ 0x00127920UL, - /* 601C */ 0x00520007UL, - /* 6020 */ 0x000000C8UL, - /* 6024 */ 0x000A0000UL, - /* 6028 */ 0x03000000UL, - /* 602C */ 0x00000000UL, - /* 6030 */ 0x00000000UL, - 0x00066050UL, - 0x00FF04C8UL, - /* 6054 */ 0x00000C41UL, - /* 6058 */ 0x00000008UL, - /* 605C */ 0x00100410UL, - /* 6060 */ 0x000000A7UL, - /* 6064 */ 0x00000000UL, - 0x000C6078UL, - 0x08E00107UL, - /* 607C */ 0x0000A47CUL, - /* 6080 */ 0x00000018UL, - /* 6084 */ 0x01959000UL, - /* 6088 */ 0x00000001UL, - /* 608C */ 0x00000000UL, - /* 6090 */ 0x00000000UL, - /* 6094 */ 0x00000000UL, - /* 6098 */ 0x00000000UL, - /* 609C */ 0x00000000UL, - /* 60A0 */ 0x00000000UL, - /* 60A4 */ 0x00000000UL, - 0x000760E4UL, - 0xCBA10881UL, - /* 60E8 */ 0x00000000UL, - /* 60EC */ 0x07830464UL, - /* 60F0 */ 0x3AC81388UL, - /* 60F4 */ 0x0006209CUL, - /* 60F8 */ 0x00206100UL, - /* 60FC */ 0x208556B7UL, - 0x00036104UL, - 0x0010F000UL, - /* 6108 */ 0x00003020UL, - /* 610C */ 0x0000BB88UL, - 0x00016120UL, - 0x00000000UL, - 0x00077014UL, - 0x000270FEUL, - /* 7018 */ 0x00001300UL, - /* 701C */ 0x850A0060UL, - /* 7020 */ 0x00000000UL, - /* 7024 */ 0x00000082UL, - /* 7028 */ 0x00000000UL, - /* 702C */ 0x000000D5UL, - 0x00027048UL, - 0x0000383EUL, - /* 704C */ 0x000025BCUL, - 0x00037070UL, - 0x00220103UL, - /* 7074 */ 0x0008300FUL, - /* 7078 */ 0x006D8480UL, - - 0xFFFFFFFFUL, -}; - -RAIL_ChannelConfigEntryAttr_t generated_entryAttr = {{0xFFFFFFFFUL}}; - -const RAIL_ChannelConfigEntry_t generated_channels[] = { - {.phyConfigDeltaAdd = NULL, - .baseFrequency = 904000000, - .channelSpacing = 2000000, - .physicalChannelOffset = 0, - .channelNumberStart = 1, - .channelNumberEnd = 10, - .maxPower = RAIL_TX_POWER_MAX, - .attr = &generated_entryAttr}, -}; - -const RAIL_ChannelConfig_t generated_channelConfig = { - .phyConfigBase = generated, - .phyConfigDeltaSubtract = NULL, - .configs = generated_channels, - .length = 1, - .signature = 0U, -}; - -const RAIL_ChannelConfig_t *channelConfigs[] = { - &generated_channelConfig, -}; - -#endif // RADIO_CONFIG_915MHZ_OQPSK_SUPPORT - -// -// | )/ ) Wireless -// \\ |//,' __ Application -// (")(_)-"()))=- Software -// (\\ Platform diff --git a/src/efr32mg13/arm-none-eabi.cmake b/src/efr32mg13/arm-none-eabi.cmake deleted file mode 100644 index 543c7ac4..00000000 --- a/src/efr32mg13/arm-none-eabi.cmake +++ /dev/null @@ -1,52 +0,0 @@ -# -# Copyright (c) 2021, The OpenThread Authors. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. Neither the name of the copyright holder nor the -# names of its contributors may be used to endorse or promote products -# derived from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# - -set(CMAKE_SYSTEM_NAME Generic) -set(CMAKE_SYSTEM_PROCESSOR ARM) - -set(CMAKE_C_COMPILER arm-none-eabi-gcc) -set(CMAKE_CXX_COMPILER arm-none-eabi-g++) -set(CMAKE_ASM_COMPILER arm-none-eabi-gcc) -set(CMAKE_RANLIB arm-none-eabi-ranlib) - -execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE COMPILER_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) - -set(COMMON_C_FLAGS "-mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -mthumb -fdata-sections -ffunction-sections") - -set(CMAKE_C_FLAGS_INIT "${COMMON_C_FLAGS} -std=c99") -set(CMAKE_CXX_FLAGS_INIT "${COMMON_C_FLAGS} -fno-exceptions -fno-rtti") -set(CMAKE_ASM_FLAGS_INIT "${CMAKE_C_FLAGS_INIT} -x assembler-with-cpp") -set(CMAKE_EXE_LINKER_FLAGS_INIT "${COMMON_C_FLAGS} -specs=nano.specs -specs=nosys.specs") - -set(CMAKE_C_FLAGS_DEBUG "-Og -g") -set(CMAKE_CXX_FLAGS_DEBUG "-Og -g") -set(CMAKE_ASM_FLAGS_DEBUG "-g") - -set(CMAKE_C_FLAGS_RELEASE "-Os") -set(CMAKE_CXX_FLAGS_RELEASE "-Os") -set(CMAKE_ASM_FLAGS_RELEASE "") diff --git a/src/efr32mg1/arm-none-eabi.cmake b/src/efr32mg26/arm-none-eabi.cmake similarity index 94% rename from src/efr32mg1/arm-none-eabi.cmake rename to src/efr32mg26/arm-none-eabi.cmake index 543c7ac4..a803b08e 100644 --- a/src/efr32mg1/arm-none-eabi.cmake +++ b/src/efr32mg26/arm-none-eabi.cmake @@ -36,7 +36,7 @@ set(CMAKE_RANLIB arm-none-eabi-ranlib) execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE COMPILER_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) -set(COMMON_C_FLAGS "-mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -mthumb -fdata-sections -ffunction-sections") +set(COMMON_C_FLAGS "-mcpu=cortex-m33 -mthumb -fmessage-length=0 -ffunction-sections -fdata-sections -mfpu=fpv5-sp-d16 -mfloat-abi=hard") set(CMAKE_C_FLAGS_INIT "${COMMON_C_FLAGS} -std=c99") set(CMAKE_CXX_FLAGS_INIT "${COMMON_C_FLAGS} -fno-exceptions -fno-rtti") diff --git a/src/src/CMakeLists.txt b/src/src/CMakeLists.txt index b65119d4..13028001 100644 --- a/src/src/CMakeLists.txt +++ b/src/src/CMakeLists.txt @@ -44,7 +44,6 @@ add_library(efr32-platform-utils OBJECT) # Create a list with all sources in "openthread-platform-utils" get_target_property(OPENTHREAD_PLATFORM_UTILS_SOURCES openthread-platform-utils SOURCES) -message(DEBUG "DEFAULT_OPENTHREAD_PLATFORM_UTILS_SOURCES (Original)\n\t" "${DEFAULT_OPENTHREAD_PLATFORM_UTILS_SOURCES}") # A list of sources that should be taken from the current directory instead of "openthread/examples/platforms/utils" file(GLOB EFR32_PAL_SOURCES @@ -54,6 +53,7 @@ file(GLOB EFR32_PAL_SOURCES # Remove sources that will be taken from "src/src" set(DEFAULT_OPENTHREAD_PLATFORM_UTILS_SOURCES ${OPENTHREAD_PLATFORM_UTILS_SOURCES}) +message(DEBUG "DEFAULT_OPENTHREAD_PLATFORM_UTILS_SOURCES (Original)\n\t" "${DEFAULT_OPENTHREAD_PLATFORM_UTILS_SOURCES}") list(REMOVE_ITEM DEFAULT_OPENTHREAD_PLATFORM_UTILS_SOURCES ${EFR32_PAL_SOURCES}) # Prepend SOURCE_DIR from "openthread-platform-utils" for all default sources for use with target_sources() diff --git a/src/src/alarm.c b/src/src/alarm.c index 0fbf92b4..1790e882 100644 --- a/src/src/alarm.c +++ b/src/src/alarm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, The OpenThread Authors. + * Copyright (c) 2024, The OpenThread Authors. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -43,6 +43,7 @@ #include "common/debug.hpp" #include "common/logging.hpp" +#include "alarm.h" #include "platform-efr32.h" #include "utils/code_utils.h" @@ -50,6 +51,12 @@ #include "rail.h" #include "sl_sleeptimer.h" +#ifndef TESTING +#define STATIC static +#else +#define STATIC +#endif + // timer data for handling wrapping typedef struct wrap_timer_data wrap_timer_data_t; struct wrap_timer_data @@ -71,7 +78,8 @@ static bool sIsUsRunning = false; static wrap_timer_data_t micro_timer_data = {0}; // millisecond-alarm callback -static void AlarmCallback(sl_sleeptimer_timer_handle_t *aHandle, void *aData) +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +STATIC void AlarmCallback(sl_sleeptimer_timer_handle_t *aHandle, void *aData) { if (aData == NULL) { @@ -106,7 +114,8 @@ static void AlarmCallback(sl_sleeptimer_timer_handle_t *aHandle, void *aData) } // microsecond-alarm callback -static void radioTimerExpired(struct RAIL_MultiTimer *tmr, RAIL_Time_t expectedTimeOfEvent, void *cbArg) +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +STATIC void radioTimerExpired(struct RAIL_MultiTimer *tmr, RAIL_Time_t expectedTimeOfEvent, void *cbArg) { if (cbArg == NULL) { @@ -139,6 +148,85 @@ static void radioTimerExpired(struct RAIL_MultiTimer *tmr, RAIL_Time_t expectedT void efr32AlarmInit(void) { memset(&sl_handle, 0, sizeof sl_handle); + sMsAlarm = 0; + sUsAlarm = 0; + sIsMsRunning = false; + sIsUsRunning = false; + memset(&milli_timer_data, 0, sizeof milli_timer_data); + memset(µ_timer_data, 0, sizeof micro_timer_data); +} + +void efr32AlarmProcess(otInstance *aInstance) +{ + int64_t remaining; + bool alarmMilliFired = false; +#if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE + bool alarmMicroFired = false; +#endif + + CORE_DECLARE_IRQ_STATE; + CORE_ENTER_ATOMIC(); + + if (sIsMsRunning) + { + remaining = (int64_t)sMsAlarm - (int64_t)otPlatAlarmMilliGetNow(); + if (remaining <= 0) + { + otPlatAlarmMilliStop(aInstance); + alarmMilliFired = true; + } + } + +#if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE + if (sIsUsRunning) + { + remaining = (int64_t)sUsAlarm - (int64_t)otPlatAlarmMicroGetNow(); + if (remaining <= 0) + { + otPlatAlarmMicroStop(aInstance); + alarmMicroFired = true; + } + } +#endif + + CORE_EXIT_ATOMIC(); + + if (alarmMilliFired) + { +#if OPENTHREAD_CONFIG_DIAG_ENABLE + if (otPlatDiagModeGet()) + { + otPlatDiagAlarmFired(aInstance); + } + else +#endif + { + otPlatAlarmMilliFired(aInstance); + } + } + +#if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE + if (alarmMicroFired) + { + otPlatAlarmMicroFired(aInstance); + } +#endif +} + +uint64_t efr32AlarmPendingTime(void) +{ + uint64_t remaining = 0; + uint32_t now = otPlatAlarmMilliGetNow(); + if (sIsMsRunning && (sMsAlarm > now)) + { + remaining = sMsAlarm - (uint64_t)now; + } + return remaining; +} + +bool efr32AlarmIsRunning(otInstance *aInstance) +{ + return (otInstanceIsInitialized(aInstance) ? sIsMsRunning : false); } uint32_t otPlatAlarmMilliGetNow(void) @@ -175,6 +263,8 @@ void otPlatAlarmMilliStartAt(otInstance *aInstance, uint32_t aT0, uint32_t aDt) int64_t remaining; uint32_t initial_wrap_time; + otEXPECT(sl_ot_rtos_task_can_access_pal()); + sl_sleeptimer_stop_timer(&sl_handle); sMsAlarm = (uint64_t)aT0 + (uint64_t)aDt; @@ -218,87 +308,22 @@ void otPlatAlarmMilliStartAt(otInstance *aInstance, uint32_t aT0, uint32_t aDt) OT_ASSERT(status == SL_STATUS_OK); } } -} - -uint64_t efr32AlarmPendingTime(void) -{ - uint64_t remaining = 0; - uint32_t now = otPlatAlarmMilliGetNow(); - if (sIsMsRunning && (sMsAlarm > now)) - { - remaining = sMsAlarm - (uint64_t)now; - } - return remaining; -} -bool efr32AlarmIsRunning(otInstance *aInstance) -{ - return (otInstanceIsInitialized(aInstance) ? sIsMsRunning : false); +exit: + return; } void otPlatAlarmMilliStop(otInstance *aInstance) { OT_UNUSED_VARIABLE(aInstance); + otEXPECT(sl_ot_rtos_task_can_access_pal()); + sl_sleeptimer_stop_timer(&sl_handle); sIsMsRunning = false; -} - -void efr32AlarmProcess(otInstance *aInstance) -{ - int64_t remaining; - bool alarmMilliFired = false; -#if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE - bool alarmMicroFired = false; -#endif - - CORE_DECLARE_IRQ_STATE; - CORE_ENTER_ATOMIC(); - - if (sIsMsRunning) - { - remaining = (int64_t)sMsAlarm - (int64_t)otPlatAlarmMilliGetNow(); - if (remaining <= 0) - { - otPlatAlarmMilliStop(aInstance); - alarmMilliFired = true; - } - } -#if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE - if (sIsUsRunning) - { - remaining = (int64_t)sUsAlarm - (int64_t)otPlatAlarmMicroGetNow(); - if (remaining <= 0) - { - otPlatAlarmMicroStop(aInstance); - alarmMicroFired = true; - } - } -#endif - - CORE_EXIT_ATOMIC(); - - if (alarmMilliFired) - { -#if OPENTHREAD_CONFIG_DIAG_ENABLE - if (otPlatDiagModeGet()) - { - otPlatDiagAlarmFired(aInstance); - } - else -#endif - { - otPlatAlarmMilliFired(aInstance); - } - } - -#if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE - if (alarmMicroFired) - { - otPlatAlarmMicroFired(aInstance); - } -#endif +exit: + return; } uint32_t otPlatAlarmMicroGetNow(void) @@ -334,6 +359,8 @@ void otPlatAlarmMicroStartAt(otInstance *aInstance, uint32_t aT0, uint32_t aDt) int64_t remaining; uint32_t initial_wrap_time; + otEXPECT(sl_ot_rtos_task_can_access_pal()); + RAIL_CancelMultiTimer(&rail_timer); sUsAlarm = (uint64_t)aT0 + (uint64_t)aDt; @@ -366,12 +393,20 @@ void otPlatAlarmMicroStartAt(otInstance *aInstance, uint32_t aT0, uint32_t aDt) OT_ASSERT(status == RAIL_STATUS_NO_ERROR); } } + +exit: + return; } void otPlatAlarmMicroStop(otInstance *aInstance) { OT_UNUSED_VARIABLE(aInstance); + otEXPECT(sl_ot_rtos_task_can_access_pal()); + RAIL_CancelMultiTimer(&rail_timer); sIsUsRunning = false; + +exit: + return; } diff --git a/src/src/alarm.h b/src/src/alarm.h new file mode 100644 index 00000000..3c89ec73 --- /dev/null +++ b/src/src/alarm.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2024, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file defines platform specific alarm methods. + * + */ + +#ifndef _ALARM_H +#define _ALARM_H + +#include +#include "openthread/instance.h" + +/** + * This function initializes the alarm service used by OpenThread. + * + */ +void efr32AlarmInit(void); + +/** + * This function provides the remaining time (in milliseconds) on an alarm service. + * + */ +uint64_t efr32AlarmPendingTime(void); + +/** + * This function checks if the alarm service is running. + * + * @param[in] aInstance The OpenThread instance structure. + * + */ +bool efr32AlarmIsRunning(otInstance *aInstance); + +/** + * This function performs alarm driver processing. + * + * @param[in] aInstance The OpenThread instance structure. + * + */ +void efr32AlarmProcess(otInstance *aInstance); + +#endif // _ALARM_H diff --git a/src/src/crypto.c b/src/src/crypto.c index 47c0f3dd..e0253242 100644 --- a/src/src/crypto.c +++ b/src/src/crypto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, The OpenThread Authors. + * Copyright (c) 2024, The OpenThread Authors. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -670,29 +670,29 @@ otError otPlatCryptoPbkdf2GenerateKey(const uint8_t *aPassword, // Initialize key derivation psa_key_derivation_operation_t operation = psa_key_derivation_operation_init(); status = psa_key_derivation_setup(&operation, algo); - otEXPECT_ACTION(status == PSA_SUCCESS, error = OT_ERROR_FAILED); + otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED); // Set capacity status = psa_key_derivation_set_capacity(&operation, aKeyLen); - otEXPECT_ACTION(status == PSA_SUCCESS, error = OT_ERROR_FAILED); + otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED); // Set iteration count as cost status = psa_key_derivation_input_integer(&operation, PSA_KEY_DERIVATION_INPUT_COST, aIterationCounter); - otEXPECT_ACTION(status == PSA_SUCCESS, error = OT_ERROR_FAILED); + otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED); // Create salt as a key psa_key_attributes_t saltKeyAttr = psa_key_attributes_init(); psa_set_key_usage_flags(&saltKeyAttr, PSA_KEY_USAGE_DERIVE); psa_set_key_type(&saltKeyAttr, PSA_KEY_TYPE_RAW_DATA); psa_set_key_algorithm(&saltKeyAttr, algo); - otEXPECT_ACTION(status == PSA_SUCCESS, error = OT_ERROR_FAILED); + otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED); status = psa_import_key(&saltKeyAttr, aSalt, aSaltLen, &saltKeyId); - otEXPECT_ACTION(status == PSA_SUCCESS, error = OT_ERROR_FAILED); + otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED); // Provide salt status = psa_key_derivation_input_key(&operation, PSA_KEY_DERIVATION_INPUT_SALT, saltKeyId); - otEXPECT_ACTION(status == PSA_SUCCESS, error = OT_ERROR_FAILED); + otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED); // Create key for password (key) psa_key_attributes_t passwordKeyAttr = psa_key_attributes_init(); @@ -701,11 +701,11 @@ otError otPlatCryptoPbkdf2GenerateKey(const uint8_t *aPassword, psa_set_key_algorithm(&passwordKeyAttr, algo); status = psa_import_key(&passwordKeyAttr, aPassword, aPasswordLen, &passwordKeyId); - otEXPECT_ACTION(status == PSA_SUCCESS, error = OT_ERROR_FAILED); + otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED); // Provide password (key) status = psa_key_derivation_input_key(&operation, PSA_KEY_DERIVATION_INPUT_PASSWORD, passwordKeyId); - otEXPECT_ACTION(status == PSA_SUCCESS, error = OT_ERROR_FAILED); + otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED); // Configure output as a key psa_key_attributes_t keyAttrResult = psa_key_attributes_init(); @@ -715,11 +715,11 @@ otError otPlatCryptoPbkdf2GenerateKey(const uint8_t *aPassword, psa_set_key_algorithm(&keyAttrResult, PSA_ALG_CTR); status = psa_key_derivation_output_key(&keyAttrResult, &operation, &keyId); - otEXPECT_ACTION(status == PSA_SUCCESS, error = OT_ERROR_FAILED); + otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED); // Export output key status = psa_export_key(keyId, aKey, aKeyLen, &outSize); - otEXPECT_ACTION(status == PSA_SUCCESS, error = OT_ERROR_FAILED); + otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED); // Release keys used psa_destroy_key(keyId); diff --git a/src/src/flash.c b/src/src/flash.c index 9336fae5..1fe109cd 100644 --- a/src/src/flash.c +++ b/src/src/flash.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, The OpenThread Authors. + * Copyright (c) 2024, The OpenThread Authors. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,6 +32,10 @@ */ #include +#include "common/debug.hpp" +#include "utils/code_utils.h" + +#include "platform-efr32.h" #ifdef SL_COMPONENT_CATALOG_PRESENT #include "sl_component_catalog.h" @@ -104,6 +108,7 @@ void otPlatFlashRead(otInstance *aInstance, uint8_t aSwapIndex, uint32_t aOffset #elif defined(SL_CATALOG_NVM3_PRESENT) // Defaults to Silabs nvm3 system #include "nvm3_default.h" +#include "sl_memory_manager.h" #include #include #include "common/code_utils.hpp" @@ -125,6 +130,8 @@ void otPlatSettingsInit(otInstance *aInstance, const uint16_t *aSensitiveKeys, u OT_UNUSED_VARIABLE(aSensitiveKeys); OT_UNUSED_VARIABLE(aSensitiveKeysLength); + otEXPECT(sl_ot_rtos_task_can_access_pal()); + // Only call nmv3_open if it has not been opened yet. if (nvm3_defaultHandle->hasBeenOpened) { @@ -141,16 +148,25 @@ void otPlatSettingsInit(otInstance *aInstance, const uint16_t *aSensitiveKeys, u nvmOpenedByOT = true; } } + +exit: + return; } void otPlatSettingsDeinit(otInstance *aInstance) { OT_UNUSED_VARIABLE(aInstance); + + otEXPECT(sl_ot_rtos_task_can_access_pal()); + if (nvmOpenedByOT && nvm3_defaultHandle->hasBeenOpened) { nvm3_close(nvm3_defaultHandle); nvmOpenedByOT = false; } + +exit: + return; } otError otPlatSettingsGet(otInstance *aInstance, uint16_t aKey, int aIndex, uint8_t *aValue, uint16_t *aValueLength) @@ -165,6 +181,8 @@ otError otPlatSettingsGet(otInstance *aInstance, uint16_t aKey, int aIndex, uint otError err; uint16_t valueLength = 0; + otEXPECT_ACTION(sl_ot_rtos_task_can_access_pal(), err = OT_ERROR_REJECTED); + nvm3_ObjectKey_t nvm3Key = makeNvm3ObjKey(aKey, 0); // The base nvm3 key value. bool idxFound = false; int idx = 0; @@ -193,15 +211,20 @@ otError otPlatSettingsGet(otInstance *aInstance, uint16_t aKey, int aIndex, uint // Only perform read if an input buffer was passed in. if ((aValue != NULL) && (aValueLength != NULL)) { + sl_status_t status; // Read all nvm3 obj bytes into a tmp buffer, then copy the required // number of bytes to the read destination buffer. - uint8_t *buf = malloc(valueLength); - err = mapNvm3Error(nvm3_readData(nvm3_defaultHandle, nvm3Key, buf, valueLength)); + uint8_t *buf = NULL; + + status = sl_memory_alloc(valueLength, BLOCK_TYPE_SHORT_TERM, (void **)&buf); + VerifyOrExit(status == SL_STATUS_OK, err = OT_ERROR_FAILED); + + err = mapNvm3Error(nvm3_readData(nvm3_defaultHandle, nvm3Key, buf, valueLength)); if (err == OT_ERROR_NONE) { memcpy(aValue, buf, (valueLength < *aValueLength) ? valueLength : *aValueLength); } - free(buf); + sl_free(buf); SuccessOrExit(err); } } @@ -230,9 +253,10 @@ otError otPlatSettingsGet(otInstance *aInstance, uint16_t aKey, int aIndex, uint otError otPlatSettingsSet(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength) { OT_UNUSED_VARIABLE(aInstance); - otError err; + otEXPECT_ACTION(sl_ot_rtos_task_can_access_pal(), err = OT_ERROR_REJECTED); + // Delete all nvm3 objects matching the input key (i.e. the 'setting indexes' of the key). err = otPlatSettingsDelete(aInstance, aKey, -1); if ((err == OT_ERROR_NONE) || (err == OT_ERROR_NOT_FOUND)) @@ -249,7 +273,14 @@ otError otPlatSettingsSet(otInstance *aInstance, uint16_t aKey, const uint8_t *a otError otPlatSettingsAdd(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength) { OT_UNUSED_VARIABLE(aInstance); - return addSetting(aKey, aValue, aValueLength); + otError error = OT_ERROR_NONE; + + otEXPECT_ACTION(sl_ot_rtos_task_can_access_pal(), error = OT_ERROR_REJECTED); + + error = addSetting(aKey, aValue, aValueLength); + +exit: + return error; } otError otPlatSettingsDelete(otInstance *aInstance, uint16_t aKey, int aIndex) @@ -266,6 +297,9 @@ otError otPlatSettingsDelete(otInstance *aInstance, uint16_t aKey, int aIndex) bool idxFound = false; int idx = 0; err = OT_ERROR_NOT_FOUND; + + otEXPECT_ACTION(sl_ot_rtos_task_can_access_pal(), err = OT_ERROR_REJECTED); + while ((idx <= NUM_INDEXED_SETTINGS) && (!idxFound)) { // Get the next nvm3 key list. @@ -312,6 +346,7 @@ otError otPlatSettingsDelete(otInstance *aInstance, uint16_t aKey, int aIndex) void otPlatSettingsWipe(otInstance *aInstance) { OT_UNUSED_VARIABLE(aInstance); + otEXPECT(sl_ot_rtos_task_can_access_pal()); // Delete nvm3 objects for all OT Settings keys (and any of their associated 'indexes'). // Note- any OT User nvm3 objects in the OT nvm3 area are NOT be erased. @@ -319,6 +354,9 @@ void otPlatSettingsWipe(otInstance *aInstance) { otPlatSettingsDelete(NULL, aKey, -1); } + +exit: + return; } // Local functions.. diff --git a/src/src/ieee802154-packet-utils.cpp b/src/src/ieee802154-packet-utils.cpp index f1ac34e2..b5a6c7d1 100644 --- a/src/src/ieee802154-packet-utils.cpp +++ b/src/src/ieee802154-packet-utils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, The OpenThread Authors. + * Copyright (c) 2024, The OpenThread Authors. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -312,3 +312,13 @@ uint8_t *efr32GetPayload(otRadioFrame *aFrame) uint8_t *payload = static_cast(aFrame)->GetPayload(); return payload; } + +bool efr32FrameIsPanIdCompressed(otRadioFrame *aFrame) +{ + return static_cast(aFrame)->IsPanIdCompressed(); +} + +uint16_t efr32GetFrameVersion(otRadioFrame *aFrame) +{ + return static_cast(aFrame)->GetVersion(); +} diff --git a/src/src/memory.c b/src/src/memory.c index 252e21d7..8d85fd16 100644 --- a/src/src/memory.c +++ b/src/src/memory.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, The OpenThread Authors. + * Copyright (c) 2024, The OpenThread Authors. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,7 +32,7 @@ #if OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE #include -#include "sl_malloc.h" +#include "sl_memory_manager.h" void *otPlatCAlloc(size_t aNum, size_t aSize) { diff --git a/src/src/misc.c b/src/src/misc.c index 35e4ca4b..2d1f3372 100644 --- a/src/src/misc.c +++ b/src/src/misc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, The OpenThread Authors. + * Copyright (c) 2024, The OpenThread Authors. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -45,11 +45,6 @@ #include "em_rmu.h" #include "platform-efr32.h" -#if defined(SL_CATALOG_OT_CRASH_HANDLER_PRESENT) -#include "crash_handler.h" -#include -#endif - static uint32_t sResetCause; void efr32MiscInit(void) @@ -158,24 +153,6 @@ otPlatResetReason otPlatGetResetReason(otInstance *aInstance) return reason; } -#if defined(SL_CATALOG_OT_CRASH_HANDLER_PRESENT) -void efr32PrintResetInfo(void) -{ - otLogCritPlat("Reset info: 0x%x (%s)", halGetResetInfo(), halGetResetString()); - - otLogCritPlat("Extended Reset info: 0x%2X (%s)", halGetExtendedResetInfo(), halGetExtendedResetString()); - - if (halResetWasCrash()) - { - // We pass port 0 here though this parameter is unused in the legacy HAL - // version of the diagnostic code. - halPrintCrashSummary(0); - halPrintCrashDetails(0); - halPrintCrashData(0); - } -} -#endif // SL_CATALOG_OT_CRASH_HANDLER_PRESENT - void otPlatWakeHost(void) { // TODO: implement an operation to wake the host from sleep state. @@ -220,3 +197,18 @@ otError railStatusToOtError(RAIL_Status_t status) return OT_ERROR_FAILED; } } + +#if OPENTHREAD_CONFIG_PLATFORM_LOG_CRASH_DUMP_ENABLE +otError otPlatLogCrashDump(void) +{ + otError error = OT_ERROR_NONE; + +#if defined(SL_CATALOG_OT_CRASH_HANDLER_PRESENT) + efr32PrintResetInfo(); +#else + error = OT_ERROR_NOT_CAPABLE; +#endif + + return error; +} +#endif diff --git a/src/src/openthread-core-efr32-config-check.h b/src/src/openthread-core-efr32-config-check.h index 109309a8..de257060 100644 --- a/src/src/openthread-core-efr32-config-check.h +++ b/src/src/openthread-core-efr32-config-check.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, The OpenThread Authors. + * Copyright (c) 2024, The OpenThread Authors. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -48,4 +48,8 @@ "One of the following must be defined: RADIO_CONFIG_915MHZ_OQPSK_SUPPORT, RADIO_CONFIG_SUBGHZ_SUPPORT or RADIO_CONFIG_2P4GHZ_OQPSK_SUPPORT" #endif +#if defined(_SILICON_LABS_32B_SERIES_1) +#error "EFR32 Series 1 parts are not supported." +#endif + #endif /* OPENTHREAD_CORE_EFR32_CONFIG_CHECK_H_ */ diff --git a/src/src/openthread-core-efr32-config.h b/src/src/openthread-core-efr32-config.h index 11b5c7c7..b5a1ada0 100644 --- a/src/src/openthread-core-efr32-config.h +++ b/src/src/openthread-core-efr32-config.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, The OpenThread Authors. + * Copyright (c) 2024, The OpenThread Authors. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,10 +35,18 @@ #ifndef OPENTHREAD_CORE_EFR32_CONFIG_H_ #define OPENTHREAD_CORE_EFR32_CONFIG_H_ +#ifdef SL_COMPONENT_CATALOG_PRESENT +#include "sl_component_catalog.h" +#endif + +#ifdef SL_CATALOG_CLOCK_MANAGER_PRESENT +#include "sl_clock_manager_oscillator_config.h" +#else #include "sl_device_init_hfxo.h" #include "sl_device_init_hfxo_config.h" +#endif -#if defined(HARDWARE_BOARD_HAS_LFXO) +#if defined(HARDWARE_BOARD_HAS_LFXO) && !defined(SL_CATALOG_CLOCK_MANAGER_PRESENT) #include "sl_device_init_lfxo.h" #include "sl_device_init_lfxo_config.h" #endif @@ -512,8 +520,12 @@ * */ #ifndef SL_OPENTHREAD_HFXO_ACCURACY +#ifdef SL_CATALOG_CLOCK_MANAGER_PRESENT +#define SL_OPENTHREAD_HFXO_ACCURACY SL_CLOCK_MANAGER_HFXO_PRECISION +#else #define SL_OPENTHREAD_HFXO_ACCURACY SL_DEVICE_INIT_HFXO_PRECISION #endif +#endif /** * @def SL_OPENTHREAD_LFXO_ACCURACY @@ -524,10 +536,14 @@ */ #ifndef SL_OPENTHREAD_LFXO_ACCURACY #if defined(HARDWARE_BOARD_HAS_LFXO) +#if SL_CATALOG_CLOCK_MANAGER_PRESENT +#define SL_OPENTHREAD_LFXO_ACCURACY SL_CLOCK_MANAGER_LFXO_PRECISION +#else #define SL_OPENTHREAD_LFXO_ACCURACY SL_DEVICE_INIT_LFXO_PRECISION +#endif // SL_CATALOG_CLOCK_MANAGER_PRESENT #else #define SL_OPENTHREAD_LFXO_ACCURACY 0 -#endif +#endif // HARDWARE_BOARD_HAS_LFXO #endif /** @@ -541,23 +557,21 @@ #endif /** - * @def SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT + * @def SL_OPENTHREAD_ECDSA_PRIVATE_KEY_SIZE * - * Max number of RX buffers to use in the radio driver + * Max Private key size supported by ECDSA Crypto handler. * */ -#ifndef SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT -#define SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT 16 +#ifndef SL_OPENTHREAD_ECDSA_PRIVATE_KEY_SIZE +#define SL_OPENTHREAD_ECDSA_PRIVATE_KEY_SIZE 32 #endif /** - * @def SL_OPENTHREAD_ECDSA_PRIVATE_KEY_SIZE + * @def OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE * - * Max Private key size supported by ECDSA Crypto handler. + * Power Calibration (SPINEL) Module (Host and RCP configuration) * */ -#ifndef SL_OPENTHREAD_ECDSA_PRIVATE_KEY_SIZE -#define SL_OPENTHREAD_ECDSA_PRIVATE_KEY_SIZE 32 -#endif +#define OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE #endif // OPENTHREAD_CORE_EFR32_CONFIG_H_ diff --git a/src/src/platform-efr32.h b/src/src/platform-efr32.h index 6d1267e6..ae3ac028 100644 --- a/src/src/platform-efr32.h +++ b/src/src/platform-efr32.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, The OpenThread Authors. + * Copyright (c) 2024, The OpenThread Authors. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -53,6 +53,15 @@ extern otInstance *sInstance; #include "sl_component_catalog.h" #endif // SL_COMPONENT_CATALOG_PRESENT +#ifndef SL_CATALOG_KERNEL_PRESENT +#define sl_ot_rtos_task_can_access_pal() (true) +#elif defined(MATTER_INTEGRATION) && MATTER_INTEGRATION +// TODO: Temporary for matter integration. This will be fixed later. +#define sl_ot_rtos_task_can_access_pal() (true) +#else +#include "sl_ot_rtos_adaptation.h" +#endif + // Global reference to rail handle #ifndef SL_CATALOG_RAIL_MULTIPLEXER_PRESENT #define gRailHandle emPhyRailHandle // use gRailHandle in the OpenThread PAL. @@ -67,34 +76,6 @@ extern RAIL_Handle_t gRailHandle; // coex needs the emPhyRailHandle symbol. */ void sl_ot_sys_init(void); -/** - * This function initializes the alarm service used by OpenThread. - * - */ -void efr32AlarmInit(void); - -/** - * This function provides the remaining time (in milliseconds) on an alarm service. - * - */ -uint64_t efr32AlarmPendingTime(void); - -/** - * This function checks if the alarm service is running. - * - * @param[in] aInstance The OpenThread instance structure. - * - */ -bool efr32AlarmIsRunning(otInstance *aInstance); - -/** - * This function performs alarm driver processing. - * - * @param[in] aInstance The OpenThread instance structure. - * - */ -void efr32AlarmProcess(otInstance *aInstance); - /** * This function initializes the radio service used by OpenThead. * diff --git a/src/src/radio.c b/src/src/radio.c index e44ac742..355503ce 100644 --- a/src/src/radio.c +++ b/src/src/radio.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, The OpenThread Authors. + * Copyright (c) 2024, The OpenThread Authors. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -41,23 +41,32 @@ #include #include #include +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE +#include +#endif +#include "common/code_utils.hpp" #include "common/debug.hpp" #include "common/logging.hpp" #include "utils/code_utils.h" #include "utils/link_metrics.h" #include "utils/mac_frame.h" -#include "board_config.h" +#include "circular_queue.h" #include "em_core.h" #include "em_system.h" #include "ieee802154mac.h" #include "pa_conversions_efr32.h" #include "platform-band.h" #include "platform-efr32.h" +#include "radio_coex.h" +#include "radio_multi_channel.h" +#include "radio_power_manager.h" #include "rail.h" #include "rail_config.h" #include "rail_ieee802154.h" +#include "sl_memory_manager.h" +#include "sl_multipan.h" #include "sl_packet_utils.h" #include "soft_source_match_table.h" @@ -76,6 +85,7 @@ #ifdef SL_CATALOG_RAIL_UTIL_COEX_PRESENT #include "coexistence-802154.h" +#include "coexistence-ot.h" #endif // SL_CATALOG_RAIL_UTIL_COEX_PRESENT #ifdef SL_CATALOG_RAIL_UTIL_IEEE802154_STACK_EVENT_PRESENT @@ -86,9 +96,7 @@ #include "sl_rail_util_ieee802154_phy_select.h" #endif // #ifdef SL_CATALOG_RAIL_UTIL_IEEE802154_PHY_SELECT_PRESENT -#ifdef SL_CATALOG_OT_RCP_GP_INTERFACE_PRESENT -#include "sl_rcp_gp_interface.h" -#endif +#include "sl_gp_interface.h" #ifdef SL_CATALOG_RAIL_UTIL_IEEE802154_FAST_CHANNEL_SWITCHING_PRESENT #include "sl_rail_util_ieee802154_fast_channel_switching_config.h" @@ -105,11 +113,9 @@ #define HIGH_BYTE(n) ((uint8_t)(LOW_BYTE((n) >> 8))) #endif // HIGH_BYTE -// Intentionally maintaining separate groups for series-1 and series-2 devices +// Intentionally maintaining separate groups for the different device series. // This gives flexibility to add new elements to be read, like CCA Thresholds. -#if defined(_SILICON_LABS_32B_SERIES_1) -#define USERDATA_MFG_CUSTOM_EUI_64 (2) -#elif defined(_SILICON_LABS_32B_SERIES_2) +#if defined(_SILICON_LABS_32B_SERIES_2) #define USERDATA_MFG_CUSTOM_EUI_64 (2) #else #error "UNSUPPORTED DEVICE" @@ -119,6 +125,10 @@ #define USERDATA_END (USERDATA_BASE + FLASH_PAGE_SIZE) #endif +#if SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT > CIRCULAR_QUEUE_LEN_MAX +#error "Rx buffer count cannot be greater than max circular queue length." +#endif + #define EFR32_RECEIVE_SENSITIVITY -100 // dBm #define EFR32_RSSI_AVERAGING_TIME 16 // us #define EFR32_RSSI_AVERAGING_TIMEOUT 300 // us @@ -183,13 +193,8 @@ | RADIO_INDEX2_ADDR_FILTER_MASK)) #define RADIO_BCAST_PANID (0xFFFF) -#define INVALID_VALUE (0xFF) -#if defined(_SILICON_LABS_32B_SERIES_1) -#define DEVICE_CAPABILITY_MCU_EN (1) -#else #define DEVICE_CAPABILITY_MCU_EN (DEVINFO->SWCAPA1 & _DEVINFO_SWCAPA1_RFMCUEN_MASK) -#endif static otRadioCaps sRadioCapabilities = (OT_RADIO_CAPS_ACK_TIMEOUT | OT_RADIO_CAPS_CSMA_BACKOFF | OT_RADIO_CAPS_ENERGY_SCAN | OT_RADIO_CAPS_SLEEP_TO_TX @@ -220,12 +225,12 @@ typedef enum typedef struct { - uint8_t length; - uint8_t channel; - uint8_t lqi; - int8_t rssi; - uint8_t iid; - uint32_t timestamp; + uint8_t length; + uint8_t channel; + uint8_t lqi; + int8_t rssi; + uint8_t iid; + RAIL_Time_t timestamp; } rxPacketDetails; typedef struct @@ -239,61 +244,52 @@ typedef uint8_t rxBufferIndex_t; static volatile energyScanStatus sEnergyScanStatus; static volatile int8_t sEnergyScanResultDbm; static energyScanMode sEnergyScanMode; +// To track active interface the energy scan is being performed. +static uint8_t sEnergyScanActiveInterface = INVALID_INTERFACE_INDEX; static bool sIsSrcMatchEnabled = false; -#if OPENTHREAD_RADIO && OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE == 1 -#define RADIO_INTERFACE_COUNT 4 +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE #define RADIO_EXT_ADDR_COUNT (RADIO_INTERFACE_COUNT - 1) +// To hold transmit/energy-scan requests from the hosts i.e. one per instance/host, +// if radio is busy. +#define RADIO_REQUEST_BUFFER_COUNT OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_NUM #else -#define RADIO_INTERFACE_COUNT 1 #define RADIO_EXT_ADDR_COUNT (RADIO_INTERFACE_COUNT) +#define RADIO_REQUEST_BUFFER_COUNT 1 #endif -#if RADIO_CONFIG_2P4GHZ_OQPSK_SUPPORT -#define SL_CHANNEL_MAX OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MAX -#define SL_CHANNEL_MIN OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MIN -#define SL_MAX_CHANNELS_SUPPORTED ((OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MAX - OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MIN) + 1) -#elif RADIO_CONFIG_SUBGHZ_SUPPORT -#define SL_CHANNEL_MAX OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MAX -#define SL_CHANNEL_MIN OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MIN -#define SL_MAX_CHANNELS_SUPPORTED \ - ((OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MAX \ - - OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MIN) \ - + 1) - -#elif RADIO_CONFIG_915MHZ_OQPSK_SUPPORT // Not supported -#define SL_CHANNEL_MAX OT_RADIO_915MHZ_OQPSK_CHANNEL_MAX -#define SL_CHANNEL_MIN OT_RADIO_915MHZ_OQPSK_CHANNEL_MIN -#define SL_MAX_CHANNELS_SUPPORTED ((OT_RADIO_915MHZ_OQPSK_CHANNEL_MAX - OT_RADIO_915MHZ_OQPSK_CHANNEL_MIN) + 1) -#endif - -#define SL_INVALID_TX_POWER (127) +typedef struct +{ + otRadioFrame frame; + uint8_t iid; +} radioFrame; // Receive -static rxBuffer sReceivePacket[SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT]; -static uint8_t sReceiveAckPsdu[IEEE802154_MAX_LENGTH]; -static otRadioFrame sReceiveFrame; -static otRadioFrame sReceiveAckFrame; -static otError sReceiveError; +static Queue_t sRxPacketQueue; +static sl_memory_pool_t sRxPacketMemPoolHandle; +static uint8_t sReceiveAckPsdu[IEEE802154_MAX_LENGTH]; +static radioFrame sReceive; +static radioFrame sReceiveAck; +static otError sReceiveError; // Transmit -static otRadioFrame sTransmitFrame; -static uint8_t sTransmitPsdu[IEEE802154_MAX_LENGTH]; -static otRadioFrame *sTxFrame = NULL; -static uint8_t sLastLqi = 0; -static int8_t sLastRssi = 0; -static otExtAddress sExtAddress[RADIO_EXT_ADDR_COUNT]; - -static int8_t sMaxChannelPower[RADIO_INTERFACE_COUNT][SL_MAX_CHANNELS_SUPPORTED]; -static int8_t sDefaultTxPower[RADIO_INTERFACE_COUNT]; +// One of the IID is reserved for broadcast hence we need RADIO_INTERFACE_COUNT - 1. +// IID zero is for broadcast, so request from host1 (i.e. iid = 1) will use tx buffer +// index 0 (i.e. iid - 1) and so on. +static radioFrame sTransmitBuffer[RADIO_REQUEST_BUFFER_COUNT]; +static uint8_t sTransmitPsdu[RADIO_REQUEST_BUFFER_COUNT][IEEE802154_MAX_LENGTH]; +static radioFrame *sCurrentTxPacket = NULL; +static uint8_t sLastLqi = 0; +static int8_t sLastRssi = 0; +static otExtAddress sExtAddress[RADIO_EXT_ADDR_COUNT]; // CSMA config: Should be globally scoped RAIL_CsmaConfig_t csmaConfig = RAIL_CSMA_CONFIG_802_15_4_2003_2p4_GHz_OQPSK_CSMA; RAIL_CsmaConfig_t cslCsmaConfig = RAIL_CSMA_CONFIG_SINGLE_CCA; #if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT -static otRadioIeInfo sTransmitIeInfo; +static otRadioIeInfo sTransmitIeInfo[RADIO_REQUEST_BUFFER_COUNT]; #endif // Radio @@ -316,19 +312,52 @@ efr32RadioCounters railDebugCounters; #define rxDebugStep (railDebugCounters.mRadioDebugData.m8[RX_DEBUG_COUNTER0]) #endif -#if OPENTHREAD_RADIO && OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE == 1 -extern uint8_t otNcpPlatGetCurCommandIid(void); -static uint8_t sRailFilterMask = RADIO_BCAST_PANID_FILTER_MASK; +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE +// Type of commands that can be added to the pending command buffer. +typedef enum +{ + kPendingCommandTypeTransmit, + kPendingCommandTypeEnergyScan, +} pendingCommandType; -#if SL_RAIL_UTIL_IEEE802154_FAST_CHANNEL_SWITCHING_ENABLED +typedef struct +{ + // Energy scan channel. + uint8_t scanChannel; + // Energy scan duration. + uint16_t scanDuration; +} energyScanParams; + +// The structure representing pending transmit and energy-scan command requests. +typedef struct +{ + // The union of transmit and energy-scan requests parameters. + union + { + // A pointer to the transmit radio frame. + otRadioFrame *txFrame; + // The structure of energy-scan request parameters. + energyScanParams energyScan; + } request; + // The pending command type. + pendingCommandType cmdType : 2; + // The interface iid of the pending command. + uint8_t iid : 2; +} pendingCommandEntry; + +static Queue_t sPendingCommandQueue; + +extern otInstance *sInstances[OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_NUM]; +static uint8_t sRailFilterMask = RADIO_BCAST_PANID_FILTER_MASK; +static bool isRadioTransmittingOrScanning(void); -#define FAST_CHANNEL_SWITCHING_SUPPORT 1 +#if SL_RAIL_UTIL_IEEE802154_FAST_CHANNEL_SWITCHING_ENABLED static RAIL_IEEE802154_RxChannelSwitchingCfg_t sChannelSwitchingCfg; static RAIL_IEEE802154_RX_CHANNEL_SWITCHING_BUF_ALIGNMENT_TYPE sChannelSwitchingBuffer[RAIL_IEEE802154_RX_CHANNEL_SWITCHING_BUF_BYTES / RAIL_IEEE802154_RX_CHANNEL_SWITCHING_BUF_ALIGNMENT]; -static bool isMultiChannel(void) +bool sl_is_multi_channel_enabled(void) { uint8_t firstChannel = UNINITIALIZED_CHANNEL; for (uint8_t i = 0U; i < RAIL_IEEE802154_RX_CHANNEL_SWITCHING_NUM_CHANNELS; i++) @@ -348,6 +377,18 @@ static bool isMultiChannel(void) return false; } +otError sl_get_channel_switching_cfg(RAIL_IEEE802154_RxChannelSwitchingCfg_t *channelSwitchingCfg) +{ + otError error = OT_ERROR_NONE; + + otEXPECT_ACTION(channelSwitchingCfg != NULL, error = OT_ERROR_INVALID_ARGS); + + memcpy(channelSwitchingCfg, &sChannelSwitchingCfg, sizeof(sChannelSwitchingCfg)); + +exit: + return error; +} + static uint8_t fastChannelIndex(uint8_t aChannel) { for (uint8_t i = 0U; i < RAIL_IEEE802154_RX_CHANNEL_SWITCHING_NUM_CHANNELS; i++) @@ -357,14 +398,11 @@ static uint8_t fastChannelIndex(uint8_t aChannel) return i; } } - return INVALID_VALUE; + return INVALID_INTERFACE_INDEX; } #endif // SL_RAIL_UTIL_IEEE802154_FAST_CHANNEL_SWITCHING_ENABLED - -#else // OPENTHREAD_RADIO && OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE == 1 -#define otNcpPlatGetCurCommandIid() 0 -#endif // OPENTHREAD_RADIO && OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE == 1 +#endif // OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE // RAIL @@ -450,141 +488,34 @@ uint32_t efr32RadioCoexCounters[SL_RAIL_UTIL_COEX_EVENT_COUNT] = {0}; #endif // SL_CATALOG_RAIL_UTIL_COEX_PRESENT -/** - * This function gets the lowest value for the maxTxPower for a channel, from the maxTxPowerTable set - * across all interfaces. It also gets the highest defaultTxPower set across all interfaces. - * - * @param[out] defaultTxPower A pointer to update the derived defaultTxPower across all IIDs. - * @param[out] txPowerFromTable A pointer to update the Tx Power derived from the MaxChannelPowerTable. - * - */ -static void sli_get_default_and_max_powers_across_iids(int8_t *defaultTxPower, - int8_t *txPowerFromTable, - uint16_t channel) -{ - OT_ASSERT(txPowerFromTable != NULL); - OT_ASSERT(defaultTxPower != NULL); - - for (uint8_t iid = 0U; iid < RADIO_INTERFACE_COUNT; iid++) - { - // Obtain the minimum Tx power set by different iids, for `channel` - // If there is an interface using lower Tx power than the one we have - // in txPowerFromTable.. - // Update txPowerFromTable. - *txPowerFromTable = SL_MIN(*txPowerFromTable, sMaxChannelPower[iid][channel - SL_CHANNEL_MIN]); - - // If the default Tx Power set is not invalid.. - if (sDefaultTxPower[iid] != SL_INVALID_TX_POWER) - { - // Obtain the Max value between local defaultTxPower and sDefaultTxPower. - // If selected default Tx Power is Invalid, initialise it to sDefaultTxPower. - // We have already validated that sDefaultTxPower holds a valid value. - *defaultTxPower = (*defaultTxPower == SL_INVALID_TX_POWER) ? sDefaultTxPower[iid] - : SL_MAX(*defaultTxPower, sDefaultTxPower[iid]); - } - } -} - -static int8_t sli_get_max_tx_power_across_iids(void) +// Note: This callback can be called from ISR context. +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +static bool rxPacketQueueOverflowCallback(const Queue_t *queue, void *data) { - int8_t maxChannelTxPower = SL_INVALID_TX_POWER; - int8_t maxDefaultTxPower = SL_INVALID_TX_POWER; - int8_t selectedTxPower = SL_INVALID_TX_POWER; - uint16_t channel; + OT_UNUSED_VARIABLE(queue); + OT_UNUSED_VARIABLE(data); -#if FAST_CHANNEL_SWITCHING_SUPPORT - if (isMultiChannel()) - { - // Find the maxChannelTxPower, to be minimum of Max channel power for the - // channels infast channel config, accross all iids. This is because, if a iid_1 - // sets the max tx power of the channel to be less than the max tx power set by - // iid_2, we will need to work with the lower tx power to be compliant on both - // interfaces. - - // Find the maxDefaultTxPower, to be maximum of the default Tx power accross all - // the interfaces. - - for (uint8_t i = 0U; i < RAIL_IEEE802154_RX_CHANNEL_SWITCHING_NUM_CHANNELS; i++) - { - // Get the channel stored in sChannelSwitchingCfg - channel = sChannelSwitchingCfg.channels[i]; - - sli_get_default_and_max_powers_across_iids(&maxDefaultTxPower, &maxChannelTxPower, channel); - } - } - else -#endif - { - RAIL_GetChannel(gRailHandle, &channel); - sli_get_default_and_max_powers_across_iids(&maxDefaultTxPower, &maxChannelTxPower, channel); - } - - // Return the minimum of maxChannelTxPower and maxDefaultTxPower. - selectedTxPower = SL_MIN(maxChannelTxPower, maxDefaultTxPower); - return (selectedTxPower == SL_INVALID_TX_POWER) ? OPENTHREAD_CONFIG_DEFAULT_TRANSMIT_POWER : selectedTxPower; -} - -//------------------------------------------------------------------------------ -// RX Buffer management - -static volatile bool sRxBufferFull = false; // Used to distinguish full vs empty circular buffer state - -static inline bool isRxBufferFull(void) -{ - return sRxBufferFull; -} - -#if SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT > 1 - -#define CIRCULAR_BUFFER_INCR(index) ((index) = ((index) + 1) % (SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT)) - -static volatile rxBufferIndex_t sRxBufferHead = 0; // Index of available buffer for use by producer callback -static rxBufferIndex_t sRxBufferTail = 0; // Index of next buffer to consume by processing loop - -static inline bool isRxBufferEmpty(void) -{ - CORE_DECLARE_IRQ_STATE; - CORE_ENTER_ATOMIC(); - bool isEmpty = ((sRxBufferHead == sRxBufferTail) && (!isRxBufferFull())); - CORE_EXIT_ATOMIC(); - return isEmpty; -} - -/* Return index of next available buffer, or return the buffer count if no buffers are available */ -static inline rxBufferIndex_t getFreeBufferIndex(void) -{ - return (isRxBufferFull()) ? SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT : sRxBufferHead; -} - -/* Return index of next buffer to process, or return the buffer count if no buffers can be processed */ -static inline rxBufferIndex_t getStoredBufferIndex(void) -{ - return (isRxBufferEmpty()) ? SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT : sRxBufferTail; + // True to discard the queue item being considered for removal. + // False for nothing to be discarded from the queue. + // Do not discard the oldest entry from the queue, rather drop + // the new received packet, hence, return false. + return false; } -/* Helper function to determine if a buffer is marked as ready to process */ -static inline bool canProcessNextRxBuffer(void) +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE +static bool pendingCommandQueueOverflowCallback(const Queue_t *queue, void *data) { - return (!isRxBufferEmpty()); -} + OT_UNUSED_VARIABLE(queue); + OT_UNUSED_VARIABLE(data); -/* Marks the state of the next available buffer as ready to process */ -static inline void reserveNextRxBuffer(void) -{ - CIRCULAR_BUFFER_INCR(sRxBufferHead); - sRxBufferFull = (sRxBufferHead == sRxBufferTail); -} + // We should never hit this callback because a host can only request + // one command at a time. Hence, added a assert if it happens. + OT_ASSERT(false); -/* Updates the buffer at the provided index as available after being processed */ -static inline void releaseCurrentRxBuffer(void) -{ - CORE_DECLARE_IRQ_STATE; - CORE_ENTER_ATOMIC(); - CIRCULAR_BUFFER_INCR(sRxBufferTail); - sRxBufferFull = false; - CORE_EXIT_ATOMIC(); + return false; } #endif + #if RADIO_CONFIG_ENABLE_CUSTOM_EUI_SUPPORT /* * This API reads the UserData page on the given EFR device. @@ -622,11 +553,12 @@ static int readUserData(void *buffer, uint16_t index, int len, bool changeByteOr * This API converts the FilterMask to appropriate IID. If there are any errors, it will fallback on bcast IID. * */ +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) static inline uint8_t getIidFromFilterMask(uint8_t mask) { - uint8_t iid = INVALID_VALUE; + uint8_t iid = INVALID_INTERFACE_INDEX; -#if OPENTHREAD_RADIO && OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE == 1 +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE // We need only the Pan Id masks here, as we are not matching the addresses. // Also mask all the unused indices. mask &= sRailFilterMask; @@ -659,11 +591,12 @@ static inline uint8_t getIidFromFilterMask(uint8_t mask) * This API validates the received FilterMask by checking if the destination address * in the received packet corresponds to destination PanID. */ +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) static bool isFilterMaskValid(uint8_t mask) { bool valid = false; -#if OPENTHREAD_RADIO && OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE == 1 +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE /* Packet will be considered as a valid packet in 3 cases: * Case 1: If the packet was directed towards bcast address or bcast panid @@ -675,49 +608,29 @@ static bool isFilterMaskValid(uint8_t mask) * Case 3: We don't have either the destination addressing field or destination PanId * in the received packet to determine if the dest address and dest pan match. */ - if ( - // Case 1 - ((mask & RADIO_BCAST_PANID_FILTER_MASK) || (mask & RADIO_BCAST_ADDR_FILTER_MASK)) || - // Case 2 - Find any non-broadcast PAN ID match and get ready to compare it + if (((mask & RADIO_BCAST_PANID_FILTER_MASK) || (mask & RADIO_BCAST_ADDR_FILTER_MASK)) + || // Case 1 + // Find any non-broadcast PAN ID match and get ready to compare it ((((mask & (RADIO_INDEX0_PANID_FILTER_MASK | RADIO_INDEX1_PANID_FILTER_MASK | RADIO_INDEX2_PANID_FILTER_MASK)) >> RADIO_PANID_FILTER_SHIFT) & - // To see if it coincides with any address matches for same IID + // ...To see if it coincides with any address matches for same IID (RADIO_GET_ADDR_FILTER_MASK(mask) >> RADIO_ADDR_FILTER_SHIFT)) != 0) - || - // Case 3 - (((RADIO_GET_PANID_FILTER_MASK(mask)) == 0) || ((RADIO_GET_ADDR_FILTER_MASK(mask)) == 0))) + || // Case 2 + (((RADIO_GET_PANID_FILTER_MASK(mask)) == 0) || ((RADIO_GET_ADDR_FILTER_MASK(mask)) == 0)) // Case 3 + ) { valid = true; } #else (void)mask; - valid = true; + valid = true; #endif return valid; } -/* - * RAIL accepts 3 pan indices 0, 1 or 2. But valid IIDs are 1, 2 and 3 (0 is reserved for bcast). - * This API validates the passed IID and converts it into usable PanIndex. - */ - -static inline uint8_t getPanIndexFromIid(uint8_t iid) -{ - uint8_t panIndex = 0; - -#if OPENTHREAD_RADIO && OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE == 1 - otEXPECT_ACTION(((iid < RADIO_INTERFACE_COUNT) && (iid != 0)), panIndex = INVALID_VALUE); - panIndex = iid - 1; -exit: -#else - panIndex = iid; -#endif - return panIndex; -} - #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) enum @@ -746,6 +659,7 @@ static securityMaterial sMacKeys[RADIO_INTERFACE_COUNT]; static uint32_t sCslPeriod; static uint32_t sCslSampleTime; +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) static uint16_t getCslPhase(uint32_t shrTxTime) { uint32_t cslPeriodInUs = sCslPeriod * OT_US_PER_TEN_SYMBOLS; @@ -766,6 +680,7 @@ static uint16_t getCslPhase(uint32_t shrTxTime) static uint8_t sAckIeData[OT_ACK_IE_MAX_SIZE]; static uint8_t sAckIeDataLength = 0; +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) static uint8_t generateAckIeData(uint8_t *aLinkMetricsIeData, uint8_t aLinkMetricsIeDataLen) { OT_UNUSED_VARIABLE(aLinkMetricsIeData); @@ -790,17 +705,18 @@ static uint8_t generateAckIeData(uint8_t *aLinkMetricsIeData, uint8_t aLinkMetri return offset; } +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) static otError radioProcessTransmitSecurity(otRadioFrame *aFrame, uint8_t iid) { otError error = OT_ERROR_NONE; uint8_t keyId; uint8_t keyToUse; - uint8_t panIndex = getPanIndexFromIid(iid); + uint8_t panIndex = efr32GetPanIndexFromIid(iid); otEXPECT(otMacFrameIsSecurityEnabled(aFrame) && otMacFrameIsKeyIdMode1(aFrame) && !aFrame->mInfo.mTxInfo.mIsSecurityProcessed); - OT_ASSERT(panIndex != INVALID_VALUE); + OT_ASSERT(panIndex != INVALID_INTERFACE_INDEX); if (otMacFrameIsAck(aFrame)) { @@ -847,17 +763,14 @@ static otError radioProcessTransmitSecurity(otRadioFrame *aFrame, uint8_t iid) otMacFrameSetFrameCounter(aFrame, sMacKeys[iid].macFrameCounter++); } -#if defined(_SILICON_LABS_32B_SERIES_2) efr32PlatProcessTransmitAesCcm(aFrame, &sExtAddress[panIndex]); -#else - otMacFrameProcessTransmitAesCcm(aFrame, &sExtAddress[panIndex]); -#endif exit: return error; } #endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) static uint8_t readInitialPacketData(RAIL_RxPacketInfo_t *packetInfo, uint8_t expected_data_bytes_max, uint8_t expected_data_bytes_min, @@ -926,11 +839,8 @@ static bool validatePacketDetails(RAIL_RxPacketHandle_t packetHandle, RAIL_RxPacketInfo_t *pPacketInfo, uint16_t *packetLength); static bool validatePacketTimestamp(RAIL_RxPacketDetails_t *pPacketDetails, uint16_t packetLength); -static void updateRxFrameDetails(RAIL_RxPacketDetails_t *pPacketDetails, - bool securedOutgoingEnhancedAck, - bool framePendingSetInOutgoingAck, - uint8_t iid, - uint8_t aReceiveBufferInUse); + +static void updateRxFrameTimestamp(bool aIsAckFrame, RAIL_Time_t aTimestamp); static otError skipRxPacketLengthBytes(RAIL_RxPacketInfo_t *pPacketInfo); @@ -939,6 +849,7 @@ static otError skipRxPacketLengthBytes(RAIL_RxPacketInfo_t *pPacketInfo); #ifdef SL_CATALOG_RAIL_UTIL_IEEE802154_STACK_EVENT_PRESENT +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) static bool phyStackEventIsEnabled(void) { bool result = false; @@ -973,6 +884,7 @@ static void updateEvents(RAIL_Events_t mask, RAIL_Events_t values) } } +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) static sl_rail_util_ieee802154_stack_event_t handlePhyStackEvent(sl_rail_util_ieee802154_stack_event_t stackEvent, uint32_t supplement) { @@ -996,6 +908,7 @@ static void updateEvents(RAIL_Events_t mask, RAIL_Events_t values) #endif // SL_CATALOG_RAIL_UTIL_IEEE802154_STACK_EVENT_PRESENT // Set or clear the passed flag. +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) static inline void setInternalFlag(uint16_t flag, bool val) { CORE_DECLARE_IRQ_STATE; @@ -1004,6 +917,7 @@ static inline void setInternalFlag(uint16_t flag, bool val) CORE_EXIT_ATOMIC(); } // Returns true if the passed flag is set, false otherwise. +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) static inline bool getInternalFlag(uint16_t flag) { bool isFlagSet; @@ -1015,15 +929,24 @@ static inline bool getInternalFlag(uint16_t flag) return isFlagSet; } +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) static inline bool txWaitingForAck(void) { return (getInternalFlag(FLAG_ONGOING_TX_DATA) - && ((sTransmitFrame.mPsdu[0] & IEEE802154_FRAME_FLAG_ACK_REQUIRED) != 0)); + && ((sCurrentTxPacket->frame.mPsdu[0] & IEEE802154_FRAME_FLAG_ACK_REQUIRED) != 0)); } +static inline bool isRadioTransmittingOrScanning(void) +{ + return ((sEnergyScanStatus != ENERGY_SCAN_STATUS_IDLE) || getInternalFlag(ONGOING_TX_FLAGS) + || getInternalFlag(FLAG_ONGOING_TX_ACK)); +} + +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) static bool txIsDataRequest(void) { - uint16_t fcf = sTransmitFrame.mPsdu[IEEE802154_FCF_OFFSET] | (sTransmitFrame.mPsdu[IEEE802154_FCF_OFFSET + 1] << 8); + uint16_t fcf = sCurrentTxPacket->frame.mPsdu[IEEE802154_FCF_OFFSET] + | (sCurrentTxPacket->frame.mPsdu[IEEE802154_FCF_OFFSET + 1] << 8); return (getInternalFlag(FLAG_ONGOING_TX_DATA) && (fcf & IEEE802154_FRAME_TYPE_MASK) == IEEE802154_FRAME_TYPE_COMMAND); @@ -1036,6 +959,7 @@ static inline bool isReceivingFrame(void) } #endif +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) static void radioSetIdle(void) { if (RAIL_GetRadioState(gRailHandle) != RAIL_RF_STATE_IDLE) @@ -1057,12 +981,12 @@ static otError radioSetRx(uint8_t aChannel) // sliptime/transaction time is not used for bg rx }; -#if FAST_CHANNEL_SWITCHING_SUPPORT - if (isMultiChannel()) +#if SL_RAIL_UTIL_IEEE802154_FAST_CHANNEL_SWITCHING_ENABLED && OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + if (sl_is_multi_channel_enabled()) { // Calling RAIL_StartRx with a channel not listed in the channel // switching config is a bug. - OT_ASSERT(fastChannelIndex(aChannel) != INVALID_VALUE); + OT_ASSERT(fastChannelIndex(aChannel) != INVALID_INTERFACE_INDEX); radioSetIdle(); status = RAIL_IEEE802154_ConfigRxChannelSwitching(gRailHandle, &sChannelSwitchingCfg); @@ -1115,29 +1039,6 @@ static otError radioScheduleRx(uint8_t aChannel, uint32_t aStart, uint32_t aDura } #endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) -static void configureTxPower(RAIL_TxPowerConfig_t *aTxPowerConfig, int8_t aTxPower) -{ - RAIL_Status_t status; - RAIL_TxPowerLevel_t tx_power_lvl; - RAIL_TxPower_t tx_power_dbm = aTxPower * 10; - - tx_power_lvl = RAIL_GetTxPower(gRailHandle); - - // Always need to call RAIL_SetTxPowerDbm after RAIL_ConfigTxPower - // First need to get existing power setting and reassert value after config - - if (tx_power_lvl != RAIL_TX_POWER_LEVEL_INVALID) - { - tx_power_dbm = RAIL_GetTxPowerDbm(gRailHandle); - } - - status = RAIL_ConfigTxPower(gRailHandle, aTxPowerConfig); - OT_ASSERT(status == RAIL_STATUS_NO_ERROR); - - status = RAIL_SetTxPowerDbm(gRailHandle, tx_power_dbm); - OT_ASSERT(status == RAIL_STATUS_NO_ERROR); -} - //------------------------------------------------------------------------------ // Radio Initialization static RAIL_Handle_t efr32RailInit(efr32CommonConfig *aCommonConfig) @@ -1230,18 +1131,10 @@ static void efr32RailConfigLoad(efr32BandConfig *aBandConfig, int8_t aTxPower) if (aTxPower != SL_INVALID_TX_POWER) { - configureTxPower(&txPowerConfig, aTxPower); + sli_update_tx_power_after_config_update(&txPowerConfig, aTxPower); } } -static void efr32RadioSetTxPower(int8_t aPowerDbm) -{ - RAIL_Status_t status; - - status = RAIL_SetTxPowerDbm(gRailHandle, ((RAIL_TxPower_t)aPowerDbm) * 10); - OT_ASSERT(status == RAIL_STATUS_NO_ERROR); -} - static efr32BandConfig *efr32RadioGetBandConfig(uint8_t aChannel) { efr32BandConfig *config = NULL; @@ -1276,8 +1169,7 @@ static void efr32ConfigInit(void (*aEventCallback)(RAIL_Handle_t railHandle, RAI memset(&railDebugCounters, 0x00, sizeof(efr32RadioCounters)); #endif - memset(sMaxChannelPower, SL_INVALID_TX_POWER, sizeof(sMaxChannelPower)); - memset(sDefaultTxPower, SL_INVALID_TX_POWER, sizeof(sDefaultTxPower)); + sli_init_power_manager(); gRailHandle = efr32RailInit(&sCommonConfig); OT_ASSERT(gRailHandle != NULL); @@ -1305,6 +1197,8 @@ void efr32RadioInit(void) return; } RAIL_Status_t status; + sl_status_t rxMemPoolStatus; + bool queueStatus; // check if RAIL_TX_FIFO_SIZE is power of two.. OT_ASSERT((RAIL_TX_FIFO_SIZE & (RAIL_TX_FIFO_SIZE - 1)) == 0); @@ -1318,19 +1212,33 @@ void efr32RadioInit(void) status = RAIL_ConfigSleep(gRailHandle, RAIL_SLEEP_CONFIG_TIMERSYNC_ENABLED); OT_ASSERT(status == RAIL_STATUS_NO_ERROR); - memset(&sReceivePacket, 0x00, sizeof(sReceivePacket)); + sReceive.frame.mLength = 0; + sReceive.frame.mPsdu = NULL; - sReceiveFrame.mLength = 0; - sReceiveFrame.mPsdu = NULL; + sReceiveAck.frame.mLength = 0; + sReceiveAck.frame.mPsdu = sReceiveAckPsdu; - sReceiveAckFrame.mLength = 0; - sReceiveAckFrame.mPsdu = sReceiveAckPsdu; - sTransmitFrame.mLength = 0; - sTransmitFrame.mPsdu = sTransmitPsdu; +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + // Initialize the queue for received packets. + queueStatus = queueInit(&sPendingCommandQueue, RADIO_REQUEST_BUFFER_COUNT); + OT_ASSERT(queueStatus); + + // Specify a callback to be called upon queue overflow. + queueStatus = queueOverflow(&sPendingCommandQueue, &pendingCommandQueueOverflowCallback); + OT_ASSERT(queueStatus); +#endif + + for (uint8_t i = 0; i < RADIO_REQUEST_BUFFER_COUNT; i++) + { + // Initialize the tx buffer params. + sTransmitBuffer[i].iid = INVALID_INTERFACE_INDEX; + sTransmitBuffer[i].frame.mLength = 0; + sTransmitBuffer[i].frame.mPsdu = sTransmitPsdu[i]; #if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT - sTransmitFrame.mInfo.mTxInfo.mIeInfo = &sTransmitIeInfo; + sTransmitBuffer[i].frame.mInfo.mTxInfo.mIeInfo = &sTransmitIeInfo[i]; #endif + } #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE otLinkMetricsInit(EFR32_RECEIVE_SENSITIVITY); @@ -1339,7 +1247,7 @@ void efr32RadioInit(void) OT_ASSERT(sCurrentBandConfig != NULL); sl_rail_util_pa_init(); - efr32RadioSetTxPower(OPENTHREAD_CONFIG_DEFAULT_TRANSMIT_POWER); + sli_set_tx_power_in_rail(OPENTHREAD_CONFIG_DEFAULT_TRANSMIT_POWER); status = RAIL_ConfigRxOptions(gRailHandle, RAIL_RX_OPTION_TRACK_ABORTED_FRAMES, RAIL_RX_OPTION_TRACK_ABORTED_FRAMES); @@ -1349,7 +1257,7 @@ void efr32RadioInit(void) sEnergyScanStatus = ENERGY_SCAN_STATUS_IDLE; -#if FAST_CHANNEL_SWITCHING_SUPPORT +#if SL_RAIL_UTIL_IEEE802154_FAST_CHANNEL_SWITCHING_ENABLED && OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE sChannelSwitchingCfg.bufferBytes = RAIL_IEEE802154_RX_CHANNEL_SWITCHING_BUF_BYTES; sChannelSwitchingCfg.buffer = sChannelSwitchingBuffer; for (uint8_t i = 0U; i < RAIL_IEEE802154_RX_CHANNEL_SWITCHING_NUM_CHANNELS; i++) @@ -1358,6 +1266,19 @@ void efr32RadioInit(void) } #endif + // Initialize the queue for received packets. + queueStatus = queueInit(&sRxPacketQueue, SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT); + OT_ASSERT(queueStatus); + + // Specify a callback to be called upon queue overflow. + queueStatus = queueOverflow(&sRxPacketQueue, &rxPacketQueueOverflowCallback); + OT_ASSERT(queueStatus); + + // Initialize the memory pool for rx packets. + rxMemPoolStatus = + sl_memory_create_pool(sizeof(rxBuffer), SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT, &sRxPacketMemPoolHandle); + OT_ASSERT(rxMemPoolStatus == SL_STATUS_OK); + otLogInfoPlat("Initialized"); } @@ -1370,11 +1291,14 @@ void efr32RadioDeinit(void) OT_ASSERT(status == RAIL_STATUS_NO_ERROR); sCurrentBandConfig = NULL; + + sl_memory_delete_pool(&sRxPacketMemPoolHandle); } //------------------------------------------------------------------------------ // Energy Scan support +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) static void energyScanComplete(int8_t scanResultDbm) { sEnergyScanResultDbm = scanResultDbm; @@ -1456,20 +1380,19 @@ void otPlatRadioGetIeeeEui64(otInstance *aInstance, uint8_t *aIeeeEui64) void otPlatRadioSetPanId(otInstance *aInstance, uint16_t aPanId) { - OT_UNUSED_VARIABLE(aInstance); - RAIL_Status_t status; - uint8_t iid = otNcpPlatGetCurCommandIid(); - uint8_t panIndex = getPanIndexFromIid(iid); + uint8_t iid = efr32GetIidFromInstance(aInstance); + uint8_t panIndex = efr32GetPanIndexFromIid(iid); - OT_ASSERT(panIndex != INVALID_VALUE); + otEXPECT(sl_ot_rtos_task_can_access_pal()); + OT_ASSERT(panIndex != INVALID_INTERFACE_INDEX); otLogInfoPlat("PANID=%X index=%u IID=%d", aPanId, panIndex, iid); utilsSoftSrcMatchSetPanId(iid, aPanId); status = RAIL_IEEE802154_SetPanId(gRailHandle, aPanId, panIndex); OT_ASSERT(status == RAIL_STATUS_NO_ERROR); -#if OPENTHREAD_RADIO && OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE == 1 +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE // We already have IID 0 enabled in filtermask to track BCAST Packets, so // track only unique PanIds. if (aPanId != RADIO_BCAST_PANID) @@ -1477,15 +1400,18 @@ void otPlatRadioSetPanId(otInstance *aInstance, uint16_t aPanId) sRailFilterMask |= RADIO_GET_FILTER_MASK(iid); } #endif +exit: + return; } void otPlatRadioSetExtendedAddress(otInstance *aInstance, const otExtAddress *aAddress) { RAIL_Status_t status; - uint8_t panIndex = getPanIndexFromIid(otNcpPlatGetCurCommandIid()); + uint8_t iid = efr32GetIidFromInstance(aInstance); + uint8_t panIndex = efr32GetPanIndexFromIid(iid); - OT_UNUSED_VARIABLE(aInstance); - OT_ASSERT(panIndex != INVALID_VALUE); + otEXPECT(sl_ot_rtos_task_can_access_pal()); + OT_ASSERT(panIndex != INVALID_INTERFACE_INDEX); for (size_t i = 0; i < sizeof(*aAddress); i++) { @@ -1505,20 +1431,26 @@ void otPlatRadioSetExtendedAddress(otInstance *aInstance, const otExtAddress *aA status = RAIL_IEEE802154_SetLongAddress(gRailHandle, (uint8_t *)aAddress->m8, panIndex); OT_ASSERT(status == RAIL_STATUS_NO_ERROR); + +exit: + return; } void otPlatRadioSetShortAddress(otInstance *aInstance, uint16_t aAddress) { - OT_UNUSED_VARIABLE(aInstance); - RAIL_Status_t status; - uint8_t panIndex = getPanIndexFromIid(otNcpPlatGetCurCommandIid()); + uint8_t iid = efr32GetIidFromInstance(aInstance); + uint8_t panIndex = efr32GetPanIndexFromIid(iid); - OT_ASSERT(panIndex != INVALID_VALUE); + otEXPECT(sl_ot_rtos_task_can_access_pal()); + OT_ASSERT(panIndex != INVALID_INTERFACE_INDEX); otLogInfoPlat("ShortAddr=%X index=%u", aAddress, panIndex); status = RAIL_IEEE802154_SetShortAddress(gRailHandle, aAddress, panIndex); OT_ASSERT(status == RAIL_STATUS_NO_ERROR); + +exit: + return; } otRadioState otPlatRadioGetState(otInstance *aInstance) @@ -1558,22 +1490,27 @@ bool otPlatRadioIsEnabled(otInstance *aInstance) otError otPlatRadioEnable(otInstance *aInstance) { + otError error = OT_ERROR_NONE; + otEXPECT(!otPlatRadioIsEnabled(aInstance)); otLogInfoPlat("State=OT_RADIO_STATE_SLEEP"); exit: - return OT_ERROR_NONE; + return error; } otError otPlatRadioDisable(otInstance *aInstance) { - otEXPECT(otPlatRadioIsEnabled(aInstance)); + otError error = OT_ERROR_NONE; + + otEXPECT_ACTION(sl_ot_rtos_task_can_access_pal(), error = OT_ERROR_REJECTED); + otEXPECT_ACTION(otPlatRadioIsEnabled(aInstance), error = OT_ERROR_INVALID_STATE); otLogInfoPlat("State=OT_RADIO_STATE_DISABLED"); exit: - return OT_ERROR_NONE; + return error; } otError otPlatRadioSleep(otInstance *aInstance) @@ -1607,7 +1544,7 @@ otError efr32RadioLoadChannelConfig(uint8_t aChannel, int8_t aTxPower) } else { - efr32RadioSetTxPower(aTxPower); + sli_set_tx_power_in_rail(aTxPower); } exit: @@ -1619,18 +1556,20 @@ otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel) otError error = OT_ERROR_NONE; RAIL_Status_t status; int8_t txPower; + uint8_t iid = efr32GetIidFromInstance(aInstance); - OT_UNUSED_VARIABLE(aInstance); + otEXPECT_ACTION(sl_ot_rtos_task_can_access_pal(), error = OT_ERROR_REJECTED); otEXPECT_ACTION(!getInternalFlag(FLAG_ONGOING_TX_DATA) && sEnergyScanStatus != ENERGY_SCAN_STATUS_IN_PROGRESS, error = OT_ERROR_INVALID_STATE); -#if FAST_CHANNEL_SWITCHING_SUPPORT - uint8_t index = getPanIndexFromIid(otNcpPlatGetCurCommandIid()); + OT_UNUSED_VARIABLE(iid); +#if SL_RAIL_UTIL_IEEE802154_FAST_CHANNEL_SWITCHING_ENABLED && OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + uint8_t index = efr32GetPanIndexFromIid(iid); OT_ASSERT(index < RAIL_IEEE802154_RX_CHANNEL_SWITCHING_NUM_CHANNELS); sChannelSwitchingCfg.channels[index] = aChannel; #endif - txPower = sli_get_max_tx_power_across_iids(); + txPower = sl_get_tx_power_for_current_channel(aInstance); error = efr32RadioLoadChannelConfig(aChannel, txPower); otEXPECT(error == OT_ERROR_NONE); @@ -1638,8 +1577,8 @@ otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel) otEXPECT_ACTION(status == RAIL_STATUS_NO_ERROR, error = OT_ERROR_FAILED); setInternalFlag(FLAG_SCHEDULED_RX_PENDING, false); - sReceiveFrame.mChannel = aChannel; - sReceiveAckFrame.mChannel = aChannel; + sReceive.frame.mChannel = aChannel; + sReceiveAck.frame.mChannel = aChannel; exit: return error; @@ -1650,8 +1589,9 @@ otError otPlatRadioReceiveAt(otInstance *aInstance, uint8_t aChannel, uint32_t a { otError error = OT_ERROR_NONE; RAIL_Status_t status; - int8_t txPower = sli_get_max_tx_power_across_iids(); + int8_t txPower = sl_get_tx_power_for_current_channel(aInstance); + otEXPECT_ACTION(sl_ot_rtos_task_can_access_pal(), error = OT_ERROR_REJECTED); OT_UNUSED_VARIABLE(aInstance); error = efr32RadioLoadChannelConfig(aChannel, txPower); @@ -1661,61 +1601,104 @@ otError otPlatRadioReceiveAt(otInstance *aInstance, uint8_t aChannel, uint32_t a otEXPECT_ACTION(status == RAIL_STATUS_NO_ERROR, error = OT_ERROR_FAILED); setInternalFlag(FLAG_SCHEDULED_RX_PENDING, true); - sReceiveFrame.mChannel = aChannel; - sReceiveAckFrame.mChannel = aChannel; + sReceive.frame.mChannel = aChannel; + sReceiveAck.frame.mChannel = aChannel; exit: return error; } #endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE +inline static void pushPendingCommand(pendingCommandType aCmdType, uint8_t aIid, void *aCmdParams) +{ + pendingCommandEntry *pendingCommand = (pendingCommandEntry *)sl_malloc(sizeof(pendingCommandEntry)); + OT_ASSERT(pendingCommand != NULL); + + pendingCommand->cmdType = aCmdType; + pendingCommand->iid = aIid; + + if (aCmdType == kPendingCommandTypeTransmit) + { + otRadioFrame *txFrame = (otRadioFrame *)aCmdParams; + pendingCommand->request.txFrame = txFrame; + } + else if (aCmdType == kPendingCommandTypeEnergyScan) + { + energyScanParams *energyScanReq = (energyScanParams *)aCmdParams; + pendingCommand->request.energyScan.scanChannel = energyScanReq->scanChannel; + pendingCommand->request.energyScan.scanDuration = energyScanReq->scanDuration; + } + + if (!queueAdd(&sPendingCommandQueue, (void *)pendingCommand)) + { + sl_free(pendingCommand); + } +} +#endif + otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame) { otError error = OT_ERROR_NONE; - int8_t txPower = sli_get_max_tx_power_across_iids(); + int8_t txPower = sl_get_tx_power_for_current_channel(aInstance); + uint8_t iid = efr32GetIidFromInstance(aInstance); -#if OPENTHREAD_RADIO && OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE == 1 && (defined SL_CATALOG_OT_RCP_GP_INTERFACE_PRESENT) + // sTransmitBuffer's index 0 corresponds to host 1 i.e. iid 1 and reason is, + // iid zero is reserved for broadcast frames in multipan case. + uint8_t txBufIndex = iid ? (iid - 1) : 0; + + otEXPECT_ACTION(sl_ot_rtos_task_can_access_pal(), error = OT_ERROR_REJECTED); + +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE // Accept GP packets even if radio is not in required state. - if ((sl_gp_intf_get_state() != SL_GP_STATE_SEND_RESPONSE) && sl_gp_intf_is_gp_pkt(aFrame, false)) + if ((sl_gp_intf_get_state() != SL_GP_STATE_SEND_RESPONSE) && sl_gp_intf_should_buffer_pkt(aInstance, aFrame, false)) { - sl_gp_intf_buffer_pkt(aFrame); + sl_gp_intf_buffer_pkt(aInstance); } else #endif { + OT_ASSERT(txBufIndex < RADIO_REQUEST_BUFFER_COUNT); + OT_ASSERT(aFrame == &sTransmitBuffer[txBufIndex].frame); + OT_ASSERT(aFrame->mPsdu == sTransmitPsdu[txBufIndex]); + +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + OT_ASSERT((iid != RADIO_BCAST_IID) && (iid < RADIO_INTERFACE_COUNT)); + // Push pending transmit and exit if radio is busy. + if (isRadioTransmittingOrScanning()) + { + pushPendingCommand(kPendingCommandTypeTransmit, iid, aFrame); + ExitNow(error = OT_ERROR_NONE); + } +#endif error = efr32RadioLoadChannelConfig(aFrame->mChannel, txPower); otEXPECT(error == OT_ERROR_NONE); OT_ASSERT(!getInternalFlag(FLAG_ONGOING_TX_DATA)); - OT_ASSERT(aFrame == &sTransmitFrame); - OT_ASSERT(aFrame->mPsdu == sTransmitPsdu); setInternalFlag(RADIO_TX_EVENTS, false); - sTxFrame = aFrame; + sTransmitBuffer[txBufIndex].iid = iid; + sCurrentTxPacket = &sTransmitBuffer[txBufIndex]; setInternalFlag(FLAG_CURRENT_TX_USE_CSMA, aFrame->mInfo.mTxInfo.mCsmaCaEnabled); #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE - if (sCslPeriod > 0 && sTxFrame->mInfo.mTxInfo.mTxDelay == 0) + if (sCslPeriod > 0 && sCurrentTxPacket->frame.mInfo.mTxInfo.mTxDelay == 0) { // Only called for CSL children (sCslPeriod > 0) // Note: Our SSEDs "schedule" transmissions to their parent in order to know // exactly when in the future the data packets go out so they can calculate // the accurate CSL phase to send to their parent. - sTxFrame->mInfo.mTxInfo.mTxDelayBaseTime = RAIL_GetTime(); - sTxFrame->mInfo.mTxInfo.mTxDelay = 3000; // Chosen after internal certification testing + sCurrentTxPacket->frame.mInfo.mTxInfo.mTxDelayBaseTime = RAIL_GetTime(); + sCurrentTxPacket->frame.mInfo.mTxInfo.mTxDelay = 3000; // Chosen after internal certification testing } #endif - updateIeInfoTxFrame(sTxFrame->mInfo.mTxInfo.mTxDelayBaseTime + sTxFrame->mInfo.mTxInfo.mTxDelay - + SHR_DURATION_US); + updateIeInfoTxFrame(sCurrentTxPacket->frame.mInfo.mTxInfo.mTxDelayBaseTime + + sCurrentTxPacket->frame.mInfo.mTxInfo.mTxDelay + SHR_DURATION_US); // Note - we need to call this outside of txCurrentPacket as for Series 2, // this results in calling the SE interface from a critical section which is not permitted. -#if OPENTHREAD_RADIO && OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE == 1 - radioProcessTransmitSecurity(sTxFrame, sTxFrame->mIid); -#else - radioProcessTransmitSecurity(sTxFrame, 0); -#endif + radioProcessTransmitSecurity(&sCurrentTxPacket->frame, sCurrentTxPacket->iid); #endif // OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 CORE_DECLARE_IRQ_STATE; @@ -1735,18 +1718,19 @@ otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame) } #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) void updateIeInfoTxFrame(uint32_t shrTxTime) { - OT_ASSERT(sTxFrame != NULL); + OT_ASSERT(sCurrentTxPacket != NULL); #if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT && OPENTHREAD_CONFIG_TIME_SYNC_ENABLE // Seek the time sync offset and update the rendezvous time - if (sTxFrame->mInfo.mTxInfo.mIeInfo->mTimeIeOffset != 0) + if (sCurrentTxPacket->frame.mInfo.mTxInfo.mIeInfo->mTimeIeOffset != 0) { - uint8_t *timeIe = sTxFrame->mPsdu + sTxFrame->mInfo.mTxInfo.mIeInfo->mTimeIeOffset; - uint64_t time = otPlatTimeGet() + sTxFrame->mInfo.mTxInfo.mIeInfo->mNetworkTimeOffset; + uint8_t *timeIe = sCurrentTxPacket->frame.mPsdu + sCurrentTxPacket->frame.mInfo.mTxInfo.mIeInfo->mTimeIeOffset; + uint64_t time = otPlatTimeGet() + sCurrentTxPacket->frame.mInfo.mTxInfo.mIeInfo->mNetworkTimeOffset; - *timeIe = sTxFrame->mInfo.mTxInfo.mIeInfo->mTimeSyncSeq; + *timeIe = sCurrentTxPacket->frame.mInfo.mTxInfo.mIeInfo->mTimeSyncSeq; *(++timeIe) = (uint8_t)(time & 0xff); for (uint8_t i = 1; i < sizeof(uint64_t); i++) @@ -1759,9 +1743,9 @@ void updateIeInfoTxFrame(uint32_t shrTxTime) #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE // Update IE data in the 802.15.4 header with the newest CSL period / phase - if (sCslPeriod > 0 && !sTxFrame->mInfo.mTxInfo.mIsHeaderUpdated) + if (sCslPeriod > 0 && !sCurrentTxPacket->frame.mInfo.mTxInfo.mIsHeaderUpdated) { - otMacFrameSetCslIe(sTxFrame, (uint16_t)sCslPeriod, getCslPhase(shrTxTime)); + otMacFrameSetCslIe(&sCurrentTxPacket->frame, (uint16_t)sCslPeriod, getCslPhase(shrTxTime)); } #else OT_UNUSED_VARIABLE(shrTxTime); @@ -1772,7 +1756,7 @@ void updateIeInfoTxFrame(uint32_t shrTxTime) void txCurrentPacket(void) { OT_ASSERT(getInternalFlag(FLAG_ONGOING_TX_DATA)); - OT_ASSERT(sTxFrame != NULL); + OT_ASSERT(sCurrentTxPacket != NULL); RAIL_TxOptions_t txOptions = RAIL_TX_OPTIONS_DEFAULT; RAIL_Status_t status = RAIL_STATUS_INVALID_STATE; @@ -1793,7 +1777,7 @@ void txCurrentPacket(void) (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_TX_PENDED_PHY, (uint32_t) false); } - frameLength = (uint8_t)sTxFrame->mLength; + frameLength = (uint8_t)sCurrentTxPacket->frame.mLength; if (PHY_HEADER_SIZE == 1) { @@ -1807,7 +1791,7 @@ void txCurrentPacket(void) RAIL_WriteTxFifo(gRailHandle, &PHRByte1, sizeof PHRByte1, true); RAIL_WriteTxFifo(gRailHandle, &PHRByte2, sizeof PHRByte2, false); } - RAIL_WriteTxFifo(gRailHandle, sTxFrame->mPsdu, frameLength - 2, false); + RAIL_WriteTxFifo(gRailHandle, sCurrentTxPacket->frame.mPsdu, frameLength - 2, false); RAIL_SchedulerInfo_t txSchedulerInfo = { .priority = RADIO_SCHEDULER_TX_PRIORITY, @@ -1815,7 +1799,7 @@ void txCurrentPacket(void) .transactionTime = 0, // will be calculated later if DMP is used }; - ackRequested = (sTxFrame->mPsdu[0] & IEEE802154_FRAME_FLAG_ACK_REQUIRED); + ackRequested = (sCurrentTxPacket->frame.mPsdu[0] & IEEE802154_FRAME_FLAG_ACK_REQUIRED); if (ackRequested) { txOptions |= RAIL_TX_OPTION_WAIT_FOR_ACK; @@ -1858,7 +1842,7 @@ void txCurrentPacket(void) } #endif - if (sTxFrame->mInfo.mTxInfo.mTxDelay == 0) + if (sCurrentTxPacket->frame.mInfo.mTxInfo.mTxDelay == 0) { if (getInternalFlag(FLAG_CURRENT_TX_USE_CSMA)) { @@ -1866,14 +1850,18 @@ void txCurrentPacket(void) // time needed for CSMA/CA txSchedulerInfo.transactionTime += RADIO_TIMING_CSMA_OVERHEAD_US; #endif - csmaConfig.csmaTries = sTxFrame->mInfo.mTxInfo.mMaxCsmaBackoffs; + csmaConfig.csmaTries = sCurrentTxPacket->frame.mInfo.mTxInfo.mMaxCsmaBackoffs; csmaConfig.ccaThreshold = sCcaThresholdDbm; - status = RAIL_StartCcaCsmaTx(gRailHandle, sTxFrame->mChannel, txOptions, &csmaConfig, &txSchedulerInfo); + status = RAIL_StartCcaCsmaTx(gRailHandle, + sCurrentTxPacket->frame.mChannel, + txOptions, + &csmaConfig, + &txSchedulerInfo); } else { - status = RAIL_StartTx(gRailHandle, sTxFrame->mChannel, txOptions, &txSchedulerInfo); + status = RAIL_StartTx(gRailHandle, sCurrentTxPacket->frame.mChannel, txOptions, &txSchedulerInfo); } if (status == RAIL_STATUS_NO_ERROR) @@ -1896,15 +1884,16 @@ void txCurrentPacket(void) // Note that both use single CCA config, overriding any CCA/CSMA configs from the stack // #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 - RAIL_ScheduleTxConfig_t scheduleTxOptions = {.when = sTxFrame->mInfo.mTxInfo.mTxDelayBaseTime - + sTxFrame->mInfo.mTxInfo.mTxDelay - SHR_DURATION_US, + RAIL_ScheduleTxConfig_t scheduleTxOptions = {.when = sCurrentTxPacket->frame.mInfo.mTxInfo.mTxDelayBaseTime + + sCurrentTxPacket->frame.mInfo.mTxInfo.mTxDelay + - SHR_DURATION_US, .mode = RAIL_TIME_ABSOLUTE, .txDuringRx = RAIL_SCHEDULED_TX_DURING_RX_POSTPONE_TX}; // CSL transmissions don't use CSMA but MAC accounts for single CCA time. // cslCsmaConfig is set to RAIL_CSMA_CONFIG_SINGLE_CCA above. status = RAIL_StartScheduledCcaCsmaTx(gRailHandle, - sTxFrame->mChannel, + sCurrentTxPacket->frame.mChannel, txOptions, &scheduleTxOptions, &cslCsmaConfig, @@ -1937,11 +1926,31 @@ void txCurrentPacket(void) } } +// This API gets called from init procedure so instance to IID mapping does not exist +// at that point. Also this api will get called sequentially so assign new transmit +// buffer if aInstance does not exist in sInstances. otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance) { OT_UNUSED_VARIABLE(aInstance); + uint8_t index = 0; + otRadioFrame *aRadioFrame = NULL; - return &sTransmitFrame; + otEXPECT(sl_ot_rtos_task_can_access_pal()); + +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + for (index = 0; index < OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_NUM; index++) + { + if (sInstances[index] == aInstance || sInstances[index] == NULL) + { + break; + } + } +#endif // OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + + aRadioFrame = &sTransmitBuffer[index].frame; + +exit: + return aRadioFrame; } int8_t otPlatRadioGetRssi(otInstance *aInstance) @@ -1949,14 +1958,15 @@ int8_t otPlatRadioGetRssi(otInstance *aInstance) otError error; uint32_t start; int8_t rssi = OT_RADIO_RSSI_INVALID; - uint8_t aChannel = sReceiveFrame.mChannel; - - OT_UNUSED_VARIABLE(aInstance); + uint8_t aChannel = sReceive.frame.mChannel; + uint8_t iid = efr32GetIidFromInstance(aInstance); + otEXPECT(sl_ot_rtos_task_can_access_pal()); otEXPECT(!getInternalFlag(FLAG_ONGOING_TX_DATA)); -#if FAST_CHANNEL_SWITCHING_SUPPORT - uint8_t index = getPanIndexFromIid(otNcpPlatGetCurCommandIid()); + OT_UNUSED_VARIABLE(iid); +#if SL_RAIL_UTIL_IEEE802154_FAST_CHANNEL_SWITCHING_ENABLED && OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + uint8_t index = efr32GetPanIndexFromIid(iid); OT_ASSERT(index < RAIL_IEEE802154_RX_CHANNEL_SWITCHING_NUM_CHANNELS); if (sChannelSwitchingCfg.channels[index] != UNINITIALIZED_CHANNEL) { @@ -2004,18 +2014,26 @@ void otPlatRadioSetPromiscuous(otInstance *aInstance, bool aEnable) RAIL_Status_t status; + otEXPECT(sl_ot_rtos_task_can_access_pal()); sPromiscuous = aEnable; status = RAIL_IEEE802154_SetPromiscuousMode(gRailHandle, aEnable); OT_ASSERT(status == RAIL_STATUS_NO_ERROR); + +exit: + return; } void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable) { OT_UNUSED_VARIABLE(aInstance); + otEXPECT(sl_ot_rtos_task_can_access_pal()); // set Frame Pending bit for all outgoing ACKs if aEnable is false sIsSrcMatchEnabled = aEnable; + +exit: + return; } otError otPlatRadioGetTransmitPower(otInstance *aInstance, int8_t *aPower) @@ -2035,40 +2053,14 @@ otError otPlatRadioGetTransmitPower(otInstance *aInstance, int8_t *aPower) otError otPlatRadioSetTransmitPower(otInstance *aInstance, int8_t aPower) { - OT_UNUSED_VARIABLE(aInstance); - - RAIL_Status_t status; - int8_t maxTxPower; - - sDefaultTxPower[otNcpPlatGetCurCommandIid()] = aPower; - maxTxPower = sli_get_max_tx_power_across_iids(); - - // RAIL_SetTxPowerDbm() takes power in units of deci-dBm (0.1dBm) - // Multiply by 10 because aPower is supposed be in units dBm - status = RAIL_SetTxPowerDbm(gRailHandle, ((RAIL_TxPower_t)maxTxPower) * 10); - OT_ASSERT(status == RAIL_STATUS_NO_ERROR); - - return OT_ERROR_NONE; + return sli_set_default_tx_power(aInstance, aPower); } // Required for RCP error recovery // See src/lib/spinel/radio_spinel.cpp::RestoreProperties() otError otPlatRadioSetChannelMaxTransmitPower(otInstance *aInstance, uint8_t aChannel, int8_t aMaxPower) { - otError error = OT_ERROR_NONE; - uint8_t iid = otNcpPlatGetCurCommandIid(); - int8_t txPower; - - OT_UNUSED_VARIABLE(aInstance); - - otEXPECT_ACTION(aChannel >= SL_CHANNEL_MIN && aChannel <= SL_CHANNEL_MAX, error = OT_ERROR_INVALID_ARGS); - - sMaxChannelPower[iid][aChannel - SL_CHANNEL_MIN] = aMaxPower; - txPower = sli_get_max_tx_power_across_iids(); - efr32RadioSetTxPower(txPower); - -exit: - return error; + return sli_set_channel_max_tx_power(aInstance, aChannel, aMaxPower); } otError otPlatRadioGetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t *aThreshold) @@ -2088,9 +2080,13 @@ otError otPlatRadioSetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t aTh { OT_UNUSED_VARIABLE(aInstance); + otError error = OT_ERROR_NONE; + + otEXPECT_ACTION(sl_ot_rtos_task_can_access_pal(), error = OT_ERROR_REJECTED); sCcaThresholdDbm = aThreshold; - return OT_ERROR_NONE; +exit: + return error; } int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance) @@ -2102,9 +2098,27 @@ int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance) otError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint16_t aScanDuration) { - OT_UNUSED_VARIABLE(aInstance); + otError error = OT_ERROR_NONE; + uint8_t iid = efr32GetIidFromInstance(aInstance); + + otEXPECT_ACTION(sl_ot_rtos_task_can_access_pal(), error = OT_ERROR_REJECTED); +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + OT_ASSERT((iid != RADIO_BCAST_IID) && (iid < RADIO_INTERFACE_COUNT)); + + // Push pending energy-scan and exit if radio is busy. + if (isRadioTransmittingOrScanning()) + { + energyScanParams params = {aScanChannel, aScanDuration}; + pushPendingCommand(kPendingCommandTypeEnergyScan, iid, ¶ms); + ExitNow(error = OT_ERROR_NONE); + } +#endif + + sEnergyScanActiveInterface = iid; + error = efr32StartEnergyScan(ENERGY_SCAN_MODE_ASYNC, aScanChannel, (RAIL_Time_t)aScanDuration * US_IN_MS); - return efr32StartEnergyScan(ENERGY_SCAN_MODE_ASYNC, aScanChannel, (RAIL_Time_t)aScanDuration * US_IN_MS); +exit: + return error; } //------------------------------------------------------------------------------ @@ -2119,12 +2133,12 @@ void otPlatRadioSetMacKey(otInstance *aInstance, const otMacKeyMaterial *aNextKey, otRadioKeyType aKeyType) { - uint8_t iid = otNcpPlatGetCurCommandIid(); - - OT_UNUSED_VARIABLE(aInstance); OT_UNUSED_VARIABLE(aKeyIdMode); OT_UNUSED_VARIABLE(aKeyType); + uint8_t iid = efr32GetIidFromInstance(aInstance); + + otEXPECT(sl_ot_rtos_task_can_access_pal()); OT_ASSERT(aPrevKey != NULL && aCurrKey != NULL && aNextKey != NULL); sMacKeys[iid].keyId = aKeyId; @@ -2153,15 +2167,17 @@ void otPlatRadioSetMacKey(otInstance *aInstance, sizeof(sMacKeys[iid].keys[MAC_KEY_NEXT]), &aKeyLen); OT_ASSERT(error == OT_ERROR_NONE); - #endif + +exit: + return; } void otPlatRadioSetMacFrameCounter(otInstance *aInstance, uint32_t aMacFrameCounter) { - uint8_t iid = otNcpPlatGetCurCommandIid(); + uint8_t iid = efr32GetIidFromInstance(aInstance); - OT_UNUSED_VARIABLE(aInstance); + otEXPECT(sl_ot_rtos_task_can_access_pal()); CORE_DECLARE_IRQ_STATE; CORE_ENTER_ATOMIC(); @@ -2169,13 +2185,16 @@ void otPlatRadioSetMacFrameCounter(otInstance *aInstance, uint32_t aMacFrameCoun sMacKeys[iid].macFrameCounter = aMacFrameCounter; CORE_EXIT_ATOMIC(); + +exit: + return; } void otPlatRadioSetMacFrameCounterIfLarger(otInstance *aInstance, uint32_t aMacFrameCounter) { - uint8_t iid = otNcpPlatGetCurCommandIid(); + uint8_t iid = efr32GetIidFromInstance(aInstance); - OT_UNUSED_VARIABLE(aInstance); + otEXPECT(sl_ot_rtos_task_can_access_pal()); CORE_DECLARE_IRQ_STATE; CORE_ENTER_ATOMIC(); @@ -2186,6 +2205,9 @@ void otPlatRadioSetMacFrameCounterIfLarger(otInstance *aInstance, uint32_t aMacF } CORE_EXIT_ATOMIC(); + +exit: + return; } //------------------------------------------------------------------------------ @@ -2197,20 +2219,28 @@ otError otPlatRadioEnableCsl(otInstance *aInstance, otShortAddress aShortAddr, const otExtAddress *aExtAddr) { + otError error = OT_ERROR_NONE; + OT_UNUSED_VARIABLE(aInstance); OT_UNUSED_VARIABLE(aShortAddr); OT_UNUSED_VARIABLE(aExtAddr); + otEXPECT_ACTION(sl_ot_rtos_task_can_access_pal(), error = OT_ERROR_REJECTED); + sCslPeriod = aCslPeriod; - return OT_ERROR_NONE; +exit: + return error; } void otPlatRadioUpdateCslSampleTime(otInstance *aInstance, uint32_t aCslSampleTime) { OT_UNUSED_VARIABLE(aInstance); + otEXPECT(sl_ot_rtos_task_can_access_pal()); sCslSampleTime = aCslSampleTime; +exit: + return; } #endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE @@ -2238,9 +2268,15 @@ otError otPlatRadioConfigureEnhAckProbing(otInstance *aInstance, const otShortAddress aShortAddress, const otExtAddress *aExtAddress) { + otError error; + OT_UNUSED_VARIABLE(aInstance); + otEXPECT_ACTION(sl_ot_rtos_task_can_access_pal(), error = OT_ERROR_REJECTED); - return otLinkMetricsConfigureEnhAckProbing(aShortAddress, aExtAddress, aLinkMetrics); + error = otLinkMetricsConfigureEnhAckProbing(aShortAddress, aExtAddress, aLinkMetrics); + +exit: + return error; } #endif #endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) @@ -2248,7 +2284,11 @@ otError otPlatRadioConfigureEnhAckProbing(otInstance *aInstance, #if OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE otError otPlatRadioSetCoexEnabled(otInstance *aInstance, bool aEnabled) { + otError error; + OT_UNUSED_VARIABLE(aInstance); + otEXPECT_ACTION(sl_ot_rtos_task_can_access_pal(), error = OT_ERROR_REJECTED); + sl_status_t status = sl_rail_util_coex_set_enable(aEnabled); if (aEnabled && !sl_rail_util_coex_is_enabled()) { @@ -2256,7 +2296,11 @@ otError otPlatRadioSetCoexEnabled(otInstance *aInstance, bool aEnabled) return OT_ERROR_FAILED; } sRadioCoexEnabled = aEnabled; - return (status != SL_STATUS_OK) ? OT_ERROR_FAILED : OT_ERROR_NONE; + + error = (status != SL_STATUS_OK) ? OT_ERROR_FAILED : OT_ERROR_NONE; + +exit: + return error; } bool otPlatRadioIsCoexEnabled(otInstance *aInstance) @@ -2265,21 +2309,6 @@ bool otPlatRadioIsCoexEnabled(otInstance *aInstance) return (sRadioCoexEnabled && sl_rail_util_coex_is_enabled()); } -otError otPlatRadioGetCoexMetrics(otInstance *aInstance, otRadioCoexMetrics *aCoexMetrics) -{ - OT_UNUSED_VARIABLE(aInstance); - otError error = OT_ERROR_NONE; - - otEXPECT_ACTION(aCoexMetrics != NULL, error = OT_ERROR_INVALID_ARGS); - - memset(aCoexMetrics, 0, sizeof(otRadioCoexMetrics)); - // TO DO: - // Tracking coex metrics with detailed granularity currently - // not implemented. - // memcpy(aCoexMetrics, &sCoexMetrics, sizeof(otRadioCoexMetrics)); -exit: - return error; -} #endif // OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) @@ -2288,6 +2317,7 @@ otError otPlatRadioGetCoexMetrics(otInstance *aInstance, otRadioCoexMetrics *aCo // Return false if we should generate an immediate ACK // Return true otherwise +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) static bool writeIeee802154EnhancedAck(RAIL_Handle_t aRailHandle, RAIL_RxPacketInfo_t *packetInfoForEnhAck, uint8_t *initialPktReadBytes, @@ -2318,7 +2348,7 @@ static bool writeIeee802154EnhancedAck(RAIL_Handle_t aRailHandle, receivedPsdu, FINAL_PACKET_LENGTH_WITH_IE); - uint8_t iid = INVALID_VALUE; + uint8_t iid = INVALID_INTERFACE_INDEX; if (*initialPktReadBytes == 0U) { @@ -2339,40 +2369,15 @@ static bool writeIeee802154EnhancedAck(RAIL_Handle_t aRailHandle, uint8_t *dataPtr = NULL; bool setFramePending = false; -#if _SILICON_LABS_32B_SERIES_1_CONFIG == 1 && OPENTHREAD_RADIO && OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE == 1 - otPanId destPanId; - - destPanId = efr32GetDstPanId(&receivedFrame); - iid = utilsSoftSrcMatchFindIidFromPanId(destPanId); -#else iid = getIidFromFilterMask(packetInfoForEnhAck->filterMask); -#endif otMacFrameGetSrcAddr(&receivedFrame, &aSrcAddress); if (sIsSrcMatchEnabled && (aSrcAddress.mType != OT_MAC_ADDRESS_TYPE_NONE)) { -#if _SILICON_LABS_32B_SERIES_1_CONFIG == 1 && OPENTHREAD_RADIO && OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE == 1 - if (iid == 0 || iid == INVALID_VALUE) // search all tables only if we cant find the iid based on dest panid - { - for (uint8_t i = 1; i <= RADIO_CONFIG_SRC_MATCH_PANID_NUM; i++) - { - setFramePending = (aSrcAddress.mType == OT_MAC_ADDRESS_TYPE_EXTENDED - ? (utilsSoftSrcMatchExtFindEntry(i, &aSrcAddress.mAddress.mExtAddress) >= 0) - : (utilsSoftSrcMatchShortFindEntry(i, aSrcAddress.mAddress.mShortAddress) >= 0)); - if (setFramePending) - { - break; - } - } - } - else -#endif - { - setFramePending = (aSrcAddress.mType == OT_MAC_ADDRESS_TYPE_EXTENDED - ? (utilsSoftSrcMatchExtFindEntry(iid, &aSrcAddress.mAddress.mExtAddress) >= 0) - : (utilsSoftSrcMatchShortFindEntry(iid, aSrcAddress.mAddress.mShortAddress) >= 0)); - } + setFramePending = (aSrcAddress.mType == OT_MAC_ADDRESS_TYPE_EXTENDED + ? (utilsSoftSrcMatchExtFindEntry(iid, &aSrcAddress.mAddress.mExtAddress) >= 0) + : (utilsSoftSrcMatchShortFindEntry(iid, aSrcAddress.mAddress.mShortAddress) >= 0)); } // Generate our IE header. @@ -2467,6 +2472,7 @@ static bool writeIeee802154EnhancedAck(RAIL_Handle_t aRailHandle, //------------------------------------------------------------------------------ // RAIL callbacks +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) static void dataRequestCommandCallback(RAIL_Handle_t aRailHandle) { #define MAX_EXPECTED_BYTES (2U + 2U + 1U) // PHR + FCF + DSN @@ -2510,29 +2516,10 @@ static void dataRequestCommandCallback(RAIL_Handle_t aRailHandle) otEXPECT(status == RAIL_STATUS_NO_ERROR); uint8_t iid = getIidFromFilterMask(packetInfo.filterMask); -#if _SILICON_LABS_32B_SERIES_1_CONFIG == 1 && OPENTHREAD_RADIO && OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE == 1 - if (iid == 0) // on MG1 the RAIL filter mask doesn't work so search all tables - { - for (uint8_t i = 1; i <= RADIO_CONFIG_SRC_MATCH_PANID_NUM; i++) - { - framePendingSet = - (sourceAddress.length == RAIL_IEEE802154_LongAddress - ? (utilsSoftSrcMatchExtFindEntry(i, (otExtAddress *)sourceAddress.longAddress) >= 0) - : (utilsSoftSrcMatchShortFindEntry(i, sourceAddress.shortAddress) >= 0)); - if (framePendingSet) - { - status = RAIL_IEEE802154_SetFramePending(aRailHandle); - otEXPECT(status == RAIL_STATUS_NO_ERROR); - break; - } - } - } - else -#endif - if ((sourceAddress.length == RAIL_IEEE802154_LongAddress - && utilsSoftSrcMatchExtFindEntry(iid, (otExtAddress *)sourceAddress.longAddress) >= 0) - || (sourceAddress.length == RAIL_IEEE802154_ShortAddress - && utilsSoftSrcMatchShortFindEntry(iid, sourceAddress.shortAddress) >= 0)) + if ((sourceAddress.length == RAIL_IEEE802154_LongAddress + && utilsSoftSrcMatchExtFindEntry(iid, (otExtAddress *)sourceAddress.longAddress) >= 0) + || (sourceAddress.length == RAIL_IEEE802154_ShortAddress + && utilsSoftSrcMatchShortFindEntry(iid, sourceAddress.shortAddress) >= 0)) { status = RAIL_IEEE802154_SetFramePending(aRailHandle); otEXPECT(status == RAIL_STATUS_NO_ERROR); @@ -2568,7 +2555,8 @@ static void dataRequestCommandCallback(RAIL_Handle_t aRailHandle) } } -static void packetReceivedCallback(RAIL_RxPacketHandle_t packetHandle) +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +static void packetReceivedCallback(void) { RAIL_RxPacketInfo_t packetInfo; RAIL_RxPacketDetails_t packetDetails; @@ -2576,12 +2564,11 @@ static void packetReceivedCallback(RAIL_RxPacketHandle_t packetHandle) bool framePendingInAck = false; bool dropPacket = false; uint8_t iid = 0; - uint8_t *psdu = sReceiveAckFrame.mPsdu; -#if SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT > 1 - rxBufferIndex_t receiveBufferInUse = SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT; -#endif + sl_status_t status; + bool isRxPacketQueued; + rxBuffer *rxPacketBuf = NULL; - packetHandle = RAIL_GetRxPacketInfo(gRailHandle, packetHandle, &packetInfo); + RAIL_RxPacketHandle_t packetHandle = RAIL_GetRxPacketInfo(gRailHandle, RAIL_RX_PACKET_HANDLE_NEWEST, &packetInfo); otEXPECT_ACTION( (packetHandle != RAIL_RX_PACKET_HANDLE_INVALID && packetInfo.packetStatus == RAIL_RX_PACKET_READY_SUCCESS), dropPacket = true); @@ -2595,15 +2582,6 @@ static void packetReceivedCallback(RAIL_RxPacketHandle_t packetHandle) iid = getIidFromFilterMask(packetInfo.filterMask); -#if SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT > 1 - if (!packetDetails.isAck) - { - receiveBufferInUse = getFreeBufferIndex(); - otEXPECT_ACTION(receiveBufferInUse < SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT, dropPacket = true); - psdu = sReceivePacket[receiveBufferInUse].psdu; - } -#endif - if (packetDetails.isAck) { otEXPECT_ACTION( @@ -2611,23 +2589,24 @@ static void packetReceivedCallback(RAIL_RxPacketHandle_t packetHandle) dropPacket = true); // read packet - RAIL_CopyRxPacket(psdu, &packetInfo); + RAIL_CopyRxPacket(sReceiveAck.frame.mPsdu, &packetInfo); #if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT railDebugCounters.mRailEventAcksReceived++; #endif - sReceiveAckFrame.mLength = length; - - // Releasing the ACK frames here, ensures that the main thread (processRxPackets) - // is not wasting cycles, releasing the ACK frames from the Rx FIFO queue. - RAIL_ReleaseRxPacket(gRailHandle, packetHandle); + sReceiveAck.frame.mLength = length; (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_RX_ENDED, (uint32_t)isReceivingFrame()); - if (txWaitingForAck() && (psdu[IEEE802154_DSN_OFFSET] == sTransmitFrame.mPsdu[IEEE802154_DSN_OFFSET])) + if (txWaitingForAck() + && (sReceiveAck.frame.mPsdu[IEEE802154_DSN_OFFSET] == sCurrentTxPacket->frame.mPsdu[IEEE802154_DSN_OFFSET])) { otEXPECT_ACTION(validatePacketTimestamp(&packetDetails, length), dropPacket = true); - updateRxFrameDetails(&packetDetails, false, false, iid, INVALID_VALUE); + + sReceiveAck.frame.mInfo.mRxInfo.mRssi = packetDetails.rssi; + sReceiveAck.frame.mInfo.mRxInfo.mLqi = packetDetails.lqi; + sReceiveAck.iid = iid; + updateRxFrameTimestamp(true, packetDetails.timeReceived.packetTime); // Processing the ACK frame in ISR context avoids the Tx state to be messed up, // in case the Rx FIFO queue gets wiped out in a DMP situation. @@ -2653,24 +2632,31 @@ static void packetReceivedCallback(RAIL_RxPacketHandle_t packetHandle) { otEXPECT_ACTION(sPromiscuous || (length >= IEEE802154_MIN_DATA_LENGTH), dropPacket = true); -#if SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT > 1 + otEXPECT_ACTION(validatePacketTimestamp(&packetDetails, length), dropPacket = true); + + // Drop the packet if queue is full. + otEXPECT_ACTION(!queueIsFull(&sRxPacketQueue), dropPacket = true); + // Allocate a block from memory pool for the received packet. + status = sl_memory_pool_alloc(&sRxPacketMemPoolHandle, (void **)&rxPacketBuf); + // Drop the packet if no more memory block present in the pool to store it. + otEXPECT_ACTION(status == SL_STATUS_OK && rxPacketBuf != NULL, dropPacket = true); + // read packet - RAIL_CopyRxPacket(psdu, &packetInfo); - RAIL_ReleaseRxPacket(gRailHandle, packetHandle); + RAIL_CopyRxPacket(rxPacketBuf->psdu, &packetInfo); - otEXPECT_ACTION(validatePacketTimestamp(&packetDetails, length), dropPacket = true); + rxPacketBuf->packetInfo.length = (uint8_t)length; + rxPacketBuf->packetInfo.channel = (uint8_t)packetDetails.channel; + rxPacketBuf->packetInfo.rssi = packetDetails.rssi; + rxPacketBuf->packetInfo.lqi = packetDetails.lqi; + rxPacketBuf->packetInfo.timestamp = packetDetails.timeReceived.packetTime; + rxPacketBuf->packetInfo.iid = iid; - reserveNextRxBuffer(); - sReceivePacket[receiveBufferInUse].packetInfo.length = length; - sReceivePacket[receiveBufferInUse].packetInfo.channel = packetDetails.channel; - sReceivePacket[receiveBufferInUse].packetInfo.rssi = packetDetails.rssi; - sReceivePacket[receiveBufferInUse].packetInfo.lqi = packetDetails.lqi; - sReceivePacket[receiveBufferInUse].packetInfo.timestamp = packetDetails.timeReceived.packetTime; - sReceivePacket[receiveBufferInUse].packetInfo.iid = iid; + // Queue the rx packet or drop it if queueing fails and free the memory block. + isRxPacketQueued = queueAdd(&sRxPacketQueue, (void *)rxPacketBuf); + otEXPECT_ACTION(isRxPacketQueued, dropPacket = true); #if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT railDebugCounters.mRailPlatRadioReceiveProcessedCount++; -#endif #endif if (macFcf & IEEE802154_FRAME_FLAG_ACK_REQUIRED) @@ -2696,12 +2682,13 @@ static void packetReceivedCallback(RAIL_RxPacketHandle_t packetHandle) exit: if (dropPacket) { - // Release the corrupted packet that won't be processed further - (void)RAIL_ReleaseRxPacket(gRailHandle, packetHandle); (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_RX_CORRUPTED, (uint32_t)isReceivingFrame()); + + IgnoreError(sl_memory_pool_free(&sRxPacketMemPoolHandle, rxPacketBuf)); } } +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) static void packetSentCallback(bool isAck) { if (isAck) @@ -2738,6 +2725,7 @@ static void packetSentCallback(bool isAck) } } +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) static void txFailedCallback(bool isAck, uint32_t status) { if (isAck) @@ -2766,6 +2754,7 @@ static void txFailedCallback(bool isAck, uint32_t status) } } +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) static void ackTimeoutCallback(void) { OT_ASSERT(txWaitingForAck()); @@ -2791,6 +2780,7 @@ static void ackTimeoutCallback(void) emPendingData = false; } +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) static void schedulerEventCallback(RAIL_Handle_t aRailHandle) { RAIL_SchedulerStatus_t status = RAIL_GetSchedulerStatus(aRailHandle); @@ -2826,6 +2816,7 @@ static void schedulerEventCallback(RAIL_Handle_t aRailHandle) } } +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) static void configUnscheduledCallback(void) { // We are waiting for an ACK: we will never get the ACK we were waiting for. @@ -2843,6 +2834,7 @@ static void configUnscheduledCallback(void) } } +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) static void RAILCb_Generic(RAIL_Handle_t aRailHandle, RAIL_Events_t aEvents) { #ifdef SL_CATALOG_RAIL_UTIL_IEEE802154_STACK_EVENT_PRESENT @@ -2957,7 +2949,7 @@ static void RAILCb_Generic(RAIL_Handle_t aRailHandle, RAIL_Events_t aEvents) if (aEvents & RAIL_EVENT_RX_PACKET_RECEIVED) { - packetReceivedCallback(RAIL_HoldRxPacket(aRailHandle)); + packetReceivedCallback(); #if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT railDebugCounters.mRailEventPacketReceived++; #endif @@ -3065,6 +3057,7 @@ static void RAILCb_Generic(RAIL_Handle_t aRailHandle, RAIL_Events_t aEvents) //------------------------------------------------------------------------------ // Main thread packet handling +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) static bool validatePacketDetails(RAIL_RxPacketHandle_t packetHandle, RAIL_RxPacketDetails_t *pPacketDetails, RAIL_RxPacketInfo_t *pPacketInfo, @@ -3129,6 +3122,7 @@ static bool validatePacketDetails(RAIL_RxPacketHandle_t packetHandle, return pktValid; } +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) static bool validatePacketTimestamp(RAIL_RxPacketDetails_t *pPacketDetails, uint16_t packetLength) { bool rxTimestampValid = true; @@ -3146,73 +3140,52 @@ static bool validatePacketTimestamp(RAIL_RxPacketDetails_t *pPacketDetails, uint return rxTimestampValid; } -static void updateRxFrameDetails(RAIL_RxPacketDetails_t *pPacketDetails, - bool securedOutgoingEnhancedAck, - bool framePendingSetInOutgoingAck, - uint8_t iid, - uint8_t aReceiveBufferInUse) +otError otPlatMultipanGetActiveInstance(otInstance **aInstance) +{ + otError error = OT_ERROR_NOT_IMPLEMENTED; + OT_UNUSED_VARIABLE(aInstance); + + return error; +} + +otError otPlatMultipanSetActiveInstance(otInstance *aInstance, bool aCompletePending) +{ + otError error = OT_ERROR_NOT_IMPLEMENTED; + + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aCompletePending); + + return error; +} + +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +static void updateRxFrameTimestamp(bool aIsAckFrame, RAIL_Time_t aTimestamp) { // Current time > sync-receive timestamp // Therefore lower 32 bits of current time should always be greater than lower 32 bits // of sync-rx timestamp unless there is a overflow. In such cases, we do not want to // take overflow into consideration for sync-rx timestamp. - uint64_t railUsTimeNow = otPlatTimeGet(); - uint32_t railUsTimerWraps = railUsTimeNow >> 32; - RAIL_Time_t timestamp = (pPacketDetails != NULL ? pPacketDetails->timeReceived.packetTime - : sReceivePacket[aReceiveBufferInUse].packetInfo.timestamp); + uint64_t railUsTimeNow = otPlatTimeGet(); + uint32_t railUsTimerWraps = railUsTimeNow >> 32; // Address multiple overflows, such as what would happen if the current time overflows // from 0x00000001FFFFFFFF to 0x0000000200000000 (leave the higher 32 bits as 0) - if ((railUsTimeNow & 0xFFFFFFFF) <= timestamp) + if ((railUsTimeNow & 0xFFFFFFFF) <= aTimestamp) { railUsTimerWraps--; } - if (pPacketDetails != NULL && pPacketDetails->isAck) + if (aIsAckFrame) { - sReceiveAckFrame.mInfo.mRxInfo.mRssi = pPacketDetails->rssi; - sReceiveAckFrame.mInfo.mRxInfo.mLqi = pPacketDetails->lqi; - sReceiveAckFrame.mInfo.mRxInfo.mTimestamp = timestamp + ((uint64_t)railUsTimerWraps << 32); -#if OPENTHREAD_RADIO && OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE == 1 - sReceiveAckFrame.mIid = iid; -#endif + sReceiveAck.frame.mInfo.mRxInfo.mTimestamp = aTimestamp + ((uint64_t)railUsTimerWraps << 32); } else { - if (pPacketDetails != NULL) - { - sReceiveFrame.mInfo.mRxInfo.mRssi = pPacketDetails->rssi; - sLastRssi = pPacketDetails->rssi; - - sReceiveFrame.mInfo.mRxInfo.mLqi = pPacketDetails->lqi; - sLastLqi = pPacketDetails->lqi; - } - else - { - sReceiveFrame.mInfo.mRxInfo.mRssi = sReceivePacket[aReceiveBufferInUse].packetInfo.rssi; - sLastRssi = sReceivePacket[aReceiveBufferInUse].packetInfo.rssi; - - sReceiveFrame.mInfo.mRxInfo.mLqi = sReceivePacket[aReceiveBufferInUse].packetInfo.lqi; - sLastLqi = sReceivePacket[aReceiveBufferInUse].packetInfo.rssi; - } - - sReceiveFrame.mInfo.mRxInfo.mTimestamp = timestamp + ((uint64_t)railUsTimerWraps << 32); - // Set this flag only when the packet is really acknowledged with a secured enhanced ACK. - sReceiveFrame.mInfo.mRxInfo.mAckedWithSecEnhAck = securedOutgoingEnhancedAck; - // Set this flag only when the packet is really acknowledged with frame pending set. - sReceiveFrame.mInfo.mRxInfo.mAckedWithFramePending = framePendingSetInOutgoingAck; -#if OPENTHREAD_RADIO && OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE == 1 - sReceiveFrame.mIid = iid; -#endif - -#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 - // Use stored values for these - sReceiveFrame.mInfo.mRxInfo.mAckKeyId = sMacKeys[iid].ackKeyId; - sReceiveFrame.mInfo.mRxInfo.mAckFrameCounter = sMacKeys[iid].ackFrameCounter; -#endif + sReceive.frame.mInfo.mRxInfo.mTimestamp = aTimestamp + ((uint64_t)railUsTimerWraps << 32); } } +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) static otError skipRxPacketLengthBytes(RAIL_RxPacketInfo_t *pPacketInfo) { otError error = OT_ERROR_NONE; @@ -3237,149 +3210,120 @@ static otError skipRxPacketLengthBytes(RAIL_RxPacketInfo_t *pPacketInfo) return error; } -static bool prepareNextRxPacketforCb(void) +// This function dequeues the rx-queue, move the content to sReceive buffer +// and return the memory block which was used to store the received packet. +// So that memory block can be freed after submitting the receiveDone Callback. +static rxBuffer *prepareNextRxPacketforCb(void) { -#if SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT == 1 - RAIL_RxPacketHandle_t packetHandle = RAIL_RX_PACKET_HANDLE_INVALID; - RAIL_RxPacketInfo_t packetInfo; - RAIL_RxPacketDetails_t packetDetails; - RAIL_Status_t status; - uint16_t length; - bool rxProcessDone = false; - uint8_t iid = 0; - rxBufferIndex_t index = 0; - - CORE_DECLARE_IRQ_STATE; - CORE_ENTER_ATOMIC(); - - // Initialise the mPsdu to free buffer - sReceiveFrame.mPsdu = sReceivePacket[index].psdu; - - packetHandle = RAIL_GetRxPacketInfo(gRailHandle, RAIL_RX_PACKET_HANDLE_OLDEST_COMPLETE, &packetInfo); - otEXPECT_ACTION( - (packetHandle != RAIL_RX_PACKET_HANDLE_INVALID && packetInfo.packetStatus == RAIL_RX_PACKET_READY_SUCCESS), - packetHandle = RAIL_RX_PACKET_HANDLE_INVALID); - - iid = getIidFromFilterMask(packetInfo.filterMask); - - otEXPECT(validatePacketDetails(packetHandle, &packetDetails, &packetInfo, &length)); - - otEXPECT((skipRxPacketLengthBytes(&packetInfo)) == OT_ERROR_NONE); - - // As received ACK frames are already processed in packetReceivedCallback, - // we only need to read and process the non-ACK frames here. - otEXPECT(sPromiscuous || (!packetDetails.isAck && (length >= IEEE802154_MIN_DATA_LENGTH))); - - // read packet - RAIL_CopyRxPacket(sReceiveFrame.mPsdu, &packetInfo); - sReceiveFrame.mLength = length; - - uint8_t *macFcfPointer = sReceiveFrame.mPsdu; - sReceiveFrame.mChannel = packetDetails.channel; + rxBuffer *rxPacketBuf = (rxBuffer *)queueRemove(&sRxPacketQueue); + OT_ASSERT(rxPacketBuf != NULL); + uint8_t *psdu = rxPacketBuf->psdu; // Check the reserved bits in the MAC header, then clear them. - // If we sent an enhanced ACK, check if it was secured. - bool securedOutgoingEnhancedAck = ((*macFcfPointer & IEEE802154_SECURED_OUTGOING_ENHANCED_ACK) != 0); - *macFcfPointer &= ~IEEE802154_SECURED_OUTGOING_ENHANCED_ACK; + // Set this flag only when the packet is really acknowledged with a secured enhanced ACK. + sReceive.frame.mInfo.mRxInfo.mAckedWithSecEnhAck = ((*psdu & IEEE802154_SECURED_OUTGOING_ENHANCED_ACK) != 0); + *psdu &= ~IEEE802154_SECURED_OUTGOING_ENHANCED_ACK; // Check whether frame pendinng bit was set in the outgoing ACK. - bool framePendingSetInOutgoingAck = ((*macFcfPointer & IEEE802154_FRAME_PENDING_SET_IN_OUTGOING_ACK) != 0); - *macFcfPointer &= ~IEEE802154_FRAME_PENDING_SET_IN_OUTGOING_ACK; + // Set this flag only when the packet is really acknowledged with frame pending set. + sReceive.frame.mInfo.mRxInfo.mAckedWithFramePending = ((*psdu & IEEE802154_FRAME_PENDING_SET_IN_OUTGOING_ACK) != 0); + *psdu &= ~IEEE802154_FRAME_PENDING_SET_IN_OUTGOING_ACK; - status = RAIL_ReleaseRxPacket(gRailHandle, packetHandle); - if (status == RAIL_STATUS_NO_ERROR) - { - packetHandle = RAIL_RX_PACKET_HANDLE_INVALID; - } + sReceive.frame.mChannel = rxPacketBuf->packetInfo.channel; + sReceive.frame.mLength = rxPacketBuf->packetInfo.length; + sReceive.frame.mPsdu = rxPacketBuf->psdu; - otEXPECT(validatePacketTimestamp(&packetDetails, length)); - updateRxFrameDetails(&packetDetails, securedOutgoingEnhancedAck, framePendingSetInOutgoingAck, iid, 0); - rxProcessDone = true; + sReceive.frame.mInfo.mRxInfo.mRssi = rxPacketBuf->packetInfo.rssi; + sLastRssi = rxPacketBuf->packetInfo.rssi; -#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT - railDebugCounters.mRailPlatRadioReceiveProcessedCount++; -#endif + sReceive.frame.mInfo.mRxInfo.mLqi = rxPacketBuf->packetInfo.lqi; + sLastLqi = rxPacketBuf->packetInfo.rssi; -exit: - if (packetHandle != RAIL_RX_PACKET_HANDLE_INVALID) - { - RAIL_ReleaseRxPacket(gRailHandle, packetHandle); - } - CORE_EXIT_ATOMIC(); -#else - bool rxProcessDone = true; - rxBufferIndex_t index = getStoredBufferIndex(); - uint8_t *psdu = sReceivePacket[index].psdu; + sReceive.iid = rxPacketBuf->packetInfo.iid; - // Check the reserved bits in the MAC header, then clear them. - // If we sent an enhanced ACK, check if it was secured. - bool securedOutgoingEnhancedAck = ((*psdu & IEEE802154_SECURED_OUTGOING_ENHANCED_ACK) != 0); - *psdu &= ~IEEE802154_SECURED_OUTGOING_ENHANCED_ACK; - - // Check whether frame pendinng bit was set in the outgoing ACK. - bool framePendingSetInOutgoingAck = ((*psdu & IEEE802154_FRAME_PENDING_SET_IN_OUTGOING_ACK) != 0); - *psdu &= ~IEEE802154_FRAME_PENDING_SET_IN_OUTGOING_ACK; - - sReceiveFrame.mChannel = sReceivePacket[index].packetInfo.channel; - sReceiveFrame.mLength = sReceivePacket[index].packetInfo.length; - sReceiveFrame.mPsdu = sReceivePacket[index].psdu; - - updateRxFrameDetails(NULL, - securedOutgoingEnhancedAck, - framePendingSetInOutgoingAck, - sReceivePacket[index].packetInfo.iid, - index); +#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 + // Use stored values for these + sReceive.frame.mInfo.mRxInfo.mAckKeyId = sMacKeys[sReceive.iid].ackKeyId; + sReceive.frame.mInfo.mRxInfo.mAckFrameCounter = sMacKeys[sReceive.iid].ackFrameCounter; #endif - return rxProcessDone; + updateRxFrameTimestamp(false, rxPacketBuf->packetInfo.timestamp); + return rxPacketBuf; } static void processNextRxPacket(otInstance *aInstance) { - if (prepareNextRxPacketforCb()) - { - sReceiveError = OT_ERROR_NONE; + OT_UNUSED_VARIABLE(aInstance); + sReceiveError = OT_ERROR_NONE; + uint8_t interfaceId = INVALID_INTERFACE_INDEX; + otInstance *instance = NULL; + rxBuffer *rxPacketBuf = NULL; + + rxPacketBuf = prepareNextRxPacketforCb(); + + // sReceive buffer gets populated from prepareNextRxPacketforCb. + interfaceId = sReceive.iid; + // Submit broadcast packet to all initilized instances. + do + { +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + instance = otPlatMultipanIidToInstance(interfaceId); +#else + instance = aInstance; +#endif + interfaceId++; + if (instance == NULL) + { + continue; + } #if OPENTHREAD_CONFIG_DIAG_ENABLE if (otPlatDiagModeGet()) { - otPlatDiagRadioReceiveDone(aInstance, &sReceiveFrame, sReceiveError); + otPlatDiagRadioReceiveDone(instance, &sReceive.frame, sReceiveError); } else -#endif +#endif // OPENTHREAD_CONFIG_DIAG_ENABLE { -#if OPENTHREAD_RADIO && OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE == 1 && (defined SL_CATALOG_OT_RCP_GP_INTERFACE_PRESENT) - (void)sl_gp_intf_is_gp_pkt(&sReceiveFrame, true); + bool isGpPacket = sl_gp_intf_is_gp_pkt(&sReceive.frame); +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + // For multipan RCP, continue normal processing. + OT_UNUSED_VARIABLE(isGpPacket); +#else + // Else, we should not receive GP packets. + otEXPECT(!isGpPacket); #endif - otPlatRadioReceiveDone(aInstance, &sReceiveFrame, sReceiveError); -#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT - railDebugCounters.mRailPlatRadioReceiveDoneCbCount++; + +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + (void)sl_gp_intf_should_buffer_pkt(instance, &sReceive.frame, true); #endif + otPlatRadioReceiveDone(instance, &sReceive.frame, sReceiveError); } + } while (sReceive.iid == RADIO_BCAST_IID && interfaceId < RADIO_INTERFACE_COUNT); -#if SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT > 1 - releaseCurrentRxBuffer(); +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + railDebugCounters.mRailPlatRadioReceiveDoneCbCount++; #endif - otSysEventSignalPending(); - } +#if !OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE +exit: +#endif + IgnoreError(sl_memory_pool_free(&sRxPacketMemPoolHandle, rxPacketBuf)); + otSysEventSignalPending(); } static void processRxPackets(otInstance *aInstance) { -#if SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT > 1 - while (canProcessNextRxBuffer()) + while (!queueIsEmpty(&sRxPacketQueue)) { processNextRxPacket(aInstance); } -#else - processNextRxPacket(aInstance); -#endif } static void processTxComplete(otInstance *aInstance) { + OT_UNUSED_VARIABLE(aInstance); otError txStatus; otRadioFrame *ackFrame = NULL; @@ -3389,9 +3333,9 @@ static void processTxComplete(otInstance *aInstance) { txStatus = OT_ERROR_NONE; - if (sTransmitFrame.mPsdu[0] & IEEE802154_FRAME_FLAG_ACK_REQUIRED) + if (sCurrentTxPacket->frame.mPsdu[0] & IEEE802154_FRAME_FLAG_ACK_REQUIRED) { - ackFrame = &sReceiveAckFrame; + ackFrame = &sReceiveAck.frame; } setInternalFlag(EVENT_TX_SUCCESS, false); @@ -3420,15 +3364,28 @@ static void processTxComplete(otInstance *aInstance) #if OPENTHREAD_CONFIG_DIAG_ENABLE if (otPlatDiagModeGet()) { - otPlatDiagRadioTransmitDone(aInstance, sTxFrame, txStatus); +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + otPlatDiagRadioTransmitDone(otPlatMultipanIidToInstance(sCurrentTxPacket->iid), + &sCurrentTxPacket->frame, + txStatus); +#else + otPlatDiagRadioTransmitDone(aInstance, &sCurrentTxPacket->frame, txStatus); +#endif } else #endif { // Clear any internally-set txDelays so future transmits are not affected. - sTxFrame->mInfo.mTxInfo.mTxDelayBaseTime = 0; - sTxFrame->mInfo.mTxInfo.mTxDelay = 0; - otPlatRadioTxDone(aInstance, sTxFrame, ackFrame, txStatus); + sCurrentTxPacket->frame.mInfo.mTxInfo.mTxDelayBaseTime = 0; + sCurrentTxPacket->frame.mInfo.mTxInfo.mTxDelay = 0; +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + otPlatRadioTxDone(otPlatMultipanIidToInstance(sCurrentTxPacket->iid), + &sCurrentTxPacket->frame, + ackFrame, + txStatus); +#else + otPlatRadioTxDone(aInstance, &sCurrentTxPacket->frame, ackFrame, txStatus); +#endif } #if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT @@ -3438,6 +3395,40 @@ static void processTxComplete(otInstance *aInstance) } } +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE +static inline void processPendingCommands(void) +{ + // Check and process pending transmit and energy scan commands if radio is not busy. + if (!queueIsEmpty(&sPendingCommandQueue) && (!isRadioTransmittingOrScanning())) + { + // Dequeue the pending command + pendingCommandEntry *pendingCommand = (pendingCommandEntry *)queueRemove(&sPendingCommandQueue); + OT_ASSERT(pendingCommand != NULL); + uint8_t iid = pendingCommand->iid; + + switch (pendingCommand->cmdType) + { + case kPendingCommandTypeTransmit: + otPlatRadioTransmit(otPlatMultipanIidToInstance(iid), pendingCommand->request.txFrame); + break; + + case kPendingCommandTypeEnergyScan: + otPlatRadioEnergyScan(otPlatMultipanIidToInstance(iid), + pendingCommand->request.energyScan.scanChannel, + pendingCommand->request.energyScan.scanDuration); + break; + + default: + OT_ASSERT(false); + break; + } + + // Free the allocated memory. + sl_free(pendingCommand); + } +} +#endif // OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + void efr32RadioProcess(otInstance *aInstance) { (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_TICK, 0U); @@ -3450,13 +3441,23 @@ void efr32RadioProcess(otInstance *aInstance) if (sEnergyScanMode == ENERGY_SCAN_MODE_ASYNC && sEnergyScanStatus == ENERGY_SCAN_STATUS_COMPLETED) { sEnergyScanStatus = ENERGY_SCAN_STATUS_IDLE; + OT_ASSERT(sEnergyScanActiveInterface != INVALID_INTERFACE_INDEX); +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + otPlatRadioEnergyScanDone(otPlatMultipanIidToInstance(sEnergyScanActiveInterface), sEnergyScanResultDbm); +#else otPlatRadioEnergyScanDone(aInstance, sEnergyScanResultDbm); +#endif + sEnergyScanActiveInterface = INVALID_INTERFACE_INDEX; otSysEventSignalPending(); #if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT railDebugCounters.mRailEventEnergyScanCompleted++; #endif } + +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + processPendingCommands(); +#endif // OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE } //------------------------------------------------------------------------------ @@ -3484,7 +3485,7 @@ otError setRadioState(otRadioState state) switch (state) { case OT_RADIO_STATE_RECEIVE: - otEXPECT_ACTION(radioSetRx(sReceiveFrame.mChannel) == OT_ERROR_NONE, error = OT_ERROR_FAILED); + otEXPECT_ACTION(radioSetRx(sReceive.frame.mChannel) == OT_ERROR_NONE, error = OT_ERROR_FAILED); break; case OT_RADIO_STATE_SLEEP: radioSetIdle(); @@ -3609,8 +3610,17 @@ static void efr32CoexInit(void) { #if SL_OPENTHREAD_COEX_COUNTER_ENABLE && defined(SL_CATALOG_RAIL_MULTIPLEXER_PRESENT) sl_rail_mux_set_coex_counter_handler(gRailHandle, &sl_ot_coex_counter_on_event); +#else + sli_radio_coex_reset(); #endif // SL_OPENTHREAD_COEX_COUNTER_ENABLE && defined(SL_CATALOG_RAIL_MULTIPLEXER_PRESENT) +#if OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE +#if defined(SL_RAIL_UTIL_COEX_REQ_GPIO) || defined(SL_RAIL_UTIL_COEX_REQ_PORT) || defined(SL_RAIL_UTIL_COEX_GNT_GPIO) \ + || defined(SL_RAIL_UTIL_COEX_GNT_PORT) || SL_RAIL_UTIL_COEX_RUNTIME_PHY_SELECT + sl_rail_util_ot_enable_coex_state_event_filter(); +#endif +#endif // OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE + sl_rail_util_coex_options_t coexOptions = sl_rail_util_coex_get_options(); #if SL_OPENTHREAD_COEX_MAC_HOLDOFF_ENABLE @@ -3728,6 +3738,7 @@ void efr32RadioClearCoexCounters(void) } #endif // SL_OPENTHREAD_COEX_COUNTER_ENABLE + #endif // SL_CATALOG_RAIL_UTIL_COEX_PRESENT #if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT @@ -3735,5 +3746,4 @@ void efr32ClearRadioCounters(void) { memset(&railDebugCounters, 0, sizeof(railDebugCounters)); } - #endif // RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT diff --git a/src/src/radio_coex.c b/src/src/radio_coex.c new file mode 100644 index 00000000..14a2aacb --- /dev/null +++ b/src/src/radio_coex.c @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2024, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file implements the OpenThread platform abstraction for radio coex metrics + * collection. + * + */ + +#include +#include +#include + +#include "radio_coex.h" + +#if OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE + +static sl_ot_coex_counter_t sl_coex_counter; + +#define SL_INCREMENT_IF_NO_OVERFLOW(var, val, incr) \ + do \ + { \ + uint32_t temp = val + incr; \ + otEXPECT_ACTION(temp >= var, sl_coex_counter.metrics.mStopped = true); \ + var = temp; \ + } while (0) + +void sl_rail_util_coex_ot_events(sl_rail_util_coex_ot_event_t event) +{ + bool isTxEvent = (event & SL_RAIL_UTIL_COEX_OT_TX_REQUEST); + sl_rail_util_coex_ot_event_t coexEvent = + (event & ~(SL_RAIL_UTIL_COEX_OT_TX_REQUEST | SL_RAIL_UTIL_COEX_OT_RX_REQUEST)); + uint32_t *metrics = (isTxEvent) ? &sl_coex_counter.metrics.mNumTxRequest : &sl_coex_counter.metrics.mNumRxRequest; + uint64_t *totalReqToGrantDuration = + (isTxEvent) ? &sl_coex_counter.totalTxReqToGrantDuration : &sl_coex_counter.totalRxReqToGrantDuration; + + // uint32_t mNumGrantGlitch; ///< Not available. + + // mNumTxRequest = mNumTxGrantImmediate + mNumTxGrantWait + // mNumTxGrantWait = mNumTxGrantWaitActivated + mNumTxGrantWaitTimeout + // Same applies for Rx counters. + + /* Tx Events*/ + // uint32_t mNumTxRequest; ///< Number of Tx Requested = mNumTxGrantImmediate + + // mNumTxGrantWait. uint32_t mNumTxGrantImmediate; ///< Not Available. uint32_t mNumTxGrantWait; + // ///< Number of tx requests while grant was inactive. uint32_t mNumTxGrantWaitActivated; ///< Number + // of tx requests while grant was inactive that were ultimately granted. uint32_t mNumTxGrantWaitTimeout; ///< + // Number of tx requests while grant was inactive that timed out. uint32_t mNumTxGrantDeactivatedDuringRequest; ///< + // Number of tx that were in progress when grant was deactivated. uint32_t mNumTxDelayedGrant; ///< Number of tx + // requests that were not granted within 50us. uint32_t mAvgTxRequestToGrantTime; ///< Average time in + // usec from tx request to grant. + + /* Rx Events*/ + // uint32_t mNumRxRequest; ///< Number of rx requests. + // uint32_t mNumRxGrantImmediate; ///< Number of rx requests while grant was active. + // uint32_t mNumRxGrantWait; ///< Number of rx requests while grant was inactive. + // uint32_t mNumRxGrantWaitActivated; ///< Number of rx requests while grant was inactive that were + // ultimately granted. uint32_t mNumRxGrantWaitTimeout; ///< Number of rx requests while grant was + // inactive that timed out. uint32_t mNumRxGrantDeactivatedDuringRequest; ///< Number of rx that were in progress + // when grant was deactivated. uint32_t mNumRxDelayedGrant; ///< Number of rx requests that were + // not granted within 50us. uint32_t mAvgRxRequestToGrantTime; ///< Average time in usec from rx + // request to grant. + + // uint32_t mNumRxGrantNone; ///< Number of rx requests that completed without receiving + // grant. bool mStopped; + + otEXPECT(sl_coex_counter.metrics.mStopped == false); + + switch (coexEvent) + { + case SL_RAIL_UTIL_COEX_OT_EVENT_GRANTED_IMMEDIATE: + { + SL_INCREMENT_IF_NO_OVERFLOW(metrics[SL_OT_COEX_EVENT_GRANT_IMMEDIATE_COUNT], + metrics[SL_OT_COEX_EVENT_GRANT_IMMEDIATE_COUNT], + 1); + } + break; + + case SL_RAIL_UTIL_COEX_OT_EVENT_REQUESTED: + { + sl_coex_counter.timestamp = otPlatAlarmMicroGetNow(); + SL_INCREMENT_IF_NO_OVERFLOW(metrics[SL_OT_COEX_EVENT_REQUEST_COUNT], + metrics[SL_OT_COEX_EVENT_REQUEST_COUNT], + 1); + } + break; + + case SL_RAIL_UTIL_COEX_OT_EVENT_GRANTED: + { + uint32_t reqToGrantDuration = otPlatAlarmMicroGetNow() - sl_coex_counter.timestamp; + SL_INCREMENT_IF_NO_OVERFLOW(metrics[SL_OT_COEX_EVENT_GRANT_WAIT_ACTIVATED_COUNT], + metrics[SL_OT_COEX_EVENT_GRANT_WAIT_ACTIVATED_COUNT], + 1); + + if (reqToGrantDuration > 50) + { + SL_INCREMENT_IF_NO_OVERFLOW(metrics[SL_OT_COEX_EVENT_DELAYED_GRANT_COUNT], + metrics[SL_OT_COEX_EVENT_DELAYED_GRANT_COUNT], + 1); + } + + *totalReqToGrantDuration += reqToGrantDuration; + } + break; + + case SL_RAIL_UTIL_COEX_OT_EVENT_DENIED: + { + SL_INCREMENT_IF_NO_OVERFLOW(metrics[SL_OT_COEX_EVENT_GRANT_WAIT_TIMEOUT_COUNT], + metrics[SL_OT_COEX_EVENT_GRANT_WAIT_TIMEOUT_COUNT], + 1); + } + break; + + case SL_RAIL_UTIL_COEX_OT_EVENT_GRANT_ABORTED: + { + SL_INCREMENT_IF_NO_OVERFLOW(metrics[SL_OT_COEX_EVENT_GRANT_DEACTIVATED_DURING_REQUEST_COUNT], + metrics[SL_OT_COEX_EVENT_GRANT_DEACTIVATED_DURING_REQUEST_COUNT], + 1); + } + break; + + default: + break; + } + + SL_INCREMENT_IF_NO_OVERFLOW(metrics[SL_OT_COEX_EVENT_GRANT_WAIT_COUNT], + metrics[SL_OT_COEX_EVENT_GRANT_WAIT_TIMEOUT_COUNT], + metrics[SL_OT_COEX_EVENT_GRANT_WAIT_ACTIVATED_COUNT]); + metrics[SL_OT_COEX_EVENT_AVG_REQUEST_TO_GRANT_TIME] = + *totalReqToGrantDuration / metrics[SL_OT_COEX_EVENT_REQUEST_COUNT]; + +exit: + return; +} + +otError otPlatRadioGetCoexMetrics(otInstance *aInstance, otRadioCoexMetrics *aCoexMetrics) +{ + OT_UNUSED_VARIABLE(aInstance); + + otError error = OT_ERROR_NONE; + + otEXPECT_ACTION(aCoexMetrics != NULL, error = OT_ERROR_INVALID_ARGS); + + memcpy(aCoexMetrics, &sl_coex_counter.metrics, sizeof(otRadioCoexMetrics)); + +exit: + return error; +} + +void sli_radio_coex_reset(void) +{ + memset(&sl_coex_counter, 0, sizeof(sl_coex_counter)); +} + +#else + +otError otPlatRadioGetCoexMetrics(otInstance *aInstance, otRadioCoexMetrics *aCoexMetrics) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aCoexMetrics); + return OT_ERROR_NOT_IMPLEMENTED; +} +#endif // OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE diff --git a/src/src/radio_power_manager.c b/src/src/radio_power_manager.c new file mode 100644 index 00000000..6e607327 --- /dev/null +++ b/src/src/radio_power_manager.c @@ -0,0 +1,290 @@ +/* + * Copyright (c) 2024, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file implements the OpenThread platform abstraction for radio communication. + * + */ + +#include + +#include "pa_conversions_efr32.h" +#include "platform-band.h" +#include "platform-efr32.h" +#include "radio_multi_channel.h" +#include "radio_power_manager.h" +#include "rail_config.h" +#include "rail_ieee802154.h" +#include "sl_multipan.h" + +#ifdef SL_CATALOG_RAIL_MULTIPLEXER_PRESENT +#include "sl_rail_mux_rename.h" +#endif // SL_CATALOG_RAIL_MULTIPLEXER_PRESENT + +#ifdef SL_CATALOG_RAIL_UTIL_IEEE802154_FAST_CHANNEL_SWITCHING_PRESENT +#include "sl_rail_util_ieee802154_fast_channel_switching_config.h" +#endif // SL_CATALOG_RAIL_UTIL_IEEE802154_FAST_CHANNEL_SWITCHING_PRESENT + +#if !OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE + +static int8_t sli_max_channel_power[RADIO_INTERFACE_COUNT][SL_MAX_CHANNELS_SUPPORTED]; +static int8_t sli_default_tx_power[RADIO_INTERFACE_COUNT]; + +/** + * This function gets the lowest value for the max_tx_power for a channel, from the max_tx_powerTable set + * across all interfaces. It also gets the highest default_tx_power set across all interfaces. + * + * @param[out] default_tx_power A pointer to update the derived default_tx_power across all IIDs. + * @param[out] tx_power_from_table A pointer to update the Tx Power derived from the MaxChannelPowerTable. + * @param[in] channel Channel of interest + * + */ +static void sli_get_default_and_max_powers_across_iids(int8_t *default_tx_power, + int8_t *tx_power_from_table, + uint16_t channel) +{ + OT_ASSERT(tx_power_from_table != NULL); + OT_ASSERT(default_tx_power != NULL); + + for (uint8_t iid = 0U; iid < RADIO_INTERFACE_COUNT; iid++) + { + // Obtain the minimum Tx power set by different iids, for `channel` + // If there is an interface using lower Tx power than the one we have + // in tx_power_from_table.. + // Update tx_power_from_table. + *tx_power_from_table = SL_MIN(*tx_power_from_table, sli_max_channel_power[iid][channel - SL_CHANNEL_MIN]); + + // If the default Tx Power set is not invalid.. + if (sli_default_tx_power[iid] != SL_INVALID_TX_POWER) + { + // Obtain the Max value between local default_tx_power and sli_default_tx_power. + // If selected default Tx Power is Invalid, initialise it to sli_default_tx_power. + // We have already validated that sli_default_tx_power holds a valid value. + *default_tx_power = (*default_tx_power == SL_INVALID_TX_POWER) + ? sli_default_tx_power[iid] + : SL_MAX(*default_tx_power, sli_default_tx_power[iid]); + } + } +} + +/** + * This function returns the tx power to be used based on the default and max tx power table, for a given channel. + * + * @param[in] channel Channel of interest + * + * @returns The radio Tx Power for the given channel, in dBm. + * + */ + +static int8_t sli_get_max_tx_power_across_iids(uint16_t channel) +{ + int8_t max_channel_tx_power = SL_INVALID_TX_POWER; + int8_t max_default_tx_power = SL_INVALID_TX_POWER; + int8_t selected_tx_power = SL_INVALID_TX_POWER; + +#if SL_RAIL_UTIL_IEEE802154_FAST_CHANNEL_SWITCHING_ENABLED && OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + + if (sl_is_multi_channel_enabled()) + { + RAIL_IEEE802154_RxChannelSwitchingCfg_t channel_switching_cfg; + + // Get switching config + sl_get_channel_switching_cfg(&channel_switching_cfg); + + // Find the max_channel_tx_power, to be minimum of Max channel power for the + // channels infast channel config, accross all iids. This is because, if a iid_1 + // sets the max tx power of the channel to be less than the max tx power set by + // iid_2, we will need to work with the lower tx power to be compliant on both + // interfaces. + + // Find the max_default_tx_power, to be maximum of the default Tx power accross all + // the interfaces. + + for (uint8_t i = 0U; i < RAIL_IEEE802154_RX_CHANNEL_SWITCHING_NUM_CHANNELS; i++) + { + channel = channel_switching_cfg.channels[i]; + sli_get_default_and_max_powers_across_iids(&max_default_tx_power, &max_channel_tx_power, channel); + } + } + else +#endif + { + sli_get_default_and_max_powers_across_iids(&max_default_tx_power, &max_channel_tx_power, channel); + } + + // Return the minimum of max_channel_tx_power and max_default_tx_power. + selected_tx_power = SL_MIN(max_channel_tx_power, max_default_tx_power); + return (selected_tx_power == SL_INVALID_TX_POWER) ? OPENTHREAD_CONFIG_DEFAULT_TRANSMIT_POWER : selected_tx_power; +} + +#endif //! OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE + +void sli_set_tx_power_in_rail(int8_t power_in_dbm) +{ + RAIL_Status_t status; + + // RAIL_SetTxPowerDbm() takes power in units of deci-dBm (0.1dBm) + // Multiply by 10 because power_in_dbm is supposed be in units dBm + status = RAIL_SetTxPowerDbm(gRailHandle, ((RAIL_TxPower_t)power_in_dbm) * 10); + + OT_ASSERT(status == RAIL_STATUS_NO_ERROR); +} + +void sli_init_power_manager(void) +{ +#if !OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE + memset(sli_max_channel_power, SL_INVALID_TX_POWER, sizeof(sli_max_channel_power)); + memset(sli_default_tx_power, SL_INVALID_TX_POWER, sizeof(sli_default_tx_power)); +#endif //! OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE +} + +void sli_update_tx_power_after_config_update(const RAIL_TxPowerConfig_t *tx_pwr_config, int8_t tx_power) +{ + RAIL_Status_t status; + RAIL_TxPowerLevel_t tx_power_lvl; + RAIL_TxPower_t tx_power_dbm = tx_power * 10; + + tx_power_lvl = RAIL_GetTxPower(gRailHandle); + + // Always need to call RAIL_SetTxPowerDbm after RAIL_ConfigTxPower + // First need to get existing power setting and reassert value after config + + if (tx_power_lvl != RAIL_TX_POWER_LEVEL_INVALID) + { + tx_power_dbm = RAIL_GetTxPowerDbm(gRailHandle); + } + + status = RAIL_ConfigTxPower(gRailHandle, tx_pwr_config); + OT_ASSERT(status == RAIL_STATUS_NO_ERROR); + + status = RAIL_SetTxPowerDbm(gRailHandle, tx_power_dbm); + OT_ASSERT(status == RAIL_STATUS_NO_ERROR); +} + +otError sli_set_channel_max_tx_power(otInstance *instance, uint8_t channel, int8_t max_power) +{ + otError error = OT_ERROR_NONE; + +#if !OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE + int8_t tx_power; + uint8_t iid = efr32GetIidFromInstance(instance); + + otEXPECT_ACTION(channel >= SL_CHANNEL_MIN && channel <= SL_CHANNEL_MAX, error = OT_ERROR_INVALID_ARGS); + + sli_max_channel_power[iid][channel - SL_CHANNEL_MIN] = max_power; + tx_power = sl_get_tx_power_for_current_channel(instance); + sli_set_tx_power_in_rail(tx_power); + +exit: +#else + OT_UNUSED_VARIABLE(instance); + OT_UNUSED_VARIABLE(channel); + OT_UNUSED_VARIABLE(max_power); + error = OT_ERROR_NOT_IMPLEMENTED; +#endif + return error; +} + +otError sli_set_default_tx_power(otInstance *instance, int8_t tx_power) +{ + otError error = OT_ERROR_NONE; + +#if !OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE + int8_t max_tx_power; + uint8_t iid = efr32GetIidFromInstance(instance); + + sli_default_tx_power[iid] = tx_power; + max_tx_power = sl_get_tx_power_for_current_channel(instance); + + sli_set_tx_power_in_rail(max_tx_power); +#else + OT_UNUSED_VARIABLE(instance); + OT_UNUSED_VARIABLE(tx_power); + error = OT_ERROR_NOT_IMPLEMENTED; +#endif + + return error; +} + +int8_t sl_get_tx_power_for_current_channel(otInstance *instance) +{ + int8_t tx_power; + uint16_t channel; + + RAIL_GetChannel(gRailHandle, &channel); + +#if OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE + uint8_t raw_power_calibration[SL_OPENTHREAD_RAW_POWER_CALIBRATION_LENGTH]; + uint8_t fem_setting[SL_OPENTHREAD_FEM_SETTING_LENGTH]; + uint16_t raw_calibration_length = SL_OPENTHREAD_RAW_POWER_CALIBRATION_LENGTH; + uint16_t fem_setting_length = SL_OPENTHREAD_FEM_SETTING_LENGTH; + otError error; + + error = otPlatRadioGetRawPowerSetting(instance, channel, raw_power_calibration, &raw_calibration_length); + + error = sl_parse_raw_power_calibration_cb(raw_power_calibration, + raw_calibration_length, + &tx_power, + fem_setting, + &fem_setting_length); + OT_ASSERT(error == OT_ERROR_NONE); + + sl_configure_fem_cb(fem_setting, fem_setting_length); + +#else + OT_UNUSED_VARIABLE(instance); + tx_power = sli_get_max_tx_power_across_iids(channel); +#endif + + return tx_power; +} + +#if OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE +SL_WEAK otError sl_parse_raw_power_calibration_cb(uint8_t *raw_power_calibration, + uint16_t raw_setting_length, + int8_t *radio_power, + uint8_t *fem_setting, + uint16_t *fem_setting_length) +{ + OT_ASSERT(raw_power_calibration != NULL); + OT_ASSERT(radio_power != NULL); + OT_UNUSED_VARIABLE(raw_setting_length); + OT_UNUSED_VARIABLE(fem_setting); + OT_UNUSED_VARIABLE(fem_setting_length); + + *radio_power = raw_power_calibration[0]; + return OT_ERROR_NONE; +} + +SL_WEAK void sl_configure_fem_cb(uint8_t *fem_setting, uint16_t fem_setting_length) +{ + OT_UNUSED_VARIABLE(fem_setting); + OT_UNUSED_VARIABLE(fem_setting_length); +} +#endif // OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE diff --git a/src/src/sl_gp_interface.c b/src/src/sl_gp_interface.c new file mode 100644 index 00000000..911cb01e --- /dev/null +++ b/src/src/sl_gp_interface.c @@ -0,0 +1,335 @@ +/* + * Copyright (c) 2024, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/******************************************************************************* + * @file + * @brief This file implements Green Power interface. + ******************************************************************************/ + +#include "sl_gp_interface.h" +#include "ieee802154mac.h" +#include "rail_ieee802154.h" +#include "sl_gp_interface_config.h" +#include "sl_packet_utils.h" +#include "sl_status.h" +#include +#include +#include +#include +#include "common/debug.hpp" +#include "common/logging.hpp" +#include "utils/code_utils.h" +#include "utils/mac_frame.h" + +// This implements mechanism to buffer outgoing Channel Configuration (0xF3) and +// Commissioning Reply (0xF0) GPDF commands on the RCP to sent out on request +// from GPD with bidirectional capability with in a certain time window, i.e. +// between 20 and 25 msec. +// The mechanism works following way - +// The zigbeed submits the outgoing GPDF command, this code on rcp intercepts the +// packet from transmit API and buffers the packet, does not send it out. +// The GPD sends request indicating its RX capability, this again intercept the +// rx message and based on the request, it sends out the above buffered message +// with in a time window of 20-25 msec from the time it received the message. + +#define GP_MIN_MAINTENANCE_FRAME_LENGTH 10 +#define GP_MIN_DATA_FRAME_LENGTH 14 + +#define GP_ADDRESSING_MODE_SRC_ID 0 +#define GP_ADDRESSING_MODE_EUI64 2 + +// Check the GP Frame Type field to ensure it is either a maintenance frame (1) or a data frame (0). +#define GP_NWK_PROTOCOL_VERSION_CHECK(nwkFc) ((((nwkFc >> 2) & 0x0F) == 3) && ((nwkFc & 0x3) <= 1)) +#define GP_NWK_FRAME_TYPE_MAINTENANCE_WITHOUT_EXTD_FC(nwkFc) ((nwkFc & 0xC3) == 0x01) +#define GP_NWK_FRAME_TYPE_DATA_WITH_EXTD_FC(nwkFc) ((nwkFc & 0xC3) == 0x80) + +#define GP_NWK_UNSECURED_RX_DATA_FRAME(nwkExntdFc) ((nwkExntdFc & 0xF8) == 0x40) +#define GP_NWK_UNSECURED_TX_DATA_FRAME(nwkExntdFc) ((nwkExntdFc & 0xF8) == 0x80) +#define GP_NWK_ADDRESSING_APP_ID(nwkExntdFc) ((nwkExntdFc & 0x07)) + +#define GP_CHANNEL_REQUEST_CMD_ID 0xE3 +#define GP_CHANNEL_CONFIGURATION_CMD_ID 0xF3 +#define GP_COMMISSIONINGING_CMD_ID 0xE0 +#define GP_COMMISSIONING_REPLY_CMD_ID 0xF0 + +#define GP_EXND_FC_INDEX 1 +#define GP_COMMAND_INDEX_FOR_MAINT_FRAME 1 +#define GP_SRC_ID_INDEX_WITH_APP_MODE_0 2 +#define GP_APP_EP_INDEX_WITH_APP_MODE_1 2 +#define GP_COMMAND_INDEX_WITH_APP_MODE_1 3 +#define GP_COMMAND_INDEX_WITH_APP_MODE_0 6 + +#define BUFFERED_PSDU_GP_SRC_ID_INDEX_WITH_APP_MODE_0 9 +#define BUFFERED_PSDU_GP_APP_EP_INDEX_WITH_APP_MODE_1 9 + +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE +static volatile sl_gp_state_t gp_state = SL_GP_STATE_INIT; +static volatile uint64_t gpStateTimeOut; + +// Needed to retrieve buffered transmit frame present in global memory. +static otInstance *sBufferedTxInstance = NULL; + +sl_gp_state_t sl_gp_intf_get_state(void) +{ + return gp_state; +} + +void efr32GpProcess(void) +{ + switch (gp_state) + { + case SL_GP_STATE_INIT: + { + gp_state = SL_GP_STATE_IDLE; + otLogDebgPlat("GP RCP INTF: GP Frame init!!"); + } + break; + case SL_GP_STATE_SEND_RESPONSE: + { + if (otPlatTimeGet() >= gpStateTimeOut) + { + OT_ASSERT(sBufferedTxInstance != NULL); + // Get the tx frame and send it without csma. + otRadioFrame *aTxFrame = otPlatRadioGetTransmitBuffer(sBufferedTxInstance); + aTxFrame->mInfo.mTxInfo.mCsmaCaEnabled = false; + aTxFrame->mInfo.mTxInfo.mMaxCsmaBackoffs = 0; + // On successful transmit, this will call the transmit complete callback for the GP packet, + // and go up to the CGP Send Handler and eventually the green power client. + otPlatRadioTransmit(sBufferedTxInstance, aTxFrame); + + gp_state = SL_GP_STATE_IDLE; + sBufferedTxInstance = NULL; + otLogDebgPlat("GP RCP INTF: Sending Response!!"); + } + } + break; + case SL_GP_STATE_WAITING_FOR_PKT: + { + if (otPlatTimeGet() >= gpStateTimeOut) + { + OT_ASSERT(sBufferedTxInstance != NULL); + // This is a timeout call for the case when the GPD did not poll the response with in 5 seconds. + otPlatRadioTxDone(sBufferedTxInstance, + otPlatRadioGetTransmitBuffer(sBufferedTxInstance), + NULL, + OT_ERROR_ABORT); + gp_state = SL_GP_STATE_IDLE; + sBufferedTxInstance = NULL; + } + } + break; + default: + { + // For all other states don't do anything + } + break; + } +} + +void sl_gp_intf_buffer_pkt(otInstance *aInstance) +{ + gpStateTimeOut = otPlatTimeGet() + GP_TX_MAX_TIMEOUT_IN_MICRO_SECONDS; + gp_state = SL_GP_STATE_WAITING_FOR_PKT; + OT_ASSERT(aInstance != NULL); + sBufferedTxInstance = aInstance; + otLogDebgPlat("GP RCP INTF: buffered!!"); +} + +bool sl_gp_intf_should_buffer_pkt(otInstance *aInstance, otRadioFrame *aFrame, bool isRxFrame) +{ + bool shouldBufferPacket = false; + +#if OPENTHREAD_CONFIG_DIAG_ENABLE + // Exit immediately if diag mode is enabled. + otEXPECT_ACTION(!otPlatDiagModeGet(), shouldBufferPacket = false); +#endif + + uint8_t *gpFrameStartIndex = efr32GetPayload(aFrame); + otEXPECT_ACTION(gpFrameStartIndex != NULL, shouldBufferPacket = false); + + // A Typical MAC Frame with GP NWK Frame in it + /* clang-format off */ + // MAC Frame : [<---------------MAC Header------------->||<------------------------------------NWK Frame----------------------------------->] + // FC(2) | Seq(1) | DstPan(2) | DstAddr(2) || FC(1) | ExtFC(0/1) | SrcId(0/4) | SecFc(0/4) | MIC(0/4) | <------GPDF(1/n)------> + // The Green Power NWK FC and Ext FC are described as : + // FC : ExtFC Present(b7)=1| AC(b6)=0| Protocol Ver(b5-b2)=3 GP frames| Frame Type(b1-b0) = 0 + // ExtFC : rxAfteTX (b6) = 1 | AppId(b2-b0) = 0 + /* clang-format on */ + + uint8_t fc = *gpFrameStartIndex; + + otEXPECT_ACTION(gp_state == SL_GP_STATE_WAITING_FOR_PKT, shouldBufferPacket = false); + + otLogDebgPlat("GP RCP INTF : (%s) PL Index = %d Channel = %d Length = %d FC = %0X", + isRxFrame ? "Rx" : "Tx", + (gpFrameStartIndex - aFrame->mPsdu), + aFrame->mChannel, + aFrame->mLength, + fc); + + // Check if packet is a GP packet + otEXPECT_ACTION(sl_gp_intf_is_gp_pkt(aFrame), shouldBufferPacket = false); + + otLogDebgPlat("GP RCP INTF : (%s) Length and Version Matched", isRxFrame ? "Rx" : "Tx"); + // For GP Maintenance Frame type without extended FC, the FC is exactly same for both RX and TX directions with + // auto commissioning bit = 0, does not have a ExtFC field, only the command Id (which is the next byte in + // frame) indicates the direction. + if (GP_NWK_FRAME_TYPE_MAINTENANCE_WITHOUT_EXTD_FC(fc)) + { + otLogDebgPlat("GP RCP INTF : (%s) Maintenance Frame match", isRxFrame ? "Rx" : "Tx"); + uint8_t cmdId = *(gpFrameStartIndex + GP_COMMAND_INDEX_FOR_MAINT_FRAME); + if (cmdId == GP_CHANNEL_REQUEST_CMD_ID && isRxFrame) + { + // Send out the buffered frame + shouldBufferPacket = true; + gp_state = SL_GP_STATE_SEND_RESPONSE; + gpStateTimeOut = aFrame->mInfo.mRxInfo.mTimestamp + GP_RX_OFFSET_IN_MICRO_SECONDS; + otLogDebgPlat("GP RCP INTF : (%s) Received GP_CHANNEL_REQUEST_CMD_ID - Send the Channel configuration", + isRxFrame ? "Rx" : "Tx"); + } + else if (cmdId == GP_CHANNEL_CONFIGURATION_CMD_ID && !isRxFrame) + { + // Buffer the frame + shouldBufferPacket = true; + otLogDebgPlat("GP RCP INTF : (%s) Buffer GP_CHANNEL_CONFIGURATION_CMD_ID command", isRxFrame ? "Rx" : "Tx"); + } + } + else if ( + // Data frame with EXT FC present, extract the App Id, SrcId, direction and command Id + GP_NWK_FRAME_TYPE_DATA_WITH_EXTD_FC(fc) && + // Minimum Data frame length with extended header and address + aFrame->mLength >= GP_MIN_DATA_FRAME_LENGTH) + { + uint8_t extFc = *(gpFrameStartIndex + GP_EXND_FC_INDEX); + + // Process only unsecured commissioning frames for Tx/Rx with correct direction and RxAfterTx fields + if ((!isRxFrame && GP_NWK_UNSECURED_TX_DATA_FRAME(extFc)) + || (isRxFrame && GP_NWK_UNSECURED_RX_DATA_FRAME(extFc))) + { + if (GP_NWK_ADDRESSING_APP_ID(extFc) == GP_ADDRESSING_MODE_SRC_ID) + { + uint8_t cmdId = *(gpFrameStartIndex + GP_COMMAND_INDEX_WITH_APP_MODE_0); + if (cmdId == GP_COMMISSIONING_REPLY_CMD_ID && !isRxFrame) + { + // Buffer the frame + shouldBufferPacket = true; + } + else if (cmdId == GP_COMMISSIONINGING_CMD_ID && isRxFrame) + { + otRadioFrame *aTxFrame = otPlatRadioGetTransmitBuffer(aInstance); + // Match the gpd src Id ? + if (!memcmp((const void *)(gpFrameStartIndex + GP_SRC_ID_INDEX_WITH_APP_MODE_0), + (const void *)((aTxFrame->mPsdu) + BUFFERED_PSDU_GP_SRC_ID_INDEX_WITH_APP_MODE_0), + sizeof(uint32_t))) + { + // Send out the buffered frame + gp_state = SL_GP_STATE_SEND_RESPONSE; + gpStateTimeOut = aFrame->mInfo.mRxInfo.mTimestamp + GP_RX_OFFSET_IN_MICRO_SECONDS; + } + } + } + else if (GP_NWK_ADDRESSING_APP_ID(extFc) == GP_ADDRESSING_MODE_EUI64) + { + uint8_t cmdId = *(gpFrameStartIndex + GP_COMMAND_INDEX_WITH_APP_MODE_1); + if (cmdId == GP_COMMISSIONING_REPLY_CMD_ID && !isRxFrame) + { + // Buffer the frame + shouldBufferPacket = true; + } + else if (cmdId == GP_COMMISSIONINGING_CMD_ID && isRxFrame) + { + otRadioFrame *aTxFrame = otPlatRadioGetTransmitBuffer(aInstance); + // Check the eui64 and app endpoint to send out the buffer packet. + otMacAddress aSrcAddress; + otMacAddress aDstAddress; + otMacFrameGetDstAddr(aTxFrame, &aDstAddress); + otMacFrameGetSrcAddr(aFrame, &aSrcAddress); + if (!memcmp(&(aDstAddress.mAddress.mExtAddress), + &(aSrcAddress.mAddress.mExtAddress), + sizeof(otExtAddress)) + && (gpFrameStartIndex[GP_APP_EP_INDEX_WITH_APP_MODE_1] + == (aTxFrame->mPsdu)[BUFFERED_PSDU_GP_APP_EP_INDEX_WITH_APP_MODE_1])) + { + shouldBufferPacket = true; + gp_state = SL_GP_STATE_SEND_RESPONSE; + gpStateTimeOut = aFrame->mInfo.mRxInfo.mTimestamp + GP_RX_OFFSET_IN_MICRO_SECONDS; + } + } + } + } + } + + if (shouldBufferPacket) + { + otLogDebgPlat("GP RCP INTF: GP filter passed!!"); + } + +exit: + return shouldBufferPacket; +} +#endif // OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + +bool sl_gp_intf_is_gp_pkt(otRadioFrame *aFrame) +{ + /* clang-format off */ + + // A Typical MAC Frame with GP NWK Frame in it + // MAC Frame : [<---------------MAC Header------------->||<------------------------------------NWK Frame----------------------------------->] + // FC(2) | Seq(1) | DstPan(2) | DstAddr(2) || FC(1) | ExtFC(0/1) | SrcId(0/4) | SecFc(0/4) | MIC(0/4) | <------GPDF(1/n)------> + + /* clang-format on */ + + bool isGpPkt = false; + uint8_t *gpFrameStartIndex = efr32GetPayload(aFrame); + otEXPECT_ACTION(gpFrameStartIndex != NULL, isGpPkt = false); + uint8_t fc = *gpFrameStartIndex; + + // Criteria: + // - The basic Identification of a GPDF Frame : The minimum GPDF length need to be 10 in this case for any + // direction + // - Network layer FC containing the Protocol Version field as 3. + // - The frame version should be 2003. + + bool lengthCheck = (aFrame->mLength >= GP_MIN_MAINTENANCE_FRAME_LENGTH); + bool networkVersionCheck = GP_NWK_PROTOCOL_VERSION_CHECK(fc); + bool frameVersionCheck = (efr32GetFrameVersion(aFrame) == IEEE802154_FRAME_VERSION_2003); + + isGpPkt = (lengthCheck && networkVersionCheck && frameVersionCheck); +#if 0 // Debugging + if (!isGpPkt) + { + otLogCritPlat("GP RCP INTF checks: Length = %d, NWK Version = %d, PanId Compression = %d, Frame Version = %d", + lengthCheck, + networkVersionCheck, + panIdCompressionCheck, + frameVersionCheck); + } +#endif +exit: + return isGpPkt; +} diff --git a/src/src/sl_rcp_gp_interface.h b/src/src/sl_gp_interface.h similarity index 80% rename from src/src/sl_rcp_gp_interface.h rename to src/src/sl_gp_interface.h index 6f609f4c..5a21e67d 100644 --- a/src/src/sl_rcp_gp_interface.h +++ b/src/src/sl_gp_interface.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, The OpenThread Authors. + * Copyright (c) 2024, The OpenThread Authors. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,8 +31,8 @@ * @brief This file implements Green Power interface. ******************************************************************************/ -#ifndef SL_RCP_GP_INTERFACE_H_ -#define SL_RCP_GP_INTERFACE_H_ +#ifndef SL_GP_INTERFACE_H_ +#define SL_GP_INTERFACE_H_ #include #include @@ -48,34 +48,46 @@ typedef enum } sl_gp_state_t; /** - * This function returns if the given frame is a GP frame. + * This function returns current state of GP state machine. * - * @param[in] aFrame A pointer to the MAC frame buffer. - * @param[in] isRxFrame If the give frame is a incoming or outgoing frame. + * @retval Status of GP state machine. + */ +sl_gp_state_t sl_gp_intf_get_state(void); + +/** + * This function performs GP RCP processing. * - * @retval true Frame is a GP packet. - * @retval false Frame is not a GP packet. */ -bool sl_gp_intf_is_gp_pkt(otRadioFrame *aFrame, bool isRxFrame); +void efr32GpProcess(void); /** * This function stores the provided packet in global memory, to be sent as * a response for specific incoming packet. * - * @param[in] aFrame A pointer to the MAC frame buffer. + * @param[in] aInstance A pointer to the OpenThread instance structure. */ -void sl_gp_intf_buffer_pkt(otRadioFrame *aFrame); +void sl_gp_intf_buffer_pkt(otInstance *aInstance); /** - * This function returns current state of GP state machine. + * This function returns if the given frame is a GP frame and should be buffered + * + * @param[in] aInstance A pointer to the OpenThread instance structure. + * @param[in] aFrame A pointer to the MAC frame buffer. + * @param[in] isRxFrame If the give frame is a incoming or outgoing frame. * - * @retval true Status of GP state machine. + * @retval true Frame should be buffered + * @retval false Frame should not be buffered */ -sl_gp_state_t sl_gp_intf_get_state(void); +bool sl_gp_intf_should_buffer_pkt(otInstance *aInstance, otRadioFrame *aFrame, bool isRxFrame); /** - * This function performs GP RCP processing. + * This function returns if the given frame is a GP frame. * + * @param[in] aFrame A pointer to the MAC frame buffer. + * + * @retval true Frame is a GP packet. + * @retval false Frame is not a GP packet. */ -void efr32GpProcess(void); +bool sl_gp_intf_is_gp_pkt(otRadioFrame *aFrame); + #endif diff --git a/src/src/sl_multipan.h b/src/src/sl_multipan.h new file mode 100644 index 00000000..2142b466 --- /dev/null +++ b/src/src/sl_multipan.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2024, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * @brief + * Helper functions for Silicon Labs Multipan implementation. + */ + +#ifndef SL_MULTIPAN_H_ +#define SL_MULTIPAN_H_ + +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE +#include +#endif +#include "utils/code_utils.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE +#define RADIO_INTERFACE_COUNT (OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_NUM + 1) +#else +#define RADIO_INTERFACE_COUNT 1 +#endif + +#define INVALID_INTERFACE_INDEX (0xFF) + +/* + * RAIL accepts 3 pan indices 0, 1 or 2. But valid IIDs are 1, 2 and 3 (0 is reserved for bcast). + * This API validates the passed IID and converts it into usable PanIndex. + */ + +static inline uint8_t efr32GetPanIndexFromIid(uint8_t iid) +{ + uint8_t panIndex = 0; + +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + otEXPECT_ACTION(((iid < RADIO_INTERFACE_COUNT) && (iid != 0)), panIndex = INVALID_INTERFACE_INDEX); + panIndex = iid - 1; +exit: +#else + panIndex = iid; +#endif + + return panIndex; +} + +static inline uint8_t efr32GetIidFromInstance(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + return otPlatMultipanInstanceToIid(aInstance); +#else + return 0; +#endif +} + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // SL_MULTIPAN_H_ diff --git a/src/src/sl_openthread.h b/src/src/sl_openthread.h index c0010a00..e9d68881 100644 --- a/src/src/sl_openthread.h +++ b/src/src/sl_openthread.h @@ -1,6 +1,6 @@ /******************************************************************************* * @brief This file enables support for all Silabs specific features available - * only through the GSDK + * only through the SiSDK ******************************************************************************* * # License * Copyright 2023 Silicon Laboratories Inc. www.silabs.com diff --git a/src/src/sl_packet_utils.h b/src/src/sl_packet_utils.h index 661339cc..eea28697 100644 --- a/src/src/sl_packet_utils.h +++ b/src/src/sl_packet_utils.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, The OpenThread Authors. + * Copyright (c) 2024, The OpenThread Authors. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -80,6 +80,24 @@ otPanId efr32GetDstPanId(otRadioFrame *aFrame); */ uint8_t *efr32GetPayload(otRadioFrame *aFrame); +/** + * This function checks if the PAN ID Compression bit is set in the given MAC frame. + * + * @param[in] aFrame A pointer to the MAC frame buffer. + * + * @return true if the PAN ID Compression bit is set, false otherwise. + */ +bool efr32FrameIsPanIdCompressed(otRadioFrame *aFrame); + +/** + * This function returns the frame version. + * + * @param[in] aFrame A pointer to the MAC frame buffer. + * + * @retval Frame version. + */ +uint16_t efr32GetFrameVersion(otRadioFrame *aFrame); + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/src/sl_rcp_gp_interface.c b/src/src/sl_rcp_gp_interface.c deleted file mode 100644 index 1d8a51f6..00000000 --- a/src/src/sl_rcp_gp_interface.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright (c) 2023, The OpenThread Authors. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holder nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/******************************************************************************* - * @file - * @brief This file implements Green Power interface. - ******************************************************************************/ - -#include "sl_rcp_gp_interface.h" -#include "ieee802154mac.h" -#include "rail_ieee802154.h" -#include "sl_packet_utils.h" -#include "sl_rcp_gp_interface_config.h" -#include "sl_status.h" -#include -#include -#include -#include "common/logging.hpp" -#include "utils/code_utils.h" -#include "utils/mac_frame.h" - -// This implements mechanism to buffer outgoing Channel Configuration (0xF3) and -// Commissioning Reply (0xF0) GPDF commands on the RCP to sent out on request -// from GPD with bidirectional capability with in a certain time window, i.e. -// between 20 and 25 msec. -// The mechanism works following way - -// The zigbeed submits the outgoing GPDF command, this code on rcp intercepts the -// packet from transmit API and buffers the packet, does not send it out. -// The GPD sends request indicating its RX capability, this again intercept the -// rx message and based on the request, it sends out the above buffered message -// with in a time window of 20-25 msec from the time it received the message. - -#define GP_MIN_MAINTENANCE_FRAME_LENGTH 10 -#define GP_MIN_DATA_FRAME_LENGTH 14 - -#define GP_ADDRESSING_MODE_SRC_ID 0 -#define GP_ADDRESSING_MODE_EUI64 2 - -#define GP_NWK_PROTOCOL_VERSION_CHECK(nwkFc) (((nwkFc >> 2) & 0x0F) == 3) -#define GP_NWK_FRAME_TYPE_MAINTENANCE_WITHOUT_EXTD_FC(nwkFc) ((nwkFc & 0xC3) == 0x01) -#define GP_NWK_FRAME_TYPE_DATA_WITH_EXTD_FC(nwkFc) ((nwkFc & 0xC3) == 0x80) - -#define GP_NWK_UNSECURED_RX_DATA_FRAME(nwkExntdFc) ((nwkExntdFc & 0xF8) == 0x40) -#define GP_NWK_UNSECURED_TX_DATA_FRAME(nwkExntdFc) ((nwkExntdFc & 0xF8) == 0x80) -#define GP_NWK_ADDRESSING_APP_ID(nwkExntdFc) ((nwkExntdFc & 0x07)) - -#define GP_CHANNEL_REQUEST_CMD_ID 0xE3 -#define GP_CHANNEL_CONFIGURATION_CMD_ID 0xF3 -#define GP_COMMISSIONINGING_CMD_ID 0xE0 -#define GP_COMMISSIONING_REPLY_CMD_ID 0xF0 - -#define GP_EXND_FC_INDEX 1 -#define GP_COMMAND_INDEX_FOR_MAINT_FRAME 1 -#define GP_SRC_ID_INDEX_WITH_APP_MODE_0 2 -#define GP_APP_EP_INDEX_WITH_APP_MODE_1 2 -#define GP_COMMAND_INDEX_WITH_APP_MODE_1 3 -#define GP_COMMAND_INDEX_WITH_APP_MODE_0 6 - -#define BUFFERED_PSDU_GP_SRC_ID_INDEX_WITH_APP_MODE_0 9 -#define BUFFERED_PSDU_GP_APP_EP_INDEX_WITH_APP_MODE_1 9 - -static volatile sl_gp_state_t gp_state = SL_GP_STATE_INIT; -static volatile uint64_t gpStateTimeOut; - -sl_gp_state_t sl_gp_intf_get_state(void) -{ - return gp_state; -} - -void efr32GpProcess(void) -{ - switch (gp_state) - { - case SL_GP_STATE_INIT: - { - gp_state = SL_GP_STATE_IDLE; - otLogDebgPlat("GP RCP INTF: GP Frame init!!"); - } - break; - case SL_GP_STATE_SEND_RESPONSE: - { - if (otPlatTimeGet() >= gpStateTimeOut) - { - // Get the tx frame and send it without csma. - otRadioFrame *aTxFrame = otPlatRadioGetTransmitBuffer(NULL); - aTxFrame->mInfo.mTxInfo.mCsmaCaEnabled = false; - aTxFrame->mInfo.mTxInfo.mMaxCsmaBackoffs = 0; - // On successful transmit, this will call the transmit complete callback for the GP packet, - // and go up to the CGP Send Handler and eventually the green power client. - otPlatRadioTransmit(NULL, aTxFrame); - - gp_state = SL_GP_STATE_IDLE; - otLogDebgPlat("GP RCP INTF: Sending Response!!"); - } - } - break; - case SL_GP_STATE_WAITING_FOR_PKT: - { - if (otPlatTimeGet() >= gpStateTimeOut) - { - // This is a timeout call for the case when the GPD did not poll the response with in 5 seconds. - otPlatRadioTxDone(NULL, otPlatRadioGetTransmitBuffer(NULL), NULL, OT_ERROR_ABORT); - gp_state = SL_GP_STATE_IDLE; - } - } - break; - default: - { - // For all other states don't do anything - } - break; - } -} - -void sl_gp_intf_buffer_pkt(otRadioFrame *aFrame) -{ - OT_UNUSED_VARIABLE(aFrame); - gpStateTimeOut = otPlatTimeGet() + GP_TX_MAX_TIMEOUT_IN_MICRO_SECONDS; - gp_state = SL_GP_STATE_WAITING_FOR_PKT; - otLogDebgPlat("GP RCP INTF: buffered!!"); -} - -bool sl_gp_intf_is_gp_pkt(otRadioFrame *aFrame, bool isRxFrame) -{ - bool isGpPkt = false; - uint8_t *gpFrameStartIndex = efr32GetPayload(aFrame); - - // A Typical MAC Frame with GP NWK Frame in it - /* clang-format off */ - // MAC Frame : [<---------------MAC Header------------->||<------------------------------------NWK Frame----------------------------------->] - // FC(2) | Seq(1) | DstPan(2) | DstAddr(2) || FC(1) | ExtFC(0/1) | SrcId(0/4) | SecFc(0/4) | MIC(0/4) | <------GPDF(1/n)------> - // The Green Power NWK FC and Ext FC are described as : - // FC : ExtFC Present(b7)=1| AC(b6)=0| Protocol Ver(b5-b2)=3 GP frames| Frame Type(b1-b0) = 0 - // ExtFC : rxAfteTX (b6) = 1 | AppId(b2-b0) = 0 - /* clang-format on */ - - uint8_t fc = *gpFrameStartIndex; - - otEXPECT_ACTION(gp_state == SL_GP_STATE_WAITING_FOR_PKT, isGpPkt = false); - - otLogDebgPlat("GP RCP INTF : (%s) PL Index = %d Channel = %d Length = %d FC = %0X", - isRxFrame ? "Rx" : "Tx", - (gpFrameStartIndex - aFrame->mPsdu), - aFrame->mChannel, - aFrame->mLength, - fc); - - // The basic Identification of a GPDF Frame : The minimum GPDF length need to be 10 in this case for any direction - // with network layer FC containing the Protocol Version field as 3. - if (aFrame->mLength >= GP_MIN_MAINTENANCE_FRAME_LENGTH && GP_NWK_PROTOCOL_VERSION_CHECK(fc)) - { - otLogDebgPlat("GP RCP INTF : (%s) Length and Version Matched", isRxFrame ? "Rx" : "Tx"); - // For GP Maintenance Frame type without extended FC, the FC is exactly same for both RX and TX directions with - // auto commissioning bit = 0, does not have a ExtFC field, only the command Id (which is the next byte in - // frame) indicates the direction. - if (GP_NWK_FRAME_TYPE_MAINTENANCE_WITHOUT_EXTD_FC(fc)) - { - otLogDebgPlat("GP RCP INTF : (%s) Maintenance Frame match", isRxFrame ? "Rx" : "Tx"); - uint8_t cmdId = *(gpFrameStartIndex + GP_COMMAND_INDEX_FOR_MAINT_FRAME); - if (cmdId == GP_CHANNEL_REQUEST_CMD_ID && isRxFrame) - { - // Send out the buffered frame - isGpPkt = true; - gp_state = SL_GP_STATE_SEND_RESPONSE; - gpStateTimeOut = aFrame->mInfo.mRxInfo.mTimestamp + GP_RX_OFFSET_IN_MICRO_SECONDS; - otLogDebgPlat("GP RCP INTF : (%s) Received GP_CHANNEL_REQUEST_CMD_ID - Send the Channel configuration", - isRxFrame ? "Rx" : "Tx"); - } - else if (cmdId == GP_CHANNEL_CONFIGURATION_CMD_ID && !isRxFrame) - { - // Buffer the frame - isGpPkt = true; - otLogDebgPlat("GP RCP INTF : (%s) Buffer GP_CHANNEL_CONFIGURATION_CMD_ID command", - isRxFrame ? "Rx" : "Tx"); - } - } - else if ( - // Data frame with EXT FC present, extract the App Id, SrcId, direction and command Id - GP_NWK_FRAME_TYPE_DATA_WITH_EXTD_FC(fc) && - // Minimum Data frame length with extended header and address - aFrame->mLength >= GP_MIN_DATA_FRAME_LENGTH) - { - uint8_t extFc = *(gpFrameStartIndex + GP_EXND_FC_INDEX); - - // Process only unsecured commissioning frames for Tx/Rx with correct direction and RxAfterTx fields - if ((!isRxFrame && GP_NWK_UNSECURED_TX_DATA_FRAME(extFc)) - || (isRxFrame && GP_NWK_UNSECURED_RX_DATA_FRAME(extFc))) - { - if (GP_NWK_ADDRESSING_APP_ID(extFc) == GP_ADDRESSING_MODE_SRC_ID) - { - uint8_t cmdId = *(gpFrameStartIndex + GP_COMMAND_INDEX_WITH_APP_MODE_0); - if (cmdId == GP_COMMISSIONING_REPLY_CMD_ID && !isRxFrame) - { - // Buffer the frame - isGpPkt = true; - } - else if (cmdId == GP_COMMISSIONINGING_CMD_ID && isRxFrame) - { - otRadioFrame *aTxFrame = otPlatRadioGetTransmitBuffer(NULL); - // Match the gpd src Id ? - if (!memcmp((const void *)(gpFrameStartIndex + GP_SRC_ID_INDEX_WITH_APP_MODE_0), - (const void *)((aTxFrame->mPsdu) + BUFFERED_PSDU_GP_SRC_ID_INDEX_WITH_APP_MODE_0), - sizeof(uint32_t))) - { - // Send out the buffered frame - gp_state = SL_GP_STATE_SEND_RESPONSE; - gpStateTimeOut = aFrame->mInfo.mRxInfo.mTimestamp + GP_RX_OFFSET_IN_MICRO_SECONDS; - } - } - } - else if (GP_NWK_ADDRESSING_APP_ID(extFc) == GP_ADDRESSING_MODE_EUI64) - { - uint8_t cmdId = *(gpFrameStartIndex + GP_COMMAND_INDEX_WITH_APP_MODE_1); - if (cmdId == GP_COMMISSIONING_REPLY_CMD_ID && !isRxFrame) - { - // Buffer the frame - isGpPkt = true; - } - else if (cmdId == GP_COMMISSIONINGING_CMD_ID && isRxFrame) - { - otRadioFrame *aTxFrame = otPlatRadioGetTransmitBuffer(NULL); - // Check the eui64 and app endpoint to send out the buffer packet. - otMacAddress aSrcAddress; - otMacAddress aDstAddress; - otMacFrameGetDstAddr(aTxFrame, &aDstAddress); - otMacFrameGetSrcAddr(aFrame, &aSrcAddress); - if (!memcmp(&(aDstAddress.mAddress.mExtAddress), - &(aSrcAddress.mAddress.mExtAddress), - sizeof(otExtAddress)) - && (gpFrameStartIndex[GP_APP_EP_INDEX_WITH_APP_MODE_1] - == (aTxFrame->mPsdu)[BUFFERED_PSDU_GP_APP_EP_INDEX_WITH_APP_MODE_1])) - { - isGpPkt = true; - gp_state = SL_GP_STATE_SEND_RESPONSE; - gpStateTimeOut = aFrame->mInfo.mRxInfo.mTimestamp + GP_RX_OFFSET_IN_MICRO_SECONDS; - } - } - } - } - } - } - - if (isGpPkt) - { - otLogDebgPlat("GP RCP INTF: GP filter passed!!"); - } - -exit: - return isGpPkt; -} diff --git a/src/src/sleep.c b/src/src/sleep.c index 37d42b3a..22c825da 100644 --- a/src/src/sleep.c +++ b/src/src/sleep.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, The OpenThread Authors. + * Copyright (c) 2024, The OpenThread Authors. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -36,6 +36,7 @@ #define CURRENT_MODULE_NAME "OPENTHREAD" #include "sleep.h" +#include "alarm.h" #include "em_core.h" #include "em_gpio.h" #include "platform-efr32.h" @@ -123,7 +124,8 @@ void sl_ot_sleep_init(void) #endif // SL_CATALOG_POWER_MANAGER_PRESENT } -__WEAK bool efr32AllowSleepCallback(void) +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) +OT_TOOL_WEAK bool efr32AllowSleepCallback(void) { return true; } @@ -192,6 +194,7 @@ bool sl_ot_is_ok_to_sleep(void) //------------------------------------------------------------------------------ // Static functions +SL_CODE_CLASSIFY(SL_CODE_COMPONENT_OT_PLATFORM_ABSTRACTION, SL_CODE_CLASS_TIME_CRITICAL) static void energy_mode_transition_callback(sl_power_manager_em_t from, sl_power_manager_em_t to) { #if defined(_SILICON_LABS_32B_SERIES_2) && defined(VCOM_TX_PORT) diff --git a/src/src/soft_source_match_table.c b/src/src/soft_source_match_table.c index 0d70bd3d..246f4a8b 100644 --- a/src/src/soft_source_match_table.c +++ b/src/src/soft_source_match_table.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, The OpenThread Authors. + * Copyright (c) 2024, The OpenThread Authors. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -41,25 +41,16 @@ #include #include +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE +#include +#endif +#include "sl_multipan.h" #include "common/debug.hpp" #include "utils/code_utils.h" // Print entire source match tables when #define PRINT_MULTIPAN_SOURCE_MATCH_TABLES 0 -#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE -extern uint8_t otNcpPlatGetCurCommandIid(void); -static inline uint8_t getPanIndex(uint8_t iid) -{ - // Assert if iid=0 (broadcast iid) - OT_ASSERT(iid != 0); - return iid - 1; -} -#else // !OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE -#define otNcpPlatGetCurCommandIid() 0 -#define getPanIndex(iid) 0 -#endif // OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE - #if RADIO_CONFIG_SRC_MATCH_SHORT_ENTRY_NUM || RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM static uint16_t sPanId[RADIO_CONFIG_SRC_MATCH_PANID_NUM] = {0}; @@ -77,9 +68,7 @@ static void printPanIdTable(void) void utilsSoftSrcMatchSetPanId(uint8_t iid, uint16_t aPanId) { - OT_UNUSED_VARIABLE(iid); - - const uint8_t panIndex = getPanIndex(iid); + const uint8_t panIndex = efr32GetPanIndexFromIid(iid); sPanId[panIndex] = aPanId; otLogInfoPlat("Setting panIndex=%d to 0x%04x", panIndex, aPanId); @@ -99,9 +88,7 @@ static sSrcMatchShortEntry srcMatchShortEntry[RADIO_CONFIG_SRC_MATCH_PANID_NUM][ #if PRINT_MULTIPAN_SOURCE_MATCH_TABLES static void printShortEntryTable(uint8_t iid) { - const uint8_t panIndex = getPanIndex(iid); - OT_UNUSED_VARIABLE(iid); - OT_UNUSED_VARIABLE(panIndex); + const uint8_t panIndex = efr32GetPanIndexFromIid(iid); otLogDebgPlat("================================|============|==========="); otLogDebgPlat("ShortEntry[panIndex][entry] | .allocated | .checksum "); @@ -122,8 +109,6 @@ static void printShortEntryTable(uint8_t iid) int16_t utilsSoftSrcMatchShortFindEntry(uint8_t iid, uint16_t aShortAddress) { - OT_UNUSED_VARIABLE(iid); - int16_t entry = -1; #if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE @@ -133,7 +118,7 @@ int16_t utilsSoftSrcMatchShortFindEntry(uint8_t iid, uint16_t aShortAddress) } #endif - const uint8_t panIndex = getPanIndex(iid); + const uint8_t panIndex = efr32GetPanIndexFromIid(iid); uint16_t checksum = aShortAddress + sPanId[panIndex]; for (int16_t i = 0; i < RADIO_CONFIG_SRC_MATCH_SHORT_ENTRY_NUM; i++) @@ -150,10 +135,8 @@ int16_t utilsSoftSrcMatchShortFindEntry(uint8_t iid, uint16_t aShortAddress) static int16_t findSrcMatchShortAvailEntry(uint8_t iid) { - OT_UNUSED_VARIABLE(iid); - int16_t entry = -1; - const uint8_t panIndex = getPanIndex(iid); + const uint8_t panIndex = efr32GetPanIndexFromIid(iid); for (int16_t i = 0; i < RADIO_CONFIG_SRC_MATCH_SHORT_ENTRY_NUM; i++) { @@ -169,9 +152,7 @@ static int16_t findSrcMatchShortAvailEntry(uint8_t iid) static inline void addToSrcMatchShortIndirect(uint8_t iid, uint16_t entry, uint16_t aShortAddress) { - OT_UNUSED_VARIABLE(iid); - - const uint8_t panIndex = getPanIndex(iid); + const uint8_t panIndex = efr32GetPanIndexFromIid(iid); uint16_t checksum = aShortAddress + sPanId[panIndex]; srcMatchShortEntry[panIndex][entry].checksum = checksum; @@ -182,9 +163,7 @@ static inline void addToSrcMatchShortIndirect(uint8_t iid, uint16_t entry, uint1 static inline void removeFromSrcMatchShortIndirect(uint8_t iid, uint16_t entry) { - OT_UNUSED_VARIABLE(iid); - - const uint8_t panIndex = getPanIndex(iid); + const uint8_t panIndex = efr32GetPanIndexFromIid(iid); srcMatchShortEntry[panIndex][entry].allocated = false; srcMatchShortEntry[panIndex][entry].checksum = 0; @@ -197,13 +176,12 @@ otError otPlatRadioAddSrcMatchShortEntry(otInstance *aInstance, uint16_t aShortA OT_UNUSED_VARIABLE(aInstance); otError error = OT_ERROR_NONE; - int8_t iid = -1; + int8_t iid = efr32GetIidFromInstance(aInstance); int16_t entry = -1; - iid = otNcpPlatGetCurCommandIid(); #if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE - // Prevent duplicate entries in multipan use case. entry = utilsSoftSrcMatchShortFindEntry(iid, aShortAddress); + // Prevent duplicate entries in multipan use case. otEXPECT(!(entry >= 0 && entry < RADIO_CONFIG_SRC_MATCH_SHORT_ENTRY_NUM)); #endif @@ -224,12 +202,9 @@ otError otPlatRadioClearSrcMatchShortEntry(otInstance *aInstance, uint16_t aShor OT_UNUSED_VARIABLE(aInstance); otError error = OT_ERROR_NONE; - int16_t entry = -1; - int8_t iid = -1; + int8_t iid = efr32GetIidFromInstance(aInstance); + int16_t entry = utilsSoftSrcMatchShortFindEntry(iid, aShortAddress); - iid = otNcpPlatGetCurCommandIid(); - - entry = utilsSoftSrcMatchShortFindEntry(iid, aShortAddress); otLogDebgPlat("Clear ShortAddr: iid=%d, entry=%d, addr=0x%04x", iid, entry, aShortAddress); otEXPECT_ACTION(entry >= 0 && entry < RADIO_CONFIG_SRC_MATCH_SHORT_ENTRY_NUM, error = OT_ERROR_NO_ADDRESS); @@ -242,11 +217,9 @@ otError otPlatRadioClearSrcMatchShortEntry(otInstance *aInstance, uint16_t aShor void otPlatRadioClearSrcMatchShortEntries(otInstance *aInstance) { - OT_UNUSED_VARIABLE(aInstance); + uint8_t iid = efr32GetIidFromInstance(aInstance); - uint8_t iid = otNcpPlatGetCurCommandIid(); - const uint8_t panIndex = getPanIndex(iid); - OT_UNUSED_VARIABLE(iid); + const uint8_t panIndex = efr32GetPanIndexFromIid(iid); otLogDebgPlat("Clear ShortAddr entries (iid: %d)", iid); @@ -268,9 +241,7 @@ static sSrcMatchExtEntry srcMatchExtEntry[RADIO_CONFIG_SRC_MATCH_PANID_NUM][RADI #if PRINT_MULTIPAN_SOURCE_MATCH_TABLES static void printExtEntryTable(uint8_t iid) { - OT_UNUSED_VARIABLE(iid); - const uint8_t panIndex = getPanIndex(iid); - OT_UNUSED_VARIABLE(panIndex); + const uint8_t panIndex = efr32GetPanIndexFromIid(iid); otLogDebgPlat("==============================|============|==========="); otLogDebgPlat("ExtEntry[panIndex][entry] | .allocated | .checksum "); @@ -291,8 +262,6 @@ static void printExtEntryTable(uint8_t iid) int16_t utilsSoftSrcMatchExtFindEntry(uint8_t iid, const otExtAddress *aExtAddress) { - OT_UNUSED_VARIABLE(iid); - int16_t entry = -1; #if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE @@ -302,7 +271,7 @@ int16_t utilsSoftSrcMatchExtFindEntry(uint8_t iid, const otExtAddress *aExtAddre } #endif - const uint8_t panIndex = getPanIndex(iid); + const uint8_t panIndex = efr32GetPanIndexFromIid(iid); uint16_t checksum = sPanId[panIndex]; checksum += (uint16_t)aExtAddress->m8[0] | (uint16_t)(aExtAddress->m8[1] << 8); @@ -324,10 +293,8 @@ int16_t utilsSoftSrcMatchExtFindEntry(uint8_t iid, const otExtAddress *aExtAddre static int16_t findSrcMatchExtAvailEntry(uint8_t iid) { - OT_UNUSED_VARIABLE(iid); - int16_t entry = -1; - const uint8_t panIndex = getPanIndex(iid); + const uint8_t panIndex = efr32GetPanIndexFromIid(iid); for (int16_t i = 0; i < RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM; i++) { @@ -343,9 +310,7 @@ static int16_t findSrcMatchExtAvailEntry(uint8_t iid) static inline void addToSrcMatchExtIndirect(uint8_t iid, uint16_t entry, const otExtAddress *aExtAddress) { - OT_UNUSED_VARIABLE(iid); - - const uint8_t panIndex = getPanIndex(iid); + const uint8_t panIndex = efr32GetPanIndexFromIid(iid); uint16_t checksum = sPanId[panIndex]; checksum += (uint16_t)aExtAddress->m8[0] | (uint16_t)(aExtAddress->m8[1] << 8); @@ -361,9 +326,7 @@ static inline void addToSrcMatchExtIndirect(uint8_t iid, uint16_t entry, const o static inline void removeFromSrcMatchExtIndirect(uint8_t iid, uint16_t entry) { - OT_UNUSED_VARIABLE(iid); - - const uint8_t panIndex = getPanIndex(iid); + const uint8_t panIndex = efr32GetPanIndexFromIid(iid); srcMatchExtEntry[panIndex][entry].allocated = false; srcMatchExtEntry[panIndex][entry].checksum = 0; @@ -376,12 +339,12 @@ otError otPlatRadioAddSrcMatchExtEntry(otInstance *aInstance, const otExtAddress OT_UNUSED_VARIABLE(aInstance); otError error = OT_ERROR_NONE; + uint8_t iid = efr32GetIidFromInstance(aInstance); int16_t entry = -1; - uint8_t iid = otNcpPlatGetCurCommandIid(); #if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE - // Prevent duplicate entries in multipan use case. entry = utilsSoftSrcMatchExtFindEntry(iid, aExtAddress); + // Prevent duplicate entries in multipan use case. otEXPECT(!(entry >= 0 && entry < RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM)); #endif @@ -399,13 +362,10 @@ otError otPlatRadioAddSrcMatchExtEntry(otInstance *aInstance, const otExtAddress otError otPlatRadioClearSrcMatchExtEntry(otInstance *aInstance, const otExtAddress *aExtAddress) { - OT_UNUSED_VARIABLE(aInstance); - otError error = OT_ERROR_NONE; - int16_t entry = -1; + uint8_t iid = efr32GetIidFromInstance(aInstance); + int16_t entry = utilsSoftSrcMatchExtFindEntry(iid, aExtAddress); - uint8_t iid = otNcpPlatGetCurCommandIid(); - entry = utilsSoftSrcMatchExtFindEntry(iid, aExtAddress); otLogDebgPlat("Clear ExtAddr: iid=%d, entry=%d", iid, entry); otEXPECT_ACTION(entry >= 0 && entry < RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM, error = OT_ERROR_NO_ADDRESS); @@ -418,13 +378,10 @@ otError otPlatRadioClearSrcMatchExtEntry(otInstance *aInstance, const otExtAddre void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance) { - OT_UNUSED_VARIABLE(aInstance); - - uint8_t iid = otNcpPlatGetCurCommandIid(); - OT_UNUSED_VARIABLE(iid); + uint8_t iid = efr32GetIidFromInstance(aInstance); otLogDebgPlat("Clear ExtAddr entries (iid: %d)", iid); - const uint8_t panIndex = getPanIndex(iid); + const uint8_t panIndex = efr32GetPanIndexFromIid(iid); memset(srcMatchExtEntry[panIndex], 0, sizeof(srcMatchExtEntry[panIndex])); @@ -434,7 +391,7 @@ void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance) uint8_t utilsSoftSrcMatchFindIidFromPanId(otPanId panId) { - uint8_t iid = 0xFF; + uint8_t iid = INVALID_INTERFACE_INDEX; for (uint8_t index = 0; index < RADIO_CONFIG_SRC_MATCH_PANID_NUM; index++) { diff --git a/src/src/spidrv_usart.c b/src/src/spidrv_usart.c index 59862f0c..b81edf4c 100644 --- a/src/src/spidrv_usart.c +++ b/src/src/spidrv_usart.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, The OpenThread Authors. + * Copyright (c) 2024, The OpenThread Authors. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -40,7 +40,6 @@ #include #include -#include "em_cmu.h" #include "em_core.h" #include "em_gpio.h" #include "em_ldma.h" @@ -48,6 +47,7 @@ #include "gpiointerrupt.h" #include "spidrv.h" +#include "sl_clock_manager.h" #if defined(SL_CATALOG_POWER_MANAGER_PRESENT) #include "sl_power_manager.h" #endif @@ -55,9 +55,9 @@ #include "sl_ncp_spidrv_usart_config.h" #include "platform-efr32.h" -#include "spi-slave.h" #include #include +#include #include "utils/code_utils.h" // DEFINES @@ -187,7 +187,7 @@ otError otPlatSpiSlaveEnable(otPlatSpiSlaveTransactionCompleteCallback aComplete otEXPECT_ACTION(process_callback == NULL, error = OT_ERROR_ALREADY); otEXPECT_ACTION(context == NULL, error = OT_ERROR_ALREADY); - CMU_ClockEnable(cmuClock_GPIO, true); + sl_clock_manager_enable_bus_clock(SL_BUS_CLOCK_GPIO); SPIDRV_Init_t init_data = (SPIDRV_Init_t) { diff --git a/src/src/system.c b/src/src/system.c index 69348de4..92b0c908 100644 --- a/src/src/system.c +++ b/src/src/system.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, The OpenThread Authors. + * Copyright (c) 2024, The OpenThread Authors. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,59 +32,110 @@ * This file includes the platform-specific initializers. */ -#include -#include "common/debug.hpp" +#include #include #include -#include "utils/uart.h" #include "common/logging.hpp" -#include "em_chip.h" -#include "em_emu.h" -#include "em_system.h" -#include "rail.h" -#include "sl_mpu.h" -#include "sl_sleeptimer.h" -#if OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE -#include "sl_malloc.h" -#include "openthread/heap.h" -#endif - -#include "platform-efr32.h" -#include "sl_openthread.h" +#include "sl_system_init.h" +//============================================================================== +// Component Catalog includes +//============================================================================== #if defined(SL_COMPONENT_CATALOG_PRESENT) #include "sl_component_catalog.h" #endif -#include "sl_system_init.h" +#if defined(SL_CATALOG_KERNEL_PRESENT) +#include "sl_system_kernel.h" +#else +#include "sl_system_process_action.h" +#endif + +#if defined(SL_CATALOG_MEMORY_MANAGER_PRESENT) +#include "sl_memory_manager.h" +#endif #if defined(SL_CATALOG_POWER_MANAGER_PRESENT) #include "sl_power_manager.h" #endif // SL_CATALOG_POWER_MANAGER_PRESENT -#if defined(SL_CATALOG_KERNEL_PRESENT) -#include "sl_system_kernel.h" -#else -#include "sl_system_process_action.h" +//============================================================================== +// PAL includes +//============================================================================== +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE +#include "sl_gp_interface.h" #endif -#if defined(SL_CATALOG_OT_RCP_GP_INTERFACE_PRESENT) -#include "sl_rcp_gp_interface.h" -#endif // SL_CATALOG_OT_RCP_GP_INTERFACE_PRESENT +#include "alarm.h" +#include "platform-efr32.h" +//============================================================================== +// Preprocessor macro definitions +//============================================================================== #define USE_EFR32_LOG (OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_PLATFORM_DEFINED) +#if defined(SL_CATALOG_OPENTHREAD_CLI_PRESENT) && defined(SL_CATALOG_KERNEL_PRESENT) +#define CLI_TASK_ENABLED (SL_OPENTHREAD_ENABLE_CLI_TASK) +#else +#define CLI_TASK_ENABLED (0) +#endif + +//============================================================================== +// Forward declarations +//============================================================================== +static void efr32SerialProcess(void); + +#if (OPENTHREAD_RADIO) +static void efr32NcpProcess(void); +#elif (CLI_TASK_ENABLED == 0) +static void efr32CliProcess(void); +#endif + +//============================================================================== +// Global variables +//============================================================================== otInstance *sInstance; -#ifndef SL_COMPONENT_CATALOG_PRESENT -__WEAK void sl_openthread_init(void) +//============================================================================== +// Serial process helper functions +//============================================================================== +static void efr32SerialProcess(void) +{ +#if (OPENTHREAD_RADIO) + efr32NcpProcess(); +#elif (CLI_TASK_ENABLED == 0) + efr32CliProcess(); +#endif // OPENTHREAD_RADIO0 +} + +#if (OPENTHREAD_RADIO) +static void efr32NcpProcess(void) +{ +#if OPENTHREAD_CONFIG_NCP_HDLC_ENABLE + efr32UartProcess(); +#elif OPENTHREAD_CONFIG_NCP_CPC_ENABLE + efr32CpcProcess(); +#elif OPENTHREAD_CONFIG_NCP_SPI_ENABLE + efr32SpiProcess(); +#endif +} +#elif (CLI_TASK_ENABLED == 0) +static void efr32CliProcess(void) +{ + efr32UartProcess(); +} +#endif + +//============================================================================== +// Weakly defined function definitions +//============================================================================== +OT_TOOL_WEAK void sl_openthread_init(void) { // Placeholder for enabling Silabs specific features available only through Simplicity Studio } -#endif // SL_COMPONENT_CATALOG_PRESENT /** * @brief Application initialization @@ -94,6 +145,14 @@ OT_TOOL_WEAK void app_init(void) // Placeholder for any application specific initialization } +OT_TOOL_WEAK void otSysEventSignalPending(void) +{ + // Intentionally empty +} + +//============================================================================== +// Other function definitions +//============================================================================== void otSysInit(int argc, char *argv[]) { OT_UNUSED_VARIABLE(argc); @@ -112,6 +171,8 @@ void otSysInit(int argc, char *argv[]) void sl_ot_sys_init(void) { + sl_openthread_init(); + #if USE_EFR32_LOG efr32LogInit(); #endif @@ -146,17 +207,12 @@ void otSysProcessDrivers(otInstance *aInstance) sl_system_process_action(); #endif -#if defined(SL_CATALOG_OT_RCP_GP_INTERFACE_PRESENT) +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE efr32GpProcess(); #endif -#if OPENTHREAD_CONFIG_NCP_HDLC_ENABLE - efr32UartProcess(); -#elif OPENTHREAD_CONFIG_NCP_CPC_ENABLE - efr32CpcProcess(); -#elif OPENTHREAD_CONFIG_NCP_SPI_ENABLE - efr32SpiProcess(); -#endif + efr32SerialProcess(); + efr32RadioProcess(aInstance); // See alarm.c: Wrapped in a critical section @@ -168,7 +224,4 @@ void otSysProcessDrivers(otInstance *aInstance) #endif } -__WEAK void otSysEventSignalPending(void) -{ - // Intentionally empty -} +//============================================================================== diff --git a/src/src/uartdrv_uart.c b/src/src/uartdrv_uart.c index dfbbdc10..28b5e52d 100644 --- a/src/src/uartdrv_uart.c +++ b/src/src/uartdrv_uart.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, The OpenThread Authors. + * Copyright (c) 2024, The OpenThread Authors. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -55,21 +55,16 @@ #include "sl_status.h" #ifdef SL_CATALOG_KERNEL_PRESENT +#include "sl_ot_rtos_adaptation.h" +#endif // SL_CATALOG_KERNEL_PRESENT -static unsigned int sGpioIntContext = 0; - -static void gpioSerialWakeupCallback(uint8_t interrupt_no, void *context) -{ - unsigned int *pin = (unsigned int *)context; +#define IRQ_CONCAT(type, instance, property) type##instance##property - (void)interrupt_no; +#define IRQ_LABEL_FORMAT(peripheral_no) IRQ_CONCAT(USART, peripheral_no, _RX_IRQn) +#define IRQ_HANDLER_FORMAT(peripheral_no) IRQ_CONCAT(USART, peripheral_no, _RX_IRQHandler) - if (*pin == SL_UARTDRV_USART_VCOM_RX_PIN) - { - otSysEventSignalPending(); - } -} -#endif // SL_CATALOG_KERNEL_PRESENT +#define USART_IRQ IRQ_LABEL_FORMAT(SL_UARTDRV_USART_VCOM_PERIPHERAL_NO) +#define USART_IRQHandler IRQ_HANDLER_FORMAT(SL_UARTDRV_USART_VCOM_PERIPHERAL_NO) enum { @@ -81,8 +76,9 @@ enum #define RECEIVE_BUFFER_SIZE 128 static uint8_t sReceiveBuffer1[RECEIVE_BUFFER_SIZE]; static uint8_t sReceiveBuffer2[RECEIVE_BUFFER_SIZE]; -static uint8_t lastCount = 0; -static volatile bool sTxComplete = false; +static uint8_t lastCount = 0; +static volatile bool sTxComplete = false; +static volatile bool sRxDataReady = false; typedef struct ReceiveFifo_t { @@ -99,6 +95,21 @@ static ReceiveFifo_t sReceiveFifo; static void processReceive(void); static void processTransmit(void); +/* Clear the RXDATAV interrupt field by reading the RXDATA register */ +static inline void clearRxIRQ(void) +{ + (void)USART_RxDataGet(SL_UARTDRV_USART_VCOM_PERIPHERAL); +} + +void USART_IRQHandler(void) +{ + sRxDataReady = true; + clearRxIRQ(); +#ifdef SL_CATALOG_KERNEL_PRESENT + sl_ot_rtos_set_pending_event(SL_OT_RTOS_EVENT_UART); +#endif +} + static void receiveDone(UARTDRV_Handle_t aHandle, Ecode_t aStatus, uint8_t *aData, UARTDRV_Count_t aCount) { OT_UNUSED_VARIABLE(aStatus); @@ -112,7 +123,10 @@ static void receiveDone(UARTDRV_Handle_t aHandle, Ecode_t aStatus, uint8_t *aDat } UARTDRV_Receive(aHandle, aData, aCount, receiveDone); - otSysEventSignalPending(); + +#ifdef SL_CATALOG_KERNEL_PRESENT + sl_ot_rtos_set_pending_event(SL_OT_RTOS_EVENT_UART); // Receive Done event +#endif } static void transmitDone(UARTDRV_Handle_t aHandle, Ecode_t aStatus, uint8_t *aData, UARTDRV_Count_t aCount) @@ -124,7 +138,9 @@ static void transmitDone(UARTDRV_Handle_t aHandle, Ecode_t aStatus, uint8_t *aDa // This value will be used later in processTransmit() to call otPlatUartSendDone() sTxComplete = true; - otSysEventSignalPending(); +#ifdef SL_CATALOG_KERNEL_PRESENT + sl_ot_rtos_set_pending_event(SL_OT_RTOS_EVENT_UART); +#endif } static void processReceive(void) @@ -132,12 +148,21 @@ static void processReceive(void) uint8_t *aData; UARTDRV_Count_t aCount, remaining; - CORE_ATOMIC_SECTION(UARTDRV_GetReceiveStatus(sl_uartdrv_usart_vcom_handle, &aData, &aCount, &remaining); - if (aCount > lastCount) { - memcpy(sReceiveFifo.mBuffer + sReceiveFifo.mTail, aData + lastCount, aCount - lastCount); - sReceiveFifo.mTail = (sReceiveFifo.mTail + aCount - lastCount) % kReceiveFifoSize; - lastCount = aCount; - }) + otEXPECT(sRxDataReady); + + CORE_DECLARE_IRQ_STATE; + CORE_ENTER_ATOMIC(); + + sRxDataReady = false; + UARTDRV_GetReceiveStatus(sl_uartdrv_usart_vcom_handle, &aData, &aCount, &remaining); + if (aCount > lastCount) + { + memcpy(sReceiveFifo.mBuffer + sReceiveFifo.mTail, aData + lastCount, aCount - lastCount); + sReceiveFifo.mTail = (sReceiveFifo.mTail + aCount - lastCount) % kReceiveFifoSize; + lastCount = aCount; + } + + CORE_EXIT_ATOMIC(); // Copy tail to prevent multiple reads uint16_t tail = sReceiveFifo.mTail; @@ -159,18 +184,19 @@ static void processReceive(void) // Set mHead to the local tail we have cached sReceiveFifo.mHead = tail; } +exit: + return; } static void processTransmit(void) { // NOTE: This check needs to be done in here and cannot be done in transmitDone because the transmit may not be // fully complete when the transmitDone callback is called. - if (!sTxComplete) - { - return; - } + otEXPECT(sTxComplete); sTxComplete = false; otPlatUartSendDone(); +exit: + return; } void efr32UartProcess(void) @@ -183,18 +209,10 @@ otError otPlatUartEnable(void) { otError error = OT_ERROR_NONE; -#ifdef SL_CATALOG_KERNEL_PRESENT - unsigned int intNo; - - GPIOINT_Init(); - - sGpioIntContext = SL_UARTDRV_USART_VCOM_RX_PIN; - intNo = GPIOINT_CallbackRegisterExt(SL_UARTDRV_USART_VCOM_RX_PIN, gpioSerialWakeupCallback, &sGpioIntContext); - - otEXPECT_ACTION(intNo != INTERRUPT_UNAVAILABLE, error = OT_ERROR_FAILED); - - GPIO_ExtIntConfig(SL_UARTDRV_USART_VCOM_RX_PORT, SL_UARTDRV_USART_VCOM_RX_PIN, intNo, false, true, true); -#endif + // Enable USART interrupt to wake OT task when data arrives + NVIC_ClearPendingIRQ(USART_IRQ); + NVIC_EnableIRQ(USART_IRQ); + USART_IntEnable(SL_UARTDRV_USART_VCOM_PERIPHERAL, USART_IF_RXDATAV); sReceiveFifo.mHead = 0; sReceiveFifo.mTail = 0; @@ -204,9 +222,6 @@ otError otPlatUartEnable(void) UARTDRV_Receive(sl_uartdrv_usart_vcom_handle, sReceiveBuffer1, RECEIVE_BUFFER_SIZE, receiveDone); UARTDRV_Receive(sl_uartdrv_usart_vcom_handle, sReceiveBuffer2, RECEIVE_BUFFER_SIZE, receiveDone); -#ifdef SL_CATALOG_KERNEL_PRESENT -exit: -#endif return error; } diff --git a/third_party/silabs/cmake/utility.cmake b/third_party/silabs/cmake/utility.cmake index 80cf5d43..11b1c37f 100644 --- a/third_party/silabs/cmake/utility.cmake +++ b/third_party/silabs/cmake/utility.cmake @@ -32,9 +32,9 @@ string(TOUPPER "${EFR32_PLATFORM}" PLATFORM_UPPERCASE) string(TOLOWER "${BOARD}" BOARD_LOWERCASE) string(TOUPPER "${BOARD}" BOARD_UPPERCASE) -set(SILABS_GSDK_DIR ${PROJECT_SOURCE_DIR}/third_party/silabs/gecko_sdk) +set(SILABS_SDK_DIR ${PROJECT_SOURCE_DIR}/third_party/silabs/simplicity_sdk) -# Check if GSDK exists -if(NOT EXISTS "${SILABS_GSDK_DIR}") - message(FATAL_ERROR "Cannot find: ${SILABS_GSDK_DIR}\nPlease make sure the submodule is initialized") +# Check if SDK exists +if(NOT EXISTS "${SILABS_SDK_DIR}") + message(FATAL_ERROR "Cannot find: ${SILABS_SDK_DIR}\nPlease make sure the submodule is initialized") endif() diff --git a/third_party/silabs/gecko_sdk b/third_party/silabs/gecko_sdk deleted file mode 160000 index d95099f4..00000000 --- a/third_party/silabs/gecko_sdk +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d95099f4c05b3c40cece93d8a261dd471e642086 diff --git a/third_party/silabs/simplicity_sdk b/third_party/silabs/simplicity_sdk new file mode 160000 index 00000000..50bdda9d --- /dev/null +++ b/third_party/silabs/simplicity_sdk @@ -0,0 +1 @@ +Subproject commit 50bdda9dcc9b4bd300deb93ea7e1b11eba663b20 diff --git a/third_party/silabs/slc/component/ot_core_vendor_extension.slcc b/third_party/silabs/slc/component/ot_core_vendor_extension.slcc index 08e44f4a..73a973a0 100644 --- a/third_party/silabs/slc/component/ot_core_vendor_extension.slcc +++ b/third_party/silabs/slc/component/ot_core_vendor_extension.slcc @@ -8,6 +8,8 @@ description: |- When used with the OT Crash Handler component, crash info will be printed after the OpenThread instance is initialized. provides: - name: ot_core_vendor_extension +ui_hints: + visibility: never include: - path: openthread/src/ file_list: @@ -17,3 +19,6 @@ source: define: - name: OPENTHREAD_ENABLE_VENDOR_EXTENSION value: 1 +metadata: + sbom: + license: Zlib diff --git a/third_party/silabs/slc/component/ot_crash_handler.slcc b/third_party/silabs/slc/component/ot_crash_handler.slcc deleted file mode 100644 index 0c823a79..00000000 --- a/third_party/silabs/slc/component/ot_crash_handler.slcc +++ /dev/null @@ -1,63 +0,0 @@ -id: ot_crash_handler -label: Crash Handler -package: OpenThread -category: OpenThread -quality: production -description: |- - This component provides a set of APIs for printing crash info. - In the case of a crash, this component captures the details. - The provided `efr32PrintResetInfo()` API prints the crash details. -provides: - - name: ot_crash_handler -conflicts: - - name: legacy_hal_soc -requires: - - name: component_catalog - - name: device - - name: emlib_rmu - - name: event_handler -include: - - path: third_party/silabs/gecko_sdk/protocol/openthread/src/legacy_hal/include - file_list: - - path: crash_handler.h - - path: third_party/silabs/gecko_sdk/platform/service/legacy_hal/inc - file_list: - - path: asm.h - - path: efm32_micro.h - condition: - - device_cortexm - - path: micro-common.h - - path: micro-types.h - - path: micro.h - - path: reset-def.h - - path: platform-header.h - - path: cortexm3/diagnostic.h - condition: - - device_cortexm -source: - - path: third_party/silabs/gecko_sdk/platform/service/legacy_hal/src/faults.s - - path: third_party/silabs/gecko_sdk/protocol/openthread/src/legacy_hal/crash_handler.c - - path: third_party/silabs/src/legacy_hal/diagnostic.c -define: - - name: "PLATFORM_HEADER" - value: "\"platform-header.h\"" - - name: CORTEXM3_EFM32_MICRO - condition: - - device_cortexm - - name: CORTEXM3 - condition: - - device_cortexm - - name: CORTEXM3_EFR32 - condition: - - device_cortexm - - name: PHY_RAIL - condition: - - device_cortexm -template_contribution: - - name: component_catalog - value: ot_crash_handler - - name: event_handler - value: - event: platform_init - include: crash_handler.h - handler: sl_ot_crash_handler_init diff --git a/third_party/silabs/slc/component/ot_headers.slcc b/third_party/silabs/slc/component/ot_headers.slcc new file mode 100644 index 00000000..dcb5a606 --- /dev/null +++ b/third_party/silabs/slc/component/ot_headers.slcc @@ -0,0 +1,59 @@ +id: ot_headers +label: OpenThread headers +package: OpenThread +category: OpenThread +quality: production +description: This component provides the OpenThread header files. +provides: + - name: ot_headers +requires: + - name: ot_headers_tcp +ui_hints: + visibility: never +root_path: openthread/src/core +include: + - path: ../../include/openthread + file_list: + - path: platform/alarm-micro.h + - path: platform/alarm-milli.h + - path: platform/ble.h + - path: platform/border_routing.h + - path: platform/crypto.h + - path: platform/diag.h + - path: platform/dns.h + - path: platform/dnssd.h + - path: platform/dso_transport.h + - path: platform/entropy.h + - path: platform/flash.h + - path: platform/infra_if.h + - path: platform/memory.h + - path: platform/misc.h + - path: platform/multipan.h + - path: platform/logging.h + - path: platform/mdns_socket.h + - path: platform/otns.h + - path: platform/radio.h + - path: platform/time.h + - path: platform/udp.h + - path: platform/spi-slave.h + - path: platform/settings.h + - path: platform/messagepool.h + - path: platform/toolchain.h + - path: platform/trel.h + - path: platform/debug_uart.h + - path: ../lib + file_list: + - path: platform/exit_code.h + - path: ../../examples/platforms + file_list: + - path: openthread-system.h + - path: utils/code_utils.h + - path: utils/link_metrics.h + - path: utils/mac_frame.h + - path: utils/logging_rtt.h + - path: utils/settings.h + - path: utils/uart.h + - path: utils/uart_rtt.h +metadata: + sbom: + reference: ot_sbom_openthread diff --git a/third_party/silabs/slc/component/ot_stack_features_config.slcc b/third_party/silabs/slc/component/ot_stack_features_config.slcc index a3e64dee..78263b6a 100644 --- a/third_party/silabs/slc/component/ot_stack_features_config.slcc +++ b/third_party/silabs/slc/component/ot_stack_features_config.slcc @@ -7,14 +7,14 @@ description: This component provides the OpenThread stack features configuration provides: - name: ot_stack_features_config config_file: - - path: third_party/silabs/gecko_sdk/protocol/openthread/config/sl_openthread_features_config.h + - path: third_party/silabs/simplicity_sdk/protocol/openthread/config/sl_openthread_features_config.h file_id: openthread_features unless: [ot_reference_device] - - path: third_party/silabs/gecko_sdk/protocol/openthread/config/sl_openthread_reference_device_config.h + - path: third_party/silabs/simplicity_sdk/protocol/openthread/config/sl_openthread_reference_device_config.h file_id: openthread_features condition: [ot_reference_device] validation_helper: - - path: third_party/silabs/gecko_sdk/protocol/openthread/component/script/ot_log_validation.lua + - path: third_party/silabs/simplicity_sdk/protocol/openthread/component/script/ot_log_validation.lua define: - name: SL_OPENTHREAD_STACK_FEATURES_CONFIG_FILE value: "\"sl_openthread_features_config.h\"" diff --git a/third_party/silabs/slc/exporter_templates/platform_library/CMakeLists.txt.jinja b/third_party/silabs/slc/exporter_templates/platform_library/CMakeLists.txt.jinja index 8f6cf25f..c34bab75 100644 --- a/third_party/silabs/slc/exporter_templates/platform_library/CMakeLists.txt.jinja +++ b/third_party/silabs/slc/exporter_templates/platform_library/CMakeLists.txt.jinja @@ -180,8 +180,8 @@ set(LD_FILE "${CMAKE_CURRENT_SOURCE_DIR}/autogen/linkerfile.ld") target_link_libraries({{PROJECT_NAME}} PUBLIC {%- for lib_name in SYS_LIBS+USER_LIBS %} - {#- Ignore GSDK static libs. These will be added below #} - {%- if 'SILABS_GSDK_DIR' not in lib_name %} + {#- Ignore SDK static libs. These will be added below #} + {%- if 'SILABS_SDK_DIR' not in lib_name %} {{ lib_name }} {%- endif %} {%- endfor %} @@ -202,20 +202,20 @@ target_link_options({{PROJECT_NAME}} PRIVATE {{ print_linker_flags() }} {% set lib_list = SYS_LIBS + USER_LIBS %} {%- if lib_list -%} # ============================================================================== -# Static libraries from GSDK +# Static libraries from SDK # ============================================================================== -{#- Generate a list of GSDK libs #} -set(GSDK_LIBS +{#- Generate a list of SDK libs #} +set(SDK_LIBS {%- for lib_name in lib_list -%} - {%- if ('SILABS_GSDK_DIR' in lib_name) and ('jlink' not in lib_name) %} + {%- if ('SILABS_SDK_DIR' in lib_name) and ('jlink' not in lib_name) %} {{lib_name}} {%- endif %} {%- endfor %} ) -# Import GSDK static libs and set a dependency on the GSDK library +# Import SDK static libs and set a dependency on the SDK library # This will ensure proper linking order -foreach(lib_file ${GSDK_LIBS}) +foreach(lib_file ${SDK_LIBS}) # Parse lib name, stripping .a extension get_filename_component(lib_name ${lib_file} NAME_WE) set(imported_lib_name "silabs-${lib_name}") diff --git a/third_party/silabs/slc/exporter_templates/platform_library/mbedtls.cmake.jinja b/third_party/silabs/slc/exporter_templates/platform_library/mbedtls.cmake.jinja index b0d8ed2b..e679fb79 100644 --- a/third_party/silabs/slc/exporter_templates/platform_library/mbedtls.cmake.jinja +++ b/third_party/silabs/slc/exporter_templates/platform_library/mbedtls.cmake.jinja @@ -54,7 +54,7 @@ set_target_properties({{PROJECT_NAME}}-mbedtls # ============================================================================== # Includes # ============================================================================== -set(SILABS_MBEDTLS_DIR "${SILABS_GSDK_DIR}/util/third_party/crypto") +set(SILABS_MBEDTLS_DIR "${SILABS_SDK_DIR}/util/third_party/crypto") {%- if MBEDTLS_INCLUDES %} target_include_directories({{PROJECT_NAME}}-mbedtls diff --git a/third_party/silabs/slc/platform_projects/openthread-efr32-rcp-spi.slcp b/third_party/silabs/slc/platform_projects/openthread-efr32-rcp-spi.slcp index 763fb5e7..07beb22e 100644 --- a/third_party/silabs/slc/platform_projects/openthread-efr32-rcp-spi.slcp +++ b/third_party/silabs/slc/platform_projects/openthread-efr32-rcp-spi.slcp @@ -6,20 +6,26 @@ category: OpenThread Examples quality: production component: + # ot-efr32 components - id: ot_crash_handler - from: ot-efr32 - id: ot_platform_abstraction_core - - id: ot_mbedtls + - id: ot_headers + from: ot-efr32 - id: ot_stack_features_config from: ot-efr32 - id: ot_core_vendor_extension from: ot-efr32 + + # SDK Components + - id: ot_mbedtls - id: ot_ncp_spidrv - id: rail_util_pti configuration: - name: SL_BOARD_ENABLE_VCOM value: 1 + - name: CIRCULAR_QUEUE_LEN_MAX + value: 16 define: - name: OPENTHREAD_COPROCESSOR diff --git a/third_party/silabs/slc/platform_projects/openthread-efr32-rcp-uart.slcp b/third_party/silabs/slc/platform_projects/openthread-efr32-rcp-uart.slcp index 7ca5d4a2..5360b1e0 100644 --- a/third_party/silabs/slc/platform_projects/openthread-efr32-rcp-uart.slcp +++ b/third_party/silabs/slc/platform_projects/openthread-efr32-rcp-uart.slcp @@ -6,14 +6,18 @@ category: OpenThread Examples quality: production component: + # ot-efr32 components - id: ot_crash_handler - from: ot-efr32 - id: ot_platform_abstraction_core - - id: ot_mbedtls + - id: ot_headers + from: ot-efr32 - id: ot_stack_features_config from: ot-efr32 - id: ot_core_vendor_extension from: ot-efr32 + + # SDK components + - id: ot_mbedtls - id: uartdrv_usart instance: - vcom @@ -22,6 +26,8 @@ component: configuration: - name: SL_BOARD_ENABLE_VCOM value: 1 + - name: CIRCULAR_QUEUE_LEN_MAX + value: 16 define: - name: OPENTHREAD_COPROCESSOR diff --git a/third_party/silabs/slc/platform_projects/openthread-efr32-soc-with-buttons-power-manager-csl.slcp b/third_party/silabs/slc/platform_projects/openthread-efr32-soc-with-buttons-power-manager-csl.slcp index 83e87381..a03119b8 100644 --- a/third_party/silabs/slc/platform_projects/openthread-efr32-soc-with-buttons-power-manager-csl.slcp +++ b/third_party/silabs/slc/platform_projects/openthread-efr32-soc-with-buttons-power-manager-csl.slcp @@ -7,15 +7,19 @@ category: OpenThread Examples quality: production component: + # ot-efr32 components - id: ot_crash_handler - from: ot-efr32 - id: ot_platform_abstraction_core - - id: ot_psa_crypto - - id: ot_mbedtls + - id: ot_headers + from: ot-efr32 - id: ot_stack_features_config from: ot-efr32 - id: ot_core_vendor_extension from: ot-efr32 + + # SDK components + - id: ot_psa_crypto + - id: ot_mbedtls - id: uartdrv_usart instance: - vcom @@ -55,6 +59,8 @@ configuration: condition: [freertos] - name: SL_STACK_SIZE value: 4608 + - name: CIRCULAR_QUEUE_LEN_MAX + value: 16 define: - name: OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE diff --git a/third_party/silabs/slc/platform_projects/openthread-efr32-soc-with-buttons-power-manager.slcp b/third_party/silabs/slc/platform_projects/openthread-efr32-soc-with-buttons-power-manager.slcp index 23fb1adc..8eaed5ce 100644 --- a/third_party/silabs/slc/platform_projects/openthread-efr32-soc-with-buttons-power-manager.slcp +++ b/third_party/silabs/slc/platform_projects/openthread-efr32-soc-with-buttons-power-manager.slcp @@ -7,15 +7,19 @@ category: OpenThread Examples quality: production component: + # ot-efr32 components - id: ot_crash_handler - from: ot-efr32 - id: ot_platform_abstraction_core - - id: ot_psa_crypto - - id: ot_mbedtls + - id: ot_headers + from: ot-efr32 - id: ot_stack_features_config from: ot-efr32 - id: ot_core_vendor_extension from: ot-efr32 + + # SDK components + - id: ot_psa_crypto + - id: ot_mbedtls - id: uartdrv_usart instance: - vcom @@ -55,6 +59,8 @@ configuration: condition: [freertos] - name: SL_STACK_SIZE value: 4608 + - name: CIRCULAR_QUEUE_LEN_MAX + value: 16 sdk_extension: - id: ot-efr32 diff --git a/third_party/silabs/slc/platform_projects/openthread-efr32-soc-with-buttons.slcp b/third_party/silabs/slc/platform_projects/openthread-efr32-soc-with-buttons.slcp index d8685f1a..e5fdcacb 100644 --- a/third_party/silabs/slc/platform_projects/openthread-efr32-soc-with-buttons.slcp +++ b/third_party/silabs/slc/platform_projects/openthread-efr32-soc-with-buttons.slcp @@ -7,15 +7,19 @@ category: OpenThread Examples quality: production component: + # ot-efr32 components - id: ot_crash_handler - from: ot-efr32 - id: ot_platform_abstraction_core - - id: ot_psa_crypto - - id: ot_mbedtls + - id: ot_headers + from: ot-efr32 - id: ot_stack_features_config from: ot-efr32 - id: ot_core_vendor_extension from: ot-efr32 + + # SDK components + - id: ot_psa_crypto + - id: ot_mbedtls - id: uartdrv_usart instance: - vcom @@ -54,6 +58,8 @@ configuration: condition: [freertos] - name: SL_STACK_SIZE value: 4608 + - name: CIRCULAR_QUEUE_LEN_MAX + value: 16 sdk_extension: - id: ot-efr32 diff --git a/third_party/silabs/slc/platform_projects/openthread-efr32-soc.slcp b/third_party/silabs/slc/platform_projects/openthread-efr32-soc.slcp index c87ac5aa..bde83ee6 100644 --- a/third_party/silabs/slc/platform_projects/openthread-efr32-soc.slcp +++ b/third_party/silabs/slc/platform_projects/openthread-efr32-soc.slcp @@ -6,15 +6,19 @@ category: OpenThread Examples quality: production component: + # ot-efr32 components - id: ot_crash_handler - from: ot-efr32 - id: ot_platform_abstraction_core - - id: ot_psa_crypto - - id: ot_mbedtls + - id: ot_headers + from: ot-efr32 - id: ot_stack_features_config from: ot-efr32 - id: ot_core_vendor_extension from: ot-efr32 + + # SDK components + - id: ot_psa_crypto + - id: ot_mbedtls - id: uartdrv_usart instance: - vcom @@ -41,6 +45,8 @@ configuration: condition: [freertos] - name: SL_STACK_SIZE value: 4608 + - name: CIRCULAR_QUEUE_LEN_MAX + value: 16 sdk_extension: - id: ot-efr32 diff --git a/third_party/silabs/src/legacy_hal/diagnostic.c b/third_party/silabs/src/legacy_hal/diagnostic.c deleted file mode 100644 index 2b5d480c..00000000 --- a/third_party/silabs/src/legacy_hal/diagnostic.c +++ /dev/null @@ -1,1422 +0,0 @@ -/***************************************************************************/ -/** - * @file - * - * @brief Diagnostic functions for the crash handler - ******************************************************************************* - * # License - * Copyright 2023 Silicon Laboratories Inc. www.silabs.com - ******************************************************************************* - * - * The licensor of this software is Silicon Laboratories Inc. Your use of this - * software is governed by the terms of Silicon Labs Master Software License - * Agreement (MSLA) available at - * www.silabs.com/about-us/legal/master-software-license-agreement. This - * software is distributed to you in Source Code format and is governed by the - * sections of the MSLA applicable to Source Code. - * - ******************************************************************************/ -/* clang-format off */ - -#include PLATFORM_HEADER - -#include -#include - -#include "crash_handler.h" - -#include "em_emu.h" -#include "em_rmu.h" - -#include - -// Crash info live in noinit RAM segment that is not modified during startup. -NO_INIT(HalCrashInfoType halCrashInfo); - -//------------------------------------------------------------------------------ -// Preprocessor definitions - -// Reserved instruction executed after a failed assert to cause a usage fault -#define ASSERT_USAGE_OPCODE 0xDE42 - -#if !defined(WDOG0) - #define WDOG0 WDOG - #define WDOG0_IRQn WDOG_IRQn -#endif - -#ifdef RTOS - #include "rtos/rtos.h" - #define freeRTOS 1 -#else - #define freeRTOS 0 -#endif - -// Forward Declarations -extern void sli_802154phy_radio_sleep(void); - -//------------------------------------------------------------------------------ -// Local Variables - -static const char * const cfsrBits[] = -{ - // Memory management (MPU) faults - "IACCVIOL: attempted instruction fetch from a no-execute address", // B0 - "DACCVIOL: attempted load or store at an illegal address", // B1 - "", // B2 - "MUNSTKERR: unstack from exception return caused access violation", // B3 - "MSTKERR: stacking from exception caused access violation", // B4 - "", // B5 - "", // B6 - "MMARVALID: MMAR contains valid fault address", // B7 - - // Bus faults - "IBUSERR: instruction prefetch caused bus fault", // B8 - "PRECISERR: precise data bus fault", // B9 - "IMPRECISERR: imprecise data bus fault", // B10 - "UNSTKERR: unstacking on exception return caused data bus fault", // B11 - "STKERR: stacking on exception entry caused data bus fault", // B12 - "", // B13 - "", // B14 - "BFARVALID: BFAR contains valid fault address", // B15 - - // Usage faults - "UNDEFINSTR: tried to execute an undefined instruction", // B16 - "INVSTATE: invalid EPSR - e.g., tried to switch to ARM mode", // B17 - "INVPC: exception return integrity checks failed", // B18 - "NOCP: attempted to execute a coprocessor instruction", // B19 - "", // B20 - "", // B21 - "", // B22 - "", // B23 - "UNALIGNED: attempted an unaligned memory access", // B24 - "DIVBYZERO: attempted to execute SDIV or UDIV with divisor of 0" // B25 -}; - -static const char * const intActiveBits[] = -{ -#if defined (_EFR_DEVICE) - #if defined (_SILICON_LABS_32B_SERIES_1_CONFIG_1) - "EMU_IRQn", // B0 - "FRC_PRI_IRQn", // B1 - "WDOG0_IRQn", // B2 - "FRC_IRQn", // B3 - "MODEM_IRQn", // B4 - "RAC_SEQ_IRQn", // B5 - "RAC_RSM_IRQn", // B6 - "BUFC_IRQn", // B7 - "LDMA_IRQn", // B8 - "GPIO_EVEN_IRQn", // B9 - "TIMER0_IRQn", // B10 - "USART0_RX_IRQn", // B11 - "USART0_TX_IRQn", // B12 - "ACMP0_IRQn", // B13 - "ADC0_IRQn", // B14 - "IDAC0_IRQn", // B15 - "I2C0_IRQn", // B16 - "GPIO_ODD_IRQn", // B17 - "TIMER1_IRQn", // B18 - "USART1_RX_IRQn", // B19 - "USART1_TX_IRQn", // B20 - "LEUART0_IRQn", // B21 - "PCNT0_IRQn", // B22 - "CMU_IRQn", // B23 - "MSC_IRQn", // B24 - "CRYPTO_IRQn", // B25 - "LETIMER0_IRQn", // B26 - "AGC_IRQn", // B27 - "PROTIMER_IRQn", // B28 - "RTCC_IRQn", // B29 - "SYNTH_IRQn", // B30 - "CRYOTIMER_IRQn", // B31 - "RFSENSE_IRQn", // B32 - "FPUEH_IRQn", // B33 - #elif defined (_SILICON_LABS_32B_SERIES_1_CONFIG_2) - "EMU_IRQn", // B0 - "FRC_PRI_IRQn", // B1 - "WDOG0_IRQn", // B2 - "WDOG1_IRQn", // B3 - "FRC_IRQn", // B4 - "MODEM_IRQn", // B5 - "RAC_SEQ_IRQn", // B6 - "RAC_RSM_IRQn", // B7 - "BUFC_IRQn", // B8 - "LDMA_IRQn", // B9 - "GPIO_EVEN_IRQn", // B10 - "TIMER0_IRQn", // B11 - "USART0_RX_IRQn", // B12 - "USART0_TX_IRQn", // B13 - "ACMP0_IRQn", // B14 - "ADC0_IRQn", // B15 - "IDAC0_IRQn", // B16 - "I2C0_IRQn", // B17 - "GPIO_ODD_IRQn", // B18 - "TIMER1_IRQn", // B19 - "USART1_RX_IRQn", // B20 - "USART1_TX_IRQn", // B21 - "LEUART0_IRQn", // B22 - "PCNT0_IRQn", // B23 - "CMU_IRQn", // B24 - "MSC_IRQn", // B25 - "CRYPTO0_IRQn", // B26 - "LETIMER0_IRQn", // B27 - "AGC_IRQn", // B28 - "PROTIMER_IRQn", // B29 - "RTCC_IRQn", // B30 - "SYNTH_IRQn", // B31 - "CRYOTIMER_IRQn", // B32 - "RFSENSE_IRQn", // B33 - "FPUEH_IRQn", // B34 - "SMU_IRQn", // B35 - "WTIMER0_IRQn", // B36 - "WTIMER1_IRQn", // B37 - "PCNT1_IRQn", // B38 - "PCNT2_IRQn", // B39 - "USART2_RX_IRQn", // B40 - "USART2_TX_IRQn", // B41 - "I2C1_IRQn", // B42 - "USART3_RX_IRQn", // B43 - "USART3_TX_IRQn", // B44 - "VDAC0_IRQn", // B45 - "CSEN_IRQn", // B46 - "LESENSE_IRQn", // B47 - "CRYPTO1_IRQn", // B48 - "TRNG0_IRQn", // B49 - #elif defined (_SILICON_LABS_32B_SERIES_1_CONFIG_3) - "EMU_IRQn", // B0 - "FRC_PRI_IRQn", // B1 - "WDOG0_IRQn", // B2 - "WDOG1_IRQn", // B3 - "FRC_IRQn", // B4 - "MODEM_IRQn", // B5 - "RAC_SEQ_IRQn", // B6 - "RAC_RSM_IRQn", // B7 - "BUFC_IRQn", // B8 - "LDMA_IRQn", // B9 - "GPIO_EVEN_IRQn", // B10 - "TIMER0_IRQn", // B11 - "USART0_RX_IRQn", // B12 - "USART0_TX_IRQn", // B13 - "ACMP0_IRQn", // B14 - "ADC0_IRQn", // B15 - "IDAC0_IRQn", // B16 - "I2C0_IRQn", // B17 - "GPIO_ODD_IRQn", // B18 - "TIMER1_IRQn", // B19 - "USART1_RX_IRQn", // B20 - "USART1_TX_IRQn", // B21 - "LEUART0_IRQn", // B22 - "PCNT0_IRQn", // B23 - "CMU_IRQn", // B24 - "MSC_IRQn", // B25 - "CRYPTO0_IRQn", // B26 - "LETIMER0_IRQn", // B27 - "AGC_IRQn", // B28 - "PROTIMER_IRQn", // B29 - "PRORTC_IRQn", // B30 - "RTCC_IRQn", // B31 - "SYNTH_IRQn", // B32 - "CRYOTIMER_IRQn", // B33 - "RFSENSE_IRQn", // B34 - "FPUEH_IRQn", // B35 - "SMU_IRQn", // B36 - "WTIMER0_IRQn", // B37 - "USART2_RX_IRQn", // B38 - "USART2_TX_IRQn", // B39 - "I2C1_IRQn", // B40 - "VDAC0_IRQn", // B41 - "CSEN_IRQn", // B42 - "LESENSE_IRQn", // B43 - "CRYPTO1_IRQn", // B44 - "TRNG0_IRQn" // B45 - #elif defined (_SILICON_LABS_32B_SERIES_1_CONFIG_4) - "EMU_IRQn", // B0 - "FRC_PRI_IRQn", // B1 - "WDOG0_IRQn", // B2 - "WDOG1_IRQn", // B3 - "FRC_IRQn", // B4 - "MODEM_IRQn", // B5 - "RAC_SEQ_IRQn", // B6 - "RAC_RSM_IRQn", // B7 - "BUFC_IRQn", // B8 - "LDMA_IRQn", // B9 - "GPIO_EVEN_IRQn", // B10 - "TIMER0_IRQn", // B11 - "USART0_RX_IRQn", // B12 - "USART0_TX_IRQn", // B13 - "ACMP0_IRQn", // B14 - "ADC0_IRQn", // B15 - "IDAC0_IRQn", // B16 - "I2C0_IRQn", // B17 - "GPIO_ODD_IRQn", // B18 - "TIMER1_IRQn", // B19 - "USART1_RX_IRQn", // B20 - "USART1_TX_IRQn", // B21 - "LEUART0_IRQn", // B22 - "PCNT0_IRQn", // B23 - "CMU_IRQn", // B24 - "MSC_IRQn", // B25 - "CRYPTO0_IRQn", // B26 - "LETIMER0_IRQn", // B27 - "AGC_IRQn", // B28 - "PROTIMER_IRQn", // B29 - "PRORTC_IRQn", // B30 - "RTCC_IRQn", // B31 - "SYNTH_IRQn", // B32 - "CRYOTIMER_IRQn", // B33 - "RFSENSE_IRQn", // B34 - "FPUEH_IRQn", // B35 - "SMU_IRQn", // B36 - "WTIMER0_IRQn", // B37 - "VDAC0_IRQn", // B38 - "LESENSE_IRQn", // B39 - "TRNG0_IRQn", // B40 - "SYSCFG_IRQn", // B41 - #elif defined (_SILICON_LABS_32B_SERIES_2_CONFIG_1) - "SETAMPERHOST_IRQn", // B0 - "SEMBRX_IRQn", // B1 - "SEMBTX_IRQn", // B2 - "SMU_SECURE_IRQn", // B3 - "SMU_PRIVILEGED_IRQn", // B4 - "EMU_IRQn", // B5 - "TIMER0_IRQn", // B6 - "TIMER1_IRQn", // B7 - "TIMER2_IRQn", // B8 - "TIMER3_IRQn", // B9 - "RTCC_IRQn", // B10 - "USART0_RX_IRQn", // B11 - "USART0_TX_IRQn", // B12 - "USART1_RX_IRQn", // B13 - "USART1_TX_IRQn", // B14 - "USART2_RX_IRQn", // B15 - "USART2_TX_IRQn", // B16 - "ICACHE0_IRQn", // B17 - "BURTC_IRQn", // B18 - "LETIMER0_IRQn", // B19 - "SYSCFG_IRQn", // B20 - "LDMA_IRQn", // B21 - "LFXO_IRQn", // B22 - "LFRCO_IRQn", // B23 - "ULFRCO_IRQn", // B24 - "GPIO_ODD_IRQn", // B25 - "GPIO_EVEN_IRQn", // B26 - "I2C0_IRQn", // B27 - "I2C1_IRQn", // B28 - "EMUDG_IRQn", // B29 - "EMUSE_IRQn", // B30 - "AGC_IRQn", // B31 - "BUFC_IRQn", // B32 - "FRC_PRI_IRQn", // B33 - "FRC_IRQn", // B34 - "MODEM_IRQn", // B35 - "PROTIMER_IRQn", // B36 - "RAC_RSM_IRQn", // B37 - "RAC_SEQ_IRQn", // B38 - "PRORTC_IRQn", // B39 - "SYNTH_IRQn", // B40 - "ACMP0_IRQn", // B41 - "ACMP1_IRQn", // B42 - "WDOG0_IRQn", // B43 - "WDOG1_IRQn", // B44 - "HFXO00_IRQn", // B45 - "HFRCO0_IRQn", // B46 - "HFRCOEM23_IRQn", // B47 - "CMU_IRQn", // B48 - "AES_IRQn", // B49 - "IADC_IRQn", // B50 - "MSC_IRQn", // B51 - "DPLL0_IRQn", // B52 - "SW0_IRQn", // B53 - "SW1_IRQn", // B54 - "SW2_IRQn", // B55 - "SW3_IRQn", // B56 - "KERNEL0_IRQn", // B57 - "KERNEL1_IRQn", // B58 - "M33CTI0_IRQn", // B59 - "M33CTI1_IRQn", // B60 - #elif defined (_SILICON_LABS_32B_SERIES_2_CONFIG_2) - "CRYPTOACC_IRQn", // B0 - "TRNG_IRQn", // B1 - "PKE_IRQn", // B2 - "SMU_SECURE_IRQn", // B3 - "SMU_S_PRIVILEGED_IRQn", // B4 - "SMU_NS_PRIVILEGED_IRQn", // B5 - "EMU_IRQn", // B6 - "TIMER0_IRQn", // B7 - "TIMER1_IRQn", // B8 - "TIMER2_IRQn", // B9 - "TIMER3_IRQn", // B10 - "TIMER4_IRQn", // B11 - "RTCC_IRQn", // B12 - "USART0_RX_IRQn", // B13 - "USART0_TX_IRQn", // B14 - "USART1_RX_IRQn", // B15 - "USART1_TX_IRQn", // B16 - "ICACHE0_IRQn", // B17 - "BURTC_IRQn", // B18 - "LETIMER0_IRQn", // B19 - "SYSCFG_IRQn", // B20 - "LDMA_IRQn", // B21 - "LFXO_IRQn", // B22 - "LFRCO_IRQn", // B23 - "ULFRCO_IRQn", // B24 - "GPIO_ODD_IRQn", // B25 - "GPIO_EVEN_IRQn", // B26 - "I2C0_IRQn", // B27 - "I2C1_IRQn", // B28 - "EMUDG_IRQn", // B29 - "EMUSE_IRQn", // B30 - "AGC_IRQn", // B31 - "BUFC_IRQn", // B32 - "FRC_PRI_IRQn", // B33 - "FRC_IRQn", // B34 - "MODEM_IRQn", // B35 - "PROTIMER_IRQn", // B36 - "RAC_RSM_IRQn", // B37 - "RAC_SEQ_IRQn", // B38 - "RDMAILBOX_IRQn", // B39 - "RFSENSE_IRQn", // B40 - "PRORTC_IRQn", // B41 - "SYNTH_IRQn", // B42 - "WDOG0_IRQn", // B43 - "HFXO0_IRQn", // B44 - "HFRCO0_IRQn", // B45 - "CMU_IRQn", // B46 - "AES_IRQn", // B47 - "IADC_IRQn", // B48 - "MSC_IRQn", // B49 - "DPLL0_IRQn", // B50 - "PDM_IRQn", // B51 - "SW0_IRQn", // B52 - "SW1_IRQn", // B53 - "SW2_IRQn", // B54 - "SW3_IRQn", // B55 - "KERNEL0_IRQn", // B56 - "KERNEL1_IRQn", // B57 - "M33CTI0_IRQn", // B58 - "M33CTI1_IRQn", // B59 - "EMUEFP_IRQn", // B60 - "DCDC_IRQn", // B61 - "EUART0_RX_IRQn", // B62 - "EUART0_TX_IRQn", // B63 -#elif defined(_SILICON_LABS_32B_SERIES_2_CONFIG_3) - "SMU_SECURE_IRQn", // B0 - "SMU_S_PRIVILEGED_IRQn", // B1 - "SMU_NS_PRIVILEGED_IRQn", // B2 - "EMU_IRQn", // B3 - "TIMER0_IRQn", // B4 - "TIMER1_IRQn", // B5 - "TIMER2_IRQn", // B6 - "TIMER3_IRQn", // B7 - "TIMER4_IRQn", // B8 - "USART0_RX_IRQn", // B9 - "USART0_TX_IRQn", // B10 - "EUSART0_RX_IRQn", // B11 - "EUSART0_TX_IRQn", // B12 - "EUSART1_RX_IRQn", // B13 - "EUSART1_TX_IRQn", // B14 - "EUSART2_RX_IRQn", // B15 - "EUSART2_TX_IRQn", // B16 - "ICACHE0_IRQn", // B17 - "BURTC_IRQn", // B18 - "LETIMER0_IRQn", // B19 - "SYSCFG_IRQn", // B20 - "MPAHBRAM_IRQn", // B21 - "LDMA_IRQn", // B22 - "LFXO_IRQn", // B23 - "LFRCO_IRQn", // B24 - "ULFRCO_IRQn", // B25 - "GPIO_ODD_IRQn", // B26 - "GPIO_EVEN_IRQn", // B27 - "I2C0_IRQn", // B28 - "I2C1_IRQn", // B29 - "EMUDG_IRQn", // B30 - "AGC_IRQn", // B31 - "BUFC_IRQn", // B32 - "FRC_PRI_IRQn", // B33 - "FRC_IRQn", // B34 - "MODEM_IRQn", // B35 - "PROTIMER_IRQn", // B36 - "RAC_RSM_IRQn", // B37 - "RAC_SEQ_IRQn", // B38 - "HOSTMAILBOX_IRQn", // B39 - "SYNTH_IRQn", // B40 - "ACMP0_IRQn", // B41 - "ACMP1_IRQn", // B42 - "WDOG0_IRQn", // B43 - "WDOG1_IRQn", // B44 - "HFXO0_IRQn", // B45 - "HFRCO0_IRQn", // B46 - "HFRCOEM23_IRQn", // B47 - "CMU_IRQn", // B48 - "AES_IRQn", // B49 - "IADC_IRQn", // B50 - "MSC_IRQn", // B51 - "DPLL0_IRQn", // B52 - "EMUEFP_IRQn", // B53 - "DCDC_IRQn", // B54 - "VDAC_IRQn", // B55 - "PCNT0_IRQn", // B56 - "SW0_IRQn", // B57 - "SW1_IRQn", // B58 - "SW2_IRQn", // B59 - "SW3_IRQn", // B60 - "KERNEL0_IRQn", // B61 - "KERNEL1_IRQn", // B62 - "M33CTI0_IRQn", // B63 - "M33CTI1_IRQn", // B64 - "FPUEXH_IRQn", // B65 - "SEMBRX_IRQn", // B67 - "SEMBTX_IRQn", // B68 - "LESENSE_IRQn", // B69 - "SYSRTC_APP_IRQn", // B70 - "SYSRTC_SEQ_IRQn", // B71 - "LCD_IRQn", // B72 - "KEYSCAN_IRQn", // B73 - "RFECA0_IRQn", // B74 - "RFECA1_IRQn", // B75 -#elif defined(_SILICON_LABS_32B_SERIES_2_CONFIG_4) - "SMU_SECURE_IRQn", // B0 - "SMU_S_PRIVILEGED_IRQn", // B1 - "SMU_NS_PRIVILEGED_IRQn", // B2 - "EMU_IRQn", // B3 - "TIMER0_IRQn", // B4 - "TIMER1_IRQn", // B5 - "TIMER2_IRQn", // B6 - "TIMER3_IRQn", // B7 - "TIMER4_IRQn", // B8 - "USART0_RX_IRQn", // B9 - "USART0_TX_IRQn", // B10 - "EUSART0_RX_IRQn", // B11 - "EUSART0_TX_IRQn", // B12 - "EUSART1_RX_IRQn", // B13 - "EUSART1_TX_IRQn", // B14 - "MVP_IRQn", // B15 - "ICACHE0_IRQn", // B16 - "BURTC_IRQn", // B17 - "LETIMER0_IRQn", // B18 - "SYSCFG_IRQn", // B19 - "MPAHBRAM_IRQn", // B20 - "LDMA_IRQn", // B21 - "LFXO_IRQn", // B22 - "LFRCO_IRQn", // B23 - "ULFRCO_IRQn", // B24 - "GPIO_ODD_IRQn", // B25 - "GPIO_EVEN_IRQn", // B26 - "I2C0_IRQn", // B27 - "I2C1_IRQn", // B28 - "EMUDG_IRQn", // B29 - "AGC_IRQn", // B30 - "BUFC_IRQn", // B31 - "FRC_PRI_IRQn", // B32 - "FRC_IRQn", // B33 - "MODEM_IRQn", // B34 - "PROTIMER_IRQn", // B35 - "RAC_RSM_IRQn", // B36 - "RAC_SEQ_IRQn", // B37 - "HOSTMAILBOX_IRQn", // B38 - "SYNTH_IRQn", // B39 - "ACMP0_IRQn", // B40 - "ACMP1_IRQn", // B41 - "WDOG0_IRQn", // B42 - "WDOG1_IRQn", // B43 - "HFXO0_IRQn", // B44 - "HFRCO0_IRQn", // B45 - "HFRCOEM23_IRQn", // B46 - "CMU_IRQn", // B47 - "AES_IRQn", // B48 - "IADC_IRQn", // B49 - "MSC_IRQn", // B50 - "DPLL0_IRQn", // B51 - "EMUEFP_IRQn", // B52 - "DCDC_IRQn", // B53 - "PCNT0_IRQn", // B54 - "SW0_IRQn", // B55 - "SW1_IRQn", // B56 - "SW2_IRQn", // B57 - "SW3_IRQn", // B58 - "KERNEL0_IRQn", // B59 - "KERNEL1_IRQn", // B60 - "FPUEXH_IRQn", // B61 - "SETAMPERHOST_IRQn", // B62 - "SEMBRX_IRQn", // B63 - "SEMBTX_IRQn", // B64 - "SYSRTC_APP_IRQn", // B65 - "SYSRTC_SEQ_IRQn", // B66 - "KEYSCAN_IRQn", // B67 - "RFECA0_IRQn", // B68 - "RFECA1_IRQn", // B69 - "VDAC0_IRQn", // B70 - "VDAC1_IRQn", // B71 - "AHB2AHB0_IRQn", // B72 - "AHB2AHB1_IRQn" // B73 -#elif defined (_SILICON_LABS_32B_SERIES_2_CONFIG_7) - "CRYPTOACC_IRQn", // B0 - "TRNG_IRQn", // B1 - "PKE_IRQn", // B2 - "SMU_SECURE_IRQn", // B3 - "SMU_S_PRIVILEGED_IRQn", // B4 - "SMU_NS_PRIVILEGED_IRQn", // B5 - "EMU_IRQn", // B6 - "EMUEFP_IRQn", // B7 - "DCDC_IRQn", // B8 - "ETAMPDET_IRQn", // B9 - "TIMER0_IRQn", // B10 - "TIMER1_IRQn", // B11 - "TIMER2_IRQn", // B12 - "TIMER3_IRQn", // B13 - "TIMER4_IRQn", // B14 - "RTCC_IRQn", // B15 - "USART0_RX_IRQn", // B16 - "USART0_TX_IRQn", // B17 - "USART1_RX_IRQn", // B18 - "USART1_TX_IRQn", // B19 - "EUSART0_RX_IRQn", // B20 - "EUSART0_TX_IRQn", // B21 - "ICACHE0_IRQn", // B22 - "BURTC_IRQn", // B23 - "LETIMER0_IRQn", // B24 - "SYSCFG_IRQn", // B25 - "LDMA_IRQn", // B26 - "LFXO_IRQn", // B27 - "LFRCO_IRQn", // B28 - "ULFRCO_IRQn", // B29 - "GPIO_ODD_IRQn", // B30 - "GPIO_EVEN_IRQn", // B31 - "I2C0_IRQn", // B32 - "I2C1_IRQn", // B33 - "EMUDG_IRQn", // B34 - "EMUSE_IRQn", // B35 - "AGC_IRQn", // B36 - "BUFC_IRQn", // B37 - "FRC_PRI_IRQn", // B38 - "FRC_IRQn", // B39 - "MODEM_IRQn", // B40 - "PROTIMER_IRQn", // B41 - "RAC_RSM_IRQn", // B42 - "RAC_SEQ_IRQn", // B43 - "RDMAILBOX_IRQn", // B44 - "RFSENSE_IRQn", // B45 - "SYNTH_IRQn", // B46 - "PRORTC_IRQn", // B47 - "ACMP0_IRQn", // B48 - "WDOG0_IRQn", // B49 - "HFXO0_IRQn", // B50 - "HFRCO0_IRQn", // B51 - "CMU_IRQn", // B52 - "AES_IRQn", // B53 - "IADC_IRQn", // B54 - "MSC_IRQn", // B55 - "DPLL0_IRQn", // B56 - "PDM_IRQn", // B57 - "SW0_IRQn", // B58 - "SW1_IRQn", // B59 - "SW2_IRQn", // B60 - "SW3_IRQn", // B61 - "KERNEL0_IRQn", // B62 - "KERNEL1_IRQn", // B63 - "M33CTI0_IRQn", // B64 - "M33CTI1_IRQn", // B65 - "FPUEXH_IRQn", // B66 -#elif defined (_SILICON_LABS_32B_SERIES_2_CONFIG_8) - "SMU_SECURE_IRQn", // B0 - "SMU_S_PRIVILEGED_IRQn", // B1 - "SMU_NS_PRIVILEGED_IRQn", // B2 - "EMU_IRQn", // B3 - "TIMER0_IRQn", // B4 - "TIMER1_IRQn", // B5 - "TIMER2_IRQn", // B6 - "TIMER3_IRQn", // B7 - "TIMER4_IRQn", // B8 - "USART0_RX_IRQn", // B9 - "USART0_TX_IRQn", // B10 - "EUSART0_RX_IRQn", // B11 - "EUSART0_TX_IRQn", // B12 - "EUSART1_RX_IRQn", // B13 - "EUSART1_TX_IRQn", // B14 - "EUSART2_RX_IRQn", // B15 - "EUSART2_TX_IRQn", // B16 - "ICACHE0_IRQn", // B17 - "BURTC_IRQn", // B18 - "LETIMER0_IRQn", // B19 - "SYSCFG_IRQn", // B20 - "MPAHBRAM_IRQn", // B21 - "LDMA_IRQn", // B22 - "LFXO_IRQn", // B23 - "LFRCO_IRQn", // B24 - "ULFRCO_IRQn", // B25 - "GPIO_ODD_IRQn", // B26 - "GPIO_EVEN_IRQn", // B27 - "I2C0_IRQn", // B28 - "I2C1_IRQn", // B29 - "EMUDG_IRQn", // B30 - "AGC_IRQn", // B31 - "BUFC_IRQn", // B32 - "FRC_PRI_IRQn", // B33 - "FRC_IRQn", // B34 - "MODEM_IRQn", // B35 - "PROTIMER_IRQn", // B36 - "RAC_RSM_IRQn", // B37 - "RAC_SEQ_IRQn", // B38 - "HOSTMAILBOX_IRQn", // B39 - "SYNTH_IRQn", // B40 - "ACMP0_IRQn", // B41 - "ACMP1_IRQn", // B42 - "WDOG0_IRQn", // B43 - "WDOG1_IRQn", // B44 - "HFXO0_IRQn", // B45 - "HFRCO0_IRQn", // B46 - "HFRCOEM23_IRQn", // B47 - "CMU_IRQn", // B48 - "AES_IRQn", // B49 - "IADC_IRQn", // B50 - "MSC_IRQn", // B51 - "DPLL0_IRQn", // B52 - "EMUEFP_IRQn", // B53 - "DCDC_IRQn", // B54 - "VDAC0_IRQn", // B55 - "PCNT0_IRQn", // B56 - "SW0_IRQn", // B57 - "SW1_IRQn", // B58 - "SW2_IRQn", // B59 - "SW3_IRQn", // B60 - "KERNEL0_IRQn", // B61 - "KERNEL1_IRQn", // B62 - "M33CTI0_IRQn", // B63 - "M33CTI1_IRQn", // B64 - "FPUEXH_IRQn", // B65 - "SETAMPERHOST_IRQn", // B66 - "SEMBRX_IRQn", // B67 - "SEMBTX_IRQn", // B68 - "LESENSE_IRQn", // B69 - "SYSRTC_APP_IRQn", // B70 - "SYSRTC_SEQ_IRQn", // B71 - "LCD_IRQn", // B72 - "KEYSCAN_IRQn", // B73 - "RFECA0_IRQn", // B74 - "RFECA1_IRQn", // B75 - "AHB2AHB0_IRQn", // B76 - "AHB2AHB1_IRQn", // B77 - "MVP_IRQn", // B78 - #endif -#elif defined (CORTEXM3_EFM32_MICRO) - "DMA", // B0 - "GPIO_EVEN", // B1 - "TIMER0", // B2 - "USART0_RX", // B3 - "USART0_TX", // B4 - "USB", // B5 - "ACMP0", // B6 - "ADC0", // B7 - "DAC0", // B8 - "I2C0", // B9 - "I2C1", // B10 - "GPIO_ODD", // B11 - "TIMER1", // B12 - "TIMER2", // B13 - "TIMER3", // B14 - "USART1_RX", // B15 - "USART1_TX", // B16 - "LESENSE", // B17 - "USART2_RX", // B18 - "USART2_TX", // B19 - "UART0_RX", // B20 - "UART0_TX", // B21 - "UART1_RX", // B22 - "UART1_TX", // B23 - "LEUART0", // B24 - "LEUART1", // B25 - "LETIMER0", // B26 - "PCNT0", // B27 - "PCNT1", // B28 - "PCNT2", // B29 - "RTC", // B30 - "BURTC", // B31 - "CMU", // B32 - "VCMP", // B33 - "LCD", // B34 - "MSC", // B35 - "AES", // B36 - "EBI", // B37 - "EMU", // B38 -#else - "Timer1", // B0 - "Timer2", // B1 - "Management", // B2 - "Baseband", // B3 - "Sleep_Timer", // B4 - "SC1", // B5 - "SC2", // B6 - "Security", // B7 - "MAC_Timer", // B8 - "MAC_TX", // B9 - "MAC_RX", // B10 - "ADC", // B11 - "IRQ_A", // B12 - "IRQ_B", // B13 - "IRQ_C", // B14 - "IRQ_D", // B15 - "Debug" // B16 -#endif -}; - -// Names of raw crash data items - each name is null terminated, and the -// end of the array is flagged by two null bytes in a row. -// NOTE: the order of these names must match HalCrashInfoType members. -static const char nameStrings[] = "R0\0R1\0R2\0R3\0" - "R4\0R5\0R6\0R7\0" - "R8\0R9\0R10\0R11\0" - "R12\0R13(LR)\0MSP\0PSP\0" - "PC\0xPSR\0MSP used\0PSP used\0" - "CSTACK bottom\0ICSR\0SHCSR\0INT_ACTIVE0\0" - "INT_ACTIVE1\0" - "CFSR\0HFSR\0DFSR\0MMAR/BFAR\0AFSR\0" - "Ret0\0Ret1\0Ret2\0Ret3\0" - "Ret4\0Ret5\0Dat0\0Dat1\0"; - -static uint16_t savedResetCause; -static HalAssertInfoType savedAssertInfo; - -//------------------------------------------------------------------------------ -// Functions - -void halPrintCrashData(uint8_t port) -{ - (void)port; - uint32_t *data = (uint32_t*)&halCrashInfo.R0; - char const *name = nameStrings; - char const *separator; - uint8_t i = 0; - char outBuf[256] = {0}; - uint8_t outBufIdx = 0; - - while (*name != '\0') { - /*lint -save -e448 */ - separator = ((*name != '\0') && ((i & 3) != 3)) ? ", " : ""; - /*lint -restore */ - - outBufIdx += snprintf(outBuf+outBufIdx, sizeof outBuf,"%s = 0x%08lx%s", name, (unsigned long)*data++,separator); - - // increment pointer to end of name - while (*name != '\0') { - name++; - } - // increment past null pointer for next name - name++; - - i++; - if (!(i % 4)) - { - otLogCritPlat(outBuf); - outBufIdx = 0; - } - } - - // Print out remaining contents of outBuf - if (outBufIdx != 0) - { - otLogCritPlat(outBuf); - outBufIdx = 0; - } -} - -void halPrintCrashDetails(uint8_t port) -{ - (void)port; - - HalCrashInfoType *c = &halCrashInfo; - uint16_t reason = savedResetCause; - uint8_t bit; - const uint8_t numFaults = sizeof(cfsrBits) / sizeof(cfsrBits[0]); - - // RESET_* are defined in `reset-def.h` - switch (reason) { - case RESET_WATCHDOG_EXPIRED: - otLogCritPlat("Reset cause: Watchdog expired, no reliable extra information"); - break; - case RESET_WATCHDOG_CAUGHT: - otLogCritPlat("Reset cause: Watchdog caught with enhanced info"); - otLogCritPlat("Instruction address: %4lx", (unsigned long)c->PC); - break; - case RESET_CRASH_ASSERT: - otLogCritPlat("Reset cause: Assert %s:%ld", - c->data.assertInfo.file, (long)c->data.assertInfo.line); - break; - case RESET_FAULT_HARD: - otLogCritPlat("Reset cause: Hard Fault"); - if (c->hfsr.bits.VECTTBL) { - otLogCritPlat( "HFSR.VECTTBL: error reading vector table for an exception"); - } - if (c->hfsr.bits.FORCED) { - otLogCritPlat( "HFSR.FORCED: configurable fault could not activate"); - } - if (c->hfsr.bits.DEBUGEVT) { - otLogCritPlat( "HFSR.DEBUGEVT: fault related to debug - e.g., executed BKPT"); - } - break; - case RESET_FAULT_MEM: - otLogCritPlat("Reset cause: Memory Management Fault"); - if (c->cfsr.bits.DACCVIOL || c->cfsr.bits.IACCVIOL) { - otLogCritPlat("Instruction address: %4lx", (unsigned long)c->PC); - } - if (c->cfsr.bits.MMARVALID) { - otLogCritPlat("Illegal access address: %4lx", (unsigned long)c->faultAddress); - } - for (bit = SCB_CFSR_MEMFAULTSR_Pos; bit < (SCB_CFSR_MEMFAULTSR_Pos + 8); bit++) { - if ((c->cfsr.word & (1 << bit)) && (*cfsrBits[bit] != '\0')) { - otLogCritPlat("CFSR.%s", cfsrBits[bit]); - } - } - break; - case RESET_FAULT_BUS: - otLogCritPlat("Reset cause: Bus Fault"); - otLogCritPlat("Instruction address: %4lx", (unsigned long)c->PC); - if (c->cfsr.bits.IMPRECISERR) { - otLogCritPlat( "Address is of an instruction after bus fault occurred, not the cause."); - } - if (c->cfsr.bits.BFARVALID) { - otLogCritPlat("Illegal access address: %4lx", - (unsigned long)c->faultAddress); - } - for (bit = SCB_CFSR_BUSFAULTSR_Pos; bit < SCB_CFSR_USGFAULTSR_Pos; bit++) { - if (((c->cfsr.word >> bit) & 1U) && (*cfsrBits[bit] != '\0')) { - otLogCritPlat("CFSR.%s", cfsrBits[bit]); - } - } - if ((c->cfsr.word & 0xFF) == 0) { - otLogCritPlat("CFSR.(none) load or store at an illegal address"); - } - break; - case RESET_FAULT_USAGE: - otLogCritPlat("Reset cause: Usage Fault"); - otLogCritPlat("Instruction address: %4lx", (unsigned long)c->PC); - for (bit = SCB_CFSR_USGFAULTSR_Pos; - (bit < numFaults) && (bit < (sizeof(c->cfsr.word) * 8)); - bit++) { - if (((c->cfsr.word >> bit) & 1U) && (*cfsrBits[bit] != '\0')) { - otLogCritPlat("CFSR.%s", cfsrBits[bit]); - } - } - break; - case RESET_FAULT_DBGMON: - otLogCritPlat("Reset cause: Debug Monitor Fault"); - otLogCritPlat("Instruction address: %4lx", (unsigned long)c->PC); - break; - default: - break; - } -} - -void halPrintCrashSummary(uint8_t port) -{ - (void)port; - - HalCrashInfoType *c = &halCrashInfo; - uint32_t sp, stackBegin, stackEnd, size, used; - uint16_t pct; - uint8_t *mode; - const char *stack; - uint8_t bit; - - if (c->LR & 4) { - stack = "process"; - sp = c->processSP; - used = c->processSPUsed; - stackBegin = 0; - stackEnd = 0; - } else { - stack = "main"; - sp = c->mainSP; - used = c->mainSPUsed; - stackBegin = (uint32_t)c->mainStackBottom; - stackEnd = (uint32_t)(uint8_t *)_CSTACK_SEGMENT_END; - } - - mode = (uint8_t *)((c->LR & 8) ? "Thread" : "Handler"); - size = stackEnd - stackBegin; - pct = size ? (uint16_t)(((100 * used) + (size / 2)) / size) : 0; - otLogCritPlat("%s mode using %s stack (%4lx to %4lx), SP = %4lx", - mode, stack, (unsigned long)stackBegin, (unsigned long)stackEnd, (unsigned long)sp); - otLogCritPlat("%u bytes used (%u%%) in %s stack (out of %u bytes total)", - (uint16_t)used, pct, stack, (uint16_t)size); - - // Valid SP range is [stackBegin, stackEnd] inclusive, but contents - // of stack only go into [stackBegin, stackend). - if ((sp > stackEnd) || (sp < stackBegin)) { - otLogCritPlat("SP is outside %s stack range!", stack); - } - - if (c->intActive.word[0] || c->intActive.word[1]) { - otLogCritPlat("Interrupts active (or pre-empted and stacked):"); - for (bit = 0; bit < 32; bit++) { - if ((c->intActive.word[0] & (1 << bit)) && (*intActiveBits[bit] != '\0')) { - otLogCritPlat(" %s", intActiveBits[bit]); - } - } - for (bit = 0; bit < (sizeof(intActiveBits) / sizeof(intActiveBits[0])) - 32; bit++) { - if ((c->intActive.word[1] & (1 << bit)) && (*intActiveBits[bit + 32] != '\0')) { - otLogCritPlat(" %s", intActiveBits[bit + 32]); - } - } - } else { - otLogCritPlat("No interrupts active"); - } -} - -void halStartPCDiagnostics(void) -{ -} - -void halStopPCDiagnostics(void) -{ -} - -uint16_t halGetPCDiagnostics(void) -{ - return 0; -} - -//------------------------------------------------------------------------------ - -void halInternalClassifyReset(void) -{ - // Table used to convert from RESET_EVENT register bits to reset types - static const uint16_t resetEventTable[] = { - #if defined (_SILICON_LABS_32B_SERIES_2) - RESET_POWERON_HV, // bit 0 : POR - RESET_EXTERNAL_PIN, // bit 1 : PIN - RESET_SOFTWARE_EM4, // bit 2 : EM4 - RESET_WATCHDOG_EXPIRED, // bit 3 : WDOG0 - RESET_WATCHDOG_EXPIRED, // bit 4 : WDOG1 - RESET_FATAL_LOCKUP, // bit 5 : LOCKUP - RESET_SOFTWARE, // bit 6 : SYSREQ - RESET_BROWNOUT_DVDD, // bit 7 : DVDDBOD - RESET_UNKNOWN_UNKNOWN, // bit 8 : DVDDLEBOD // TODO: make new reset cause? - RESET_BROWNOUT_DEC, // bit 9 : DECBOD - RESET_BROWNOUT_AVDD, // bit 10 : AVDDBOD - RESET_UNKNOWN_UNKNOWN, // bit 11 : IOVDD0BOD // TODO: make new reset cause? - RESET_UNKNOWN_UNKNOWN, // bit 12 : RESERVED - RESET_UNKNOWN_UNKNOWN, // bit 13 : TAMPER // TODO: make new reset cause? - RESET_UNKNOWN_UNKNOWN, // bit 14 : M0SYSREQ // TODO: make new reset cause? - RESET_UNKNOWN_UNKNOWN, // bit 15 : M0LOCKUP // TODO: make new reset cause? - #elif defined (_EFR_DEVICE) - RESET_POWERON_HV, // bit 0: PORST - RESET_UNKNOWN_UNKNOWN, // bit 1: RESERVED - RESET_BROWNOUT_AVDD, // bit 2: AVDDBOD - RESET_BROWNOUT_DVDD, // bit 3: DVDDBOD - RESET_BROWNOUT_DEC, // bit 4: DECBOD - RESET_UNKNOWN_UNKNOWN, // bit 5: RESERVED - RESET_UNKNOWN_UNKNOWN, // bit 6: RESERVED - RESET_UNKNOWN_UNKNOWN, // bit 7: RESERVED - RESET_EXTERNAL_PIN, // bit 8: EXTRST - RESET_FATAL_LOCKUP, // bit 9: LOCKUPRST - RESET_SOFTWARE, // bit 10: SYSREQRST - RESET_WATCHDOG_EXPIRED, // bit 11: WDOGRST - RESET_UNKNOWN_UNKNOWN, // bit 12: RESERVED - RESET_UNKNOWN_UNKNOWN, // bit 13: RESERVED - RESET_UNKNOWN_UNKNOWN, // bit 14: RESERVED - RESET_UNKNOWN_UNKNOWN, // bit 15: RESERVED - RESET_SOFTWARE_EM4, // bit 16: EM4RST - #endif - }; - - uint32_t resetEvent = RMU_ResetCauseGet(); - RMU_ResetCauseClear(); - uint16_t cause = RESET_UNKNOWN; - uint16_t i; - - HalResetCauseType *resetCause = (HalResetCauseType*)(RAM_MEM_BASE); - - for (i = 0; i < sizeof(resetEventTable) / sizeof(resetEventTable[0]); i++) { - if (resetEvent & (1 << i)) { - cause = resetEventTable[i]; - break; - } - } - - if (cause == RESET_SOFTWARE) { - if ((resetCause->signature == RESET_VALID_SIGNATURE) - && (RESET_BASE_TYPE(resetCause->reason) < NUM_RESET_BASE_TYPES)) { - // The extended reset cause is recovered from RAM - // This can be trusted because the hardware reset event was software - // and additionally because the signature is valid - savedResetCause = resetCause->reason; - } else { - savedResetCause = RESET_SOFTWARE_UNKNOWN; - } - // mark the signature as invalid - resetCause->signature = RESET_INVALID_SIGNATURE; - } else if ((cause == RESET_BOOTLOADER_DEEPSLEEP) - && (resetCause->signature == RESET_VALID_SIGNATURE) - && (resetCause->reason == RESET_BOOTLOADER_DEEPSLEEP)) { - // Save the crash info for bootloader deep sleep (even though it's not used - // yet) and invalidate the reset signature. - resetCause->signature = RESET_INVALID_SIGNATURE; - savedResetCause = resetCause->reason; - } else { - savedResetCause = cause; - } - - // If the last reset was due to an assert, save the assert info. - if (savedResetCause == RESET_CRASH_ASSERT) { - savedAssertInfo = halCrashInfo.data.assertInfo; - } -} - -uint16_t halGetExtendedResetInfo(void) -{ - return savedResetCause; -} - -const HalAssertInfoType *halGetAssertInfo(void) -{ - return &savedAssertInfo; -} - -uint8_t halGetResetInfo(void) -{ - return RESET_BASE_TYPE(savedResetCause); -} - -// Translate EM3xx reset codes to the codes previously used by the EM2xx. -// If there is no corresponding code, return the EM3xx base code with bit 7 set. -uint8_t halGetEm2xxResetInfo(void) -{ - uint8_t reset = halGetResetInfo(); - - // Any reset with an extended value field of zero is considered an unknown - // reset, except for FIB resets. - if ((RESET_EXTENDED_FIELD(halGetExtendedResetInfo()) == 0) - && (reset != RESET_FIB)) { - return EM2XX_RESET_UNKNOWN; - } - - switch (reset) { - case RESET_UNKNOWN: - return EM2XX_RESET_UNKNOWN; - case RESET_BOOTLOADER: - return EM2XX_RESET_BOOTLOADER; - case RESET_EXTERNAL: // map pin resets to poweron for EM2xx compatibility -// return EM2XX_RESET_EXTERNAL; - case RESET_POWERON: - return EM2XX_RESET_POWERON; - case RESET_WATCHDOG: - return EM2XX_RESET_WATCHDOG; - case RESET_SOFTWARE: - return EM2XX_RESET_SOFTWARE; - case RESET_CRASH: - return EM2XX_RESET_ASSERT; - default: - return (reset | 0x80); // set B7 for all other reset codes - } -} - -const char * halGetResetString(void) -{ - // Table used to convert from reset types to reset strings. - #define RESET_BASE_DEF(basename, value, string) string, - #define RESET_EXT_DEF(basename, extname, extvalue, string) /*nothing*/ - static const char resetStringTable[][4] = { - #include "reset-def.h" - }; - #undef RESET_BASE_DEF - #undef RESET_EXT_DEF - uint8_t resetInfo = halGetResetInfo(); - if (resetInfo >= (sizeof(resetStringTable) / sizeof(resetStringTable[0]))) { - return resetStringTable[0x00]; // return unknown - } else { - return resetStringTable[resetInfo]; - } -} - -const char * halGetExtendedResetString(void) -{ - // Create a table of reset strings for each extended reset type - typedef const char ResetStringTableType[][4]; - #define RESET_BASE_DEF(basename, value, string) \ - }; static ResetStringTableType basename##ResetStringTable = { - #define RESET_EXT_DEF(basename, extname, extvalue, string) string, - { - #include "reset-def.h" - }; - #undef RESET_BASE_DEF - #undef RESET_EXT_DEF - - // Create a table of pointers to each of the above tables - #define RESET_BASE_DEF(basename, value, string) (ResetStringTableType *)basename##ResetStringTable, - #define RESET_EXT_DEF(basename, extname, extvalue, string) /*nothing*/ - static ResetStringTableType * const extendedResetStringTablePtrs[] = { - #include "reset-def.h" - }; - #undef RESET_BASE_DEF - #undef RESET_EXT_DEF - - uint16_t extResetInfo = halGetExtendedResetInfo(); - // access the particular table of extended strings we are interested in - ResetStringTableType *extendedResetStringTable = - extendedResetStringTablePtrs[RESET_BASE_TYPE(extResetInfo)]; - - // return the string from within the proper table - return (*extendedResetStringTable)[((extResetInfo) & 0xFF)]; -} - -#if _SILICON_LABS_GECKO_INTERNAL_SDID == 80 - -// Workaround for brownouts on Dumbo when DCDC is retimed and radio subsystem is reset -__STATIC_INLINE void disableDcdcRetimingAndRcosync(void) -{ - // Ensure access to EMU registers - EMU_Unlock(); - EMU_PowerUnlock(); - - // Don't need to disable retiming if DCDC is not powering DVDD - if ((EMU->PWRCFG & _EMU_PWRCFG_PWRCFG_MASK) != EMU_PWRCFG_PWRCFG_DCDCTODVDD) { - return; - } - - // Ensure sequencer is halted - uint32_t clockEnable = *(volatile uint32_t *)(0x400E4000 + 0xC8); - volatile uint32_t *reg; - - if (clockEnable & 0x4UL) { - reg = (volatile uint32_t *)(0x40084000UL + 0x40); - *reg = 0x1UL; - } - - // If DCDC is in use, ensure retiming and rcosync are disabled - uint32_t dcdcMode = EMU->DCDCCTRL & _EMU_DCDCCTRL_DCDCMODE_MASK; - if ((dcdcMode == EMU_DCDCCTRL_DCDCMODE_LOWNOISE) - || (dcdcMode == EMU_DCDCCTRL_DCDCMODE_LOWPOWER)) { - BUS_RegBitWrite(&EMU->DCDCTIMING, 28, 0); - // EMU->DCDCRCOSC is internal, _EMU_DCDCRCOSC_RCOSYNC_SHIFT = 0 - BUS_RegBitWrite((void *)(EMU_BASE + 0x74), 0, 0); - } -} - -#else - -// Workaround not needed for dies other than Dumbo -#define disableDcdcRetimingAndRcosync() ((void)0) - -#endif - -void halInternalSysReset(uint16_t extendedCause) -{ - HalResetCauseType *resetCause = (HalResetCauseType*)(RAM_MEM_BASE); - INTERRUPTS_OFF(); - // Ensure DCDC settings are compatible with the upcoming radio subsystem reset - disableDcdcRetimingAndRcosync(); - - resetCause->reason = extendedCause; - resetCause->signature = RESET_VALID_SIGNATURE; - // force write to complete before reset - asm ("DMB"); - NVIC_SystemReset(); -} - -// Cause a usage fault by executing a special UNDEFINED instruction. -// The high byte (0xDE) is reserved to be undefined - the low byte (0x42) -// is arbitrary and distiguishes a failed assert from other usage faults. -// the fault handler with then decode this, grab the filename and linenumber -// parameters from R0 and R1 and save the information for display after a reset -#if defined (__ICCARM__) -#pragma diag_suppress=Og014 -static void halInternalAssertFault(const char * filename, int linenumber) -{ - asm ("DC16 0DE42h"); -} -#pragma diag_default=Og014 -#elif defined (__GNUC__) -__attribute__((noinline)) -static void halInternalAssertFault(const char * filename, int linenumber) -{ - asm (".short 0xDE42" : : "r" (filename), "r" (linenumber)); -} -#endif - -void halInternalAssertFailed(const char * filename, int linenumber) -{ - INTERRUPTS_OFF(); - - otLogCritPlat("\r\n[ASSERT:%s:%d]\r", filename, linenumber); - -#if defined (__ICCARM__) || defined (__GNUC__) - // We can use the special fault mechanism to preserve more assert - // information for display after a crash - halInternalAssertFault(filename, linenumber); -#else - // Other toolchains don't handle the inline assembly correctly, so - // we just call the internal reset - halCrashInfo.data.assertInfo.file = filename; - halCrashInfo.data.assertInfo.line = linenumber; - halInternalSysReset(RESET_CRASH_ASSERT); -#endif -} - -// Returns the bytes used in the main stack area. -static uint32_t halInternalGetMainStackBytesUsed(uint32_t *p) -{ - for (; p < (uint32_t *)_CSTACK_SEGMENT_END; p++) { - if (*p != STACK_FILL_VALUE) { - break; - } - } - return (uint32_t)((uint8_t *)_CSTACK_SEGMENT_END - (uint8_t *)p); -} - -// After the low-level fault handler (in faults.s79) has saved the processor -// registers (R0-R12, LR and both MSP an PSP), it calls halInternalCrashHandler -// to finish saving additional crash data. This function returns the reason for -// the crash to the low-level fault handler that then calls -// halInternalSystsemReset() to reset the processor. -uint16_t halInternalCrashHandler(void) -{ - uint32_t activeException; - uint16_t reason = (uint16_t)RESET_FAULT_UNKNOWN; - HalCrashInfoType *c = &halCrashInfo; - uint8_t i, j; - uint32_t *sp, *s, *sEnd, *stackBottom, *stackTop; - uint32_t data; - - c->icsr.word = SCB->ICSR; - c->shcsr.word = SCB->SHCSR; - - c->intActive.word[0] = NVIC->IABR[0]; - c->intActive.word[1] = NVIC->IABR[1]; - - c->cfsr.word = SCB->CFSR; - c->hfsr.word = SCB->HFSR; - c->dfsr.word = SCB->DFSR; - c->faultAddress = SCB->MMFAR; - c->afsr.word = SCB->AFSR; - - // Examine B2 of the saved LR to know the stack in use when the fault occurred - sp = (uint32_t *)(((c->LR & 4U) != 0U) ? c->processSP : c->mainSP); - sEnd = sp; // Keep a copy around for walking the stack later - - // Get the bottom of the stack since we allow stack resizing - c->mainStackBottom = (uint32_t)_CSTACK_SEGMENT_BEGIN; - - // If we're running FreeRTOS and this is a process stack then add - // extra diagnostic information - if ((freeRTOS != 0) && ((c->LR & 4U) != 0U)) { - stackBottom = sp; - stackTop = sp + 8; - c->processSPUsed = stackTop - sp; - } else { - stackBottom = (uint32_t*)c->mainStackBottom; - stackTop = (uint32_t*)_CSTACK_SEGMENT_END; - c->processSPUsed = 0; // process stack not in use - } - - // If the stack pointer is valid, read and save the stacked PC and xPSR - if ((sp >= stackBottom) - && ((sp + 8) <= stackTop)) { - sp += 6; // Skip over R0,R1,R2,R3,R12,LR - c->PC = *sp++; - c->xPSR.word = *sp++; - - // See if fault was due to a failed assert. This is indicated by - // a usage fault caused by executing a reserved instruction. - if ( c->icsr.bits.VECTACTIVE == USAGE_FAULT_VECTOR_INDEX - && ((uint16_t *)c->PC >= (uint16_t *)_TEXT_SEGMENT_BEGIN) - && ((uint16_t *)c->PC < (uint16_t *)_TEXT_SEGMENT_END) - && *(uint16_t *)(c->PC) == ASSERT_USAGE_OPCODE ) { - // Copy halInternalAssertFailed() arguments into data member specific - // to asserts. - c->data.assertInfo.file = (const char *)c->R0; - c->data.assertInfo.line = c->R1; -#ifdef PUSH_REGS_BEFORE_ASSERT - // Just before calling halInternalAssertFailed(), R0, R1, R2 and LR were - // pushed onto the stack - copy these values into the crash data struct. - c->R0 = *sp++; - c->R1 = *sp++; - c->R2 = *sp++; - c->LR = *sp++; -#endif - reason = (uint16_t)RESET_CRASH_ASSERT; - } - // If a bad stack pointer, PC and xPSR to 0 to indicate they are not known. - } else { - c->PC = 0; - c->xPSR.word = 0; - sEnd = stackBottom; - } - - c->mainSPUsed = halInternalGetMainStackBytesUsed((uint32_t*)c->mainStackBottom); - - for (i = 0; i < NUM_RETURNS; i++) { - c->returns[i] = 0; - } - - // Search the stack downward for probable return addresses. A probable - // return address is a value in the CODE segment that also has bit 0 set - // (since we're in Thumb mode). - i = 0U; - s = stackTop; - while (s > sEnd) { - data = *(--s); - if (((uint16_t *)data >= (uint16_t *)_TEXT_SEGMENT_BEGIN) - && ((uint16_t *)data < (uint16_t *)_TEXT_SEGMENT_END) - && ((data & 1U) != 0U)) { - // Only record the first occurrence of a return - other copies could - // have been in registers that then were pushed. - for (j = 0; j < NUM_RETURNS; j++) { - if (c->returns[j] == data) { - break; - } - } - if (j != NUM_RETURNS) { - continue; - } - // Save the return in the returns array managed as a circular buffer. - // This keeps only the last NUM_RETURNS in the event that there are more. - i = (i != 0U) ? i - 1U : NUM_RETURNS - 1U; - c->returns[i] = data; - } - } - // Shuffle the returns array so returns[0] has last probable return found. - // If there were fewer than NUM_RETURNS, unused entries will contain zero. - while ((i--) != 0U) { - data = c->returns[0]; - for (j = 0; j < NUM_RETURNS - 1U; j++ ) { - c->returns[j] = c->returns[j + 1U]; - } - c->returns[NUM_RETURNS - 1U] = data; - } - - // Read the highest priority active exception to get reason for fault - activeException = c->icsr.bits.VECTACTIVE; - switch (activeException) { - #if defined(WDOG_IF_WARN) && !defined(BOOTLOADER) - case IRQ_TO_VECTOR_NUMBER(WDOG0_IRQn): - if (WDOG0->IF & WDOG_IF_WARN) { - reason = RESET_WATCHDOG_CAUGHT; - } - break; - #endif - case HARD_FAULT_VECTOR_INDEX: - reason = (uint16_t)RESET_FAULT_HARD; - break; - case MEMORY_FAULT_VECTOR_INDEX: - reason = (uint16_t)RESET_FAULT_MEM; - break; - case BUS_FAULT_VECTOR_INDEX: - reason = (uint16_t)RESET_FAULT_BUS; - break; - case USAGE_FAULT_VECTOR_INDEX: - // make sure we didn't already identify the usage fault as an assert - if (reason == (uint16_t)RESET_FAULT_UNKNOWN) { - reason = (uint16_t)RESET_FAULT_USAGE; - } - break; - case DEBUG_MONITOR_VECTOR_INDEX: - reason = (uint16_t)RESET_FAULT_DBGMON; - break; - default: - if ((activeException != 0U) && (activeException < VECTOR_TABLE_LENGTH)) { - reason = (uint16_t)RESET_FAULT_BADVECTOR; - } - break; - } - return reason; -}