Skip to content

Commit

Permalink
[cp-caps] compare the send and received frames
Browse files Browse the repository at this point in the history
  • Loading branch information
zhanglongxia committed Jan 15, 2025
1 parent 7bd3abd commit 7ce665e
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 130 deletions.
2 changes: 2 additions & 0 deletions tools/cp-caps/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@ TX ver:2003,Cmd,seq,dst[addr:short,pan:id],src[addr:no,pan:no],sec:no,ie:no,plen
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:2003,MP,noseq,dst[addr:extd,pan:id],src[addr:extd,pan:no],sec:l5,ie[ren con],plen:0 --------- OK
RX ver:2003,MP,noseq,dst[addr:extd,pan:id],src[addr:extd,pan:no],sec:l5,ie[ren con],plen:0 --------- 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
Expand Down
287 changes: 157 additions & 130 deletions tools/cp-caps/rcp_caps_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,14 @@
import sys
import textwrap
import threading
import queue

from typing import List, Optional

import otci
from otci import OTCI
from otci.types import Ip6Addr
from otci.errors import ExpectLineTimeoutError

CP_CAPABILITY_VERSION = "0.1.1-dev"

Expand Down Expand Up @@ -75,6 +77,11 @@ def test_diag_commands(self):
self.__test_diag_repeat()
self.__test_diag_send()
self.__test_diag_frame()

# The self.__test_diag_frame will factoryreset the device
self.__dut.diag_start()
self.__ref.diag_start()

self.__test_diag_echo()
self.__test_diag_utils()
self.__test_diag_rawpowersetting()
Expand All @@ -85,112 +92,92 @@ def test_diag_commands(self):
self.__ref.diag_stop()
self.__dut.diag_stop()

class Frame:

