mirror of
https://github.com/micropython/micropython.git
synced 2025-12-16 09:50:15 +01:00
tests/serial_test.py: Add a serial echo test.
The existing `serial_test.py` script tests data in/out throughput and reliability. But it only tests data sizes that are a power of two, which may not catch certain errors with USB transmission (because FS packet size is 64 bytes). This commit adds a new echo sub-test to the `serial_test.py` script. It sends out data to the target and gets the target to echo it back, and then compares the result (the echo'd data should be equal to the sent data). It does this for data packets between 1 and 520 (inclusive) bytes, which covers USB FS and HS packet sizes (64 and 512 respectively). It uses random data for the test, but seeded by a constant seed so that it's deterministic. If there's an error then it prints out all the sent and echo'd data to make it easier to see where it went wrong (eg if the previous packet was repeated). Signed-off-by: Damien George <damien@micropython.org>
This commit is contained in:
@@ -8,12 +8,25 @@
|
||||
# The `serial-device` will default to /dev/ttyACM0.
|
||||
|
||||
import argparse
|
||||
import random
|
||||
import serial
|
||||
import sys
|
||||
import time
|
||||
|
||||
run_tests_module = __import__("run-tests")
|
||||
|
||||
echo_test_script = """
|
||||
import sys
|
||||
bytes_min=%u
|
||||
bytes_max=%u
|
||||
repeat=%u
|
||||
b=memoryview(bytearray(bytes_max))
|
||||
for n in range(bytes_min,bytes_max+1):
|
||||
for _ in range(repeat):
|
||||
n2 = sys.stdin.readinto(b[:n])
|
||||
sys.stdout.write(b[:n2])
|
||||
"""
|
||||
|
||||
read_test_script = """
|
||||
bin = True
|
||||
try:
|
||||
@@ -100,6 +113,59 @@ def send_script(ser, script):
|
||||
raise TestError("could not send script", response)
|
||||
|
||||
|
||||
def echo_test(ser_repl, ser_data):
|
||||
global test_passed
|
||||
|
||||
# Make the test data deterministic.
|
||||
random.seed(0)
|
||||
|
||||
# Set parameters for the test.
|
||||
# Go just a bit above the size of a USB high-speed packet.
|
||||
bytes_min = 1
|
||||
bytes_max = 520
|
||||
num_repeat = 1
|
||||
|
||||
# Load and run the write_test_script.
|
||||
script = bytes(echo_test_script % (bytes_min, bytes_max, num_repeat), "ascii")
|
||||
send_script(ser_repl, script)
|
||||
|
||||
# A selection of printable bytes for echo data.
|
||||
printable_bytes = list(range(48, 58)) + list(range(65, 91)) + list(range(97, 123))
|
||||
|
||||
# Write data to the device and record the echo'd data.
|
||||
# Use a different selection of random printable characters for each
|
||||
# echo, to make it easier to debug when the echo doesn't match.
|
||||
num_errors = 0
|
||||
echo_results = []
|
||||
for num_bytes in range(bytes_min, bytes_max + 1):
|
||||
print(f"DATA ECHO: {num_bytes} / {bytes_max}", end="\r")
|
||||
for repeat in range(num_repeat):
|
||||
rand_bytes = list(random.choice(printable_bytes) for _ in range(8))
|
||||
buf = bytes(random.choice(rand_bytes) for _ in range(num_bytes))
|
||||
ser_data.write(buf)
|
||||
buf2 = ser_data.read(len(buf))
|
||||
match = buf == buf2
|
||||
num_errors += not match
|
||||
echo_results.append((match, buf, buf2))
|
||||
if num_errors > 8:
|
||||
# Stop early if there are too many errors.
|
||||
break
|
||||
ser_repl.write(b"\x03")
|
||||
|
||||
# Print results.
|
||||
if all(match for match, _, _ in echo_results):
|
||||
print("DATA ECHO: OK for {}-{} bytes at a time".format(bytes_min, bytes_max))
|
||||
else:
|
||||
test_passed = False
|
||||
print("DATA ECHO: FAIL ")
|
||||
for match, buf, buf2 in echo_results:
|
||||
print(" sent", len(buf), buf)
|
||||
if match:
|
||||
print(" echo match")
|
||||
else:
|
||||
print(" echo", len(buf), buf2)
|
||||
|
||||
|
||||
def read_test(ser_repl, ser_data, bufsize, nbuf):
|
||||
global test_passed
|
||||
|
||||
@@ -212,6 +278,12 @@ def do_test(dev_repl, dev_data=None, time_per_subtest=1):
|
||||
ser_repl = serial.Serial(dev_repl, baudrate=115200, timeout=1)
|
||||
ser_data = serial.Serial(dev_data, baudrate=115200, timeout=1)
|
||||
|
||||
# Do echo test first, and abort if it doesn't pass.
|
||||
echo_test(ser_repl, ser_data)
|
||||
if not test_passed:
|
||||
return
|
||||
|
||||
# Do read and write throughput test.
|
||||
for test_func, test_args, bufsize in (
|
||||
(read_test, (), 256),
|
||||
(write_test, (True,), 128),
|
||||
|
||||
Reference in New Issue
Block a user