80 lines
2.5 KiB
Python
Executable File
80 lines
2.5 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
import argparse
|
|
import sys
|
|
import time
|
|
import serial
|
|
|
|
def read_response(port: serial.Serial, timeout_s: float) -> list[str]:
|
|
deadline = time.monotonic() + timeout_s
|
|
lines: list[str] = []
|
|
|
|
while time.monotonic() < deadline:
|
|
raw = port.readline()
|
|
if not raw:
|
|
continue
|
|
|
|
line = raw.decode(errors="replace").strip()
|
|
if not line:
|
|
continue
|
|
|
|
lines.append(line)
|
|
if line in {"OK", "ERROR"}:
|
|
break
|
|
|
|
return lines
|
|
|
|
def send_at(port: serial.Serial, command: str, timeout_s: float) -> tuple[bool, list[str]]:
|
|
port.write((command + "\r").encode())
|
|
port.flush()
|
|
lines = read_response(port, timeout_s)
|
|
|
|
ok = any(line == "OK" for line in lines)
|
|
err = any(line == "ERROR" for line in lines)
|
|
return ok and not err, lines
|
|
|
|
def send_and_log(port: serial.Serial, command: str, timeout_s: float) -> tuple[bool, list[str]]:
|
|
ok, lines = send_at(port, command, timeout_s)
|
|
print(f"> {command}")
|
|
for line in lines:
|
|
print(f"< {line}")
|
|
return ok, lines
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(description="Control an AT modem and send DTMF tones")
|
|
parser.add_argument("device", help="Serial device path, e.g. /dev/ttyACM0")
|
|
parser.add_argument("--baud", type=int, default=115200, help="Serial baudrate (default: 115200)")
|
|
parser.add_argument("--timeout", type=float, default=2.0, help="AT command timeout seconds")
|
|
args = parser.parse_args()
|
|
|
|
try:
|
|
with serial.Serial(args.device, args.baud, timeout=0.2, write_timeout=1.0) as port:
|
|
port.reset_input_buffer()
|
|
port.reset_output_buffer()
|
|
|
|
# Inicialise
|
|
|
|
for cmd in ("AT", "ATZ0", "ATE1", "ATX0"):
|
|
ok, lines = send_and_log(port, cmd, args.timeout)
|
|
if not ok:
|
|
print(f"Modem did not accept {cmd}", file=sys.stderr)
|
|
return 1
|
|
|
|
send_and_log(port, "ATS6=0", args.timeout) # Set wait for dial tone time to 0
|
|
send_and_log(port, "ATS11=2", args.timeout) # set tone length to 1 ms
|
|
send_and_log(port, "ATH1", args.timeout)
|
|
while True:
|
|
send_and_log(port, "ATDT0123456789;", args.timeout)
|
|
send_and_log(port, "ATH0", args.timeout)
|
|
|
|
except serial.SerialException as exc:
|
|
print(f"Serial error: {exc}", file=sys.stderr)
|
|
return 1
|
|
|
|
print("Done")
|
|
return 0
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|