                            Chapter 1 - Introduction

     This package of asynchronous communications tools for IBM (COM1 - COM4)
and Digiboard (intelligent communications hardware, up to 32 ports) hardware,
consists of library (.LIB) files for each memory model (SMALL, COMPACT, MEDIUM,
LARGE), and for both IBM and Digiboard hardware.  It also includes all of the
source files, header files (with prototypes) and MAKE files needed to generate
the various libraries.  Batch files are included for calling make with
appropriate flags for each supported compiler.

     With standard IBM asynchronous hardware, two ports can be opened
simultaneous in any of the following combinations (limited because of only 2
interrupts allowed for asynchronous ports in DOS).

        ALLOWED                  NOT ALLOWED

        COM1 and COM2            COM1 and COM3
        COM1 and COM4            COM2 and COM4
        COM2 and COM3
        COM3 and COM4

     A working knowledge of 'C' and operation of your compiler is assumed.

     The "shareware" version is configured for the BORLANDC++ V3.0 compiler in .
LIB format, and comes with the small memory model library only (ASYNCS.LIB).
Header files with module prototypes for the library routines are included, as
well as TEST.C for testing the modules on your system.  No other source code is
provided with the shareware version or support for Digiboard hardware.

     Also included are useful demonstration utilities as described in .

     Becoming a registered user will provide full source code to every module,
support for other C compilers, 3 more utility programs, and a bound laser
printed manual.  There is also full support for Digiboard communications boards
which will allow up to 32 ports on your PC.  You will also be put on our
registered users' list and receive upgrade notification whenever new, expanded
versions become available.

     To register send a check for $45 to:

               Nordtech Research, Inc.
               P.O. Box 1011
               1608 North Fourth
               Fairfield, Iowa  52556

               Or by phone:                  (800) 274-7820  (515) 472-7820

               Or by Compuserve Mail:        73200,2371

               You may also register online with Compuserve.

               Or by FAX:                    (515) 472-3524

     You can also pay with Visa or Mastercard.  Provide your card number and
expiration date.  Please include the spelling of the name on the credit card.
Always include your shipping address.

     To order by phone, call (800) 274-7820 (please use 800 number for ordering
only) or (515) 472-7820.

     There is a registration/order form in the file README of the shareware
version.

                            Chapter 2 - Installation

     Registered users will receive 2 diskettes.  The first diskette contains
all files for standard IBM communications hardware (COM1 - COM4).

     The second diskette contains code for use with Digiboard hardware.  If you
are not going to use Digiboard hardware, file this diskette.  If you are,
follow the instructions below for both of your diskettes.

     First, place the diskette into the floppy drive and then copy all of the
utility programs in the root directory of the diskette into the directory where
you will place the library source code (for now).

     All of the utility and library source files, make files, batch files and
the file README are archived into the file \SOURCE\SOURCE.ZIP (and
\SOURCE\DSOURCE for Digiboard).  If you desire to modify the library or want to
look at these files, copy this file to the directory where you normally put
your source code or to a new directory of your choice.  Also copy the public
domain utility PKUNZIP.COM (in the \SOURCE directory).  Type PKUNZIP SOURCE
(DSOURCE for Digiboard) to uncompress all of the source files, make files and
batch files.

     Then follow the directions below for you specific compiler.  The following
sections assume that you have structured your subdirectories according to the
directions for each of the compilers supported.

2.1 Shareware Version

     The shareware version contains only the BORLANDC small memory model
library (ASYNCS.LIB), include files (*.h), and DATAMON.EXE (a nifty data line
monitor program for debugging and testing RS-232 devices).  All files are
compressed together into ASYNC.ZIP.

     First copy ASYNC.ZIP to the subdirectory where your C source files are
kept.  Then type PKUNZIP ASYNC to uncompress the files.

     Copy ASYNCS.LIB to your \BORLANDC\LIB subdirectory.

     Copy *.H files to \BORLANDC\INCLUDE subdirectory.

     Print out READMEBC and this manual if desired.

     Follow instructions in  to test your installation with a simple
communications test program.

2.2 BorlandC Version

     Copy \BORLANDC\LIB\*.LIB to your \BORLANDC\LIB subdirectory.

     Copy \INCLUDE\*.H files to \BORLANDC\INCLUDE subdirectory.

     In your autoexec.bat file make sure you define the following environment
variables to the proper directory.

     SET INCLUDE=C:\BORLANDC\INCLUDE\
     SET LIB=C:\BORLANDC\LIB\
     SET BIN=C:\BORLANDC\BIN\

     Print out README for latest changes.

     Follow instructions in  to test your installation with a simple
communications test program.

2.3 ZORTECH Version

     Copy \ZORTECH\LIB\*.LIB files to your \ZORTECH\LIB subdirectory.

     Copy \INCLUDE\*.H files to \ZORTECH\INCLUDE subdirectory.

     In your autoexec.bat file make sure you define the following environment
variables to the proper directory.

     SET INCLUDE=C:\ZORTECH\INCLUDE\
     SET LIB=C:\ZORTECH\LIB\

     Print out README for latest changes.

     Follow instructions in  to test your installation with a simple
communications test program.

2.4 QuickC Version

     Copy \MSC\LIB\*.LIB to your \QC\LIB subdirectory.  Or to the \LIB
directory if this is where you QuickC library files are kept.

     Copy \INCLUDE\*.H files to \QC\INCLUDE subdirectory.  Or to the \INCLUDE
directory if this is where your include files are kept.

     In your autoexec.bat file make sure you define the following environment
variables to the proper directory.

     SET INCLUDE=C:\QC\INCLUDE\
     SET LIB=C:\QC\LIB\

     Print out README for latest changes.

     Follow instructions in  to test your installation with a simple
communications test program.

2.5 MSC Version

     Copy \C600\LIB\*.LIB to your \C600\LIB subdirectory.  Or to the \LIB
directory if this is where you MSC library files are kept.

     Copy \INCLUDE\*.H files to \C600\INCLUDE subdirectory.  Or to the \INCLUDE
directory if this is where your include files are kept.

     In your autoexec.bat file make sure you define the following environment
variables to the proper directory.

     SET INCLUDE=C:\C600\INCLUDE\
     SET LIB=C:\C600\LIB\
     SET BIN=C:\C600\BIN\

     Print out README for latest changes.

     Follow instructions in  to test your installation with a simple
communications test program.

                       Chapter 3 - Demonstration Program

     The following code can be used to test this communications package.  It is
a simple terminal emulation program which reads characters from COM1 and
displays them, and sends characters typed at the keyboard out COM1 (change
statement in initialize() module if COM2-COM4 is desired).

     The baud rate as configured is set to 1200 but can be set to any legal
value (as defined in ASYNC.H) by changing value in call to Async_Open in the
module initialize().

     The file TEST.C is included in all versions of the software and contains
the code shown in section .

     Do not attempt to develop larger programs with the library until you can
get TEST to work and you fully understand the program.  It is quite simple and
should be mastered within a few minute's time.

     Note that this file has included ASYNC.H.  ASYNC.H should always be
included in any program using these tools.  The include file VID.H is included
from ASYNC.H to allow generic support for direct video as explained in section
.  Other tools (file transfer, windows, etc) have other include files as
defined in the introductory paragraphs to each of the individual sections
discussing modules and files.

     Note the calls to Async_Init and Async_Open.  These modules must always be
called prior to any use of the other Async modules.

3.1 Compiler Independent Direct Video

     All of the supported compilers support direct access to the screen (much
faster than using BIOS calls).  To allow compiler independent calls to these
routines the include file VID.H is supplied.

     The code you develop does not have to take advantage of these routines,
but if you intend to modify the ASYNC library modules, it is recommended that
you look at this include file to see how they work.

     As an example TEST.C below demonstrates their use.  The first call to
VID_open is needed for the Zortech version.  All other compilers require no
initialization, and therefore VID_open is a dummy macro in VID.H for BorlandC,
QuickC and MSC and is redefined to disp_open for Zortech.  VID_putc is for
character output, VID_puts for string output and VID_printf for formatted
output.  VID_startstand sets all following characters to reverse video,
VID_endstand sets the following characters to normal video.  VID_clr_scr erases
the entire screen.  VID_move(x,y) moves the cursor to row x, column y (0,0 is
upper left).

     Microsoft (MSC and QC) users should be aware that using direct video
requires linking with the GRAPHICS.LIB library that came with your compiler.
This makes programs grow quite large.

3.2 EXTERN symbol

     You will notice that the first statement in TEST.C is:

     #define EXTERN

     This symbol is used by ASYNC.H and other header files to determine if this
