[comp.unix.ultrix] Tru-facts about /etc/acucap generic dial support

grr@cbmvax.UUCP (George Robbins) (02/10/88)

XYZXYZ		Warning: this may be Ultrix 1.2 specific	XYZXYZ

I've been trying get my Telebit Trailblazer modems working reliably
with the Ultrix shared modem support at assorted speeds for both
dial-in and dial-out.  Up till today, I've been trying to do this
with the "built-in" hayes support, but have encountered a fair
amount of frustration.

I've previously tried to use the "generic dialer" or acucap support,
but was greatly frustrated by my inability to get the software to
do anything consistently.  Before trying again, I decided to try to
map out fairly precisely what the dialing code really does, where
error/status messages come out and what the general constraints are.

This is the result of a days debugging and analysis, combined with
some general notions about the way uucp works.  There are bound to
be some minor and more stupid mistakes, but I think the gist of this
information will be useful.  I don't have Ultrix sources, but I'd be
glad if someone that does could check this out.  Of course it's also
possible that everything has been fixed and made rational in Ultrix
Release 2.x; perhaps Marc T. can comment...

Now, I guess that based on all this research, I am should be able to
construct functional and even reliable acucap entries!  However, I'll
leave the results for another message. 


Notes:

1) The acucap generic dialer facility is completely separate form the
   normal unix dialers.

2) The strings defined in the termcap entries are *not* send/expect
   strings in the uucp sense.  Any escapes are translated by the termcap
   type routines, and the dialer routines simply print the result with
   some specified intra-character delay.

3) Not only does this mean you can't "program" in delays, breaks, parity
   or similar stuff, you have very little control over the timing of
   sending the strings.

4) You may not be able to combine a functional hayes style +++ sequence,
   with other commands, depending on the definition your modem uses.
   If 'guard' is the number of seconds of quiet required  before and after
   the +++, some modems also require less than 'guard' between the +'s.
   You may find similar problems with too much delay between the A and T
   of AT style command sequences.

5) Despite the documentation, the delay to wait for carrier to come on :fd:
   is always in seconds.  If you use the :lt: option and try to specify
   a value in microseconds, your uucp will be hung up for a looooog time.

6) Not exactly mentioned in the documentation, but if you don't specify
   a dial initialization string :di:, then the entire dialing step is
   skipped.

7) The intra-character delay in the disconnect sequence is always 1,
   either 1 second if you don't use :lt: or 1 microsecond if you do.

8) They way the response strings are processed is kind of goofy.  If there
   is a time limit on the response, then the program does a "sleep" for
   that period.  After the sleep, or if there was no limit, the input
   routine checks for characters and tries to match them against the
   desired response string.  If there's not a match, it tries to get more
   characters.  Anyway, if no characters are received within one second
   it times out and fails, otherwise keeps trying as long as characters
   keep coming.

9) Operations in "shared" line mode require careful modem setup.  The
   modem should normally leave DSR off until in data mode, should not
   deliver response messages on incoming calls and should not echo in
   command mode.  An ill-mannered modem will appear to be "active" to
   getty and will not be available for sharing.  It may also engage
   in a prolonged conversation with getty/login, potentially wasting
   cpu cycles or more dire evils.

10) Owners of DMF-32's will find that *no* incoming characters are
   delivered unless the modem is asserting carrier detect.  Due to (9)
   above you can't leave "carrier detect on in command mode" set, or
   the modem will not "share".  This generally means that you will
   have to use the :si: flag and dial "blind" and that you won't get
   much in the way of meaningful diagnostic response codes.

11) An alternative, assuming that dropping DTR resets your modem's
   options, is to include some modem command in the synchronization :ss:
   string that turns on carrier in command mode, since no response codes
   are looked at until after the :ss: string has been sent.

12) Since it cannot be guaranteed that the +++ style disconnect sequences
  will work for a random hayes type modem, it is all but essential that
  you use a cable/interface that supports modem control, and that modem
  control be enabled for that line.  For a shared line, this appears to
  be controlled by the lines entry in the /etc/ttys's file, however it
  would probably be a good idea not to have modem control disabled by
  the interface flags in your systems config file.

