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 introduces a basic `CslNeighborTable` which currently
assumes a single ehanced CSL capable neighbor: the Wake-up Parent.

When a wake-up frame is received:

- Schedule modified Parent Request to Wake-up Parent
- Suppress Announce messages
- Suppress data polling
- Pause MLE attach backoff
  • Loading branch information
edmont committed Nov 27, 2024
1 parent 65dd8bf commit 03caf15
Show file tree
Hide file tree
Showing 20 changed files with 838 additions and 92 deletions.
2 changes: 1 addition & 1 deletion include/openthread/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -1142,7 +1142,7 @@ uint32_t otThreadGetStoreFrameCounterAhead(otInstance *aInstance);
* @param[in] aWakeupIntervalUs An interval between consecutive wake-up frames (in microseconds).
* @param[in] aWakeupDurationMs Duration of the wake-up sequence (in milliseconds).
* @param[in] aCallback A pointer to function that is called when the wake-up succeeds or fails.
* @param[in] aContext A pointer to callback application-specific context.
* @param[in] aCallbackContext A pointer to callback application-specific context.
*
* @retval OT_ERROR_NONE Successfully started the wake-up.
* @retval OT_ERROR_INVALID_STATE Another attachment request is still in progress.
Expand Down
2 changes: 2 additions & 0 deletions src/core/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,8 @@ openthread_core_files = [
"thread/dua_manager.hpp",
"thread/energy_scan_server.cpp",
"thread/energy_scan_server.hpp",
"thread/enh_csl_neighbor_table.cpp",
"thread/enh_csl_neighbor_table.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 @@ -214,6 +214,7 @@ set(COMMON_SOURCES
thread/discover_scanner.cpp
thread/dua_manager.cpp
thread/energy_scan_server.cpp
thread/enh_csl_neighbor_table.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
20 changes: 20 additions & 0 deletions src/core/common/message.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,9 @@ class Buffer : public otMessageBuffer, public LinkedListEntry<Buffer>
#endif
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
bool mTimeSync : 1; // Whether the message is also used for time sync purpose.
#endif
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
bool mIsEnhCslNeighbor : 1; // Whether the message is for an enhanced CSL neighbor.
#endif
uint8_t mPriority : 2; // The message priority level (higher value is higher priority).
uint8_t mOrigin : 2; // The origin of the message.
Expand Down Expand Up @@ -1469,6 +1472,23 @@ class Message : public otMessage, public Buffer, public GetProvider<Message>

#endif // #if OPENTHREAD_CONFIG_MULTI_RADIO

#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
/**
* Indicates whether the message is destined for an enhanced CSL neighbor.
*
* @retval TRUE If the message is destined for an enhanced CSL neighbor.
* @retval FALSE If the message is not destined for an enhanced CSL neighbor.
*/
bool IsForEnhancedCslNeighbor(void) const { return GetMetadata().mIsEnhCslNeighbor; }

/**
* Sets whether the message is destined for an enhanced CSL neighbor.
*
* @param[in] aIsEnhCslNeighbor TRUE if the message is destined for an enhanced CSL neighbor, FALSE otherwise.
*/
void SetForEnhancedCslNeighbor(bool aIsEnhCslNeighbor) { GetMetadata().mIsEnhCslNeighbor = aIsEnhCslNeighbor; }
#endif

protected:
class ConstIterator : public ItemPtrIterator<const Message, ConstIterator>
{
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
39 changes: 33 additions & 6 deletions src/core/mac/mac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1655,7 +1655,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>().IsWakeupParentPresent(), error = kErrorInvalidState);

IgnoreError(aFrame.GetKeyId(keyid));
sequence = BigEndian::ReadUint32(aFrame.GetKeySource());
Expand Down Expand Up @@ -2475,15 +2476,23 @@ void Mac::ProcessCsl(const RxFrame &aFrame, const Address &aSrcAddr)
CslNeighbor *neighbor = nullptr;
const CslIe *csl;

OT_UNUSED_VARIABLE(aSrcAddr);

VerifyOrExit(aFrame.IsVersion2015() && aFrame.GetSecurityEnabled());

csl = aFrame.GetCslIe();
VerifyOrExit(csl != nullptr);

#if OPENTHREAD_FTD
neighbor = Get<ChildTable>().FindChild(aSrcAddr, Child::kInStateAnyExceptInvalid);
#else
OT_UNUSED_VARIABLE(aSrcAddr);
#endif

#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
if (neighbor == nullptr)
{
neighbor = Get<Mle::Mle>().GetWakeupParent();
VerifyOrExit(neighbor->GetExtAddress() == aSrcAddr.GetExtended());
}
#endif

VerifyOrExit(neighbor != nullptr);
Expand Down Expand Up @@ -2620,14 +2629,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;
Address parentAddress;
CslNeighbor * parent;

VerifyOrExit(mWakeupListenEnabled && aFrame.IsWakeupFrame());
connectionIe = aFrame.GetConnectionIe();
Expand Down Expand Up @@ -2662,8 +2674,23 @@ 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(parentAddress));
Get<Mle::Mle>().AddWakeupParent(parentAddress.GetExtended(), TimerMilli::GetNow() + attachDelayMs,
kWakeupIntervalUs * retryInterval * retryCount / 1000);

