1#!/usr/bin/env python3 2# 3# Copyright (c) 2018, The OpenThread Authors. 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions are met: 8# 1. Redistributions of source code must retain the above copyright 9# notice, this list of conditions and the following disclaimer. 10# 2. Redistributions in binary form must reproduce the above copyright 11# notice, this list of conditions and the following disclaimer in the 12# documentation and/or other materials provided with the distribution. 13# 3. Neither the name of the copyright holder nor the 14# names of its contributors may be used to endorse or promote products 15# derived from this software without specific prior written permission. 16# 17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27# POSSIBILITY OF SUCH DAMAGE. 28 29import time 30import wpan 31from wpan import verify 32 33# ----------------------------------------------------------------------------------------------------------------------- 34# Test description: verifies `ChannelManager` channel selection procedure 35 36test_name = __file__[:-3] if __file__.endswith('.py') else __file__ 37print('-' * 120) 38print('Starting \'{}\''.format(test_name)) 39 40 41def verify_channel(nodes, new_channel, wait_time=20): 42 """ 43 This function checks the channel on a given list of `nodes` and verifies that all nodes 44 switch to a given `new_channel` (as int) within certain `wait_time` (int and in seconds) 45 """ 46 start_time = time.time() 47 48 while not all([(new_channel == int(node.get(wpan.WPAN_CHANNEL), 0)) for node in nodes]): 49 if time.time() - start_time > wait_time: 50 print('Took too long to switch to channel {} ({}>{} sec)'.format(new_channel, 51 time.time() - start_time, wait_time)) 52 exit(1) 53 time.sleep(0.1) 54 55 56# ----------------------------------------------------------------------------------------------------------------------- 57# Creating `wpan.Nodes` instances 58 59# Run the test with 10,000 time speedup factor 60wpan.Node.set_time_speedup_factor(10000) 61 62node = wpan.Node() 63 64# ----------------------------------------------------------------------------------------------------------------------- 65# Init all nodes 66 67wpan.Node.init_all_nodes() 68 69# ----------------------------------------------------------------------------------------------------------------------- 70# Build network topology 71 72node.form('channel-manager', channel=24) 73 74# ----------------------------------------------------------------------------------------------------------------------- 75# Test implementation 76 77all_channels_mask = int('0x7fff800', 0) 78chan_12_to_15_mask = int('0x000f000', 0) 79chan_15_to_17_mask = int('0x0038000', 0) 80 81# Set supported channel mask to be all channels 82node.set(wpan.WPAN_CHANNEL_MANAGER_SUPPORTED_CHANNEL_MASK, str(all_channels_mask)) 83verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_SUPPORTED_CHANNEL_MASK), 0) == all_channels_mask) 84 85WAIT_TIME = 15 86EXPECTED_SAMEPLE_COUNT = 970 87 88# Sleep for 4.5 second with speedup factor of 10,000 this is more than 12 89# hours. We sleep instead of immediately checking the sample counter in 90# order to not add more actions/events into simulation (specially since 91# we are running at very high speedup). 92time.sleep(4.5) 93 94 95def check_sample_count(): 96 verify(int(node.get(wpan.WPAN_CHANNEL_MONITOR_SAMPLE_COUNT), 0) > EXPECTED_SAMEPLE_COUNT) 97 98 99wpan.verify_within(check_sample_count, WAIT_TIME) 100 101# Verify the initial value of `NEW_CHANNEL` (should be zero if there has 102# been no channel change so far). 103 104verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL), 0) == 0) 105 106# Issue a channel-select with quality check enabled, and verify that no 107# action is taken. 108 109node.set(wpan.WPAN_CHANNEL_MANAGER_CHANNEL_SELECT, 'false') 110verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL), 0) == 0) 111 112# Issue a channel-select with quality check disabled, verify that channel 113# is switched to channel 11. 114 115node.set(wpan.WPAN_CHANNEL_MANAGER_CHANNEL_SELECT, 'true') 116verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL), 0) == 11) 117verify_channel([node], 11) 118 119# Set channels 12-15 as favorable and request a channel select, verify that channel is switched to 12. 120# 121# Even though 11 would be best, quality difference between 11 and 12 is not high enough for selection 122# algorithm to pick an unfavored channel. 123 124node.set(wpan.WPAN_CHANNEL_MANAGER_FAVORED_CHANNEL_MASK, str(chan_12_to_15_mask)) 125node.set(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL, '25') # request a channel change to 25 126verify_channel([node], 25) 127node.set(wpan.WPAN_CHANNEL_MANAGER_CHANNEL_SELECT, 'true') 128verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL), 0) == 12) 129verify_channel([node], 12) 130 131# Set channels 15-17 as favorables and request a channel select, verify that channel is switched to 11. 132# 133# This time the quality difference between 11 and 15 should be high enough for selection 134# algorithm to pick the best though unfavored channel (i.e., channel 11). 135 136node.set(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL, '25') # request a channel change to 25 137verify_channel([node], 25) 138node.set(wpan.WPAN_CHANNEL_MANAGER_FAVORED_CHANNEL_MASK, str(chan_15_to_17_mask)) 139node.set(wpan.WPAN_CHANNEL_MANAGER_CHANNEL_SELECT, 'true') 140verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL), 0) == 11) 141verify_channel([node], 11) 142 143# Set channels 12-15 as favorable and request a channel select, verify 144# that channel is not switched. 145 146node.set(wpan.WPAN_CHANNEL_MANAGER_FAVORED_CHANNEL_MASK, str(chan_12_to_15_mask)) 147node.set(wpan.WPAN_CHANNEL_MANAGER_CHANNEL_SELECT, 'true') 148verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL), 0) == 11) 149verify_channel([node], 11) 150 151# Starting from channel 12 and issuing a channel select (which would pick 11 as best channel). 152# However, since quality difference between current channel 12 and new best channel 11 is not large 153# enough, no action should be taken. 154 155node.set(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL, '12') # request a channel change to 12 156verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL), 0) == 12) 157verify_channel([node], 12) 158node.set(wpan.WPAN_CHANNEL_MANAGER_FAVORED_CHANNEL_MASK, str(all_channels_mask)) 159node.set(wpan.WPAN_CHANNEL_MANAGER_CHANNEL_SELECT, 'true') 160verify(int(node.get(wpan.WPAN_CHANNEL_MANAGER_NEW_CHANNEL), 0) == 12) 161verify_channel([node], 12) 162 163# ----------------------------------------------------------------------------------------------------------------------- 164# Test finished 165 166wpan.Node.finalize_all_nodes() 167 168print('\'{}\' passed.'.format(test_name)) 169