is the main module where variables are not defined as "extern".  ASYNC.H and
the other header files first check to see if EXTERN is already defined and if
not they create it as:

     #define EXTERN extern

     Only define EXTERN (#define EXTERN) in your main module to tell the
compiler that it should place the global variables there.

3.3 BorlandC Command Line

     To compile TEST.C and link it with the async library small memory model
library, type the following:

     tmf test S

      After successful compilation, type TEST and press .  As you type
characters they will be sent out COM1.  Characters received at COM1 will be
displayed on the screen.  Press  to quit back to DOS.

3.4 BorlandC Environment

     First create a project file called test.prj which has the following lines:

               test
               asyncs.lib

     Then enter the BorlandC environment (BC) and name the project file TEST.
Set a compiler DEFINE to be _BORLANDC and then RUN.   After successful
compilation, the screen will blank and as you type characters they will be sent
out COM1.  Characters received at COM1 will be displayed on the screen.  Press
to quit back to the BORLANDC environment.

3.5 Zortech C

     To compile TEST.C and link it with the async library, type the following:

     zmf test

      After successful compilation, type TEST and press .  As you type
characters, they will be sent out COM1.  Characters received at COM1 will be
displayed on the screen.  Press  to quit back to DOS.

3.6 QuickC Command Line

     To compile TEST.C and link it with the async library, type the following:

     qmf test

      After successful compilation, type TEST and press .  As you type
characters, they will be sent out COM1.  Characters received at COM1 will be
displayed on the screen.  Press  to quit back to DOS.

     QMF.BAT will place an 'M' after the name of the file (i.e. TEST will
become TESTM).  This is because the make files for Microsofts MAKE program are
quite a bit different than for Borlands MAKE.

3.7 MSC Command Line

     To compile TEST.C and link it with the async library, type the following:

     mmf test

      After successful compilation, type TEST and press .  As you type
characters, they will be sent out COM1.  Characters received at COM1 will be
displayed on the screen.  Press  to quit back to DOS.

     MMF.BAT will place an 'M' after the name of the file (i.e. TEST will
become TESTM).  This is because the make files for Microsofts MAKE program are
quite a bit different than for Borlands MAKE.

3.8 TEST.C

/* |-----------------------------------------------|*/
/* |                                               |*/
/* |  test -- test async library program           |*/
/* |                                               |*/
/* |-----------------------------------------------|*/

#define EXTERN

#include <async.h>
#include <stdio.h>
#include <stdlib.h>

#define    COM1     0
#define    COM2     1
#define    COM3     2
#define    COM4     3

#define    SCAN    0   /* func. key scan code lead in */
#define    QUIT    'D'/* F10 quit  */
#define    TRUE    1

char KbData, ModData;
int port;

main()
{
   initialize();
   VID_puts("\nPress F10 to quit...\n");
   do {
       if (kbhit()) {                           /* get any char at kbd */
           KbData = getch();
           if (KbData == SCAN) {                /* FUNCTION KEY */
               KbData = getch();
               switch (KbData) {

                   case QUIT :
                       CloseUp();

               }
           }
           else
               Async_Send(port, KbData);
       }
       if (Async_Receive(port, &ModData)) {
           VID_putc(ModData);
       }
   } while (TRUE)  /* main while loop */
}      /* main */

CloseUp()
{
   Async_Close(port);
   VID_close();
   exit(0);
}

initialize()
{
   VID_open();
   port = COM1;
   Async_Init();
   if (!Async_Open(port, 1200, 'E', 7, 1, 1000, 1000)) {
       VID_printf("Error opening COM%1s\n", port+1);
       VID_flush();
   }
}

ProcessInputs()    /* dummy routine for Delay module */
{
}

                         Chapter 4 - Files and Modules

     This chapter will describe each of the modules included with this
communications library.

4.1 File A_INIT.C Modules (initialize, open, close)

     Before using any of the modules described in this section, include the
file ASYNC.H.

     The 3 following modules need to be called whenever using these tools.  The
first procedure (Async_Init) initializes all buffer variables and is only
called once before any other Async routine is called.  The second procedure (
Async_Open) is called once for each communications port needed before it is
ever used.  The third routine (Async_Close) is called at the end of processing
once for each open port.

Routines:

Async_Init                            Performs initialization.
Async_Open                            Sets up COM port
Async_Close                           Closes down COM port


Async_Init --- Initialize Asynchronous Variables


Purpose:   Initializes variables, always call first and only call one time.

Calling Sequence:
           Flag = Async_Init();

Calls:     None (Except Digiboard version).

Returns:   TRUE is successful FALSE otherwise.  (Always true except for
           DIGIBOARD version).

int Async_Init(void)


Async_Open --- Open communications port


Purpose:   This module initializes the communications hardware and sets up the
           interrupt vectors for the receive and send buffers.

Calling Sequence:

Flag = Async_Open(Port, BaudRate, Parity, WordSize, StopBits, RBuff, SBuff)

           Port           which port (0, 1, 2, 3)(0=COM1 1=COM2 2=COM3 3= COM4)

           BaudRate       Baud rate (110 to 57600)
                                    set to B115K for 115200 baud

           Parity         "E" for even, "O" for odd, "N" for none

           WordSize       Bits per character  (5 through 8)

           StopBits       How many stop bits  (1 or 2)

           RBuff          Size of receive buffer to allocate (number of WORDS,
                          max 32K)

           SBuff          Size of send buffer to allocate (number of CHARS, max
                          64K).  Set to 0 to not use send interrupts.

Flag returned TRUE if port opened successfully.

Flag returned FALSE if any errors.

Calls:
           intsetup (see asyncm.asm)

Async_Open(int Port, unsigned BaudRate, char Parity, int WordSize, int
           StopBits, int RBuff, unsigned SBuff)


Async_Close --- Close down communications interrupts


Purpose:   Resets interrupt system to what it was before port opened.

Calling Sequence:
           Async_Close(port);

           port           port to close.

Calls:     None

void Async_Close(int Port)

4.2 File A_CHAR.C Modules (Send/Recv 1 char at a time)

     IMPORTANT: when compiling this module do not turn on the compiler stack
overflow checking option.  The interrupt service routine sets up its own stack
that will cause run time errors if this switch is turned on.

     The modules in this section are used to send and receive data one
character at a time.  The module Async_Receive_With_Timeout returns -1 if a
specified time elapses without a character coming in.  The module Async_Putback
puts a character back into the receive buffer such that it will be the next
character read by Async_Receive or any module used to read characters from the
buffer.

Routines:

Async_Receive                          Reads character from COM buffer
Async_Putback                          Replace a character in COM buffer
Async_Send                             Places char in send buffer
Async_Receive_With_Timeout             Receives char with timeout check
Async_Send_Brk                         Sends break (attention) signal
Async_Purge_Buffer                     Clears receive buffer
Async_Isr                              Interrupt service routine


Async_Receive --- Retrieve a character from buffer



Purpose:   Retrieve character (if any) from buffer

Calling Sequence:
           Flag = Async_Receive(port, &c);

           port           port to read character from

           c              character (if any) retrieved from buffer

Flag returned 1 if character retrieved from buffer.

Flag returned 0 if no character retrieved.

Flag returned with port status if character retrieved with parity, overrun or
           framing error

Calls:     None

Async_Receive(int port, unsigned char *c)


Async_Putback --- Return character to buffer


Purpose:   Replace character in buffer.  If a character needs to be put back
           into buffer for a another module, etc.

Calling Sequence:
           Async_Putback(port, c);

           port           port to put character into

           c              character to put back into buffer

Calls:     None

Async_Putback(int port, unsigned char c)


Async_Send --- Places a character in the send buffer


Purpose:   This module places a character in the send buffer.  The character
           will be sent automatically at a later time by the interrupt service
           routine.

Calling Sequence:
           Async_Send(port, c);

           port           port to send character to

           c              character to place in send buffer

Calls:     DeltaTime

Remarks:   If the send buffer is full this routine will wait .25 seconds for
           room to be made.  If it is still full (probably something wrong) it
           will return ERR.

void Async_Send(int port, unsigned char c)


Async_putc --- Sends a character out the port without buffering


Purpose:   This module sends a character out the port.  The character is sent
           immediately and not buffered.

Calling Sequence:
           Async_putc(port, c);

           port           port to send character to

           c              character to send

Calls:     DeltaTime

Remarks:   If the send holding register is full this routine will wait .25
           seconds for room to be made.  If it is still full (probably
           something wrong) it will return ERR.

void Async_putc(int port, unsigned char c)


Async_Receive_With_TimeOut --- Retrieve a char from buffer with delay


Purpose:   Retrieve character as integer from buffer, or return TIMEOUT if
           specified delay period expires.

Calling Sequence:
           Async_Receive_With_Timeout(port, delay, &C);

           port           which commo port

           delay          Timeout period in hundreths of a second

           C              character (if any) retrieved from buffer.  Set to
                          TIMEOUT if Timeout occurs prior to character being
                          received.

Calls:     Async_Receive

int Async_Receive_With_Timeout(int Port, int Hunds, unsigned char *C)


Async_Send_Brk --- Send break (attention) signal


Calling Sequence:
           Async_Send_Brk(port);

           port           which commo port

Calls:     None

void Async_Send_Brk(int Port)


Async_Purge_Buffer --- Purge communications input buffer


Calling Sequence:
           Async_Purge_Buffer(port);

           port           which commo port

Calls:     Async_Receive

void Async_Purge_Buffer(int port)


Async_Isr --- Interrupt Service Routine


Purpose:   When an interrupt has occurred for one of the communications ports,
           this routine is called by the routine to which the commo interrupts
           are vectored (intserv in asyncm.asm).  Used for both send and
           receive interrupts as well as receive errors and BREAK processing.
           DO NOT CALL THIS ROUTINE.

Calling Sequence:
           Async_Isr(port);

interrupt Async_Isr(int port)

4.3 File A_STRNG.C Modules (Send strings)

Routines:

Async_Send_String                     Sends string over COM port
Async_Send_String_With_Delays         Sends string with timed delays


Async_Send_String --- Send string over communications port


Purpose:   This module places a string of characters into the send buffer.

Calling Sequence:
           Async_Send_String(port, s);

           port           port to send chars to

           s              string to send

Calls:     Async_Send

void Async_Send_String(int port, unsigned char *s)


Async_Send_Line --- Send line over communications port


Purpose:   This module places a string of characters into the send buffer
           followed by a NEWLINE.

Calling Sequence:
           Async_Send_Line(port, s);

           port           port to send chars to

           s              string to send

Calls:     Async_Send

void Async_Send_Line(int port, unsigned char *s)


Async_Send_String_With_Delays --- Send string with timed delays


Purpose:   Sends string out over communications port with specified delays for
           each character and at the end of the string.

Calling Sequence:
           Async_Send_String_With_Delays(port, s, char_Delay, EOS_Delay);

           port           which commo port

           s              String to send

           char_Delay     Number of hundreth of second to delay per character

           EOS_Delay      Number of hundreth of second to delay at end

Calls:     Async_Send
           Async_Send_String
           Delay

Remarks:

     This routine is useful when writing routines to perform non-protocol
uploads.  Many computer systems require delays between receipt of characters
for correct processing.  The delay for end-of-string usually applies when the
string represents an entire line of a file.

     If delays are not required, Async_Send_String is faster. This routine will
call Async_Send_String if no character delay is to be done.

void Async_Send_String_With_Delays(int port, unsigned char *s, int char_Delay,
           int EOS_Delay)

4.4 File A_HNDSHK.C Hardware Handshake Modules

Routines:

Async_DTR                              Set or clear Data Terminal Ready
Async_RTS                              Set or clear Request To Send
Async_DSR                              Check for modem DSR
Async_CTS                              Check for modem CTS
Async_DCD                              Checks for modem carrier detect
Async_Carrier_Drop                     Checks for modem carrier drop
Async_RI                               Check for modem RI
Async_Percentage_Used                  Returns percentage Buffer used
Async_SPercentage_Used                 Returns percentage SBuffer used
Async_Buffer_Check                     Checks if character in COM buffer


Async_DTR --- Set data terminal ready status


Calling Sequence:
           Async_DTR(port, Ready_Status);

           port           which commo port

           Ready_Status   Set TRUE to set on, Set FALSE to set off.

Calls:     None

void Async_DTR(int Port, char Ready_Status)


Async_RTS --- Set Request To Send


Calling Sequence:
           Async_RTS(port, Ready_Status );

           port           which commo port

           Ready_Status   Set TRUE to set send on, Set FALSE to set off

Calls:     None

void Async_RTS(int Port, char Ready_Status)


Async_DSR --- Check for modem DSR


Calling Sequence:
           Flag = Async_DSR(port);

           port           which commo port

Flag is set TRUE if "data set ready" detected, else FALSE.

Calls:     None

int Async_DSR(int Port)


Async_CTS --- Check for modem CTS


Calling Sequence:
           Flag = Async_CTS(port);

           port           which commo port

Flag is set TRUE if "clear to send" detected, else FALSE.

Calls:     None

int Async_CTS(int Port)


Async_DCD  --- Check for modem carrier detect


Calling Sequence:
           Flag = Async_DCD(port);

           port           which commo port

Flag is set TRUE if "data carrier" detected, else FALSE.

Calls:     None

int Async_DCD(int Port)


Async_Carrier_Drop --- Check for modem carrier drop


Calling Sequence:
           Flag = Async_Carrier_Drop(port);

           port           which commo port

Flag is set TRUE if carrier not detected, else FALSE.

Calls:     None

int Async_Carrier_Drop(int Port)


Async_RI --- Check for modem RI


Calling Sequence:
           Flag = Async_RI(port);

           port           which commo port

Flag is set TRUE if "ring indication" detected, else FALSE.

Calls:     None

int Async_RI(int Port)


Async_Percentage_Used --- Report Percentage Buffer Filled


Calling Sequence:
           Percentage = Async_Percentage_Used(port);

           port           which commo port

Percentage value range from 0 (empty) to 100 (full).

Calls:     None

     Remarks:

     This routine is helpful when incorporating handshake into a communications
program.  For example, assume that the host computer uses the XON/XOFF
(DC1/DC3) protocol.  Then the PC program should issue an XOFF to the host when
the value returned by Async_Percentage_Used > 75 or so.  When the utilization
percentage drops below 25 or so, the PC program should transmit an XON.

int Async_Percentage_Used(int port)


Async_SPercentage_Used --- Report Percentage SBuffer Filled


Calling Sequence:
           Percentage = Async_SPercentage_Used(port);

           port           which commo port

Percentage value range from 0 (empty) to 100 (full).

Calls:     None

     Remarks:

     This routine reports the status of the send buffer.

int Async_SPercentage_Used(int port)


Async_Buffer_Check --- Check if character in receive buffer


Calling Sequence:
           Flag = Async_Buffer_Check(port);

           port           port to check for waiting chars.

Flag returned TRUE if character received in buffer.

Flag returned FALSE if no character received.

Calls:     None

     Remarks:

     This routine only checks if a character has been received and thus can be
read; it does NOT return the character.  Use Async_Receive to read the
character.

int Async_Buffer_Check(int port)

4.5 File A_MODEM.C Modules (Hayes modem support)

Routines:

Async_Signon                 Sign on with Hayes modem (AT)
Async_Signoff                Hang up phone (place on hook)


Async_Signon --- Dial phone using Hayes AT command sequence


Calling Sequence:
           Async_Signon(port, phone);

           port           port conneted to modem.

           phone          string with phone number (T first char for Touch
                          Tone)

Calls:     Async_Send_String, Async_Send, Delay

void Async_Signon(int port, unsigned char *phone)


Async_Signoff --- Hang up phone using Hayes AT command sequence


Calling Sequence:
           Async_Signoff(port);

           port           which commo port

Calls:     Async_Send_String, Delay

void Async_Signoff(int port)

4.6 File A_TIMING.C Modules

     Modules in this file are used for real-time delays where various processes
may still need to be performed while another process is being delayed (user
needs to provide a ProcessInputs() routine, can be empty if not needed).

     Two other routines are provided for timing purposes.

     Before using any of the modules in this section include the file TIMING.H.

Routines:

Delay                           Wait for n hundredths of a second
DeltaTime                       Determine elapsed time since specified time.
GetSystemHundreths              Read system hundreths of a second from counter.


Delay -- Wait for n hundredths of a second


Calling Sequence:
           Delay(n)

           n              number of hundreths of a second to wait for

Calls:     ProcessInputs (provided by user or dummy if not needed)

void Delay(int n)


DeltaTime -- Determine how much time has elapsed since specified time.


Calling Sequence:
           delta = DeltaTime(t1)

           t1             number of system hundreths to calculate elapsed time
                          since.

           delta          is set to number of hundreths elapsed since t1.

Calls:     GetSystemHundreths

unsigned DeltaTime(unsigned long t1)


GetSystemHundreths -- Read system hundreths of a second from counter.


Calling Sequence:
           t = GetSystemHundreths()

           t              Hundreths of a second counter from system.

Calls:     system (DOS or memory location)

unsigned long GetSystemHundreths(void)

4.7 File FILEXFER.C Modules

     Before using any of the modules in this section include the file XFER.H.

Routines:

initxfer                    Initialize xfer variables
upload                      upload a file with XOFF/XON protocol
recvfile                    Receive a file in XMODEM protocol
sendfile                    send a file in XMODEM protocol
WaitFor                     Wait for specified string from port


initxfer --- initialize file transfer variables


Calling Sequence:
           initxfer();

Calls:     none

void initxfer(void)


upload --- upload a file with XOFF/XON protocol


Purpose:   Sends a file with XOFF/XON protocol, no error check

Calling Sequence:
           upload(port, file);

           port           port to send file out of

           file           name of file to send

Calls:     Async_Send, mcharinp, readchar, Async_Buffer_Check

void upload(int port, char *file)


sendfile --- send a file using XMODEM protocol


Calling Sequence:
           flag = sendfile(port, file);

           port           port to send file out of

           file           name of file to send

flag is set to ERROR if file is not found or transfer was not successful.

flag is set to TRUE if file transfer was successful

Calls:     Async_Send, readchar

int sendfile(int port, char *file)


recvfile --- receive a file using XMODEM CHECKSUM protocol


Calling Sequence:
           flag = recvfile(port, file);

           port           port to send file out of

           file           name of file to receive

flag is set to ERROR if file can't be created or transfer was not successful.

flag is set to TRUE if file transfer was successful

Calls:     Async_Send, readchar, creat, putc_scr

int recvfile(int port, char *file)


WaitFor --- Get data from a port until specified string is received.


Calling Sequence:
           flag = WaitFor(port, string, startdelay, chardelay);

           port           port to send file out of

           string         string to wait for

           startdelay     delay time to allow for first char to come

           chardelay      delay time to allow for each additonal char

flag is set to TIMEOUT if string is not received within time allowed.

flag is set to TRUE if string is received.

Calls:     readchar

int WaitFor(int port, unsigned char *string, int startdelay, int chardelay);

4.8 File WIND.C Modules

     Before using any of the modules in this section include the file WIND.H.
See DATAMON.C for an example of the use of these modules.

Routines:

InitWindow               Initialize window variables
DefineWindow             Define a new window in screen coordinates
SelectWindow             Change current window number for subsequent data
StringToWindow           Write a string to a specified window
CharToWindow             Write a character to a specified window
CRLFToWindow             Put cursor of specified window to next line start
WindowNorm               Set current window to normal
WindowRV                 Set current window to reverse video
WindowBlink              Set current window to blink
WindowUL                 Set current window to underline
WindowHigh               Set current window to high intensity
WindowLow                Set current window to low intensity
scroll                   scroll current window up or down
scroll_partial           scroll current window, or insert/delete line
ClearWindow              clear current window to all blanks
clear                    clear portion of current window
inccur                   increment cursor location, scroll if necessary
putcursor                display the cursor in current position
deccursor                move cursor left and wrap up if flag set
poscur                   position current window cursor
proprt                   process a printing character to current window
proctl                   process a control char to current window
clr_scr                  clears the actual screen
SwapOut                  copy screen to buffer area
SwapIn                   copy saved page to screen buffer


InitWindow --- Initialize window variables


Calling Sequence:
           InitWindow();

Calls:     None

Remarks:   See Datamon for example of usage

void InitWindow(void)


DefineWindow --- Define a new window in screen coordinates


Calling Sequence:
           DefineWindow(num, xul, yul, xlr, ylr);

           num            window number (set by caller)

           xul, yul       x and y of upper left corner of window (screen)

           xlr, ylr       x and y of lower right corner of window

Calls:     None

Remarks:   See Datamon for example of usage

void DefineWindow(int num, int xul, int yul, int xlr, int ylr)


SelectWindow --- Change current window number for subsequent data


Calling Sequence:
           SelectWindow(n)

           n              number of new window

Calls:     None

Remarks:   Sets WindowN global variable

void SelectWindow(int n)


StringToWindow --- Write a string to a specified window


Calling Sequence:
           StringToWindow(Window, Str)

           Window         number of window to write string to

           Str            character string to write

Calls:     CharToWindow

Remarks:   Call with WindowN for current window

void StringToWindow(int Window, char *Str)


CharToWindow --- Write a character to a specified window


Calling Sequence:
           CharToWindow(Window, c)

           Window         number of window to write char to

           c              char to write

Calls:     proprt, proctl

Remarks:   call with WindowN for current window.  c can be a control character.

void CharToWindow(int Window, char c)


CRLFToWindow --- Put cursor of specified window to next line start


Calling Sequence:
           CRLFToWindow(Window);

           Window         number of window to move cursor of

Calls:     CharToWindow

void CRLFToWindow(int Window)


WindowNorm --- Set attribute of current window to Normal


Calling Sequence:
           WindowNorm();

Calls:     None

void WindowNorm(void)


WindowRV --- Set attribute of current window to Reverse Video


Calling Sequence:
           WindowRV();

Calls:     None

void WindowRV(void)


WindowBlink --- Set attribute of current window to Blink


Calling Sequence:
           WindowBlink();

Calls:     None

void WindowBlink(void)


WindowUL --- Set attribute of current window to Underline


Calling Sequence:
           WindowUL();

Calls:     None

void WindowUL(void)


WindowHigh --- Set attribute of current window to High Intensity


Calling Sequence:
           WindowHigh();

Calls:     None

void WindowHigh(void)


WindowLow --- Set attribute of current window to Low Intensity


Calling Sequence:
           WindowLow();

Calls:     None

void WindowLow(void)


scroll --- scroll current window up or down


Calling Sequence:
           scroll(Direction);

           Direction      set to UP or DOWN for direction of scroll

Calls:     scroll_partial

Remarks:   UP means top line of top of screen, blank bottom

void scroll(int Direction)


scroll_partial --- scroll current window, or insert/delete line


Calling Sequence:
           scroll_partial(Direction, YTop)

           Direction      set to UP or DOWN for direction of scroll

           YTop           set to top line of window to scroll

Calls:     memmovew, memsetw, get_off_xy

Remarks:   This routine is used to scroll window, insert line
           (scroll DOWN at YTop set to insert point) and delete
           line (scroll UP at YTop set to delete line)

void scroll_partial(int Direction, int YTop)


ClearWindow  --- clear current window to all blanks


Calling Sequence:
           ClearWindow();

Calls: clear

void ClearWindow(void)


clear --- clear portion of current window


Calling Sequence:
           clear(xmin, ymin, xmax, ymax)

           xmin, ymin     coords of up/left corner of region to clear

           xmax, ymax     coords of lower/right corner of region to clear

Calls:     memsetw

Remarks:   coords relative to current window

void clear(int xmin, int ymin, int xmax, int ymax)


inccur --- move cursor right, wrap, scroll if necessary


Calling Sequence:
           inccur();

Calls:     scroll, poscur

Remarks:   Current window.  Called by proprt, etc.

void inccur(void)


putcursor --- display the cursor in current position


Calling Sequence:
           putcursor();

Calls:     poscur

Remarks:   Current window.  Called by proprt, etc.

void putcursor(void)


deccursor --- move cursor left and wrap up if flag set


Calling Sequence:
           deccursor();

Calls:     poscur

Remarks:   does not scroll down if at top. Current window

void deccursor(void)


poscur --- position current window cursor.


Calling Sequence:
           poscur(x, y);

           x, y           location to move cursor to

Calls:

Remarks:   x and y relative to window start

void poscur(int x, int y)


proprt --- process a printing character to current window


Calling Sequence:
           proprt(c);

           c              printable char (> BLANK)

Calls:     memsetw, inccur

Remarks:   use proctl for control characters (in current window)

void proprt(char c)


proctl --- process a control char to current window


Calling Sequence:
           proctl(c);

           c              a control character

Calls:     bdos, clear, poscur, scroll, deccursor, proprt, proctl (recursive)

Remarks:   many control chars are displayed <CTRL?>

void proctl(char c)


SwapOut --- Copy screen to buffer area


Calling Sequence:
           SwapOut();

Calls:     peekw

Remarks:   Uses global variables initialized in InitWindow.  Only one screen
           can be swapped out at a time.

void SwapOut(void)


SwapIn --- copy saved page to screen buffer


Calling Sequence:
           SwapIn();

Calls:     pokew

void SwapIn(void)

4.9 File PRINTER.C Modules

     This file contains code for buffered printer support for LPT1 only at this
point.

Routines:

InitPrinter                 Initialize printer, alloc memory
StringToPrinter             Write a string to printer
CRLFToPrinter               Send CR/LF sequence to printer
CharToPrinter               Write a char to printer (doesn't use buffer)
PutPrinterBuffer            Put a character into printer output buffer
SendPrinterBuffer           Send a character from printer buffer


InitPrinter --- Initialize printer, alloc memory


Calling Sequence:
           InitPrinter();

Calls:     int86, VID_puts, CloseUp

void InitPrinter(void)


StringToPrinter --- Write a string to printer


Calling Sequence:
           StringToPrinter(s);

Calls:     PutPrinterBuffer

void StringToPrinter(unsigned char *s)


CRLFToPrinter --- Write a CR and LF to printer


Calling Sequence:
           CRLFToPrinter();

Calls:     PutPrinterBuffer

void CRLFToPrinter(void)


CharToPrinter --- Write a char directly to printer


Calling Sequence:
           CharToPrinter(c);

Calls:     int86

void CharToPrinter(unsigned char c)


PutPrinterBuffer --- Put a char into printer buffer


Calling Sequence:
           PutPrinterBuffer(c);

Calls:     none

void PutPrinterBuffer(unsigned char c)


SendPrinterBuffer --- Write a char to printer from buffer


Calling Sequence:
           SendPrinterBuffer();

Calls:     CharToPrinter

void SendPrinterBuffer(void)

4.10 File ASYNCM.ASM Modules

     The modules in this file are written in assembly language for speed and
portability across various "C" compilers.  Users of this library will not need
to call any of these routines.  They are all called by Async_Open, described in
.

     If you do modify or otherwise need to recompile them, MASM v5.1 or later
must be used, or any version of TASM.  See make files for command line compile
options.

Routines:

intsetup                       Set interrupt vector offset with current CS
intserv                        Low level commo interrupt service
getvec                         Get current interrupt vector
setvec                         Set interrupt vector (segment and offset)
inton                          STI
intoff                         CLI

4.11 File PEEKW.ASM Modules

     The modules in this file are written in assembly language for speed and
portability across various "C" compilers.  Users of this library will not need
to call any of these routines.  These routines augment standard library
routines for accessing and writing to memory.

Routines:

peekw                          Move n words from SEG:OFF to DS:BUF
pokew                          Move n words from DS:BUF to SEG:OFF
movewords                      Move n words from SEG1:OFF1 to SEG2:OFF2
memsetw                        Set n words at SEG:OFF to c
memmovew                       Move n words from SEG:OFF1 to SEG:OFF2
peekb                          Get 1 byte from SEG:OFF to AL
pokeb                          Store 1 byte at SEG:OFF

                        Chapter 5 - Library Maintenance

     Please see Chapter  for instructions on decompressing the source, make and
batch files discussed here.

     Each of the libraries (different memory models) can be created with a
specific makefile.  A batch file is included for each compiler (see following
sections) which will set the flags necessary to invoke the correct compiler and
route the completed library to the correct subdirectory.

     There is also a batch file for each compiler (MAKEALLT for BorlandC,
MAKEALLZ for Zortech, MAKEALLQ for QuickC, MAKEALLM for MSC) which will
recompile each of the memory model libraries.  These batch files can be used
only if you have DOS 3.3 or later (they use the CALL command within the batch
file).

     If you do not use the standard directory layout specified with the
compiler, you will need to edit the appropriate batch file.

     The following files are combined into the library and if modified you will
need to recreate the library.  If you do not have an assembler (WHAT?) you will
need to extract the 2 object files ASYNCM.OBJ and PEEKW.OBJ from the
appropriate library file (your compiler, the appropriate memory model .LIB
file) prior to running the batch file to create the library.  Otherwise the LIB
command (or TLIB) will not be able to find the object file.  Alternatively you
could edit the makefile and take out the part of the statement which attempts
to update these 2 modules in the library.

           A_INIT.C
           A_CHAR.C
           A_HNDSHK.C
           A_MODEM.C
           A_STRNG.C
           A_TIMING.C
           ASYNCM.ASM
           PEEKW.ASM

     For the Digiboard version, the following are combined into the library
file:

           D_INIT.C
           D_CHAR.C
           D_HNDSHK.C
           D_MODEM.C
           D_STRNG.C
           D_TIMING.C
           DIGI.C
           PEEKW.ASM

5.1 BorlandC maintenance

     The batch file is called TMF.BAT.  It utilizes the command line version of
BorlandC.  If you modify any of the files that are part of the standard library
type TMF ASYNC ?.  ? is replaced by S for the small memory model, C for compact
(large data) model, M for medium (large code) model, and L for the Large
model.  Or use MAKEALLT as described above to recompile every memory model.

     There is also a batch file called BORLANDC.BAT which sets up the
environment variables needed in the makefiles.  You will undoubtedly need to
edit this file because your environment (directories, disks, etc.) will be
different than ours.

5.2 ZORTECH maintenance

     The batch file is called ZMF.BAT.  If you modify any of the files that are
part of the standard library type ZMF ASYNC?.  ? is replaced by S for the small
memory model, C for compact (large data) model, M for medium (large code)
model, and L for the large (large code and data) model.  Or use MAKEALLZ as
described above to recompile every memory model.

     There is also a batch file called ZORTECH.BAT which sets up the
environment variables needed in the makefiles.  You will undoubtedly need to
edit this file because your environment (directories, disks, etc.) will be
different than mine.

5.3 QuickC maintenance

     The batch file is called QMF.BAT.  If you modify any of the files that are
part of the standard library type QMF ASYNC?.  ? is replaced by S for the small
memory model, C for compact (large data) model, M for medium (large code)
model, and L for the large (large code and data) model.  Or use MAKEALLQ as
described above to recompile every memory model.

     There is also a batch file called QUICKC.BAT which sets up the environment
variables needed in the makefiles.  You will undoubtedly need to edit this file
because your environment (directories, disks, etc.) will be different than
mine.

     An additional file is needed for the Microsoft versions: a_printf.c.  This
file is used to implement a direct video printf routine.

5.4 MSC maintenance

     The batch file is called MMF.BAT.  If you modify any of the files that are
part of the standard library type MMF ASYNC S.  ? is replaced by S for the
small memory model, C for compact (large data) model, M for medium (large code)
model, and L for the large (large code and data) model.  Or use MAKEALLM as
described above to recompile every memory model.

     An additional file is needed for the Microsoft versions: a_printf.c.  This
file is used to implement a direct video printf routine.

     There is also a batch file called MSC.BAT which sets up the environment
variables needed in the makefiles.  You will undoubtedly need to edit this file
because your environment (directories, disks, etc.) will be different than
mine.

                         Chapter 6 - DIGIBOARD Software

6.1 DIGIBOARD Concepts

     The Digiboard intelligent communications hardware boards utilize different
libraries than the standard IBM asynchronous hardware.  These routines are
found in the files D_*.C, DIGI.C with header files ASCYND.H and M232.H.

     Use of the routines should be identical to using the normal modules,
however several special considerations need to be addressed.

     Upon start up, Async_Init will need to upload the file M232.FCM to each
board installed in the system (up to 4 boards, 32 ports).  Make sure that this
file (M232.FCM) is in the same directory as your compiled program.

     The number of boards installed, total number of ports, and number of ports
per board need to be set in the header file M232.H.  The library files
ASYNC?D.LIB on distribution diskette #2 were compiled for 1, 8 port board.  If
your system is different than this, you will need to recompile the library
after setting these variables in M232.H.  To recompile the library type:

     TMF ASYNC S -DDIGI (small memory model, Digiboard, BorlandC)
     ZMF ASYNCSD ( Zortech)
     QMF ASYNCSD ( QuickC)
     MMF ASYNC S DIGI=1 ( MSC)

     For other memory models, replace S with C, M or L.

     The utility DATAMOND is the same as DATAMON but configured for use with
Digiboard hardware.  The make file DATAMOND.M should be used instead of
DATAMONS.M if you desire to modify the program.  The header file DATAMON.H
shows how the include file ASYNCD.H is used in place of the normal ASYNC.H if
Digiboard hardware is present.  The DEFINE variable DIGI is set automatically
by DATAMOND.M as shown.  Please use these examples when creating your own
software for use with Digiboard hardware.

6.2 Digiboard Hardware Setup

     The Digiboard hardware can be setup at many different interrupts and port
locations.  Use of this software as configured requires the following setup.


 Board #   I/O Port    IRQ      J2      J3      J4      J15     J16      J17

    1        320      5(J11)    1-2     1-2     1-2     1-2     1-2      2-3

    2        300      5(J11)    1-2     1-2     2-3     1-2     2-3      2-3

    3        220      5(J11)    1-2     2-3     1-2     2-3     1-2      2-3

    4        200      5(J11)    1-2     2-3     2-3     2-3     2-3      2-3



     See the Digiboard COMi installation manual (page 7) for information on
jumpering of the I/O port addresses.

6.3 DIGI.C

     User should not modify modules in this file.  There are however several
handshaking options which are set with routines in this file.  See DATAMON.C
for an example of setting up incoming hardware flow control.  For further
information contact us.

6.4 D_*.C

     These files contain all modules which are found in the files a_*.c as
defined in .  Many of the modules are implemented differently due to the
special requirements of using the coprocessor on board the Digiboard.  Their
use remains the same as previously discussed.

     The one change is that you can not specify the size of the receive or send
buffers (Async_Open).  They are fixed at 1000 characters.  When calling
Async_Open you still need to have some value set as in the IBM versions for
compatilbilty, again see DIGIBOARD.C.

6.5 D_BLOCK.C


Async_Send_Block --- Send a block of data over communications port


Purpose:   This module retrieves a block of characters from the Digiboard
           receive buffer.

Calling Sequence:
           num = Async_Get_Block(port, unsigned char *data, max);

           port           port to get chars from

           data           pointer to area to put block of chars

           max            maximum number of chars to get

           num returned with number of characters (words) copied from
           Digiboard, 0 if no characters retrieved.

Calls:     None

int Async_Get_Block(int port, unsigned char *data, max)


Async_Send_Block --- Send a block of data over communications port


Purpose:   This module places a block of characters into the Digiboard send
           buffer.  Useful when a

Calling Sequence:
           numsent = Async_Send_Block(port, char *s, num);

           port           port to send chars to

           s              string to send

           num            number of char in block to send

           numsent returned with number of characters (words) sent to
           Digiboard, 0 if buffer couldn't hold num.

Calls:     None

int Async_Send_Block(int port, unsigned char *s, num)

                         Chapter 7 - Included Utilities

     The following sections will describe complete programs developed using the
modules describe in .  Each of these programs is provided on disk in compiled
form with all source code included.

     Each of these modules are useful tools for anyone who uses a personal
computer.

7.1 DATAMON

     The Datamon program is a very powerful and useful tool when developing new
software involving communications or anytime two communications devices are
being connected.

     The makefile DATAMONS.M (S for small memory model) can be used to recreate
the program if you desire to modify it.  Use the appropriate batch file for
your compiler to execute make (i.e. TMF DATAMON S for BorlandC users, see .
Microsoft users type MMF DATAMON S or QMF DATAMON).  Also see section  for
information about creating DATAMOND for use with Digiboard hardware.

     This utility can immediately show whether a "null" modem cable is needed
and which control voltages are being provided by the other device.  It can also
be used to determine baud rates, parity, etc.

     The program shows the status of each hardware handshake line, allows easy
changing of baud rate, port number, data bits, parity, stop bits.  With one
function key () it sends the "The quick brown fox... " message.  It can capture
received data and save the captured data to disk at exit.

     A very powerful feature is the Auto Baud Detect capability described
later.  It can, as its name implies, determine and set baud rate, parity and
number of data bits to match that of incoming data on a line.

     There are no command line arguments and after starting the program the
following screen is displayed.



     The upper window of the screen displays the current status of each of the
handshake lines.  The DCE STATUS lines are values provided by the device on the
other end.  The DTE STATUS values are controlled by pressing  (RTS) and  (
DTR).  They are HIGH when first brought up.  These control signals can only be
used of course, if the appropriate pin is connected properly to the other
device.

     This window also displays the status of the other pertinent communications
parameters: baud rate, # of data bits, parity, # of stop bits, and which
communications port.

     Baud rate is 1200 when first brought up and is changed by pressing .  It
will vary between 110 and 115200.

     If you see PARITY, FRAMING, BREAK or OVERRUN displayed those conditions
are detected.  These conditions, when displayed, are for the last character or
bit sequence received.

     Framing and overrun usually means incorrect baud rate selection.  Playing
with baud rate (),number of data bits and parity in that order will allow you
to determine appropriate settings for a more permanent program to attach to the
port.  Also see Auto Baud Detect discussion below.

     The middle window of the screen will display characters received over the
communications port.

     The lower area of the screen displays the use of each of the function
keys.  These are described here.

     Pressing  will start capturing received text into a 16K buffer.  Pressing
it again will discontinue capture.  When you end the session () you will be
asked for a filename to save the captured text to if desired, or RETURN if you
don't want it.

     Pressing  will send the message "The quick brown fox jumped over the lazy
dog's back.".  This message contains every alphabetic character

      controls parity.  Values are EVEN, ODD and NONE.

      controls the number of data bits.  Values are 5, 6, 7 and 8.

      is for number of stop bits (1 or 2).

      controls RTS.

      controls DTR.

      controls which PORT is being used.  Pressing  will look for another port
and change to it if it is found.  Values are COM1 through COM4.

      is used to send a BREAK sequence over the communications line.  This
signal (hold transmit line at SPACE) is used often to interrupt or otherwise
signal other processes.

      turns on Auto Baud Detect.  This is a powerful feature which actually can
adjust baud rate, number of data bits, and parity to match that of an incoming
signal.  The word DETECT will appear in reverse video and any line error will
change parity, data bits or baud rate in an attempt to adjust.  Press  again to
turn this feature off.  Manual adjustments are allowed when this process is
taking place so you can help the system out.

                          SUMMARY OF DATAMON KEY USAGE


                    CAPTURE text to buffer for later saving to disk.

                    Send "The quick brown fox ... "

                    Change BAUD RATE

                    Change PARITY

                    Change DATA BITS

                    Change STOP BITS

                    Toggle RTS

                    Toggle DTR

                    Change PORT

                    Send BREAK signal

                    Toggles Auto Baud Detect

                    QUIT (return to DOS)




7.2 SEND and RECV: quick file transfer

     The combination of SEND and RECV allows rapid transferring of files
between two computers.  Each of the two uses the XMODEM protocol to insure data
integrity.

     The makefile SEND.M (RECV.M for RECV) can be used to recreate the program
if you desire to modify it.  Use the appropriate batch file for your compiler
to execute make (i.e. TMF SEND S for BorlandC users, see ).

     Individual files can be specified or, optionally, a file can be specified
which contains names of other files (one per line) which are to be
transferred.  This can also be done in conjunction with specifying individual
file names.

     One very powerful use of these utility programs is to specify a file which
contains names of other files transferred.  To do this first send the file with
these filenames and then use the file (by preceding its name on the command
line with an @ symbol) to send the other files.

     For example, if the file FOO contained the names of three other files:
FOO1 FOO2 and FOO3 (one filename per line, can include path information) then
typing on the sending computer.

     SEND FOO @FOO

     And on the receiving computer:

     RECV FOO @FOO

     Would first transfer the file FOO and then transfer FOO1 FOO2 and FOO3 at
19200 baud over COM1 (baud, port can be changed as described below).

     Other command line options allow specifying baud rate, port, and number of
stop bits.  Data bits are always 8 and parity is none.  This allows
transferring binary (executable) files as well as text files.

     If no command line parameters are specified (or are specified incorrectly)
the following is displayed:



     The same message is used for RECV (except of course recv instead of send).

     The default values are shown bracketed (i.e. COM1, 19200 baud, 1 stop
bit).  All parameters are optional except at least one filename or FILELIST
must be specified.

7.3 MODEM: complete commo program

     The MODEM utility is a simple terminal program which can be used to access
remote databases, etc.  It has built in file transfer capabilities (like SEND
and RECV) for exchanging files using XMODEM protocol.  It also has a non-error
correcting protocol which just sends files using the XOFF/XON protocol.  It can
also CAPTURE data (like DATAMON) and save the data at any time.

     Upon startup the following screen is displayed:



     Like TEST.C, characters typed at the keyboard are sent out of the
communications port and characters received through the communications port are
displayed on the screen.

                           Chapter 8 - RS-232 Basics

                    A Practical Guide to RS-232 Interfacing

                                   Thanks to:
                               Lawrence E. Hughes

     The following information is intended to collect together in one place,
and explain in relatively simple terms, enough of the details of the RS-232
standard to allow a technician to construct and/or debug interfaces between any
two "RS-232 Compatible" devices.  A more detailed coverage of the subject may
be found in the book "Technical Aspects of Data Communication" by John E.
McNamara (1977, Digital Press).

     This guide is necessary due to the casual way that vendors implement "
RS-232" interfaces, sometimes omitting required signals, requiring optional
ones, or worse, implementing signals incorrectly.  Due to this, and a lack of
readily available information about the real EIA standard, there is often
considerable confusion involved in trying to interface two RS-232 devices.

8.1 BACKGROUND

     RS-232-C is the most recent version of the EIA (Electronics Industry
Association) standard for low speed serial data communication.  It defines a
number of parameters concerning voltage levels, loading characteristics and
timing relationships.  The actual connectors which are almost universally used
(DB-25P and DB-25S, sometimes called "EIA connectors") are recommended, but not
mandatory.  Typical practice requires mounting the female (DB-25S) connector on
the chassis of communication equipment, and male (DB-25P) connectors on the
cable connecting two such devices.

     There are two main classes of RS-232 devices, namely DTE (Data Terminal
Equipment), such as terminals, and DCE (Data Communication Equipment), such as
modems.  Typically, one only interfaces a DTE to a DCE, as opposed to one DTE
to another DTE, or one DCE to another DCE, although there are ways to do the
later two by building non-standard cables.  Rarely if ever are more than two
devices involved in a given interface (multidrop is not supported).  A serial
port on a computer may be implemented as either DTE or DCE, depending on what
type of device it is intended to support.

     RS-232 is intended for relatively short (50 feet or less), relatively low
speed (19,200 bits per second or less) serial (as opposed to parallel)
communications.  Both asynchronous and synchronous serial encoding are
supported.  As "digital" signals (switched D.C. voltage, such as square waves)
are used, as opposed to "analog" signals (continuously varying voltage, such as
sine waves) a very wide bandwidth channel (such as direct wire) is required.  A
limited bandwidth channel (such as a phone circuit) would cause severe and
unacceptable distortion and consequent loss of information.

     RS-232 will support simplex, half-duplex, or full-duplex type channels.
In a simplex channel, data will only ever be travelling in one direction, e.g.
from DCE to DTE.  An example might be a "Receive Only" printer.  In a
half-duplex channel, data may travel in either direction, but at any given time
data will only be travelling in one direction, and the line must be "turned
around" before data can travel in the other direction.  An example might be a
Bell 201 style modem.  In a full-duplex channel, data may travel in both
directions simultaneously.  An example might be a Bell 103 style modem.
Certain of the RS-232 "handshaking" lines are used to resolve problems
associated with these modes, such as which direction data may travel at any
given instant.

     If one of the devices involved in an RS-232 interface is a real modem
(especially a half-duplex modem), the "handshaking" lines must be supported,
and the timing relationships between them are quite important.  These lines are
typically much easier to deal with if no modems are involved.  In certain
cases, these lines may be used to allow one device (which is receiving data at
a higher rate than it is capable of processing indefinitely) to cause the other
device to pause while the first one "catches up".  This use of the handshaking
lines was not really intended by the designers of the RS-232 standard, but it
is a useful by-product of the way such interfaces are typically implemented.

     Much of the RS-232 standard is concerned with support of "modems".  These
are devices which can convert a serial digital data signal into an analog
signal compatible with a narrow bandwidth (e.g. 3 kHz) channel such as a
switched telephone circuit, and back into serial digital data on the other
end.  The first process is called "modulation", and the second process is
called "demodulation", hence the term "MODEM".  The actual process used (at
data rates of up to 1200 bits per second) is FSK (Frequency Shift Keying), in
which a constant frequency sine wave (called the "carrier") is shifted to a
slightly higher or slightly lower frequency to represent a logic 0 or logic 1,
respectively.  In a half duplex modem, the entire available bandwidth is used
for one direction.  In a full duplex modem, the available bandwidth is divided
into two sub-bands, hence there is both an "originate carrier" (e.g. for data
from the terminal to the computer), and an "answer carrier" (e.g. for data from
the computer to the terminal).  The actual frequencies (in Hertz) used on the
Bell 103A full duplex modem are:

                          Bell 103A Modem Frequencies


    Signal         State        Originate                  Answer

    logic 0        SPACE          1180                      1850
    carrier                       1080                      1750
    logic 1        MARK            980                      1650




8.2 THE STANDARD CIRCUITS AND THEIR DEFINITIONS

     For the purposes of the RS-232 standard, a "circuit" is defined to be a
continuous wire from one device to the other.  There are 25 circuits in the
full specification, less than half of which are at all likely to be found in a
given interface.  In the simplest case, a full-duplex interface may be
implemented with as few as 3 circuits.  There is a certain amount of confusion
associated with the names of these circuits, partly because there are three
different naming conventions (common name, EIA circuit name, and CCITT circuit
name).  The table below lists all three names, along with the circuit number
(which is also the connector pin with which that circuit is normally associated
on both ends).  Note that the signal names are from the viewpoint of the DTE
(e.g. Transmit Data is data being sent by the DTE, but received by the DCE).

                     RS-232 Pinouts and Signal Descriptions


  PIN     NAME      EIA   CCITT    DTE DCE   Description

   1       CG       AA     101       ---     Chassis Ground
   2       TD       BA     103       -->     Transmit Data
   3       RD.      BB     104       <--     Receive Data
   4       RTS      CA     105       -->     Request To Send
   5       CTS      CB     106       <--     Clear To Send
   6       DSR      CC     107       <--     Data Set Ready
   7       SG       AB     102       ---     Signal Ground
   8       DCD      CF     109       <--     Data Carrier Detect
  9*                                 <--     Pos. Test Voltage
  10*                                <--     Neg. Test Voltage
  11                                         (usually not used)
  12+     SCDC      SCF    122       <--     Sec. Data Car. Detect
  13+     SCTS      SCB    121       <--     Sec. Clear To Send
  14+      STD      SBA    118       -->     Sec. Transmit Data
  15#      TC       DB     114       <--     Transmit Clock
  16+      SRD      SBB    119       <--     Sec. Receive Data
  17#      RC       DD     115        <-     Receive Clock
  18                                         (not usually used)
  19+     SRTS      SCA    120       -->     Sec. Request To Send
  20       DTR      CD     1082      -->     Data Terminal Ready
  21*      SQ       CG     110       <--     Signal Quality
  22       RI       CE     125       <--     Ring Indicator
  23*               CH     111       -->     Data Rate Selector
                    CI     112       <--     Data Rate Selector
  24*      XTC      DA     113       -->     Ext. Transmit Clock
  25*                                -->     Busy




     In the above, the character following the pin number means:

     * rarely used + used only if secondary channel implemented # used only on
synchronous interfaces also, the direction of the arrow indicates which end (
DTE or DCE) originates each signal, except for the ground lines (---).  For
example, circuit 2 (TD) is originated by the DTE, and received by the DCE.
Certain of the above circuits (11, 14, 16, and 18) are used only by (or in a
different way by) Bell 208A modems.

     A secondary channel is sometimes used to provide a very slow (5 to 10 bits
per second) path for return information (such as ACK or NAK characters) on a
primarily half duplex channel.  If the modem used supports this feature, it is
possible for the receiver to accept or reject a message without having to "turn
the line around", a process that usually takes 100 to 200 milliseconds.

     On the above circuits, all voltages are with respect to the Signal Ground
(SG) line.  The following conventions are used:

                          RS-232 Logic Voltage Levels


     Voltage         Signal        Logic                  Control

    +3 to +25         SPACE          0                       On
    -3 to -25         MARK           1                      Off




     Note that the voltage values are inverted from the logic values (e.g. the
more positive logic value corresponds to the more negative voltage).  Note also
that a logic 0 corresponds to the signal name being "true" (e.g. if the DTR
line is at logic 0, that is, in the +3 to +25 voltage range, then the Data
Terminal IS Ready).

8.3 ELECTRICAL CHARACTERISTICS OF EACH CIRCUIT

     The following criteria apply to the electrical characteristics of each of
the above lines:

     1) The magnitude of an open circuit voltage shall not exceed 25V.  2) The
