mirror of
https://github.com/espressif/openthread.git
synced 2026-08-13 14:17:47 +00:00
[tests] add new toranj test scripts for "ChannelManager" module
This commit adds new `toranj` test scripts to test newly added functionality by `ChannelManager` including: - Test to check new spinel/wpan properties, - Test to check channel change request feature, - Test to check channel selection feature. This commit also updates the posix/radio `otPlatRadioGetRssi()` to emulate a simple interference model where it would return either a high or a low RSSI value with a fixed probability per each channel. This is used to verify the `ChannelMonitor` sampling logic and channel selection functionality.
This commit is contained in:
@@ -33,6 +33,7 @@
|
||||
#include <openthread/platform/alarm-milli.h>
|
||||
#include <openthread/platform/diag.h>
|
||||
#include <openthread/platform/radio.h>
|
||||
#include <openthread/platform/random.h>
|
||||
|
||||
#include "utils/code_utils.h"
|
||||
|
||||
@@ -82,6 +83,10 @@ enum
|
||||
{
|
||||
POSIX_RECEIVE_SENSITIVITY = -100, // dBm
|
||||
POSIX_MAX_SRC_MATCH_ENTRIES = OPENTHREAD_CONFIG_MAX_CHILDREN,
|
||||
|
||||
POSIX_HIGH_RSSI_SAMPLE = -30, // dBm
|
||||
POSIX_LOW_RSSI_SAMPLE = -98, // dBm
|
||||
POSIX_HIGH_RSSI_PROB_INC_PER_CHANNEL = 5,
|
||||
};
|
||||
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
@@ -504,8 +509,27 @@ otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance)
|
||||
|
||||
int8_t otPlatRadioGetRssi(otInstance *aInstance)
|
||||
{
|
||||
int8_t rssi = POSIX_LOW_RSSI_SAMPLE;
|
||||
uint8_t channel = sReceiveFrame.mChannel;
|
||||
uint32_t probabilityThreshold;
|
||||
|
||||
(void)aInstance;
|
||||
return 0;
|
||||
|
||||
otEXPECT((OT_RADIO_CHANNEL_MIN <= channel) && channel <= (OT_RADIO_CHANNEL_MAX));
|
||||
|
||||
// To emulate a simple interference model, we return either a high or
|
||||
// a low RSSI value with a fixed probability per each channel. The
|
||||
// probability is increased per channel by a constant.
|
||||
|
||||
probabilityThreshold = (channel - OT_RADIO_CHANNEL_MIN) * POSIX_HIGH_RSSI_PROB_INC_PER_CHANNEL;
|
||||
|
||||
if ((otPlatRandomGet() & 0xffff) < (probabilityThreshold * 0xffff / 100))
|
||||
{
|
||||
rssi = POSIX_HIGH_RSSI_SAMPLE;
|
||||
}
|
||||
|
||||
exit:
|
||||
return rssi;
|
||||
}
|
||||
|
||||
otRadioCaps otPlatRadioGetCaps(otInstance *aInstance)
|
||||
|
||||
@@ -1271,6 +1271,7 @@ public:
|
||||
|
||||
/**
|
||||
* Default Delay Timer value for a Pending Operational Dataset (ms)
|
||||
*
|
||||
*/
|
||||
kDelayTimerDefault = OPENTHREAD_CONFIG_MESHCOP_PENDING_DATASET_DEFAULT_DELAY,
|
||||
};
|
||||
|
||||
@@ -532,7 +532,8 @@
|
||||
*
|
||||
* Minimum Delay Timer value for a Pending Operational Dataset (in ms).
|
||||
*
|
||||
* Thread specification defines this value as 30,000. Changing from the specified value should be done for testing only.
|
||||
* Thread specification defines this value as 30,000 ms. Changing from the specified value should be done for testing
|
||||
* only.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_MESHCOP_PENDING_DATASET_MINIMUM_DELAY
|
||||
@@ -544,7 +545,7 @@
|
||||
*
|
||||
* Default Delay Timer value for a Pending Operational Dataset (in ms).
|
||||
*
|
||||
* Thread specification defines this value as 300,000. Changing from the specified value should be done for testing
|
||||
* Thread specification defines this value as 300,000 ms. Changing from the specified value should be done for testing
|
||||
* only.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -183,6 +183,61 @@
|
||||
*/
|
||||
#define OPENTHREAD_CONFIG_MLE_SEND_LINK_REQUEST_ON_ADV_TIMEOUT 1
|
||||
|
||||
/**
|
||||
* @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).
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_CONFIG_CHANNEL_MANAGER_MINIMUM_DELAY 2
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_CHANNEL_MANAGER_THRESHOLD_TO_SKIP_FAVORED
|
||||
*
|
||||
* This threshold specifies the minimum occupancy rate difference between two channels for the Channel Manager to
|
||||
* prefer an unfavored channel over the best favored one. This is used when (auto) selecting a channel based on the
|
||||
* collected channel quality data by "channel monitor" feature.
|
||||
*
|
||||
* The difference is based on the `ChannelMonitor::GetChannelOccupancy()` definition which provides the average
|
||||
* percentage of RSSI samples (within a time window) indicating that channel was busy (i.e., RSSI value higher than
|
||||
* a threshold). Value 0 maps to 0% and 0xffff maps to 100%.
|
||||
*
|
||||
* Applicable only if Channel Manager feature is enabled (i.e., `OPENTHREAD_ENABLE_CHANNEL_MANAGER` is set).
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_CONFIG_CHANNEL_MANAGER_THRESHOLD_TO_SKIP_FAVORED (0xffff * 7 / 100)
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_CHANNEL_MANAGER_THRESHOLD_TO_CHANGE_CHANNEL
|
||||
*
|
||||
* This threshold specifies the minimum occupancy rate difference required between the current channel and a newly
|
||||
* selected channel for Channel Manager to allow channel change to the new channel.
|
||||
*
|
||||
* The difference is based on the `ChannelMonitor::GetChannelOccupancy()` definition which provides the average
|
||||
* percentage of RSSI samples (within a time window) indicating that channel was busy (i.e., RSSI value higher than
|
||||
* a threshold). Value 0 maps to 0% rate and 0xffff maps to 100%.
|
||||
*
|
||||
* Applicable only if Channel Manager feature is enabled (i.e., `OPENTHREAD_ENABLE_CHANNEL_MANAGER` is set).
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_CONFIG_CHANNEL_MANAGER_THRESHOLD_TO_CHANGE_CHANNEL (0xffff * 10 / 100)
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_MESHCOP_PENDING_DATASET_MINIMUM_DELAY
|
||||
*
|
||||
* Minimum Delay Timer value for a Pending Operational Dataset (in ms).
|
||||
*
|
||||
* Thread specification defines this value as 30,000. Changing from the specified value should be done for testing only.
|
||||
*
|
||||
* For `toranj` test script the value is decreased so that the tests can be run faster.
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_CONFIG_MESHCOP_PENDING_DATASET_MINIMUM_DELAY 1000
|
||||
|
||||
#endif /* OPENTHREAD_CORE_TORANJ_CONFIG_H_ */
|
||||
|
||||
|
||||
@@ -95,6 +95,7 @@ cd ../..
|
||||
--enable-mac-filter \
|
||||
--enable-service \
|
||||
--enable-channel-monitor \
|
||||
--enable-channel-manager \
|
||||
--disable-docs \
|
||||
--disable-test || die
|
||||
|
||||
@@ -115,4 +116,8 @@ run test-006-traffic-router-end-device.py
|
||||
run test-007-traffic-router-sleepy.py
|
||||
run test-008-permit-join.py
|
||||
|
||||
run test-600-channel-manager-properties.py
|
||||
run test-601-channel-manager-channel-change.py
|
||||
run test-602-channel-manager-channel-select.py
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# 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.
|
||||
|
||||
import time
|
||||
import wpan
|
||||
from wpan import verify
|
||||
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
# Test description: This test verifies wpantund properties related to `ChannelManager` feature
|
||||
|
||||
test_name = __file__[:-3] if __file__.endswith('.py') else __file__
|
||||
print '-' * 120
|
||||
print 'Starting \'{}\''.format(test_name)
|
||||
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
# Creating `wpan.Nodes` instances
|
||||
|
||||
node = wpan.Node()
|
||||
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
# Init all nodes
|
||||
|
||||
wpan.Node.init_all_nodes()
|
||||
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
# Build network topology
|
||||
|
||||
node.form("channel-manager", channel=11)
|
||||
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
# Test implementation
|
||||
|
||||
# Check default property values
|
||||
|
||||
verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL), 0) == 0)
|
||||
verify(node.get(wpan.WPAN_CHANNEL_MANAGER_AUTO_SELECT_ENABLED) == 'false')
|
||||
verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_SUPPORTED_CHANNEL_MASK), 0) == 0)
|
||||
verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_FAVORED_CHANNEL_MASK), 0) == 0)
|
||||
|
||||
# Set different wpan Channel Manager properties and get and check the output
|
||||
|
||||
node.set(wpan.WPAN_CHANNEL_MANAGER_DELAY, '180')
|
||||
verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_DELAY), 0) == 180)
|
||||
|
||||
node.set(wpan.WPAN_CHANNEL_MANAGER_AUTO_SELECT_ENABLED, '1')
|
||||
verify(node.get(wpan.WPAN_CHANNEL_MANAGER_AUTO_SELECT_ENABLED) == 'true')
|
||||
|
||||
node.set(wpan.WPAN_CHANNEL_MANAGER_AUTO_SELECT_ENABLED, '0')
|
||||
verify(node.get(wpan.WPAN_CHANNEL_MANAGER_AUTO_SELECT_ENABLED) == 'false')
|
||||
|
||||
node.set(wpan.WPAN_CHANNEL_MANAGER_AUTO_SELECT_INTERVAL, '1000')
|
||||
verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_AUTO_SELECT_INTERVAL), 0) == 1000)
|
||||
|
||||
all_channls_mask = int('0x7fff800', 0)
|
||||
chan_11_mask = int('0x800', 0)
|
||||
chan_11_to_13_mask = int('0x3800', 0)
|
||||
|
||||
node.set(wpan.WPAN_CHANNEL_MANAGER_SUPPORTED_CHANNEL_MASK, str(all_channls_mask))
|
||||
verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_SUPPORTED_CHANNEL_MASK), 0) == all_channls_mask)
|
||||
|
||||
node.set(wpan.WPAN_CHANNEL_MANAGER_FAVORED_CHANNEL_MASK, str(chan_11_mask))
|
||||
verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_FAVORED_CHANNEL_MASK), 0) == chan_11_mask)
|
||||
|
||||
node.set(wpan.WPAN_CHANNEL_MANAGER_SUPPORTED_CHANNEL_MASK, str(chan_11_to_13_mask))
|
||||
verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_SUPPORTED_CHANNEL_MASK), 0) == chan_11_to_13_mask)
|
||||
|
||||
node.set(wpan.WPAN_CHANNEL_MANAGER_FAVORED_CHANNEL_MASK, str(all_channls_mask))
|
||||
verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_FAVORED_CHANNEL_MASK), 0) == all_channls_mask)
|
||||
|
||||
node.set(wpan.WPAN_CHANNEL_MANAGER_AUTO_SELECT_ENABLED, '1')
|
||||
verify(node.get(wpan.WPAN_CHANNEL_MANAGER_AUTO_SELECT_ENABLED) == 'true')
|
||||
|
||||
# Check to ensure the property values are retained after an NCP reset
|
||||
|
||||
node.reset()
|
||||
|
||||
start_time = time.time()
|
||||
wait_time = 20
|
||||
|
||||
while node.get(wpan.WPAN_STATE) != wpan.STATE_ASSOCIATED:
|
||||
if time.time() - start_time > wait_time:
|
||||
print 'Took too long to restore after reset ({}>{} sec)'.format(time.time() - start_time, wait_time)
|
||||
exit(1)
|
||||
time.sleep(2)
|
||||
|
||||
verify(node.get(wpan.WPAN_CHANNEL_MANAGER_AUTO_SELECT_ENABLED) == 'true')
|
||||
verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_FAVORED_CHANNEL_MASK), 0) == all_channls_mask)
|
||||
verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_SUPPORTED_CHANNEL_MASK), 0) == chan_11_to_13_mask)
|
||||
verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_AUTO_SELECT_INTERVAL), 0) == 1000)
|
||||
verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_DELAY), 0) == 180)
|
||||
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
# Test finished
|
||||
|
||||
print '\'{}\' passed.'.format(test_name)
|
||||
@@ -0,0 +1,146 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# 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.
|
||||
|
||||
import time
|
||||
import wpan
|
||||
from wpan import verify
|
||||
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
# Test description: verifies `ChannelManager` channel change process
|
||||
|
||||
test_name = __file__[:-3] if __file__.endswith('.py') else __file__
|
||||
print '-' * 120
|
||||
print 'Starting \'{}\''.format(test_name)
|
||||
|
||||
|
||||
def verify_channel(nodes, new_channel, wait_time=20):
|
||||
"""
|
||||
This function checks the channel on a given list of `nodes` and verifies that all nodes
|
||||
switch to a given `new_channel` (as int) within certain `wait_time` (int and in seconds)
|
||||
"""
|
||||
start_time = time.time()
|
||||
|
||||
while not all([ (new_channel == int(node.get(wpan.WPAN_CHANNEL), 0)) for node in nodes ]):
|
||||
if time.time() - start_time > wait_time:
|
||||
print 'Took too long to switch to channel {} ({}>{} sec)'.format(new_channel, time.time() - start_time,
|
||||
wait_time)
|
||||
exit(1)
|
||||
time.sleep(0.1)
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
# Creating `wpan.Nodes` instances
|
||||
|
||||
speedup = 4
|
||||
wpan.Node.set_time_speedup_factor(speedup)
|
||||
|
||||
r1 = wpan.Node()
|
||||
r2 = wpan.Node()
|
||||
r3 = wpan.Node()
|
||||
sc1 = wpan.Node()
|
||||
ec1 = wpan.Node()
|
||||
sc2 = wpan.Node()
|
||||
sc3 = wpan.Node()
|
||||
|
||||
all_nodes = [r1, r2, r3, sc1, ec1, sc2, sc3]
|
||||
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
# Init all nodes
|
||||
|
||||
wpan.Node.init_all_nodes()
|
||||
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
# Build network topology
|
||||
|
||||
for node in all_nodes:
|
||||
node.set(wpan.WPAN_OT_LOG_LEVEL, '0')
|
||||
|
||||
r1.whitelist_node(r2)
|
||||
r2.whitelist_node(r1)
|
||||
r1.whitelist_node(r3)
|
||||
r3.whitelist_node(r1)
|
||||
|
||||
r1.whitelist_node(sc1)
|
||||
r1.whitelist_node(ec1)
|
||||
r2.whitelist_node(sc2)
|
||||
r3.whitelist_node(sc3)
|
||||
|
||||
r1.form('channel-manager', channel=12)
|
||||
r2.join_node(r1, node_type=wpan.JOIN_TYPE_ROUTER)
|
||||
r3.join_node(r1, node_type=wpan.JOIN_TYPE_ROUTER)
|
||||
sc1.join_node(r1, node_type=wpan.JOIN_TYPE_SLEEPY_END_DEVICE)
|
||||
ec1.join_node(r1, node_type=wpan.JOIN_TYPE_END_DEVICE)
|
||||
sc2.join_node(r2, node_type=wpan.JOIN_TYPE_SLEEPY_END_DEVICE)
|
||||
sc3.join_node(r3, node_type=wpan.JOIN_TYPE_SLEEPY_END_DEVICE)
|
||||
|
||||
sc1.set(wpan.WPAN_POLL_INTERVAL, '500')
|
||||
sc2.set(wpan.WPAN_POLL_INTERVAL, '500')
|
||||
sc3.set(wpan.WPAN_POLL_INTERVAL, '500')
|
||||
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
# Test implementation
|
||||
|
||||
# The channel manager delay is set from "openthread-core-toranj-config.h". Verify that it is 2 seconds.
|
||||
|
||||
verify(int(r1.get(wpan.WPAN_CHANNEL_MANAGER_DELAY), 0) == 2)
|
||||
|
||||
verify_channel(all_nodes, 12)
|
||||
|
||||
# Request a channel change to channel 13 from router r1
|
||||
|
||||
r1.set(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL, '13')
|
||||
verify(int(r1.get(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL), 0) == 13)
|
||||
verify_channel(all_nodes, 13)
|
||||
|
||||
# Request same channel change on multiple routers at the same time
|
||||
|
||||
r1.set(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL, '14')
|
||||
r2.set(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL, '14')
|
||||
r3.set(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL, '14')
|
||||
verify_channel(all_nodes, 14)
|
||||
|
||||
# Request different channel changes from same router (router r1).
|
||||
|
||||
r1.set(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL, '15')
|
||||
verify_channel(all_nodes, 14)
|
||||
r1.set(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL, '16')
|
||||
verify_channel(all_nodes, 16)
|
||||
|
||||
# Request different channels from two routers (r1 and r2)
|
||||
|
||||
r1.set(wpan.WPAN_CHANNEL_MANAGER_DELAY, '20') # increase the time to ensure r1 change is in process
|
||||
r1.set(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL, '17')
|
||||
time.sleep(10.5 / speedup)
|
||||
verify_channel(all_nodes, 16)
|
||||
r2.set(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL, '18')
|
||||
verify_channel(all_nodes, 18)
|
||||
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
# Test finished
|
||||
|
||||
print '\'{}\' passed.'.format(test_name)
|
||||
@@ -0,0 +1,151 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# 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.
|
||||
|
||||
import time
|
||||
import wpan
|
||||
from wpan import verify
|
||||
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
# Test description: verifies `ChannelManager` channel selection procedure
|
||||
|
||||
test_name = __file__[:-3] if __file__.endswith('.py') else __file__
|
||||
print '-' * 120
|
||||
print 'Starting \'{}\''.format(test_name)
|
||||
|
||||
def verify_channel(nodes, new_channel, wait_time=20):
|
||||
"""
|
||||
This function checks the channel on a given list of `nodes` and verifies that all nodes
|
||||
switch to a given `new_channel` (as int) within certain `wait_time` (int and in seconds)
|
||||
"""
|
||||
start_time = time.time()
|
||||
|
||||
while not all([ (new_channel == int(node.get(wpan.WPAN_CHANNEL), 0)) for node in nodes ]):
|
||||
if time.time() - start_time > wait_time:
|
||||
print 'Took too long to switch to channel {} ({}>{} sec)'.format(new_channel, time.time() - start_time,
|
||||
wait_time)
|
||||
exit(1)
|
||||
time.sleep(0.1)
|
||||
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
# Creating `wpan.Nodes` instances
|
||||
|
||||
# Run the test with 10,000 time speedup factor
|
||||
wpan.Node.set_time_speedup_factor(10000)
|
||||
|
||||
node = wpan.Node()
|
||||
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
# Init all nodes
|
||||
|
||||
wpan.Node.init_all_nodes()
|
||||
|
||||
node.set(wpan.WPAN_OT_LOG_LEVEL, '0')
|
||||
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
# Build network topology
|
||||
|
||||
node.form('channel-manager', channel=24)
|
||||
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
# Test implementation
|
||||
|
||||
all_channls_mask = int('0x7fff800', 0)
|
||||
chan_12_to_15_mask = int('0x000f000', 0)
|
||||
chan_15_to_17_mask = int('0x0038000', 0)
|
||||
|
||||
# Set supported channel mask to be all channels
|
||||
node.set(wpan.WPAN_CHANNEL_MANAGER_SUPPORTED_CHANNEL_MASK, str(all_channls_mask))
|
||||
verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_SUPPORTED_CHANNEL_MASK), 0) == all_channls_mask)
|
||||
|
||||
# Sleep for 4 second with speedup factor of 10,000 this is more than 11 hours.
|
||||
time.sleep(4)
|
||||
|
||||
verify(int(node.get(wpan.WPAN_CHANNEL_MONITOR_SAMPLE_COUNT), 0) > 970)
|
||||
|
||||
# Verify the initial value of `NEW_CHANNEL` (should be zero if there has been no channel change so far).
|
||||
|
||||
verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL), 0) == 0)
|
||||
|
||||
# Issue a channel-select with quality check enabled, and verify that no action is taken.
|
||||
|
||||
node.set(wpan.WPAN_CHANNEL_MANAGER_CHANNEL_SELECT, 'false')
|
||||
verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL), 0) == 0)
|
||||
|
||||
# Issue a channel-select with quality check disabled, verify that channel is switched to channel 11.
|
||||
|
||||
node.set(wpan.WPAN_CHANNEL_MANAGER_CHANNEL_SELECT, 'true')
|
||||
verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL), 0) == 11)
|
||||
verify_channel([node], 11)
|
||||
|
||||
# Set channels 12-15 as favorable and request a channel select, verify that channel is switched to 12.
|
||||
#
|
||||
# Even though 11 would be best, quality difference between 11 and 12 is not high enough for selection
|
||||
# algorithm to pick an unfavored channel.
|
||||
|
||||
node.set(wpan.WPAN_CHANNEL_MANAGER_FAVORED_CHANNEL_MASK, str(chan_12_to_15_mask))
|
||||
node.set(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL, '25') # request a channel change to 25
|
||||
verify_channel([node], 25)
|
||||
node.set(wpan.WPAN_CHANNEL_MANAGER_CHANNEL_SELECT, 'true')
|
||||
verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL), 0) == 12)
|
||||
verify_channel([node], 12)
|
||||
|
||||
# Set channels 15-17 as favorables and request a channel select, verify that channel is switched to 11.
|
||||
#
|
||||
# This time the quality difference between 11 and 15 should be high enough for selection
|
||||
# algorithm to pick the best though unfavored channel (i.e., channel 11).
|
||||
|
||||
node.set(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL, '25') # request a channel change to 25
|
||||
verify_channel([node], 25)
|
||||
node.set(wpan.WPAN_CHANNEL_MANAGER_FAVORED_CHANNEL_MASK, str(chan_15_to_17_mask))
|
||||
node.set(wpan.WPAN_CHANNEL_MANAGER_CHANNEL_SELECT, 'true')
|
||||
verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL), 0) == 11)
|
||||
verify_channel([node], 11)
|
||||
|
||||
# Set channels 12-15 as favorable and request a channel select, verify that channel is not switched.
|
||||
|
||||
node.set(wpan.WPAN_CHANNEL_MANAGER_FAVORED_CHANNEL_MASK, str(chan_12_to_15_mask))
|
||||
node.set(wpan.WPAN_CHANNEL_MANAGER_CHANNEL_SELECT, 'true')
|
||||
verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL), 0) == 11)
|
||||
verify_channel([node], 11)
|
||||
|
||||
# Starting from channel 12 and issuing a channel select (which would pick 11 as best channel).
|
||||
# However, since quality difference between current channel 12 and new best channel 11 is not large
|
||||
# enough, no action should be taken.
|
||||
|
||||
node.set(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL, '12') # request a channel change to 12
|
||||
verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL), 0) == 12)
|
||||
verify_channel([node], 12)
|
||||
node.set(wpan.WPAN_CHANNEL_MANAGER_FAVORED_CHANNEL_MASK, str(all_channls_mask))
|
||||
node.set(wpan.WPAN_CHANNEL_MANAGER_CHANNEL_SELECT, 'true')
|
||||
verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL), 0) == 12)
|
||||
verify_channel([node], 12)
|
||||
|
||||
#-----------------------------------------------------------------------------------------------------------------------
|
||||
# Test finished
|
||||
|
||||
print '\'{}\' passed.'.format(test_name)
|
||||
@@ -123,6 +123,14 @@ WPAN_CHANNEL_MONITOR_SAMPLE_COUNT = "ChannelMonitor:SampleCount"
|
||||
WPAN_CHANNEL_MONITOR_CHANNEL_QUALITY = "ChannelMonitor:ChannelQuality"
|
||||
WPAN_CHANNEL_MONITOR_CHANNEL_QUALITY_ASVALMAP = "ChannelMonitor:ChannelQuality:AsValMap"
|
||||
|
||||
WPAN_CHANNEL_MANAGER_NEW_CHANNEL = "ChannelManager:NewChannel"
|
||||
WPAN_CHANNEL_MANAGER_DELAY = "ChannelManager:Delay"
|
||||
WPAN_CHANNEL_MANAGER_CHANNEL_SELECT = "ChannelManager:ChannelSelect"
|
||||
WPAN_CHANNEL_MANAGER_AUTO_SELECT_ENABLED = "ChannelManager:AutoSelect:Enabled"
|
||||
WPAN_CHANNEL_MANAGER_AUTO_SELECT_INTERVAL = "ChannelManager:AutoSelect:Interval"
|
||||
WPAN_CHANNEL_MANAGER_SUPPORTED_CHANNEL_MASK = "ChannelManager:SupportedChannelMask"
|
||||
WPAN_CHANNEL_MANAGER_FAVORED_CHANNEL_MASK = "ChannelManager:FavoredChannelMask"
|
||||
|
||||
#----------------------------------------------------------------------------------------------------------------------
|
||||
# Valid state values
|
||||
|
||||
|
||||
Reference in New Issue
Block a user