home *** CD-ROM | disk | FTP | other *** search
- Comm_TP4.PAS Ver. 1.50 - RS-232 Support for IBM Compatibles - Documentation
-
- (c) Copyright, 1989
- Kevin R. Bulgrien
- November, 1989
-
- c/o LeTourneau University
- Microcomputer Services
- P.O. Box 7001
- Longview, TX 75607
-
-
-
- INTRODUCTION
-
- This utility is an answer to the many public domain serial port routines which
- I have acquired in the quest for good RS-232 support under Turbo Pascal. Unlike
- the others, this one works. Not only does it work, but it also allows you to
- use as many COM ports as you want at the same time. Designed to be relatively
- simple and easy to use, I hope many will benefit from it.
-
- This code only works under Turbo Pascal versions 4.0 and 5.x. For functionally
- equivalent routines that work under Turbo Pascal 3.0, look for COMM_TP3. Also,
- a Turbo C version called COMM_TC2 is available. While it was written for Turbo
- C 2.0, it will probably also work for lower versions as well. Additionally, I
- am in in the process of developing a Turbo Assembler version called Comm_TA1.
-
-
-
- DISTRIBUTION POLICY
-
- The following files must all be present whenever this package is distributed:
-
- COMM_TP4.PAS - Turbo 4.0 & 5.x compatible TPU source code
- COMM_TP4.DOC - Documentation for the TPU source code
- COMM_TTY.PAS - Demo terminal emulator which uses COMM_TP4
-
- This package may be used in any non-commercial application without restriction,
- although I do require that the source code not be distributed in a modified
- form unless you clearly identify the modifications and do not remove any of
- my copyright information, distribution policy, or other relevant documentation.
-
- If you wish to use this package for development of software which will be sold
- or released with a shareware notice, I do require that a one-time registration
- fee of $10.00 be paid to me. Because this source code is a platform from which
- one can build other tools, you are not exempt from this requirement if you have
- to modify or add to my code in order to make it fit your specific application.
- A letter which acknowledges your payment will be sent to you by return mail.
-
- I specifically prohibit any distribution of the source code where a disk fee is
- charged, unless I have granted written permission to the specific vendor making
- such a charge. A general access fee to an electronic bulletin board system is
- not considered a disk fee.
-
- I also specifically prohibit any person or entity from claiming copyright on
- this material without first obtaining my personal, written consent. Monetary
- compensation to me will be required for any such agreement to be valid. This
- does not infer that you may not copyright material which uses this product.
-
-
-
- DISCLAIMER
-
- While I have extensively tested the routines in this package, I will not be
- held responsible for any consequence arising from the use thereof. It is the
- responsibility of the user to determine whether or not the enclosed routines
- will satisfactorily perform the required functions.
-
- This software directly accesses the Intel 8250 UART as well as the Intel 8259
- interrupt controller hardware. Though they are IBM standards, it is possible
- that some manufacturers could use different hardware to supply these functions,
- in which case, program compatibility would be questionable.
-
-
-
- CREDITS
-
- Credit for this product must go to the various authors who showed me that if I
- wanted something that worked, I would have to write it myself. I won't try to
- identify the items, but I obtained at least twelve serial port handlers from
- GEnie which could not satisfy my meager requirements. It amazing to see how
- much code is out there which either: 1) does not perform satisfactorily, 2)
- has inadequate documentation, 3) is so complex that only an expert could use
- it, or, 4) does not contain modifiable source code.
-
- All of the enclosed code is completely original to me, and has not been stolen,
- borrowed, or purchased from any other source.
-
- Credit for the information on the IBM compatible hardware must go to the
- Prentice-Hall book "Systems Software Tools" by Ted J. Biggerstaff. I was
- amazed to find a book that so clearly outlined the IBM PC interrupt and serial
- port hardware. The world of IBM PC technical information is a desert, and
- this book is a rare oasis in the midst of it.
-
- Additionally, credit must also go to the "DOS Programmer's Reference" by Terry
- R. Dettmann which is published by the QUE corporation. I would recommend it
- to any programmer who needs a good DOS or BIOS reference.
-
-
-
- FEATURES
-
- - Easily expandable interrupt routine
- - Interrupt driven send and receive routines
- - Carrier Detect monitoring for modem support
- - Turbo Pascal 4.0 & 5.x compatible TPU source code
- - Convenient TPU format keeps your code uncluttered
- - Easy to customize for your hardware, and software requirements
- - Uninstalls the interrupt handlers on abnormal program termination
- - Number of COM ports limited only by buffer sizes & Turbo memory limits
- - A TPU which handles 4 ports can be less than 8K in size
- - Easy to use even if you don't understand how it works
- - All COM ports handled concurrently in the background
- - Example TTY and port setup routines included
- - Optional error checking and error messages
- - Extensive documentation for software use
- - Heavily documented source code
-
-
-
- DESIGN PHILOSOPHY
-
- This is a rather grand heading, but I think now is a good time to share the
- philosophy used while writing this software. This, along with a look at the
- code and the rest of the documentation, will help you to decide if Comm_TP4
- is for you.
-
- Most serial applications which I have been involved with were very simple in
- nature. I did not require a super-high-performance-do-everything-imaginable
- piece of software, and as a result, I wrote a port handler which reflected my
- particular needs - but also a little bit more.
-
- For example, the simple monitoring of Carrier Detect makes this an ideal
- package to write online BBS support programs with. One of the university
- students here has used my package to write a complete online game.
-
- Also, early versions of Comm_TP4 only supported standard DOS ports, but since
- I saw that some people would need non-standard setups, I rewrote the code so
- that it would allow most any setup. I have yet to need such a feature, but it
- is there and you can be sure that I will keep on adding more support items
- like this as time goes on.
-
- Perhaps one of the most important guiding principles I have tried to abide by
- can be summed up with a KISS (Keep It Simple Stupid). I have seen one or two
- communications packages that provided a plethora of low level routines which
- could be used to manipulate every aspect of the hardware. I have deliberately
- kept this type of code out of Comm_TP4 in the interest of providing a simple-
- to-use package rather than an it-does-everything one. I figure that if someone
- knows how to use the low-level operations, they probably know enough to be able
- to add them to my code. Because most people do not need complicated routines,
- I felt I would gain more friends by making Comm_TP4 easy-to-use than enemies by
- making Comm_TP4 "incomplete". Make no mistake, though, "incomplete" is a very
- relative term, and I really don't believe it applies here.
-
- In summary, I am confident that the routines are high-performance enough to
- satisfy the bulk of serial port applications. They do not, however, provide
- a do-everything-imaginable user interface, and yet, there is little that one
- cannot do. Easy-to-use, flexible, and growing are the key words.
-
-
-
- GETTING STARTED - DOES IT REALLY WORK?
-
- If you want to prove that these routines really work, first compile the source
- file COMM_TP4.PAS into a TPU file with your Turbo compiler.
-
- IMPORTANT NOTE: Never compile interrupt driven routines with the stack
- checking code enabled. Doing so will cause the program
- to crash whenever the interrupt is invoked.
-
- Next, compile and run the COMM_TTY program as it is distributed. What you will
- see is a crude terminal emulation program which uses the COMM_TP4 routines. It
- is capable of receiving data from several COM ports at the same time. The
- screen echoes data from the "logged" COM port and buffers the data from other
- ports. When a different COM port is logged, the buffered data is sent to the
- screen. Also provided is a setup routine that lets you select a baud rate from
- 110 to 38400. The other protocol attributes are also selectable.
-
-
-
- AN EXAMPLE OF HOW EASY IT IS TO USE COMM_TP4
-
- All it takes is a few simple commands. For example, let us set up the serial
- port to 2400 baud, 8 bits, no parity, and 1 stop bit. Then, we'll install an
- interrupt handler and send a string out the port, and wait for a short
- response. Lastly, we will shut off the interrupt handler.
-
- The program that follows will work with COM1 or COM2 without any modification
- to the TPU source code that has been included with this documentation.
-
- PROGRAM TestPort;
-
- USES Comm_TP4;
-
- CONST
- Com = 1; { Use COM1, use 2 for COM2 }
-
- VAR
- InputData : CHAR;
-
- BEGIN
- SetupCOMPort (Com, ORD(B2400), 8, ORD(None), 1);
- InstallInt (Com);
- WriteCOM (Com, 'This really is easy. Isn't it?');
- InputData := TimedReadCOM (Com);
- RemoveInt (Com);
- END.
-
- That is all there is to it. The Comm_TTY example may be intimidating because
- of its size, but that's just because it is a whole terminal emulator.
-
- To be sure, most applications will need a bit more than what is shown here, but
- that's what the rest of the documentation addresses. I just thought it would
- be good to emphasize the ease of using Comm_TP4 before delving into the deep,
- dark world of technical information.
-
-
-
- HOW TO USE THE INTERRUPT HANDLERS IN YOUR PROGRAM
-
- You may invoke SetupCOMPort to change the settings of the COM ports at any
- time. Unless you are sure the port is already set up correctly, you should
- use it before you attempt to communicate with the port.
-
- You may turn DTR and RTS on and off with Set_DTR_RTS in order to provide
- simple hardware handshake capability.
-
- You may install COM port handlers with InstallInt at any time and any order.
-
- You may uninstall COM port handlers with RemoveInt at any time and any order.
-
- You may force any of the input or output buffers empty at any time by using
- Procedure EmptyBuffer. This allows you to abort any interrupt driven transmit
- routine. It also allows you to flush unwanted input from the receive buffers.
-
- To read data that has come in from a port, one of the following is required:
-
- 1) FUNCTION ReadCOM (Com : BYTE) : CHAR;
- FUNCTION TimedReadCOM (Com : BYTE; VAR Data : CHAR) : BOOLEAN;
-
- where Com <= MaxPorts. Usually Com will refer to the DOS COM port
- number, but it does not have to. In any case, the global value
- COMNmbr [Com] indicates the DOS COM port number.
-
- ReadCOM will wait until data becomes available if there is no data in
- the receive buffer - forever if necessary.
-
- TimedReadCOM will abort and return FALSE if data does not become
- available in a relatively short period of time. The data is placed in
- the VARiable parameter 'Data' when TimedReadCOM returns TRUE.
-
- 2) DisableInts;
- CharReady := InTail [Com] <> InHead [Com];
- EnableInts;
-
- where CharReady is a user defined BOOLEAN that will be TRUE if data is
- waiting in the buffer or FALSE if not data is waiting.
-
- DisableInts;
- CharData := CHR(InBuffer [Com, InHead [Com]]);
- InHead [Com] := (InHead [Com] + 1) MOD (MaxInSize + 1);
- EnableInts;
-
- where CharData is a user defined CHAR variable that will contain the
- next item in the buffer IF AND ONLY IF CharReady is TRUE. The item is
- removed from the buffer with the statement following the CharData
- assignment.
-
- To write data to a port, use one of the following methods:
-
- 1) FUNCTION WriteCOM (Com : BYTE; Data : STRING) : BOOLEAN;
- PROCEDURE WriteCOM (Com : BYTE; Data : STRING);
- PROCEDURE IWriteCOM (Com : BYTE; Data : STRING);
-
- where Com <= MaxPorts. Usually Com will refer to the DOS COM port
- number, but it does not have to. In any case, the global value
- COMNmbr [Com] indicates the DOS port number. Data is either STRING
- or CHAR information to be sent to the port.
-
- Both the function and procedure declarations of WriteCOM will wait for
- all of the data to be sent. If it has trouble sending the information,
- both will time out and return. Use the function declaration if you
- want to be notified when this happens. A returned FALSE indicates that
- the transmission failed.
-
- IWriteCOM returns immediately after placing all data in the transmit
- buffer. The data is sent in the background while your program does
- other things. It is not practical to use IWriteCOM for sending single
- characters since it always calls WriteCOM once. No provision is made
- to handle transmission failures.
-
- 2) PortReady := ((PORT [COMPort [Com]+LSR] AND $20) = $20);
-
- where PortReady is a user defined BOOLEAN variable which will be TRUE
- if the port Transmitter Holding Register is ready for a character to
- send to the port.
-
- PortReady := PortReady AND CTS [Com] AND DSR [Com];
-
- This statement allows you to see if the CTS and DTR lines indicate that
- the other serial device is ready to receive data. It may be omitted if
- you do not want to check these lines.
-
- PORT [COMPort [Com]+LCR] := PORT [COMPort [Com]+LCR] AND $7F;
- PORT [COMPort [Com]+THR] := ORD (CharData);
-
- This statement places the data in the transmit buffer. CharData is a
- user-defined CHAR variable that contains a character to send to the
- port. PortReady, as defined above, MUST be TRUE before placing this
- data in the Transmitter Holding Register otherwise the previous data
- item will be lost.
-
- NOTE: These low-level code fragments are provided so that you can write
- receiver and transmitter routines which support your particular needs.
- See the following technical information for more details.
-
-
-
- SETTING COMM_TP4 UP TO USE IN YOUR OWN PROGRAMS - TECHNICAL INFORMATION
-
- In order to use the serial routines, simply include Comm_TP4 in your USES
- statement at the top of the program. Of course, you can add or delete routines
- from the TPU source code to make it fit your applications. Because of Turbo's
- smart linking, however, it is not necessary to remove code that you do not need
- in a particular program since unused code is not added to the final .EXE file.
-
- All of the variables necessary for developing your own customized input/output
- routines are in the INTERFACE section so that you do not have to recompile the
- unit if you include new serial I/O source code in your program.
-
- Several conditional compilation directives at the top of the source file allow
- you to compile TPUs customized for special applications:
-
- {$DEFINE ErrorChecking} - Inclusion of this directive will enable various
- error checking code that could help you debug a
- program under development. It can also be used
- as a basis for your own error checking routines.
- To safeguard against fatal run-time errors, the
- procedures InstallInt & RemoveInt always contain
- some error checking whether this directive is
- present or not.
-
- {$DEFINE NoMessageCode} - This directive is used to eliminate all code
- which would send error messages to the screen.
- It does not disable error handling.
-
- The global variables ErrMsgX, ErrMsgY, and
- ShowMessages are also disabled with this
- directive.
-
- Error messages consist of a beep, the procedure
- or function name, the handler number, and the
- error description.
-
- {$DEFINE FWriteCOM} - WriteCOM is the main procedure which is used to
- send data to a port. It times out if the data
- cannot be transmitted for some reason. Placing
- this directive at the top of the source file
- causes WriteCOM to be made a function that
- returns a boolean value of TRUE if all of the
- data was transmitted successfully.
-
- I would suggest that you use the {$UNDEF} directive in place of {$DEFINE} when
- you do not want to use one of these compilation directives. By doing so, you
- will always realize that the directive exists when you casually look over the
- source code.
-
- Several CONSTants exist which can be used to customize Comm_TP4 for a variety
- of purposes:
-
- MaxPorts - The maximum number of ports which can be supported at the
- same time. The maximum possible setting of MaxPorts is
- restricted only by Turbo Pascal's space limitations for
- TPU files.
-
- MaxInSize - The maximum size of the input and output buffers. Both are
- MaxOutSize provided so that memory can be conserved if the sizes needed
- for input and output are different, and both affect the
- maximum possible value of MaxPorts.
-
- COMNmbr - A predefined array which can be used to identify the actual
- COM port serviced in case the order does not agree with the
- internal port/buffer numbers.
-
- Actual COM number = COMNmbr [Software Port Number]
-
- COMPort - A predefined array of base addresses for the INTEL 8250
- serial ports available. Comm_TP4 comes preconfigured with
- the standard IBM/DOS addresses used for COM1 through COM4 but
- can be set up for any valid port address.
-
- To access the registers of a given port, use the following
- constants:
-
- THR - Transmit Holding Register
- RHR - Receive Holding Register
- DLL - Divisor Latch Register Least Significant Byte
- IER - Interrupt Enable Register
- DLM - Divisor Latch Register Most Significant Byte
- IIR - Interrupt ID Register
- LCR - Line Control Register
- MCR - Modem Control Register
- LSR - Line Status Register
- MSR - Modem Status Register
-
- For example, to access the Modem Control Register, use the
- following expression where Com is the port handler number:
-
- PORT [COMPort [Com] + MSR]
-
- One exception exists however. The THR, RHR, and DLL occupy
- the same address, as do the DLM and IER. To distinguish
- which registers you are accessing, use the LCR register.
-
- Do not be confused by THR and RHR, as they are really the
- same register, but functions differently depending on whether
- you write to or read from it. In any case, to select the
- THR, RHR, and the IER, use the following commands:
-
- PORT [COMPort [Com]+LCR] := PORT [COMPort [Com]+LCR] AND $7F;
-
- To select the DLL and DLM registers, use:
-
- PORT [COMPort [Com]+LCR] := PORT [COMPort [Com]+LCR] OR $80;
-
- IRQNmbr - A predefined array which identifies the interrupt priority to
- be used for each port. Lower IRQ numbers cause the port to
- receive attention first if a conflict arises. This number
- depends on a hardware setting, and can have fatal effects
- if numbers other than 3 or 4 are used. You must know exactly
- what you are doing if you change these numbers. Comm_TP4
- comes preconfigured with the standard IBM/DOS IRQ numbers for
- COM1 through COM4.
-
- ChainInt - A predefined array which is not used at this time. It is
- here to remind me to make an enhancement that will allow a
- Comm_TP4 interrupt handler to be placed in series with a
- pre-existing interrupt handler. For example, many memory
- resident programs place their own keyboard interrupt handler
- in series with the original DOS interrupt handler so that
- they can invoke themselves with unique key combinations.
- The possibilities are intriguing...
-
- NOTE: All of these CONSTants could be changed to VARiables so that your
- program could prompt the user for the correct information about his
- machine. Dynamically allocated heap variables would come in handy if
- you wanted to change the MaxPorts, MaxInSize, and MaxOutSize constants
- at run-time. Perhaps Comm_TP4 will incorporate these ideas later on.
-
- Several VARiables exist which can be used to poll Comm_TP4 for the current port
- status. They can also be used to build your own low-level Comm_TP4 functions
- for a variety of purposes:
-
- OutBuffer - These two dimensional character arrays are the output and
- InBuffer input buffers for all of the ports which can be serviced
- by the Comm_TP4 routines. CONSTants MaxPorts, MaxInSize,
- and MaxOutSize directly affect the size of these arrays,
- so you should optimize their settings for your particular
- application. All buffer operations are outlined below.
-
- OutHead - These one dimensional word arrays are the pointers into the
- OutTail buffer arrays. They are used so that the buffers become
- InHead circular queues. The head points to the next item in the
- InTail buffer, unless (Head = Tail) in which case the buffer is
- empty. The tail points points to the place where new data
- will be placed when it arrives, unless (Tail + 1) MOD
- MaxSize = Head in which case, the buffer is full.
-
- When you want to take something out of a buffer:
-
- 1) You must first be sure the buffer is not empty.
- 2) Get the character with Buffer [Com] [Head]
- 3) Adjust the head pointer to (Head + 1) MOD MaxSize
-
- When you put something into the buffer:
-
- 1) You must first be sure the buffer is not full
- 2) Put the character into Buffer [Com] [Tail]
- 3) Adjust the tail pointer to (Tail + 1) MOD MaxSize
-
- In the above examples, the "In" and "Out" qualifiers have
- been left out. Also, "Com" refers to the handler number.
-
- NOTE: ALWAYS disable the hardware interrupts before you
- do anything with the input or output buffers and pointers.
- Not doing so will cause hard to find run-time errors, but
- NEVER forget to re-enable the interrupts after you disable
- them. Not doing so will disable other crucial hardware
- operations along with your serial port I/O functions.
-
- IntInstalled - This one dimensional boolean array indicates when a port
- handler has been installed. You should never change its
- value as doing so will eventually cause the computer to
- crash since it controls the modification of the system
- interrupt vectors. To read the install status, check the
- following expression, where Com refers to the appropriate
- handler number:
- IntInstalled [Com]
-
- ErrorCode - ErrorCode is set to 0 after a serial port operation has
- ErrorPort occurred without any errors. If it is not zero, ErrorPort
- indicates which port the error occurred on. ErrorCode will
- be one of the following:
-
- 1 - Invalid port number
- 2 - Port already installed
- 3 - Port not installed yet
- 4 - Timeout writing to port
- 5 - Timeout reading a port
-
- ErrorCode and ErrorPort remain valid until the next serial
- port operation is requested.
-
- ShowMessages - This global boolean variable is used to tell Comm_TP4's
- error handler whether or not it should display messages
- on the screen. TRUE allows messages to be displayed, and
- the default value may be set in the unit initialization
- code. If the {$DEFINE NoMessageCode} directive is used,
- this variable will not exist.
-
- ErrMsgX - Like ShowMessages, these global variables are used by the
- ErrMsgY Comm_TP4 error handler. The {$DEFINE NoMessageCode}
- directive also removes them from the code.
-
- ErrMsgX and ErrMsgY determine where the messages will be
- printed. A coordinate of 0 will cause the message to print
- at the current cursor coordinate given by WHEREX or WHEREY.
- Their default values are 0. If you want the messages to be
- written at a specific screen position, you must set them to
- the desired coordinates before you request a serial port
- operation which uses error checking. The default settings
- may be specified in the unit initialization code.
-
- DTR_RTS - This array controls whether or not the Comm_TP4 routines
- are allowed to change the status of DTR and RTS. Programs
- which use modems may not want the software to drop DTR and
- RTS since this can cause the modem to hang up. A TRUE
- enables DTR and RTS setting, and the default value may be
- specified in the unit initialization code.
-
- Be wary of hardware handshaking... I have found that my
- modem refuses to work when I set DTR_RTS TRUE even though
- it theoretically should work. Actually, I prefer to write
- my applications so they turn DTR and RTS on, them leave
- them on. Hardware handshakes end up being headaches more
- often than not.
-
- CD - These one dimensional boolean arrays indicate the current
- CTS status of each port's input lines. They are correctly set
- DSR when the program starts up, but only track changes in
- RI status while an interrupt handler is installed AND while
- the Modem Status Change interrupt type is enabled. When
- you install an interrupt handler, each array is set again.
- The current status of an individual line can be read while
- an interrupt handler is not installed as well. To do so,
- use one of the following statements, where Com refers to
- the port handler number:
-
- CD [Com] := ($80 AND PORT [COMPort [Com]+MSR] <> 0);
- CTS [Com] := ($10 AND PORT [COMPort [Com]+MSR] <> 0);
- DSR [Com] := ($20 AND PORT [COMPort [Com]+MSR] <> 0);
- RI [Com] := ($40 AND PORT [COMPort [Com]+MSR] <> 0);
-
- Framing - These arrays are used to keep track of the number of
- Break communications errors which occur on each port. This is
- Overrun perhaps a trivial operation, however, it does serve to
- Parity document how to detect the error conditions.
-
- Each array element is initialized to zero on startup, then
- they are incremented every time a corresponding line status
- error interrupt occurs. You may change their values at any
- time without affecting the operation of the software.
-
- Several VARiables exist which are deliberately not included in the INTERFACE
- section of the TPU. They are critical to the internal operation of Comm_TP4,
- and should NEVER be altered by external routines. They are documented here
- for completeness.
-
- OldIntVector - This array keeps track of the interrupt vector which should
- be restored when Comm_TP4 uses RemoveInt to uninstall an
- interrupt handler. InstallInt initializes OldIntVector
- as necessary.
-
- ExitSave - A pointer which is necessary for linking into Turbo's exit
- procedure structure. This is what allows the automatic
- uninstallation of Comm_TP4 interrupts whenever the program
- terminates - whether normally or abnormally. ExitSave is
- initialized on program startup.
-
- IRQMask - A bit map of all IRQ levels which currently have Comm_TP4
- interrupts installed. This makes it fairly easy for the
- InstallInt and RemoveInt procedures to know whether or not
- they need to alter the interrupt vectors and the 8259 IMR.
- The primary reason for using IRQMask, however, is to allow
- the interrupt handler to enable higher priority interrupts
- while preventing Comm_TP4 from interrupting itself. Only
- InstallInt and RemoveInt may modify the value of IRQMask
- after it is initialized to zero on program startup.
-
-
-
- KNOWN PROBLEMS WITH COMM_TP4
-
- At this time, the interrupt handler is not efficient enough to operate well
- at high baud rates on slow PC's if you have too many of the interrupt types
- enabled. It will fail, for example, if you try to communicate at 9600 baud
- on a 4.77 MHz machine while the Line Status, Modem Status, and Receive
- interrupt are all activated. I plan to explore the nature of the problem
- further in the near future.
-
-
-
- CONSIDERATIONS FOR PROGRAMS WHICH USE INTERRUPT HANDLERS
-
- Interrupt handlers operate in ways that can confuse those who are not used to
- working with them, so, the following discussion may be helpful if you are
- planning to modify Comm_TP4.
-
- Keep in mind that an interrupt can occur at ANY time. This means that a Pascal
- statement could be interrupted during its evaluation. Usually this is not a
- problem, but sometimes it is very much a problem. This is the case when both
- the interrupted code and the interrupt handler need to access and/or modify the
- same data. Consider the following trivial, unrealistic, but enlightening code
- fragment:
- X := 1;
- { Interrupt1 }
- Y := 2;
- Z := X * Y;
- IF (Y = { Interrupt2 } Z)
- THEN WRITE ('EQUAL')
- ELSE WRITE ('NOT EQUAL');
-
- It seems obvious that the else clause will never be executed, but this can be
- very untrue in the case of a program which uses interrupts! If, for example,
- an interrupt handler interrupted this program at the comment { Interrupt1 },
- we can easily see that the program would not do what we expect it to do if the
- interrupt handler changed the value of X. A less obvious flaw shows up though,
- if you consider an interrupt occurring at { Interrupt2 }. Here, both Y and Z
- could actually equal 2, but since the interrupt changes Z before it finishes
- comparing the values, the comparison fails. Once again, this is a non-sensible
- example, but try to imagine the same thing happening with our serial port
- handler buffers and buffer pointers...
-
- The whole point is that certain operations should not be interrupted, and this
- is where the DisableInts and EnableInts inline procedures come into play. They
- are used to temporarily suspend interrupt processing and to re-enable interrupt
- processing when the program has passed the danger zones. This is the reason
- you will see them sprinkled throughout the Comm_TP4 routines, and if you plan
- to write you own serial I/O routines, you will need to know where to put them.
-
- 1) Always disable interrupts while setting the 8259 interrupt hardware.
-
- 2) Consider disabling interrupts when you are accessing data which could
- be altered by the interrupt handler. The key is to be able to discern
- whether or not the effects of an interrupt would cause the program to
- operate abnormally -or- if an interrupt could even occur in crucial
- areas. Obviously, if an interrupt has not been installed, it is
- pointless to disable it during that section of code.
-
- 3) Remember that you must not leave interrupts off for significant periods
- of time. The clock, keyboard, disk drives, etc. all work off of the
- hardware interrupt system. Things could really get flaky if you forgot
- to reenable interrupts after turning them off - besides, you would
- defeat the whole purpose behind using an interrupt driven routine.
-
- 4) Be careful that you don't paint yourself into a corner by disabling
- interrupts during an operation that requires the interrupts to be on.
- For example, if we disabled interrupts while checking to see if data
- was in the input buffer, we had better turn them back on sometime before
- the loop returns to check the buffer again, or else you've just created
- an endless loop.
-
- Interrupt handlers can be tricky to use, but with the right mix of caution,
- bravery, and forethought the results can be impressive. Don't let the words
- of warning scare you off!
-
-
-
- SUPPORT
-
- User support may be obtained by contacting me via the LeTourneau University BBS
- at (214) 237-2742. The BBS runs 24 hours a day and accepts calls at 300, 1200,
- and 2400 baud. Since I am the SysOp of this board, this is the fastest way to
- reach me. My GEnie mail address is K.BULGRIEN, but money being at a premium,
- I do not always check in on a regular basis. I may also be reached during
- business hours at (214) 753-0231 ext. 352.
-
- Support will be limited to clarification of the routines I wrote, but don't
- holler for help if you haven't bothered to read the documentation first. I
- will be glad to fix any bugs that I may have missed, but I cannot be expected
- to debug your routines or enhance my routines for your specific application.
- Money does have a way of changing people's minds though...
-
-
- UPDATES
-
- I will place updates of the enclosed routines on LeTourneau University BBS at
- (214) 237-2742. The BBS runs 24 hours a day and accepts calls at 300, 1200,
- and 2400 baud.
-
- I will also place updates in the BORLAND RT on the GEnie information service.
-
- Possible updates may include:
-
- 1) Run-time allocation/configuration of port handler variables and setup
- 2) Addition of file transfer protocols
- 3) Miscellaneous enhancements
- 4) Other language versions
- 5) Your ideas...
- 6) Bug fixes
-
-
-
- VERSION HISTORY
-
- Version numbers will always be in the form [a.bc] where [c] indicates a bug fix
- or a minor file change, [b] indicates a minor enhancement or rewrite, and [a]
- indicates a major addition or rewrite. I will always increment the version
- number when I release a set of files with code changes as I want to maintain
- strict control of the status of files which are being distributed.
-
- Beta ??/87 It was a long time in the making. The early implementations were
- buggy and undocumented since I was just learning the technology.
-
- 1.00 11/88 The first officially released version which was placed in the
- Borland Roundtable on GEnie. The code was written under Turbo
- Pascal Version 3.01A and I ported the routines to Version 4.0 &
- 5.0, and then to Turbo C 2.0. Subsequent versions have been
- developed under Turbo Pascal 4.0/5.x and ported to the other
- language implementations.
-
- 1.01 02/89 Bug fix in Procedure RemoveInt. It correctly uninstalled the
- interrupt code except that it would disable all IRQ interrupts
- except the one used by the specified COM port. (An AND instead
- of an OR in the statement writing to PORT [$21]. Uploaded the
- new version to GEnie to replace the old one.
-
- 1.10, 02/89 Interrupt transmitter added. (Procedure IWriteCOM)
-
- 1.20, 02/89 Major improvements corrected limitations and potential flaws
- in the code. Unlimited port support was made possible by
- allowing the user to specify IRQ numbers with port numbers and
- addresses instead of using the assumed DOS standards. To use
- the additional features, the interrupt handler now processes
- all ports with the same IRQ when it is invoked. Planning for
- chained interrupts was started with this revision.
-
- 1.30, 03/89 Converted code to a unit file with a separate TTY test program.
- Repositioned DataBits parameter in SetupCOMPort so the order
- is more intuitive.
-
- 1.31, 10/89 Added the conditional compilation directive Online to optionally
- disable RTS & DTR from being shut off if the program expects a
- modem online at startup. Added the conditional compilation
- directive Debug to optionally disable debugging code.
-
- 1.40, 10/89 Added the conditional compilation directive FWriteCOM that lets
- you easily convert procedure WriteCOM to a function that returns
- a boolean TRUE if the transmission was successful. Also added
- CONST COMNmbr that shows which COM port each handler refers to
- in case non-sequential port numbers are used. Renamed IRQNum
- to IRQNmbr to match COMNmbr. I moved more declarations to the
- INTERFACE section so they are visible to the calling program.
- Added procedure EmptyBuffer. Expanded the initialization code
- so that it sets up all variables which might be needed by the
- calling program. Renamed the conditional compilation directive
- Debug to ErrorChecking. Rewrote the debugging code and error
- message handling by adding in procedure MakeError and function
- ValidPort. Added variables ErrMsgX, ErrMsgY, ErrorCode, and
- ErrorPort to make the error handling code more versatile. Added
- the conditional compilation directive ShowMessages to enable or
- disable the error messages. Removed the buffer initialization
- commands from InstallInt. Fixed IWriteCOM bugs: 1) Eliminated
- the possibility of it locking up on a full output buffer, and 2)
- added a check to see if the interrupt was already on before
- attempting to turn it on. This also improved the through-put
- efficiency for the buffers during heavy data transfer.
-
- 1.50, 11/89 Removed the conditional compile directives Online & ShowMessages.
- ShowMessages is now a global boolean variable which may be set by
- the calling code. Added the compiler directive NoMessageCode
- which is used to optionally eliminate the error message support
- and the control variables ShowMessages, ErrMsgX, and ErrMsgY.
- The global boolean DTR_RTS was added to allow the calling code to
- decide if DTR and RTS should be modified. This replaces the less
- flexible conditional compilation directive Online. Added the
- procedure Set_DTR_RTS which is called when DTR and RTS are to be
- set. Fixed a bug in InstallInt and RemoveInt so that they now
- work correctly when more than one port handler is installed on a
- single IRQ. Created the header file Comm_TC2.H for the Turbo C
- version. Renamed Carrier to CD and added CTS, DSR, and RI modem
- status arrays with the code to track their current states. Added
- the Break, Framing, Overrun, and Parity arrays along with code to
- track the number of communications errors. Streamlined various
- parts of the code by removing some unnecessary DisableInts and
- EnableInts statements. Reworked some of the I/O routines. Fixed
- IntHandler so that it safely enables higher priority interrupts
- while making sure Comm_TP4 will never interrupt itself. Added
- IRQMask and modified InstallInt and RemoveInt for this feature.
-
-
-
- THE END