Overview

The gateway's serial ports emulate a Hayes Smartmodem. A vintage computer drives them with the same AT commands it would send a real modem — except a “dial” opens a TCP connection instead of a phone call.

Each of the two serial ports, when in Modem (AT Command) Mode, presents a Hayes-compatible command interface. Your retro machine's terminal program talks to it exactly as if it were a Smartmodem 2400 or compatible: type AT commands in command mode, “dial” to open a connection, exchange data in online mode, and use the +++ escape to slip back to command mode without dropping the link. There is no phone line — ATDT host:port is a TcpStream::connect().

Command basics
  • Every command line begins with the attention prefix AT (or at — commands are case-insensitive) and ends with a carriage return.
  • The lone exception is A/, which repeats the last command with no AT and no carriage return.
  • The modem answers with a result codeOK, CONNECT, ERROR, etc. — in words (verbose) or as a digit (numeric), controlled by ATV.
  • Several commands can be chained on one line (ATE0Q0V1); see Command Chaining.
  • Numeric command parameters default to 0 when omitted: ATH = ATH0, ATE = ATE0.
  • Settings are held in RAM; AT&W persists them to egateway.conf and ATZ reloads that saved profile.
Where these apply: AT commands work on either serial port while it is in modem mode, and on the ATDT ethernet-gateway loopback. Each port keeps its own independent AT / S-register state and its own AT&W profile (serial_a_* / serial_b_*). For the hardware-setup and menu walkthrough, see the Serial Modem section of the User Manual.

Core Commands
CommandEffect
ATAttention / line check. Returns OK — the classic “is the modem there?” probe.
A/Repeat the last command line. No AT prefix, no carriage return — the modem acts the instant it sees the slash. Handy for re-dialing.
AT?Print the built-in AT command help.
ATZReset to the stored profile (the last AT&W, read from egateway.conf). Drops any active connection.
AT&FRestore the gateway-friendly factory defaults. Does not overwrite the stored profile, but does drop any active connection.
AT&W / AT&W0Save the current settings (echo, verbose, quiet, all 27 S-registers, X, &C, &D, &K, +PETSCII, and the four stored numbers) to egateway.conf.
AT&VDisplay the current configuration — a line of mode flags, a line of all S-registers, and a line of stored numbers.
ATH / ATH0Hang up — close any active connection and return to command mode.
ATAAnswer an incoming “call” (a ring from the Ring Emulator) immediately, before S0 rings elapse.
ATO / ATO0Return to online (data) mode after a +++ escape, resuming the preserved connection.

Identification (ATI)

The ATIn family reports product and firmware strings — some terminal programs probe these to recognise the modem.

CommandResponse
ATI / ATI0Hayes-compatible Ethernet Gateway Modem Emulator v0.6.2
ATI1000 — ROM checksum (virtual)
ATI2OK — ROM self-test
ATI3Ethernet Gateway v0.6.2 (Hayes-compatible)
ATI4Hayes-compatible virtual modem over TCP
ATI5B00 — OEM / country code
ATI6No link diagnostics available
ATI7Product: ethernet-gateway (software emulator)

Echo, Result Codes & ATX Levels
Echo / verbosity / quiet
CommandEffect
ATE0 / ATE1Command echo off / on. Default on. Turn it off (ATE0) for scripted init strings so you don't see your own typing echoed back.
ATV0 / ATV1Result codes as numeric digits / verbose words. Default verbose.
ATQ0 / ATQ1Result codes enabled / suppressed (quiet). Default enabled. ATQ1 silences all result codes — useful when a program is confused by them.
Result codes

In verbose mode the modem returns the word; in numeric mode (ATV0) the digit. Which codes can appear depends on the ATX level (below).