driver shall be able to sustain a short to any other wire in the cable without
damage to itself or to the other equipment, and the short circuit current shall
not exceed 0.5 ampere.

     3) Signals shall be considered in the MARK (logic 1) state when the
voltage is more negative than -3V with respect to the Signal Ground.  Signals
shall be considered in the SPACE (logic 0) state when the voltage is more
positive that 3V with respect to the Signal Ground.  The range between -3V and
3V is defined as the transition region, within which the signal state is not
defined.

     4) The load impedance shall have a DC resistance of less than 7000 ohms
when measured with an applied voltage of from 3V to 25V but more than 3000 ohms
when measured with a voltage of less than 25V.

     5) When the terminator load resistance meets the requirements of Rule 4
above, and the terminator open circuit voltage is 0V, the magnitude of the
potential of that circuit with respect to Signal Ground will be in the 5V to
15V range.

     6) The driver shall assert a voltage between -5V and -15V relative to the
signal ground to represent a MARK signal condition.  The driver shall assert a
voltage between 5V and 15V relative to the Signal Ground to represent a SPACE
signal condition.  Note that this rule in conjunction with Rule 3 above allows
for 2V of noise margin.  Note also that in practice, -12V and 12V are typically
used.

     7) The driver shall change the output voltage at a rate not exceeding 30
