Skip to content

Commit

Permalink
[spinel] Add iid-list option to radio_url.
Browse files Browse the repository at this point in the history
List of IIDs a host can subscribe to receive spinel frames other than provided in 'iid' argument. If not specified, host will subscribe to the interface ID provided in 'iid` argument. Valid values are 0-3.

Also, remove the use of openthread config option from spinel.h as a part of the review comment.
  • Loading branch information
parag-silabs committed Aug 17, 2023
1 parent 97ca7c4 commit 8e0fc78
Show file tree
Hide file tree
Showing 9 changed files with 125 additions and 29 deletions.
28 changes: 26 additions & 2 deletions src/lib/spinel/radio_spinel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,16 @@
namespace ot {
namespace Spinel {

/**
* Maximum number of Spinel Interface IDs.
*
*/
#ifdef OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE
static constexpr uint8_t kSpinelHeaderMaxNumIid = 4;
#else
static constexpr uint8_t kSpinelHeaderMaxNumIid = 1;
#endif

/**
* The class for providing a OpenThread radio interface by talking with a radio-only
* co-processor(RCP). The InterfaceType template parameter should provide the following
Expand Down Expand Up @@ -115,10 +125,12 @@ template <typename InterfaceType> class RadioSpinel
*
* @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] aIid The IID of the Host Application.
* @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.
*
*/
void Init(bool aResetRadio, bool aSkipRcpCompatibilityCheck, spinel_iid_t aIid);
void Init(bool aResetRadio, bool aSkipRcpCompatibilityCheck, const spinel_iid_t *aIidList, uint8_t aIidListLength);

/**
* Deinitialize this radio transceiver.
Expand Down Expand Up @@ -1009,6 +1021,17 @@ template <typename InterfaceType> class RadioSpinel
return !(aKey == SPINEL_PROP_STREAM_RAW || aKey == SPINEL_PROP_MAC_ENERGY_SCAN_RESULT);
}

/**
* Checks whether given interface ID is part of list of IIDs to be allowed.
*
* @param[in] aIid Spinel Interface ID.
*
* @retval TRUE Given IID present in allow list.
* @retval FALSE Otherwise.
*
*/
inline bool IsFrameForUs(spinel_iid_t aIid);

void HandleNotification(SpinelInterface::RxFrameBuffer &aFrameBuffer);
void HandleNotification(const uint8_t *aBuffer, uint16_t aLength);
void HandleValueIs(spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength);
Expand Down Expand Up @@ -1054,6 +1077,7 @@ template <typename InterfaceType> class RadioSpinel
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];
Expand Down
31 changes: 27 additions & 4 deletions src/lib/spinel/radio_spinel_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,22 @@ static inline void LogIfFail(const char *aText, otError aError)
}
}

template <typename InterfaceType> inline bool RadioSpinel<InterfaceType>::IsFrameForUs(spinel_iid_t aIid)
{
bool found = false;

for (spinel_iid_t iid : mIidList)
{
if (aIid == iid)
{
ExitNow(found = true);
}
}

exit:
return found;
}

