mirror of https://github.com/tongzx/nt5src
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.
2443 lines
97 KiB
2443 lines
97 KiB
/***************************************************************************
|
|
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, "<<WARNING>> 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, "<<ERROR>> 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, "<<ERROR>> 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, "<<WARNING>> 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, "<<ERROR>> 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, "<<ERROR>> 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, "<<ERROR>> 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, "<<ERROR>> 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, "<<WARNING>> 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, "<<ERROR>> 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, "<<ERROR>> 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, "<<ERROR>> 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, "<<ERROR>> 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, "<<ERROR>> 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, "<<ERROR>> 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, "<<ERROR>> 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, "<<ERROR>> 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, "<<ERROR>> 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, "<<ERROR>> 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>> 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>> 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, "<<ERROR>> 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, "<<ERROR>> 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, "<<WARNING>> 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, "<<ERROR>> 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; i<N; i++)
|
|
SendFrame( lplpfr[i]->ifr, 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; i<N; i++)
|
|
{
|
|
if(pTG->T30.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, "<<ERROR>> 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, "<<ERROR>> 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, "<<WARNING>> 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, "<<ERROR>> DCN following UNKNOWN on Receiver\r\n"));
|
|
ICommFailureCode(pTG, T30FAILR_UNKNOWN_DCN1);
|
|
return actionHANGUP;
|
|
}
|
|
|
|
default: return actionGONODE_RECVCMD;
|
|
}
|
|
}
|
|
|
|
T2Timeout:
|
|
(MyDebugPrint(pTG, LOG_ERR, "<<WARNING>> 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, "<<ERROR>> 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, "<<ERROR>> 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, "<<ERROR>> 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, "<<ERROR>> 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, "<<ERROR>> 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, "<<WARNING>> 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, "<<WARNING>> 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, "<<ERROR>> 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, "<<WARNING>> 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, "<<WARNING>> 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, "<<ERROR>> Got actionDCN from eventSTARTRECV\r\n"));
|
|
return actionDCN; // goto NodeC;
|
|
case actionHANGUP: (MyDebugPrint(pTG, LOG_ERR, "<<ERROR>> 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, "<<ERROR>> 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, "<<ERROR>> 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, "<<ERROR>> 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, "<<ERROR>> 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).
|
|
<<<Node1 (ifrERROR is bad, so we dont use it. On error
|
|
we immediately return BAD or NULL or TIMEOUT and allow retry>>>
|
|
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 <CR><LF>OK<CR><LF><CR><LF>CONNECT
|
|
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, "<<WARNING>> 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, "<<ERROR>> 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, "<<ERROR>> 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, "<<WARNING>> 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.
|
|
<CHANGE> 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.
|
|
<CHANGE> We've stopped saving bad frames
|
|
***/
|
|
|
|
// AT&T modem gives us frames w/o CRC, so we get just 1 byte here!!
|
|
// <CHNAGE> 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; ifr<ifrMAX; ifr++)
|
|
{
|
|
if(rgFrameInfo[ifr].fInsertDISBit)
|
|
{
|
|
// Mask off the DIS bit
|
|
if(rgFrameInfo[ifr].bFCF1 != (BYTE)(bRecv[2] & 0xFE))
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
if(rgFrameInfo[ifr].bFCF1 != bRecv[2])
|
|
continue;
|
|
}
|
|
|
|
j=3;
|
|
if(rgFrameInfo[ifr].bFCF2)
|
|
{
|
|
// AT&T modem gives us frames w/o CRC, so we get just 1 byte frames!!
|
|
if(uRecv < 4)
|
|
goto badframe;
|
|
|
|
if((BYTE)(rgFrameInfo[ifr].bFCF2-1) != bRecv[3])
|
|
continue;
|
|
j++;
|
|
}
|
|
BG_CHK(j <= uRecv);
|
|
if(rgFrameInfo[ifr].wFIFLength == 0xFF) // var length FIF
|
|
{
|
|
// Var length frames
|
|
// Cant accept it if the modem thought they it was bad
|
|
// accept it IFF RECV_OK & FIFlen>0
|
|
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, "<<WARNING>> 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, "<<ERROR>> 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, "<<WARNING>> 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, "<<ERROR>> 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, "<<ERROR>> 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
|
|
*-----------------------------------------------------------------*/
|
|
}
|
|
|
|
|
|
|