parent = Get<Mle::Mle>().GetWakeupParent();
OT_ASSERT(parent != nullptr);
parent->SetCslPeriod(kDefaultWedListenInterval * retryInterval);
parent->SetCslPhase(0);
parent->SetCslSynchronized(true);
parent->SetCslLastHeard(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.
parent->SetLastRxTimestamp(rvTimestampUs + kRadioHeaderShrDuration + Get<Radio>().GetCslUncertainty() * 10);
parent->SetEnhCslMaxTxAttempts(retryCount);

Get<Mle::Mle>().AttachToWakeupParent();

exit:
return error;
Expand Down
1 change: 1 addition & 0 deletions src/core/mac/mac.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,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
16 changes: 16 additions & 0 deletions src/core/thread/csl_tx_scheduler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ class CslTxScheduler : public InstanceLocator, private NonCopyable

public:
static constexpr uint8_t kMaxCslTriggeredTxAttempts = OPENTHREAD_CONFIG_MAC_MAX_TX_ATTEMPTS_INDIRECT_POLLS;
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
static constexpr uint8_t kMaxEnhCslTriggeredTxAttempts = OPENTHREAD_CONFIG_MAC_ENH_CSL_TX_ATTEMPTS;
#endif

/**
* Defines all the neighbor info required for scheduling CSL transmissions.
Expand Down Expand Up @@ -98,6 +101,15 @@ class CslTxScheduler : public InstanceLocator, private NonCopyable
uint64_t GetLastRxTimestamp(void) const { return mLastRxTimestamp; }
void SetLastRxTimestamp(uint64_t aLastRxTimestamp) { mLastRxTimestamp = aLastRxTimestamp; }

#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
uint8_t GetEnhCslMaxTxAttempts(void) const
{
return mCslMaxTxAttempts != 0 ? mCslMaxTxAttempts : kMaxEnhCslTriggeredTxAttempts;
}
void SetEnhCslMaxTxAttempts(uint8_t txAttempts) { mCslMaxTxAttempts = txAttempts; }
void ResetEnhCslMaxTxAttempts() { mCslMaxTxAttempts = 0; }
#endif

private:
uint8_t mCslTxAttempts : 7; ///< Number of CSL triggered tx attempts.
bool mCslSynchronized : 1; ///< Indicates whether or not the child is CSL synchronized.
Expand Down Expand Up @@ -153,6 +165,10 @@ class CslTxScheduler : public InstanceLocator, private NonCopyable
uint64_t
mLastRxTimestamp; ///< Radio clock time when last frame containing CSL IE was received, in microseconds.

#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
uint8_t mCslMaxTxAttempts; ///< Override for the maximum number of enhanced CSL triggered tx attempts.
#endif

static_assert(kMaxCslTriggeredTxAttempts < (1 << 7), "mCslTxAttempts cannot fit max!");
};

Expand Down
62 changes: 62 additions & 0 deletions src/core/thread/enh_csl_neighbor_table.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright (c) 2024, 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.
*/

/**
* @file
* This file includes definitions for enhanced CSL neighbor table.
*/

#include "enh_csl_neighbor_table.hpp"

#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE

#include "instance/instance.hpp"

namespace ot {

CslNeighborTable::CslNeighborTable(Instance &aInstance)
{
for (CslNeighbor &cslNeighbor : mCslNeighbors)
{
cslNeighbor.Init(aInstance);
}
}

CslNeighbor *CslNeighborTable::GetNewCslNeighbor(void)
{
return mCslNeighbors;
}

CslNeighbor *CslNeighborTable::GetFirstCslNeighbor(void)
{
return mCslNeighbors;
}

} // namespace ot

#endif // OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
89 changes: 89 additions & 0 deletions src/core/thread/enh_csl_neighbor_table.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Copyright (c) 2024, 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.
*/

/**
* @file
* This file includes definitions for the CSL neighbors table.
*/

#ifndef ENH_CSL_NEIGHBOR_TABLE_HPP_
#define ENH_CSL_NEIGHBOR_TABLE_HPP_

#include "openthread-core-config.h"

#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE

#include "common/const_cast.hpp"
#include "common/iterator_utils.hpp"
#include "common/locator.hpp"
#include "common/non_copyable.hpp"
#include "thread/neighbor.hpp"

namespace ot {

/**
* Represents the CSL neighbors table.
*/
class CslNeighborTable : private NonCopyable
{
public:
/**
* Initializes a `CslNeighborTable` instance.
*
* @param[in] aInstance A reference to the OpenThread instance.
*/
explicit CslNeighborTable(Instance &aInstance);

/**
* Gets a new/unused `CslNeighbor` entry from the enhanced CSL neighbor table.
*
* @note The returned neighbor entry will be cleared (`memset` to zero).
*
* @returns A pointer to a new `CslNeighbor` entry, or `nullptr` if all `CslNeighbor` entries are in use.
*/
CslNeighbor *GetNewCslNeighbor(void);

/**
* Gets the first `CslNeighbor` entry in the enhanced CSL neighbor table.
*
* @returns A pointer to the first `CslNeighbor` entry, or `nullptr` if the table is empty.
*/
CslNeighbor *GetFirstCslNeighbor(void);

private:
// static constexpr uint16_t kMaxCslNeighbors = OPENTHREAD_CONFIG_MLE_MAX_ENH_CSL_NEIGHBORS;
static constexpr uint16_t kMaxCslNeighbors = 1;

CslNeighbor mCslNeighbors[kMaxCslNeighbors];
};

} // namespace ot

#endif // OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE

#endif // ENH_CSL_NEIGHBOR_TABLE_HPP_
Loading

0 comments on commit 03caf15

Please sign in to comment.