"""Read and decode CAN frames from the CANdapter (candapter.com) USB adapter. Usage: python read_can.py [--bitrate 500000] [--port /dev/cu.usbserial-DNBJV4F5] Connect the adapter to the CAN bus first, then run this script. It opens the channel at the given bitrate and prints every frame it receives: timestamp, arbitration ID (with an 'x' suffix for 29-bit extended IDs), DLC, raw bytes (hex), and an ASCII preview. If you don't know the bus's bitrate, common values are 125000, 250000, 500000 (most likely - the adapter is rated for automotive use at 500 kbps), and 1000000. Wrong bitrate usually means zero frames or garbled data -- try another value. """ import argparse import sys from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parents[1])) from adapters.candapter import Candapter # noqa: E402 DEFAULT_PORT = "/dev/cu.usbserial-DNBJV4F5" DEFAULT_BITRATE = 500000 def ascii_preview(data: bytes) -> str: return "".join(chr(b) if 32 <= b < 127 else "." for b in data) def main() -> int: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--port", default=DEFAULT_PORT, help="Serial device path") parser.add_argument("--bitrate", type=int, default=DEFAULT_BITRATE, help="CAN bus bitrate") args = parser.parse_args() try: adapter = Candapter(args.port, args.bitrate, timestamps=True) except (OSError, ValueError) as exc: print(f"Failed to open adapter on {args.port}: {exc}", file=sys.stderr) return 1 print(f"Listening on {args.port} at {args.bitrate} bps (Ctrl+C to stop)...\n") print(f"{'timestamp':>14} {'id':>10} {'dlc':>3} data (hex) ascii") try: with adapter: while True: frame = adapter.read_frame(timeout=None) if frame is None: continue id_str = f"{frame.arbitration_id:08X}x" if frame.is_extended else f"{frame.arbitration_id:03X}" data_hex = " ".join(f"{b:02X}" for b in frame.data) ts = frame.timestamp_ms if frame.timestamp_ms is not None else frame.recv_time print( f"{ts:14.3f} {id_str:>10} {len(frame.data):>3} " f"{data_hex:<24} {ascii_preview(frame.data)}" ) except KeyboardInterrupt: print("\nStopped.") return 0 if __name__ == "__main__": raise SystemExit(main())