source: 2.19_branch/Sibyl/RTL/SERIALIO.PAS@ 376

Last change on this file since 376 was 8, checked in by RBRi, 19 years ago

+ rest of sibyl stuff

  • Property svn:eol-style set to native
File size: 8.7 KB
Line 
1UNIT SerialIO;
2
3INTERFACE
4
5{**************************************************************************
6 * *
7 * Written for Speed Pascal/2 *
8 * Interface to Async communications under OS/2 *
9 * Author: Alex T. Vermeulen (a.vermeulen@ecn.nl, atverm@xs4all.nl)*
10 * Date: 17-4-95 *
11 **************************************************************************}
12
13
14
15TYPE
16 parityt = (par_none,par_odd,par_even,par_mark,par_space);
17
18
19
20FUNCTION initport (port_num:integer;
21 parity:parityt;
22 databits,stopbits:byte;
23 RTS_CTS,XON_XOFF:BOOLEAN):INTEGER;
24
25{ This function initializes the com buffer, setting up the interrupt,
26 and com parameters, returns 0 ik ok else an error number}
27
28
29PROCEDURE closeport;
30
31{ This function closes the com port, removing the interrupt routine,
32 etc. }
33
34
35PROCEDURE outcomch (ch: char);
36
37{ This function outputs one character to the com port }
38
39
40FUNCTION peek1char:char;
41
42{ return next char in receive buffer, or 0 for none available }
43
44
45FUNCTION get1char:char;
46
47{ This function returns one character from the com port, or a zero if
48 no character is waiting }
49
50
51
52FUNCTION comhit:boolean;
53
54{ This returns a value telling if there is a character waiting in the com
55 buffer. }
56
57
58PROCEDURE dump;
59
60{ This function clears the com buffer }
61
62
63PROCEDURE set_baud (baud:longint);
64
65{ This function sets the com speed to that passed }
66
67
68PROCEDURE setdtr(i:boolean);
69
70{ This function sets the DTR pin to the status given }
71
72
73PROCEDURE setrts(i:boolean);
74
75{ This function sets the RTS pin to the status given }
76
77
78FUNCTION carrierdetect:boolean;
79
80{ This returns the status of the carrier detect lead from the modem }
81
82
83IMPLEMENTATION
84
85
86
87USES crt,bsedev,bsedos,os2def;
88
89
90
91CONST
92
93 BAUD_RATE : WORD =38400;
94 COMM_BUFFER_SIZE =16384;
95
96VAR
97 head, { index to the last char in buffer }
98 tail : INTEGER; { index to first char in buffer }
99 buffer : ARRAY [0..COMM_BUFFER_SIZE] OF CHAR; { incoming character buffer }
100 PortHandle : HFILE; { OS/2 file handle for COM port }
101 RecvThreadID : TID; { Thread ID of receive-character thread }
102
103{
104 * our receive-character thread; all it does is wait for a
105 * character to come in on the com port. when one does, it
106 * suspends the current process with DosEnterCritSec() and
107 * places the character in the buffer.
108 *
109 * Purists will note that using DosEnterCritSec() instead of
110 * semaphores is not "clean" or "true" multi-threading, but I chose
111 * this method because it gave the largest performance boost.
112}
113
114PROCEDURE async_isr (ulThreadArg:ULONG); CDECL;
115VAR
116 BytesRead : ULONG; { num. bytes read from last DosRead() call }
117 ch : CHAR; { char read in from last DosRead() call }
118 res : APIRET;
119BEGIN
120 { endless loop }
121 while true do
122 begin
123 { read character; this will block until a char is available }
124 res:=DosRead (PortHandle, ch, 1, BytesRead);
125
126 { if a character was actually read in... }
127 if (BytesRead=1) then
128 begin
129 { suspend all other processing }
130 DosEnterCritSec;
131
132 { put char in buffer and adjust indices }
133 buffer[head] := ch;
134 inc(head);
135 if (head = COMM_BUFFER_SIZE) then head := 0;
136
137 { release suspended processes }
138 DosExitCritSec;
139 end;
140 end;
141END;
142
143
144
145{ This function outputs one character to the com port }
146
147PROCEDURE outcomch (ch: char);
148
149VAR
150
151 rc : APIRET;
152 BytesWritten : ULONG; { unless but required parameter }
153BEGIN
154 rc:=DosWrite (PortHandle, ch, 1, BytesWritten);
155END;
156
157
158
159{ return next char in receive buffer, or 0 for none available }
160
161FUNCTION peek1char:char;
162begin
163 if head<>tail then peek1char:=buffer[tail]
164 else peek1char:=#0;
165end;
166
167
168
169{ This function returns one character from the com port, or a zero if
170
171 * no character is waiting }
172
173FUNCTION get1char:char;
174var
175 { temp var to hold char for returning if one is available }
176 c1 : char;
177begin
178 if (head <>tail) then
179 begin
180 c1 := buffer[tail];
181 inc(tail);
182 if (tail = COMM_BUFFER_SIZE) then tail := 0;
183 get1char:=c1;
184 end
185 else get1char:=#0;
186end;
187
188
189
190{ This returns a value telling if there is a character waiting in the com
191 * buffer.
192 }
193
194FUNCTION comhit:boolean;
195begin
196 comhit:=(head<>tail);
197end;
198
199
200
201{ This function clears the com buffer }
202PROCEDURE dump;
203begin
204 head:=0;tail:=0;
205end;
206
207
208
209CONST
210 ASYNC_EXTSETBAUDRATE = $43;
211
212
213
214{ This function sets the com speed to that passed }
215
216PROCEDURE set_baud (baud:longint);
217var
218 par : RECORD
219 rate : ULONG;
220 fraction : UCHAR;
221 END;
222
223 res : APIRET;
224begin
225 {
226 * OS/2 2.11+ standard COM drivers support up to 345600 bps !
227 }
228
229 par.rate:=baud;
230 par.fraction:=0;
231 if ((par.rate <= 345600) and (par.rate >= 10)) then
232 res:=DosDevIOCtl (PortHandle, IOCTL_ASYNC, ASYNC_EXTSETBAUDRATE,
233 par, sizeof (par), NIL, NIL, 0, NIL);
234end;
235
236
237
238{ This function sets the DTR pin to the status given }
239
240PROCEDURE setdtr(i:boolean);
241var
242 ms : MODEMSTATUS;
243 data : UINT;
244 res : APIRET;
245begin
246 ms.fbModemOn:=0;ms.fbModemOff:=0;
247
248 if i then ms.fbModemOn := DTR_ON
249 else ms.fbModemOff := DTR_OFF;
250
251 res:=DosDevIOCtl (PortHandle, IOCTL_ASYNC, ASYNC_SETMODEMCTRL, ms,
252 sizeof (ms), NIL, data, sizeof (data), NIL);
253end;
254
255
256{ This function sets the RTS pin to the status given }
257
258PROCEDURE setrts(i:boolean);
259var
260 ms : MODEMSTATUS;
261 data : UINT;
262 res : APIRET;
263begin
264 ms.fbModemOn:=0;ms.fbModemOff:=0;
265 if i then ms.fbModemOn := RTS_ON
266 else ms.fbModemOff := RTS_OFF;
267
268 res:=DosDevIOCtl (PortHandle, IOCTL_ASYNC, ASYNC_SETMODEMCTRL, ms,
269 sizeof (ms), NIL, data, sizeof (data), NIL);
270end;
271
272
273
274{ This function initializes the com buffer, setting up the interrupt,
275 * and com parameters }
276
277FUNCTION initport (port_num:integer;
278 parity:parityt;
279 databits,stopbits:byte;
280 RTS_CTS,XON_XOFF:BOOLEAN):integer;
281var
282 rc : APIRET;
283 action : ULONG;
284 lctl : LINECONTROL;
285 dcb : DCBINFO;
286 portname : Cstring;
287begin
288 { open com port }
289 initport:=0;
290
291 portname:= 'COM'+CHR(port_num + ORD('0'));
292
293 if DosOpen (portname, PortHandle, action, 0, 0, 1, $42, NIL)<>0 then
294 begin
295 initport:=1;
296 Exit;
297 end;
298
299 { set line }
300 lctl.bParity := ord(parity);
301 lctl.bDataBits := databits;
302 if stopbits=1 then lctl.bStopBits := 0 else lctl.bStopBits:=2;
303 lctl.fTransBreak := 0;
304 if DosDevIOCtl (PortHandle, IOCTL_ASYNC, ASYNC_SETLINECTRL,
305 lctl, sizeof (LINECONTROL), NIL, NIL, 0, NIL)<>0 then
306 begin
307 DosClose (PortHandle);
308 initport:=2;
309 exit;
310 end;
311
312 { set device control block info }
313 dcb.usWriteTimeout := 0;
314 dcb.usReadTimeout := 0;
315 dcb.fbCtlHndShake := MODE_DTR_CONTROL;
316
317 IF RTS_CTS THEN
318 BEGIN
319 dcb.fbFlowReplace := MODE_RTS_HANDSHAKE;
320 dcb.fbCtlHndShake := dcb.fbCtlHndShake + MODE_CTS_HANDSHAKE;
321 END
322 ELSE dcb.fbFlowReplace := MODE_RTS_CONTROL;
323
324 IF XON_XOFF THEN
325 dcb.fbFlowReplace := dcb.fbFlowReplace + MODE_AUTO_RECEIVE + MODE_AUTO_TRANSMIT;
326
327 dcb.fbTimeout := MODE_NO_WRITE_TIMEOUT + MODE_WAIT_READ_TIMEOUT;
328 dcb.bErrorReplacementChar := 0;
329 dcb.bBreakReplacementChar := 0;
330 dcb.bXONChar := $11;
331 dcb.bXOFFChar := $13;
332 if DosDevIOCtl (PortHandle, IOCTL_ASYNC, ASYNC_SETDCBINFO, dcb,
333 sizeof (DCBINFO), NIL, NIL, 0, NIL)<>0 then
334 begin
335 initport:=3;
336 DosClose (PortHandle);
337 exit;
338 end;
339
340 { indicate receive buffer is currently empty }
341
342 head :=0; tail := 0;
343
344 { spawn receive thread }
345 if DosCreateThread (RecvThreadID, @async_isr, NIL, 0, 4096)<>0 then
346 begin
347 initport:=4;
348 DosClose (PortHandle);
349 exit
350 end;
351
352 setdtr(true);
353end;
354
355
356
357{ This function closes out the com port, removing the interrupt routine,
358
359 * etc. }
360
361PROCEDURE closeport;
362begin
363 { kill receive thread and wait for it to close }
364 DosKillThread (RecvThreadID);
365
366 DosWaitThread (RecvThreadID, DCWW_WAIT);
367
368 { close COM port handle }
369 DosClose (PortHandle);
370end;
371
372
373
374{ This returns the status of the carrier detect lead from the modem }
375FUNCTION carrierdetect:boolean;
376var
377 instat : BYTE;
378begin
379 { if DosDevIOCtl() returns an error, return 0 }
380 if DosDevIOCtl (PortHandle, IOCTL_ASYNC, ASYNC_GETMODEMINPUT,
381 NIL, 0, NIL, instat, sizeof (instat), NIL)<>0 then
382 begin
383 carrierdetect:=false;
384 exit;
385 end;
386
387 { otherwise return carrier detect status }
388 carrierdetect:=(instat and DCD_ON)<>0;
389end;
390
391
392end.
393
394
Note: See TracBrowser for help on using the repository browser.