volts per microsecond, but the time required for the signal to pass through the
-3V to +3V transition region shall not exceed 1 millisecond, or 4 percent of a
bit time, whichever is smaller.

     8) The shunt capacitance of the terminator shall not exceed 2500
picofarads, including the capacitance of the cable.  Note that when using
standard cable with 40 to 50 picofarads per foot capacitance, this limits the
cable length to no more than 50 feet.  Lower capacitance cable allows longer
runs.  9) The impedance of the driver circuit under power-off conditions shall
be greater than 300 ohms.

     Note that two widely available integrated circuit chips (1488 and 1489)
implement TTL to RS-232 drivers (4 per chip), and RS-232 receivers to TTL (also
4 per chip), in a manner consistent with all of the above rules.

8.4 DEFINITION OF THE MOST COMMON CIRCUITS

     1 CG Chassis Ground

     This circuit (also called Frame Ground) is a mechanism to insure that the
chassis of the two devices are at the same potential, to prevent electrical
shock to the operator.  Note that this circuit is not used as the reference for
any of the other voltages.  This circuit is optional.  If it is used, care
should be taken to not set up ground loops.

     2 TD Transmit Data

     This circuit is the path whereby serial data is sent from the DTE to the
DCE.  This circuit must be present if data is to travel in that direction at
any time.

     3 RD. Receive Data

     This circuit is the path whereby serial data is sent from the DCE to the
