<> <> <> 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] ; DicentraRS232CAsyncImpl: CEDAR PROGRAM IMPORTS IO, Process, PupName, PupStream, Rope EXPORTS DicentraRS232CAsync ~ 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; END.