home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / os2sdk / os2sdk10 / apps / terminal / modem.c next >
Encoding:
C/C++ Source or Header  |  1988-08-11  |  11.6 KB  |  523 lines

  1. /***    modem.c
  2.  *
  3.  * TITLE 
  4.  *
  5.  *    modem.c
  6.  *    Copyright (C) Microsoft Corporation 1987
  7.  *    March 1987
  8.  *
  9.  * DESCRIPTION
  10.  *
  11.  *     This module contains routines that support Hayes compatible modem. 
  12.  *
  13.  ***/
  14.  
  15. #include    <stdio.h>    
  16. #include    <doscalls.h>
  17. #include    <subcalls.h>
  18. #include    <malloc.h>
  19. #include    <string.h>
  20. #include     <memory.h>
  21. #include     <conio.h>
  22. #include     "term.h"
  23.  
  24. #define min(a,b) (((a)<(b)) ? (a):(b))    /* This is pulled out of the old */
  25.                     /* v2tov3.h (c v2.0) header file */
  26.  
  27. extern char     *ErrMsg[]; 
  28. extern unsigned FileHndl;
  29.  
  30. make_dial_cmd(char *, int);
  31. void flush_ques(int);
  32. void clr_com_error(void);
  33. void com_clr_flush(void);
  34.  
  35. static char Init[]    = {'A', 'T', 'V', '0', 0x0d};
  36. static char Attn[]    = {'A', 'T', 0x0d};
  37. static char Esc[]     = {'+', '+', '+'};
  38. static char OnHook[]  = {'A', 'T', 'H', '0', 0X0d};
  39. static char OffHook[] = {'A', 'T', 'H', '1', 0x0d};
  40. static char Reset[]   = {'A', 'T', 'Z', 0x0d};
  41.  
  42. struct s_Cmd{
  43.         char *pCmd;
  44.         int   CmdLen;
  45. } Cmds[] = {
  46.     {Init, sizeof(Init)},            /* Initialize modem */
  47.     {Attn, sizeof(Attn)},            /* Attention cmd */
  48.     {Esc, sizeof(Esc)},              /* Modem escape sequence*/
  49.     {OnHook, sizeof(OnHook)},        /* Put phone on hook */
  50.     {OffHook, sizeof(OffHook)},      /* Take phone off hook */
  51.     {Reset, sizeof(Reset)}           /* Reset command */
  52.   };
  53.  
  54.  
  55.  
  56. /***    make_modem_conn - make modem connection
  57.  *
  58.  *    This routine tries to setup the modem connection, retrying if 
  59.  *    appropriate.
  60.  *
  61.  *    make_modem_conn()
  62.  *
  63.  *    ENTRY
  64.  *
  65.  *    EXIT
  66.  *        TRUE if modem connection was made 
  67.  *        FALSE if modem connection did not go through
  68.  *
  69.  *    WARNING
  70.  *
  71.  *    EFFECTS
  72.  *
  73.  ***/
  74.  
  75. make_modem_conn()
  76. {
  77.     unsigned    NumBytes,    /* number of bytes to be written    */
  78.             RetCode,    /* return code from system calls    */
  79.             Result = FALSE; /* to be returned by this routine */
  80.     char        OutBuffer,
  81.             ModemRetry = TRUE,   /* retry for modem connection   */
  82.             NumRetries = 0;      /* no. times connection retried */
  83.  
  84.     printf("trying modem connection...\n");
  85.  
  86.       while (ModemRetry)
  87.           switch (setup_modem_conn()) {
  88.         case MS_CONNECT    :
  89.         case MS_CONNECT1200: 
  90.           Result = TRUE;
  91.           ModemRetry = FALSE;
  92.           OutBuffer = '\r';
  93.           if ((RetCode = DOSWRITE(FileHndl, &OutBuffer, 1, 
  94.                                       &NumBytes)) != 0)
  95.             error(ERR_DOSWRITE, RetCode);
  96.               break;
  97.         case MS_NOCARRIER  :
  98.         case MS_NODIALTONE :
  99.           if (++NumRetries > NUM_RETRY) {
  100.             printf("modem connection failed\n");
  101.             ModemRetry = FALSE;
  102.           }
  103.           else
  104.             printf("modem connection failed; retrying...\n");
  105.           break;
  106.         case MS_NOREPLY    :
  107.             case MS_ERROR      : 
  108.         case OT_FAILURE    :        /* OTher failure */
  109.             case MS_BUSY       : 
  110.         default            : 
  111.           ModemRetry = FALSE;
  112.               printf("modem connection failed\n");
  113.               break;
  114.       }        /* switch (setup_modem_conn()) */
  115.  
  116.     return(Result);
  117.  
  118. }
  119.  
  120.  
  121.  
  122.  
  123. /***    setup_modem_conn - setup modem connection
  124.  *
  125.  *    This is the helper routine for the make_modem_conn(). It initialises
  126.  *    the modem connection and sends out the dial command to the modem.
  127.  *
  128.  *    setup_modem_conn()
  129.  *
  130.  *    ENTRY
  131.  *
  132.  *    EXIT
  133.  *        returns one of the following: MS_CONNECT MS_CONNECT1200 
  134.  *            MS_NOCARRIER MS_NODIALTONE MS_NOREPLY MS_ERROR MS_BUSY 
  135.  *            OT_FAILURE
  136.  *
  137.  *    WARNING
  138.  *
  139.  *    EFFECTS
  140.  *
  141.  ***/
  142.  
  143. int    setup_modem_conn()
  144. {
  145.     int        Result = OT_FAILURE;
  146.  
  147.     /* initialise modem connection */
  148.     if (!(send_modem_cmd(MC_INIT)))
  149.       return(Result);
  150.     if (get_modem_reply() != MS_OK)
  151.       return(Result);
  152.     DOSSLEEP((long) 100);
  153.  
  154.     /* write AT string to the modem. This will cause the modem to
  155.      * determine the communications rate of the terminal as well
  156.      * as its parity setting.
  157.       */
  158.     if (!(send_modem_cmd(MC_ATTN)))
  159.       return(Result);
  160.     if (get_modem_reply() != MS_OK)
  161.       return(Result);
  162.     DOSSLEEP((long) 100);
  163.  
  164.     /* send DIAL command to the modem */
  165.     if (!(send_modem_cmd(MC_DIAL)))
  166.       return(Result);
  167.  
  168.     return(get_modem_reply());
  169. };
  170.  
  171.  
  172.  
  173.  
  174. /***    send_modem_cmd - send a command to modem
  175.  *
  176.  *    This routine sends a command to the modem and ensures that the echo 
  177.  *    from the modem matches the input command.
  178.  *
  179.  *    send_modem_cmd(CmdType)
  180.  *
  181.  *    ENTRY
  182.  *        CmdType - type of modem command: MC_INIT MC_ATTN MC_ESC 
  183.  *                      MC_ONHOOK MC_OFFHOOK MC_RESET MC_DIAL
  184.  *
  185.  *    EXIT
  186.  *        TRUE if command was sent succesfully
  187.  *        FALSE if command failed
  188.  *
  189.  *    WARNING
  190.  *
  191.  *    EFFECTS
  192.  *
  193.  ***/
  194.  
  195. send_modem_cmd(CmdType)
  196. int     CmdType;                /* The command to send */
  197. {
  198.         int          Result = TRUE,
  199.                 ReadCnt,
  200.                 WriteCnt,
  201.                 CmdLen,
  202.             RetCode;
  203.         char         Buf[80],
  204.                 Cmd[80],
  205.                 *pDst,
  206.                 *pCmd;
  207.     
  208.  
  209.     /* clear COM error and flush transmit/receive queues */
  210.     com_clr_flush();
  211.  
  212.         if (CmdType == MC_INIT) {
  213.       send_modem_cmd(MC_RESET);    /* modem command: ATZ */
  214.       /* clear COM error and flush transmit/receive queues */
  215.       com_clr_flush();
  216.     };
  217.  
  218.     /* set pCmd -> command string; CmdLen = length of command string */
  219.         if (CmdType == MC_DIAL) {
  220.           CmdLen = make_dial_cmd(Cmd, sizeof(Cmd));
  221.           pCmd = Cmd;
  222.         }
  223.         else {
  224.           pCmd = Cmds[CmdType].pCmd;
  225.           CmdLen = Cmds[CmdType].CmdLen;
  226.         };
  227.  
  228.     /* write the command out to the modem */
  229.          if (((RetCode = DOSWRITE(FileHndl, pCmd, CmdLen, &WriteCnt)) != 0)
  230.         || (WriteCnt != CmdLen))
  231.       return(FALSE);
  232.  
  233.         /* wait for the echo & wait for the command to clear */
  234.         DOSSLEEP((long) 250); 
  235.         if (CmdType == MC_DIAL || CmdType == MC_RESET)
  236.           DOSSLEEP((long) 750); 
  237.  
  238.     /* read back the echo from the modem & check if it matches the input */
  239.     RetCode = 
  240.           DOSREAD(FileHndl, Buf, min(WriteCnt, sizeof(Buf)), &ReadCnt);
  241.     if ((RetCode != 0) || (ReadCnt != WriteCnt))
  242.       Result = FALSE;
  243.         else {
  244.           pDst = Buf;
  245.           while (--ReadCnt >= 0) {
  246.             if (*pDst++ != *pCmd++) {
  247.           printf("send_modem_cmd: error in echo of modem input\n");
  248.               Result = FALSE;
  249.               break;
  250.             }
  251.           } /* while (--ReadCnt >= 0) */
  252.         } 
  253.  
  254.         return(Result);
  255. }
  256.  
  257.  
  258.  
  259.  
  260. /***    make_dial_cmd - create a modem command for dialing 
  261.  *
  262.  *    builds the dial command string and returns its length in bytes
  263.  *
  264.  *    make_dial_cmd(pBuf, BufLen)
  265.  *
  266.  *    ENTRY
  267.  *        pBuf - ptr to buffer
  268.  *            BufLen - length of buffer in bytes
  269.  *
  270.  *    EXIT
  271.  *        pBuf -> dial command string
  272.  *            make_dial_cmd = length of dial command string in bytes 
  273.  *
  274.  *    WARNING
  275.  *
  276.  *    EFFECTS
  277.  *
  278.  ***/
  279.  
  280. make_dial_cmd(pBuf, BufLen)
  281. char     *pBuf;
  282. int      BufLen;
  283. {
  284.         char         *pSrc,
  285.                 *pDst,
  286.                 Ch,
  287.                 Cmd[80],      /* allocate a huge command buffer */
  288.             *bin_to_dec();
  289.         int           Len;
  290.     structModemOptions sModemOptions;        /* modem options */
  291.  
  292.     get_modem_options(&sModemOptions);
  293.         pDst = Cmd;
  294.         *pDst++ = 'A';          /* get Modem's attention */
  295.         *pDst++ = 'T';
  296.         *pDst++ = 'S';          /* set R6 for wait for dial tone */
  297.         *pDst++ = '6';
  298.         *pDst++ = '=';
  299.         pDst = bin_to_dec(pDst, sModemOptions.iWaitTone);
  300.         *pDst++ = B_PAUSE;
  301.         *pDst++ = 'S';          /* set R7 for wait for carrier time */
  302.         *pDst++ = '7';
  303.         *pDst++ = '=';
  304.         pDst = bin_to_dec(pDst, sModemOptions.iWaitCarrier); 
  305.         *pDst++ = B_PAUSE;
  306.         *pDst++ = 'D';
  307.         *pDst++ = (sModemOptions.chDialType == PULSE) ? 'P' : 'T';
  308.         pSrc = sModemOptions.pPhoneNumber;
  309.         while (Ch = *pSrc++) 
  310.           if ((Ch >= '0' && Ch <= '9') || (Ch == ','))
  311.             *pDst++ = Ch;
  312.         *pDst++ = 0x0d;
  313.         *pDst = 0;
  314.  
  315.         /* copy the command string into caller's buffer */
  316.         pSrc = Cmd;
  317.         pDst = pBuf;
  318.         for (Len = 0; Len <= BufLen; ++Len)
  319.           if (*pSrc==0)
  320.             break;
  321.           else
  322.             *pDst++ = *pSrc++;
  323.         return(Len);
  324. }
  325.  
  326.  
  327.  
  328.  
  329. /***    bin_to_dec - convert a binary number to ASCII decimal 
  330.  *
  331.  *    bin_to_dec(pDst, i)
  332.  *
  333.  *    ENTRY
  334.  *        pDst -> buffer to place the ASCII decimal
  335.  *        i = integer to be converted to ASCII decimal
  336.  *
  337.  *    EXIT
  338.  *        ASCII decimal placed in the buffer pointed by pDst
  339.  *        bin_to_dec -> byte next to ASCII decimal in the buffer
  340.  *
  341.  *    WARNING
  342.  *
  343.  *    EFFECTS
  344.  *
  345.  ***/
  346.  
  347. char *bin_to_dec(pDst, i)
  348. char     *pDst;
  349. int      i;
  350. {
  351.         if (i > 10)
  352.           pDst = bin_to_dec (pDst, i/10);
  353.         *pDst++ = '0' + (i % 10);
  354.         return(pDst);
  355. }
  356.  
  357.  
  358.  
  359.  
  360. /***    get_modem_reply - get reply from modem
  361.  *
  362.  *    get_modem_reply()
  363.  *
  364.  *    ENTRY
  365.  *
  366.  *    EXIT
  367.  *        get_modem_reply = MS_CONNECT MS_CONNECT1200 MS_NOCARRIER 
  368.  *                  MS_NODIALTONE MS_NOREPLY MS_ERROR MS_BUSY
  369.  *
  370.  *    WARNING
  371.  *
  372.  *    EFFECTS
  373.  *
  374.  ***/
  375.  
  376. int get_modem_reply()
  377. {
  378.         char         Ch;
  379.         int          Cnt,
  380.                 Result,
  381.                  RetCode;
  382.  
  383.         do          /* skip CR, LF and get resultcode */
  384.       if ((RetCode = DOSREAD(FileHndl, &Ch, 1, &Cnt)) != 0) 
  385.             Error(ERR_DOSREAD, RetCode);
  386.         while ((Cnt == 1) && ((Ch == 0x0d) || (Ch == 0x0a)));
  387.  
  388.         switch(Cnt) {
  389.           case 0:  Result = MS_NOREPLY;
  390.                    break;
  391.           case 1:  if ((Ch >= '0') && (Ch <= '7'))
  392.                      Result = Ch - '0';
  393.                    else
  394.                      Result = MS_ERROR;
  395.                    break;
  396.           default: Result = MS_ERROR;
  397.                    break;
  398.         }
  399.  
  400.         return(Result);
  401. }
  402.  
  403.  
  404.  
  405.  
  406. /***    discon_modem - disconnect the modem 
  407.  *
  408.  *    discon_modem()
  409.  *
  410.  *    ENTRY
  411.  *
  412.  *    EXIT
  413.  *        modem disconnected
  414.  *
  415.  *    WARNING
  416.  *
  417.  *    EFFECTS
  418.  *
  419.  ***/
  420.  
  421. void discon_modem()
  422. {
  423.         /* Wait for the last command to clear, then be quiet for 1.5 seconds */
  424.         DOSSLEEP((long) 1000);          /* wait 1. second */
  425.         flush_ques(FLUSHOUTPUT);        /* flush the transmit que */
  426.         DOSSLEEP((long) 1500);          /* wait 1.5 seconds */
  427.  
  428.         send_modem_cmd(MC_ESC);        /* put modem in command mode */
  429.         DOSSLEEP((long) 2000);          /* wait 2 seconds */
  430.  
  431.         send_modem_cmd(MC_ONHOOK);         /* place phone back on hook */
  432.         DOSSLEEP((long) 200);              /* wait for command to clear*/
  433. }
  434.  
  435.  
  436.  
  437.  
  438. /***    com_clr_flush - clear COM error and flush transmit/receive queues
  439.  *
  440.  *    com_clr_flush()
  441.  *
  442.  *    ENTRY
  443.  *
  444.  *    EXIT
  445.  *        com error cleared
  446.  *        transmit and receive queues of com port flushed out
  447.  *
  448.  *    WARNING
  449.  *
  450.  *    EFFECTS
  451.  *
  452.  ***/
  453.  
  454. void com_clr_flush()
  455. {
  456.     /* retrieve and clear the com error information */
  457.     clr_com_error();
  458.     /* flush transmit and receive queues */
  459.     flush_ques(FLUSHINPUT);
  460.     flush_ques(FLUSHOUTPUT);
  461. }
  462.  
  463.  
  464.  
  465.  
  466. /***    flush_ques - flush COM transmit/receive queue 
  467.  *
  468.  *    flush_ques(FuncId)
  469.  *
  470.  *    ENTRY
  471.  *        FuncId - set to one of: FLUSHINPUT FLUSHOUTPUT
  472.  *
  473.  *    EXIT
  474.  *        transmit or receive queue of com port flushed
  475.  *
  476.  *    WARNING
  477.  *
  478.  *    EFFECTS
  479.  *
  480.  ***/
  481.  
  482. void flush_ques(FuncId)
  483. int    FuncId;            
  484. {    
  485.     char    FlushData,    /* data returned by flush IOCTL function */
  486.         FlushParm = FLUSH_CMDINFO; /* param to flush IOCTL function */
  487.     int    RetCode;
  488.     
  489.     /* flush transmit/receive queue */
  490.     if ((RetCode = DOSDEVIOCTL(&FlushData, &FlushParm, 
  491.                        FuncId, GENERIC, FileHndl)) != 0) 
  492.       Error(ERR_IOCTLFLUSHQUE, RetCode);
  493. }
  494.  
  495.  
  496.  
  497.  
  498. /***    clr_com_error - retrieve and clear COM error information
  499.  *
  500.  *    clr_com_error()
  501.  *
  502.  *    ENTRY
  503.  *
  504.  *    EXIT
  505.  *        com error cleared
  506.  *
  507.  *    WARNING
  508.  *
  509.  *    EFFECTS
  510.  *
  511.  ***/
  512.  
  513. void clr_com_error()
  514.  
  515. {
  516.     int      ComError,
  517.             RetCode;
  518.  
  519.     if ((RetCode = DOSDEVIOCTL((char *) &ComError, 0L, GETCOMERROR, 
  520.                                    SERIAL, FileHndl)) != 0)
  521.       Error(ERR_IOCTLGETCOMERROR, RetCode);
  522. }
  523.