Zynq.PsUart.Mod 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  1. MODULE PsUart;
  2. (**
  3. AUTHOR: Alexey Morozov, Timothee Martiel, HighDim GmbH, 2013-2018
  4. PURPOSE: driver implementation for Xilinx Zynq UART PS controller
  5. *)
  6. IMPORT SYSTEM, UartMin := PsUartMin, PsUartInterrupts, Trace;
  7. CONST
  8. (** Receive errors - compatible with A2 Serials *)
  9. OverrunError* = 10;
  10. ParityError* = 11;
  11. FramingError* = 12;
  12. BreakInterrupt* = 13;
  13. DefaultRxBufSize* = 4096;
  14. DefaultTxBufSize* = 4096;
  15. ReceiveTimeoutInUs* = 500; (** Receive timeout in microseconds *)
  16. (* RX data interrupts *)
  17. RxDataInterrupts = {UartMin.XUARTPS_IXR_TOUT , UartMin.XUARTPS_IXR_RXFULL , UartMin.XUARTPS_IXR_RXOVR};
  18. (* RX error interrupts *)
  19. RxErrorInterrupts = {UartMin.XUARTPS_IXR_PARITY , UartMin.XUARTPS_IXR_FRAMING , UartMin.XUARTPS_IXR_OVER};
  20. (* TX data interrupts *)
  21. TxDataInterrupts = {UartMin.XUARTPS_IXR_TXEMPTY, UartMin.XUARTPS_IXR_TTRIG};
  22. (* TX error interrupts *)
  23. TxErrorInterrupts = {UartMin.XUARTPS_IXR_TOVR};
  24. TYPE
  25. UartController* = POINTER TO RECORD
  26. id-: LONGINT; (** UART controller ID *)
  27. regs-: UartMin.UartRegisters; (** controller registers *)
  28. inputClock-: LONGINT; (** controller input clock in Hz *)
  29. bps-, data-, parity-, stop-: LONGINT; (** current parameter values *)
  30. open-: BOOLEAN; (** TRUE if the controller is open *)
  31. rxBuf: POINTER TO ARRAY OF CHAR; (* receive (RX) circular buffer *)
  32. rxBufRdPos, rxBufWrPos: LONGINT; (* RX buffer read and write positions *)
  33. txBuf: POINTER TO ARRAY OF CHAR; (* transmit (TX) circular buffer *)
  34. txBufRdPos, txBufWrPos: LONGINT; (* TX buffer read and write positions *)
  35. errors: SET;
  36. END;
  37. VAR
  38. uarts: ARRAY 2 OF UartController;
  39. (* Disable all UART interrupts *)
  40. PROCEDURE DisableInterrupts(regs: UartMin.UartRegisters);
  41. BEGIN
  42. regs.idr := UartMin.XUARTPS_IXR_MASK;
  43. END DisableInterrupts;
  44. PROCEDURE IntrHandler(param: ANY);
  45. VAR
  46. uart: UartController;
  47. intrStatus: SET;
  48. BEGIN
  49. uart := param(UartController);
  50. (*Trace.String("imr="); Trace.Set(uart.regs.imr); Trace.Ln;
  51. Trace.String("isr="); Trace.Set(uart.regs.isr); Trace.Ln;*)
  52. intrStatus := uart.regs.imr * uart.regs.isr;
  53. uart.regs.isr := intrStatus; (* clear the interrupt *)
  54. (*Trace.String("intrStatus="); Trace.Set(intrStatus); Trace.Ln;*)
  55. IF intrStatus * (RxDataInterrupts+RxErrorInterrupts) # {} THEN
  56. IntrHandlerRx(uart,intrStatus);
  57. END;
  58. IF intrStatus * TxDataInterrupts # {} THEN
  59. IntrHandlerTx(uart,intrStatus);
  60. END;
  61. END IntrHandler;
  62. PROCEDURE IntrHandlerRx(uart: UartController; intrStatus: SET);
  63. VAR
  64. bufWrPos: LONGINT;
  65. BEGIN
  66. IF intrStatus * RxErrorInterrupts # {} THEN
  67. IF UartMin.XUARTPS_IXR_OVER IN intrStatus THEN
  68. INCL(uart.errors,OverrunError);
  69. Trace.String("---rx overrun(1)---: intrStatus="); Trace.Set(intrStatus); Trace.Ln;
  70. RETURN;
  71. END;
  72. END;
  73. bufWrPos := uart.rxBufWrPos;
  74. WHILE ~(UartMin.XUARTPS_SR_RXEMPTY IN uart.regs.sr) DO
  75. uart.rxBuf[bufWrPos] := CHR(uart.regs.fifo);
  76. INC(bufWrPos);
  77. IF bufWrPos = LEN(uart.rxBuf) THEN
  78. bufWrPos := 0;
  79. END;
  80. IF bufWrPos = uart.rxBufRdPos THEN
  81. INCL(uart.errors,OverrunError);
  82. Trace.String("---rx overrun(2)---: intrStatus="); Trace.Set(intrStatus); Trace.Ln;
  83. RETURN;
  84. END;
  85. END;
  86. uart.rxBufWrPos := bufWrPos;
  87. END IntrHandlerRx;
  88. PROCEDURE IntrHandlerTx(uart: UartController; intrStatus: SET);
  89. VAR bufRdPos: LONGINT;
  90. BEGIN
  91. IF intrStatus * TxErrorInterrupts # {} THEN
  92. IF UartMin.XUARTPS_IXR_TOVR IN intrStatus THEN
  93. INCL(uart.errors,OverrunError);
  94. Trace.String("---tx overrun---: intrStatus="); Trace.Set(intrStatus); Trace.Ln;
  95. RETURN;
  96. END;
  97. END;
  98. bufRdPos := uart.txBufRdPos;
  99. WHILE (bufRdPos # uart.txBufWrPos) & ~(UartMin.XUARTPS_SR_TXFULL IN uart.regs.sr) DO
  100. uart.regs.fifo := ORD(uart.txBuf[bufRdPos]);
  101. INC(bufRdPos);
  102. IF bufRdPos = LEN(uart.txBuf) THEN
  103. bufRdPos := 0;
  104. END;
  105. END;
  106. (* disable TX data interrupts if the buffer is empty *)
  107. IF bufRdPos = uart.txBufWrPos THEN
  108. uart.regs.idr := uart.regs.idr + TxDataInterrupts;
  109. END;
  110. uart.txBufRdPos := bufRdPos;
  111. END IntrHandlerTx;
  112. (*
  113. Returns TRUE if a cyclic buffer is full
  114. *)
  115. PROCEDURE BufIsFull(bufWrPos, bufRdPos, bufSize: LONGINT): BOOLEAN;
  116. BEGIN
  117. IF bufWrPos # (bufSize-1) THEN
  118. RETURN bufRdPos = (bufWrPos+1);
  119. ELSE
  120. RETURN bufRdPos = 0;
  121. END;
  122. END BufIsFull;
  123. (**
  124. Install a UART controller present in the system
  125. uart: ID (0-based index) of the UART controller to install
  126. base: controller base address
  127. inputClock: controller input clock in Hz
  128. res: returned error code, 0 in case of success
  129. *)
  130. PROCEDURE Install* (uart: LONGINT; base: ADDRESS; inputClock: LONGINT; VAR res: LONGINT);
  131. VAR ctl: UartController;
  132. BEGIN
  133. UartMin.Install(uart, base, inputClock, res);
  134. IF res # 0 THEN RETURN; END;
  135. NEW(ctl);
  136. uarts[uart] := ctl;
  137. ctl.id := uart;
  138. ctl.regs := UartMin.GetUart(uart);
  139. ctl.inputClock := inputClock;
  140. ctl.open := FALSE;
  141. ctl.bps := UartMin.DefaultBPS;
  142. ctl.data := UartMin.DefaultDataBits;
  143. ctl.parity := UartMin.DefaultParity;
  144. ctl.stop := UartMin.DefaultStop;
  145. NEW(ctl.rxBuf,DefaultRxBufSize);
  146. NEW(ctl.txBuf,DefaultTxBufSize);
  147. ASSERT(PsUartInterrupts.InstallInterruptHandler(uart,IntrHandler,ctl));
  148. END Install;
  149. (**
  150. Get UART controller with a given ID
  151. uart: UART controller ID
  152. Returns NIL in case if no controller with given ID has been installed
  153. *)
  154. PROCEDURE GetUart*(uart: LONGINT): UartController;
  155. BEGIN
  156. IF (uart >= 0) & (uart < LEN(uarts)) THEN
  157. RETURN uarts[uart];
  158. ELSE RETURN NIL;
  159. END;
  160. END GetUart;
  161. (**
  162. Open a UART controller
  163. uart: UART controller
  164. bps: baudrate
  165. data: number of data bits
  166. parity: parity control
  167. stop: number of stop bits
  168. res: returned error code, 0 in case of success
  169. *)
  170. PROCEDURE Open*(uart: UartController; bps, data, parity, stop: LONGINT; VAR res: LONGINT);
  171. VAR n: LONGINT;
  172. BEGIN
  173. IF uart.open THEN res := UartMin.PortInUse; RETURN; END;
  174. UartMin.Reset(uart.regs);
  175. IF ~UartMin.SetBps(uart.regs, bps, res) OR
  176. ~UartMin.SetDataBits(uart.regs, data, res) OR
  177. ~UartMin.SetParity(uart.regs, parity, res) OR
  178. ~UartMin.SetStopBits(uart.regs, stop, res) THEN RETURN;
  179. END;
  180. uart.bps := bps;
  181. uart.data := data;
  182. uart.parity := parity;
  183. uart.stop := stop;
  184. uart.rxBufWrPos := 0;
  185. uart.rxBufRdPos := 0;
  186. uart.txBufWrPos := 0;
  187. uart.txBufRdPos := 0;
  188. (* configure receive timeout to be as close as possible to ReceiveTimeoutInUs *)
  189. n := ENTIER((ReceiveTimeoutInUs*REAL(bps)+1000000) / 4000000 + 0.5);
  190. n := MAX(1,MIN(255,n-1));
  191. TRACE(n);
  192. uart.regs.rxtout := n;
  193. uart.regs.cr := uart.regs.cr + {UartMin.XUARTPS_CR_TORST}; (* restart receive timeout counter *)
  194. uart.regs.rxwm := 32; (* RX FIFO triggering threshold *)
  195. uart.regs.txwm := 32; (* TX FIFO triggering threshold *)
  196. uart.regs.ier := (RxDataInterrupts+RxErrorInterrupts+TxErrorInterrupts);
  197. UartMin.Enable(uart.regs,TRUE);
  198. res := 0;
  199. uart.open := TRUE;
  200. END Open;
  201. (**
  202. Close a UART controller
  203. uart: UART controller
  204. *)
  205. PROCEDURE Close*(uart: UartController);
  206. BEGIN
  207. uart.open := FALSE;
  208. DisableInterrupts(uart.regs);
  209. UartMin.Enable(uart.regs,FALSE);
  210. END Close;
  211. PROCEDURE OccupiedBufSpace(bufWrPos, bufRdPos, bufSize: LONGINT): LONGINT;
  212. VAR n: LONGINT;
  213. BEGIN
  214. n := bufWrPos - bufRdPos;
  215. IF n >= 0 THEN
  216. RETURN n;
  217. ELSE
  218. RETURN n+bufSize;
  219. END;
  220. END OccupiedBufSpace;
  221. (* Returns the amount of available free space in a cyclic buffer *)
  222. PROCEDURE AvailableBufSpace(bufWrPos, bufRdPos, bufSize: LONGINT): LONGINT;
  223. VAR n: LONGINT;
  224. BEGIN
  225. n := bufWrPos - bufRdPos;
  226. IF n >= 0 THEN
  227. RETURN bufSize-1-n;
  228. ELSE
  229. RETURN -n-1;
  230. END;
  231. END AvailableBufSpace;
  232. (**
  233. Returns number of bytes available in the receive buffer of a UART controller
  234. uart: UART controller
  235. res: error code, 0 in case of success
  236. *)
  237. PROCEDURE Available*(uart: UartController): LONGINT;
  238. BEGIN
  239. RETURN OccupiedBufSpace(uart.rxBufWrPos,uart.rxBufRdPos,LEN(uart.rxBuf));
  240. END Available;
  241. (**
  242. Send a single character to the UART
  243. ch: character to send
  244. propagate: TRUE for flushing the TX FIFO buffer
  245. res: error code, 0 in case of success
  246. *)
  247. PROCEDURE SendChar*(uart: UartController; ch: CHAR; propagate: BOOLEAN; onBusy: UartMin.BusyLoopCallback; VAR res: LONGINT);
  248. BEGIN
  249. (*! for the moment just write directly to the FIFO *)
  250. res := 0;
  251. WHILE uart.open DO
  252. IF ~(UartMin.XUARTPS_SR_TNFUL IN uart.regs.sr) THEN
  253. uart.regs.fifo := ORD(ch); RETURN;
  254. END;
  255. END;
  256. res := UartMin.Closed;
  257. (*TYPE ArrayOfChar1 = ARRAY 1 OF CHAR;
  258. BEGIN
  259. (*!TODO: do not use interrupts here to avoid problems when SendChar is used for trace output *)
  260. Send(uart, SYSTEM.VAL(ArrayOfChar1,ch), 0, 1, propagate, onBusy, res);*)
  261. END SendChar;
  262. (**
  263. Send data to the UART
  264. *)
  265. PROCEDURE Send*(uart: UartController; CONST buf: ARRAY OF CHAR; offs, len: LONGINT; propagate: BOOLEAN; onBusy: UartMin.BusyLoopCallback; VAR res: LONGINT);
  266. VAR
  267. bufWrPos, n: LONGINT;
  268. BEGIN
  269. IF ~uart.open THEN res := UartMin.Closed; RETURN; END;
  270. WHILE uart.open & (len > 0) DO
  271. bufWrPos := uart.txBufWrPos;
  272. n := AvailableBufSpace(bufWrPos,uart.txBufWrPos,LEN(uart.txBuf));
  273. IF n # 0 THEN
  274. n := MIN(n,len);
  275. DEC(len,n);
  276. WHILE n > 0 DO
  277. uart.txBuf[bufWrPos] := buf[offs];
  278. INC(bufWrPos);
  279. IF bufWrPos = LEN(uart.txBuf) THEN
  280. bufWrPos := 0;
  281. END;
  282. INC(offs); DEC(n);
  283. END;
  284. uart.txBufWrPos := bufWrPos;
  285. (* enable TX interrupts *)
  286. uart.regs.ier := uart.regs.ier + TxDataInterrupts;
  287. ELSE
  288. (* enable TX interrupts *)
  289. uart.regs.ier := uart.regs.ier + TxDataInterrupts;
  290. IF (onBusy # NIL) & ~onBusy(res) THEN RETURN; END;
  291. END;
  292. END;
  293. IF propagate THEN
  294. (* flush the buffer *)
  295. WHILE uart.open & (uart.txBufRdPos # uart.txBufWrPos) DO
  296. IF (onBusy # NIL) & ~onBusy(res) THEN RETURN; END;
  297. END;
  298. (* flush the FIFO *)
  299. WHILE uart.open & ~(UartMin.XUARTPS_SR_TXEMPTY IN uart.regs.sr) DO
  300. IF (onBusy # NIL) & ~onBusy(res) THEN RETURN; END;
  301. END;
  302. END;
  303. IF uart.open THEN
  304. res := 0;
  305. ELSE
  306. IF OverrunError IN uart.errors THEN res := OverrunError;
  307. ELSE res := UartMin.Closed;
  308. END;
  309. END;
  310. (* BEGIN
  311. WHILE uart.open & (len > 0) DO
  312. IF ~(UartMin.XUARTPS_SR_TNFUL IN uart.regs.sr) THEN
  313. uart.regs.fifo := ORD(buf[offs]);
  314. INC(offs); DEC(len);
  315. ELSIF (onBusy # NIL) & ~onBusy(res) THEN
  316. RETURN;
  317. END;
  318. END;
  319. IF propagate THEN (* flush the FIFO *)
  320. WHILE uart.open & ~(UartMin.XUARTPS_SR_TXEMPTY IN uart.regs.sr) DO
  321. IF (onBusy # NIL) & ~onBusy(res) THEN RETURN; END;
  322. END;
  323. END;
  324. IF uart.open THEN
  325. res := UartMin.Ok;
  326. ELSE
  327. res := UartMin.Closed;
  328. END;*)
  329. END Send;
  330. (**
  331. Receive a single character from UART
  332. res: error code, 0 in case of success
  333. Remarks: blocks until a character is available
  334. *)
  335. PROCEDURE ReceiveChar*(uart: UartController; onBusy: UartMin.BusyLoopCallback; VAR res: LONGINT): CHAR;
  336. VAR
  337. buf: ARRAY 1 OF CHAR;
  338. len: LONGINT;
  339. BEGIN
  340. Receive(uart,buf,0,1,1,len,onBusy,res);
  341. RETURN buf[0];
  342. END ReceiveChar;
  343. (**
  344. Receive data from the UART
  345. *)
  346. PROCEDURE Receive*(uart: UartController; VAR buf: ARRAY OF CHAR; offs, size, min: LONGINT; VAR len: LONGINT; onBusy: UartMin.BusyLoopCallback; VAR res: LONGINT);
  347. VAR
  348. bufRdPos, n: LONGINT;
  349. BEGIN
  350. IF ~uart.open THEN res := UartMin.Closed; RETURN; END;
  351. res := 0;
  352. len := 0;
  353. IF size = 0 THEN RETURN; END;
  354. min := MIN(size,min);
  355. WHILE uart.open & (size > 0) DO
  356. bufRdPos := uart.rxBufRdPos;
  357. n := OccupiedBufSpace(uart.rxBufWrPos,bufRdPos,LEN(uart.rxBuf));
  358. IF n # 0 THEN
  359. n := MIN(n,size);
  360. DEC(size,n); INC(len,n);
  361. IF min > 0 THEN DEC(min,n); END;
  362. WHILE n > 0 DO
  363. buf[offs] := uart.rxBuf[bufRdPos];
  364. INC(bufRdPos);
  365. IF bufRdPos = LEN(uart.rxBuf) THEN
  366. bufRdPos := 0;
  367. END;
  368. INC(offs); DEC(n);
  369. END;
  370. uart.rxBufRdPos := bufRdPos;
  371. ELSIF min > 0 THEN
  372. IF (onBusy # NIL) & ~onBusy(res) THEN RETURN; END;
  373. ELSE
  374. RETURN;
  375. END;
  376. END;
  377. (*BEGIN
  378. res := Ok;
  379. len := 0;
  380. IF size = 0 THEN RETURN; END;
  381. min := MIN(size,min);
  382. WHILE uart.open & (~(UartMin.XUARTPS_SR_RXEMPTY IN uart.regs.sr) OR (min > 0)) DO
  383. IF ~(UartMin.XUARTPS_SR_RXEMPTY IN uart.regs.sr) THEN
  384. WHILE (size > 0) & ~(UartMin.XUARTPS_SR_RXEMPTY IN uart.regs.sr) DO
  385. buf[offs] := uart.regs.fifo;
  386. DEC(min); DEC(size); INC(offs); INC(len);
  387. END;
  388. ELSIF (onBusy # NIL) & ~onBusy(res) THEN
  389. RETURN;
  390. END;
  391. END;
  392. IF ~uart.open THEN
  393. res := Closed;
  394. END;*)
  395. END Receive;
  396. PROCEDURE PrintRegisters(regs: UartMin.UartRegisters);
  397. BEGIN
  398. Trace.String("cr("); Trace.Hex(ADDRESSOF(regs.cr),-8); Trace.String("): "); Trace.Set(regs.cr); Trace.Ln;
  399. Trace.String("mr("); Trace.Hex(ADDRESSOF(regs.mr),-8); Trace.String("): "); Trace.Set(regs.mr); Trace.Ln;
  400. Trace.String("ier("); Trace.Hex(ADDRESSOF(regs.ier),-8); Trace.String("): write only"); Trace.Ln;
  401. Trace.String("idr("); Trace.Hex(ADDRESSOF(regs.idr),-8); Trace.String("): write only"); Trace.Ln;
  402. Trace.String("imr("); Trace.Hex(ADDRESSOF(regs.imr),-8); Trace.String("): "); Trace.Set(regs.imr); Trace.Ln;
  403. Trace.String("isr("); Trace.Hex(ADDRESSOF(regs.isr),-8); Trace.String("): "); Trace.Set(regs.isr); Trace.Ln;
  404. Trace.String("baudgen("); Trace.Hex(ADDRESSOF(regs.baudgen),-8); Trace.String("): "); Trace.Int(regs.baudgen,0); Trace.Ln;
  405. Trace.String("rxtout("); Trace.Hex(ADDRESSOF(regs.rxtout),-8); Trace.String("): "); Trace.Int(regs.rxtout,0); Trace.Ln;
  406. Trace.String("rxwm("); Trace.Hex(ADDRESSOF(regs.rxwm),-8); Trace.String("): "); Trace.Int(regs.rxwm,0); Trace.Ln;
  407. Trace.String("modemcr("); Trace.Hex(ADDRESSOF(regs.modemcr),-8); Trace.String("): "); Trace.Set(regs.modemcr); Trace.Ln;
  408. Trace.String("modemsr("); Trace.Hex(ADDRESSOF(regs.modemsr),-8); Trace.String("): "); Trace.Set(regs.modemsr); Trace.Ln;
  409. Trace.String("sr("); Trace.Hex(ADDRESSOF(regs.sr),-8); Trace.String("): "); Trace.Set(regs.sr); Trace.Ln;
  410. Trace.String("fifo("); Trace.Hex(ADDRESSOF(regs.fifo),-8); Trace.String("): --- "); Trace.Ln;
  411. Trace.String("bauddiv("); Trace.Hex(ADDRESSOF(regs.bauddiv),-8); Trace.String("): "); Trace.Int(regs.bauddiv,0); Trace.Ln;
  412. Trace.String("flowdel("); Trace.Hex(ADDRESSOF(regs.flowdel),-8); Trace.String("): "); Trace.Int(regs.flowdel,0); Trace.Ln;
  413. Trace.String("txwm("); Trace.Hex(ADDRESSOF(regs.txwm),-8); Trace.String("): "); Trace.Int(regs.txwm,0); Trace.Ln;
  414. END PrintRegisters;
  415. PROCEDURE Show*;
  416. BEGIN
  417. IF uarts[0] # NIL THEN
  418. Trace.StringLn("PS UART0:");
  419. PrintRegisters(uarts[0].regs);
  420. Trace.String("rxBufRdPos="); Trace.Int(uarts[0].rxBufRdPos,0); Trace.Ln;
  421. Trace.String("rxBufWrPos="); Trace.Int(uarts[0].rxBufWrPos,0); Trace.Ln;
  422. Trace.String("txBufRdPos="); Trace.Int(uarts[0].txBufRdPos,0); Trace.Ln;
  423. Trace.String("txBufWrPos="); Trace.Int(uarts[0].txBufWrPos,0); Trace.Ln;
  424. Trace.Ln;
  425. END;
  426. IF uarts[1] # NIL THEN
  427. Trace.StringLn("PS UART1:");
  428. PrintRegisters(uarts[1].regs);
  429. Trace.String("rxBufRdPos="); Trace.Int(uarts[1].rxBufRdPos,0); Trace.Ln;
  430. Trace.String("rxBufWrPos="); Trace.Int(uarts[1].rxBufWrPos,0); Trace.Ln;
  431. Trace.String("txBufRdPos="); Trace.Int(uarts[1].txBufRdPos,0); Trace.Ln;
  432. Trace.String("txBufWrPos="); Trace.Int(uarts[1].txBufWrPos,0); Trace.Ln;
  433. Trace.Ln;
  434. END;
  435. END Show;
  436. END PsUart.