diff --git a/src/lib/spinel/radio_spinel.hpp b/src/lib/spinel/radio_spinel.hpp index 4ed17448c..da3ec1731 100644 --- a/src/lib/spinel/radio_spinel.hpp +++ b/src/lib/spinel/radio_spinel.hpp @@ -650,13 +650,16 @@ public: otError SetMacFrameCounter(uint32_t aMacFrameCounter); /** - * This method checks whether the spinel interface is radio-only + * This method checks whether the spinel interface is radio-only. + * + * @param[out] aSupportsRcpApiVersion A reference to a boolean variable to update whether the list of spinel + * capabilities include `SPINEL_CAP_RCP_API_VERSION`. * * @retval TRUE The radio chip is in radio-only mode. * @retval FALSE Otherwise. * */ - bool IsRcp(void); + bool IsRcp(bool &aSupportsRcpApiVersion); /** * This method checks whether there is pending frame in the buffer. @@ -726,6 +729,7 @@ private: otError CheckSpinelVersion(void); otError CheckRadioCapabilities(void); + otError CheckRcpApiVersion(bool aSupportsRcpApiVersion); /** * This method triggers a state transfer of the state machine. diff --git a/src/lib/spinel/radio_spinel_impl.hpp b/src/lib/spinel/radio_spinel_impl.hpp index d0bbc3d3f..58dce3c6f 100644 --- a/src/lib/spinel/radio_spinel_impl.hpp +++ b/src/lib/spinel/radio_spinel_impl.hpp @@ -222,6 +222,7 @@ template void RadioSpinel::Init(bool aResetRadio, bool aRestoreDatasetFromNcp) { otError error = OT_ERROR_NONE; + bool supportsRcpApiVersion; #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0 mResetRadioOnStartup = aResetRadio; @@ -239,7 +240,7 @@ void RadioSpinel::Init(bool aResetRadio, bool SuccessOrExit(error = Get(SPINEL_PROP_NCP_VERSION, SPINEL_DATATYPE_UTF8_S, mVersion, sizeof(mVersion))); SuccessOrExit(error = Get(SPINEL_PROP_HWADDR, SPINEL_DATATYPE_EUI64_S, mIeeeEui64.m8)); - if (!IsRcp()) + if (!IsRcp(supportsRcpApiVersion)) { uint8_t exitCode = OT_EXIT_RADIO_SPINEL_INCOMPATIBLE; @@ -251,6 +252,7 @@ void RadioSpinel::Init(bool aResetRadio, bool DieNow(exitCode); } + SuccessOrDie(CheckRcpApiVersion(supportsRcpApiVersion)); SuccessOrDie(CheckRadioCapabilities()); mRxRadioFrame.mPsdu = mRxPsdu; @@ -285,7 +287,7 @@ exit: } template -bool RadioSpinel::IsRcp(void) +bool RadioSpinel::IsRcp(bool &aSupportsRcpApiVersion) { uint8_t capsBuffer[kCapsBufferSize]; const uint8_t *capsData = capsBuffer; @@ -293,6 +295,8 @@ bool RadioSpinel::IsRcp(void) bool supportsRawRadio = false; bool isRcp = false; + aSupportsRcpApiVersion = false; + SuccessOrDie(Get(SPINEL_PROP_CAPS, SPINEL_DATATYPE_DATA_S, capsBuffer, &capsLength)); while (capsLength > 0) @@ -318,6 +322,11 @@ bool RadioSpinel::IsRcp(void) mSupportsLogStream = true; } + if (capability == SPINEL_CAP_RCP_API_VERSION) + { + aSupportsRcpApiVersion = true; + } + capsData += unpacked; capsLength -= static_cast(unpacked); } @@ -364,6 +373,36 @@ exit: return error; } +template +otError RadioSpinel::CheckRcpApiVersion(bool aSupportsRcpApiVersion) +{ + otError error = OT_ERROR_NONE; + unsigned int rcpApiVersion = 1; + + // Use RCP API Version value 1, when the RCP capability + // list does not contain `SPINEL_CAP_RCP_API_VERSION`. + + if (aSupportsRcpApiVersion) + { + SuccessOrExit(error = Get(SPINEL_PROP_RCP_API_VERSION, SPINEL_DATATYPE_UINT_PACKED_S, &rcpApiVersion)); + } + + otLogNotePlat("RCP API Version: %u", rcpApiVersion); + + static_assert(SPINEL_MIN_HOST_SUPPORTED_RCP_API_VERSION <= SPINEL_RCP_API_VERSION, + "MIN_HOST_SUPPORTED_RCP_API_VERSION must be smaller than or equal to RCP_API_VERSION"); + + if ((rcpApiVersion < SPINEL_MIN_HOST_SUPPORTED_RCP_API_VERSION) || (rcpApiVersion > SPINEL_RCP_API_VERSION)) + { + otLogCritPlat("RCP API Version %u is not in the supported range [%u-%u]", rcpApiVersion, + SPINEL_MIN_HOST_SUPPORTED_RCP_API_VERSION, SPINEL_RCP_API_VERSION); + DieNow(OT_EXIT_RADIO_SPINEL_INCOMPATIBLE); + } + +exit: + return error; +} + template otError RadioSpinel::RestoreDatasetFromNcp(void) {