DTE.  This circuit must be present if data is to travel in that direction at
any time.

     4 RTS Request To Send

     This circuit is the signal that indicates that the DTE wishes to send data
to the DCE (note that no such line is available for the opposite direction,
hence the DTE must always be ready to accept data).  In normal operation, the
RTS line will be OFF (logic 1 / MARK).  Once the DTE has data to send, and has
determined that the channel is not busy, it will set RTS to ON (logic 0 /
SPACE), and await an ON condition on CTS from the DCE, at which time it may
then begin sending.  Once the DTE is through sending, it will reset RTS to OFF
(logic 1 / MARK).  On a full-duplex or simplex channel, this signal may be set
to ON once at initialization and left in that state.  Note that some DCEs must
have an incoming RTS in order to transmit (although this is not strictly
according to the standard).  In this case, this signal must either be brought
across from the DTE, or provided by a wraparound (e.g. from DSR) locally at the
DCE end of the cable.

     5 CTS Clear To Send

     This circuit is the signal that indicates that the DCE is ready to accept
data from the DTE.  In normal operation, the CTS line will be in the OFF
state.  When the DTE asserts RTS, the DCE will do whatever is necessary to
allow data to be sent (e.g.  a modem would raise carrier, and wait until it
stabilized).  At this time, the DCE would set CTS to the ON state, which would
then allow the DTE to send data.  When the RTS from the DTE returns to the OFF
state, the DCE releases the channel (e.g. a modem would drop carrier), and then
set CTS back to the OFF state.  Note that a typical DTE must have an incoming
CTS before it can transmit.  This signal must either be brought over from the
DCE, or provided by a wraparound (e.g. from DTR) locally at the DTE end of the
cable.

     6 DSR Data Set Ready

     This circuit is the signal that informs the DTE that the DCE is alive and
