{Include file to master rs232; By Kari Lammassaari 1995 - code is based on - Siemens Chip documents - portar.doc by Mayer Of WC Hackers Sun 25-Apr-1993 } - tested on SVI 378 X'press Const {Following data concerns the ACIA chip 8251.} DataPort = $80; CommandPort = $81; StatusPort = $81; IntEnable = $82; { bit 0 set = RxReady produces interrupt} LineStatus = $82; { bit 0 = carrier detect ,0 = active bit 1 = ring indicator (Not used in Svo X'press bit 6 = user set timer period has passed bit 7 = Clear To Send (CTS) 0 = active } {Mode Instruction Byte Format, Asynchronous mode} SyncMode = 0; {Not used in asuchronous mode} Divider1 = 1; {Baud Rate Factor} Divider16 = 2; Divider64 = 3; DataBits7 = 8; {Character lenght 7 bits} DataBits8 = 12; ParityEnable = 16; NoParity = 0; OddParity = 16; EvenParity = 32; StopBit1 = 64; StopBit15 = 128; {Number of sop bits = 1,5} StopBit2 = 192; {Command Instruction Byte Format } TransmitEnable = 1; DataTerminalReady = 2; {When set DTR goes Low} ReceiveEnable = 4; SendBreak = 8; {When set forces TxD low} ErrorReset = 16; {Clears error flags (parity error,frame error overrun error } RequestToSend = 32; {When set, forces RTS low} InternalReset = 64; {Sets i8251 to Mode Instruction format} EnterHuntMode =128; {Used only in synchronous mode to start i8251 to search the SYNC-chars} {Status Read Format } TransmitterReady = 1; ReceiverReady = 2; TransmitterEmpty = 4; {No data to send} ParityError = 8; {Does not inhibit i8251 to go on operating} OverrunError = 16; {Data hasn't been read in time. Data is lost.} FramingError = 32; {No valid stop bit.Doesn't inhibit operation.} BreakDetected = 64; {Sync detected in synchronous mode} DataSetReady = 128; {Indicates zero level on DSR pin} {Following data concerns the TIMER chip 8253.} {8253 contains three identical and independent 16-bit timer circuits.} ModePort = $87; Timer1DataPort = $84; {Receive clock} Timer2DataPort = $85; {Transmit clock} Timer3DataPort = $86; {User clock} {The control byte format} BCD = 1; {Binary decoded Decimals , 4 decades} BitMode = 0; {16-bit counter values used.} Mode0 = 0; {When counter reaches zero, output pin is set high. In SVI Xpress output of Timer2 can be seen on bit 6 of port $82.} {Bit remains high,until new count is set or mode 0 is set.} Mode1 = 2; {Output pin status (first high) chages after the set count clock cycles. You dont have to rewrite a new counter value (N). So. after N cycles output voltage level changes.} Mode2 = 4; {Rate generator mode. Initially high output pin level goes down vhen counter has reached zero. Then counter reloads the original value and the output pin goes high again. An easy way to produce periodic interrupt.} Mode3 = 6; {Square wave mode used to baud rate generation. It's similar to Mode2. The originally high output level goes low, when the half of the counter value is reached. It stays low until counter is zero. Original counter value is reloaded and the operation repeats itself.} {USED to generate baud rate to i8251.} Mode4 = 8; {Software triggered Stobe. Originally high output pin level goes low for one clock cycle, when counter reaches zero. Counting starts after the counter values has been loaded.} Mode5 = 10; {Like Mode 2, but the countin is triggered by setting gate pin high. Counter value is reloaded.} {NOT USABLE IN SVI, gates have been grouded.} CounterLatchCommand = 0;{You can read the counter value on the fly without affecting the counting using this command. Set the counter address in the most significant bits and read the counter value. If you set two byte value in the counter, you must read two bytes. LSB is read first.} {Example binary value 01000000 would latch counter1. 10000000 would latch counter 2. ReadWriteLSBOnly = 16; {Read/write only the least significant byte of the 16 bit counter.} ReadWriteMSBOnly = 32; {Read/write only the Most significant byte .} TwoByteValue = 48; {Read/write first LSB then MSB.} {In SVI each counter has an IO-port of it's own. $84,$85,$86. The control byte of timer chip should be written in $87.} Counter0 = 0; {Select counter bits.}{Receive baud rate counter} Counter1 = 64;{Transmit baud rate counter.} Counter2 = 128; {User counter.Output signal can be seen in bit6 of port ($82} {Baud factors for timer chip} Baud19200 = 6; Baud9600 = 12; Baud4800 = 24; Baud2400 = 48; Baud1200 = 96; Baud600 = 192; Baud300 = 384; Procedure InitTimers(ReceiveBauds,TransmitBauds,UserCounterValue:Integer); Var BaudFactor :Integer; Begin {Receive timer} BaudFactor := 1152 Div (ReceiveBauds Div 100) ; Port[$87] := Counter0 + TwoByteValue + Mode3 + BitMode; Port[$84] := Lo(BaudFactor); Port[$84] := Hi(BaudFactor); Writeln(BaudFactor); {Transmit timer} BaudFactor := 1152 Div (TransmitBauds Div 100) ; Port[$87] := Counter1 + TwoByteValue + Mode3 + BitMode; Port[$85] := Lo(BaudFactor); Port[$85] := Hi(BaudFactor); Writeln(BaudFactor); BaudFactor := UserCounterValue ; Port[$87] := Counter2 + TwoByteValue + Mode3 + BitMode; Port[$86] := Lo(BaudFactor); Port[$86] := Hi(BaudFactor); Writeln(BaudFactor); End;{InitTimers} Procedure Init8251; Begin Port[$81] :=0; Port[$81] :=0; Port[$81] :=0; Port[$81] := InternalReset; Port[$81] := DataBits8 + StopBit1 + NoParity + Divider16;{Mode byte} Port[$81] := ErrorReset; Port[$81] := TransmitEnable+ReceiveEnable+DataTerminalReady; End; Procedure SetDtrOn; Begin Port[$81] := TransmitEnable + ReceiveEnable + DataTerminalReady; End; Procedure SetDtrOff; Begin Port[$81] := TransmitEnable + ReceiveEnable ; End; Const SizeOfBuffer = 1024; Type ReceiveBufferType = Array[0..SizeOfBuffer] Of Byte; Var RsBuffer :ReceiveBufferType; {Circular buffer} RsBufferPtr :Integer; {Used by interrupt} ReadBufferPtr :Integer; {Used by program} BufferStart :Integer; {addr of first byte in buffer} BufferEnd :Integer; {addr of last byte in buffer} BufferSize :Integer; OldInt :Array[0..4] Of Byte; Procedure RemoveRsInt; Var i :Byte; Begin Mem[$fd9a] := $c9; For i := 4 DownTo 0 Do Mem[$fd9a +i]:= OldInt[i]; End; Procedure SaveKeyInt; Var i:Byte; Begin For i := 0 to 4 Do OldInt[i] := Mem[$fd9a+i]; End; Procedure RsInt; {This code is NEWER called by Turbo Pascal It's used ONLY by interrupt handler.} Begin Inline ( $F3/ {di} $DB/$81/ {in a,(rs_status)} $E6/$02/ {and 2} $28/ 24/ {jrz, to KEYINT} $DB/$80/ {in a,rs_data} $2A/RsBufferPtr/ {ld hl,(RsBufferPtr)} $77/ {ld (hl),a} $23/ {inc hl} $e5/ {push hl} $ED/$5B/BufferEnd/ {Ld de,BufferEnd} $b7/ {or a, reset carry} $ed/$52/ {sbc hl,de} $e1/ {pop hl} $20/3 / {jr nz,over the reloadind } $2a/ BufferStart / {back to the start of the buffer} $22/RsBufferPtr/ {Ld (RsBufferPtr),hl} $00/$00/$00/$00/$00 {here comes original KEYINT hook} ); End;{RsInt} Procedure SetRsInt; Var SaveInt :Integer; RsIntAddr :Integer; Begin SaveKeyInt; RsIntAddr := Addr(RsInt); SaveInt := Addr(RsInt)+31; BufferSize := SizeOfBuffer; RsBufferPtr := Addr(RsBuffer); BufferStart := Addr(RsBuffer); BufferEnd := BufferStart + SizeOfBuffer; ReadBufferPtr := Addr(RsBuffer); Inline ( $F3/ {di} $ED/$5B/SaveInt/ {ld de,SaveInt} $21/$9a/$FD/ {ld hl,KEYINT} $01/$05/$00/ {ld bc,5} $ED/$B0/ {ldir} $3e/$f7/ {ld a,'Rst 30'} $32/$9a/$FD/ {ld (KEYINT),a} $3a/$41/$f3/ {ld a,(ramslot)} $32/$9b/$fd/ {ld (KEYINT+1),a} $2A/RsIntAddr/ {ld hl,RsIntAddr} $22/$9c/$FD/ {ld (KEYINT+2),hl} $FB/ {ei} $AF/ {xor a} $D3/$82 {out ($82,a ;enable keyint} ); End; {SetRsInt} Function RsByteReady:Boolean; Begin RsByteReady := ( ReadBufferPtr <> RsBufferPtr); End; Function GetRsByte:Byte; Begin GetRsByte := Mem[ReadBufferPtr]; ReadBufferPtr := ReadBufferPtr +1; If ReadBufferPtr = BufferEnd Then ReadBufferPtr := BufferStart; End; Function DirectRsChar:Char; Begin Repeat Until (Port[$81] And 2) = 2 ; DirectRsChar := Chr(Port[$80]); End; Procedure RsChSend(Ch:Char); Begin Repeat Until (Port[$81] = 133); Port[$80] := Ord(Ch); End; Procedure KeyBreak; Var Ch,key :Char; Begin Ch := ' '; If KeyPressed Then Read(Kbd,Ch); If Ch = Chr(27) Then Begin RemoveRsInt; Writeln('KEYBREAK'); Halt ; End; End; {KeyBreak} Type RsBufferType = Array[0..255]Of Byte; Procedure RsByteBlockSend(Cmd:Char;Buf:RsBufferType;Counter:Integer); Label Again; Var i :Integer; buff :Array[0..260] Of Byte; sum :Integer; Ch :Char; Begin While RsByteReady Do i := GetRsByte; {Make RsBuffer Empty} Buff[0] := Ord(Cmd); Buff[1] := Lo(Counter); Buff[2] := Hi(Counter); Sum := 0; For i := 0 to Counter-1 Do Begin Sum := Sum + Buf[i]; Buff[5+i] := Buf[i]; End; Buff[3] := Lo(Sum); Buff[4] := Hi(Sum); Again: For i := 0 to Counter+4 Do Begin Repeat Until (Port[$81] = 133); Port[$80] := Buff[i]; End; Repeat KeyBreak; Until RsByteReady; Ch := Chr(GetRsByte); If Ch = 'A' Then Begin RsChSend('o'); Goto Again; End; While Ch <> 'O' Do Begin KeyBreak; If RsByteReady Then Ch := Chr(GetRsByte); End; RsChSend('o'); End; Procedure Connect; Var ch :Char; i :Integer; Begin i:=0; Repeat i := i + 1; If i > $500 Then Begin Writeln('Cannot create connection. Program aborted.'); RemoveRsInt; Halt; End; RsChSend('C'); If RsByteReady Then Ch := Chr(GetRsByte) Else Ch := ' '; KeyBreak; Until Ch = 'O'; RsChSend('o'); Writeln('Serial connection created '); While RsByteReady Do i := GetRsByte; {Make RsBuffer Empty} End; {Connect}