-- File: DicentraRS232CAsyncImpl.mesa -- Last Edited: 13-Nov-81 15:18:10 By: Fay -- Last Edited: 27-Oct-82 12:02:02 By: Loretta -- Last Edited: September 20, 1984 3:49:16 pm PDT By: Plass -- Last Edited: 15-Jun-87 10:13:25 By: Tim Diebert DIRECTORY Ascii USING [BS, ControlG, CR, LF, SP], DicentraRS232CAsync, Environment USING [Block], Process USING [GetPriority, Priority, -- priorityForeground, -- SetPriority], Stream USING [ Byte, defaultObject, DeleteProcedure, GetProcedure, Handle, Object, PutProcedure, PutByteProcedure, SendAttentionProcedure, SendNowProcedure, SetSSTProcedure, WaitAttentionProcedure], TTY, TTYConstants, TTYPort USING [ChannelHandle, ChannelQuiesced, Create, Delete, Get, Quiesce, Put, CharacterLength, LineSpeed, Parity, StopBits, SetParameter, TransferStatus], TTYPortEnvironment USING [LineSpeed]; DicentraRS232CAsyncImpl: MONITOR IMPORTS Process, Stream, TTY, TTYPort EXPORTS DicentraRS232CAsync, TTY = BEGIN -- Types Byte: TYPE = Stream.Byte; CharObjectHandle: TYPE = LONG POINTER TO CharObject; CharObject: TYPE = RECORD [p: CharObjectHandle, c: CHARACTER]; ControlG: Byte = LOOPHOLE[Ascii.ControlG]; CR: Byte = LOOPHOLE[Ascii.CR]; LF: Byte = LOOPHOLE[Ascii.LF]; BS: Byte = LOOPHOLE[Ascii.BS]; SP: Byte = LOOPHOLE[Ascii.SP]; -- this might be expanded to multiple tty's by having several of thes buggers -- and refering to them (somehow) via handle, and having object monitors. myTTY: RECORD [ so: Stream.Object Stream.defaultObject, breakDetected: BOOLEAN NULL, breakCount: INTEGER NULL, channel: TTYPort.ChannelHandle NIL, -- also on/off flag mode: Byte TTYConstants.normal, modeVal: CARDINAL 0]; receiveDeath: CONDITION; controlStop: CHARACTER = 36C; CreateTTYInstance: PUBLIC ENTRY PROC [ name: LONG STRING, backingStream: Stream.Handle, tty: TTY.Handle] RETURNS [ttyImpl, backing: Stream.Handle] = {[ttyImpl, backing] CreateRS232Instance[name, backingStream, tty]}; CreateRS232Instance: PUBLIC ENTRY PROC [ name: LONG STRING, backingStream: Stream.Handle, tty: TTY.Handle, parameters: DicentraRS232CAsync.CommParams DicentraRS232CAsync.defaultParams ] RETURNS [ttyImpl, backing: Stream.Handle] = { ENABLE UNWIND => NULL; cl: TTYPort.CharacterLength = SELECT parameters.charLength FROM lengthIs5bits => lengthIs5bits, lengthIs6bits => lengthIs6bits, lengthIs7bits => lengthIs7bits, lengthIs8bits => lengthIs8bits, ENDCASE => ERROR; ls: TTYPort.LineSpeed = SELECT parameters.speed FROM bps50 => bps50, bps75 => bps75, bps110 => bps110, bps150 => bps150, bps300 => bps300, bps600 => bps600, bps1200 => bps1200, bps2400 => bps2400, bps3600 => bps3600, bps4800 => bps4800, bps7200 => bps7200, bps9600 => bps9600, bps19200 => bps19200, ENDCASE => bps1200; parity: TTYPort.Parity = SELECT parameters.parity FROM none => none, odd => odd, even => even, ENDCASE => none; stop: TTYPort.StopBits = SELECT parameters.stop FROM one => one, two => two, oneAndHalf => oneAndHalf, none => none, ENDCASE => ERROR; IF myTTY.channel # NIL THEN RETURN WITH ERROR TTY.OutOfInstances; myTTY.channel TTYPort.Create[0]; myTTY.breakDetected FALSE; myTTY.breakCount 0; TTYPort.SetParameter[myTTY.channel, [dataSetReady[TRUE]]]; TTYPort.SetParameter[myTTY.channel, [clearToSend[TRUE]]]; TTYPort.SetParameter[myTTY.channel, [lineSpeed[ls]]]; TTYPort.SetParameter[myTTY.channel, [parity[parity]]]; TTYPort.SetParameter[myTTY.channel, [characterLength[cl]]]; TTYPort.SetParameter[myTTY.channel, [stopBits[stop]]]; myTTY.so.get GetBlock; myTTY.so.putByte PutByte; myTTY.so.put Put; myTTY.so.delete Delete; myTTY.so.waitAttention WaitAttention; myTTY.so.sendAttention SendAttention; myTTY.so.setSST SetSST; myTTY.so.sendNow SendNow; RETURN[@myTTY.so, NIL]}; Delete: ENTRY Stream.DeleteProcedure = { channel: TTYPort.ChannelHandle = myTTY.channel; IF channel=NIL THEN RETURN; TTYPort.Quiesce[channel]; TTYPort.Delete[channel]; WHILE myTTY.channel#NIL DO WAIT receiveDeath [] ENDLOOP; myTTY.channel NIL}; PutByte: ENTRY Stream.PutByteProcedure = { SELECT myTTY.mode FROM TTYConstants.normal => PutByteInternal[byte]; TTYConstants.removeChars => myTTY.modeVal myTTY.modeVal*256 + byte; ENDCASE}; Put: Stream.PutProcedure = { IF endRecord THEN RETURN; FOR i: CARDINAL IN [block.startIndex..block.stopIndexPlusOne) DO sH.putByte[sH, block.blockPointer[i]] ENDLOOP; }; lastChar: Byte 0; PutByteInternal: INTERNAL PROC [c: Byte] = { PutIt: PROCEDURE [c: Stream.Byte] = INLINE { [] TTYPort.Put[myTTY.channel, LOOPHOLE[c] ! TTYPort.ChannelQuiesced => CONTINUE]}; IF myTTY.channel = NIL THEN RETURN; PutIt[c]; }; WaitAttention: Stream.WaitAttentionProcedure = { RETURN[IF myTTY.breakDetected THEN TTYConstants.aborted ELSE TTYConstants.notAborted]}; SendAttention: Stream.SendAttentionProcedure = { SELECT byte FROM TTYConstants.aborted => { myTTY.breakCount myTTY.breakCount + 1; IF myTTY.breakCount > 0 THEN myTTY.breakDetected TRUE}; TTYConstants.notAborted => { IF myTTY.breakCount > 0 THEN myTTY.breakCount myTTY.breakCount - 1; IF myTTY.breakCount = 0 THEN myTTY.breakDetected FALSE}; ENDCASE}; SetSST: ENTRY Stream.SetSSTProcedure = { SELECT myTTY.mode FROM TTYConstants.removeChars => FOR i: CARDINAL IN [0..myTTY.modeVal) DO PutByteInternal[BS]; ENDLOOP; TTYConstants.blinkDisplay => PutByteInternal[ControlG]; ENDCASE; myTTY.mode sst; myTTY.modeVal 0}; SendNow: Stream.SendNowProcedure = {}; GetBlock: Stream.GetProcedure = { csmPriority: Process.Priority = 4; -- Process.priorityForeground; NotifyNextOfKin: ENTRY PROC = INLINE {myTTY.channel NIL; NOTIFY receiveDeath}; oldPriority: Process.Priority = Process.GetPriority[]; ProcessChar: ENTRY PROC RETURNS [done: BOOLEAN FALSE] = INLINE { IF stat = breakDetected OR ch = controlStop THEN { myTTY.breakDetected TRUE; myTTY.breakCount myTTY.breakCount + 1; TTYPort.SetParameter[myTTY.channel, [breakDetectedClear[TRUE]] ! TTYPort.ChannelQuiesced => CONTINUE]} ELSE { block.blockPointer[block.startIndex] LOOPHOLE[ch]; bytesTransferred 1; why normal; sst TTYConstants.normal; RETURN[TRUE]}}; ch: CHARACTER; stat: TTYPort.TransferStatus; Process.SetPriority[csmPriority]; bytesTransferred 0; DO [ch, stat] TTYPort.Get[myTTY.channel ! TTYPort.ChannelQuiesced => EXIT]; IF stat=aborted OR stat=abortedByDelete THEN EXIT; IF ProcessChar[] THEN RETURN; ENDLOOP; Process.SetPriority[oldPriority]; NotifyNextOfKin[]}; KillIt: PUBLIC PROC [] = BEGIN TTYPort.Quiesce[myTTY.channel ! TTYPort.ChannelQuiesced => CONTINUE]; END; -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- MAINLINE CODE -- -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ END.... LOG July 28, 1980 9:25 AM Mary Artibee Created. August 15, 1980 1:18 PM Mary Artibee Many changes. Time: August 27, 1980 7:01 PM Mary Artibee Private errors on Create, BackingStream. Time: September 12, 1980 11:41 PM Yokota Added UserAbort and ResetUserAbort. Time: September 19, 1980 3:24 PM Yokota Line Speed is set to 9600bps. Time: October 2, 1980 1:32 PM Artibee Change tty init; remove Process. October 3, 1980 5:32 PM Yokota Added tty.breakDetected, tty.breakCount and controlStop. UserAbort, ResetUserAbort and Receive are modified to use them. October 7, 1980 4:38 PM Yokota Priority of Receive process is raised and Break detection is done using only tty.breakDetected. February 23, 1981 1:24 PM Gobbel Fixed bug in input stream processing; replaced calls to Storage with Heap ops. 26-Aug-81 18:54:16 Forrest Rolled into 8.0c 13-Nov-81 15:18:04 Fay Converted to new TTY interface for 8.0e. September 20, 1984 3:49:39 pm PDT Plass Made smarter about CR vs. CRLF, added NOP SendNow operation. "J77