Metropoli BBS
VIEWER: modem.c MODE: TEXT (ASCII)
/* modem.c */
/*---------------------------------------------------------------------------*/
/* This file is part of PSFax/2.                                             */
/*                                                                           */
/* Written By: Gary L. Hennigan                                              */
/*                                                                           */
/* This code can modified as much as you like provided you follow the        */
/* guidelines as described in the file install.doc which you should have     */
/* received with this file. If you did not please notify the author for a    */
/* copy of this file via Internet email. The address is:		     */
/*			ghenniga@NMSU.Edu				     */
/*---------------------------------------------------------------------------*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "psfax2.h"

#define DevIOCtl DosDevIOCtl32

/**Global variables defined in psfax2.c **/
extern char cGlobResp[];

ULONG ulTemp;  	     /* Used by various functions in modem.c */
USHORT usTemp;

void vFlushIO( HFILE );
unsigned char swap_bits( unsigned char );
USHORT usSetTTYTime( HFILE, DCBINFO *, int );
int iGetResp( HFILE, DCBINFO *, char *, int, int, char * );

/****************************************************************************/
/*************************Used for simplifying*******************************/
/*************************IOCtl function calls*******************************/
/****************************************************************************/
USHORT DosDevIOCtl32(PVOID pData, USHORT cbData, PVOID pParms, USHORT cbParms,
		     USHORT usFunction, USHORT usCategory, HFILE hDevice)
{
   ULONG ulParmLengthInOut = cbParms, ulDataLengthInOut = cbData;
   return (USHORT)DosDevIOCtl(hDevice, usCategory, usFunction,
			      pParms, cbParms, &ulParmLengthInOut,
			      pData, cbData, &ulDataLengthInOut);
}
/****************************************************************************/
/***************************Open the COM Port********************************/
/****************************************************************************/
ULONG ulOpenPort(char *cPort, HFILE *hTTY)
{

   return DosOpen(cPort, hTTY, &ulTemp, 0L, 0, FILE_OPEN,
		  OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYREADWRITE |
		  OPEN_FLAGS_FAIL_ON_ERROR, 0L);
}
/****************************************************************************/
/**********************Get the current port settings*************************/
/****************************************************************************/
int iPortGetSet(HFILE hTTY, DCBINFO *dcbCom)
{
   usTemp = DevIOCtl(dcbCom,sizeof(*dcbCom),NULL,0,
		     ASYNC_GETDCBINFO, IOCTL_ASYNC, hTTY);

   if(usTemp != 0)
      return 1;
   
   return 0;
}
/****************************************************************************/
/**************************Initialize the Port*******************************/
/****************************************************************************/
int iPortInit(HFILE hTTY, DCBINFO *dcbCom)
{
   MODEMSTATUS ms;
   UINT data;
/*-------------------------------End Declarations---------------------------*/

/**Set XON/XOFF flow control. **/   
   dcbCom->fbCtlHndShake = MODE_DTR_CONTROL;
   dcbCom->fbFlowReplace &= ~(MODE_AUTO_RECEIVE | MODE_AUTO_TRANSMIT |
			      MODE_RTS_CONTROL | MODE_RTS_HANDSHAKE);
   dcbCom->fbFlowReplace |= (MODE_AUTO_RECEIVE | MODE_AUTO_TRANSMIT |
			     MODE_RTS_CONTROL);
   ms.fbModemOn = RTS_ON;
   ms.fbModemOff = 255;
   
   usTemp = DevIOCtl(NULL,0,dcbCom,sizeof(*dcbCom),ASYNC_SETDCBINFO,
		     IOCTL_ASYNC, hTTY);
   if(usTemp != 0)
      return -1;
   
   usTemp = DevIOCtl(&data,sizeof(data),&ms,sizeof(ms),
		     ASYNC_SETMODEMCTRL,IOCTL_ASYNC,hTTY);
   if(usTemp != 0)
      return -1;

   return 0;
}
/****************************************************************************/
/**************************Initialize the Modem******************************/
/****************************************************************************/
int iModemInit(HFILE hTTY, DCBINFO *dcbCom)
{
   char cBuff[256];
   int iCnt=0;
/*-------------------------------End Declarations---------------------------*/

   strcpy(cBuff,"ATZ\r");	   /* Use the default profile of the modem. */
   DosWrite(hTTY, cBuff, strlen(cBuff), &ulTemp);
   if(iGetResp(hTTY, dcbCom, cBuff, 10*sizeof(char), 3, NULL) <= 0 ||
      !strstr(cBuff,"OK\r") )
      return 1;

   strcpy(cBuff,"AT&K4V0Q0E0L2M1W2S0=0S2=255S12=255 +FCLASS=2\r");
   DosWrite(hTTY, cBuff, strlen(cBuff), &ulTemp);
   if(iGetResp(hTTY, dcbCom, cBuff, strlen(cBuff)+2*sizeof(char), 
	       2, NULL) <= 0 || !strstr(cBuff,"0\r"))
      return 1;

   strcpy(cBuff,"ATS7=120 +FCR=1\r");
   DosWrite(hTTY, cBuff, strlen(cBuff), &ulTemp); sleep(1);
   if(iGetResp(hTTY, dcbCom, cBuff, 2*sizeof(char), 2, NULL) <= 0 ||
      !strstr(cBuff,"0\r"))
      return 1;

   strcpy(cBuff,"AT+FDCC=1,3\r");
   DosWrite(hTTY, cBuff, strlen(cBuff), &ulTemp); sleep(1);
   if(iGetResp(hTTY, dcbCom, cBuff, 2*sizeof(char), 2, NULL) <= 0 ||
      !strstr(cBuff,"0\r"))
      return 1;

   strcpy(cBuff,"AT+FBOR=0\r");
   DosWrite(hTTY, cBuff, strlen(cBuff), &ulTemp); sleep(1);
   if(iGetResp(hTTY, dcbCom, cBuff, 2*sizeof(char), 2, NULL) <= 0 ||
      !strstr(cBuff,"0\r"))
      return 1;

/**Flush all the I/O, set the timeout for reads, and see if the modem **/
/**is responding properly. 					      **/
   vFlushIO(hTTY);
   usSetTTYTime(hTTY, dcbCom, 2);

   strcpy(cBuff, "AT\r");
   do
   {
      DosWrite(hTTY, cBuff, strlen(cBuff), &ulTemp);
      iCnt++;
      DosRead(hTTY, cBuff, 2, &ulTemp);
   }
   while(ulTemp == 0 && iCnt <= MAXTIMEOUTS);

   if(ulTemp == 0 && iCnt >= MAXTIMEOUTS)return 1;
   
   if(strncmp(cBuff,"0\r",2) != 0)
   {
      printf("Bad modem response while attempting to sync!\n");
      return 1;
   }

   return 0;
}
/****************************************************************************/
/****************************Dial the Phone**********************************/
/****************************************************************************/
int iModemDial( HFILE hTTY, char *cPhoneNum, DCBINFO *dcbCom, int iWait )
{
   int iRedial;
   char cBuff[256];
/*-------------------------------End Declarations---------------------------*/

   strcpy(cBuff,"ATD");
   strcat(cBuff,cPhoneNum);
   strcat(cBuff,"\r");

   DosWrite(hTTY, cBuff, strlen(cBuff), &ulTemp); sleep(1);
   if(iGetResp(hTTY, dcbCom, cBuff, 2, iWait, NULL) <= 0)
   {
      cBuff[0] = 0x1b;
      cBuff[1] = 0x00;
      DosWrite(hTTY, cBuff, strlen(cBuff), &ulTemp); sleep(2);
      vFlushIO(hTTY);
      return DIAL_NOANSWER;
   }

   if( cBuff[0] )
   {
      switch(cBuff[0])
      {
         case '3':
	    iRedial = DIAL_NOCARRIER;
	    vFlushIO(hTTY);
	    return iRedial;

	 case '6':
	    iRedial = DIAL_NODIALTONE;
	    vFlushIO(hTTY);
	    return iRedial;

	 case '7':
	    iRedial = DIAL_BUSY;
	    vFlushIO(hTTY);
	    return iRedial;

	 case '8':
	    iRedial = DIAL_NOANSWER;
	    vFlushIO(hTTY);
	    return iRedial;
	    
	 default:
	    iRedial = 0;
	    break;
      }
   }
   else
   {
      vFlushIO(hTTY);
      return DIAL_NOANSWER;
   }
   
/**Make sure the remote responds with a connection indication. **/
   if(iGetResp(hTTY, dcbCom, &cBuff[2], 8, -20, "+FCON\r") <= 0)
   {
      printf("Incorrect response \"%s\" received...\n",cBuff);
      vFlushIO(hTTY);
      return DIAL_UNKNOWN;
   }
   else
      strcpy(cGlobResp,cBuff);
   
   puts("Fax connection established!");
   return iRedial;
}
/****************************************************************************/
/*******************Initialize the fax-fax connection************************/
/****************************************************************************/
int iFaxInit(HFILE hTTY, DCBINFO *dcbCom, int df, int vr, int wd, int ln)
{
   char cBuff[256];
/*-------------------------------End Declarations---------------------------*/

/**Make sure the remote responded correctly. **/
   if(iGetResp(hTTY, dcbCom, cBuff, 50, -15, "0\r") <= 0)
   {
      puts("Remote fax is not responding....");
      return 1;
   }

/**Set transmission parameters. **/
   sprintf(cBuff,"AT+FDT=%d,%d,%d,%d\r", df, vr, wd, ln);
   vFlushIO(hTTY);
   DosWrite(hTTY, cBuff, strlen(cBuff), &ulTemp); sleep(1);

/**Make sure the remote responds with a CONNECT. **/
   if(iGetResp(hTTY, dcbCom, cBuff, 50, -15, "1\r") <= 0)
   {
      puts("Remote fax is not responding....");
      return 1;
   }
   vFlushIO(hTTY);

   return 0;
}
/****************************************************************************/
/*********************Send a page via the Fax/Modem**************************/
/****************************************************************************/
int iFaxSendPage(HFILE hTTY, DCBINFO *dcbCom, FILE *fStream, int iLast)
{
   unsigned char cBuff[SENDCHUNK], cBuff2[2*SENDCHUNK];
   int iNumRead, iNumWrite, i1, iPPRCode;
/*-------------------------------End Declarations---------------------------*/

   iNumRead = fread(cBuff, sizeof(char), SENDCHUNK, fStream);
   usSetTTYTime(hTTY, dcbCom, -15);

   while(iNumRead > 0)
   {
      iNumWrite = 0;

/**   Swap the bits and pad DLE characters. **/
      for(i1=0; i1 < iNumRead; i1++)
      {
	 cBuff2[iNumWrite] = swap_bits(cBuff[i1]);
	 if(cBuff2[iNumWrite++] == DLE)
	    cBuff2[iNumWrite++] = DLE;
      }

/**   Write the stuff out to the modem. **/
      DosWrite(hTTY, cBuff2, iNumWrite, &ulTemp);

/**   Check for a response, if any, from the modem. **/
      DosRead(hTTY, cBuff, sizeof(cBuff), &ulTemp);
      if(ulTemp != 0)
      {
	 for(i1=0; i1 < ulTemp; i1++)
	 {
	    if((cBuff[i1] & 0x7f) == CAN)
	    {
	       printf("Remote has canceled transmission!\n");
	       sprintf(cBuff,"%c%c",DLE,ETX);
	       DosWrite(hTTY, cBuff, 2*sizeof(char), &ulTemp);
	       return -1;
	    }
	 }
      }
      
      iNumRead = fread(cBuff, sizeof(char), SENDCHUNK, fStream);
   }
   sprintf(cBuff,"%c%c",DLE,ETX);
   DosWrite(hTTY, cBuff, 2*sizeof(char), &ulTemp);
   i1 = iGetResp(hTTY, dcbCom, cBuff, 2, -15, "0\r");
   if(i1 <= 0)
   {
      puts("Incorrect response from remote to end-of-page message!\n");
      return -1;
   }
   
   switch(iLast)
   {
      case PEND_ANOTHER:
         strcpy(cBuff,"AT+FET=0\r");
	 DosWrite(hTTY, cBuff, strlen(cBuff), &ulTemp);
	 break;
      case PEND_ENDTRAN:
	 strcpy(cBuff,"AT+FET=2\r");
	 DosWrite(hTTY, cBuff, strlen(cBuff), &ulTemp);
	 break;
   }

/**Get the post-page response. **/
   if(iGetResp(hTTY, dcbCom, cBuff, 20, -10, "0\r") <= 0)
   {
      puts("No post-page response from remote!");
      return -1;
   }
   if(iLast == PEND_ANOTHER)
      DosWrite(hTTY, "AT+FDT\r", sizeof("AT+FDT\r"), &ulTemp);

   strtok(&cBuff[8],"\r");
   i1 = sscanf(&cBuff[8], "%d", &iPPRCode);
   if(i1 <= 0)
   {
      puts("Incorrect post-page response from remote!");
      return -1;
   }
   if(iLast == PEND_ANOTHER)
   {
      if(iGetResp(hTTY, dcbCom, cBuff, 2, -10, "1\r") <= 0)
      {
	 puts("Unable to continue transmission!");
	 return -1;
      }
   }
   else
   {
      if(iGetResp(hTTY, dcbCom, cBuff, 2, -15, "0\r") <= 0)
      {
	 puts("Failed to properly end transmission!");
	 return -1;
      }
   }
   
   return iPPRCode;
}
/****************************************************************************/
/************Tell the remote to intterrupt the transmission******************/
/****************************************************************************/
int iFaxInterrupt(HFILE hTTY, DCBINFO *dcbCom)
{
   char cBuff[20];
/*-------------------------------End Declarations---------------------------*/

   strcpy(cBuff,"AT+FK\r");
   DosWrite(hTTY, cBuff, strlen(cBuff), &ulTemp);
   
   return 0;
}
/****************************************************************************/
/**************************Close the COM Port********************************/
/****************************************************************************/
ULONG ulClosePort(HFILE hTTY)
{
   return DosClose(hTTY);
}
/****************************************************************************/
/********************Read the response from the modem************************/
/****************************************************************************/
int iGetResp( HFILE hTTY, DCBINFO *dcbCom, char *cBuff, int iExpSize, 
	      int iTimeout, char *cSearch )
{
   int iStart=0, iCnt=0;
   
/**Initialize the buffer. **/
   cBuff[0] = '\000';
   
/**Set the desired timeout for this read. **/
   usSetTTYTime(hTTY, dcbCom, iTimeout);

/**Read the response. **/
   if(!cSearch)
   {
      DosRead(hTTY, cBuff, iExpSize, &ulTemp);
      cBuff[ulTemp] = '\000';  /* For string manipulation functions. */
      iStart = ulTemp;
   }
   else
   {
      do
      {
	 DosRead(hTTY, &cBuff[iStart], iExpSize, &ulTemp);
	 iStart += ulTemp;
	 cBuff[iStart] = '\000';
	 iCnt++;
      }
      while(!strstr(cBuff,cSearch) && iCnt <= MAXTIMEOUTS);
   }

   if(iCnt > MAXTIMEOUTS)
      return -1;
   
   return iStart;
}
/****************************************************************************/
/***********************Set the read timeout on******************************/
/******************************the COM port**********************************/
/****************************************************************************/
USHORT usSetTTYTime(HFILE hTTY, DCBINFO *dcbCom, int iTime)
{
   if(iTime >= 0)
      iTime *= 100;
   else
      iTime *= -1;

   dcbCom->usReadTimeout = iTime;
   return (DevIOCtl(NULL,0,dcbCom,sizeof(*dcbCom),ASYNC_SETDCBINFO,
		   IOCTL_ASYNC, hTTY));
}
/****************************************************************************/
/*************************Flush all pending I/O******************************/
/****************************************************************************/
void vFlushIO(HFILE hTTY)
{
   UINT data;
   char parm=0;
/*-------------------------------End Declarations---------------------------*/
   
   DevIOCtl(&data,sizeof(data),&parm,sizeof(parm),
	    DEV_FLUSHINPUT, IOCTL_GENERAL, hTTY);
   DevIOCtl(&data,sizeof(data),&parm,sizeof(parm),
	    DEV_FLUSHOUTPUT, IOCTL_GENERAL, hTTY);
   
}
/****************************************************************************/
/************************Builds table to swap the****************************/
/******************low order 4 bits with the high order**********************/
/****************************************************************************/
static void init_swaptable(unsigned char *swaptable)
{
    int i, j;
/*-------------------------------End Declarations---------------------------*/

    for (i = 0; i < 256; i++) {
	j = ( ((i & 0x01) << 7) |
	     ((i & 0x02) << 5) |
	     ((i & 0x04) << 3) |
	     ((i & 0x08) << 1) |
	     ((i & 0x10) >> 1) |
	     ((i & 0x20) >> 3) |
	     ((i & 0x40) >> 5) |
	     ((i & 0x80) >> 7) );
	swaptable[i] = j;
    }
}

/****************************************************************************/
/********************Reverses the low order 4 bits of a byte*****************/
/****************************************************************************/
unsigned char swap_bits(unsigned char c)
{
    static unsigned char swaptable[256];
    static int swaptable_init = FALSE;
/*-------------------------------End Declarations---------------------------*/

    if (!swaptable_init) {
	init_swaptable(swaptable);
	swaptable_init = TRUE;
    }

    return(swaptable[c]);
}
[ RETURN TO DIRECTORY ]