Linda, I have marked some keywords with <*...*>. If possible, please print in some highlighted form (bold, etc). The file CRC16.MAC holds the routine mentioned in the last section. The Non-Terminal Terminal Most RSX system managers would turn white when told the new data entry clerk could type at the rate of 12,000 words-per-minute. Yet the same managers would not think twice about hooking a pile of black boxes to the same system as a non-terminal terminals, even though a single black box outputting steadily at 9600 baud equals a 12,000 WPM typist. EIA-232D (formerly RS-232C) is the most popular computer interconnect standard in the world. It is trivial to hook a 25-pin connector to any of the thousands of black boxes which speak ASCII. It is quite another matter to get RSX to communicate with the box. This article looks at different techniques you can use to input and output to non-terminal terminals. Asynchronous serial interfaces appear to be one of the easist PDP-11 peripherals to program. You simply move characters between the computer and device. EIA-232D I/O is a problem because RSX, like almost all operating systems, assumes the device at the other end of the wire is a human using a terminal. The software provided by RSX for asynchronous interfaces, the terminal driver, is geared toward the idiosyncrancies of people communications. People and terminals tend to have exactly opposite performance characteristics from black boxes. 99% of all normal terminal traffic is display output. Any input which does occur is at a very low effective baud rate. A 100 WPM typist does not even reach 110 baud. Finally, people I/O is very interactive at the lowest level. The terminal user expects immediate feedback to every keystroke (echoing) and can and will perform direct error correction (RUBOUT, Control-U). Some black boxes follow the human model and present no problems. However a large class of black boxes reverses the input/output ratio. Almost all character traffic is generated by the black box and sent to the computer. The computer transmits only a few short control sequences to the black box. Black boxes are also not restricted to the frailities of fingers and are capable of true 9600 baud output. Black boxes also tend to be very simple minded about error detection and correction. Most do nothing. The most common black box is another computer. The communications problem is doubled because each system assumes the other system is human. The classic "MCR Huh?" syndrome shows some of the problems common to non-terminal terminals. Any traffic generated by system A, such as a broadcast to all terminals, causes system B to return an error message as well as echoing the initial message. System A blindly echoes the echo and eventually responds with an error message of its own. The two systems continue to esculate the garbage war until performance on one or both systems degrades sufficiently and the system(s) lock up. Terminal Characteristics -------- --------------- The RSX full-duplex terminal driver assigns 38 different characteristics to each terminal line. When a black box is connected to a line instead of a terminal, the characteristics values suitable for a terminal do not work. It is critical for proper operation to change some of the characteristics to match the needs of the black box. Terminal characteristics can be changed by VMR or MCR SET commands or by program control. When terminal lines are permanently assigned to particular terminals and black boxes, the appropriate SET command should be issued from either VMR or the system startup file. I have always found it useful to keep all terminal SET commands in a separate file and use with VMR to permanently establish terminal characteristics in the boot image. Using VMR makes sure the appropriate characteristics are set the moment the system is booted and saves some time during system startup. Anytime a terminal characteristics changes, the characteristics command file is editted and used with VMR to reset terminal characteristics. The same command file can also be used interactively to reset the terminal characteristics of a running system. A task can also set terminal characteristics using the Set Multiple Characteristics function (SF.SMC). This approach is used for terminal lines attached to terminal switches or dial-up modems and thus have no permanent definition. There are also some characteristics which can only be set using the SF.SMC function. Experience shows the following seven terminal characteristics functions have special importance to non-terminal terminals. Some functions such as no-echo or read-pass-all can also be issued on a per I/O basis using the appropriate subfunction code. It is a better practice, however, to set the line characteristics. This eliminates any window which could occur between I/O functions. <*Slave*>. A slave terminal cannot issue MCR/DCL commands. A slaved terminal ignores the Control-C character and discards any unsolicitated input. Unless the black box occasionaly acts as a terminal emulator, the terminal line attached to a black box should always be set slaved. <*No Echo*>. The terminal driver normally echoes input characters back to the display. Many black boxes would be confused by character echo, which can simply be turned off by setting the line characteristic to no echo. <*Full-Duplex*>. The terminal drivers default mode processes one QIO at a time. In effect, terminal I/O is half-duplex. Terminal output is blocked by any pending terminal input. Setting the full-duplex characteristic allows a terminal line to be treated as separate input and output devices. A read QIO does not block a write request. <*Read-Pass-All/Eight-Bit*>. Some black boxes use only the printable character subset of the ASCII codes and thus cause no particualar problems for the terminal driver. However, other applications may use the control characters (000-037) or pass binary information using all eight data bits. Such black boxes should set the read-pass-all and eight-bit characteristics so terminal I/O is analogous to an eight-bit data channel. No interpretation of characters is performed. <*Parity*>. When seven-bit ASCII codes are used, the high data bit may be used as a character integrity check. The parity characteristics can only be enabled by the SF.SMC I/O function. Parity checks are enabled by the TC.PAR characteristics. The TC.EPA characteristics is set non-zero to select even partity, otherwise odd parity is used. <*No Broadcast*>. Any privilege RSX task can issue an output to a terminal which will breakthrough any pending I/O or attach status. One common example is the BROADCAST /ALL command. Setting the no broadcast characteristics sets a status flag which is obeyed by the BRO utility. <*Type-Ahead*>. RSX offers a varity of type-ahead buffering. On RSX-11M, this option determines if a one or 36-character type-ahead buffer is available. RSX-11M-Plus uses this characteristic to set the type-ahead buffer size. Input Overflow ----- -------- Non-terminal terminals problems can be grouped into in three major areas: input overflow, non-standard characters, and error detection. The most common problem is input overflow. The problem is simple. Whenever a character is received by the terminal driver, the character must be stored somewhere. If a read has been posted, the terminal driver stores the character in the supplied buffer. Otherwise, one of two actions occur. For slaved terminals, the character is simply discarded. Normal terminal lines have a worse problem. The terminal driver assumes the character starts an unsolicited command and begins a MCR/DCL command line buffer. Under these conditions, the simple FORTRAN-77 READ loop shown below should be able to read lines forveer from a black box hooked to a slaved terminal line. The problem is the gap in time between when a line is read and the program loops and issues the next READ. CHARACTER*80 LINE 1000 READ (5,2000) LINE GOTO 1000 2000 FORMAT (A) END If the black box does not pause long enough after sending a carriage return, the next character will be discarded. While it appears at first glance that only a very short pause is needed, in fact the length the black box should wait is indefinite. Other tasks executing on the system may block the above program from immediately executing when the READ statement finishes. Terminal input overflow is solved using a three-step solution. First, the terminal driver type-ahead buffering mechanism is enabled for the terminal line. With type-ahead buffering, the terminal driver will now store in temporary storage some number of characters before discarding overflow. RSX-11M system can store up to 36 characters. RSX-11M-Plus systems can use the SET /TYPEAHEAD command to set a buffer size up to 255 characters. Type-ahead buffering is enabled only when the terminal line is attached by a task. This is the reason the sample program above fails. There is no statement in Fortran or other high-level languages which causes terminal lines to be attached. To enable type-ahead buffering, the sample program must issue the attach QIO as shown below: PARAMETER IOATT 3*256 CALL WTQI0(IOATT,5,,,,) Type-ahead buffering starts to close the lost character window. In some slow speed applications, type-ahead buffering may be sufficient. If not the second step to take is to multi-buffer incoming I/O. When the terminal driver finishes one I/O buffer, the driver can start the next request immediately. Multi-buffer algorithms were covered in this column in the April 1985 issue. Finally, the task must run at the appropriate priority. All other measures will be to no avail if the program processing character input is blocked from timely execution. At 9600 baud, a character arrives every millisecond. A 36 character type-ahead buffer gains you a 36 millisecond window before characters are discarded. Multi-buffering extends the window only to some finite limit. Some applications involve bursts of high-speed traffic. One recent application I work on involved a UNIX system which sends 60 lines of data at 9600 baud every 15 minutes. A high priority task is needed to not miss any input, but the actual analysis can take place in the background. The solution is to break the application into two tasks. A small high-priority task attaches the terminal line and uses double buffering to input the text to a disk file. When all 60 lines of data are input, the task sends a message to the background analysis program. The first task then loops and waits for the next burst of activity. One common mechanism used to control terminal traffic is XON/XOFF flow control. Terminal users are very familar with using Control-Q (XON) and Control-S (XOFF) to start and stop display output. Unlike some systems which issue XOFF when the type-ahead buffer fills, RSX does not have any standard means to use XON/XOFF for terminal line input. If the black box understands the XON/XOFF conventions, it is possible to issue the flow control characters from an application. The trick is to use the read-after-prompt function (IO.RPR) with send XOFF subfunction (TF.XOF). You use a Control-Q character as the prompt character. This causes the black box to resume sending characters. When the input is complete, the TF.XOF subfunction tells the terminal driver to send a XOFF to the black box. Note that TF.XOF is ignored if the line is set to full-duplex. Non-Standard Characters ------------ ---------- The RSX I/O Drivers Reference Manual documents 13 control characters and three other characters (ESCape, RETURN, and RUBOUT) which have special meaning to the terminal driver. If a black box is sending binary data, these characters cause problems. The solution is to turn the terminal line into a eight-bit data channel by using the Read-Pass-All and Eight-Bit Data characteristics. The terminal driver no longer interprets any character. The major problem with this mode is determining when input is finished. A standard read function will only finish when the input buffer is filled. If input lines are a standard length, this mode presents no problem. There are several methods to handle variable length input. The best is to use some special character or characters as a line terminator. This assumes the character(s) do not occur anywhere else in the line. The IO.RTT function is used to specify which characters are line terminators. The IO.RTT function uses a 16-word bit table to list which of the possible 256 bit patterns may terminate the line. If it possible that all bit patterns can occur in a line, it is still possible to use the IO.RTT function. One character is chosen as a line terminator and another as an escape character. Before a message is sent, the buffer is scanned for both characters. When either are found, the character is changed to some other character (for instance incremented) and a escape character inserted before it. The line terminator is put at end of the buffer. The receiving program removes any escape characters and converts the next character to its original value. Naturally, infrequently used bit patterns should be used for the line terminator and escape characters. A analysis of variety of disk files show octal values 277 and 247 are reasonable choices. Error Detection ----- --------- Terminal lines are an imperfect media, especially when modems and the telephone system are involved. Any program reading data from a black box should include logic to detect transmission errors. For dumb black boxes, error detection is simply scanning for impossible characters and character sequences. For instance, the output from a laboratory instrument may be a line with 6 five-digit decimal integers. The input program should reject any lines with non-numeric characters or missing or too many digits. Black boxes which use just the ASCII character set may use the parity bit as a simple frame check for each character. The eigth bit is set so the total number of one bits in the character is either odd or even. The RSX task can enable parity checking using the SF.SMC function. Any parity error dected by the terminal driver will result in IE.VER error status. Parity checks detect some errors, however, some common errors can escape detection. For instance, if line noise generates the character 'A', no error is detected for even parity lines. The best error detection uses some form of checksum. The transmitting program passes the each character in a message through some algorithm. The resulting integer value is appended to the message sent to the receiving system. The receiver uses the same algorithm to recompute the sum and compares to the received value. If not equal, a bad message was transmitted. The simpilest checksum algorithm is straight summation or exclusive-OR. Each character is added or exclusive-OR to the previous sum. These algorithms are work very well when combined with a parity check for each character. A more rigorous algorithm, particularly when passing eight-bit data, is a cyclic redundancy check or CRC. DECnet uses one type of CRC check called CRC-16 for its DDCMP protocol. See the listing of CRC16.MAC for a for a Fortran-callable function with computes CRC-16 checksums using a table lookup algorithm. In summary, non-terminal terminals are easy to handle with proper programming. You start by setting the appropriate terminal characteristics. Your program listening to the black box should attach the terminal line so type-ahead buffering is enabled. If the black box sends ASCII control characters, the terminal line should be used as an eight-bit data channel. Finally, your program should expect some errors from terminal lines and take appropriate action. Most often the correct action is to ignore the offending input line.