#!/usr/bin/env python3 """Class 1 Fax Receiver - for testing with USR sender""" import termios import os import time import sys def main(): if len(sys.argv) < 2: print("Usage: class1_receive.py ") sys.exit(1) device = sys.argv[1] fd = os.open(device, os.O_RDWR | os.O_NOCTTY | os.O_NONBLOCK) attrs = termios.tcgetattr(fd) attrs[4] = termios.B115200 attrs[5] = termios.B115200 attrs[2] |= termios.CLOCAL | termios.CREAD attrs[3] &= ~termios.ICANON attrs[3] &= ~termios.ECHO attrs[3] &= ~termios.ECHOE attrs[3] &= ~termios.ISIG termios.tcsetattr(fd, termios.TCSANOW, attrs) termios.tcflush(fd, termios.TCIOFLUSH) def drain(): try: while True: os.read(fd, 4096) except BlockingIOError: pass def send_cmd(cmd, wait=0.5): drain() os.write(fd, cmd.encode() + b"\r") time.sleep(wait) result = b"" try: while True: data = os.read(fd, 4096) result += data except BlockingIOError: pass return result.decode(errors="replace") def wait_for(pattern, timeout=30): start = time.time() result = b"" while time.time() - start < timeout: try: data = os.read(fd, 4096) result += data decoded = result.decode(errors="replace") for p in pattern if isinstance(pattern, list) else [pattern]: if p in decoded: return decoded except BlockingIOError: time.sleep(0.1) return result.decode(errors="replace") print("[RECV] Initializing Class 1...") send_cmd("AT", 0.3) send_cmd("AT+FCLASS=1", 0.3) print("[RECV] Waiting for rings...") ring_count = 0 while ring_count < 2: try: data = os.read(fd, 4096) text = data.decode(errors="replace") if "RING" in text: ring_count += text.count("RING") print(f"[RECV] Ring {ring_count}") except BlockingIOError: time.sleep(0.3) print("[RECV] Answering...") answer_result = send_cmd("ATA", 3) print(f"[RECV] ATA result: {answer_result.strip()}") if "CONNECT" not in answer_result: drain() os.write(fd, b"ATA\r") wait_result = wait_for("CONNECT", 10) print(f"[RECV] Wait result: {wait_result.strip()}") print("[RECV] Connected! Sending CED tone...") time.sleep(0.5) # Send CED tone (2100Hz for 2.6-4 seconds) ced_result = send_cmd("AT+FTS=8", 4) # FTS=8 sends 2100Hz print(f"[RECV] CED result: {ced_result.strip()}") # Wait 75ms then send DIS time.sleep(0.1) print("[RECV] Sending DIS frame...") # Start HDLC transmit os.write(fd, b"AT+FTH=3\r") fth_result = wait_for("CONNECT", 5) print(f"[RECV] FTH=3: {fth_result.strip()}") if "CONNECT" in fth_result: # DIS frame: preamble+flags+DCS+data+RTC # Address: 0xFF (broadcast), Control: 0x80 (DIS from called) # DIS data: minimum capabilities dis_data = bytes([ 0xFF, 0x13, 0x80, # Address + Control (DIS from called) 0x00, 0x50, 0x1F, # DIS parameters ]) # Add FCS (we'll let modem calculate) os.write(fd, dis_data) os.write(fd, b"\x00\x00\x00") # Padding time.sleep(0.5) # Wait for OK dis_ok = wait_for("OK", 5) print(f"[RECV] DIS sent: {dis_ok.strip()}") print("[RECV] Waiting for DCS...") drain() os.write(fd, b"AT+FRH=3\r") dcs_result = wait_for("OK", 10) print(f"[RECV] DCS received: {len(dcs_result)} bytes") print("[RECV] Waiting for TCF...") drain() os.write(fd, b"AT+FRM=96\r") # Receive at 14400 bps tcf_result = wait_for("CONNECT", 5) print(f"[RECV] TCF: {tcf_result.strip()}") # Send CFR print("[RECV] Sending CFR...") drain() os.write(fd, b"AT+FTH=3\r") wait_for("CONNECT", 5) cfr_data = bytes([0xFF, 0x13, 0x21]) # CFR frame os.write(fd, cfr_data) os.write(fd, b"\x00\x00\x00") time.sleep(0.5) wait_for("OK", 5) print("[RECV] CFR sent") print("[RECV] Waiting for page data...") # Receive page drain() os.write(fd, b"AT+FRM=96\r") page_result = wait_for("OK", 60) print(f"[RECV] Page received!") # Send MCF print("[RECV] Sending MCF...") drain() os.write(fd, b"AT+FTH=3\r") wait_for("CONNECT", 5) mcf_data = bytes([0xFF, 0x13, 0x31]) # MCF frame os.write(fd, mcf_data) os.write(fd, b"\x00\x00\x00") time.sleep(0.5) wait_for("OK", 5) print("[RECV] MCF sent") # Wait for DCN or hangup print("[RECV] Waiting for DCN...") drain() os.write(fd, b"AT+FRH=3\r") dcn_result = wait_for("OK", 10) print(f"[RECV] Session ended: {dcn_result[:50]}") os.close(fd) print("[RECV] Done!") if __name__ == "__main__": main()