MODULE ShellSerial;
IMPORT
Modules, Kernel, Commands, Streams, Strings, Files, Serials, Shell, XYModem;
CONST
DefaultPort = 1;
DefaultBPS = 115200; DefaultParity = Serials.ParNo; DefaultStop = Serials.Stop1;
BufferSize = 1024;
Prompt = "SHELL>";
VAR
shells : ARRAY Serials.MaxPorts + 1 OF Shell.Shell;
PROCEDURE YReceive*(context : Commands.Context);
VAR
name : Files.FileName; file : Files.File;
port : Serials.Port; portNbr, bps, parity, stop, res : LONGINT;
shellBps, shellData, shellParity, shellStop : LONGINT; isOpen : BOOLEAN;
recv : XYModem.Receiver; awaitF : BOOLEAN;
w : Streams.Writer; r : Streams.Reader;
error: ARRAY 64 OF CHAR;
BEGIN {EXCLUSIVE}
IF GetXYPars(context, name, portNbr, bps, parity, stop) THEN
port := Serials.GetPort(portNbr);
IF port = NIL THEN
context.error.String("Cannot find port "); context.error.Int(portNbr, 0); context.error.Ln;
RETURN;
END;
IF shells[portNbr] # NIL THEN
port.GetPortState(isOpen, shellBps, shellData, shellParity, shellStop);
IF isOpen THEN port.Close; END;
END;
port.Open(bps, 8, parity, stop, res);
IF res # Serials.Ok THEN
context.error.String("Could not open port "); context.error.Int(portNbr, 0); context.error.Ln;
RETURN;
END;
context.out.String("YReceive "); context.out.String(name); context.out.Ln;
IF name # "" THEN
file := Files.New(name); awaitF := FALSE
ELSE
file := NIL; awaitF := TRUE
END;
NEW(w, port.Send, BufferSize); NEW(r, port.Receive, BufferSize);
NEW(recv, w, r, file, XYModem.YModem);
IF ~awaitF THEN
recv.Await(error)
ELSE
recv.AwaitF(file, error)
END;
port.Close();
IF shells[portNbr] # NIL THEN
port.Open(shellBps, shellData, shellParity, shellStop, res);
IF res # Serials.Ok THEN
context.error.String("Warning: Could not re-open shell port "); context.error.Int(portNbr, 0); context.error.Ln;
END;
END;
Wait(1000);
IF error # "" THEN
context.error.String(" "); context.error.String(error)
ELSE
Files.Register(file);
IF awaitF THEN
file.GetName(name);
context.out.String(" "); context.out.String(name);
context.out.String(" ("); context.out.Int(file.Length(), 0); context.out.String(" Bytes"); context.out.String(")");
END;
context.out.String(" done.");
END;
context.out.Ln;
END;
END YReceive;
PROCEDURE XReceive*(context : Commands.Context);
VAR
name : Files.FileName; file : Files.File;
port : Serials.Port; portNbr, bps, parity, stop, res: LONGINT;
recv : XYModem.Receiver; awaitF : BOOLEAN;
w : Streams.Writer; r : Streams.Reader;
shellBps, shellData, shellParity, shellStop : LONGINT; isOpen : BOOLEAN;
error: ARRAY 64 OF CHAR;
BEGIN
IF GetXYPars(context, name, portNbr, bps, parity, stop) THEN
port := Serials.GetPort(portNbr);
IF port = NIL THEN
context.error.String("Cannot find port "); context.error.Int(portNbr, 0); context.error.Ln;
RETURN;
END;
IF shells[portNbr] # NIL THEN
port.GetPortState(isOpen, shellData, shellBps, shellParity, shellStop);
IF isOpen THEN port.Close; END;
END;
port.Open(bps, 8, parity, stop, res);
IF (res # Serials.Ok) THEN
context.error.String("Could not open port "); context.error.Int(portNbr, 0); context.error.Ln;
RETURN;
END;
context.out.String("YReceive "); context.out.String(name); context.out.Ln;
IF name # "" THEN
file := Files.New(name); awaitF := FALSE
ELSE
file := NIL; awaitF := TRUE
END;
NEW(w, port.Send, BufferSize); NEW(r, port.Receive, BufferSize);
NEW(recv, w, r, file, XYModem.XModem);
IF ~awaitF THEN
recv.Await(error)
ELSE
recv.AwaitF(file, error)
END;
port.Close();
IF shells[portNbr] # NIL THEN
port.Open(shellBps, shellData, shellParity, shellStop, res);
IF (res # Serials.Ok) THEN
END;
END;
Wait(1000);
IF error # "" THEN
context.error.String(" "); context.error.String(error)
ELSE
Files.Register(file);
IF awaitF THEN
file.GetName(name);
context.out.String(" "); context.out.String(name);
context.out.String(" ("); context.out.Int(file.Length(), 0); context.out.String(" Bytes"); context.out.String(")");
END;
context.out.String(" done.");
END;
context.out.Ln;
END;
END XReceive;
PROCEDURE IsDigit(ch: CHAR): BOOLEAN;
BEGIN
RETURN (ch >= "0") & (ch <= "9")
END IsDigit;
PROCEDURE Wait(ms: LONGINT);
VAR timer: Kernel.Timer;
BEGIN
NEW(timer); timer.Sleep(ms);
END Wait;
PROCEDURE GetXYPars(context : Commands.Context; VAR name: ARRAY OF CHAR; VAR port, bps, parity, stop: LONGINT): BOOLEAN;
BEGIN
port := DefaultPort; bps := DefaultBPS; parity := DefaultParity; stop := DefaultStop;
IF context.arg.GetString(name) & IsDigit(name[0]) THEN
Strings.StrToInt(name, port);
IF (port < 1) OR (port > Serials.MaxPorts) THEN
context.error.String("wrong port number"); context.error.Ln;
RETURN FALSE
END;
context.arg.SkipWhitespace; context.arg.Int(bps, FALSE);
context.arg.SkipWhitespace; context.arg.String(name);
IF name = "odd" THEN
parity := Serials.ParOdd
ELSIF name = "even" THEN
parity := Serials.ParEven
ELSIF name = "mark" THEN
parity := Serials.ParMark
ELSIF name = "space" THEN
parity := Serials.ParSpace
ELSIF name # "no" THEN
context.error.String("wrong parity"); context.error.Ln;
RETURN FALSE
END;
context.arg.SkipWhitespace; context.arg.String(name);
IF name = "1.5" THEN
stop := Serials.Stop1dot5
ELSIF name = "2" THEN
stop := Serials.Stop2
ELSIF name # "1" THEN
context.error.String("wrong stop bits"); context.error.Ln;
RETURN FALSE
END;
context.arg.SkipWhitespace; context.arg.String(name);
END;
RETURN TRUE
END GetXYPars;
PROCEDURE GetSerialPortParameters(context : Commands.Context; VAR port, bps, parity, stop: LONGINT): BOOLEAN;
VAR str : ARRAY 32 OF CHAR;
BEGIN
port := DefaultPort; bps := DefaultBPS; parity := DefaultParity; stop := DefaultStop;
context.arg.String(str);
IF IsDigit(str[0]) THEN
Strings.StrToInt(str, port);
IF (port < 1) OR (port > Serials.MaxPorts) THEN
context.error.String("wrong port number"); context.error.Ln();
RETURN FALSE
END;
context.arg.Int(bps, FALSE);
context.arg.String(str);
IF str = "odd" THEN
parity := Serials.ParOdd
ELSIF str = "even" THEN
parity := Serials.ParEven
ELSIF str = "mark" THEN
parity := Serials.ParMark
ELSIF str = "space" THEN
parity := Serials.ParSpace
ELSIF str # "no" THEN
context.error.String("wrong parity"); context.error.Ln();
RETURN FALSE
END;
context.arg.String(str);
IF str = "1.5" THEN
stop := Serials.Stop1dot5
ELSIF str = "2" THEN
stop := Serials.Stop2
ELSIF str # "1" THEN
context.error.String("wrong stop bits"); context.error.Ln();
RETURN FALSE
END
END;
RETURN TRUE
END GetSerialPortParameters;
PROCEDURE Open*(context : Commands.Context);
VAR
port : Serials.Port; portNbr, bps, parity, stop, res : LONGINT;
w : Streams.Writer; r : Streams.Reader;
BEGIN {EXCLUSIVE}
IF ~GetSerialPortParameters(context, portNbr, bps, parity, stop) THEN
portNbr := DefaultPort; bps := DefaultBPS; parity := DefaultParity; stop := DefaultStop
END;
port := Serials.GetPort(portNbr);
IF port # NIL THEN
IF shells[portNbr] # NIL THEN
shells[portNbr].Exit; shells[portNbr].AwaitDeath;
shells[portNbr] := NIL;
port.Close;
END;
port.Open(bps, 8, parity, stop, res);
IF (res = Serials.Ok) THEN
NEW(w, port.Send, BufferSize); NEW(r, port.Receive, BufferSize);
NEW(shells[portNbr], r, w, w, TRUE, Prompt);
ELSE
context.error.String("Shell: Could not open port "); context.error.Int(portNbr, 0);
context.error.String(", res: "); context.error.Int(res, 0); context.error.Ln;
END;
ELSE
context.error.String("Shell: Serial port "); context.error.Int(portNbr, 0); context.error.String(" not found."); context.error.Ln;
END;
END Open;
PROCEDURE Cleanup;
VAR port : Serials.Port; i : LONGINT;
BEGIN
FOR i := 0 TO LEN(shells)-1 DO
IF (shells[i] # NIL) THEN
shells[i].Exit; shells[i].AwaitDeath;
shells[i] := NIL;
port := Serials.GetPort(i);
IF port # NIL THEN port.Close; END;
END;
END;
END Cleanup;
BEGIN
Modules.InstallTermHandler(Cleanup);
END ShellSerial.