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
Smartmodem.
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
line.
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
themselves.
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
later]
, 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
sequence
&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
control
&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
lost
&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 =
ATZ
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 trouble...it now becomes obvious
why often only a subset of the AT command set is listed in introductory
texts!
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
below:
Modem Response Codes
OK
CONNECT
RING
NO CARRIER
ERROR
NO DIALTONE
BUSY
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.
S-Registers
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
http://www.unicom.net/fyi/help/modeminfo.html 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
package.