template <typename InterfaceType> void RadioSpinel<InterfaceType>::HandleReceivedFrame(void *aContext)
{
static_cast<RadioSpinel *>(aContext)->HandleReceivedFrame();
Expand Down Expand Up @@ -210,11 +226,15 @@ RadioSpinel<InterfaceType>::RadioSpinel(void)
, mRadioTimeOffset(UINT64_MAX)
{
mVersion[0] = '\0';
memset(mIidList, SPINEL_HEADER_INVALID_IID, sizeof(mIidList));
memset(&mRadioSpinelMetrics, 0, sizeof(mRadioSpinelMetrics));
}

template <typename InterfaceType>
void RadioSpinel<InterfaceType>::Init(bool aResetRadio, bool aSkipRcpCompatibilityCheck, spinel_iid_t aIid)
void RadioSpinel<InterfaceType>::Init(bool aResetRadio,
bool aSkipRcpCompatibilityCheck,
const spinel_iid_t *aIidList,
uint8_t aIidListLength)
{
otError error = OT_ERROR_NONE;
bool supportsRcpApiVersion;
Expand All @@ -224,7 +244,11 @@ void RadioSpinel<InterfaceType>::Init(bool aResetRadio, bool aSkipRcpCompatibili
mResetRadioOnStartup = aResetRadio;
#endif

mIid = aIid;
VerifyOrDie(aIidList != nullptr, OT_EXIT_INVALID_ARGUMENTS);
VerifyOrDie(aIidListLength != 0 && aIidListLength <= OT_ARRAY_LENGTH(mIidList), OT_EXIT_INVALID_ARGUMENTS);
mIid = aIidList[0];
memset(mIidList, SPINEL_HEADER_INVALID_IID, sizeof(mIidList));
memcpy(mIidList, aIidList, aIidListLength * sizeof(spinel_iid_t));

ResetRcp(aResetRadio);
SuccessOrExit(error = CheckSpinelVersion());
Expand Down Expand Up @@ -472,9 +496,8 @@ template <typename InterfaceType> void RadioSpinel<InterfaceType>::HandleReceive
LogSpinelFrame(mRxFrameBuffer.GetFrame(), mRxFrameBuffer.GetLength(), false);
unpacked = spinel_datatype_unpack(mRxFrameBuffer.GetFrame(), mRxFrameBuffer.GetLength(), "C", &header);

// Accept spinel messages with the correct IID or broadcast IID 0.
iid = SPINEL_HEADER_GET_IID(header);
if (iid != 0 && iid != mIid)
if (!IsFrameForUs(iid))
{
mRxFrameBuffer.DiscardFrame();
ExitNow();
Expand Down
10 changes: 2 additions & 8 deletions src/lib/spinel/spinel.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,6 @@
* response is not expected or needed, such as for unsolicited update
* commands sent to the host from the NCP.
*
* In case of multiple IID support, the co-processor can use the IID value
* of zero to broadcast spinel frames to all the hosts.
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*
* The command identifier is a 21-bit unsigned integer encoded in up to
Expand Down Expand Up @@ -4945,17 +4942,14 @@ typedef uint32_t spinel_prop_key_t;
#define SPINEL_HEADER_IID_SHIFT 4
#define SPINEL_HEADER_IID_MASK (3 << SPINEL_HEADER_IID_SHIFT)
#define SPINEL_HEADER_IID(iid) (static_cast<uint8_t>((iid) << SPINEL_HEADER_IID_SHIFT))
#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE
#define SPINEL_HEADER_IID_MAX 3
#else // !OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE
#define SPINEL_HEADER_IID_MAX 0
#endif // OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE

#define SPINEL_HEADER_IID_0 SPINEL_HEADER_IID(0)
#define SPINEL_HEADER_IID_1 SPINEL_HEADER_IID(1)
#define SPINEL_HEADER_IID_2 SPINEL_HEADER_IID(2)
#define SPINEL_HEADER_IID_3 SPINEL_HEADER_IID(3)

#define SPINEL_HEADER_INVALID_IID 0xFF

#define SPINEL_HEADER_GET_IID(x) (((x)&SPINEL_HEADER_IID_MASK) >> SPINEL_HEADER_IID_SHIFT)
#define SPINEL_HEADER_GET_TID(x) (spinel_tid_t)(((x)&SPINEL_HEADER_TID_MASK) >> SPINEL_HEADER_TID_SHIFT)

Expand Down
2 changes: 1 addition & 1 deletion src/ncp/ncp_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ void NcpBase::HandleReceive(const uint8_t *aBuf, uint16_t aBufLength)

mCurCommandIid = SPINEL_HEADER_GET_IID(header);

if (mCurCommandIid > SPINEL_HEADER_IID_MAX)
if (mCurCommandIid >= kSpinelHeaderMaxNumIid)
{
IgnoreError(WriteLastStatusFrame(header, SPINEL_STATUS_INVALID_INTERFACE));
ExitNow();
Expand Down
9 changes: 7 additions & 2 deletions src/ncp/ncp_base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ class NcpBase
{
kSpinelCmdHeaderSize = 2, ///< Size of spinel command header (in bytes).
kSpinelPropIdSize = 3, ///< Size of spinel property identifier (in bytes).
#ifdef OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE
kSpinelHeaderMaxNumIid = 4, ///< Maximum number of Spinel Interface IDs.
#else
kSpinelHeaderMaxNumIid = 1, ///< Maximum number of Spinel Interface IDs.
#endif
};

/**
Expand Down Expand Up @@ -581,7 +586,7 @@ class NcpBase

uint8_t mTxBuffer[kTxBufferSize];

spinel_tid_t mNextExpectedTid[SPINEL_HEADER_IID_MAX + 1];
spinel_tid_t mNextExpectedTid[kSpinelHeaderMaxNumIid];

uint8_t mResponseQueueHead;
uint8_t mResponseQueueTail;
Expand Down Expand Up @@ -615,7 +620,7 @@ class NcpBase

#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE
#if OPENTHREAD_RADIO || OPENTHREAD_CONFIG_LINK_RAW_ENABLE
static constexpr uint16_t kPendingCommandQueueSize = SPINEL_HEADER_IID_MAX;
static constexpr uint16_t kPendingCommandQueueSize = kSpinelHeaderMaxNumIid - 1;

enum PendingCommandType
{
Expand Down
4 changes: 3 additions & 1 deletion src/ncp/ncp_base_radio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,9 @@ void NcpBase::LinkRawReceiveDone(otRadioFrame *aFrame, otError aError)
{
uint8_t header = SPINEL_HEADER_FLAG;

header |= ((aFrame->mIid <= SPINEL_HEADER_IID_MAX) ? SPINEL_HEADER_IID(aFrame->mIid) : SPINEL_HEADER_IID_0);
OT_ASSERT(aFrame->mIid < kSpinelHeaderMaxNumIid);

header |= SPINEL_HEADER_IID(aFrame->mIid);

// Append frame header
SuccessOrExit(mEncoder.BeginFrame(header, SPINEL_CMD_PROP_VALUE_IS, SPINEL_PROP_STREAM_RAW));
Expand Down
61 changes: 51 additions & 10 deletions src/posix/platform/radio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,21 +90,14 @@ void Radio::Init(void)
bool resetRadio = (mRadioUrl.GetValue("no-reset") == nullptr);
bool restoreDataset = (mRadioUrl.GetValue("ncp-dataset") != nullptr);
bool skipCompatibilityCheck = (mRadioUrl.GetValue("skip-rcp-compatibility-check") != nullptr);
spinel_iid_t iid = 0;
const char *iidString = (mRadioUrl.GetValue("iid"));
spinel_iid_t iidList[Spinel::kSpinelHeaderMaxNumIid];
const char *parameterValue;
const char *region;
#if OPENTHREAD_POSIX_CONFIG_MAX_POWER_TABLE_ENABLE
const char *maxPowerTable;
#endif

#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE
VerifyOrDie(iidString != nullptr, OT_EXIT_INVALID_ARGUMENTS);
iid = static_cast<spinel_iid_t>(atoi(iidString));
VerifyOrDie(iid != 0 && iid <= SPINEL_HEADER_IID_MAX, OT_EXIT_INVALID_ARGUMENTS);
#else
VerifyOrDie(iidString == nullptr, OT_EXIT_INVALID_ARGUMENTS);
#endif
GetIidListFromRadioUrl(iidList);

#if OPENTHREAD_POSIX_VIRTUAL_TIME
// The last argument must be the node id
Expand All @@ -126,7 +119,8 @@ void Radio::Init(void)
}

SuccessOrDie(sRadioSpinel.GetSpinelInterface().Init(mRadioUrl));
sRadioSpinel.Init(resetRadio, skipCompatibilityCheck, iid);

sRadioSpinel.Init(resetRadio, skipCompatibilityCheck, iidList, OT_ARRAY_LENGTH(iidList));

parameterValue = mRadioUrl.GetValue("fem-lnagain");
if (parameterValue != nullptr)
Expand Down Expand Up @@ -215,6 +209,53 @@ void Radio::Init(void)

void *Radio::GetSpinelInstance(void) { return &sRadioSpinel; }

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

Expand Down
2 changes: 2 additions & 0 deletions src/posix/platform/radio.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ class Radio

private:
RadioUrl mRadioUrl;

void GetIidListFromRadioUrl(spinel_iid_t (&aIidList)[Spinel::kSpinelHeaderMaxNumIid]);
};

} // namespace Posix
Expand Down
7 changes: 6 additions & 1 deletion src/posix/platform/radio_url.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,12 @@ const char *otSysGetRadioUrlHelpString(void)
" no-reset Do not send Spinel reset command to RCP on initialization.\n"
" skip-rcp-compatibility-check Skip checking RCP API version and capabilities during initialization.\n"
#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE
" iid Set the Spinel Interface ID for this process. Valid values are 1-3.\n"
" iid Set the Spinel Interface ID for this process. Valid values are 0-3.\n"
" iid-list List of IIDs a host can subscribe to receive spinel frames other than \n"
" provided in 'iid' argument. If not specified, host will subscribe to \n"
" the interface ID provided in 'iid` argument. Valid values are 0-3. \n"
" Upto three IIDs can be provided with each IID separated by ',' \n"
" e.g. iid-list=1,2,3 \n"
#endif
;
}
Expand Down

0 comments on commit 8e0fc78

Please sign in to comment.