diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d3b9ad3e..1811f6fc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -50,18 +50,12 @@ jobs: fail-fast: false matrix: include: - - gcc_ver: 6 - gcc_download_url: https://developer.arm.com/-/media/Files/downloads/gnu-rm/6-2017q2/gcc-arm-none-eabi-6-2017-q2-update-linux.tar.bz2 - gcc_extract_dir: gcc-arm-none-eabi-6-2017-q2-update - - gcc_ver: 7 - gcc_download_url: https://developer.arm.com/-/media/Files/downloads/gnu-rm/7-2018q2/gcc-arm-none-eabi-7-2018-q2-update-linux.tar.bz2 - gcc_extract_dir: gcc-arm-none-eabi-7-2018-q2-update - - gcc_ver: 9 - gcc_download_url: https://developer.arm.com/-/media/Files/downloads/gnu-rm/9-2019q4/RC2.1/gcc-arm-none-eabi-9-2019-q4-major-x86_64-linux.tar.bz2 - gcc_extract_dir: gcc-arm-none-eabi-9-2019-q4-major - - gcc_ver: 10.3 - gcc_download_url: https://developer.arm.com/-/media/Files/downloads/gnu-rm/10.3-2021.10/gcc-arm-none-eabi-10.3-2021.10-x86_64-linux.tar.bz2 - gcc_extract_dir: gcc-arm-none-eabi-10.3-2021.10 + - gcc_ver: 12.2.Rel1 + gcc_download_url: https://developer.arm.com/-/media/Files/downloads/gnu/12.2.rel1/binrel/arm-gnu-toolchain-12.2.rel1-x86_64-arm-none-eabi.tar.xz + gcc_extract_dir: arm-gnu-toolchain-12.2.rel1-x86_64-arm-none-eabi + - gcc_ver: 12.3.Rel1 + gcc_download_url: https://developer.arm.com/-/media/Files/downloads/gnu/12.3.rel1/binrel/arm-gnu-toolchain-12.3.rel1-x86_64-arm-none-eabi.tar.xz + gcc_extract_dir: arm-gnu-toolchain-12.3.rel1-x86_64-arm-none-eabi steps: - uses: actions/checkout@v4 @@ -83,13 +77,12 @@ jobs: - name: Bootstrap run: | - cd /tmp - wget --tries 4 --no-check-certificate --quiet ${{ matrix.gcc_download_url }} -O gcc-arm.tar.bz2 - tar xjf gcc-arm.tar.bz2 + script/bootstrap packages + script/bootstrap arm_toolchain ${{ matrix.gcc_download_url }} ${{ matrix.gcc_extract_dir }} - name: Build run: | - export PATH=/tmp/${{ matrix.gcc_extract_dir }}/bin:$PATH + export PATH=${HOME}/.local/${{ matrix.gcc_extract_dir }}/bin:$PATH script/test - name: Gather SLC generated files @@ -107,5 +100,5 @@ jobs: - uses: actions/upload-artifact@v4 if: failure() with: - name: build-${{ matrix.gcc_ver }}-${{ matrix.os }} + name: build-${{ matrix.gcc_ver }} path: artifact diff --git a/examples/example_vendor_slc_extension/projects/example-vendor-rcp-spi.slcp b/examples/example_vendor_slc_extension/projects/example-vendor-rcp-spi.slcp index b73660f1..0f6def10 100644 --- a/examples/example_vendor_slc_extension/projects/example-vendor-rcp-spi.slcp +++ b/examples/example_vendor_slc_extension/projects/example-vendor-rcp-spi.slcp @@ -35,7 +35,9 @@ quality: production component: - id: ot_platform_abstraction_core - - id: ot_thirdparty + - id: ot_mbedtls + - id: ot_stack_features_config + from: ot-efr32 - id: ot_ncp_spidrv - id: rail_util_pti 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 aad90227..d49e8336 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,7 +35,9 @@ quality: production component: - id: ot_platform_abstraction_core - - id: ot_thirdparty + - id: ot_mbedtls + - id: ot_stack_features_config + from: ot-efr32 - id: uartdrv_usart instance: - vcom diff --git a/examples/example_vendor_slc_extension/projects/example-vendor-soc-with-buttons.slcp b/examples/example_vendor_slc_extension/projects/example-vendor-soc-with-buttons.slcp index 4c5749f7..c4a4f93e 100644 --- a/examples/example_vendor_slc_extension/projects/example-vendor-soc-with-buttons.slcp +++ b/examples/example_vendor_slc_extension/projects/example-vendor-soc-with-buttons.slcp @@ -36,7 +36,9 @@ quality: production component: - id: ot_platform_abstraction_core - id: ot_psa_crypto - - id: ot_thirdparty + - id: ot_mbedtls + - id: ot_stack_features_config + from: ot-efr32 - id: uartdrv_usart instance: - vcom diff --git a/examples/example_vendor_slc_extension/projects/example-vendor-soc.slcp b/examples/example_vendor_slc_extension/projects/example-vendor-soc.slcp index 7d2e8e1a..7c214c8f 100644 --- a/examples/example_vendor_slc_extension/projects/example-vendor-soc.slcp +++ b/examples/example_vendor_slc_extension/projects/example-vendor-soc.slcp @@ -36,7 +36,9 @@ quality: production component: - id: ot_platform_abstraction_core - id: ot_psa_crypto - - id: ot_thirdparty + - id: ot_mbedtls + - id: ot_stack_features_config + from: ot-efr32 - id: uartdrv_usart instance: - vcom diff --git a/openthread b/openthread index 5cab1584..3400692b 160000 --- a/openthread +++ b/openthread @@ -1 +1 @@ -Subproject commit 5cab15840df7dddd9d2578106bde3067ad45bbae +Subproject commit 3400692b03044b9c673d3e015c24f9c0cd7cb404 diff --git a/ot-efr32.slce b/ot-efr32.slce index 93734ad5..4dd1da9d 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" -label: "Silicon Labs Matter" +label: "Silicon Labs OpenThread" sdk: id: gecko_sdk - version: 4.2.1 + version: 4.4.0 component_path: - path: slc/component diff --git a/script/bootstrap b/script/bootstrap index b4c1bbc2..260d512e 100755 --- a/script/bootstrap +++ b/script/bootstrap @@ -55,7 +55,8 @@ install_packages_apt() python3-pip \ git-lfs \ unzip \ - wget + wget \ + xz-utils } install_packages_opkg() @@ -118,6 +119,38 @@ do_bootstrap_silabs() echo "Bootstrapping silabs" "${repo_dir}"/script/bootstrap_silabs } + +install_arm_toolchain() +{ + local url=${1-"https://developer.arm.com/-/media/Files/downloads/gnu/12.2.rel1/binrel/arm-gnu-toolchain-12.2.rel1-x86_64-arm-none-eabi.tar.xz"} + local extract_dir=${2-"arm-gnu-toolchain-12.2.rel1-x86_64-arm-none-eabi"} + + local toolchain_dir="${HOME}/.local" + + # Check if the toolchain is already present at the desired location + if command -v "${toolchain_dir}/${extract_dir}/bin/arm-none-eabi-gcc"; then + echo "'arm-none-eabi-gcc' found. Skipping GNU ARM Embedded toolchain install" + "${toolchain_dir}"/"${extract_dir}"/bin/arm-none-eabi-gcc --version + return + fi + + echo 'Installing GNU ARM Embedded Toolchain...' + + # Download + local tarball=gcc-arm.tar.xz + mkdir -p "${toolchain_dir}/${extract_dir}" + wget --tries 4 --no-check-certificate --quiet "${url}" -O "${toolchain_dir}/${tarball}" + + # Extract + tar xf "${toolchain_dir}/${tarball}" --directory "${toolchain_dir}/${extract_dir}" --strip-components=1 + + # Link + sudo ln -s -f "${toolchain_dir}"/"${extract_dir}"/bin/* /usr/local/bin/ + + # Cleanup + rm -rf "${toolchain_dir:?}/${tarball:?}" +} + main() { if [ $# == 0 ]; then @@ -126,6 +159,9 @@ main() do_bootstrap_silabs elif [ "$1" == 'packages' ]; then install_packages + elif [ "$1" == 'arm_toolchain' ]; then + shift 1 + install_arm_toolchain "$@" elif [ "$1" == 'openthread' ]; then do_bootstrap_openthread elif [ "$1" == 'python' ]; then diff --git a/slc/component/ot_stack_features_config.slcc b/slc/component/ot_stack_features_config.slcc new file mode 100644 index 00000000..a3e64dee --- /dev/null +++ b/slc/component/ot_stack_features_config.slcc @@ -0,0 +1,24 @@ +id: ot_stack_features_config +label: Stack Features Config +package: OpenThread +category: OpenThread +quality: production +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 + file_id: openthread_features + unless: [ot_reference_device] + - path: third_party/silabs/gecko_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 +define: + - name: SL_OPENTHREAD_STACK_FEATURES_CONFIG_FILE + value: "\"sl_openthread_features_config.h\"" + unless: [ot_reference_device] + - name: SL_OPENTHREAD_STACK_FEATURES_CONFIG_FILE + value: "\"sl_openthread_reference_device_config.h\"" + condition: [ot_reference_device] diff --git a/src/platform_projects/openthread-efr32-rcp-spi.slcp b/src/platform_projects/openthread-efr32-rcp-spi.slcp index 55438b9d..e5071802 100644 --- a/src/platform_projects/openthread-efr32-rcp-spi.slcp +++ b/src/platform_projects/openthread-efr32-rcp-spi.slcp @@ -7,7 +7,9 @@ quality: production component: - id: ot_platform_abstraction_core - - id: ot_thirdparty + - id: ot_mbedtls + - id: ot_stack_features_config + from: ot-efr32 - id: ot_ncp_spidrv - id: rail_util_pti @@ -20,3 +22,7 @@ define: value: 1 - name: OPENTHREAD_RADIO value: 1 + +sdk_extension: +- id: ot-efr32 + version: 0.0.1 diff --git a/src/platform_projects/openthread-efr32-rcp-uart.slcp b/src/platform_projects/openthread-efr32-rcp-uart.slcp index 616a6ea3..7b3a2833 100644 --- a/src/platform_projects/openthread-efr32-rcp-uart.slcp +++ b/src/platform_projects/openthread-efr32-rcp-uart.slcp @@ -7,7 +7,9 @@ quality: production component: - id: ot_platform_abstraction_core - - id: ot_thirdparty + - id: ot_mbedtls + - id: ot_stack_features_config + from: ot-efr32 - id: uartdrv_usart instance: - vcom @@ -22,3 +24,7 @@ define: value: 1 - name: OPENTHREAD_RADIO value: 1 + +sdk_extension: + - id: ot-efr32 + version: 0.0.1 diff --git a/src/platform_projects/openthread-efr32-soc-with-buttons-power-manager-csl.slcp b/src/platform_projects/openthread-efr32-soc-with-buttons-power-manager-csl.slcp index 9c9d4aa2..e11cbf77 100644 --- a/src/platform_projects/openthread-efr32-soc-with-buttons-power-manager-csl.slcp +++ b/src/platform_projects/openthread-efr32-soc-with-buttons-power-manager-csl.slcp @@ -9,7 +9,9 @@ quality: production component: - id: ot_platform_abstraction_core - id: ot_psa_crypto - - id: ot_thirdparty + - id: ot_mbedtls + - id: ot_stack_features_config + from: ot-efr32 - id: uartdrv_usart instance: - vcom @@ -53,3 +55,7 @@ configuration: define: - name: OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE value: 1 + +sdk_extension: + - id: ot-efr32 + version: 0.0.1 diff --git a/src/platform_projects/openthread-efr32-soc-with-buttons-power-manager.slcp b/src/platform_projects/openthread-efr32-soc-with-buttons-power-manager.slcp index dbbfae3b..49fe6e0f 100644 --- a/src/platform_projects/openthread-efr32-soc-with-buttons-power-manager.slcp +++ b/src/platform_projects/openthread-efr32-soc-with-buttons-power-manager.slcp @@ -9,7 +9,9 @@ quality: production component: - id: ot_platform_abstraction_core - id: ot_psa_crypto - - id: ot_thirdparty + - id: ot_mbedtls + - id: ot_stack_features_config + from: ot-efr32 - id: uartdrv_usart instance: - vcom @@ -49,3 +51,7 @@ configuration: condition: [freertos] - name: SL_STACK_SIZE value: 4608 + +sdk_extension: + - id: ot-efr32 + version: 0.0.1 diff --git a/src/platform_projects/openthread-efr32-soc-with-buttons.slcp b/src/platform_projects/openthread-efr32-soc-with-buttons.slcp index f834e078..931829e9 100644 --- a/src/platform_projects/openthread-efr32-soc-with-buttons.slcp +++ b/src/platform_projects/openthread-efr32-soc-with-buttons.slcp @@ -9,7 +9,9 @@ quality: production component: - id: ot_platform_abstraction_core - id: ot_psa_crypto - - id: ot_thirdparty + - id: ot_mbedtls + - id: ot_stack_features_config + from: ot-efr32 - id: uartdrv_usart instance: - vcom @@ -48,3 +50,7 @@ configuration: condition: [freertos] - name: SL_STACK_SIZE value: 4608 + +sdk_extension: + - id: ot-efr32 + version: 0.0.1 diff --git a/src/platform_projects/openthread-efr32-soc.slcp b/src/platform_projects/openthread-efr32-soc.slcp index 2fdd99c0..3d995ea3 100644 --- a/src/platform_projects/openthread-efr32-soc.slcp +++ b/src/platform_projects/openthread-efr32-soc.slcp @@ -8,7 +8,9 @@ quality: production component: - id: ot_platform_abstraction_core - id: ot_psa_crypto - - id: ot_thirdparty + - id: ot_mbedtls + - id: ot_stack_features_config + from: ot-efr32 - id: uartdrv_usart instance: - vcom @@ -35,3 +37,7 @@ configuration: condition: [freertos] - name: SL_STACK_SIZE value: 4608 + +sdk_extension: + - id: ot-efr32 + version: 0.0.1 diff --git a/src/src/alarm.c b/src/src/alarm.c index e943d6ba..9e814b79 100644 --- a/src/src/alarm.c +++ b/src/src/alarm.c @@ -32,6 +32,7 @@ * */ +#include #include #include #include diff --git a/src/src/crypto.c b/src/src/crypto.c index dd6b0ca6..47c0f3dd 100644 --- a/src/src/crypto.c +++ b/src/src/crypto.c @@ -35,8 +35,12 @@ #include #include #include +#include "common/debug.hpp" #include "utils/code_utils.h" +#include "em_device.h" +#include "em_system.h" +#include "sl_psa_crypto.h" #include #include #include @@ -44,6 +48,9 @@ #if OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA +#define PERSISTENCE_KEY_ID_USED_MAX (7) +#define MAX_HMAC_KEY_SIZE (32) + // Helper function to convert otCryptoKeyType to psa_key_type_t static psa_key_type_t getPsaKeyType(otCryptoKeyType aKeyType) { @@ -134,20 +141,62 @@ static psa_key_persistence_t getPsaKeyPersistence(otCryptoKeyStorage aKeyPersist switch (aKeyPersistence) { case OT_CRYPTO_KEY_STORAGE_VOLATILE: - aPsaKeyPersistence = PSA_KEY_LIFETIME_VOLATILE; + aPsaKeyPersistence = PSA_KEY_PERSISTENCE_VOLATILE; break; case OT_CRYPTO_KEY_STORAGE_PERSISTENT: - aPsaKeyPersistence = PSA_KEY_LIFETIME_PERSISTENT; + aPsaKeyPersistence = PSA_KEY_PERSISTENCE_DEFAULT; break; } return aPsaKeyPersistence; } +#if defined(SEMAILBOX_PRESENT) && !defined(SL_TRUSTZONE_NONSECURE) +static bool shouldWrap(psa_key_attributes_t *key_attr) +{ + psa_key_location_t keyLocation = PSA_KEY_LIFETIME_GET_LOCATION(psa_get_key_lifetime(key_attr)); + psa_key_type_t keyType = psa_get_key_type(key_attr); + + return ((keyLocation != SL_PSA_KEY_LOCATION_WRAPPED) && (keyType != PSA_KEY_TYPE_HMAC)); +} + +static void checkAndWrapKeys(void) +{ + for (int index = 1; index <= PERSISTENCE_KEY_ID_USED_MAX; index++) + { + otCryptoKeyRef key_ref = OPENTHREAD_CONFIG_PSA_ITS_NVM_OFFSET + index; + psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT; + + // If there is a key present in the location.. + if (sl_sec_man_get_key_attributes(key_ref, &key_attr) == PSA_SUCCESS) + { + if (shouldWrap(&key_attr)) + { + // Wrap the key.. + otCryptoKeyRef dst_key_ref = key_ref; + psa_key_lifetime_t key_lifetime = + PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(PSA_KEY_PERSISTENCE_DEFAULT, + SL_PSA_KEY_LOCATION_WRAPPED); + + psa_set_key_lifetime(&key_attr, key_lifetime); + sl_sec_man_copy_key(key_ref, &key_attr, &dst_key_ref); + } + } + } +} +#endif // SEMAILBOX_PRESENT && !SL_TRUSTZONE_NONSECURE + void otPlatCryptoInit(void) { (void)sl_sec_man_init(); + +#if defined(SEMAILBOX_PRESENT) && !defined(SL_TRUSTZONE_NONSECURE) + if (SYSTEM_GetSecurityCapability() == securityCapabilityVault) + { + checkAndWrapKeys(); + } +#endif } static otError extractPrivateKeyFromDer(uint8_t *aPrivateKey, const uint8_t *aDer, uint8_t aDerLen) @@ -312,16 +361,61 @@ otError otPlatCryptoHmacSha256Deinit(otCryptoContext *aContext) return error; } +static psa_status_t reImportUnwrapped(const otCryptoKey *aKey, otCryptoKeyRef *aHmacKeyRef) +{ + psa_status_t status = PSA_SUCCESS; + +#if defined(SEMAILBOX_PRESENT) + uint8_t hmacKeyBytes[MAX_HMAC_KEY_SIZE]; + size_t key_size; + psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT; + + status = sl_sec_man_get_key_attributes(aKey->mKeyRef, &key_attr); + + otEXPECT(status == PSA_SUCCESS); + + status = sl_sec_man_export_key(aKey->mKeyRef, hmacKeyBytes, sizeof(hmacKeyBytes), &key_size); + + otEXPECT(status == PSA_SUCCESS); + + status = sl_sec_man_import_key(aHmacKeyRef, + psa_get_key_type(&key_attr), + psa_get_key_algorithm(&key_attr), + psa_get_key_usage_flags(&key_attr), + PSA_KEY_PERSISTENCE_VOLATILE, + hmacKeyBytes, + key_size); + + memset(hmacKeyBytes, 0, sizeof(hmacKeyBytes)); + + otEXPECT(status == PSA_SUCCESS); + +exit: +#else + *aHmacKeyRef = aKey->mKeyRef; +#endif + return status; +} + otError otPlatCryptoHmacSha256Start(otCryptoContext *aContext, const otCryptoKey *aKey) { otError error = OT_ERROR_NONE; psa_mac_operation_t *mMacOperation = (psa_mac_operation_t *)aContext->mContext; psa_status_t status; + otCryptoKeyRef hmacKeyRef; - status = sl_sec_man_hmac_start(mMacOperation, aKey->mKeyRef); + status = reImportUnwrapped(aKey, &hmacKeyRef); + otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED); + status = sl_sec_man_hmac_start(mMacOperation, hmacKeyRef); otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED); +#if defined(SEMAILBOX_PRESENT) + sl_sec_man_destroy_key(hmacKeyRef); +#else + hmacKeyRef = 0; +#endif + exit: return error; } @@ -555,4 +649,85 @@ otError otPlatCryptoEcdsaVerifyUsingKeyRef(otCryptoKeyRef aKe return error; } +otError otPlatCryptoPbkdf2GenerateKey(const uint8_t *aPassword, + uint16_t aPasswordLen, + const uint8_t *aSalt, + uint16_t aSaltLen, + uint32_t aIterationCounter, + uint16_t aKeyLen, + uint8_t *aKey) +{ + otError error = OT_ERROR_NONE; + psa_status_t status; + size_t outSize; + psa_key_id_t passwordKeyId = 0; + psa_key_id_t saltKeyId = 0; + psa_key_id_t keyId = 0; + + // Algorithm is PBKDF2-AES-CMAC-PRF-128 + psa_algorithm_t algo = PSA_ALG_PBKDF2_AES_CMAC_PRF_128; + + // 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); + + // Set capacity + status = psa_key_derivation_set_capacity(&operation, aKeyLen); + 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); + + // 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); + + status = psa_import_key(&saltKeyAttr, aSalt, aSaltLen, &saltKeyId); + 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); + + // Create key for password (key) + psa_key_attributes_t passwordKeyAttr = psa_key_attributes_init(); + psa_set_key_usage_flags(&passwordKeyAttr, PSA_KEY_USAGE_DERIVE); + psa_set_key_type(&passwordKeyAttr, PSA_KEY_TYPE_PASSWORD); + psa_set_key_algorithm(&passwordKeyAttr, algo); + + status = psa_import_key(&passwordKeyAttr, aPassword, aPasswordLen, &passwordKeyId); + 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); + + // Configure output as a key + psa_key_attributes_t keyAttrResult = psa_key_attributes_init(); + psa_set_key_bits(&keyAttrResult, (8 * aKeyLen)); + psa_set_key_usage_flags(&keyAttrResult, PSA_KEY_USAGE_EXPORT); + psa_set_key_type(&keyAttrResult, PSA_KEY_TYPE_RAW_DATA); + 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); + + // Export output key + status = psa_export_key(keyId, aKey, aKeyLen, &outSize); + otEXPECT_ACTION(status == PSA_SUCCESS, error = OT_ERROR_FAILED); + + // Release keys used + psa_destroy_key(keyId); + psa_destroy_key(saltKeyId); + psa_destroy_key(passwordKeyId); + +exit: + return error; +} + #endif // OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE diff --git a/src/src/diag.c b/src/src/diag.c index 631fb6cd..cd15f47f 100644 --- a/src/src/diag.c +++ b/src/src/diag.c @@ -32,6 +32,7 @@ * */ +#include #include #include #include diff --git a/src/src/ieee802154-packet-utils.cpp b/src/src/ieee802154-packet-utils.cpp index 89c4bb5f..f1ac34e2 100644 --- a/src/src/ieee802154-packet-utils.cpp +++ b/src/src/ieee802154-packet-utils.cpp @@ -39,6 +39,7 @@ #include "sl_packet_utils.h" #include "sli_protocol_crypto.h" +#include #include "common/code_utils.hpp" #include "common/debug.hpp" #include "crypto/aes_ccm.hpp" diff --git a/src/src/logging.c b/src/src/logging_rtt.c similarity index 95% rename from src/src/logging.c rename to src/src/logging_rtt.c index 458a9444..a0ece6b0 100644 --- a/src/src/logging.c +++ b/src/src/logging_rtt.c @@ -27,8 +27,8 @@ */ /** - * @file logging.c - * Platform abstraction for the logging + * @file logging_rtt.c + * This file implements the OpenThread platform abstraction for logging using RTT interface. * */ diff --git a/src/src/misc.c b/src/src/misc.c index 831da285..3e9185c0 100644 --- a/src/src/misc.c +++ b/src/src/misc.c @@ -31,11 +31,25 @@ * This file implements the OpenThread platform abstraction for miscellaneous behaviors. */ +#include #include +#if defined(SL_COMPONENT_CATALOG_PRESENT) +#include "sl_component_catalog.h" +#endif + +#if defined(SL_CATALOG_GECKO_BOOTLOADER_INTERFACE_PRESENT) +#include "btl_interface.h" +#endif + #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) @@ -53,6 +67,17 @@ void otPlatReset(otInstance *aInstance) NVIC_SystemReset(); } +#if defined(SL_CATALOG_GECKO_BOOTLOADER_INTERFACE_PRESENT) +#if OPENTHREAD_CONFIG_PLATFORM_BOOTLOADER_MODE_ENABLE +otError otPlatResetToBootloader(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + bootloader_rebootAndInstall(); + return OT_ERROR_NONE; +} +#endif +#endif + otPlatResetReason otPlatGetResetReason(otInstance *aInstance) { OT_UNUSED_VARIABLE(aInstance); @@ -125,6 +150,24 @@ 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. diff --git a/src/src/openthread-core-efr32-config.h b/src/src/openthread-core-efr32-config.h index e0079ecf..e0280101 100644 --- a/src/src/openthread-core-efr32-config.h +++ b/src/src/openthread-core-efr32-config.h @@ -57,6 +57,16 @@ #include "board_config.h" #include "em_device.h" +/** + * @def OPENTHREAD_CONFIG_PLATFORM_BOOTLOADER_MODE_ENABLE + * + * Allow triggering a platform reset to bootloader mode, if supported. + * + */ +#if defined(SL_CATALOG_GECKO_BOOTLOADER_INTERFACE_PRESENT) +#define OPENTHREAD_CONFIG_PLATFORM_BOOTLOADER_MODE_ENABLE 1 +#endif + /** * @def OPENTHREAD_CONFIG_PLATFORM_MAC_KEYS_EXPORTABLE_ENABLE * @@ -182,6 +192,24 @@ #define OPENTHREAD_CONFIG_UPTIME_ENABLE OPENTHREAD_FTD #endif +/** + * @def OPENTHREAD_CONFIG_CHILD_SUPERVISION_CHECK_TIMEOUT + * + * The default supervision check timeout interval (in seconds) used by a device in child state. Set to zero to disable + * the supervision check process on the child. + * + * The check timeout interval can be changed using `otChildSupervisionSetCheckTimeout()`. + * + * If the sleepy child does not hear from its parent within the specified timeout interval, it initiates the re-attach + * process (MLE Child Update Request/Response exchange with its parent). + * + * Setting to zero by default as this is an optional feature that can lead to unexpected detach behavior. + * + */ +#ifndef OPENTHREAD_CONFIG_CHILD_SUPERVISION_CHECK_TIMEOUT +#define OPENTHREAD_CONFIG_CHILD_SUPERVISION_CHECK_TIMEOUT 0 +#endif + /** * @def OPENTHREAD_CONFIG_MAC_CSL_REQUEST_AHEAD_US * diff --git a/src/src/platform-band.h b/src/src/platform-band.h index 574618f5..0de9375c 100644 --- a/src/src/platform-band.h +++ b/src/src/platform-band.h @@ -53,7 +53,6 @@ #define RADIO_TIMING_CSMA_OVERHEAD_US 500 #define RADIO_TIMING_DEFAULT_BYTETIME_US 32 // only used if RAIL_GetBitRate returns 0 #define RADIO_TIMING_DEFAULT_SYMBOLTIME_US 16 // only used if RAIL_GetSymbolRate returns 0 - typedef struct efr32CommonConfig { RAIL_Config_t mRailConfig; diff --git a/src/src/platform-efr32.h b/src/src/platform-efr32.h index ef6ba112..2a277ffd 100644 --- a/src/src/platform-efr32.h +++ b/src/src/platform-efr32.h @@ -153,6 +153,12 @@ void efr32LogInit(void); */ void efr32LogDeinit(void); +/** + * Print reset info. + * + */ +void efr32PrintResetInfo(void); + /** * Set 802.15.4 CCA mode * diff --git a/src/src/radio.c b/src/src/radio.c index e9060426..3a1745d1 100644 --- a/src/src/radio.c +++ b/src/src/radio.c @@ -32,6 +32,7 @@ * */ +#include #include #include #include @@ -40,8 +41,8 @@ #include #include #include -#include "common/debug.hpp" +#include "common/debug.hpp" #include "common/logging.hpp" #include "utils/code_utils.h" #include "utils/link_metrics.h" @@ -158,16 +159,28 @@ #define RADIO_BCAST_IID (0) #define RADIO_GET_FILTER_MASK(iid) (1 << (iid)) +#define RADIO_PANID_FILTER_SHIFT (0) +#define RADIO_ADDR_FILTER_SHIFT (4) #define RADIO_BCAST_PANID_FILTER_MASK RADIO_GET_FILTER_MASK(0) #define RADIO_INDEX0_PANID_FILTER_MASK RADIO_GET_FILTER_MASK(1) #define RADIO_INDEX1_PANID_FILTER_MASK RADIO_GET_FILTER_MASK(2) #define RADIO_INDEX2_PANID_FILTER_MASK RADIO_GET_FILTER_MASK(3) -#define RADIO_BCAST_ADDR_FILTER_MASK (RADIO_BCAST_PANID_FILTER_MASK << 4) -#define RADIO_INDEX0_ADDR_FILTER_MASK (RADIO_INDEX0_PANID_FILTER_MASK << 4) -#define RADIO_INDEX1_ADDR_FILTER_MASK (RADIO_INDEX1_PANID_FILTER_MASK << 4) -#define RADIO_INDEX2_ADDR_FILTER_MASK (RADIO_INDEX2_PANID_FILTER_MASK << 4) +#define RADIO_GET_PANID_FILTER_MASK(filter) \ + (filter \ + & (RADIO_BCAST_PANID_FILTER_MASK | RADIO_INDEX0_PANID_FILTER_MASK | RADIO_INDEX1_PANID_FILTER_MASK \ + | RADIO_INDEX2_PANID_FILTER_MASK)) + +#define RADIO_BCAST_ADDR_FILTER_MASK (RADIO_GET_FILTER_MASK(0) << RADIO_ADDR_FILTER_SHIFT) +#define RADIO_INDEX0_ADDR_FILTER_MASK (RADIO_GET_FILTER_MASK(1) << RADIO_ADDR_FILTER_SHIFT) +#define RADIO_INDEX1_ADDR_FILTER_MASK (RADIO_GET_FILTER_MASK(2) << RADIO_ADDR_FILTER_SHIFT) +#define RADIO_INDEX2_ADDR_FILTER_MASK (RADIO_GET_FILTER_MASK(3) << RADIO_ADDR_FILTER_SHIFT) + +#define RADIO_GET_ADDR_FILTER_MASK(filter) \ + (filter \ + & (RADIO_BCAST_ADDR_FILTER_MASK | RADIO_INDEX0_ADDR_FILTER_MASK | RADIO_INDEX1_ADDR_FILTER_MASK \ + | RADIO_INDEX2_ADDR_FILTER_MASK)) #define RADIO_BCAST_PANID (0xFFFF) #define INVALID_VALUE (0xFF) @@ -205,21 +218,24 @@ typedef enum ENERGY_SCAN_MODE_ASYNC } energyScanMode; -typedef enum +typedef struct { - BUFFER_IS_FREE, - BUFFER_PACKET_STORED, - BUFFER_PACKET_IN_PROCESSING -} bufferState; + uint8_t length; + uint8_t channel; + uint8_t lqi; + int8_t rssi; + uint8_t iid; + uint32_t timestamp; +} rxPacketDetails; typedef struct { - volatile bufferState state; - uint8_t ackKeyId; - volatile uint32_t ackFrameCounter; - uint8_t sReceivePsdu[IEEE802154_MAX_LENGTH]; + rxPacketDetails packetInfo; + uint8_t psdu[IEEE802154_MAX_LENGTH]; } rxBuffer; +typedef uint8_t rxBufferIndex_t; + static volatile energyScanStatus sEnergyScanStatus; static volatile int8_t sEnergyScanResultDbm; static energyScanMode sEnergyScanMode; @@ -257,10 +273,9 @@ static bool sIsSrcMatchEnabled = false; // Receive static rxBuffer sReceivePacket[SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT]; static uint8_t sReceiveAckPsdu[IEEE802154_MAX_LENGTH]; -static otRadioFrame sReceiveFrame[SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT]; +static otRadioFrame sReceiveFrame; static otRadioFrame sReceiveAckFrame; static otError sReceiveError; -static uint8_t sReceiveBufferInUse = 0; // Transmit static otRadioFrame sTransmitFrame; @@ -268,7 +283,6 @@ static uint8_t sTransmitPsdu[IEEE802154_MAX_LENGTH]; static otRadioFrame *sTxFrame = NULL; static uint8_t sLastLqi = 0; static int8_t sLastRssi = 0; -static uint8_t sRxChannel[RADIO_INTERFACE_COUNT]; static otExtAddress sExtAddress[RADIO_EXT_ADDR_COUNT]; static int8_t sMaxChannelPower[RADIO_INTERFACE_COUNT][SL_MAX_CHANNELS_SUPPORTED]; @@ -297,6 +311,9 @@ static int8_t sCcaThresholdDbm = CCA_THRESHOLD_DEFAULT; #if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT efr32RadioCounters railDebugCounters; + +// Create an alias for readability of RX debug tracking +#define rxDebugStep (railDebugCounters.mRadioDebugData.m8[RX_DEBUG_COUNTER0]) #endif #if OPENTHREAD_RADIO && OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE == 1 @@ -322,7 +339,7 @@ static bool isMultiChannel(void) { firstChannel = sChannelSwitchingCfg.channels[i]; } - else + else if (firstChannel != sChannelSwitchingCfg.channels[i]) { return true; } @@ -464,7 +481,6 @@ static void sli_get_default_and_max_powers_across_iids(int8_t *defaultTxPower, // We have already validated that sDefaultTxPower holds a valid value. *defaultTxPower = (*defaultTxPower == SL_INVALID_TX_POWER) ? sDefaultTxPower[iid] : SL_MAX(*defaultTxPower, sDefaultTxPower[iid]); - ; } } } @@ -508,6 +524,67 @@ static int8_t sli_get_max_tx_power_across_iids(void) 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; +} + +/* Helper function to determine if a buffer is marked as ready to process */ +static inline bool canProcessNextRxBuffer(void) +{ + return (!isRxBufferEmpty()); +} + +/* Marks the state of the next available buffer as ready to process */ +static inline void reserveNextRxBuffer(void) +{ + CIRCULAR_BUFFER_INCR(sRxBufferHead); + sRxBufferFull = (sRxBufferHead == sRxBufferTail); +} + +/* 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(); +} +#endif #if RADIO_CONFIG_ENABLE_CUSTOM_EUI_SUPPORT /* * This API reads the UserData page on the given EFR device. @@ -589,12 +666,13 @@ static bool isFilterMaskValid(uint8_t mask) #if OPENTHREAD_RADIO && OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE == 1 /* Packet will be considered as a valid packet in 3 cases: - * Case 1: If the packet was directed towards bcast address or bcase panid + * Case 1: If the packet was directed towards bcast address or bcast panid * - * Case 2: If the packet was directed to right address corresponding to the panid - * (If Address filter and pan filter in the received packet match). + * Case 2: If the packet was directed to one of our valid address/PANID combos + * (Compare all non-bcast PANID filters against their corresponding + * address filters for same IID and see if any match) * - * Case 3: We dont have either the destination addressing feild or destination PanId + * 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 ( @@ -646,8 +724,10 @@ enum typedef struct securityMaterial { + uint8_t ackKeyId; uint8_t keyId; uint32_t macFrameCounter; + uint32_t ackFrameCounter; otMacKeyMaterial keys[MAC_KEY_COUNT]; } securityMaterial; @@ -752,12 +832,9 @@ static otError radioProcessTransmitSecurity(otRadioFrame *aFrame, uint8_t iid) { if (otMacFrameIsAck(aFrame)) { - otEXPECT_ACTION(sReceivePacket[sReceiveBufferInUse].state == BUFFER_IS_FREE, error = OT_ERROR_FAILED); // Store ack frame counter and ack key ID for receive frame - // TODO: What's a better solution? (With flags like - // frame pending or enh-secure, we have used reserved bits) - sReceivePacket[sReceiveBufferInUse].ackKeyId = keyId; - sReceivePacket[sReceiveBufferInUse].ackFrameCounter = sMacKeys[iid].macFrameCounter; + sMacKeys[iid].ackKeyId = keyId; + sMacKeys[iid].ackFrameCounter = sMacKeys[iid].macFrameCounter; } otMacFrameSetKeyId(aFrame, keyId); @@ -846,7 +923,8 @@ static bool validatePacketTimestamp(RAIL_RxPacketDetails_t *pPacketDetails, uint static void updateRxFrameDetails(RAIL_RxPacketDetails_t *pPacketDetails, bool securedOutgoingEnhancedAck, bool framePendingSetInOutgoingAck, - uint8_t iid); + uint8_t iid, + uint8_t aReceiveBufferInUse); static otError skipRxPacketLengthBytes(RAIL_RxPacketInfo_t *pPacketInfo); @@ -1015,7 +1093,8 @@ static otError radioScheduleRx(uint8_t aChannel, uint32_t aStart, uint32_t aDura .endMode = RAIL_TIME_DELAY, .rxTransitionEndSchedule = 1, // This lets us idle after a scheduled-rx .hardWindowEnd = 0}; // This lets us receive a packet near a window-end-event - status = RAIL_ScheduleRx(gRailHandle, aChannel, &rxCfg, &bgRxSchedulerInfo); + + status = RAIL_ScheduleRx(gRailHandle, aChannel, &rxCfg, &bgRxSchedulerInfo); otEXPECT_ACTION(status == RAIL_STATUS_NO_ERROR, error = OT_ERROR_FAILED); (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_RX_LISTEN, 0U); @@ -1229,17 +1308,13 @@ void efr32RadioInit(void) memset(&sReceivePacket, 0x00, sizeof(sReceivePacket)); - for (int index = 0; index < SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT; index++) - { - sReceiveFrame[index].mLength = 0; - sReceiveFrame[index].mPsdu = (uint8_t *)&sReceivePacket[index].sReceivePsdu[0]; - } + sReceiveFrame.mLength = 0; + sReceiveFrame.mPsdu = NULL; sReceiveAckFrame.mLength = 0; sReceiveAckFrame.mPsdu = sReceiveAckPsdu; sTransmitFrame.mLength = 0; sTransmitFrame.mPsdu = sTransmitPsdu; - sReceiveBufferInUse = 0; #if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT sTransmitFrame.mInfo.mTxInfo.mIeInfo = &sTransmitIeInfo; @@ -1494,7 +1569,7 @@ otError otPlatRadioSleep(otInstance *aInstance) OT_UNUSED_VARIABLE(aInstance); otError error = OT_ERROR_NONE; - otEXPECT_ACTION(getInternalFlag(ONGOING_TX_FLAGS) == 0, error = OT_ERROR_INVALID_STATE); + otEXPECT_ACTION(!getInternalFlag(ONGOING_TX_FLAGS), error = OT_ERROR_BUSY); otLogInfoPlat("State=OT_RADIO_STATE_SLEEP"); setInternalFlag(FLAG_SCHEDULED_RX_PENDING, false); @@ -1509,12 +1584,10 @@ otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel) otError error = OT_ERROR_NONE; RAIL_Status_t status; efr32BandConfig *config; - uint8_t iid = otNcpPlatGetCurCommandIid(); int8_t txPower; OT_UNUSED_VARIABLE(aInstance); - - otEXPECT_ACTION((getInternalFlag(FLAG_ONGOING_TX_DATA) == 0) && sEnergyScanStatus != ENERGY_SCAN_STATUS_IN_PROGRESS, + otEXPECT_ACTION(!getInternalFlag(FLAG_ONGOING_TX_DATA) && sEnergyScanStatus != ENERGY_SCAN_STATUS_IN_PROGRESS, error = OT_ERROR_INVALID_STATE); #if FAST_CHANNEL_SWITCHING_SUPPORT @@ -1542,9 +1615,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); - sRxChannel[iid] = aChannel; - sReceiveFrame[sReceiveBufferInUse].mChannel = aChannel; - sReceiveAckFrame.mChannel = aChannel; + sReceiveFrame.mChannel = aChannel; + sReceiveAckFrame.mChannel = aChannel; exit: return error; @@ -1556,7 +1628,6 @@ otError otPlatRadioReceiveAt(otInstance *aInstance, uint8_t aChannel, uint32_t a otError error = OT_ERROR_NONE; RAIL_Status_t status; efr32BandConfig *config; - uint8_t iid = otNcpPlatGetCurCommandIid(); int8_t txPower = sli_get_max_tx_power_across_iids(); OT_UNUSED_VARIABLE(aInstance); @@ -1579,9 +1650,8 @@ 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); - sRxChannel[iid] = aChannel; - sReceiveFrame[sReceiveBufferInUse].mChannel = aChannel; - sReceiveAckFrame.mChannel = aChannel; + sReceiveFrame.mChannel = aChannel; + sReceiveAckFrame.mChannel = aChannel; exit: return error; @@ -1643,11 +1713,8 @@ otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame) + 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 #endif // OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 @@ -1882,11 +1949,11 @@ int8_t otPlatRadioGetRssi(otInstance *aInstance) otError error; uint32_t start; int8_t rssi = OT_RADIO_RSSI_INVALID; - uint8_t aChannel = sRxChannel[otNcpPlatGetCurCommandIid()]; + uint8_t aChannel = sReceiveFrame.mChannel; OT_UNUSED_VARIABLE(aInstance); - otEXPECT(getInternalFlag(FLAG_ONGOING_TX_DATA) == 0); + otEXPECT(!getInternalFlag(FLAG_ONGOING_TX_DATA)); #if FAST_CHANNEL_SWITCHING_SUPPORT uint8_t index = getPanIndexFromIid(otNcpPlatGetCurCommandIid()); @@ -1985,7 +2052,7 @@ otError otPlatRadioSetTransmitPower(otInstance *aInstance, int8_t aPower) } // Required for RCP error recovery -// See src/lib/spinel/radio_spinel_impl.hpp::RestoreProperties() +// See src/lib/spinel/radio_spinel.cpp::RestoreProperties() otError otPlatRadioSetChannelMaxTransmitPower(otInstance *aInstance, uint8_t aChannel, int8_t aMaxPower) { otError error = OT_ERROR_NONE; @@ -2505,20 +2572,23 @@ static void packetReceivedCallback(RAIL_RxPacketHandle_t packetHandle) { RAIL_RxPacketInfo_t packetInfo; RAIL_RxPacketDetails_t packetDetails; - uint16_t length; + uint16_t length = 0; bool framePendingInAck = false; - bool rxCorrupted = 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 packetHandle = RAIL_GetRxPacketInfo(gRailHandle, packetHandle, &packetInfo); otEXPECT_ACTION( (packetHandle != RAIL_RX_PACKET_HANDLE_INVALID && packetInfo.packetStatus == RAIL_RX_PACKET_READY_SUCCESS), - rxCorrupted = true); + dropPacket = true); - otEXPECT_ACTION(validatePacketDetails(packetHandle, &packetDetails, &packetInfo, &length), rxCorrupted = true); + otEXPECT_ACTION(validatePacketDetails(packetHandle, &packetDetails, &packetInfo, &length), dropPacket = true); - otEXPECT_ACTION((skipRxPacketLengthBytes(&packetInfo)) == OT_ERROR_NONE, rxCorrupted = true); + otEXPECT_ACTION((skipRxPacketLengthBytes(&packetInfo)) == OT_ERROR_NONE, dropPacket = true); uint8_t macFcf = ((packetInfo.firstPortionBytes == 0) ? packetInfo.lastPortionData[0] : packetInfo.firstPortionData[0]); @@ -2526,34 +2596,38 @@ static void packetReceivedCallback(RAIL_RxPacketHandle_t packetHandle) iid = getIidFromFilterMask(packetInfo.filterMask); #if SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT > 1 - psdu = (packetDetails.isAck) ? sReceiveAckFrame.mPsdu : sReceivePacket[sReceiveBufferInUse].sReceivePsdu; + if (!packetDetails.isAck) + { + receiveBufferInUse = getFreeBufferIndex(); + otEXPECT_ACTION(receiveBufferInUse < SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT, dropPacket = true); + psdu = sReceivePacket[receiveBufferInUse].psdu; + } #endif - // read packet - RAIL_CopyRxPacket(psdu, &packetInfo); - if (packetDetails.isAck) { otEXPECT_ACTION( (length >= IEEE802154_MIN_LENGTH && (macFcf & IEEE802154_FRAME_TYPE_MASK) == IEEE802154_FRAME_TYPE_ACK), - rxCorrupted = true); + dropPacket = true); + + // read packet + RAIL_CopyRxPacket(psdu, &packetInfo); #if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT railDebugCounters.mRailEventAcksReceived++; #endif sReceiveAckFrame.mLength = length; - // Releasing the ACK frames here, ensures that the main thread (processNextRxPacket) + // 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); (void)handlePhyStackEvent(SL_RAIL_UTIL_IEEE802154_STACK_EVENT_RX_ENDED, (uint32_t)isReceivingFrame()); - if (txWaitingForAck() - && (sReceiveAckFrame.mPsdu[IEEE802154_DSN_OFFSET] == sTransmitFrame.mPsdu[IEEE802154_DSN_OFFSET])) + if (txWaitingForAck() && (psdu[IEEE802154_DSN_OFFSET] == sTransmitFrame.mPsdu[IEEE802154_DSN_OFFSET])) { - otEXPECT_ACTION(validatePacketTimestamp(&packetDetails, length), rxCorrupted = true); - updateRxFrameDetails(&packetDetails, false, false, iid); + otEXPECT_ACTION(validatePacketTimestamp(&packetDetails, length), dropPacket = true); + updateRxFrameDetails(&packetDetails, false, false, iid, INVALID_VALUE); // 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. @@ -2577,26 +2651,22 @@ static void packetReceivedCallback(RAIL_RxPacketHandle_t packetHandle) } else { - otEXPECT_ACTION(sPromiscuous || (length >= IEEE802154_MIN_DATA_LENGTH), rxCorrupted = true); - otEXPECT_ACTION(sReceivePacket[sReceiveBufferInUse].state == BUFFER_IS_FREE, rxCorrupted = true); + otEXPECT_ACTION(sPromiscuous || (length >= IEEE802154_MIN_DATA_LENGTH), dropPacket = true); #if SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT > 1 - sReceiveFrame[sReceiveBufferInUse].mLength = length; - sReceiveFrame[sReceiveBufferInUse].mChannel = packetDetails.channel; - - // 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; - + // read packet + RAIL_CopyRxPacket(psdu, &packetInfo); RAIL_ReleaseRxPacket(gRailHandle, packetHandle); - otEXPECT(validatePacketTimestamp(&packetDetails, length)); - updateRxFrameDetails(&packetDetails, securedOutgoingEnhancedAck, framePendingSetInOutgoingAck, iid); + otEXPECT_ACTION(validatePacketTimestamp(&packetDetails, length), dropPacket = true); + + 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; #if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT railDebugCounters.mRailPlatRadioReceiveProcessedCount++; @@ -2624,22 +2694,12 @@ static void packetReceivedCallback(RAIL_RxPacketHandle_t packetHandle) } } exit: - if (rxCorrupted) + 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()); } -#if SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT > 1 - else - { - if (!packetDetails.isAck) - { - sReceivePacket[sReceiveBufferInUse].state = BUFFER_PACKET_STORED; - sReceiveBufferInUse = (sReceiveBufferInUse + 1) % SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT; - } - } -#endif } static void packetSentCallback(bool isAck) @@ -2991,8 +3051,15 @@ static void RAILCb_Generic(RAIL_Handle_t aRailHandle, RAIL_Events_t aEvents) railDebugCounters.mRailPlatRadioEnergyScanDoneCbCount++; #endif } - - otSysEventSignalPending(); + // scheduled and unscheduled config events happen very often, + // especially in a DMP situation where there is an active BLE connection. + // Waking up the OT RTOS task on every one of these occurrences causes + // a lower priority CLI task to starve and makes it appear like a code lockup + // There is no reason to wake the OT task for these events! + if (!(aEvents & RAIL_EVENT_CONFIG_SCHEDULED) && !(aEvents & RAIL_EVENT_CONFIG_UNSCHEDULED)) + { + otSysEventSignalPending(); + } } //------------------------------------------------------------------------------ @@ -3003,12 +3070,22 @@ static bool validatePacketDetails(RAIL_RxPacketHandle_t packetHandle, RAIL_RxPacketInfo_t *pPacketInfo, uint16_t *packetLength) { - bool pktValid = true; + bool pktValid = true; + RAIL_Status_t rStatus; +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + rxDebugStep = 0; +#endif - otEXPECT_ACTION((RAIL_GetRxPacketDetailsAlt(gRailHandle, packetHandle, pPacketDetails) == RAIL_STATUS_NO_ERROR), - pktValid = false); + rStatus = RAIL_GetRxPacketDetailsAlt(gRailHandle, packetHandle, pPacketDetails); + otEXPECT_ACTION(rStatus == RAIL_STATUS_NO_ERROR, pktValid = false); +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + rxDebugStep++; +#endif otEXPECT_ACTION(isFilterMaskValid(pPacketInfo->filterMask), pktValid = false); +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + rxDebugStep++; +#endif // RAIL's packetBytes includes the (1 or 2 byte) PHY header but not the 2-byte CRC. // We want *packetLength to match the PHY header length so we add 2 for CRC @@ -3025,11 +3102,30 @@ static bool validatePacketDetails(RAIL_RxPacketHandle_t packetHandle, ((pPacketInfo->firstPortionBytes > 1) ? pPacketInfo->firstPortionData[1] : pPacketInfo->lastPortionData[0]); otEXPECT_ACTION(*packetLength == (uint16_t)(__RBIT(lengthByte) >> 24), pktValid = false); } +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + rxDebugStep++; +#endif // check the length validity of recv packet; RAIL should take care of this. otEXPECT_ACTION((*packetLength >= IEEE802154_MIN_LENGTH && *packetLength <= IEEE802154_MAX_LENGTH), pktValid = false); +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + rxDebugStep++; +#endif + exit: +#if (OPENTHREAD_CONFIG_LOG_LEVEL == OT_LOG_LEVEL_DEBG) + if (!pktValid) + { + otLogDebgPlat("RX Pkt Invalid: rStatus=0x%X, filterMask=0x%2X, pktLen=%i", + rStatus, + pPacketInfo->filterMask, + *packetLength); +#if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT + otLogDebgPlat("RX debug step=%i", rxDebugStep); +#endif + } +#endif return pktValid; } @@ -3053,58 +3149,66 @@ static bool validatePacketTimestamp(RAIL_RxPacketDetails_t *pPacketDetails, uint static void updateRxFrameDetails(RAIL_RxPacketDetails_t *pPacketDetails, bool securedOutgoingEnhancedAck, bool framePendingSetInOutgoingAck, - uint8_t iid) + uint8_t iid, + uint8_t aReceiveBufferInUse) { - OT_UNUSED_VARIABLE(iid); - OT_ASSERT(pPacketDetails != NULL); - // 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; + uint64_t railUsTimeNow = otPlatTimeGet(); + uint32_t railUsTimerWraps = railUsTimeNow >> 32; + RAIL_Time_t timestamp = (pPacketDetails != NULL ? pPacketDetails->timeReceived.packetTime + : sReceivePacket[aReceiveBufferInUse].packetInfo.timestamp); // 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) <= pPacketDetails->timeReceived.packetTime) + if ((railUsTimeNow & 0xFFFFFFFF) <= timestamp) { railUsTimerWraps--; } - if (pPacketDetails->isAck) + if (pPacketDetails != NULL && pPacketDetails->isAck) { - sReceiveAckFrame.mInfo.mRxInfo.mRssi = pPacketDetails->rssi; - sReceiveAckFrame.mInfo.mRxInfo.mLqi = pPacketDetails->lqi; - sReceiveAckFrame.mInfo.mRxInfo.mTimestamp = - pPacketDetails->timeReceived.packetTime + ((uint64_t)railUsTimerWraps << 32); -// TODO: Maybe remove #if ? + 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 } else { - sReceiveFrame[sReceiveBufferInUse].mInfo.mRxInfo.mRssi = pPacketDetails->rssi; - sReceiveFrame[sReceiveBufferInUse].mInfo.mRxInfo.mLqi = pPacketDetails->lqi; - sReceiveFrame[sReceiveBufferInUse].mInfo.mRxInfo.mTimestamp = - pPacketDetails->timeReceived.packetTime + ((uint64_t)railUsTimerWraps << 32); + 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[sReceiveBufferInUse].mInfo.mRxInfo.mAckedWithSecEnhAck = securedOutgoingEnhancedAck; + sReceiveFrame.mInfo.mRxInfo.mAckedWithSecEnhAck = securedOutgoingEnhancedAck; // Set this flag only when the packet is really acknowledged with frame pending set. - sReceiveFrame[sReceiveBufferInUse].mInfo.mRxInfo.mAckedWithFramePending = framePendingSetInOutgoingAck; + sReceiveFrame.mInfo.mRxInfo.mAckedWithFramePending = framePendingSetInOutgoingAck; #if OPENTHREAD_RADIO && OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE == 1 - sReceiveFrame[sReceiveBufferInUse].mIid = iid; + sReceiveFrame.mIid = iid; #endif - sLastLqi = pPacketDetails->lqi; - sLastRssi = pPacketDetails->rssi; - #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 // Use stored values for these - sReceiveFrame[sReceiveBufferInUse].mInfo.mRxInfo.mAckKeyId = sReceivePacket[sReceiveBufferInUse].ackKeyId; - sReceiveFrame[sReceiveBufferInUse].mInfo.mRxInfo.mAckFrameCounter = - sReceivePacket[sReceiveBufferInUse].ackFrameCounter; + sReceiveFrame.mInfo.mRxInfo.mAckKeyId = sMacKeys[iid].ackKeyId; + sReceiveFrame.mInfo.mRxInfo.mAckFrameCounter = sMacKeys[iid].ackFrameCounter; #endif } } @@ -3133,7 +3237,7 @@ static otError skipRxPacketLengthBytes(RAIL_RxPacketInfo_t *pPacketInfo) return error; } -static bool prepareRxPacketforCb(uint8_t index) +static bool prepareNextRxPacketforCb(void) { #if SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT == 1 RAIL_RxPacketHandle_t packetHandle = RAIL_RX_PACKET_HANDLE_INVALID; @@ -3143,10 +3247,14 @@ static bool prepareRxPacketforCb(uint8_t index) 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), @@ -3163,11 +3271,11 @@ static bool prepareRxPacketforCb(uint8_t index) otEXPECT(sPromiscuous || (!packetDetails.isAck && (length >= IEEE802154_MIN_DATA_LENGTH))); // read packet - RAIL_CopyRxPacket(sReceiveFrame[index].mPsdu, &packetInfo); - sReceiveFrame[index].mLength = length; + RAIL_CopyRxPacket(sReceiveFrame.mPsdu, &packetInfo); + sReceiveFrame.mLength = length; - uint8_t *macFcfPointer = sReceiveFrame[index].mPsdu; - sReceiveFrame[index].mChannel = packetDetails.channel; + uint8_t *macFcfPointer = sReceiveFrame.mPsdu; + sReceiveFrame.mChannel = packetDetails.channel; // Check the reserved bits in the MAC header, then clear them. @@ -3186,7 +3294,7 @@ static bool prepareRxPacketforCb(uint8_t index) } otEXPECT(validatePacketTimestamp(&packetDetails, length)); - updateRxFrameDetails(&packetDetails, securedOutgoingEnhancedAck, framePendingSetInOutgoingAck, iid); + updateRxFrameDetails(&packetDetails, securedOutgoingEnhancedAck, framePendingSetInOutgoingAck, iid, 0); rxProcessDone = true; #if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT @@ -3200,7 +3308,28 @@ static bool prepareRxPacketforCb(uint8_t index) } CORE_EXIT_ATOMIC(); #else - bool rxProcessDone = (sReceivePacket[index].state == BUFFER_PACKET_STORED); + bool rxProcessDone = true; + rxBufferIndex_t index = getStoredBufferIndex(); + uint8_t *psdu = sReceivePacket[index].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 = ((*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); #endif return rxProcessDone; @@ -3208,45 +3337,45 @@ static bool prepareRxPacketforCb(uint8_t index) static void processNextRxPacket(otInstance *aInstance) { - int index = 0; - -#if SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT > 1 - index = (sReceiveBufferInUse + 1) % SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT; -#endif - - do + if (prepareNextRxPacketforCb()) { - if (prepareRxPacketforCb(index)) - { - sReceiveError = OT_ERROR_NONE; + sReceiveError = OT_ERROR_NONE; #if OPENTHREAD_CONFIG_DIAG_ENABLE - if (otPlatDiagModeGet()) - { - otPlatDiagRadioReceiveDone(aInstance, &sReceiveFrame[index], sReceiveError); - } - else + if (otPlatDiagModeGet()) + { + otPlatDiagRadioReceiveDone(aInstance, &sReceiveFrame, sReceiveError); + } + else #endif - { + { #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[index], true); + (void)sl_gp_intf_is_gp_pkt(&sReceiveFrame, true); #endif - otLogInfoPlat("Received %d bytes", sReceiveFrame[index].mLength); - sReceivePacket[index].state = BUFFER_PACKET_IN_PROCESSING; - otPlatRadioReceiveDone(aInstance, &sReceiveFrame[index], sReceiveError); + otPlatRadioReceiveDone(aInstance, &sReceiveFrame, sReceiveError); #if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT - railDebugCounters.mRailPlatRadioReceiveDoneCbCount++; + railDebugCounters.mRailPlatRadioReceiveDoneCbCount++; #endif - } + } - sReceivePacket[index].state = BUFFER_IS_FREE; +#if SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT > 1 + releaseCurrentRxBuffer(); +#endif - otSysEventSignalPending(); - } + otSysEventSignalPending(); + } +} + +static void processRxPackets(otInstance *aInstance) +{ #if SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT > 1 - index = ((index + 1) % SL_OPENTHREAD_RADIO_RX_BUFFER_COUNT); + while (canProcessNextRxBuffer()) + { + processNextRxPacket(aInstance); + } +#else + processNextRxPacket(aInstance); #endif - } while (index != sReceiveBufferInUse); } static void processTxComplete(otInstance *aInstance) @@ -3315,7 +3444,7 @@ void efr32RadioProcess(otInstance *aInstance) // We should process the received packet first. Adding it at the end of this function, // will delay the stack notification until the next call to efr32RadioProcess() - processNextRxPacket(aInstance); + processRxPackets(aInstance); processTxComplete(aInstance); if (sEnergyScanMode == ENERGY_SCAN_MODE_ASYNC && sEnergyScanStatus == ENERGY_SCAN_STATUS_COMPLETED) @@ -3350,13 +3479,12 @@ otError setRadioState(otRadioState state) otError error = OT_ERROR_NONE; // Defer idling the radio if we have an ongoing TX task - otEXPECT_ACTION((!getInternalFlag(ONGOING_TX_FLAGS)), error = OT_ERROR_FAILED); + otEXPECT_ACTION(!getInternalFlag(ONGOING_TX_FLAGS), error = OT_ERROR_FAILED); switch (state) { case OT_RADIO_STATE_RECEIVE: - otEXPECT_ACTION(radioSetRx(sReceiveFrame[sReceiveBufferInUse].mChannel) == OT_ERROR_NONE, - error = OT_ERROR_FAILED); + otEXPECT_ACTION(radioSetRx(sReceiveFrame.mChannel) == OT_ERROR_NONE, error = OT_ERROR_FAILED); break; case OT_RADIO_STATE_SLEEP: radioSetIdle(); @@ -3555,7 +3683,8 @@ static void setCcaThreshold(void) { thresholddBm = RAIL_RSSI_INVALID_DBM; } - OT_ASSERT(RAIL_SetCcaThreshold(gRailHandle, thresholddBm) == RAIL_STATUS_NO_ERROR); + RAIL_Status_t status = RAIL_SetCcaThreshold(gRailHandle, thresholddBm); + OT_ASSERT(status == RAIL_STATUS_NO_ERROR); } CORE_EXIT_ATOMIC(); } diff --git a/src/src/rail_config.h b/src/src/rail_config.h index 858187bf..211eb614 100644 --- a/src/src/rail_config.h +++ b/src/src/rail_config.h @@ -33,8 +33,6 @@ #include "rail_types.h" #include -#define RADIO_CONFIG_XTAL_FREQUENCY 38400000UL - #if RADIO_CONFIG_SUBGHZ_SUPPORT extern const RAIL_ChannelConfig_t *channelConfigs[]; #endif diff --git a/src/src/sl_rcp_gp_interface.c b/src/src/sl_rcp_gp_interface.c index 71005f9e..13d9daaa 100644 --- a/src/src/sl_rcp_gp_interface.c +++ b/src/src/sl_rcp_gp_interface.c @@ -37,9 +37,9 @@ #include "sl_packet_utils.h" #include "sl_rcp_gp_interface_config.h" #include "sl_status.h" +#include #include #include -#include "common/debug.hpp" #include "common/logging.hpp" #include "utils/mac_frame.h" diff --git a/src/src/sleep.c b/src/src/sleep.c index 3788083c..9f0ce74e 100644 --- a/src/src/sleep.c +++ b/src/src/sleep.c @@ -37,16 +37,37 @@ #include "sleep.h" #include "em_core.h" +#include "em_gpio.h" #include "platform-efr32.h" #include "sl_component_catalog.h" +#include #include #include -#include "common/debug.hpp" #if defined(SL_CATALOG_POWER_MANAGER_PRESENT) #include "sl_power_manager.h" #endif // SL_CATALOG_POWER_MANAGER_PRESENT +// Define generic VCOM TX port-pin definitions to use either the USART or the EUSART pins. +// These pins need to be disabled to minimize power consumption. +#ifdef SL_CATALOG_UARTDRV_USART_PRESENT +#include "sl_uartdrv_usart_vcom_config.h" +#define VCOM_TX_PORT SL_UARTDRV_USART_VCOM_TX_PORT +#define VCOM_TX_PIN SL_UARTDRV_USART_VCOM_TX_PIN +#elif defined(SL_CATALOG_UARTDRV_EUSART_PRESENT) +#include "sl_uartdrv_eusart_vcom_config.h" +#define VCOM_TX_PORT SL_UARTDRV_EUSART_VCOM_TX_PORT +#define VCOM_TX_PIN SL_UARTDRV_EUSART_VCOM_TX_PIN +#elif defined(SL_CATALOG_UARTDRV_LEUART_PRESENT) +#include "sl_uartdrv_leuart_vcom_config.h" +#define VCOM_TX_PORT SL_UARTDRV_LEUART_VCOM_TX_PORT +#define VCOM_TX_PIN SL_UARTDRV_LEUART_VCOM_TX_PIN +#elif defined(SL_CATALOG_CPC_DRIVER_UART_PRESENT) +#include "sl_cpc_drv_uart_config.h" +#define VCOM_TX_PORT SL_CPC_DRV_UART_VCOM_TX_PORT +#define VCOM_TX_PIN SL_CPC_DRV_UART_VCOM_TX_PIN +#endif + // Power manager transition events of interest. /* clang-format off */ #define POWER_MANAGER_EVENTS_OF_INTEREST \ @@ -173,16 +194,23 @@ bool sl_ot_is_ok_to_sleep(void) 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) + static GPIO_Mode_TypeDef vcom_tx_pin_state = gpioModePushPull; + if (from == SL_POWER_MANAGER_EM2) { // Leaving EM2 - // emberStackPowerUp(); // TO DO: Do we need to take care of any state? + // Reset the USART Tx pin + GPIO_PinModeSet(VCOM_TX_PORT, VCOM_TX_PIN, vcom_tx_pin_state, 1); } else if (to == SL_POWER_MANAGER_EM2) { // Going to EM2 - // emberStackPowerDown(); // TO DO: Do we need to take care of any state? + // Sleep the USART Tx pin on series 2 devices to save energy + vcom_tx_pin_state = GPIO_PinModeGet(VCOM_TX_PORT, VCOM_TX_PIN); + GPIO_PinModeSet(VCOM_TX_PORT, VCOM_TX_PIN, gpioModeDisabled, 1); } +#endif } #endif // SL_CATALOG_POWER_MANAGER_PRESENT && !SL_CATALOG_KERNEL_PRESENT diff --git a/src/src/soft_source_match_table.c b/src/src/soft_source_match_table.c index 0e3ae414..0d70bd3d 100644 --- a/src/src/soft_source_match_table.c +++ b/src/src/soft_source_match_table.c @@ -36,12 +36,12 @@ #include "soft_source_match_table.h" +#include #include #include -#include "common/debug.hpp" #include - +#include "common/debug.hpp" #include "utils/code_utils.h" // Print entire source match tables when diff --git a/third_party/silabs/gecko_sdk b/third_party/silabs/gecko_sdk index 1228a952..124fa19d 160000 --- a/third_party/silabs/gecko_sdk +++ b/third_party/silabs/gecko_sdk @@ -1 +1 @@ -Subproject commit 1228a95262ee099a21c6be4d35224479c8e4dde2 +Subproject commit 124fa19de8c8b3961d21c20857f7df32239786da