diff --git a/src/lib/spinel/openthread-spinel-config.h b/src/lib/spinel/openthread-spinel-config.h index 0669de27e574..860c78a40490 100644 --- a/src/lib/spinel/openthread-spinel-config.h +++ b/src/lib/spinel/openthread-spinel-config.h @@ -136,6 +136,16 @@ #define OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE 0 #endif +/** + * @def OPENTHREAD_SPINEL_CONFIG_COMPATABILITY_ERROR_CALLBACK_ENABLE + * + * Enables compilation of compatability error callback code for Spinel + * + */ +#ifndef OPENTHREAD_SPINEL_CONFIG_COMPATABILITY_ERROR_CALLBACK_ENABLE +#define OPENTHREAD_SPINEL_CONFIG_COMPATABILITY_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..5ba07f752472 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_COMPATABILITY_ERROR_CALLBACK_ENABLE + , mCompatabilityErrorCallback(nullptr) + , mCompatabilityErrorContext(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); + HandleCompatabilityError(); } 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); + HandleCompatabilityError(); } 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); + HandleCompatabilityError(); } sSupportsLogStream = GetSpinelDriver().CoprocessorHasCap(SPINEL_CAP_OPENTHREAD_LOG_METADATA); @@ -251,7 +255,7 @@ otError RadioSpinel::CheckRadioCapabilities(otRadioCaps aRequiredRadioCaps) } } - DieNow(OT_EXIT_RADIO_SPINEL_INCOMPATIBLE); + HandleCompatabilityError(); } 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); + HandleCompatabilityError(); } } @@ -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); + HandleCompatabilityError(); } } @@ -2395,5 +2399,24 @@ otError RadioSpinel::SetChannelTargetPower(uint8_t aChannel, int16_t aTargetPowe } #endif // OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE +#if OPENTHREAD_SPINEL_CONFIG_COMPATABILITY_ERROR_CALLBACK_ENABLE +void RadioSpinel::SetCompatabilityErrorCallback(otRadioSpinelCompatabilityErrorCallback aCallback, void *aContext) +{ + mCompatabilityErrorCallback = aCallback; + mCompatabilityErrorContext = aContext; +} +#endif // OPENTHREAD_SPINEL_CONFIG_COMPATABILITY_ERROR_CALLBACK_ENABLE + +void RadioSpinel::HandleCompatabilityError(void) +{ +#if OPENTHREAD_SPINEL_CONFIG_COMPATABILITY_ERROR_CALLBACK_ENABLE + if (mCompatabilityErrorCallback) + { + mCompatabilityErrorCallback(mCompatabilityErrorContext); + } +#endif // OPENTHREAD_SPINEL_CONFIG_COMPATABILITY_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 241d7aed60f3..dfccb449fa4c 100644 --- a/src/lib/spinel/radio_spinel.hpp +++ b/src/lib/spinel/radio_spinel.hpp @@ -1090,8 +1090,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. @@ -1100,12 +1102,36 @@ 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_COMPATABILITY_ERROR_CALLBACK_ENABLE + /** + * A callback type for handling compatability error of radio spinel. + * + * @param[in] aContext A pointer to the user context. + * + */ + typedef void (*otRadioSpinelCompatabilityErrorCallback)(void *aContext); + + /** + * Registers a callback to handle error of radio spinel. + * + * This function is used to register a callback to handle radio spinel compatability errors. When a radio spinel + * compatability 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 SetCompatabilityErrorCallback(otRadioSpinelCompatabilityErrorCallback aCallback, void *aContext); +#endif + /** * Enables or disables the time synchronization between the host and RCP. * @@ -1244,6 +1270,8 @@ class RadioSpinel : private Logger void PlatDiagOutput(const char *aFormat, ...); #endif + void HandleCompatabilityError(void); + otInstance *mInstance; RadioSpinelCallbacks mCallbacks; ///< Callbacks for notifications of higher layer. @@ -1349,6 +1377,11 @@ class RadioSpinel : private Logger void *mVendorRestorePropertiesContext; #endif +#if OPENTHREAD_SPINEL_CONFIG_COMPATABILITY_ERROR_CALLBACK_ENABLE + otRadioSpinelCompatabilityErrorCallback mCompatabilityErrorCallback; + void *mCompatabilityErrorContext; +#endif + bool mTimeSyncEnabled : 1; bool mTimeSyncOn : 1;