[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:
Abtin Keshavarzian
2018-02-06 17:23:10 +00:00
committed by Jonathan Hui
parent 2e08471706
commit cc8579fb3f
10 changed files with 720 additions and 0 deletions
+33
View File
@@ -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}
+1
View File
@@ -47,6 +47,7 @@ PRETTY_SUBDIRS = \
$(NULL)
openthread_headers = \
channel_manager.h \
channel_monitor.h \
child_supervision.h \
cli.h \
+128
View File
@@ -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_
+3
View File
@@ -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 \
+79
View File
@@ -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
+10
View File
@@ -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
+17
View File
@@ -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;
};
+15
View File
@@ -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
*
+241
View File
@@ -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
+193
View File
@@ -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_