-- RS232ServerImpl.mesa -- Copyright (C) 1984, 1985 Xerox Corporation. All rights reserved. -- Tim Diebert: 8-Nov-85 10:15:58 DIRECTORY DicentraRS232CAsync, Process, PupDefs USING [PupAddressLookup, PupNameTrouble], PupStream USING [CloseReason, CreatePupByteStreamListener, PupAddress, PupListener, RejectThisRequest, SecondsToTocks, StreamClosing], Stream, String USING [Copy], TTY; RS232ServerImpl: MONITOR IMPORTS DicentraRS232CAsync, Process, PupDefs, PupStream, Stream, String = BEGIN rs232Stream: Stream.Handle ← NIL; busy: ARRAY DicentraRS232CAsync.PortNumber OF BOOL ← ALL [FALSE]; listener: PupStream.PupListener ← NIL; active: BOOL ← FALSE; kill, killKeyWatcher: BOOL ← FALSE; currentUser: LONG STRING ← [255]; wakeUp, bufferFlushed: CONDITION; -- set their timeouts buffer: ARRAY [0 .. 255) OF CHAR; bufferPtr: CARDINAL ← 0; KeyWatcher: PROC = { PutIt: ENTRY PROC [c: CHAR] = { WHILE bufferPtr > 255 DO NOTIFY wakeUp; EXIT; -- WAIT bufferFlushed; -- IF killKeyWatcher THEN RETURN; ENDLOOP; IF bufferPtr <= 255 THEN { buffer[bufferPtr] ← c; bufferPtr ← bufferPtr + 1}; }; DO c: CHAR ← rs232Stream.GetChar[]; -- IF killKeyWatcher THEN -- {killKeyWatcher ← FALSE; Stream.Delete[rs232Stream]; active ← FALSE; RETURN}; PutIt[c]; -- IF killKeyWatcher THEN -- {killKeyWatcher ← FALSE; Stream.Delete[rs232Stream]; active ← FALSE; RETURN}; ENDLOOP; }; keySenderRunning: BOOL ← FALSE; KeySender: ENTRY PROC [s: Stream.Handle] = { ENABLE PupStream.StreamClosing => {GOTO Out}; keySenderRunning ← TRUE; DO WAIT wakeUp; IF kill THEN { kill ← FALSE; -- killKeyWatcher ← TRUE; GOTO Out}; IF bufferPtr = 0 THEN LOOP; FOR i: CARDINAL IN [0 .. bufferPtr) DO s.PutChar[buffer[i]] ENDLOOP; Stream.SendNow[s]; bufferPtr ← 0; NOTIFY bufferFlushed; ENDLOOP; EXITS Out => {-- killKeyWatcher ← TRUE; kill ← FALSE; NOTIFY bufferFlushed; keySenderRunning ← FALSE; RETURN}; -- and kill process }; NetWatcher: PROC [s: Stream.Handle] = { ENABLE PupStream.StreamClosing => {kill ← TRUE; Note[]; GOTO Out}; DO c: CHAR ← s.GetChar[]; rs232Stream.PutChar[c]; ENDLOOP; EXITS Out => {Stream.Delete[s]; RETURN}; }; Note: ENTRY PROC [] = {NOTIFY wakeUp}; InitCommand: PROC [stream: Stream.Handle, pupAddress: PupStream.PupAddress] = BEGIN ENABLE { PupStream.StreamClosing => GOTO Exit; Stream.TimeOut => GOTO Exit}; -- name: STRING = "DicentraRS232.log"L; -- ttyImpl, backing: Stream.Handle; port: DicentraRS232CAsync.PortNumber ← LOOPHOLE[Stream.GetChar[stream]]; charLength: DicentraRS232CAsync.CharLength ← LOOPHOLE[Stream.GetChar[stream]]; speed: DicentraRS232CAsync.LineSpeed ← LOOPHOLE[Stream.GetChar[stream]]; parity: DicentraRS232CAsync.Parity ← LOOPHOLE[Stream.GetChar[stream]]; stop: DicentraRS232CAsync.StopBits ← LOOPHOLE[Stream.GetChar[stream]]; currentUser.length ← 0; PupDefs.PupAddressLookup[currentUser, pupAddress ! PupDefs.PupNameTrouble => {String.Copy[to: currentUser, from: e]; CONTINUE}]; bufferPtr ← 0; active ← TRUE; -- [ttyImpl, backing] ← DicentraRS232CAsync.CreateRS232Instance[name, NIL, -- TTY.nullHandle, [charLength, speed, parity, stop]]; -- rs232Stream ← ttyImpl; Stream.PutChar[stream, 'k]; Stream.SendNow[stream]; bufferPtr ← 0; -- Process.Detach[FORK KeyWatcher[]]; Process.Detach[FORK KeySender[stream]]; -- Process.Detach[FORK NetWatcher[stream]]; BEGIN ENABLE PupStream.StreamClosing, Stream.TimeOut => {IF keySenderRunning THEN kill ← TRUE; Note[]; GOTO Out}; DO c: CHAR ← stream.GetChar[]; rs232Stream.PutChar[c]; ENDLOOP; EXITS Out => {Stream.Delete[stream]; GOTO Exit}; END; EXITS Exit => {active ← FALSE; RETURN}; END; CheckBusy: PROC [pupAddress: PupStream.PupAddress] = BEGIN IF active THEN ERROR PupStream.RejectThisRequest[currentUser]; END; Init: PROC [] = BEGIN ttyImpl, backing: Stream.Handle; name: STRING = "DicentraRS232.log"L; bufferPtr ← 0; [ttyImpl, backing] ← DicentraRS232CAsync.CreateRS232Instance[name, NIL, TTY.nullHandle, -- [charLength, speed, parity, stop] --]; rs232Stream ← ttyImpl; IF listener = NIL THEN listener ← PupStream.CreatePupByteStreamListener[ local: [0, 32B], proc: InitCommand, ticks: PupStream.SecondsToTocks[30*60], filter: CheckBusy]; Process.SetTimeout[@wakeUp, Process.MsecToTicks[250]]; Process.SetTimeout[@bufferFlushed, Process.MsecToTicks[1000]]; Process.Detach[FORK KeyWatcher[]]; END; Init[]; END.