/*************************************************************************** Name : T30.C Comment : Contains the main T30 routine, which drives this whole baby. It calls the user-supplied protocol function to make all the protocol decision functions. Thus in a sense this merely a hollow shell. This file should be read together with the appropriate protocol function that is in use, and the T30 flowchart (the enhanced one which includes ECM that is supplied in T.30 Appendix-A). Ideally the (paper) copy of the chart which I've annotated to chow which nodes are implemented in the protocol callback function. The other routines contained here implement the T.30 flowchart "subroutines" labelled "Response Received" "Command Received", "RR Response Received" and "CTC Response Received". All of which are called (only) from ET30MainBody(). Most of teh real work is farmed out to HDLC.C (and macros in HDLC.H), so the T30 routine is reasonably lucid. It's organized as a block of statements with gotos between them to closely mirror the T30 flowchart. (It's actually uncannily close!) Functions: (see Prototypes just below) Revision Log Date Name Description -------- ----- --------------------------------------------------------- 06/14/92 arulm Created it in the new incarnation for the first time. The T30Main() function is re-written to call WhatNext() at *all* decision points. Some parts are simplified. It bears some resemblance to the original. Command/ResponseReceived is completely re-written. 06/15/92 arulm Added ECM. Still havn't tried compiling it. 06/16/92 arulm First successful compile. ***************************************************************************/ #include "prep.h" #include "efaxcb.h" #include "t30.h" #include "hdlc.h" #include "..\comm\modemint.h" #include "..\comm\fcomint.h" #include "..\comm\mdmcmds.h" #include "debug.h" #include "tiff.h" #include "glbproto.h" #include "t30gl.h" #define faxTlog(m) DEBUGMSG(ZONE_T30, m) #define faxT2log(m) DEBUGMSG(ZONE_FRAMES, m) #define FILEID FILEID_T30 #ifdef MDDI // zero-stuffing # define SetStuffZERO(x) T30SetStuffZERO(x) extern void T30SetStuffZERO(PThrdGlbl pTG, USHORT cbLineMin); extern BOOL FilterSendMem(PThrdGlbl pTG, HMODEM h, LPBYTE lpb, USHORT uCount); #else # define SetStuffZERO(pTG, x) FComSetStuffZERO(pTG, x) # define FilterSendMem(pTG, h, lpb, uCnt) ModemSendMem(pTG, h, lpb, uCnt, 0) #endif #ifdef DEBUG # define TIMESTAMP(str) \ faxTlog((SZMOD "TIMESTAMP %lu %s--\r\n", (unsigned long) GetTickCount(), (LPSTR) (str))); #else // !DEBUG # define TIMESTAMP(str) #endif // !DEBUG /*************************************************************************** Name : ET30MainBody Purpose : This is the main T30. It's main purpose is to faithfully reproduce the flowchart on pages 100-103 of Fascicle VII.3 of the CCITT blue book, Recomendation T30. It is to be called from the protocol module after a call has been successfully placed or answered & the modem is in HDLC receive or send mode respectively. It conducts the entire call, making callbacks at all decision points to a protocol-supplied callback function. It also calls protocol-supplied callback functions to get data to send and to unload received data. Returns : When it returns, the phone is on hook & the modem reset. It returns TRUE on successful call completion, and FALSE on error. In all cases, GetLastError() will return the completion status. Arguments: Comment : This function is supposed to mirror the flowchart so it is structured as a series of statement blocks and a rats nest of Gotos. Yes I hate GOTOs too. Havn't used one in years, but try to do this yourself sometime in a "structured" way. The Labels used are the same as those used in the Flowchart, and the blocks are arranged in approximately teh same order as in the chart, so reading both together will be a pleasant surprise. Make sure you use the chart in the __APPENDIX-A__ of the **1988** (or Blue Book) CCITT specs. The chart in teh main body of teh spec is (a) deceptively similar (b) out-of-date Calls : All of HDLC.C, some of MODEM.C, and a little of FCOM.C. all the rest of the functions in this file. Called By: Revision Log Date Name Description -------- ----- --------------------------------------------------------- 06/15/92 arulm Adding ECM. Making it compilable ***************************************************************************/ #ifdef MDDI # // Ricohs protocol tester complains if this exceeds 40secs # define T1_TIMEOUT 35000L // use exact 35s nominal value #else # define T1_TIMEOUT 40000L // 35s + 5s. On PCs be more lax #endif // #define T2_TIMEOUT 7000 // 6s + 1s #define T2_TIMEOUT 6000 // 6s #define T3_TIMEOUT 15000L // 10s + 5s // #define T4_TIMEOUT 3450 // 3s + 15% #define T4_TIMEOUT 3000 // 3s // #define T4_TIMEOUT 2550 // 3s - 15% // if our DCS-TCF collides with the recvrs 2nd NSF-DIS or NSC-DTC // then if the lengths are just right, we can end up in lock step // after the first try, increase the TCF-response timeout so we // get out of lock step! This is bug#6847 #define TCFRESPONSE_TIMEOUT_SLACK 500 // 0.5 secs /****************** begin prototypes from t30.c *****************/ ET30ACTION PhaseNodeA(PThrdGlbl pTG); ET30ACTION PhaseNodeT(PThrdGlbl pTG); ET30ACTION PhaseNodeD(PThrdGlbl pTG, BOOL); ET30ACTION NonECMPhaseC(PThrdGlbl pTG ); ET30ACTION NonECMPhaseD(PThrdGlbl pTG ); ET30ACTION RecvPhaseB(PThrdGlbl pTG, ET30ACTION action); ET30ACTION PhaseNodeF(PThrdGlbl pTG, BOOL, BOOL); ET30ACTION PhaseRecvCmd(PThrdGlbl pTG ); ET30ACTION PhaseGetTCF(PThrdGlbl pTG, IFR, BOOL); ET30ACTION NonECMRecvPhaseC(PThrdGlbl pTG); ET30ACTION NonECMRecvPhaseD(PThrdGlbl pTG); /***************** end of prototypes from t30.c *****************/ USHORT T30MainBody(PThrdGlbl pTG, BOOL fCaller, ET30ACTION actionInitial, HLINE hLine, HMODEM hModem ) { ET30ACTION action; USHORT uRet; BOOL fEnteredHalfway; uRet = T30_CALLFAIL; FComCriticalNeg(pTG, TRUE); (MyDebugPrint(pTG, LOG_ALL, "\r\n\r\n\r\n\r\n\r\n======================= Entering MainBody ==============================\r\n\r\n\r\n\r\n")); // zero-init the 3 global structs T30, ECM and Params. After this some // fields are inited to non-zero below. Rest are set approp elsewhere // in the code (hopefully before use :-) _fmemset(&pTG->Params, 0, sizeof(pTG->Params)); _fmemset(&pTG->T30, 0, sizeof(pTG->T30)); _fmemset(&pTG->ECM, 0, sizeof(pTG->ECM)); _fmemset(&pTG->EchoProtect, 0, sizeof(pTG->EchoProtect)); pTG->Params.hModem = hModem; pTG->Params.hLine = hLine; pTG->Params.lpfnWhatNext = ProtGetWhatNext(pTG); // INI file settings related stuff pTG->T30.uSkippedDIS = 0; // Initialize this global. Very Important!! See HDLC.C for usage. pTG->T30.fReceivedDIS = FALSE; pTG->T30.fReceivedDTC = FALSE; pTG->T30.fReceivedEOM = FALSE; pTG->T30.uTrainCount = 0; pTG->T30.uRecvTCFMod = 0xFFFF; pTG->T30.ifrCommand = pTG->T30.ifrResp = pTG->T30.ifrSend = 0; pTG->ECM.ifrPrevResponse = 0; pTG->ECM.SendPageCount = 0; pTG->ECM.fEndOfPage = pTG->ECM.fRecvEndOfPage = TRUE; pTG->T30.fAtEndOfRecvPage = FALSE; pTG->ECM.fSentCTC = FALSE; pTG->ECM.fRecvdCTC = FALSE; #ifdef SMM pTG->T30.lpfs = (LPFRAMESPACE)pTG->bStaticRecvdFrameSpace; #else #error NYI ERROR: Code Not Complete--Have to pick GMEM_ flags (FIXED? SHARE?) ...also have to call IFProcSetResFlags(hinstMe)..... pTG->T30.lpfs = (LPFRAMESPACE)IFMemAlloc(0,TOTALRECVDFRAMESPACE, &uwJunk); #endif pTG->T30.Nframes = 0; fEnteredHalfway = FALSE; if(actionInitial != actionNULL) { (MyDebugPrint(pTG, LOG_ERR, "<> Got Initial Action = %d\r\n", actionInitial)); action = actionInitial; fEnteredHalfway = TRUE; BG_CHK(action==actionGONODE_F || action==actionGONODE_D); } else if(fCaller) // choose the right entry point action = actionGONODE_T; else { action = actionGONODE_R1; pTG->T30.fSendAfterSend = TRUE; // CED--NSF/DIS } // fall through into PhaseLoop /******** Phase loop ********/ //PhaseLoop: for(;;) { /****************************************************************************** T = Start of Phase be for transmitter R1 = Start of Phase B for callee R2 = start of Phase B for poller A = Poll/Send decision point D = Start of DCS/TCF F = Recv Command loop RecvCmd = Interpretation of pre-page cmds RecvPhaseC = Start of Rx PhaseC (ECM and Non-pTG->ECM. New Page in ECM mode) I = Start of Tx PhaseC (ECM & Non-pTG->ECM. New page in ECM mode) II = Start of Tx Non-ECM PhaseD III = Start of Rx Non-ECM PhaseD IV = Start of Tx ECM PhaseC (Same page, new block) V = Start of Tx ECM PhaseD (end of partial page) VII = Start of Rx ECM PhaseD RecvPRIQ = Handling of recvd PRI-Q commands E = Handling of received PIP/PIN responses *******************************************************************************/ switch(action) { case actionGONODE_T: (MyDebugPrint(pTG, LOG_ALL, "EndPhase: Got actionGONODE_T\r\n")); action = PhaseNodeT(pTG); break; case actionGONODE_D: (MyDebugPrint(pTG, LOG_ALL, "EndPhase: Got actionGONODE_D\r\n")); action = PhaseNodeD(pTG, fEnteredHalfway); fEnteredHalfway = FALSE; break; case actionGONODE_A: (MyDebugPrint(pTG, LOG_ALL, "EndPhase: Got actionGONODE_A\r\n")); action = PhaseNodeA(pTG); break; case actionGONODE_R1: (MyDebugPrint(pTG, LOG_ALL, "EndPhase: Got actionGONODE_R1\r\n")); action = RecvPhaseB(pTG, action); break; case actionGONODE_R2: (MyDebugPrint(pTG, LOG_ALL, "EndPhase: Got actionGONODE_R2\r\n")); action = RecvPhaseB(pTG, action); break; case actionNODEF_SUCCESS: (MyDebugPrint(pTG, LOG_ALL, "EndPhase: Got actionNODEF_SUCCESS\r\n")); action = PhaseNodeF(pTG, TRUE, FALSE); break; case actionGONODE_F: (MyDebugPrint(pTG, LOG_ALL, "EndPhase: Got actionGONODE_F\r\n")); action = PhaseNodeF(pTG, FALSE, fEnteredHalfway); fEnteredHalfway = FALSE; break; case actionGONODE_RECVCMD: (MyDebugPrint(pTG, LOG_ALL, "EndPhase: Got actionGONODE_RECVCMD\r\n")); action = PhaseRecvCmd(pTG); break; case actionGONODE_I: (MyDebugPrint(pTG, LOG_ALL, "EndPhase: Got actionGONODE_I\r\n")); action = NonECMPhaseC(pTG); break; case actionGONODE_II: (MyDebugPrint(pTG, LOG_ALL, "EndPhase: Got actionGONODE_II\r\n")); action = NonECMPhaseD(pTG); break; case actionGONODE_III: (MyDebugPrint(pTG, LOG_ALL, "EndPhase: Got actionGONODE_III\r\n")); action = NonECMRecvPhaseD(pTG); break; case actionGONODE_IV: (MyDebugPrint(pTG, LOG_ALL, "EndPhase: Got actionGONODE_IV_New\r\n")); action = ECMPhaseC(pTG, FALSE); // ReTx break; case actionGONODE_ECMRETRANSMIT: (MyDebugPrint(pTG, LOG_ALL, "EndPhase: Got actionGONODE_ECMRETRANSMIT\r\n")); action = ECMPhaseC(pTG, TRUE); // ReTx break; case actionGONODE_V: (MyDebugPrint(pTG, LOG_ALL, "EndPhase: Got actionGONODE_V\r\n")); action = ECMPhaseD(pTG); break; case actionSENDEOR_EOP: (MyDebugPrint(pTG, LOG_ALL, "EndPhase: Got actionSENDEOR_EOP\r\n")); action = ECMSendEOR_EOP(pTG); break; case actionGONODE_VII: (MyDebugPrint(pTG, LOG_ALL, "EndPhase: Got actionGONODE_VII\r\n")); action = ECMRecvPhaseD(pTG); break; case actionGONODE_RECVPHASEC: // (MyDebugPrint(pTG, LOG_ALL, "EndPhase: Got actionGONODE_RECVPHASEC\r\n")); /**/ if(ProtReceivingECM(pTG)) action = ECMRecvPhaseC(pTG, FALSE); else /**/ action = NonECMRecvPhaseC(pTG); break; case actionGONODE_RECVECMRETRANSMIT: // (MyDebugPrint(pTG, LOG_ALL, "EndPhase: Got actionGONODE_RECVECMRETRANSMIT\r\n")); BG_CHK(ProtReceivingECM(pTG)); action = ECMRecvPhaseC(pTG, TRUE); break; case actionNULL: BG_CHK(FALSE); goto error; case actionDCN_SUCCESS: (MyDebugPrint(pTG, LOG_ALL, "EndPhase: Got actionDCN_SUCCESS\r\n")); uRet = T30_CALLDONE; goto NodeC; // successful end of send call case actionHANGUP_SUCCESS: (MyDebugPrint(pTG, LOG_ALL, "EndPhase: Got actionHANGUP_SUCCESS\r\n")); ICommGotDisconnect(pTG); uRet = T30_CALLDONE; goto NodeB; // successful end of recv call case actionDCN: (MyDebugPrint(pTG, LOG_ALL, "EndPhase: Got actionDCN\r\n")); goto NodeC; case actionHANGUP: (MyDebugPrint(pTG, LOG_ALL, "EndPhase: Got actionHANGUP\r\n")); // This should only be called on a _successful_ completion, // otherwise we get either (a) a DCN that MSGHNDLR does not // want OR (b) A fake EOJ posted to MSGHNDLR. See bug#4019 ////// ICommGotDisconnect(); ///// goto NodeB; case actionERROR: (MyDebugPrint(pTG, LOG_ALL, "EndPhase: Got actionERROR\r\n")); // ICommStatus(T30STAT_ERROR, 0, 0, 0); goto error; default: BG_CHK(FALSE); goto error; # ifdef PRI case actionGONODE_RECVPRIQ: (MyDebugPrint(pTG, LOG_ALL, "EndPhase: Got actionGONODE_RECVPRIQ\r\n")); goto RecvPriQ; case actionGONODE_E:(MyDebugPrint(pTG, LOG_ALL, "EndPhase: Got actionGONODE_E\r\n")); goto NodeE; case actionGOVOICE: (MyDebugPrint(pTG, LOG_ALL, "EndPhase: Got actionGOVOICE\r\n")); goto VoiceLine; # endif } } /******** PRI-Q stuff (Rx side) ********/ #ifdef PRI // no fall through here BG_CHK(FALSE); RecvPRIQ: switch(action = pTG->Params.lpfnWhatNext(pTG, eventGOTPRIQ, (WORD)pTG->T30.ifrCommand)) { case actionSENDPIP: pTG->T30.ifrSend=ifrPIP; goto VoiceLine; case actionSENDPIN: pTG->T30.ifrSend=ifrPIN; goto VoiceLine; case actionGONODE_F: CLEAR_MISSED_TCFS(); break; case actionGO_RECVPOSTPAGE: pTG->T30.ifrCommand = pTG->T30.ifrCommand-ifrPRI_MPS+ifrMPS; action = GONODE_III; break; case actionHANGUP: break; case actionERROR: break; // goto PhaseLoop & exit //// default: return BadAction(action); } goto PhaseLoop; /******** PIP/PIN stuff (Tx side) ********/ // no fall through here BG_CHK(FALSE); NodeE: switch(action = pTG->Params.lpfnWhatNext(pTG, eventGOTPIPPIN, (WORD)pTG->T30.ifrResp, (DWORD)pTG->T30.ifrSend)) { case actionGOVOICE: goto VoiceLine; case actionGONODE_A: BG_CHK(FALSE); // dunno what to do here case actionDCN: (MyDebugPrint(pTG, LOG_ERR, "<> Got actionDCN from eventGOTPIPPIN\r\n")); action = actionDCN; break; case actionERROR: break; // goto PhaseLoop & exit //// default: return BadAction(action); } goto PhaseLoop; // no fall through here VoiceLine: SendSingleFrame(pTG, pTG->T30.ifrSend, 0, 0, 1); // re-send PRI-Q or send PIP/PIN switch(action = pTG->Params.lpfnWhatNext(pTG, eventVOICELINE)) { case actionHANGUP: (MyDebugPrint(pTG, LOG_ERR, "<> Got actionHANGUP from eventVOICELINE\r\n")); action = actionHANGUP; break; case actionGONODE_T: case actionGONODE_R1: case actionGONODE_R2: break; case actionERROR: break; // goto PhaseLoop & exit //// default: return BadAction(action); } goto PhaseLoop; #endif error: (MyDebugPrint(pTG, LOG_ERR, "=======******* USER ABORT or TRANSPORT FATAL ERROR *******========\r\n")); // must call this always, because it's resets the Modem Driver's // global state (e.g. shuts down SW framing & filters if open, // resets the state variables etc (EndMode())) // Must call it before the SendDCN() because SendDCN causes // BG_CHKs if in strange state. ModemSync(pTG, pTG->Params.hModem, RESYNC_TIMEOUT1); if(pTG->T30.fReceivedDIS || pTG->T30.fReceivedDTC) SendDCN(pTG); // hangup in T30Main // NCULink(pTG->Params.hLine, 0, 0, NCULINK_HANGUP); // already hungup? #ifndef SMM IFMemFree(pTG, pTG->T30.lpfs); #endif FComCriticalNeg(pTG, FALSE); uRet = T30_CALLFAIL; goto done; NodeC: #ifdef MDDI ModemSync(pTG, pTG->Params.hModem, RESYNC_TIMEOUT1); #else // !MDDI // +++ 4/12/95 Win95 hack -- to prevent ModemSync from sending // an AT here. ModemSyncEx(pTG, pTG->Params.hModem, RESYNC_TIMEOUT1, fMDMSYNC_DCN); #endif // !MDDI SendDCN(pTG); // falls through here NodeB: // call this here also?? // ModemSync(pTG->Params.hModem, RESYNC_TIMEOUT1); // hangup in T30Main // NCULink(pTG->Params.hLine, 0, 0, NCULINK_HANGUP); #ifndef SMM IFMemFree(pTG, pTG->T30.lpfs); #endif FComCriticalNeg(pTG, FALSE); // fall through to done: done: return uRet; } // End of T30 routine!!!!!!!!! ET30ACTION PhaseNodeA(PThrdGlbl pTG) { MyDebugPrint (pTG, LOG_ALL, "T30: PhaseNodeA \n" ); if(pTG->T30.ifrCommand == ifrDIS) pTG->T30.fReceivedDIS = TRUE; else if(pTG->T30.ifrCommand == ifrDTC) pTG->T30.fReceivedDTC = TRUE; return (pTG->Params.lpfnWhatNext) (pTG, eventNODE_A, (WORD)pTG->T30.ifrCommand); } ET30ACTION PhaseNodeT(PThrdGlbl pTG) { MyDebugPrint (pTG, LOG_ALL, "T30: PhaseNodeT \n" ); /******** Transmitter Phase B. Fig A-7/T.30 (sheet 1) ********/ // NodeT: // Have to redo this "DIS bit" everytime through PhaseB pTG->T30.fReceivedDIS = FALSE; // also the Received EOM stuff pTG->T30.fReceivedEOM = FALSE; // and teh received-DTC stuff pTG->T30.fReceivedDTC = FALSE; // INI file settings related stuff if(pTG->ProtParams.SendT1Timer) TstartTimeOut(pTG, &pTG->T30.toT1, pTG->ProtParams.SendT1Timer); else TstartTimeOut(pTG, &pTG->T30.toT1, T1_TIMEOUT); do { if(pTG->Params.lpfnWhatNext(pTG, eventNODE_T) == actionERROR) break; // no need for echo protection. We havnt transmitted anything! switch(pTG->T30.ifrCommand=GetCommand(pTG, ifrPHASEBcommand)) { // ifrTIMEOUT means no flags before T2 // ifrNULL means timeout, or loss of carrier, or no flags // or no frame. ifrBAD means *only* bad frames recvd. case ifrBAD: SendCRP(pTG); // and fall thru to NULL/TIMEOUT case ifrTIMEOUT: case ifrNULL: break; case ifrDIS: // INI file settings related stuff if(pTG->ProtParams.IgnoreDIS && ((int)pTG->T30.uSkippedDIS < pTG->ProtParams.IgnoreDIS)) { (MyDebugPrint(pTG, LOG_ERR, "<> Ignoring First DIS\r\n")); pTG->T30.uSkippedDIS++; break; // continue with T1 loop } case ifrDTC: // case ifrNSF: // case ifrNSC: return actionGONODE_A; // got a valid frame default: (MyDebugPrint(pTG, LOG_ERR, "<> Caller T1: Got random ifr=%d\r\n", pTG->T30.ifrCommand)); break; // continue with T1 loop } } while(TcheckTimeOut(pTG, &pTG->T30.toT1)); (MyDebugPrint(pTG, LOG_ERR, "<> T1 timeout at Caller\r\n")); ICommFailureCode(pTG, T30FAILS_T1); return actionHANGUP; } ET30ACTION PhaseNodeD(PThrdGlbl pTG, BOOL fEnteredHere) { LPLPFR lplpfr; USHORT N; ET30ACTION action; USHORT uWhichDCS; // 0=first, 1=after NoReply 2=afterFTT DWORD TiffConvertThreadId; /******** Transmitter Phase B2. Fig A-7/T.30 (sheet 1) ********/ MyDebugPrint (pTG, LOG_ALL, "T30: PhaseNodeD \n" ); if (pTG->Inst.SendParams.Fax.Encoding == MR_DATA) { pTG->TiffConvertThreadParams.tiffCompression = TIFF_COMPRESSION_MR; } else { pTG->TiffConvertThreadParams.tiffCompression = TIFF_COMPRESSION_MH; } if (pTG->Inst.SendParams.Fax.AwRes & ( AWRES_mm080_077 | AWRES_200_200 ) ) { pTG->TiffConvertThreadParams.HiRes = 1; } else { pTG->TiffConvertThreadParams.HiRes = 0; // use LoRes TIFF file prepared by FaxSvc // pTG->lpwFileName[ wcslen(pTG->lpwFileName) - 1] = (unsigned short) ('$'); } _fmemcpy (pTG->TiffConvertThreadParams.lpszLineID, pTG->lpszPermanentLineID, 8); pTG->TiffConvertThreadParams.lpszLineID[8] = 0; uWhichDCS = 0; NodeD: N = 0; lplpfr = 0; action = pTG->Params.lpfnWhatNext(pTG, eventSENDDCS,(WORD)uWhichDCS, (ULONG_PTR)((LPUWORD)&N),(ULONG_PTR)((LPLPLPFR)&lplpfr)); switch(action) { case actionDCN: (MyDebugPrint(pTG, LOG_ERR, "<> Got actionDCN from eventSENDDCS(uWhichDCS=%d)\r\n", uWhichDCS)); return actionDCN; case actionSENDDCSTCF: break; case actionSKIPTCF: break; // Ricoh hook case actionERROR: return action; // goto PhaseLoop & exit default: return BadAction(pTG, action); } NodeDprime: // used only by TCF--no reply ICommStatus(pTG, T30STATS_TRAIN, ProtGetSendMod(pTG), (USHORT)(pTG->T30.uTrainCount+1), 0); SendManyFrames(pTG, lplpfr, N); if(action != actionSKIPTCF) // Ricoh hook { if (!pTG->fTiffThreadCreated) { (MyDebugPrint(pTG, LOG_ALL, "Creating TIFF helper thread \r\n")); pTG->hThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE) TiffConvertThreadSafe, (LPVOID) pTG, 0, &TiffConvertThreadId ); if (!pTG->hThread) { (MyDebugPrint(pTG, LOG_ERR, "<> TiffConvertThread create FAILED\r\n")); return actionDCN; } pTG->fTiffThreadCreated = 1; pTG->AckTerminate = 0; pTG->fOkToResetAbortReqEvent = 0; if ( (pTG->RecoveryIndex >=0 ) && (pTG->RecoveryIndex < MAX_T30_CONNECT) ) { T30Recovery[pTG->RecoveryIndex].TiffThreadId = TiffConvertThreadId; T30Recovery[pTG->RecoveryIndex].CkSum = ComputeCheckSum( (LPDWORD) &T30Recovery[pTG->RecoveryIndex].fAvail, sizeof ( T30_RECOVERY_GLOB ) / sizeof (DWORD) - 1 ); } } (MyDebugPrint(pTG, LOG_ALL, "SENDING TCF\r\n")); SendTCF(pTG); pTG->T30.uTrainCount++; (MyDebugPrint(pTG, LOG_ALL, "TCF Send Done\r\n")); } // no need for echo protection? Wouldnt know what to do anyway! pTG->T30.ifrResp = GetResponse(pTG, ifrTCFresponse); #ifdef RICOHAI if(fEnteredHere) { if(pTG->T30.ifrResp != ifrCFR && pTG->T30.ifrResp != ifrFTT) { (MyDebugPrint(pTG, LOG_ERR, "<> Send-side AI protocol failed\r\n")); fUsingOEMProt = 0; return actionGONODE_T; } } #else BG_CHK(!fEnteredHere); #endif switch(pTG->T30.ifrResp) { case ifrDCN: (MyDebugPrint(pTG, LOG_ERR, "<> Got ifrDCN in GetResponse after sending TCF\r\n")); ICommFailureCode(pTG, T30FAILS_TCF_DCN); return actionHANGUP; // got DCN. Must hangup case ifrBAD: // ifrBAD means *only* bad frames recvd. Treat like NULL case ifrNULL: // timeout. May try again if(pTG->T30.uTrainCount >= 3) { (MyDebugPrint(pTG, LOG_ERR, "<> Got no reply after 3 TCFs\r\n")); ICommFailureCode(pTG, T30FAILS_3TCFS_NOREPLY); return actionDCN; } else { uWhichDCS = 1; // goto NodeD; // send new DCS?? goto NodeDprime; // resend *same* DCS, same baudrate } case ifrDIS: case ifrDTC: if(pTG->T30.uTrainCount >= 3) { (MyDebugPrint(pTG, LOG_ERR, "<> Got DIS/DTC after 3 TCFs\r\n")); ICommFailureCode(pTG, T30FAILS_3TCFS_DISDTC); return actionDCN; } else { pTG->T30.ifrCommand = pTG->T30.ifrResp; return actionGONODE_A; } case ifrFTT: // reset training count on FTT since we drop speed. Want to try // 3 times _without_ a response (DIS DTC doesn't count) before // giving up pTG->T30.uTrainCount = 0; uWhichDCS = 2; goto NodeD; case ifrCFR: pTG->T30.uTrainCount = 0; switch(action = pTG->Params.lpfnWhatNext(pTG, eventGOTCFR)) { case actionGONODE_I: // Non-ECM PhaseC case actionGONODE_IV: // ECM PhaseC, new page return action; case actionGONODE_D: goto NodeD; // Ricoh hook case actionERROR: return action; // goto PhaseLoop & exit default: return BadAction(pTG, action); } default: { (MyDebugPrint(pTG, LOG_ERR, "<> Unknown Reply to TCF\r\n")); ICommFailureCode(pTG, T30FAILS_TCF_UNKNOWN); return actionDCN; } } BG_CHK(FALSE); } ET30ACTION NonECMPhaseC(PThrdGlbl pTG) { /******** Transmitter Phase C. Fig A-7/T.30 (sheet 1) ********/ LPBUFFER lpbf=0; ULONG lTotalLen=0; SWORD swRet; USHORT uMod, uEnc; (MyDebugPrint(pTG, LOG_ALL, "T30: NonECMPhaseC Starting Page SEND.......\r\n")); /*** switch(action = pTG->Params.lpfnWhatNext(eventSTARTSEND)) { case actionCONTINUE: break; case actionDCN: case actionHANGUP: return action; case actionERROR: return action; // goto PhaseLoop & exit default: return BadAction(action); } ***/ // already done in WhatNext // ICommSetSendMode(FALSE, MY_BIGBUF_SIZE, MY_BIGBUF_ACTUALSIZE-4, FALSE); // Callback to open file to send. Returns no data (MyDebugPrint(pTG, LOG_ALL, "Waiting for Startpage in T30 at 0x%08lx\r\n", GetTickCount())); DEBUGSTMT(IFProcProfile((HTASK)(-1), TRUE)); if((swRet=GetSendBuf(pTG, 0, SEND_STARTPAGE)) != SEND_OK) { (MyDebugPrint(pTG, LOG_ERR, "<> Nonzero return %d from SendProc at Start Page\r\n", swRet)); // return actionDCN; return actionERROR; } DEBUGSTMT(IFProcProfile((HTASK)(-1), FALSE)); (MyDebugPrint(pTG, LOG_ALL, "Got Startpage in T30 at 0x%08lx\r\n", GetTickCount())); uEnc = ProtGetSendEncoding(pTG); BG_CHK(uEnc==MR_DATA || uEnc==MH_DATA); uMod = ProtGetSendMod(pTG); // in non-ECM mode, PhaseC is ALWAYS with short-train. // Only TCF uses long-train if(uMod >= V17_START) uMod |= ST_FLAG; //(MyDebugPrint(pTG, "Calling SendMode in T30 at 0x%08lx\r\n", GetTickCount())); // **MUST** call RecvSilence here since it is recv-followed-by-send case // here we should use a small timeout (100ms?) and if it fails, // should go back to sending the previous V21 frame (which could be DCS // or MPS or whatever, which is why it gets complicated & we havn't // done it!). Meanwhile use a long timeout, ignore return value // and send anyway. if(!ModemRecvSilence(pTG, pTG->Params.hModem, RECV_PHASEC_PAUSE, LONG_RECVSILENCE_TIMEOUT)) { (MyDebugPrint(pTG, LOG_ERR, "<> Non-ECM PIX RecvSilence(%d, %d) FAILED!!!\r\n", RECV_PHASEC_PAUSE, LONG_RECVSILENCE_TIMEOUT)); } if(!ModemSendMode(pTG, pTG->Params.hModem, uMod, FALSE, (IFR)((uEnc==MR_DATA) ? ifrPIX_MR : ifrPIX_MH))) { (MyDebugPrint(pTG, LOG_ERR, "<> ModemSendMode failed in Tx PhaseC\r\n")); ICommFailureCode(pTG, T30FAILS_SENDMODE_PHASEC); BG_CHK(FALSE); return actionERROR; } //(MyDebugPrint(pTG, "Done SendMode in T30 at 0x%08lx\r\n", GetTickCount())); // need to send these quickly to avoid underrun (see bug842). // Also move the preamble/postamble into the ModemSendMode // and ModemSendMem(FINAL) // Already sent (in ModemSendMode) // SendZeros(PAGE_PREAMBLE, FALSE); // Send some zeros to warm up.... // (MyDebugPrint(pTG, "SENT Preamble Training.....\r\n")); // need to set line min zeros here. get from prot and call Modem SetStuffZERO(pTG, (ProtGetMinBytesPerLine(pTG)) ); // Enable ZERO stuffing // Start yielding *after* entering PhaseC and getting some stuff into the buffer FComCriticalNeg(pTG, FALSE); // DONT SEND an EOL here. See BUG#6441. We now make sure the EOL is // added by FAXCODEC. At this level we only append the RTC #ifdef IFAX BroadcastMessage(pTG, IF_PSIFAX_DATAMODE, PSIFAX_SEND, (uMod & (~ST_FLAG))); #endif (MyDebugPrint(pTG, LOG_ALL, "SENDING Page Data.....at %ld \n", GetTickCount())); lTotalLen = 0; BG_CHK(lpbf == 0); while((swRet=GetSendBuf(pTG, &lpbf, SEND_SEQ)) == SEND_OK) { BG_CHK(lpbf); if(!lpbf->wLengthData) { (MyDebugPrint(pTG, LOG_ERR, "<> Got 0 bytes from GetSendBuf--freeing buf\r\n")); MyFreeBuf(pTG, lpbf); continue; } lTotalLen += lpbf->wLengthData; if(!FilterSendMem(pTG, pTG->Params.hModem, lpbf->lpbBegData, lpbf->wLengthData)) { (MyDebugPrint(pTG, LOG_ERR, "<> DataWrite Timeout in NON-ECM Phase C\r\n")); ICommFailureCode(pTG, T30FAILS_MODEMSEND_PHASEC); BG_CHK(FALSE); return actionERROR; // goto error; } // (MyDebugPrint(pTG, "Freeing 0x%08lx in NON-ECM\r\n", lpbf)); if(!MyFreeBuf(pTG, lpbf)) { (MyDebugPrint(pTG, LOG_ERR, "<> FReeBuf failed in NON-ECM Phase C\r\n")); ICommFailureCode(pTG, T30FAILS_FREEBUF_PHASEC); BG_CHK(FALSE); return actionERROR; // goto error; } lpbf = 0; } BG_CHK(!lpbf); if(swRet == SEND_ERROR) { (MyDebugPrint(pTG, LOG_ERR, "<> Error in SendBuf\r\n")); // return actionDCN; return actionERROR; } BG_CHK(swRet == SEND_EOF); (MyDebugPrint(pTG, LOG_ALL, "SENDING RTC.....at %ld \n", GetTickCount())); SetStuffZERO(pTG, 0); // Disable ZERO stuffing BEFORE sending RTC! if(!SendRTC(pTG, FALSE)) // RTC and final flag NOT set { (MyDebugPrint(pTG, LOG_ERR, "<> Error in SendMem at end-PhaseC\r\n")); BG_CHK(FALSE); ICommFailureCode(pTG, T30FAILS_MODEMSEND_ENDPHASEC); return actionERROR; // error return from ModemSendMem } // Turn off yielding *before* the buffer completely drains FComCriticalNeg(pTG, TRUE); #if (PAGE_POSTAMBLE_DIV != 0) BG_CHK(PAGE_POSTAMBLE_DIV); // Send zeros to cool off FINAL flag SET SendZeros(pTG, (USHORT)(TCFLen[uMod & 0x0F] / (PAGE_POSTAMBLE_DIV)), TRUE); #else // Need this!! Need to send the SEND_EOF flag to modem driver SendZeros(pTG, 1, TRUE); // sending 0 bytes is a bit unsafe.... #endif // (PAGE_POSTAMBLE_DIV != 0) // I think this can precede the SEND_FINAL code, // to be _very_ safe put it after the whole buffer has drained // need to set line min back to 0 here. //+++SetStuffZERO(0); // Disable ZERO stuffing (MyDebugPrint(pTG, LOG_ALL, "Page Send Done.....len=(%ld, 0x%08x)\r\n", lTotalLen, lTotalLen)); pTG->T30.fSendAfterSend = TRUE; // PhaseC/PIX--MPS/EOM/EOP return actionGONODE_II; } ET30ACTION NonECMPhaseD(PThrdGlbl pTG) { USHORT uTryCount; ET30ACTION action; /******** Transmitter Phase D. Fig A-7/T.30 (sheet 2) ********/ // NodeII: MyDebugPrint (pTG, LOG_ALL, "T30: NonECMPhaseD \n" ); switch(action = pTG->Params.lpfnWhatNext(pTG, eventPOSTPAGE)) { case actionSENDMPS: pTG->T30.ifrSend = ifrMPS; break; case actionSENDEOM: pTG->T30.ifrSend = ifrEOM; break; case actionSENDEOP: pTG->T30.ifrSend = ifrEOP; break; #ifdef PRI case actionSENDPRIMPS: pTG->T30.ifrSend = ifrPRIMPS; break; case actionSENDPRIEOM: pTG->T30.ifrSend = ifrPRIEOM; break; case actionSENDPRIEOP: pTG->T30.ifrSend = ifrPRIEOP; break; #endif case actionERROR: return action; // goto PhaseLoop & exit default: return BadAction(pTG, action); } for(uTryCount=0;;) { (MyDebugPrint(pTG, LOG_ALL, "Sending postpage in T30 at %ld\r\n", GetTickCount())); // RSL dont sleep here SendSingleFrame(pTG, pTG->T30.ifrSend, 0, 0, 0); echoretry: pTG->T30.ifrResp = GetResponse(pTG, ifrPOSTPAGEresponse); // if we hear our own frame, try to recv again. DONT retransmit! if(pTG->T30.ifrResp==pTG->T30.ifrSend) { ECHOMSG(pTG->T30.ifrResp); goto echoretry; } (MyDebugPrint(pTG, LOG_ALL, "Got postpage resp in T30 at %08ld\r\n", GetTickCount())); if(pTG->T30.ifrResp != ifrNULL && pTG->T30.ifrResp != ifrBAD) break; if(++uTryCount >= 3) { (MyDebugPrint(pTG, LOG_ERR, "<> Got no reply after 3 post-page commands\r\n")); ICommFailureCode(pTG, T30FAILS_3POSTPAGE_NOREPLY); return actionDCN; } } switch(pTG->T30.ifrResp) { case ifrBAD: // ifrBAD means *only* bad frames recvd. Treat like NULL case ifrNULL: BG_CHK(FALSE); // these should never get here ICommFailureCode(pTG, T30FAILS_BUG1); return actionERROR; // in case they do case ifrDCN: (MyDebugPrint(pTG, LOG_ERR, "<> Got ifrDCN from GetResponse after sending post-page command\r\n")); ICommFailureCode(pTG, T30FAILS_POSTPAGE_DCN); return actionHANGUP; case ifrPIN: case ifrPIP: # ifdef PRI goto NodeE; # else (MyDebugPrint(pTG, LOG_ERR, "<> Procedure interrupts not supported\r\n")); pTG->T30.ifrResp = pTG->T30.ifrResp - ifrPIP + ifrRTP; // ICommFailureCode(T30FAILS_POSTPAGE_PIPPIN); // return actionERROR; // return actionDCN; # endif // default: // fallthrough --- MCF, RTN, RTP } action = pTG->Params.lpfnWhatNext(pTG, eventGOTPOSTPAGERESP, (WORD)pTG->T30.ifrResp, (DWORD)pTG->T30.ifrSend); if(pTG->T30.ifrSend==ifrEOP && (pTG->T30.ifrResp==ifrMCF || pTG->T30.ifrResp==ifrRTP) && action==actionDCN) { ICommFailureCode(pTG, T30FAILS_SUCCESS); return actionDCN_SUCCESS; } else return action; } ET30ACTION RecvPhaseB(PThrdGlbl pTG, ET30ACTION action) { LPLPFR lplpfr; USHORT N, i; /******** Receiver Phase B. Fig A-7/T.30 (sheet 1) ********/ MyDebugPrint (pTG, LOG_ALL, "T30: RecvPhaseB \n" ); if(action == actionGONODE_R1) { // NodeR1: // Have to redo this "DIS bit" everytime through PhaseB pTG->T30.fReceivedDIS = FALSE; // set to FALSE when sending DIS // also the Received EOM stuff pTG->T30.fReceivedEOM = FALSE; // and teh received-DTC stuff pTG->T30.fReceivedDTC = FALSE; N = 0; lplpfr = 0; action = pTG->Params.lpfnWhatNext(pTG, eventSENDDIS,(WORD)0, (ULONG_PTR)((LPUWORD)&N),(ULONG_PTR)((LPLPLPFR)&lplpfr)); } else { // NodeR2: BG_CHK(action == actionGONODE_R2); // fix the Received EOM stuff pTG->T30.fReceivedEOM = FALSE; N = 0; lplpfr = 0; action = pTG->Params.lpfnWhatNext(pTG, eventSENDDTC,(WORD)0, (ULONG_PTR)((LPUWORD)&N),(ULONG_PTR)((LPLPLPFR)&lplpfr)); } switch(action) { case actionDCN: (MyDebugPrint(pTG, LOG_ERR, "<> Got actionDCN from eventSENDDIS or SENDDTC\r\n")); return actionDCN; case actionSEND_DIS: case actionSEND_DTC: break; case actionERROR: return action; // goto PhaseLoop & exit default: return BadAction(pTG, action); } // INI file settings related stuff if(pTG->ProtParams.RecvT1Timer) TstartTimeOut(pTG, &pTG->T30.toT1, pTG->ProtParams.RecvT1Timer); else TstartTimeOut(pTG, &pTG->T30.toT1, T1_TIMEOUT); do { ICommStatus(pTG, T30STATR_TRAIN, 0, 0, 0); if(pTG->Params.lpfnWhatNext(pTG, eventNODE_R) == actionERROR) break; TIMESTAMP("Sending NSF-DIS") SendManyFrames(pTG, lplpfr, N); /** for(i=0; iifr, lplpfr[i]->fif, lplpfr[i]->cb, i==(N-1)); **/ pTG->T30.uRecvTCFMod = 0xFFFF; echoretry: TIMESTAMP("Getting Response") pTG->T30.ifrCommand=GetResponse(pTG, ifrPHASEBresponse); // if we hear our own frame, try to recv again. DONT retransmit! for(i=0; iT30.ifrCommand == lplpfr[i]->ifr) { ECHOMSG(pTG->T30.ifrCommand); goto echoretry; } } switch(pTG->T30.ifrCommand) { case ifrNSS: // do same as for DCS case ifrDCS: return PhaseGetTCF(pTG, pTG->T30.ifrCommand, FALSE); case ifrBAD: // ifrBAD means *only* bad frames recvd. Treat like NULL case ifrNULL: break; // out of the switch() and continue with loop case ifrDCN: (MyDebugPrint(pTG, LOG_ERR, "<> Got DCN after DIS or DTC\r\n")); ICommFailureCode(pTG, T30FAILR_PHASEB_DCN); return actionHANGUP; //bugfix #478 default: return actionGONODE_RECVCMD; } } while(TcheckTimeOut(pTG, &(pTG->T30.toT1))); (MyDebugPrint(pTG, LOG_ERR, "<> T1 timeout on Receiver\r\n")); ICommFailureCode(pTG, T30FAILR_T1); return actionDCN; } ET30ACTION PhaseNodeF(PThrdGlbl pTG, BOOL fEopMcf, BOOL fEnteredHere) { USHORT uFLoopCount; MyDebugPrint (pTG, LOG_ALL, "T30: PhaseNodeF \n" ); // NodeF: uFLoopCount = 0; NodeFprime: for(;;) { pTG->T30.uRecvTCFMod = 0xFFFF; echoretry: pTG->T30.ifrCommand = GetCommand(pTG, (USHORT)(pTG->EchoProtect.fGotWrongMode ? ifrNODEFafterWRONGMODE : ifrNODEFcommand)); // reset the fGotWrongMode flag pTG->EchoProtect.fGotWrongMode = 0; // if we hear the last frame we sent, try to recv again. DONT retx! // bug--might have matched ifrNULL... // added: if ModemRecvMode() returns EOF then also retry. RecvMode // returns RECV_EOF only if we pass it the ifrNODEFafterWRONGMODE hint // and it senses silence (i.e. we saw a V21 echo but missed it). In // this case we want to retry the high speed PIX recv if(pTG->EchoProtect.ifrLastSent && (pTG->T30.ifrCommand==pTG->EchoProtect.ifrLastSent || pTG->T30.ifrCommand==ifrEOFfromRECVMODE)) { ECHOMSG(pTG->T30.ifrCommand); switch(pTG->EchoProtect.modePrevRecv) { default: case modeNONE: goto echoretry; case modeNONECM: return actionGONODE_RECVPHASEC; case modeECM: return actionGONODE_RECVPHASEC; case modeECMRETX:return actionGONODE_RECVECMRETRANSMIT; } } // as soon as we get anything else ZERO the pTG->EchoProtect state _fmemset(&pTG->EchoProtect, 0, sizeof(pTG->EchoProtect)); // reset this flag if we fail completely to train after a CTC. We may // get an echo of our last command, go to NodeF, reject the echo and // loop back to ECMRecvPhaseC. AT that point we need this flag STILL // set so we try to recv LONG train. HOWEVER should the ECMRecvPhaseC // fail for some OTHER reason than echo, this flag need to be reset // here or it may stay alive confusing something much later. pTG->ECM.fRecvdCTC = FALSE; #ifdef RICOHAI if(fEnteredHere) { if(pTG->T30.ifrCommand!=ifrNSS) { (MyDebugPrint(pTG, LOG_ERR, "<> Recv-side AI protocol failed\r\n")); fUsingOEMProt = 0; return actionGONODE_R1; } } #else BG_CHK(!fEnteredHere); #endif switch(pTG->T30.ifrCommand) { // ifrNULL means T2 timeout, or loss of carrier, or no flags // or no frame. ifrBAD means *only* bad frame(s) recvd. case ifrNSS: // do same as for DCS case ifrDCS: return PhaseGetTCF(pTG, pTG->T30.ifrCommand, fEnteredHere); // ifrDCS is highly time-critical!! case ifrBAD: SendCRP(pTG); // and fall thru to ifrNULL case ifrNULL: break; // Loop again, until timeout case ifrTIMEOUT: goto T2Timeout; // ifrTIMEOUT means T2 timed out without flags... case ifrDCN: if(fEopMcf) { ICommFailureCode(pTG, T30FAILR_SUCCESS); return actionHANGUP_SUCCESS; } else { (MyDebugPrint(pTG, LOG_ERR, "<> DCN following UNKNOWN on Receiver\r\n")); ICommFailureCode(pTG, T30FAILR_UNKNOWN_DCN1); return actionHANGUP; } default: return actionGONODE_RECVCMD; } } T2Timeout: (MyDebugPrint(pTG, LOG_ERR, "<> T2 timed out\r\n")); // restart PhaseB after T2 timeout IFF (a) EOM or PPS-EOM was recvd // AND (b) If we are in ECM mode, the last response sent was n MCF // This avoids us doing this after sending a CTR, RNR or PPR // Ricoh's protocol conformance tester doesnt like this. This is // Ricoh's bug numbbers B3-0142, 0143, 0144 if(pTG->T30.fReceivedEOM && (ProtReceivingECM(pTG) ? (pTG->ECM.ifrPrevResponse==ifrMCF) : TRUE) ) return actionGONODE_R1; else if(ProtReceivingECM(pTG) && ++uFLoopCount<3) goto NodeFprime; #ifdef PRI else // no EOM && (no ECM || 3 times) { if((pTG->Params.lpfnWhatNext(pTG, eventQUERYLOCALINT))==actionTRUE) goto NodeF; } #endif (MyDebugPrint(pTG, LOG_ERR, "<> Got T2 timeout in GetCommand\r\n")); ICommFailureCode(pTG, T30FAILR_T2); return actionHANGUP; } ET30ACTION PhaseRecvCmd(PThrdGlbl pTG) { ET30ACTION action; MyDebugPrint (pTG, LOG_ALL, "T30: PhaseRecvCmd \n" ); if(pTG->T30.ifrCommand == ifrDCN) { (MyDebugPrint(pTG, LOG_ERR, "<> Got DCN in GetCommand\r\n")); ICommFailureCode(pTG, T30FAILR_UNKNOWN_DCN2); return actionHANGUP; } if( pTG->T30.ifrCommand==ifrDTC || pTG->T30.ifrCommand==ifrDCS || pTG->T30.ifrCommand==ifrDIS || pTG->T30.ifrCommand==ifrNSS) { switch(action = pTG->Params.lpfnWhatNext(pTG, eventRECVCMD, (WORD)pTG->T30.ifrCommand)) { case actionGETTCF: (MyDebugPrint(pTG, LOG_ERR, "<> MainBody: Wrong Way to GETTCF\r\n")); ICommFailureCode(pTG, T30FAILR_BUG2); BG_CHK(FALSE); return actionERROR; case actionGONODE_A: return actionGONODE_A; case actionGONODE_D: return action; case actionHANGUP: (MyDebugPrint(pTG, LOG_ERR, "<> Got actionHANGUP from eventRECVCMD\r\n")); return action; case actionERROR: return action; // goto PhaseLoop & exit default: return BadAction(pTG, action); } } if( pTG->T30.ifrCommand == ifrEOM || pTG->T30.ifrCommand == ifrPRI_EOM || pTG->T30.ifrCommand == ifrPPS_EOM || pTG->T30.ifrCommand == ifrPPS_PRI_EOM || pTG->T30.ifrCommand == ifrEOR_EOM || pTG->T30.ifrCommand == ifrEOR_PRI_EOM) pTG->T30.fReceivedEOM = TRUE; if(ProtReceivingECM(pTG)) return actionGONODE_VII; else if(pTG->T30.ifrCommand >= ifrPRI_FIRST && pTG->T30.ifrCommand <= ifrPRI_LAST) { #ifdef PRI return actionGONODE_RECVPRIQ; #else pTG->T30.ifrCommand = pTG->T30.ifrCommand-ifrPRI_MPS+ifrMPS; // fall thru to GONODEIII #endif } if(pTG->T30.ifrCommand >= ifrMPS && pTG->T30.ifrCommand <= ifrEOP) return actionGONODE_III; else { (MyDebugPrint(pTG, LOG_ERR, "<> Got UNKNOWN in GetCommand\r\n")); ICommFailureCode(pTG, T30FAILR_UNKNOWN_UNKNOWN2); return actionHANGUP; } /*** else if(pTG->T30.ifrCommand >= ifrMPS && pTG->T30.ifrCommand <= ifrEOP) return actionGONODE_III; else if(pTG->T30.ifrCommand >= ifrECM_FIRST && ProtReceivingECM()) return actionGONODE_VII; #ifdef PRI else if(pTG->T30.ifrCommand >= ifrPRI_FIRST && pTG->T30.ifrCommand <= ifrPRI_LAST) return actionGONODE_RECVPRIQ; #endif ***/ } ET30ACTION PhaseGetTCF(PThrdGlbl pTG, IFR ifr, BOOL fEnteredHere) { SWORD swRet; IFR ifrDummy; ET30ACTION action; MyDebugPrint (pTG, LOG_ALL, "T30: PhaseGetTCF \n" ); if(pTG->T30.uRecvTCFMod == 0xFFFF) // uninitialised { ECHOPROTECT(0, 0); CLEAR_MISSED_TCFS(); action = actionGONODE_F; goto error; } #ifdef OEMNSF else if(pTG->T30.uRecvTCFMod == 0xFF) { swRet = 0; goto sendcfr; } #endif swRet = GetTCF(pTG); // swRet = errs per 1000, +ve or 0 if we think its good // -ve if we think its bad. -1111 if other error // -1000 if too short if(swRet < -1000) { BG_CHK(swRet == -1112 || swRet == -1113); (MyDebugPrint(pTG, LOG_ERR, "<> Timed out/missed getting TCF\r\n")); ECHOPROTECT(0, 0); #ifndef MDDI pTG->T30.uMissedTCFs++; if (pTG->T30.uMissedTCFs >= MAX_MISSED_TCFS_BEFORE_FTT) { (MyDebugPrint(pTG, LOG_ERR, "<> Sending FTT after %u missed TCFs\r\n", (unsigned) pTG->T30.uMissedTCFs)); CLEAR_MISSED_TCFS(); swRet = -1000; // We pretend we got a too-short TCF. } else #endif // !MDDI { action = actionGONODE_F; goto error; } } #ifdef OEMNSF sendcfr: #endif // Here we can also signal the frames received before DCS! // Were no longer in time-critical mode, so call all the // callbacks we skipped. One for recording the received frames // and one for handling teh received command, i.e. DCS. // (the only options the protocol has is actionGETTCF or HANGUP) ifrDummy = ifr; action = pTG->Params.lpfnWhatNext(pTG, eventGOTFRAMES, pTG->T30.Nframes, (ULONG_PTR)((LPLPFR)(pTG->T30.lpfs->rglpfr)), (ULONG_PTR)((LPIFR)(&ifrDummy))); if(action == actionERROR) goto error; if(ifr != ifrDummy) { switch(ifrDummy) { case ifrNULL: case ifrBAD: (MyDebugPrint(pTG, LOG_ERR, "<> Got ifrBAD from whatnext after recv TCF\r\n")); ECHOPROTECT(0, 0); CLEAR_MISSED_TCFS(); action = actionGONODE_F; goto error; default: BG_CHK(FALSE); break; } } // BG_CHK(action == actionNULL); // BG_CHK(ifrDummy == ifr); // Now call teh callback to check the received TCF and // return either FTT or CFR switch(action = pTG->Params.lpfnWhatNext(pTG, eventGOTTCF,(WORD)swRet)) { case actionSENDCFR: (MyDebugPrint(pTG, LOG_ALL, "Good TCF\r\n")); EnterPageCrit(); // start the CFR--PAGE critsection SendCFR(pTG); // after sending CFR we are again in a race ECHOPROTECT(ifrCFR, 0); // dunno recv mode yet return actionGONODE_RECVPHASEC; case actionSENDFTT: (MyDebugPrint(pTG, LOG_ERR, "<> Bad TCF.....!!!\r\n")); SendFTT(pTG); ECHOPROTECT(ifrFTT, 0); CLEAR_MISSED_TCFS(); return actionGONODE_F; case actionERROR: goto error; default: action = BadAction(pTG, action); goto error; } error: // missed TCF or no NSS. Did _not_ reply to TCF // if we sent a reply, must _not_ come here #ifdef RICOHAI if(fEnteredHere) return actionGONODE_R1; #else BG_CHK(!fEnteredHere); #endif return action; } ET30ACTION NonECMRecvPhaseC(PThrdGlbl pTG) { /******** Receiver Phase C. Fig A-7/T.30 (sheet 1) ********/ LPBUFFER lpbf; ULONG lTotalLen=0; USHORT uRet, uMod, uEnc; DWORD tiffCompression; LPSTR lpsTemp; DWORD HiRes; // There is a race between sending the CFR and sending out an // +FRM=xx command, so we want to do it ASAP. MyDebugPrint (pTG, LOG_ALL, "T30: NonECMRecvPhaseC \n" ); uEnc = ProtGetRecvEncoding(pTG); BG_CHK(uEnc==MR_DATA || uEnc==MH_DATA); if (uEnc == MR_DATA) { tiffCompression = TIFF_COMPRESSION_MR; } else { tiffCompression = TIFF_COMPRESSION_MH; } if (pTG->ProtInst.RecvParams.Fax.AwRes & (AWRES_mm080_077 | AWRES_200_200) ) { HiRes = 1; } else { HiRes = 0; } // // do it once per RX // if ( !pTG->fTiffOpenOrCreated) { // // top 32bits of 64bit handle are guaranteed to be zero // pTG->Inst.hfile = PtrToUlong(TiffCreateW ( pTG->lpwFileName, tiffCompression, 1728, FILLORDER_LSB2MSB, HiRes ) ); if (! (pTG->Inst.hfile)) { lpsTemp = UnicodeStringToAnsiString(pTG->lpwFileName); MyDebugPrint(pTG, LOG_ERR, "ERROR:Can't create tiff file %s compr=%d \n", lpsTemp, tiffCompression); MemFree(lpsTemp); return actionERROR; } pTG->fTiffOpenOrCreated = 1; lpsTemp = UnicodeStringToAnsiString(pTG->lpwFileName); MyDebugPrint(pTG, LOG_ALL, "Created tiff file %s compr=%d HiRes=%d \n", lpsTemp, tiffCompression, HiRes); MemFree(lpsTemp); } uMod = ProtGetRecvMod(pTG); // in non-ECM mode, PhaseC is ALWAYS with short-train. // Only TCF uses long-train if(uMod >= V17_START) uMod |= ST_FLAG; pTG->T30.sRecvBufSize = MY_BIGBUF_SIZE; if((uRet = ModemRecvMode(pTG, pTG->Params.hModem, uMod, FALSE, PHASEC_TIMEOUT, (IFR)((uEnc==MR_DATA) ? ifrPIX_MR : ifrPIX_MH))) != RECV_OK) { ExitPageCrit(); // reset Page ack. In case we miss page completely ProtResetRecvPageAck(pTG); (MyDebugPrint(pTG, LOG_ERR, "<> NonECMPhC: RecvMode returned %d\r\n", uRet)); pTG->EchoProtect.modePrevRecv = modeNONECM; // set global flag if we got WRONGMODE pTG->EchoProtect.fGotWrongMode = (uRet==RECV_WRONGMODE); // elim flush--does no good & wastes 10ms // ModemFlush(pTG->Params.hModem); CLEAR_MISSED_TCFS(); return actionGONODE_F; // try to get 300bps command // return actionHANGUP; // goto error instead. No way to recover from here! } ExitPageCrit(); // as soon as we get good carrier ZERO the EchoProtect state _fmemset(&pTG->EchoProtect, 0, sizeof(pTG->EchoProtect)); #ifdef IFAX BroadcastMessage(pTG, IF_PSIFAX_DATAMODE, PSIFAX_RECV, (uMod & (~ST_FLAG))); #endif (MyDebugPrint(pTG, LOG_ALL, "RECEIVING Page.......\r\n")); // reset Page ack ProtResetRecvPageAck(pTG); // Turn yielding on *after* entering receive mode safely! FComCriticalNeg(pTG, FALSE); /*** switch(action = pTG->Params.lpfnWhatNext(eventSTARTRECV)) { case actionCONTINUE: break; case actionDCN: (MyDebugPrint(pTG, LOG_ERR, "<> Got actionDCN from eventSTARTRECV\r\n")); return actionDCN; // goto NodeC; case actionHANGUP: (MyDebugPrint(pTG, LOG_ERR, "<> Got actionHANGUP from eventSTARTRECV\r\n")); return actionHANGUP; // goto NodeB; case actionERROR: return action; // goto PhaseLoop & exit default: return BadAction(action); } ***/ /*** BG_CHK((BOOL)Comm.dcb.fOutX == FALSE); // Paranoia! Dont want to take ^Q/^S from modem to // be XON/XOFF in the receive data phase!! FComInFilterInit(); ***/ // to mark start of Page if(!PutRecvBuf(pTG, NULL, RECV_STARTPAGE)) { (MyDebugPrint(pTG, LOG_ERR, "<> Zero return from PutRecvBuf(start page)\r\n")); return actionERROR; } // make it large, in case of large buffers & slow modems #define READ_TIMEOUT 25000 lTotalLen = 0; do { uRet=ModemRecvBuf(pTG, pTG->Params.hModem, FALSE, &lpbf, READ_TIMEOUT); // lpbf==0 && uRet==RECV_OK just does nothing & loops back if (uRet == RECV_EOF) { // indicate that this is actually last recv_seq (we've got dle/etx already). (MyDebugPrint(pTG, LOG_ALL, "RECV: NonECMRecvPhaseC fLastReadBlock = 1 \n")); pTG->fLastReadBlock = 1; } if(lpbf) { lTotalLen += lpbf->wLengthData; if(!PutRecvBuf(pTG, lpbf, RECV_SEQ)) { (MyDebugPrint(pTG, LOG_ERR, "<> Zero return from PutRecvBuf in page\r\n")); return actionERROR; } lpbf = 0; } else { if ( pTG->fLastReadBlock == 1) { PutRecvBuf(pTG, lpbf, RECV_FLUSH); } } } while(uRet == RECV_OK); if(uRet == RECV_EOF) { FComCriticalNeg(pTG, TRUE); pTG->T30.fAtEndOfRecvPage = TRUE; // call this *after* getting MPS/EOM/EOP // PutRecvBuf(NULL, RECV_ENDPAGE); // to mark end of Page } else { // Timeout from ModemRecvBuf (MyDebugPrint(pTG, LOG_ERR, "<> DataRead Timeout or Error=%d\r\n", uRet)); // BG_CHK(FALSE); ICommFailureCode(pTG, T30FAILR_MODEMRECV_PHASEC); return actionERROR; // goto error; } (MyDebugPrint(pTG, LOG_ALL, "Page Recv Done.....len=(%ld, 0x%08x)\r\n", lTotalLen, lTotalLen)); ECHOPROTECT(0, 0); CLEAR_MISSED_TCFS(); return actionGONODE_F; // goto NodeF; // get post-message command } ET30ACTION NonECMRecvPhaseD(PThrdGlbl pTG) { ET30ACTION action; ET30ACTION ret; MyDebugPrint (pTG, LOG_ALL, "T30: NonECMRecvPhaseD \n" ); /******** Receiver Phase D. Fig A-7/T.30 (sheet 2) ********/ // NodeIII: /** Here the T30 flowchart is all BS. Fundamentally relying on a +FCERROR response is not possible, so what we do here really depends on what we've got. (According to the T30 flowchart we return to NodeF after sending MCF/RTP/RTN, in all cases. What we now know is that, after MPS/MCF goto RecvPhaseC to get the next page after EOM/MCF goto NodeR1 and send NSF etc all over again ***changed*** go back to NodeF, wait for T2 timeout before sending DIS all over again. after EOP/MCF goto NodeF, where GetResponse() will get a DCN and we end up in NodeB (disconnect) after xxx/RTN or xxx/RTP, I don't know what to do, but my guess (looking at the Sender side of T30 flowchart) is:- after MPS/RTx goto NodeF (sender goes to NodeD) after EOP/RTx goto NodeF (sender goes to D or C) after EOM/RTx goto NodeR1 (sender goes to NodeT) ***changed*** go back to NodeF, wait for T2 timeout before sending DIS all over again. ****/ // only MPS/EOM/EOP commands come here if(pTG->T30.fAtEndOfRecvPage) // so we won't call this twice { // This calls ET30ProtRecvPageAck so that WhatNext can choose // MCF or RTN respectively. So it *must* be done before the // call to WhatNext below // RECV_ENDDOC if EOP or EOM PutRecvBuf(pTG, NULL, ((pTG->T30.ifrCommand==ifrMPS) ? RECV_ENDPAGE : RECV_ENDDOC)); // ignore error/abort. We'll catch it soon enough pTG->T30.fAtEndOfRecvPage = FALSE; } // returns MCF if page was OK, or RTN if it was bad ret=actionGONODE_F; ECHOPROTECT(0, 0); CLEAR_MISSED_TCFS(); switch(action = pTG->Params.lpfnWhatNext(pTG, eventRECVPOSTPAGECMD,(WORD)pTG->T30.ifrCommand)) { case actionSENDMCF: if(pTG->T30.ifrCommand==ifrMPS) { EnterPageCrit(); //start MPS--PAGE critsection ECHOPROTECT(ifrMCF, modeNONECM); ret=actionGONODE_RECVPHASEC; } else if(pTG->T30.ifrCommand==ifrEOP) { ECHOPROTECT(ifrMCF, 0); CLEAR_MISSED_TCFS(); ret=actionNODEF_SUCCESS; } SendMCF(pTG); break; case actionSENDRTN: ECHOPROTECT(ifrRTN, 0); SendRTN(pTG); break; case actionHANGUP: (MyDebugPrint(pTG, LOG_ERR, "<> Got actionHANGUP from eventRECVPOSTPAGECMD\r\n")); ret=actionHANGUP; break; // case actionSENDRTP: SendRTP(pTG); break; // never send RTP case actionERROR: ret=action; break; // goto PhaseLoop & exit default: return BadAction(pTG, action); } return ret; } /*************************************************************************** Name : IFR GetCmdResp(BOOL fCommand) Purpose : Implement the "Command Received" and "Response Received" subroutines in the T.30 flowchart. The following macros are defined:- #define GetResponse() GetCmdResp(FALSE) #define GetCommand() GetCmdResp(TRUE) where the first form results in a faithful implem. of the "Response Received" subroutine, the 2nd one changes two things (i) the timeout for getting falgs goes from T4 to T2, and (ii) if the routine times out on the very first frame without getting flags (i.e. T2 times out) it returns ifrTIMEOUT. This results in the "Command Recvd" and the enclosing T2 loop being implemented in this routine. Upon receiving a set of frames, this routine assembles them into the ET30FR structs pointed to by rglpfr, and if any of them have a non-null FIF, or if >1 frame are received, it calls (*Callbacks.Callbacks.lpWhatNext)(). Finally it returns the ifr of the last frame received, if all frames were good, or ifrBAD if *all* frames were bad. The algorithm it implements is very close to the "Response Received" flowchart, minus the "Transmit DCN" box & below. It returns ifrNULL or ifrBAD corresponding to return via Node 2, (i.e. ifrNULL for timeout and other errors), ifrBAD for bad frames, *iff* it can resync and get 200ms of silence following these. ifrERROR for Node 1 (i.e. any error or timeout after which we cannot resync or get silence for 200ms), and ifrDCN for Node 3 (i.e. DCN was received). <<>> The "Optional Response" box is replaced by a "Not final frame". A "start T4" box is assumed at "Enter" and a "Reset T4" box is assumed after "process optional response" It also modifies the flowchart in that *all* the frames are got until a final frame, even if an FCS error frame is recvd. This is partly because after an erroneous frame we have absolutely no idea how long to wait until we either get silence or timeout and hangup. ALso it may be more robust. The main routine throws away the entire set of frames if one is bad. The callback function is called before any return and it gets a pointer to the desired return vakue, so it can modify this. Arguments: whether it is called as "Command Received" or as "Response Received" Returns : ifrNULL -- timeout ifrTIMEOUT -- T2 timed out before first flag (returns this if and only if fCommand==TRUE) ifrBAD -- all frames received were bad ifrDCN -- DCN was received. The only valid action is "goto NodeB" ifrXXXX -- last received frame Calls : Called By: GetResponse() GetCommand1() and GetCommand2() macros (ONLY!) These are called only from ET30MainBody. Comment : Watch out for timeouts > 65535 (max UWORD) Revision Log Date Name Description -------- ----- --------------------------------------------------------- 06/15/92 arulm Created for first time (completely from scratch) ***************************************************************************/ IFR GetCmdResp(PThrdGlbl pTG, BOOL fCommand, USHORT ifrHint) { /*** we need to try for T4 to get a frame here. The way Class1 modems works, as long as no flags are received, the AT+FRH=3 command will time out and return ERROR. CONNECT is returned as soon as flags are received. Some modems return OKCONNECT which is still taken care of by out new ModemDialog which throws away blank lines and looks for the expected answer i.e. "CONNECT" in this case, in multi-line responses. ***/ BYTE bRecv[MAXFRAMESIZE]; BOOL fFinal, fNoFlags, fGotFIF, fGotBad; IFR ifr, ifrLastGood; USHORT uRet, uRecv, j; ET30ACTION action; LPLPFR lplpfr; LPFR lpfrNext; BOOL fResync=0; ULONG ulTimeout; BOOL fGotEofFromRecvMode=0; // need to init these first pTG->T30.Nframes=0, fFinal=FALSE, fNoFlags=TRUE, fGotFIF=FALSE, fGotBad=FALSE; ifrLastGood=ifrNULL; // figure out the timeout if(fCommand) ulTimeout = T2_TIMEOUT; else ulTimeout = T4_TIMEOUT; // if we're sending DCS-TCF and waiting for CFR, we increase the timeout each time // we fail, to avoid getting an infinite collision. This fixes bug#6847 if(ifrHint==ifrTCFresponse && pTG->T30.uTrainCount>1) { ulTimeout += TCFRESPONSE_TIMEOUT_SLACK; (MyDebugPrint(pTG, LOG_ALL, "Get TCF response: traincount=%d timeout=%ld\r\n", pTG->T30.uTrainCount, ulTimeout)); } lplpfr = pTG->T30.lpfs->rglpfr; lpfrNext = (LPFR)(pTG->T30.lpfs->b); pTG->T30.sRecvBufSize = 0; uRet = ModemRecvMode(pTG, pTG->Params.hModem, V21_300, TRUE, ulTimeout, ifrHint); if(uRet == RECV_TIMEOUT || uRet == RECV_ERROR) { (MyDebugPrint(pTG, LOG_ERR, "<> RecvMode failed=%d\r\n", uRet)); fResync = TRUE; goto error; } else if(uRet == RECV_WRONGMODE) { // BG_CHK(FALSE); // just so we know who gives it!! (MyDebugPrint(pTG, LOG_ERR, "<> Got FCERROR from FRH=3\r\n")); // treat like timeout // fReSync = FALSE; // no need to resync goto error; } else if(uRet == RECV_EOF) { // ModemRecvMode() returns EOF then return ifrEOF immediately. RecvMode // returns RECV_EOF only if we pass it the ifrNODEFafterWRONGMODE hint // and it senses silence (i.e. we saw a V21 echo but missed it). In // this case we want to retry the high speed PIX recv again immediately (MyDebugPrint(pTG, LOG_ERR, "WARNING: ECHO--Got EOF from V21 RecvMode\r\n")); fGotEofFromRecvMode=TRUE; goto error; } BG_CHK(uRet == RECV_OK); for( ;!fFinal; ) { if((((LPB)lpfrNext+sizeof(FR)+30-(LPB)pTG->T30.lpfs) > TOTALRECVDFRAMESPACE) || (pTG->T30.Nframes >= MAXRECVFRAMES)) { (MyDebugPrint(pTG, LOG_ERR, "<> Out of space for received frames. Haaalp!!\r\n")); pTG->T30.Nframes = 0; // fGotBad = TRUE; // fGotBad = FALSE; lplpfr = pTG->T30.lpfs->rglpfr; lpfrNext = (LPFR)(pTG->T30.lpfs->b); // BG_CHK(FALSE); // fall through } uRet = ModemRecvMem(pTG, pTG->Params.hModem, bRecv, MAXFRAMESIZE, ulTimeout, &uRecv); if(uRet == RECV_TIMEOUT) { fResync = TRUE; goto error; // timeout in FRH=3 } fNoFlags = FALSE; if(uRet == RECV_EOF) { (MyDebugPrint(pTG, LOG_ERR, "<> Got NO CARRIER, but no final bit\r\n")); BG_CHK(uRecv == 0); goto error; // ignore good frames if we got any, because we // must've missed the last (most important) one // fFinal = TRUE; // pretend we got fFinal // continue; } else if(uRet == RECV_ERROR) { fResync = TRUE; goto error; // error in FRH=3 } /** Sometimes modems give use ERROR even when teh frame is good. Happens a lot from Though to PP144MT on CFR. So we ignore the BADFRAME response, and check the recvd data for ourselves. First stage--check the FF-03/13-FCF. If this is OK (i.e. got a known FCF) and no FIF reqd and data length is correct then accept it. But if the frame requires an FIF and we got a BADFRAME response then don't accept it even if it looks good--too dangerous. 2nd-stage(NYI)--keep a table of CRCs for each fixed frame & check them ourselves. **/ #ifdef MDDI // badframe handling else if(uRet == RECV_BADFRAME) goto badframe; BG_CHK(uRet==RECV_OK); #else BG_CHK(uRet == RECV_OK || uRet==RECV_BADFRAME); #endif // faxT2log(("FRAME>>> \r\n")); // ST_FRAMES(D_HexPrint(bRecv, uRecv)); /*** Got Valid OK Frame. Now analyse it. In general here we want to be pretty lax in recognizing frames. Oftentimes we have mucho garbage thrown in. Actually we're checking strictly now.... If we get a bad frame, we mark this in the lpfrfr[] array and go on to try and get another frame. We've stopped saving bad frames ***/ // AT&T modem gives us frames w/o CRC, so we get just 1 byte here!! // fixed that at driver level, so we always get 3 bytes here // IFF it is a valid frame if(uRecv < 3) goto badframe; if(bRecv[0] != 0xFF) goto badframe; if(bRecv[1] == 0x03) fFinal = FALSE; else if(bRecv[1] == 0x13) { fFinal = TRUE; #ifdef CL0 // tell modem that recv is done // but keep calling RecvMem until we get RECV_EOF ModemEndRecv(pTG, pTG->Params.hModem); #endif //CL0 } else goto badframe; for(ifr=1; ifr0 if(uRet==RECV_OK && (j < uRecv)) fGotFIF = TRUE; else { (MyDebugPrint(pTG, LOG_ERR, "Discarding Bad Frame: uRet=%d FIFlen=%d Reqd=Var\r\n", uRet, (uRecv-j))); goto badframe; } } else if(rgFrameInfo[ifr].wFIFLength) // fixed length FIF { // if frame length is exactly right then accept it // else if modem said frame was ok and length is // longer than expected then accept it too if((j+rgFrameInfo[ifr].wFIFLength) == uRecv) fGotFIF = TRUE; else if(uRet==RECV_OK && (j+rgFrameInfo[ifr].wFIFLength < uRecv)) fGotFIF = TRUE; else { (MyDebugPrint(pTG, LOG_ERR, "Discarding Bad Frame: uRet=%d FIFlen=%d Reqd=%d\r\n", uRet, (uRecv-j), rgFrameInfo[ifr].wFIFLength)); goto badframe; } } else // no FIF reqd { if(j != uRecv) { (MyDebugPrint(pTG, LOG_ALL, "Weird frame(2)\r\n")); BG_CHK(j < uRecv); // see the BADFRAME comment block above on why we do this if(uRet != RECV_OK) goto badframe; // accept it even if wrong length *iff* uRet==RECV_OK // goto badframe; // **additional** reason to do this that 2 bytes of extra // CRC may be present. This happens because of the AT&T and // NEC modems that doen't give CRC, so we do no CRC lopping-off // in the modem driver. So accept it anyway here. } } goto goodframe; } // fall through here when ifr == ifrMAX BG_CHK(ifr==ifrMAX); badframe: (MyDebugPrint(pTG, LOG_ERR, "<> IGNORING Bad Frame (Size=%d) -->\r\n", uRecv)); // D_HexPrint(bRecv, uRecv); //Protocol Dump DumpFrame(pTG, FALSE, 0, uRecv, bRecv); fGotBad = TRUE; // remember we got a bad frame // Don't want to save bad frames /*** // mark frame as bad ifr = ifrBAD; lpfrNext->ifr = ifrBAD; lpfrNext->cb = (BYTE)uRecv; _fmemcpy(lpfrNext->fif, bRecv, uRecv); lplpfr[pTG->T30.Nframes] = lpfrNext; pTG->T30.Nframes++; lpfrNext++; // skips over only the base part of frame lpfrNext = ((LPBYTE)lpfrNext + uRecv); // skips over FIF too ***/ continue; // loop back here for the next frame goodframe: // (MyDebugPrint(pTG, "FRAME RECEIVED: (%s) 0x%02x -->\r\n", (LPSTR)(rgFrameInfo[ifr].szName), bRecv[2])); // ST_T30_2(D_HexPrint(bRecv, uRecv)); ifrLastGood = ifr; // save last good ifr lpfrNext->ifr = ifr; if(uRecv > j) { lpfrNext->cb = uRecv-j; _fmemcpy(lpfrNext->fif, bRecv+j, uRecv-j); //Protocol Dump DumpFrame(pTG, FALSE, ifr, (USHORT)(uRecv-j), bRecv+j); } else { lpfrNext->cb = 0; BG_CHK(uRecv == j); //Protocol Dump DumpFrame(pTG, FALSE, ifr, 0, 0); } lplpfr[pTG->T30.Nframes] = lpfrNext; pTG->T30.Nframes++; ///////////// back to NSS-DCS form //////////// if(ifr==ifrDCS && fFinal) { // Need to set receive speed, since bypass all callbacks // now and go straight to AT+FRM=xx pTG->T30.uRecvTCFMod = (((lpfrNext->fif[1])>>2) & 0x0F); (MyDebugPrint(pTG, LOG_ALL, "cmdresp-DCS fx sp=%d\r\n", pTG->T30.uRecvTCFMod)); // fastexit: BG_CHK(ifr==ifrDCS); return ifr; // ifr of final frame } #ifdef OEMNSF else if(ifr==ifrNSS && lpfnOEMGetBaudRate && fUsingOEMProt) { WORD wRet = lpfnOEMGetBaudRate(pTG, lpfrNext->fif, lpfrNext->cb, fFinal); if(wRet) { BG_CHK(fFinal); if(LOBYTE(wRet) == OEMNSF_GET_TCF) { (MyDebugPrint(pTG, LOG_ALL, "cmdresp-NSS fx sp=%d\r\n", pTG->T30.uRecvTCFMod)); pTG->T30.uRecvTCFMod = HIBYTE(wRet); BG_CHK(ifr==ifrNSS); return ifr; } else if(LOBYTE(wRet) == OEMNSF_NO_TCF) { (MyDebugPrint(pTG, LOG_ALL, "cmdresp-NSS fx sp=%d\r\n", pTG->T30.uRecvTCFMod)); pTG->T30.uRecvTCFMod = 0xFF; BG_CHK(ifr==ifrNSS); return ifr; } } else if(fFinal) { (MyDebugPrint(pTG, LOG_ERR, "<> OEMGetBaudRate returned %d for FINAL frame. Using standard T30\r\n")); fUsingOEMProt = 0; return ifrNULL; } } #endif lpfrNext++; // skips over only the base part of frame lpfrNext = (LPFR)((LPBYTE)lpfrNext + (uRecv-j)); // skips over FIF too if(ifr == ifrCRP) { fGotBad = TRUE; // pretend we got a bad response (so the T30 chart says!) // fResync = FALSE; goto error; // exit, but get 200ms of silence // caller will resend command } if(ifr == ifrDCN) goto exit2; // exit. Don't call callback function! // loop back here for the next frame } BG_CHK(fFinal); // only reason we ever drop through here // let ifrDCN also come through here. No hurry, so we can report // it to the protocol module. If we got *only* bad frames, here we'll // return ifrBAD //exit: if(!pTG->T30.Nframes || // we got no good frames (ifr != ifrLastGood)) // final frame was bad { (MyDebugPrint(pTG, LOG_ERR, "<> Got %d good frames. LastGood=%d Last=%d. Ignoring ALL\r\n", pTG->T30.Nframes, ifrLastGood, ifr )); // fResync = FALSE; goto error; } // ifr of final frame BG_CHK(ifr == ifrLastGood); if(pTG->T30.Nframes>1 || fGotFIF) { action=pTG->Params.lpfnWhatNext(pTG, eventGOTFRAMES, pTG->T30.Nframes, (ULONG_PTR)lplpfr, (ULONG_PTR)((LPIFR)&ifr)); BG_CHK(action==actionNULL || action==actionERROR); } exit2: // ifr can be changed by callback function (e.g. if bad FIFs) if(ifr==ifrDTC) pTG->T30.fReceivedDTC = TRUE; return ifr; // ifr of final frame error: // comes here on getting RECV_TIMEOUT, RECV_WRONGMODE, RECV_ERROR // and ifrCRP, or on getting no Frames // fReSync is set on RECV_TIMEOUT or RECV_ERROR #ifdef DEBUG if(pTG->T30.Nframes>0 && ifr!=ifrCRP && ifrLastGood!=ifrCRP) { (MyDebugPrint(pTG, LOG_ERR, "<> Got some good frames--Throwing away!! IFR=%d Last=%d\r\n", ifr, ifrLastGood)); // BG_CHK(FALSE); } #endif if(fGotBad) ifr = ifrBAD; // caller can send CRP if desired else ifr = ifrNULL; // caller can repeat command & try again if(fCommand && fNoFlags) ifr = ifrTIMEOUT; // hook for "Command Recvd?" // may not need this on TIMEOUT since AT-OK has already been // called in ModemDialog. Probably need it on ERROR if(uRet==RECV_ERROR) { BG_CHK(fResync); ModemSync(pTG, pTG->Params.hModem, RESYNC_TIMEOUT2); } // eliminate Flush--serves no purpose // else if(uRet==RECV_WRONGMODE) // { // ModemFlush(pTG->Params.hModem); // } // ModemRecvMode() returns EOF then return ifrEOF immediately. RecvMode // returns RECV_EOF only if we pass it the ifrNODEFafterWRONGMODE hint // and it senses silence (i.e. we saw a V21 echo but missed it). In // this case we want to retry the high speed PIX recv again immediately if(fGotEofFromRecvMode) ifr=ifrEOFfromRECVMODE; BG_CHK(ifr==ifrBAD || ifr==ifrNULL || ifr==ifrTIMEOUT || ifr==ifrEOFfromRECVMODE); return ifr; /*----------------------------------------------------------------- * Don't want to return ifrERROR ever. Nobody wants to deal with it. * Don't try to get the 200ms of silence, because it causes us to * get badly out of sync, i.e. after a few bad frames we don't * resync and we lose the call. Just do a local-resync (AT-OK) * and try to recv again. * ----------------------------------------------------------------- * * if( !ModemSync(pTG->Params.hModem, RESYNC_TIMEOUT) || * !ModemRecvSilence(pTG->Params.hModem, 20, RESYNC_TIMEOUT)) * { * (MyDebugPrint(pTG, LOG_ERR, "<> Can't get silence after Response timeout--hanging up\r\n")); * // ifr = ifrERROR; * // caller must send DCN and hangup * } * action=pTG->Params.lpfnWhatNext(eventGOTFRAMES, pTG->T30.Nframes, * (DWORD)lplpfr, (DWORD)((LPIFR)&ifr)); * BG_CHK(action == actionNULL); * * ----------------------------------------------------------------- * and don't want to regsiter garbage frame sets. Nobody does anything * but retry on BAD/NULL/TIMEOUT returns anyway *-----------------------------------------------------------------*/ }