DIRECTORY
DicentraRS232CAsync,
IO,
Process USING [CheckForAbort, MsecToTicks, Pause],
Pup USING [Address, Socket],
PupName USING [Error, NameLookup],
PupStream USING [Create, StreamClosing, CloseReason, Timeout, waitForever],
Rope USING [Find, ROPE, Substr]
;
~
BEGIN
OPEN DicentraRS232CAsync;
STREAM: TYPE ~ IO.STREAM;
ROPE: TYPE ~ Rope.ROPE;
StreamState: TYPE ~ REF StreamStateRep;
StreamStateRep:
TYPE ~
RECORD [
pupStream: STREAM ← NIL
];
CommBusy: PUBLIC ERROR [currentUser: Rope.ROPE] = CODE;
CommError: PUBLIC ERROR [ec: Rope.ROPE] = CODE;
CreateStream:
PUBLIC
PROC
[host: Rope.
ROPE, port: PortNumber ← 0, commParams: CommParams ← defaultParams]
RETURNS [stream:
IO.
STREAM] =
BEGIN
ENABLE PupStream.StreamClosing => MakePupStreamError [host, why, text];
ok: CHAR;
socket: Pup.Socket ← [0, 0, 0, 32B];
commPortAddress: Pup.Address ← PupName.NameLookup[host, socket
! PupName.Error => {
codeRope:
ROPE ←
IO.PutFR[(
SELECT code
FROM
noRoute => "No route to %g from here",
noResponse => "No response from name lookup server for %g",
ENDCASE => "Name %g not found"), IO.rope[host]];
ERROR CommError[ec: codeRope];}];
s: StreamState = NEW [StreamStateRep];
streamProcs:
REF
IO.StreamProcs ←
IO.CreateStreamProcs[class: $DicentraRS232CAsyncStream,
variety: inputOutput, getChar: GetChar, endOf: EndOf, putChar: PutChar, flush: Flush, close: Close, charsAvail: CharsAvail];
s.pupStream← PupStream.Create[commPortAddress, PupStream.waitForever, PupStream.waitForever];
stream ← IO.CreateStream[streamProcs, s];
IO.PutChar[s.pupStream, LOOPHOLE[port, CHAR]];
IO.PutChar[s.pupStream, LOOPHOLE[commParams.charLength, CHAR]];
IO.PutChar[s.pupStream, LOOPHOLE[commParams.speed, CHAR]];
IO.PutChar[s.pupStream, LOOPHOLE[commParams.parity, CHAR]];
IO.PutChar[s.pupStream, LOOPHOLE[commParams.stop, CHAR]];
IO.Flush[s.pupStream];
ok← IO.GetChar[s.pupStream ! IO.EndOfStream => RETRY];
IF ok = 'k
THEN
RETURN [stream]
ELSE ERROR CommError [IO.PutFR1["Bad return from %g", IO.rope[host]]];
END;
PutChar:
PROC[self:
IO.
STREAM, char:
CHAR] =
BEGIN
ENABLE {PupStream.StreamClosing => ERROR IO.Error [ec: Failure, stream: self]; PupStream.Timeout => RETRY; IO.Error => ERROR IO.Error [ec: Failure, stream: self]; IO.EndOfStream => ERROR IO.EndOfStream[self]};
s: StreamState = NARROW [self.streamData];
IO.PutChar[s.pupStream, char];
END;
GetChar:
PROC[self:
IO.
STREAM]
RETURNS [char:
CHAR] =
BEGIN
ENABLE {PupStream.StreamClosing => ERROR IO.Error [ec: Failure, stream: self]; PupStream.Timeout => RETRY; IO.Error => ERROR IO.Error [ec: Failure, stream: self]; IO.EndOfStream => ERROR IO.EndOfStream[self]};
s: StreamState = NARROW [self.streamData];
DO
i: INT ← IO.CharsAvail[s.pupStream];
IF i # 0 THEN RETURN [IO.GetChar[s.pupStream]];
Process.Pause[Process.MsecToTicks[100]]; Process.CheckForAbort[];
ENDLOOP;
END;
Close:
PROC[self:
IO.
STREAM, abort:
BOOL ←
FALSE] =
BEGIN
ENABLE {PupStream.StreamClosing => ERROR IO.Error [ec: Failure, stream: self]; PupStream.Timeout => RETRY; IO.Error => ERROR IO.Error [ec: Failure, stream: self]; IO.EndOfStream => ERROR IO.EndOfStream[self]};
s: StreamState = NARROW [self.streamData];
IO.Close[s.pupStream];
END;
EndOf:
PUBLIC
PROC[self:
IO.
STREAM]
RETURNS [
BOOL] =
BEGIN
ENABLE {PupStream.StreamClosing => ERROR IO.Error [ec: Failure, stream: self]; PupStream.Timeout => RETRY; IO.Error => ERROR IO.Error [ec: Failure, stream: self]; IO.EndOfStream => ERROR IO.EndOfStream[self]};
s: StreamState = NARROW [self.streamData];
RETURN [IO.EndOf[s.pupStream]];
END;
Flush:
PUBLIC
PROC [ self:
IO.
STREAM ] =
BEGIN
ENABLE {PupStream.StreamClosing => ERROR IO.Error [ec: Failure, stream: self]; PupStream.Timeout => RETRY; IO.Error => ERROR IO.Error [ec: Failure, stream: self]; IO.EndOfStream => ERROR IO.EndOfStream[self]};
s: StreamState = NARROW [self.streamData];
IO.Flush[s.pupStream];
END;
CharsAvail:
PUBLIC
PROC [self:
STREAM, wait:
BOOL]
RETURNS [
INT] =
BEGIN
ENABLE {PupStream.StreamClosing => ERROR IO.Error [ec: Failure, stream: self]; PupStream.Timeout => RETRY; IO.Error => ERROR IO.Error [ec: Failure, stream: self]; IO.EndOfStream => ERROR IO.EndOfStream[self]};
s: StreamState = NARROW [self.streamData];
RETURN [IO.CharsAvail[s.pupStream, wait]];
END;
MakePupStreamError:
PROC
[ host: ROPE, why: PupStream.CloseReason, text: ROPE] = BEGIN
pos: INT ← Rope.Find[text, "+"];
codeRope:
ROPE ←
IO.PutFR["Error from %g; %s ",
IO.rope[host],
IO.rope[
SELECT why
FROM
localClose => "Local Close",
localAbort => "Local Abort",
remoteClose => "Remote Close",
noRouteToNetwork => "No route",
transmissionTimeout => "Timeout",
ENDCASE => text]];
IF pos > 0 THEN text ← Rope.Substr[text, 0, pos];
IF why = remoteReject
THEN
ERROR CommBusy[currentUser: text]
ELSE ERROR CommError[ec: codeRope];
END;