Skip to content

Commit f42af4e

Browse files
author
Thomas
authored
[otci] add support for IPv4, vendor commands, networkdiagnostics (openthread#11397)
With Thread 1.4 the cli application not can also (dns) resolve IPv4 addresses. This commit adds the same support in otci * dns_resolve4 Implements support for vendor operations in otci get/set * vendor_name * vendor_model * vendor_sw_version Implements network diagnostic commands * get * reset * non_preferred_channels Various other (small changes)" * allow setting read timeout on serial connections * allow replacing read routine filter * expose latest thread versions in the public module api * expand the definition of dns_get_config * replaces mgmtget/mgmtset with the correct mgmtgetcommand and mgmtsetcommand * replaces addressmode with the correct addrmode * adds an `ignore_result` option to `execute_command` * adds a missing `diag` command * removes some unexisting getters
1 parent 2e73358 commit f42af4e

10 files changed

Lines changed: 391 additions & 163 deletions

File tree

src/cli/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,9 +1196,9 @@ CSL period is shown in microseconds.
11961196
11971197
```bash
11981198
> csl
1199-
Channel: 11
1200-
Period: 160000us
1201-
Timeout: 1000s
1199+
channel: 11
1200+
period: 160000us
1201+
timeout: 1000s
12021202
Done
12031203
```
12041204

src/cli/cli.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7535,7 +7535,7 @@ template <> otError Interpreter::Process<Cmd("networkdiagnostic")>(Arg aArgs[])
75357535
* @code
75367536
* networkdiagnostic get ff02::1 0 1
75377537
* DIAG_GET.rsp/ans: 00080e336e1c41494e1c01020c00
7538-
* Ext Address: '0e336e1c41494e1c'
7538+
* Ext Address: 0e336e1c41494e1c
75397539
* Rloc16: 0x0c00
75407540
* Done
75417541
* DIAG_GET.rsp/ans: 00083efcdb7e3f9eb0f201021800

tools/otci/README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# OpenThread Control Interface
22

3-
The OpenThread Control Interface (OTCI) is a library which provides uniform python interfaces to connect and control various kinds of devices running OpenThread.
3+
The OpenThread Control Interface (OTCI) is a library which provides uniform Python interfaces to connect and control various kinds of devices running OpenThread.
44

55
## Supported device types
66

@@ -22,7 +22,7 @@ node1 = otci.connect_otbr_ssh("192.168.1.101")
2222
# Connect to an OpenThread CLI device via Serial
2323
node2 = otci.connect_cli_serial("/dev/ttyACM0"))
2424

25-
# Start node1 to become Leader
25+
# Start node1 and wait for it to become the Leader
2626
node1.dataset_init_buffer()
2727
node1.dataset_set_buffer(network_name='test', network_key='00112233445566778899aabbccddeeff', panid=0xface, channel=11)
2828
node1.dataset_commit_buffer('active')
@@ -32,7 +32,7 @@ node1.thread_start()
3232
node1.wait(5)
3333
assert node1.get_state() == "leader"
3434

35-
# Start Commissioner on node1
35+
# Start the Commissioner role on node1
3636
node1.commissioner_start()
3737
node1.wait(3)
3838

@@ -42,11 +42,11 @@ node1.commissioner_add_joiner("TEST123",eui64='*')
4242
node2.ifconfig_up()
4343
node2.set_router_selection_jitter(1)
4444

45-
# Start Joiner on node2 to join the network
45+
# Start the Joiner role on node2 and wait for it to join the network
4646
node2.joiner_start("TEST123")
4747
node2.wait(10, expect_line="Join success")
4848

49-
# Wait for node 2 to become Router
49+
# Wait for node 2 to become a Router
5050
node2.thread_start()
5151
node2.wait(5)
5252
assert node2.get_state() == "router"

tools/otci/otci/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@
2828
#
2929

