/* 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 #include #include #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]); }