def __init__(self, name: str, tx_frame: str, dst_address: str):
self.name = name
self.tx_frame = tx_frame
self.dst_address = dst_address

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.Frame(name='ver:2003,Cmd,seq,dst[addr:short,pan:id],src[addr:no,pan:no],sec:no,ie:no,plen:0',
tx_frame='030800ffffffff070000',
dst_address='0xffff'),
self.Frame(
name='ver:2003,Bcon,seq,dst[addr:no,pan:no],src[addr:extd,pan:id],sec:no,ie:no,plen:30',
tx_frame='00c000eeee0102030405060708ff0f000003514f70656e54687265616400000000000001020304050607080000',
dst_address='-'),
self.Frame(
name='ver:2003,MP,noseq,dst[addr:extd,pan:id],src[addr:extd,pan:no],sec:l5,ie[ren con],plen:0',
tx_frame=
'fd87dddd1020304050607080010203040506070815000000007265616401820ee80305009bb8ea011c807aa1120000',
dst_address='8070605040302010'),
self.Frame(name='ver:2006,Cmd,seq,dst[addr:short,pan:id],src[addr:short,pan:no],sec:l5,ie:no,plen:0',
tx_frame='4b9800ddddaaaabbbb0d0000000001043daa1aea0000',
dst_address='0xaaaa'),
self.Frame(name='ver:2006,Cmd,seq,dst[addr:extd,pan:id],src[addr:extd,pan:no],sec:l5,ie:no,plen:0',
tx_frame='4bdc00dddd102030405060708001020304050607080d000000000104483cb8a90000',
dst_address='8070605040302010'),
self.Frame(name='ver:2006,Data,seq,dst[addr:extd,pan:id],src[addr:extd,pan:id],sec:no,ie:no,plen:0',
tx_frame='41dc00dddd102030405060708001020304050607080000',
dst_address='8070605040302010'),
self.Frame(name='ver:2006,Data,seq,dst[addr:short,pan:id],src[addr:short,pan:id],sec:no,ie:no,plen:0',
tx_frame='019800ddddaaaaeeeebbbb0000',
dst_address='0xaaaa'),
self.Frame(name='ver:2006,Data,seq,dst[addr:extd,pan:id],src[addr:no,pan:no],sec:no,ie:no,plen:0',
tx_frame='011c00dddd10203040506070800000',
dst_address='8070605040302010'),
self.Frame(name='ver:2006,Data,seq,dst[addr:short,pan:id],src[addr:no,pan:no],sec:no,ie:no,plen:0',
tx_frame='011800ddddaaaa0000',
dst_address='0xaaaa'),
self.Frame(name='ver:2015,Data,seq,dst[addr:no,pan:no],src[addr:no,pan:no],sec:no,ie:no,plen:0',
tx_frame='0120000000',
dst_address='-'),
self.Frame(name='ver:2015,Data,seq,dst[addr:no,pan:id],src[addr:no,pan:no],sec:no,ie:no,plen:0',
tx_frame='412000dddd0000',
dst_address='-'),
self.Frame(name='ver:2015,Data,seq,dst[addr:extd,pan:id],src[addr:no,pan:no],sec:no,ie:no,plen:0',
tx_frame='012c00dddd10203040506070800000',
dst_address='8070605040302010'),
self.Frame(name='ver:2015,Data,seq,dst[addr:extd,pan:no],src[addr:no,pan:no],sec:no,ie:no,plen:0',
tx_frame='412c0010203040506070800000',
dst_address='8070605040302010'),
self.Frame(name='ver:2015,Data,seq,dst[addr:no,pan:no],src[addr:extd,pan:id],sec:no,ie:no,plen:0',
tx_frame='01e000eeee01020304050607080000',
dst_address='-'),
self.Frame(name='ver:2015,Data,seq,dst[addr:no,pan:no],src[addr:extd,pan:no],sec:no,ie:no,plen:0',
tx_frame='41e00001020304050607080000',
dst_address='-'),
self.Frame(name='ver:2015,Data,seq,dst[addr:extd,pan:id],src[addr:extd,pan:no],sec:no,ie:no,plen:0',
tx_frame='01ec00dddd102030405060708001020304050607080000',
dst_address='8070605040302010'),
self.Frame(name='ver:2015,Data,seq,dst[addr:extd,pan:no],src[addr:extd,pan:no],sec:no,ie:no,plen:0',
tx_frame='41ec00102030405060708001020304050607080000',
dst_address='8070605040302010'),
self.Frame(name='ver:2015,Data,seq,dst[addr:short,pan:id],src[addr:short,pan:id],sec:no,ie:no,plen:0',
tx_frame='01a800ddddaaaaeeeebbbb0000',
dst_address='0xaaaa'),
self.Frame(name='ver:2015,Data,seq,dst[addr:short,pan:id],src[addr:extd,pan:id],sec:no,ie:no,plen:0',
tx_frame='01e800ddddaaaaeeee01020304050607080000',
dst_address='0xaaaa'),
self.Frame(name='ver:2015,Data,seq,dst[addr:extd,pan:id],src[addr:short,pan:id],sec:no,ie:no,plen:0',
tx_frame='01ac00dddd1020304050607080eeeebbbb0000',
dst_address='8070605040302010'),
self.Frame(name='ver:2015,Data,seq,dst[addr:short,pan:id],src[addr:short,pan:id],sec:no,ie[csl],plen:0',
tx_frame='01aa00ddddaaaaeeeebbbb040dc800e8030000',
dst_address='0xaaaa'),
self.Frame(name='ver:2015,Data,noseq,dst[addr:short,pan:id],src[addr:short,pan:id],sec:no,ie:no,plen:0',
tx_frame='01a9ddddaaaaeeeebbbb0000',
dst_address='0xaaaa'),
]

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()
ret = self.__test_send_formated_frames_retries(self.__dut, self.__ref, frame)
self.__output_format_bool(f'TX {frame.name}', ret, 100)
ret = self.__test_send_formated_frames_retries(self.__ref, self.__dut, frame)
self.__output_format_bool(f'RX {frame.name}', ret, 100)

