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