General Flow:

This is intended only to show the sequence of operations, and indicate
where error messages and stuff are coming from....

debug implies a message controlled by uucico "-x" switch
ddebug implies a message controlled by the :db: termcap option
assert implies a message that is fatal - usually some inconsistently
log imples something that should show up in the /usr/spool/uucp/LOGFILE

genopn() is called from the general connect processing when your L-devices
file indicates you want some auto-dialer, and it isn't one of the built-ins,
and it was found in the /etc/acucap file.

genopn()
========
open device
log open errors
ioctl TIOCSINUSE - get shared modem
log shared modem error
debug "calling gen_setup"
ioctl TIOCNCAR - ignore software carrier
call routine to extract acucap fields
get process group
ioctl TIOCSPGRP - set device process group
call fixline() common setup processing
  looks up speed in spds table
  assert "BAD SPEED" - not in table
  ioctl TIOCGETP - gtty
  munge line parameters
  ioctl TIOCSETP - stty
  assert "RETURN FROM STTY" - no driver support
  ioctl TIOCHPCL - hangup on close
  ioctl TIOCEXCL - set exclusive use
calls gen_dialer
error analysis
debug "generic dialer error on %s"
set up message - one of:
  "can't sync" "misdialed - try another" "no carrier"
log "generic dialer failed - acu = %s, cause = <message>"
flush input
return - either try new dialer or proceed with "login"


gencls() is called after the call is complete, or if things go sour.
note than more general clsacu does a ioctl TIOCNCAR to disable software
carrier detect before calling gencls.

gencls()
========
debug "close generic - Def = %d"
call gen_disconnect
log "close generic acu fd = %d"
sleep 5
return

gendialer() is the routine that actually handles the entire dialing sequence.
it really uses several more subroutines, but they'be been unrolled here.

gen_dialer()
============

ddebug - dump acucap parameters
ddebug - "gensync"
if :re: 
  ioctl TIOCCDTR - clear DTR
  sleep 2
  ioctl ITOCSDTR - set DTR
if :ss:
  call output(:ss:,:sd:) - string, delay
  if :sr:
    call input(:sr:) -- note only 1 sec to respond!
if :hu:
  ioctl TIOCHPCL - hangup on close - note already set by fixline!
if error
  return can't sync

ddebug "gendial"
if :di: - skips dialing sequence if no :di: !!!
  if :rs: - replace string
    munge = and - in phone number to :rs:
  concat :di: and number
  if :dt:
    concat :dt:
  ddebug "dials = <concat>"
  output(concat,:dd:) - output :di:phone:dt: at one crack, dial delay per :lt:
if :dr: - dial response
  sleep(:da:) - :da: interpreted per :lt:
  call input(:dr:)
  if error 
    ddebug "gendial failed <dialer>"
  else
    ddebug "gendial success: respbuf = <response>"
if error
  call gen_disconnect()
  return mis-dialed

ioctl TIOCFLSH - flush buffers

setup alarm handler
when alarm
  ddebug "online failed"
  break
ioctl TIOCCAR - enable software carrier det.
if :cr: - wait for carrier
  ddebug "waiting for carrier"
  call alarm(:fd:) - note :fd: is always in seconds - no :lt: mediation
  ioctl TIOCWONLINE - wait for carrier
  call alarm(0) - unless timed out...
  ddebug "carrier detected"
reset alarm handler
if :os: - online string
  call input(:os:) - note :os: must start within one second of carrier!!!
  if error 
    ddebug "online failed"
  else
    ddebug "online succeded"

if error
  call gen_disconnect()
  return no carrier

if :cs:
  output(:cs:,:cd:) - completion string, completion delay per :lt:

if any errors
  can gen_disconnect()
  return error
else
  return good


gen_disconnect() is called either at the end of a call, or by the gen_dialer
code when a call has been started, but hasn't been completed successfully.

gen_disconnect()
================

  ddebug "gendisconnect"
  if :ds: - disconnect string
    call sleep(1) - one second 
    call output(:ds:,1) - disc string, one second or 1 microsec delay per :lt:
    call sleep(1)
    close device