xref: /aosp_15_r20/external/openthread/tests/toranj/cli/cli.py (revision cfb92d1480a9e65faed56933e9c12405f45898b4)
1*cfb92d14SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*cfb92d14SAndroid Build Coastguard Worker#
3*cfb92d14SAndroid Build Coastguard Worker#  Copyright (c) 2021, The OpenThread Authors.
4*cfb92d14SAndroid Build Coastguard Worker#  All rights reserved.
5*cfb92d14SAndroid Build Coastguard Worker#
6*cfb92d14SAndroid Build Coastguard Worker#  Redistribution and use in source and binary forms, with or without
7*cfb92d14SAndroid Build Coastguard Worker#  modification, are permitted provided that the following conditions are met:
8*cfb92d14SAndroid Build Coastguard Worker#  1. Redistributions of source code must retain the above copyright
9*cfb92d14SAndroid Build Coastguard Worker#     notice, this list of conditions and the following disclaimer.
10*cfb92d14SAndroid Build Coastguard Worker#  2. Redistributions in binary form must reproduce the above copyright
11*cfb92d14SAndroid Build Coastguard Worker#     notice, this list of conditions and the following disclaimer in the
12*cfb92d14SAndroid Build Coastguard Worker#     documentation and/or other materials provided with the distribution.
13*cfb92d14SAndroid Build Coastguard Worker#  3. Neither the name of the copyright holder nor the
14*cfb92d14SAndroid Build Coastguard Worker#     names of its contributors may be used to endorse or promote products
15*cfb92d14SAndroid Build Coastguard Worker#     derived from this software without specific prior written permission.
16*cfb92d14SAndroid Build Coastguard Worker#
17*cfb92d14SAndroid Build Coastguard Worker#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18*cfb92d14SAndroid Build Coastguard Worker#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19*cfb92d14SAndroid Build Coastguard Worker#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20*cfb92d14SAndroid Build Coastguard Worker#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21*cfb92d14SAndroid Build Coastguard Worker#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22*cfb92d14SAndroid Build Coastguard Worker#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23*cfb92d14SAndroid Build Coastguard Worker#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24*cfb92d14SAndroid Build Coastguard Worker#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25*cfb92d14SAndroid Build Coastguard Worker#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26*cfb92d14SAndroid Build Coastguard Worker#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27*cfb92d14SAndroid Build Coastguard Worker#  POSSIBILITY OF SUCH DAMAGE.
28*cfb92d14SAndroid Build Coastguard Worker#
29*cfb92d14SAndroid Build Coastguard Worker
30*cfb92d14SAndroid Build Coastguard Workerimport sys
31*cfb92d14SAndroid Build Coastguard Workerimport os
32*cfb92d14SAndroid Build Coastguard Workerimport time
33*cfb92d14SAndroid Build Coastguard Workerimport re
34*cfb92d14SAndroid Build Coastguard Workerimport random
35*cfb92d14SAndroid Build Coastguard Workerimport string
36*cfb92d14SAndroid Build Coastguard Workerimport subprocess
37*cfb92d14SAndroid Build Coastguard Workerimport pexpect
38*cfb92d14SAndroid Build Coastguard Workerimport pexpect.popen_spawn
39*cfb92d14SAndroid Build Coastguard Workerimport signal
40*cfb92d14SAndroid Build Coastguard Workerimport inspect
41*cfb92d14SAndroid Build Coastguard Workerimport weakref
42*cfb92d14SAndroid Build Coastguard Worker
43*cfb92d14SAndroid Build Coastguard Worker# ----------------------------------------------------------------------------------------------------------------------
44*cfb92d14SAndroid Build Coastguard Worker# Constants
45*cfb92d14SAndroid Build Coastguard Worker
46*cfb92d14SAndroid Build Coastguard WorkerJOIN_TYPE_ROUTER = 'router'
47*cfb92d14SAndroid Build Coastguard WorkerJOIN_TYPE_END_DEVICE = 'ed'
48*cfb92d14SAndroid Build Coastguard WorkerJOIN_TYPE_SLEEPY_END_DEVICE = 'sed'
49*cfb92d14SAndroid Build Coastguard WorkerJOIN_TYPE_REED = 'reed'
50*cfb92d14SAndroid Build Coastguard Worker
51*cfb92d14SAndroid Build Coastguard Worker# for use as `radios` parameter in `Node.__init__()`
52*cfb92d14SAndroid Build Coastguard WorkerRADIO_15_4 = "-15.4"
53*cfb92d14SAndroid Build Coastguard WorkerRADIO_TREL = "-trel"
54*cfb92d14SAndroid Build Coastguard WorkerRADIO_15_4_TREL = "-15.4-trel"
55*cfb92d14SAndroid Build Coastguard Worker
56*cfb92d14SAndroid Build Coastguard Worker# ----------------------------------------------------------------------------------------------------------------------
57*cfb92d14SAndroid Build Coastguard Worker
58*cfb92d14SAndroid Build Coastguard Worker
59*cfb92d14SAndroid Build Coastguard Workerdef _log(text, new_line=True, flush=True):
60*cfb92d14SAndroid Build Coastguard Worker    sys.stdout.write(text)
61*cfb92d14SAndroid Build Coastguard Worker    if new_line:
62*cfb92d14SAndroid Build Coastguard Worker        sys.stdout.write('\n')
63*cfb92d14SAndroid Build Coastguard Worker    if flush:
64*cfb92d14SAndroid Build Coastguard Worker        sys.stdout.flush()
65*cfb92d14SAndroid Build Coastguard Worker
66*cfb92d14SAndroid Build Coastguard Worker
67*cfb92d14SAndroid Build Coastguard Worker# ----------------------------------------------------------------------------------------------------------------------
68*cfb92d14SAndroid Build Coastguard Worker# CliError class
69*cfb92d14SAndroid Build Coastguard Worker
70*cfb92d14SAndroid Build Coastguard Worker
71*cfb92d14SAndroid Build Coastguard Workerclass CliError(Exception):
72*cfb92d14SAndroid Build Coastguard Worker
73*cfb92d14SAndroid Build Coastguard Worker    def __init__(self, error_code, message):
74*cfb92d14SAndroid Build Coastguard Worker        self._error_code = error_code
75*cfb92d14SAndroid Build Coastguard Worker        self._message = message
76*cfb92d14SAndroid Build Coastguard Worker
77*cfb92d14SAndroid Build Coastguard Worker    @property
78*cfb92d14SAndroid Build Coastguard Worker    def error_code(self):
79*cfb92d14SAndroid Build Coastguard Worker        return self._error_code
80*cfb92d14SAndroid Build Coastguard Worker
81*cfb92d14SAndroid Build Coastguard Worker    @property
82*cfb92d14SAndroid Build Coastguard Worker    def message(self):
83*cfb92d14SAndroid Build Coastguard Worker        return self._message
84*cfb92d14SAndroid Build Coastguard Worker
85*cfb92d14SAndroid Build Coastguard Worker
86*cfb92d14SAndroid Build Coastguard Worker# ----------------------------------------------------------------------------------------------------------------------
87*cfb92d14SAndroid Build Coastguard Worker# Node class
88*cfb92d14SAndroid Build Coastguard Worker
89*cfb92d14SAndroid Build Coastguard Worker
90*cfb92d14SAndroid Build Coastguard Workerclass Node(object):
91*cfb92d14SAndroid Build Coastguard Worker    """ An OT CLI instance """
92*cfb92d14SAndroid Build Coastguard Worker
93*cfb92d14SAndroid Build Coastguard Worker    # defines the default verbosity setting (can be changed per `Node`)
94*cfb92d14SAndroid Build Coastguard Worker    _VERBOSE = os.getenv('TORANJ_VERBOSE', 'no').lower() in ['true', '1', 't', 'y', 'yes', 'on']
95*cfb92d14SAndroid Build Coastguard Worker
96*cfb92d14SAndroid Build Coastguard Worker    _SPEED_UP_FACTOR = 1  # defines the default time speed up factor
97*cfb92d14SAndroid Build Coastguard Worker
98*cfb92d14SAndroid Build Coastguard Worker    # Determine whether to save logs in a file.
99*cfb92d14SAndroid Build Coastguard Worker    _SAVE_LOGS = True
100*cfb92d14SAndroid Build Coastguard Worker
101*cfb92d14SAndroid Build Coastguard Worker    # name of  log file (if _SAVE_LOGS is `True`)
102*cfb92d14SAndroid Build Coastguard Worker    _LOG_FNAME = 'ot-logs'
103*cfb92d14SAndroid Build Coastguard Worker
104*cfb92d14SAndroid Build Coastguard Worker    _OT_BUILDDIR = os.getenv('top_builddir', '../../..')
105*cfb92d14SAndroid Build Coastguard Worker
106*cfb92d14SAndroid Build Coastguard Worker    _OT_CLI_FTD = '%s/examples/apps/cli/ot-cli-ftd' % _OT_BUILDDIR
107*cfb92d14SAndroid Build Coastguard Worker
108*cfb92d14SAndroid Build Coastguard Worker    _WAIT_TIME = 10
109*cfb92d14SAndroid Build Coastguard Worker
110*cfb92d14SAndroid Build Coastguard Worker    _START_INDEX = 1
111*cfb92d14SAndroid Build Coastguard Worker    _cur_index = _START_INDEX
112*cfb92d14SAndroid Build Coastguard Worker
113*cfb92d14SAndroid Build Coastguard Worker    _all_nodes = weakref.WeakSet()
114*cfb92d14SAndroid Build Coastguard Worker
115*cfb92d14SAndroid Build Coastguard Worker    def __init__(self, radios='', index=None, verbose=_VERBOSE):
116*cfb92d14SAndroid Build Coastguard Worker        """Creates a new `Node` instance"""
117*cfb92d14SAndroid Build Coastguard Worker
118*cfb92d14SAndroid Build Coastguard Worker        if index is None:
119*cfb92d14SAndroid Build Coastguard Worker            index = Node._cur_index
120*cfb92d14SAndroid Build Coastguard Worker            Node._cur_index += 1
121*cfb92d14SAndroid Build Coastguard Worker
122*cfb92d14SAndroid Build Coastguard Worker        self._index = index
123*cfb92d14SAndroid Build Coastguard Worker        self._verbose = verbose
124*cfb92d14SAndroid Build Coastguard Worker
125*cfb92d14SAndroid Build Coastguard Worker        cmd = f'{self._OT_CLI_FTD}{radios} --time-speed={self._SPEED_UP_FACTOR} '
126*cfb92d14SAndroid Build Coastguard Worker
127*cfb92d14SAndroid Build Coastguard Worker        if Node._SAVE_LOGS:
128*cfb92d14SAndroid Build Coastguard Worker            log_file_name = self._LOG_FNAME + str(index) + '.log'
129*cfb92d14SAndroid Build Coastguard Worker            cmd = cmd + f'--log-file={log_file_name} '
130*cfb92d14SAndroid Build Coastguard Worker
131*cfb92d14SAndroid Build Coastguard Worker        cmd = cmd + f'{self._index}'
132*cfb92d14SAndroid Build Coastguard Worker
133*cfb92d14SAndroid Build Coastguard Worker        if self._verbose:
134*cfb92d14SAndroid Build Coastguard Worker            _log(f'$ Node{index}.__init__() cmd: `{cmd}`')
135*cfb92d14SAndroid Build Coastguard Worker
136*cfb92d14SAndroid Build Coastguard Worker        self._cli_process = pexpect.popen_spawn.PopenSpawn(cmd)
137*cfb92d14SAndroid Build Coastguard Worker        Node._all_nodes.add(self)
138*cfb92d14SAndroid Build Coastguard Worker
139*cfb92d14SAndroid Build Coastguard Worker    def __del__(self):
140*cfb92d14SAndroid Build Coastguard Worker        self._finalize()
141*cfb92d14SAndroid Build Coastguard Worker
142*cfb92d14SAndroid Build Coastguard Worker    def __repr__(self):
143*cfb92d14SAndroid Build Coastguard Worker        return f'Node(index={self._index})'
144*cfb92d14SAndroid Build Coastguard Worker
145*cfb92d14SAndroid Build Coastguard Worker    @property
146*cfb92d14SAndroid Build Coastguard Worker    def index(self):
147*cfb92d14SAndroid Build Coastguard Worker        return self._index
148*cfb92d14SAndroid Build Coastguard Worker
149*cfb92d14SAndroid Build Coastguard Worker    # ------------------------------------------------------------------------------------------------------------------
150*cfb92d14SAndroid Build Coastguard Worker    # Executing a `cli` command
151*cfb92d14SAndroid Build Coastguard Worker
152*cfb92d14SAndroid Build Coastguard Worker    def cli(self, *args):
153*cfb92d14SAndroid Build Coastguard Worker        """ Issues a CLI command on the given node and returns the resulting output.
154*cfb92d14SAndroid Build Coastguard Worker
155*cfb92d14SAndroid Build Coastguard Worker            The returned result is a list of strings (with `\r\n` removed) as outputted by the CLI.
156*cfb92d14SAndroid Build Coastguard Worker            If executing the command fails, `CliError` is raised with error code and error message.
157*cfb92d14SAndroid Build Coastguard Worker        """
158*cfb92d14SAndroid Build Coastguard Worker
159*cfb92d14SAndroid Build Coastguard Worker        cmd = ' '.join([f'{arg}' for arg in args if arg is not None]).strip()
160*cfb92d14SAndroid Build Coastguard Worker
161*cfb92d14SAndroid Build Coastguard Worker        if self._verbose:
162*cfb92d14SAndroid Build Coastguard Worker            _log(f'$ Node{self._index}.cli(\'{cmd}\')', new_line=False)
163*cfb92d14SAndroid Build Coastguard Worker
164*cfb92d14SAndroid Build Coastguard Worker        self._cli_process.send(cmd + '\n')
165*cfb92d14SAndroid Build Coastguard Worker        index = self._cli_process.expect(['(.*)Done\r\n', '.*Error (\d+):(.*)\r\n'])
166*cfb92d14SAndroid Build Coastguard Worker
167*cfb92d14SAndroid Build Coastguard Worker        if index == 0:
168*cfb92d14SAndroid Build Coastguard Worker            result = [
169*cfb92d14SAndroid Build Coastguard Worker                line for line in self._cli_process.match.group(1).decode().splitlines()
170*cfb92d14SAndroid Build Coastguard Worker                if not self._is_ot_logg_line(line) if not line.strip().endswith(cmd)
171*cfb92d14SAndroid Build Coastguard Worker            ]
172*cfb92d14SAndroid Build Coastguard Worker
173*cfb92d14SAndroid Build Coastguard Worker            if self._verbose:
174*cfb92d14SAndroid Build Coastguard Worker                if len(result) > 1:
175*cfb92d14SAndroid Build Coastguard Worker                    _log(':')
176*cfb92d14SAndroid Build Coastguard Worker                    for line in result:
177*cfb92d14SAndroid Build Coastguard Worker                        _log('     ' + line)
178*cfb92d14SAndroid Build Coastguard Worker                elif len(result) == 1:
179*cfb92d14SAndroid Build Coastguard Worker                    _log(f' -> {result[0]}')
180*cfb92d14SAndroid Build Coastguard Worker                else:
181*cfb92d14SAndroid Build Coastguard Worker                    _log('')
182*cfb92d14SAndroid Build Coastguard Worker
183*cfb92d14SAndroid Build Coastguard Worker            return result
184*cfb92d14SAndroid Build Coastguard Worker        else:
185*cfb92d14SAndroid Build Coastguard Worker            match = self._cli_process.match
186*cfb92d14SAndroid Build Coastguard Worker            e = CliError(int(match.group(1).decode()), match.group(2).decode().strip())
187*cfb92d14SAndroid Build Coastguard Worker            if self._verbose:
188*cfb92d14SAndroid Build Coastguard Worker                _log(f': Error {e.message} ({e.error_code})')
189*cfb92d14SAndroid Build Coastguard Worker            raise e
190*cfb92d14SAndroid Build Coastguard Worker
191*cfb92d14SAndroid Build Coastguard Worker    def _is_ot_logg_line(self, line):
192*cfb92d14SAndroid Build Coastguard Worker        return any(level in line for level in [' [D] ', ' [I] ', ' [N] ', ' [W] ', ' [C] ', ' [-] '])
193*cfb92d14SAndroid Build Coastguard Worker
194*cfb92d14SAndroid Build Coastguard Worker    def _cli_no_output(self, cmd, *args):
195*cfb92d14SAndroid Build Coastguard Worker        outputs = self.cli(cmd, *args)
196*cfb92d14SAndroid Build Coastguard Worker        verify(len(outputs) == 0)
197*cfb92d14SAndroid Build Coastguard Worker
198*cfb92d14SAndroid Build Coastguard Worker    def _cli_single_output(self, cmd, *args, expected_outputs=None):
199*cfb92d14SAndroid Build Coastguard Worker        outputs = self.cli(cmd, *args)
200*cfb92d14SAndroid Build Coastguard Worker        verify(len(outputs) == 1)
201*cfb92d14SAndroid Build Coastguard Worker        verify((expected_outputs is None) or (outputs[0] in expected_outputs))
202*cfb92d14SAndroid Build Coastguard Worker        return outputs[0]
203*cfb92d14SAndroid Build Coastguard Worker
204*cfb92d14SAndroid Build Coastguard Worker    def _finalize(self):
205*cfb92d14SAndroid Build Coastguard Worker        if self._cli_process.proc.poll() is None:
206*cfb92d14SAndroid Build Coastguard Worker            if self._verbose:
207*cfb92d14SAndroid Build Coastguard Worker                _log(f'$ Node{self.index} terminating')
208*cfb92d14SAndroid Build Coastguard Worker            self._cli_process.send('exit\n')
209*cfb92d14SAndroid Build Coastguard Worker            self._cli_process.wait()
210*cfb92d14SAndroid Build Coastguard Worker
211*cfb92d14SAndroid Build Coastguard Worker    # ------------------------------------------------------------------------------------------------------------------
212*cfb92d14SAndroid Build Coastguard Worker    # cli commands
213*cfb92d14SAndroid Build Coastguard Worker
214*cfb92d14SAndroid Build Coastguard Worker    def get_state(self):
215*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('state', expected_outputs=['detached', 'child', 'router', 'leader', 'disabled'])
216*cfb92d14SAndroid Build Coastguard Worker
217*cfb92d14SAndroid Build Coastguard Worker    def get_version(self):
218*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('version')
219*cfb92d14SAndroid Build Coastguard Worker
220*cfb92d14SAndroid Build Coastguard Worker    def get_channel(self):
221*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('channel')
222*cfb92d14SAndroid Build Coastguard Worker
223*cfb92d14SAndroid Build Coastguard Worker    def set_channel(self, channel):
224*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('channel', channel)
225*cfb92d14SAndroid Build Coastguard Worker
226*cfb92d14SAndroid Build Coastguard Worker    def get_csl_config(self):
227*cfb92d14SAndroid Build Coastguard Worker        outputs = self.cli('csl')
228*cfb92d14SAndroid Build Coastguard Worker        result = {}
229*cfb92d14SAndroid Build Coastguard Worker        for line in outputs:
230*cfb92d14SAndroid Build Coastguard Worker            fields = line.split(':')
231*cfb92d14SAndroid Build Coastguard Worker            result[fields[0].strip()] = fields[1].strip()
232*cfb92d14SAndroid Build Coastguard Worker        return result
233*cfb92d14SAndroid Build Coastguard Worker
234*cfb92d14SAndroid Build Coastguard Worker    def set_csl_period(self, period):
235*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('csl period', period)
236*cfb92d14SAndroid Build Coastguard Worker
237*cfb92d14SAndroid Build Coastguard Worker    def get_ext_addr(self):
238*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('extaddr')
239*cfb92d14SAndroid Build Coastguard Worker
240*cfb92d14SAndroid Build Coastguard Worker    def set_ext_addr(self, ext_addr):
241*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('extaddr', ext_addr)
242*cfb92d14SAndroid Build Coastguard Worker
243*cfb92d14SAndroid Build Coastguard Worker    def get_ext_panid(self):
244*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('extpanid')
245*cfb92d14SAndroid Build Coastguard Worker
246*cfb92d14SAndroid Build Coastguard Worker    def set_ext_panid(self, ext_panid):
247*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('extpanid', ext_panid)
248*cfb92d14SAndroid Build Coastguard Worker
249*cfb92d14SAndroid Build Coastguard Worker    def get_mode(self):
250*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('mode')
251*cfb92d14SAndroid Build Coastguard Worker
252*cfb92d14SAndroid Build Coastguard Worker    def set_mode(self, mode):
253*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('mode', mode)
254*cfb92d14SAndroid Build Coastguard Worker
255*cfb92d14SAndroid Build Coastguard Worker    def get_network_key(self):
256*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('networkkey')
257*cfb92d14SAndroid Build Coastguard Worker
258*cfb92d14SAndroid Build Coastguard Worker    def set_network_key(self, networkkey):
259*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('networkkey', networkkey)
260*cfb92d14SAndroid Build Coastguard Worker
261*cfb92d14SAndroid Build Coastguard Worker    def get_network_name(self):
262*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('networkname')
263*cfb92d14SAndroid Build Coastguard Worker
264*cfb92d14SAndroid Build Coastguard Worker    def set_network_name(self, network_name):
265*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('networkname', network_name)
266*cfb92d14SAndroid Build Coastguard Worker
267*cfb92d14SAndroid Build Coastguard Worker    def get_panid(self):
268*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('panid')
269*cfb92d14SAndroid Build Coastguard Worker
270*cfb92d14SAndroid Build Coastguard Worker    def set_panid(self, panid):
271*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('panid', panid)
272*cfb92d14SAndroid Build Coastguard Worker
273*cfb92d14SAndroid Build Coastguard Worker    def get_router_upgrade_threshold(self):
274*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('routerupgradethreshold')
275*cfb92d14SAndroid Build Coastguard Worker
276*cfb92d14SAndroid Build Coastguard Worker    def set_router_upgrade_threshold(self, threshold):
277*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('routerupgradethreshold', threshold)
278*cfb92d14SAndroid Build Coastguard Worker
279*cfb92d14SAndroid Build Coastguard Worker    def get_router_selection_jitter(self):
280*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('routerselectionjitter')
281*cfb92d14SAndroid Build Coastguard Worker
282*cfb92d14SAndroid Build Coastguard Worker    def set_router_selection_jitter(self, jitter):
283*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('routerselectionjitter', jitter)
284*cfb92d14SAndroid Build Coastguard Worker
285*cfb92d14SAndroid Build Coastguard Worker    def get_router_eligible(self):
286*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('routereligible')
287*cfb92d14SAndroid Build Coastguard Worker
288*cfb92d14SAndroid Build Coastguard Worker    def set_router_eligible(self, enable):
289*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('routereligible', enable)
290*cfb92d14SAndroid Build Coastguard Worker
291*cfb92d14SAndroid Build Coastguard Worker    def get_context_reuse_delay(self):
292*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('contextreusedelay')
293*cfb92d14SAndroid Build Coastguard Worker
294*cfb92d14SAndroid Build Coastguard Worker    def set_context_reuse_delay(self, delay):
295*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('contextreusedelay', delay)
296*cfb92d14SAndroid Build Coastguard Worker
297*cfb92d14SAndroid Build Coastguard Worker    def interface_up(self):
298*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('ifconfig up')
299*cfb92d14SAndroid Build Coastguard Worker
300*cfb92d14SAndroid Build Coastguard Worker    def interface_down(self):
301*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('ifconfig down')
302*cfb92d14SAndroid Build Coastguard Worker
303*cfb92d14SAndroid Build Coastguard Worker    def get_interface_state(self):
304*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('ifconfig')
305*cfb92d14SAndroid Build Coastguard Worker
306*cfb92d14SAndroid Build Coastguard Worker    def thread_start(self):
307*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('thread start')
308*cfb92d14SAndroid Build Coastguard Worker
309*cfb92d14SAndroid Build Coastguard Worker    def thread_stop(self):
310*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('thread stop')
311*cfb92d14SAndroid Build Coastguard Worker
312*cfb92d14SAndroid Build Coastguard Worker    def get_rloc16(self):
313*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('rloc16')
314*cfb92d14SAndroid Build Coastguard Worker
315*cfb92d14SAndroid Build Coastguard Worker    def get_ip_addrs(self, verbose=None):
316*cfb92d14SAndroid Build Coastguard Worker        return self.cli('ipaddr', verbose)
317*cfb92d14SAndroid Build Coastguard Worker
318*cfb92d14SAndroid Build Coastguard Worker    def add_ip_addr(self, address):
319*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('ipaddr add', address)
320*cfb92d14SAndroid Build Coastguard Worker
321*cfb92d14SAndroid Build Coastguard Worker    def remove_ip_addr(self, address):
322*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('ipaddr del', address)
323*cfb92d14SAndroid Build Coastguard Worker
324*cfb92d14SAndroid Build Coastguard Worker    def get_mleid_ip_addr(self):
325*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('ipaddr mleid')
326*cfb92d14SAndroid Build Coastguard Worker
327*cfb92d14SAndroid Build Coastguard Worker    def get_linklocal_ip_addr(self):
328*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('ipaddr linklocal')
329*cfb92d14SAndroid Build Coastguard Worker
330*cfb92d14SAndroid Build Coastguard Worker    def get_rloc_ip_addr(self):
331*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('ipaddr rloc')
332*cfb92d14SAndroid Build Coastguard Worker
333*cfb92d14SAndroid Build Coastguard Worker    def get_mesh_local_prefix(self):
334*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('prefix meshlocal')
335*cfb92d14SAndroid Build Coastguard Worker
336*cfb92d14SAndroid Build Coastguard Worker    def get_ip_maddrs(self):
337*cfb92d14SAndroid Build Coastguard Worker        return self.cli('ipmaddr')
338*cfb92d14SAndroid Build Coastguard Worker
339*cfb92d14SAndroid Build Coastguard Worker    def add_ip_maddr(self, maddr):
340*cfb92d14SAndroid Build Coastguard Worker        return self._cli_no_output('ipmaddr add', maddr)
341*cfb92d14SAndroid Build Coastguard Worker
342*cfb92d14SAndroid Build Coastguard Worker    def get_leader_weight(self):
343*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('leaderweight')
344*cfb92d14SAndroid Build Coastguard Worker
345*cfb92d14SAndroid Build Coastguard Worker    def set_leader_weight(self, weight):
346*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('leaderweight', weight)
347*cfb92d14SAndroid Build Coastguard Worker
348*cfb92d14SAndroid Build Coastguard Worker    def get_pollperiod(self):
349*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('pollperiod')
350*cfb92d14SAndroid Build Coastguard Worker
351*cfb92d14SAndroid Build Coastguard Worker    def set_pollperiod(self, period):
352*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('pollperiod', period)
353*cfb92d14SAndroid Build Coastguard Worker
354*cfb92d14SAndroid Build Coastguard Worker    def get_partition_id(self):
355*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('partitionid')
356*cfb92d14SAndroid Build Coastguard Worker
357*cfb92d14SAndroid Build Coastguard Worker    def get_nexthop(self, rloc16):
358*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('nexthop', rloc16)
359*cfb92d14SAndroid Build Coastguard Worker
360*cfb92d14SAndroid Build Coastguard Worker    def get_parent_info(self):
361*cfb92d14SAndroid Build Coastguard Worker        outputs = self.cli('parent')
362*cfb92d14SAndroid Build Coastguard Worker        result = {}
363*cfb92d14SAndroid Build Coastguard Worker        for line in outputs:
364*cfb92d14SAndroid Build Coastguard Worker            fields = line.split(':')
365*cfb92d14SAndroid Build Coastguard Worker            result[fields[0].strip()] = fields[1].strip()
366*cfb92d14SAndroid Build Coastguard Worker        return result
367*cfb92d14SAndroid Build Coastguard Worker
368*cfb92d14SAndroid Build Coastguard Worker    def get_child_table(self):
369*cfb92d14SAndroid Build Coastguard Worker        return Node.parse_table(self.cli('child table'))
370*cfb92d14SAndroid Build Coastguard Worker
371*cfb92d14SAndroid Build Coastguard Worker    def get_neighbor_table(self):
372*cfb92d14SAndroid Build Coastguard Worker        return Node.parse_table(self.cli('neighbor table'))
373*cfb92d14SAndroid Build Coastguard Worker
374*cfb92d14SAndroid Build Coastguard Worker    def get_router_table(self):
375*cfb92d14SAndroid Build Coastguard Worker        return Node.parse_table(self.cli('router table'))
376*cfb92d14SAndroid Build Coastguard Worker
377*cfb92d14SAndroid Build Coastguard Worker    def get_eidcache(self):
378*cfb92d14SAndroid Build Coastguard Worker        return self.cli('eidcache')
379*cfb92d14SAndroid Build Coastguard Worker
380*cfb92d14SAndroid Build Coastguard Worker    def get_vendor_name(self):
381*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('vendor name')
382*cfb92d14SAndroid Build Coastguard Worker
383*cfb92d14SAndroid Build Coastguard Worker    def set_vendor_name(self, name):
384*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('vendor name', name)
385*cfb92d14SAndroid Build Coastguard Worker
386*cfb92d14SAndroid Build Coastguard Worker    def get_vendor_model(self):
387*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('vendor model')
388*cfb92d14SAndroid Build Coastguard Worker
389*cfb92d14SAndroid Build Coastguard Worker    def set_vendor_model(self, model):
390*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('vendor model', model)
391*cfb92d14SAndroid Build Coastguard Worker
392*cfb92d14SAndroid Build Coastguard Worker    def get_vendor_sw_version(self):
393*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('vendor swversion')
394*cfb92d14SAndroid Build Coastguard Worker
395*cfb92d14SAndroid Build Coastguard Worker    def set_vendor_sw_version(self, version):
396*cfb92d14SAndroid Build Coastguard Worker        return self._cli_no_output('vendor swversion', version)
397*cfb92d14SAndroid Build Coastguard Worker
398*cfb92d14SAndroid Build Coastguard Worker    def get_vendor_app_url(self):
399*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('vendor appurl')
400*cfb92d14SAndroid Build Coastguard Worker
401*cfb92d14SAndroid Build Coastguard Worker    def set_vendor_app_url(self, url):
402*cfb92d14SAndroid Build Coastguard Worker        return self._cli_no_output('vendor appurl', url)
403*cfb92d14SAndroid Build Coastguard Worker
404*cfb92d14SAndroid Build Coastguard Worker    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
405*cfb92d14SAndroid Build Coastguard Worker    # netdata
406*cfb92d14SAndroid Build Coastguard Worker
407*cfb92d14SAndroid Build Coastguard Worker    def get_netdata(self, rloc16=None):
408*cfb92d14SAndroid Build Coastguard Worker        outputs = self.cli('netdata show', rloc16)
409*cfb92d14SAndroid Build Coastguard Worker        outputs = [line.strip() for line in outputs]
410*cfb92d14SAndroid Build Coastguard Worker        routes_index = outputs.index('Routes:')
411*cfb92d14SAndroid Build Coastguard Worker        services_index = outputs.index('Services:')
412*cfb92d14SAndroid Build Coastguard Worker        if rloc16 is None:
413*cfb92d14SAndroid Build Coastguard Worker            contexts_index = outputs.index('Contexts:')
414*cfb92d14SAndroid Build Coastguard Worker            commissioning_index = outputs.index('Commissioning:')
415*cfb92d14SAndroid Build Coastguard Worker        result = {}
416*cfb92d14SAndroid Build Coastguard Worker        result['prefixes'] = outputs[1:routes_index]
417*cfb92d14SAndroid Build Coastguard Worker        result['routes'] = outputs[routes_index + 1:services_index]
418*cfb92d14SAndroid Build Coastguard Worker        if rloc16 is None:
419*cfb92d14SAndroid Build Coastguard Worker            result['services'] = outputs[services_index + 1:contexts_index]
420*cfb92d14SAndroid Build Coastguard Worker            result['contexts'] = outputs[contexts_index + 1:commissioning_index]
421*cfb92d14SAndroid Build Coastguard Worker            result['commissioning'] = outputs[commissioning_index + 1:]
422*cfb92d14SAndroid Build Coastguard Worker        else:
423*cfb92d14SAndroid Build Coastguard Worker            result['services'] = outputs[services_index + 1:]
424*cfb92d14SAndroid Build Coastguard Worker
425*cfb92d14SAndroid Build Coastguard Worker        return result
426*cfb92d14SAndroid Build Coastguard Worker
427*cfb92d14SAndroid Build Coastguard Worker    def get_netdata_prefixes(self):
428*cfb92d14SAndroid Build Coastguard Worker        return self.get_netdata()['prefixes']
429*cfb92d14SAndroid Build Coastguard Worker
430*cfb92d14SAndroid Build Coastguard Worker    def get_netdata_routes(self):
431*cfb92d14SAndroid Build Coastguard Worker        return self.get_netdata()['routes']
432*cfb92d14SAndroid Build Coastguard Worker
433*cfb92d14SAndroid Build Coastguard Worker    def get_netdata_services(self):
434*cfb92d14SAndroid Build Coastguard Worker        return self.get_netdata()['services']
435*cfb92d14SAndroid Build Coastguard Worker
436*cfb92d14SAndroid Build Coastguard Worker    def get_netdata_contexts(self):
437*cfb92d14SAndroid Build Coastguard Worker        return self.get_netdata()['contexts']
438*cfb92d14SAndroid Build Coastguard Worker
439*cfb92d14SAndroid Build Coastguard Worker    def get_netdata_versions(self):
440*cfb92d14SAndroid Build Coastguard Worker        leaderdata = Node.parse_list(self.cli('leaderdata'))
441*cfb92d14SAndroid Build Coastguard Worker        return (int(leaderdata['Data Version']), int(leaderdata['Stable Data Version']))
442*cfb92d14SAndroid Build Coastguard Worker
443*cfb92d14SAndroid Build Coastguard Worker    def get_netdata_length(self):
444*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('netdata length')
445*cfb92d14SAndroid Build Coastguard Worker
446*cfb92d14SAndroid Build Coastguard Worker    def add_prefix(self, prefix, flags=None, prf=None):
447*cfb92d14SAndroid Build Coastguard Worker        return self._cli_no_output('prefix add', prefix, flags, prf)
448*cfb92d14SAndroid Build Coastguard Worker
449*cfb92d14SAndroid Build Coastguard Worker    def add_route(self, prefix, flags=None, prf=None):
450*cfb92d14SAndroid Build Coastguard Worker        return self._cli_no_output('route add', prefix, flags, prf)
451*cfb92d14SAndroid Build Coastguard Worker
452*cfb92d14SAndroid Build Coastguard Worker    def remove_prefix(self, prefix):
453*cfb92d14SAndroid Build Coastguard Worker        return self._cli_no_output('prefix remove', prefix)
454*cfb92d14SAndroid Build Coastguard Worker
455*cfb92d14SAndroid Build Coastguard Worker    def register_netdata(self):
456*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('netdata register')
457*cfb92d14SAndroid Build Coastguard Worker
458*cfb92d14SAndroid Build Coastguard Worker    def get_netdata_full(self):
459*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('netdata full')
460*cfb92d14SAndroid Build Coastguard Worker
461*cfb92d14SAndroid Build Coastguard Worker    def reset_netdata_full(self):
462*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('netdata full reset')
463*cfb92d14SAndroid Build Coastguard Worker
464*cfb92d14SAndroid Build Coastguard Worker    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
465*cfb92d14SAndroid Build Coastguard Worker    # ping and counters
466*cfb92d14SAndroid Build Coastguard Worker
467*cfb92d14SAndroid Build Coastguard Worker    def ping(self, address, size=0, count=1, verify_success=True):
468*cfb92d14SAndroid Build Coastguard Worker        outputs = self.cli('ping', address, size, count)
469*cfb92d14SAndroid Build Coastguard Worker        m = re.match(r'(\d+) packets transmitted, (\d+) packets received.', outputs[-1].strip())
470*cfb92d14SAndroid Build Coastguard Worker        verify(m is not None)
471*cfb92d14SAndroid Build Coastguard Worker        verify(int(m.group(1)) == count)
472*cfb92d14SAndroid Build Coastguard Worker        if verify_success:
473*cfb92d14SAndroid Build Coastguard Worker            verify(int(m.group(2)) == count)
474*cfb92d14SAndroid Build Coastguard Worker
475*cfb92d14SAndroid Build Coastguard Worker    def get_mle_counter(self):
476*cfb92d14SAndroid Build Coastguard Worker        return self.cli('counters mle')
477*cfb92d14SAndroid Build Coastguard Worker
478*cfb92d14SAndroid Build Coastguard Worker    def get_ip_counters(self):
479*cfb92d14SAndroid Build Coastguard Worker        return Node.parse_list(self.cli('counters ip'))
480*cfb92d14SAndroid Build Coastguard Worker
481*cfb92d14SAndroid Build Coastguard Worker    def get_br_counter_unicast_outbound_packets(self):
482*cfb92d14SAndroid Build Coastguard Worker        outputs = self.cli('counters br')
483*cfb92d14SAndroid Build Coastguard Worker        for line in outputs:
484*cfb92d14SAndroid Build Coastguard Worker            m = re.match(r'Outbound Unicast: Packets (\d+) Bytes (\d+)', line.strip())
485*cfb92d14SAndroid Build Coastguard Worker            if m is not None:
486*cfb92d14SAndroid Build Coastguard Worker                counter = int(m.group(1))
487*cfb92d14SAndroid Build Coastguard Worker                break
488*cfb92d14SAndroid Build Coastguard Worker        else:
489*cfb92d14SAndroid Build Coastguard Worker            verify(False)
490*cfb92d14SAndroid Build Coastguard Worker        return counter
491*cfb92d14SAndroid Build Coastguard Worker
492*cfb92d14SAndroid Build Coastguard Worker    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
493*cfb92d14SAndroid Build Coastguard Worker    # Misc
494*cfb92d14SAndroid Build Coastguard Worker
495*cfb92d14SAndroid Build Coastguard Worker    def get_mle_adv_imax(self):
496*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('mleadvimax')
497*cfb92d14SAndroid Build Coastguard Worker
498*cfb92d14SAndroid Build Coastguard Worker    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
499*cfb92d14SAndroid Build Coastguard Worker    # Border Agent
500*cfb92d14SAndroid Build Coastguard Worker
501*cfb92d14SAndroid Build Coastguard Worker    def ba_get_state(self):
502*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('ba state')
503*cfb92d14SAndroid Build Coastguard Worker
504*cfb92d14SAndroid Build Coastguard Worker    def ba_get_port(self):
505*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('ba port')
506*cfb92d14SAndroid Build Coastguard Worker
507*cfb92d14SAndroid Build Coastguard Worker    def ba_is_ephemeral_key_active(self):
508*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('ba ephemeralkey')
509*cfb92d14SAndroid Build Coastguard Worker
510*cfb92d14SAndroid Build Coastguard Worker    def ba_set_ephemeral_key(self, keystring, timeout=None, port=None):
511*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('ba ephemeralkey set', keystring, timeout, port)
512*cfb92d14SAndroid Build Coastguard Worker
513*cfb92d14SAndroid Build Coastguard Worker    def ba_clear_ephemeral_key(self):
514*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('ba ephemeralkey clear')
515*cfb92d14SAndroid Build Coastguard Worker
516*cfb92d14SAndroid Build Coastguard Worker    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
517*cfb92d14SAndroid Build Coastguard Worker    # UDP
518*cfb92d14SAndroid Build Coastguard Worker
519*cfb92d14SAndroid Build Coastguard Worker    def udp_open(self):
520*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('udp open')
521*cfb92d14SAndroid Build Coastguard Worker
522*cfb92d14SAndroid Build Coastguard Worker    def udp_close(self):
523*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('udp close')
524*cfb92d14SAndroid Build Coastguard Worker
525*cfb92d14SAndroid Build Coastguard Worker    def udp_bind(self, address, port):
526*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('udp bind', address, port)
527*cfb92d14SAndroid Build Coastguard Worker
528*cfb92d14SAndroid Build Coastguard Worker    def udp_send(self, address, port, text):
529*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('udp send', address, port, '-t', text)
530*cfb92d14SAndroid Build Coastguard Worker
531*cfb92d14SAndroid Build Coastguard Worker    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
532*cfb92d14SAndroid Build Coastguard Worker    # multiradio
533*cfb92d14SAndroid Build Coastguard Worker
534*cfb92d14SAndroid Build Coastguard Worker    def multiradio_get_radios(self):
535*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('multiradio')
536*cfb92d14SAndroid Build Coastguard Worker
537*cfb92d14SAndroid Build Coastguard Worker    def multiradio_get_neighbor_list(self):
538*cfb92d14SAndroid Build Coastguard Worker        return self.cli('multiradio neighbor list')
539*cfb92d14SAndroid Build Coastguard Worker
540*cfb92d14SAndroid Build Coastguard Worker    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
541*cfb92d14SAndroid Build Coastguard Worker    # SRP client
542*cfb92d14SAndroid Build Coastguard Worker
543*cfb92d14SAndroid Build Coastguard Worker    def srp_client_start(self, server_address, server_port):
544*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('srp client start', server_address, server_port)
545*cfb92d14SAndroid Build Coastguard Worker
546*cfb92d14SAndroid Build Coastguard Worker    def srp_client_stop(self):
547*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('srp client stop')
548*cfb92d14SAndroid Build Coastguard Worker
549*cfb92d14SAndroid Build Coastguard Worker    def srp_client_get_state(self):
550*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('srp client state', expected_outputs=['Enabled', 'Disabled'])
551*cfb92d14SAndroid Build Coastguard Worker
552*cfb92d14SAndroid Build Coastguard Worker    def srp_client_get_auto_start_mode(self):
553*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('srp client autostart', expected_outputs=['Enabled', 'Disabled'])
554*cfb92d14SAndroid Build Coastguard Worker
555*cfb92d14SAndroid Build Coastguard Worker    def srp_client_enable_auto_start_mode(self):
556*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('srp client autostart enable')
557*cfb92d14SAndroid Build Coastguard Worker
558*cfb92d14SAndroid Build Coastguard Worker    def srp_client_disable_auto_start_mode(self):
559*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('srp client autostart disable')
560*cfb92d14SAndroid Build Coastguard Worker
561*cfb92d14SAndroid Build Coastguard Worker    def srp_client_get_server_address(self):
562*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('srp client server address')
563*cfb92d14SAndroid Build Coastguard Worker
564*cfb92d14SAndroid Build Coastguard Worker    def srp_client_get_server_port(self):
565*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('srp client server port')
566*cfb92d14SAndroid Build Coastguard Worker
567*cfb92d14SAndroid Build Coastguard Worker    def srp_client_get_host_state(self):
568*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('srp client host state')
569*cfb92d14SAndroid Build Coastguard Worker
570*cfb92d14SAndroid Build Coastguard Worker    def srp_client_set_host_name(self, name):
571*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('srp client host name', name)
572*cfb92d14SAndroid Build Coastguard Worker
573*cfb92d14SAndroid Build Coastguard Worker    def srp_client_get_host_name(self):
574*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('srp client host name')
575*cfb92d14SAndroid Build Coastguard Worker
576*cfb92d14SAndroid Build Coastguard Worker    def srp_client_remove_host(self, remove_key=False, send_unreg_to_server=False):
577*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('srp client host remove', int(remove_key), int(send_unreg_to_server))
578*cfb92d14SAndroid Build Coastguard Worker
579*cfb92d14SAndroid Build Coastguard Worker    def srp_client_clear_host(self):
580*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('srp client host clear')
581*cfb92d14SAndroid Build Coastguard Worker
582*cfb92d14SAndroid Build Coastguard Worker    def srp_client_enable_auto_host_address(self):
583*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('srp client host address auto')
584*cfb92d14SAndroid Build Coastguard Worker
585*cfb92d14SAndroid Build Coastguard Worker    def srp_client_set_host_address(self, *addrs):
586*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('srp client host address', *addrs)
587*cfb92d14SAndroid Build Coastguard Worker
588*cfb92d14SAndroid Build Coastguard Worker    def srp_client_get_host_address(self):
589*cfb92d14SAndroid Build Coastguard Worker        return self.cli('srp client host address')
590*cfb92d14SAndroid Build Coastguard Worker
591*cfb92d14SAndroid Build Coastguard Worker    def srp_client_add_service(self,
592*cfb92d14SAndroid Build Coastguard Worker                               instance_name,
593*cfb92d14SAndroid Build Coastguard Worker                               service_name,
594*cfb92d14SAndroid Build Coastguard Worker                               port,
595*cfb92d14SAndroid Build Coastguard Worker                               priority=0,
596*cfb92d14SAndroid Build Coastguard Worker                               weight=0,
597*cfb92d14SAndroid Build Coastguard Worker                               txt_entries=[],
598*cfb92d14SAndroid Build Coastguard Worker                               lease=0,
599*cfb92d14SAndroid Build Coastguard Worker                               key_lease=0):
600*cfb92d14SAndroid Build Coastguard Worker        txt_record = "".join(self._encode_txt_entry(entry) for entry in txt_entries)
601*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('srp client service add', instance_name, service_name, port, priority, weight, txt_record,
602*cfb92d14SAndroid Build Coastguard Worker                            lease, key_lease)
603*cfb92d14SAndroid Build Coastguard Worker
604*cfb92d14SAndroid Build Coastguard Worker    def srp_client_remove_service(self, instance_name, service_name):
605*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('srp client service remove', instance_name, service_name)
606*cfb92d14SAndroid Build Coastguard Worker
607*cfb92d14SAndroid Build Coastguard Worker    def srp_client_clear_service(self, instance_name, service_name):
608*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('srp client service clear', instance_name, service_name)
609*cfb92d14SAndroid Build Coastguard Worker
610*cfb92d14SAndroid Build Coastguard Worker    def srp_client_get_services(self):
611*cfb92d14SAndroid Build Coastguard Worker        outputs = self.cli('srp client service')
612*cfb92d14SAndroid Build Coastguard Worker        return [self._parse_srp_client_service(line) for line in outputs]
613*cfb92d14SAndroid Build Coastguard Worker
614*cfb92d14SAndroid Build Coastguard Worker    def _encode_txt_entry(self, entry):
615*cfb92d14SAndroid Build Coastguard Worker        """Encodes the TXT entry to the DNS-SD TXT record format as a HEX string.
616*cfb92d14SAndroid Build Coastguard Worker
617*cfb92d14SAndroid Build Coastguard Worker           Example usage:
618*cfb92d14SAndroid Build Coastguard Worker           self._encode_txt_entries(['abc'])     -> '03616263'
619*cfb92d14SAndroid Build Coastguard Worker           self._encode_txt_entries(['def='])    -> '046465663d'
620*cfb92d14SAndroid Build Coastguard Worker           self._encode_txt_entries(['xyz=XYZ']) -> '0778797a3d58595a'
621*cfb92d14SAndroid Build Coastguard Worker        """
622*cfb92d14SAndroid Build Coastguard Worker        return '{:02x}'.format(len(entry)) + "".join("{:02x}".format(ord(c)) for c in entry)
623*cfb92d14SAndroid Build Coastguard Worker
624*cfb92d14SAndroid Build Coastguard Worker    def _parse_srp_client_service(self, line):
625*cfb92d14SAndroid Build Coastguard Worker        """Parse one line of srp service list into a dictionary which
626*cfb92d14SAndroid Build Coastguard Worker           maps string keys to string values.
627*cfb92d14SAndroid Build Coastguard Worker
628*cfb92d14SAndroid Build Coastguard Worker           Example output for input
629*cfb92d14SAndroid Build Coastguard Worker           'instance:\"%s\", name:\"%s\", state:%s, port:%d, priority:%d, weight:%d"'
630*cfb92d14SAndroid Build Coastguard Worker           {
631*cfb92d14SAndroid Build Coastguard Worker               'instance': 'my-service',
632*cfb92d14SAndroid Build Coastguard Worker               'name': '_ipps._udp',
633*cfb92d14SAndroid Build Coastguard Worker               'state': 'ToAdd',
634*cfb92d14SAndroid Build Coastguard Worker               'port': '12345',
635*cfb92d14SAndroid Build Coastguard Worker               'priority': '0',
636*cfb92d14SAndroid Build Coastguard Worker               'weight': '0'
637*cfb92d14SAndroid Build Coastguard Worker           }
638*cfb92d14SAndroid Build Coastguard Worker
639*cfb92d14SAndroid Build Coastguard Worker           Note that value of 'port', 'priority' and 'weight' are represented
640*cfb92d14SAndroid Build Coastguard Worker           as strings but not integers.
641*cfb92d14SAndroid Build Coastguard Worker        """
642*cfb92d14SAndroid Build Coastguard Worker        key_values = [word.strip().split(':') for word in line.split(', ')]
643*cfb92d14SAndroid Build Coastguard Worker        return {key_value[0].strip(): key_value[1].strip('"') for key_value in key_values}
644*cfb92d14SAndroid Build Coastguard Worker
645*cfb92d14SAndroid Build Coastguard Worker    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
646*cfb92d14SAndroid Build Coastguard Worker    # SRP server
647*cfb92d14SAndroid Build Coastguard Worker
648*cfb92d14SAndroid Build Coastguard Worker    def srp_server_get_state(self):
649*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('srp server state', expected_outputs=['disabled', 'running', 'stopped'])
650*cfb92d14SAndroid Build Coastguard Worker
651*cfb92d14SAndroid Build Coastguard Worker    def srp_server_get_addr_mode(self):
652*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('srp server addrmode', expected_outputs=['unicast', 'anycast'])
653*cfb92d14SAndroid Build Coastguard Worker
654*cfb92d14SAndroid Build Coastguard Worker    def srp_server_set_addr_mode(self, mode):
655*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('srp server addrmode', mode)
656*cfb92d14SAndroid Build Coastguard Worker
657*cfb92d14SAndroid Build Coastguard Worker    def srp_server_get_anycast_seq_num(self):
658*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('srp server seqnum')
659*cfb92d14SAndroid Build Coastguard Worker
660*cfb92d14SAndroid Build Coastguard Worker    def srp_server_set_anycast_seq_num(self, seqnum):
661*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('srp server seqnum', seqnum)
662*cfb92d14SAndroid Build Coastguard Worker
663*cfb92d14SAndroid Build Coastguard Worker    def srp_server_enable(self):
664*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('srp server enable')
665*cfb92d14SAndroid Build Coastguard Worker
666*cfb92d14SAndroid Build Coastguard Worker    def srp_server_disable(self):
667*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('srp server disable')
668*cfb92d14SAndroid Build Coastguard Worker
669*cfb92d14SAndroid Build Coastguard Worker    def srp_server_auto_enable(self):
670*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('srp server auto enable')
671*cfb92d14SAndroid Build Coastguard Worker
672*cfb92d14SAndroid Build Coastguard Worker    def srp_server_auto_disable(self):
673*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('srp server auto disable')
674*cfb92d14SAndroid Build Coastguard Worker
675*cfb92d14SAndroid Build Coastguard Worker    def srp_server_set_lease(self, min_lease, max_lease, min_key_lease, max_key_lease):
676*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('srp server lease', min_lease, max_lease, min_key_lease, max_key_lease)
677*cfb92d14SAndroid Build Coastguard Worker
678*cfb92d14SAndroid Build Coastguard Worker    def srp_server_get_hosts(self):
679*cfb92d14SAndroid Build Coastguard Worker        """Returns the host list on the SRP server as a list of property
680*cfb92d14SAndroid Build Coastguard Worker           dictionary.
681*cfb92d14SAndroid Build Coastguard Worker
682*cfb92d14SAndroid Build Coastguard Worker           Example output:
683*cfb92d14SAndroid Build Coastguard Worker           [{
684*cfb92d14SAndroid Build Coastguard Worker               'fullname': 'my-host.default.service.arpa.',
685*cfb92d14SAndroid Build Coastguard Worker               'name': 'my-host',
686*cfb92d14SAndroid Build Coastguard Worker               'deleted': 'false',
687*cfb92d14SAndroid Build Coastguard Worker               'addresses': ['2001::1', '2001::2']
688*cfb92d14SAndroid Build Coastguard Worker           }]
689*cfb92d14SAndroid Build Coastguard Worker        """
690*cfb92d14SAndroid Build Coastguard Worker        outputs = self.cli('srp server host')
691*cfb92d14SAndroid Build Coastguard Worker        host_list = []
692*cfb92d14SAndroid Build Coastguard Worker        while outputs:
693*cfb92d14SAndroid Build Coastguard Worker            host = {}
694*cfb92d14SAndroid Build Coastguard Worker            host['fullname'] = outputs.pop(0).strip()
695*cfb92d14SAndroid Build Coastguard Worker            host['name'] = host['fullname'].split('.')[0]
696*cfb92d14SAndroid Build Coastguard Worker            host['deleted'] = outputs.pop(0).strip().split(':')[1].strip()
697*cfb92d14SAndroid Build Coastguard Worker            if host['deleted'] == 'true':
698*cfb92d14SAndroid Build Coastguard Worker                host_list.append(host)
699*cfb92d14SAndroid Build Coastguard Worker                continue
700*cfb92d14SAndroid Build Coastguard Worker            addresses = outputs.pop(0).strip().split('[')[1].strip(' ]').split(',')
701*cfb92d14SAndroid Build Coastguard Worker            map(str.strip, addresses)
702*cfb92d14SAndroid Build Coastguard Worker            host['addresses'] = [addr for addr in addresses if addr]
703*cfb92d14SAndroid Build Coastguard Worker            host_list.append(host)
704*cfb92d14SAndroid Build Coastguard Worker        return host_list
705*cfb92d14SAndroid Build Coastguard Worker
706*cfb92d14SAndroid Build Coastguard Worker    def srp_server_get_host(self, host_name):
707*cfb92d14SAndroid Build Coastguard Worker        """Returns host on the SRP server that matches given host name.
708*cfb92d14SAndroid Build Coastguard Worker
709*cfb92d14SAndroid Build Coastguard Worker           Example usage:
710*cfb92d14SAndroid Build Coastguard Worker           self.srp_server_get_host("my-host")
711*cfb92d14SAndroid Build Coastguard Worker        """
712*cfb92d14SAndroid Build Coastguard Worker        for host in self.srp_server_get_hosts():
713*cfb92d14SAndroid Build Coastguard Worker            if host_name == host['name']:
714*cfb92d14SAndroid Build Coastguard Worker                return host
715*cfb92d14SAndroid Build Coastguard Worker
716*cfb92d14SAndroid Build Coastguard Worker    def srp_server_get_services(self):
717*cfb92d14SAndroid Build Coastguard Worker        """Returns the service list on the SRP server as a list of property
718*cfb92d14SAndroid Build Coastguard Worker           dictionary.
719*cfb92d14SAndroid Build Coastguard Worker
720*cfb92d14SAndroid Build Coastguard Worker           Example output:
721*cfb92d14SAndroid Build Coastguard Worker           [{
722*cfb92d14SAndroid Build Coastguard Worker               'fullname': 'my-service._ipps._tcp.default.service.arpa.',
723*cfb92d14SAndroid Build Coastguard Worker               'instance': 'my-service',
724*cfb92d14SAndroid Build Coastguard Worker               'name': '_ipps._tcp',
725*cfb92d14SAndroid Build Coastguard Worker               'deleted': 'false',
726*cfb92d14SAndroid Build Coastguard Worker               'port': '12345',
727*cfb92d14SAndroid Build Coastguard Worker               'priority': '0',
728*cfb92d14SAndroid Build Coastguard Worker               'weight': '0',
729*cfb92d14SAndroid Build Coastguard Worker               'ttl': '7200',
730*cfb92d14SAndroid Build Coastguard Worker               'lease': '7200',
731*cfb92d14SAndroid Build Coastguard Worker               'key-lease', '1209600',
732*cfb92d14SAndroid Build Coastguard Worker               'TXT': ['abc=010203'],
733*cfb92d14SAndroid Build Coastguard Worker               'host_fullname': 'my-host.default.service.arpa.',
734*cfb92d14SAndroid Build Coastguard Worker               'host': 'my-host',
735*cfb92d14SAndroid Build Coastguard Worker               'addresses': ['2001::1', '2001::2']
736*cfb92d14SAndroid Build Coastguard Worker           }]
737*cfb92d14SAndroid Build Coastguard Worker
738*cfb92d14SAndroid Build Coastguard Worker           Note that the TXT data is output as a HEX string.
739*cfb92d14SAndroid Build Coastguard Worker        """
740*cfb92d14SAndroid Build Coastguard Worker        outputs = self.cli('srp server service')
741*cfb92d14SAndroid Build Coastguard Worker        service_list = []
742*cfb92d14SAndroid Build Coastguard Worker        while outputs:
743*cfb92d14SAndroid Build Coastguard Worker            service = {}
744*cfb92d14SAndroid Build Coastguard Worker            service['fullname'] = outputs.pop(0).strip()
745*cfb92d14SAndroid Build Coastguard Worker            name_labels = service['fullname'].split('.')
746*cfb92d14SAndroid Build Coastguard Worker            service['instance'] = name_labels[0]
747*cfb92d14SAndroid Build Coastguard Worker            service['name'] = '.'.join(name_labels[1:3])
748*cfb92d14SAndroid Build Coastguard Worker            service['deleted'] = outputs.pop(0).strip().split(':')[1].strip()
749*cfb92d14SAndroid Build Coastguard Worker            if service['deleted'] == 'true':
750*cfb92d14SAndroid Build Coastguard Worker                service_list.append(service)
751*cfb92d14SAndroid Build Coastguard Worker                continue
752*cfb92d14SAndroid Build Coastguard Worker            # 'subtypes', port', 'priority', 'weight', 'ttl', 'lease', 'key-lease'
753*cfb92d14SAndroid Build Coastguard Worker            for i in range(0, 7):
754*cfb92d14SAndroid Build Coastguard Worker                key_value = outputs.pop(0).strip().split(':')
755*cfb92d14SAndroid Build Coastguard Worker                service[key_value[0].strip()] = key_value[1].strip()
756*cfb92d14SAndroid Build Coastguard Worker            txt_entries = outputs.pop(0).strip().split('[')[1].strip(' ]').split(',')
757*cfb92d14SAndroid Build Coastguard Worker            txt_entries = map(str.strip, txt_entries)
758*cfb92d14SAndroid Build Coastguard Worker            service['TXT'] = [txt for txt in txt_entries if txt]
759*cfb92d14SAndroid Build Coastguard Worker            service['host_fullname'] = outputs.pop(0).strip().split(':')[1].strip()
760*cfb92d14SAndroid Build Coastguard Worker            service['host'] = service['host_fullname'].split('.')[0]
761*cfb92d14SAndroid Build Coastguard Worker            addresses = outputs.pop(0).strip().split('[')[1].strip(' ]').split(',')
762*cfb92d14SAndroid Build Coastguard Worker            addresses = map(str.strip, addresses)
763*cfb92d14SAndroid Build Coastguard Worker            service['addresses'] = [addr for addr in addresses if addr]
764*cfb92d14SAndroid Build Coastguard Worker            service_list.append(service)
765*cfb92d14SAndroid Build Coastguard Worker        return service_list
766*cfb92d14SAndroid Build Coastguard Worker
767*cfb92d14SAndroid Build Coastguard Worker    def srp_server_get_service(self, instance_name, service_name):
768*cfb92d14SAndroid Build Coastguard Worker        """Returns service on the SRP server that matches given instance
769*cfb92d14SAndroid Build Coastguard Worker           name and service name.
770*cfb92d14SAndroid Build Coastguard Worker
771*cfb92d14SAndroid Build Coastguard Worker           Example usage:
772*cfb92d14SAndroid Build Coastguard Worker           self.srp_server_get_service("my-service", "_ipps._tcp")
773*cfb92d14SAndroid Build Coastguard Worker        """
774*cfb92d14SAndroid Build Coastguard Worker        for service in self.srp_server_get_services():
775*cfb92d14SAndroid Build Coastguard Worker            if (instance_name == service['instance'] and service_name == service['name']):
776*cfb92d14SAndroid Build Coastguard Worker                return service
777*cfb92d14SAndroid Build Coastguard Worker
778*cfb92d14SAndroid Build Coastguard Worker    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
779*cfb92d14SAndroid Build Coastguard Worker    # br
780*cfb92d14SAndroid Build Coastguard Worker
781*cfb92d14SAndroid Build Coastguard Worker    def br_init(self, if_inex, is_running):
782*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('br init', if_inex, is_running)
783*cfb92d14SAndroid Build Coastguard Worker
784*cfb92d14SAndroid Build Coastguard Worker    def br_enable(self):
785*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('br enable')
786*cfb92d14SAndroid Build Coastguard Worker
787*cfb92d14SAndroid Build Coastguard Worker    def br_disable(self):
788*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('br disable')
789*cfb92d14SAndroid Build Coastguard Worker
790*cfb92d14SAndroid Build Coastguard Worker    def br_get_state(self):
791*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('br state')
792*cfb92d14SAndroid Build Coastguard Worker
793*cfb92d14SAndroid Build Coastguard Worker    def br_get_favored_omrprefix(self):
794*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('br omrprefix favored')
795*cfb92d14SAndroid Build Coastguard Worker
796*cfb92d14SAndroid Build Coastguard Worker    def br_get_local_omrprefix(self):
797*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('br omrprefix local')
798*cfb92d14SAndroid Build Coastguard Worker
799*cfb92d14SAndroid Build Coastguard Worker    def br_get_favored_onlinkprefix(self):
800*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('br onlinkprefix favored')
801*cfb92d14SAndroid Build Coastguard Worker
802*cfb92d14SAndroid Build Coastguard Worker    def br_get_local_onlinkprefix(self):
803*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('br onlinkprefix local')
804*cfb92d14SAndroid Build Coastguard Worker
805*cfb92d14SAndroid Build Coastguard Worker    def br_set_test_local_onlinkprefix(self, prefix):
806*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('br onlinkprefix test', prefix)
807*cfb92d14SAndroid Build Coastguard Worker
808*cfb92d14SAndroid Build Coastguard Worker    def br_get_routeprf(self):
809*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('br routeprf')
810*cfb92d14SAndroid Build Coastguard Worker
811*cfb92d14SAndroid Build Coastguard Worker    def br_set_routeprf(self, prf):
812*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('br routeprf', prf)
813*cfb92d14SAndroid Build Coastguard Worker
814*cfb92d14SAndroid Build Coastguard Worker    def br_clear_routeprf(self):
815*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('br routeprf clear')
816*cfb92d14SAndroid Build Coastguard Worker
817*cfb92d14SAndroid Build Coastguard Worker    def br_get_routers(self):
818*cfb92d14SAndroid Build Coastguard Worker        return self.cli('br routers')
819*cfb92d14SAndroid Build Coastguard Worker
820*cfb92d14SAndroid Build Coastguard Worker    def br_get_peer_brs(self):
821*cfb92d14SAndroid Build Coastguard Worker        return self.cli('br peers')
822*cfb92d14SAndroid Build Coastguard Worker
823*cfb92d14SAndroid Build Coastguard Worker    def br_count_peers(self):
824*cfb92d14SAndroid Build Coastguard Worker        return self._cli_single_output('br peers count')
825*cfb92d14SAndroid Build Coastguard Worker
826*cfb92d14SAndroid Build Coastguard Worker    # ------------------------------------------------------------------------------------------------------------------
827*cfb92d14SAndroid Build Coastguard Worker    # Helper methods
828*cfb92d14SAndroid Build Coastguard Worker
829*cfb92d14SAndroid Build Coastguard Worker    def form(self, network_name=None, network_key=None, channel=None, panid=0x1234, xpanid=None):
830*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('dataset init new')
831*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('dataset panid', panid)
832*cfb92d14SAndroid Build Coastguard Worker        if network_name is not None:
833*cfb92d14SAndroid Build Coastguard Worker            self._cli_no_output('dataset networkname', network_name)
834*cfb92d14SAndroid Build Coastguard Worker        if network_key is not None:
835*cfb92d14SAndroid Build Coastguard Worker            self._cli_no_output('dataset networkkey', network_key)
836*cfb92d14SAndroid Build Coastguard Worker        if channel is not None:
837*cfb92d14SAndroid Build Coastguard Worker            self._cli_no_output('dataset channel', channel)
838*cfb92d14SAndroid Build Coastguard Worker        if xpanid is not None:
839*cfb92d14SAndroid Build Coastguard Worker            self._cli_no_output('dataset extpanid', xpanid)
840*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('dataset commit active')
841*cfb92d14SAndroid Build Coastguard Worker        self.set_mode('rdn')
842*cfb92d14SAndroid Build Coastguard Worker        self.interface_up()
843*cfb92d14SAndroid Build Coastguard Worker        self.thread_start()
844*cfb92d14SAndroid Build Coastguard Worker        verify_within(_check_node_is_leader, self._WAIT_TIME, arg=self)
845*cfb92d14SAndroid Build Coastguard Worker
846*cfb92d14SAndroid Build Coastguard Worker    def join(self, node, type=JOIN_TYPE_ROUTER):
847*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('dataset clear')
848*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('dataset networkname', node.get_network_name())
849*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('dataset networkkey', node.get_network_key())
850*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('dataset channel', node.get_channel())
851*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('dataset panid', node.get_panid())
852*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('dataset commit active')
853*cfb92d14SAndroid Build Coastguard Worker        if type == JOIN_TYPE_END_DEVICE:
854*cfb92d14SAndroid Build Coastguard Worker            self.set_mode('rn')
855*cfb92d14SAndroid Build Coastguard Worker        elif type == JOIN_TYPE_SLEEPY_END_DEVICE:
856*cfb92d14SAndroid Build Coastguard Worker            self.set_mode('-')
857*cfb92d14SAndroid Build Coastguard Worker        elif type == JOIN_TYPE_REED:
858*cfb92d14SAndroid Build Coastguard Worker            self.set_mode('rdn')
859*cfb92d14SAndroid Build Coastguard Worker            self.set_router_eligible('disable')
860*cfb92d14SAndroid Build Coastguard Worker        else:
861*cfb92d14SAndroid Build Coastguard Worker            self.set_mode('rdn')
862*cfb92d14SAndroid Build Coastguard Worker            self.set_router_selection_jitter(1)
863*cfb92d14SAndroid Build Coastguard Worker        self.interface_up()
864*cfb92d14SAndroid Build Coastguard Worker        self.thread_start()
865*cfb92d14SAndroid Build Coastguard Worker        if type == JOIN_TYPE_ROUTER:
866*cfb92d14SAndroid Build Coastguard Worker            verify_within(_check_node_is_router, self._WAIT_TIME, arg=self)
867*cfb92d14SAndroid Build Coastguard Worker        else:
868*cfb92d14SAndroid Build Coastguard Worker            verify_within(_check_node_is_child, self._WAIT_TIME, arg=self)
869*cfb92d14SAndroid Build Coastguard Worker
870*cfb92d14SAndroid Build Coastguard Worker    def allowlist_node(self, node):
871*cfb92d14SAndroid Build Coastguard Worker        """Adds a given node to the allowlist of `self` and enables allowlisting on `self`"""
872*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('macfilter addr add', node.get_ext_addr())
873*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('macfilter addr allowlist')
874*cfb92d14SAndroid Build Coastguard Worker
875*cfb92d14SAndroid Build Coastguard Worker    def un_allowlist_node(self, node):
876*cfb92d14SAndroid Build Coastguard Worker        """Removes a given node (of node `Node) from the allowlist"""
877*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('macfilter addr remove', node.get_ext_addr())
878*cfb92d14SAndroid Build Coastguard Worker
879*cfb92d14SAndroid Build Coastguard Worker    def set_macfilter_lqi_to_node(self, node, lqi):
880*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('macfilter rss add-lqi', node.get_ext_addr(), lqi)
881*cfb92d14SAndroid Build Coastguard Worker
882*cfb92d14SAndroid Build Coastguard Worker    # ------------------------------------------------------------------------------------------------------------------
883*cfb92d14SAndroid Build Coastguard Worker    # Radio nodeidfilter
884*cfb92d14SAndroid Build Coastguard Worker
885*cfb92d14SAndroid Build Coastguard Worker    def nodeidfilter_clear(self, node):
886*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('nodeidfilter clear')
887*cfb92d14SAndroid Build Coastguard Worker
888*cfb92d14SAndroid Build Coastguard Worker    def nodeidfilter_allow(self, node):
889*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('nodeidfilter allow', node.index)
890*cfb92d14SAndroid Build Coastguard Worker
891*cfb92d14SAndroid Build Coastguard Worker    def nodeidfilter_deny(self, node):
892*cfb92d14SAndroid Build Coastguard Worker        self._cli_no_output('nodeidfilter deny', node.index)
893*cfb92d14SAndroid Build Coastguard Worker
894*cfb92d14SAndroid Build Coastguard Worker    # ------------------------------------------------------------------------------------------------------------------
895*cfb92d14SAndroid Build Coastguard Worker    # Parsing helpers
896*cfb92d14SAndroid Build Coastguard Worker
897*cfb92d14SAndroid Build Coastguard Worker    @classmethod
898*cfb92d14SAndroid Build Coastguard Worker    def parse_table(cls, table_lines):
899*cfb92d14SAndroid Build Coastguard Worker        verify(len(table_lines) >= 2)
900*cfb92d14SAndroid Build Coastguard Worker        headers = cls.split_table_row(table_lines[0])
901*cfb92d14SAndroid Build Coastguard Worker        info = []
902*cfb92d14SAndroid Build Coastguard Worker        for row in table_lines[2:]:
903*cfb92d14SAndroid Build Coastguard Worker            if row.strip() == '':
904*cfb92d14SAndroid Build Coastguard Worker                continue
905*cfb92d14SAndroid Build Coastguard Worker            fields = cls.split_table_row(row)
906*cfb92d14SAndroid Build Coastguard Worker            verify(len(fields) == len(headers))
907*cfb92d14SAndroid Build Coastguard Worker            info.append({headers[i]: fields[i] for i in range(len(fields))})
908*cfb92d14SAndroid Build Coastguard Worker        return info
909*cfb92d14SAndroid Build Coastguard Worker
910*cfb92d14SAndroid Build Coastguard Worker    @classmethod
911*cfb92d14SAndroid Build Coastguard Worker    def split_table_row(cls, row):
912*cfb92d14SAndroid Build Coastguard Worker        return [field.strip() for field in row.strip().split('|')[1:-1]]
913*cfb92d14SAndroid Build Coastguard Worker
914*cfb92d14SAndroid Build Coastguard Worker    @classmethod
915*cfb92d14SAndroid Build Coastguard Worker    def parse_list(cls, list_lines):
916*cfb92d14SAndroid Build Coastguard Worker        result = {}
917*cfb92d14SAndroid Build Coastguard Worker        for line in list_lines:
918*cfb92d14SAndroid Build Coastguard Worker            fields = line.split(':', 1)
919*cfb92d14SAndroid Build Coastguard Worker            result[fields[0].strip()] = fields[1].strip()
920*cfb92d14SAndroid Build Coastguard Worker        return result
921*cfb92d14SAndroid Build Coastguard Worker
922*cfb92d14SAndroid Build Coastguard Worker    @classmethod
923*cfb92d14SAndroid Build Coastguard Worker    def parse_multiradio_neighbor_entry(cls, line):
924*cfb92d14SAndroid Build Coastguard Worker        # Example: "ExtAddr:42aa94ad67229f14, RLOC16:0x9400, Radios:[15.4(245), TREL(255)]"
925*cfb92d14SAndroid Build Coastguard Worker        result = {}
926*cfb92d14SAndroid Build Coastguard Worker        for field in line.split(', ', 2):
927*cfb92d14SAndroid Build Coastguard Worker            key_value = field.split(':')
928*cfb92d14SAndroid Build Coastguard Worker            result[key_value[0]] = key_value[1]
929*cfb92d14SAndroid Build Coastguard Worker        radios = {}
930*cfb92d14SAndroid Build Coastguard Worker        for item in result['Radios'][1:-1].split(','):
931*cfb92d14SAndroid Build Coastguard Worker            name, prf = item.strip().split('(')
932*cfb92d14SAndroid Build Coastguard Worker            verify(prf.endswith(')'))
933*cfb92d14SAndroid Build Coastguard Worker            radios[name] = int(prf[:-1])
934*cfb92d14SAndroid Build Coastguard Worker        result['Radios'] = radios
935*cfb92d14SAndroid Build Coastguard Worker        return result
936*cfb92d14SAndroid Build Coastguard Worker
937*cfb92d14SAndroid Build Coastguard Worker    # ------------------------------------------------------------------------------------------------------------------
938*cfb92d14SAndroid Build Coastguard Worker    # class methods
939*cfb92d14SAndroid Build Coastguard Worker
940*cfb92d14SAndroid Build Coastguard Worker    @classmethod
941*cfb92d14SAndroid Build Coastguard Worker    def finalize_all_nodes(cls):
942*cfb92d14SAndroid Build Coastguard Worker        """Finalizes all previously created `Node` instances (stops the CLI process)"""
943*cfb92d14SAndroid Build Coastguard Worker        for node in Node._all_nodes:
944*cfb92d14SAndroid Build Coastguard Worker            node._finalize()
945*cfb92d14SAndroid Build Coastguard Worker
946*cfb92d14SAndroid Build Coastguard Worker    @classmethod
947*cfb92d14SAndroid Build Coastguard Worker    def set_time_speedup_factor(cls, factor):
948*cfb92d14SAndroid Build Coastguard Worker        """Sets up the time speed up factor - should be set before creating any `Node` objects"""
949*cfb92d14SAndroid Build Coastguard Worker        if len(Node._all_nodes) != 0:
950*cfb92d14SAndroid Build Coastguard Worker            raise Node._NodeError('set_time_speedup_factor() cannot be called after creating a `Node`')
951*cfb92d14SAndroid Build Coastguard Worker        Node._SPEED_UP_FACTOR = factor
952*cfb92d14SAndroid Build Coastguard Worker
953*cfb92d14SAndroid Build Coastguard Worker
954*cfb92d14SAndroid Build Coastguard Workerdef _check_node_is_leader(node):
955*cfb92d14SAndroid Build Coastguard Worker    verify(node.get_state() == 'leader')
956*cfb92d14SAndroid Build Coastguard Worker
957*cfb92d14SAndroid Build Coastguard Worker
958*cfb92d14SAndroid Build Coastguard Workerdef _check_node_is_router(node):
959*cfb92d14SAndroid Build Coastguard Worker    verify(node.get_state() == 'router')
960*cfb92d14SAndroid Build Coastguard Worker
961*cfb92d14SAndroid Build Coastguard Worker
962*cfb92d14SAndroid Build Coastguard Workerdef _check_node_is_child(node):
963*cfb92d14SAndroid Build Coastguard Worker    verify(node.get_state() == 'child')
964*cfb92d14SAndroid Build Coastguard Worker
965*cfb92d14SAndroid Build Coastguard Worker
966*cfb92d14SAndroid Build Coastguard Worker# ----------------------------------------------------------------------------------------------------------------------
967*cfb92d14SAndroid Build Coastguard Worker
968*cfb92d14SAndroid Build Coastguard Worker
969*cfb92d14SAndroid Build Coastguard Workerclass VerifyError(Exception):
970*cfb92d14SAndroid Build Coastguard Worker    pass
971*cfb92d14SAndroid Build Coastguard Worker
972*cfb92d14SAndroid Build Coastguard Worker
973*cfb92d14SAndroid Build Coastguard Worker_is_in_verify_within = False
974*cfb92d14SAndroid Build Coastguard Worker
975*cfb92d14SAndroid Build Coastguard Worker
976*cfb92d14SAndroid Build Coastguard Workerdef verify(condition):
977*cfb92d14SAndroid Build Coastguard Worker    """Verifies that a `condition` is true, otherwise raises a VerifyError"""
978*cfb92d14SAndroid Build Coastguard Worker    global _is_in_verify_within
979*cfb92d14SAndroid Build Coastguard Worker    if not condition:
980*cfb92d14SAndroid Build Coastguard Worker        calling_frame = inspect.currentframe().f_back
981*cfb92d14SAndroid Build Coastguard Worker        error_message = 'verify() failed at line {} in "{}"'.format(calling_frame.f_lineno,
982*cfb92d14SAndroid Build Coastguard Worker                                                                    calling_frame.f_code.co_filename)
983*cfb92d14SAndroid Build Coastguard Worker        if not _is_in_verify_within:
984*cfb92d14SAndroid Build Coastguard Worker            print(error_message)
985*cfb92d14SAndroid Build Coastguard Worker        raise VerifyError(error_message)
986*cfb92d14SAndroid Build Coastguard Worker
987*cfb92d14SAndroid Build Coastguard Worker
988*cfb92d14SAndroid Build Coastguard Workerdef verify_within(condition_checker_func, wait_time, arg=None, delay_time=0.1):
989*cfb92d14SAndroid Build Coastguard Worker    """Verifies that a given function `condition_checker_func` passes successfully within a given wait timeout.
990*cfb92d14SAndroid Build Coastguard Worker       `wait_time` is maximum time waiting for condition_checker to pass (in seconds).
991*cfb92d14SAndroid Build Coastguard Worker       `arg` is optional parameter and if it s not None, will be passed to `condition_checker_func()`
992*cfb92d14SAndroid Build Coastguard Worker       `delay_time` specifies a delay interval added between failed attempts (in seconds).
993*cfb92d14SAndroid Build Coastguard Worker    """
994*cfb92d14SAndroid Build Coastguard Worker    global _is_in_verify_within
995*cfb92d14SAndroid Build Coastguard Worker    start_time = time.time()
996*cfb92d14SAndroid Build Coastguard Worker    old_is_in_verify_within = _is_in_verify_within
997*cfb92d14SAndroid Build Coastguard Worker    _is_in_verify_within = True
998*cfb92d14SAndroid Build Coastguard Worker    while True:
999*cfb92d14SAndroid Build Coastguard Worker        try:
1000*cfb92d14SAndroid Build Coastguard Worker            if arg is None:
1001*cfb92d14SAndroid Build Coastguard Worker                condition_checker_func()
1002*cfb92d14SAndroid Build Coastguard Worker            else:
1003*cfb92d14SAndroid Build Coastguard Worker                condition_checker_func(arg)
1004*cfb92d14SAndroid Build Coastguard Worker        except VerifyError as e:
1005*cfb92d14SAndroid Build Coastguard Worker            if time.time() - start_time > wait_time:
1006*cfb92d14SAndroid Build Coastguard Worker                print('Took too long to pass the condition ({}>{} sec)'.format(time.time() - start_time, wait_time))
1007*cfb92d14SAndroid Build Coastguard Worker                if hasattr(e, 'message'):
1008*cfb92d14SAndroid Build Coastguard Worker                    print(e.message)
1009*cfb92d14SAndroid Build Coastguard Worker                raise e
1010*cfb92d14SAndroid Build Coastguard Worker        except BaseException:
1011*cfb92d14SAndroid Build Coastguard Worker            raise
1012*cfb92d14SAndroid Build Coastguard Worker        else:
1013*cfb92d14SAndroid Build Coastguard Worker            break
1014*cfb92d14SAndroid Build Coastguard Worker        if delay_time != 0:
1015*cfb92d14SAndroid Build Coastguard Worker            time.sleep(delay_time)
1016*cfb92d14SAndroid Build Coastguard Worker    _is_in_verify_within = old_is_in_verify_within
1017