mirror of
https://github.com/espressif/openthread.git
synced 2026-07-26 22:09:05 +00:00
[nexus] implement CSL transmitter and receiver (#12595)
This commit implements CSL transmitter and receiver functionality in the Nexus simulation platform. It enables the necessary OpenThread configurations and provides the platform-level support for CSL. It also implements the otPlatRadioGetNow platform API to provide a high-resolution 64-bit microsecond time base, which is required for accurate CSL timing and synchronization. Changes: - Added GetNowMicro64() to Nexus::Core to expose the raw 64-bit microsecond timer. - Implemented otPlatRadioGetNow() in nexus_radio.cpp. - Enabled OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE and OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE in Nexus config. - Added otRadioContext to Nexus::Radio to track CSL parameters and manage security material for radio operations. - Implemented otPlatRadioEnableCsl, otPlatRadioResetCsl, otPlatRadioUpdateCslSampleTime, and otPlatRadioGetCslAccuracy. - Implemented otPlatRadioSetMacKey, otPlatRadioSetMacFrameCounter, and otPlatRadioSetAlternateShortAddress to keep radio context synchronized with OpenThread stack. - Updated otPlatRadioSetExtendedAddress and otPlatRadioEnableCsl to use AsCoreType for better readability and project conventions. - Moved Radio member initializations to the initializer list in its constructor. - Refactored radio SFD processing: moved otMacFrameProcessTxSfd and UpdateFcs from otPlatRadioTransmit (radio platform) to Core::ProcessRadio (simulation engine), ensuring CSL IEs and security headers are updated exactly when transmission starts. - Enhanced Nexus::Core::ProcessRadio to support generating Enhanced ACKs with CSL IEs for 802.15.4-2015 frames. - Updated Nexus and fuzz build systems to include necessary Nexus platform and utils headers/utilities.
This commit is contained in:
@@ -1114,10 +1114,7 @@ inline Error Radio::ReceiveAt(uint8_t, uint32_t, uint32_t) { return kErrorNone;
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
inline void Radio::UpdateCslSampleTime(uint32_t) {}
|
||||
|
||||
inline Error Radio::EnableCsl(uint32_t, Mac::ShortAddress aShortAddr, const Mac::ExtAddress &)
|
||||
{
|
||||
return kErrorNotImplemented;
|
||||
}
|
||||
inline Error Radio::EnableCsl(uint32_t, Mac::ShortAddress, const Mac::ExtAddress &) { return kErrorNotImplemented; }
|
||||
|
||||
inline Error Radio::ResetCsl(void) { return kErrorNotImplemented; }
|
||||
#endif
|
||||
|
||||
@@ -31,6 +31,8 @@ set(COMMON_INCLUDES
|
||||
${PROJECT_SOURCE_DIR}/src
|
||||
${PROJECT_SOURCE_DIR}/src/core
|
||||
${PROJECT_SOURCE_DIR}/tests/nexus
|
||||
${PROJECT_SOURCE_DIR}/tests/nexus/platform
|
||||
${PROJECT_SOURCE_DIR}/examples/platforms/utils
|
||||
)
|
||||
|
||||
set(COMMON_COMPILE_OPTIONS
|
||||
|
||||
@@ -32,6 +32,7 @@ set(COMMON_INCLUDES
|
||||
${PROJECT_SOURCE_DIR}/src/core
|
||||
${PROJECT_SOURCE_DIR}/tests/nexus
|
||||
${PROJECT_SOURCE_DIR}/tests/nexus/platform
|
||||
${PROJECT_SOURCE_DIR}/examples/platforms/utils
|
||||
)
|
||||
|
||||
set(COMMON_COMPILE_OPTIONS
|
||||
@@ -51,6 +52,7 @@ add_library(ot-nexus-platform
|
||||
platform/nexus_radio.cpp
|
||||
platform/nexus_settings.cpp
|
||||
platform/nexus_trel.cpp
|
||||
../../examples/platforms/utils/mac_frame.cpp
|
||||
)
|
||||
|
||||
target_include_directories(ot-nexus-platform
|
||||
|
||||
@@ -89,8 +89,8 @@
|
||||
#define OPENTHREAD_CONFIG_LOG_PREPEND_LEVEL 1
|
||||
#define OPENTHREAD_CONFIG_LOG_PREPEND_UPTIME 0
|
||||
#define OPENTHREAD_CONFIG_LOG_SUFFIX ""
|
||||
#define OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE 0
|
||||
#define OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE 0
|
||||
#define OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE 1
|
||||
#define OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE 1
|
||||
#define OPENTHREAD_CONFIG_MAC_FILTER_ENABLE 1
|
||||
#define OPENTHREAD_CONFIG_MAC_FILTER_SIZE 80
|
||||
#define OPENTHREAD_CONFIG_MESH_DIAG_ENABLE 1
|
||||
|
||||
@@ -348,6 +348,7 @@ void Core::ProcessRadio(Node &aNode)
|
||||
uint16_t dstPanId;
|
||||
bool ackRequested;
|
||||
AckMode ackMode = kNoAck;
|
||||
Node *ackNode = nullptr;
|
||||
|
||||
VerifyOrExit(aNode.mRadio.mState == Radio::kStateTransmit);
|
||||
|
||||
@@ -361,7 +362,11 @@ void Core::ProcessRadio(Node &aNode)
|
||||
dstPanId = Mac::kPanIdBroadcast;
|
||||
}
|
||||
|
||||
ackRequested = aNode.mRadio.mTxFrame.GetAckRequest();
|
||||
ackRequested = aNode.mRadio.mTxFrame.GetAckRequest();
|
||||
aNode.mRadio.mRadioContext.mCslPresent = aNode.mRadio.mTxFrame.mInfo.mTxInfo.mCslPresent;
|
||||
|
||||
SuccessOrQuit(otMacFrameProcessTxSfd(&aNode.mRadio.mTxFrame, mNow, &aNode.mRadio.mRadioContext));
|
||||
static_cast<Radio::Frame &>(aNode.mRadio.mTxFrame).UpdateFcs();
|
||||
|
||||
mPcap.WriteFrame(aNode.mRadio.mTxFrame, mNow);
|
||||
|
||||
@@ -393,6 +398,7 @@ void Core::ProcessRadio(Node &aNode)
|
||||
Mac::Address srcAddr;
|
||||
|
||||
ackMode = kSendAckNoFramePending;
|
||||
ackNode = &rxNode;
|
||||
|
||||
if ((aNode.mRadio.mTxFrame.GetSrcAddr(srcAddr) == kErrorNone) &&
|
||||
rxNode.mRadio.HasFramePendingFor(srcAddr))
|
||||
@@ -416,13 +422,35 @@ void Core::ProcessRadio(Node &aNode)
|
||||
aNode.mRadio.mChannel = aNode.mRadio.mTxFrame.mChannel;
|
||||
aNode.mRadio.mState = Radio::kStateReceive;
|
||||
|
||||
if (ackMode != kNoAck)
|
||||
if (ackNode != nullptr)
|
||||
{
|
||||
Radio::Frame ackFrame;
|
||||
Radio::Frame ackFrame;
|
||||
const Mac::RxFrame &rxFrame =
|
||||
static_cast<const Mac::RxFrame &>(static_cast<const Mac::Frame &>(aNode.mRadio.mTxFrame));
|
||||
|
||||
ackFrame.GenerateImmAck(
|
||||
static_cast<const Mac::RxFrame &>(static_cast<const Mac::Frame &>(aNode.mRadio.mTxFrame)),
|
||||
(ackMode == kSendAckFramePending));
|
||||
if (rxFrame.IsVersion2015())
|
||||
{
|
||||
uint8_t ackIeData[OT_ACK_IE_MAX_SIZE];
|
||||
uint8_t ackIeDataLength = 0;
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
ackNode->mRadio.mRadioContext.mCslPresent =
|
||||
(ackNode->mRadio.mRadioContext.mCslPeriod > 0) &&
|
||||
otMacFrameSrcAddrMatchCslReceiverPeer(&aNode.mRadio.mTxFrame, &ackNode->mRadio.mRadioContext);
|
||||
|
||||
if (ackNode->mRadio.mRadioContext.mCslPresent)
|
||||
{
|
||||
ackIeDataLength = otMacFrameGenerateCslIeTemplate(ackIeData);
|
||||
}
|
||||
#endif
|
||||
SuccessOrExit(
|
||||
ackFrame.GenerateEnhAck(rxFrame, (ackMode == kSendAckFramePending), ackIeData, ackIeDataLength));
|
||||
SuccessOrExit(otMacFrameProcessTxSfd(&ackFrame, mNow, &ackNode->mRadio.mRadioContext));
|
||||
}
|
||||
else
|
||||
{
|
||||
ackFrame.GenerateImmAck(rxFrame, (ackMode == kSendAckFramePending));
|
||||
}
|
||||
|
||||
ackFrame.UpdateFcs();
|
||||
mPcap.WriteFrame(ackFrame, mNow);
|
||||
|
||||
@@ -57,6 +57,7 @@ public:
|
||||
|
||||
TimeMilli GetNow(void) { return TimeMilli(static_cast<uint32_t>(mNow / 1000u)); }
|
||||
TimeMicro GetNowMicro(void) { return TimeMicro(static_cast<uint32_t>(mNow)); }
|
||||
uint64_t GetNowMicro64(void) const { return mNow; }
|
||||
void AdvanceTime(uint32_t aDuration);
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
@@ -42,7 +42,7 @@ extern "C" {
|
||||
otRadioCaps otPlatRadioGetCaps(otInstance *aInstance)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
return OT_RADIO_CAPS_NONE;
|
||||
return OT_RADIO_CAPS_TRANSMIT_SEC;
|
||||
}
|
||||
|
||||
int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance)
|
||||
@@ -65,12 +65,23 @@ void otPlatRadioSetPanId(otInstance *aInstance, otPanId aPanId) { AsNode(aInstan
|
||||
|
||||
void otPlatRadioSetExtendedAddress(otInstance *aInstance, const otExtAddress *aExtAddress)
|
||||
{
|
||||
AsNode(aInstance).mRadio.mExtAddress.Set(aExtAddress->m8, Mac::ExtAddress::kReverseByteOrder);
|
||||
Radio &radio = AsNode(aInstance).mRadio;
|
||||
|
||||
radio.mExtAddress.Set(aExtAddress->m8, Mac::ExtAddress::kReverseByteOrder);
|
||||
AsCoreType(&radio.mRadioContext.mExtAddress).Set(aExtAddress->m8, Mac::ExtAddress::kReverseByteOrder);
|
||||
}
|
||||
|
||||
void otPlatRadioSetShortAddress(otInstance *aInstance, otShortAddress aShortAddress)
|
||||
{
|
||||
AsNode(aInstance).mRadio.mShortAddress = aShortAddress;
|
||||
Radio &radio = AsNode(aInstance).mRadio;
|
||||
|
||||
radio.mShortAddress = aShortAddress;
|
||||
radio.mRadioContext.mShortAddress = aShortAddress;
|
||||
}
|
||||
|
||||
void otPlatRadioSetAlternateShortAddress(otInstance *aInstance, otShortAddress aShortAddress)
|
||||
{
|
||||
AsNode(aInstance).mRadio.mRadioContext.mAlternateShortAddress = aShortAddress;
|
||||
}
|
||||
|
||||
bool otPlatRadioGetPromiscuous(otInstance *aInstance) { return AsNode(aInstance).mRadio.mPromiscuous; }
|
||||
@@ -135,8 +146,6 @@ otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame)
|
||||
VerifyOrExit(radio.mState == Radio::kStateReceive, error = kErrorInvalidState);
|
||||
OT_ASSERT(aFrame == &AsNode(aInstance).mRadio.mTxFrame);
|
||||
|
||||
static_cast<Radio::Frame *>(aFrame)->UpdateFcs();
|
||||
|
||||
radio.mState = Radio::kStateTransmit;
|
||||
|
||||
Core::Get().MarkPendingAction();
|
||||
@@ -145,6 +154,13 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
uint64_t otPlatRadioGetNow(otInstance *aInstance)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
return Core::Get().GetNowMicro64();
|
||||
}
|
||||
|
||||
int8_t otPlatRadioGetRssi(otInstance *aInstance)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
@@ -223,6 +239,47 @@ void otPlatRadioClearSrcMatchShortEntries(otInstance *aInstance)
|
||||
|
||||
void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance) { AsNode(aInstance).mRadio.mSrcMatchExtEntries.Clear(); }
|
||||
|
||||
void otPlatRadioSetMacKey(otInstance *aInstance,
|
||||
uint8_t aKeyIdMode,
|
||||
uint8_t aKeyId,
|
||||
const otMacKeyMaterial *aPrevKey,
|
||||
const otMacKeyMaterial *aCurrKey,
|
||||
const otMacKeyMaterial *aNextKey,
|
||||
otRadioKeyType aKeyType)
|
||||
{
|
||||
Radio &radio = AsNode(aInstance).mRadio;
|
||||
|
||||
OT_UNUSED_VARIABLE(aKeyIdMode);
|
||||
|
||||
radio.mRadioContext.mKeyId = aKeyId;
|
||||
radio.mRadioContext.mKeyType = aKeyType;
|
||||
|
||||
if (!radio.mMacFrameCounterReset)
|
||||
{
|
||||
radio.mRadioContext.mPrevMacFrameCounter = radio.mRadioContext.mMacFrameCounter;
|
||||
radio.mRadioContext.mMacFrameCounter = 0;
|
||||
}
|
||||
|
||||
radio.mMacFrameCounterReset = false;
|
||||
|
||||
memcpy(&radio.mRadioContext.mPrevKey, aPrevKey, sizeof(otMacKeyMaterial));
|
||||
memcpy(&radio.mRadioContext.mCurrKey, aCurrKey, sizeof(otMacKeyMaterial));
|
||||
memcpy(&radio.mRadioContext.mNextKey, aNextKey, sizeof(otMacKeyMaterial));
|
||||
}
|
||||
|
||||
void otPlatRadioSetMacFrameCounter(otInstance *aInstance, uint32_t aMacFrameCounter)
|
||||
{
|
||||
Radio &radio = AsNode(aInstance).mRadio;
|
||||
|
||||
if (aMacFrameCounter == 0)
|
||||
{
|
||||
radio.mRadioContext.mPrevMacFrameCounter = radio.mRadioContext.mMacFrameCounter;
|
||||
radio.mMacFrameCounterReset = true;
|
||||
}
|
||||
|
||||
radio.mRadioContext.mMacFrameCounter = aMacFrameCounter;
|
||||
}
|
||||
|
||||
// Not supported
|
||||
|
||||
otError otPlatRadioEnergyScan(otInstance *, uint8_t, uint16_t) { return kErrorNotImplemented; }
|
||||
@@ -236,10 +293,53 @@ otError otPlatRadioSetFemLnaGain(otInstance *, int8_t) { return kErrorNotImpleme
|
||||
bool otPlatRadioIsCoexEnabled(otInstance *) { return false; }
|
||||
otError otPlatRadioSetCoexEnabled(otInstance *, bool) { return kErrorNotImplemented; }
|
||||
otError otPlatRadioGetCoexMetrics(otInstance *, otRadioCoexMetrics *) { return kErrorNotImplemented; }
|
||||
otError otPlatRadioEnableCsl(otInstance *, uint32_t, otShortAddress, const otExtAddress *) { return kErrorNone; }
|
||||
otError otPlatRadioResetCsl(otInstance *) { return kErrorNotImplemented; }
|
||||
void otPlatRadioUpdateCslSampleTime(otInstance *, uint32_t) {}
|
||||
uint8_t otPlatRadioGetCslAccuracy(otInstance *) { return 0; }
|
||||
otError otPlatRadioEnableCsl(otInstance *aInstance,
|
||||
uint32_t aCslPeriod,
|
||||
otShortAddress aShortAddr,
|
||||
const otExtAddress *aExtAddr)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
Radio &radio = AsNode(aInstance).mRadio;
|
||||
|
||||
if (aCslPeriod > 0)
|
||||
{
|
||||
VerifyOrExit((aShortAddr != OT_RADIO_BROADCAST_SHORT_ADDR) && (aShortAddr != OT_RADIO_INVALID_SHORT_ADDR),
|
||||
error = kErrorFailed);
|
||||
VerifyOrExit(aExtAddr != nullptr, error = kErrorFailed);
|
||||
}
|
||||
|
||||
radio.mRadioContext.mCslPeriod = static_cast<uint16_t>(aCslPeriod);
|
||||
radio.mRadioContext.mCslShortAddress = aShortAddr;
|
||||
|
||||
if (aExtAddr != nullptr)
|
||||
{
|
||||
AsCoreType(&radio.mRadioContext.mCslExtAddress).Set(aExtAddr->m8, Mac::ExtAddress::kReverseByteOrder);
|
||||
}
|
||||
else
|
||||
{
|
||||
AsCoreType(&radio.mRadioContext.mCslExtAddress).Clear();
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError otPlatRadioResetCsl(otInstance *aInstance)
|
||||
{
|
||||
AsNode(aInstance).mRadio.mRadioContext.mCslPeriod = 0;
|
||||
return kErrorNone;
|
||||
}
|
||||
|
||||
void otPlatRadioUpdateCslSampleTime(otInstance *aInstance, uint32_t aCslSampleTime)
|
||||
{
|
||||
AsNode(aInstance).mRadio.mRadioContext.mCslSampleTime = aCslSampleTime;
|
||||
}
|
||||
|
||||
uint8_t otPlatRadioGetCslAccuracy(otInstance *aInstance)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
return 0;
|
||||
}
|
||||
otError otPlatRadioSetChannelTargetPower(otInstance *, uint8_t, int16_t) { return kErrorNotImplemented; }
|
||||
otError otPlatRadioClearCalibratedPowers(otInstance *) { return kErrorNotImplemented; }
|
||||
otError otPlatRadioAddCalibratedPower(otInstance *, uint8_t, int16_t, const uint8_t *, uint16_t)
|
||||
@@ -256,16 +356,28 @@ Radio::Radio(void)
|
||||
: mState(kStateDisabled)
|
||||
, mPromiscuous(false)
|
||||
, mSrcMatchEnabled(false)
|
||||
, mMacFrameCounterReset(false)
|
||||
, mChannel(0)
|
||||
, mPanId(0)
|
||||
, mShortAddress(Mac::kShortAddrInvalid)
|
||||
{
|
||||
mExtAddress.Clear();
|
||||
ClearAllBytes(mRadioContext);
|
||||
}
|
||||
|
||||
void Radio::Reset(void)
|
||||
{
|
||||
mState = kStateDisabled;
|
||||
mPromiscuous = false;
|
||||
mSrcMatchEnabled = false;
|
||||
mState = kStateDisabled;
|
||||
mPromiscuous = false;
|
||||
mSrcMatchEnabled = false;
|
||||
mMacFrameCounterReset = false;
|
||||
mChannel = 0;
|
||||
mPanId = 0;
|
||||
mShortAddress = Mac::kShortAddrInvalid;
|
||||
mExtAddress.Clear();
|
||||
mSrcMatchShortEntries.Clear();
|
||||
mSrcMatchExtEntries.Clear();
|
||||
ClearAllBytes(mRadioContext);
|
||||
}
|
||||
|
||||
bool Radio::CanReceiveOnChannel(uint8_t aChannel) const
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#ifndef OT_NEXUS_PLATFORM_NEXUS_RADIO_HPP_
|
||||
#define OT_NEXUS_PLATFORM_NEXUS_RADIO_HPP_
|
||||
|
||||
#include "mac_frame.h"
|
||||
#include "instance/instance.hpp"
|
||||
|
||||
namespace ot {
|
||||
@@ -72,11 +73,13 @@ struct Radio
|
||||
State mState;
|
||||
bool mPromiscuous : 1;
|
||||
bool mSrcMatchEnabled : 1;
|
||||
bool mMacFrameCounterReset : 1;
|
||||
uint8_t mChannel;
|
||||
Mac::PanId mPanId;
|
||||
Mac::ShortAddress mShortAddress;
|
||||
Mac::ExtAddress mExtAddress;
|
||||
Frame mTxFrame;
|
||||
otRadioContext mRadioContext;
|
||||
Array<uint16_t, kMaxSrcMaatchShort> mSrcMatchShortEntries;
|
||||
Array<Mac::ExtAddress, kMaxSrcMatchExt> mSrcMatchExtEntries;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user