我有一个设置,其中 Raspberry Pi 4 通过 5 个 USB 串行转换器连接到 USB 集线器 (https://www.dfrobot.com/product-104.html)
每个转换器都连接到基于 STM32 的设备。这些设备还通过 USB 转换器供电。这些设备消耗的电量并不多,USB 转换器还连接有外部电源。
我正在尝试使用 pytest 在设备上运行自动化测试。测试将命令写入设备并等待响应。设备相互交互,因此命令大致同时发送到许多设备。
如果测试是逐个手动运行的,那么设置似乎工作正常,但是当一起运行所有测试时(pytest 仍然串行运行它们,因此串行端口上的竞争条件不应该发生)第一个总是成功,但其余的似乎非常随机地失败。不过,随机性并不完全随机,因为如果我更改代码中的延迟,测试会以不同的方式失败,但如果不进行任何更改,则测试总是会以相同的方式失败。
所有端口和所有设备都被证明可以工作(有些测试使用所有设备和端口并且已经通过了很多次),因此接线应该没问题并且USB串行转换器正在工作。
我做了一些调试,注意到测试确实写入了串行端口,但有时物理线路上没有任何内容(用示波器检查)。因此,在 pytest/python 端,写入似乎成功,但线路中仍然没有数据流。这种情况仅有时发生,在某些测试/延迟配置中存在数据流动,因此范围设置也应该没问题。
这是串行数据初始化和传输的片段:
class Link_Serial(linkcore.LinkCore):
def __init__(self, comport, packet_queue, ack_queue, id_queue, link_address):
super().__init__(packet_queue, ack_queue, id_queue, link_address)
self.serial = serial.Serial(port=comport, baudrate=115200)
self.rx_buffer = []
self.received_packets = []
self.events = []
def on_transmit(self, tx_data):
print("TX", self.serial.name, self.serial.is_open, tx_data)
time.sleep(0.02)
self.serial.write(tx_data)
self.tx_done()
return 1
def reset(self):
self.rx_buffer.clear()
self.received_packets.clear()
self.events.clear()
self.serial.reset_input_buffer()
self.serial.reset_output_buffer()
super().reset()
稍微更改 time.sleep(...) 值会导致不同的测试失败
以下是 pytest 初始化测试对象的方式:
def get_module_n(n):
if n >= len(modules) or n < 0:
raise
if radios[n] is None:
info = modules[n]
radios[n] = Link_Serial(...)
radios[n].reset()
return radios[n]
def stop_module(radio):
radio.power_off()
radio.reset()
...
@pytest.fixture
def radio0():
ctrl = rack.get_module_n(0)
yield ctrl
rack.stop_module(ctrl)
@pytest.fixture
def radio1():
ctrl = rack.get_module_n(1)
yield ctrl
rack.stop_module(ctrl)
...
这是一个对时间非常敏感的示例测试:
def test_many_senders_one_receiver(radio0, radio1, radio2, radio3, radio4):
time.sleep(0.1)
radio0.power_on()
radio1.power_on()
radio2.power_on()
radio3.power_on()
radio4.power_on()
time.sleep(0.1)
message = [1, 2, 3, 4, 5, 6]
for radio in [radio1, radio2, radio3, radio4]:
radio.send_packet(radio0.id, message)
for _ in range(0, 1000):
rack.run_links([radio0, radio1, radio2, radio3, radio4], 10)
if radio0.get_events().count(LINK_DATA_RECEIVED) == 4:
break
assert LINK_DATA_ACKED in radio1.get_events()
print(radio2.get_events())
assert LINK_DATA_ACKED in radio2.get_events()
assert LINK_DATA_ACKED in radio3.get_events()
assert LINK_DATA_ACKED in radio4.get_events()
assert radio0.get_events().count(LINK_DATA_RECEIVED) == 4
assert len(radio0.get_packets()) == 4
最初我有它,以便 pytest 为每个测试初始化一个新对象,但只有第一个测试成功(手动运行时所有测试都工作正常)。这样,对象就会初始化一次,并且仅在测试之间重置。
事实证明,如果串行转换器有故障的话。工作了一段时间,然后就不再工作了。 另外,我的代码中的一个错误导致一些消息延迟了很长时间。这些问题加在一起使得问题非常难以调试。