-- RS232ServerImpl.mesa -- Copyright (C) 1984, 1985, 1987 Xerox Corporation. All rights reserved. -- Tim Diebert: 24-Jun-87 14:13:56 DIRECTORY DicentraInputOutput, DicentraRS232CAsync, MultibusAddresses, Process, PupDefs USING [PupAddressLookup, PupNameTrouble], PupStream USING [CloseReason, CreatePupByteStreamListener, PupAddress, PupListener, RejectThisRequest, SecondsToTocks, StreamClosing], Stream, String USING [Copy], TTY; RS232ServerImpl: MONITOR IMPORTS DicentraInputOutput, DicentraRS232CAsync, Process, PupDefs, PupStream, Stream, String = BEGIN rs232Stream: Stream.Handle ← NIL; listener: PupStream.PupListener ← NIL; active: BOOL ← FALSE; kill, killKeyWatcher: BOOL ← FALSE; currentUser: LONG STRING ← [256]; wakeUp: CONDITION; -- set their timeouts maxBuffer: CARDINAL ← 2048; buffer: ARRAY [0 .. 2048) OF CHAR; bufferPtr: CARDINAL ← 0; almostFull: CARDINAL ← 2000; KeyWatcher: PROC = { -- watches the input stream from the RS232 port PutIt: ENTRY PROC [c: CHAR] = { IF bufferPtr > almostFull THEN DO NOTIFY wakeUp; EXIT; ENDLOOP; IF bufferPtr <= maxBuffer-1 THEN {buffer[bufferPtr] ← c; bufferPtr ← (bufferPtr + 1) MOD 256f }; }; -- PutIt DO c: CHAR ← Stream.GetChar[rs232Stream]; PutIt[c]; ENDLOOP; }; -- KeyWatcher keySenderRunning: BOOL ← FALSE; KeySender: PROC [s: Stream.Handle] = { ENABLE {PupStream.StreamClosing => GOTO Out; UNWIND => NULL}; UpdateBuffer: ENTRY PROC = {ENABLE UNWIND => NULL; FOR i: CARDINAL IN [0 .. bufferPtr) DO Stream.PutChar[s, buffer[i]] ENDLOOP; bufferPtr ← 0; }; -- UpdateBuffer BufferCheck: ENTRY PROC RETURNS [BOOL] = {ENABLE UNWIND => NULL; RETURN[bufferPtr = 0]}; -- BufferCheck Wait: ENTRY PROC = {ENABLE UNWIND => NULL; WAIT wakeUp}; keySenderRunning ← TRUE; DO -- until told to die Wait[]; -- timeout or a notify by KeyWatcher IF kill THEN GOTO Out; -- die........ IF BufferCheck[] THEN LOOP; -- nothing to do UpdateBuffer[]; Stream.SendNow[s]; ENDLOOP; -- until told to die EXITS Out => {kill ← FALSE; keySenderRunning ← FALSE; RETURN}; -- and kill process }; NetWatcher: PROC [s: Stream.Handle] = { ENABLE PupStream.StreamClosing => {kill ← TRUE; Note[]; GOTO Out}; DO c: CHAR ← Stream.GetChar[s]; Stream.PutChar[rs232Stream, c]; ENDLOOP; EXITS Out => {Stream.Delete[s]; RETURN}; }; Note: ENTRY PROC [] = {ENABLE UNWIND => NULL; NOTIFY wakeUp}; InitCommand: PROC [stream: Stream.Handle, pupAddress: PupStream.PupAddress] = BEGIN ENABLE { PupStream.StreamClosing => GOTO Exit; Stream.TimeOut => GOTO Exit}; 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; Stream.PutChar[stream, 'k]; Stream.SendNow[stream]; bufferPtr ← 0; Process.Detach[FORK KeySender[stream]]; BEGIN ENABLE PupStream.StreamClosing, Stream.TimeOut => {IF keySenderRunning THEN kill ← TRUE; Note[]; GOTO Out}; DO c: CHAR ← Stream.GetChar[stream]; Stream.PutChar[rs232Stream, 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]; SetBaudRate[]; -- wired to 300 Process.SetTimeout[@wakeUp, Process.MsecToTicks[2000]]; Process.Detach[FORK KeyWatcher[]]; END; -- Krock: Use second connector because it doesn't fit. scc0: DicentraInputOutput.IOAddress = MultibusAddresses.scc2; chanB: LONG POINTER TO Words = scc0 + 00H; chanA: LONG POINTER TO Words = scc0 + 10H; chan: LONG POINTER TO Words ← chanA; -- Line 0 Words: TYPE = RECORD [ r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15: WORD]; SetBaudRate: PROC [] = { DicentraInputOutput.Output[000H, @chan.r14]; -- Disable Baud Rate Gen from PClk DicentraInputOutput.Output[080H, @chan.r12]; -- Low byte of time constant DicentraInputOutput.Output[000H, @chan.r13]; -- High byte of time constant DicentraInputOutput.Output[003H, @chan.r14]; -- Enable Baud Rate Gen from PClk -- 600 baud.... }; Init[]; END.