[spinel] add coprocessor reset failure callback (#11284)

Add a coprocessor reset failure callback to handle the coprocessor
reset failure instead of letting the program crash directly.
This commit is contained in:
xusiyu
2025-03-24 08:49:27 -07:00
committed by GitHub
parent 52ebf6f821
commit 036256729c
7 changed files with 78 additions and 2 deletions
+1
View File
@@ -261,6 +261,7 @@ ot_option(OT_UPTIME OPENTHREAD_CONFIG_UPTIME_ENABLE "uptime")
ot_option(OT_VERHOEFF_CHECKSUM OPENTHREAD_CONFIG_VERHOEFF_CHECKSUM_ENABLE "verhoeff checksum")
ot_option(OT_WAKEUP_COORDINATOR OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE "wake-up coordinator")
ot_option(OT_WAKEUP_END_DEVICE OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE "wake-up end device")
ot_option(OT_SPINEL_CP_RESET_FAIL_CALLBACK_ENABLE OPENTHREAD_SPINEL_CONFIG_COPROCESSOR_RESET_FAILURE_CALLBACK_ENABLE "CP reset failure callback")
option(OT_DOC "build OpenThread documentation")
message(STATUS "- - - - - - - - - - - - - - - - ")
+1 -1
View File
@@ -76,7 +76,7 @@ main()
fi
reset_source
build -DOT_POSIX_RCP_VENDOR_BUS=ON "$@"
build -DOT_POSIX_RCP_VENDOR_BUS=ON -DOT_SPINEL_CP_RESET_FAIL_CALLBACK_ENABLE=ON "$@"
}
main "$@"
@@ -163,4 +163,13 @@
#define OPENTHREAD_SPINEL_CONFIG_RCP_TX_WAIT_TIME_SECS 5
#endif
/**
* @def OPENTHREAD_SPINEL_CONFIG_COPROCESSOR_RESET_FAILURE_CALLBACK_ENABLE
*
* Enables Co-processor reset failure callback in Spinel driver
*/
#ifndef OPENTHREAD_SPINEL_CONFIG_COPROCESSOR_RESET_FAILURE_CALLBACK_ENABLE
#define OPENTHREAD_SPINEL_CONFIG_COPROCESSOR_RESET_FAILURE_CALLBACK_ENABLE 0
#endif
#endif // OPENTHREAD_SPINEL_CONFIG_H_
+26 -1
View File
@@ -52,6 +52,10 @@ SpinelDriver::SpinelDriver(void)
, mSpinelVersionMajor(-1)
, mSpinelVersionMinor(-1)
, mIsCoprocessorReady(false)
#if OPENTHREAD_SPINEL_CONFIG_COPROCESSOR_RESET_FAILURE_CALLBACK_ENABLE
, mCoprocessorResetFailureCallback(nullptr)
, mCoprocessorResetFailureContext(nullptr)
#endif
{
memset(mVersion, 0, sizeof(mVersion));
@@ -119,6 +123,15 @@ exit:
return error;
}
#if OPENTHREAD_SPINEL_CONFIG_COPROCESSOR_RESET_FAILURE_CALLBACK_ENABLE
void SpinelDriver::SetCoprocessorResetFailureCallback(otSpinelDriverCoprocessorResetFailureCallback aCallback,
void *aContext)
{
mCoprocessorResetFailureCallback = aCallback;
mCoprocessorResetFailureContext = aContext;
}
#endif
void SpinelDriver::ResetCoprocessor(bool aSoftwareReset)
{
bool hardwareReset;
@@ -129,7 +142,13 @@ void SpinelDriver::ResetCoprocessor(bool aSoftwareReset)
VerifyOrExit(!mIsCoprocessorReady, resetDone = true);
#endif
mWaitingKey = SPINEL_PROP_LAST_STATUS;
// Before resetting the co-processor, mIsCoprocessorReady must be set to false.
// Otherwise, in some cases, the host may misinterpret the reset result.
// For example, if mIsCoprocessorReady is true when calling ResetCoprocessor,
// and the reset fails but the co-processor sends some invalid data, `WaitResponse`
// may mistakenly return OT_ERROR_NONE, causing the host to believe the reset succeeded.
mIsCoprocessorReady = false;
mWaitingKey = SPINEL_PROP_LAST_STATUS;
if (aSoftwareReset && (SendReset(SPINEL_RESET_STACK) == OT_ERROR_NONE) && (WaitResponse() == OT_ERROR_NONE))
{
@@ -160,6 +179,12 @@ exit:
if (!resetDone)
{
LogCrit("Failed to reset co-processor!");
#if OPENTHREAD_SPINEL_CONFIG_COPROCESSOR_RESET_FAILURE_CALLBACK_ENABLE
if (mCoprocessorResetFailureCallback)
{
mCoprocessorResetFailureCallback(mCoprocessorResetFailureContext);
}
#endif
DieNow(OT_EXIT_FAILURE);
}
}
+26
View File
@@ -215,6 +215,27 @@ public:
*/
spinel_iid_t GetIid(void) { return mIid; }
#if OPENTHREAD_SPINEL_CONFIG_COPROCESSOR_RESET_FAILURE_CALLBACK_ENABLE
/**
* A callback type for handling Co-processor reset failure of spinel driver.
*
* @param[in] aContext A pointer to the user context.
*/
typedef void (*otSpinelDriverCoprocessorResetFailureCallback)(void *aContext);
/**
* Registers a callback to handle Co-processor reset failure of Spinel driver.
*
* This function is used to register a callback to handle Co-processor reset failure.
* When the Spinel driver fails to reset the Co-processor through both software and
* hardware resets, the user can handle the error through the callback(such as OTA).
*
* @param[in] aCallback The callback.
* @param[in] aContext A pointer to the user context.
*/
void SetCoprocessorResetFailureCallback(otSpinelDriverCoprocessorResetFailureCallback aCallback, void *aContext);
#endif
private:
static constexpr uint16_t kMaxSpinelFrame = SPINEL_FRAME_MAX_SIZE;
static constexpr uint16_t kVersionStringSize = 128;
@@ -314,6 +335,11 @@ private:
char mVersion[kVersionStringSize];
Array<unsigned int, kCapsBufferSize> mCoprocessorCaps;
#if OPENTHREAD_SPINEL_CONFIG_COPROCESSOR_RESET_FAILURE_CALLBACK_ENABLE
otSpinelDriverCoprocessorResetFailureCallback mCoprocessorResetFailureCallback;
void *mCoprocessorResetFailureContext;
#endif
};
} // namespace Spinel
+7
View File
@@ -444,6 +444,13 @@ void platformResolverUpdateFdSet(otSysMainloopContext *aContext);
*/
void platformResolverProcess(const otSysMainloopContext *aContext);
/**
* The callback for coprocessor reset failure.
*
* @param[in] aContext A pointer to the mainloop context.
*/
void platformCoprocessorResetFailed(void *aContext);
#ifdef __cplusplus
}
#endif
+8
View File
@@ -73,6 +73,10 @@ Radio::Radio(void)
{
}
#if OPENTHREAD_SPINEL_CONFIG_COPROCESSOR_RESET_FAILURE_CALLBACK_ENABLE
OT_TOOL_WEAK void platformCoprocessorResetFailed(void *) {}
#endif
void Radio::Init(const char *aUrl)
{
bool resetRadio;
@@ -107,6 +111,10 @@ void Radio::Init(const char *aUrl)
resetRadio = !mRadioUrl.HasParam("no-reset");
skipCompatibilityCheck = mRadioUrl.HasParam("skip-rcp-compatibility-check");
#if OPENTHREAD_SPINEL_CONFIG_COPROCESSOR_RESET_FAILURE_CALLBACK_ENABLE
GetSpinelDriver().SetCoprocessorResetFailureCallback(platformCoprocessorResetFailed, this);
#endif
mRadioSpinel.SetCallbacks(callbacks);
mRadioSpinel.Init(skipCompatibilityCheck, resetRadio, &GetSpinelDriver(),
(skipCompatibilityCheck ? 0 : kRequiredRadioCaps), aEnableRcpTimeSync);