Basics of Modem Programming

The modem isn't dealt with directly in most communications applications.
Instead, protcols which abstract the modem are used. The standard,
gauranteed protocol for performing basic communicaton with a modem is the
Hayes AT command set, developed oringally by Hayes corp. for their

When a modem isn't connected or connecting to another modem, it's in what's
called command mode. When a modem is in command mode, the modem can accept
commands from you, in the form of strings written to the serial port to
which the modem is attached. When the modem isn't in command mode, it is
said to be in online mode. In online mode, everything written to a modem's
serial port is sent over the phone line to another modem.

To get from command mode to online mode, you have to connect with another
modem by sending appropriate commands to your modem.

To get from online mode to command mode, you have to either hang up the
phone (at which point the modem automatically returns to command mode), or
drop the DTR (Data Terminal Ready) line with &D1 set. Dropping the DTR will
cause both the modem to be sent back into command mode, and can be achieved
through resetting bit 0 of the UART's MCR [see Programming the 8250 UART].
Alternatively, on most modems, you can send an "escape sequence" that puts
the modem back into command mode. The most common one is "+++" alone on a

Okay, with that out of the way, we can get to the actuall AT command set.
By default, when modems are in command mode, they accept commands taken
from the Hayes AT command set. A string of Hayes AT commands begins with
the characters "AT" (which, for the record, stands for ATtention) and ends
with a carriage return (CRLF, character 13 followed by character 10). AT
commands can either be strung together as one big long string on the same
line, not seperated by any characters, or they can occur on lines alone by

Below is a fairly complete listing of the AT command set (I didn't include
the AT prefix in front of them all, for reasons of sanity...). This took a
little while to compile, so hopefully you can find some use for it.

   Hayes AT Commands