well.  It is normally set to the ON state by the DCE upon power-up and left
there.  Note that a typical DTE must have an incoming DSR in order to function
normally.  This line must either be brought over from the DCE, or provided by a
wraparound (e.g. from DTR) locally at the DTE end of the cable.  On the DCE end
of the interface, this signal is almost always present, and may be wrapped back
around (to DTR and/or RTS) to satisfy required signals whose normal function is
not required.

     7 SG Signal Ground

     This circuit is the ground to which all other voltages are relative.  It
must be present in any RS-232 interface.

     8 DCD Data Carrier Detect

     This circuit is the signal whereby the DCE informs the DTE that it has an
incoming carrier.  It may be used by the DTE to determine if the channel is
idle, so that the DTE can request it with RTS.  Note that some DTEs must have
an incoming DCD before they will operate.  In this case, this signal must
either be brought over from the DCE, or provided locally by a wraparound (e.g.
from DTR) locally at the DTE end of the cable.

     15 TC Transmit Clock

     This circuit provides the clock for the transmitter section of a
synchronous DTE.  It may or may not be running at the same rate as the receiver
clock.  This circuit must be present on synchronous interfaces.

     17 RC Receiver Clock

     This circuit provides the clock for the receiver section of a synchronous
DTE.  It may of may not be running at the same rate as the transmitter clock.
Note that both TC and RC are sourced by the DCE.  This circuit must be present
on synchronous interfaces.

     20 DTR Data Terminal Ready

     This circuit provides the signal that informs the DCE that the DTE is
