diff --git a/examples/platforms/nrf528xx/src/radio.c b/examples/platforms/nrf528xx/src/radio.c index 702713efc..7e5337fcd 100644 --- a/examples/platforms/nrf528xx/src/radio.c +++ b/examples/platforms/nrf528xx/src/radio.c @@ -45,6 +45,7 @@ #include "common/code_utils.hpp" #include "utils/code_utils.h" +#include "utils/link_metrics.h" #include "utils/mac_frame.h" #include @@ -195,6 +196,16 @@ static void convertShortAddress(uint8_t *aTo, uint16_t aFrom) aTo[1] = (uint8_t)(aFrom >> 8); } +#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE +static void convertExtAddress(uint8_t *aTo, const otExtAddress *aFrom) +{ + for (uint8_t i = 0; i < sizeof(otExtAddress); i++) + { + aTo[i] = aFrom->m8[sizeof(otExtAddress) - i - 1]; + } +} +#endif + static inline bool isPendingEventSet(RadioPendingEvents aEvent) { return sPendingEvents & (1UL << aEvent); @@ -1063,8 +1074,23 @@ static uint16_t getCslPhase() } #endif -void nrf_802154_tx_ack_started(uint8_t *p_data) +void nrf_802154_tx_ack_started(uint8_t *p_data, int8_t power, uint8_t lqi) { + otRadioFrame ackFrame; +#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE + uint8_t linkMetricsDataLen = 0; + uint8_t linkMetricsData[OT_ENH_PROBING_IE_DATA_MAX_SIZE]; + otMacAddress macAddress; +#else + OT_UNUSED_VARIABLE(power); + OT_UNUSED_VARIABLE(lqi); +#endif + + OT_UNUSED_VARIABLE(ackFrame); + + ackFrame.mPsdu = (uint8_t *)(p_data + 1); + ackFrame.mLength = p_data[0]; + // Check if the frame pending bit is set in ACK frame. sAckedWithFramePending = p_data[FRAME_PENDING_OFFSET] & FRAME_PENDING_BIT; @@ -1073,13 +1099,18 @@ void nrf_802154_tx_ack_started(uint8_t *p_data) #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE if (sCslPeriod > 0) { - otRadioFrame ackFrame; - ackFrame.mPsdu = (uint8_t *)(p_data + 1); - ackFrame.mLength = p_data[0]; otMacFrameSetCslIe(&ackFrame, sCslPeriod, getCslPhase()); } #endif +#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE + otMacFrameGetDstAddr(&ackFrame, &macAddress); + if ((linkMetricsDataLen = otLinkMetricsEnhAckGenData(&macAddress, lqi, power, linkMetricsData)) > 0) + { + otMacFrameSetEnhAckProbingIe(&ackFrame, linkMetricsData, linkMetricsDataLen); + } +#endif + txAckProcessSecurity(p_data); #endif } @@ -1265,51 +1296,66 @@ void otPlatRadioSetMacFrameCounter(otInstance *aInstance, uint32_t aMacFrameCoun } #endif // OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 -#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE -static void updateIeData(otInstance *aInstance, const uint8_t *aShortAddr, const uint8_t *aExtAddr) +#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE +static void updateIeData(otInstance *aInstance, otShortAddress aShortAddr, const otExtAddress *aExtAddr) { OT_UNUSED_VARIABLE(aInstance); int8_t offset = 0; uint8_t ackIeData[OT_ACK_IE_MAX_SIZE]; + uint8_t extAddr[OT_EXT_ADDRESS_SIZE]; + uint8_t shortAddr[SHORT_ADDRESS_SIZE]; +#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE + uint8_t enhAckProbingDataLen = 0; + otMacAddress macAddress; + macAddress.mType = OT_MAC_ADDRESS_TYPE_SHORT; + macAddress.mAddress.mShortAddress = aShortAddr; +#endif +#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE if (sCslPeriod > 0) { memcpy(ackIeData, sCslIeHeader, OT_IE_HEADER_SIZE); offset += OT_IE_HEADER_SIZE + OT_CSL_IE_SIZE; // reserve space for CSL IE } +#endif + +#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE + if ((enhAckProbingDataLen = otLinkMetricsEnhAckGetDataLen(&macAddress)) > 0) + { + offset += otMacFrameGenerateEnhAckProbingIe(ackIeData + offset, NULL, enhAckProbingDataLen); + } +#endif + + convertShortAddress(shortAddr, aShortAddr); + convertExtAddress(extAddr, aExtAddr); if (offset > 0) { - nrf_802154_ack_data_set(aShortAddr, false, ackIeData, offset, NRF_802154_ACK_DATA_IE); - nrf_802154_ack_data_set(aExtAddr, true, ackIeData, offset, NRF_802154_ACK_DATA_IE); + nrf_802154_ack_data_set(shortAddr, false, ackIeData, offset, NRF_802154_ACK_DATA_IE); + nrf_802154_ack_data_set(extAddr, true, ackIeData, offset, NRF_802154_ACK_DATA_IE); } else { - nrf_802154_ack_data_clear(aShortAddr, false, NRF_802154_ACK_DATA_IE); - nrf_802154_ack_data_clear(aExtAddr, true, NRF_802154_ACK_DATA_IE); + nrf_802154_ack_data_clear(shortAddr, false, NRF_802154_ACK_DATA_IE); + nrf_802154_ack_data_clear(extAddr, true, NRF_802154_ACK_DATA_IE); } } +#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE +#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE otError otPlatRadioEnableCsl(otInstance *aInstance, uint32_t aCslPeriod, const otExtAddress *aExtAddr) { otError error = OT_ERROR_NONE; - uint8_t parentExtAddr[OT_EXT_ADDRESS_SIZE]; - uint8_t parentShortAddress[SHORT_ADDRESS_SIZE]; - const uint8_t *shortAddress; + otShortAddress shortAddress; sCslPeriod = aCslPeriod; - for (uint32_t i = 0; i < sizeof(parentExtAddr); i++) - { - parentExtAddr[i] = aExtAddr->m8[sizeof(parentExtAddr) - i - 1]; - } + shortAddress = nrf_802154_pib_short_address_get()[1] + << 8; // Don't need the other byte because this is parent's short address + shortAddress &= 0xfc00; - shortAddress = nrf_802154_pib_short_address_get(); - memcpy(parentShortAddress, shortAddress, SHORT_ADDRESS_SIZE); - parentShortAddress[0] &= 0xfc; - - updateIeData(aInstance, parentShortAddress, parentExtAddr); + updateIeData(aInstance, shortAddress, aExtAddr); return error; } @@ -1333,7 +1379,13 @@ otError otPlatRadioConfigureEnhAckProbing(otInstance * aInstance, OT_UNUSED_VARIABLE(aShortAddress); OT_UNUSED_VARIABLE(aExtAddress); - return OT_ERROR_NOT_IMPLEMENTED; + otError error = OT_ERROR_NONE; + + SuccessOrExit(error = otLinkMetricsConfigureEnhAckProbing(aShortAddress, aExtAddress, aLinkMetrics)); + updateIeData(aInstance, aShortAddress, aExtAddress); + +exit: + return error; } #endif diff --git a/examples/platforms/utils/Makefile.am b/examples/platforms/utils/Makefile.am index a8cf2e46a..24e42bb7f 100644 --- a/examples/platforms/utils/Makefile.am +++ b/examples/platforms/utils/Makefile.am @@ -29,19 +29,32 @@ include $(abs_top_nlbuild_autotools_dir)/automake/pre.am lib_LIBRARIES = libopenthread-platform-utils.a +noinst_LTLIBRARIES = libutils-link-metrics.la -libopenthread_platform_utils_a_CPPFLAGS = \ +COMMON_FLAGS = \ -I$(top_srcdir)/include \ -I$(top_srcdir)/examples/platforms \ -I$(top_srcdir)/src/core \ -I$(top_srcdir)/third_party/jlink/SEGGER_RTT_V640/RTT \ $(NULL) +libutils_link_metrics_la_CPPFLAGS = \ + $(COMMON_FLAGS) \ + -fno-threadsafe-statics \ + $(NULL) + +libutils_link_metrics_la_SOURCES = \ + link_metrics.cpp \ + link_metrics.h \ + $(NULL) + +libopenthread_platform_utils_a_CPPFLAGS = \ + $(COMMON_FLAGS) \ + $(NULL) + libopenthread_platform_utils_a_SOURCES = \ code_utils.h \ debug_uart.c \ - link_metrics.cpp \ - link_metrics.h \ logging_rtt.c \ logging_rtt.h \ mac_frame.cpp \ @@ -53,4 +66,8 @@ libopenthread_platform_utils_a_SOURCES = \ soft_source_match_table.h \ $(NULL) +libopenthread_platform_utils_a_LIBADD = \ + libutils-link-metrics.la \ + $(NULL) + include $(abs_top_nlbuild_autotools_dir)/automake/post.am diff --git a/examples/platforms/utils/link_metrics.cpp b/examples/platforms/utils/link_metrics.cpp index f73f13188..883ed5936 100644 --- a/examples/platforms/utils/link_metrics.cpp +++ b/examples/platforms/utils/link_metrics.cpp @@ -113,6 +113,18 @@ public: 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(mLinkMetrics.mLqi) + static_cast(mLinkMetrics.mLinkMargin) + + static_cast(mLinkMetrics.mRssi); + } + /** * This method gets the metrics configured for the Enhanced-ACK Based Probing. * @@ -236,4 +248,16 @@ uint8_t otLinkMetricsEnhAckGenData(const otMacAddress *aMacAddress, uint8_t aLqi 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_ENABLE diff --git a/examples/platforms/utils/link_metrics.h b/examples/platforms/utils/link_metrics.h index 1582b8705..099d64b44 100644 --- a/examples/platforms/utils/link_metrics.h +++ b/examples/platforms/utils/link_metrics.h @@ -97,6 +97,16 @@ otError otLinkMetricsConfigureEnhAckProbing(otShortAddress aShortAddress, */ uint8_t otLinkMetricsEnhAckGenData(const otMacAddress *aMacAddress, uint8_t aLqi, int8_t aRssi, uint8_t *aData); +/** + * This method returns the data length of Enhanced-ACK Based Probing for a specific Initiator. + * + * @param[in] aMacAddress The Mac address of the Initiator. + * + * @returns The size of data. `0` if it's not configured for the Initiator. + * + */ +uint8_t otLinkMetricsEnhAckGetDataLen(const otMacAddress *aMacAddress); + #ifdef __cplusplus } // extern "C" #endif diff --git a/examples/platforms/utils/mac_frame.cpp b/examples/platforms/utils/mac_frame.cpp index 24c0dea81..353e02481 100644 --- a/examples/platforms/utils/mac_frame.cpp +++ b/examples/platforms/utils/mac_frame.cpp @@ -91,6 +91,26 @@ bool otMacFrameIsAckRequested(const otRadioFrame *aFrame) return static_cast(aFrame)->GetAckRequest(); } +static void GetOtMacAddress(const Mac::Address &aInAddress, otMacAddress *aOutAddress) +{ + switch (aInAddress.GetType()) + { + case Mac::Address::kTypeNone: + aOutAddress->mType = OT_MAC_ADDRESS_TYPE_NONE; + break; + + case Mac::Address::kTypeShort: + aOutAddress->mType = OT_MAC_ADDRESS_TYPE_SHORT; + aOutAddress->mAddress.mShortAddress = aInAddress.GetShort(); + break; + + case Mac::Address::kTypeExtended: + aOutAddress->mType = OT_MAC_ADDRESS_TYPE_EXTENDED; + aOutAddress->mAddress.mExtAddress = aInAddress.GetExtended(); + break; + } +} + otError otMacFrameGetSrcAddr(const otRadioFrame *aFrame, otMacAddress *aMacAddress) { otError error; @@ -99,22 +119,21 @@ otError otMacFrameGetSrcAddr(const otRadioFrame *aFrame, otMacAddress *aMacAddre error = static_cast(aFrame)->GetSrcAddr(address); SuccessOrExit(error); - switch (address.GetType()) - { - case Mac::Address::kTypeNone: - aMacAddress->mType = OT_MAC_ADDRESS_TYPE_NONE; - break; + GetOtMacAddress(address, aMacAddress); - case Mac::Address::kTypeShort: - aMacAddress->mType = OT_MAC_ADDRESS_TYPE_SHORT; - aMacAddress->mAddress.mShortAddress = address.GetShort(); - break; +exit: + return error; +} - case Mac::Address::kTypeExtended: - aMacAddress->mType = OT_MAC_ADDRESS_TYPE_EXTENDED; - aMacAddress->mAddress.mExtAddress = address.GetExtended(); - break; - } +otError otMacFrameGetDstAddr(const otRadioFrame *aFrame, otMacAddress *aMacAddress) +{ + otError error; + Mac::Address address; + + error = static_cast(aFrame)->GetDstAddr(address); + SuccessOrExit(error); + + GetOtMacAddress(address, aMacAddress); exit: return error; diff --git a/examples/platforms/utils/mac_frame.h b/examples/platforms/utils/mac_frame.h index 5aef72470..1d6c39a81 100644 --- a/examples/platforms/utils/mac_frame.h +++ b/examples/platforms/utils/mac_frame.h @@ -153,6 +153,18 @@ bool otMacFrameDoesAddrMatch(const otRadioFrame *aFrame, */ otError otMacFrameGetSrcAddr(const otRadioFrame *aFrame, otMacAddress *aMacAddress); +/** + * Get destination MAC address. + * + * @param[in] aFrame A pointer to the frame. + * @param[out] aMacAddress A pointer to MAC address. + * + * @retval OT_ERROR_NONE Successfully got the destination MAC address. + * @retval OT_ERROR_PARSE Failed to parse the destination MAC address. + * + */ +otError otMacFrameGetDstAddr(const otRadioFrame *aFrame, otMacAddress *aMacAddress); + /** * Get the sequence of @p aFrame. * diff --git a/src/core/thread/link_metrics.cpp b/src/core/thread/link_metrics.cpp index 95f6bea0c..63e2706a6 100644 --- a/src/core/thread/link_metrics.cpp +++ b/src/core/thread/link_metrics.cpp @@ -498,7 +498,7 @@ void LinkMetrics::HandleLinkMetricsReport(const Message & aMessage, case kLinkMetricsReportSub: VerifyOrExit(!hasStatus, error = OT_ERROR_DROP); // There shouldn't be any Report-Sub TLV when there's a Status TLV - VerifyOrExit(tlv.GetLength() == sizeof(typeIdFlags), error = OT_ERROR_PARSE); + VerifyOrExit(tlv.GetLength() > sizeof(typeIdFlags), error = OT_ERROR_PARSE); SuccessOrExit(aMessage.Read(pos, typeIdFlags)); if (typeIdFlags.IsExtendedFlagSet()) { diff --git a/third_party/NordicSemiconductor/drivers/radio/nrf_802154.c b/third_party/NordicSemiconductor/drivers/radio/nrf_802154.c index a2c590b8e..d61f6f357 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_802154.c +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_802154.c @@ -697,9 +697,11 @@ void nrf_802154_ack_timeout_set(uint32_t time) #endif // NRF_802154_ACK_TIMEOUT_ENABLED -__WEAK void nrf_802154_tx_ack_started(uint8_t * p_data) +__WEAK void nrf_802154_tx_ack_started(uint8_t * p_data, int8_t power, uint8_t lqi) { (void)p_data; + (void)power; + (void)lqi; } #if NRF_802154_USE_RAW_API diff --git a/third_party/NordicSemiconductor/drivers/radio/nrf_802154.h b/third_party/NordicSemiconductor/drivers/radio/nrf_802154.h index ad982a3ed..56be11b8a 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_802154.h +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_802154.h @@ -536,8 +536,10 @@ bool nrf_802154_continuous_carrier(void); * @note This function must be very short to prevent dropping frames by the driver. * * @param[in] p_data Pointer to a buffer with PHR and PSDU of the ACK frame. + * @param[in] power RSSI of the received frame. + * @param[in] lqi LQI of the received frame. */ -extern void nrf_802154_tx_ack_started(uint8_t * p_data); +extern void nrf_802154_tx_ack_started(uint8_t * p_data, int8_t power, uint8_t lqi); #if NRF_802154_USE_RAW_API diff --git a/third_party/NordicSemiconductor/drivers/radio/nrf_802154_core.c b/third_party/NordicSemiconductor/drivers/radio/nrf_802154_core.c index e938f394b..d623ecb98 100644 --- a/third_party/NordicSemiconductor/drivers/radio/nrf_802154_core.c +++ b/third_party/NordicSemiconductor/drivers/radio/nrf_802154_core.c @@ -169,6 +169,7 @@ static uint8_t * mp_ack; ///< Pointer to Ack frame buffer. static const uint8_t * mp_tx_data; ///< Pointer to the data to transmit. static uint32_t m_ed_time_left; ///< Remaining time of the current energy detection procedure [us]. static uint8_t m_ed_result; ///< Result of the current energy detection procedure. +static uint8_t m_last_lqi; ///< LQI value of last Rx frame. static volatile radio_state_t m_state; ///< State of the radio driver. @@ -1976,7 +1977,7 @@ static void irq_address_state_tx_frame(void) static void irq_address_state_tx_ack(void) { - nrf_802154_tx_ack_started(mp_ack); + nrf_802154_tx_ack_started(mp_ack, rssi_last_measurement_get(), m_last_lqi); } static void irq_address_state_rx_ack(void) @@ -2144,6 +2145,8 @@ static void irq_crcok_state_rx(void) nrf_802154_pib_auto_ack_get()) { mp_ack = nrf_802154_ack_generator_create(mp_current_rx_buffer->data); + m_last_lqi = lqi_get(mp_current_rx_buffer->data); + if (NULL != mp_ack) { send_ack = true;