1#!/usr/bin/env python3
2#
3#  Copyright (c) 2020, 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: This test covers joining of nodes with different radio links
35#
36# Parent node with trel and 15.4 with 3 children.
37#
38#        parent
39#    (trel + 15.4)
40#      /    |    \
41#     /     |     \
42#    /      |      \
43#   c1     c2       c3
44# (15.4)  (trel)  (trel+15.4)
45
46test_name = __file__[:-3] if __file__.endswith('.py') else __file__
47print('-' * 120)
48print('Starting \'{}\''.format(test_name))
49
50# -----------------------------------------------------------------------------------------------------------------------
51# Creating `wpan.Nodes` instances
52
53speedup = 4
54wpan.Node.set_time_speedup_factor(speedup)
55
56parent = wpan.Node(wpan.NODE_15_4_TREL)
57c1 = wpan.Node(wpan.NODE_15_4)
58c2 = wpan.Node(wpan.NODE_TREL)
59c3 = wpan.Node(wpan.NODE_15_4_TREL)
60
61# -----------------------------------------------------------------------------------------------------------------------
62# Init all nodes
63
64wpan.Node.init_all_nodes()
65
66# -----------------------------------------------------------------------------------------------------------------------
67# Test implementation
68
69WAIT_TIME = 5
70
71# Verify that each node supports the correct radio links:
72
73parent_radios = wpan.parse_list(parent.get(wpan.WPAN_OT_SUPPORTED_RADIO_LINKS))
74verify(
75    len(parent_radios) == 2 and (wpan.RADIO_LINK_IEEE_802_15_4 in parent_radios) and
76    (wpan.RADIO_LINK_TREL_UDP6 in parent_radios))
77
78c1_radios = wpan.parse_list(c1.get(wpan.WPAN_OT_SUPPORTED_RADIO_LINKS))
79verify(len(c1_radios) == 1 and wpan.RADIO_LINK_IEEE_802_15_4 in c1_radios)
80
81c2_radios = wpan.parse_list(c2.get(wpan.WPAN_OT_SUPPORTED_RADIO_LINKS))
82verify(len(c2_radios) == 1 and wpan.RADIO_LINK_TREL_UDP6 in c2_radios)
83
84c3_radios = wpan.parse_list(c3.get(wpan.WPAN_OT_SUPPORTED_RADIO_LINKS))
85verify(
86    len(c3_radios) == 2 and (wpan.RADIO_LINK_IEEE_802_15_4 in c3_radios) and (wpan.RADIO_LINK_TREL_UDP6 in c3_radios))
87
88parent.form("multi-radio")
89
90c1.join_node(parent, wpan.JOIN_TYPE_END_DEVICE)
91c2.join_node(parent, wpan.JOIN_TYPE_END_DEVICE)
92c3.join_node(parent, wpan.JOIN_TYPE_END_DEVICE)
93
94# Verify that parent correctly knows about all the children and their supported radio links
95
96radio_info_entries = wpan.parse_multi_radio_result(parent.get(wpan.WPAN_OT_NEIGHBOR_TABLE_MULTI_RADIO_INFO))
97verify(len(radio_info_entries) == 3)
98
99for node in [c1, c2, c3]:
100    # Find the entry matching node ext address
101    address = node.get(wpan.WPAN_EXT_ADDRESS)[1:-1]
102    filtred_list = [entry for entry in radio_info_entries if entry.ext_address == address]
103    verify(len(filtred_list) == 1)
104    entry = filtred_list[0]
105
106    # Verify that the multi radio info matches the radio links supported by the node
107    node_radios = wpan.parse_list(node.get(wpan.WPAN_OT_SUPPORTED_RADIO_LINKS))
108    verify(len(node_radios) == len(entry.radios))
109    for radio in node_radios:
110        verify(entry.supports(radio))
111
112# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
113
114# Reset the parent and check that all children are attached back successfully
115
116parent.reset()
117
118
119def check_all_children_are_attached():
120    neighbor_table = wpan.parse_neighbor_table_result(parent.get(wpan.WPAN_THREAD_NEIGHBOR_TABLE))
121    verify(len(neighbor_table) == 3)
122
123
124wpan.verify_within(check_all_children_are_attached, WAIT_TIME)
125
126# -----------------------------------------------------------------------------------------------------------------------
127# Test finished
128
129wpan.Node.finalize_all_nodes()
130
131print('\'{}\' passed.'.format(test_name))
132