home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 3 Comm / 03-Comm.zip / ot-100.zip / os2term.c < prev    next >
C/C++ Source or Header  |  1993-12-28  |  10KB  |  389 lines

  1. #define INCL_DOS
  2. #define INCL_DOSDEVIOCTL
  3. #define INCL_VIO
  4. #define INCL_KBD
  5. #include <os2.h>
  6.  
  7.  
  8. /* baud rate at which we wish to use the com port */
  9. #define BAUD_RATE 38400
  10.  
  11. /* size of incoming character buffer we wish to use */
  12. #define COMM_BUFFER_SIZE 2048
  13.  
  14.  
  15. /* GLOBAL VARIABLES */
  16. int head,            /* index to the last char in buffer */
  17.   tail;             /* index to first char in buffer */
  18. char buffer[COMM_BUFFER_SIZE];    /* incoming character buffer */
  19. HFILE PortHandle;        /* OS/2 file handle for COM port */
  20. TID RecvThreadID;        /* Thread ID of receive-character thread */
  21.  
  22.  
  23. /*
  24.  * our receive-character thread; all it does is wait for a
  25.  * character to come in on the com port.  when one does, it
  26.  * suspends the current process with DosEnterCritSec() and
  27.  * places the character in the buffer.
  28.  *
  29.  * Purists will note that using DosEnterCritSec() instead of
  30.  * semaphores is not "clean" or "true" multi-threading, but I chose
  31.  * this method because it gave the largest performance boost.
  32.  */
  33. VOID async_isr (ULONG ulThreadArg)
  34. {
  35.   ULONG BytesRead;        /* num. bytes read from last DosRead() call */
  36.   char ch;            /* char read in from last DosRead() call */
  37.  
  38.   /* endless loop */
  39.   while (1)
  40.     {
  41.       /* read character; this will block until a char is available */
  42.       DosRead (PortHandle, (PVOID) & ch, 1L, &BytesRead);
  43.  
  44.       /* if a character was actually read in... */
  45.       if (BytesRead)
  46.     {
  47.       /* suspend all other processing */
  48.       DosEnterCritSec ();
  49.  
  50.       /* put char in buffer and adjust indices */
  51.       buffer[head] = ch;
  52.       head++;
  53.       if (head == COMM_BUFFER_SIZE)
  54.         head = 0;
  55.  
  56.       /* release suspended processes */
  57.       DosExitCritSec ();
  58.     }
  59.     }
  60. }
  61.  
  62.  
  63. /* This function outputs one character to the com port */
  64. void outcomch (char ch)
  65. {
  66.   ULONG BytesWritten;        /* unless but required parameter */
  67.  
  68.   DosWrite (PortHandle, &ch, sizeof (ch), &BytesWritten);
  69. }
  70.  
  71.  
  72. /* return next char in receive buffer, or 0 for none available */
  73. char peek1c (void)
  74. {
  75.   return ((head != tail) ? buffer[tail] : 0);
  76. }
  77.  
  78.  
  79. /* This function returns one character from the com port, or a zero if
  80.  * no character is waiting
  81.  */
  82. char get1c (void)
  83. {
  84.   /* temp var to hold char for returning if one is available */
  85.   char c1;
  86.  
  87.   if (head != tail)
  88.     {
  89.       c1 = buffer[tail++];
  90.       if (tail == COMM_BUFFER_SIZE)
  91.     tail = 0;
  92.       return (c1);
  93.     }
  94.   else
  95.     return (0);
  96. }
  97.  
  98.  
  99. /* This returns a value telling if there is a character waiting in the com
  100.  * buffer.
  101.  */
  102. int comhit (void)
  103. {
  104.   return (head != tail);
  105. }
  106.  
  107.  
  108. /* This function clears the com buffer */
  109. void dump (void)
  110. {
  111.   head = tail = 0;
  112. }
  113.  
  114.  
  115. /* This function sets the com speed to that passed */
  116. void set_baud (unsigned int rate)
  117. {
  118.   USHORT Baud = (USHORT) rate;
  119.  
  120.   /*
  121.    * OS/2 2.x standard COM drivers only support up to 38400 bps
  122.    */
  123.   if ((rate <= 38400) && (rate >= 50))
  124.     DosDevIOCtl (PortHandle, IOCTL_ASYNC, ASYNC_SETBAUDRATE,
  125.          &Baud, sizeof (USHORT), NULL, NULL, 0L, NULL);
  126. }
  127.  
  128.  
  129. /* This function sets the DTR pin to the status given */
  130. void dtr (int i)
  131. {
  132.   MODEMSTATUS ms;
  133.   UINT data;
  134.  
  135.   ms.fbModemOn = i ? DTR_ON : 0;
  136.   ms.fbModemOff = i ? 255 : DTR_OFF;
  137.   DosDevIOCtl (PortHandle, IOCTL_ASYNC, ASYNC_SETMODEMCTRL, &ms,
  138.            sizeof (ms), NULL, &data, sizeof (data), NULL);
  139. }
  140.  
  141.  
  142. /* This function sets the RTS pin to the status given */
  143. void rts (int i)
  144. {
  145.   MODEMSTATUS ms;
  146.   UINT data;
  147.  
  148.   ms.fbModemOn = i ? RTS_ON : 0;
  149.   ms.fbModemOff = i ? 255 : RTS_OFF;
  150.   DosDevIOCtl (PortHandle, IOCTL_ASYNC, ASYNC_SETMODEMCTRL, &ms,
  151.            sizeof (ms), NULL, &data, sizeof (data), NULL);
  152. }
  153.  
  154.  
  155. /* This function initializes the com buffer, setting up the interrupt,
  156.  * and com parameters
  157.  */
  158. void initport (int port_num)
  159. {
  160.   char s[10] = "COMx";
  161.   APIRET rc;
  162.   ULONG action;
  163.   LINECONTROL lctl;
  164.   DCBINFO dcb;
  165.  
  166.   /* open com port */
  167.   s[3] = port_num + '0';
  168.   if ((rc = DosOpen (s, &PortHandle, &action, 0L, 0, FILE_OPEN,
  169.              OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYREADWRITE |
  170.              OPEN_FLAGS_FAIL_ON_ERROR, 0L)))
  171.     {
  172.       VioWrtTTY ("Cannot open com port\r\n", 22, 0);
  173.       DosExit (EXIT_PROCESS, 1);
  174.     }
  175.  
  176.   /* set line to no parity, 8 databits, 1 stop bit */
  177.   lctl.bParity = 0;
  178.   lctl.bDataBits = 8;
  179.   lctl.bStopBits = 0;
  180.   lctl.fTransBreak = 0;
  181.   if ((rc = DosDevIOCtl (PortHandle, IOCTL_ASYNC, ASYNC_SETLINECTRL,
  182.              &lctl, sizeof (LINECONTROL), NULL, NULL, 0L, NULL)))
  183.     {
  184.       VioWrtTTY ("Cannot set line settings\r\n", 26, 0);
  185.       DosExit (EXIT_PROCESS, 1);
  186.     }
  187.  
  188.   /* set device control block info */
  189.   dcb.usWriteTimeout = 0;
  190.   dcb.usReadTimeout = 0;
  191.   dcb.fbCtlHndShake = MODE_DTR_CONTROL | MODE_CTS_HANDSHAKE;
  192.   dcb.fbFlowReplace = MODE_RTS_CONTROL;
  193.   dcb.fbTimeout = MODE_NO_WRITE_TIMEOUT | MODE_WAIT_READ_TIMEOUT;
  194.   dcb.bErrorReplacementChar = 0x00;
  195.   dcb.bBreakReplacementChar = 0x00;
  196.   dcb.bXONChar = 0x11;
  197.   dcb.bXOFFChar = 0x13;
  198.   if ((rc = DosDevIOCtl (PortHandle, IOCTL_ASYNC, ASYNC_SETDCBINFO, &dcb,
  199.              sizeof (DCBINFO), 0L, NULL, 0L, NULL)))
  200.     {
  201.       VioWrtTTY ("Cannot device control block info\r\n", 34, 0);
  202.       DosExit (EXIT_PROCESS, 1);
  203.     }
  204.  
  205.   /* indicate receive buffer is currently empty */
  206.   head = tail = 0;
  207.  
  208.   /* spawn receive thread */
  209.   if (DosCreateThread (&RecvThreadID, async_isr, 0, 0, 4096))
  210.     {
  211.       VioWrtTTY ("Cannot create receive thread.\r\n", 31, 0);
  212.       DosExit (EXIT_PROCESS, 1);
  213.     }
  214.   dtr (1);
  215. }
  216.  
  217.  
  218. /* This function closes out the com port, removing the interrupt routine,
  219.  * etc.
  220.  */
  221. void closeport (void)
  222. {
  223.   /* kill receive thread and wait for it to close */
  224.   DosKillThread (RecvThreadID);
  225.   DosWaitThread (&RecvThreadID, DCWW_WAIT);
  226.  
  227.   /* close COM port handle */
  228.   DosClose (PortHandle);
  229. }
  230.  
  231.  
  232. /* This returns the status of the carrier detect lead from the modem */
  233. int cdet (void)
  234. {
  235.   BYTE instat;
  236.  
  237.   /* if DosDevIOCtl() returns an error, return 0 */
  238.   if (DosDevIOCtl (PortHandle, IOCTL_ASYNC, ASYNC_GETMODEMINPUT,
  239.            NULL, 0, NULL, &instat, sizeof (instat), NULL))
  240.     return 0;
  241.  
  242.   /* otherwise return carrier detect status */
  243.   return (instat & DCD_ON);
  244. }
  245.  
  246.  
  247. void main (int argc, char *argv[])
  248. {
  249.   int done = 0;
  250.   char ch1,
  251.        s[3] = {' ', 7, 0},
  252.        s1[3] = {' ', 7, 0};
  253.   USHORT x, y;
  254.   VIOMODEINFO vmi;
  255.   KBDKEYINFO ki;
  256.  
  257.   /* print intro message */
  258.   VioWrtTTY("\r\nOS2TERM v1.00  Copyright 1993 by Jeff M. Garzik\r\n"
  259.         "An OS/2 2.x 32-bit serial programming example\r\n"
  260.         "Hit Alt-X to exit, Alt-Z for list of commands\r\n"
  261.         "\r\n", 147, 0);
  262.  
  263.   /* check command line argument validity */
  264.   if (argc != 2)
  265.     {
  266.       VioWrtTTY("Usage: OS2TERM <com-port-number>\r\n"
  267.         "\r\n"
  268.         "Example: OS2TERM 1\r\n", 56, 0);
  269.       DosExit(EXIT_PROCESS, 1);
  270.     }
  271.  
  272.   /* find out number of rows and columns on the screen */
  273.   vmi.cb = sizeof (VIOMODEINFO);
  274.   VioGetMode (&vmi, 0);
  275.  
  276.   /* set up the com port stuff */
  277.   initport ((int)(argv[1][0] - '0'));
  278.   set_baud (BAUD_RATE);
  279.  
  280.   /* init this to 0 so that KbdCharIn() does not report any false
  281.    * character readings the first time through */
  282.   ki.chScan = 0;
  283.  
  284.   /* the main i/o loop */
  285.   while (!done)
  286.     {
  287.  
  288.       /* if a character from the modem is available, process it */
  289.       if (comhit ())
  290.     switch (ch1 = get1c ())
  291.       {
  292.       case 0:
  293.       case 255: /* ignore null characters */
  294.         break;
  295.       case 12: /* formfeed char = clear screen */
  296.         VioScrollUp (0, 0, 65535, 65535, 65535, s, 0);
  297.         VioSetCurPos (0, 0, 0);
  298.         break;
  299.       case '\b': /* backspace char */
  300.         VioGetCurPos (&y, &x, 0);
  301.         if (x > 0)
  302.           VioSetCurPos (y, x - 1, 0);
  303.         break;
  304.       case '\r': /* carraige return */
  305.         VioGetCurPos (&y, &x, 0);
  306.         VioSetCurPos (y, 0, 0);
  307.         break;
  308.       case '\n': /* line feed */
  309.         VioGetCurPos (&y, &x, 0);
  310.         if (y == (vmi.row - 1))
  311.           VioScrollUp (0, 0, vmi.row - 1, vmi.col - 1, 1, s, 0);
  312.         else
  313.           VioSetCurPos (y + 1, x, 0);
  314.         break;
  315.       default: /* anything else not processed above print on screen */
  316.         VioGetCurPos (&y, &x, 0);
  317.         s1[0] = ch1;
  318.         VioWrtCellStr (s1, 2, y, x, 0);
  319.         if (x == (vmi.col - 1))
  320.           if (y == (vmi.row - 1))
  321.         {
  322.           VioScrollUp (0, 0, vmi.row - 1, vmi.col - 1, 1, s, 0);
  323.           VioSetCurPos (y, 0, 0);
  324.         }
  325.           else
  326.         VioSetCurPos (y + 1, 0, 0);
  327.         else
  328.           VioSetCurPos (y, x + 1, 0);
  329.         break;
  330.       }
  331.  
  332.       /* if a character from the keyboard is available, process it */
  333.       KbdCharIn (&ki, 1, 0);
  334.       if (ki.chScan != 0)
  335.     {
  336.  
  337.       /* if chChar = 0 then it was an extended char, like F1 or Alt-X;
  338.        * process known extended keys */
  339.       if (ki.chChar == 0)
  340.         {
  341.           switch (ki.chScan)
  342.         {
  343.         case 0x2E:    /* alt-c - clear screen */
  344.           VioScrollUp (0, 0, 65535, 65535, 65535, s, 0);
  345.           VioSetCurPos (0, 0, 0);
  346.           break;
  347.         case 0x23:    /* alt-h - drop DTR to hang up */
  348.           VioWrtTTY ("\r\nHanging up...", 15, 0);
  349.           dtr (0);
  350.           DosSleep (500);
  351.           dtr (1);
  352.           VioWrtTTY ("Done.\r\n", 7, 0);
  353.           break;
  354.         case 0x2D:    /* alt-x - exit program */
  355.           VioWrtTTY ("Exiting...\r\n", 12, 0);
  356.           done = 1;
  357.           break;
  358.         case 0x2C:    /* alt-z - print menu */
  359.           VioWrtTTY ("\r\n"
  360.                  "OS2TERM Commands\r\n"
  361.                  "----------------\r\n"
  362.                  "Alt-C  Clear screen\r\n"
  363.                  "Alt-H  Hang up\r\n"
  364.                  "Alt-X  Exit OS2TERM\r\n"
  365.                  "Alt-Z  Print list of commands\r\n"
  366.                  "\r\n", 129, 0);
  367.           break;
  368.         }
  369.         }
  370.  
  371.       /* otherwise, send key to modem */
  372.       else
  373.         outcomch ((unsigned char) ki.chChar);
  374.  
  375.       /* set scan back to 0 because when calling KbdCharIn() with
  376.        * IOWait parameter set to 1, KbdCharIn will exit w/o changing
  377.        * the data if no key is available */
  378.       ki.chScan = 0;
  379.     }
  380.     }
  381.  
  382.   /* we are exiting, shut down threads and com port */
  383.   closeport ();
  384.  
  385.   /* return to OS/2 with successful return code */
  386.   DosExit(EXIT_PROCESS, 0);
  387. }
  388.  
  389.