Y334275 commented on PR #21761:
URL: https://github.com/apache/nuttx/pull/21761#issuecomment-6816717165

   ## Host-side test script
   
   This is the script used for the TX/RX and reconnect runs. It is not part
   of the NuttX tree; run it on the host that owns the CDC ACM port.
   
   ```python
   #!/usr/bin/env python3
   """Host-side TX/RX reconnect test for the mavlink_otg target.
   
   TX check: HEARTBEAT custom_mode must keep increasing.
   RX check: PARAM_REQUEST_LIST must return PARAM_VALUE frames.
   
   Requires pyserial.  Run it on the host that owns the CDC ACM port:
   
       python otg_host_test.py --port COMx --cycles 20
       python3 otg_host_test.py --port /dev/ttyACM0 --cycles 20
   """
   
   import argparse
   import time
   
   import serial
   
   MAV_MAGIC = 0xFD
   MSG_HEARTBEAT = 0
   MSG_PARAM_REQUEST_LIST = 21
   MSG_PARAM_VALUE = 22
   CRC_EXTRA_PARAM_REQUEST_LIST = 159
   
   
   def crc_accumulate(crc, data):
       tmp = data ^ (crc & 0xFF)
       tmp = (tmp ^ (tmp << 4)) & 0xFF
       return ((crc >> 8) ^ (tmp << 8) ^ (tmp << 3) ^ (tmp >> 4)) & 0xFFFF
   
   
   def request_frame(seq):
       payload = bytes((1, 1))
       header = bytes((len(payload), 0, 0, seq & 0xFF, 255, 190,
                       MSG_PARAM_REQUEST_LIST, 0, 0))
       crc = 0xFFFF
       for byte in header + payload:
           crc = crc_accumulate(crc, byte)
       crc = crc_accumulate(crc, CRC_EXTRA_PARAM_REQUEST_LIST)
       return bytes((MAV_MAGIC,)) + header + payload + bytes(
           (crc & 0xFF, crc >> 8))
   
   
   def parse_frames(data):
       frames = []
       i = 0
       while i + 12 <= len(data):
           if data[i] != MAV_MAGIC:
               i += 1
               continue
           payload_len = data[i + 1]
           frame_len = 10 + payload_len + 2
           if i + frame_len > len(data):
               break
           msgid = data[i + 7] | (data[i + 8] << 8) | (data[i + 9] << 16)
           frames.append((msgid, data[i + 10:i + 10 + payload_len]))
           i += frame_len
       return frames
   
   
   def read_for(ser, seconds, quiet=0.3):
       data = b""
       last = time.time()
       end = last + seconds
       while time.time() < end:
           chunk = ser.read(4096)
           if chunk:
               data += chunk
               last = time.time()
           elif time.time() - last > quiet:
               break
       return data
   
   
   def open_port(port, baud):
       deadline = time.time() + 5.0
       while True:
           try:
               return serial.Serial(port, baud, timeout=0.1)
           except serial.SerialException:
               if time.time() > deadline:
                   raise
               time.sleep(0.2)
   
   
   def main():
       parser = argparse.ArgumentParser()
       parser.add_argument("--port", default="/dev/ttyACM0")
       parser.add_argument("--baud", type=int, default=115200)
       parser.add_argument("--cycles", type=int, default=20)
       args = parser.parse_args()
   
       failures = 0
       last_counter = None
   
       for cycle in range(args.cycles):
           try:
               ser = open_port(args.port, args.baud)
               time.sleep(0.3)
   
               # Host connects: observe TX without sending anything.
               tx_data = read_for(ser, 1.0)
               heartbeats = []
               for msgid, payload in parse_frames(tx_data):
                   if msgid == MSG_HEARTBEAT and len(payload) >= 9:
                       heartbeats.append(int.from_bytes(payload[0:4], "little"))
   
               # Host requests parameters.
               ser.write(request_frame(cycle))
               rx_data = read_for(ser, 1.0)
               params = sum(1 for msgid, _ in parse_frames(rx_data)
                            if msgid == MSG_PARAM_VALUE)
               ser.close()
           except Exception as exc:  # noqa: BLE001
               print("cycle %d: ERROR %s" % (cycle, exc))
               failures += 1
               time.sleep(0.3)
               continue
   
           tx_ok = len(heartbeats) >= 5
           tx_seq_ok = True
           if heartbeats:
               if last_counter is not None and heartbeats[0] <= last_counter:
                   tx_seq_ok = False
               last_counter = heartbeats[-1]
   
           rx_ok = params >= 14
           ok = tx_ok and tx_seq_ok and rx_ok
   
           tx_range = ("%d..%d" % (heartbeats[0], heartbeats[-1])
                       if heartbeats else "none")
           print("cycle %d: tx_hb=%d tx_seq=%s params=%d %s"
                 % (cycle, len(heartbeats), tx_range, params,
                    "OK" if ok else "FAIL"))
           if not ok:
               failures += 1
   
           # Host disconnects; the port is already closed above.
           time.sleep(0.3)
   
       print("failures=%d/%d" % (failures, args.cycles))
       return 1 if failures else 0
   
   
   if __name__ == "__main__":
       raise SystemExit(main())
   ```
   
   Usage:
   
   ```bash
   python otg_host_test.py --port COMx --cycles 20
   # or
   python3 otg_host_test.py --port /dev/ttyACM0 --cycles 20
   ```
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to