mirror of
https://github.com/espressif/openthread.git
synced 2026-08-08 19:57:46 +00:00
[channel-manager] adding Channel Manager module (#2535)
This commit adds a new module/class `ChannelManager` which provides a mechanism to perform a network-wide channel change. It internally uses Pending Operational Dataset updates to trigger the channel change in the network. It also manages retries in case of errors/failures. This commit also adds public OT APIs for user to request a channel change and get/set different parameters related to operation of Channel Manager (e.g., supported channels mask). This feature can be enabled using `--enable-channel-manager` configure option (by default it is disabled).
This commit is contained in:
committed by
Jonathan Hui
parent
2e08471706
commit
cc8579fb3f
@@ -796,6 +796,38 @@ AC_SUBST(OPENTHREAD_ENABLE_CHANNEL_MONITOR)
|
||||
AM_CONDITIONAL([OPENTHREAD_ENABLE_CHANNEL_MONITOR], [test "${enable_channel_monitor}" = "yes"])
|
||||
AC_DEFINE_UNQUOTED([OPENTHREAD_ENABLE_CHANNEL_MONITOR],[${OPENTHREAD_ENABLE_CHANNEL_MONITOR}],[Define to 1 if you want to use channel monitor feature])
|
||||
|
||||
#
|
||||
# Channel Manager
|
||||
#
|
||||
|
||||
AC_ARG_ENABLE(channel_manager,
|
||||
[AS_HELP_STRING([--enable-channel-manager],[Enable Channel Manager support @<:@default=no@:>@.])],
|
||||
[
|
||||
case "${enableval}" in
|
||||
|
||||
no|yes)
|
||||
enable_channel_manager=${enableval}
|
||||
;;
|
||||
|
||||
*)
|
||||
AC_MSG_ERROR([Invalid value ${enable_channel_manager} for --enable-channel-manager])
|
||||
;;
|
||||
esac
|
||||
],
|
||||
[enable_channel_manager=no])
|
||||
|
||||
if test "$enable_channel_manager" = "yes"; then
|
||||
OPENTHREAD_ENABLE_CHANNEL_MANAGER=1
|
||||
else
|
||||
OPENTHREAD_ENABLE_CHANNEL_MANAGER=0
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([whether to enable channel manager])
|
||||
AC_MSG_RESULT(${enable_channel_manager})
|
||||
AC_SUBST(OPENTHREAD_ENABLE_CHANNEL_MANAGER)
|
||||
AM_CONDITIONAL([OPENTHREAD_ENABLE_CHANNEL_MANAGER], [test "${enable_channel_manager}" = "yes"])
|
||||
AC_DEFINE_UNQUOTED([OPENTHREAD_ENABLE_CHANNEL_MANAGER],[${OPENTHREAD_ENABLE_CHANNEL_MANAGER}],[Define to 1 if you want to enable channel manager feature])
|
||||
|
||||
#
|
||||
# MAC Filter (include AddressFilter and RssInFilter)
|
||||
#
|
||||
@@ -1601,6 +1633,7 @@ AC_MSG_NOTICE([
|
||||
OpenThread DTLS support : ${enable_dtls}
|
||||
OpenThread Jam Detection support : ${enable_jam_detection}
|
||||
OpenThread Channel Monitor support : ${enable_channel_monitor}
|
||||
OpenThread Channel Manager support : ${enable_channel_manager}
|
||||
OpenThread MAC Filter support : ${enable_mac_filter}
|
||||
OpenThread Diagnostics support : ${enable_diag}
|
||||
OpenThread Child Supervision support : ${enable_child_supervision}
|
||||
|
||||
@@ -47,6 +47,7 @@ PRETTY_SUBDIRS = \
|
||||
$(NULL)
|
||||
|
||||
openthread_headers = \
|
||||
channel_manager.h \
|
||||
channel_monitor.h \
|
||||
child_supervision.h \
|
||||
cli.h \
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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
|
||||
* @brief
|
||||
* This file includes the OpenThread API for Channel Manager module.
|
||||
*/
|
||||
|
||||
#ifndef OPENTHREAD_CHANNEL_MANAGER_H_
|
||||
#define OPENTHREAD_CHANNEL_MANAGER_H_
|
||||
|
||||
|
||||
#include "openthread/types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @addtogroup api-channel-manager
|
||||
*
|
||||
* @brief
|
||||
* This module includes functions for Channel Manager.
|
||||
*
|
||||
* The functions in this module are available when Channel Manager feature (`OPENTHREAD_ENABLE_CHANNEL_MANAGER`)
|
||||
* is enabled. Channel Manager is available only on an FTD build.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* This function requests a Thread network channel change.
|
||||
*
|
||||
* The network switches to the given channel after a specified delay (@sa otChannelManagerSetDelay). The channel change
|
||||
* is performed by updating the Pending Operational Dataset.
|
||||
*
|
||||
* A subsequent call to this function will cancel an ongoing previously requested channel change.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aChannel The new channel for the Thread network.
|
||||
|
||||
* @retval OT_ERROR_NONE Channel change request successfully processed.
|
||||
* @retval OT_ERROR_INVALID_ARGS The channel is not a supported channel (@sa otChannelManagerGetSupportedChannels).
|
||||
*
|
||||
*/
|
||||
otError otChannelManagerRequestChannelChange(otInstance *aInstance, uint8_t aChannel);
|
||||
|
||||
/**
|
||||
* This function gets the delay (in seconds) used by Channel Manager for a channel change.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
*
|
||||
* @returns The delay (in seconds) for channel change.
|
||||
*
|
||||
*/
|
||||
uint16_t otChannelManagerGetDelay(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* This function sets the delay (in seconds) used for a channel change.
|
||||
*
|
||||
* The delay should preferably be longer than maximum data poll interval used by all sleepy-end-devices within the
|
||||
* Thread network.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aDelay Delay in seconds.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Delay was updated successfully.
|
||||
* @retval OT_ERROR_INVALID_ARGS The given delay @p aDelay is too short.
|
||||
*
|
||||
*/
|
||||
otError otChannelManagerSetDelay(otInstance *aInstance, uint16_t aDelay);
|
||||
|
||||
/**
|
||||
* This function gets the supported channel mask.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
*
|
||||
* @returns The supported channels as bit-mask.
|
||||
*
|
||||
*/
|
||||
uint32_t otChannelManagerGetSupportedChannels(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* This function sets the supported channel mask.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aChannelMask A channel mask.
|
||||
*
|
||||
*/
|
||||
void otChannelManagerSetSupportedChannels(otInstance *aInstance, uint32_t aChannelMask);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // OPENTHREAD_CHANNEL_MANAGER_H_
|
||||
@@ -90,6 +90,7 @@ libopenthread_mtd_a_CPPFLAGS = \
|
||||
SOURCES_COMMON = \
|
||||
api/coap_api.cpp \
|
||||
api/commissioner_api.cpp \
|
||||
api/channel_manager_api.cpp \
|
||||
api/channel_monitor_api.cpp \
|
||||
api/child_supervision_api.cpp \
|
||||
api/crypto_api.cpp \
|
||||
@@ -185,6 +186,7 @@ SOURCES_COMMON = \
|
||||
thread/thread_netif.cpp \
|
||||
thread/tmf_proxy.cpp \
|
||||
thread/topology.cpp \
|
||||
utils/channel_manager.cpp \
|
||||
utils/channel_monitor.cpp \
|
||||
utils/child_supervision.cpp \
|
||||
utils/jam_detector.cpp \
|
||||
@@ -295,6 +297,7 @@ HEADERS_COMMON = \
|
||||
thread/thread_uri_paths.hpp \
|
||||
thread/tmf_proxy.hpp \
|
||||
thread/topology.hpp \
|
||||
utils/channel_manager.hpp \
|
||||
utils/channel_monitor.hpp \
|
||||
utils/child_supervision.hpp \
|
||||
utils/slaac_address.hpp \
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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 implements the OpenThread channel manager APIs.
|
||||
*/
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
#include "openthread/channel_manager.h"
|
||||
|
||||
#include "common/instance.hpp"
|
||||
#include "utils/channel_manager.hpp"
|
||||
|
||||
using namespace ot;
|
||||
|
||||
#if OPENTHREAD_ENABLE_CHANNEL_MANAGER && OPENTHREAD_FTD
|
||||
|
||||
otError otChannelManagerRequestChannelChange(otInstance *aInstance, uint8_t aChannel)
|
||||
{
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
return instance.GetChannelManager().RequestChannelChange(aChannel);
|
||||
}
|
||||
|
||||
uint16_t otChannelManagerGetDelay(otInstance *aInstance)
|
||||
{
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
return instance.GetChannelManager().GetDelay();
|
||||
}
|
||||
|
||||
otError otChannelManagerSetDelay(otInstance *aInstance, uint16_t aMinDelay)
|
||||
{
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
return instance.GetChannelManager().SetDelay(aMinDelay);
|
||||
}
|
||||
|
||||
uint32_t otChannelManagerGetSupportedChannels(otInstance *aInstance)
|
||||
{
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
return instance.GetChannelManager().GetSupportedChannels();
|
||||
}
|
||||
|
||||
void otChannelManagerSetSupportedChannels(otInstance *aInstance, uint32_t aChannelMask)
|
||||
{
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
return instance.GetChannelManager().SetSupportedChannels(aChannelMask);
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_ENABLE_CHANNEL_MANAGER && OPENTHREAD_FTD
|
||||
@@ -73,6 +73,9 @@ Instance::Instance(void) :
|
||||
#endif
|
||||
#if OPENTHREAD_ENABLE_CHANNEL_MONITOR
|
||||
mChannelMonitor(*this),
|
||||
#endif
|
||||
#if OPENTHREAD_ENABLE_CHANNEL_MANAGER
|
||||
mChannelManager(*this),
|
||||
#endif
|
||||
mMessagePool(*this),
|
||||
mIsInitialized(false)
|
||||
@@ -402,4 +405,11 @@ template<> Utils::ChannelMonitor &Instance::Get(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_ENABLE_CHANNEL_MANAGER
|
||||
template<> Utils::ChannelManager &Instance::Get(void)
|
||||
{
|
||||
return GetChannelManager();
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace ot
|
||||
|
||||
@@ -55,6 +55,9 @@
|
||||
#include "net/ip6.hpp"
|
||||
#include "thread/link_quality.hpp"
|
||||
#include "thread/thread_netif.hpp"
|
||||
#if OPENTHREAD_ENABLE_CHANNEL_MANAGER
|
||||
#include "utils/channel_manager.hpp"
|
||||
#endif
|
||||
#if OPENTHREAD_ENABLE_CHANNEL_MONITOR
|
||||
#include "utils/channel_monitor.hpp"
|
||||
#endif
|
||||
@@ -314,6 +317,16 @@ public:
|
||||
Utils::ChannelMonitor &GetChannelMonitor(void) { return mChannelMonitor; }
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_ENABLE_CHANNEL_MANAGER
|
||||
/**
|
||||
* This method returns a reference to ChannelManager object.
|
||||
*
|
||||
* @returns A reference to the ChannelManager object.
|
||||
*
|
||||
*/
|
||||
Utils::ChannelManager &GetChannelManager(void) { return mChannelManager; }
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This method returns a reference to message pool object.
|
||||
*
|
||||
@@ -382,6 +395,10 @@ private:
|
||||
Utils::ChannelMonitor mChannelMonitor;
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_ENABLE_CHANNEL_MANAGER
|
||||
Utils::ChannelManager mChannelManager;
|
||||
#endif
|
||||
|
||||
MessagePool mMessagePool;
|
||||
bool mIsInitialized;
|
||||
};
|
||||
|
||||
@@ -1056,6 +1056,21 @@
|
||||
#define OPENTHREAD_CONFIG_CHANNEL_MONITOR_SAMPLE_WINDOW 960
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_CHANNEL_MANAGER_MINIMUM_DELAY
|
||||
*
|
||||
* The minimum delay in seconds used by Channel Manager module for performing a channel change.
|
||||
*
|
||||
* The minimum delay should preferably be longer than maximum data poll interval used by all sleepy-end-devices within
|
||||
* the Thread network.
|
||||
*
|
||||
* Applicable only if Channel Manager feature is enabled (i.e., `OPENTHREAD_ENABLE_CHANNEL_MANAGER` is set).
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_CHANNEL_MANAGER_MINIMUM_DELAY
|
||||
#define OPENTHREAD_CONFIG_CHANNEL_MANAGER_MINIMUM_DELAY 120
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_CHILD_SUPERVISION_INTERVAL
|
||||
*
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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 implements Channel Manager.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "channel_manager.hpp"
|
||||
|
||||
#include <openthread/platform/random.h>
|
||||
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/instance.hpp"
|
||||
#include "common/logging.hpp"
|
||||
#include "common/owner-locator.hpp"
|
||||
|
||||
#if OPENTHREAD_ENABLE_CHANNEL_MANAGER && OPENTHREAD_FTD
|
||||
|
||||
namespace ot {
|
||||
namespace Utils {
|
||||
|
||||
ChannelManager::ChannelManager(Instance &aInstance):
|
||||
InstanceLocator(aInstance),
|
||||
mSupportedChannels(kDefaultSupprotedChannelMask),
|
||||
mActiveTimestamp(0),
|
||||
mNotifierCallback(&ChannelManager::HandleStateChanged, this),
|
||||
mDelay(kMinimumDelay),
|
||||
mChannel(0),
|
||||
mState(kStateIdle),
|
||||
mTimer(aInstance, &ChannelManager::HandleTimer, this)
|
||||
{
|
||||
}
|
||||
|
||||
otError ChannelManager::RequestChannelChange(uint8_t aChannel)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
otLogInfoUtil(GetInstance(), "ChannelManager: Request to change to channel %d with delay %d sec", aChannel, mDelay);
|
||||
|
||||
VerifyOrExit(aChannel != GetInstance().Get<Mac::Mac>().GetChannel());
|
||||
|
||||
if ((mSupportedChannels & (1U << aChannel)) == 0)
|
||||
{
|
||||
otLogInfoUtil(GetInstance(), "ChannelManager: Request rejected! Channel %d not in supported mask 0x%x",
|
||||
aChannel, mSupportedChannels);
|
||||
|
||||
ExitNow(error = OT_ERROR_INVALID_ARGS);
|
||||
}
|
||||
|
||||
mState = kStateChangeRequested;
|
||||
mChannel = aChannel;
|
||||
mActiveTimestamp = 0;
|
||||
PreparePendingDataset();
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError ChannelManager::SetDelay(uint16_t aDelay)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
VerifyOrExit(aDelay >= kMinimumDelay, error = OT_ERROR_INVALID_ARGS);
|
||||
mDelay = aDelay;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void ChannelManager::PreparePendingDataset(void)
|
||||
{
|
||||
ThreadNetif &netif = GetInstance().GetThreadNetif();
|
||||
uint64_t pendingTimestamp = 0;
|
||||
otOperationalDataset dataset;
|
||||
uint32_t delayInMs;
|
||||
otError error;
|
||||
|
||||
VerifyOrExit(mState == kStateChangeRequested);
|
||||
|
||||
if (netif.GetPendingDataset().Get(dataset) == OT_ERROR_NONE)
|
||||
{
|
||||
if (dataset.mIsPendingTimestampSet)
|
||||
{
|
||||
pendingTimestamp = dataset.mPendingTimestamp;
|
||||
}
|
||||
}
|
||||
|
||||
pendingTimestamp += (otPlatRandomGet() % kMaxTimestampIncrease) + 1;
|
||||
|
||||
error = netif.GetActiveDataset().Get(dataset);
|
||||
|
||||
if (error != OT_ERROR_NONE)
|
||||
{
|
||||
// If there is no valid Active Dataset but we are not disabled, set
|
||||
// the timer to try again after the retry interval. This handles the
|
||||
// situation where a channel change request comes right after the
|
||||
// network is formed but before the active dataset is created.
|
||||
|
||||
if (GetInstance().Get<Mle::Mle>().GetRole() != OT_DEVICE_ROLE_DISABLED)
|
||||
{
|
||||
mTimer.Start(kPendingDatasetTxRetryInterval);
|
||||
}
|
||||
else
|
||||
{
|
||||
mState = kStateIdle;
|
||||
otLogInfoUtil(GetInstance(), "ChannelManager: Request to change to channel %d failed. Device is disabled",
|
||||
mChannel);
|
||||
}
|
||||
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
// A non-zero `mActiveTimestamp` indicates that this is not the first
|
||||
// attempt to update the Dataset for the ongoing requested channel
|
||||
// change. In that case, if the Timestamp in current Active Dataset is
|
||||
// more recent compared to `mActiveTimestamp`, the channel change
|
||||
// process is canceled. This helps address situations where two
|
||||
// different devices may be performing channel change around the same
|
||||
// time.
|
||||
|
||||
if (mActiveTimestamp != 0)
|
||||
{
|
||||
if (dataset.mActiveTimestamp >= mActiveTimestamp)
|
||||
{
|
||||
otLogInfoUtil(GetInstance(),
|
||||
"ChannelManager: Canceling channel change to %d since current ActiveDataset is more recent",
|
||||
mChannel);
|
||||
|
||||
ExitNow();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mActiveTimestamp = dataset.mActiveTimestamp + 1 + (otPlatRandomGet() % kMaxTimestampIncrease);
|
||||
}
|
||||
|
||||
dataset.mActiveTimestamp = mActiveTimestamp;
|
||||
dataset.mIsActiveTimestampSet = true;
|
||||
|
||||
dataset.mChannel = mChannel;
|
||||
dataset.mIsChannelSet = true;
|
||||
|
||||
dataset.mPendingTimestamp = pendingTimestamp;
|
||||
dataset.mIsPendingTimestampSet = true;
|
||||
|
||||
delayInMs = TimerMilli::SecToMsec(static_cast<uint32_t>(mDelay));
|
||||
dataset.mDelay = delayInMs;
|
||||
dataset.mIsDelaySet = true;
|
||||
|
||||
error = netif.GetPendingDataset().SendSetRequest(dataset, NULL, 0);
|
||||
|
||||
if (error == OT_ERROR_NONE)
|
||||
{
|
||||
otLogInfoUtil(GetInstance(), "ChannelManager: Sent PendingDatasetSet to change channel to %d", mChannel);
|
||||
|
||||
mState = kStateSentMgmtPendingDataset;
|
||||
mTimer.Start(delayInMs + kChangeCheckWaitInterval);
|
||||
}
|
||||
else
|
||||
{
|
||||
otLogInfoUtil(GetInstance(), "ChannelManager: %s error in dataset update (channel change %d), retry in %d sec",
|
||||
otThreadErrorToString(error), mChannel, TimerMilli::MsecToSec(kPendingDatasetTxRetryInterval));
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void ChannelManager::HandleTimer(Timer &aTimer)
|
||||
{
|
||||
aTimer.GetOwner<ChannelManager>().HandleTimer();
|
||||
}
|
||||
|
||||
void ChannelManager::HandleTimer(void)
|
||||
{
|
||||
switch (mState)
|
||||
{
|
||||
case kStateIdle:
|
||||
break;
|
||||
|
||||
case kStateSentMgmtPendingDataset:
|
||||
otLogInfoUtil(GetInstance(), "ChannelManager: Timed out waiting for channel change to %d", mChannel);
|
||||
|
||||
// fall through
|
||||
|
||||
case kStateChangeRequested:
|
||||
PreparePendingDataset();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ChannelManager::HandleStateChanged(Notifier::Callback &aCallback, uint32_t aFlags)
|
||||
{
|
||||
aCallback.GetOwner<ChannelManager>().HandleStateChanged(aFlags);
|
||||
}
|
||||
|
||||
void ChannelManager::HandleStateChanged(uint32_t aFlags)
|
||||
{
|
||||
VerifyOrExit((aFlags & OT_CHANGED_THREAD_CHANNEL) != 0);
|
||||
VerifyOrExit(mChannel == GetInstance().Get<Mac::Mac>().GetChannel());
|
||||
|
||||
mState = kStateIdle;
|
||||
mTimer.Stop();
|
||||
|
||||
otLogInfoUtil(GetInstance(), "ChannelManager: Channel successfully changed to %d", mChannel);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
} // namespace Utils
|
||||
} // namespace ot
|
||||
|
||||
#endif // #if OPENTHREAD_ENABLE_CHANNEL_MANAGER
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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 Channel Manager.
|
||||
*/
|
||||
|
||||
#ifndef CHANNEL_MANAGER_HPP_
|
||||
#define CHANNEL_MANAGER_HPP_
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#include <openthread/platform/radio.h>
|
||||
#include <openthread/types.h>
|
||||
|
||||
#include "common/locator.hpp"
|
||||
#include "common/notifier.hpp"
|
||||
#include "common/timer.hpp"
|
||||
|
||||
namespace ot {
|
||||
namespace Utils {
|
||||
|
||||
/**
|
||||
* @addtogroup utils-channel-manager
|
||||
*
|
||||
* @brief
|
||||
* This module includes definitions for Channel Manager.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#if OPENTHREAD_ENABLE_CHANNEL_MANAGER
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
|
||||
/**
|
||||
* This class implements the Channel Manager.
|
||||
*
|
||||
*/
|
||||
class ChannelManager : public InstanceLocator
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
/**
|
||||
* Minimum delay in seconds used for network channel change.
|
||||
*
|
||||
*/
|
||||
kMinimumDelay = OPENTHREAD_CONFIG_CHANNEL_MANAGER_MINIMUM_DELAY,
|
||||
};
|
||||
|
||||
/**
|
||||
* This constructor initializes a `ChanelManager` object.
|
||||
*
|
||||
* @param[in] aInstance A reference to the OpenThread instance.
|
||||
*
|
||||
*/
|
||||
explicit ChannelManager(Instance &aInstance);
|
||||
|
||||
/**
|
||||
* This method requests a Thread network channel change.
|
||||
*
|
||||
* The Thread network switches to the given channel after a specified delay (@sa GetDelay()). The channel change is
|
||||
* performed by updating the Pending Operational Dataset.
|
||||
*
|
||||
* A subsequent call to this method will cancel an ongoing previously requested channel change.
|
||||
*
|
||||
* @param[in] aChannel The new channel for the Thread network.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Channel change request successfully processed.
|
||||
* @retval OT_ERROR_INVALID_ARGS The new channel is not a supported channel.
|
||||
*
|
||||
*/
|
||||
otError RequestChannelChange(uint8_t aChannel);
|
||||
|
||||
/**
|
||||
* This method gets the delay (in seconds) used for a channel change.
|
||||
*
|
||||
* @returns The delay (in seconds)
|
||||
*
|
||||
*/
|
||||
uint16_t GetDelay(void) const { return mDelay; }
|
||||
|
||||
/**
|
||||
* This method sets the delay (in seconds) used for a channel change.
|
||||
*
|
||||
* The delay should preferably be longer than maximum data poll interval used by all sleepy-end-devices within the
|
||||
* Thread network.
|
||||
*
|
||||
* @param[in] aDelay Delay in seconds.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Delay was updated successfully.
|
||||
* @retval OT_ERROR_INVALID_ARGS The given delay @p aDelay is shorter than `kMinimumDelay`.
|
||||
*
|
||||
*/
|
||||
otError SetDelay(uint16_t aDelay);
|
||||
|
||||
/**
|
||||
* This method gets the supported channel mask.
|
||||
*
|
||||
* @returns The supported channels mask.
|
||||
*
|
||||
*/
|
||||
uint32_t GetSupportedChannels(void) const { return mSupportedChannels; }
|
||||
|
||||
/**
|
||||
* This method sets the supported channel mask.
|
||||
*
|
||||
* @param[in] aChannelMask A channel mask.
|
||||
*
|
||||
*/
|
||||
void SetSupportedChannels(uint32_t aChannelMask) {
|
||||
mSupportedChannels = (aChannelMask & OT_RADIO_SUPPORTED_CHANNELS);
|
||||
}
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
kDefaultSupprotedChannelMask = OT_RADIO_SUPPORTED_CHANNELS,
|
||||
kMaxTimestampIncrease = 128,
|
||||
|
||||
kPendingDatasetTxRetryInterval = 20000, // in ms
|
||||
kChangeCheckWaitInterval = 30000, // in ms
|
||||
};
|
||||
|
||||
enum State
|
||||
{
|
||||
kStateIdle,
|
||||
kStateChangeRequested,
|
||||
kStateSentMgmtPendingDataset,
|
||||
};
|
||||
|
||||
static void HandleTimer(Timer &aTimer);
|
||||
void HandleTimer(void);
|
||||
static void HandleStateChanged(Notifier::Callback &aCallback, uint32_t aChangedFlags);
|
||||
void HandleStateChanged(uint32_t aChangedFlags);
|
||||
void PreparePendingDataset(void);
|
||||
|
||||
uint32_t mSupportedChannels;
|
||||
uint64_t mActiveTimestamp;
|
||||
Notifier::Callback mNotifierCallback;
|
||||
uint16_t mDelay;
|
||||
uint8_t mChannel;
|
||||
State mState;
|
||||
TimerMilli mTimer;
|
||||
};
|
||||
|
||||
#else // OPENTHREAD_FTD
|
||||
|
||||
class ChannelManager
|
||||
{
|
||||
public:
|
||||
explicit ChannelManager(Instance &) { }
|
||||
};
|
||||
|
||||
#endif // OPENTHREAD_FTD
|
||||
|
||||
#endif // OPENTHREAD_ENABLE_CHANNEL_MANAGER
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
*/
|
||||
|
||||
} // namespace Utils
|
||||
} // namespace ot
|
||||
|
||||
#endif // CHANNEL_MANAGER_HPP_
|
||||
Reference in New Issue
Block a user