-- 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.