home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / os2sdk / os2sdk12 / terminal / modem.c next >
Encoding:
C/C++ Source or Header  |  1989-11-20  |  11.5 KB  |  526 lines

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