[csl] introduce CslNeighbor class (#10956)

This commit introduces `CslNeighbor`, a subclass of `Neighbor` that
also inherits from `IndirectSender::NeighborInfo` and
`CslTxScheduler::NeighborInfo` to manage indirect transmission and
CSL-specific information.

The `Child` class now inherits from `CslNeighbor`, inheriting all CSL
functionalities while adding extra child-specific information. The
newly added `CslNeighbor` allows extending CSL functionality to
devices in other roles, not just `Child` devices.

The `CslTxScheduler` class is updated to use `CslNeighbor` as well
(instead of `Child`), making it more general-purpose.

`IndirectSender`, its sub-components, and `Mac` are updated to enable
CSL on MTD builds when `OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE`
is enabled.

This restructuring provides a more flexible and scalable framework for
implementing enhanced CSL functionality on new device types.
This commit is contained in:
Abtin Keshavarzian
2024-11-26 10:58:25 -08:00
committed by GitHub
parent 147de7e4cb
commit d43cb0d1ea
17 changed files with 237 additions and 130 deletions
@@ -71,6 +71,7 @@
#define OPENTHREAD_CONFIG_LOG_LEVEL OT_LOG_LEVEL_INFO
#define OPENTHREAD_CONFIG_LOG_LEVEL_DYNAMIC_ENABLE 1
#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_MESH_DIAG_ENABLE 1
#define OPENTHREAD_CONFIG_MESSAGE_USE_HEAP_ENABLE 1
@@ -71,6 +71,7 @@
#define OPENTHREAD_CONFIG_LOG_LEVEL OT_LOG_LEVEL_INFO
#define OPENTHREAD_CONFIG_LOG_LEVEL_DYNAMIC_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_MESH_DIAG_ENABLE 1
#define OPENTHREAD_CONFIG_MESSAGE_USE_HEAP_ENABLE 1
@@ -71,6 +71,7 @@
#define OPENTHREAD_CONFIG_LOG_LEVEL OT_LOG_LEVEL_INFO
#define OPENTHREAD_CONFIG_LOG_LEVEL_DYNAMIC_ENABLE 0
#define OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE 1
#define OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE 0
#define OPENTHREAD_CONFIG_MAC_FILTER_ENABLE 1
#define OPENTHREAD_CONFIG_MESH_DIAG_ENABLE 0
#define OPENTHREAD_CONFIG_MESSAGE_USE_HEAP_ENABLE 1
+8 -6
View File
@@ -821,9 +821,15 @@ template <> inline Ip6::Filter &Instance::Get(void) { return mIp6Filter; }
template <> inline AddressResolver &Instance::Get(void) { return mAddressResolver; }
#if OPENTHREAD_FTD
#if OPENTHREAD_FTD || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
template <> inline IndirectSender &Instance::Get(void) { return mMeshForwarder.mIndirectSender; }
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
template <> inline CslTxScheduler &Instance::Get(void) { return mMeshForwarder.mIndirectSender.mCslTxScheduler; }
#endif
#if OPENTHREAD_FTD
template <> inline SourceMatchController &Instance::Get(void)
{
@@ -832,10 +838,6 @@ template <> inline SourceMatchController &Instance::Get(void)
template <> inline DataPollHandler &Instance::Get(void) { return mMeshForwarder.mIndirectSender.mDataPollHandler; }
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
template <> inline CslTxScheduler &Instance::Get(void) { return mMeshForwarder.mIndirectSender.mCslTxScheduler; }
#endif
template <> inline MeshCoP::Leader &Instance::Get(void) { return mLeader; }
template <> inline MeshCoP::JoinerRouter &Instance::Get(void) { return mJoinerRouter; }
+14 -8
View File
@@ -36,8 +36,6 @@
#include "openthread-core-config.h"
#if OPENTHREAD_FTD
#include "common/code_utils.hpp"
#include "common/locator.hpp"
#include "common/non_copyable.hpp"
@@ -57,7 +55,11 @@ namespace ot {
* @{
*/
#if OPENTHREAD_FTD || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
#if OPENTHREAD_FTD
class Child;
#endif
/**
* Implements the data poll (mac data request command) handler.
@@ -79,14 +81,14 @@ public:
};
/**
* Defines all the child info required for handling of data polls and indirect frame transmissions.
* Defines all the neighbor info required for handling of data polls and indirect frame transmissions.
*
* `Child` class publicly inherits from this class.
* `Child` (and `CslNeighbor`) class publicly inherits from this class.
*/
class ChildInfo
class NeighborInfo
{
friend class DataPollHandler;
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
friend class CslTxScheduler;
#endif
@@ -132,6 +134,8 @@ public:
static_assert(kMaxPollTriggeredTxAttempts < (1 << 5), "mIndirectTxAttempts cannot fit max!");
};
#if OPENTHREAD_FTD
/**
* Initializes the data poll handler object.
*
@@ -191,14 +195,16 @@ private:
Child *mIndirectTxChild; // The child being handled (`nullptr` indicates no active indirect tx).
FrameContext mFrameContext; // Context for the prepared frame for the current indirect tx (if any)
#endif // OPENTHREAD_FTD
};
#endif // OPENTHREAD_FTD || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
/**
* @}
*/
} // namespace ot
#endif // OPENTHREAD_FTD
#endif // DATA_POLL_HANDLER_HPP_
+32 -23
View File
@@ -200,9 +200,9 @@ bool Mac::IsInTransmitState(void) const
case kOperationTransmitDataDirect:
#if OPENTHREAD_FTD
case kOperationTransmitDataIndirect:
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
case kOperationTransmitDataCsl:
#endif
#endif
case kOperationTransmitBeacon:
case kOperationTransmitPoll:
@@ -508,6 +508,7 @@ void Mac::RequestIndirectFrameTransmission(void)
exit:
return;
}
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
void Mac::RequestCslFrameTransmission(uint32_t aDelay)
@@ -522,7 +523,6 @@ exit:
return;
}
#endif
#endif // OPENTHREAD_FTD
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
void Mac::RequestWakeupFrameTransmission(void)
@@ -577,7 +577,7 @@ void Mac::UpdateIdleMode(void)
}
#endif
}
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
else if (IsPending(kOperationTransmitDataCsl))
{
mTimer.FireAt(mCslTxFireTime);
@@ -661,7 +661,7 @@ void Mac::PerformNextOperation(void)
mOperation = kOperationTransmitWakeup;
}
#endif
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
else if (IsPending(kOperationTransmitDataCsl) && TimerMilli::GetNow() >= mCslTxFireTime)
{
mOperation = kOperationTransmitDataCsl;
@@ -727,9 +727,9 @@ void Mac::PerformNextOperation(void)
case kOperationTransmitDataDirect:
#if OPENTHREAD_FTD
case kOperationTransmitDataIndirect:
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
case kOperationTransmitDataCsl:
#endif
#endif
case kOperationTransmitPoll:
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
@@ -1036,6 +1036,7 @@ void Mac::BeginTransmit(void)
frame->SetSequence(mDataSequence++);
}
break;
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
case kOperationTransmitDataCsl:
@@ -1053,7 +1054,6 @@ void Mac::BeginTransmit(void)
break;
#endif
#endif // OPENTHREAD_FTD
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
case kOperationTransmitWakeup:
@@ -1352,7 +1352,7 @@ void Mac::HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aError)
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
ProcessEnhAckProbing(*aAckFrame, *neighbor);
#endif
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
ProcessCsl(*aAckFrame, dstAddr);
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
@@ -1473,7 +1473,6 @@ void Mac::HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aError)
PerformNextOperation();
break;
#if OPENTHREAD_FTD
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
case kOperationTransmitDataCsl:
mCounters.mTxData++;
@@ -1485,6 +1484,8 @@ void Mac::HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aError)
break;
#endif
#if OPENTHREAD_FTD
case kOperationTransmitDataIndirect:
mCounters.mTxData++;
@@ -1550,7 +1551,7 @@ void Mac::HandleTimer(void)
}
#endif
}
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
else if (IsPending(kOperationTransmitDataCsl))
{
PerformNextOperation();
@@ -1962,7 +1963,7 @@ void Mac::HandleReceivedFrame(RxFrame *aFrame, Error aError)
ExitNow();
}
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
ProcessCsl(*aFrame, srcaddr);
#endif
@@ -2282,10 +2283,10 @@ const char *Mac::OperationToString(Operation aOperation)
"WaitingForData", // (6) kOperationWaitingForData
#if OPENTHREAD_FTD
"TransmitDataIndirect", // (7) kOperationTransmitDataIndirect
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
"TransmitDataCsl", // (8) kOperationTransmitDataCsl
#endif
#endif
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
"TransmitWakeup", // kOperationTransmitWakeup
#endif
@@ -2304,9 +2305,9 @@ const char *Mac::OperationToString(Operation aOperation)
ValidateNextEnum(kOperationWaitingForData);
#if OPENTHREAD_FTD
ValidateNextEnum(kOperationTransmitDataIndirect);
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
ValidateNextEnum(kOperationTransmitDataCsl);
#endif
#endif
};
@@ -2467,10 +2468,11 @@ bool Mac::IsCslSupported(void) const
}
#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
void Mac::ProcessCsl(const RxFrame &aFrame, const Address &aSrcAddr)
{
Child *child;
CslNeighbor *neighbor = nullptr;
const CslIe *csl;
VerifyOrExit(aFrame.IsVersion2015() && aFrame.GetSecurityEnabled());
@@ -2478,26 +2480,33 @@ void Mac::ProcessCsl(const RxFrame &aFrame, const Address &aSrcAddr)
csl = aFrame.GetCslIe();
VerifyOrExit(csl != nullptr);
child = Get<ChildTable>().FindChild(aSrcAddr, Child::kInStateAnyExceptInvalid);
VerifyOrExit(child != nullptr);
#if OPENTHREAD_FTD
neighbor = Get<ChildTable>().FindChild(aSrcAddr, Child::kInStateAnyExceptInvalid);
#else
OT_UNUSED_VARIABLE(aSrcAddr);
#endif
VerifyOrExit(neighbor != nullptr);
VerifyOrExit(csl->GetPeriod() >= kMinCslIePeriod);
child->SetCslPeriod(csl->GetPeriod());
child->SetCslPhase(csl->GetPhase());
child->SetCslSynchronized(true);
child->SetCslLastHeard(TimerMilli::GetNow());
child->SetLastRxTimestamp(aFrame.GetTimestamp());
neighbor->SetCslPeriod(csl->GetPeriod());
neighbor->SetCslPhase(csl->GetPhase());
neighbor->SetCslSynchronized(true);
neighbor->SetCslLastHeard(TimerMilli::GetNow());
neighbor->SetLastRxTimestamp(aFrame.GetTimestamp());
LogDebg("Timestamp=%lu Sequence=%u CslPeriod=%u CslPhase=%u TransmitPhase=%u",
ToUlong(static_cast<uint32_t>(aFrame.GetTimestamp())), aFrame.GetSequence(), csl->GetPeriod(),
csl->GetPhase(), child->GetCslPhase());
csl->GetPhase(), neighbor->GetCslPhase());
#if OPENTHREAD_FTD
Get<CslTxScheduler>().Update();
#endif
exit:
return;
}
#endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
#endif // OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
void Mac::ProcessEnhAckProbing(const RxFrame &aFrame, const Neighbor &aNeighbor)
+4 -5
View File
@@ -209,6 +209,7 @@ public:
* Requests an indirect data frame transmission.
*/
void RequestIndirectFrameTransmission(void);
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
/**
@@ -219,8 +220,6 @@ public:
void RequestCslFrameTransmission(uint32_t aDelay);
#endif
#endif
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
/**
* Requests `Mac` to start a wake-up frame transmission.
@@ -786,10 +785,10 @@ private:
kOperationWaitingForData,
#if OPENTHREAD_FTD
kOperationTransmitDataIndirect,
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
kOperationTransmitDataCsl,
#endif
#endif
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
kOperationTransmitWakeup,
#endif
@@ -858,7 +857,7 @@ private:
uint8_t GetTimeIeOffset(const Frame &aFrame);
#endif
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
void ProcessCsl(const RxFrame &aFrame, const Address &aSrcAddr);
#endif
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
@@ -903,10 +902,10 @@ private:
uint8_t mMaxFrameRetriesDirect;
#if OPENTHREAD_FTD
uint8_t mMaxFrameRetriesIndirect;
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
TimeMilli mCslTxFireTime;
#endif
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
// When Mac::mCslChannel is 0, it indicates that CSL channel has not been specified by the upper layer.
uint8_t mCslChannel;
+1 -1
View File
@@ -1196,7 +1196,7 @@ exit:
bool Frame::HasCslIe(void) const { return GetHeaderIe(CslIe::kHeaderIeId) != nullptr; }
#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || (OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE)
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
const CslIe *Frame::GetCslIe(void) const
{
const uint8_t *cur;
+2 -2
View File
@@ -676,7 +676,7 @@ public:
bool HasCslIe(void) const;
#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || (OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE)
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
/**
* Returns a pointer to a CSL IE.
*
@@ -690,7 +690,7 @@ public:
* @returns A pointer to the CSL IE, `nullptr` if not found.
*/
CslIe *GetCslIe(void) { return AsNonConst(AsConst(this)->GetCslIe()); }
#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || (OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE)
#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
/**
+1 -7
View File
@@ -50,13 +50,7 @@ namespace ot {
/**
* Represents a Thread Child.
*/
class Child : public Neighbor,
public IndirectSender::ChildInfo,
public DataPollHandler::ChildInfo
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
,
public CslTxScheduler::ChildInfo
#endif
class Child : public CslNeighbor
{
public:
static constexpr uint8_t kMaxRequestTlvs = 6;
+51 -47
View File
@@ -28,7 +28,7 @@
#include "csl_tx_scheduler.hpp"
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
#include "instance/instance.hpp"
@@ -38,7 +38,7 @@ RegisterLogModule("CslTxScheduler");
CslTxScheduler::CslTxScheduler(Instance &aInstance)
: InstanceLocator(aInstance)
, mCslTxChild(nullptr)
, mCslTxNeighbor(nullptr)
, mCslTxMessage(nullptr)
, mFrameContext()
{
@@ -71,18 +71,19 @@ void CslTxScheduler::Update(void)
{
RescheduleCslTx();
}
else if ((mCslTxChild != nullptr) && (mCslTxChild->GetIndirectMessage() != mCslTxMessage))
else if ((mCslTxNeighbor != nullptr) && (mCslTxNeighbor->GetIndirectMessage() != mCslTxMessage))
{
// `Mac` has already started the CSL tx, so wait for tx done callback
// to call `RescheduleCslTx`
mCslTxChild->ResetCslTxAttempts();
mCslTxChild = nullptr;
mCslTxNeighbor->ResetCslTxAttempts();
mCslTxNeighbor = nullptr;
mFrameContext.mMessageNextOffset = 0;
}
}
void CslTxScheduler::Clear(void)
{
#if OPENTHREAD_FTD
for (Child &child : Get<ChildTable>().Iterate(Child::kInStateAnyExceptInvalid))
{
child.ResetCslTxAttempts();
@@ -93,9 +94,10 @@ void CslTxScheduler::Clear(void)
child.SetCslPhase(0);
child.SetCslLastHeard(TimeMilli(0));
}
#endif
mFrameContext.mMessageNextOffset = 0;
mCslTxChild = nullptr;
mCslTxNeighbor = nullptr;
mCslTxMessage = nullptr;
}
@@ -106,9 +108,10 @@ void CslTxScheduler::Clear(void)
*/
void CslTxScheduler::RescheduleCslTx(void)
{
uint32_t minDelayTime = Time::kMaxDuration;
Child *bestChild = nullptr;
uint32_t minDelayTime = Time::kMaxDuration;
CslNeighbor *bestNeighbor = nullptr;
#if OPENTHREAD_FTD
for (Child &child : Get<ChildTable>().Iterate(Child::kInStateAnyExceptInvalid))
{
uint32_t delay;
@@ -124,27 +127,28 @@ void CslTxScheduler::RescheduleCslTx(void)
if (delay < minDelayTime)
{
minDelayTime = delay;
bestChild = &child;
bestNeighbor = &child;
}
}
#endif
if (bestChild != nullptr)
if (bestNeighbor != nullptr)
{
Get<Mac::Mac>().RequestCslFrameTransmission(minDelayTime / 1000UL);
}
mCslTxChild = bestChild;
mCslTxNeighbor = bestNeighbor;
}
uint32_t CslTxScheduler::GetNextCslTransmissionDelay(const Child &aChild,
uint32_t &aDelayFromLastRx,
uint32_t aAheadUs) const
uint32_t CslTxScheduler::GetNextCslTransmissionDelay(const CslNeighbor &aCslNeighbor,
uint32_t &aDelayFromLastRx,
uint32_t aAheadUs) const
{
uint64_t radioNow = Get<Radio>().GetNow();
uint32_t periodInUs = aChild.GetCslPeriod() * kUsPerTenSymbols;
uint32_t periodInUs = aCslNeighbor.GetCslPeriod() * kUsPerTenSymbols;
/* see CslTxScheduler::ChildInfo::mCslPhase */
uint64_t firstTxWindow = aChild.GetLastRxTimestamp() + aChild.GetCslPhase() * kUsPerTenSymbols;
/* see CslTxScheduler::NeighborInfo::mCslPhase */
uint64_t firstTxWindow = aCslNeighbor.GetLastRxTimestamp() + aCslNeighbor.GetCslPhase() * kUsPerTenSymbols;
uint64_t nextTxWindow = radioNow - (radioNow % periodInUs) + (firstTxWindow % periodInUs);
while (nextTxWindow < radioNow + aAheadUs)
@@ -152,7 +156,7 @@ uint32_t CslTxScheduler::GetNextCslTransmissionDelay(const Child &aChild,
nextTxWindow += periodInUs;
}
aDelayFromLastRx = static_cast<uint32_t>(nextTxWindow - aChild.GetLastRxTimestamp());
aDelayFromLastRx = static_cast<uint32_t>(nextTxWindow - aCslNeighbor.GetLastRxTimestamp());
return static_cast<uint32_t>(nextTxWindow - radioNow - aAheadUs);
}
@@ -165,8 +169,8 @@ Mac::TxFrame *CslTxScheduler::HandleFrameRequest(Mac::TxFrames &aTxFrames)
uint32_t txDelay;
uint32_t delay;
VerifyOrExit(mCslTxChild != nullptr);
VerifyOrExit(mCslTxChild->IsCslSynchronized());
VerifyOrExit(mCslTxNeighbor != nullptr);
VerifyOrExit(mCslTxNeighbor->IsCslSynchronized());
#if OPENTHREAD_CONFIG_MULTI_RADIO
frame = &aTxFrames.GetTxFrame(Mac::kRadioTypeIeee802154);
@@ -174,24 +178,24 @@ Mac::TxFrame *CslTxScheduler::HandleFrameRequest(Mac::TxFrames &aTxFrames)
frame = &aTxFrames.GetTxFrame();
#endif
VerifyOrExit(Get<IndirectSender>().PrepareFrameForChild(*frame, mFrameContext, *mCslTxChild) == kErrorNone,
VerifyOrExit(Get<IndirectSender>().PrepareFrameForCslNeighbor(*frame, mFrameContext, *mCslTxNeighbor) == kErrorNone,
frame = nullptr);
mCslTxMessage = mCslTxChild->GetIndirectMessage();
mCslTxMessage = mCslTxNeighbor->GetIndirectMessage();
VerifyOrExit(mCslTxMessage != nullptr, frame = nullptr);
if (mCslTxChild->GetIndirectTxAttempts() > 0 || mCslTxChild->GetCslTxAttempts() > 0)
if (mCslTxNeighbor->GetIndirectTxAttempts() > 0 || mCslTxNeighbor->GetCslTxAttempts() > 0)
{
// For a re-transmission of an indirect frame to a sleepy
// child, we ensure to use the same frame counter, key id, and
// data sequence number as the previous attempt.
frame->SetIsARetransmission(true);
frame->SetSequence(mCslTxChild->GetIndirectDataSequenceNumber());
frame->SetSequence(mCslTxNeighbor->GetIndirectDataSequenceNumber());
if (frame->GetSecurityEnabled())
{
frame->SetFrameCounter(mCslTxChild->GetIndirectFrameCounter());
frame->SetKeyId(mCslTxChild->GetIndirectKeyId());
frame->SetFrameCounter(mCslTxNeighbor->GetIndirectFrameCounter());
frame->SetKeyId(mCslTxNeighbor->GetIndirectKeyId());
}
}
else
@@ -199,15 +203,15 @@ Mac::TxFrame *CslTxScheduler::HandleFrameRequest(Mac::TxFrames &aTxFrames)
frame->SetIsARetransmission(false);
}
frame->SetChannel(mCslTxChild->GetCslChannel() == 0 ? Get<Mac::Mac>().GetPanChannel()
: mCslTxChild->GetCslChannel());
frame->SetChannel(mCslTxNeighbor->GetCslChannel() == 0 ? Get<Mac::Mac>().GetPanChannel()
: mCslTxNeighbor->GetCslChannel());
if (frame->GetChannel() != Get<Mac::Mac>().GetPanChannel())
{
frame->SetRxChannelAfterTxDone(Get<Mac::Mac>().GetPanChannel());
}
delay = GetNextCslTransmissionDelay(*mCslTxChild, txDelay, /* aAheadUs */ 0);
delay = GetNextCslTransmissionDelay(*mCslTxNeighbor, txDelay, /* aAheadUs */ 0);
// We make sure that delay is less than `mCslFrameRequestAheadUs`
// plus some guard time. Note that we used `mCslFrameRequestAheadUs`
@@ -228,7 +232,7 @@ Mac::TxFrame *CslTxScheduler::HandleFrameRequest(Mac::TxFrames &aTxFrames)
frame->SetTxDelay(txDelay);
frame->SetTxDelayBaseTime(
static_cast<uint32_t>(mCslTxChild->GetLastRxTimestamp())); // Only LSB part of the time is required.
static_cast<uint32_t>(mCslTxNeighbor->GetLastRxTimestamp())); // Only LSB part of the time is required.
frame->SetCsmaCaEnabled(false);
exit:
@@ -243,41 +247,41 @@ Mac::TxFrame *CslTxScheduler::HandleFrameRequest(Mac::TxFrames &) { return nullp
void CslTxScheduler::HandleSentFrame(const Mac::TxFrame &aFrame, Error aError)
{
Child *child = mCslTxChild;
CslNeighbor *neighbor = mCslTxNeighbor;
mCslTxMessage = nullptr;
VerifyOrExit(child != nullptr); // The result is no longer interested by upper layer
VerifyOrExit(neighbor != nullptr);
mCslTxChild = nullptr;
mCslTxNeighbor = nullptr;
HandleSentFrame(aFrame, aError, *child);
HandleSentFrame(aFrame, aError, *neighbor);
exit:
RescheduleCslTx();
}
void CslTxScheduler::HandleSentFrame(const Mac::TxFrame &aFrame, Error aError, Child &aChild)
void CslTxScheduler::HandleSentFrame(const Mac::TxFrame &aFrame, Error aError, CslNeighbor &aCslNeighbor)
{
switch (aError)
{
case kErrorNone:
aChild.ResetCslTxAttempts();
aChild.ResetIndirectTxAttempts();
aCslNeighbor.ResetCslTxAttempts();
aCslNeighbor.ResetIndirectTxAttempts();
break;
case kErrorNoAck:
OT_ASSERT(!aFrame.GetSecurityEnabled() || aFrame.IsHeaderUpdated());
aChild.IncrementCslTxAttempts();
LogInfo("CSL tx to child %04x failed, attempt %d/%d", aChild.GetRloc16(), aChild.GetCslTxAttempts(),
aCslNeighbor.IncrementCslTxAttempts();
LogInfo("CSL tx to %04x failed, attempt %d/%d", aCslNeighbor.GetRloc16(), aCslNeighbor.GetCslTxAttempts(),
kMaxCslTriggeredTxAttempts);
if (aChild.GetCslTxAttempts() >= kMaxCslTriggeredTxAttempts)
if (aCslNeighbor.GetCslTxAttempts() >= kMaxCslTriggeredTxAttempts)
{
// CSL transmission attempts reach max, consider child out of sync
aChild.SetCslSynchronized(false);
aChild.ResetCslTxAttempts();
aCslNeighbor.SetCslSynchronized(false);
aCslNeighbor.ResetCslTxAttempts();
}
OT_FALL_THROUGH;
@@ -291,7 +295,7 @@ void CslTxScheduler::HandleSentFrame(const Mac::TxFrame &aFrame, Error aError, C
if (!aFrame.IsEmpty())
{
aChild.SetIndirectDataSequenceNumber(aFrame.GetSequence());
aCslNeighbor.SetIndirectDataSequenceNumber(aFrame.GetSequence());
if (aFrame.GetSecurityEnabled() && aFrame.IsHeaderUpdated())
{
@@ -299,10 +303,10 @@ void CslTxScheduler::HandleSentFrame(const Mac::TxFrame &aFrame, Error aError, C
uint8_t keyId;
IgnoreError(aFrame.GetFrameCounter(frameCounter));
aChild.SetIndirectFrameCounter(frameCounter);
aCslNeighbor.SetIndirectFrameCounter(frameCounter);
IgnoreError(aFrame.GetKeyId(keyId));
aChild.SetIndirectKeyId(keyId);
aCslNeighbor.SetIndirectKeyId(keyId);
}
}
@@ -313,7 +317,7 @@ void CslTxScheduler::HandleSentFrame(const Mac::TxFrame &aFrame, Error aError, C
OT_UNREACHABLE_CODE(break);
}
Get<IndirectSender>().HandleSentFrameToChild(aFrame, mFrameContext, aError, aChild);
Get<IndirectSender>().HandleSentFrameToCslNeighbor(aFrame, mFrameContext, aError, aCslNeighbor);
exit:
return;
@@ -321,4 +325,4 @@ exit:
} // namespace ot
#endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
#endif // OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
+12 -10
View File
@@ -31,7 +31,7 @@
#include "openthread-core-config.h"
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
#include "common/locator.hpp"
#include "common/message.hpp"
@@ -52,7 +52,7 @@ namespace ot {
* @{
*/
class Child;
class CslNeighbor;
/**
* Implements CSL tx scheduling functionality.
@@ -66,11 +66,11 @@ public:
static constexpr uint8_t kMaxCslTriggeredTxAttempts = OPENTHREAD_CONFIG_MAC_MAX_TX_ATTEMPTS_INDIRECT_POLLS;
/**
* Defines all the child info required for scheduling CSL transmissions.
* Defines all the neighbor info required for scheduling CSL transmissions.
*
* `Child` class publicly inherits from this class.
* `CslNeighbor` publicly inherits from this class.
*/
class ChildInfo
class NeighborInfo
{
public:
uint8_t GetCslTxAttempts(void) const { return mCslTxAttempts; }
@@ -167,7 +167,7 @@ public:
* Updates the next CSL transmission (finds the nearest child).
*
* It would then request the `Mac` to do the CSL tx. If the last CSL tx has been fired at `Mac` but hasn't been
* done yet, and it's aborted, this method would set `mCslTxChild` to `nullptr` to notify the `HandleTransmitDone`
* done yet, and it's aborted, this method would clear current tx CSL neighbor to notify the `HandleTransmitDone`
* that the operation has been aborted.
*/
void Update(void);
@@ -190,16 +190,18 @@ private:
void RescheduleCslTx(void);
uint32_t GetNextCslTransmissionDelay(const Child &aChild, uint32_t &aDelayFromLastRx, uint32_t aAheadUs) const;
uint32_t GetNextCslTransmissionDelay(const CslNeighbor &aCslNeighbor,
uint32_t &aDelayFromLastRx,
uint32_t aAheadUs) const;
// Callbacks from `Mac`
Mac::TxFrame *HandleFrameRequest(Mac::TxFrames &aTxFrames);
void HandleSentFrame(const Mac::TxFrame &aFrame, Error aError);
void HandleSentFrame(const Mac::TxFrame &aFrame, Error aError, Child &aChild);
void HandleSentFrame(const Mac::TxFrame &aFrame, Error aError, CslNeighbor &aaCslNeighbor);
uint32_t mCslFrameRequestAheadUs;
Child *mCslTxChild;
CslNeighbor *mCslTxNeighbor;
Message *mCslTxMessage;
FrameContext mFrameContext;
};
@@ -210,6 +212,6 @@ private:
} // namespace ot
#endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
#endif // OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
#endif // CSL_TX_SCHEDULER_HPP_
+53 -7
View File
@@ -33,21 +33,21 @@
#include "indirect_sender.hpp"
#if OPENTHREAD_FTD
#include "instance/instance.hpp"
namespace ot {
const Mac::Address &IndirectSender::ChildInfo::GetMacAddress(Mac::Address &aMacAddress) const
#if OPENTHREAD_FTD || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
const Mac::Address &IndirectSender::NeighborInfo::GetMacAddress(Mac::Address &aMacAddress) const
{
if (mUseShortAddress)
{
aMacAddress.SetShort(static_cast<const Child *>(this)->GetRloc16());
aMacAddress.SetShort(static_cast<const CslNeighbor *>(this)->GetRloc16());
}
else
{
aMacAddress.SetExtended(static_cast<const Child *>(this)->GetExtAddress());
aMacAddress.SetExtended(static_cast<const CslNeighbor *>(this)->GetExtAddress());
}
return aMacAddress;
@@ -56,8 +56,10 @@ const Mac::Address &IndirectSender::ChildInfo::GetMacAddress(Mac::Address &aMacA
IndirectSender::IndirectSender(Instance &aInstance)
: InstanceLocator(aInstance)
, mEnabled(false)
#if OPENTHREAD_FTD
, mSourceMatchController(aInstance)
, mDataPollHandler(aInstance)
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
, mCslTxScheduler(aInstance)
#endif
@@ -68,6 +70,7 @@ void IndirectSender::Stop(void)
{
VerifyOrExit(mEnabled);
#if OPENTHREAD_FTD
for (Child &child : Get<ChildTable>().Iterate(Child::kInStateAnyExceptInvalid))
{
child.SetIndirectMessage(nullptr);
@@ -75,6 +78,8 @@ void IndirectSender::Stop(void)
}
mDataPollHandler.Clear();
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
mCslTxScheduler.Clear();
#endif
@@ -83,6 +88,8 @@ exit:
mEnabled = false;
}
#if OPENTHREAD_FTD
void IndirectSender::AddMessageForSleepyChild(Message &aMessage, Child &aChild)
{
uint16_t childIndex;
@@ -563,6 +570,45 @@ bool IndirectSender::AcceptSupervisionMessage(const Message &aMessage)
return aMessage.GetType() == Message::kTypeSupervision;
}
} // namespace ot
#endif // OPENTHREAD_FTD
#endif // #if OPENTHREAD_FTD
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
Error IndirectSender::PrepareFrameForCslNeighbor(Mac::TxFrame &aFrame,
FrameContext &aContext,
CslNeighbor &aCslNeighbor)
{
Error error = kErrorNotFound;
#if OPENTHREAD_FTD
// `CslNeighbor` can only be a `Child` for now, but can be changed later.
error = PrepareFrameForChild(aFrame, aContext, static_cast<Child &>(aCslNeighbor));
#else
OT_UNUSED_VARIABLE(aFrame);
OT_UNUSED_VARIABLE(aContext);
OT_UNUSED_VARIABLE(aCslNeighbor);
#endif
return error;
}
void IndirectSender::HandleSentFrameToCslNeighbor(const Mac::TxFrame &aFrame,
const FrameContext &aContext,
Error aError,
CslNeighbor &aCslNeighbor)
{
#if OPENTHREAD_FTD
HandleSentFrameToChild(aFrame, aContext, aError, static_cast<Child &>(aCslNeighbor));
#else
OT_UNUSED_VARIABLE(aFrame);
OT_UNUSED_VARIABLE(aContext);
OT_UNUSED_VARIABLE(aError);
OT_UNUSED_VARIABLE(aCslNeighbor);
#endif
}
#endif // OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
#endif // OPENTHREAD_FTD || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
} // namespace ot
+35 -12
View File
@@ -36,8 +36,6 @@
#include "openthread-core-config.h"
#if OPENTHREAD_FTD
#include "common/locator.hpp"
#include "common/message.hpp"
#include "common/non_copyable.hpp"
@@ -59,7 +57,12 @@ namespace ot {
* @{
*/
#if OPENTHREAD_FTD || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
class CslNeighbor;
#if OPENTHREAD_FTD
class Child;
#endif
/**
* Implements indirect transmission.
@@ -67,23 +70,27 @@ class Child;
class IndirectSender : public InstanceLocator, public IndirectSenderBase, private NonCopyable
{
friend class Instance;
#if OPENTHREAD_FTD
friend class DataPollHandler;
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
friend class CslTxScheduler;
#endif
public:
/**
* Defines all the child info required for indirect transmission.
* Defines all the neighbor info required for indirect (CSL or data-poll) transmission.
*
* `Child` class publicly inherits from this class.
* Sub-classes of `Neighbor`, e.g., `CslNeighbor` or `Child` publicly inherits from this class.
*/
class ChildInfo
class NeighborInfo
{
friend class IndirectSender;
#if OPENTHREAD_FTD
friend class DataPollHandler;
friend class CslTxScheduler;
friend class SourceMatchController;
#endif
friend class CslTxScheduler;
public:
/**
@@ -159,6 +166,7 @@ public:
*/
void Stop(void);
#if OPENTHREAD_FTD
/**
* Adds a message for indirect transmission to a sleepy child.
*
@@ -247,8 +255,20 @@ public:
*/
void HandleChildModeChange(Child &aChild, Mle::DeviceMode aOldMode);
#endif // OPENTHREAD_FTD
private:
// Callbacks from `DataPollHandler` or `CslTxScheduler`
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
// Callbacks from `CslTxScheduler`
Error PrepareFrameForCslNeighbor(Mac::TxFrame &aFrame, FrameContext &aContext, CslNeighbor &aCslNeighbor);
void HandleSentFrameToCslNeighbor(const Mac::TxFrame &aFrame,
const FrameContext &aContext,
Error aError,
CslNeighbor &aCslNeighbor);
#endif
#if OPENTHREAD_FTD
// Callbacks from `DataPollHandler`
Error PrepareFrameForChild(Mac::TxFrame &aFrame, FrameContext &aContext, Child &aChild);
void HandleSentFrameToChild(const Mac::TxFrame &aFrame, const FrameContext &aContext, Error aError, Child &aChild);
void HandleFrameChangeDone(Child &aChild);
@@ -261,21 +281,24 @@ private:
static bool AcceptAnyMessage(const Message &aMessage);
static bool AcceptSupervisionMessage(const Message &aMessage);
#endif // OPENTHREAD_FTD
bool mEnabled;
bool mEnabled;
#if OPENTHREAD_FTD
SourceMatchController mSourceMatchController;
DataPollHandler mDataPollHandler;
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
CslTxScheduler mCslTxScheduler;
#endif
};
#endif // #if OPENTHREAD_FTD || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
/**
* @}
*/
} // namespace ot
#endif // OPENTHREAD_FTD
#endif // INDIRECT_SENDER_HPP_
+1 -1
View File
@@ -105,7 +105,7 @@ MeshForwarder::MeshForwarder(Instance &aInstance)
, mTxDelayTimer(aInstance)
#endif
, mScheduleTransmissionTask(aInstance)
#if OPENTHREAD_FTD
#if OPENTHREAD_FTD || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
, mIndirectSender(aInstance)
#endif
, mDataPollSender(aInstance)
+4 -1
View File
@@ -643,8 +643,11 @@ private:
otIpCounters mIpCounters;
#if OPENTHREAD_FTD || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
IndirectSender mIndirectSender;
#endif
#if OPENTHREAD_FTD
IndirectSender mIndirectSender;
FwdFrameInfoArray mFwdFrameInfoArray;
#endif
+16
View File
@@ -769,6 +769,22 @@ private:
DefineCoreType(otNeighborInfo, Neighbor::Info);
/**
* Represents a CSL neighbor.
*/
class CslNeighbor : public Neighbor
#if OPENTHREAD_FTD || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
,
public IndirectSender::NeighborInfo,
public DataPollHandler::NeighborInfo
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
,
public CslTxScheduler::NeighborInfo
#endif
{
};
} // namespace ot
#endif // NEIGHBOR_HPP_