alive and well.  It is normally set to the ON state by the DTE at power-up and
left there.  Note that a typical DCE must have an incoming DTR before it will
function normally.  This signal must either be brought over from the DTE, or
provided by a wraparound (e.g. from DSR) locally at the DCE end of the cable.
On the DTE side of the interface, this signal is almost always present, and may
be wrapped back around to other circuits (e.g. DSR, CTS and/or DCD) to satisfy
required handshaking signals if their normal function is not required.

     Note that in an asynchronous channel, both ends provide their own internal
timing, which (as long as they are within 5% of each other) is sufficient for
them to agree when the bits occur within a single character.  In this case, no
timing information need be sent over the interface between the two devices.  In
a synchronous channel, however, both ends must agree when the bits occur over
possibly thousands of characters.  In this case, both devices must use the same
clocks.  Note that the transmitter and receiver may be running at different
rates.  Note also that BOTH clocks are provided by the DCE.  When one has a
synchronous terminal tied into a synchronous port on a computer via two
synchronous modems, for example, and the terminal is transmitting, the
terminal's modem supplies the Transmit Clock, which is brought directly out to
the terminal at its end, and encodes the clock with the data, sends it to the
computer's modem, which recovers the clock and brings it out as the Receive
Clock to the computer.  When the computer is transmitting, the same thing
happens in the other direction.  Hence, whichever modem is transmitting must
supply the clock for that direction, but on each end, the DCE device supplies
both clocks to the DTE device.

     All of the above applies to interfacing a DTE device to a DCE device.  In
