Not every machine has FOCAS or an Ethernet port. Plenty of the machines still earning their keep predate all of that — and they run fine. What they do have is an RS-232 serial port, and Python talks to it fluently through the pyserial library. If you can plug in a serial cable, you can read programs off that control, push programs to it, and back the whole thing up to a database.
The setup
- A serial connection — a USB-to-RS-232 adapter and the right cable (often a null-modem) to the control's port.
- Matching settings — baud rate, data bits, parity, and stop bits must match the control's config exactly, or you get garbage.
- Handshaking — the flow-control method (software XON/XOFF or hardware RTS/CTS) also has to match. This is where most people get stuck.
import serial
# settings must match the control's I/O config exactly
port = serial.Serial(
port='COM3',
baudrate=9600,
bytesize=serial.SEVENBITS,
parity=serial.PARITY_EVEN,
stopbits=serial.STOPBITS_TWO,
xonxoff=True, # software handshaking
timeout=2,
)
# send a program to the control (it must be in receive/punch mode)
with open('O1234.nc', 'rb') as f:
port.write(f.read())
port.close()That's the whole idea. Open the port with settings that match the control, then read or write bytes. Receiving a program is the mirror image: put the control in punch/output mode and port.read() until it stops sending.
Handshaking is where DNC dies
If the control and your PC disagree on flow control, you'll drop characters mid-transfer — and a G-code program with a dropped character is a crash waiting to happen. Match XON/XOFF vs RTS/CTS before you trust a single transfer, and always verify the program on the control after sending.
Drip-feeding (DNC) a program too big for memory
The classic reason to write your own serial code: a program too large for the control's memory. You drip-feed it — stream the file line by line while the machine runs, so the control only ever holds a small buffer. Old controls do this every day; a few dozen lines of pyserial with correct handshaking reproduces it, and now you control the pipeline.
Why bother in 2026
Because those machines aren't going anywhere, and the programs on them are institutional memory. Reading them off the control lets you back them up, diff them, search them, and pull them into the same database as your modern machines — so a 1995 lathe and a 2024 5-axis finally live in one system. Old iron, modern pipeline.
The machine doesn't care what year it is. If it has a serial port, it has an API — you just have to speak its baud rate.
Bridging legacy machines into a central system is one of the highest-ROI, lowest-glamour jobs in a shop. If you've got a fleet of older controls and no way to see them, let's talk.


