From 8b328e56bf59a8d2d89faa09796a45b94bcc9461 Mon Sep 17 00:00:00 2001 From: Xu Si Yu Date: Tue, 24 Sep 2024 17:25:58 +0800 Subject: [PATCH] [spinel] allow registering callback to handle compatibility errors --- src/lib/spinel/openthread-spinel-config.h | 9 ++++++ src/lib/spinel/radio_spinel.cpp | 35 +++++++++++++++++++---- src/lib/spinel/radio_spinel.hpp | 34 ++++++++++++++++++++-- 3 files changed, 70 insertions(+), 8 deletions(-) diff --git a/src/lib/spinel/openthread-spinel-config.h b/src/lib/spinel/openthread-spinel-config.h index b8de8325fb6d..3e67fe980cb8 100644 --- a/src/lib/spinel/openthread-spinel-config.h +++ b/src/lib/spinel/openthread-spinel-config.h @@ -126,6 +126,15 @@ #define OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE 0 #endif +/** + * @def OPENTHREAD_SPINEL_CONFIG_COMPATIBILITY_ERROR_CALLBACK_ENABLE + * + * Enables compatibility error callback in Spinel + */ +#ifndef OPENTHREAD_SPINEL_CONFIG_COMPATIBILITY_ERROR_CALLBACK_ENABLE +#define OPENTHREAD_SPINEL_CONFIG_COMPATIBILITY_ERROR_CALLBACK_ENABLE 0 +#endif + /** * @def OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_HEADER * diff --git a/src/lib/spinel/radio_spinel.cpp b/src/lib/spinel/radio_spinel.cpp index 0bd60e4b2510..4b86249d5a57 100644 --- a/src/lib/spinel/radio_spinel.cpp +++ b/src/lib/spinel/radio_spinel.cpp @@ -111,6 +111,10 @@ RadioSpinel::RadioSpinel(void) #if OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE , mVendorRestorePropertiesCallback(nullptr) , mVendorRestorePropertiesContext(nullptr) +#endif +#if OPENTHREAD_SPINEL_CONFIG_COMPATIBILITY_ERROR_CALLBACK_ENABLE + , mCompatibilityErrorCallback(nullptr) + , mCompatibilityErrorContext(nullptr) #endif , mTimeSyncEnabled(false) , mTimeSyncOn(false) @@ -198,7 +202,7 @@ otError RadioSpinel::CheckSpinelVersion(void) { LogCrit("Spinel version mismatch - Posix:%d.%d, RCP:%d.%d", SPINEL_PROTOCOL_VERSION_THREAD_MAJOR, SPINEL_PROTOCOL_VERSION_THREAD_MINOR, versionMajor, versionMinor); - DieNow(OT_EXIT_RADIO_SPINEL_INCOMPATIBLE); + HandleCompatibilityError(); } exit: @@ -210,13 +214,13 @@ void RadioSpinel::InitializeCaps(bool &aSupportsRcpApiVersion, bool &aSupportsRc if (!GetSpinelDriver().CoprocessorHasCap(SPINEL_CAP_CONFIG_RADIO)) { LogCrit("The co-processor isn't a RCP!"); - DieNow(OT_EXIT_RADIO_SPINEL_INCOMPATIBLE); + HandleCompatibilityError(); } if (!GetSpinelDriver().CoprocessorHasCap(SPINEL_CAP_MAC_RAW)) { LogCrit("RCP capability list does not include support for radio/raw mode"); - DieNow(OT_EXIT_RADIO_SPINEL_INCOMPATIBLE); + HandleCompatibilityError(); } sSupportsLogStream = GetSpinelDriver().CoprocessorHasCap(SPINEL_CAP_OPENTHREAD_LOG_METADATA); @@ -251,7 +255,7 @@ otError RadioSpinel::CheckRadioCapabilities(otRadioCaps aRequiredRadioCaps) } } - DieNow(OT_EXIT_RADIO_SPINEL_INCOMPATIBLE); + HandleCompatibilityError(); } exit: @@ -279,7 +283,7 @@ otError RadioSpinel::CheckRcpApiVersion(bool aSupportsRcpApiVersion, bool aSuppo LogCrit("RCP and host are using incompatible API versions"); LogCrit("RCP API Version %u is older than min required by host %u", rcpApiVersion, SPINEL_MIN_HOST_SUPPORTED_RCP_API_VERSION); - DieNow(OT_EXIT_RADIO_SPINEL_INCOMPATIBLE); + HandleCompatibilityError(); } } @@ -299,7 +303,7 @@ otError RadioSpinel::CheckRcpApiVersion(bool aSupportsRcpApiVersion, bool aSuppo LogCrit("RCP and host are using incompatible API versions"); LogCrit("RCP requires min host API version %u but host is older and at version %u", minHostRcpApiVersion, SPINEL_RCP_API_VERSION); - DieNow(OT_EXIT_RADIO_SPINEL_INCOMPATIBLE); + HandleCompatibilityError(); } } @@ -2395,5 +2399,24 @@ otError RadioSpinel::SetChannelTargetPower(uint8_t aChannel, int16_t aTargetPowe } #endif // OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE +#if OPENTHREAD_SPINEL_CONFIG_COMPATIBILITY_ERROR_CALLBACK_ENABLE +void RadioSpinel::SetCompatibilityErrorCallback(otRadioSpinelCompatibilityErrorCallback aCallback, void *aContext) +{ + mCompatibilityErrorCallback = aCallback; + mCompatibilityErrorContext = aContext; +} +#endif // OPENTHREAD_SPINEL_CONFIG_COMPATIBILITY_ERROR_CALLBACK_ENABLE + +void RadioSpinel::HandleCompatibilityError(void) +{ +#if OPENTHREAD_SPINEL_CONFIG_COMPATIBILITY_ERROR_CALLBACK_ENABLE + if (mCompatibilityErrorCallback) + { + mCompatibilityErrorCallback(mCompatibilityErrorContext); + } +#endif // OPENTHREAD_SPINEL_CONFIG_COMPATIBILITY_ERROR_CALLBACK_ENABLE + DieNow(OT_EXIT_RADIO_SPINEL_INCOMPATIBLE); +} + } // namespace Spinel } // namespace ot diff --git a/src/lib/spinel/radio_spinel.hpp b/src/lib/spinel/radio_spinel.hpp index 4ca2d721be28..3cf05446798c 100644 --- a/src/lib/spinel/radio_spinel.hpp +++ b/src/lib/spinel/radio_spinel.hpp @@ -1006,8 +1006,10 @@ class RadioSpinel : private Logger /** * A callback type for restoring vendor properties. + * + * @param[in] aContext A pointer to the user context. */ - typedef void (*otRadioSpinelVendorRestorePropertiesCallback)(void *context); + typedef void (*otRadioSpinelVendorRestorePropertiesCallback)(void *aContext); /** * Registers a callback to restore vendor properties. @@ -1016,11 +1018,32 @@ class RadioSpinel : private Logger * properties occurs (such as an unexpected RCP reset), the user can restore the vendor properties via the callback. * * @param[in] aCallback The callback. - * @param[in] aContext The context. + * @param[in] aContext A pointer to the user context. */ void SetVendorRestorePropertiesCallback(otRadioSpinelVendorRestorePropertiesCallback aCallback, void *aContext); #endif // OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE +#if OPENTHREAD_SPINEL_CONFIG_COMPATIBILITY_ERROR_CALLBACK_ENABLE + /** + * A callback type for handling compatibility error of radio spinel. + * + * @param[in] aContext A pointer to the user context. + */ + typedef void (*otRadioSpinelCompatibilityErrorCallback)(void *aContext); + + /** + * Registers a callback to handle error of radio spinel. + * + * This function is used to register a callback to handle radio spinel compatibility errors. When a radio spinel + * compatibility error occurs that cannot be resolved by a restart (e.g., RCP version mismatch), the user can + * handle the error through the callback(such as OTA) instead of letting the program crash directly. + * + * @param[in] aCallback The callback. + * @param[in] aContext A pointer to the user context. + */ + void SetCompatibilityErrorCallback(otRadioSpinelCompatibilityErrorCallback aCallback, void *aContext); +#endif + /** * Enables or disables the time synchronization between the host and RCP. * @@ -1155,6 +1178,8 @@ class RadioSpinel : private Logger void PlatDiagOutput(const char *aFormat, ...); #endif + void HandleCompatibilityError(void); + otInstance *mInstance; RadioSpinelCallbacks mCallbacks; ///< Callbacks for notifications of higher layer. @@ -1260,6 +1285,11 @@ class RadioSpinel : private Logger void *mVendorRestorePropertiesContext; #endif +#if OPENTHREAD_SPINEL_CONFIG_COMPATIBILITY_ERROR_CALLBACK_ENABLE + otRadioSpinelCompatibilityErrorCallback mCompatibilityErrorCallback; + void *mCompatibilityErrorContext; +#endif + bool mTimeSyncEnabled : 1; bool mTimeSyncOn : 1;