order to interface two DTE devices, it is usually sufficient to provide a
"flipped" cable, in which the pairs (TD, RD.), (RTS, CTS) and (DTR, DSR) have
been flipped.  Hence, the TD of one DTE is connected to the RD. of the other
DTE, and vice versa.  It may be necessary to wrap various of the handshaking
lines back around from the DTR on each end in order to have both ends work.  In
a similar manner, two DCE devices can be interfaced to each other.

     An RS-232 "breakout box" is particularly useful in solving interfacing
problems.  This is a device which is inserted between the DTE and DCE.
Firstly, it allows you to monitor the state of the various handshaking lines
(light on = signal ON / logic 0), and watch the serial data flicker on TD
and/or RD.  Secondly, it allows you to break the connection on one or more of
the lines (with dip-switches), and make any kind of cross-connections and/or
wraparounds (with jumper wires).  Using this, it is fairly easy to determine
which lines are not functioning as required, and quickly build a prototype of a
cable that will serve to interface the two devices.  At this point, the
breakout box can be removed and a real cable built that performs the same
function.

     An example of this kind of device is the Datatran Datatracker available
from Nordtech Research, Inc.  With many breakout boxes, care has to be taken to
connect the correct end of it to the DTE device, or the lights and switches do
not correspond to the actual signals.  But with this device the voltages of the
two inputs are separated so, for example, if two DTE devices are hooked up to
it the DTR light on both sides would show a Red light.

              Chapter 9 - Products/Services from Nordtech Research

9.1 Communications Hardware

     Nordtech Research, Inc. is a distributor of many communications hardware
products.

     One of the most useful tools available when developing communications
software is an RS-232 breakout box.  This device allows monitoring of data and
control (handshake) lines at the physical level, provides a means of rewiring
from one line on one side to another on the other side.  By connecting this
device in line with a serial cable, it becomes a science rather then an art to
establish communications between two devices.

     When connecting two computers together, the first question to ask is
whether they are both DTE devices or if one has a DCE wired port (many serial
boards for the IBM-PC for example allow setting up as either).  This can be
easily determined by connecting a breakout box to one of the devices (after the
software is running) and observing which data line is being "marked" (i.e.
negative voltage).  If the transmit line (line 2) is being marked it is
configured as a DTE; receive line (line 3) would indicate that the device is
configured as DCE.

     If both devices are DTE (or both DCE) then a "null modem" cable will be
needed.  Unfortunately many different options need to be resolved.  If you are
developing the software for both devices, you will have control over the
hardware and softwarehandshaking.

     Many times, however, you only have control over one end and won't have
good specifications for the other end.  A breakout box can determine what, if
any, handshake is needed by the other end very quickly.  Often you can wire a
cable that feeds the DTR signal provided by the other computer back to his DSR
and CTS lines, but this disallows you from stopping his transmission at the
hardware level.  This may be desirable, however, if you are using a software
protocol (i.e. XOFF/XON, etc.).

     Please call for our latest pricing and availability on these and other
useful testing devices, cabling, modems, etc.  You can count on getting a
better price from us than the list price usually charged by communications
specialists.

                    Nordtech Research, Inc. Current Pricing


  Manufacturer            Model             List Price          Our Price

    Datatran               Mini-Tracker           $29.95                $24.95
                      Mini-Tracker Plus           $49.95                $42.95
                            Datatracker          $239.95               $195.95
                             Micropatch           $29.95                $24.95
                         Gender Menders           $19.95                $14.95
                   Universal Cable (4")           $39.95                $34.95
                   Universal Cable (8")           $44.95                $39.95
                    Standard Cable (4")           $24.95                $19.95
                    Standard Cable (8")           $29.95                $24.95

    Digiboard                     Com 4          $479.00               $399.00
                                  Com 8          $749.00               $625.00
                                 Com 4i          $985.00               $825.00
                                 Com 8i         $1195.00               $995.00




     The mini-tracker and mini-Tracker Plus are simple LED devices which show
the state of the various signals.  The Mini-Tracker shows the 9 most used
signals and the Plus version shows all 24 (line 1 not monitored).  The
Mini-Tracker uses Tri-State LEDs which glow red for negative voltage and green
for positive.  The Plus has separate LED's for positive and negative voltages
which can be very helpful in identifying data on a line, especially at higher
baud rates.

     The Datatracker is one of the most powerful Breakout Boxes on the market
today for analyzing RS-232 communications problems.  It not only has 2 LEDs for
each line, but it separates the DTE side from the DCE side so if both devices
are actually DTE, both DTR lights would be illuminated.  The device also allows
breaking each signal and patching it to another line.  For example when you
have determined that both pieces of hardware are DTE you could patch the DTR on
one side (line 20) to DSR on the other side (line 6), and vice-versa.  2 would
go to 3 (xmit to recv), 4 to 5 (CTS to RTS).  This would give complete
handshake between the two devices.  All other lines would be left connected
straight across (i.e. 1 and 7).  The Datatracker also has provisions to
automatically switch lines 2 and 3 (a common need).  It also has optional add
on devices to test an installed cable (i.e. one that has been run through the
ceiling down the hall 100 feet (beyond the recommended limit for RS-232!).  By
attaching the Datatracker to one end of the cable and the optional cable tester
to the other end, the Datatracker will show which lines are connected and how.
Call for pricing on the cable tester.

9.2 Consulting Services

     Nordtech Research specializes in communications software development.  Our
services can be obtained for large and small software development projects and
for phone questions.

     Phone questions can be billed to your Visa/MasterCard at the rate of $20
per 15 minutes (as of June 1988).  Longer term projects can be done on a fixed
price basis if suitable specifications for the project are available, or on an
hourly rate of $60/hour (as of June 1988).

                          Chapter 10 - Version History

                                 Version 3.0:

     This version adds support for the 16550 UART.  This UART has built in FIFO
buffers which greatly improve high speed communications reliability.  Even
though the chip is advertised to be completely compatbile with the 16450 UART 
and earlier chips, it would not work with previous versions of the toolbox.
The Async_Open function now checks to see if this UART is present and sets it
up to use the FIFO it is there.

     Other fixes have been made including a problem with some copies of the 
Version 2.9 Borland Large Memory model library.  There were no code fixes,
just some corrupt files.

                                  Version 2.9:

     This version further improves upon the send interrupt handling, especially
for the 8250 and 82C50 chips.

     Some 82C50 chips don't seem to ever generate an interrupt when the
transmit buffer is empty.  To handle this case call Async_Open with the
transmit buffer size parameter set to 0 and all data is then sent without using
interrupts.  The data is also not buffered.  See Async_putc.

     The sendfile function in filexfer (XMODEM Send) has been fixed to work
when sending to PROCOMM.  It takes a few seconds before data flow begins.
PROCOMM first trys to use the CRC protocol then trys the CHECKSUM protocol
which these tools use.

     The function SendLine is added to the Async_String module.

     The function SendBlock and GetBlock are added to the Digiboard versions.

     The function WaitFor is added to the filexfer module.

     All BorlandC libraries were compiled with BorlandC++ V2.0.  No C++
capabilities are used.

     All Microsoft libraries were compiled with MSC 6.0.

                                  Version 2.8:

     This version further improves upon the interrupt handling, especially when
2 ports are being used simultaneously.  The previous versions had a common
stack area for all ports and this version creates a separate stack area for
each port.  It also allows higher priority interrupts to have priority over the
commo port interrupts.

     Several new functions have been added (window attributes, a routine to
check percentage use of the send buffer, etc.).

     All BorlandC libraries were recompiled with BorlandC C++ version 1.0.

     The Digiboard version has been overhauled and uses the latest board
drivers from Digiboard Corporation.  The previous version didn't handle
hardware handshaking properly.  See DATAMON.C : Open_Commo_Ports() for an
example of setting up incoming hardware flow control (i.e. handshaking).

     Many batch and make files were modified to accommodate our new computer
systems modified environment (i.e. directory structure).  These include:
TMF.BAT, MMF.BAT, ZMF.BAT, BORLANDC.BAT, MSC.BAT, ZOR.BAT and almost all make
files (*.m).

                                  Version 2.7:

     This version fixed a bug in the interrupt handling which could cause the
system to hang when characters are being sent and recieved simultaneously.  It
also added processing of receive errors and BREAK detection via interrupt
handlers.  It also fixes a potential problem for users who use the DI and SI
registers (used with optimization turned on in 'C').  They were not being saved
in the interrupt routine previously.

     Several routines were added to the windowing package for controlling
character attributes.

     It also includes faster code for users of Digiboard products.  FAR
pointers are used instead of assembly routines to access data in the Digiboard
memory.

                                  Version 2.6:

     This version fixed several bugs in the large code models.

     It also has several fixes to the filexfer.c module.

     Several improvements to the quality of the manual.

                                  Version 2.5:

     Fixed bugs in modem.c, added print capability for modem.c (ALT-P).  Fixed
various other minor bugs.

                                  Version 2.4:

     Added interrupt driven, buffered SEND modules.  Requires changes to
previously developed code (add size of send buffer in Async_Open).

     Fixed Microsoft C bug which caused stack overflow message (fix is in make
file).
