Using the Interlisp-D RS232 Facility File: RS232.tty Created: Jan 10, 1983 Revised: Feb 21, 1983, and August 18, 1983, by JonL White Basic RS232 Facililty Support Functions Through a special circuit board plugged into the parallel port of a Dolphin, serial RS232 communications may be interfaced using the following basic functions. As characters arrive in at the interface port, they are stored in a ring buffer (and the output functions will buffer their data in a ring buffer until it is full, or until explicit request is made to force it out). Since there is no microcode support for buffering the characters as they come in, there are some limitations using this facility -- primarily that the user has to call one of the functions which will update the input ring buffer at intervals frequent enough to insure getting all the characters. RS232INIT: before using the RS232 facility, it is necessary to install certain parameters in the INS8250 chip on the abovementioned board; the four arguments to this function correspond to the desired Baud rate (150, 300, 600, . . . 9600 are supported), the number of bits per serial character (i.e., 7 or 8), whether or not to use the 8th bit as a parity bit (and if so, whether parity is to be odd or even), and the number of "stop" bits (except in unusual cases, 1 the default value, is used here). CAUTION: the value of RS232INIT as a global variable is used by these driver functions; do not reset it at any time. A global variable, RS232XON\XOFF?, if non-NIL, causes the driver functions to look for ^S on the incoming side, and to "gag" the output transmitter until a subsequent ^Q has been received; it will probably cause undue trouble to set this flag to true if the corresponding host doesn't also obey the XON-XOFF protocols. This value is, of course, temporarily turned off by the FTP protocols, which transmit and receive random bytes. RS232CLEARBUFFER: one argument, typically one of (IN OUTPUT BOTH) the corresponding ring buffer is cleared (and the data lost); also, return will be delayed until any character currently being sent out by the INS8250 chip has been fully transmitted (this way, not only is the ring buffer empty, but so is the one-character buffer in the INS8250). RS232FORCEOUTPUT: no arguments. Ensures that all data in the output ring buffer is actually transmitted "on the lines". One use of this function is to ensure that all data are out -- it won't return until this is true [but also see RS23BACKGROUND below]. RS232BACKGROUND: one argument, "state" The "state" argument must be among {OFF, INPUT, OUTPUT, BOTH, ON}; except for input of OFF, this turns on a background low-level process which will service the UART at least once every 16 milliseconds and/or flush out the output buffer. A "state" of OFF shuts this background activity off. A "state" of INPUT causes only the input buffer to be serviced; OUTPUT for only the output buffer, and either ON or BOTH for both buffers. A period of 16 milliseconds for the input service time should give the appearance i of asynchronous buffering, without dropping any characters, when used at speeds of less than about 600 baud. RS232PEEKBYTE: no arguments. Returns the next character sitting in the input ring buffer, if any; the hardware port is checked to see if any input characters are waiting, and if so they are put into the ring buffer first. Calling this function is a good way to insure that characters are moved, in a timely fashion, from the chip to the input ring buffer. RS232READBYTE: two optional arguments. This is the basic input function, which will return a fixp of up to 8-bits in length. If no character is available, it will return NIL; but if the first argument is a fixp, then it will wait up to that many time units before returning (possibly getting an incoming character in the meantime); if the first argument is any other non-NIL value, the it will wait (possibly forever) until some byte comes in to be returned. The second argument determines the length of a "time unit"; default is milliseconds, but alternatives are SECONDS and TICKS (which is the internal Dolphin clock unit -- see the documentation of DURATION). As with RS232PEEKBYTE, any call to this function will update the input ring buffer as its first action. RS232READWORD: arguments as in RS232READBYTE. If two bytes can be read in the alloted time, they are composed into a "word"; the first byte comprises the high-order 8 bits of a 16-bit word, and the second byte comprises the low-order 8 bits. RS232READLINE: three optional arguments. A sequence of characters is read, until an End-of-Line character is received; all the characters except the EOL are returned as a string. The first two optional arugments are interpreted exactly as the two optional arguments to RS232READBYTE; that is, if the expected EOL is not seen "in time", then NIL is returned. However, if the third argument is supplied, it must be a string pointer, and it will be re-used to return the characters accumulated so far, even if there is a timeout; note that the "characters accumulated so far" are merely sitting in a local "RS232READLINE" buffer, so succesive calls will reuse that buffer. One other caveat: up to 8 character times are dallied after receiving the EOL, to see if it is followed by a line-feed, and if so, the line-feed is flushed. RS232READSTRING: six arguments, most optional. (#chars.limit? stopcode? noblocksflg wait? timerUnits oldstrbuffer) This function will take input bytes from the RS232 port until one of three conditions obtains. (1) the total number of characters taken in by this call is equal to "#chars.limit?" [NIL means no limit]; (2) a character is read with character code equal to the argument "stopcode?" [NIL means no limiting charcter]; or (3) an interval of time greater than that specified by "wait?" has passed with no bytes available at the port. If "wait?" is non-null, it must be an integer, and "timerUnits" specifies the units (see section 14.6 of new manual "Timers and Duratin Functions). i If "noblocksflg" is non-null, then RS232READSTRING will consume all the CPU cycles without offering to yield to other processes [including the MOUSE process]; this mode is important to very-time-critical applications. If "oldstrbuffer" is supplied, it must be a string and the result characters are smashed into it [so that no consing is done]. RS232WRITEBYTE: one argument required, one optional. An 8-bit byte is sent out; actually, if the second arg is NIL, it will just be stored in the output ring buffer, and will be forced out if the buffer starts to get full. Additionally, the ringbuffer will be forced out if the second argument is non-NIL (or whenever there is an explicit call to the function RS232FORCEOUTPUT, or from time to time when RS232BACKGROUND has specified background output from the buffer -- see documentation above.). RS232WRITECHARS: one argument required, one optional. First argument is either a litatom or string, and all the characters therein are "written"; second argument is interpreted the same as with RS232WRITEBYTE. RS232SENDBREAK: one optional argument. The out-of-band BREAK signal is transmitted for a period of 0.25 seconds; if the optional argument is non-NIL, then the period is extended to 3.5 seconds. RS232MODEMCONTROL: one argument, "signalslst". A NoSpread function which sets the modem control lines to be "on", for the signals in the list "signalslst". Returns the former setting of the lines. If "signalslst" is not supplied [which is not the same as supplying NIL], then the control lines are merely returned. The entries in "signalslst" are litatom names for standard modem control lines. Current signal names usable are DTR and RTS. RS232MODIFYMODEMCONTROL: two arguments "signalsonlst" and "signalsofflst" Changes only those modem control lines specified in the union of the two arguments; those in "signalsonlst" are set to be on, and those in "signalsofflst" are set off. Returns the former state just as (RS232MODEMCONTROL) does. RS232MODEMSTATUSP: one argument, "booleanform" Returns non-null iff the reading of the modem status lines is consistent with the form "booleanform" [modem status signals currently supported are CTS, DSR, RI, and RLSD]. "booleanform" may be any AND/OR/NOT combination over the signal names. Example: (RS232MODEMSTATUSP '(AND CTS (NOT RLSD))). RS232MODEMHANGUP: no arguments Takes whatever steps appropriate to cause the modem to "hang up" [mostly, this means turning the DTR signal down for about 3 seconds, or until the DSR signal has gone down]. The {RS232} device is created by RS232INIT; one can obtain a stream interface to the RS232 port by calling (GETSTREAM '{RS232} ). However, in most cases, this stream approach will not work unless the asynchronous buffering mentioned above is successful -- the time taken by general I/O operations is unpredictable and often quite large. The global variable RS232XON\XOFF? controls whether or not these driver functions will participate in an XON/XOFF protocol; when non-NIL, the any incoming XOFF character (the ^S of ascii) will cause the output functions to "hang" until a releasing XON character has come in (the ^Q of ascii). Also the global variable RS232XOFF? will reflect whether or not the the port is currently in the "hanging" state. The hardware will detect the usual error conditions (dropped characters, parity errors when so initialized, and framing errors) in addition to detecting a BREAK being sent. When a BREAK has been detected, the software will set the global variable RS232BREAKSEEN? to non-NIL; it will also check the value of RS232BREAKFN, and if non-NIL, will apply it to NIL. Similarly, if there is any error condition which causes a character to be dropped, the software will apply the value of RS232LOSTCHARFN to a litatom describing the reason for the lossage; the default value for RS232LOSTCHARFN is \RS232DING, which will "flash" the display screen a couple of times, and put the value of \RS232.DROPPEDCHARACTER.CODE into the ring buffer [initially this is set to (CHARCODE #^G)]. RS232LOSTCHARFN must, at all times, be a runnable function. RS232CHAT Facility The function RS232CHAT, with four optional arguments, initiates a full- duplex transmission throught the RS232 port. The first argument is coerced into a stream for printing the received characters (default is to use the window in the value of \RS232CHATWINDOW, which if null, will interactively ask the user to lay out a region for such window); second argument, if non-null, is a user-programmable interface for filtering the characters which arrive from the remote correspondent -- it must be the output of the function MAKEBINHOOK [as of August 18, 1983, this facility isn't quite ready -- it's primary application will be to provide a flexible means for emulation of the various semi-smart terminals like the Heath-19 etc.]; third argument, if not null, specifies that local echoing of the typed-in characters is to be done, with T meaning to use the same stream as the first argument, and any other value being coerced into a stream to use for local echoing; fourth argument is whether or not to use the XON\XOFF protocol. While in "chat" mode, character interrupts are shut off, the keyboard is rather plainly interpreted, and characters typed in on it are sent to the correspondent. Ordinarily, a host will send a CR/LF for "newline", but some send only one; the menu selection lets you pick one or the other if this is the case (especially useful with UNIX systems). Similarly, you can specify that the RETURN key (or, EOL key) send either just CR or both CR/LF. If local echoing is being performed, and it the local echo stream is the same as the main RS232CHAT window, then the locally-generated characters will be enclosed in square-brackets, as a means of distinguishing local echo from remote output. Caveat: Output to the the Dolphin display takes a non-trivial amount of time (e.g., just going through the character printout routines, and "painting" a character onto the screen bit-map requires over a millisecond; scrolling a modest-sized window may take well over 30 milliseconds). Without additional microcode support, to maintain the input ring buffer asynchronously, it is questionable whether rates above 2400 baud will be acceptable for RS232CHAT, and there may be ocasional problems above 1200 baud). At "slower" speeds, that is, at less than about 600 baud, the use of RS232BACKGROUND may alleviate these problems. However, RS232CHAT will pay attention to the DSPSCROLL setting of the chat window, and will do "roll" mode rather than "wrap" mode provided that it can do so without dropping characters ["roll" describes the "scroll up" action when typeout reaches the bottom of the window]. If the XON/XOFF protocol is being used, or if the background process mentioned above is in operation, then likely there will be no problem is using "roll" mode. Escape from "duplex" mode is made by typing the the character which is found in the value of \RS232ESCAPE.CHARCODE, currently initialized to (CHARACTER #B) [this happens to be middle-blank]. Typing "?" just after the escape character will give a small "help message; the commands to be used in this mode are all one-letter: B - send a BREAK (0.25 seconds) E - change the escape character F - deactivate the XON\XOFF protocol H - call the function (HELP), with interrupts re-activated L - call the function (RS232.PROMPT&LOGIN) O - set the XON\XOFF protocol active Q - for quit and exit, presumably back to LISPX S - set the speed of the RS232 port; ? will display choices. - 'Return' key sends to remote host - 'Return' key sends to remote host ^B - run a "break" or HELP loop R - call RAID 7 - truncate incoming characters to 7 bits (this is necessary when you have opened an 8-bit connection ignoring the parity bit; you really only want to see the lower 7 bits interpreted as a character to be printed on the window). 8 - undo the "7-bit" mode above (just in case you actually wanted to see the eight bit -- typically the printout will be just the same as as the 7-bit printout, but preceeded by a "#" when the eighth bit is on in a character.) Additional control may be exercised with the pop-up menu obtained by pressing the middle mouse button with the cursor in the RS232CHAT window while RS232CHAT is active; its commands are essentially self-documenting, and are a super-set of the above-mentioned commands available from the keyboard. In particular, it's possible to alter what RS232CHAT thinks is the "NewLine" character; Interlisp-D's default is to choose CR, but for connections to some systems, LF is a much better choice. Two other commands permit "toggling" (that is, switching the state from one choice to an alternate, and vice-versa): ~LocalEcho and ~RollMode. The latter will change the DSPSCROLL of \RS232CHATWINDOW; the former will "toggle" the use of the local echo stream provided in the call to RS232CHAT (or will use \RS232CHATWINDOW if no stream was provided). The RS232CHAT window tries to play the "TTY-process passing" protocol described in the recent documentation for multiple-process and TTY interactions. A number of variables control certain characteristics; in addition to \RS232ESCAPE.CHARCODE mentioned above, there are: \RS232PERMITTED.INTERRUPTS -- a list of items such as returned by INTERRUPTCHAR (or such as would be input to RESET.INTERRUPT), which will be "active" during RS232CHAT; initially this list is null. \RS232CHAT.IgnoreCharcodes -- a list of character codes that will be ignored by the input side of RS232CHAT; initially this list contains only the single code (CHARCODE NULL). \RS232CHAT.EOLsequence -- A string of characters to be sent out whenever the RETURN key is typed on the keyboard; initially this just contains the one character CR, and is changeable by a menu command. \RS232CHAT.NEWLINECHAR -- Normally set to LF, which will cause RS232CHAT to work right for systems which send both CR/LF for newline as well as for those that send only LF (e.g., UNIX). However, some hosts send only CR, and thus to get RS232CHAT to advance to a new line, CR must be recognized as the "newline" character. This option is changeable by a menu command. Note that this section isn't talking about the EOL character. \RS232CHAT.BellSequence -- Since the standard Interlisp-D action for printing a "bell" to a display stream takes too long (much longer than the inter- character time at 1200 baud), then unless the XON\XOFF protocol is active, this string of characters will be substituted for the (CHARCODE BELL). Initially, this is "^". The following two functions are most useful when trying to "chat" to a host through an RS232 connection running at a speed higher than Interlisp-D can support for display stream activities: RS232LOGIN: 6 arguments, most optional. First is the name of a host machine with which the RS232 port is corresponding, second is the desired username/login.id on that machine, third is the password needed there, and fourth is the "host system type"; the remaining two arguments are concerned where to echo the activity caused by this function, and are mainly of interest to other system-level functions. If either "username" or "password" is NIL, the will be obtained via PROMPTFORWORD from the keyboard (this is so that you don't have to have passwords in code files); there is also an internal cache of the information about host/username/password, just as is kept for logins over the Ethernet. [see documentation of PROMPTFORWORD] When the Host's system type is known, then a database of login protocols is consulted to figure out how to send (automatically and blindly) the necessary characters to effect a login. At convenient moments, the output from the host, which is accumulated in the RS232 line buffer, will be output for the user's perusal (the fifth argument is a stream for this printout: NIL defaults to the primary output, NONE gags this type-out; window, files ets. all are acceptable here). A primary reason for this function's existence, besides the cacheing of such information as login.id and password, is to permit loggin in at speeds which cannot support RS232CHAT (see documentation below). RS232.PROMPT&LOGIN: one argument. Prompts the user (via PROMPTFORWORD) to type in the necessary information, in the PROMPTWINDOW, to call and use RS232LOGIN; the argument is handed to RS232LOGIN as its fifth argument (the "Type-out stream" argument). RS232 "FTP" Facility Two functions exist for interfacing to a new protocol for doing file transfers over an RS232 connection; the primary version of this new protocol was developed in the micro/home computer world, where there was a need to transfrer files between a "home" computer and some major, RS232 accessible host. Since the RS232 connection was most often made through a telephone modem, this protocol has come to be known as MODEM; unfortunately, since CP/M was the predominant operating system on these "home" computers, the protocol does not provide a totally secure way of knowing how long a file really is; furthermore, the packet size is fixed at 128 bytes, and some systems have input buffers for which this is frequently too large. [But I have some variants on this protocol which solve these problems, and I intend to certify their implementation in Interlisp and suggest them to the other MODEM users]. Nevertheless, the protocol does have packetizing, checksumming, and timeouts; so there is only a very small probability that a file so transmitted will have undetected errors. RS232GETFILE: three required arguments, and one optional. First argument is the name of a file to store the file being transmitted *from* the correspondent; second arg is either TEXT or BINARY (ASCII permissible in place of TEXT), indicating the file type (in the Interlisp-D sense); third argument is the protocol being used (currently, only MODEM is acceptable here); fourth argument, when given is just transmitted first (typically, this would be the series of characters you would type at the remote executive to cause the desired file to be run). RS232PUTFILE: arguments the same as for RS232GETFILE, except that the direction of transmission is from the existing file on the Dolphin *to* the correspondent. Examples: (assuming connection to a TOPS-20 host) (RS232GETFILE '{DSK}MUMBLE 'TEXT 'MODEM "MODEM SA MUMBLE ") (RS232PUTFILE '{DSK}RUN.DCOM 'BINARY 'MODEM "MODEM RB RUN.DCOM ") Both ends of the MODEM protocol have "synchronizing" features, so a typical scenario of usage would be to use RS232CHAT to login to the host, and then simply put the MODEM program in its wait state, by typing whatever arguments it needs, and finally exiting from RS232CHAT and calling RS232GETFILE (or RS232PUTFILE) directly, without the fourth argument. The fourth-argument facility is provided so that one may use RS232FTP at speeds greater than would be available for RS232CHAT; login could thus be achieved through use of the function RS232.PROMPT&LOGIN. The global variable RS232FTPTRACEFLG, if non-null, causes a trace of activity to be printed out on the file/stream specified by the global variable RS232TRACEFILE; it the value is PEEK, then only a "+" will be printed for successful transit of packets, and "-" for unsuccessful ones; any other non-null value causes a more verbose output. Several implementations of the MODEM protocol for other machines are available: one for the IBM/PC is available on floppy disk through XSIS (and is also on [MAXC]IBMFTP.ASC). Several files are available also on [MAXC] for VAX/VMS users: XMODEM.FOR and QIO.DCK are an implementation in FORTRAN; TOXMOD.FOR and FMXMOD.FOR are helpful for dealing with the structure of files in VMS's record management system.