def test_csl(self):
"""Test whether the DUT supports CSL transmitter."""
Expand Down Expand Up @@ -585,44 +572,84 @@ def __test_diag_repeat(self):
self.__output_format_bool(cmd_diag_repeat, ret)
self.__output_format_bool(cmd_diag_repeat_stop, ret)

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
cmd_diag_frame = f'diag frame {frame}'
commands = [cmd_diag_frame, f'diag send {packets}', f'diag stats', f'diag stats clear']
def __test_send_formated_frames_retries(self,
sender: OTCI,
receiver: OTCI,
frame: Frame,
max_send_retries: int = 5):
for i in range(0, max_send_retries):
if self.__test_send_formated_frame(sender, receiver, frame):
return True

if self.__support_commands(commands):
sender.wait(1)
sender.diag_set_channel(channel)
receiver.diag_set_channel(channel)
receiver.diag_radio_receive()
return False

def __test_send_formated_frame(self, sender: OTCI, receiver: OTCI, frame: Frame):
sender.factory_reset()
receiver.factory_reset()

sender.diag_start()
receiver.diag_start()

channel = 11
num_sent_frames = 1

sender.diag_set_channel(channel)
receiver.diag_set_channel(channel)
receiver.diag_radio_receive()
receiver.diag_set_radio_receive_filter_dest_mac_address(frame.dst_address)
receiver.diag_enable_radio_receive_filter()

result_queue = queue.Queue()
receive_task = threading.Thread(target=self.__radio_receive_task,
args=(receiver, num_sent_frames, result_queue),
daemon=True)
receive_task.start()

sender.wait(0.1)

sender.diag_stats_clear()
sender.diag_stats_clear()
sender.diag_frame(frame.tx_frame,
is_security_processed=True,
max_csma_backoffs=4,
max_frame_retries=4,
csma_ca_enabled=True)
sender.diag_send(num_sent_frames, is_async=False)

sender.diag_frame(frame)
sender.diag_send(packets, None)
sender.wait(1)
sender_stats = sender.diag_get_stats()
receiver_stats = receiver.diag_get_stats()
receive_task.join()

ret = sender_stats['sent_success_packets'] == packets and receiver_stats['received_packets'] > threshold
if result_queue.empty():
ret = False # No frame is received.
else:
ret = False
received_frames = result_queue.get()
if len(received_frames) != num_sent_frames:
ret = False
else:
# The radio driver may not append the FCF field to the received frame. Do not check the FCF field here.
ret = frame.tx_frame[:-4] == received_frames[0]['psdu'][:-4]

self.__output_format_bool(format_name, ret, align_length)
if ret:
sender.diag_stop()
receiver.diag_stop()
else:
# The command 'diag radio receive <number>' may fail to receive specified number of frames in default
# timeout time. In this case, the diag module still in 'sync' mode, and it only allows users to run the
# command `factoryreset` to terminate the test.
sender.factory_reset()
receiver.factory_reset()

def __test_diag_frame(self):
frame = '00010203040506070809'
cmd_diag_frame = f'diag frame {frame}'
return ret

def __radio_receive_task(self, receiver: OTCI, number: int, result_queue: queue):
try:
result = receiver.diag_radio_receive_number(number)
except ExpectLineTimeoutError:
pass
else:
result_queue.put(result)

self.__test_send_formated_frame(self.__dut, self.__ref, cmd_diag_frame, frame)
def __test_diag_frame(self):
frame = self.Frame(name='diag frame 00010203040506070809', tx_frame='00010203040506070809', dst_address='-')
ret = self.__test_send_formated_frames_retries(self.__dut, self.__ref, frame)
self.__output_format_bool(frame.name, ret)

def __support_commands(self, commands: List[str]) -> bool:
ret = True
Expand Down

0 comments on commit 7ce665e

Please sign in to comment.