serial string driver
As writing a serial driver seems to be a problem, the following code is a sample
string driver.
{
StrDrv - uart driver 16550
----------------------------------------------------
It is optimized for a 16550 UART in the PC, but
should work also with a 8250 UART. - not yet tested
Just below IMPLEMENTATION there is <$DEFINE U16550>,
which enables codegeneration for the 16550, which is
strongly recommended.
There is a VAR Is16550 locally to this unit, that is
set at PROC UARTInit, it reflects the UART detected.
The detection is off when conditionally disabled.
----------------------------------------------------
It is set for COM1, IRQ4, 8bit, 1stop, no parity
----------------------------------------------------
Furthermore it supports RTS/CTS handshake ,
that the other side may stop the PC from sending.
It then activates the CTS-line(-12V).
Upon a trailing edge (-12V to +12V), the Driver resumes
transmitting. The levels are assumed after the drivers,
that means on the cable.
----------------------------------------------------
Benchmarks : on a 386/16MHz
At 9600 full speed tx and rx : ( shorted )
real mode :5% CPU time
protected mode :8% CPU time
----------------------------------------------------
The interface is PROC PutBuffer,GetBuffer, which
assumes a STRING.
The string is as follows:
[0]:stringlength
Note:
MMUDRV.InitDrv; < only once >
rep
MMUDRV.PutBuffer(@p);
Wait(RxSema);
MMUDRV.GetBuffer(q); < either >
end rep
q: reply conforms the above structure
----------------------------------------------------
----------------------------------------------------
New from mmudrv2.pas :
Tx is timed, this reduces interrupts, as the tx is
always on. further the txsema is not required anymore.
Now putbuffer includes a timed wait until the new message
fits into the buffer. This allows the senders to fill
the buffer, where the tx has maximum performance, as
the txirq then moves 16 bytes at a time.
The txbuffer has 256 bytes
----------------------------------------------------
Created :27/sept/93
Last Update :6/feb/96
Is updated version of :mmudriv.pas,mmudrv2.pas,mmudrv.pas
----------------------------------------------------
TestFile is :DRVTEST.PAS
----------------------------------------------------
}
UNIT StrDrv;
INTERFACE
USES RTKernel,OPString;
TYPE StrPtr=^STRING;
PROCEDURE InitDrv(baud:LONGINT;Fifosize:BYTE);
PROCEDURE PutBuffer(p:StrPtr); { p is @String }
PROCEDURE GetBuffer(VAR p:STRING); { p is a string }
FUNCTION IsLineOpen:BOOLEAN;
{ the rest is for debug }
PROCEDURE WriteTx;
PROCEDURE WriteRx;
PROCEDURE WriteCStr(p:StrPtr); { write string passed to/from driver }
PROCEDURE WriteUARTState;
VAR
RxSema1 :RTKernel.Semaphore;
IMPLEMENTATION
{===========================================================}
{ The following defines are disabled by a dot : .$DEFINE }
{$DEFINE U16550 } { enables 16550 UART }
{-------------------------------------------------------}
CONST
{ UARTAdress for COM1 }
RBR1=$3F8;THR1=$3F8;IER1=$3F9;IIR1=$3FA;FCR1=$3FA;LCR1=$3FB;
MCR1=$3FC;LSR1=$3FD;MSR1=$3FE;DLL1=$3F8;DLM1=$3F9;
{ UARTAdress for COM2 }
RBR2=$2F8;THR2=$2F8;IER2=$2F9;IIR2=$2FA;FCR2=$2FA;LCR2=$2FB;
MCR2=$2FC;LSR2=$2FD;MSR2=$2FE;DLL2=$2F8;DLM2=$2F9;
CONST
RxBufferSize=256; { must be, as byte wraps }
TxBufferSize=256; { must be, as byte wraps }
{ TxDepth=16; } { nr of bytes being filled at TxIRQ <=16 }
VAR
ExitSave :POINTER;
RxBuffer1 :ARRAY[0..RxBufferSize-1]OF BYTE;
ErrorBuffer1:ARRAY[0..RxBufferSize-1]OF BYTE;
RxWrite1,RxRead1,RxFree1 :BYTE;
TxBuffer1 :ARRAY[0..TxBufferSize-1]OF BYTE;
TxWrite1,TxRead1,TxFree1 :BYTE;
TxOnIRQ1,TxStop1,RxStop1 :BOOLEAN; { set during message }
Is16550 :BOOLEAN;
TxDepth:BYTE; { nr of bytes being filled at TxIRQ <=16 }
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
PROCEDURE EnableInterrupts; INLINE($FB);
PROCEDURE DisableInterrupts; INLINE($FA);
{$F+}
{ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ}
{$F+,S-,R-} { far, not stack chk, no range chk }
PROCEDURE UARTHandler1;INTERRUPT;
VAR td,iirc,msrc :BYTE;
BEGIN
iirc:=Port[IIR1] AND $0F; { get interrupt source }
Port[MCR1]:=Port[MCR1] AND $07; { switch interrupts of UART off }
msrc:=Port[MSR1]; { get modem status reg }
CASE IIRC OF
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
$06: { line IRQ }
BEGIN
td:=port[LSR1]AND $71; { accept only OV,PA,FR,FI }
ErrorBuffer1[RxWrite1]:=td;
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{ Note :for a 16550 UART, the FIFO is emptied.
}
$04,$0C: { rx data avail IRQ }
BEGIN
{$IFDEF U16550}
WHILE ((port[LSR1] AND $01)<>0) DO { read 16550 FIFO }
BEGIN
{$ENDIF}
td:=port[RBR1];
RxBuffer1[RxWrite1]:=td;
Inc(RxWrite1);
Dec(RxFree1);
IF (RxFree1<16) THEN RxStop1:=TRUE ELSE RxStop1:=FALSE;
{$IFDEF U16550}
END; { while data }
{$ENDIF}
IF RxStop1 THEN
port[MCR1]:=port[MCR1] and $FC; { DTR/RTS low }
{ ELSE
port[MCR1]:=port[MCR1] or $03;} { DTR/RTS high }
END;
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{ as long as the txbuffer is not empty, another byte is put to the
transmitter. The 16550 UART is fed with up to 16 bytes.
should the CTS signal stop, nothing is done
}
$02: { tx empty IRQ }
BEGIN
IF (TxRead1=TxWrite1) THEN TxOnIRQ1:=FALSE { last byte sent }
ELSE { TxRead<>TxWrite }
BEGIN
TxOnIRQ1:=TRUE;
IF (((msrc AND $10)=0)) THEN TxStop1:=TRUE; { cts signals stop }
IF (not TxStop1) THEN
BEGIN
{$IFDEF U16550}
td:=0;
REPEAT
{$ENDIF}
inc(td);
Port[THR1]:=TxBuffer1[TxRead1];
Inc(TxRead1); Inc(TxFree1);
{$IFDEF U16550}
UNTIL (Not Is16550)OR(TxRead1=TxWrite1)OR(td=TxDepth);
{$ENDIF}
END;
END; { txonirq and not stop }
END; { txempty }
{ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ}
{ The CTS stops transmitting (TxStop:=TRUE). When the CTS disappears
the transmitter resumes action
}
$00: { modem status IRQ }
BEGIN
IF (((msrc and $11)=$01)) THEN { cts signals stop }
BEGIN
TxStop1:=TRUE;
END
ELSE
BEGIN
IF (((msrc AND $11)=$11)) THEN { cts signals ready again }
BEGIN
TxStop1:=FALSE;
IF (TxRead1<>TxWrite1) THEN
BEGIN
TxOnIRQ1:=TRUE;
IF ((Port[LSR1] and $20)<>0) THEN { THR1e empty }
BEGIN
{$IFDEF U16550}
td:=0;
REPEAT
{$ENDIF}
inc(td);
Port[THR1]:=TxBuffer1[TxRead1];
Inc(TxRead1); Inc(TxFree1); { includes wrap }
{$IFDEF U16550}
UNTIL (Not Is16550)OR(TxRead1=TxWrite1)OR(td=TxDepth);
{$ENDIF}
END;
END; { txread<>txwrite }
END; { cts signal }
END;
END; { modem line }
{ÄÄÄÄÄÄÄÄÄÄÄÄ