[spinel] allow registering callback to handle compatibility errors (#10724)

When the RCP capabilities check fails, a mechanism should be provided
to notify the user of the error instead of causing the program to
crash.

For example, the hardware reboot function provided in the Spinel
driver interface could be invoked. The specific hardware reboot
implementation is left to the user, such as performing an RCP update.
This commit is contained in:
gytxxsy
2024-10-15 09:16:14 -07:00
committed by GitHub
parent 7ec2c31816
commit 328e247341
3 changed files with 70 additions and 8 deletions
@@ -136,6 +136,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
*
+29 -6
View File
@@ -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();
}
}
@@ -2399,5 +2403,24 @@ exit:
}
#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
void RadioSpinel::HandleCompatibilityError(void)
{
#if OPENTHREAD_SPINEL_CONFIG_COMPATIBILITY_ERROR_CALLBACK_ENABLE
if (mCompatibilityErrorCallback)
{
mCompatibilityErrorCallback(mCompatibilityErrorContext);
}
#endif
DieNow(OT_EXIT_RADIO_SPINEL_INCOMPATIBLE);
}
} // namespace Spinel
} // namespace ot
+32 -2
View File
@@ -1006,8 +1006,10 @@ public:
/**
* 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 @@ public:
* 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 @@ private:
void PlatDiagOutput(const char *aFormat, ...);
#endif
void HandleCompatibilityError(void);
otInstance *mInstance;
RadioSpinelCallbacks mCallbacks; ///< Callbacks for notifications of higher layer.
@@ -1262,6 +1287,11 @@ private:
void *mVendorRestorePropertiesContext;
#endif
#if OPENTHREAD_SPINEL_CONFIG_COMPATIBILITY_ERROR_CALLBACK_ENABLE
otRadioSpinelCompatibilityErrorCallback mCompatibilityErrorCallback;
void *mCompatibilityErrorContext;
#endif
bool mTimeSyncEnabled : 1;
bool mTimeSyncOn : 1;