'AT' (Hayes) Serial Modem Operation Manual (Draft)
Unlike the VT100 terminal, the modem does not try to faithfully emulate any particular original device.
Instead it is designed to provide an MVP (minimum viable product) providing a modified Hayes 'AT' compatible command set for connecting over Wi-Fi via TCP/IP sockets with an optional Telnet protocol layer.
Although later standardized by the TIA/EIA, in the early days of dialup modems the 'AT' command set of the Hayes SmartModem was copied by other modem makers and became a de-facto standard or rather a convention, as other modem manufacturers took the liberty to alter and extend the 'AT' command set. The same applied to the so called 'S' Registers where settings and configuration are made and saved to non-volatile storage (NVS).
See Hardware Configuration for details on connecting from a UART on your system to the modem.
The original 'AT' command set was strictly in upper case. This is because the bit sequence of the ASCII values for 'A' and 'T' have a specific property that enables autobaud detection of the connection to the data terminal equipment (DTE).
- The modem only responds to 'AT' commands in upper case.
- Commands are terminated by
0x0D, decimal 13) usually generated by the
Returnkey on your keyboard.
- Commands can by edited, before pressing
0x08decimal 8) to erase the previous character entered. You may need to configure the terminal to generate
<BS>when you press the
<-key on your keyboard.
The 'AT' command processor is based on a finite state machine (FSM). If you type anything that is not recognized by the rules of the FSM you will immediately see an
'AT' Command Help
AT$ when connected to the modem will result in the following 'AT' command summary being returned by the modem.
- All commands must be prefixed with
ATexcept for the immediate command
- Commands can be concatenated into a single command string, except in the cases where the command accepts all the remaining input up to the
<CR>as part of the command.
- See the table below for examples.
The maximum length command string that can be entered is 80 characters.
Each command is explained in the following table.
'AT' Command Summary Table
|A/||Repeat last command (immediate)||This immediate command is not prefixed by |
|$||Help||Responds with the 'AT' Command Help see above|
|I or I0||Information zero||Responds with the modem model string |
|I1||Information one||Responds with the modem firmware version string eg. |
|I2||Information two||Responds with the modem firmware build chain version string eg. |
|Z||Reset modem||Soft resets the modem. Reloads settings and 'S' Registers from NVS. Closes open TCP/IP connections. But does not disconnect from the Wi-Fi Access Point (AP) if connected|
|&F||Restore factory defaults||Return the current settings and 'S' Registers to factory defaults. But does not save these to NVS|
|&W||Write settings to NVS||Writes the current settings to NVS. This takes approximately 10 seconds, during which the modem appears frozen. The modem will respond |
|D||Dial (TCP/IP connect)||The full form is |
|+++||Escape Sequence||When connected and in Data Mode the Escape Sequence will return to Command Mode. The |
|O||Return Online||When connected and in Command Mode |
|H||Hangup||When connected and in Command Mode |
|&A||Enable Answer mode||Unless |
|A||Answer||When an incoming connection request is indicated by the modem responding |
|Sn||Select current register||Select register n as the current 'S' register|
|?||Query current register||The modem will respond with the value of the current 'S' register. If no register has been selected the default is zero (0). As commands can be concatenated it is normal to append this to the |
|=r||Set current register||Sets the value of the current 'S' register to r. If no register has been selected the default is zero (0). As commands can be concatenated it is normal to append this to the |
|&K or &K0||Disable CTS/RTS flow control||The 6-pin modem header provides CTS/RTS lines. |
|&K1||Enable CTS/RTS flow control||The 6-pin modem header provides CTS/RTS lines. |
|+W?||Query Wi-Fi Access Point (AP) connection status||Responds with the status of the Wi-Fi connection as a string. The possible responses are listed below under Wi-Fi Connection Results|
|+W=sss,ppp||Join Wi-Fi Access Point (AP)||Connects to the Wi-Fi access point with SSID - sss and password - ppp. The modem responds |
|+W$||Show Wi-Fi IP address||Responds with the IP address allocated to the modem from the AP by DHCP. If the connection has not completed or has been unsuccessful the IP address returned will be |
|+W#||Show Wi-Fi MAC address||Responds with the MAC address of the modem. No connection is required, the MAC address is always available|
|+W+||Reconnect to Wi-Fi AP||Reconnects to the AP using the SSID and password stored in NVS. If the modem is already joined to the AP, the connection is first disconnected and then reconnected|
|+W-||Disconnect from Wi-Fi AP||Disconnects from the AP|
|+B?||Query Baud Rate||Responds with the current baud rate configured for the connection to the DTE|
|+B=n||Set Baud Rate||Sets the current baud rate to a supported value closest to n. The supported speeds are 4800, 9600, 14400, 19200, 38400, 57600, 115200. After the command is entered there is a 5 second delay before the baud rate is changed to allow changes to be made on the DTE before the modem responds. The new baud rate is immediately stored in NVS|
|+T?||Query Telnet TERM environment variable||Responds with the current string value of the TERM environment variable that will be used by the Telnet protocol layer when negotiating the TERMINAL-TYPE option. If no value has been set, or has been cleared, the default value |
|+T=ttt||Set Telnet TERM environment variable||Sets the current string value of the TERM environment variable to ttt. The Telnet protocol layer will use this value when negotiating the TERMINAL-TYPE option. If the command includes no value and is given only as |
There are a total of 51 'S' Registers reserved in the modem,
Most of them are undefined and unused. The defined registers are set with default values but some registers are ignored as their purpose is typically not useful, this is indicated in the table below. Changing the value of a register that is ignored will have no effect on the operation of the modem.
'S' Registers originally held only 8-bit (byte) values. In this implementation registers are 16-bit.
Defined 'S' Registers
|S0||Number of rings before Auto-Answer||0–255 (0 = never)||0||Yes|
|S1||Ring Counter||0–255 rings||0||Yes|
|S2||Escape character||0–255, ASCII decimal||43 ('+')||Ignored|
|S3||Carriage Return Character||0–127, ASCII decimal||13 (Carriage Return)||Ignored|
|S4||Line Feed Character||0–127, ASCII decimal||10 (Line Feed)||Ignored|
|S5||Backspace Character||0–32, ASCII decimal||8 (Backspace)||Ignored|
|S14||TCP/IP Port number for Answer Mode||0-65535||23||Yes|
|S15||Telnet Protocol for Data Mode||0 - disabled, 1 - enabled||0||Yes|
|S16||Negotiate Telnet SGA||0 - Won't/Don't, 1 - Will, 2 - Do, 3 - Will/Do||3||Yes|
|S17||Negotiate Telnet ECHO||0 - Won't/Don't, 1 - Will, 2 - Do, 3 - Will/Do||3||Yes|
|S18||Negotiate Telnet BIN||0 - Won't/Don't, 1 - Will, 2 - Do, 3 - Will/Do||0||Yes|
|S19||Negotiate Telnet NAWS||0 - Won't/Don't, 1 - Will, 2 - Do, 3 - Will/Do||3||Yes|
|S20||NAWS Negotiate Columns||0-255 columns||80||Yes|
|S21||NAWS Negotiate Rows||0-255 rows||24||Yes|
|S22||Negotiate Telnet TERMINAL-TYPE||0 - Won't/Don't, 1 - Will, 2 - Do, 3 - Will/Do||3||Yes|
|S39||CTS/RTS Flow Control||0 - disabled, 1 - enabled, set by ||0||Yes|
Wi-Fi Connection Results
Wi-Fi cannot be started when the terminal is in 30 line mode due to the limited amount of internal memory in the EPS32.
If you attempt to (re)connect the Wi-Fi when in this mode you will receive the response:
Return the terminal to 24 or 25 line mode and you will be able to (re)connect the Wi-Fi.
The following table details the responses from the modem for the Dial command
|Response||Reason for Response|
| ||when no Wi-Fi connection has been established with an AP|
| ||when a connection is already established ('Dialed' or 'Answered') with another host|
| ||when no hostname is provided|
| ||when a TCP/IP socket can't be opened with the hostname:port|
| ||when a TCP/IP socket is opened with the hostname:port|
Query Wi-Fi Responses
The following table details the responses from the modem for the Query Wi-Fi Access Point (AP) connection status command
| ||when no Wi-Fi connection has been attempted since power-on or hardware reset|
| ||if Wi-Fi status is queried during a connection attempt|
| ||when no AP with the given SSID/password is found following the |
| ||following a successful connection to an AP with the |
| ||following a lost connection with the AP|
| ||following an unsuccessful connection attempt, or a successful disconnection with the |
The Telnet protocol in normally considered an optional layer when establishing TCP/IP socket connections with remote hosts to operate as a Network Virtual Terminal (NVT).
Some hosts will provide a more functional service if Telnet is negotiated.
The Telnet daemon
telnetd I have on MacOS won't accept a connection if Telnet is not negotiated.
When Telnet is not enabled, TCP/IP socket connections are 8-bit clean. With Telnet enabled only one value,
0xFF known as the IAC byte (Interpret As Command) is overloaded to indicate that the next byte is a Telnet command. Telnet must negotiate binary mode (BIN) to transmit binary files.
If connecting to a remote c-Kermit server ie. under c-Kermit on a remote host enter the command
set host /server * 8080
DO NOT enable the Telnet protocol as you are not acting as an NVT in this use-case and c-Kermit doesn't expect Telnet.
Telnet Options Implemented
The modem implements the following minimum set of Telnet options:
- SGA (Suppress Go Ahead)
- BIN (Binary Transmission)
- NAWS (Negotiate About Window Size)
Each Telnet Option is negotiated in via a request/response exchange described as Do/Don't (request) and Will/Won't (response). Trying to understand how these work for each Option usually requires reading the RFC (linked in the list above) and extreme patience and experimentation.
Usually you either want an Option completely On (Do/Will) or Off (Don't/Won't).
Setting the supported Options and their default values are defined via specific 'S' Registers detailed above.
In summary the defaults are:
|SGA||Do/Will||SGA is required for the NVT to work character by character and not in linemode|
|BIN||Don't/Won't||To operate as an NVT, binary mode is not required. File transfer protocols like KERMIT and XMODEM do their own binary encoding|
|NAWS||Do/Will||The remote host can learn your terminal windows size in characters, the default is |
|TERMINAL-TYPE||Do/Will||The remote host can learn your terminal type, the default is |
TERMINAL-TYPEs must be known by the remote system to be recognised.
When connecting to
telnetd on MacOS I use
vt100+ from the
terminfo database which provides support for color over and above the standard
vt100 terminal type, making text applications like
htop work as expected and in color.
Enabling Telnet Protocol
Telnet protocol is not enabled by default.
- To enable the Telnet protocol you must manually set 'S' Register
- To disable the Telnet protocol you must manually set 'S' Register
The Telnet protocol is applied to both outgoing connections 'Dialed' with
ATD and incoming connections 'Answered' with
ATA or Auto-answer.
Telnet Protocol Framework
The Telnet protocol implementation in the modem is not fixed, but is instead based on a library libtelnet. There is further information about Telnet and Telnet Options on the GitHub repository for the library.
The library provides a framework for implementing any Telnet Option. So if there are Options that you feel are important beyond the minimum set already implemented let me know, providing a compelling use-case, and I will consider adding them.
Listening for incoming TCP/IP socket connections is not enabled by default.
- To enable listening for incoming TCP/IP socket connections you must manually enter
AT&Ato Enable Answer Mode.
- Answer Mode will remain enabled, and can only disabled by an
ATZSoft Reset, hardware reset or power-cycle.
- Incoming TCP/IP socket connections will cause the modem to respond with
RING, repeated every three (3) seconds.
- As each
RINGoccurs the Ring Counter in
S1is incremented by one (1).
- The user can Answer the incoming call at any time with
ATAand the modem will accept the TCP/IP socket connection and enter Data Mode.
- If the Number of rings before Auto-Answer is set in
S0to a number greater than zero (0 = never) and
S1is greater-then-or-equal to
S0the modem will Auto-answer: accept the TCP/IP socket connection and enter Data Mode.
- If Telnet protocol is enabled by
ATS15=1then the Telnet Protocol will be negotiated with the remote host after the modem enters Data Mode.
- The user can Hangup an incoming call by sending the Escape Sequence
+++(with guard times) to return to Command Mode and then sending
- A Hangup
ATHwill reset the Ring Counter in
S1to zero (0).