Win32.V24.Mod 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. MODULE V24; (** AUTHOR "fof"; PURPOSE "V24 (V24/RS-232 driver) for WinAos"; **)
  2. IMPORT Kernel32, KernelLog, Heaps, Kernel, Commands, Serials, Strings;
  3. CONST
  4. MaxPortNo = 32; (* Up to 8 serial ports supported *)
  5. (*
  6. TYPE
  7. DCB32 = RECORD (* DCB structure for Win32 *)
  8. DCBlength: LONGINT; (* sizeof(DCB) *)
  9. BaudRate: LONGINT; (* current baud rate*)
  10. flags: SET; (* bits in flags:
  11. DWORD fBinary: 1; (* binary mode, no EOF check *)
  12. DWORD fParity: 1; (* enable parity checking *)
  13. DWORD fOutxCtsFlow:1; (* CTS output flow control *)
  14. DWORD fOutxDsrFlow:1; (* DSR output flow control *)
  15. DWORD fDtrControl:2; (* DTR flow control type *)
  16. DWORD fDsrSensitivity:1; (* DSR sensitivity *)
  17. DWORD fTXContinueOnXoff:1; (* XOFF continues Tx *)
  18. DWORD fOutX: 1; (* XON/XOFF out flow control *)
  19. DWORD fInX: 1; (* XON/XOFF in flow control *)
  20. DWORD fErrorChar: 1; (* enable error replacement *)
  21. DWORD fNull: 1; (* enable null stripping *)
  22. DWORD fRtsControl:2; (* RTS flow control *)
  23. DWORD fAbortOnError:1; (* abort reads/writes on error *)
  24. DWORD fDummy2:17; (* reserved *) *)
  25. wReserved: INTEGER; (* not currently used *)
  26. XonLim: INTEGER; (* transmit XON threshold *)
  27. XoffLim: INTEGER; (* transmit XOFF threshold *)
  28. ByteSize: SHORTINT; (* number of bits/byte, 4-8 *)
  29. Parity: SHORTINT; (* 0-4=no,odd,even,mark,space *)
  30. StopBits: SHORTINT; (* 0, 1, 2 = 1, 1.5, 2 *)
  31. XonChar: CHAR; (* Tx and Rx XON character *)
  32. XoffChar: CHAR; (* Tx and Rx XOFF character *)
  33. ErrorChar: CHAR; (* error replacement character *)
  34. EofChar: CHAR; (* end of input character *)
  35. EvtChar: CHAR (* received event character *)
  36. END;
  37. COMMTIMEOUTS = RECORD (* COMMTIMEOUTS *)
  38. ReadInterval: LONGINT;
  39. ReadTotalMultiplier: LONGINT;
  40. ReadTotalConstant: LONGINT;
  41. WriteTotalMultiplier: LONGINT;
  42. WriteTotalConstant: LONGINT
  43. END;
  44. COMSTAT32 = RECORD (* COMSTAT for Win32 *)
  45. status: SET; (* fields in status:
  46. DWORD fCtsHold : 1; (* Tx waiting for CTS signal *)
  47. DWORD fDsrHold : 1; (* Tx waiting for DSR signal *)
  48. DWORD fRlsdHold : 1; (* Tx waiting for RLSD signal *)
  49. DWORD fXoffHold : 1; (* Tx waiting, XOFF char rec'd *)
  50. DWORD fXoffSent : 1; (* Tx waiting, XOFF char sent *)
  51. DWORD fEof : 1; (* EOF character sent *)
  52. DWORD fTxim : 1; (* character waiting for Tx *)
  53. DWORD fReserved : 25; (* reserved *) *)
  54. cbInQueue: LONGINT; (* bytes in input buffer *)
  55. cbOutQueue: LONGINT (* bytes in output buffer *)
  56. END;
  57. *)
  58. (* Handle = POINTER TO RECORD (Kernel32.Object)
  59. (*
  60. recBuf: ARRAY BufSize OF S.BYTE;
  61. recBufSize, recBufPos: LONGINT;
  62. *)
  63. port: LONGINT
  64. END;
  65. *)
  66. TYPE
  67. Port* = OBJECT (Serials.Port)
  68. VAR
  69. handle: Kernel32.HANDLE;
  70. portname: ARRAY 6 OF CHAR; (* Name COM1 to COM8 must terminate with a 0X *)
  71. timer : Kernel.Timer;
  72. rOverlapped, wOverlapped: Kernel32.Overlapped;
  73. PROCEDURE & Init*( port: LONGINT );
  74. VAR fn: Heaps.FinalizerNode;
  75. BEGIN
  76. NEW(timer);
  77. COPY( "COM ", portname );
  78. IF port < 10 THEN
  79. portname[3] := CHR( ORD( "0" ) + port );
  80. portname[4]:= 0X;
  81. ELSE
  82. portname[3] := CHR( ORD( "0" ) + (port DIV 10) );
  83. portname[4] := CHR( ORD( "0" ) + (port MOD 10) );
  84. portname[5] := 0X;
  85. END;
  86. handle := Kernel32.InvalidHandleValue;
  87. NEW( fn ); fn.finalizer := SELF.FinalizePort; Heaps.AddFinalizer( SELF, fn );
  88. END Init;
  89. PROCEDURE Open*( bps, data, parity, stop: LONGINT; VAR res: LONGINT );
  90. BEGIN {EXCLUSIVE}
  91. IF handle = Kernel32.InvalidHandleValue THEN
  92. SetPortState( bps, data, parity, stop, res );
  93. IF res = Serials.Ok THEN
  94. rOverlapped.hEvent := Kernel32.CreateEvent(NIL,Kernel32.True,Kernel32.False,NIL);
  95. ASSERT(rOverlapped.hEvent # NIL);
  96. wOverlapped.hEvent := Kernel32.CreateEvent(NIL,Kernel32.True,Kernel32.False,NIL);
  97. ASSERT(wOverlapped.hEvent # NIL);
  98. KernelLog.String( portname ); KernelLog.String( " opened" ); KernelLog.Ln
  99. END;
  100. ELSE
  101. res := Serials.PortInUse;
  102. END;
  103. END Open;
  104. (** Send len characters from buf to output, starting at ofs. res is non-zero on error. *)
  105. PROCEDURE Send*( CONST buf: ARRAY OF CHAR; ofs, len: LONGINT; propagate: BOOLEAN; VAR res: LONGINT );
  106. VAR written: LONGINT; ret: Kernel32.BOOL;
  107. BEGIN
  108. ASSERT ( LEN( buf ) >= ofs + len ); (* array bound check not implemented in Kernel32.WriteFile *)
  109. IF (handle # Kernel32.InvalidHandleValue) THEN
  110. written := 0;
  111. ret := Kernel32.WriteFile( handle, buf[ofs], len, written, wOverlapped );
  112. IF ret = Kernel32.False THEN
  113. ret := Kernel32.GetOverlappedResult(handle,wOverlapped,written,Kernel32.True);
  114. END;
  115. INC(charactersSent,written);
  116. IF (ret # Kernel32.False) & (written = len) THEN
  117. res := Serials.Ok;
  118. ELSE
  119. res := Serials.TransportError;
  120. END;
  121. ELSE
  122. res := Serials.Closed;
  123. END
  124. END Send;
  125. (** Send a single character to the UART. *)
  126. PROCEDURE SendChar*( ch: CHAR; VAR res: LONGINT );
  127. VAR ret: Kernel32.BOOL; written: LONGINT;
  128. BEGIN
  129. IF handle # Kernel32.InvalidHandleValue THEN
  130. written := 0;
  131. ret := Kernel32.WriteFile( handle, ch, 1, written, wOverlapped );
  132. IF ret = Kernel32.False THEN
  133. ret := Kernel32.GetOverlappedResult(handle,wOverlapped,written,Kernel32.True);
  134. END;
  135. INC(charactersSent,written);
  136. IF (ret # Kernel32.False) & (written=1) THEN
  137. res := Serials.Ok;
  138. ELSE
  139. res := Serials.TransportError;
  140. END;
  141. ELSE
  142. res := Serials.Closed;
  143. END
  144. END SendChar;
  145. (** Receive size characters into buf, starting at ofs and return the effective number of bytes read in len.
  146. Wait until at least min bytes (possibly zero) are available.
  147. res is non-zero on error. *)
  148. PROCEDURE Receive*( VAR buf: ARRAY OF CHAR; ofs, size, min: LONGINT; VAR len, res: LONGINT );
  149. VAR i, l, read, ret: LONGINT;
  150. BEGIN
  151. ASSERT ( LEN( buf ) >= ofs + size );
  152. ASSERT ( LEN( buf ) >= ofs + min ); (* array bound check not implemented in Kernel32.ReadFile *)
  153. IF handle # Kernel32.InvalidHandleValue THEN
  154. res := Serials.Ok; len := 0;
  155. (* blocking read of the minimally required amount of data *)
  156. IF min > 0 THEN
  157. read := 0;
  158. ret := Kernel32.ReadFile( handle, buf[ofs], min, read, rOverlapped );
  159. IF ret = Kernel32.False THEN
  160. ret := Kernel32.GetOverlappedResult(handle,rOverlapped,read,Kernel32.True);
  161. END;
  162. INC(ofs,read); INC(len,read); INC(charactersReceived,read); DEC(size,read);
  163. IF ret = Kernel32.False THEN
  164. res := Serials.TransportError; RETURN;
  165. END;
  166. END;
  167. (* Non-blocking read of available data *)
  168. l := MIN(size,Available());
  169. IF l > 0 THEN
  170. read := 0;
  171. ret := Kernel32.ReadFile( handle, buf[ofs], l, read, rOverlapped );
  172. IF ret = Kernel32.False THEN
  173. ret := Kernel32.GetOverlappedResult(handle,rOverlapped,read,Kernel32.True);
  174. END;
  175. INC(len,read); INC(charactersReceived,read);
  176. IF ret = Kernel32.False THEN (* we've already received <min> bytes, but there was an error and we are going to report it anyway! *)
  177. res := Serials.TransportError;
  178. END;
  179. END;
  180. ELSE
  181. res := Serials.Closed;
  182. END;
  183. END Receive;
  184. (** Wait for the next character is received in the input buffer. *)
  185. PROCEDURE ReceiveChar*( VAR ch: CHAR; VAR res: LONGINT );
  186. VAR l, ret, read: LONGINT;
  187. BEGIN
  188. IF handle # Kernel32.InvalidHandleValue THEN
  189. read := 0;
  190. ret := Kernel32.ReadFile( handle, ch, 1, read, rOverlapped );
  191. IF ret = Kernel32.False THEN
  192. ret := Kernel32.GetOverlappedResult(handle,rOverlapped,read,Kernel32.True);
  193. END;
  194. INC(charactersReceived,read);
  195. IF (ret # Kernel32.False) & (read = 1) THEN
  196. res := Serials.Ok;
  197. ELSE
  198. res := Serials.TransportError;
  199. END;
  200. ELSE
  201. res := Serials.Closed;
  202. END
  203. END ReceiveChar;
  204. PROCEDURE Available*( ): LONGINT;
  205. VAR errors: Kernel32.DWORD; stat: Kernel32.ComStat; res: Kernel32.BOOL;
  206. BEGIN
  207. IF handle # Kernel32.InvalidHandleValue THEN
  208. res := Kernel32.ClearCommError( handle, errors, stat );
  209. IF res # Kernel32.False THEN RETURN stat.cbInQue END
  210. END;
  211. RETURN 0
  212. END Available;
  213. (** Open a serial port (numbered from 0) connection. bps is the required bits per second.
  214. data is the number of bits per communication unit. parity is the parity mode.
  215. stop is the number of stop bits.
  216. res: Ok, PortInUse, NoSuchPort, WrongBPS, WrongData, WrongParity, WrongStop, Failed *)
  217. PROCEDURE SetPortState( bps, data, parity, stop: LONGINT; VAR res: LONGINT );
  218. VAR
  219. hFile: Kernel32.HANDLE; dcb: Kernel32.DCB;
  220. ret: Kernel32.BOOL; err: LONGINT;
  221. windowsComName: ARRAY 16 OF CHAR;
  222. BEGIN
  223. res := Serials.Ok;
  224. windowsComName := "\\.\";
  225. Strings.Append(windowsComName, portname);
  226. hFile := Kernel32.CreateFile( windowsComName,
  227. Kernel32.SetToDW({Kernel32.GenericRead, Kernel32.GenericWrite}), Kernel32.SetToDW({}),
  228. NIL , Kernel32.OpenExisting, Kernel32.SetToDW({}), Kernel32.NULL );
  229. IF hFile # Kernel32.InvalidHandleValue THEN
  230. ret := Kernel32.GetCommState( hFile, dcb );
  231. IF ret # Kernel32.False THEN
  232. dcb.BaudRate := bps;
  233. IF (data >= 4) & (data <= 8) THEN dcb.ByteSize := CHR( data )
  234. ELSE res := Serials.WrongData
  235. END;
  236. CASE stop OF
  237. | Serials.Stop1:
  238. dcb.StopBits := Kernel32.OneStopBit
  239. | Serials.Stop1dot5:
  240. dcb.StopBits := Kernel32.One5StopBits
  241. | Serials.Stop2:
  242. dcb.StopBits := Kernel32.TwoStopBits
  243. ELSE
  244. res := Serials.WrongStop
  245. END;
  246. CASE parity OF
  247. | Serials.ParNo:
  248. dcb.Parity := Kernel32.NoParity
  249. | Serials.ParOdd:
  250. dcb.Parity := Kernel32.OddParity
  251. | Serials.ParEven:
  252. dcb.Parity := Kernel32.EvenParity
  253. | Serials.ParMark:
  254. dcb.Parity := Kernel32.MarkParity
  255. | Serials.ParSpace:
  256. dcb.Parity := Kernel32.SpaceParity
  257. ELSE
  258. res := Serials.WrongParity
  259. END;
  260. IF res = Serials.Ok THEN
  261. ret := Kernel32.SetCommState( hFile, dcb );
  262. IF ret # Kernel32.False THEN
  263. ret := Kernel32.PurgeComm( hFile, Kernel32.SetToDW({Kernel32.PurgeTXClear, Kernel32.PurgeRXClear}) );
  264. ret := Kernel32.SetupComm( hFile, 800H, 800H );
  265. handle := hFile;
  266. RETURN
  267. END
  268. END
  269. END;
  270. ret := Kernel32.CloseHandle( hFile )
  271. END;
  272. IF res = Serials.Ok THEN
  273. err := Kernel32.GetLastError();
  274. CASE err OF
  275. Kernel32.ErrorFileNotFound:
  276. res := Serials.NoSuchPort
  277. | Kernel32.ErrorAccessDenied:
  278. res := Serials.PortInUse
  279. | Kernel32.ErrorInvalidParameter:
  280. res := Serials.WrongBPS
  281. ELSE res := Serials.TransportError
  282. END
  283. END
  284. END SetPortState;
  285. PROCEDURE FinalizePort( ptr: ANY );
  286. BEGIN
  287. Close();
  288. END FinalizePort;
  289. (** Get the port state: speed, no. of data bits, parity, no. of stop bits (only valid if openstat is TRUE) *)
  290. PROCEDURE GetPortState*( VAR openstat: BOOLEAN; VAR bps, data, parity, stop: LONGINT );
  291. VAR dcb: Kernel32.DCB; ret: Kernel32.BOOL;
  292. BEGIN {EXCLUSIVE}
  293. openstat := FALSE;
  294. IF handle # Kernel32.InvalidHandleValue THEN
  295. ret := Kernel32.GetCommState(handle, dcb );
  296. IF ret # Kernel32.False THEN
  297. openstat := TRUE;
  298. bps := dcb.BaudRate;
  299. data := ORD(dcb.ByteSize);
  300. CASE dcb.StopBits OF
  301. |Kernel32.OneStopBit: stop := Serials.Stop1;
  302. |Kernel32.One5StopBits: stop := Serials.Stop1dot5;
  303. |Kernel32.TwoStopBits: stop := Serials.Stop2;
  304. ELSE
  305. KernelLog.String("Win32.V24.GetPortState: Wrong stops bits"); KernelLog.Ln;
  306. END;
  307. CASE dcb.Parity OF
  308. |Kernel32.NoParity: parity := Serials.ParNo;
  309. |Kernel32.OddParity: parity := Serials.ParOdd;
  310. |Kernel32.EvenParity: parity := Serials.ParEven;
  311. |Kernel32.MarkParity: parity := Serials.ParMark;
  312. |Kernel32.SpaceParity: parity := Serials.ParSpace;
  313. ELSE
  314. KernelLog.String("Win32.V24.GetPortState: Wrong parity mode"); KernelLog.Ln;
  315. END;
  316. END;
  317. END;
  318. END GetPortState;
  319. (** ClearMC - Clear the specified modem control lines. s may contain DTR, RTS & Break. *)
  320. PROCEDURE ClearMC*( s: SET );
  321. BEGIN {EXCLUSIVE}
  322. IF (handle # Kernel32.InvalidHandleValue) THEN
  323. IF Serials.Break IN s THEN Kernel32.ClearCommBreak( handle ) END;
  324. IF Serials.DTR IN s THEN Kernel32.EscapeCommFunction( handle, Kernel32.CLRDTR ) END;
  325. IF Serials.RTS IN s THEN Kernel32.EscapeCommFunction( handle, Kernel32.CLRRTS ) END
  326. END
  327. END ClearMC;
  328. (** SetMC - Set the specified modem control lines. s may contain DTR, RTS & Break. *)
  329. PROCEDURE SetMC*( s: SET );
  330. VAR res: LONGINT;
  331. BEGIN {EXCLUSIVE}
  332. IF handle # Kernel32.InvalidHandleValue THEN
  333. IF Serials.Break IN s THEN res := Kernel32.SetCommBreak( handle ) END;
  334. IF Serials.DTR IN s THEN
  335. res := Kernel32.EscapeCommFunction( handle, Kernel32.SETDTR )
  336. END;
  337. IF Serials.RTS IN s THEN
  338. res := Kernel32.EscapeCommFunction( handle, Kernel32.SETRTS )
  339. END
  340. END
  341. END SetMC;
  342. (** GetMC - Return the state of the specified modem control lines. s contains
  343. the current state of DSR, CTS, RI, DCD & Break Interrupt. *)
  344. PROCEDURE GetMC*( VAR s: SET );
  345. VAR state: Kernel32.DWORD; res: LONGINT;
  346. BEGIN {EXCLUSIVE}
  347. s := {};
  348. IF handle # Kernel32.InvalidHandleValue THEN
  349. res := Kernel32.GetCommModemStatus( handle, state );
  350. IF Kernel32.MSCTSOn IN Kernel32.DWToSet(state) THEN INCL( s, Serials.CTS ) END;
  351. IF Kernel32.MSDSROn IN Kernel32.DWToSet(state) THEN INCL( s, Serials.DSR ) END;
  352. IF Kernel32.MSRingOn IN Kernel32.DWToSet(state) THEN INCL( s, Serials.RI ) END;
  353. IF Kernel32.MSRLSDOn IN Kernel32.DWToSet(state) THEN INCL( s, Serials.DCD ) END
  354. END
  355. END GetMC;
  356. PROCEDURE Wait;
  357. BEGIN {EXCLUSIVE}
  358. timer.Sleep(1);
  359. END Wait;
  360. PROCEDURE Close*;
  361. BEGIN {EXCLUSIVE}
  362. IF handle # Kernel32.InvalidHandleValue THEN
  363. Kernel32.CancelIoEx(handle, NIL);
  364. Kernel32.CloseHandle( handle ); handle := Kernel32.InvalidHandleValue;
  365. IF rOverlapped.hEvent # NIL THEN Kernel32.CloseHandle(rOverlapped.hEvent); rOverlapped.hEvent := NIL; END;
  366. IF wOverlapped.hEvent # NIL THEN Kernel32.CloseHandle(wOverlapped.hEvent); wOverlapped.hEvent := NIL; END;
  367. END
  368. END Close;
  369. END Port;
  370. (** Scan the installed serial ports *)
  371. PROCEDURE Scan*(context : Commands.Context);
  372. VAR i, ret: LONGINT; name,winname: ARRAY 256 OF CHAR;
  373. strNumber: ARRAY 4 OF CHAR; found: BOOLEAN;
  374. BEGIN
  375. context.out.String( "Serial port detection and inspection (WinAos):" ); context.out.Ln;
  376. found := FALSE;
  377. FOR i := 1 TO MaxPortNo DO
  378. COPY( "COM", name );
  379. Strings.IntToStr(i, strNumber);
  380. Strings.Append(name, strNumber);
  381. ret := Kernel32.QueryDosDevice( name, winname, LEN( name ) );
  382. IF ret # Kernel32.False THEN
  383. found := TRUE;
  384. context.out.String( name ); context.out.String( ":" );
  385. context.out.String( winname ); context.out.String( "." );
  386. context.out.Ln
  387. END;
  388. END;
  389. IF ~found THEN context.out.String("no ports found"); context.out.Ln END;
  390. END Scan;
  391. PROCEDURE Install*(context: Commands.Context);
  392. END Install;
  393. (** Create a port object for each windows COM port *)
  394. PROCEDURE Init*;
  395. VAR
  396. i, ret: LONGINT;
  397. name : ARRAY 8 OF CHAR;
  398. winname: ARRAY 256 OF CHAR;
  399. port: Port;
  400. strNumber: ARRAY 4 OF CHAR;
  401. serialsPort: Serials.Port;
  402. BEGIN
  403. FOR i := 1 TO MaxPortNo DO
  404. COPY( "COM", name );
  405. Strings.IntToStr(i, strNumber);
  406. Strings.Append(name, strNumber);
  407. ret := Kernel32.QueryDosDevice(name, winname, LEN( winname ) );
  408. IF ret # 0 THEN
  409. serialsPort := Serials.GetPort(i);
  410. IF (serialsPort = NIL) OR (serialsPort.description # winname) THEN
  411. IF serialsPort # NIL THEN Serials.UnRegisterPort(serialsPort) END;
  412. NEW(port, i);
  413. Serials.RegisterOnboardPort( i , port, name, winname );
  414. END;
  415. END;
  416. END;
  417. END Init;
  418. BEGIN
  419. Init();
  420. END V24.
  421. V24.Install ~
  422. V24.Scan ~
  423. SystemTools.Free V24 ~
  424. Serials.Show ~
  425. SystemTools.Free Serials ~