From 9e4cbb8c60dcef74baf0b34a05849e16f5fbdaa9 Mon Sep 17 00:00:00 2001 From: Li Cao Date: Thu, 2 May 2024 13:00:34 +0800 Subject: [PATCH] [spinel] breakdown posix radio module (#10051) This commit breaks down current posix radio module into `Radio` and `SpinelManager`. The static instance of `SpinelDriver` is moved from `Radio` to `SpinelManager`. The `platformRadioXXX` methods are also broken down into `platformSpinelXXX` and `platformRadioXXX`. The purpose is to make `platformSpinelXXX` resuable under both NCP and RCP cases. And to use `platformSpinelInit` to detect to co-processor type during initialization. --- src/lib/spinel/radio_spinel.cpp | 71 ++++---- src/lib/spinel/radio_spinel.hpp | 44 ++--- src/lib/spinel/spinel_driver.cpp | 35 +++- src/lib/spinel/spinel_driver.hpp | 20 ++- src/posix/platform/CMakeLists.txt | 1 + src/posix/platform/coprocessor_type.h | 50 ++++++ src/posix/platform/platform-posix.h | 48 +++++- src/posix/platform/radio.cpp | 117 +------------- src/posix/platform/radio.hpp | 17 +- src/posix/platform/spinel_manager.cpp | 224 ++++++++++++++++++++++++++ src/posix/platform/spinel_manager.hpp | 131 +++++++++++++++ src/posix/platform/system.cpp | 13 ++ src/posix/platform/virtual_time.cpp | 3 +- 13 files changed, 565 insertions(+), 209 deletions(-) create mode 100644 src/posix/platform/coprocessor_type.h create mode 100644 src/posix/platform/spinel_manager.cpp create mode 100644 src/posix/platform/spinel_manager.hpp diff --git a/src/lib/spinel/radio_spinel.cpp b/src/lib/spinel/radio_spinel.cpp index 65d2123f7..73507ff5a 100644 --- a/src/lib/spinel/radio_spinel.cpp +++ b/src/lib/spinel/radio_spinel.cpp @@ -53,12 +53,8 @@ namespace ot { namespace Spinel { -char RadioSpinel::sVersion[kVersionStringSize] = ""; - otExtAddress RadioSpinel::sIeeeEui64; -bool RadioSpinel::sIsReady = false; ///< NCP ready. - bool RadioSpinel::sSupportsLogStream = false; ///< RCP supports `LOG_STREAM` property with OpenThread log meta-data format. @@ -71,7 +67,6 @@ otRadioCaps RadioSpinel::sRadioCaps = OT_RADIO_CAPS_NONE; RadioSpinel::RadioSpinel(void) : Logger("RadioSpinel") , mInstance(nullptr) - , mSpinelInterface(nullptr) , mCmdTidsInUse(0) , mCmdNextTid(1) , mTxRadioTid(0) @@ -80,7 +75,6 @@ RadioSpinel::RadioSpinel(void) , mPropertyFormat(nullptr) , mExpectedCommand(0) , mError(OT_ERROR_NONE) - , mIid(SPINEL_HEADER_INVALID_IID) , mTransmitFrame(nullptr) , mShortAddress(0) , mPanId(0xffff) @@ -117,35 +111,32 @@ RadioSpinel::RadioSpinel(void) , mVendorRestorePropertiesCallback(nullptr) , mVendorRestorePropertiesContext(nullptr) #endif + , mSpinelDriver(nullptr) { memset(&mRadioSpinelMetrics, 0, sizeof(mRadioSpinelMetrics)); memset(&mCallbacks, 0, sizeof(mCallbacks)); } -void RadioSpinel::Init(SpinelInterface &aSpinelInterface, - bool aResetRadio, - bool aSkipRcpCompatibilityCheck, - const spinel_iid_t *aIidList, - uint8_t aIidListLength) +void RadioSpinel::Init(bool aSkipRcpCompatibilityCheck, bool aSoftwareReset, SpinelDriver *aSpinelDriver) { otError error = OT_ERROR_NONE; bool supportsRcpApiVersion; bool supportsRcpMinHostApiVersion; + OT_UNUSED_VARIABLE(aSoftwareReset); + #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0 - mResetRadioOnStartup = aResetRadio; + mResetRadioOnStartup = aSoftwareReset; #endif - mSpinelInterface = &aSpinelInterface; + mSpinelDriver = aSpinelDriver; + mSpinelDriver->SetFrameHandler(&HandleReceivedFrame, &HandleSavedFrame, this); #if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT && OPENTHREAD_CONFIG_TIME_SYNC_ENABLE memset(&mTxIeInfo, 0, sizeof(otRadioIeInfo)); mTxRadioFrame.mInfo.mTxInfo.mIeInfo = &mTxIeInfo; #endif - mSpinelDriver.Init(aSpinelInterface, aResetRadio, aIidList, aIidListLength); - mSpinelDriver.SetFrameHandler(&HandleReceivedFrame, &HandleSavedFrame, this); - SuccessOrExit(error = Get(SPINEL_PROP_HWADDR, SPINEL_DATATYPE_EUI64_S, sIeeeEui64.m8)); InitializeCaps(supportsRcpApiVersion, supportsRcpMinHostApiVersion); @@ -207,22 +198,23 @@ exit: void RadioSpinel::InitializeCaps(bool &aSupportsRcpApiVersion, bool &aSupportsRcpMinHostApiVersion) { - if (!mSpinelDriver.CoprocessorHasCap(SPINEL_CAP_CONFIG_RADIO)) + if (!GetSpinelDriver().CoprocessorHasCap(SPINEL_CAP_CONFIG_RADIO)) { LogCrit("The co-processor isn't a RCP!"); DieNow(OT_EXIT_RADIO_SPINEL_INCOMPATIBLE); } - if (!mSpinelDriver.CoprocessorHasCap(SPINEL_CAP_MAC_RAW)) + + 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); } - sSupportsLogStream = mSpinelDriver.CoprocessorHasCap(SPINEL_CAP_OPENTHREAD_LOG_METADATA); - aSupportsRcpApiVersion = mSpinelDriver.CoprocessorHasCap(SPINEL_CAP_RCP_API_VERSION); - aSupportsRcpMinHostApiVersion = mSpinelDriver.CoprocessorHasCap(SPINEL_CAP_RCP_MIN_HOST_API_VERSION); - sSupportsResetToBootloader = mSpinelDriver.CoprocessorHasCap(SPINEL_CAP_RCP_RESET_TO_BOOTLOADER); - sSupportsLogCrashDump = mSpinelDriver.CoprocessorHasCap(SPINEL_CAP_RCP_LOG_CRASH_DUMP); + sSupportsLogStream = GetSpinelDriver().CoprocessorHasCap(SPINEL_CAP_OPENTHREAD_LOG_METADATA); + aSupportsRcpApiVersion = GetSpinelDriver().CoprocessorHasCap(SPINEL_CAP_RCP_API_VERSION); + sSupportsResetToBootloader = GetSpinelDriver().CoprocessorHasCap(SPINEL_CAP_RCP_RESET_TO_BOOTLOADER); + aSupportsRcpMinHostApiVersion = GetSpinelDriver().CoprocessorHasCap(SPINEL_PROP_RCP_MIN_HOST_API_VERSION); + sSupportsLogCrashDump = GetSpinelDriver().CoprocessorHasCap(SPINEL_CAP_RCP_LOG_CRASH_DUMP); } otError RadioSpinel::CheckRadioCapabilities(void) @@ -312,12 +304,6 @@ exit: void RadioSpinel::Deinit(void) { - if (mSpinelInterface != nullptr) - { - mSpinelInterface->Deinit(); - mSpinelInterface = nullptr; - } - // This allows implementing pseudo reset. new (this) RadioSpinel(); } @@ -525,11 +511,10 @@ void RadioSpinel::HandleValueIs(spinel_prop_key_t aKey, const uint8_t *aBuffer, } // this clear is necessary in case the RCP has sent messages between disable and reset - mSpinelDriver.ClearRxBuffer(); - mSpinelDriver.SetCoprocessorReady(); + mSpinelDriver->ClearRxBuffer(); + mSpinelDriver->SetCoprocessorReady(); LogInfo("RCP reset: %s", spinel_status_to_cstr(status)); - sIsReady = true; } else if (status == SPINEL_STATUS_SWITCHOVER_DONE || status == SPINEL_STATUS_SWITCHOVER_FAILED) { @@ -630,6 +615,12 @@ void RadioSpinel::SetVendorRestorePropertiesCallback(otRadioSpinelVendorRestoreP } #endif +SpinelDriver &RadioSpinel::GetSpinelDriver(void) const +{ + OT_ASSERT(mSpinelDriver != nullptr); + return *mSpinelDriver; +} + otError RadioSpinel::SendReset(uint8_t aResetType) { otError error; @@ -638,7 +629,7 @@ otError RadioSpinel::SendReset(uint8_t aResetType) { ExitNow(error = OT_ERROR_NOT_CAPABLE); } - error = mSpinelDriver.SendReset(aResetType); + error = GetSpinelDriver().SendReset(aResetType); exit: return error; @@ -788,7 +779,7 @@ void RadioSpinel::ProcessRadioStateMachine(void) void RadioSpinel::Process(const void *aContext) { - mSpinelDriver.Process(aContext); + OT_UNUSED_VARIABLE(aContext); ProcessRadioStateMachine(); RecoverFromRcpFailure(); @@ -1383,7 +1374,7 @@ otError RadioSpinel::WaitResponse(bool aHandleRcpTimeout) uint64_t now; now = otPlatTimeGet(); - if ((end <= now) || (mSpinelInterface->WaitForFrame(end - now) != OT_ERROR_NONE)) + if ((end <= now) || (GetSpinelDriver().GetSpinelInterface()->WaitForFrame(end - now) != OT_ERROR_NONE)) { LogWarn("Wait for response timeout"); if (aHandleRcpTimeout) @@ -1433,7 +1424,7 @@ otError RadioSpinel::RequestV(uint32_t command, spinel_prop_key_t aKey, const ch VerifyOrExit(tid > 0, error = OT_ERROR_BUSY); - error = mSpinelDriver.SendCommand(command, aKey, tid, aFormat, aArgs); + error = GetSpinelDriver().SendCommand(command, aKey, tid, aFormat, aArgs); SuccessOrExit(error); if (aKey == SPINEL_PROP_STREAM_RAW) @@ -1887,7 +1878,7 @@ exit: uint64_t RadioSpinel::GetNow(void) { return (mIsTimeSynced) ? (otPlatTimeGet() + mRadioTimeOffset) : UINT64_MAX; } -uint32_t RadioSpinel::GetBusSpeed(void) const { return mSpinelInterface->GetBusSpeed(); } +uint32_t RadioSpinel::GetBusSpeed(void) const { return GetSpinelDriver().GetSpinelInterface()->GetBusSpeed(); } void RadioSpinel::HandleRcpUnexpectedReset(spinel_status_t aStatus) { @@ -1953,14 +1944,14 @@ void RadioSpinel::RecoverFromRcpFailure(void) mState = kStateDisabled; - mSpinelDriver.ClearRxBuffer(); + GetSpinelDriver().ClearRxBuffer(); if (skipReset) { - mSpinelDriver.SetCoprocessorReady(); + GetSpinelDriver().SetCoprocessorReady(); } else { - mSpinelDriver.ResetCoprocessor(mResetRadioOnStartup); + GetSpinelDriver().ResetCoprocessor(mResetRadioOnStartup); } mCmdTidsInUse = 0; diff --git a/src/lib/spinel/radio_spinel.hpp b/src/lib/spinel/radio_spinel.hpp index 6eb5e4e4c..2096b720d 100644 --- a/src/lib/spinel/radio_spinel.hpp +++ b/src/lib/spinel/radio_spinel.hpp @@ -158,19 +158,13 @@ public: /** * Initialize this radio transceiver. * - * @param[in] aSpinelInterface A reference to the Spinel interface. - * @param[in] aResetRadio TRUE to reset on init, FALSE to not reset on init. * @param[in] aSkipRcpCompatibilityCheck TRUE to skip RCP compatibility check, FALSE to perform the check. - * @param[in] aIidList A Pointer to the list of IIDs to receive spinel frame from. - * First entry must be the IID of the Host Application. - * @param[in] aIidListLength The Length of the @p aIidList. + * @param[in] aSoftwareReset When doing RCP recovery, TRUE to try software reset first, FALSE to + * directly do a hardware reset. + * @param[in] aSpinelDriver A pointer to the spinel driver instance that this object depends on. * */ - void Init(SpinelInterface &aSpinelInterface, - bool aResetRadio, - bool aSkipRcpCompatibilityCheck, - const spinel_iid_t *aIidList, - uint8_t aIidListLength); + void Init(bool aSkipRcpCompatibilityCheck, bool aSoftwareReset, SpinelDriver *aSpinelDriver); /** * This method sets the notification callbacks. @@ -815,7 +809,7 @@ public: * @returns Whether there is pending frame in the buffer. * */ - bool HasPendingFrame(void) const { return mSpinelDriver.HasPendingFrame(); } + bool HasPendingFrame(void) const { return mSpinelDriver->HasPendingFrame(); } /** * Returns the next timepoint to recalculate RCP time offset. @@ -847,7 +841,7 @@ public: * @returns A pointer to the co-processor version string. * */ - const char *GetVersion(void) const { return mSpinelDriver.GetVersion(); } + const char *GetVersion(void) const { return mSpinelDriver->GetVersion(); } /** * Sets the max transmit power. @@ -1101,6 +1095,8 @@ private: typedef otError (RadioSpinel::*ResponseHandler)(const uint8_t *aBuffer, uint16_t aLength); + SpinelDriver &GetSpinelDriver(void) const; + otError CheckSpinelVersion(void); otError CheckRadioCapabilities(void); otError CheckRcpApiVersion(bool aSupportsRcpApiVersion, bool aSupportsRcpMinHostApiVersion); @@ -1200,9 +1196,6 @@ private: otInstance *mInstance; - SpinelInterface::RxFrameBuffer mRxFrameBuffer; - SpinelInterface *mSpinelInterface; - RadioSpinelCallbacks mCallbacks; ///< Callbacks for notifications of higher layer. uint16_t mCmdTidsInUse; ///< Used transaction ids. @@ -1214,16 +1207,13 @@ private: va_list mPropertyArgs; ///< The arguments pack or unpack spinel property of current transaction. uint32_t mExpectedCommand; ///< Expected response command of current transaction. otError mError; ///< The result of current transaction. - spinel_iid_t mIid; ///< The spinel interface id used by this process. - spinel_iid_t mIidList[kSpinelHeaderMaxNumIid]; ///< Array of interface ids to accept the incoming spinel frames. - - uint8_t mRxPsdu[OT_RADIO_FRAME_MAX_SIZE]; - uint8_t mTxPsdu[OT_RADIO_FRAME_MAX_SIZE]; - uint8_t mAckPsdu[OT_RADIO_FRAME_MAX_SIZE]; - otRadioFrame mRxRadioFrame; - otRadioFrame mTxRadioFrame; - otRadioFrame mAckRadioFrame; - otRadioFrame *mTransmitFrame; ///< Points to the frame to send + uint8_t mRxPsdu[OT_RADIO_FRAME_MAX_SIZE]; + uint8_t mTxPsdu[OT_RADIO_FRAME_MAX_SIZE]; + uint8_t mAckPsdu[OT_RADIO_FRAME_MAX_SIZE]; + otRadioFrame mRxRadioFrame; + otRadioFrame mTxRadioFrame; + otRadioFrame mAckRadioFrame; + otRadioFrame *mTransmitFrame; ///< Points to the frame to send #if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT && OPENTHREAD_CONFIG_TIME_SYNC_ENABLE otRadioIeInfo mTxIeInfo; @@ -1235,7 +1225,6 @@ private: uint8_t mChannel; int8_t mRxSensitivity; otError mTxError; - static char sVersion[kVersionStringSize]; static otExtAddress sIeeeEui64; static otRadioCaps sRadioCaps; @@ -1244,7 +1233,6 @@ private: bool mRxOnWhenIdle : 1; ///< RxOnWhenIdle mode. bool mIsTimeSynced : 1; ///< Host has calculated the time difference between host and RCP. - static bool sIsReady; ///< NCP ready. static bool sSupportsLogStream; ///< RCP supports `LOG_STREAM` property with OpenThread log meta-data format. static bool sSupportsResetToBootloader; ///< RCP supports resetting into bootloader mode. static bool sSupportsLogCrashDump; ///< RCP supports logging a crash dump. @@ -1311,7 +1299,7 @@ private: void *mVendorRestorePropertiesContext; #endif - SpinelDriver mSpinelDriver; + SpinelDriver *mSpinelDriver; }; } // namespace Spinel diff --git a/src/lib/spinel/spinel_driver.cpp b/src/lib/spinel/spinel_driver.cpp index dcf244531..0f49262cc 100644 --- a/src/lib/spinel/spinel_driver.cpp +++ b/src/lib/spinel/spinel_driver.cpp @@ -59,11 +59,13 @@ SpinelDriver::SpinelDriver(void) mFrameHandlerContext = this; } -void SpinelDriver::Init(SpinelInterface &aSpinelInterface, - bool aSoftwareReset, - const spinel_iid_t *aIidList, - uint8_t aIidListLength) +CoprocessorType SpinelDriver::Init(SpinelInterface &aSpinelInterface, + bool aSoftwareReset, + const spinel_iid_t *aIidList, + uint8_t aIidListLength) { + CoprocessorType coprocessorType; + mSpinelInterface = &aSpinelInterface; mRxFrameBuffer.Clear(); SuccessOrDie(mSpinelInterface->Init(HandleReceivedFrame, this, mRxFrameBuffer)); @@ -81,6 +83,15 @@ void SpinelDriver::Init(SpinelInterface &aSpinelInterface, SuccessOrDie(CheckSpinelVersion()); SuccessOrDie(GetCoprocessorVersion()); SuccessOrDie(GetCoprocessorCaps()); + + coprocessorType = GetCoprocessorType(); + if (coprocessorType == OT_COPROCESSOR_UNKNOWN) + { + LogCrit("The coprocessor mode is unknown!"); + DieNow(OT_EXIT_FAILURE); + } + + return coprocessorType; } void SpinelDriver::Deinit(void) @@ -447,6 +458,22 @@ exit: return error; } +CoprocessorType SpinelDriver::GetCoprocessorType(void) +{ + CoprocessorType type = OT_COPROCESSOR_UNKNOWN; + + if (CoprocessorHasCap(SPINEL_CAP_CONFIG_RADIO)) + { + type = OT_COPROCESSOR_RCP; + } + else if (CoprocessorHasCap(SPINEL_CAP_CONFIG_FTD) || CoprocessorHasCap(SPINEL_CAP_CONFIG_MTD)) + { + type = OT_COPROCESSOR_NCP; + } + + return type; +} + void SpinelDriver::ProcessFrameQueue(void) { uint8_t *frame = nullptr; diff --git a/src/lib/spinel/spinel_driver.hpp b/src/lib/spinel/spinel_driver.hpp index fe412c1f1..2e00c694d 100644 --- a/src/lib/spinel/spinel_driver.hpp +++ b/src/lib/spinel/spinel_driver.hpp @@ -34,6 +34,7 @@ #include "lib/spinel/logger.hpp" #include "lib/spinel/spinel.h" #include "lib/spinel/spinel_interface.hpp" +#include "posix/platform/coprocessor_type.h" namespace ot { namespace Spinel { @@ -70,11 +71,15 @@ public: * First entry must be the IID of the Host Application. * @param[in] aIidListLength The Length of the @p aIidList. * + * @retval OT_COPROCESSOR_UNKNOWN The initialization fails. + * @retval OT_COPROCESSOR_RCP The Co-processor is a RCP. + * @retval OT_COPROCESSOR_NCP The Co-processor is a NCP. + * */ - void Init(SpinelInterface &aSpinelInterface, - bool aSoftwareReset, - const spinel_iid_t *aIidList, - uint8_t aIidListLength); + CoprocessorType Init(SpinelInterface &aSpinelInterface, + bool aSoftwareReset, + const spinel_iid_t *aIidList, + uint8_t aIidListLength); /** * Deinitialize this SpinelDriver Instance. @@ -272,9 +277,10 @@ private: otError SendCommand(uint32_t aCommand, spinel_prop_key_t aKey, spinel_tid_t aTid); - otError CheckSpinelVersion(void); - otError GetCoprocessorVersion(void); - otError GetCoprocessorCaps(void); + otError CheckSpinelVersion(void); + otError GetCoprocessorVersion(void); + otError GetCoprocessorCaps(void); + CoprocessorType GetCoprocessorType(void); void ProcessFrameQueue(void); diff --git a/src/posix/platform/CMakeLists.txt b/src/posix/platform/CMakeLists.txt index 825d106dc..d38bebbfb 100644 --- a/src/posix/platform/CMakeLists.txt +++ b/src/posix/platform/CMakeLists.txt @@ -145,6 +145,7 @@ add_library(openthread-posix radio_url.cpp resolver.cpp settings.cpp + spinel_manager.cpp spi_interface.cpp system.cpp trel.cpp diff --git a/src/posix/platform/coprocessor_type.h b/src/posix/platform/coprocessor_type.h new file mode 100644 index 000000000..309f2d5c4 --- /dev/null +++ b/src/posix/platform/coprocessor_type.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef OT_PLATFORM_COPROCESSOR_MODE_H_ +#define OT_PLATFORM_COPROCESSOR_MODE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Represents the mode of the co-processor. + * A co-processor could be either a RCP or NCP. + */ +typedef enum CoprocessorType +{ + OT_COPROCESSOR_UNKNOWN = 0, + OT_COPROCESSOR_RCP = 1, + OT_COPROCESSOR_NCP = 2, +} CoprocessorType; + +#ifdef __cplusplus +} +#endif +#endif // OT_PLATFORM_COPROCESSOR_MODE_H_ diff --git a/src/posix/platform/platform-posix.h b/src/posix/platform/platform-posix.h index a5d3a302d..93ef4ac16 100644 --- a/src/posix/platform/platform-posix.h +++ b/src/posix/platform/platform-posix.h @@ -52,6 +52,7 @@ #include #include +#include "coprocessor_type.h" #include "lib/platform/exit_code.h" #include "lib/url/url.hpp" @@ -338,13 +339,22 @@ void virtualTimeReceiveEvent(struct VirtualTimeEvent *aEvent); void virtualTimeSendSleepEvent(const struct timeval *aTimeout); /** - * Performs radio spinel processing of virtual time simulation. + * Performs radio processing of virtual time simulation. * * @param[in] aInstance A pointer to the OpenThread instance. * @param[in] aEvent A pointer to the current event. * */ -void virtualTimeRadioSpinelProcess(otInstance *aInstance, const struct VirtualTimeEvent *aEvent); +void virtualTimeRadioProcess(otInstance *aInstance, const struct VirtualTimeEvent *aEvent); + +/** + * Performs radio processing of virtual time simulation. + * + * @param[in] aInstance A pointer to the OpenThread instance. + * @param[in] aEvent A pointer to the current event. + * + */ +void virtualTimeSpinelProcess(otInstance *aInstance, const struct VirtualTimeEvent *aEvent); enum SocketBlockOption { @@ -421,6 +431,40 @@ extern otInstance *gInstance; */ void platformBacktraceInit(void); +/** + * Initializes the spinel service used by OpenThread. + * + * @param[in] aUrl A pointer to the null-terminated spinel URL. + * + * @retval OT_COPROCESSOR_UNKNOWN The initialization fails. + * @retval OT_COPROCESSOR_RCP The Co-processor is a RCP. + * @retval OT_COPROCESSOR_NCP The Co-processor is a NCP. + */ +CoprocessorType platformSpinelManagerInit(const char *aUrl); + +/** + * Shuts down the spinel service used by OpenThread. + * + */ +void platformSpinelManagerDeinit(void); + +/** + * Performs spinel driver processing. + * + * @param[in] aInstance A pointer to the OT instance. + * @param[in] aContext A pointer to the mainloop context. + * + */ +void platformSpinelManagerProcess(otInstance *aInstance, const otSysMainloopContext *aContext); + +/** + * Updates the file descriptor sets with file descriptors used by the spinel driver. + * + * @param[in] aContext A pointer to the mainloop context. + * + */ +void platformSpinelManagerUpdateFdSet(otSysMainloopContext *aContext); + #ifdef __cplusplus } #endif diff --git a/src/posix/platform/radio.cpp b/src/posix/platform/radio.cpp index f5eb17cc2..2d5716efa 100644 --- a/src/posix/platform/radio.cpp +++ b/src/posix/platform/radio.cpp @@ -41,6 +41,7 @@ #include "common/code_utils.hpp" #include "common/new.hpp" #include "posix/platform/radio.hpp" +#include "posix/platform/spinel_manager.hpp" #include "utils/parse_cmdline.hpp" #if OPENTHREAD_POSIX_CONFIG_CONFIGURATION_FILE_ENABLE @@ -62,7 +63,6 @@ const char Radio::kLogModuleName[] = "Radio"; Radio::Radio(void) : mRadioUrl(nullptr) , mRadioSpinel() - , mSpinelInterface(nullptr) { } @@ -70,7 +70,6 @@ void Radio::Init(const char *aUrl) { bool resetRadio; bool skipCompatibilityCheck; - spinel_iid_t iidList[Spinel::kSpinelHeaderMaxNumIid]; struct ot::Spinel::RadioSpinelCallbacks callbacks; mRadioUrl.Init(aUrl); @@ -86,74 +85,15 @@ void Radio::Init(const char *aUrl) callbacks.mTransmitDone = otPlatRadioTxDone; callbacks.mTxStarted = otPlatRadioTxStarted; - GetIidListFromRadioUrl(iidList); - -#if OPENTHREAD_POSIX_VIRTUAL_TIME - VirtualTimeInit(); -#endif - - mSpinelInterface = CreateSpinelInterface(mRadioUrl.GetProtocol()); - VerifyOrDie(mSpinelInterface != nullptr, OT_EXIT_FAILURE); - resetRadio = !mRadioUrl.HasParam("no-reset"); skipCompatibilityCheck = mRadioUrl.HasParam("skip-rcp-compatibility-check"); mRadioSpinel.SetCallbacks(callbacks); - mRadioSpinel.Init(*mSpinelInterface, resetRadio, skipCompatibilityCheck, iidList, OT_ARRAY_LENGTH(iidList)); - LogDebg("instance init:%p - iid = %d", (void *)&mRadioSpinel, iidList[0]); + mRadioSpinel.Init(skipCompatibilityCheck, resetRadio, &SpinelManager::GetSpinelDriver()); ProcessRadioUrl(mRadioUrl); } -#if OPENTHREAD_POSIX_VIRTUAL_TIME -void Radio::VirtualTimeInit(void) -{ - // The last argument must be the node id - const char *nodeId = nullptr; - - for (const char *arg = nullptr; (arg = mRadioUrl.GetValue("forkpty-arg", arg)) != nullptr; nodeId = arg) - { - } - - virtualTimeInit(static_cast(atoi(nodeId))); -} -#endif - -Spinel::SpinelInterface *Radio::CreateSpinelInterface(const char *aInterfaceName) -{ - Spinel::SpinelInterface *interface; - - if (aInterfaceName == nullptr) - { - DieNow(OT_ERROR_FAILED); - } -#if OPENTHREAD_POSIX_CONFIG_SPINEL_HDLC_INTERFACE_ENABLE - else if (HdlcInterface::IsInterfaceNameMatch(aInterfaceName)) - { - interface = new (&mSpinelInterfaceRaw) HdlcInterface(mRadioUrl); - } -#endif -#if OPENTHREAD_POSIX_CONFIG_SPINEL_SPI_INTERFACE_ENABLE - else if (Posix::SpiInterface::IsInterfaceNameMatch(aInterfaceName)) - { - interface = new (&mSpinelInterfaceRaw) SpiInterface(mRadioUrl); - } -#endif -#if OPENTHREAD_POSIX_CONFIG_SPINEL_VENDOR_INTERFACE_ENABLE - else if (VendorInterface::IsInterfaceNameMatch(aInterfaceName)) - { - interface = new (&mSpinelInterfaceRaw) VendorInterface(mRadioUrl); - } -#endif - else - { - LogCrit("The Spinel interface name \"%s\" is not supported!", aInterfaceName); - DieNow(OT_ERROR_FAILED); - } - - return interface; -} - void Radio::ProcessRadioUrl(const RadioUrl &aRadioUrl) { const char *region; @@ -248,53 +188,6 @@ exit: #endif // OPENTHREAD_POSIX_CONFIG_MAX_POWER_TABLE_ENABLE } -void Radio::GetIidListFromRadioUrl(spinel_iid_t (&aIidList)[Spinel::kSpinelHeaderMaxNumIid]) -{ - const char *iidString; - const char *iidListString; - - memset(aIidList, SPINEL_HEADER_INVALID_IID, sizeof(aIidList)); - - iidString = (mRadioUrl.GetValue("iid")); - iidListString = (mRadioUrl.GetValue("iid-list")); - -#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE - // First entry to the aIidList must be the IID of the host application. - VerifyOrDie(iidString != nullptr, OT_EXIT_INVALID_ARGUMENTS); - aIidList[0] = static_cast(atoi(iidString)); - - if (iidListString != nullptr) - { - // Convert string to an array of integers. - // Integer i is for traverse the iidListString. - // Integer j is for aIidList array offset location. - // First entry of aIidList is for host application iid hence j start from 1. - for (uint8_t i = 0, j = 1; iidListString[i] != '\0' && j < Spinel::kSpinelHeaderMaxNumIid; i++) - { - if (iidListString[i] == ',') - { - j++; - continue; - } - - if (iidListString[i] < '0' || iidListString[i] > '9') - { - DieNow(OT_EXIT_INVALID_ARGUMENTS); - } - else - { - aIidList[j] = iidListString[i] - '0'; - VerifyOrDie(aIidList[j] < Spinel::kSpinelHeaderMaxNumIid, OT_EXIT_INVALID_ARGUMENTS); - } - } - } -#else // !OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE - VerifyOrDie(iidString == nullptr, OT_EXIT_INVALID_ARGUMENTS); - VerifyOrDie(iidListString == nullptr, OT_EXIT_INVALID_ARGUMENTS); - aIidList[0] = 0; -#endif // OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE -} - } // namespace Posix } // namespace ot @@ -439,9 +332,7 @@ void platformRadioUpdateFdSet(otSysMainloopContext *aContext) aContext->mTimeout.tv_usec = 0; } - sRadio.GetSpinelInterface().UpdateFdSet(aContext); - - if (GetRadioSpinel().HasPendingFrame() || GetRadioSpinel().IsTransmitDone()) + if (GetRadioSpinel().IsTransmitDone()) { aContext->mTimeout.tv_sec = 0; aContext->mTimeout.tv_usec = 0; @@ -449,7 +340,7 @@ void platformRadioUpdateFdSet(otSysMainloopContext *aContext) } #if OPENTHREAD_POSIX_VIRTUAL_TIME -void virtualTimeRadioSpinelProcess(otInstance *aInstance, const struct VirtualTimeEvent *aEvent) +void virtualTimeRadioProcess(otInstance *aInstance, const struct VirtualTimeEvent *aEvent) { OT_UNUSED_VARIABLE(aInstance); GetRadioSpinel().Process(aEvent); diff --git a/src/posix/platform/radio.hpp b/src/posix/platform/radio.hpp index e4a8b1a9e..4caa85f8d 100644 --- a/src/posix/platform/radio.hpp +++ b/src/posix/platform/radio.hpp @@ -33,9 +33,11 @@ #include "logger.hpp" #include "radio_url.hpp" #include "spi_interface.hpp" +#include "spinel_manager.hpp" #include "vendor_interface.hpp" #include "common/code_utils.hpp" #include "lib/spinel/radio_spinel.hpp" +#include "lib/spinel/spinel_driver.hpp" #if OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE #ifdef OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_HEADER #include OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_HEADER @@ -74,11 +76,7 @@ public: * @returns A reference to the radio's spinel interface instance. * */ - Spinel::SpinelInterface &GetSpinelInterface(void) - { - OT_ASSERT(mSpinelInterface != nullptr); - return *mSpinelInterface; - } + Spinel::SpinelInterface &GetSpinelInterface(void) { return SpinelManager::GetSpinelManager().GetSpinelInterface(); } /** * Acts as an accessor to the radio spinel instance used by the radio. @@ -89,15 +87,9 @@ public: Spinel::RadioSpinel &GetRadioSpinel(void) { return mRadioSpinel; } private: -#if OPENTHREAD_POSIX_VIRTUAL_TIME - void VirtualTimeInit(void); -#endif void ProcessRadioUrl(const RadioUrl &aRadioUrl); void ProcessMaxPowerTable(const RadioUrl &aRadioUrl); - Spinel::SpinelInterface *CreateSpinelInterface(const char *aInterfaceName); - void GetIidListFromRadioUrl(spinel_iid_t (&aIidList)[Spinel::kSpinelHeaderMaxNumIid]); - #if OPENTHREAD_POSIX_CONFIG_SPINEL_HDLC_INTERFACE_ENABLE && OPENTHREAD_POSIX_CONFIG_SPINEL_SPI_INTERFACE_ENABLE static constexpr size_t kSpinelInterfaceRawSize = sizeof(ot::Posix::SpiInterface) > sizeof(ot::Posix::HdlcInterface) ? sizeof(ot::Posix::SpiInterface) @@ -118,9 +110,6 @@ private: #else Spinel::RadioSpinel mRadioSpinel; #endif - Spinel::SpinelInterface *mSpinelInterface; - - OT_DEFINE_ALIGNED_VAR(mSpinelInterfaceRaw, kSpinelInterfaceRawSize, uint64_t); }; } // namespace Posix diff --git a/src/posix/platform/spinel_manager.cpp b/src/posix/platform/spinel_manager.cpp new file mode 100644 index 000000000..88037e385 --- /dev/null +++ b/src/posix/platform/spinel_manager.cpp @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2024, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "platform-posix.h" + +#include "posix/platform/spinel_manager.hpp" + +#include "common/code_utils.hpp" +#include "common/new.hpp" +#include "lib/spinel/spinel_driver.hpp" +#include "posix/platform/hdlc_interface.hpp" +#include "posix/platform/radio_url.hpp" +#include "posix/platform/spi_interface.hpp" +#include "posix/platform/vendor_interface.hpp" + +static ot::Posix::SpinelManager sSpinelManager; + +namespace ot { +namespace Posix { + +SpinelManager &SpinelManager::GetSpinelManager(void) { return sSpinelManager; } + +Spinel::SpinelDriver &SpinelManager::GetSpinelDriver(void) { return sSpinelManager.mSpinelDriver; } + +SpinelManager::SpinelManager(void) + : mUrl(nullptr) + , mSpinelDriver() + , mSpinelInterface(nullptr) +{ +} + +SpinelManager::~SpinelManager(void) { Deinit(); } + +CoprocessorType SpinelManager::Init(const char *aUrl) +{ + bool swReset; + spinel_iid_t iidList[Spinel::kSpinelHeaderMaxNumIid]; + CoprocessorType mode; + + mUrl.Init(aUrl); + VerifyOrDie(mUrl.GetPath() != nullptr, OT_EXIT_INVALID_ARGUMENTS); + + GetIidListFromUrl(iidList); + +#if OPENTHREAD_POSIX_VIRTUAL_TIME + VirtualTimeInit(); +#endif + + mSpinelInterface = CreateSpinelInterface(mUrl.GetProtocol()); + VerifyOrDie(mSpinelInterface != nullptr, OT_EXIT_FAILURE); + + swReset = !mUrl.HasParam("no-reset"); + + mode = mSpinelDriver.Init(*mSpinelInterface, swReset, iidList, OT_ARRAY_LENGTH(iidList)); + + otLogDebgPlat("instance init:%p - iid = %d", (void *)&mSpinelDriver, iidList[0]); + + return mode; +} + +void SpinelManager::Deinit(void) +{ + if (mSpinelInterface != nullptr) + { + mSpinelInterface->Deinit(); + mSpinelInterface = nullptr; + } + + mSpinelDriver.Deinit(); +} + +Spinel::SpinelInterface *SpinelManager::CreateSpinelInterface(const char *aInterfaceName) +{ + Spinel::SpinelInterface *interface; + + if (aInterfaceName == nullptr) + { + DieNow(OT_ERROR_FAILED); + } +#if OPENTHREAD_POSIX_CONFIG_SPINEL_HDLC_INTERFACE_ENABLE + else if (HdlcInterface::IsInterfaceNameMatch(aInterfaceName)) + { + interface = new (&mSpinelInterfaceRaw) HdlcInterface(mUrl); + } +#endif +#if OPENTHREAD_POSIX_CONFIG_SPINEL_SPI_INTERFACE_ENABLE + else if (Posix::SpiInterface::IsInterfaceNameMatch(aInterfaceName)) + { + interface = new (&mSpinelInterfaceRaw) SpiInterface(mUrl); + } +#endif +#if OPENTHREAD_POSIX_CONFIG_SPINEL_VENDOR_INTERFACE_ENABLE + else if (VendorInterface::IsInterfaceNameMatch(aInterfaceName)) + { + interface = new (&mSpinelInterfaceRaw) VendorInterface(mUrl); + } +#endif + else + { + otLogCritPlat("The Spinel interface name \"%s\" is not supported!", aInterfaceName); + DieNow(OT_ERROR_FAILED); + } + + return interface; +} + +void SpinelManager::GetIidListFromUrl(spinel_iid_t (&aIidList)[Spinel::kSpinelHeaderMaxNumIid]) +{ + const char *iidString; + const char *iidListString; + + memset(aIidList, SPINEL_HEADER_INVALID_IID, sizeof(aIidList)); + + iidString = mUrl.GetValue("iid"); + iidListString = mUrl.GetValue("iid-list"); + +#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + // First entry to the aIidList must be the IID of the host application. + VerifyOrDie(iidString != nullptr, OT_EXIT_INVALID_ARGUMENTS); + aIidList[0] = static_cast(atoi(iidString)); + + if (iidListString != nullptr) + { + // Convert string to an array of integers. + // Integer i is for traverse the iidListString. + // Integer j is for aIidList array offset location. + // First entry of aIidList is for host application iid hence j start from 1. + for (uint8_t i = 0, j = 1; iidListString[i] != '\0' && j < Spinel::kSpinelHeaderMaxNumIid; i++) + { + if (iidListString[i] == ',') + { + j++; + continue; + } + + if (iidListString[i] < '0' || iidListString[i] > '9') + { + DieNow(OT_EXIT_INVALID_ARGUMENTS); + } + else + { + aIidList[j] = iidListString[i] - '0'; + VerifyOrDie(aIidList[j] < Spinel::kSpinelHeaderMaxNumIid, OT_EXIT_INVALID_ARGUMENTS); + } + } + } +#else // !OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE + VerifyOrDie(iidString == nullptr, OT_EXIT_INVALID_ARGUMENTS); + VerifyOrDie(iidListString == nullptr, OT_EXIT_INVALID_ARGUMENTS); + aIidList[0] = 0; +#endif // OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE +} + +#if OPENTHREAD_POSIX_VIRTUAL_TIME +void SpinelManager::VirtualTimeInit(void) +{ + // The last argument must be the node id + const char *nodeId = nullptr; + + for (const char *arg = nullptr; (arg = mUrl.GetValue("forkpty-arg", arg)) != nullptr; nodeId = arg) + { + } + + virtualTimeInit(static_cast(atoi(nodeId))); +} +#endif + +} // namespace Posix +} // namespace ot + +CoprocessorType platformSpinelManagerInit(const char *aUrl) { return sSpinelManager.Init(aUrl); } + +void platformSpinelManagerDeinit(void) { return sSpinelManager.Deinit(); } + +#if OPENTHREAD_POSIX_VIRTUAL_TIME +void virtualTimeSpinelProcess(otInstance *aInstance, const struct VirtualTimeEvent *aEvent) +{ + OT_UNUSED_VARIABLE(aInstance); + ot::Posix::SpinelManager::GetSpinelDriver().Process(aEvent); +} +#else +void platformSpinelManagerProcess(otInstance *aInstance, const otSysMainloopContext *aContext) +{ + OT_UNUSED_VARIABLE(aInstance); + + ot::Posix::SpinelManager::GetSpinelDriver().Process(aContext); +} +#endif // OPENTHREAD_POSIX_VIRTUAL_TIME + +void platformSpinelManagerUpdateFdSet(otSysMainloopContext *aContext) +{ + sSpinelManager.GetSpinelInterface().UpdateFdSet(aContext); + + if (ot::Posix::SpinelManager::GetSpinelDriver().HasPendingFrame()) + { + aContext->mTimeout.tv_sec = 0; + aContext->mTimeout.tv_usec = 0; + } +} diff --git a/src/posix/platform/spinel_manager.hpp b/src/posix/platform/spinel_manager.hpp new file mode 100644 index 000000000..1922c1e6b --- /dev/null +++ b/src/posix/platform/spinel_manager.hpp @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2024, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef POSIX_PLATFORM_SPINEL_MANAGER_HPP_ +#define POSIX_PLATFORM_SPINEL_MANAGER_HPP_ + +#include "common/code_utils.hpp" +#include "lib/spinel/spinel_driver.hpp" +#include "posix/platform/hdlc_interface.hpp" +#include "posix/platform/radio_url.hpp" +#include "posix/platform/spi_interface.hpp" +#include "posix/platform/vendor_interface.hpp" + +namespace ot { +namespace Posix { + +class SpinelManager +{ +public: + /** + * Returns the static instance of the SpinelDriver. + * + */ + static Spinel::SpinelDriver &GetSpinelDriver(void); + + /** + * Returns the static instance of the SpinelManager. + * + */ + static SpinelManager &GetSpinelManager(void); + + /** + * Constructor of the SpinelManager + * + */ + SpinelManager(void); + + /** + * Destructor of the SpinelManager + * + */ + ~SpinelManager(void); + + /** + * Initializes the SpinelManager. + * + * @param[in] aUrl A pointer to the null-terminated spinel URL. + * + * @retval OT_COPROCESSOR_UNKNOWN The initialization fails. + * @retval OT_COPROCESSOR_RCP The Co-processor is a RCP. + * @retval OT_COPROCESSOR_NCP The Co-processor is a NCP. + * + */ + CoprocessorType Init(const char *aUrl); + + /** + * Deinitializes the SpinelManager. + * + */ + void Deinit(void); + + /** + * Returns the spinel interface. + * + * @returns The spinel interface. + * + */ + Spinel::SpinelInterface &GetSpinelInterface(void) + { + OT_ASSERT(mSpinelInterface != nullptr); + return *mSpinelInterface; + } + +private: +#if OPENTHREAD_POSIX_VIRTUAL_TIME + void VirtualTimeInit(void); +#endif + void GetIidListFromUrl(spinel_iid_t (&aIidList)[Spinel::kSpinelHeaderMaxNumIid]); + + Spinel::SpinelInterface *CreateSpinelInterface(const char *aInterfaceName); + +#if OPENTHREAD_POSIX_CONFIG_SPINEL_HDLC_INTERFACE_ENABLE && OPENTHREAD_POSIX_CONFIG_SPINEL_SPI_INTERFACE_ENABLE + static constexpr size_t kSpinelInterfaceRawSize = sizeof(Posix::SpiInterface) > sizeof(Posix::HdlcInterface) + ? sizeof(Posix::SpiInterface) + : sizeof(Posix::HdlcInterface); +#elif OPENTHREAD_POSIX_CONFIG_SPINEL_HDLC_INTERFACE_ENABLE + static constexpr size_t kSpinelInterfaceRawSize = sizeof(Posix::HdlcInterface); +#elif OPENTHREAD_POSIX_CONFIG_SPINEL_SPI_INTERFACE_ENABLE + static constexpr size_t kSpinelInterfaceRawSize = sizeof(Posix::SpiInterface); +#elif OPENTHREAD_POSIX_CONFIG_SPINEL_VENDOR_INTERFACE_ENABLE + static constexpr size_t kSpinelInterfaceRawSize = sizeof(Posix::VendorInterface); +#else +#error "No Spinel interface is specified!" +#endif + + RadioUrl mUrl; + Spinel::SpinelDriver mSpinelDriver; + Spinel::SpinelInterface *mSpinelInterface; + + OT_DEFINE_ALIGNED_VAR(mSpinelInterfaceRaw, kSpinelInterfaceRawSize, uint64_t); +}; + +} // namespace Posix +} // namespace ot + +#endif // POSIX_PLATFORM_SPINEL_MANAGER_HPP_ diff --git a/src/posix/platform/system.cpp b/src/posix/platform/system.cpp index c209d63aa..4cb8dc810 100644 --- a/src/posix/platform/system.cpp +++ b/src/posix/platform/system.cpp @@ -129,11 +129,21 @@ void otSysSetInfraNetif(const char *aInfraNetifName, int aIcmp6Socket) void platformInit(otPlatformConfig *aPlatformConfig) { + CoprocessorType type; + #if OPENTHREAD_POSIX_CONFIG_BACKTRACE_ENABLE platformBacktraceInit(); #endif platformAlarmInit(aPlatformConfig->mSpeedUpFactor, aPlatformConfig->mRealTimeSignal); + + type = platformSpinelManagerInit(get802154RadioUrl(aPlatformConfig)); + if (type != OT_COPROCESSOR_RCP) + { + printf("Only RCP is supported!\n"); + exit(OT_EXIT_FAILURE); + } + platformRadioInit(get802154RadioUrl(aPlatformConfig)); // For Dry-Run option, only init the radio. @@ -266,6 +276,7 @@ void platformDeinit(void) virtualTimeDeinit(); #endif platformRadioDeinit(); + platformSpinelManagerDeinit(); // For Dry-Run option, only the radio is initialized. VerifyOrExit(!gDryRun); @@ -343,6 +354,7 @@ void otSysMainloopUpdate(otInstance *aInstance, otSysMainloopContext *aMainloop) #if OPENTHREAD_POSIX_VIRTUAL_TIME virtualTimeUpdateFdSet(aMainloop); #else + platformSpinelManagerUpdateFdSet(aMainloop); platformRadioUpdateFdSet(aMainloop); #endif #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE @@ -406,6 +418,7 @@ void otSysMainloopProcess(otInstance *aInstance, const otSysMainloopContext *aMa #if OPENTHREAD_POSIX_VIRTUAL_TIME virtualTimeProcess(aInstance, aMainloop); #else + platformSpinelManagerProcess(aInstance, aMainloop); platformRadioProcess(aInstance, aMainloop); #endif #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE diff --git a/src/posix/platform/virtual_time.cpp b/src/posix/platform/virtual_time.cpp index e278ed45c..6777456c8 100644 --- a/src/posix/platform/virtual_time.cpp +++ b/src/posix/platform/virtual_time.cpp @@ -181,7 +181,8 @@ void virtualTimeProcess(otInstance *aInstance, const otSysMainloopContext *aCont virtualTimeReceiveEvent(&event); } - virtualTimeRadioSpinelProcess(aInstance, &event); + virtualTimeSpinelProcess(aInstance, &event); + virtualTimeRadioProcess(aInstance, &event); } uint64_t otPlatTimeGet(void) { return sNow; }