mirror of
https://github.com/espressif/openthread.git
synced 2026-07-27 22:37:45 +00:00
[low-power] add CSL implementations on nrf52840 (#5449)
This commit is contained in:
@@ -268,6 +268,16 @@
|
||||
#define RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_CSL_SAMPLE_WINDOW
|
||||
*
|
||||
* CSL sample window in units of 10 symbols.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_CSL_SAMPLE_WINDOW
|
||||
#define OPENTHREAD_CONFIG_CSL_SAMPLE_WINDOW 30
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Suppress the ARMCC warning on unreachable statement,
|
||||
* e.g. break after assert(false) or ExitNow() macro.
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openthread/link.h>
|
||||
|
||||
#include "utils/code_utils.h"
|
||||
#include "utils/mac_frame.h"
|
||||
|
||||
@@ -56,6 +58,7 @@
|
||||
|
||||
#include <nrf.h>
|
||||
#include <nrf_802154.h>
|
||||
#include <nrf_802154_pib.h>
|
||||
|
||||
#include <openthread-core-config.h>
|
||||
#include <openthread/config.h>
|
||||
@@ -109,6 +112,12 @@ static uint32_t sEnergyDetectionTime;
|
||||
static uint8_t sEnergyDetectionChannel;
|
||||
static int8_t sEnergyDetected;
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
static uint32_t sCslPeriod;
|
||||
static uint32_t sCslSampleTime;
|
||||
static const uint8_t sCslIeHeader[OT_IE_HEADER_SIZE] = {CSL_IE_HEADER_BYTES_LO, CSL_IE_HEADER_BYTES_HI};
|
||||
#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
|
||||
typedef enum
|
||||
{
|
||||
kPendingEventSleep, // Requested to enter Sleep state.
|
||||
@@ -413,7 +422,7 @@ otError otPlatRadioSleep(otInstance *aInstance)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
if (nrf_802154_sleep())
|
||||
if (nrf_802154_sleep_if_idle())
|
||||
{
|
||||
clearPendingEvents();
|
||||
}
|
||||
@@ -818,7 +827,7 @@ void nrf5RadioProcess(otInstance *aInstance)
|
||||
|
||||
if (isPendingEventSet(kPendingEventSleep))
|
||||
{
|
||||
if (nrf_802154_sleep())
|
||||
if (nrf_802154_sleep_if_idle())
|
||||
{
|
||||
resetPendingEvent(kPendingEventSleep);
|
||||
}
|
||||
@@ -943,6 +952,17 @@ void nrf_802154_receive_failed(nrf_802154_rx_error_t error)
|
||||
setPendingEvent(kPendingEventReceiveFailed);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
static uint16_t getCslPhase()
|
||||
{
|
||||
uint32_t curTime = otPlatAlarmMicroGetNow();
|
||||
uint32_t cslPeriodInUs = sCslPeriod * OT_US_PER_TEN_SYMBOLS;
|
||||
uint32_t diff = ((sCslSampleTime % cslPeriodInUs) - (curTime % cslPeriodInUs) + cslPeriodInUs) % cslPeriodInUs;
|
||||
|
||||
return (uint16_t)(diff / OT_US_PER_TEN_SYMBOLS);
|
||||
}
|
||||
#endif
|
||||
|
||||
void nrf_802154_tx_ack_started(uint8_t *p_data)
|
||||
{
|
||||
// Check if the frame pending bit is set in ACK frame.
|
||||
@@ -950,6 +970,16 @@ void nrf_802154_tx_ack_started(uint8_t *p_data)
|
||||
|
||||
#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
|
||||
// Update IE and secure Enh-ACK.
|
||||
#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
|
||||
|
||||
txAckProcessSecurity(p_data);
|
||||
#endif
|
||||
}
|
||||
@@ -1046,6 +1076,13 @@ void nrf_802154_tx_started(const uint8_t *aFrame)
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
if (sCslPeriod > 0)
|
||||
{
|
||||
otMacFrameSetCslIe(&sTransmitFrame, (uint16_t)sCslPeriod, getCslPhase());
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
|
||||
otEXPECT(otMacFrameIsSecurityEnabled(&sTransmitFrame) && otMacFrameIsKeyIdMode1(&sTransmitFrame) &&
|
||||
!sTransmitFrame.mInfo.mTxInfo.mIsSecurityProcessed);
|
||||
@@ -1084,6 +1121,13 @@ uint32_t nrf_802154_random_get(void)
|
||||
return otRandomNonCryptoGetUint32();
|
||||
}
|
||||
|
||||
uint64_t otPlatRadioGetNow(otInstance *aInstance)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
return otPlatTimeGet();
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
|
||||
void otPlatRadioSetMacKey(otInstance * aInstance,
|
||||
uint8_t aKeyIdMode,
|
||||
@@ -1118,3 +1162,58 @@ void otPlatRadioSetMacFrameCounter(otInstance *aInstance, uint32_t aMacFrameCoun
|
||||
CRITICAL_REGION_EXIT();
|
||||
}
|
||||
#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)
|
||||
{
|
||||
int8_t offset = 0;
|
||||
uint8_t ackIeData[OT_ACK_IE_MAX_SIZE];
|
||||
|
||||
if (sCslPeriod > 0)
|
||||
{
|
||||
memcpy(ackIeData, sCslIeHeader, OT_IE_HEADER_SIZE);
|
||||
offset += OT_IE_HEADER_SIZE + OT_CSL_IE_SIZE; // reserve space for CSL IE
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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();
|
||||
memcpy(parentShortAddress, shortAddress, SHORT_ADDRESS_SIZE);
|
||||
parentShortAddress[0] &= 0xfc;
|
||||
|
||||
updateIeData(aInstance, parentShortAddress, parentExtAddr);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void otPlatRadioUpdateCslSampleTime(otInstance *aInstance, uint32_t aCslSampleTime)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
sCslSampleTime = aCslSampleTime;
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
|
||||
@@ -120,7 +120,7 @@ static uint8_t sAckIeDataLength = 0;
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
static const uint8_t sCslIeHeader[OT_IE_HEADER_IE_SIZE] = {0x04, 0x0d};
|
||||
static const uint8_t sCslIeHeader[OT_IE_HEADER_SIZE] = {CSL_IE_HEADER_BYTES_LO, CSL_IE_HEADER_BYTES_HI};
|
||||
static uint32_t sCslSampleTime;
|
||||
static uint32_t sCslPeriod;
|
||||
#endif
|
||||
@@ -1073,8 +1073,8 @@ static otError updateIeData(otInstance *aInstance)
|
||||
|
||||
if (sCslPeriod > 0)
|
||||
{
|
||||
memcpy(sAckIeData, sCslIeHeader, OT_IE_HEADER_IE_SIZE);
|
||||
offset += OT_IE_HEADER_IE_SIZE + OT_CSL_IE_SIZE; // reserve space for CSL IE
|
||||
memcpy(sAckIeData, sCslIeHeader, OT_IE_HEADER_SIZE);
|
||||
offset += OT_IE_HEADER_SIZE + OT_CSL_IE_SIZE; // reserve space for CSL IE
|
||||
}
|
||||
|
||||
sAckIeDataLength = offset;
|
||||
|
||||
@@ -149,11 +149,14 @@ typedef uint16_t otShortAddress;
|
||||
*/
|
||||
enum
|
||||
{
|
||||
OT_IE_HEADER_IE_SIZE = 2, ///< Size of IE header in bytes.
|
||||
OT_CSL_IE_SIZE = 4, ///< Size of CSL IE content in bytes.
|
||||
OT_ACK_IE_MAX_SIZE = 16, ///< Max length for header IE in ACK.
|
||||
OT_IE_HEADER_SIZE = 2, ///< Size of IE header in bytes.
|
||||
OT_CSL_IE_SIZE = 4, ///< Size of CSL IE content in bytes.
|
||||
OT_ACK_IE_MAX_SIZE = 16, ///< Max length for header IE in ACK.
|
||||
};
|
||||
|
||||
#define CSL_IE_HEADER_BYTES_LO 0x04 ///< Fixed CSL IE header first byte
|
||||
#define CSL_IE_HEADER_BYTES_HI 0x0d ///< Fixed CSL IE header second byte
|
||||
|
||||
/**
|
||||
* @struct otExtAddress
|
||||
*
|
||||
|
||||
@@ -2281,10 +2281,10 @@ exit:
|
||||
void Mac::SetCslPeriod(uint16_t aPeriod)
|
||||
{
|
||||
mSubMac.SetCslPeriod(aPeriod);
|
||||
IgnoreError(Get<Radio>().EnableCsl(GetCslPeriod(), &Get<Mle::Mle>().GetParent().GetExtAddress()));
|
||||
|
||||
if (IsCslEnabled())
|
||||
{
|
||||
IgnoreError(Get<Radio>().EnableCsl(GetCslPeriod(), &Get<Mle::Mle>().GetParent().GetExtAddress()));
|
||||
Get<Mle::Mle>().ScheduleChildUpdateRequest();
|
||||
}
|
||||
|
||||
|
||||
@@ -253,10 +253,11 @@ void SubMac::HandleReceiveDone(RxFrame *aFrame, otError aError)
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_DEBUG_ENABLE
|
||||
if (aFrame != nullptr && aError == OT_ERROR_NONE)
|
||||
{
|
||||
otLogDebgMac(
|
||||
"Received frame in state (SubMac %s, CSL %d), timestamp %lu, target sample start time %u, time drift %d",
|
||||
StateToString(mState), mCslState, aFrame->mInfo.mRxInfo.mTimestamp, mCslSampleTime.GetValue(),
|
||||
static_cast<uint32_t>(aFrame->mInfo.mRxInfo.mTimestamp) - mCslSampleTime.GetValue());
|
||||
// Split the log into two lines for RTT to output
|
||||
otLogDebgMac("Received frame in state (SubMac %s, CSL %s), timestamp %u", StateToString(mState),
|
||||
CslStateToString(mCslState), static_cast<uint32_t>(aFrame->mInfo.mRxInfo.mTimestamp));
|
||||
otLogDebgMac("Target sample start time %u, time drift %d", mCslSampleTime.GetValue(),
|
||||
static_cast<uint32_t>(aFrame->mInfo.mRxInfo.mTimestamp) - mCslSampleTime.GetValue());
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -404,7 +405,7 @@ void SubMac::BeginTransmit(void)
|
||||
VerifyOrExit(mState == kStateCsmaBackoff, OT_NOOP);
|
||||
#endif
|
||||
|
||||
mTransmitFrame.SetCsmaCaEnabled(mTransmitFrame.mInfo.mTxInfo.mPeriod != 0);
|
||||
mTransmitFrame.SetCsmaCaEnabled(mTransmitFrame.mInfo.mTxInfo.mPeriod == 0);
|
||||
|
||||
if ((mRadioCaps & OT_RADIO_CAPS_SLEEP_TO_TX) == 0)
|
||||
{
|
||||
@@ -858,6 +859,30 @@ const char *SubMac::StateToString(State aState)
|
||||
return str;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
const char *SubMac::CslStateToString(CslState aCslState)
|
||||
{
|
||||
const char *str = "Unknown";
|
||||
|
||||
switch (aCslState)
|
||||
{
|
||||
case kCslIdle:
|
||||
str = "CslIdle";
|
||||
break;
|
||||
case kCslSample:
|
||||
str = "CslSample";
|
||||
break;
|
||||
case kCslSleep:
|
||||
str = "kCslSleep";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
+23
-18
@@ -520,6 +520,26 @@ private:
|
||||
#endif
|
||||
};
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
/**
|
||||
* The SSED sample window in units of 10 symbols.
|
||||
*
|
||||
*/
|
||||
enum : uint32_t{
|
||||
kCslSampleWindow = OPENTHREAD_CONFIG_CSL_SAMPLE_WINDOW * kUsPerTenSymbols,
|
||||
};
|
||||
|
||||
/**
|
||||
* CSL state, always updated by `mCslTimer`.
|
||||
*
|
||||
*/
|
||||
enum CslState : uint8_t{
|
||||
kCslIdle = 0, ///< CSL receiver is not started.
|
||||
kCslSample, ///< Sampling CSL channel.
|
||||
kCslSleep, ///< Radio in sleep.
|
||||
};
|
||||
#endif
|
||||
|
||||
bool RadioSupportsCsmaBackoff(void) const
|
||||
{
|
||||
return ((mRadioCaps & (OT_RADIO_CAPS_CSMA_BACKOFF | OT_RADIO_CAPS_TRANSMIT_RETRIES)) != 0);
|
||||
@@ -553,6 +573,9 @@ private:
|
||||
|
||||
void SetState(State aState);
|
||||
static const char *StateToString(State aState);
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
static const char *CslStateToString(CslState aCslState);
|
||||
#endif
|
||||
|
||||
otRadioCaps mRadioCaps;
|
||||
State mState;
|
||||
@@ -579,24 +602,6 @@ private:
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
/**
|
||||
* The SSED sample window in units of 10 symbols.
|
||||
*
|
||||
*/
|
||||
enum : uint32_t{
|
||||
kCslSampleWindow = OPENTHREAD_CONFIG_CSL_SAMPLE_WINDOW * kUsPerTenSymbols,
|
||||
};
|
||||
|
||||
/**
|
||||
* CSL state, always updated by `mCslTimer`.
|
||||
*
|
||||
*/
|
||||
enum CslState : uint8_t{
|
||||
kCslIdle = 0, ///< CSL receiver is not started.
|
||||
kCslSample, ///< Sampling CSL channel.
|
||||
kCslSleep, ///< Radio in sleep.
|
||||
};
|
||||
|
||||
uint32_t mCslTimeout; ///< The CSL synchronized timeout in seconds.
|
||||
TimeMicro mCslSampleTime; ///< The CSL sample time of the current period.
|
||||
uint16_t mCslPeriod; ///< The CSL sample period, in units of 10 symbols (160 microseconds).
|
||||
|
||||
@@ -686,6 +686,7 @@ void Mle::SetStateChild(uint16_t aRloc16)
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
|
||||
if (Get<Mac::Mac>().IsCslEnabled())
|
||||
{
|
||||
IgnoreError(Get<Radio>().EnableCsl(Get<Mac::Mac>().GetCslPeriod(), &GetParent().GetExtAddress()));
|
||||
ScheduleChildUpdateRequest();
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user