diff --git a/tools/cp-caps/README.md b/tools/cp-caps/README.md index a7cccecc769..21c639761a1 100644 --- a/tools/cp-caps/README.md +++ b/tools/cp-caps/README.md @@ -54,26 +54,28 @@ Show help info. ```bash $ python3 ./tools/cp-caps/rcp_caps_test.py -h -usage: rcp_caps_test.py [-h] [-c] [-d] [-p] [-t] [-v] [-D] +usage: rcp_caps_test.py [-h] [-c] [-l] [-d] [-f] [-p] [-t] [-v] [-D] This script is used for testing RCP capabilities. options: -h, --help show this help message and exit -c, --csl test whether the RCP supports CSL transmitter - -d, --diag-commands test whether the RCP supports all diag commands -l, --link-metrics test whether the RCP supports link metrics + -d, --diag-commands test whether the RCP supports all diag commands + -f, --frame-format test whether the RCP supports 802.15.4 frames of all formats -p, --data-poll test whether the RCP supports data poll - -t, --throughput test the Thread network 1-hop throughput + -t, --throughput test Thread network 1-hop throughput -v, --version output version -D, --debug output debug information Device Interfaces: - DUT_SSH= Connect to the DUT via ssh DUT_ADB_TCP= Connect to the DUT via adb tcp DUT_ADB_USB= Connect to the DUT via adb usb - REF_CLI_SERIAL= Connect to the reference device via cli serial port + DUT_CLI_SERIAL= Connect to the DUT via cli serial port + DUT_SSH= Connect to the DUT via ssh REF_ADB_USB= Connect to the reference device via adb usb + REF_CLI_SERIAL= Connect to the reference device via cli serial port REF_SSH= Connect to the reference device via ssh Example: @@ -82,7 +84,7 @@ Example: ### Test Diag Commands -The parameter `-d` or `--diag-commands` starts to test all diag commands. +The option `-d` or `--diag-commands` tests all diag commands. Following environment variables are used to configure diag command parameters: @@ -131,7 +133,7 @@ diag gpio set 2 1 ---------------------------------------- NotSupported ### Test CSL Transmitter -The parameter `-c` or `--csl` starts to test whether the RCP supports the CSL transmitter. +The option `-c` or `--csl` tests whether the RCP supports the CSL transmitter. ```bash $ DUT_ADB_USB=TW69UCKFZTGM95OR REF_CLI_SERIAL=/dev/ttyACM0 python3 ./tools/cp-caps/rcp_caps_test.py -c @@ -140,7 +142,7 @@ CSL Transmitter ------------------------------------------ OK ### Test Data Poll -The parameter `-p` or `--data-poll` starts to test whether the RCP supports data poll. +The option `-p` or `--data-poll` tests whether the RCP supports data poll. ```bash $ DUT_ADB_USB=1269UCKFZTAM95OR REF_CLI_SERIAL=/dev/ttyACM0 python3 ./tools/cp-caps/rcp_caps_test.py -p @@ -150,7 +152,7 @@ Data Poll Child ------------------------------------------ OK ### Test Link Metrics -The parameter `-l` or `--link-metrics` starts to test whether the RCP supports link metrics. +The option `-l` or `--link-metrics` tests whether the RCP supports link metrics. ```bash $ DUT_ADB_USB=1269UCKFZTAM95OR REF_CLI_SERIAL=/dev/ttyACM0 python3 ./tools/cp-caps/rcp_caps_test.py -l @@ -160,9 +162,59 @@ Link Metrics Subject ------------------------------------- OK ### Test Throughput -The parameter `-t` or `--throughput` starts to test the Thread network 1-hop throughput of the DUT. +The option `-t` or `--throughput` tests the Thread network 1-hop throughput of the DUT. ```bash $ DUT_ADB_USB=1269UCKFZTAM95OR REF_ADB_USB=44061HFAG01AQK python3 ./tools/cp-caps/rcp_caps_test.py -t Throughput ----------------------------------------------- 75.6 Kbits/sec ``` + +### Test Frame Format + +The option `-f` or `--frame-format` tests whether the RCP supports sending and receiving 802.15.4 frames of all formats. + +```bash +$ DUT_ADB_USB=1269UCKFZTAM95OR REF_CLI_SERIAL=/dev/ttyACM0 python3 ./tools/cp-caps/rcp_caps_test.py -f +TX ver:2003,Cmd,seq,dst[addr:short,pan:id],src[addr:no,pan:no],sec:no,ie:no,plen:0 ----------------- OK +RX ver:2003,Cmd,seq,dst[addr:short,pan:id],src[addr:no,pan:no],sec:no,ie:no,plen:0 ----------------- OK +TX ver:2003,Bcon,seq,dst[addr:no,pan:no],src[addr:extd,pan:id],sec:no,ie:no,plen:30 ---------------- OK +RX ver:2003,Bcon,seq,dst[addr:no,pan:no],src[addr:extd,pan:id],sec:no,ie:no,plen:30 ---------------- OK +TX ver:2006,Cmd,seq,dst[addr:short,pan:id],src[addr:short,pan:no],sec:l5,ie:no,plen:0 -------------- OK +RX ver:2006,Cmd,seq,dst[addr:short,pan:id],src[addr:short,pan:no],sec:l5,ie:no,plen:0 -------------- OK +TX ver:2006,Cmd,seq,dst[addr:extd,pan:id],src[addr:extd,pan:no],sec:l5,ie:no,plen:0 ---------------- OK +RX ver:2006,Cmd,seq,dst[addr:extd,pan:id],src[addr:extd,pan:no],sec:l5,ie:no,plen:0 ---------------- OK +TX ver:2006,Data,seq,dst[addr:extd,pan:id],src[addr:extd,pan:id],sec:no,ie:no,plen:0 --------------- OK +RX ver:2006,Data,seq,dst[addr:extd,pan:id],src[addr:extd,pan:id],sec:no,ie:no,plen:0 --------------- OK +TX ver:2006,Data,seq,dst[addr:short,pan:id],src[addr:short,pan:id],sec:no,ie:no,plen:0 ------------- OK +RX ver:2006,Data,seq,dst[addr:short,pan:id],src[addr:short,pan:id],sec:no,ie:no,plen:0 ------------- OK +TX ver:2006,Data,seq,dst[addr:extd,pan:id],src[addr:no,pan:no],sec:no,ie:no,plen:0 ----------------- OK +RX ver:2006,Data,seq,dst[addr:extd,pan:id],src[addr:no,pan:no],sec:no,ie:no,plen:0 ----------------- OK +TX ver:2006,Data,seq,dst[addr:short,pan:id],src[addr:no,pan:no],sec:no,ie:no,plen:0 ---------------- OK +RX ver:2006,Data,seq,dst[addr:short,pan:id],src[addr:no,pan:no],sec:no,ie:no,plen:0 ---------------- OK +TX ver:2015,Data,seq,dst[addr:no,pan:no],src[addr:no,pan:no],sec:no,ie:no,plen:0 ------------------- OK +RX ver:2015,Data,seq,dst[addr:no,pan:no],src[addr:no,pan:no],sec:no,ie:no,plen:0 ------------------- OK +TX ver:2015,Data,seq,dst[addr:no,pan:id],src[addr:no,pan:no],sec:no,ie:no,plen:0 ------------------- OK +RX ver:2015,Data,seq,dst[addr:no,pan:id],src[addr:no,pan:no],sec:no,ie:no,plen:0 ------------------- OK +TX ver:2015,Data,seq,dst[addr:extd,pan:id],src[addr:no,pan:no],sec:no,ie:no,plen:0 ----------------- OK +RX ver:2015,Data,seq,dst[addr:extd,pan:id],src[addr:no,pan:no],sec:no,ie:no,plen:0 ----------------- OK +TX ver:2015,Data,seq,dst[addr:extd,pan:no],src[addr:no,pan:no],sec:no,ie:no,plen:0 ----------------- OK +RX ver:2015,Data,seq,dst[addr:extd,pan:no],src[addr:no,pan:no],sec:no,ie:no,plen:0 ----------------- OK +TX ver:2015,Data,seq,dst[addr:no,pan:no],src[addr:extd,pan:id],sec:no,ie:no,plen:0 ----------------- OK +RX ver:2015,Data,seq,dst[addr:no,pan:no],src[addr:extd,pan:id],sec:no,ie:no,plen:0 ----------------- OK +TX ver:2015,Data,seq,dst[addr:no,pan:no],src[addr:extd,pan:no],sec:no,ie:no,plen:0 ----------------- OK +RX ver:2015,Data,seq,dst[addr:no,pan:no],src[addr:extd,pan:no],sec:no,ie:no,plen:0 ----------------- OK +TX ver:2015,Data,seq,dst[addr:extd,pan:id],src[addr:extd,pan:no],sec:no,ie:no,plen:0 --------------- OK +RX ver:2015,Data,seq,dst[addr:extd,pan:id],src[addr:extd,pan:no],sec:no,ie:no,plen:0 --------------- OK +TX ver:2015,Data,seq,dst[addr:extd,pan:no],src[addr:extd,pan:no],sec:no,ie:no,plen:0 --------------- OK +RX ver:2015,Data,seq,dst[addr:extd,pan:no],src[addr:extd,pan:no],sec:no,ie:no,plen:0 --------------- OK +TX ver:2015,Data,seq,dst[addr:short,pan:id],src[addr:short,pan:id],sec:no,ie:no,plen:0 ------------- OK +RX ver:2015,Data,seq,dst[addr:short,pan:id],src[addr:short,pan:id],sec:no,ie:no,plen:0 ------------- OK +TX ver:2015,Data,seq,dst[addr:short,pan:id],src[addr:extd,pan:id],sec:no,ie:no,plen:0 -------------- OK +RX ver:2015,Data,seq,dst[addr:short,pan:id],src[addr:extd,pan:id],sec:no,ie:no,plen:0 -------------- OK +TX ver:2015,Data,seq,dst[addr:extd,pan:id],src[addr:short,pan:id],sec:no,ie:no,plen:0 -------------- OK +RX ver:2015,Data,seq,dst[addr:extd,pan:id],src[addr:short,pan:id],sec:no,ie:no,plen:0 -------------- OK +TX ver:2015,Data,seq,dst[addr:short,pan:id],src[addr:short,pan:id],sec:no,ie[csl],plen:0 ----------- OK +RX ver:2015,Data,seq,dst[addr:short,pan:id],src[addr:short,pan:id],sec:no,ie[csl],plen:0 ----------- OK +TX ver:2015,Data,noseq,dst[addr:short,pan:id],src[addr:short,pan:id],sec:no,ie:no,plen:0 ----------- OK +RX ver:2015,Data,noseq,dst[addr:short,pan:id],src[addr:short,pan:id],sec:no,ie:no,plen:0 ----------- OK +``` diff --git a/tools/cp-caps/rcp_caps_test.py b/tools/cp-caps/rcp_caps_test.py index 79b30f52752..3fdfc49650b 100644 --- a/tools/cp-caps/rcp_caps_test.py +++ b/tools/cp-caps/rcp_caps_test.py @@ -40,7 +40,7 @@ from otci import OTCI from otci.types import Ip6Addr -CP_CAPABILITY_VERSION = "0.1.0" +CP_CAPABILITY_VERSION = "0.1.1-dev" logging.basicConfig(level=logging.WARNING) @@ -50,6 +50,8 @@ class RcpCaps(object): This class represents an OpenThread RCP capability test instance. """ + DEFAULT_FORMAT_ALIGN_LENGTH = 58 # The default formatted string alignment length + def __init__(self): self.__dut = self.__connect_dut() self.__ref = self.__connect_reference_device() @@ -83,6 +85,113 @@ def test_diag_commands(self): self.__ref.diag_stop() self.__dut.diag_stop() + def test_frame_format(self): + """Test whether the DUT supports sending and receiving 802.15.4 frames of all formats.""" + frames = [ + { + 'name': 'ver:2003,Cmd,seq,dst[addr:short,pan:id],src[addr:no,pan:no],sec:no,ie:no,plen:0', + 'psdu': '030800ffffffff070000' + }, + { + 'name': 'ver:2003,Bcon,seq,dst[addr:no,pan:no],src[addr:extd,pan:id],sec:no,ie:no,plen:30', + 'psdu': '00c000eeee0102030405060708ff0f000003514f70656e54687265616400000000000001020304050607080000' + }, + { + 'name': 'ver:2006,Cmd,seq,dst[addr:short,pan:id],src[addr:short,pan:no],sec:l5,ie:no,plen:0', + 'psdu': '4b98ddddddaaaabbbb0d708001020304050607081565' + }, + { + 'name': 'ver:2006,Cmd,seq,dst[addr:extd,pan:id],src[addr:extd,pan:no],sec:l5,ie:no,plen:0', + 'psdu': '4bdcdddddd102030405060708001020304050607080d6e54687265046400820ee803' + }, + { + 'name': 'ver:2006,Data,seq,dst[addr:extd,pan:id],src[addr:extd,pan:id],sec:no,ie:no,plen:0', + 'psdu': '01dcdddddd1020304050607080000001020304050607085468' + }, + { + 'name': 'ver:2006,Data,seq,dst[addr:short,pan:id],src[addr:short,pan:id],sec:no,ie:no,plen:0', + 'psdu': '0198ddddddaaaaeeeebbbb7080' + }, + { + 'name': 'ver:2006,Data,seq,dst[addr:extd,pan:id],src[addr:no,pan:no],sec:no,ie:no,plen:0', + 'psdu': '011cdddddd10203040506070800000' + }, + { + 'name': 'ver:2006,Data,seq,dst[addr:short,pan:id],src[addr:no,pan:no],sec:no,ie:no,plen:0', + 'psdu': '0118ddddddaaaa3040' + }, + { + 'name': 'ver:2015,Data,seq,dst[addr:no,pan:no],src[addr:no,pan:no],sec:no,ie:no,plen:0', + 'psdu': '0120dddddd' + }, + { + 'name': 'ver:2015,Data,seq,dst[addr:no,pan:id],src[addr:no,pan:no],sec:no,ie:no,plen:0', + 'psdu': '4120ddddddaaaa' + }, + { + 'name': 'ver:2015,Data,seq,dst[addr:extd,pan:id],src[addr:no,pan:no],sec:no,ie:no,plen:0', + 'psdu': '012cdddddd10203040506070800000' + }, + { + 'name': 'ver:2015,Data,seq,dst[addr:extd,pan:no],src[addr:no,pan:no],sec:no,ie:no,plen:0', + 'psdu': '412cdd10203040506070807080' + }, + { + 'name': 'ver:2015,Data,seq,dst[addr:no,pan:no],src[addr:extd,pan:id],sec:no,ie:no,plen:0', + 'psdu': '01e0ddeeee01020304050607080000' + }, + { + 'name': 'ver:2015,Data,seq,dst[addr:no,pan:no],src[addr:extd,pan:no],sec:no,ie:no,plen:0', + 'psdu': '41e0dd01020304050607080708' + }, + { + 'name': 'ver:2015,Data,seq,dst[addr:extd,pan:id],src[addr:extd,pan:no],sec:no,ie:no,plen:0', + 'psdu': '01ecdddddd102030405060708001020304050607080708' + }, + { + 'name': 'ver:2015,Data,seq,dst[addr:extd,pan:no],src[addr:extd,pan:no],sec:no,ie:no,plen:0', + 'psdu': '41ecdd102030405060708001020304050607080708' + }, + { + 'name': 'ver:2015,Data,seq,dst[addr:short,pan:id],src[addr:short,pan:id],sec:no,ie:no,plen:0', + 'psdu': '01a8ddddddaaaaeeeebbbb0102' + }, + { + 'name': 'ver:2015,Data,seq,dst[addr:short,pan:id],src[addr:extd,pan:id],sec:no,ie:no,plen:0', + 'psdu': '01e8ddddddaaaaeeee01020304050607080708' + }, + { + 'name': 'ver:2015,Data,seq,dst[addr:extd,pan:id],src[addr:short,pan:id],sec:no,ie:no,plen:0', + 'psdu': '01acdddddd1020304050607080eeeebbbb0708' + }, + { + 'name': 'ver:2015,Data,seq,dst[addr:short,pan:id],src[addr:short,pan:id],sec:no,ie[csl],plen:0', + 'psdu': '01aaddddddaaaaeeeebbbb040dc800e8030708' + }, + { + 'name': 'ver:2015,Data,noseq,dst[addr:short,pan:id],src[addr:short,pan:id],sec:no,ie:no,plen:0', + 'psdu': '01a9ddddaaaaeeeebbbbbb04' + }, + ] + + self.__dut.factory_reset() + self.__ref.factory_reset() + + ret = self.__dut.is_command_supported('diag start') + if ret is False: + print('Diag commands are not supported') + return + + self.__dut.diag_start() + self.__ref.diag_start() + + for frame in frames: + self.__test_send_formated_frame(self.__dut, self.__ref, 'TX ' + frame['name'], frame['psdu'], 100) + self.__test_send_formated_frame(self.__ref, self.__dut, 'RX ' + frame['name'], frame['psdu'], 100) + + self.__ref.diag_stop() + self.__dut.diag_stop() + def test_csl(self): """Test whether the DUT supports CSL transmitter.""" self.__dataset = self.__get_default_dataset() @@ -476,34 +585,44 @@ def __test_diag_repeat(self): self.__output_format_bool(cmd_diag_repeat, ret) self.__output_format_bool(cmd_diag_repeat_stop, ret) - def __test_diag_frame(self): + def __test_send_formated_frame(self, + sender: OTCI, + receiver: OTCI, + format_name: str, + frame: str, + align_length: int = DEFAULT_FORMAT_ALIGN_LENGTH): packets = 100 threshold = 80 channel = 20 - frame = '00010203040506070809' cmd_diag_frame = f'diag frame {frame}' commands = [cmd_diag_frame, f'diag send {packets}', f'diag stats', f'diag stats clear'] if self.__support_commands(commands): - self.__dut.wait(1) - self.__dut.diag_set_channel(channel) - self.__ref.diag_set_channel(channel) - self.__ref.diag_radio_receive() + sender.wait(1) + sender.diag_set_channel(channel) + receiver.diag_set_channel(channel) + receiver.diag_radio_receive() - self.__dut.diag_stats_clear() - self.__ref.diag_stats_clear() + sender.diag_stats_clear() + sender.diag_stats_clear() - self.__ref.diag_frame(frame) - self.__dut.diag_send(packets, None) - self.__dut.wait(1) - dut_stats = self.__dut.diag_get_stats() - ref_stats = self.__ref.diag_get_stats() + sender.diag_frame(frame) + sender.diag_send(packets, None) + sender.wait(1) + sender_stats = sender.diag_get_stats() + receiver_stats = receiver.diag_get_stats() - ret = dut_stats['sent_packets'] == packets and ref_stats['received_packets'] > threshold + ret = sender_stats['sent_packets'] == packets and receiver_stats['received_packets'] > threshold else: ret = False - self.__output_format_bool(cmd_diag_frame, ret) + self.__output_format_bool(format_name, ret, align_length) + + def __test_diag_frame(self): + frame = '00010203040506070809' + cmd_diag_frame = f'diag frame {frame}' + + self.__test_send_formated_frame(self.__dut, self.__ref, cmd_diag_frame, frame) def __support_commands(self, commands: List[str]) -> bool: ret = True @@ -533,10 +652,12 @@ def __connect_dut(self) -> OTCI: node = otci.connect_otbr_adb_tcp(os.getenv('DUT_ADB_TCP')) elif os.getenv('DUT_ADB_USB'): node = otci.connect_otbr_adb_usb(os.getenv('DUT_ADB_USB')) + elif os.getenv('DUT_CLI_SERIAL'): + node = otci.connect_cli_serial(os.getenv('DUT_CLI_SERIAL')) elif os.getenv('DUT_SSH'): node = otci.connect_otbr_ssh(os.getenv('DUT_SSH')) else: - self.__fail("Please set DUT_ADB_TCP, DUT_ADB_USB or DUT_SSH to connect to the DUT device.") + self.__fail("Please set DUT_ADB_TCP, DUT_ADB_USB, DUT_CLI_SERIAL or DUT_SSH to connect to the DUT device.") return node @@ -552,12 +673,12 @@ def __connect_reference_device(self) -> OTCI: return node - def __output_format_string(self, name: str, value: str): - prefix = '{0:-<58}'.format('{} '.format(name)) + def __output_format_string(self, name: str, value: str, align_length: int = DEFAULT_FORMAT_ALIGN_LENGTH): + prefix = (name + ' ').ljust(align_length, '-') print(f'{prefix} {value}') - def __output_format_bool(self, name: str, value: bool): - self.__output_format_string(name, 'OK' if value else 'NotSupported') + def __output_format_bool(self, name: str, value: bool, align_length: int = DEFAULT_FORMAT_ALIGN_LENGTH): + self.__output_format_string(name, 'OK' if value else 'NotSupported', align_length) def __fail(self, value: str): print(f'{value}') @@ -569,11 +690,12 @@ def parse_arguments(): description_msg = 'This script is used for testing RCP capabilities.' epilog_msg = textwrap.dedent( 'Device Interfaces:\r\n' - ' DUT_SSH= Connect to the DUT via ssh\r\n' ' DUT_ADB_TCP= Connect to the DUT via adb tcp\r\n' ' DUT_ADB_USB= Connect to the DUT via adb usb\r\n' - ' REF_CLI_SERIAL= Connect to the reference device via cli serial port\r\n' + ' DUT_CLI_SERIAL= Connect to the DUT via cli serial port\r\n' + ' DUT_SSH= Connect to the DUT via ssh\r\n' ' REF_ADB_USB= Connect to the reference device via adb usb\r\n' + ' REF_CLI_SERIAL= Connect to the reference device via cli serial port\r\n' ' REF_SSH= Connect to the reference device via ssh\r\n' '\r\n' 'Example:\r\n' @@ -607,6 +729,14 @@ def parse_arguments(): help='test whether the RCP supports all diag commands', ) + parser.add_argument( + '-f', + '--frame-format', + action='store_true', + default=False, + help='test whether the RCP supports 802.15.4 frames of all formats', + ) + parser.add_argument( '-p', '--data-poll', @@ -670,6 +800,9 @@ def main(): if arguments.throughput: rcp_caps.test_throughput() + if arguments.frame_format: + rcp_caps.test_frame_format() + if __name__ == '__main__': main()