DIRECTORY Ascii USING [BS, ControlG, CR, LF, SP], Basics USING [RawBytes], IO USING [CreateStream, CreateStreamProcs, STREAM, StreamProcs, UnsafeBlock], Process USING [GetPriority, Priority, priorityForeground, SetPriority], Rope USING [ROPE], TTY, TTYConstants, TTYPort USING [ChannelHandle, ChannelQuiesced, CharsAvailable, Create, Delete, Get, Quiesce, Put, SetParameter, TransferStatus], TTYStream, TTYEnvironment USING [LineSpeed]; TTYLearSiegler: CEDAR MONITOR IMPORTS IO, Process, TTY, TTYPort EXPORTS TTY, TTYStream = BEGIN STREAM: TYPE ~ IO.STREAM; ControlG: CHAR = LOOPHOLE[Ascii.ControlG]; CR: CHAR = LOOPHOLE[Ascii.CR]; LF: CHAR = LOOPHOLE[Ascii.LF]; BS: CHAR = LOOPHOLE[Ascii.BS]; SP: CHAR = LOOPHOLE[Ascii.SP]; myTTY: RECORD [ so: IO.STREAM _ NIL, 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; CreateStream: PUBLIC PROC [] RETURNS [stream: IO.STREAM] = BEGIN RETURN[CreateTTYInstance[NIL, NIL, NIL].ttyImpl]; END; CreateTTYInstance: PUBLIC ENTRY PROC [name: Rope.ROPE, backingStream: IO.STREAM, tty: TTY.Handle] RETURNS [ttyImpl, backing: IO.STREAM] = { ENABLE UNWIND => NULL; streamProcs: REF IO.StreamProcs _ IO.CreateStreamProcs[class: $TTY, variety: inputOutput, unsafeGetBlock: GetBlock, charsAvail: CharsAvail, putChar: PutChar, close: Close]; 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[bps9600]]]; myTTY.so _ IO.CreateStream[streamProcs, NIL, backingStream]; RETURN[myTTY.so, NIL]}; Close: ENTRY PROC [self: IO.STREAM, abort: BOOL _ FALSE] ~ TRUSTED { channel: TTYPort.ChannelHandle ~ myTTY.channel; IF channel=NIL THEN RETURN; TTYPort.Quiesce[channel]; WHILE myTTY.channel#NIL DO WAIT receiveDeath [] ENDLOOP; TTYPort.Delete[myTTY.channel]; myTTY.channel _ NIL; }; CharsAvail: PUBLIC PROC [self: IO.STREAM, wait: BOOL] RETURNS [INT] ~ TRUSTED { RETURN [TTYPort.CharsAvailable[myTTY.channel]]; }; PutChar: ENTRY PROC [self: STREAM, char: CHAR] = { SELECT myTTY.mode FROM TTYConstants.normal => PutByteInternal[char]; TTYConstants.removeChars => myTTY.modeVal _ myTTY.modeVal*256 + LOOPHOLE[char, CARDINAL]; ENDCASE}; PutByteInternal: INTERNAL PROC [c: CHAR] = { PutIt: PROCEDURE [c: CHAR] = INLINE { [] _ TTYPort.Put[myTTY.channel, c ! TTYPort.ChannelQuiesced => CONTINUE]}; IF myTTY.channel = NIL THEN RETURN; PutIt[c]; SELECT c FROM CR => PutIt[LF]; BS => {PutIt[SP]; PutIt[BS]}; ENDCASE}; WaitAttention: PUBLIC PROC[self: IO.STREAM] RETURNS [BYTE] = { RETURN[ IF myTTY.breakDetected THEN TTYConstants.aborted ELSE TTYConstants.notAborted]}; SendAttention: PUBLIC PROC[self: IO.STREAM, byte: BYTE] = { 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: PUBLIC ENTRY PROC [self: IO.STREAM, sst: TTYStream.SubSequenceType] = { 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}; GetBlock: UNSAFE PROC [self: STREAM, block: IO.UnsafeBlock] RETURNS [nBytesRead: INT] = { csmPriority: Process.Priority = Process.priorityForeground; NotifyNextOfKin: ENTRY PROC = INLINE {myTTY.channel _ NIL; NOTIFY receiveDeath}; oldPriority: Process.Priority = Process.GetPriority[]; ProcessChar: ENTRY PROC RETURNS [done: BOOLEAN _ FALSE] = TRUSTED 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 { base: LONG POINTER TO Basics.RawBytes; UNTIL block.startIndex < LAST[CARDINAL] DO block.startIndex _ block.startIndex - LAST[CARDINAL]; base _ base + LAST[CARDINAL]; ENDLOOP; base _ LOOPHOLE[block.base]; base[block.startIndex] _ LOOPHOLE[ch]; RETURN[TRUE]}}; ch: CHARACTER; stat: TTYPort.TransferStatus; Process.SetPriority[csmPriority]; DO [ch, stat] _ TTYPort.Get[myTTY.channel ! TTYPort.ChannelQuiesced => EXIT]; IF stat=aborted OR stat=abortedByDelete THEN EXIT; IF ProcessChar[] THEN RETURN[1]; ENDLOOP; Process.SetPriority[oldPriority]; NotifyNextOfKin[]; RETURN[0]; }; END.... LOG July 28, 1980 9:25 AM Mary MXA Created. August 15, 1980 1:18 PM Mary MXA Many changes. Time: August 27, 1980 7:01 PM Mary MXA Private errors on Create, BackingStream. Time: September 12, 1980 11:41 PM SXY Added UserAbort and ResetUserAbort. Time: September 19, 1980 3:24 PM SXY Line Speed is set to 9600bps. Time: October 2, 1980 1:32 PM MXA Change tty init; remove Process. October 3, 1980 5:32 PM SXY Added tty.breakDetected, tty.breakCount and controlStop. UserAbort, ResetUserAbort and Receive are modified to use them. October 7, 1980 4:38 PM SXY Priority of Receive process is raised and Break detection is done using only tty.breakDetected. February 23, 1981 1:24 PM RXG Fixed bug in input stream processing; replaced calls to Storage with Heap ops. 26-Aug-81 18:54:16 FXH Rolled into 8.0c 13-Nov-81 15:18:04 CRF Converted to new TTY interface for 8.0e. TTYLearSiegler.mesa Copyright Σ 1981, 1982, 1984, 1986, 1987 by Xerox Corporation. All rights reserved. Last Edited: 13-Nov-81 15:18:10 By: CRF Last Edited: 27-Oct-82 12:02:02 By: LXR Tim Diebert: March 5, 1987 1:52:06 pm PST Types 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. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ MAINLINE CODE -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Κ$˜codešœ™KšœU™UKšœ,™,Kšœ/™/K™)—K˜šΟk ˜ Kš œœœ œœœ˜'Kšœœ ˜Kšœœ#œ˜MKšœœ:˜GKšœœœ˜Kšœ˜K˜ Kšœœs˜€Kšœ ˜ Kšœœ ˜!—K˜šΟnœœ˜Kšœœ œ ˜!Kšœœ˜K˜Kšœ™K˜Kšœœœœ˜K˜Kšœ œœ˜*Kšœœœœ˜Kšœœœœ˜Kšœœœœ˜Kšœœœœ˜K˜K˜Kšœ‘™‘šœœ˜Kšœœœœ˜Kšœœœ˜Kšœ œœ˜Kšœ!œΟc˜:Kšœœ˜!Kšœ œ˜—K˜Kšœ œ˜Kšœ œ˜K˜š ž œœœœ œœ˜@Kšœœœœ ˜1Kšœ˜K˜—šžœœœœ œœœœ œœœ˜ŒKšœœœ˜Kšœ œœœˆ˜¬Kšœœœœœœœ˜AK˜"Kšœœ˜2Kšœ2œ˜:Kšœ1œ˜9K˜:Kšœ œœ˜šœ˜Kšœœœ˜P——K˜š ž œœœœœœ˜;šœ˜˜K˜(Kšœœœ˜9—˜Kšœœ)˜EKšœœœ˜:—Kšœ˜ ——K˜š žœœœœœœ&˜Pšœ ˜˜šœœœ˜(Kšœœœ˜—K˜7Kšœ˜——K˜K˜K˜—šžœœœœ œœœ˜YK˜;Kš žœœœœœœ˜PK˜6šž œœœœœœœœ˜Jšœœ˜+šœ˜Kšœœ*˜Dšœ8œ˜>Kšœœ˜'——šœ˜Kšœœœœ˜&šœœœ˜*Kšœ&œœ˜5Kšœœœ˜Kšœ˜—Kšœœ ˜Kšœœ˜&Kšœœ˜———Kšœ œ˜,K˜!š˜KšœDœ˜JKšœœœœ˜2Kšœœœ˜ Kšœ˜—K˜!K˜Kšœ˜ Kšœ˜K˜—K˜Kšœ9™9Kšœ™Kšœ9™9K˜Kšœ˜K˜—Kš˜Kšœœœ ˜-Kšœœœ˜3Kšžœœœ-˜TKšžœœœ'˜MKšžœœœ!˜FKšžœœœ%˜Gšœœœ/˜LK˜L—šœœœ-˜JK˜5—šœœœ)˜HK˜(—Kšœœ˜+Kšœœœ˜?K˜—…—R Š