Below is the code exemplifying my woes, with the best solution I could come up with. Do I simply miss the obvious solution here?!
I would appreciate any comments and hints. Thanks!
Code: Select all
MODULE M40;
IMPORT Error;
CONST
(* Buffer sizes for the two example serial devices *)
S1TxBufSize = 128;
S1RxBufSize = 32;
S2TxBufSize = 64;
S2RxBufSize = 8;
TYPE
(* Channel TYPE def *)
(* From IO.mod *)
Channel* = POINTER TO ChannelDesc;
ChannelDesc* = RECORD
PutBytes*: PROCEDURE(ch: Channel; data: ARRAY OF BYTE; n: INTEGER)
(* ... *)
END;
(* these are the essential "ideal" TYPE defs, one per serial device *)
(* simply two circular buffers plus the int prio *)
(* --- not used in code below, just to give the idea --- *)
SerialB1 = POINTER TO SerialB1Desc;
SerialB1Desc = RECORD(ChannelDesc)
irqPrio: INTEGER;
tix, tox, rix, rox: INTEGER;
txBbuf: ARRAY S1TxBufSize OF BYTE;
rxBbuf: ARRAY S1RxBufSize OF BYTE
END;
SerialB2 = POINTER TO SerialB2Desc;
SerialB2Desc = RECORD(ChannelDesc)
irqPrio: INTEGER;
tix, tox, rix, rox: INTEGER;
txBbuf: ARRAY S2TxBufSize OF BYTE;
rxBbuf: ARRAY S2RxBufSize OF BYTE
END;
(* --- *)
(* this is the actual implementation *)
(* abstract serial buffer *)
SerialBuffer = POINTER TO SerialBufferDesc;
SerialBufferDesc = RECORD END;
(* the serial device abstraction *)
SerialB* = POINTER TO SerialBDesc;
SerialBDesc* = RECORD(ChannelDesc)
irqPrio: INTEGER;
tix, tox, rix, rox: INTEGER;
buf: SerialBuffer
END;
(* the actual buffers for the two serial devices *)
Serial1Buffer = POINTER TO Serial1BufferDesc;
Serial1BufferDesc = RECORD(SerialBufferDesc)
tx: ARRAY S1TxBufSize OF BYTE;
rx: ARRAY S1RxBufSize OF BYTE
END;
Serial2Buffer = POINTER TO Serial2BufferDesc;
Serial2BufferDesc = RECORD(SerialBufferDesc)
tx: ARRAY S2TxBufSize OF BYTE;
rx: ARRAY S2RxBufSize OF BYTE
END;
PROCEDURE putB(sb: SerialB; data: ARRAY OF BYTE; n: INTEGER; VAR buf: ARRAY OF BYTE);
VAR i, next: INTEGER;
BEGIN
(* enter monitor to inhibit serial interrupts, based on sb.irqPrio *)
FOR i := 0 TO n - 1 DO
next := (sb.tix + 1) MOD LEN(buf);
ASSERT(next # sb.tox, Error.BufferOverflow);
buf[sb.tix] := data[i];
sb.tix := next
END
(* exit monitor *)
END putB;
PROCEDURE putBytes(ch: Channel; data: ARRAY OF BYTE; n: INTEGER);
VAR
buf: SerialBuffer;
BEGIN
buf := ch(SerialB).buf;
CASE buf OF
Serial1Buffer: putB(ch(SerialB), data, n, buf.tx)
| Serial2Buffer: putB(ch(SerialB), data, n, buf.tx)
END
END putBytes;
PROCEDURE Init*(sb: SerialB; serialNo: INTEGER (* ... *));
VAR s1b: Serial1Buffer; s2b: Serial2Buffer;
BEGIN
sb.PutBytes := putBytes;
(* ... *)
CASE serialNo OF
1: NEW(s1b); sb.buf := s1b
| 2: NEW(s2b); sb.buf := s2b
END;
(* ... *)
END Init;
END M40.