3030
from . import errors
31-
from .constants import THREAD_VERSION_1_1, THREAD_VERSION_1_2
31+
from .constants import THREAD_VERSION_1_1, THREAD_VERSION_1_2, THREAD_VERSION_1_3, THREAD_VERSION_1_4
3232
from .command_handlers import OTCommandHandler
33+
from .connectors import OtCliHandler
3334
from .otci import OTCI
3435
from .otci import (
3536
connect_cli_sim,
@@ -56,6 +57,7 @@
5657
__all__ = [
5758
'OTCI',
5859
'OTCommandHandler',
60+
'OTCliHandler',
5961
'errors',
6062
'Rloc16',
6163
'ChildId',

tools/otci/otci/command_handlers.py

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -84,26 +84,30 @@ def set_line_read_callback(self, callback: Optional[Callable[[str], Any]]):
8484
def shell(self, cmd: str, timeout: float) -> List[str]:
8585
raise NotImplementedError("shell command is not supported on %s" % self.__class__.__name__)
8686

87+
@classmethod
88+
def set_filter(cls, filter: re.Pattern[str]):
89+
return
90+
8791

8892
class OtCliCommandRunner(OTCommandHandler):
8993
__PATTERN_COMMAND_DONE_OR_ERROR = re.compile(
9094
r'(Done|Error|Error \d+:.*|.*: command not found)$') # "Error" for spinel-cli.py
9195

92-
__PATTERN_LOG_LINE = re.compile(r'((\[(NONE|CRIT|WARN|NOTE|INFO|DEBG)\])'
96+
__pattern_log_line = re.compile(r'((\[(NONE|CRIT|WARN|NOTE|INFO|DEBG)\])'
9397
r'|(-.*-+: )' # e.g. -CLI-----:
9498
r'|(\[[DINWC\-]\] (?=[\w\-]{14}:)\w+-*:)' # e.g. [I] Mac-----------:
9599
r')')
96100
"""regex used to filter logs"""
97101

98-
assert __PATTERN_LOG_LINE.match('[I] ChannelMonitor: debug log')
99-
assert __PATTERN_LOG_LINE.match('[I] Mac-----------: info log')
100-
assert __PATTERN_LOG_LINE.match('[N] MeshForwarder-: note log')
101-
assert __PATTERN_LOG_LINE.match('[W] Notifier------: warn log')
102-
assert __PATTERN_LOG_LINE.match('[C] Mle-----------: critical log')
103-
assert __PATTERN_LOG_LINE.match('[-] Settings------: none log')
104-
assert not __PATTERN_LOG_LINE.match('[-] Settings-----: none log') # not enough `-` after module name
102+
assert __pattern_log_line.match('[I] ChannelMonitor: debug log')
103+
assert __pattern_log_line.match('[I] Mac-----------: info log')
104+
assert __pattern_log_line.match('[N] MeshForwarder-: note log')
105+
assert __pattern_log_line.match('[W] Notifier------: warn log')
106+
assert __pattern_log_line.match('[C] Mle-----------: critical log')
107+
assert __pattern_log_line.match('[-] Settings------: none log')
108+
assert not __pattern_log_line.match('[-] Settings-----: none log') # not enough `-` after module name
105109

106-
__ASYNC_COMMANDS = {'scan', 'ping', 'discover'}
110+
__ASYNC_COMMANDS = {'scan', 'ping', 'discover', 'networkdiagnostic get'}
107111

108112
def __init__(self, otcli: OtCliHandler, is_spinel_cli: bool = False):
109113
self.__otcli: OtCliHandler = otcli
@@ -134,7 +138,8 @@ def execute_command(self, cmd: str, timeout: float = 10) -> List[str]:
134138

135139
output = self.__expect_line(timeout,
136140
OtCliCommandRunner.__PATTERN_COMMAND_DONE_OR_ERROR,
137-
asynchronous=cmd.split()[0] in OtCliCommandRunner.__ASYNC_COMMANDS)
141+
asynchronous=any(cmd.startswith(x) for x in OtCliCommandRunner.__ASYNC_COMMANDS))
142+
138143
return output
139144

140145
def execute_platform_command(self, cmd: str, timeout: float = 10) -> List[str]:
@@ -162,6 +167,18 @@ def close(self):
162167
def set_line_read_callback(self, callback: Optional[Callable[[str], Any]]):
163168
self.__line_read_callback = callback
164169

170+
@classmethod
171+
def set_filter(cls, filter: re.Pattern[str]):
172+
"""Set a different filter for the read routine that still matches the original filter"""
173+
assert filter.match('[I] ChannelMonitor: debug log')
174+
assert filter.match('[I] Mac-----------: info log')
175+
assert filter.match('[N] MeshForwarder-: note log')
176+
assert filter.match('[W] Notifier------: warn log')
177+
assert filter.match('[C] Mle-----------: critical log')
178+
assert filter.match('[-] Settings------: none log')
179+
assert not filter.match('[-] Settings-----: none log') # not enough `-` after module name
180+
cls.__pattern_log_line = filter
181+
165182
#
166183
# Private methods
167184
#
@@ -216,6 +233,8 @@ def __otcli_read_routine(self):
216233
if line is None:
217234
break
218235

236+
line = line.rstrip()
237+
219238
if line.startswith('> '):
220239
line = line[2:]
221240

@@ -224,8 +243,9 @@ def __otcli_read_routine(self):
224243

225244
logging.debug('%s: %s', self.__otcli, line)
226245

227-
if not OtCliCommandRunner.__PATTERN_LOG_LINE.match(line):
228-
logging.info('%s: %s', self.__otcli, line)
246+
if not OtCliCommandRunner.__pattern_log_line.match(line):
247+
if line:
248+
logging.info('%s: %s', self.__otcli, line)
229249
self.__pending_lines.put(line)
230250

231251

tools/otci/otci/connectors.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,12 +138,12 @@ def __init__(self, executable: str, nodeid: int, simulator: Optional[Simulator])
138138
class OtCliSerial(OtCliHandler):
139139
"""Connector for OT CLI SOC devices via Serial."""
140140

141-
def __init__(self, dev: str, baudrate: int):
141+
def __init__(self, dev: str, baudrate: int, timeout: float = 0.1):
142142
self.__dev = dev
143143
self.__baudrate = baudrate
144144

145145
import serial
146-
self.__serial = serial.Serial(self.__dev, self.__baudrate, timeout=0.1, exclusive=True)
146+
self.__serial = serial.Serial(self.__dev, self.__baudrate, timeout=timeout, exclusive=True)
147147
self.writeline('\r\n')
148148
self.__linebuffer = b''
149149

0 commit comments

Comments
 (0)