123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267 |
- MODULE ShellSerial; (** AUTHOR "staubesv/be" PURPOSE "Serial port utilities for shell"; *)
- (**
- * Note: Based on code of "be"
- *
- * Usage:
- *
- * ShellSerial.Open [portNbr BitsPerSecond DataBits Parity StopBits] ~ opens a shell listening to serial port <portNbr>
- *
- * ShellSerial.YReceive [[filename] portNbr BitsPerSecond DataBits Parity StopBits Prompt] ~
- * ShellSerial.XReceive [[filename] portNbr BitsPerSecond DataBits Parity StopBits Prompt] ~
- *
- * Whereas
- * Parity = "odd"|"even"|"mark"|"space"|"no"
- * StopBits = "1"|"1.5"|"2"
- *
- * Examples:
- *
- * ShellSerial.Open 1 115200 no 1 8 ~
- * ShellSerial.YReceive ~
- * ShellSerial.XReceive ~
- *
- * History:
- *
- * 25.06.2007 First release (staubesv)
- *)
- IMPORT
- Modules, Kernel, Commands, Streams, (*Strings,*) Files, Serials, Shell, Objects, XYModem;
- CONST
- BufferSize = 1024;
- DefaultPrompt = "SHELL>";
- VAR
- shells : ARRAY Serials.MaxPorts + 1 OF Shell.Shell;
- PROCEDURE Yield(): BOOLEAN;
- BEGIN
- Objects.Yield();
- RETURN TRUE;
- END Yield;
- PROCEDURE ModemReceive(context : Commands.Context; modemMode: LONGINT); (** [[filename] portNbr BitsPerSecond DataBits Parity StopBits] ~ *)
- VAR
- fileName : Files.FileName;
- length: LONGINT;
- port : Serials.Port; portNbr, bps, data, parity, stop, res : LONGINT;
- isOpen0 : BOOLEAN;
- bps0, data0, parity0, stop0 : LONGINT;
- w : Streams.Writer; r : Streams.Reader;
- isTracePort: BOOLEAN;
- params: SET;
- i, receiveRes: LONGINT;
- BEGIN
- IF ~context.arg.GetString(fileName) & (modemMode # XYModem.YModem) THEN
- context.result := Commands.CommandParseError;
- context.error.String("file name is missing"); context.error.Ln;
- RETURN;
- END;
- context.arg.SkipWhitespace;
- TRACE(context.arg.Available());
- IF context.arg.Available() # 0 THEN (* port settings are specified *)
- Serials.GetPortParameters(context.arg, portNbr, bps, data, parity, stop, params, res);
- IF res # 0 THEN
- context.result := 2;
- context.error.String("Invalid port settings, res="); context.error.Int(res,0); context.error.Ln;
- RETURN;
- END;
- ELSE
- (*
- if the command context is the same as the context of the currently executed command of a shell
- take that shell port as the port used for data transmission
- *)
- i := 0;
- WHILE (i < LEN(shells)) & ((shells[i] = NIL) OR ~shells[i].IsCurrentCmdContext(context)) DO
- INC(i);
- END;
- IF i < LEN(shells) THEN
- portNbr := i+1;
- bps := -1;
- ELSE
- context.result := 3;
- context.error.String("port number is not specified"); context.error.Ln;
- RETURN;
- END;
- END;
- port := Serials.GetPort(portNbr);
- IF port = NIL THEN
- context.result := 4;
- context.error.String("Cannot find port "); context.error.Int(portNbr, 0); context.error.Ln;
- RETURN;
- END;
- port.GetPortState(isOpen0, bps0, data0, parity0, stop0);
- IF bps = -1 THEN (* using port of a shell *)
- bps := bps0; data := data0; parity := parity0; stop := stop0;
- END;
- TRACE(portNbr, isOpen0, bps0, data0, parity0, stop0);
- (* disable tracing over the selected port *)
- IF Serials.IsTracePort(port) THEN
- TRACE("disabling trace port");
- isTracePort := TRUE;
- Serials.SetTracePort(0,0,0,0,0, res);
- END;
- TRACE("closing port");
- port.Close;
- TRACE("opening port", bps, data, parity, stop);
- port.Open(bps, data, parity, stop, res);
- TRACE(res);
- IF res # Serials.Ok THEN
- context.result := 5;
- context.error.String("Could not open port "); context.error.Int(portNbr, 0);
- context.error.String(", res="); context.error.Int(res,0);
- context.error.Ln;
- IF isTracePort THEN
- Serials.SetTracePort(portNbr, bps0, data0, parity0, stop0, res);
- ELSIF isOpen0 THEN
- port.Open(bps0, data0, parity0, stop0, res);
- END;
- RETURN;
- END;
- NEW(w, port.Send, 4096); NEW(r, port.Receive, 4096);
- XYModem.Receive(r,w,fileName,modemMode,15000,5000,length,Yield,receiveRes);
- TRACE("closing port");
- port.Close();
- IF isTracePort THEN
- Serials.SetTracePort(portNbr, bps0, data0, parity0, stop0, res);
- IF res # Serials.Ok THEN
- context.error.String("Warning: could not re-activate trace over port "); context.error.Int(portNbr, 0);
- context.error.String(", res="); context.error.Int(res,0);
- context.error.Ln;
- END;
- ELSIF isOpen0 THEN
- port.Open(bps0, data0, parity0, stop0, res);
- IF res # Serials.Ok THEN
- context.error.String("Warning: could not re-open port "); context.error.Int(portNbr, 0);
- context.error.String(", res="); context.error.Int(res,0);
- context.error.Ln;
- END;
- END;
- Wait(1000); (* Give the port open time so we see the output below *)
- IF receiveRes = 0 THEN
- context.out.String(" "); context.out.String(fileName);
- context.out.String(" ("); context.out.Int(length, 0); context.out.String(" Bytes"); context.out.String(")");
- context.out.String(" done.");
- context.out.Ln;
- ELSE
- context.result := 6;
- context.error.String("error "); context.error.Int(receiveRes,0); context.error.Ln;
- END;
- END ModemReceive;
- (** Receive a file using X-modem protocol *)
- PROCEDURE XReceive*(context : Commands.Context); (** [[filename] portNbr BitsPerSecond DataBits Parity StopBits] ~ *)
- BEGIN
- ModemReceive(context,XYModem.XModem);
- END XReceive;
- (** Receive a file using Y-modem protocol *)
- PROCEDURE YReceive*(context : Commands.Context); (** [[filename] portNbr BitsPerSecond DataBits Parity StopBits] ~ *)
- BEGIN
- ModemReceive(context,XYModem.YModem);
- END YReceive;
- (*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;
- (** Open a shell listening on the specified <portNbr> *)
- PROCEDURE Open*(context : Commands.Context); (** [portNbr BitsPerSecond DataBits Parity StopBits Prompt] ~ *)
- VAR
- port : Serials.Port; portNbr, bps, data, parity, stop, res : LONGINT;
- prompt: ARRAY 32 OF CHAR;
- w : Streams.Writer; r : Streams.Reader;
- params: SET;
- BEGIN {EXCLUSIVE}
- Serials.GetPortParameters(context.arg, portNbr, bps, data, parity, stop, params, res);
- IF res # 0 THEN
- context.result := Commands.CommandError;
- context.error.String("Invalid port settings, res="); context.error.Int(res,0); context.error.Ln;
- RETURN;
- END;
- IF ~context.arg.GetString(prompt) THEN prompt := DefaultPrompt; END;
- port := Serials.GetPort(portNbr);
- IF port # NIL THEN
- TRACE("closing port");
- port.Close;
- IF shells[portNbr-1] # NIL THEN
- TRACE("exiting a shell");
- shells[portNbr-1].Exit;
- (* avoid dead-lock if this command is issued by shells[portNbr-1] *)
- TRACE(~shells[portNbr-1].IsCurrentCmdContext(context));
- IF ~shells[portNbr-1].IsCurrentCmdContext(context) THEN
- shells[portNbr-1].AwaitDeath;
- END;
- shells[portNbr-1] := NIL;
- END;
- TRACE("opening port", portNbr, bps, data, parity, stop);
- port.Open(bps, data, parity, stop, res);
- TRACE(res);
- IF (res = Serials.Ok) THEN
- NEW(w, port.Send, BufferSize); NEW(r, port.Receive, BufferSize);
- NEW(shells[portNbr-1], 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, res : LONGINT;
- isOpen0, isTracePort : BOOLEAN;
- bps0, data0, parity0, stop0 : LONGINT;
- BEGIN
- FOR i := 0 TO LEN(shells)-1 DO
- IF (shells[i] # NIL) THEN
- port := Serials.GetPort(i+1);
- isTracePort := Serials.IsTracePort(port);
- IF port # NIL THEN
- port.GetPortState(isOpen0, bps0, data0, parity0, stop0);
- port.Close;
- END;
- shells[i].Exit;
- (*shells[i].AwaitDeath;*)
- shells[i] := NIL;
- IF isTracePort THEN
- Serials.SetTracePort(i+1, bps0, data0, parity0, stop0, res);
- END;
- END;
- END;
- END Cleanup;
- BEGIN
- Modules.InstallTermHandler(Cleanup);
- END ShellSerial.
|