| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879 |
- #!/usr/bin/env python3
- """Tiny TCP<->serial bridge for MUST PV1800 monitoring.
- Listens on 127.0.0.1:$PROXY_PORT, forwards every byte to/from $PROXY_TTY
- using pyserial. Multiple sequential TCP clients are served one at a time.
- """
- import os, sys, threading, time
- import serial, socket
- PORT = int(os.environ.get("PROXY_PORT", "9700"))
- TTY = os.environ.get("PROXY_TTY", "/dev/ttyUSB0")
- BAUD = int(os.environ.get("PROXY_BAUD", "19200"))
- def log(msg):
- print(f"[must-proxy] {msg}", file=sys.stderr, flush=True)
- try:
- # Pre-flush: read-and-discard whatever stale bytes are sitting in the
- # kernel TTY buffer from previous runs. Without this, those bytes get
- # delivered to the first client and corrupt its first read.
- pre = serial.Serial(TTY, BAUD, timeout=0.2)
- pre.reset_input_buffer()
- pre.reset_output_buffer()
- flushed = 0
- quiet_for = 0.0
- pre_start = time.monotonic()
- while time.monotonic() - pre_start < 3.0 and quiet_for < 0.3:
- chunk = pre.read(512)
- if chunk:
- flushed += len(chunk)
- quiet_for = 0.0
- else:
- quiet_for += 0.05
- time.sleep(0.05)
- pre.close()
- if flushed:
- log(f"flushed {flushed} stale bytes from kernel TTY buffer")
- ser = serial.Serial(TTY, BAUD, timeout=0.05)
- ser.reset_input_buffer()
- ser.reset_output_buffer()
- log(f"opened {TTY} @ {BAUD} fd={ser.fd}")
- except Exception as e:
- log(f"could not open {TTY}: {e}")
- sys.exit(1)
- def tty_to_tcp(client):
- while True:
- try:
- data = ser.read(256)
- if data:
- client.sendall(data)
- except Exception:
- return
- srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- srv.bind(("127.0.0.1", PORT))
- srv.listen(5)
- log(f"listening on 127.0.0.1:{PORT}")
- while True:
- client, addr = srv.accept()
- log(f"client {addr}")
- threading.Thread(target=tty_to_tcp, args=(client,), daemon=True).start()
- try:
- while True:
- data = client.recv(4096)
- if not data:
- break
- ser.write(data)
- ser.flush()
- except Exception as e:
- log(f"tcp err: {e}")
- try:
- client.close()
- except Exception:
- pass
- log(f"client closed")
|