mirror of
https://github.com/espressif/openthread.git
synced 2026-08-07 19:27:46 +00:00
[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.
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_
|
||||
@@ -52,6 +52,7 @@
|
||||
#include <openthread/openthread-system.h>
|
||||
#include <openthread/platform/time.h>
|
||||
|
||||
#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
|
||||
|
||||
@@ -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<uint16_t>(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<spinel_iid_t>(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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<spinel_iid_t>(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<uint16_t>(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;
|
||||
}
|
||||
}
|
||||
@@ -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_
|
||||
@@ -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
|
||||
|
||||
@@ -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; }
|
||||
|
||||
Reference in New Issue
Block a user