VerboseNumericMeaning
OK0Command accepted.
CONNECT1Connected (no speed reported — X0, or a non-standard rate).
RING2An incoming call is ringing.
NO CARRIER3Connection failed, ended, or was refused.
ERROR4Command not understood or out of range.
CONNECT <baud>5/10/12/16/28/87Connected, with speed (X1+). Codes: 1200=5, 2400=10, 9600=12, 19200=16, 38400=28, 115200=87, 300=1.
NO DIALTONE6Only at X2 and above; otherwise folds into NO CARRIER.
BUSY7Only at X3 and above; otherwise NO CARRIER.
NO ANSWER8Only at X3 and above; otherwise NO CARRIER.
ATX result-code level
CommandExtended codesCONNECT format
ATX0Basic only; BUSY / NO DIALTONE / NO ANSWER all collapse to NO CARRIERCONNECT (no baud)
ATX1Basic + speed reportingCONNECT <baud>
ATX2Adds NO DIALTONECONNECT <baud>
ATX3Adds BUSY / NO ANSWERCONNECT <baud>
ATX4 (default)Full extended setCONNECT <baud>

Hardware Pin State (&C, &D, &K)
CommandMeaning
AT&C0DCD (carrier-detect) always asserted.
AT&C1 (Hayes default)DCD reflects the connection state.
AT&D0 (gateway default)Ignore DTR entirely.
AT&D1DTR drop → return to command mode.
AT&D2 (Hayes default)DTR drop → hang up.
AT&D3DTR drop → hang up and reset.
AT&K0 (gateway default)No modem-layer flow control.
AT&K1Auto-detect (accepted and stored; no wire-level effect).
AT&K3Bidirectional RTS/CTS hardware flow control.
AT&K4Bidirectional XON/XOFF software flow control.
Gateway-friendly default deviations. The emulator ships with &D0 (not &D2) and &K0 (not &K3) because many C64 / CP/M clients don't wire DTR or implement flow control — the Hayes defaults would cause spurious disconnects. S7 is also lowered to 15 s. All are overridable (AT&D2, AT&K3, ATS7=50) and persist with AT&W.
Signal pins are not physically driven. &C, &D, and &K are parsed, stored, persisted, and shown by AT&V, but the emulator does not toggle the real RS-232 DCD / DTR / DSR / RI pins. Actual wire flow control is set by each port's serial_x_flowcontrol config key, not by &K. If your terminal program insists on DCD before it will talk, look for its “ignore carrier” / “force DTR” option.

AT+PETSCII — Commodore Translation

A gateway-specific vendor extension that makes ASCII BBSes readable on a PETSCII Commodore when you dial them directly over TCP.

CommandEffect
AT+PETSCII=0 (default)Off — direct-TCP dials (ATDT host:port) are raw ASCII passthrough.
AT+PETSCII=1On — translate between PETSCII and ASCII on direct-TCP dials.

