<> <> <> DIRECTORY DicentraRS232CAsync, IO, Process USING [CheckForAbort, MsecToTicks, Pause], PupStream USING [Tocks, SecondsToTocks, GetPupAddress, PupNameTrouble, PupByteStreamCreate, StreamClosing, CloseReason, TimeOut], PupTypes USING [PupSocketID, PupAddress], Rope USING [Find, ROPE, Substr] ; DicentraRS232CAsyncImpl: CEDAR PROGRAM IMPORTS IO, Process, 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: PupTypes.PupSocketID _ [0, 32B]; ticks: PupStream.Tocks _ PupStream.SecondsToTocks[10*60]; commPortAddress: PupTypes.PupAddress _ PupStream.GetPupAddress[socket, host ! PupStream.PupNameTrouble => { 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.PupByteStreamCreate[commPortAddress, ticks]; 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.