Setting up a High-Speed Modem
Larry Reznick
The prices on 14400 modems are coming down. Those modems
are being
supported more and more widely by various services.
I've been using
one for months, but not on a UNIX system. The time came
to install
one on a client's central site and on the client's beta
site, both
running SCO UNIX. Once that setup was proven, it would
become the
standard setup for my client's turnkey product.
My first concern was the delay in making the connection
while the
modems at each end negotiate with each other. That negotiation
establishes
the speed each modem is capable of, whether error correction
can be
used, and whether data compression can be used. A few
years ago, when
MNP-5 modems were popular and inexpensive, I experimented
with attaching
one to a Sun UNIX system. I ran into some problems with
that negotiation
delay. UUCP timed out before the negotiation could finish.
Unfortunately,
the priority for getting this MNP-5 modem to work was
very low. I
was moved to another project before I could find a way
around the
problem and still get the MNP-5 advantages: data compression
delivering
up to 4800 BPS on a 2400 modem. This time, with making
it work a high
priority, I knew there had to be a way.
The 14400 modems can adjust their speed to that of the
modem at the
other end, which means that modem doesn't need to be
another 14400.
After adjusting, they can notify the computer of the
speed. On the
one hand, 14400 is not a standard BPS rate, since BPS
rates, as a
general rule, double from each increment starting with
300. In fact,
I know of no communication software that actually supports
that 14400
rate. On the other hand, the modems are capable of communicating
with
the computer at speeds up to 57600 BPS. The modem does
this by taking
advantage of the difference between the data communications
equipment
(DCE) connection from modem to modem and the data terminal
equipment
(DTE) connection from modem to computer.
By not requiring each of the connections to run at the
same rate,
one modem can negotiate with the other modem over the
phone line,
establish the appropriate DCE speed according to what
the modems can
handle, and translate to a different DTE speed for transmission
to
and from the computer. To achieve a DTE speed higher
than the DCE
speed, each local modem buffers the data. If the DTE
speed is higher
than the DCE speed, the effect is an average faster
throughput than
would be expected were the two speeds identical.
Because of the modem's local buffering, the computer
can be told to
connect to the modem (DTE) at a single BPS rate, ideally
the fastest
the modem is capable of: 57600. However, the ideal and
the real are
often different. For instance, during Zmodem transfers
on some computers,
I've found that the time it takes for the system to
write a disk block
is long enough to miss the next modem data. The data
is just coming
in too fast for the disk handling. Slow the DTE speed
down and the
system can keep up. The DCE speed is still 14400, though,
so the transfers
are measurably fast.
SCO UNIX doesn't strictly support any modem speed faster
than 9600.
However, they do indicate that some Hayes compatible
modems have been
tested and work at the faster rates. I hooked up a Practical
Peripherals
14400 FXSA in early tests, and in the final installation
used two
Practical Peripherals 14400 FXMTs. Those modems worked
just fine.
I have no reason to believe other brands wouldn't work
as well; I
can't vouch for them because I haven't tried them.
To set up the 14400 modem on UNIX, some files need to
be changed for
the hardware interface and some for the UUCP interface.
Before starting,
be sure the getty on the modem port is disabled. On
SCO UNIX,
the port I used for the modem is tty1A, so the command
to disable
it is:
disable tty1A
This command changes the /etc/inittab file and
the /etc/conf/cf.d/init.base file. The SPBinittab(F)SPE
file contains the device names and characteristics used
when SPBinit(M)SPE
starts. The init.base file supposedly feeds default
settings
to inittab when the kernel is rebuilt, but I have no
evidence
this actually happens on SCO UNIX. Whenever the kernel
is rebuilt,
inittab settings come from a file named /etc/conf/init.d/sio.
(On SVR4, the equivalent to sio is named asy.) Unfortunately,
when the kernel is rebuilt the sio file's settings are
appended
to the end of the inittab without checking to see if
that appending
creates duplicate settings. Since it does create duplicates,
"tty
spawning too rapidly" errors appear after subsequent
reboots.
init is trying to spawn two or more gettys on the same
tty. To solve this problem, I commented out any lines
in the
sio file that are also in the inittab file. I keep the
inittab and init.base files identical, just in case
SCO does draw from the init.base file.
Once the getty is disabled, two files need to be changed:
/etc/inittab
and /etc/gettydefs. The inittab file contains the init
reference for the tty. That reference points to the
gettydefs
entry. The gettydefs file contains the port settings
used by
the getty before and after making a tty connection.
These settings are similar to stty(C) except that they
use
all capital letters. (See gettydefs(F) and termio(M)
for more information about those settings.)
I created the following single-line entry in /etc/gettydefs:
ppi14 # B38400 CS8 SANE HUPCL TAB3 ECHOE CRTSFL -IXANY
-IXON -IXOFF -CLOCAL -CTSFLOW -RTSFLOW # B38400 CS8
SANE HUPCL TAB3 ECHOE CRTSFL -IXANY -IXON -IXOFF
-CLOCAL -CTSFLOW -RTSFLOW #\r\n@!login: # ppi14
A gettydefs entry has five fields, each separated
by a pound sign (#). The first field contains the name
of the gettydefs
entry. Inittab refers to this name. The second field
contains
the initial termio settings used when init runs getty.
The third field contains the final termio settings used
before
getty runs login(M). The fourth field contains the login
prompt string. The "@" symbol in the login
prompt represents
the system name, which is taken from /etc/systemid.
The fifth
field refers to the next gettydefs entry to be used
if a BREAK
code is sent down the line. This BREAK is commonly used
to cycle through
multiple BPS rates controlled by software. For instance,
2400 BPS
modem setups often allow users to dial in at 1200 and
300, while 9600
BPS setups typically allow 4800 and 2400. In the first
case, the 2400
entry refers to the 1200 entry, and the 1200 entry refers
to the 300
entry, and the 300 entry refers back to the 2400 entry,
closing the
cycle. The ppi14 entry refers to itself. There is no
need for software
cycling through different BPS rates because the modem
hardware negotiates
the rate. Thus, the DTE rate is fixed at 38400. Other
operations set
a lower speed if needed.
(I didn't honestly expect 57600 to work well under multitasking
conditions.
I had hopes for 38400 and expected no trouble with 19200.)
This entry contains identical initial and final termio
settings.
The 14400 modem is best run with RTS/CTS turned on and
XON/XOFF turned
off.
XON/XOFF is a software protocol. When an internal software
buffer
gets to a certain percentage of full, say 75 percent,
the software
sends an XOFF data byte to the other system. The other
system stops
sending. The remaining 25 percent of the buffer catches
the data sent
down the line before the XOFF was received by the remote
system. With
the data flow stopped, the local system can empty the
buffer without
worrying about a buffer overflow. When the buffer is
a certain smaller
percentage full, say 25 percent, the modem sends an
XON data byte.
The other system will start sending again. The remaining
25 percent
of the buffer still containing data keeps the local
system busy while
the remote system is receiving the XON.
RTS/CTS (Ready-To-Send/Clear-To-Send) is a hardware
protocol. Instead
of the local modem telling the remote computer's software
to stop
sending, using the RTS/CTS protocol the local modem
tells the local
computer to stop sending. When data is available to
send, the RTS
line is raised. When the data can be received, the CTS
line is raised.
By toggling those lines, the local computer and modem
avoid buffer
overflows and the data from modem to modem goes as fast
as it
can. Yet, no extraneous data transmits between the two
modems. With
the higher speed modems, RTS/CTS is required due to
the modem's internal
buffering, used to make the different DTE/DCE speeds
work.
I was using SCO UNIX System V Release 3.2 Version 4.0.
I found out
that v4.0 didn't properly handle the RTS/CTS protocol.
This bug was
resolved in the interim release v4.1. Without RTS/CTS,
the best I
could do was 9600 BPS using XON/XOFF protocol. (The
termio
setting for XON/XOFF in gettydefs would be the same
as above
except you would substitute IXANY for all the settings
between the
ECHOE and the #. Other AT-style initialization codes
are needed for
the modem itself. More about those later.) Once I installed
the v4.1
upgrade I got the RTS/CTS protocol working. The CRTSFL
flag
was created by SCO for v4.0. In a single setting, it
is supposed to
replace the CTSFLOW and RTSFLOW flags. When CRTSFL
is used, the other flags must be turned off: -CTSFLOW
-RTSFLOW.
The CLOCAL flag must be turned off whenever RTS/CTS
protocol
is used. (SCO v4.2 is available now. I haven't installed
it as of
the time of this writing. I have seen a note from SCO
that the gettydefs
settings are slightly different, requiring the elimination
of the
CRTSFL and use of CTSFLOW and RTSFLOW.)
With gettydefs set, I edited /etc/inittab to make tty1A
(labeled in the inittab file as "t1A") point
to the
new gettydefs entry. If I change the last field in the
inittab
file to ppi14, the new gettydefs entry will be used
when I enable tty1A. It's also necessary to change the
init.base
file, too.
The next steps configure cu(C) and uucp(C) to work.
After cding to /usr/lib/uucp, I edit /usr/lib/uucp/Devices.
The Devices(F) file identifies the speed and dialing
characteristics
of the modem's tty port. If there is more than one entry
for
the same device in the Devices file, the first one becomes
the default entry. Otherwise, the speed identifies the
entry to use.
When cu or uucp names a system, the Systems(F)
file contains that system's speed and device information.
If you use
cu to dial any other phone number or to make a direct
connection
to the modem, you must name the tty line with the "-l"
option. Then, you must either identify the speed to
use on the tty
line with the "-s" option or cu will use the
highest
speed configured in the first entry in the Devices file.
I ended up using three Devices lines:
ACU tty1A - 19200-38400 /usr/lib/uucp/atdialPPI14
ACU tty1A - 300-9600 /usr/lib/uucp/atdialPPI9
Direct tty1a - 300-38400 direct
The first two lines specify two different dialers to
use for the ACU: the first one for the higher rates
using the 14400
DCE, and the second one for the lower rates using a
DCE of anything
else. The third line, labeled "Direct," lets
me make a direct
connection to the modem at any speed without modem control,
since
tty1a (notice the lowercase "a") has no modem
control
in the device driver.
The last field of each ACU line refers to the SCO "atdialer"
program as the dialer. I first tried to use entries
in the Dialers(F)
file, which is also found in /usr/lib/uucp. Here are
the single-line
entries that I tried in the Dialers file:
ppi14400 =,-, "" ATZ\r\c OK\r
AT&FE1L2M1Q0X4&C1&D2&K3&Q5S0=0S2=43S95=46&W\r\c OK\r \
ATDT\T\r\c Speed
&ppi14400 =,-, "" +++\dATH OK\r ATS0=1S2=128\r
ppi9600 =,-, ATZ\r\c OK\r
AT&FE1L2M1Q0X4&C1&D2&K3&Q6S0=0S2=43S95=46&W\r\c OK\r \
ATDT\T\r\c Speed
&ppi9600 =,-, "" +++\dATH OK\r ATS0=1S2=128\r
There are really only three fields: the dialer name,
the pause translation table, and the chat script.
The lines named ppi14400 and ppi9600 are the dialer
names referred
to by the Devices file entries. These lines' chat scripts
are
sent as initialization codes just prior to dialing with
any cu
or uucp command. The lines having the same names but
preceded
by an ampersand (&) are used to hang up and reset
after the session
is finished.
The pause translation table contains translation characters
for certain
kinds of delays. The first one is a wait-for-dialtone
pause, the second,
a simple pause. Some modems use different characters
for those different
pauses. In a phone number used on cu's command line
or in uucp's
Systems file, the equals sign represents the wait-for-dialtone
code, and the minus sign represents the pause code.
For example, if
you needed to dial 9, wait for a dialtone, then dial
the number, you
might use the phone number 9=5551212. The dialer script
will replace
the equals sign with the modem's character for that
kind of delay.
For Hayes-compatible modems, there is no distinction
between the two
pauses: the equals sign and minus sign is replaced by
a comma for
both of them.
The chat script is just like the one used in the Systems
file:
a set of expect/send strings. The first string defines
the expected
response from the modem and the second is a string to
send. The rest
of the chat script is more expect/send sequences. When
an empty string
("") is used for the expect string, that means
expect nothing.
The 14400 and 9600 chat scripts are identical except
for the &Q entry.
Briefly, the initialization string breaks down like
this:
AT -- Get the modem's attention.
&F -- Load the default factory profile for
the switches and S-registers and completely reset the
modem. This
is a more complete reset than that used by the old ATZ.
E1 -- Turn on command echo. Use this to
see what you're typing when you're not connected to
another modem.
L2 -- Set speaker volume to medium. This
is a default setting. I have it here so I can explicitly
turn it low
(L0) for a customer site's modem.
M1 -- Keep speaker on until carrier detect.
This is also a default setting. Again, I have it here
so I can explicitly
turn it off (M0) so customers don't have to listen to
the tones.
Q0 -- Enable result codes.
X4 -- Set extended result codes to show
connect speed. Also waits for a dialtone before dialing.
&C1 -- Set Data Carrier Detect (DCD) according
to the remote modem.
&D2 -- Use Data Terminal Ready (DTR). Dropped
DTR hangs up and goes to command mode.
&K3 -- Set local flow control to RTS/CTS.
Use &K4 if you must use 9600 with XON/XOFF instead.
&Q5 -- Set v.42 error control. The v.42bis
(data compression with theoretical 4:1 compression for
text) will
be automatically negotiated if the remote modem supports
it. If you
must use 9600 or less, use &Q6 instead. Data compression
will be disabled
but you should get a good connection. However, if you
must run XON/XOFF
(using &K4) this must be set to &Q0. That turns
off negotiation and
error correction, giving you a straightforward connection
at exactly
the BPS rate specified. The BPS rate must be 9600 or
less to use XON/XOFF.
S0=0 -- Turn off the autoanswer.
S2=43 -- Enable the plus symbol as the escape
code. Normally, this is best turned off when connected
to another
modem. But, while debugging the communication, it is
very handy to
be able to go into command mode and run ATI6 and AT&V.
ATI6 shows
the active BPS rates, &K and &Q settings, and
whether error correction
and data compression protocols were activated. AT&V
shows the current
DTE and DCE settings, all of the options, and all of
the S-register
settings. After looking at them, I can go back online
by typing ATO.
If you're configuring both sides of a modem connection,
though, be
sure that the remote modem has the escape code turned
off, using S2=128.
Otherwise, when you escape your local modem, you might
escape the
remote modem too. If a timeout isn't active to kill
the connection
after carrier is dropped, that modem will hang on the
line even after
you hangup.
S95=46 -- Set the modem to tell the maximum
information about the connection. This is useful primarily
when debugging
the communication. There are five bits available:
|
|
1 |
Show Connect DCE speed instead of DTE. |
2 |
Show /ARQ if error correction active. |
4 |
Show Carrier DCE speed. |
8 |
Show Protocol NONE, LAP-M, or MNP. |
32 |
Show Compression NONE, 4.2BIS, or MNP5. |
Just add the bits together to get the value to set
in the register. I don't use the 1 value because the
regular Connect
message shows the DTE speed while the Carrier message
shows the DCE
speed. This S-register can remain set this way because
the uucp
and other chat scripts will either ignore or absorb
the other messages
this setting generates.
&W -- Write the current switch and register
settings to nonvolatile profile 0. Strictly speaking,
this setting
isn't needed with every dialer initialization. I could
have sent everything
other than the &Q (and maybe the &K) to the
modem manually, stored
it once with the &W, and then reduced the chat script's
initialization
string to AT&F to reset to factory conditions, followed
by ATZ to
set the profile 0 configurations. I didn't do it this
way because
if I or anyone else in the future needed to experiment
with other
settings, including changes to the modem's profile,
I wanted cu
and uucp to be able to reset the modem completely.
When the communication is finished, the appropriate
&ppi setting
is activated. The three pluses get the modem's attention,
the ATH
hangs up the line, the autoanswer will pick up the phone
on the first
ring (S0=1), and the modem escape is disabled (S2=128),
so that the
next remote call that comes in can't escape the local
modem to command
mode.
(The "\T" in the dialer entries marks the
location where the
phone number will be placed when the dialer is used.
The keyword "Speed"
in the expect field tells the dialing program to match
the connect
speed for a variable speed modem.)
These were good-looking Dialers entries. I got the 9600
entry
to work in the XON/XOFF mode (using &K4&Q0)
while I waited for SCO's
v4.1 upgrade to arrive. When v4.1 arrived, I expected
the dialer entries
would continue to work with &K3&Q5 at 19200
and above. No such luck.
The problem was that despite my gettydefs entries, the
RTS/CTS
flow control simply wouldn't set properly. Using stty
while
the test connections were active, I could debug the
line protocols
from another virtual terminal (SCO calls them multiscreens). The
stty
program always works with the standard input (stdin),
even though
it looks weird to do so. To find out what the line is
doing, I executed
the following command:
stty -a </dev/tty1A
That shows all the settings currently active on tty1A.
(You
can't look at tty1A while the Terminal Ready (TR) light
is
off. The stty program simply hangs until an interrupt
is sent
to the stty process. When stty is interrupted, you'll
see a message such as "Can't open device."
If you must look
at the serial line when TR is off, use tty1a (notice
the lowercase)
instead. The settings will be the same when there is
no connection.
When the port has been disabled, the TR light turns
off. When it is
enabled, TR is on. The cu and uucp programs turn TR
on as needed.) I needed the following settings: -clocal,
crtsfl,
-ctsflow, -rtsflow, -ixon, -ixany, and
-ixoff. I wasn't getting them with v4.1. Despite the
gettydefs
settings, RTS/CTS was off and XON/XOFF was on! Because
of that, the
modem connection would lose lots of characters and every
so often,
there would be ^S and ^Q characters in my keyboard commands.
To force the settings the way I wanted, I used the following
command:
stty crtsfl -ctsflow -rtsflow -ixon -ixany -ixoff </dev/tty1A
That looks strange because the command seems to need
input from tty1A, yet the intent is to output to tty1A.
But, that's the way stty works. It reads input from
whatever
is on stdin, and it writes output to whatever is on
stdin. When I
had a 19200 BPS connection with lost data, it worked
correctly once
I forced those settings. I needed something to force
those stty
settings. I have no idea why gettydefs isn't sufficient
on
SCO UNIX.
Fortunately, SCO saved me some programming by providing
a program
named atdialer. The C source code is included, but I
was able
to use the supplied program without modification instead
of the Dialers
file entries. atdialer looks for a textfile in the /etc/defaults
directory containing a description of various modem
commands and responses.
You can use a shell script named make.dialer, supplied
with
the atdialer program, to create that file if you like,
or use
a text editor. The textfile must be given a unique name.
Usually, the textfile name is "atdial" followed
by an all-capitals
abbreviation for the modem being configured. atdialer
knows
which textfile to use by looking at its program name.
The name of
the atdialer program will be the same as the textfile
name.
This is similar to the trick used for ls(1). On some
UNIX systems,
ls has alias names, such as ll and lc. They are
really hard links to the primary program. The program
looks at which
name was used to invoke it and modifies its operation
according to
the name.
When make.dialer is run, it asks what name I want to
use. I
selected "atdialPPI14" for the 14400 mode
of operation. The
make.dialer script asked me a bunch of questions about
the
modem's commands and responses. The answers are put
into a textfile
named /etc/default/atdialPPI14, and a hard link to /usr/lib/uucp/atdialer,
named /usr/lib/uucp/atdialPPI14, is generated. In other
words,
the program's basename is identical to the configuration
textfile's
basename. Internally, the program only needs to change
the path to
get to the textfile.
Unfortunately, the make.dialer script doesn't request
stty
settings, even though the atdialer.c source shows that
the
program can use them. To solve the problem, edit the
file and manually
enter the stty settings. Following is the resulting
file for
the 14400 operations:
* Setup for Practical Peripherals 14400 FXMT
STTY=-IXON -IXOFF -RTSFLOW -CTSFLOW CRTSFL
MDM_SETUP=AT&FE1Q0X4&C1&D2&K3&Q5S0=0S2=43S95=46&W
MDM_OPTION=
MDM_DIALCMD=ATDT
MDM_ESCAPE=+++
MDM_HANGUP=ATQ0H0
MDM_RESET=ATQ0Z
MDM_DIALIN=ATS0=1
MDM_ATTN=AT
MDM_DSBLESC=ATS2=128
RTC_OK=OK
RTC_NOCARR=NO CARRIER
RTC_ERROR=ERROR
RTC_NOTONE=NO DIALTONE
RTC_BUSY=BUSY
RTC_NOANS=NO ANSWER
RTC_300=CONNECT
RTC_1200=CONNECT 1200
RTC_2400=CONNECT 2400
RTC_4800=CONNECT 4800
RTC_9600=CONNECT 9600
RTC_19200=CONNECT 19200
RTC_38400=CONNECT 38400
(The atdialer program searches through the file
for an exact match of each variable name, so anything
in the file
not using one of those names is ignored. Since SCO used
the asterisk
(*) as if it were a comment introducer, I did the same.)
The only change for 9600 or less operations is to change
the &Q5
to &Q6, make one file for the 14400, (which I named
atdialPPI14),
and another file for the 9600 (named atdialPPI9). Those
files
must be worldwide readable and are placed in /etc/default.
The next step is to make hard links to /usr/lib/uucp/atdialer
using those same names. After creating the files, the
entire command
sequence should be:
cd /etc/default
chmod a+r atdial*
cd /usr/lib/uucp
ln atdialer atdialPPI14
ln atdialer atdialPPI9
After setting up the atdialer, I changed the Devices
file to refer to the atdialPPI14 and atdialPPI9 dialer
programs, as shown earlier.
Finally, so cu and uucp can use the system names, I
changed the /usr/lib/uucp/Systems file to make each
system
entry refer to the correct speed: 19200. I tried 38400
and got connections,
but cu lost characters when UNIX did other things. This
was
annoying with interactive connections; it would be devastating
for
uucp transfers. So, for now, set the top rate as 19200.
The problem
is probably that the sio driver can't keep up with that
speed
in its current condition and SCO hasn't chosen to bring
the driver
up to date with modern higher-speed modems yet. There
might be a way
to fix that without rewriting the device driver. Writing
a new device
driver is the last resort.
The /usr/spool/uucp/.Admin/xferstats file keeps track
of the
uucp transfer speeds. Sample entries, each a single
line, look
like this:
rezbook!mmdf S (6/24-11:57:01) (C,1997,1) [tty1A] -> 528 /
1.230 secs, 429 bytes/sec
rezbook!mmdf S (6/24-11:57:05) (C,1997,2) [tty1A] -> 146 /
0.090 secs, 1622 bytes/sec
chevrn1!mgr M (6/24-16:18:43) (C,3106,64) [tty1A] <- 308655 /
360.420 secs, 856 bytes/sec
chevrn1!mgr M (6/24-16:25:16) (C,3106,78) [tty1A] <- 309225 /
370.850 secs, 833 bytes/sec
(The rezbook system had a 2400 BPS connection. The chevrn1
system had the 14400 FXMT.) These samples show the system!user
who
sent the file, the date and time of the transfer, a
sequence number
within the connection, the port, whether it is coming
from the other
system (an arrow formed from a less-than and a hyphen
<-) or going
to the other system (an arrow formed from a hyphen and
a greater-than
->), how many bytes are in the transfer, how many
seconds it took
to transfer, and the bytes-per-second throughput.
The number of seconds is total time, not just the time
of the actual
transferring. It reflects not only the time it took
to transfer the
bytes, but the time UNIX used to do other things, so
the bytes-per-second
is a real throughput time. In the traditional estimation
of transfer
time, you divide the BPS rate by 10 (eight data bits,
one start bit,
and one stop bit) to get the theoretical maximum bytes-per-second
rate. That means a 9600 transfer can reach a top rate
of 960 bytes
per second, and a 14400 transfer goes to 1440. Since
the DTE speed
is higher than 14400, the actual maximum speed could
be higher than
1440 (although not quite as high as 1920 or 3840). But,
UNIX has other
things to do. Time taken away from the transfer reduces
the throughput.
Still, the sample numbers show that the transfers are
in the 800 bytes-per-second
range. This time represents a four to five times speedup
from 2400.
Since 14400:2400 is a 6:1 ratio, we seem to be getting
most of the
speed out of the modem. Because the modem is able to
deliver 57600
BPS, we might be able to get more out of the modem with
a better sio
driver.
About the Author
Larry Reznick has been programming professionally since
1978. He is currently
working on systems programming in UNIX and DOS. He teaches
C language courses
at American River College in Sacramento. He can be reached
via email at:
rezbook!reznick@csusac.ecs.csus.edu.
|