Ticket #17861: test_serial.py

File test_serial.py, 4.9 KB (added by bipolar, 20 months ago)

Updating the test script, as this version works more reliably and it's easier to use.

Line 
1"""
2Test serial port baudrates on multiple platforms.
3
4Requires:
5
6 - PySerial (`pip3 install {--user} pyserial`, or use `pkgman install pyserial`)
7 - A loopback wire (Rx<->Tx) on the serial port.
8
9For Haiku versions older than hrev56354:
10
11Due to bug https://dev.haiku-os.org/ticket/17861, you need to comment out
12line 344: "self._reset_input_buffer()" on PySerial's serialposix.py file.
13
14Normal test duration: < 20 seconds.
15
16For each tested baudrate:
17 - Write a string to the loopback port. Ensure all bytes get written.
18 - Split the reading back of that string on 3 parts, making sure that on each step:
19 - the read data is correct.
20 - the input buffer has the correct number of bytes left.
21
22Supossedly supported baudrates on each platform:
23
24Win32: 50 to 115200 bps - Confirmed working
25Linux: 50 to 4000000 bps - Confirmed working
26Haiku: 50 to 230400 bps - only 50 - 115200 seems to work.
27
28For Haiku versions older than hrev56354:
29 Make sure you don't call any function that call:
30 - termios.tcflush() - like serial.reset_input_buffer() and serial.reset_output_buffer()
31 - termios.tcdrain() - like serial.flush()
32 - termios.tcsendbreak() - like serial.send_break()
33"""
34
35import os
36import serial
37import sys
38import time
39
40#
41# Default port names. Used if not given on the command line
42#
43if sys.platform == 'win32':
44 PORT = 'COM1'
45elif sys.platform == 'linux':
46 PORT = '/dev/ttyS0'
47elif sys.platform == 'haiku1':
48 PORT = '/dev/ports/pc_serial0'
49else:
50 exit('unsupported platform')
51
52
53USAGE_TEXT = """Test serial ports read/write via a loopback cable.
54
55Usage:
56
57> test_serial.py [-h] [port] [baudrate]
58
59 -h Show this text and exit.
60 [port] Name of the port to test. Default: '%s'.
61 [baudrate] Baudrate to test. Tests all the supported ones if not given.
62""" % PORT
63
64
65TEST_STRING = b'Hello World!'
66TS_FIRST_HALF = TEST_STRING.split()[0]
67TS_SECOND_HALF = TEST_STRING.split()[-1]
68
69# print('Test strings:\n\t%s\n\t%s\n\t%s\n' % (TEST_STRING, TS_FIRST_HALF, TS_SECOND_HALF))
70
71def test(port, baudrates=None):
72 print('Testing port: %s.' % port)
73
74 with serial.Serial(port) as s:
75 if not s.isOpen():
76 exit('Could not open the serial port.')
77
78 if baudrates is None:
79 baudrates = s.BAUDRATES
80
81 for b in baudrates[::-1]:
82 # 230400 hangs on Haiku, and it doesn't supports setting custom baudrates on pc_serial.
83 if sys.platform == 'haiku1' and int(b) >= 230400:
84 continue
85
86 if (int(b) == 0):
87 print('Skipping tests for baudrate = 0 bps.')
88 continue
89
90 s.baudrate = b
91 s.bytesize = serial.SEVENBITS
92 s.timeout = 200000
93 assert s.baudrate == b, b
94 in_wating = s.in_waiting
95 assert in_wating == 0, in_wating
96
97 bytes_written = s.write(TEST_STRING)
98 # Give it time to send the data:
99 if sys.platform == 'linux':
100 # PySerial flush() calls tcdrain(). This is enough on Linux, as it blocks until all the
101 # bytes are written.
102 s.flush()
103 print('Testing baudrate: %d bps.' % b)
104 else:
105 # On Win32 flush() returns right away, so we need to wait an BPS appropiate time here
106 # (same on Haiku, at least for now):
107 s.flush()
108 print('Testing baudrate: %d bps.' % b, end='')
109 sleep_time = (1 / (b / 8) * bytes_written) * 2 # we need to write AND read, thus: time x 2.
110 if sys.version_info < (3, 11) and sleep_time < 0.001:
111 sleep_time = 0.001 # time.sleep() is not THAT precise on earlier Python versions.
112 print(' - Sleeping for %s seconds.' % sleep_time)
113 time.sleep(sleep_time)
114
115 assert bytes_written == len(TEST_STRING), bytes_written
116 in_waiting = s.in_waiting
117 assert in_waiting == bytes_written, '%d != %d' % (in_waiting, bytes_written)
118
119 data = s.read(len(TS_FIRST_HALF))
120 assert data == TS_FIRST_HALF, data
121 in_waiting = s.in_waiting
122 assert in_waiting == (len(TEST_STRING) - len(TS_FIRST_HALF)), in_waiting
123
124 # Eat away the expected ' ' separator.
125 data = s.read(1)
126 assert data == b' ', data
127
128 data = s.read(len(TS_SECOND_HALF))
129 assert data == TS_SECOND_HALF, data
130 in_waiting = s.in_waiting
131 assert in_waiting == 0, in_waiting
132
133
134if __name__ == '__main__':
135 port = PORT
136 baudrates = None
137
138 if len(sys.argv) > 1:
139 if '-h' in sys.argv:
140 print(USAGE_TEXT)
141 exit(0)
142
143 if os.path.exists(sys.argv[1]):
144 port = sys.argv[1]
145 elif sys.argv[1].isnumeric():
146 baudrates = [int(sys.argv[1])]
147 else:
148 exit('Couldn\'t find port "%s"' % sys.argv[1])
149
150 if len(sys.argv) > 2 and sys.argv[2].isnumeric():
151 baudrates = [int(sys.argv[2])]
152
153 test(port, baudrates)