-
Notifications
You must be signed in to change notification settings - Fork 0
/
UARTkstr.mod
123 lines (112 loc) · 3.28 KB
/
UARTkstr.mod
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
MODULE UARTkstr;
(**
Oberon RTK Framework
--
UART string device driver for kernel use
--
* string IO procedures
* hw-buffered (fifo)
--
Copyright (c) 2020-2024 Gray, gray@grayraven.org
https://oberon-rtk.org/licences/
**)
IMPORT SYSTEM, UARTdev, TextIO, Kernel (*, GPIO, LED *);
PROCEDURE PutString*(dev: TextIO.Device; s: ARRAY OF CHAR; numChar: INTEGER);
VAR dev0: UARTdev.Device; i: INTEGER;
BEGIN
dev0 := dev(UARTdev.Device);
IF numChar > LEN(s) THEN numChar := LEN(s) END;
i := 0;
WHILE i < numChar DO
IF ~SYSTEM.BIT(dev0.FR, UARTdev.FR_TXFF) THEN (* not full *)
SYSTEM.PUT(dev0.TDR, s[i]);
INC(i)
ELSE
Kernel.AwaitDeviceFlags(dev0.FR, {UARTdev.FR_TXFE}, {})
END
END
END PutString;
PROCEDURE GetChar*(dev: TextIO.Device; VAR ch: CHAR);
VAR dev0: UARTdev.Device;
BEGIN
dev0 := dev(UARTdev.Device);
IF SYSTEM.BIT(dev0.FR, UARTdev.FR_RXFE) THEN
(* debug/test
GPIO.Clear({20}); (* for oscilloscope on pin 20 *)
*)
Kernel.AwaitDeviceFlags(dev0.FR, {}, {UARTdev.FR_RXFE});
(* debug/test
ASSERT(Kernel.Trigger() = Kernel.TrigDevice);
GPIO.Set({20})
*)
END;
SYSTEM.GET(dev0.RDR, ch)
END GetChar;
PROCEDURE checkFifoOverrun(dev0: UARTdev.Device; VAR overrun: BOOLEAN);
BEGIN
overrun := SYSTEM.BIT(dev0.RSR, UARTdev.RSR_OR)
END checkFifoOverrun;
PROCEDURE GetString*(dev: TextIO.Device; VAR s: ARRAY OF CHAR; VAR numCh, res: INTEGER);
CONST FifoCapture = 30;
VAR dev0: UARTdev.Device; bufLimit, fifoLimit: INTEGER; ch: CHAR; overrun, done: BOOLEAN;
BEGIN
dev0 := dev(UARTdev.Device);
bufLimit := LEN(s) - 1; (* space for 0X *)
res := TextIO.NoError;
numCh := 0;
done := FALSE;
GetChar(dev, ch);
checkFifoOverrun(dev0, overrun);
WHILE ~overrun & ~done DO
done := (ch < " ") OR (numCh = bufLimit);
IF ~done THEN
s[numCh] := ch;
INC(numCh);
GetChar(dev, ch);
checkFifoOverrun(dev0, overrun)
END
END;
IF numCh = bufLimit THEN
res := TextIO.BufferOverflow
END;
(* capture the valid data in the fifo before the overrun *)
IF overrun & ~done THEN
res := TextIO.FifoOverrun;
fifoLimit := numCh + FifoCapture;
WHILE (ch >= " ") & (numCh < bufLimit) & (numCh < fifoLimit) DO
s[numCh] := ch;
INC(numCh);
GetChar(dev, ch)
END
END;
s[numCh] := 0X;
(* if buffer overflow or fifo overrun, ignore and flush the rest *)
(* we have no idea how many chars that are *)
IF ch >= " " THEN
REPEAT
(* read all incoming data until we have a timeout *)
Kernel.StartTimeout(10);
GetChar(dev0, ch)
UNTIL Kernel.Trigger() = Kernel.TrigDelay
END;
Kernel.CancelAwaitDeviceFlags;
SYSTEM.PUT(dev0.RSR, 0)
END GetString;
PROCEDURE DeviceStatus*(dev: TextIO.Device): SET;
(*
Mainly for getting fifo full/empty status, ie.
"TxAvail" and "RxAvail" extended for fifo
Bits as defined in UARTdev.
*)
VAR dev0: UARTdev.Device;
BEGIN
dev0 := dev(UARTdev.Device);
RETURN UARTdev.Flags(dev0)
END DeviceStatus;
BEGIN
(* debug/test with oscilloscope
GPIO.SetFunction(20, GPIO.Fsio);
GPIO.OutputEnable({20});
GPIO.Clear({20})
*)
END UARTkstr.