264 lines
8.9 KiB
C++
264 lines
8.9 KiB
C++
|
|
/*
|
||
|
|
* Copyright (c) 2020, 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 "link_metrics.h"
|
||
|
|
|
||
|
|
#include <openthread/link_metrics.h>
|
||
|
|
|
||
|
|
#include "common/clearable.hpp"
|
||
|
|
#include "common/linked_list.hpp"
|
||
|
|
#include "common/pool.hpp"
|
||
|
|
#include "thread/link_quality.hpp"
|
||
|
|
|
||
|
|
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
|
||
|
|
|
||
|
|
using namespace ot;
|
||
|
|
|
||
|
|
static int8_t sNoiseFloor; ///< The noise floor used by Link Metrics. It should be set to the platform's
|
||
|
|
///< noise floor (measured noise floor, receiver sensitivity or a constant).
|
||
|
|
|
||
|
|
class LinkMetricsDataInfo : public LinkedListEntry<LinkMetricsDataInfo>, public Clearable<LinkMetricsDataInfo>
|
||
|
|
{
|
||
|
|
friend class LinkedList<LinkMetricsDataInfo>;
|
||
|
|
friend class LinkedListEntry<LinkMetricsDataInfo>;
|
||
|
|
|
||
|
|
public:
|
||
|
|
/**
|
||
|
|
* Construtor.
|
||
|
|
*
|
||
|
|
*/
|
||
|
|
LinkMetricsDataInfo(void) { Clear(); };
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Set the information for this object.
|
||
|
|
*
|
||
|
|
* @param[in] aLinkMetrics Flags specifying what metrics to query.
|
||
|
|
* @param[in] aShortAddress Short Address of the Probing Initiator tracked by this object.
|
||
|
|
* @param[in] aExtAddress A reference to the Extended Address of the Probing Initiator tracked by this
|
||
|
|
* object.
|
||
|
|
*
|
||
|
|
*/
|
||
|
|
void Set(otLinkMetrics aLinkMetrics, otShortAddress aShortAddress, const otExtAddress &aExtAddress)
|
||
|
|
{
|
||
|
|
mLinkMetrics = aLinkMetrics;
|
||
|
|
mShortAddress = aShortAddress;
|
||
|
|
memcpy(mExtAddress.m8, aExtAddress.m8, sizeof(aExtAddress));
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* This method gets Link Metrics data stored in this object.
|
||
|
|
*
|
||
|
|
* TODO: Currently the order of Link Metircs data is fixed. Will update it to follow the order specified in TLV.
|
||
|
|
*
|
||
|
|
* @param[in] aLqi LQI value of the acknowledeged frame.
|
||
|
|
* @param[in] aRssi RSSI value of the acknowledged frame.
|
||
|
|
* @param[out] aData A pointer to the output buffer. @p aData MUST NOT be `nullptr`. The buffer must have
|
||
|
|
* at least 2 bytes (per spec 4.11.3.4.4.6). Otherwise the behavior would be undefined.
|
||
|
|
*
|
||
|
|
* @returns The number of bytes written. `0` on failure.
|
||
|
|
*
|
||
|
|
*/
|
||
|
|
uint8_t GetEnhAckData(uint8_t aLqi, int8_t aRssi, uint8_t *aData) const
|
||
|
|
{
|
||
|
|
enum
|
||
|
|
{
|
||
|
|
kEnhAckProbingDataMaxLen = 2,
|
||
|
|
};
|
||
|
|
|
||
|
|
uint8_t bytes = 0;
|
||
|
|
|
||
|
|
VerifyOrExit(aData != nullptr);
|
||
|
|
|
||
|
|
if (mLinkMetrics.mLqi)
|
||
|
|
{
|
||
|
|
aData[bytes++] = aLqi;
|
||
|
|
}
|
||
|
|
if (mLinkMetrics.mLinkMargin)
|
||
|
|
{
|
||
|
|
aData[bytes++] = static_cast<uint8_t>(GetLinkMargin(aRssi) * 255 /
|
||
|
|
130); // Linear scale Link Margin from [0, 130] to [0, 255]
|
||
|
|
}
|
||
|
|
if (bytes < kEnhAckProbingDataMaxLen && mLinkMetrics.mRssi)
|
||
|
|
{
|
||
|
|
aData[bytes++] =
|
||
|
|
static_cast<uint8_t>((aRssi + 130) * 255 / 130); // Linear scale RSSI from [-130, 0] to [0, 255]
|
||
|
|
}
|
||
|
|
|
||
|
|
exit:
|
||
|
|
return bytes;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* This method gets the length of Link Metrics Data.
|
||
|
|
*
|
||
|
|
* @returns The number of bytes for the data.
|
||
|
|
*
|
||
|
|
*/
|
||
|
|
uint8_t GetEnhAckDataLen() const
|
||
|
|
{
|
||
|
|
return static_cast<uint8_t>(mLinkMetrics.mLqi) + static_cast<uint8_t>(mLinkMetrics.mLinkMargin) +
|
||
|
|
static_cast<uint8_t>(mLinkMetrics.mRssi);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* This method gets the metrics configured for the Enhanced-ACK Based Probing.
|
||
|
|
*
|
||
|
|
* @returns The metrics configured.
|
||
|
|
*
|
||
|
|
*/
|
||
|
|
otLinkMetrics GetLinkMetrics(void) const { return mLinkMetrics; }
|
||
|
|
|
||
|
|
private:
|
||
|
|
uint8_t GetLinkMargin(int8_t aRssi) const { return LinkQualityInfo::ConvertRssToLinkMargin(sNoiseFloor, aRssi); }
|
||
|
|
|
||
|
|
bool Matches(const otShortAddress &aShortAddress) const { return mShortAddress == aShortAddress; };
|
||
|
|
|
||
|
|
bool Matches(const otExtAddress &aExtAddress) const
|
||
|
|
{
|
||
|
|
return memcmp(&mExtAddress, &aExtAddress, sizeof(otExtAddress)) == 0;
|
||
|
|
};
|
||
|
|
|
||
|
|
LinkMetricsDataInfo *mNext;
|
||
|
|
|
||
|
|
otLinkMetrics mLinkMetrics;
|
||
|
|
|
||
|
|
otShortAddress mShortAddress;
|
||
|
|
otExtAddress mExtAddress;
|
||
|
|
};
|
||
|
|
|
||
|
|
enum
|
||
|
|
{
|
||
|
|
kMaxEnhAckProbingInitiator = OPENTHREAD_CONFIG_MLE_LINK_METRICS_MAX_SERIES_SUPPORTED,
|
||
|
|
};
|
||
|
|
|
||
|
|
typedef Pool<LinkMetricsDataInfo, kMaxEnhAckProbingInitiator> LinkMetricsDataInfoPool;
|
||
|
|
|
||
|
|
typedef LinkedList<LinkMetricsDataInfo> LinkMetricsDataInfoList;
|
||
|
|
|
||
|
|
static LinkMetricsDataInfoPool &GetLinkMetricsDataInfoPool(void)
|
||
|
|
{
|
||
|
|
static LinkMetricsDataInfoPool sDataInfoPool;
|
||
|
|
return sDataInfoPool;
|
||
|
|
}
|
||
|
|
|
||
|
|
static LinkMetricsDataInfoList &GetLinkMetricsDataInfoActiveList(void)
|
||
|
|
{
|
||
|
|
static LinkMetricsDataInfoList sDataInfoActiveList;
|
||
|
|
return sDataInfoActiveList;
|
||
|
|
}
|
||
|
|
|
||
|
|
static inline bool IsLinkMetricsClear(otLinkMetrics aLinkMetrics)
|
||
|
|
{
|
||
|
|
return !aLinkMetrics.mPduCount && !aLinkMetrics.mLqi && !aLinkMetrics.mLinkMargin && !aLinkMetrics.mRssi;
|
||
|
|
}
|
||
|
|
|
||
|
|
void otLinkMetricsInit(int8_t aNoiseFloor)
|
||
|
|
{
|
||
|
|
sNoiseFloor = aNoiseFloor;
|
||
|
|
}
|
||
|
|
|
||
|
|
otError otLinkMetricsConfigureEnhAckProbing(otShortAddress aShortAddress,
|
||
|
|
const otExtAddress *aExtAddress,
|
||
|
|
otLinkMetrics aLinkMetrics)
|
||
|
|
{
|
||
|
|
otError error = OT_ERROR_NONE;
|
||
|
|
LinkMetricsDataInfo *dataInfo = nullptr;
|
||
|
|
|
||
|
|
VerifyOrExit(aExtAddress != nullptr, error = OT_ERROR_INVALID_ARGS);
|
||
|
|
|
||
|
|
if (IsLinkMetricsClear(aLinkMetrics)) ///< Remove the entry
|
||
|
|
{
|
||
|
|
dataInfo = GetLinkMetricsDataInfoActiveList().RemoveMatching(aShortAddress);
|
||
|
|
VerifyOrExit(dataInfo != nullptr, error = OT_ERROR_NOT_FOUND);
|
||
|
|
GetLinkMetricsDataInfoPool().Free(*dataInfo);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
dataInfo = GetLinkMetricsDataInfoActiveList().FindMatching(aShortAddress);
|
||
|
|
|
||
|
|
if (dataInfo == nullptr)
|
||
|
|
{
|
||
|
|
dataInfo = GetLinkMetricsDataInfoPool().Allocate();
|
||
|
|
VerifyOrExit(dataInfo != nullptr, error = OT_ERROR_NO_BUFS);
|
||
|
|
dataInfo->Clear();
|
||
|
|
GetLinkMetricsDataInfoActiveList().Push(*dataInfo);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Overwrite the previous configuration if it already existed.
|
||
|
|
dataInfo->Set(aLinkMetrics, aShortAddress, *aExtAddress);
|
||
|
|
}
|
||
|
|
|
||
|
|
exit:
|
||
|
|
return error;
|
||
|
|
}
|
||
|
|
|
||
|
|
LinkMetricsDataInfo *GetLinkMetricsInfoByMacAddress(const otMacAddress *aMacAddress)
|
||
|
|
{
|
||
|
|
LinkMetricsDataInfo *dataInfo = nullptr;
|
||
|
|
|
||
|
|
VerifyOrExit(aMacAddress != nullptr);
|
||
|
|
|
||
|
|
if (aMacAddress->mType == OT_MAC_ADDRESS_TYPE_SHORT)
|
||
|
|
{
|
||
|
|
dataInfo = GetLinkMetricsDataInfoActiveList().FindMatching(aMacAddress->mAddress.mShortAddress);
|
||
|
|
}
|
||
|
|
else if (aMacAddress->mType == OT_MAC_ADDRESS_TYPE_EXTENDED)
|
||
|
|
{
|
||
|
|
dataInfo = GetLinkMetricsDataInfoActiveList().FindMatching(aMacAddress->mAddress.mExtAddress);
|
||
|
|
}
|
||
|
|
|
||
|
|
exit:
|
||
|
|
return dataInfo;
|
||
|
|
}
|
||
|
|
|
||
|
|
uint8_t otLinkMetricsEnhAckGenData(const otMacAddress *aMacAddress, uint8_t aLqi, int8_t aRssi, uint8_t *aData)
|
||
|
|
{
|
||
|
|
uint8_t bytes = 0;
|
||
|
|
LinkMetricsDataInfo *dataInfo = GetLinkMetricsInfoByMacAddress(aMacAddress);
|
||
|
|
|
||
|
|
VerifyOrExit(dataInfo != nullptr);
|
||
|
|
|
||
|
|
bytes = dataInfo->GetEnhAckData(aLqi, aRssi, aData);
|
||
|
|
|
||
|
|
exit:
|
||
|
|
return bytes;
|
||
|
|
}
|
||
|
|
|
||
|
|
uint8_t otLinkMetricsEnhAckGetDataLen(const otMacAddress *aMacAddress)
|
||
|
|
{
|
||
|
|
uint8_t len = 0;
|
||
|
|
LinkMetricsDataInfo *dataInfo = GetLinkMetricsInfoByMacAddress(aMacAddress);
|
||
|
|
|
||
|
|
VerifyOrExit(dataInfo != nullptr);
|
||
|
|
len = dataInfo->GetEnhAckDataLen();
|
||
|
|
|
||
|
|
exit:
|
||
|
|
return len;
|
||
|
|
}
|
||
|
|
#endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
|