home *** CD-ROM | disk | FTP | other *** search
- Path: sparky!uunet!cs.utexas.edu!usc!howland.reston.ans.net!bogus.sura.net!darwin.sura.net!newsserver.jvnc.net!yale.edu!ira.uka.de!smurf.sub.org!pfm!rebell!root
- From: root@rebell.rmt.sub.org (Gottfried Hamm)
- Newsgroups: alt.sources
- Subject: v24.pas - Turbo Pascal Unit for the serial V.24 interface (MS-DOS)
- Message-ID: <root00241930025231405@rebell.rmt.sub.org>
- Date: Mon, 25 Jan 93 23:14:05 MESZ
- Distribution: world
- Organization: rebell * +49 6249 8842 * D-6524 Guntersblum
- Lines: 1136
- X-Newsreader: NWREADER [version 3.01]
-
- The following ist the source to build a Turbo Pascal Unit (tpu) to
- communicate with the serial interface of a PC. I use it in all my programs,
- using this interface.
-
- I hope it will be helpful to you.
-
- Gottfried
-
- -----cut here-----cut here-----cut here-----cut here-----cut here-----
- unit v24;
-
- INTERFACE
-
- uses dos, crt;
-
- (*----------------------------------------------------------------------*)
- (* V24.PAS --- Asynchronous I/O for Turbo Pascal *)
- (*----------------------------------------------------------------------*)
- (* *)
- (* Author: Philip R. Burns *)
- (* Date: January, 1985 *)
- (* Version: 1.0 *)
- (* Systems: For MS-DOS on IBM PCs and close compatibles only. *)
- (* Note: I have checked these on Zenith 151s under *)
- (* MSDOS 2.1 and IBM PCs under PCDOS 2.0. *)
- (* *)
- (* History: Some of these routines are based upon ones written by: *)
- (* *)
- (* Alan Bishop *)
- (* C. J. Dunford *)
- (* Michael Quinlan *)
- (* *)
- (* I have cleaned up these other authors' code, fixed some *)
- (* bugs, and added many new features. *)
- (* *)
- (* Suggestions for improvements or corrections are welcome. *)
- (* Please leave messages on Gene Plantz's BBS (312) 882 4145 *)
- (* or Ron Fox's BBS (312) 940 6496. *)
- (* *)
- (* If you use this code in your own programs, please be nice *)
- (* and give all of us credit. *)
- (* *)
- (* Realization as Turbo-Pascal-Unit by Gottfried Hamm, June 1990 *)
- (* *)
- (*----------------------------------------------------------------------*)
- (* *)
- (* Routines: *)
- (* *)
- (* Async_Init --- Performs initialization. *)
- (* Async_Open --- Sets up COM port *)
- (* Async_Close --- Closes down COM port *)
- (* Async_Carrier_Detect --- Checks for modem carrier detect *)
- (* Async_Carrier_Drop --- Checks for modem carrier drop *)
- (* Async_Buffer_Check --- Checks if character in COM buffer *)
- (* Async_Term_Ready --- Toggles terminal ready status *)
- (* Async_Receive --- Reads character from COM buffer *)
- (* Async_Receive_With_Timeout *)
- (* --- Receives char. with timeout check *)
- (* Async_Send --- Transmits char over COM port *)
- (* Async_Send_String --- Sends string over COM port *)
- (* Async_Send_String_With_Delays *)
- (* --- Sends string with timed delays *)
- (* Async_Send_Break --- Sends break (attention) signal *)
- (* Async_Percentage_Used --- Returns percentage com buffer used *)
- (* Async_Purge_Buffer --- Purges receive buffer *)
- (* *)
- (*----------------------------------------------------------------------*)
- (* *)
- (*----------------------------------------------------------------------*)
-
- (*----------------------------------------------------------------------*)
- (* *)
- (* COMMUNICATIONS HARDWARE ADDRESSES *)
- (* *)
- (* These are specific to IBM PCs and close compatibles. *)
- (* *)
- (*----------------------------------------------------------------------*)
-
- Const
-
- UART_THR = $00; (* offset from base of UART Registers for IBM PC *)
- UART_RBR = $00;
- UART_IER = $01;
- UART_IIR = $02;
- UART_LCR = $03;
- UART_MCR = $04;
- UART_LSR = $05;
- UART_MSR = $06;
-
- I8088_IMR = $21; (* port address of the Interrupt Mask Register *)
-
- COM1_Base = $03F8; (* port addresses for the UART *)
- COM2_Base = $02F8;
-
- COM1_Irq = 4; (* Interrupt line for the UART *)
- COM2_Irq = 3;
-
- Async_DSeg_Save : Integer = 0; (* Save DS reg in Code Segment for *)
- (* interrupt routine *)
-
- (*----------------------------------------------------------------------*)
- (* *)
- (* COMMUNICATIONS BUFFER VARIABLES *)
- (* *)
- (* The Communications Buffer is implemented as a circular (ring) *)
- (* buffer, or double-ended queue. The asynchronous I/O routines *)
- (* enter characters in the buffer as they are received. Higher- *)
- (* level routines may extract characters from the buffer. *)
- (* *)
- (* Note that this buffer is used for input only; output is done *)
- (* on a character-by-character basis. *)
- (* *)
- (*----------------------------------------------------------------------*)
-
- Async_Buffer_Max = 8191; (* Size of Communications Buffer *)
- (* Async_Loops_Per_Sec = 6500; Loops per second -- 4.77 clock *)
- (* Als Variable definiert - siehe unten! *)
- TimeOut = 256; (* TimeOut value *)
-
- Type anystr = string[80];
-
- Var
- (* Communications Buffer Itself *)
-
- Async_Buffer : Array[0..Async_Buffer_Max] of Char;
-
- Async_Loops_Per_Sec : Integer; (* Loops per second - siehe oben *)
- Async_Open_Flag : Boolean; (* true if Open but no Close *)
- Async_Port : Integer; (* current Open port number (1 or 2) *)
- Async_Base : Integer; (* base for current open port *)
- Async_Irq : Integer; (* irq for current open port *)
-
- Async_Buffer_Overflow : Boolean; (* True if buffer overflow has happened *)
- Async_Buffer_Used : Integer;
- Async_MaxBufferUsed : Integer;
-
- (* Async_Buffer empty if Head = Tail *)
- Async_Buffer_Head : Integer; (* Loc in Async_Buffer to put next char *)
- Async_Buffer_Tail : Integer; (* Loc in Async_Buffer to get next char *)
- Async_Buffer_NewTail : Integer;
-
- (*----------------------------------------------------------------------*)
- (* BIOS_RS232_Init --- Initialize UART *)
- (* *)
- Procedure BIOS_RS232_Init( ComPort, ComParm : Integer );
- (* *)
- (* Procedure: BIOS_RS232_Init *)
- (* *)
- (* Purpose: Issues interrupt $14 to initialize the UART *)
- (* *)
- (* Calling Sequence: *)
- (* *)
- (* BIOS_RS232_Init( ComPort, ComParm : Integer ); *)
- (* *)
- (* ComPort --- Communications Port Number (1 or 2) *)
- (* ComParm --- Communications Parameter Word *)
- (* *)
- (* Calls: INTR (to perform BIOS interrupt $14) *)
- (*----------------------------------------------------------------------*)
-
- (*----------------------------------------------------------------------*)
- (* DOS_Set_Intrpt --- Call DOS to set interrupt vector *)
- (* *)
- Procedure DOS_Set_Intrpt( v, s, o : Integer );
- (* *)
- (* Procedure: DOS_Set_Intrpt *)
- (* *)
- (* Purpose: Calls DOS to set interrupt vector *)
- (* *)
- (* Calling Sequence: *)
- (* *)
- (* DOS_Set_Intrpt( v, s, o : Integer ); *)
- (* *)
- (* v --- interrupt vector number to set *)
- (* s --- segment address of interrupt routine *)
- (* o --- offset address of interrupt routine *)
- (* *)
- (* Calls: MSDOS (to set interrupt) *)
- (*----------------------------------------------------------------------*)
-
- (*----------------------------------------------------------------------*)
- (* Async_Isr --- Interrupt Service Routine *)
- (* *)
- Procedure Async_Isr;
- (* *)
- (* Procedure: Async_Isr *)
- (* *)
- (* Purpose: Invoked when UART has received character from *)
- (* communications line (asynchronous) *)
- (* *)
- (* Calling Sequence: *)
- (* *)
- (* Async_Isr; *)
- (* *)
- (* --- Called asyncronously only!!!!!! *)
- (* *)
- (* Remarks: *)
- (* *)
- (* This is Michael Quinlan's version of the interrupt handler. *)
- (*----------------------------------------------------------------------*)
-
- (*----------------------------------------------------------------------*)
- (* Async_Init --- Initialize Asynchronous Variables *)
- (* *)
- Procedure Async_Init;
- (* *)
- (* Procedure: Async_Init *)
- (* *)
- (* Purpose: Initializes variables *)
- (* *)
- (* Calling Sequence: *)
- (* *)
- (* Async_Init; *)
- (* *)
- (* Calls: None *)
- (*----------------------------------------------------------------------*)
-
- (*----------------------------------------------------------------------*)
- (* Async_Close --- Close down communications interrupts *)
- (* *)
- Procedure Async_Close;
- (* *)
- (* Procedure: Async_Close *)
- (* *)
- (* Purpose: Resets interrupt system when UART interrupts *)
- (* are no longer needed. *)
- (* *)
- (* Calling Sequence: *)
- (* *)
- (* Async_Close; *)
- (* *)
- (* Calls: None *)
- (*----------------------------------------------------------------------*)
-
- (*----------------------------------------------------------------------*)
- (* Async_Open --- Open communications port *)
- (* *)
- Function Async_Open( ComPort : Integer;
- BaudRate : Integer;
- Parity : Char;
- WordSize : Integer;
- StopBits : Integer ) : Boolean;
- (* *)
- (* Function: Async_Open *)
- (* *)
- (* Purpose: Opens communications port *)
- (* *)
- (* Calling Sequence: *)
- (* *)
- (* Flag := Async_Open( ComPort : Integer; *)
- (* BaudRate : Integer; *)
- (* Parity : Char; *)
- (* WordSize : Integer; *)
- (* StopBits : Integer) : Boolean; *)
- (* *)
- (* ComPort --- which port (1 or 2) *)
- (* BaudRate --- Baud rate (110 to 9600) *)
- (* 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) *)
- (* *)
- (* Flag returned TRUE if port initialized successfully; *)
- (* Flag returned FALSE if any errors. *)
- (* *)
- (* Calls: *)
- (* *)
- (* BIOS_RS232_Init --- initialize RS232 port *)
- (* DOS_Set_Intrpt --- set address of RS232 interrupt routine *)
- (*----------------------------------------------------------------------*)
-
- (*----------------------------------------------------------------------*)
- (* Async_Carrier_Detect --- Check for modem carrier detect *)
- (* *)
- Function Async_Carrier_Detect : Boolean;
- (* *)
- (* Function: Async_Carrier_Detect *)
- (* *)
- (* Purpose: Looks for modem carrier detect *)
- (* *)
- (* Calling Sequence: *)
- (* *)
- (* Flag := Async_Carrier_Detect : Boolean; *)
- (* *)
- (* Flag is set TRUE if carrier detected, else FALSE. *)
- (* *)
- (* Calls: None *)
- (*----------------------------------------------------------------------*)
-
- (*----------------------------------------------------------------------*)
- (* Async_Carrier_Drop --- Check for modem carrier drop/timeout *)
- (* *)
- Function Async_Carrier_Drop : Boolean;
- (* *)
- (* Function: Async_Carrier_Drop *)
- (* *)
- (* Purpose: Looks for modem carrier drop/timeout *)
- (* *)
- (* Calling Sequence: *)
- (* *)
- (* Flag := Async_Carrier_Drop : Boolean; *)
- (* *)
- (* Flag is set TRUE if carrier dropped, else FALSE. *)
- (* *)
- (* Calls: None *)
- (*----------------------------------------------------------------------*)
-
- (*----------------------------------------------------------------------*)
- (* Async_Term_Ready --- Set terminal ready status *)
- (* *)
- Procedure Async_Term_Ready( Ready_Status : Boolean );
- (* *)
- (* Procedure: Async_Term_Ready *)
- (* *)
- (* Purpose: Sets terminal ready status *)
- (* *)
- (* Calling Sequence: *)
- (* *)
- (* Async_Term_Ready( Ready_Status : Boolean ); *)
- (* *)
- (* Ready_Status --- Set TRUE to set terminal ready on, *)
- (* Set FALSE to set terminal ready off. *)
- (* *)
- (* Calls: None *)
- (*----------------------------------------------------------------------*)
-
- (*----------------------------------------------------------------------*)
- (* Async_Buffer_Check --- Check if character in buffer *)
- (* *)
- Function Async_Buffer_Check : Boolean;
- (* *)
- (* Function: Async_Buffer_Check *)
- (* *)
- (* Purpose: Check if character in buffer *)
- (* *)
- (* Calling Sequence: *)
- (* *)
- (* Flag := Async_Buffer_Check : Boolean; *)
- (* *)
- (* 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. *)
- (*----------------------------------------------------------------------*)
-
- (*----------------------------------------------------------------------*)
- (* Async_Receive --- Return character from buffer *)
- (* *)
- Function Async_Receive( Var C : Char ) : Boolean;
- (* *)
- (* Function: Async_Receive *)
- (* *)
- (* Purpose: Retrieve character (if any) from buffer *)
- (* *)
- (* Calling Sequence: *)
- (* *)
- (* Flag := Async_Receive( Var C: Char ) : Boolean; *)
- (* *)
- (* C --- character (if any) retrieved from buffer; *)
- (* set to CHR(0) if no character available. *)
- (* *)
- (* Flag returned TRUE if character retrieved from buffer, *)
- (* Flag returned FALSE if no character retrieved. *)
- (* *)
- (* Calls: None *)
- (*----------------------------------------------------------------------*)
-
- (*----------------------------------------------------------------------*)
- (* Async_Receive_With_TimeOut --- Return char. from buffer with delay *)
- (* *)
- Procedure Async_Receive_With_Timeout( Secs : Integer; Var C : Integer );
- (* *)
- (* Procedure: Async_Receive_With_Delay *)
- (* *)
- (* Purpose: Retrieve character as integer from buffer, *)
- (* or return TimeOut if specified delay period *)
- (* expires. *)
- (* *)
- (* Calling Sequence: *)
- (* *)
- (* Async_Receive_With_Timeout( Secs: Integer; Var C: Integer ); *)
- (* *)
- (* Secs --- Timeout period in seconds *)
- (* C --- ORD(character) (if any) retrieved from buffer; *)
- (* set to TimeOut if no character found before *)
- (* delay period expires. *)
- (* *)
- (* Calls: Async_Receive *)
- (* *)
- (* WATCH OUT! THIS ROUTINE RETURNS AN INTEGER, NOT A CHARACTER!!! *)
- (* *)
- (* Note: This routine uses a CPU loop to do timing. The value of *)
- (* the constant used is suitable for 4.77 MHz CPUs. If your *)
- (* CPU is faster or slower, you will need to adjust the *)
- (* value of ASYNC_LOOPS_PER_SEC. *)
- (*----------------------------------------------------------------------*)
-
- (*----------------------------------------------------------------------*)
- (* Async_Send --- Send character over communications port *)
- (* *)
- Procedure Async_Send( C : Char );
- (* *)
- (* Procedure: Async_Send *)
- (* *)
- (* Purpose: Sends character out over communications port *)
- (* *)
- (* Calling Sequence: *)
- (* *)
- (* Async_Send( C : Char ); *)
- (* *)
- (* C --- Character to send *)
- (* *)
- (* Calls: None *)
- (*----------------------------------------------------------------------*)
-
- (*----------------------------------------------------------------------*)
- (* Async_Send_Break --- Send break (attention) signal *)
- (* *)
- Procedure Async_Send_Break;
- (* *)
- (* Procedure: Async_Send_Break *)
- (* *)
- (* Purpose: Sends break signal over communications port *)
- (* *)
- (* Calling Sequence: *)
- (* *)
- (* Async_Send_Break; *)
- (* *)
- (* Calls: None *)
- (*----------------------------------------------------------------------*)
-
- (*----------------------------------------------------------------------*)
- (* Async_Send_String --- Send string over communications port *)
- (* *)
- Procedure Async_Send_String( S : AnyStr );
- (* *)
- (* Procedure: Async_Send_String *)
- (* *)
- (* Purpose: Sends string out over communications port *)
- (* *)
- (* Calling Sequence: *)
- (* *)
- (* Async_Send_String( S : AnyStr ); *)
- (* *)
- (* S --- String to send *)
- (* *)
- (* Calls: Async_Send *)
- (*----------------------------------------------------------------------*)
-
- (*----------------------------------------------------------------------*)
- (* Async_Send_String_With_Delays --- Send string with timed delays *)
- (* *)
- Procedure Async_Send_String_With_Delays( S : AnyStr;
- Char_Delay : Integer;
- EOS_Delay : Integer );
- (* *)
- (* Procedure: Async_Send_String_With_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( S : AnyStr ; *)
- (* Char_Delay : Integer; *)
- (* EOS_Delay : Integer ); *)
- (* *)
- (* S --- String to send *)
- (* Char_Delay --- Number of milliseconds to delay after *)
- (* sending each character *)
- (* EOS_Delay --- Number of milleseconds to delay after *)
- (* sending last character in string *)
- (* *)
- (* Calls: Async_Send *)
- (* Async_Send_String *)
- (* Length *)
- (* 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. *)
- (*----------------------------------------------------------------------*)
-
- (*----------------------------------------------------------------------*)
- (* Async_Percentage_Used --- Report Percentage Buffer Filled *)
- (* *)
- Function Async_Percentage_Used : Real;
- (* *)
- (* Function: Async_Percent_Used *)
- (* *)
- (* Purpose: Reports percentage of com buffer currently filled *)
- (* *)
- (* Calling Sequence: *)
- (* *)
- (* Percentage := Async_Percentage_Used : Real; *)
- (* *)
- (* Percentage gets how much of buffer is filled; *)
- (* value goes from 0.0 (empty) to 1.0 (totally full). *)
- (* *)
- (* Calls: None *)
- (* *)
- (* Remarks: *)
- (* *)
- (* This routine is helpful when incorporating handshaking 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. *)
- (*----------------------------------------------------------------------*)
-
- (*----------------------------------------------------------------------*)
- (* Async_Purge_Buffer --- Purge communications input buffer *)
- (* *)
- Procedure Async_Purge_Buffer;
- (* *)
- (* Procedure: Async_Purge_Buffer *)
- (* *)
- (* Purpose: Purges communications input buffer *)
- (* *)
- (* Calling Sequence: *)
- (* *)
- (* Async_Purge_Buffer; *)
- (* *)
- (* Calls: Async_Receive *)
- (*----------------------------------------------------------------------*)
-
-
- IMPLEMENTATION
-
- (*----------------------------------------------------------------------*)
-
- Procedure BIOS_RS232_Init;
-
- Var
- Regs: Registers;
-
- Begin (* BIOS_RS232_Init *)
-
- With Regs Do
- Begin
- Ax := ComParm AND $00FF; (* AH=0; AL=ComParm *)
- Dx := ComPort; (* Port number to use *)
- INTR($14, Regs);
- End;
-
- End (* BIOS_RS232_Init *);
-
- (*----------------------------------------------------------------------*)
-
- Procedure DOS_Set_Intrpt;
-
- Var
- Regs : Registers;
-
- Begin (* DOS_Set_Intrpt *)
-
- With Regs Do
- Begin
- Ax := $2500 + ( v AND $00FF );
- Ds := s;
- Dx := o;
- MsDos( Regs );
- End;
-
- End (* DOS_Set_Intrpt *);
-
- (*----------------------------------------------------------------------*)
-
- Procedure Async_Isr;
-
- Begin (* Async_Isr *)
-
- (* NOTE: on entry, Turbo Pascal has already PUSHed BP and SP *)
-
- Inline(
- (* save all registers used *)
- $50/ (* PUSH AX *)
- $53/ (* PUSH BX *)
- $52/ (* PUSH DX *)
- $1E/ (* PUSH DS *)
- $FB/ (* STI *)
- (* set up the DS register to point to Turbo Pascal's data segment *)
- $2E/$FF/$36/Async_Dseg_Save/ (* PUSH CS:Async_Dseg_Save *)
- $1F/ (* POP DS *)
- (* get the incomming character *)
- (* Async_Buffer[Async_Buffer_Head] := Chr(Port[UART_RBR + Async_Base]); *)
- $8B/$16/Async_Base/ (* MOV DX,Async_Base *)
- $EC/ (* IN AL,DX *)
- $8B/$1E/Async_Buffer_Head/ (* MOV BX,Async_Buffer_Head *)
- $88/$87/Async_Buffer/ (* MOV Async_Buffer[BX],AL *)
- (* Async_Buffer_NewHead := Async_Buffer_Head + 1; *)
- $43/ (* INC BX *)
- (* if Async_Buffer_NewHead > Async_Buffer_Max then
- Async_Buffer_NewHead := 0; *)
- $81/$FB/Async_Buffer_Max/ (* CMP BX,Async_Buffer_Max *)
- $7E/$02/ (* JLE L001 *)
- $33/$DB/ (* XOR BX,BX *)
- (* if Async_Buffer_NewHead = Async_Buffer_Tail then
- Async_Buffer_Overflow := TRUE
- else *)
- (*L001:*)
- $3B/$1E/Async_Buffer_Tail/ (* CMP BX,Async_Buffer_Tail *)
- $75/$08/ (* JNE L002 *)
- $C6/$06/Async_Buffer_Overflow/$01/ (* MOV Async_Buffer_Overflow,1 *)
- $90/ (* NOP generated by assembler for some reason *)
- $EB/$16/ (* JMP SHORT L003 *)
- (* begin
- Async_Buffer_Head := Async_Buffer_NewHead;
- Async_Buffer_Used := Async_Buffer_Used + 1;
- if Async_Buffer_Used > Async_MaxBufferUsed then
- Async_MaxBufferUsed := Async_Buffer_Used
- end; *)
- (*L002:*)
- $89/$1E/Async_Buffer_Head/ (* MOV Async_Buffer_Head,BX *)
- $FF/$06/Async_Buffer_Used/ (* INC Async_Buffer_Used *)
- $8B/$1E/Async_Buffer_Used/ (* MOV BX,Async_Buffer_Used *)
- $3B/$1E/Async_MaxBufferUsed/ (* CMP BX,Async_MaxBufferUsed *)
- $7E/$04/ (* JLE L003 *)
- $89/$1E/Async_MaxBufferUsed/ (* MOV Async_MaxBufferUsed,BX *)
- (*L003:*)
- (* disable interrupts *)
- $FA/ (* CLI *)
- (* Port[$20] := $20; *) (* use non-specific EOI *)
- $B0/$20/ (* MOV AL,20h *)
- $E6/$20/ (* OUT 20h,AL *)
- (* restore the registers then use IRET to return *)
- (* the last two POPs are required because Turbo Pascal PUSHes these regs
- before we get control. The manual doesn't say so, but that is what
- really happens *)
- $1F/ (* POP DS *)
- $5A/ (* POP DX *)
- $5B/ (* POP BX *)
- $58/ (* POP AX *)
- $5C/ (* POP SP *)
- $5D/ (* POP BP *)
- $CF) (* IRET *)
-
- End (* Async_Isr *);
-
- (*----------------------------------------------------------------------*)
-
- Procedure Async_Init;
-
- Begin (* Async_Init *)
-
- Async_DSeg_Save := DSeg;
- Async_Open_Flag := FALSE;
- Async_Buffer_Overflow := FALSE;
- Async_Buffer_Used := 0;
- Async_MaxBufferUsed := 0;
-
- End (* Async_Init *);
-
- (*----------------------------------------------------------------------*)
-
- Procedure Async_Close;
-
- Var
- i : Integer;
- m : Integer;
-
- Begin (* Async_Close *)
-
- If Async_Open_Flag Then
- Begin
-
- (* disable the IRQ on the 8259 *)
-
- Inline($FA); (* disable interrupts *)
-
- i := Port[I8088_IMR]; (* get the interrupt mask register *)
- m := 1 shl Async_Irq; (* set mask to turn off interrupt *)
- Port[I8088_IMR] := i or m;
-
- (* disable the 8250 data ready interrupt *)
-
- Port[UART_IER + Async_Base] := 0;
-
- (* disable OUT2 on the 8250 *)
-
- Port[UART_MCR + Async_Base] := 0;
-
- Inline($FB); (* enable interrupts *)
-
- (* re-initialize our data areas so we know *)
- (* the port is closed *)
-
- Async_Open_Flag := FALSE;
-
- End;
-
- End (* Async_Close *);
-
- (*----------------------------------------------------------------------*)
-
- Function Async_Open;
-
- Const (* Baud Rate Constants *)
-
- Async_Num_Bauds = 8;
-
- Async_Baud_Table : Array [1..Async_Num_Bauds] Of Record
- Baud, Bits : Integer;
- End
-
- = ( ( Baud: 110; Bits: $00 ),
- ( Baud: 150; Bits: $20 ),
- ( Baud: 300; Bits: $40 ),
- ( Baud: 600; Bits: $60 ),
- ( Baud: 1200; Bits: $80 ),
- ( Baud: 2400; Bits: $A0 ),
- ( Baud: 4800; Bits: $C0 ),
- ( Baud: 9600; Bits: $E0 ) );
-
- Var
- ComParm : Integer;
- i : Integer;
- m : Integer;
-
- Begin (* Async_Open *)
-
- (* If port open, close it down first. *)
-
- If Async_Open_Flag Then Async_Close;
-
- (* Choose communications port *)
- If ComPort = 2 Then
- Begin
- Async_Port := 2;
- Async_Base := COM2_Base;
- Async_Irq := COM2_Irq;
- End
- Else
- Begin
- Async_Port := 1; (* default to COM1 *)
- Async_Base := COM1_Base;
- Async_Irq := COM1_Irq;
- End;
-
- If (Port[UART_IIR + Async_Base] and $00F8) <> 0 Then
- Async_Open := FALSE (* Serial port not installed *)
- Else
- Begin (* Open the port *)
-
- (* Set buffer pointers *)
-
- Async_Buffer_Head := 0;
- Async_Buffer_Tail := 0;
- Async_Buffer_Overflow := FALSE;
-
- (*---------------------------------------------------*)
- (* Build the ComParm for RS232_Init *)
- (* See Technical Reference Manual for description *)
- (*---------------------------------------------------*)
-
- (* Set up the bits for the baud rate *)
-
- If BaudRate > 9600 Then
- BaudRate := 9600
- Else If BaudRate <= 0 Then
- BaudRate := 300;
-
- i := 0;
-
- Repeat
- i := i + 1
- Until ( ( i >= Async_Num_Bauds ) OR
- ( BaudRate = Async_Baud_Table[i].Baud ) );
-
- ComParm := Async_Baud_Table[i].Bits;
-
- (* Choose Parity *)
-
- If Parity In ['E', 'e'] Then
- ComParm := ComParm or $0018
- Else If Parity In ['O', 'o'] Then
- ComParm := ComParm or $0008;
-
- (* Choose number of data bits *)
-
- WordSize := WordSize - 5;
-
- If ( WordSize < 0 ) OR ( WordSize > 3 ) Then
- WordSize := 3;
-
- ComParm := ComParm OR WordSize;
-
- (* Choose stop bits *)
-
- If StopBits = 2 Then
- ComParm := ComParm OR $0004; (* default is 1 stop bit *)
-
- (* use the BIOS COM port initialization routine *)
-
- BIOS_RS232_Init( Async_Port - 1 , ComParm );
-
- DOS_Set_Intrpt( Async_Irq + 8 , CSeg , Ofs( Async_Isr ) );
-
- (* Read the RBR and reset any pending error conditions. *)
- (* First turn off the Divisor Access Latch Bit to allow *)
- (* access to RBR, etc. *)
-
- Inline($FA); (* disable interrupts *)
-
- Port[UART_LCR + Async_Base] := Port[UART_LCR + Async_Base] and $7F;
-
- (* Read the Line Status Register to reset any errors *)
- (* it indicates *)
-
- i := Port[UART_LSR + Async_Base];
-
- (* Read the Receiver Buffer Register in case it *)
- (* contains a character *)
-
- i := Port[UART_RBR + Async_Base];
-
- (* enable the irq on the 8259 controller *)
-
- i := Port[I8088_IMR]; (* get the interrupt mask register *)
- m := (1 shl Async_Irq) xor $00FF;
-
- Port[I8088_IMR] := i and m;
-
- (* enable the data ready interrupt on the 8250 *)
-
- Port[UART_IER + Async_Base] := $01;
-
- (* enable OUT2 on 8250 *)
-
- i := Port[UART_MCR + Async_Base];
- Port[UART_MCR + Async_Base] := i or $08;
-
-
- Inline($FB); (* enable interrupts *)
-
- Async_Open := TRUE
-
- End;
-
- End (* Async_Open *);
-
- (*----------------------------------------------------------------------*)
-
- Function Async_Carrier_Detect;
-
- Begin (* Async_Carrier_Detect *)
-
- Async_Carrier_Detect := ODD( Port[ UART_MSR + Async_Base ] SHR 7 );
-
- End (* Async_Carrier_Detect *);
-
- (*----------------------------------------------------------------------*)
-
- Function Async_Carrier_Drop;
-
- Begin (* Async_Carrier_Drop *)
-
- Async_Carrier_Drop := NOT ODD( Port[ UART_MSR + Async_Base ] SHR 7 );
-
- End (* Async_Carrier_Drop *);
-
- (*----------------------------------------------------------------------*)
-
- Procedure Async_Term_Ready;
-
- Var
- Mcr_Value: Byte;
-
- Begin (* Async_Term_Ready *)
-
- Mcr_Value := Port[ UART_MCR + Async_Base ];
-
- If ODD( Mcr_Value ) Then Mcr_Value := Mcr_Value - 1;
-
- If Ready_Status Then Mcr_Value := Mcr_Value + 1;
-
- Port[ UART_MCR + Async_Base ] := Mcr_Value;
-
- End (* Async_Term_Ready *);
-
- (*----------------------------------------------------------------------*)
-
- Function Async_Buffer_Check;
-
- Begin (* Async_Buffer_Check *)
-
- Async_Buffer_Check := ( Async_Buffer_Head <> Async_Buffer_Tail );
-
- End (* Async_Buffer_Check *);
-
- (*----------------------------------------------------------------------*)
-
- Function Async_Receive;
-
- Begin (* Async_Receive *)
-
- If Async_Buffer_Head = Async_Buffer_Tail Then
- Begin (* No character to retrieve *)
-
- Async_Receive := FALSE;
- C := CHR( 0 );
-
- End (* No character available *)
-
- Else
- Begin (* Character available *)
-
- (* Turn off interrupts *)
-
- INLINE( $FA ); (* CLI --- Turn off interrupts *)
-
- (* Get character from buffer *)
-
- C := Async_Buffer[ Async_Buffer_Tail ];
-
- (* Increment buffer pointer. If past *)
- (* end of buffer, reset to beginning. *)
-
- Async_Buffer_Tail := Async_Buffer_Tail + 1;
-
- If Async_Buffer_Tail > Async_Buffer_Max Then
- Async_Buffer_Tail := 0;
-
- (* Decrement buffer use count *)
-
- Async_Buffer_Used := Async_Buffer_Used - 1;
-
- (* Turn on interrupts *)
-
- INLINE( $FB ); (* STI --- Turn on interrupts *)
-
- (* Indicate character successfully retrieved *)
-
- Async_Receive := TRUE;
-
- End (* Character available *);
-
- End (* Async_Receive *);
-
- (*----------------------------------------------------------------------*)
-
- Procedure Async_Receive_With_Timeout;
-
- Var
- Isecs : Integer;
- Jsecs : Integer;
- I : Integer;
- J : Integer;
- Char_Waiting : Boolean;
- Ch : Char;
-
- Begin (* Async_Receive_With_Timeout *)
-
- I := Maxint DIV Async_Loops_Per_Sec;
- Isecs := ( Secs + I - 1 ) DIV I;
- Jsecs := ( Secs - Isecs * ( I - 1 ) ) * Async_Loops_Per_Sec;
- Isecs := Isecs + 1;
-
- Repeat
- J := Jsecs;
- Repeat
- J := J - 1;
- Char_Waiting := ( Async_Buffer_Head <> Async_Buffer_Tail );
- Until( ( J = 0 ) OR ( Char_Waiting ) );
- Isecs := Isecs - 1;
- Until( ( Isecs = 0 ) OR ( Char_Waiting ) );
-
- If ( NOT Char_Waiting) Then
- C := TimeOut
- Else
- Begin
- Char_Waiting := Async_Receive( Ch );
- C := ORD( Ch );
- End;
-
- End (* Async_Receive_With_Timeout *);
-
- (*----------------------------------------------------------------------*)
-
- Procedure Async_Send;
-
- Var
- i : Integer;
- m : Integer;
- Counter : Integer;
-
- Begin (* Async_Send *)
-
- (* Turn on OUT2, DTR, and RTS *)
-
- Port[UART_MCR + Async_Base] := $0B;
-
- (* Wait for CTS using Busy Wait *)
-
- Counter := MaxInt;
-
- While ( Counter <> 0 ) AND
- ( ( Port[UART_MSR + Async_Base] AND $10 ) = 0 ) Do
- Counter := Counter - 1;
-
- (* Wait for Transmit Hold Register Empty (THRE) *)
-
- If Counter <> 0 Then Counter := MaxInt;
-
- While ( Counter <> 0 ) AND
- ( ( Port[UART_LSR + Async_Base] AND $20 ) = 0 ) Do
- Counter := Counter - 1;
-
- (* Send the character if port clear *)
-
- If Counter <> 0 Then
- Begin (* Send the Character *)
-
- Inline($FA); (* CLI --- disable interrupts *)
-
- Port[UART_THR + Async_Base] := Ord(C);
-
- Inline($FB); (* STI --- enable interrupts *)
-
- End (* Send the Character *)
-
- Else (* Timed Out *)
- Writeln('<<<TIMEOUT>>>');
-
- End (* Async_Send *);
-
- (*----------------------------------------------------------------------*)
-
- Procedure Async_Send_Break;
-
- Var
- Old_Lcr : Byte;
- Break_Lcr : Byte;
-
- Begin (* Async_Send_Break *)
-
- Old_Lcr := Port[ UART_LCR + Async_Base ];
- Break_Lcr := Old_Lcr;
-
- If Break_Lcr > 127 Then Break_Lcr := Break_Lcr - 128;
- If Break_Lcr <= 63 Then Break_Lcr := Break_Lcr + 64;
-
- Port[ UART_LCR + Async_Base ] := Break_Lcr;
-
- Delay( 400 );
-
- Port[ UART_LCR + Async_Base ] := Old_Lcr;
-
- End (* Async_Send_Break *);
-
- (*----------------------------------------------------------------------*)
-
- Procedure Async_Send_String;
-
- Var
- i : Integer;
-
- Begin (* Async_Send_String *)
-
- For i := 1 To LENGTH( S ) Do
- Async_Send( S[i] )
-
- End (* Async_Send_String *);
-
- (*----------------------------------------------------------------------*)
-
- Procedure Async_Send_String_With_Delays;
-
- Var
- I : Integer;
-
- Begin (* Async_Send_String_With_Delays *)
-
- If Char_Delay <= 0 Then
- Async_Send_String( S )
- Else
- For I := 1 To LENGTH( S ) Do
- Begin
- Async_Send( S[I] );
- Delay( Char_Delay );
- End;
-
- If EOS_Delay > 0 Then Delay( EOS_Delay );
-
- End (* Async_Send_String_With_Delays *);
-
- (*----------------------------------------------------------------------*)
-
- Function Async_Percentage_Used;
-
- Begin (* Async_Percentage_Used *)
-
- Async_Percentage_Used := Async_Buffer_Used / ( Async_Buffer_Max + 1 );
-
- End (* Async_Percentage_Used *);
-
- (*----------------------------------------------------------------------*)
-
- Procedure Async_Purge_Buffer;
-
- Var
- C: Char;
-
- Begin (* Async_Purge_Buffer *)
-
- Repeat
- Delay( 35 );
- Until ( NOT Async_Receive( C ) );
-
- End (* Async_Purge_Buffer *);
-
- (*----------------------------------------------------------------------*)
-
- End (* V24.PAS *).
- -----cut here-----cut here-----cut here-----cut here-----cut here-----
-
-
- | Gottfried Hamm | Email: root@rebell.rmt.sub.org | I'm |
- | Wormser Str. 36 | Phone: +49 6249 8997 | awaiting |
- | D-6524 Guntersblum | Fax : +49 6249 8842 | your mail... |
-