With AT+PETSCII=1, on a direct-TCP dial the emulator:

  • Case-swaps letters in both directions, because a C64 in upper/graphics mode maps the cases opposite to ASCII — so an ASCII BBS like telehack.com reads in the right case.
  • Maps ASCII Backspace ↔ PETSCII Delete (0x14) so the C64 INST/DEL key edits correctly, including while you type the AT command line itself.
  • Strips inbound ANSI escape sequences (ESC [ … cursor / colour codes) so they don't spray as garbage on a screen that can't render them.
  • Normalizes punctuation the C64 can't show: the back-tick and UTF-8 “smart” single quotes fold to ', smart double quotes to ", tilde / en- / em-dashes to -, the ellipsis to ...; other undisplayable high bytes are dropped or shown as ?.
Notes. It applies only to direct-TCP dials — ATDT ethernet-gateway already detects PETSCII terminals through the telnet menu and renders accordingly. It is set-only (=0/=1), persists immediately (and re-saves with AT&W), reloads on ATZ, resets to off on AT&F, and is reported by AT&V as +PETSCII:n. It lives in the ITU-T V.250 + extended-command namespace (not AT&P, which means pulse-dial ratio on real modems). Also editable from the telnet, web, and GUI config surfaces.

Dialing & Stored Numbers

A “dial” is a TCP connect. The dial string is a host:port, a stored slot, or a phone number mapped in dialup.conf.

CommandEffect
ATDT host:portTone-dial — open a TCP connection to host:port. The default for all TCP dials.
ATDP host:portPulse-dial — identical to ATDT over TCP (there's no audible difference).
ATD host:portGeneric dial (no T/P selector).
ATDT ethernet-gatewayBuilt-in shortcut — “dial” this gateway's own main menu, so the serial device gets file transfer, browser, AI chat, etc. with no network detour.
ATDT KERMITDrop straight into Kermit server mode (aliases: kermit, kermit-server, kermit server). Requires allow_atdt_kermit = true; off by default. See the Kermit Reference.
ATDLRedial the last number.
ATDS / ATDSnDial the stored number in slot n (0–3; bare ATDS = slot 0).
AT&Zn=sStore phone number or host:port string s in slot n (0–3). Hostname case is preserved. Persisted with AT&W.
Dial-string modifiers

Honoured only when the dial string looks like a phone number (digits + formatting). A hostname such as pine.example.com is dialled verbatim — modifiers are not stripped from it (except a trailing ;).

ModifierEffect
,Pause S8 seconds (default 2) per comma before continuing.
WWait for dial tone — adds S6 seconds to the pre-delay.
;Return to command mode after connect instead of going online (applies to hostnames too).
* #DTMF digits — preserved in the dial target for dialup.conf lookup.
P T @ !Pulse / tone / quiet-answer / hookflash selectors — accepted and ignored.
Phone-number mapping. An all-digit dial string is looked up in dialup.conf (digits only — dashes, spaces, and parens are ignored), which maps numbers to host:port targets. The built-in entry 1001000 always reaches the local gateway menu and can't be deleted. An unmapped number returns NO CARRIER.

S-Registers

S-registers hold numeric timing and behaviour parameters. Query with ATSn?, set with ATSn=v (0–255), list help with ATS?. AT&W saves all 27; ATZ restores them; AT&F resets to factory.

RegDefaultMeaning
S05Auto-answer ring count (0 = don't auto-answer).
S10Ring counter (read-only).
S243Escape character (43 = +). Values > 127 disable the +++ escape.
S313Carriage-return character.
S410Line-feed character.
S58Backspace character.
S62Wait-for-dial-tone seconds (the W modifier).
S715Wait-for-carrier seconds. Hayes default is 50; lowered here so failed TCP dials return fast. Capped internally at 60.
S82Comma pause time (seconds).
S96Carrier-detect response time (1/10 s).
S1014Carrier-loss disconnect time (1/10 s).
S1195DTMF tone duration (ms).
S1250Escape guard time (1/50 s; 50 = 1.0 s). 0 disables the escape.
S13–S240Reserved placeholders — stored and persisted so legacy init strings don't error, but with no effect.
S255DTR detect time (1/100 s). Reserved — no DTR pin.
S261RTS-to-CTS delay (1/100 s). Reserved — no RTS/CTS pins.
Keep S3 / S4 / S5 distinct. Command-mode line editing dispatches on the raw byte and checks the CR branch before the backspace branch — so setting S3 = 8 would make backspace terminate the line. The Hayes defaults (13 / 10 / 8) are safe; leave them be.

The +++ Escape Sequence

How to get back to command mode without hanging up.

While online (passing data), typing +++ framed by a guard time of silence on both sides drops you to command mode with the connection still alive. From there, ATO resumes the data session and ATH hangs up. This is the exact Hayes guard-time behaviour:

  • The escape character is S2 (default 43 = +).
  • The guard time is S12 / 50 seconds (default S12 = 50 → 1.0 s) of silence required both before the first + and after the third.
  • Setting S12 = 0, or S2 > 127, disables escape detection entirely.
  • Exactly three escape characters are required — fewer or more pass through as data.
  • Any non-escape byte sent in the middle cancels the sequence (it's treated as data).
(online, exchanging data)
   ...wait ~1 second of silence...
+++
   ...wait ~1 second of silence...
OK                       now in command mode, link preserved
ATO                      resume the data session
   -- or --
ATH                      hang up for good
Escape won't trigger on bit-banged C64 serial? A stray byte picked up while “idle” resets the guard timer. Lower S12 (e.g. ATS12=25 for a half-second guard) to tighten the window, or enable the gateway byte-trace (EGATEWAY_GATEWAY_DEBUG) to see exactly what broke it.

Command Chaining & Unknown Commands

Multiple commands can ride on a single AT line, the way real Hayes modems accept init strings. The emulator parses left-to-right, applies each subcommand, and emits a single OK at the end (or ERROR at the first failure — subcommands before the failure still apply; those after do not run). Spaces between subcommands are tolerated.

Some subcommands terminate the chain because they consume the rest of the line or leave command mode:

  • D… — any dial command goes online and consumes the rest of the line.
  • A — answer; leaves command mode.
  • O / O0 — return to online mode.
  • &Zn=… — the stored-number value runs to end of line.

S-register set values stop at the first non-digit, so ATS0=2E0 sets S0=2 then turns echo off — no separator needed.

Unknown commands return OK. Commands the emulator has no hardware to implement — ATB, ATC, ATL (speaker volume), ATM (speaker), AT&B, AT&G, AT&J, AT&S, AT&T, AT&Y, and the like — are silently accepted with OK so legacy init strings run to completion instead of halting mid-setup with ERROR.

Worked Examples

Common things you'll actually type. Lines without a result code shown assume verbose mode (the default).

Check the modem and connect to a BBS
AT                       OK
ATDT bbs.example.com:23
CONNECT 9600
(you're online — the BBS appears)
Reach this gateway's own menu
ATDT ethernet-gateway
CONNECT 9600
(the Ethernet Gateway main menu appears)
Store a favourite and redial it
AT&Z0=bbs.example.com:23   OK
AT&W                        OK   (persist it)
ATDS0                       CONNECT 9600
A typical init string (chained, one OK)
ATE0Q0V1X4               OK
(echo off, result codes on, verbose, full extended codes)
Escape to command mode, then resume or hang up
+++                      OK   (still connected)
ATO                      CONNECT 9600   (back online)
...or...
ATH                      NO CARRIER   (hung up)
Tune behaviour with S-registers
ATS0=2                   OK   (auto-answer after 2 rings)
ATS7=50                  OK   (wait up to 50s for a slow connect)
ATS0?                    002  (query: 3-digit decimal)
AT&W                     OK   (persist)
Dial an ASCII BBS from a Commodore 64
AT+PETSCII=1             OK   (translate ASCII ↔ PETSCII)
ATDT telehack.com:23
CONNECT 9600
(text now reads in the correct case on the C64)
Re-issue the last command
ATDT bbs.example.com:23
NO CARRIER   (busy — try again)
A/                       (repeats the dial, no AT/Enter needed)

See Also
The Serial Modem section of the User Manual covers port setup, modes, the Ring Emulator, and Console Mode. For file transfers over a dialed connection, see the XMODEM, YMODEM, ZMODEM, and Kermit references.

References

Deep-dive reference pages for every protocol and interface, plus the character-set tables and ANSI escape-sequence reference.

XMODEM

128-byte blocks; CRC-16 / checksum negotiation.

YMODEM

Block-0 metadata, batch, exact size truncation.

ZMODEM

Streaming; ZDLE, CRC-32, autostart, resume.

Kermit

Send-Init negotiation; F / A / D / Z / B transfer.

Punter

C1 dual checksum, two-phase, GOO/BAD/ACK.

AT Commands (this page)

Hayes command set, S-registers, +++ escape.

Telnet

IAC negotiation, every option, the NVT data phase.

SSH

Server, gateway, host keys, TOFU, auth modes.

Character Code Tables

Hex tables for every encoding: ASCII, ANSI, PETSCII, ATASCII, Baudot/ITA2, ZX Spectrum, TRS-80.

ANSI Escape Sequences

Cursor, colour/SGR, erase, and screen-mode escape codes, with the raw hex bytes.