Jim Lawless is a programmer specializing in C development for Windows for a financial institution. He teaches C & Visual BASIC programming at a local college. He can be reached at [email protected] or 2414 4th Ave., Council Bluffs, IA 51501.
The number of people who utilize online services and electronic bulletin-board systems grows each year. Despite public interest in telecommunication, accessing a modem from an MS-DOS application has been a somewhat arcane science.
MS-DOS provides extremely minimal support for access to the RS-232 communication ports. In fact, MS-DOS relies heavily on the hardware Basic Input/Output Subsystem (BIOS) to handle all of the dirty work related to utilization of a modem as an I/O device. The major problem with utilization of BIOS communication routines is that characters that are sent and received are not buffered. An application must poll the ports frequently to avoid losing data.
Although the BIOS does not readily support lossless RS-232 I/O, the Universal Asynchronous Receiver/Transmitter (UART) chip found in every IBM PC/XT/AT or compatible computer does provide for an interrupt-driven method of accessing the communication ports. The UART can be programmed to generate an interrupt upon reception of data. It can also generate an interrupt when its transmit register becomes empty.
For an application to properly utilize interrupt-driven serial functions, it must perform the following tasks:
1. The application must provide interrupt-processing routines.
2. The application must determine which interrupt is associated with a given communication port. Some RS-232 cards allow non-standard interrupts to be paired with existing communication ports.
3. The application must manipulate the Programmable Interrupt Controller (PIC) chip registers so that it allows interrupts from the UART.
4. The application must manipulate the appropriate UART control registers so that RS-232 I/O finally occurs.
This sounds like quite a bit of complexity just to send and receive data, doesn't it? While communications libraries began to appear to minimize the work involved in writing a telecommunications application, a somewhat more flexible methodology became available in 1987.
Programmers involved in software related to the Fido electronic message network system (particularly with the SEADog mailer, the Opus electronic bulletin-board system, and general Fido driver) found themselves dealing with problems with what were then referred to as "clone" machines. This was at a time when clone machines were still suffering from hardware compatibility problems.
One of the most important problems that they encountered pertained to inconsistencies found in certain UART chips. The obvious answer to the compatibility problem was to isolate the program code to handle the inconsistencies into a single driver with a standard interface. This interface/driver became known as the Fido-Opus-SEADog Standard Interface Layer (FOSSIL).
FOSSIL's interface is an extension of the BIOS interrupt Ox14 interface. FOSSIL incorporates buffered input and output as well as providing functions for video and keyboard I/O. A FOSSIL driver is usually implemented either as an MS-DOS device driver or as a Terminate-but-Stay-Resident (TSR) program.
Utilization of a FOSSIL driver has many advantages, one of which is that just about any programming language can readily access FOSSIL functions through the INT 0x14 interface. This can include some macro scripting languages found with applications such as word processors and spreadsheet programs.
The foremost advantage of utilizing a FOSSIL driver is that applications can more readily tolerate changes and advances in communication hardware. For instance, many workplaces now tie PCs together via Local-Area Networks (LAN's). A FOSSIL driver can be constructed which routes modem I/O from a client PC to a communications-server PC. A terminal program dependent on the FOSSIL interface would not even be able to determine that the modem is actually connected to a separate PC! And newer UART features such as built-in buffering can be automatically identified and activated when the FOSSIL driver initializes.
The primary disadvantage you'll encounter when using a FOSSIL driver will most likely be distribution costs. If you distribute a FOSSIL-based application, you may have to pay a royalty if you plan on distributing the driver as well. While this could be a concern, most distributed FOSSIL-based software simply states that it requires a FOSSIL driver to run (allowing the customers to choose the driver that best suits their needs). See the sidebar for a list of FOSSIL driver products.
Table 1 shows the FOSSIL functions, which are selected by setting the contents of AX (the main 80x86 accumulator register) prior to caling INT 0x14. The contents of AH correspond to the FOSSIL function number called. FOSSIL function 0 accepts values that differ slightly from its BIOS counterpart for initialization of the port baud-rate. Rather than providing support for 110 and 150 bit-per-second speeds, the codes for these two speeds now represent 19,200 and 38,400 bits-per-second, respectively.
FOSSIL functions 0x18 and 0x19 provide a means for an entire block of data to be received or transmitted. While this appears to be something that can be easily implemented by a simple loop, modems exist that allow high-speed DMA (Direct Memory Access) transfers of data. If a FOSSIL driver were constructed to handle these modems and their serial I/O controller chip, utilization of the block-oriented functions would make the actual existence of DMA movement an abstract concept. If DMA transfer capability is not present for the modem/driver combination, transfer duration will be no worse than that of a simple loop utilizing single-character I/O functions.
While FOSSIL provides functions to read the keyboard, get/set cursor position, and display characters to the console, I've chosen to use standard I/O functions from the C library to handle these tasks.
Many of the functions in the miscellaneous section are provided to make construction of electronic bulletin board systems and add-ons for BBSs easier to implement. One such function is the "watchdog" function, which will reboot the PC when a carrier signal is no longer detected. This eliminates the need for complex polling during idle-for-user-input operations. If a user hangs up while the system is waiting for input, the PC is simply rebooted. Finally, timer management functions allow the user to implement timer-interrupt functions by allowing the FOSSIL driver to install and remove timer handlers.
I've provided a short, bare-bones terminal program (FTERM.C, shown in Listing 1) which utilizes a FOSSIL driver solely for its serial I/O capabilities. FTERM initializes port 1 for a 9,600 baud rate. Port parameters are set to an eight-bit word length, one stop bit, and no parity. I purposely built FTERM with a minimal (i.e., non-existent) user interface to show the simplicity of implementing a FOSSIL-based terminal program.
As demonstrated in FTERM, all of the hard work is now handled by FOSSIL. Using FOSSIL, the modem becomes the simple I/O device that we wanted in the first place!