"""CLI entry point for the car<->EPS gateway (headless, no GUI). Usage: python gateway/run_gateway.py \\ --car-port /dev/cu.usbserial-DNBJV4F5 --car-bitrate 500000 \\ --eps-port /dev/cu.usbmodemXXXX --eps-bitrate 500000 \\ [--block 0x1D6 0x380] [--log captures/gateway_log.csv] Starts fully transparent (every frame relayed both ways) unless --block is given. For interactive control (toggle IDs while it's running, live monitor), use gateway/gateway_app.py (Streamlit) instead. """ import argparse import sys import time from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parents[1])) from adapters.candapter import Candapter # noqa: E402 from adapters.slcan_adapter import SlcanAdapter # noqa: E402 from gateway.gateway import Gateway, GatewayLogger # noqa: E402 from gateway.rules import FilterRules # noqa: E402 DEFAULT_CAR_PORT = "/dev/cu.usbserial-DNBJV4F5" def main() -> int: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--car-port", default=DEFAULT_CAR_PORT) parser.add_argument("--car-bitrate", type=int, default=500_000) parser.add_argument("--eps-port", required=True, help="Serial port of the CAN-IO board's USB bridge") parser.add_argument("--eps-bitrate", type=int, default=500_000) parser.add_argument("--block", nargs="*", default=[], help="Arbitration IDs (hex) to block in BOTH directions") parser.add_argument("--log", default=None, help="CSV path to log every frame seen (relayed or not)") args = parser.parse_args() car = Candapter(args.car_port, args.car_bitrate, timestamps=True) eps = SlcanAdapter(args.eps_port, args.eps_bitrate) car_to_eps = FilterRules() eps_to_car = FilterRules() for tok in args.block: aid = int(tok, 16) car_to_eps.set_allow(aid, False) eps_to_car.set_allow(aid, False) logger = GatewayLogger(Path(args.log)) if args.log else None gw = Gateway(car, eps, car_to_eps, eps_to_car, logger=logger) gw.start() print(f"Gateway running: car({args.car_port}) <-> eps({args.eps_port}). Ctrl+C to stop.") try: while True: time.sleep(2) passed, blocked = gw.stats.snapshot() print(f"passed IDs: {len(passed)} blocked IDs: {len(blocked)} " f"total passed: {sum(passed.values())} total blocked: {sum(blocked.values())}") except KeyboardInterrupt: pass finally: gw.stop() car.close() eps.close() return 0 if __name__ == "__main__": raise SystemExit(main())