Skip to content

Commit

Permalink
[wed] send Parent Request when receiving a wake-up frame
Browse files Browse the repository at this point in the history
This commit implements a new `EnhCslSender` module which combines
functionality from `CslTxScheduler` and `IndirectSender` for MTD
devices.

For now it's only used for communication with Wake-up Parent, but can
be extended in the future to schedule messages for other synchronized
neigbors.

In `Mac`, a new `kOperationTransmitDataEnhCsl` operation is added which
mimics `kOperationTransmitDataCsl`.

When a wake-up frame is received:

- Schedule modified Parent Request to Wake-up Coordinator
- Suppress Announce messages
- Suppress data polling
- Pause MLE attach backoff
  • Loading branch information
edmont committed Oct 15, 2024
1 parent 7ec2c31 commit ed856d7
Show file tree
Hide file tree
Showing 17 changed files with 1,076 additions and 38 deletions.
2 changes: 2 additions & 0 deletions src/core/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,8 @@ openthread_core_files = [
"thread/dua_manager.hpp",
"thread/energy_scan_server.cpp",
"thread/energy_scan_server.hpp",
"thread/enh_csl_sender.cpp",
"thread/enh_csl_sender.hpp",
"thread/indirect_sender.cpp",
"thread/indirect_sender.hpp",
"thread/indirect_sender_frame_context.hpp",
Expand Down
1 change: 1 addition & 0 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ set(COMMON_SOURCES
thread/discover_scanner.cpp
thread/dua_manager.cpp
thread/energy_scan_server.cpp
thread/enh_csl_sender.cpp
thread/indirect_sender.cpp
thread/key_manager.cpp
thread/link_metrics.cpp
Expand Down
2 changes: 1 addition & 1 deletion src/core/common/locator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ template <class InstanceGetProvider> class GetProvider
*
* @returns A reference to the `Type` object of the instance.
*/
template <typename Type> inline Type &Get(void) const; // Implemented in `locator_getters.hpp`.
template <typename Type> inline Type &Get(void) const;

protected:
GetProvider(void) = default;
Expand Down
19 changes: 19 additions & 0 deletions src/core/config/mac.h
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,25 @@
#define OPENTHREAD_CONFIG_MAC_DATA_POLL_TIMEOUT 100
#endif

/**
* @def OPENTHREAD_CONFIG_MAC_CSL_WAKEUP_INTERVAL
*
* Periodicity of wake-up frame transmission by WC (in units of 10 symbols).
*/
#ifndef OPENTHREAD_CONFIG_MAC_CSL_WAKEUP_INTERVAL
#define OPENTHREAD_CONFIG_MAC_CSL_WAKEUP_INTERVAL 47
#endif

/**
* @def OPENTHREAD_CONFIG_MAC_ENH_CSL_TX_ATTEMPTS
*
* Maximum number of TX attempts for the enhanced CSL communication before considering the peer de-synchronized.
*
*/
#ifndef OPENTHREAD_CONFIG_MAC_ENH_CSL_TX_ATTEMPTS
#define OPENTHREAD_CONFIG_MAC_ENH_CSL_TX_ATTEMPTS 8
#endif

/**
* @}
*/
Expand Down
4 changes: 4 additions & 0 deletions src/core/instance/instance.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -835,6 +835,10 @@ template <> inline MeshCoP::Leader &Instance::Get(void) { return mLeader; }
template <> inline MeshCoP::JoinerRouter &Instance::Get(void) { return mJoinerRouter; }
#endif // OPENTHREAD_FTD

#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
template <> inline EnhCslSender &Instance::Get(void) { return mMeshForwarder.mEnhCslSender; }
#endif

template <> inline AnnounceBeginServer &Instance::Get(void) { return mAnnounceBegin; }

template <> inline DataPollSender &Instance::Get(void) { return mMeshForwarder.mDataPollSender; }
Expand Down
97 changes: 92 additions & 5 deletions src/core/mac/mac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,9 @@ bool Mac::IsInTransmitState(void) const
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
case kOperationTransmitDataCsl:
#endif
#endif
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
case kOperationTransmitDataEnhCsl:
#endif
case kOperationTransmitBeacon:
case kOperationTransmitPoll:
Expand Down Expand Up @@ -517,6 +520,20 @@ void Mac::RequestCslFrameTransmission(uint32_t aDelay)
#endif
#endif // OPENTHREAD_FTD

#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
void Mac::RequestEnhCslFrameTransmission(uint32_t aDelay)
{
VerifyOrExit(mEnabled);

mEnhCslTxFireTime = TimerMilli::GetNow() + aDelay;

StartOperation(kOperationTransmitDataEnhCsl);

exit:
return;
}
#endif

Error Mac::RequestDataPollTransmission(void)
{
Error error = kErrorNone;
Expand All @@ -542,6 +559,13 @@ void Mac::UpdateIdleMode(void)

VerifyOrExit(mOperation == kOperationIdle);

#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
if (IsPending(kOperationTransmitDataEnhCsl))
{
mTimer.FireAt(mEnhCslTxFireTime);
}
#endif

if (!mRxOnWhenIdle)
{
#if OPENTHREAD_CONFIG_MAC_STAY_AWAKE_BETWEEN_FRAGMENTS
Expand Down Expand Up @@ -642,6 +666,12 @@ void Mac::PerformNextOperation(void)
{
mOperation = kOperationTransmitDataCsl;
}
#endif
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
else if (IsPending(kOperationTransmitDataEnhCsl) && TimerMilli::GetNow() >= mEnhCslTxFireTime)
{
mOperation = kOperationTransmitDataEnhCsl;
}
#endif
else if (IsPending(kOperationActiveScan))
{
Expand Down Expand Up @@ -706,6 +736,9 @@ void Mac::PerformNextOperation(void)
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
case kOperationTransmitDataCsl:
#endif
#endif
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
case kOperationTransmitDataEnhCsl:
#endif
case kOperationTransmitPoll:
BeginTransmit();
Expand Down Expand Up @@ -1019,6 +1052,23 @@ void Mac::BeginTransmit(void)
#endif
#endif // OPENTHREAD_FTD

#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
case kOperationTransmitDataEnhCsl:
txFrames.SetChannel(mRadioChannel);
txFrames.SetMaxCsmaBackoffs(kMaxCsmaBackoffsCsl);
txFrames.SetMaxFrameRetries(kMaxFrameRetriesCsl);
frame = Get<EnhCslSender>().HandleFrameRequest(txFrames);
VerifyOrExit(frame != nullptr);

// If the frame is marked as retransmission, then data sequence number is already set.
if (!frame->IsARetransmission())
{
frame->SetSequence(mDataSequence++);
}

break;
#endif

default:
OT_ASSERT(false);
}
Expand Down Expand Up @@ -1453,14 +1503,25 @@ void Mac::HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aError)
mRetryHistogram.mTxIndirectRetrySuccess[mLinks.GetTransmitRetries()]++;
}
#endif

DumpDebg("TX", aFrame.GetHeader(), aFrame.GetLength());
FinishOperation();
Get<DataPollHandler>().HandleSentFrame(aFrame, aError);
PerformNextOperation();
break;
#endif // OPENTHREAD_FTD

#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
case kOperationTransmitDataEnhCsl:
mCounters.mTxData++;

DumpDebg("TX", aFrame.GetHeader(), aFrame.GetLength());
FinishOperation();
Get<EnhCslSender>().HandleSentFrame(aFrame, aError);
PerformNextOperation();

break;
#endif

default:
OT_ASSERT(false);
}
Expand All @@ -1487,6 +1548,12 @@ void Mac::HandleTimer(void)
break;

case kOperationIdle:
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
if (IsPending(kOperationTransmitDataEnhCsl))
{
PerformNextOperation();
}
#endif
if (!mRxOnWhenIdle)
{
#if OPENTHREAD_CONFIG_MAC_STAY_AWAKE_BETWEEN_FRAGMENTS
Expand Down Expand Up @@ -1602,7 +1669,8 @@ Error Mac::ProcessReceiveSecurity(RxFrame &aFrame, const Address &aSrcAddr, Neig
{
uint32_t sequence;

// TODO: Avoid generating a new key if a wake-up frame was recently received already
// Avoid generating a new key if a wake-up frame was recently received already
VerifyOrExit(!Get<Mle::Mle>().IsWakeupCoordPresent(), error = kErrorInvalidState);

IgnoreError(aFrame.GetKeyId(keyid));
sequence = BigEndian::ReadUint32(aFrame.GetKeySource());
Expand Down Expand Up @@ -2207,6 +2275,9 @@ const char *Mac::OperationToString(Operation aOperation)
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
"TransmitDataCsl", // (8) kOperationTransmitDataCsl
#endif
#endif
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
"TransmitDataEnhCsl", // kOperationTransmitDataEnhCsl
#endif
};

Expand Down Expand Up @@ -2525,14 +2596,17 @@ void Mac::UpdateWakeupListening(void)

Error Mac::HandleWakeupFrame(const RxFrame &aFrame)
{
Error error = kErrorNone;
Error error = kErrorNone;
constexpr uint32_t kWakeupIntervalUs = kDefaultWedListenInterval * kUsPerTenSymbols;
const ConnectionIe *connectionIe;
uint32_t rvTimeUs;
uint64_t rvTimestampUs;
uint32_t attachDelayMs;
uint64_t radioNowUs;
uint8_t retryInterval;
uint8_t retryCount;
Neighbor *coord;
Address coordAddress;

VerifyOrExit(mWakeupListenEnabled && aFrame.IsWakeupFrame());
connectionIe = aFrame.GetConnectionIe();
Expand Down Expand Up @@ -2566,8 +2640,21 @@ Error Mac::HandleWakeupFrame(const RxFrame &aFrame)
// Stop receiving more wake up frames
IgnoreError(SetWakeupListenEnabled(false));

// TODO: start MLE attach process with the WC
OT_UNUSED_VARIABLE(attachDelayMs);
IgnoreError(aFrame.GetSrcAddr(coordAddress));
Get<Mle::Mle>().InitParentCandidate(coordAddress.GetExtended());
coord = &Get<Mle::MleRouter>().GetParentCandidate();
coord->SetEnhCslPeriod(kDefaultWedListenInterval * retryInterval);
coord->SetEnhCslPhase(0);
coord->SetEnhCslSynchronized(true);
coord->SetEnhCslLastHeard(TimerMilli::GetNow());
// Rendezvous time is the time when the WC begins listening for the connection request from the awakened WED.
// Since EnhCslSender schedules a frame's PHR at `LastRxTimestamp + Phase + n*Period`, increase the timestamp
// by SHR length and the CSL uncertainty to make sure SHR begins while the WC is already listening.
coord->SetEnhLastRxTimestamp(rvTimestampUs + kRadioHeaderShrDuration + Get<Radio>().GetCslUncertainty() * 10);
coord->SetEnhCslMaxTxAttempts(retryCount);

Get<Mle::Mle>().AttachToWakeupCoord(coordAddress.GetExtended(), TimerMilli::GetNow() + attachDelayMs,
kWakeupIntervalUs * retryInterval * retryCount / 1000);

exit:
return error;
Expand Down
19 changes: 17 additions & 2 deletions src/core/mac/mac.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ constexpr uint16_t kMinCslIePeriod = OPENTHREAD_CONFIG_MAC_CSL_MIN_PERIOD;

constexpr uint32_t kDefaultWedListenInterval = OPENTHREAD_CONFIG_WED_LISTEN_INTERVAL;
constexpr uint32_t kDefaultWedListenDuration = OPENTHREAD_CONFIG_WED_LISTEN_DURATION;
constexpr uint16_t kDefaultWakeupInterval = OPENTHREAD_CONFIG_MAC_CSL_WAKEUP_INTERVAL;

/**
* Defines the function pointer called on receiving an IEEE 802.15.4 Beacon during an Active Scan.
Expand Down Expand Up @@ -213,6 +214,16 @@ class Mac : public InstanceLocator, private NonCopyable
void RequestCslFrameTransmission(uint32_t aDelay);
#endif

#endif

#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
/**
* Requests `Mac` to start an enhanced CSL tx operation after a delay of @p aDelay time.
*
* @param[in] aDelay Delay time for `Mac` to start an enhanced CSL tx, in units of milliseconds.
*
*/
void RequestEnhCslFrameTransmission(uint32_t aDelay);
#endif

/**
Expand Down Expand Up @@ -762,6 +773,9 @@ class Mac : public InstanceLocator, private NonCopyable
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
kOperationTransmitDataCsl,
#endif
#endif
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
kOperationTransmitDataEnhCsl,
#endif
};

Expand Down Expand Up @@ -883,8 +897,9 @@ class Mac : public InstanceLocator, private NonCopyable
#endif
uint8_t mWakeupChannel;
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
uint32_t mWakeupListenInterval;
uint32_t mWakeupListenDuration;
uint32_t mWakeupListenInterval;
uint32_t mWakeupListenDuration;
TimeMilli mEnhCslTxFireTime;
#endif
union
{
Expand Down
Loading

0 comments on commit ed856d7

Please sign in to comment.