home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / sp15demo.zip / libsrc.zip / LIBSRC / SERIALIO.PAS < prev    next >
Pascal/Delphi Source File  |  1996-02-07  |  9KB  |  395 lines

  1. UNIT SerialIO;
  2.  
  3. INTERFACE
  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.  
  15. TYPE
  16.   parityt = (par_none,par_odd,par_even,par_mark,par_space);
  17.  
  18.  
  19.  
  20. FUNCTION 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.  
  29. PROCEDURE closeport;
  30.  
  31. { This function closes the com port, removing the interrupt routine,
  32.   etc. }
  33.  
  34.  
  35. PROCEDURE outcomch (ch: char);
  36.  
  37. { This function outputs one character to the com port }
  38.  
  39.  
  40. FUNCTION peek1char:char;
  41.  
  42. { return next char in receive buffer, or 0 for none available }
  43.  
  44.  
  45. FUNCTION 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.  
  52. FUNCTION comhit:boolean;
  53.  
  54. { This returns a value telling if there is a character waiting in the com
  55.    buffer. }
  56.  
  57.  
  58. PROCEDURE dump;
  59.  
  60. { This function clears the com buffer }
  61.  
  62.  
  63. PROCEDURE set_baud (baud:longint);
  64.  
  65. { This function sets the com speed to that passed }
  66.  
  67.  
  68. PROCEDURE setdtr(i:boolean);
  69.  
  70. { This function sets the DTR pin to the status given }
  71.  
  72.  
  73. PROCEDURE setrts(i:boolean);
  74.  
  75. { This function sets the RTS pin to the status given }
  76.  
  77.  
  78. FUNCTION carrierdetect:boolean;
  79.  
  80. { This returns the status of the carrier detect lead from the modem }
  81.  
  82.  
  83. IMPLEMENTATION
  84.  
  85.  
  86.  
  87. USES crt,bsedev,bsedos,os2def;
  88.  
  89.  
  90.  
  91. CONST
  92.  
  93.   BAUD_RATE : WORD =38400;
  94.   COMM_BUFFER_SIZE =16384;
  95.  
  96. VAR
  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.  
  114. PROCEDURE async_isr (ulThreadArg:ULONG);
  115. VAR
  116.   BytesRead : ULONG;                { num. bytes read from last DosRead() call }
  117.   ch        : CHAR;                 { char read in from last DosRead() call }
  118.   res       : APIRET;
  119. BEGIN
  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;
  141. END;
  142.  
  143.  
  144.  
  145. { This function outputs one character to the com port }
  146.  
  147. PROCEDURE outcomch (ch: char);
  148.  
  149. VAR
  150.  
  151.   rc : APIRET;
  152.   BytesWritten : ULONG;                { unless but required parameter }
  153. BEGIN
  154.   rc:=DosWrite (PortHandle, ch, 1, BytesWritten);
  155. END;
  156.  
  157.  
  158.  
  159. { return next char in receive buffer, or 0 for none available }
  160.  
  161. FUNCTION peek1char:char;
  162. begin
  163.   if head<>tail then peek1char:=buffer[tail]
  164.   else peek1char:=#0;
  165. end;
  166.  
  167.  
  168.  
  169. { This function returns one character from the com port, or a zero if
  170.  
  171.  * no character is waiting }
  172.  
  173. FUNCTION get1char:char;
  174. var
  175.   { temp var to hold char for returning if one is available }
  176.   c1 : char;
  177. begin
  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;
  186. end;
  187.  
  188.  
  189.  
  190. { This returns a value telling if there is a character waiting in the com
  191.  * buffer.
  192.  }
  193.  
  194. FUNCTION comhit:boolean;
  195. begin
  196.   comhit:=(head<>tail);
  197. end;
  198.  
  199.  
  200.  
  201. { This function clears the com buffer }
  202. PROCEDURE dump;
  203. begin
  204.   head:=0;tail:=0;
  205. end;
  206.  
  207.  
  208.  
  209. CONST
  210.   ASYNC_EXTSETBAUDRATE = $43;
  211.  
  212.  
  213.  
  214. { This function sets the com speed to that passed }
  215.  
  216. PROCEDURE set_baud (baud:longint);
  217. var
  218.   par : RECORD
  219.           rate     : ULONG;
  220.           fraction : UCHAR;
  221.         END;
  222.  
  223.   res : APIRET;
  224. begin
  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);
  234. end;
  235.  
  236.  
  237.  
  238. { This function sets the DTR pin to the status given }
  239.  
  240. PROCEDURE setdtr(i:boolean);
  241. var
  242.   ms   : MODEMSTATUS;
  243.   data : UINT;
  244.   res  : APIRET;
  245. begin
  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);
  253. end;
  254.  
  255.  
  256. { This function sets the RTS pin to the status given }
  257.  
  258. PROCEDURE setrts(i:boolean);
  259. var
  260.   ms    : MODEMSTATUS;
  261.   data  : UINT;
  262.   res   : APIRET;
  263. begin
  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);
  270. end;
  271.  
  272.  
  273.  
  274. { This function initializes the com buffer, setting up the interrupt,
  275.  * and com parameters }
  276.  
  277. FUNCTION initport (port_num:integer;
  278.                    parity:parityt;
  279.                    databits,stopbits:byte;
  280.                    RTS_CTS,XON_XOFF:BOOLEAN):integer;
  281. var
  282.   rc            : APIRET;
  283.   action        : ULONG;
  284.   lctl          : LINECONTROL;
  285.   dcb           : DCBINFO;
  286.   portname      : Cstring;
  287. begin
  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);
  353. end;
  354.  
  355.  
  356.  
  357. { This function closes out the com port, removing the interrupt routine,
  358.  
  359.  * etc. }
  360.  
  361. PROCEDURE closeport;
  362. begin
  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);
  370. end;
  371.  
  372.  
  373.  
  374. { This returns the status of the carrier detect lead from the modem }
  375. FUNCTION carrierdetect:boolean;
  376. var
  377.   instat : BYTE;
  378. begin
  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;
  389. end;
  390.  
  391.  
  392. end.
  393.  
  394.  
  395.