Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1825 lines
57 KiB

  1. /***************************************************************************
  2. Name : DDI.C
  3. Copyright (c) Microsoft Corp. 1991 1992 1993
  4. Revision Log
  5. Num Date Name Description
  6. --- -------- ---------- -----------------------------------------------
  7. ***************************************************************************/
  8. #pragma warning(disable:4100) // unreferenced formal param
  9. #include "prep.h"
  10. #include "mmsystem.h"
  11. #include "comdevi.h"
  12. #include "class1.h"
  13. // #include "modem.h"
  14. #include "debug.h"
  15. #include "decoder.h"
  16. ///RSL
  17. #include "glbproto.h"
  18. #define faxTlog(m) DEBUGMSG(ZONE_DDI, m)
  19. #define faxT2log(m) DEBUGMSG(ZONE_FRAMES, m)
  20. #define FILEID FILEID_DDI
  21. /* Converts a the T30 code for a speed to the Class1 code
  22. * Generates V.17 with Long Training.
  23. * Add 1 to V.17 codes to get teh Short-train version
  24. */
  25. BYTE T30toC1[16] =
  26. {
  27. /* V27_2400 0 */ 24,
  28. /* V29_9600 1 */ 96,
  29. /* V27_4800 2 */ 48,
  30. /* V29_7200 3 */ 72,
  31. /* V33_14400 4 */ 145, // 144, // V33==V17_long_train FTM=144 is illegal
  32. 0,
  33. /* V33_12000 6 */ 121, // 120, // V33==V17_long_train FTM=120 is illegal
  34. /* V21 squeezed in */ 3,
  35. /* V17_14400 8 */ 145,
  36. /* V17_9600 9 */ 97,
  37. /* V17_12000 10 */ 121,
  38. /* V17_7200 11 */ 73,
  39. 0,
  40. 0,
  41. 0,
  42. 0
  43. };
  44. int T30toSpeed[16] =
  45. {
  46. /* V27_2400 0 */ 2400,
  47. /* V29_9600 1 */ 9600,
  48. /* V27_4800 2 */ 4800,
  49. /* V29_7200 3 */ 7200,
  50. /* V33_14400 4 */ 14400, // 144, // V33==V17_long_train FTM=144 is illegal
  51. 0,
  52. /* V33_12000 6 */ 12000, // 120, // V33==V17_long_train FTM=120 is illegal
  53. /* V21 squeezed in */ 300,
  54. /* V17_14400 8 */ 14400,
  55. /* V17_9600 9 */ 9600,
  56. /* V17_12000 10 */ 12000,
  57. /* V17_7200 11 */ 7200,
  58. 0,
  59. 0,
  60. 0,
  61. 0
  62. };
  63. // used only for checking
  64. static BYTE SpeedtoCap[16] =
  65. {
  66. /* V27_2400 0 */ 0,
  67. /* V29_9600 1 */ V29, // 1
  68. /* V27_4800 2 */ V27, // 2
  69. /* V29_7200 3 */ V29, // 1
  70. /* V33_14400 4 */ V33, // 4
  71. 0,
  72. /* V33_12000 6 */ V33, // 4
  73. /* V21 squeezed in */ 0,
  74. /* V17_14400 8 */ V17, // 8
  75. /* V17_9600 9 */ V17, // 8
  76. /* V17_12000 10 */ V17, // 8
  77. /* V17_7200 11 */ V17, // 8
  78. 0,
  79. 0,
  80. 0,
  81. 0
  82. };
  83. CBSZ cbszFTH3 = "AT+FTH=3\r";
  84. CBSZ cbszFRH3 = "AT+FRH=3\r";
  85. CBSZ cbszFRS = "AT+FRS=%d\r";
  86. CBSZ cbszFTS = "AT+FTS=%d\r";
  87. CBSZ cbszFTM = "AT+FTM=%d\r";
  88. CBSZ cbszFRM = "AT+FRM=%d\r";
  89. #ifdef MDRV
  90. CBSZ cbszOK, cbszCONNECT, cbszNOCARRIER, cbszERROR, cbszFCERROR;
  91. #else //MDRV
  92. // echo off, verbose response, no auto answer, hangup on DTR drop
  93. // 30 seconds timer on connect, speaker always off, speaker volume=0
  94. // busy&dialtone detect enabled
  95. extern CBSZ cbszOK ;
  96. extern CBSZ cbszCONNECT ;
  97. extern CBSZ cbszNOCARRIER ;
  98. extern CBSZ cbszERROR ;
  99. extern CBSZ cbszFCERROR ;
  100. #endif //MDRV
  101. #define ST_MASK (0x8 | ST_FLAG) // 8 selects V17 only. 16 selects ST flag
  102. /******************** Global Vars *********/
  103. BYTE bDLEETX[3] = { DLE, ETX, 0 };
  104. BYTE bDLEETXOK[9] = { DLE, ETX, '\r', '\n', 'O', 'K', '\r', '\n', 0 };
  105. /******************** Global Vars *********/
  106. /****************** begin prototypes from ddi.c *****************/
  107. void iModemParamsReset(PThrdGlbl pTG);
  108. void iModemInitGlobals(PThrdGlbl pTG);
  109. // If defined, iModemRecvFrame retries FTH until timeout,
  110. // if it receiving a null frame followed by ERROR or NO_CARRIER.
  111. //#define USR_HACK
  112. #ifdef USR_HACK
  113. USHORT iModemFRHorM(PThrdGlbl pTG, ULONG ulTimeout);
  114. #endif // USR_HACK
  115. /****************** begin prototypes from ddi.c *****************/
  116. #ifndef MDRV
  117. #ifdef DEBUG
  118. DBGPARAM dpCurSettings = {
  119. "Modem Driver", 0x0000, {
  120. "DDI", "Frames", "", "",
  121. "Class0", "", "", "",
  122. "", "", "SW Framing", "SW Framing Hi"
  123. "Debug", "", "", "" },
  124. // 0x00000FFF
  125. // 0x00000001
  126. // 0x0000000F0
  127. // 0x00000400 // too much for 14400 ECM
  128. // 0x00000F01
  129. 0x00000000
  130. // 0xFFFFFFFF
  131. };
  132. #endif
  133. #define szMODULENAME "awcl1_32"
  134. #endif //MDRV
  135. void iModemInitGlobals(PThrdGlbl pTG)
  136. {
  137. _fmemset(&pTG->Class1Modem, 0, sizeof(CLASS1_MODEM));
  138. _fmemset(&pTG->Class1Status, 0, sizeof(CLASS1_STATUS));
  139. pTG->Class1Modem.eRecvFCS = RECV_FCS_NO;
  140. #if 0 /// RSL #ifndef MDDI
  141. {
  142. LPCMDTAB lpCmdTab = iModemGetCmdTabPtr(pTG);
  143. pTG->Class1Modem.eRecvFCS = RECV_FCS_DUNNO;
  144. if (lpCmdTab)
  145. {
  146. if (lpCmdTab->dwFlags&fMDMSP_C1_FCS_NO)
  147. pTG->Class1Modem.eRecvFCS = RECV_FCS_NO;
  148. else if (lpCmdTab->dwFlags&fMDMSP_C1_FCS_YES_BAD)
  149. pTG->Class1Modem.eRecvFCS = RECV_FCS_NOCHK;
  150. }
  151. }
  152. #endif //!MDDI
  153. }
  154. void iModemParamsReset(PThrdGlbl pTG)
  155. {
  156. _fmemset(&pTG->ModemParams, 0 , sizeof(pTG->ModemParams));
  157. pTG->ModemParams.uSize = sizeof(pTG->ModemParams);
  158. pTG->ModemParams.Class = FAXCLASS1;
  159. // Don't use this. Need differnet number of flags according to speed
  160. // pTG->ModemParams.PreambleFlags = 400; // 200ms @ 14400bps
  161. pTG->ModemParams.InterframeFlags = 3; // random. one or two may do!
  162. // pTG->ModemParams.InterframeFlags = 10; // too much!
  163. // must be **less* than 50, so need a
  164. // different length for each speed
  165. // pTG->ModemParams.ClosingFlags = 50;
  166. // pTG->ModemParams.fCEDOff = 0;
  167. // pTG->ModemParams.fCNGOff = 0;
  168. // pTG->ModemParams.InactivityTimer = 0;
  169. // pTG->ModemParams.cbLineMin = 0;
  170. // pTG->ModemParams.hJob = 0;
  171. }
  172. // added for CLASS0
  173. BOOL ModemSetParams(PThrdGlbl pTG, USHORT uModem, LPMODEMPARAMS lpParams)
  174. {
  175. BG_CHK((uModem==1||uModem==5) && lpParams->uSize >= sizeof(MODEMPARAMS));
  176. if(lpParams->Class && lpParams->Class != (-1))
  177. {
  178. #ifdef CL0
  179. BG_CHK(lpParams->Class == FAXCLASS1 || lpParams->Class == FAXCLASS0);
  180. #else //CL0
  181. BG_CHK(lpParams->Class == FAXCLASS1);
  182. #endif //CL0
  183. pTG->ModemParams.Class = lpParams->Class;
  184. }
  185. return TRUE;
  186. }
  187. USHORT NCUDial(PThrdGlbl pTG, HLINE hLine, LPSTR szPhoneNum)
  188. {
  189. USHORT uRet;
  190. D_PrintDDI("NCUDial", (USHORT)hLine, 0);
  191. IF_BG_CHK(hLine==HLINE_2);
  192. IF_BG_CHK(pTG->DDI.uComPort && pTG->DDI.fModemOpen && pTG->DDI.fLineInUse && pTG->DDI.fNCUModemLinked);
  193. iModemInitGlobals(pTG);
  194. #ifndef CL0
  195. pTG->ModemParams.Class = FAXCLASS1;
  196. #endif
  197. if((uRet = iModemDial(pTG, szPhoneNum, pTG->ModemParams.Class)) == CONNECT_OK)
  198. pTG->Class1Modem.ModemMode = FRH;
  199. return uRet;
  200. }
  201. USHORT NCULink(PThrdGlbl pTG, HLINE hLine, HMODEM hModem, USHORT uHandset, USHORT uFlags)
  202. {
  203. USHORT uRet;
  204. D_PrintDDI("NCULink", (USHORT)hLine, (USHORT)hModem);
  205. D_PrintDDI("NCULink", uHandset, uFlags);
  206. IF_BG_CHK(hLine==HLINE_2);
  207. IF_BG_CHK(pTG->DDI.uComPort && pTG->DDI.fModemOpen && pTG->DDI.fLineInUse);
  208. switch(uFlags & NCULINK_MODEMASK)
  209. {
  210. case NCULINK_HANGUP:
  211. if(iModemHangup(pTG))
  212. {
  213. MDDISTMT(pTG->pTG->DDI.fNCUModemLinked = FALSE);
  214. uRet = CONNECT_OK;
  215. }
  216. else
  217. uRet = CONNECT_ERROR;
  218. break;
  219. case NCULINK_TX:
  220. MDDISTMT(pTG->DDI.fNCUModemLinked = TRUE);
  221. uRet = CONNECT_OK;
  222. break;
  223. case NCULINK_RX:
  224. iModemInitGlobals(pTG);
  225. # ifdef MDDI
  226. pTG->ModemParams.Class = FAXCLASS1;
  227. # endif //MDDI
  228. pTG->ModemParams.Class = FAXCLASS1; //RSL
  229. if((uRet = iModemAnswer(pTG, (uFlags & NCULINK_IMMEDIATE), pTG->ModemParams.Class)) == CONNECT_OK)
  230. {
  231. MDDISTMT(pTG->DDI.fNCUModemLinked = TRUE);
  232. pTG->Class1Modem.ModemMode = FTH;
  233. }
  234. break;
  235. case NCULINK_OFFHOOK:
  236. // fall through. Can't handle yet
  237. default: BG_CHK(FALSE);
  238. uRet = CONNECT_ERROR;
  239. break;
  240. }
  241. //done:
  242. MDDISTMT((MyDebugPrint(pTG, LOG_ALL, "NCULink: uRet=%d Linked=%d\r\n", uRet, pTG->DDI.fNCUModemLinked)));
  243. return uRet;
  244. }
  245. // dangerous. May get 2 OKs, may get one. Generally avoid
  246. // CBSZ cbszATAT = "AT\rAT\r";
  247. CBSZ cbszAT1 = "AT\r";
  248. BOOL iModemSyncEx(PThrdGlbl pTG, HMODEM hModem, ULONG ulTimeout, DWORD dwFlags);
  249. BOOL ModemSync(PThrdGlbl pTG, HMODEM hModem, ULONG ulTimeout)
  250. {
  251. return iModemSyncEx(pTG, hModem, ulTimeout, 0);
  252. }
  253. #ifndef MDDI
  254. BOOL ModemSyncEx(PThrdGlbl pTG, HMODEM hModem, ULONG ulTimeout, DWORD dwFlags)
  255. {
  256. return iModemSyncEx(pTG, hModem, ulTimeout, dwFlags);
  257. }
  258. #endif // !MDDI
  259. BOOL iModemSyncEx(PThrdGlbl pTG, HMODEM hModem, ULONG ulTimeout, DWORD dwFlags)
  260. {
  261. IF_BG_CHK(hModem==HMODEM_3 && pTG->DDI.uComPort && pTG->DDI.fModemOpen && pTG->DDI.fLineInUse && pTG->DDI.fNCUModemLinked);
  262. faxIFlog(("In ModemSync fModemOpen=%d fLineInUse=%d\r\n", pTG->DDI.fModemOpen, pTG->DDI.fLineInUse));
  263. ///// Do cleanup of global state //////
  264. FComOutFilterClose(pTG);
  265. FComOverlappedIO(pTG, FALSE);
  266. SWFramingSendSetup(pTG, FALSE);
  267. SWFramingRecvSetup(pTG, FALSE);
  268. FComXon(pTG, FALSE);
  269. EndMode(pTG);
  270. ///// Do cleanup of global state //////
  271. #ifdef CL0
  272. if(pTG->ModemParams.Class == FAXCLASS0)
  273. return TRUE;
  274. #endif //CL0
  275. {
  276. LPCMDTAB lpCmdTab = iModemGetCmdTabPtr(pTG);
  277. if (
  278. #ifndef MDDI
  279. (dwFlags & fMDMSYNC_DCN) &&
  280. #endif //MDDI
  281. pTG->Class1Modem.ModemMode == COMMAND
  282. && lpCmdTab
  283. && (lpCmdTab->dwFlags&fMDMSP_C1_NO_SYNC_IF_CMD) )
  284. {
  285. ERRMSG((SZMOD "<<WARNING>> ModemSync: NOT Syching modem (MSPEC)\r\n"));
  286. #ifdef WIN32
  287. Sleep(100); // +++ 4/12 JosephJ -- try to elim this -- it's juse
  288. #endif // WIN32
  289. // that we used to always issue an AT here, which
  290. // we now don't, so I issue a 100ms delay here instead.
  291. // MOST probably unnessary. The AT was issued by
  292. // accident on 4/94 -- as a side effect of
  293. // a change in T.30 code -- when ModemSync was
  294. // called just before a normal dosconnect. Unfortunately
  295. // we discovered in 4/95, 2 weeks before code freeze,
  296. // that the AT&T DataPort express (TT14), didn't
  297. // like this AT.
  298. return TRUE;
  299. }
  300. else
  301. {
  302. return (iModemPauseDialog(pTG, (LPSTR)cbszAT1, sizeof(cbszAT1)-1, ulTimeout, cbszOK)==1);
  303. }
  304. }
  305. }
  306. // Does nothing in this driver
  307. BOOL ModemFlush(PThrdGlbl pTG, HMODEM hModem)
  308. {
  309. D_PrintDDI("ModemFlush", (USHORT)hModem, 0);
  310. IF_BG_CHK(hModem==HMODEM_3 && pTG->DDI.uComPort && pTG->DDI.fModemOpen && pTG->DDI.fLineInUse && pTG->DDI.fNCUModemLinked);
  311. return TRUE;
  312. }
  313. // #if (PAGE_PREAMBLE_DIV != 0)
  314. // length of TCF = 1.5 * bpscode * 100 / 8 == 75 * bpscode / 4
  315. USHORT TCFLen[16] =
  316. {
  317. /* V27_2400 0 */ 450,
  318. /* V29_9600 1 */ 1800,
  319. /* V27_4800 2 */ 900,
  320. /* V29_7200 3 */ 1350,
  321. /* V33_14400 4 */ 2700,
  322. 0,
  323. /* V33_12000 6 */ 2250,
  324. 0,
  325. /* V17_14400 8 */ 2700,
  326. /* V17_9600 9 */ 1800,
  327. /* V17_12000 10 */ 2250,
  328. /* V17_7200 11 */ 1350,
  329. 0,
  330. 0,
  331. 0,
  332. 0
  333. };
  334. #define min(x,y) (((x) < (y)) ? (x) : (y))
  335. void SendZeros1(PThrdGlbl pTG, USHORT uCount)
  336. {
  337. #define ZERO_BUFSIZE 256
  338. BYTE bZero[ZERO_BUFSIZE];
  339. short i; // must be signed
  340. _fmemset(bZero, 0, ZERO_BUFSIZE);
  341. for(i=uCount; i>0; i -= ZERO_BUFSIZE)
  342. {
  343. // no need to stuff. They're all zeros!
  344. FComDirectAsyncWrite(pTG, bZero, (UWORD)(min((UWORD)i, (UWORD)ZERO_BUFSIZE)));
  345. }
  346. TRACE((SZMOD "Sent %d zeros\r\n", uCount));
  347. }
  348. // #endif //PAGE_PREAMBLE_DIV != 0
  349. BOOL ModemSendMode(PThrdGlbl pTG, HMODEM hModem, USHORT uMod, BOOL fHDLC, USHORT ifrHint)
  350. {
  351. #ifdef CL0
  352. if(pTG->ModemParams.Class == FAXCLASS0)
  353. return Class0ModemSendMode(pTG, hModem, fHDLC);
  354. #endif //CL0
  355. BG_CHK(ifrHint && ifrHint < ifrEND);
  356. IF_BG_CHK(hModem==HMODEM_3 && pTG->DDI.uComPort && pTG->DDI.fModemOpen && pTG->DDI.fLineInUse && pTG->DDI.fNCUModemLinked);
  357. pTG->Class1Modem.CurMod = T30toC1[uMod & 0xF];
  358. pTG->CurrentCommSpeed = T30toSpeed[uMod & 0xF];
  359. BG_CHK(pTG->Class1Modem.CurMod);
  360. if((uMod & ST_MASK) == ST_MASK) // mask selects V.17 and ST bits
  361. pTG->Class1Modem.CurMod++;
  362. // BG_CHK((pTG->Class1Modem.CurMod>24 && ModemCaps.uSendSpeeds!=V27_V29_V33_V17) ?
  363. // (SpeedtoCap[uMod & 0xF] & ModemCaps.uSendSpeeds) : 1);
  364. (MyDebugPrint(pTG, LOG_ALL, "In ModemSendMode uMod=%d CurMod=%d fHDLC=%d\r\n", uMod, pTG->Class1Modem.CurMod, fHDLC));
  365. if(uMod == V21_300)
  366. {
  367. BG_CHK(pTG->Class1Modem.CurMod == 3);
  368. _fstrcpy(pTG->Class1Modem.bCmdBuf, (LPSTR)cbszFTH3);
  369. pTG->Class1Modem.uCmdLen = sizeof(cbszFTH3)-1;
  370. pTG->Class1Modem.fHDLC = TRUE;
  371. FComXon(pTG, FALSE); // for safety. _May_ be critical
  372. }
  373. else
  374. {
  375. pTG->Class1Modem.uCmdLen = (USHORT)wsprintf(pTG->Class1Modem.bCmdBuf, cbszFTM, pTG->Class1Modem.CurMod);
  376. pTG->Class1Modem.fHDLC = FALSE;
  377. FComXon(pTG, TRUE); // critical!! Start of PhaseC
  378. // no harm doing it here(i.e before issuing +FTM)
  379. if(fHDLC)
  380. {
  381. if(!SWFramingSendSetup(pTG, TRUE))
  382. {
  383. BG_CHK(FALSE);
  384. goto error2;
  385. }
  386. }
  387. }
  388. FComOutFilterInit(pTG); // _not_ used for 300bps HDLC
  389. // but here just in case
  390. // want to do all the work _before_ issuing command
  391. pTG->Class1Modem.DriverMode = SEND;
  392. pTG->Class1Status.ifrHint = ifrHint; // need this before ModemDialog
  393. if(pTG->Class1Modem.ModemMode == FTH)
  394. {
  395. // already in send mode. This happens on Answer only
  396. BG_CHK(fHDLC && uMod==V21_300);
  397. BG_CHK(pTG->Class1Modem.CurMod==3 && pTG->Class1Modem.fHDLC == TRUE);
  398. return TRUE;
  399. }
  400. #define STARTSENDMODE_TIMEOUT 5000 // Random Timeout
  401. //// Try to cut down delay between getting CONNECT and writing the
  402. // first 00s (else modems can quit because of underrun).
  403. // Can do this by not sleeping in this. Only in fatal
  404. // cases will it lock up for too long (max 5secs). In those cases
  405. // the call is trashed too.
  406. FComCritical(pTG, TRUE); // start Crit in ModemSendMode
  407. if(!iModemNoPauseDialog(pTG, (LPB)pTG->Class1Modem.bCmdBuf, pTG->Class1Modem.uCmdLen, STARTSENDMODE_TIMEOUT, cbszCONNECT))
  408. {
  409. FComCritical(pTG, FALSE); // end Crit in ModemSendMode
  410. goto error;
  411. }
  412. // can't set this earlier. We'll trash previous value
  413. pTG->Class1Modem.ModemMode = ((uMod==V21_300) ? FTH : FTM);
  414. // Turn OFF overlapped I/O if in V.21 else ON
  415. FComOverlappedIO(pTG, uMod != V21_300);
  416. if(pTG->Class1Modem.fSendSWFraming) // set in SWFramingSendSetup
  417. {
  418. SWFramingSendPreamble(pTG, pTG->Class1Modem.CurMod);
  419. }
  420. #if (PAGE_PREAMBLE_DIV != 0)
  421. else if(pTG->Class1Modem.ModemMode == FTM)
  422. {
  423. // don't send 00s if ECM
  424. BG_CHK(ifrHint==ifrPIX_MH || ifrHint==ifrPIX_MR || ifrHint==ifrTCF);
  425. BG_CHK(PAGE_PREAMBLE_DIV);
  426. SendZeros1(pTG, (USHORT)(TCFLen[uMod & 0x0F] / PAGE_PREAMBLE_DIV));
  427. }
  428. #else
  429. else if(ifrHint==ifrPIX_MH || ifrHint==ifrPIX_MR)
  430. {
  431. // even if MDDI is on need to send some 00s otherwise
  432. // some modems underrun and hangup
  433. SendZeros1(pTG, TCFLen[uMod & 0x0F] / 2);
  434. }
  435. #endif
  436. // FComDrain(-,FALSE) causes fcom to write out any internally-
  437. // maintained buffers, but not to drain the comm-driver buffers.
  438. FComDrain(pTG, TRUE,FALSE);
  439. FComCritical(pTG, FALSE); // end Crit in ModemSendMode
  440. TRACE((SZMOD "Starting Send at %d\r\n", pTG->Class1Modem.CurMod));
  441. return TRUE;
  442. error:
  443. FComOutFilterClose(pTG);
  444. FComOverlappedIO(pTG, FALSE);
  445. SWFramingSendSetup(pTG, FALSE);
  446. error2:
  447. FComXon(pTG, FALSE); // important. Cleanup on error
  448. EndMode(pTG);
  449. return FALSE;
  450. }
  451. BOOL iModemDrain(PThrdGlbl pTG)
  452. {
  453. (MyDebugPrint(pTG, LOG_ALL, "Entering iModemDrain\r\n"));
  454. if(!FComDrain(pTG, TRUE, TRUE))
  455. return FALSE;
  456. // Must turn XON/XOFF off immediately *after* drain, but before we
  457. // send the next AT command, since recieved frames have 0x13 or
  458. // even 0x11 in them!! MUST GO AFTER the getOK ---- See BELOW!!!!
  459. // increase this---see bug number 495. Must be big enough for
  460. // COM_OUTBUFSIZE to safely drain at 2400bps(300bytes/sec = 0.3bytes/ms)
  461. // let's say (COM_OUTBUFSIZE * 10 / 3) == (COM_OUTBUFSIZE * 4)
  462. // can be quite long, because on failure we just barf anyway
  463. #ifdef CL0
  464. if(pTG->ModemParams.Class == FAXCLASS0)
  465. return TRUE;
  466. #endif //CL0
  467. #define POSTPAGEOK_TIMEOUT (10000L + (((ULONG)COM_OUTBUFSIZE) << 2))
  468. // Here we were looking for OK only, but some modems (UK Cray Quantun eg)
  469. // give me an ERROR after sending TCF or a page (at speeds < 9600) even
  470. // though the page was sent OK. So we were timing out here. Instead look
  471. // for ERROR (and NO CARRIER too--just in case!), and accept those as OK
  472. // No point returning ERROR from here, since we just abort. We can't/don't
  473. // recover from send errors
  474. // if(!iModemResp1(POSTPAGEOK_TIMEOUT, cbszOK))
  475. if(iModemResp3(pTG, POSTPAGEOK_TIMEOUT, cbszOK, cbszERROR, cbszNOCARRIER) == 0)
  476. return FALSE;
  477. // Must change FlowControl State *after* getting OK because in Windows
  478. // this call takes 500 ms & resets chips, blows away data etc.
  479. // So do this *only* when you *know* both RX & TX are empty.
  480. // check this in all usages of this function
  481. return TRUE;
  482. }
  483. BOOL iModemSendData(PThrdGlbl pTG, LPB lpb, USHORT uCount, USHORT uFlags)
  484. {
  485. BG_CHK((uFlags & SEND_ENDFRAME) == 0);
  486. BG_CHK(lpb);
  487. BG_CHK(!pTG->Class1Modem.fSendSWFraming);
  488. // if(uFlags & SEND_STUFF)
  489. {
  490. // always DLE-stuff here. Sometimes zero-stuff
  491. (MyDebugPrint(pTG, LOG_ALL, "In ModemSendData calling FComFilterAsyncWrite at %ld \n", GetTickCount() ) );
  492. if(!FComFilterAsyncWrite(pTG, lpb, uCount, FILTER_DLEZERO))
  493. goto error;
  494. }
  495. /*******
  496. else
  497. {
  498. if(!FComDirectAsyncWrite(pTG, lpb, uCount))
  499. goto error;
  500. }
  501. *******/
  502. if(uFlags & SEND_FINAL)
  503. {
  504. (MyDebugPrint(pTG, LOG_ALL, "In ModemSendData calling FComDIRECTAsyncWrite at %ld \n", GetTickCount() ) );
  505. // if(!FComDirectAsyncWrite(bDLEETXCR, 3))
  506. if(!FComDirectAsyncWrite(pTG, bDLEETX, 2))
  507. goto error;
  508. if(!iModemDrain(pTG))
  509. goto error;
  510. FComOutFilterClose(pTG);
  511. FComOverlappedIO(pTG, FALSE);
  512. FComXon(pTG, FALSE); // critical. End of PhaseC
  513. // must come after Drain
  514. EndMode(pTG);
  515. }
  516. return TRUE;
  517. error:
  518. FComXon(pTG, FALSE); // critical. End of PhaseC (error)
  519. FComFlush(pTG); // clean out the bad stuff if we got an error
  520. FComOutFilterClose(pTG);
  521. FComOverlappedIO(pTG, FALSE);
  522. EndMode(pTG);
  523. return FALSE;
  524. }
  525. BOOL iModemSendFrame(PThrdGlbl pTG, LPB lpb, USHORT uCount, USHORT uFlags)
  526. {
  527. UWORD uwResp=0;
  528. (MyDebugPrint(pTG, LOG_ALL, "Entering iModemSendFrame\r\n"));
  529. BG_CHK(uFlags & SEND_ENDFRAME);
  530. BG_CHK(lpb && uCount);
  531. BG_CHK(!pTG->Class1Modem.fSendSWFraming);
  532. // always DLE-stuff here. Never zero-stuff
  533. // This is only called for 300bps HDLC
  534. BG_CHK(pTG->Class1Modem.fHDLC && pTG->Class1Modem.CurMod == 3);
  535. if(pTG->Class1Modem.ModemMode != FTH) // Special case on just answering!!
  536. {
  537. #define FTH_TIMEOUT 5000 // Random Timeout
  538. if(!iModemNoPauseDialog(pTG, (LPB)pTG->Class1Modem.bCmdBuf, pTG->Class1Modem.uCmdLen, FTH_TIMEOUT, cbszCONNECT))
  539. goto error;
  540. }
  541. // if(uFlags & SEND_STUFF)
  542. {
  543. // always DLE-stuff here. Never zero-stuff
  544. if(!FComFilterAsyncWrite(pTG, lpb, uCount, FILTER_DLEONLY))
  545. goto error;
  546. }
  547. /***
  548. else
  549. {
  550. if(!FComDirectAsyncWrite(pTG, lpb, uCount))
  551. goto error;
  552. }
  553. ***/
  554. // if(uFlags & SEND_STUFF)
  555. {
  556. // SyncWrite call Drain here which we should not need
  557. // as we are immediately waiting for a response
  558. // if(!FComDirectSyncWrite(bDLEETX, 2))
  559. // goto error;
  560. if(!FComDirectAsyncWrite(pTG, bDLEETX, 2))
  561. goto error;
  562. }
  563. // 2000 is too short because PPRs can be 32+7 bytes long and
  564. // preamble is 1 sec, so set this to 3000
  565. // 3000 is too short because NSFs and CSIs can be arbitrarily long
  566. // MAXFRAMESIZE is defined in et30type.h. 30ms/byte at 300bps
  567. // async (I think V.21 is syn though), so use N*30+1000+slack
  568. #define WRITEFRAMERESP_TIMEOUT (1000+30*MAXFRAMESIZE+500)
  569. if(!(uwResp = iModemResp2(pTG, WRITEFRAMERESP_TIMEOUT, cbszOK, cbszCONNECT)))
  570. goto error;
  571. pTG->Class1Modem.ModemMode = ((uwResp == 2) ? FTH : COMMAND);
  572. if(uFlags & SEND_FINAL)
  573. {
  574. FComOutFilterClose(pTG);
  575. FComOverlappedIO(pTG, FALSE);
  576. // FComXon(FALSE); // at 300bps. no Xon-Xoff in use
  577. // in some weird cases (Practical Peripherals PM14400FXMT) we get
  578. // CONNECT<cr><lf>OK, but we get the CONNECT here. Should we
  579. // just set pTG->Class1Modem.ModemMode=COMMAND?? (EndMode does that)
  580. // Happens on PP 144FXSA also. Ignore it & just set mode to COMMAND
  581. // BG_CHK(pTG->Class1Modem.ModemMode == COMMAND);
  582. EndMode(pTG);
  583. }
  584. // ST_FRAMES(TRACE((SZMOD "FRAME SENT-->\r\n")); D_PrintFrame(lpb, uCount));
  585. return TRUE;
  586. error:
  587. FComOutFilterClose(pTG);
  588. FComOverlappedIO(pTG, FALSE);
  589. FComXon(pTG, FALSE); // just for safety. cleanup on error
  590. EndMode(pTG);
  591. return FALSE;
  592. }
  593. BOOL ModemSendMem(PThrdGlbl pTG, HMODEM hModem, LPBYTE lpb, USHORT uCount, USHORT uFlags)
  594. {
  595. #ifdef CL0
  596. if(pTG->ModemParams.Class == FAXCLASS0)
  597. return Class0ModemSendMem(pTG, hModem, lpb, uCount, uFlags);
  598. #endif //CL0
  599. IF_BG_CHK(hModem==HMODEM_3 && pTG->DDI.uComPort && pTG->DDI.fModemOpen && pTG->DDI.fLineInUse && pTG->DDI.fNCUModemLinked);
  600. BG_CHK(pTG->Class1Modem.CurMod);
  601. BG_CHK(lpb);
  602. (MyDebugPrint(pTG, LOG_ALL, "In ModemSendMem lpb=%08lx uCount=%d wFlags=%04x\r\n", lpb, uCount, uFlags));
  603. if(pTG->Class1Modem.DriverMode != SEND)
  604. {
  605. BG_CHK(FALSE);
  606. return FALSE;
  607. }
  608. if(pTG->Class1Modem.fSendSWFraming)
  609. return SWFramingSendFrame(pTG, lpb, uCount, uFlags);
  610. else if(pTG->Class1Modem.fHDLC)
  611. return iModemSendFrame(pTG, lpb, uCount, uFlags);
  612. else
  613. return iModemSendData(pTG, lpb, uCount, uFlags);
  614. }
  615. void TwiddleThumbs(ULONG ulTime);
  616. #ifndef MDRV
  617. void TwiddleThumbs(ULONG ulTime)
  618. {
  619. MY_TWIDDLETHUMBS(ulTime);
  620. }
  621. #endif //MDRV
  622. BOOL ModemSendSilence(PThrdGlbl pTG, HMODEM hModem, USHORT uMillisecs, ULONG ulTimeout)
  623. {
  624. //USHORT uTemp;
  625. IF_BG_CHK(hModem==HMODEM_3 && pTG->DDI.uComPort && pTG->DDI.fModemOpen && pTG->DDI.fLineInUse && pTG->DDI.fNCUModemLinked);
  626. (MyDebugPrint(pTG, LOG_ALL, "Before ModemSendSilence uMillsecs=%d ulTimeout=%ld at %ld\r\n",
  627. uMillisecs, ulTimeout, GetTickCount() ));
  628. #ifdef CL0
  629. if(pTG->ModemParams.Class == FAXCLASS0)
  630. return TRUE;
  631. #endif //CL0
  632. // we're so slow it seems we don't need to and should not do this
  633. // I measured teh dealy due to this (FTS=10) to be about 500ms,
  634. // all of it on our side (dunno why?) except exactly the 100ms
  635. // by the modem. If we really want to insert teh delay we should
  636. // use TwiddleThumbs
  637. // Can't just return here, because we do _need_ the delay between
  638. // send DCS and send TCF so that receiver is not overwhelmed
  639. // return TRUE;
  640. // use TwiddleThumbs
  641. TwiddleThumbs(uMillisecs);
  642. (MyDebugPrint(pTG, LOG_ALL, "After ModemSendSilence at %ld\r\n", GetTickCount() ));
  643. return TRUE;
  644. // uTemp = wsprintf(pTG->Class1Modem.bCmdBuf, cbszFTS, uMillisecs/10);
  645. // return (iModemNoPauseDialog((LPB)pTG->Class1Modem.bCmdBuf, uTemp, ulTimeout, cbszOK) == 1);
  646. }
  647. BOOL ModemRecvSilence(PThrdGlbl pTG, HMODEM hModem, USHORT uMillisecs, ULONG ulTimeout)
  648. {
  649. // USHORT uTemp;
  650. // CBPSTR cbpstr;
  651. D_PrintDDI("RecvSilence", (USHORT)hModem, uMillisecs);
  652. IF_BG_CHK(hModem==HMODEM_3 && pTG->DDI.uComPort && pTG->DDI.fModemOpen && pTG->DDI.fLineInUse && pTG->DDI.fNCUModemLinked);
  653. (MyDebugPrint(pTG, LOG_ALL, "Before ModemRecvSilence uMillsecs=%d ulTimeout=%ld at %ld \r\n",
  654. uMillisecs, ulTimeout, GetTickCount() ));
  655. #ifdef CL0
  656. if(pTG->ModemParams.Class == FAXCLASS0)
  657. return TRUE;
  658. #endif //CL0
  659. // can't use AT+FRS -- see above for why. Basically, we take so long
  660. // sending the command and getting teh reply etc, that we can't use
  661. // it accurately. So use TwiddleThumbs.
  662. TwiddleThumbs(uMillisecs);
  663. (MyDebugPrint(pTG, LOG_ALL, "After ModemRecvSilence at %ld \r\n", GetTickCount() ));
  664. return TRUE;
  665. // uTemp = wsprintf(pTG->Class1Modem.bCmdBuf, cbpstr, uMillisecs/10);
  666. // return (iModemNoPauseDialog((LPB)pTG->Class1Modem.bCmdBuf, uTemp, ulTimeout, cbszOK)==1);
  667. }
  668. #define MINRECVMODETIMEOUT 500
  669. #define RECVMODEPAUSE 200
  670. USHORT ModemRecvMode(PThrdGlbl pTG, HMODEM hModem, USHORT uMod, BOOL fHDLC, ULONG ulTimeout, USHORT ifrHint)
  671. {
  672. USHORT uRet;
  673. ULONG ulBefore, ulAfter, ulDelta;
  674. #ifdef CL0
  675. if(pTG->ModemParams.Class == FAXCLASS0)
  676. return Class0ModemRecvMode(pTG, hModem, fHDLC, ulTimeout);
  677. #endif //CL0
  678. // Here we should watch for a different modulation scheme from what we expect.
  679. // Modems are supposed to return a +FCERROR code to indicate this condition,
  680. // but I have not seen it from any modem yet, so we just scan for ERROR
  681. // (this will catch +FCERROR too since iiModemDialog does not expect whole
  682. // words or anything like that!), and treat both the same.
  683. pTG->Class1Modem.CurMod = T30toC1[uMod & 0xF];
  684. pTG->CurrentCommSpeed = T30toSpeed[uMod & 0xF];
  685. BG_CHK(pTG->Class1Modem.CurMod);
  686. if((uMod & ST_MASK) == ST_MASK) // mask selects V.17 and ST bits
  687. pTG->Class1Modem.CurMod++;
  688. if(uMod == V21_300)
  689. {
  690. BG_CHK(fHDLC && pTG->Class1Modem.CurMod==3);
  691. _fstrcpy(pTG->Class1Modem.bCmdBuf, (LPSTR)cbszFRH3);
  692. pTG->Class1Modem.uCmdLen = sizeof(cbszFRH3)-1;
  693. }
  694. else
  695. {
  696. pTG->Class1Modem.uCmdLen = (USHORT)wsprintf(pTG->Class1Modem.bCmdBuf, cbszFRM, pTG->Class1Modem.CurMod);
  697. }
  698. pTG->Class1Status.ifrHint = ifrHint; // need this before ModemDialog
  699. if(pTG->Class1Modem.ModemMode == FRH)
  700. {
  701. // already in receive mode. This happens upon Dial only
  702. BG_CHK(fHDLC && uMod==V21_300);
  703. BG_CHK(pTG->Class1Modem.CurMod == 3);
  704. pTG->Class1Modem.fHDLC = TRUE;
  705. pTG->Class1Modem.DriverMode = RECV;
  706. pTG->Class1Modem.fRecvNotStarted = TRUE; // fNoFlags = FALSE;
  707. // pTG->Class1Modem.sRecvBufSize = sBufSize;
  708. FComInFilterInit(pTG);
  709. return RECV_OK;
  710. }
  711. #ifdef WIN32
  712. // On Win32, we have a problem going into 2400baud recv.
  713. // +++ remember to put this into iModemFRHorM when that code is enabled.
  714. if (pTG->Class1Modem.CurMod==24) TwiddleThumbs(80);
  715. #endif // WIN32
  716. #ifdef USR_HACK
  717. uRet = iModemFRHorM(pTG, ulTimeout);
  718. #else // !USR_HACK (iModemFRHorM contains the following code..)
  719. retry:
  720. ulBefore=GetTickCount();
  721. // Don't look for NO CARRIER. Want it to retry until FRM timeout on NO CARRIER
  722. // ----This is changed. See below----
  723. uRet = iModemNoPauseDialog3(pTG, pTG->Class1Modem.bCmdBuf, pTG->Class1Modem.uCmdLen, ulTimeout, cbszCONNECT, cbszFCERROR, cbszNOCARRIER);
  724. // uRet = iModemNoPauseDialog2(pTG->Class1Modem.bCmdBuf, pTG->Class1Modem.uCmdLen, ulTimeout, cbszCONNECT, cbszFCERROR);
  725. ulAfter=GetTickCount();
  726. if(uRet==2 || uRet==3) // uRet==FCERROR or uRet==NOCARRIER
  727. {
  728. ulDelta = (ulAfter >= ulBefore) ? (ulAfter - ulBefore) : (0xFFFFFFFFL - ulBefore) + ulAfter;
  729. if(ulTimeout < (ulDelta + MINRECVMODETIMEOUT))
  730. {
  731. ERRMSG((SZMOD "<<WARNING>> Giving up on RecvMode. uRet=%d ulTimeout=%ld\r\n", uRet, ulTimeout));
  732. }
  733. else
  734. {
  735. ulTimeout -= (ulAfter-ulBefore);
  736. // need this pause for NO CARRIER for USR modems. See bug#1516
  737. // for the RC229DP, dunno if it's reqd because I dunno why theyre
  738. // giving the FCERROR. Don't want to miss the carrier so currently
  739. // don't pause. (Maybe we can achieve same effect by simply taking
  740. // FCERROR out of the response list above--but that won't work for
  741. // NOCARRIER because we _need_ teh pause. iiModemDialog is too fast)
  742. if(uRet == 3)
  743. TwiddleThumbs(RECVMODEPAUSE);
  744. BG_CHK(ulTimeout >= MINRECVMODETIMEOUT);
  745. goto retry;
  746. }
  747. }
  748. #endif // !USR_HACK
  749. (MyDebugPrint(pTG, LOG_ALL, "Ex ModemRecvMode uMod=%d CurMod=%d fHDLC=%d ulTimeout=%ld: Got=%d\r\n", uMod, pTG->Class1Modem.CurMod, fHDLC, ulTimeout, uRet));
  750. if(uRet != 1)
  751. {
  752. EndMode(pTG);
  753. if(uRet == 2)
  754. {
  755. ERRMSG((SZMOD "<<WARNING>> RecvMode:: Got FCERROR after %ldms\r\n", ulAfter-ulBefore));
  756. return RECV_WRONGMODE; // need to return quickly
  757. }
  758. else
  759. {
  760. BG_CHK(uRet == 0);
  761. ERRMSG((SZMOD "<<WARNING>> RecvMode:: Got Timeout after %ldms\r\n", ulAfter-ulBefore));
  762. return RECV_TIMEOUT;
  763. }
  764. }
  765. BG_CHK(ifrHint && ifrHint < ifrEND);
  766. IF_BG_CHK(hModem==HMODEM_3 && pTG->DDI.uComPort && pTG->DDI.fModemOpen && pTG->DDI.fLineInUse && pTG->DDI.fNCUModemLinked);
  767. BG_CHK(pTG->Class1Modem.CurMod);
  768. // BG_CHK((pTG->Class1Modem.CurMod>24 && ModemCaps.uRecvSpeeds!=V27_V29_V33_V17) ?
  769. // (SpeedtoCap[uMod & 0xF] & ModemCaps.uRecvSpeeds) : 1);
  770. if(uMod==V21_300)
  771. {
  772. pTG->Class1Modem.ModemMode = FRH;
  773. pTG->Class1Modem.fHDLC = TRUE;
  774. }
  775. else
  776. {
  777. pTG->Class1Modem.ModemMode = FRM;
  778. pTG->Class1Modem.fHDLC = FALSE;
  779. if(fHDLC)
  780. {
  781. if(!SWFramingRecvSetup(pTG, TRUE))
  782. {
  783. BG_CHK(FALSE);
  784. EndMode(pTG);
  785. return RECV_ERROR;
  786. }
  787. }
  788. }
  789. // pTG->Class1Modem.sRecvBufSize = sBufSize;
  790. pTG->Class1Modem.DriverMode = RECV;
  791. pTG->Class1Modem.fRecvNotStarted = TRUE; // fNoFlags = FALSE;
  792. FComInFilterInit(pTG);
  793. TRACE((SZMOD "Starting Recv at %d\r\n", pTG->Class1Modem.CurMod));
  794. return RECV_OK;
  795. }
  796. #ifdef CL0
  797. void ModemEndRecv(PThrdGlbl pTG, HMODEM hModem)
  798. {
  799. #ifdef CL0
  800. if(pTG->ModemParams.Class == FAXCLASS0)
  801. Class0ModemEndRecv(pTG, hModem);
  802. #endif //CL0
  803. }
  804. #endif //CL0
  805. USHORT iModemRecvData(PThrdGlbl pTG, LPB lpb, USHORT cbMax, ULONG ulTimeout, USHORT far* lpcbRecv)
  806. {
  807. SWORD swEOF;
  808. USHORT uRet;
  809. BG_CHK(pTG->Class1Modem.ModemMode == FRM);
  810. BG_CHK(lpb && cbMax && lpcbRecv);
  811. BG_CHK(!pTG->Class1Modem.fRecvSWFraming);
  812. startTimeOut(pTG, &(pTG->Class1Modem.toRecv), ulTimeout);
  813. // 4th arg must be FALSE for Class1
  814. *lpcbRecv = FComFilterReadBuf(pTG, lpb, cbMax, &(pTG->Class1Modem.toRecv), FALSE, &swEOF);
  815. if(swEOF == -1)
  816. {
  817. // we got a DLE-ETX _not_ followed by OK or NO CARRIER. So now
  818. // we have to decide whether to (a) declare end of page (swEOF=1)
  819. // or (b) ignore it & assume page continues on (swEOF=0).
  820. //
  821. // The problem is that some modems produce spurious EOL during a page
  822. // I believe this happens due a momentary loss of carrier that they
  823. // recover from. For example IFAX sending to the ATI 19200. In those
  824. // cases we want to do (b). The opposite problem is that we'll run
  825. // into a modem whose normal response is other than OK or NO CARRIER.
  826. // Then we want to do (a) because otherwise we'll _never_ work with
  827. // that modem.
  828. //
  829. // So we have to either do (a) always, or have an INI setting that
  830. // can force (a), which could be set thru the AWMODEM.INF file. But
  831. // we also want to do (b) if possible because otehrwise we'll not be
  832. // able to recieve from weak or flaky modems or machines or whatever
  833. //
  834. // Snowball does (b). I believe best soln is an INI setting, with (b)
  835. // as default
  836. // option (a)
  837. // ERRMSG((SZMOD "<<WARNING>> Got arbitrary DLE-ETX. Assuming END OF PAGE!!!\r\n"));
  838. // swEOF = 1;
  839. // option (b)
  840. ERRMSG((SZMOD "<<WARNING>> Got arbitrary DLE-ETX. Ignoring\r\n"));
  841. swEOF = 0;
  842. }
  843. BG_CHK(swEOF == 0 || swEOF == 1 || swEOF == -2 || swEOF == -3);
  844. switch(swEOF)
  845. {
  846. case 1: uRet = RECV_EOF; break;
  847. case 0: return RECV_OK;
  848. default: BG_CHK(FALSE); // fall through
  849. case -2: uRet = RECV_ERROR; break;
  850. case -3: uRet = RECV_TIMEOUT; break;
  851. }
  852. EndMode(pTG);
  853. return uRet;
  854. }
  855. const static BYTE LFCRETXDLE[4] = { LF, CR, ETX, DLE };
  856. USHORT iModemRecvFrame(PThrdGlbl pTG, LPB lpb, USHORT cbMax, ULONG ulTimeout, USHORT far* lpcbRecv)
  857. {
  858. SWORD swRead, swRet;
  859. USHORT i;
  860. BOOL fRestarted=0;
  861. USHORT uRet;
  862. BOOL fGotGoodCRC = 0; // see comment-block below
  863. /** Sometimes modems give use ERROR even when thr frame is good.
  864. Happens a lot from Thought to PP144MT on CFR. So we check
  865. the CRC. If the CRc was good and everything else looks good
  866. _except_ the "ERROR" response from teh modem then return
  867. RECV_OK, not RECV_BADFRAME.
  868. This should fix BUG#1218
  869. **/
  870. BG_CHK(lpb && cbMax && lpcbRecv);
  871. restart:
  872. *lpcbRecv=0;
  873. if(pTG->Class1Modem.ModemMode!= FRH)
  874. {
  875. #ifdef USR_HACK
  876. swRet = iModemFRHorM(pTG, ulTimeout);
  877. #else // !USR_HACK
  878. swRet=iModemNoPauseDialog2(pTG, (LPB)pTG->Class1Modem.bCmdBuf, pTG->Class1Modem.uCmdLen, ulTimeout, cbszCONNECT, cbszNOCARRIER);
  879. #endif // !USR_HACK
  880. if(swRet==2||swRet==3)
  881. {
  882. (MyDebugPrint(pTG, LOG_ALL, "Got NO CARRIER from FRH=3\r\n"));
  883. EndMode(pTG);
  884. return RECV_EOF;
  885. }
  886. else if(swRet != 1)
  887. {
  888. ERRMSG((SZMOD "<<WARNING>> Can't get CONNECT from FRH=3\r\n"));
  889. EndMode(pTG);
  890. return RECV_TIMEOUT; // may not need this, since we never got flags??
  891. // actually we dont know what the heck we got!!
  892. }
  893. }
  894. pTG->Class1Modem.fRecvNotStarted = FALSE; // fNoFlags = FALSE;
  895. /*** Got CONNECT (i.e. flags). Now try to get a frame ***/
  896. /****************************************************************
  897. * Using 3 secs here is a misinterpretation of the T30 CommandReceived?
  898. * flowchart. WE want to wait here until we get something or until T2
  899. * or T4 timeout. It would have been best if we started T2 ot T4 on
  900. * entry into the search routine (t30.c), but starting it here is good
  901. * enough.
  902. * Using this 3secs timeout fails when Genoa simulates a bad frame
  903. * because Zoom PKT modem gives us a whole raft of bad frames for one
  904. * bad PPS-EOP and then gives a CONNECT that we timeout below exactly
  905. * as the sender's T4 timeout expires and he re-sends the PPS-EOP
  906. * so we miss all of them.
  907. * Alternately, we could timeout here on 2sec & retry. But that's risky
  908. * If less than 2sec then we'll timeout on modems that give connect
  909. * first flag, then 2sec elapse before CR-LF (1sec preamble & 1sec for
  910. * long frames, e.g. PPR!)
  911. ****************************************************************/
  912. // #define TIMEOUT_3SECS 3000L
  913. // startTimeOut(&(pTG->Class1Modem.toRecv), TIMEOUT_3SECS);
  914. startTimeOut(pTG, &(pTG->Class1Modem.toRecv), ulTimeout);
  915. swRead = FComFilterReadLine(pTG, lpb, cbMax, &(pTG->Class1Modem.toRecv));
  916. pTG->Class1Modem.ModemMode = COMMAND;
  917. // may change this to FRH if we get CONNECT later.
  918. // but set it here just in case we short circuit out due to errors
  919. if(swRead<=0)
  920. {
  921. // Timeout
  922. ERRMSG((SZMOD "<<WARNING>> Can't get frame after connect. Got-->\r\n"));
  923. D_HexPrint(lpb, (WORD)-swRead);
  924. EndMode(pTG);
  925. *lpcbRecv = -swRead;
  926. return RECV_ERROR; // goto error;
  927. }
  928. faxT2log(("FRAME>>> \r\n"));
  929. ST_FRAMES(D_HexPrint(lpb, swRead));
  930. for(i=0, swRead--; i<4 && swRead>=0; i++, swRead--)
  931. {
  932. if(lpb[swRead] != LFCRETXDLE[i])
  933. break;
  934. }
  935. // exits when swRead is pointing to last non-noise char
  936. // or swRead == -1
  937. // incr by 1 to give actual non-noise data size.
  938. // (size = ptr to last byte + 1!)
  939. swRead++;
  940. // Hack for AT&T AK144 modem that doesn't send us the CRC
  941. // only lop off last 2 bytes IFF the frame is >= 5 bytes long
  942. // that will leave us at least the FF 03/13 FCF
  943. // if(i==4 && swRead>=2) // i.e. found all of DLE-ETX_CR-LF
  944. // 09/25/95 This code was changed to never lop of the CRC.
  945. // All of the routines except NSxtoBC can figure out the correct length,
  946. // and that way if the modem doesn't pass on the CRC, we no longer
  947. // lop off the data.
  948. // NSxtoBC has been changed to expect the CRC.
  949. // we really want this CRC-checking in the MDDI case too
  950. // #ifdef MDDI
  951. // if(i==4 && swRead>=5) // i.e. found all of DLE-ETX_CR-LF
  952. // {
  953. // swRead -= 2; // get rid of CRC
  954. // uRet = RECV_OK;
  955. // }
  956. // #else //MDDI
  957. if(i==4) // i.e. found all of DLE-ETX_CR-LF
  958. {
  959. // Determine if the frame has the CRC or not..
  960. // (AT&T and NEC modems don't have them)
  961. if (pTG->Class1Modem.eRecvFCS != RECV_FCS_NO)
  962. {
  963. if (swRead > 2)
  964. {
  965. #ifdef PORTABLE_CODE
  966. WORD wCRCgot = *(UNALIGNED WORD FAR*)(lpb+swRead-2); // +++alignment
  967. #else
  968. WORD wCRCgot = *(LPWORD)(lpb+swRead-2); // +++alignment
  969. #endif
  970. WORD wCRCcalc;
  971. // Elliot bug 1811: TI PCMCIA modem TI1411 sends control byte twice
  972. // instead of address (0xff) followed by control.
  973. // So we correct for that here...
  974. if (lpb[0]==lpb[1] && (*lpb==0x3 || *lpb==0x13))
  975. {
  976. ERRMSG((SZMOD
  977. "<<WARNING>> V.21 w/ wrong address:%04x.\r\n"
  978. "\t\tZapping 1st byte with 0xff.\r\n",
  979. (unsigned)*lpb));
  980. *lpb = 0xff;
  981. }
  982. wCRCcalc = CalcCRC(pTG, lpb, (USHORT) (swRead-2));
  983. if (wCRCgot==wCRCcalc)
  984. {
  985. // swRead -=2;
  986. fGotGoodCRC = TRUE;
  987. }
  988. else
  989. {
  990. #define MUNGECRC(crc) MAKEWORD(LOBYTE(crc),\
  991. (HIBYTE(crc)<<2)|(LOBYTE(crc)>>6))
  992. ERRMSG((SZMOD
  993. "<<WARNING>> V.21 CRC mismatch. Got 0x%04x."
  994. " Want 0x%04x\r\n",
  995. (unsigned) wCRCgot, (unsigned) wCRCcalc ));
  996. // MC1411, MH9611 hack...
  997. if (wCRCgot == MUNGECRC(wCRCcalc))
  998. {
  999. ERRMSG((SZMOD
  1000. "<<WARNING>> mutant V.21 CRC:%04x\r\n",
  1001. MUNGECRC(wCRCcalc)));
  1002. // swRead -=2;
  1003. fGotGoodCRC = TRUE;
  1004. }
  1005. // Elliot bug 2659: PP PM288MT II V.34 adds a flag (0x7e) to the END
  1006. // Of every V.21 flag it receives! So we check for this special case.
  1007. else if (swRead>3 && *(lpb+swRead-1)==0x7e)
  1008. {
  1009. ERRMSG((SZMOD
  1010. "<<WARNING>> Last byte == 0x7e\r\n"));
  1011. #ifdef PORTABLE_CODE
  1012. wCRCgot = *(UNALIGNED WORD FAR*)(lpb+swRead-3);
  1013. #else
  1014. wCRCgot = *(LPWORD)(lpb+swRead-3);
  1015. #endif
  1016. wCRCcalc = CalcCRC(pTG, lpb, (USHORT) (swRead-3));
  1017. ERRMSG((SZMOD
  1018. "<<WARNING>> Final flag? New Calc:%04x;Got=%04x\r\n",
  1019. (unsigned) wCRCcalc,
  1020. (unsigned) wCRCgot));
  1021. if (wCRCgot==wCRCcalc)
  1022. {
  1023. // swRead -=3;
  1024. swRead--;
  1025. fGotGoodCRC = TRUE;
  1026. }
  1027. }
  1028. else if (pTG->Class1Modem.eRecvFCS == RECV_FCS_NOCHK)
  1029. {
  1030. ERRMSG((SZMOD
  1031. "<<WARNING>> ASSUMING BAD V.21 CRC\r\n"));
  1032. // swRead -=2;
  1033. }
  1034. else
  1035. {
  1036. ERRMSG((SZMOD
  1037. "<<WARNING>> no/bad V.21 CRC\r\n"));
  1038. }
  1039. }
  1040. }
  1041. }
  1042. uRet = RECV_OK;
  1043. }
  1044. // #endif //MDDI
  1045. else
  1046. {
  1047. ERRMSG((SZMOD "<<WARNING>> Frame doesn't end in dle-etx-cr-lf\r\n"));
  1048. // leave tast two bytes in. We don't *know* it's a CRC, since
  1049. // frame ending was non-standard
  1050. uRet = RECV_BADFRAME;
  1051. }
  1052. *lpcbRecv = swRead;
  1053. // check if it is the NULL frame (i.e. DLE-ETX-CR-LF) first.
  1054. // (check is: swRead==0 and uRet==RECV_OK (see above))
  1055. // if so AND if we get OK or CONNECT or ERROR below then ignore
  1056. // it completely. The Thought modem and the PP144MT generate
  1057. // this poor situation! Keep a flag to avoid a possible
  1058. // endless loop
  1059. // broaden this so that we Restart on either a dle-etx-cr-lf
  1060. // NULL frame or a simple cr-lf NULL frame. But then we need
  1061. // to return an ERROR (not BADFRAME) after restarting once,
  1062. // otheriwse there is an infinite loop with T30 calling us
  1063. // again and again (see bug#834)
  1064. // chnage yet again. This takes too long, and were trying to tackle
  1065. // a specific bug (the PP144MT) bug here, so let's retsrat only
  1066. // on dle-etx-cr-lf (not just cr-lf), and in teh latter case
  1067. // return a response according to what we get
  1068. BG_CHK(uRet==RECV_OK || uRet==RECV_BADFRAME);
  1069. /*** Got Frame. Now try to get OK or ERROR. Timeout=0! ***/
  1070. switch(swRet = iModemResp4(pTG, 0, cbszOK, cbszCONNECT, cbszNOCARRIER, cbszERROR))
  1071. {
  1072. case 2: pTG->Class1Modem.ModemMode = FRH;
  1073. // fall through and do exactly like OK!!
  1074. case 1: // ModemMode already == COMMAND
  1075. if(swRead<=0 && uRet==RECV_OK && !fRestarted)
  1076. {
  1077. ERRMSG((SZMOD "<<WARNING>> Got %d after frame. RESTARTING\r\n", swRet));
  1078. fRestarted = 1;
  1079. goto restart;
  1080. }
  1081. //uRet already set
  1082. break;
  1083. case 3: // NO CARRIER. If got null-frame or no frame return
  1084. // RECV_EOF. Otherwise if got OK frame then return RECV_OK
  1085. // and return frame as usual. Next time around it'll get a
  1086. // NO CARRIER again (hopefully) or timeout. On a bad frame
  1087. // we can return RECV_EOF, but this will get into trouble if
  1088. // the recv is not actually done. Or return BADFRAME, and hope
  1089. // for a NO CARRIER again next time. But next time we may get a
  1090. // timeout. ModemMode is always set to COMMAND (already)
  1091. ERRMSG((SZMOD "<<WARNING>> Got NO CARRIER after frame. swRead=%d uRet=%d\r\n", swRead, uRet));
  1092. if(swRead <= 0)
  1093. uRet = RECV_EOF;
  1094. // else uRet is already BADFRAME or OK
  1095. break;
  1096. // this is bad!!
  1097. // alternately:
  1098. // if(swRead<=0 || uRet==RECV_BADFRAME)
  1099. // {
  1100. // uRet = RECV_EOF;
  1101. // *lpcbRecv = 0; // must return 0 bytes with RECV_EOF
  1102. // }
  1103. case 4: // ERROR
  1104. if(swRead<=0)
  1105. {
  1106. // got no frame
  1107. if(uRet==RECV_OK && !fRestarted)
  1108. {
  1109. // if we got dle-etx-cr-lf for first time
  1110. ERRMSG((SZMOD "<<WARNING>> Got ERROR after frame. RESTARTING\r\n"));
  1111. fRestarted = 1;
  1112. #ifdef USR_HACK
  1113. TwiddleThumbs(RECVMODEPAUSE);
  1114. #endif //USR_HACK
  1115. goto restart;
  1116. }
  1117. else
  1118. uRet = RECV_ERROR;
  1119. }
  1120. else
  1121. {
  1122. // if everything was OK until we got the "ERROR" response from
  1123. // the modem and we got a good CRC then treat it as "OK"
  1124. // This should fix BUG#1218
  1125. if(uRet==RECV_OK && fGotGoodCRC)
  1126. uRet = RECV_OK;
  1127. else
  1128. uRet = RECV_BADFRAME;
  1129. }
  1130. ERRMSG((SZMOD "<<WARNING>> Got ERROR after frame. swRead=%d uRet=%d\r\n", swRead, uRet));
  1131. break;
  1132. case 0: // timeout
  1133. ERRMSG((SZMOD "<<WARNING>> Got TIMEOUT after frame. swRead=%d uRet=%d\r\n", swRead, uRet));
  1134. // if everything was OK until we got the timeout from
  1135. // the modem and we got a good CRC then treat it as "OK"
  1136. // This should fix BUG#1218
  1137. if(uRet==RECV_OK && fGotGoodCRC)
  1138. uRet = RECV_OK;
  1139. else
  1140. uRet = RECV_BADFRAME;
  1141. break;
  1142. }
  1143. return uRet;
  1144. }
  1145. USHORT ModemRecvMem(PThrdGlbl pTG, HMODEM hModem, LPBYTE lpb, USHORT cbMax, ULONG ulTimeout, USHORT far* lpcbRecv)
  1146. {
  1147. USHORT uRet;
  1148. #ifdef CL0
  1149. if(pTG->ModemParams.Class == FAXCLASS0)
  1150. return Class0ModemRecvMem(pTG, hModem, lpb, cbMax, ulTimeout, lpcbRecv);
  1151. #endif //CL0
  1152. IF_BG_CHK((WORD)hModem==3 && pTG->DDI.uComPort && pTG->DDI.fModemOpen && pTG->DDI.fLineInUse && pTG->DDI.fNCUModemLinked);
  1153. BG_CHK(pTG->Class1Modem.CurMod);
  1154. BG_CHK(lpb && cbMax && lpcbRecv);
  1155. (MyDebugPrint(pTG, LOG_ALL, "In ModemRecvMem lpb=%08lx cbMax=%d ulTimeout=%ld\r\n", lpb, cbMax, ulTimeout));
  1156. if(pTG->Class1Modem.DriverMode != RECV)
  1157. {
  1158. BG_CHK(FALSE);
  1159. return RECV_ERROR; // see bug#1492
  1160. }
  1161. *lpcbRecv=0;
  1162. if(pTG->Class1Modem.fRecvSWFraming)
  1163. uRet = SWFramingRecvFrame(pTG, lpb, cbMax, ulTimeout, lpcbRecv);
  1164. else if(pTG->Class1Modem.fHDLC)
  1165. uRet = iModemRecvFrame(pTG, lpb, cbMax, ulTimeout, lpcbRecv);
  1166. else
  1167. uRet = iModemRecvData(pTG, lpb, cbMax, ulTimeout, lpcbRecv);
  1168. (MyDebugPrint(pTG, LOG_ALL, "Ex ModemRecvMem lpbf=%08lx uCount=%d uRet=%d\r\n", lpb, *lpcbRecv, uRet));
  1169. return uRet;
  1170. }
  1171. #ifdef USR_HACK
  1172. USHORT iModemFRHorM(PThrdGlbl pTG, ULONG ulTimeout)
  1173. {
  1174. ULONG ulBefore, ulAfter, ulDelta;
  1175. USHORT uRet;
  1176. retry:
  1177. ulBefore=GetTickCount();
  1178. // Don't look for NO CARRIER. Want it to retry until FRM timeout on NO CARRIER
  1179. // ----This is changed. See below----
  1180. uRet = iModemNoPauseDialog3(pTG, pTG->Class1Modem.bCmdBuf, pTG->Class1Modem.uCmdLen, ulTimeout, cbszCONNECT, cbszFCERROR, cbszNOCARRIER);
  1181. // uRet = iModemNoPauseDialog2(pTG, pTG->Class1Modem.bCmdBuf, pTG->Class1Modem.uCmdLen, ulTimeout, cbszCONNECT, cbszFCERROR);
  1182. ulAfter=GetTickCount();
  1183. if(uRet==2 || uRet==3) // uRet==FCERROR or uRet==NOCARRIER
  1184. {
  1185. ulDelta = (ulAfter >= ulBefore) ? (ulAfter - ulBefore) : (0xFFFFFFFFL - ulBefore) + ulAfter;
  1186. if(ulTimeout < (ulDelta + MINRECVMODETIMEOUT))
  1187. {
  1188. ERRMSG((SZMOD "<<WARNING>> Giving up on RecvMode. uRet=%d ulTimeout=%ld\r\n", uRet, ulTimeout));
  1189. }
  1190. else
  1191. {
  1192. ulTimeout -= (ulAfter-ulBefore);
  1193. // need this pause for NO CARRIER for USR modems. See bug#1516
  1194. // for the RC229DP, dunno if it's reqd because I dunno why theyre
  1195. // giving the FCERROR. Don't want to miss the carrier so currently
  1196. // don't pause. (Maybe we can achieve same effect by simply taking
  1197. // FCERROR out of the response list above--but that won't work for
  1198. // NOCARRIER because we _need_ teh pause. iiModemDialog is too fast)
  1199. if(uRet == 3)
  1200. TwiddleThumbs(RECVMODEPAUSE);
  1201. BG_CHK(ulTimeout >= MINRECVMODETIMEOUT);
  1202. goto retry;
  1203. }
  1204. }
  1205. return uRet;
  1206. }
  1207. #endif // USR_HACK