mirror of
https://github.com/espressif/openthread.git
synced 2026-08-10 20:57:47 +00:00
[nexus] implement link metrics support (#12621)
This commit implements Link Metrics support in the nexus platform, similar to the simulation platform implementation. Key changes include: - Added 'LinkMetricsInfo' struct and management methods to 'Radio' in 'nexus_radio'. - Implemented 'otPlatRadioConfigureEnhAckProbing()' and Enhanced ACK IE generation in 'nexus_core' and 'nexus_radio'. - Enabled Link Metrics initiator and subject configuration flags in 'openthread-core-nexus-config.h'. - Fixed spelling of 'kRadioSensitivity' in 'nexus_radio'. - Added 'fflush(stdout)' to the logging utility in 'nexus_misc' to improve real-time log capture during tests.
This commit is contained in:
@@ -99,8 +99,8 @@
|
||||
#define OPENTHREAD_CONFIG_MLE_DISCOVERY_SCAN_REQUEST_CALLBACK_ENABLE 1
|
||||
#define OPENTHREAD_CONFIG_MLE_INFORM_PREVIOUS_PARENT_ON_REATTACH 1
|
||||
#define OPENTHREAD_CONFIG_MLE_IP_ADDRS_PER_CHILD 10
|
||||
#define OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE 0
|
||||
#define OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE 0
|
||||
#define OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE 1
|
||||
#define OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE 1
|
||||
#define OPENTHREAD_CONFIG_MLE_MAX_CHILDREN 128
|
||||
#define OPENTHREAD_CONFIG_MULTICAST_DNS_AUTO_ENABLE_ON_INFRA_IF 1
|
||||
#define OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE 1
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "mac_frame.h"
|
||||
#include "nexus_node.hpp"
|
||||
|
||||
namespace ot {
|
||||
@@ -391,7 +392,7 @@ void Core::ProcessRadio(Node &aNode)
|
||||
|
||||
rxFrame.mInfo.mRxInfo.mTimestamp = mNow;
|
||||
rxFrame.mInfo.mRxInfo.mRssi = kDefaultRxRssi;
|
||||
rxFrame.mInfo.mRxInfo.mLqi = 0;
|
||||
rxFrame.mInfo.mRxInfo.mLqi = kDefaultRxLqi;
|
||||
|
||||
if (matchesDst && !dstAddr.IsNone() && !dstAddr.IsBroadcast() && ackRequested)
|
||||
{
|
||||
@@ -443,6 +444,26 @@ void Core::ProcessRadio(Node &aNode)
|
||||
ackIeDataLength = otMacFrameGenerateCslIeTemplate(ackIeData);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
|
||||
{
|
||||
uint8_t linkMetricsData[OT_ENH_PROBING_IE_DATA_MAX_SIZE];
|
||||
uint8_t linkMetricsDataLen;
|
||||
Mac::Address srcAddr;
|
||||
|
||||
if (aNode.mRadio.mTxFrame.GetSrcAddr(srcAddr) == kErrorNone)
|
||||
{
|
||||
linkMetricsDataLen = ackNode->mRadio.GenerateEnhAckProbingData(srcAddr, kDefaultRxLqi,
|
||||
kDefaultRxRssi, linkMetricsData);
|
||||
|
||||
if (linkMetricsDataLen > 0)
|
||||
{
|
||||
ackIeDataLength += otMacFrameGenerateEnhAckProbingIe(ackIeData + ackIeDataLength,
|
||||
linkMetricsData, linkMetricsDataLen);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
SuccessOrExit(
|
||||
ackFrame.GenerateEnhAck(rxFrame, (ackMode == kSendAckFramePending), ackIeData, ackIeDataLength));
|
||||
SuccessOrExit(otMacFrameProcessTxSfd(&ackFrame, mNow, &ackNode->mRadio.mRadioContext));
|
||||
|
||||
@@ -82,7 +82,8 @@ public:
|
||||
void MarkPendingAction(void) { mPendingAction = true; }
|
||||
|
||||
private:
|
||||
static constexpr int8_t kDefaultRxRssi = -20;
|
||||
static constexpr int8_t kDefaultRxRssi = -20;
|
||||
static constexpr uint8_t kDefaultRxLqi = 255;
|
||||
|
||||
enum AckMode : uint8_t
|
||||
{
|
||||
|
||||
@@ -158,6 +158,7 @@ static void LogVarArgs(Node *aActiveNode, const char *aFormat, va_list aArgs)
|
||||
|
||||
vprintf(aFormat, aArgs);
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
} // namespace Nexus
|
||||
|
||||
@@ -48,7 +48,7 @@ otRadioCaps otPlatRadioGetCaps(otInstance *aInstance)
|
||||
int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
return Radio::kRadioSensetivity;
|
||||
return Radio::kRadioSensitivity;
|
||||
}
|
||||
|
||||
void otPlatRadioGetIeeeEui64(otInstance *aInstance, uint8_t *aIeeeEui64)
|
||||
@@ -164,7 +164,7 @@ uint64_t otPlatRadioGetNow(otInstance *aInstance)
|
||||
int8_t otPlatRadioGetRssi(otInstance *aInstance)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
return Radio::kRadioSensetivity;
|
||||
return Radio::kRadioSensitivity;
|
||||
}
|
||||
|
||||
void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable)
|
||||
@@ -347,6 +347,14 @@ otError otPlatRadioAddCalibratedPower(otInstance *, uint8_t, int16_t, const uint
|
||||
return kErrorNotImplemented;
|
||||
}
|
||||
|
||||
otError otPlatRadioConfigureEnhAckProbing(otInstance *aInstance,
|
||||
otLinkMetrics aLinkMetrics,
|
||||
otShortAddress aShortAddress,
|
||||
const otExtAddress *aExtAddress)
|
||||
{
|
||||
return AsNode(aInstance).mRadio.ConfigureEnhAckProbing(aShortAddress, AsCoreTypePtr(aExtAddress), aLinkMetrics);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
@@ -363,6 +371,7 @@ Radio::Radio(void)
|
||||
{
|
||||
mExtAddress.Clear();
|
||||
ClearAllBytes(mRadioContext);
|
||||
mTxFrame.mInfo.mTxInfo.mIeInfo = &mTxIeInfo;
|
||||
}
|
||||
|
||||
void Radio::Reset(void)
|
||||
@@ -377,7 +386,96 @@ void Radio::Reset(void)
|
||||
mExtAddress.Clear();
|
||||
mSrcMatchShortEntries.Clear();
|
||||
mSrcMatchExtEntries.Clear();
|
||||
mLinkMetricsEntries.Clear();
|
||||
ClearAllBytes(mRadioContext);
|
||||
mTxFrame.mInfo.mTxInfo.mIeInfo = &mTxIeInfo;
|
||||
}
|
||||
|
||||
Error Radio::ConfigureEnhAckProbing(Mac::ShortAddress aShortAddress,
|
||||
const Mac::ExtAddress *aExtAddress,
|
||||
otLinkMetrics aMetrics)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
LinkMetricsInfo *dataInfo = mLinkMetricsEntries.FindMatching(aShortAddress);
|
||||
|
||||
if (!aMetrics.mPduCount && !aMetrics.mLqi && !aMetrics.mLinkMargin && !aMetrics.mRssi) // Remove entry
|
||||
{
|
||||
VerifyOrExit(dataInfo != nullptr, error = kErrorNotFound);
|
||||
mLinkMetricsEntries.Remove(*dataInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
VerifyOrExit(aExtAddress != nullptr, error = kErrorInvalidArgs);
|
||||
|
||||
if (dataInfo == nullptr)
|
||||
{
|
||||
dataInfo = mLinkMetricsEntries.PushBack();
|
||||
VerifyOrExit(dataInfo != nullptr, error = kErrorNoBufs);
|
||||
}
|
||||
|
||||
dataInfo->mShortAddress = aShortAddress;
|
||||
dataInfo->mExtAddress = *aExtAddress;
|
||||
dataInfo->mMetrics = aMetrics;
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
uint8_t Radio::GenerateEnhAckProbingData(const Mac::Address &aAddress, uint8_t aLqi, int8_t aRssi, uint8_t *aData) const
|
||||
{
|
||||
uint8_t bytes = 0;
|
||||
const LinkMetricsInfo *dataInfo = nullptr;
|
||||
|
||||
if (aAddress.IsShort())
|
||||
{
|
||||
dataInfo = mLinkMetricsEntries.FindMatching(aAddress.GetShort());
|
||||
}
|
||||
else if (aAddress.IsExtended())
|
||||
{
|
||||
dataInfo = mLinkMetricsEntries.FindMatching(aAddress.GetExtended());
|
||||
}
|
||||
|
||||
VerifyOrExit(dataInfo != nullptr);
|
||||
|
||||
if (dataInfo->mMetrics.mLqi)
|
||||
{
|
||||
aData[bytes++] = aLqi;
|
||||
}
|
||||
|
||||
if (dataInfo->mMetrics.mLinkMargin)
|
||||
{
|
||||
uint8_t linkMargin = ComputeLinkMargin(kRadioSensitivity, aRssi);
|
||||
|
||||
// Linear scale Link Margin from [0, 130] to [0, 255]
|
||||
if (linkMargin > kLinkMetricsScale)
|
||||
{
|
||||
linkMargin = kLinkMetricsScale;
|
||||
}
|
||||
|
||||
aData[bytes++] = static_cast<uint8_t>(static_cast<uint16_t>(linkMargin) * kLinkMetricsMax / kLinkMetricsScale);
|
||||
}
|
||||
|
||||
if (bytes < kEnhAckProbingDataMaxLen && dataInfo->mMetrics.mRssi)
|
||||
{
|
||||
int16_t rssi = aRssi;
|
||||
|
||||
// Linear scale RSSI from [-130, 0] to [0, 255]
|
||||
if (rssi > 0)
|
||||
{
|
||||
rssi = 0;
|
||||
}
|
||||
else if (rssi < -static_cast<int16_t>(kRssiOffset))
|
||||
{
|
||||
rssi = -static_cast<int16_t>(kRssiOffset);
|
||||
}
|
||||
|
||||
aData[bytes++] =
|
||||
static_cast<uint8_t>((static_cast<uint16_t>(rssi + kRssiOffset)) * kLinkMetricsMax / kLinkMetricsScale);
|
||||
}
|
||||
|
||||
exit:
|
||||
return bytes;
|
||||
}
|
||||
|
||||
bool Radio::CanReceiveOnChannel(uint8_t aChannel) const
|
||||
|
||||
@@ -39,10 +39,15 @@ struct Radio
|
||||
{
|
||||
static constexpr uint16_t kMaxFrameSize = OT_RADIO_FRAME_MAX_SIZE;
|
||||
|
||||
static constexpr uint16_t kMaxSrcMaatchShort = 80;
|
||||
static constexpr uint16_t kMaxSrcMatchExt = 10;
|
||||
static constexpr uint16_t kMaxSrcMatchShort = 80;
|
||||
static constexpr uint16_t kMaxSrcMatchExt = 10;
|
||||
|
||||
static constexpr int8_t kRadioSensetivity = -100;
|
||||
static constexpr int8_t kRadioSensitivity = -100;
|
||||
|
||||
static constexpr uint8_t kEnhAckProbingDataMaxLen = 2;
|
||||
static constexpr uint8_t kLinkMetricsMax = 255;
|
||||
static constexpr uint8_t kLinkMetricsScale = 130;
|
||||
static constexpr int16_t kRssiOffset = 130;
|
||||
|
||||
using State = otRadioState;
|
||||
|
||||
@@ -64,12 +69,27 @@ struct Radio
|
||||
uint8_t mPsduBuffer[kMaxFrameSize];
|
||||
};
|
||||
|
||||
struct LinkMetricsInfo
|
||||
{
|
||||
bool Matches(Mac::ShortAddress aShortAddress) const { return mShortAddress == aShortAddress; }
|
||||
bool Matches(const Mac::ExtAddress &aExtAddress) const { return mExtAddress == aExtAddress; }
|
||||
|
||||
Mac::ShortAddress mShortAddress;
|
||||
Mac::ExtAddress mExtAddress;
|
||||
otLinkMetrics mMetrics;
|
||||
};
|
||||
|
||||
Radio(void);
|
||||
void Reset(void);
|
||||
bool CanReceiveOnChannel(uint8_t aChannel) const;
|
||||
bool Matches(const Mac::Address &aAddress, Mac::PanId aPanId) const;
|
||||
bool HasFramePendingFor(const Mac::Address &aAddress) const;
|
||||
|
||||
Error ConfigureEnhAckProbing(Mac::ShortAddress aShortAddress,
|
||||
const Mac::ExtAddress *aExtAddress,
|
||||
otLinkMetrics aMetrics);
|
||||
uint8_t GenerateEnhAckProbingData(const Mac::Address &aAddress, uint8_t aLqi, int8_t aRssi, uint8_t *aData) const;
|
||||
|
||||
State mState;
|
||||
bool mPromiscuous : 1;
|
||||
bool mSrcMatchEnabled : 1;
|
||||
@@ -79,9 +99,12 @@ struct Radio
|
||||
Mac::ShortAddress mShortAddress;
|
||||
Mac::ExtAddress mExtAddress;
|
||||
Frame mTxFrame;
|
||||
otRadioIeInfo mTxIeInfo;
|
||||
otRadioContext mRadioContext;
|
||||
Array<uint16_t, kMaxSrcMaatchShort> mSrcMatchShortEntries;
|
||||
Array<uint16_t, kMaxSrcMatchShort> mSrcMatchShortEntries;
|
||||
Array<Mac::ExtAddress, kMaxSrcMatchExt> mSrcMatchExtEntries;
|
||||
|
||||
Array<LinkMetricsInfo, OPENTHREAD_CONFIG_MLE_LINK_METRICS_MAX_SERIES_SUPPORTED> mLinkMetricsEntries;
|
||||
};
|
||||
|
||||
} // namespace Nexus
|
||||
|
||||
Reference in New Issue
Block a user