RS232DriverImpl:
PROGRAM
IMPORTS Inline, DicentraInputOutput, RS232Driver
EXPORTS RS232Driver
= BEGIN
MiscBoardOffset: DicentraInputOutput.IOAddress = LOOPHOLE[LONG[09000H]];
chanB: LONG POINTER TO Words ← MiscBoardOffset; -- channel B
chanA: LONG POINTER TO Words ← MiscBoardOffset + 10H; -- channel A
Words:
TYPE =
RECORD [
r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15: WORD];
Bits8: CARDINAL = 0C1H;
Clock16x: CARDINAL = 04CH;
ClockRate:LONG CARDINAL ← 2500000; -- 2.5MHz
Clocks: CARDINAL = 050H;
DisableInt: CARDINAL = 0H;
DTR: CARDINAL = 0EAH;
Enable: CARDINAL = 003H;
Reset: CARDINAL = 0C0H;
RXFullBit: CARDINAL = 01H;
ShiftLeft: CARDINAL = 002H;
TXEmptyBit: CARDINAL = 040H;
ComputeBaudPair:
PROC[baudRate:
CARDINAL]
RETURNS[l,h:
CARDINAL] =
BEGIN
Calculate the magic numbers for the baud rate registers
Kludge:
TYPE =
MACHINE
DEPENDENT
RECORD [
SELECT
OVERLAID *
FROM
card => [c:CARDINAL],
pair => [topHalf:[0..255], bottomHalf:[0..255]],
ENDCASE];
k:Kludge;
k.c← (ClockRate / (32 * baudRate)) - 2;
l ← k.bottomHalf;
h ← k.topHalf;
END;
Open:
PUBLIC PROC[baudRate:
CARDINAL] =
BEGIN
Open RS232 connection and establish baud rate. Can do this at any time.
l,h:CARDINAL;
[l, h] ← ComputeBaudPair[baudRate];
DicentraInputOutput.Output[ShiftLeft, @chanB.r0]; -- Shift Left (ADR0 is ignored)
DicentraInputOutput.Output[Reset, @chanA.r9]; -- Hardware Reset, Dis Ints
DicentraInputOutput.Output[DisableInt, @chanA.r1]; -- Rx No Int, Tx No En
DicentraInputOutput.Output[Bits8, @chanA.r3]; -- 8bits/char, RxE
DicentraInputOutput.Output[Clock16x, @chanA.r4]; -- 16xClock, 2 Stop Bits
DicentraInputOutput.Output[DTR, @chanA.r5]; -- DTR, 8bits/char, TxE, RTS
DicentraInputOutput.Output[Clocks, @chanA.r11]; -- Clocks from BR Gen
DicentraInputOutput.Output[63, @chanA.r12]; -- Low byte of time constant
DicentraInputOutput.Output[0, @chanA.r13]; -- High byte of time constant
DicentraInputOutput.Output[Enable, @chanA.r14]; -- Enable Baud Rate Gen from PClk
END;
TX: PUBLIC PROC[b:RS232Driver.BYTE] = BEGIN DicentraInputOutput.Output[b, @chanA.r8]; END;
Send a byte of data and return without waiting for TX to finish
RX: PUBLIC PROC[] RETURNS[RS232Driver.BYTE] = BEGIN RETURN[DicentraInputOutput.Input[@chanA.r8]]; END;
Read the input data register - should check data present using RXReady
TXEmpty:
PUBLIC PROC[]
RETURNS[
BOOLEAN] =
BEGIN
RETURN[Inline.BITAND[DicentraInputOutput.Input[@chanA.r0], TXEmptyBit] # 0];
END;
Check to see if last character transmitted has departed
RXFull:
PUBLIC PROC[]
RETURNS[
BOOLEAN] =
BEGIN
RETURN[Inline.BITAND[DicentraInputOutput.Input[@chanA.r0], RXFullBit] # 0];
END;
Check to see if there is anything in the input buffer
WriteString:
PUBLIC
PROC[string:
LONG
STRING] =
BEGIN
FOR i:
NAT
IN [0..string.length)
DO
RS232Driver.Write[VAL[string[i]]];
ENDLOOP;
END;
WriteInt:
PUBLIC
PROC[int:
INT, base:
NAT ← 10, minDigits:
NAT ← 1] =
BEGIN
card: LONG CARDINAL;
IF int < 0 THEN {RS232Driver.Write[VAL['-]]; card ← -int} ELSE card ← int;
IF card = 0 THEN {FOR i: NAT IN [0..minDigits) DO RS232Driver.Write[VAL['0]] ENDLOOP; RETURN};
WriteInt[card / base, base, MAX[minDigits, 1] - 1];
{d: NAT ← card MOD base; RS232Driver.Write[d + (IF d IN [0..9] THEN VAL['0] ELSE VAL['A])]};
END;
Open[9600];
DO
WriteString[" here is a number: "]; WriteInt[999];
ENDLOOP;
END.