ShellSerial.Mod 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. MODULE ShellSerial; (** AUTHOR "staubesv/be" PURPOSE "Serial port utilities for shell"; *)
  2. (**
  3. * Note: Based on code of "be"
  4. *
  5. * Usage:
  6. *
  7. * ShellSerial.Open [portNbr BitsPerSecond DataBits Parity StopBits] ~ opens a shell listening to serial port <portNbr>
  8. *
  9. * ShellSerial.YReceive [[filename] portNbr BitsPerSecond DataBits Parity StopBits Prompt] ~
  10. * ShellSerial.XReceive [[filename] portNbr BitsPerSecond DataBits Parity StopBits Prompt] ~
  11. *
  12. * Whereas
  13. * Parity = "odd"|"even"|"mark"|"space"|"no"
  14. * StopBits = "1"|"1.5"|"2"
  15. *
  16. * Examples:
  17. *
  18. * ShellSerial.Open 1 115200 no 1 8 ~
  19. * ShellSerial.YReceive ~
  20. * ShellSerial.XReceive ~
  21. *
  22. * History:
  23. *
  24. * 25.06.2007 First release (staubesv)
  25. *)
  26. IMPORT
  27. Modules, Kernel, Commands, Streams, (*Strings,*) Files, Serials, Shell, XYModem;
  28. CONST
  29. BufferSize = 1024;
  30. DefaultPrompt = "SHELL>";
  31. VAR
  32. shells : ARRAY Serials.MaxPorts + 1 OF Shell.Shell;
  33. PROCEDURE ModemReceive(context : Commands.Context; modemMode: LONGINT); (** [[filename] portNbr BitsPerSecond DataBits Parity StopBits] ~ *)
  34. VAR
  35. name : Files.FileName; file : Files.File;
  36. port : Serials.Port; portNbr, bps, data, parity, stop, res : LONGINT; params: SET;
  37. isOpen0 : BOOLEAN;
  38. bps0, data0, parity0, stop0 : LONGINT;
  39. recv : XYModem.Receiver; awaitF : BOOLEAN;
  40. w : Streams.Writer; r : Streams.Reader;
  41. error: ARRAY 64 OF CHAR;
  42. isTracePort: BOOLEAN;
  43. BEGIN
  44. IF ~context.arg.GetString(name) THEN
  45. context.result := 1;
  46. context.error.String("Invalid port settings, res="); context.error.Int(res,0); context.error.Ln;
  47. RETURN;
  48. END;
  49. Serials.GetPortParameters(context.arg, portNbr, bps, data, parity, stop, params, res);
  50. IF res # 0 THEN
  51. context.result := 2;
  52. context.error.String("Invalid port settings, res="); context.error.Int(res,0); context.error.Ln;
  53. RETURN;
  54. END;
  55. port := Serials.GetPort(portNbr);
  56. IF port = NIL THEN
  57. context.result := 3;
  58. context.error.String("Cannot find port "); context.error.Int(portNbr, 0); context.error.Ln;
  59. RETURN;
  60. END;
  61. port.GetPortState(isOpen0, bps0, data0, parity0, stop0);
  62. (* disable tracing over the selected port *)
  63. IF Serials.IsTracePort(port) THEN
  64. isTracePort := TRUE;
  65. Serials.SetTracePort(-1,0,0,0,0, res);
  66. END;
  67. port.Close;
  68. port.Open(bps, data, parity, stop, res);
  69. IF res # Serials.Ok THEN
  70. context.result := 4;
  71. context.error.String("Could not open port "); context.error.Int(portNbr, 0);
  72. context.error.String(", res="); context.error.Int(res,0);
  73. context.error.Ln;
  74. IF isTracePort THEN
  75. Serials.SetTracePort(portNbr, bps0, data0, parity0, stop0, res);
  76. ELSIF isOpen0 THEN
  77. port.Open(bps0, data0, parity0, stop0, res);
  78. END;
  79. RETURN;
  80. END;
  81. IF (modemMode = XYModem.XModem) OR (modemMode = XYModem.XModem1K) THEN
  82. context.out.String("XReceive ");
  83. ELSE
  84. context.out.String("YReceive ");
  85. END;
  86. context.out.String(name); context.out.Ln;
  87. IF name # "" THEN
  88. file := Files.New(name); awaitF := FALSE
  89. ELSE
  90. file := NIL; awaitF := TRUE
  91. END;
  92. NEW(w, port.Send, BufferSize); NEW(r, port.Receive, BufferSize);
  93. NEW(recv, w, r, file, modemMode);
  94. IF ~awaitF THEN
  95. recv.Await(error)
  96. ELSE
  97. recv.AwaitF(file, error)
  98. END;
  99. port.Close();
  100. IF isTracePort THEN
  101. Serials.SetTracePort(portNbr, bps0, data0, parity0, stop0, res);
  102. IF res # Serials.Ok THEN
  103. context.error.String("Warning: could not re-activate trace over port "); context.error.Int(portNbr, 0);
  104. context.error.String(", res="); context.error.Int(res,0);
  105. context.error.Ln;
  106. END;
  107. ELSIF isOpen0 THEN
  108. port.Open(bps0, data0, parity0, stop0, res);
  109. IF res # Serials.Ok THEN
  110. context.error.String("Warning: could not re-open port "); context.error.Int(portNbr, 0);
  111. context.error.String(", res="); context.error.Int(res,0);
  112. context.error.Ln;
  113. END;
  114. END;
  115. Wait(1000); (* Give the port open time so we see the output below *)
  116. IF error # "" THEN
  117. context.result := 5;
  118. context.error.String(" "); context.error.String(error)
  119. ELSE
  120. Files.Register(file);
  121. IF awaitF THEN
  122. file.GetName(name);
  123. context.out.String(" "); context.out.String(name);
  124. context.out.String(" ("); context.out.Int(file.Length(), 0); context.out.String(" Bytes"); context.out.String(")");
  125. END;
  126. context.out.String(" done.");
  127. context.out.Ln;
  128. END;
  129. END ModemReceive;
  130. (** Receive a file using X-modem protocol *)
  131. PROCEDURE XReceive*(context : Commands.Context); (** [[filename] portNbr BitsPerSecond DataBits Parity StopBits] ~ *)
  132. BEGIN
  133. ModemReceive(context,XYModem.XModem);
  134. END XReceive;
  135. (** Receive a file using Y-modem protocol *)
  136. PROCEDURE YReceive*(context : Commands.Context); (** [[filename] portNbr BitsPerSecond DataBits Parity StopBits] ~ *)
  137. BEGIN
  138. ModemReceive(context,XYModem.YModem);
  139. END YReceive;
  140. (*PROCEDURE IsDigit(ch: CHAR): BOOLEAN;
  141. BEGIN
  142. RETURN (ch >= "0") & (ch <= "9")
  143. END IsDigit;*)
  144. PROCEDURE Wait(ms: LONGINT);
  145. VAR timer: Kernel.Timer;
  146. BEGIN
  147. NEW(timer); timer.Sleep(ms);
  148. END Wait;
  149. (*PROCEDURE GetSerialPortParameters(context : Commands.Context; VAR port, bps, data, parity, stop: LONGINT): BOOLEAN;
  150. VAR str : ARRAY 32 OF CHAR;
  151. BEGIN
  152. bps := DefaultBPS; data := DefaultDataBits; parity := DefaultParity; stop := DefaultStop;
  153. IF ~context.arg.GetInteger(port,FALSE) THEN
  154. context.result := 1;
  155. context.error.String("port number not specified"); context.error.Ln();
  156. RETURN FALSE
  157. END;
  158. IF (port < 1) OR (port > Serials.MaxPorts) THEN
  159. context.result := 2;
  160. context.error.String("wrong port number"); context.error.Ln();
  161. RETURN FALSE
  162. END;
  163. IF ~context.arg.GetInteger(bps, FALSE) THEN
  164. RETURN TRUE;
  165. END;
  166. IF ~context.arg.GetInteger(data, FALSE) THEN
  167. RETURN TRUE;
  168. END;
  169. IF ~context.arg.GetString(str) THEN
  170. RETURN TRUE;
  171. END;
  172. IF str = "odd" THEN
  173. parity := Serials.ParOdd
  174. ELSIF str = "even" THEN
  175. parity := Serials.ParEven
  176. ELSIF str = "mark" THEN
  177. parity := Serials.ParMark
  178. ELSIF str = "space" THEN
  179. parity := Serials.ParSpace
  180. ELSIF str # "no" THEN
  181. context.result := 3;
  182. context.error.String("wrong parity"); context.error.Ln();
  183. RETURN FALSE
  184. END;
  185. IF ~context.arg.GetString(str) THEN
  186. RETURN TRUE;
  187. END;
  188. IF str = "1.5" THEN
  189. stop := Serials.Stop1dot5
  190. ELSIF str = "2" THEN
  191. stop := Serials.Stop2
  192. ELSIF str # "1" THEN
  193. context.result := 4;
  194. context.error.String("wrong stop bits"); context.error.Ln();
  195. RETURN FALSE
  196. END;
  197. RETURN TRUE
  198. END GetSerialPortParameters;*)
  199. (** Open a shell listening on the specified <portNbr> *)
  200. PROCEDURE Open*(context : Commands.Context); (** [portNbr BitsPerSecond DataBits Parity StopBits Prompt] ~ *)
  201. VAR
  202. port : Serials.Port; portNbr, bps, data, parity, stop, res : LONGINT; params: SET;
  203. prompt: ARRAY 32 OF CHAR;
  204. w : Streams.Writer; r : Streams.Reader;
  205. BEGIN {EXCLUSIVE}
  206. Serials.GetPortParameters(context.arg, portNbr, bps, data, parity, stop, params, res);
  207. IF res # 0 THEN
  208. context.result := 1;
  209. context.error.String("Invalid port settings, res="); context.error.Int(res,0); context.error.Ln;
  210. RETURN;
  211. END;
  212. port := Serials.GetPort(portNbr);
  213. IF port # NIL THEN
  214. IF shells[portNbr-1] # NIL THEN
  215. shells[portNbr-1].Exit; shells[portNbr-1].AwaitDeath;
  216. shells[portNbr-1] := NIL;
  217. port.Close;
  218. END;
  219. port.Open(bps, data, parity, stop, res);
  220. IF (res = Serials.Ok) THEN
  221. NEW(w, port.Send, BufferSize); NEW(r, port.Receive, BufferSize);
  222. IF ~context.arg.GetString(prompt) THEN prompt := DefaultPrompt; END;
  223. NEW(shells[portNbr-1], r, w, w, TRUE, prompt);
  224. ELSE
  225. context.error.String("Shell: could not open port "); context.error.Int(portNbr, 0);
  226. context.error.String(", res: "); context.error.Int(res, 0); context.error.Ln;
  227. END;
  228. ELSE
  229. context.error.String("Shell: serial port "); context.error.Int(portNbr, 0); context.error.String(" not found."); context.error.Ln;
  230. END;
  231. END Open;
  232. PROCEDURE Cleanup;
  233. VAR
  234. port : Serials.Port;
  235. i, res : LONGINT;
  236. isOpen0, isTracePort : BOOLEAN;
  237. bps0, data0, parity0, stop0 : LONGINT;
  238. BEGIN
  239. FOR i := 0 TO LEN(shells)-1 DO
  240. IF (shells[i] # NIL) THEN
  241. port := Serials.GetPort(i+1);
  242. isTracePort := Serials.IsTracePort(port);
  243. IF port # NIL THEN
  244. port.GetPortState(isOpen0, bps0, data0, parity0, stop0);
  245. port.Close;
  246. END;
  247. shells[i].Exit;
  248. (*shells[i].AwaitDeath;*)
  249. shells[i] := NIL;
  250. IF isTracePort THEN
  251. Serials.SetTracePort(i+1, bps0, data0, parity0, stop0, res);
  252. END;
  253. END;
  254. END;
  255. END Cleanup;
  256. BEGIN
  257. Modules.InstallTermHandler(Cleanup);
  258. END ShellSerial.