in alphabetical order.
Command                Function
A                      Answer incoming call
B0                     Use V.22 1200 baud connection
B1                     Use Bell 212A 1200 baud connection
D#                     Dials a phone number #
D can be followed by:

  !                    Goes on hook for time given in S29 [I'll explain
  ,                    Pauses during dial (pause time is in S8)
  S=#{#=0-3}           Dials a number stored using &Z#

  ;                    (comes after dial string) Return to command mode
                       after dialing
  @                    Waits for 5+ seconds of line silence before dialing
  L                    Redials last number dialed
  P                    Dial using pulses (OLD...)
  R                    Accept command, but don't act on it [...]
  W                    Wait for dial tone
  ^                    Turn on call tone
E0                     Don't echo command characters
E1                     Echo command characters
H0                     Makes modem hang up
H1                     Takes modem off of the hook
I0                     Returns product code
I1                     Returns ROM checksum

I2                     Compares ROM checksum with acutal ROM and returns
                       OK or ERROR
I3                     Returns firmware revision code
I4                     Returns modem ID string
I5                     Returns country code
I6                     Returns data pump info
L0                     Sets speaker volume to lowest
L1                     Sets speaker volume to low
L2                     Sets speaker volume to medium
L3                     Sets speaker volume to highest
M0                     Speaker is always off
M1                     Speaker is on until a carrier is detected
M2                     Speaker is always on
M3                     Speaker is on during answering only

N0                     Disables automatic modulation negotation--uses
                       connection speed given in S37. See +MS...
O0                     Puts modem in data mode
O1                     Takes modem out of data mode
P                      Use pulse dialing until T command is received
Q0                     Sets DTR line
Q1                     Clears DTR line
S#                     Make S-register # default register
S#=x                   Set S-register # to x
S#?                    Returns value of register #
T                      Use tone dialing until P command is received
V0                     Send numeric responses
V1                     Send textual responses
W0                     Returns computer-modem speed

W1                     Returns modem-modem, computer-modem speed, as well
                       as error correction protocol
W2                     Returns modem-modem speed

X0                     Modem will send OK, CONNECT, RING, NO-CARRIER,
                       ERROR, and NO ANSWER
X1                     Modem will send X0 responses and connect speed
X2                     Modem will send X1 responses and NO DIALTONE
X3                     Modem will send X1 responses and BUSY
X4                     Modem will send all responses
Y0                     Disable disconnection on pause

Y1                     Enable disconnection on pause; generally 2 seconds
                       or so on loss of signal, 4-5 w/o error correction
Z0                     Sets modem to profile 0 (see &W0)
Z1                     Sets modem to profile 1 (see &W1)

&C0                    Sets DCD on (Data Carrier Detect, it's an RS-232
                       line; indicates that a carrier has been detected).
&C1                    Sets DCD to follow the actual carrier

&D0                    DTR (Data Terminal Ready) is assumed to be active,
                       whether it is or not

&D1                    Modem will interpret a DTR drop as an escape

&D2                    Modem will interpret a DTR drop as a hang up
                       command; auto answer doesn't work with this

&D3                    Modem will interpret a DTR drop as a command to do
                       a reset; loads profile from &Y setting
&F                     Loads the factory profile
&G0                    Disables gaurd tone
&G1                    Disables gaurd tone
&G2                    Enables 1800 Hz gaurd tone
&K0                    No flow control

&K3                    Hardware (Request To Send/Clear To Send) flow
&K4                    Software (XON/XOFF) flow control
&M0                    Selects no error correction, no speed control
&P0                    {Something with make/break dial ratio?}
&P(1-3)                Accept commands, but do nothing
&Q0                    Does same thing as &M0
&Q5                    Modem negotiates error correction
&Q6                    &M0 with speed buffering
&S0                    Keeps Data Set Ready (DSR) active all the time

&S1                    DSR active after answer detected until carrier is
&T0-8                  {Engineering tests}

&V                     Returns active and stored profiles [&Y], as well as
                       stored numbers [&Z]
&W0                    Save current config as profile 0
&W1                    Save current config as profile 1
&Y0                    Modem uses profile 0 on startup
&Y1                    Modem uses profile 1 on startup
&Z#=x                  Set stored number (0-3) to #
Note that commands followed by a 0 can be specified without it, eg ATZ0 =

It turns out that the table above is only partially complete. I've listed
the portion of the Hayes AT command set that's the most widespread.
However, it there are some inconsistencies among implementations of the
extended Hayes AT command set in actual modems. Not all of them implement
the same set of commands; some less, some more. In addition to the above,
many modems implement additional commands, not necessarily standard, to
support selection of error correction and data compression protcols. These
are specific to the device or protocol. However, you shouldn't have a great
deal of difficulty locating information for these--you need only look as
far as your modem's own technical specification, which should've shipped
with it. Take a look and see if there's anything interesting; if so, tell
the rest of us about it, or perhaps write a driver just for the fun of it?

Fortunately for your sake, you won't have to use a great deal of the
extended AT command set to get basic telecommunications stuff up and
running. Otherwise, we might run into some now becomes obvious
why often only a subset of the AT command set is listed in introductory

If you studied the table above carefully, you probably noticed that I refer
often to "returns" and occasionally to some obscure S-register-things. What
am I talking about, here?

There is a standard set of response strings that the modem sends back to
you to tell you the results of an AT command. They have the format CRLF,
"response code", CRLF. A few of the more common response codes are listed

                            Modem Response Codes




                     NO CARRIER


                     NO DIALTONE


                     NO ANSWER

                     CONNECT {BAUD}

                     CARRIER {BAUD}

You just read the response code from the serial port after a command is
executed. It's not at all complicated.

So what about the other question? Those S-registers?

S-registers are a partially standard set of registers implemented a modem
that can be used to program the modem on a lower level than the AT command
set provides. Their implementation is (for the most part) fairly
straightforward. You can set an S register using the ATS#=x command. As
with the Hayes "Standard" AT command-set, though, there are some minute
variances here and there.

The number of S-registers that a modem posesses is variable, but you
probably won't find a modem with more than 255 of them. There are about
16-20 of them that I personally would ever find the need to use. Therefore,
to avoid confusion, I'm going to list only those registers which are the
most useful and/or standard; if you want to go hunt for complete listings
for your particular modem, there are some references for you at the end of
this article.


    Register    Range    Function

    S0:         0-255    Number of rings before auto-answer

    S1:         0-255    Incoming ring counter

    S2:         0-255    Holds ASCII value of escape character

    S3:         0-127    Holds ASCII value of carriage return character

    S4:         0-127    Holds ASCII value of line feed character

    S5:         0-255    Holds ASCII value of backspace character

    S6:         2-255    Dial tone wait time (seconds)

    S7:         1-255    Remote carrier wait time (seconds)

    S8:         0-255    Pause time for comma in dial (seconds)

    S9:         1-255    Carrier detect time (100s of ms)

    S24:        0-255    Sleep timer (seconds)

    S25:        0-255    DTR delay (10s of ms)

    S30:        0-255    Inactivity time before hangup (10s of seconds)

    S32:        0-255    Holds ASCII value of XON character

    S33:        0-255    Holds ASCII value of XOFF character

Well, that's about it for the technical information on modems. As you can
see, it's really not terribly complicated material.

At this point, you have probably read and understood most of this, but you
might still be wondering exactly how it all fits together. What commands do
you send when? How do you use all of this jargon about S-registers and
response codes?

In a very simple model, you need only to initialize the modem, to make a
connection to a remote machine, and then to send your data out the serial
port. Most of the information provided in this article, you probably won't
use in your first modem experimentation. Modem initialization for various
modems will vary, but in general, to initialize the modem, send over at
least ATZ, which will set it up using the default profile. If you plan to
be transfering raw data with no error correction or interferance from the
modem, as you might in a game, send an AT&Q0 (direct asynchronous mode
select) to the modem. You might also choose to send specific initialization
strings to specific forms of modems. See for some information if you
choose to do this.

Connecting to a remote machine is also trivial. You just send over the
appropriate ATD command to dial the remote machine's phone number, and wait
for a modem response code that indicates that a connection was made (CONNET
{baud} or CARRIER {baud}). Then you simply proceed to send data out the
serial port, and read from the serial port in order to receive data. That's
really all you need to know to develop a basic modem communications