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.
1338 lines
50 KiB
1338 lines
50 KiB
/***************************************************************************
|
|
Name : ECM.C
|
|
Comment : Contains the ECM T30 routines
|
|
Revision Log
|
|
Date Name Description
|
|
-------- ----- ---------------------------------------------------------
|
|
***************************************************************************/
|
|
|
|
|
|
#include "prep.h"
|
|
|
|
#include "efaxcb.h"
|
|
#include "t30.h"
|
|
#include "hdlc.h"
|
|
#include "debug.h"
|
|
|
|
///RSL
|
|
#include "glbproto.h"
|
|
|
|
|
|
#define faxTlog(m) DEBUGMSG(ZONE_ECM, m)
|
|
#define FILEID FILEID_ECM
|
|
|
|
typedef enum
|
|
{
|
|
ECMRECVOK_OK,
|
|
ECMRECVOK_BADFR,
|
|
ECMRECVOK_ABORT
|
|
}
|
|
ECMRECVOK;
|
|
|
|
/****************** begin prototypes from ecm.c *****************/
|
|
IFR RNR_RRLoop(PThrdGlbl pTG);
|
|
IFR CTC_RespRecvd(PThrdGlbl pTG, USHORT uBaud);
|
|
BOOL Recv_NotReadyLoop(PThrdGlbl pTG, IFR ifrFirst, IFR ifrLast);
|
|
BOOL FillInFrames(PThrdGlbl pTG, USHORT N, LONG sBufSize, USHORT uDataSize);
|
|
ECMRECVOK ECMRecvOK(PThrdGlbl pTG);
|
|
/***************** end of prototypes from ecm.c *****************/
|
|
|
|
|
|
|
|
BYTE RCP[3] = { 0xFF, 0x03, 0x86 };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ET30ACTION ECMPhaseC(PThrdGlbl pTG, BOOL fReTx)
|
|
{
|
|
USHORT uFrameNum, uFramesSent, uLim;
|
|
SWORD swRet;
|
|
ULONG lTotalLen=0;
|
|
LPBYTE lpPPRMask;
|
|
LPBUFFER lpbf=0;
|
|
USHORT uMod;
|
|
|
|
/******** Transmitter ECM Phase C. Fig A-7/T.30 (sheet 1) ********/
|
|
|
|
/***
|
|
switch(action = Params.lpfnWhatNext(pTG, eventSTARTSEND))
|
|
{
|
|
case actionCONTINUE: break;
|
|
case actionDCN:
|
|
case actionHANGUP: return action;
|
|
case actionERROR: return action; // goto PhaseLoop & exit
|
|
default: return BadAction(action);
|
|
}
|
|
***/
|
|
|
|
pTG->ECM.uFrameSize = ProtGetECMFrameSize(pTG);
|
|
BG_CHK(pTG->ECM.uFrameSize==6 || pTG->ECM.uFrameSize==8);
|
|
|
|
// already done in WhatNext
|
|
// uSize = (1 << pTG->ECM.uFrameSize);
|
|
// ICommSetSendMode(TRUE, uSize+ECM_EXTRA, uSize, TRUE);
|
|
|
|
if(fReTx)
|
|
{
|
|
lpPPRMask = ProtGetRetransmitMask(pTG);
|
|
}
|
|
else
|
|
{
|
|
pTG->ECM.uPPRCount = 0;
|
|
|
|
if(pTG->ECM.fEndOfPage)
|
|
{
|
|
pTG->ECM.SendPageCount++;
|
|
pTG->ECM.SendBlockCount = 1;
|
|
pTG->ECM.dwPageSize=0;
|
|
|
|
faxTlog((SZMOD "Waiting for Startpage in ECM at 0x%08lx\r\n", GetTickCount()));
|
|
DEBUGSTMT(IFProcProfile((HTASK)(-1), TRUE));
|
|
|
|
// Callback to open file to send. Doesn't return any data
|
|
if((swRet=GetSendBuf(pTG, 0, SEND_STARTPAGE)) != SEND_OK)
|
|
{
|
|
ERRMSG((SZMOD "<<ERROR>> Nonzero return %d from SendProc at Start Page\r\n", swRet));
|
|
// return actionDCN;
|
|
return actionERROR;
|
|
}
|
|
|
|
DEBUGSTMT(IFProcProfile((HTASK)(-1), FALSE));
|
|
faxTlog((SZMOD "Got Startpage in ECM at 0x%08lx\r\n", GetTickCount()));
|
|
}
|
|
else
|
|
{
|
|
pTG->ECM.SendBlockCount++;
|
|
|
|
faxTlog((SZMOD "Waiting for Startblock in ECM at 0x%08lx\r\n", GetTickCount()));
|
|
DEBUGSTMT(IFProcProfile((HTASK)(-1), TRUE));
|
|
|
|
// Callback to open file to send. Doesn't return any data
|
|
if((swRet=GetSendBuf(pTG, 0, SEND_STARTBLOCK)) != SEND_OK)
|
|
{
|
|
ERRMSG((SZMOD "<<ERROR>> Nonzero return %d from SendProc at Start Page\r\n", swRet));
|
|
// return actionDCN;
|
|
return actionERROR;
|
|
}
|
|
|
|
DEBUGSTMT(IFProcProfile((HTASK)(-1), FALSE));
|
|
faxTlog((SZMOD "Got Startblock in ECM at 0x%08lx\r\n", GetTickCount()));
|
|
}
|
|
}
|
|
|
|
faxTlog((SZMOD "Starting ECM Partial Page SEND.......P=%d B=%d ReTx=%d\r\n",
|
|
pTG->ECM.SendPageCount, pTG->ECM.SendBlockCount, fReTx));
|
|
if(fReTx)
|
|
ICommStatus(pTG, T30STATS_RESEND_ECM, pTG->ECM.SendPageCount, 0, pTG->ECM.SendBlockCount);
|
|
|
|
uMod = ProtGetSendMod(pTG);
|
|
if(uMod >= V17_START && !pTG->ECM.fSentCTC) uMod |= ST_FLAG;
|
|
pTG->ECM.fSentCTC = FALSE;
|
|
|
|
// 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))
|
|
{
|
|
ERRMSG((SZMOD "<<ERROR>> ECM Pix RecvSilence(%d, %d) FAILED!!!\r\n", RECV_PHASEC_PAUSE, LONG_RECVSILENCE_TIMEOUT));
|
|
}
|
|
|
|
if(!ModemSendMode(pTG, pTG->Params.hModem, uMod, TRUE, ifrECMPIX))
|
|
{
|
|
ERRMSG((SZMOD "<<ERROR>> ModemSendMode failed in Tx ECM PhaseC\r\n"));
|
|
ICommFailureCode(pTG, T30FAILSE_SENDMODE_PHASEC);
|
|
BG_CHK(FALSE);
|
|
return actionERROR;
|
|
}
|
|
|
|
#ifdef IFAX
|
|
BroadcastMessage(pTG, IF_PSIFAX_DATAMODE, (PSIFAX_SEND|PSIFAX_ECM|(fReTx ? PSIFAX_RESEND : 0)), (uMod & (~ST_FLAG)));
|
|
#endif
|
|
faxTlog((SZMOD "SENDING ECM Page Data.....\r\n"));
|
|
FComCriticalNeg(pTG, FALSE);
|
|
|
|
uLim = (fReTx ? pTG->ECM.SendFrameCount : 256);
|
|
BG_CHK(uLim);
|
|
BG_CHK(lpbf == 0);
|
|
|
|
for(uFrameNum=0, uFramesSent=0, lTotalLen=0, swRet=0; uFrameNum<uLim; uFrameNum++)
|
|
{
|
|
if(!fReTx || (lpPPRMask[uFrameNum/8] & (1 << (uFrameNum%8))))
|
|
{
|
|
BG_CHK(uFrameNum < 256 && pTG->ECM.uFrameSize <=8); // shift below won't ovf 16 bits
|
|
BG_CHK(lpbf == 0);
|
|
swRet = GetSendBuf(pTG, &lpbf, (fReTx ? ((SLONG)(uFrameNum << pTG->ECM.uFrameSize)) : SEND_SEQ));
|
|
|
|
if(swRet == SEND_ERROR)
|
|
{
|
|
ERRMSG((SZMOD "<<ERROR>> Error return from SendProc in ECM retransmit\r\n"));
|
|
BG_CHK(lpbf == 0);
|
|
// return actionDCN; // goto NodeC;
|
|
return actionERROR;
|
|
}
|
|
else if(swRet == SEND_EOF)
|
|
{
|
|
BG_CHK(lpbf == 0);
|
|
if(!fReTx)
|
|
break;
|
|
else
|
|
{
|
|
BG_CHK(FALSE);
|
|
ICommFailureCode(pTG, T30FAILSE_PHASEC_RETX_EOF);
|
|
return actionDCN;
|
|
}
|
|
}
|
|
BG_CHK(swRet == SEND_OK);
|
|
|
|
BG_CHK(lpbf);
|
|
BG_CHK(lpbf->lpbBegBuf+4 == lpbf->lpbBegData);
|
|
|
|
lpbf->lpbBegBuf[0] = 0xFF;
|
|
lpbf->lpbBegBuf[1] = 0x03;
|
|
lpbf->lpbBegBuf[2] = 0x06;
|
|
lpbf->lpbBegBuf[3] = (BYTE) uFrameNum;
|
|
lpbf->lpbBegData -= 4;
|
|
lpbf->wLengthData += 4;
|
|
|
|
lTotalLen += lpbf->wLengthData;
|
|
|
|
if(!ModemSendMem(pTG, pTG->Params.hModem, lpbf->lpbBegData, lpbf->wLengthData, SEND_ENDFRAME))
|
|
{
|
|
ERRMSG((SZMOD "<<ERROR>> DataWrite Timeout in ECM Phase C\r\n"));
|
|
ICommFailureCode(pTG, T30FAILSE_MODEMSEND_PHASEC);
|
|
BG_CHK(FALSE);
|
|
return actionERROR; // goto error;
|
|
}
|
|
|
|
// faxTlog((SZMOD "Freeing 0x%08lx in ECM\r\n", lpbf));
|
|
if(!MyFreeBuf(pTG, lpbf))
|
|
{
|
|
ERRMSG((SZMOD "<<ERROR>> FReeBuf failed in ECM Phase C\r\n"));
|
|
ICommFailureCode(pTG, T30FAILSE_FREEBUF_PHASEC);
|
|
BG_CHK(FALSE);
|
|
return actionERROR; // goto error;
|
|
}
|
|
lpbf = 0;
|
|
uFramesSent++;
|
|
}
|
|
}
|
|
|
|
if( !ModemSendMem(pTG, pTG->Params.hModem, RCP, 3, SEND_ENDFRAME) ||
|
|
!ModemSendMem(pTG, pTG->Params.hModem, RCP, 3, SEND_ENDFRAME) ||
|
|
!ModemSendMem(pTG, pTG->Params.hModem, RCP, 3, SEND_ENDFRAME|SEND_FINAL))
|
|
{
|
|
ERRMSG((SZMOD "<<ERROR>> DataWrite Timeout on RCPs\r\n"));
|
|
ICommFailureCode(pTG, T30FAILSE_MODEMSEND_ENDPHASEC);
|
|
BG_CHK(FALSE);
|
|
return actionERROR; // goto error;
|
|
}
|
|
/***
|
|
if(!ModemDrain())
|
|
return FALSE;
|
|
***/
|
|
|
|
FComCriticalNeg(pTG, TRUE);
|
|
|
|
faxTlog((SZMOD "Page Send Done.....len=(%ld, 0x%08x)\r\n", lTotalLen, lTotalLen));
|
|
pTG->ECM.FramesSent = uFramesSent;
|
|
|
|
if(!fReTx)
|
|
{
|
|
BG_CHK(lTotalLen>=(ULONG)uFramesSent*4);
|
|
pTG->ECM.dwPageSize+= (lTotalLen-uFramesSent*4); // 4-bytes of framing data
|
|
pTG->ECM.SendFrameCount = uFrameNum;
|
|
|
|
switch(GetSendBuf(pTG, 0, SEND_QUERYENDPAGE))
|
|
{
|
|
case SEND_OK: pTG->ECM.fEndOfPage = FALSE; break;
|
|
case SEND_EOF: pTG->ECM.fEndOfPage = TRUE; break;
|
|
default: ERRMSG((SZMOD "<<ERROR>> Got SEND_ERROR from GetSendBuf at end of page\r\n"));
|
|
return actionERROR;
|
|
}
|
|
}
|
|
if(!pTG->ECM.FramesSent)
|
|
{
|
|
ERRMSG((SZMOD "<<ERROR>> Sent 0 frames--Bad PPR recvd or bad send file\r\n"));
|
|
ICommFailureCode(pTG, T30FAILSE_BADPPR);
|
|
return actionERROR;
|
|
}
|
|
|
|
pTG->T30.fSendAfterSend = TRUE; // ECM PhaseC/PIX--PPS-X
|
|
return actionGONODE_V;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ET30ACTION ECMPhaseD(PThrdGlbl pTG)
|
|
{
|
|
USHORT uTryCount, i;
|
|
ET30ACTION action;
|
|
BYTE bPPSfif[3];
|
|
LPBYTE lpPPR;
|
|
|
|
/******** Transmitter ECM Phase D. Fig A-8 to A-17/T.30 ********/
|
|
|
|
if(!pTG->ECM.fEndOfPage)
|
|
{
|
|
pTG->T30.ifrSend = ifrPPS_NULL;
|
|
}
|
|
else
|
|
{
|
|
switch(action = pTG->Params.lpfnWhatNext(pTG, eventPOSTPAGE))
|
|
{
|
|
case actionSENDMPS: pTG->T30.ifrSend = ifrPPS_MPS; break;
|
|
case actionSENDEOM: pTG->T30.ifrSend = ifrPPS_EOM; break;
|
|
case actionSENDEOP: pTG->T30.ifrSend = ifrPPS_EOP; break;
|
|
#ifdef PRI
|
|
case actionSENDPRIMPS: pTG->T30.ifrSend = ifrPPS_PRI_MPS; break;
|
|
case actionSENDPRIEOM: pTG->T30.ifrSend = ifrPPS_PRI_EOM; break;
|
|
case actionSENDPRIEOP: pTG->T30.ifrSend = ifrPPS_PRI_EOP; break;
|
|
#endif
|
|
case actionERROR: return action; // goto PhaseLoop & exit
|
|
default: return BadAction(pTG, action);
|
|
}
|
|
}
|
|
|
|
bPPSfif[0] = pTG->ECM.SendPageCount-1;
|
|
bPPSfif[1] = pTG->ECM.SendBlockCount-1;
|
|
BG_CHK(pTG->ECM.FramesSent && pTG->ECM.FramesSent<=256);
|
|
// bPPSfif[2] = pTG->ECM.SendFrameCount-1; // don't know which one..!!
|
|
bPPSfif[2] = pTG->ECM.FramesSent-1; // this one! For sure
|
|
|
|
for(uTryCount=0 ;;)
|
|
{
|
|
SendSingleFrame(pTG, pTG->T30.ifrSend, bPPSfif, 3, 1);
|
|
|
|
echoretry:
|
|
pTG->T30.ifrResp = GetResponse(pTG, ifrPPSresponse);
|
|
// 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; }
|
|
|
|
if(pTG->T30.ifrResp != ifrNULL && pTG->T30.ifrResp != ifrBAD)
|
|
break;
|
|
|
|
if(++uTryCount >= 3)
|
|
{
|
|
ERRMSG((SZMOD "<<ERROR>> ECM 3 PostPages, No reply\r\n"));
|
|
ICommFailureCode(pTG, T30FAILSE_3POSTPAGE_NOREPLY);
|
|
return actionDCN;
|
|
}
|
|
}
|
|
|
|
switch(pTG->T30.ifrResp)
|
|
{
|
|
case ifrBAD:
|
|
case ifrNULL: BG_CHK(FALSE); // should never get here
|
|
ICommFailureCode(pTG, T30FAILSE_BUG2);
|
|
return actionERROR; // in case they do :-)
|
|
|
|
case ifrDCN: ERRMSG((SZMOD "<<ERROR>> Got ifrDCN from GetResponse after sending post-page command\r\n"));
|
|
ICommFailureCode(pTG, T30FAILSE_POSTPAGE_DCN);
|
|
return actionHANGUP;
|
|
case ifrPPR: faxTlog((SZMOD "PPR (P=%d B=%d F=%d) Received: ", pTG->ECM.SendPageCount-1, pTG->ECM.SendBlockCount-1, pTG->ECM.FramesSent-1));
|
|
lpPPR = ProtGetRetransmitMask(pTG);
|
|
#ifdef DEBUG
|
|
for(i=0; i<32; i++)
|
|
faxTlog((" %02x", lpPPR[i]));
|
|
faxTlog(("]\r\n"));
|
|
#endif //DEBUG
|
|
|
|
|
|
if(++pTG->ECM.uPPRCount >= 4)
|
|
goto FourthPPR;
|
|
return actionGONODE_ECMRETRANSMIT;
|
|
|
|
case ifrRNR: if((pTG->T30.ifrResp=RNR_RRLoop(pTG)) == ifrDCN)
|
|
{
|
|
ERRMSG((SZMOD "<<ERROR>> RR_RNR loop failed\r\n"));
|
|
// ICommFailureCode already called in RR_RNRLoop()
|
|
return actionDCN;
|
|
}
|
|
faxTlog((SZMOD "Got %d from RNR\r\n", pTG->T30.ifrResp));
|
|
break;
|
|
}
|
|
|
|
switch(pTG->T30.ifrResp)
|
|
{
|
|
case ifrPIP:
|
|
case ifrPIN:
|
|
# ifdef PRI
|
|
return GONODE_E;
|
|
# else
|
|
ERRMSG((SZMOD "<<WARNING>> Procedure interrupts not supported\r\n"));
|
|
// return actionERROR;
|
|
// fallthru and treat like MCF
|
|
pTG->T30.ifrResp = ifrMCF;
|
|
# endif
|
|
|
|
case ifrMCF:
|
|
{
|
|
WORD wSize = (WORD) (pTG->ECM.dwPageSize>>10); //Units are KB
|
|
ICommStatus(pTG, T30STATS_CONFIRM_ECM,
|
|
(USHORT) LOBYTE(wSize),
|
|
(USHORT) HIBYTE(wSize),
|
|
(USHORT)(pTG->ECM.SendPageCount&0xff));
|
|
ERRMSG((SZMOD "Sending T30STATS_CONFIRM_pTG->ECM. wSize=%u\r\n",
|
|
(unsigned) wSize));
|
|
|
|
}
|
|
action=pTG->Params.lpfnWhatNext(pTG, eventGOT_ECM_PPS_RESP,
|
|
(UWORD)pTG->T30.ifrResp, (LPVOID)((DWORD)pTG->T30.ifrSend));
|
|
if(pTG->T30.ifrSend==ifrPPS_EOP && pTG->T30.ifrResp==ifrMCF && action==actionDCN)
|
|
{
|
|
ICommFailureCode(pTG, T30FAILSE_SUCCESS);
|
|
return actionDCN_SUCCESS;
|
|
}
|
|
else
|
|
return action;
|
|
|
|
default: ERRMSG((SZMOD "<<ERROR>> Got UNKNOWN from GetResponse after sending post-page command\r\n"));
|
|
ICommFailureCode(pTG, T30FAILSE_POSTPAGE_UNKNOWN);
|
|
return actionDCN;
|
|
}
|
|
|
|
FourthPPR:
|
|
action = pTG->Params.lpfnWhatNext(pTG, event4THPPR, (WORD)pTG->ECM.SendFrameCount, (DWORD)pTG->ECM.FramesSent);
|
|
switch(action)
|
|
{
|
|
case actionGONODE_ECMRETRANSMIT:
|
|
if(CTC_RespRecvd(pTG, ProtGetSendMod(pTG)) == ifrCTR)
|
|
{
|
|
pTG->ECM.uPPRCount = 0;
|
|
pTG->ECM.fSentCTC = TRUE;
|
|
return actionGONODE_ECMRETRANSMIT;
|
|
}
|
|
else
|
|
{
|
|
ERRMSG((SZMOD "<<ERROR>> CTC-CTR failed\r\n"));
|
|
// ICommFailureCode already called in CTC_RespRecvd(pTG)
|
|
return actionDCN;
|
|
}
|
|
|
|
case actionSENDEOR_EOP:
|
|
case actionDCN:
|
|
case actionERROR:
|
|
return action;
|
|
default:
|
|
return BadAction(pTG, action);
|
|
// none of the EOR stuff
|
|
// return actionDCN;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ET30ACTION ECMSendEOR_EOP(PThrdGlbl pTG)
|
|
{
|
|
// dont set new ICommFailure codes in this function. We have already
|
|
// set the 'too many retries' code
|
|
|
|
USHORT uTryCount;
|
|
|
|
for(uTryCount=0 ;;)
|
|
{
|
|
RETAILMSG((SZMOD "<<WARNING>> Sending EOR-EOP\r\n"));
|
|
|
|
pTG->T30.ifrSend = ifrEOR_EOP;
|
|
SendEOR_EOP(pTG);
|
|
|
|
echoretry:
|
|
pTG->T30.ifrResp = GetResponse(pTG, ifrEORresponse);
|
|
// 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; }
|
|
|
|
if(pTG->T30.ifrResp != ifrNULL && pTG->T30.ifrResp != ifrBAD)
|
|
break;
|
|
|
|
if(++uTryCount >= 3)
|
|
{
|
|
ERRMSG((SZMOD "<<ERROR>> ECM 3 EORs, No reply\r\n"));
|
|
return actionDCN;
|
|
}
|
|
}
|
|
|
|
switch(pTG->T30.ifrResp)
|
|
{
|
|
case ifrBAD:
|
|
case ifrNULL: BG_CHK(FALSE); // should never get here
|
|
return actionERROR; // in case they do :-)
|
|
|
|
case ifrDCN: ERRMSG((SZMOD "<<ERROR>> Got ifrDCN from GetResponse after sending EOR\r\n"));
|
|
return actionHANGUP;
|
|
|
|
case ifrRNR: RETAILMSG((SZMOD "<<WARNING>> Sent EOR-EOP, got RNR\r\n"));
|
|
if((pTG->T30.ifrResp=RNR_RRLoop(pTG)) == ifrDCN)
|
|
{
|
|
ERRMSG((SZMOD "<<ERROR>> RR_RNR loop failed\r\n"));
|
|
// ICommFailureCode already called in RR_RNRLoop(pTG)
|
|
return actionDCN;
|
|
}
|
|
faxTlog((SZMOD "Got %d from RNR\r\n", pTG->T30.ifrResp));
|
|
break;
|
|
}
|
|
|
|
switch(pTG->T30.ifrResp)
|
|
{
|
|
case ifrERR: RETAILMSG((SZMOD "<<WARNING>> Sent EOR-EOP. Got ERR. Sending DCN\r\n"));
|
|
return actionDCN;
|
|
default: ERRMSG((SZMOD "<<ERROR>> Got UNKNOWN from GetResponse after sending EOR\r\n"));
|
|
return actionDCN;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// reduce this so that when externally measured it always ends up less
|
|
// then the specified max of 65s, so we pass protocol conformance tests
|
|
#define T5_TIMEOUT 62000L // 60s + 5s
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
IFR RNR_RRLoop(PThrdGlbl pTG)
|
|
{
|
|
/** Flowchart is:- Enter this on getting an RNR. Then start T5,
|
|
send RR, get response (standard ResponseRecvd routine). If
|
|
no response, send RR again. Repeat 3 times. If RNR response
|
|
recvd, send RR again & repeat, until T5 expires, upon which
|
|
send DCN & hangup.
|
|
|
|
This routine returns ifrDCN, implying teh caller should
|
|
go to NodeC, or ifrXXX, which is used as the response to be
|
|
analysed further down the chart. Never returns ifrNULL
|
|
**/
|
|
|
|
UWORD i;
|
|
IFR ifr;
|
|
|
|
TstartTimeOut(pTG, &(pTG->ECM.toT5), T5_TIMEOUT);
|
|
do
|
|
{
|
|
for(i=0; i<3; i++)
|
|
{
|
|
if(!TcheckTimeOut(pTG, &(pTG->ECM.toT5)))
|
|
{
|
|
ERRMSG((SZMOD "<<ERROR>> T5 timeout on Sender\r\n"));
|
|
ICommFailureCode(pTG, T30FAILSE_RR_T5);
|
|
return ifrDCN; // T5 timed out
|
|
}
|
|
|
|
SendRR(pTG);
|
|
|
|
echoretry:
|
|
ifr = GetResponse(pTG, ifrRRresponse);
|
|
// if we hear our own frame, try to recv again. DONT retransmit!
|
|
if(ifr==ifrRR) { ECHOMSG(ifr); goto echoretry; }
|
|
|
|
if(ifr!=ifrNULL && ifr!=ifrBAD)
|
|
break;
|
|
// on ifrNULL (T4 timeout) we resend RR & try again -- 3 times
|
|
}
|
|
}
|
|
while(ifr == ifrRNR);
|
|
|
|
// BG_CHK(ifr!=ifrRNR && ifr!=ifrNULL && ifr!=ifrBAD && ifr!=ifrTIMEOUT);
|
|
// can get BAD or NULL here when i=3
|
|
BG_CHK(ifr!=ifrRNR && ifr!=ifrTIMEOUT);
|
|
|
|
if(ifr == ifrDCN)
|
|
{
|
|
ERRMSG((SZMOD "<<ERROR>> Got DCN in response to RR\r\n"));
|
|
ICommFailureCode(pTG, T30FAILSE_RR_DCN);
|
|
}
|
|
|
|
if(ifr==ifrBAD || ifr==ifrNULL)
|
|
{
|
|
BG_CHK(i==3);
|
|
ERRMSG((SZMOD "<<ERROR>> No response to RR 3 times\r\n"));
|
|
ICommFailureCode(pTG, T30FAILSE_RR_3xT4);
|
|
ifr=ifrDCN; // same as T5 timeout
|
|
}
|
|
return ifr; // finally got a non-RNR response
|
|
// return ifrDCN or ifrXXXX (not RNR)
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
IFR CTC_RespRecvd(PThrdGlbl pTG, USHORT uBaud)
|
|
{
|
|
UWORD i;
|
|
IFR ifr = ifrDCN;
|
|
BYTE bCTCfif[2];
|
|
|
|
BG_CHK((uBaud & (~0x0F)) == 0);
|
|
bCTCfif[0] = 0;
|
|
bCTCfif[1] = (uBaud << 2);
|
|
|
|
for(i=0; i<3; i++)
|
|
{
|
|
SendCTC (pTG, bCTCfif);
|
|
|
|
echoretry:
|
|
ifr = GetResponse(pTG, ifrCTCresponse);
|
|
// if we hear our own frame, try to recv again. DONT retransmit!
|
|
if(ifr==ifrCTC) { ECHOMSG(ifr); goto echoretry; }
|
|
|
|
|
|
if(ifr!=ifrNULL && ifr!=ifrBAD)
|
|
break;
|
|
// on ifrNULL (T4 timeout) we resend RR & try again -- 3 times
|
|
}
|
|
|
|
if(ifr==ifrNULL || ifr==ifrBAD)
|
|
{
|
|
BG_CHK(i == 3);
|
|
ERRMSG((SZMOD "<<ERROR>> No response to CTC 3 times\r\n"));
|
|
ICommFailureCode(pTG, T30FAILSE_CTC_3xT4);
|
|
ifr = ifrDCN;
|
|
}
|
|
else if(ifr != ifrCTR)
|
|
{
|
|
ERRMSG((SZMOD "<<ERROR>> Bad response CTC\r\n"));
|
|
ICommFailureCode(pTG, T30FAILSE_CTC_UNKNOWN);
|
|
}
|
|
return ifr; // return ifrDCN or ifrXXXX
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ET30ACTION ECMRecvPhaseD ( PThrdGlbl pTG)
|
|
{
|
|
DWORD CurrPPS;
|
|
ET30ACTION action;
|
|
|
|
switch(pTG->T30.ifrCommand)
|
|
{
|
|
case ifrPRI_MPS:
|
|
case ifrPRI_EOM:
|
|
case ifrPRI_EOP:
|
|
# ifdef PRI
|
|
return actionGONODE_RECVPRIQ;
|
|
# else
|
|
pTG->T30.ifrCommand = pTG->T30.ifrCommand-ifrPRI_MPS+ifrMPS;
|
|
break;
|
|
# endif
|
|
|
|
case ifrPPS_PRI_MPS:
|
|
case ifrPPS_PRI_EOM:
|
|
case ifrPPS_PRI_EOP:
|
|
# ifdef PRI
|
|
goto RecvPPSPRIQ;
|
|
# else
|
|
pTG->T30.ifrCommand = pTG->T30.ifrCommand-ifrPPS_PRI_MPS+ifrPPS_MPS;
|
|
break;
|
|
# endif
|
|
|
|
case ifrEOR_PRI_MPS:
|
|
case ifrEOR_PRI_EOM:
|
|
case ifrEOR_PRI_EOP:
|
|
# ifdef PRI
|
|
goto RecvEORPRIQ;
|
|
# else
|
|
pTG->T30.ifrCommand = pTG->T30.ifrCommand-ifrEOR_PRI_MPS+ifrEOR_MPS;
|
|
break;
|
|
# endif
|
|
}
|
|
|
|
|
|
UsePrevCommand:
|
|
|
|
switch(pTG->T30.ifrCommand)
|
|
{
|
|
case ifrCTC:
|
|
EnterPageCrit(); //start CTR--PAGE critsection
|
|
pTG->ECM.fRecvdCTC = TRUE;
|
|
SendCTR(pTG);
|
|
ECHOPROTECT(ifrCTR, modeECMRETX);
|
|
return actionGONODE_RECVECMRETRANSMIT;
|
|
case ifrPPS_NULL:
|
|
case ifrPPS_MPS:
|
|
case ifrPPS_EOM:
|
|
case ifrPPS_EOP:
|
|
// saved for PPS--RNR--RR--MCF(missed)--RR--MCF sequences
|
|
pTG->ECM.ifrPrevCommand = pTG->T30.ifrCommand;
|
|
|
|
//////BugFix 396//////
|
|
CurrPPS = ProtGetPPS(pTG);
|
|
if(pTG->ECM.ifrPrevResponse==ifrMCF && _fmemcmp(pTG->ECM.bPrevPPS, (LPBYTE)(&CurrPPS), 4)==0)
|
|
goto GoSendMCF;
|
|
_fmemcpy(pTG->ECM.bPrevPPS, (LPBYTE)(&CurrPPS), 4);
|
|
pTG->ECM.ifrPrevResponse = 0;
|
|
//////BugFix 396//////
|
|
|
|
switch(ECMRecvOK(pTG))
|
|
{
|
|
default:
|
|
case ECMRECVOK_ABORT: return actionERROR;
|
|
case ECMRECVOK_OK: break;
|
|
case ECMRECVOK_BADFR:
|
|
EnterPageCrit(); //start PPR--PAGE critsection
|
|
SendPPR(pTG, pTG->ECM.bRecvBadFrameMask);
|
|
ECHOPROTECT(ifrPPR, modeECMRETX);
|
|
return actionGONODE_RECVECMRETRANSMIT;
|
|
}
|
|
|
|
// now we can mark eop here
|
|
// #ifdef PRI is on, this won't work (e.g. if the guy sends
|
|
// PRI_MPS at end of page, then this needs to be called but it won't.
|
|
|
|
if(pTG->T30.ifrCommand != ifrPPS_NULL
|
|
&& !pTG->ECM.fRecvEndOfPage) // so we won't call this twice
|
|
{
|
|
// RECV_ENDDOC if PPS_EOP or PPS_EOM
|
|
PutRecvBuf(pTG, NULL, ((pTG->T30.ifrCommand==ifrPPS_MPS) ? RECV_ENDPAGE : RECV_ENDDOC));
|
|
// ignore error/abort. We'll catch it soon enough
|
|
pTG->ECM.fRecvEndOfPage = TRUE;
|
|
}
|
|
|
|
if(!Recv_NotReadyLoop(pTG, ifrPPS_FIRST, ifrPPS_LAST))
|
|
{
|
|
ICommFailureCode(pTG, T30FAILRE_PPS_RNR_LOOP);
|
|
return actionHANGUP;
|
|
}
|
|
|
|
if(pTG->T30.ifrCommand == ifrPPS_NULL)
|
|
{
|
|
action = actionSENDMCF;
|
|
}
|
|
else switch(action = pTG->Params.lpfnWhatNext(pTG, eventRECVPOSTPAGECMD,(WORD)pTG->T30.ifrCommand))
|
|
{
|
|
case actionSENDMCF: break;
|
|
case actionSENDRTN:
|
|
case actionHANGUP:
|
|
case actionERROR:
|
|
default: return BadAction(pTG, action);
|
|
}
|
|
|
|
#ifdef PRI
|
|
if(pTG->T30.ifrCommand != ifrPPS_NULL)
|
|
{
|
|
if((action = pTG->Params.lpfnWhatNext(pTG, eventQUERYLOCALINT))==actionTRUE)
|
|
{
|
|
ECHOPROTECT(ifrPIP, 0);
|
|
SendPIP(pTG);
|
|
break;
|
|
}
|
|
else if(action == actionERROR)
|
|
return action;
|
|
}
|
|
#endif //PRI
|
|
|
|
GoSendMCF:
|
|
pTG->ECM.ifrPrevResponse = ifrMCF;
|
|
if(pTG->T30.ifrCommand == ifrPPS_NULL || pTG->T30.ifrCommand == ifrPPS_MPS)
|
|
{
|
|
EnterPageCrit(); //start ECM MCF--PAGE critsection
|
|
ECHOPROTECT(ifrMCF, modeECM);
|
|
SendMCF(pTG);
|
|
return actionGONODE_RECVPHASEC;
|
|
}
|
|
ECHOPROTECT(ifrMCF, 0);
|
|
SendMCF(pTG);
|
|
if(pTG->T30.ifrCommand==ifrPPS_EOP)
|
|
return actionNODEF_SUCCESS;
|
|
else
|
|
break;
|
|
|
|
case ifrEOR_NULL:
|
|
case ifrEOR_MPS:
|
|
case ifrEOR_EOM:
|
|
case ifrEOR_EOP:
|
|
// saved for EOR--RNR--RR--ERR(missed)--RR--ERR sequences
|
|
pTG->ECM.ifrPrevCommand = pTG->T30.ifrCommand;
|
|
|
|
if(pTG->T30.ifrCommand!=ifrEOR_NULL
|
|
&& !pTG->ECM.fRecvEndOfPage) // so we won't call this twice
|
|
{
|
|
// RECV_ENDDOC if EOR_EOP or EOR_EOM
|
|
PutRecvBuf(pTG, NULL, ((pTG->T30.ifrCommand==ifrEOR_MPS) ? RECV_ENDPAGE : RECV_ENDDOC));
|
|
// ignore error/abort. We'll catch it soon enough
|
|
pTG->ECM.fRecvEndOfPage = TRUE;
|
|
}
|
|
|
|
|
|
if(!Recv_NotReadyLoop(pTG, ifrEOR_FIRST, ifrEOR_LAST))
|
|
{
|
|
ICommFailureCode(pTG, T30FAILRE_EOR_RNR_LOOP);
|
|
return actionHANGUP;
|
|
}
|
|
|
|
#ifdef PRI
|
|
if(pTG->T30.ifrCommand != ifrPPS_NULL)
|
|
{
|
|
if((action = pTG->Params.lpfnWhatNext(pTG, eventQUERYLOCALINT))==actionTRUE)
|
|
{
|
|
ECHOPROTECT(ifrPIN, 0);
|
|
SendPIN(pTG);
|
|
break;
|
|
}
|
|
else if(action == actionERROR)
|
|
return action;
|
|
}
|
|
#endif //PRI
|
|
if(pTG->T30.ifrCommand == ifrEOR_NULL || pTG->T30.ifrCommand == ifrEOR_MPS)
|
|
{
|
|
EnterPageCrit(); //start ERR--PAGE critsection
|
|
ECHOPROTECT(ifrERR, modeECM);
|
|
SendERR(pTG);
|
|
return actionGONODE_RECVPHASEC;
|
|
}
|
|
ECHOPROTECT(ifrERR, 0);
|
|
SendERR(pTG);
|
|
break;
|
|
|
|
case ifrRR:
|
|
if(pTG->ECM.ifrPrevCommand)
|
|
{
|
|
pTG->T30.ifrCommand = pTG->ECM.ifrPrevCommand;
|
|
goto UsePrevCommand;
|
|
}
|
|
else
|
|
{
|
|
ERRMSG((SZMOD "<<WARNING>> ignoring ERR at weird time\r\n"));
|
|
break;
|
|
}
|
|
|
|
default:
|
|
ERRMSG((SZMOD "<<WARNING>> Random Command frame received=%d\r\n", pTG->T30.ifrCommand));
|
|
break; // ignore it
|
|
}
|
|
return actionGONODE_F;
|
|
|
|
#ifdef PRI
|
|
RecvPRIPPS:
|
|
switch(ECMRecvOK(pTG))
|
|
{
|
|
default:
|
|
ECMRECVOK_ABORT: return actionERROR;
|
|
ECMRECVOK_OK: break;
|
|
ECMRECVOK_BADFR:
|
|
EnterPageCrit(); //start PRI PPR--PAGE critsection
|
|
ECHOPROTECT(ifrPPR, modeECMRETX);
|
|
SendPPR(pTG, pTG->ECM.bRecvBadFrameMask);
|
|
return actionGONODE_RECVECMRETRANSMIT;
|
|
}
|
|
RecvPRIEOR:
|
|
switch(action = pTG->Params.lpfnWhatNext(pTG, eventGOTPRIQ, (WORD)pTG->T30.ifrCommand))
|
|
{
|
|
case actionERROR: break; // return to PhaseLoop
|
|
case actionHANGUP: break;
|
|
case actionGONODE_F: break;
|
|
case actionSENDPIP: pTG->T30.ifrSend=ifrPIP; return actionGOVOICE;
|
|
case actionSENDPIN: pTG->T30.ifrSend=ifrPIN; return actionGOVOICE;
|
|
case actionGO_RECVPOSTPAGE:
|
|
if(pTG->T30.ifrCommand >= ifrPPS_PRI_FIRST && pTG->T30.ifrCommand <= ifrPPS_PRI_LAST)
|
|
{
|
|
pTG->T30.ifrCommand = pTG->T30.ifrCommand-ifrPPS_PRI_MPS+ifrPPS_MPS;
|
|
goto NodeVIIIa;
|
|
}
|
|
else if(pTG->T30.ifrCommand >= ifrEOR_PRI_FIRST && pTG->T30.ifrCommand <= ifrEOR_PRI_LAST)
|
|
{
|
|
pTG->T30.ifrCommand = pTG->T30.ifrCommand-ifrEOR_PRI_MPS+ifrEOR_MPS;
|
|
goto NodeIXa;
|
|
}
|
|
else
|
|
{
|
|
BG_CHK(FALSE);
|
|
}
|
|
}
|
|
return action;
|
|
#endif //PRI
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BOOL Recv_NotReadyLoop(PThrdGlbl pTG, IFR ifrFirst, IFR ifrLast)
|
|
{
|
|
IFR ifrCommand;
|
|
|
|
// OBSOLETE:- (??)
|
|
// this is wrong. We should exit only on DCN I think.
|
|
// We should definitely loop again on BAD
|
|
// dunno about TIMEOUT and NULL
|
|
|
|
do
|
|
{
|
|
if(ICommRecvBufIsEmpty(pTG))
|
|
return TRUE;
|
|
|
|
// sleep for a while, to give FMTRES etc some CPU cycles to catch
|
|
// up with us. Can sleep just before sending response, since sender
|
|
// waits upto 3 (6?) secs for it.
|
|
#ifndef FILET30
|
|
IFProcSleep(1000);
|
|
#endif
|
|
|
|
SendRNR(pTG);
|
|
|
|
echoretry:
|
|
ifrCommand = GetCommand(pTG, ifrRNRcommand);
|
|
// if we hear our own frame, try to recv again. DONT retransmit!
|
|
if(ifrCommand==ifrRNR) { ECHOMSG(ifrCommand); goto echoretry; }
|
|
}
|
|
while( ifrCommand==ifrNULL || ifrCommand==ifrBAD ||
|
|
ifrCommand == ifrRR ||
|
|
(ifrCommand >= ifrFirst && ifrCommand <= ifrLast) );
|
|
|
|
// This means we exit on any valid frame _except_ RR and the PPS-X
|
|
// or EOR-X we were expecting. We also exit on ifrTIMEOUT which is
|
|
// when the GetCommand() times out without getting any CONNECT.
|
|
// Otherwise we'd end up sending an MCF after timing out which
|
|
// Ricoh's protocol tester doesnt like. (Ricoh's bug numbbers B3-0106)
|
|
|
|
return FALSE; // just hangs up after this
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ECMRECVOK ECMRecvOK(PThrdGlbl pTG)
|
|
{
|
|
USHORT N, i;
|
|
|
|
N = ProtGetRecvECMFrameCount(pTG);
|
|
// N==actual number of frames, i.e. PPR value+1
|
|
|
|
faxTlog((SZMOD "ECMRecvChk %d frames\r\n", N));
|
|
if(!N || N>256)
|
|
{
|
|
BG_CHK(FALSE);
|
|
return ECMRECVOK_ABORT;
|
|
}
|
|
|
|
for(i=0; i<N; i++)
|
|
{
|
|
if(pTG->ECM.bRecvBadFrameMask[i/8] & (1 << (i%8)))
|
|
{
|
|
faxTlog((SZMOD "ECMRecvChk--bad fr=%d\r\n", i));
|
|
return ECMRECVOK_BADFR;
|
|
}
|
|
}
|
|
return ECMRECVOK_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ET30ACTION ECMRecvPhaseC(PThrdGlbl pTG, BOOL fRetrans)
|
|
{
|
|
/******** Receiver ECM Phase C. Fig A-7/T.30 (sheet 1) ********/
|
|
|
|
ULONG lTotalLen=0;
|
|
USHORT uRet, uFrameNum, uRCPCount, uSize;
|
|
USHORT uRecvFrame, uMod;
|
|
LPBUFFER lpbf;
|
|
LPBUFFER lpbfShort;
|
|
|
|
// There is a race between sending the CFR and sending out an
|
|
// +FRM=xx command, so we want to do it ASAP.
|
|
|
|
pTG->ECM.uFrameSize = ProtGetRecvECMFrameSize(pTG);
|
|
BG_CHK(pTG->ECM.uFrameSize==6 || pTG->ECM.uFrameSize==8);
|
|
uSize = (1 << pTG->ECM.uFrameSize);
|
|
|
|
uMod = ProtGetRecvMod(pTG);
|
|
if(uMod >= V17_START && !pTG->ECM.fRecvdCTC) uMod |= ST_FLAG;
|
|
|
|
pTG->T30.sRecvBufSize = MY_ECMBUF_SIZE;
|
|
|
|
if((uRet = ModemECMRecvMode(pTG, pTG->Params.hModem, uMod, PHASEC_TIMEOUT)) != RECV_OK)
|
|
{
|
|
ExitPageCrit();
|
|
ERRMSG((SZMOD "<<WARNING>> ECMPhC: RecvMode ret=%d\r\n", uRet));
|
|
|
|
if(!fRetrans)
|
|
{
|
|
// in case we miss the page entirely
|
|
// and jump into PhaseD directly
|
|
|
|
// init bad frame bitmask to all-bad
|
|
memset(pTG->ECM.bRecvBadFrameMask, 0xFF, 32); // all bad
|
|
// init the status vars for the PPS/EOR--(RR-RNR)*--PPR/MCF loop
|
|
pTG->ECM.ifrPrevCommand = 0;
|
|
// reset the FrameInThisBlock count. Reset only on
|
|
// non-retransmit. Set when first PPS is recvd
|
|
ProtResetRecvECMFrameCount(pTG);
|
|
|
|
if(pTG->ECM.fRecvEndOfPage) // as opposed to end-of-block
|
|
uRet = (USHORT)PutRecvBuf(pTG, NULL, RECV_STARTPAGE);
|
|
else
|
|
uRet = (USHORT)PutRecvBuf(pTG, NULL, RECV_STARTBLOCK);
|
|
|
|
pTG->ECM.fRecvEndOfPage = FALSE;
|
|
if(!uRet)
|
|
{
|
|
ERRMSG((SZMOD "<<ERROR>> Got Error from PutRecvBuf at StartPage/Block\r\n"));
|
|
return actionERROR;
|
|
}
|
|
pTG->EchoProtect.modePrevRecv = modeECM;
|
|
}
|
|
else
|
|
pTG->EchoProtect.modePrevRecv = modeECMRETX;
|
|
|
|
// set global flag if we got WRONGMODE
|
|
pTG->EchoProtect.fGotWrongMode = (uRet==RECV_WRONGMODE);
|
|
|
|
// elim flush--does no good & wastes 10ms
|
|
// ModemFlush(pTG->Params.hModem);
|
|
return actionGONODE_F;
|
|
// try to get 300bps command instead
|
|
}
|
|
ExitPageCrit();
|
|
|
|
// as soon as we get good carrier ZERO the pTG->EchoProtect state
|
|
_fmemset(&pTG->EchoProtect, 0, sizeof(pTG->EchoProtect));
|
|
|
|
// reset this flag AFTER we successfully recv LONG_TRAIN. We may get an
|
|
// echo of our last command, go to NodeF, reject the echo and loop back
|
|
// here. In that case we want to retry LONG train, otherwise we always
|
|
// croak after a CTC
|
|
pTG->ECM.fRecvdCTC = FALSE;
|
|
|
|
#ifdef IFAX
|
|
BroadcastMessage(pTG, IF_PSIFAX_DATAMODE, (PSIFAX_RECV|PSIFAX_ECM|(fRetrans ? PSIFAX_RERECV : 0)), (uMod & (~ST_FLAG)));
|
|
#endif
|
|
faxTlog((SZMOD "RECEIVING ECM Page.......\r\n"));
|
|
if(fRetrans)
|
|
ICommStatus(pTG, T30STATR_RERECV_ECM, 0, 0, 0);
|
|
|
|
// Turn yielding on *after* entering receive mode safely!
|
|
FComCriticalNeg(pTG, FALSE);
|
|
|
|
/***
|
|
switch(action = pTG->Params.lpfnWhatNext(eventSTARTRECV))
|
|
{
|
|
case actionCONTINUE: break;
|
|
case actionDCN: ERRMSG((SZMOD "<<ERROR>> Got actionDCN from eventSTARTRECV\r\n"));
|
|
return actionDCN; // goto NodeC;
|
|
case actionHANGUP: ERRMSG((SZMOD "<<ERROR>> Got actionHANGUP from eventSTARTRECV\r\n"));
|
|
return action; // goto NodeB;
|
|
case actionERROR: return action;
|
|
default: return BadAction(action);
|
|
}
|
|
***/
|
|
|
|
if(!fRetrans)
|
|
{
|
|
memset(pTG->ECM.bRecvBadFrameMask, 0xFF, 32);
|
|
ProtResetRecvECMFrameCount(pTG);
|
|
|
|
if(pTG->ECM.fRecvEndOfPage) // as opposed to end-of-block
|
|
uRet = (USHORT)PutRecvBuf(pTG, NULL, RECV_STARTPAGE);
|
|
else
|
|
uRet = (USHORT)PutRecvBuf(pTG, NULL, RECV_STARTBLOCK);
|
|
if(!uRet)
|
|
{
|
|
ERRMSG((SZMOD "<<ERROR>> Got Error from PutRecvBuf at StartPage/Block\r\n"));
|
|
return actionERROR;
|
|
}
|
|
}
|
|
pTG->ECM.ifrPrevCommand = 0;
|
|
pTG->ECM.fRecvEndOfPage = FALSE;
|
|
pTG->ECM.ifrPrevResponse = 0;
|
|
|
|
|
|
DEBUGSTMT(if(fRetrans) D_PSIFAXCheckMask(pTG, pTG->ECM.bRecvBadFrameMask));
|
|
|
|
|
|
// make it large, in case of large buffers & slow modems
|
|
#define READ_TIMEOUT 25000
|
|
|
|
lpbfShort=0;
|
|
for(uFrameNum=0, lpbf=0, lTotalLen=0, uRCPCount=0, uRet=RECV_OK; uRet!=RECV_EOF;)
|
|
{
|
|
if(lpbf)
|
|
{
|
|
faxTlog((SZMOD "<<WARNING>> ECM RecvPhC: Freeing leftover Buf 0x%08lx inside loop\r\n", lpbf));
|
|
MyFreeBuf(pTG, lpbf); // need to free after bad frames etc
|
|
}
|
|
|
|
lpbf = 0;
|
|
uRet=ModemRecvBuf(pTG, pTG->Params.hModem, TRUE, &lpbf, READ_TIMEOUT);
|
|
|
|
if(uRet == RECV_BADFRAME)
|
|
{
|
|
ERRMSG((SZMOD "<<WARNING>> ModemRecvBuf returns BADFRAME\r\n"));
|
|
continue;
|
|
}
|
|
else if(uRet == RECV_EOF)
|
|
{
|
|
BG_CHK(lpbf == 0);
|
|
if(lpbfShort)
|
|
{
|
|
lpbf = lpbfShort;
|
|
lpbfShort = 0;
|
|
|
|
if(fRetrans && ((USHORT)(lpbf->lpbBegData[3])+1 < ProtGetRecvECMFrameCount(pTG)))
|
|
{
|
|
RETAILMSG((SZMOD "<<WARNING>> DISCARDING Short but not-really-terminal FCD frame(N=%d). len=%d. PADDING to %d!!\r\n", lpbf->lpbBegData[3], lpbf->wLengthData, uSize+4));
|
|
IFBufFree(lpbf);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
RETAILMSG((SZMOD "<<WARNING>> Short Terminal FCD frame(N=%d). len=%d. PADDING to %d!!\r\n", lpbf->lpbBegData[3], lpbf->wLengthData, uSize+4));
|
|
BG_CHK(lpbf->wLengthBuf >= uSize+4);
|
|
_fmemset(lpbf->lpbBegData+lpbf->wLengthData, 0, (uSize+4-lpbf->wLengthData));
|
|
lpbf->wLengthData = uSize+4;
|
|
goto skipchks;
|
|
}
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
else if(uRet != RECV_OK)
|
|
{
|
|
ERRMSG((SZMOD "<<WARNING>> Got %d from RecvBuf in ECMREcvPhaseC\r\n", uRet));
|
|
break;
|
|
}
|
|
else if(lpbf==0)
|
|
{
|
|
// sometimes we get RECV_OK with no data. Treat same as bad frame
|
|
continue;
|
|
}
|
|
|
|
BG_CHK(uRet==RECV_OK && lpbf && lpbf->lpbBegData);
|
|
|
|
if(uRCPCount >= 3)
|
|
{
|
|
ERRMSG((SZMOD "<<WARNING>> Got a good frame after %d RCP\r\n", uRCPCount));
|
|
continue;
|
|
}
|
|
|
|
if( lpbf->lpbBegData[0] != 0xFF ||
|
|
lpbf->lpbBegData[1] != 0x03 ||
|
|
(lpbf->lpbBegData[2] & 0x7F) != 0x06)
|
|
{
|
|
ERRMSG((SZMOD "<<ERROR>> Bad frame (N=%d) not caught FCF=%02x!!\r\n", uFrameNum, lpbf->lpbBegData[2]));
|
|
BG_CHK(FALSE);
|
|
continue;
|
|
}
|
|
|
|
if(lpbf->lpbBegData[2] == 0x86)
|
|
{
|
|
// got RCP
|
|
if(lpbf->wLengthData != 3)
|
|
{
|
|
ERRMSG((SZMOD "<<ERROR>> Bad RCP frame len=%d\r\n", lpbf->wLengthData));
|
|
BG_CHK(FALSE);
|
|
continue;
|
|
}
|
|
uRCPCount++;
|
|
faxTlog((SZMOD "Got %d RCP\r\n", uRCPCount));
|
|
#ifdef CL0
|
|
if(uRCPCount >= 3)
|
|
{
|
|
// tell modem that recv is done
|
|
// but keep calling RecvMem until we get RECV_EOF
|
|
ModemEndRecv(pTG, pTG->Params.hModem);
|
|
}
|
|
#endif //CL0
|
|
continue;
|
|
}
|
|
|
|
if(lpbfShort)
|
|
{
|
|
ERRMSG((SZMOD "<<ERROR>> Short FCD frame(N=%d). len=%d DISCARDING\r\n", lpbfShort->lpbBegData[3], lpbfShort->wLengthData));
|
|
MyFreeBuf(pTG, lpbfShort);
|
|
lpbfShort = NULL;
|
|
}
|
|
if(lpbf->wLengthData > (uSize+4))
|
|
{
|
|
ERRMSG((SZMOD "<<ERROR>> FCD frame too long(N=%d %d). len=%d. DISCARDING\r\n", uFrameNum, lpbf->lpbBegData[3], lpbf->wLengthData));
|
|
continue;
|
|
}
|
|
else if(lpbf->wLengthData < (uSize+4))
|
|
{
|
|
RETAILMSG((SZMOD "<<WARNING>> Short FCD frame(N=%d %d). len=%d. Storing\r\n", uFrameNum, lpbf->lpbBegData[3], lpbf->wLengthData));
|
|
BG_CHK(lpbfShort==0);
|
|
lpbfShort = lpbf;
|
|
lpbf = NULL;
|
|
continue;
|
|
}
|
|
|
|
skipchks:
|
|
BG_CHK(lpbf->lpbBegData[2] == 0x06);
|
|
BG_CHK(lpbf->wLengthData == (uSize+4));
|
|
|
|
uRecvFrame = lpbf->lpbBegData[3];
|
|
lpbf->lpbBegData += 4;
|
|
lpbf->wLengthData -= 4;
|
|
|
|
if(!fRetrans)
|
|
{
|
|
if(uFrameNum > uRecvFrame)
|
|
{
|
|
ERRMSG((SZMOD "<<ERROR>> Out of order frame. Got %d Looking for %d\r\n", uRecvFrame, uFrameNum));
|
|
BG_CHK(FALSE);
|
|
// ignore this frame in non-debug mode
|
|
continue;
|
|
}
|
|
else if(uFrameNum < uRecvFrame)
|
|
{
|
|
if(!FillInFrames(pTG, (USHORT)(uRecvFrame-uFrameNum), pTG->T30.sRecvBufSize, uSize))
|
|
{
|
|
ERRMSG((SZMOD "<<ERROR>> Zero return from PutRecvBuf in FillInFrames\r\n"));
|
|
return actionERROR;
|
|
}
|
|
}
|
|
lTotalLen += lpbf->wLengthData;
|
|
}
|
|
uFrameNum = uRecvFrame;
|
|
|
|
if(!fRetrans || (pTG->ECM.bRecvBadFrameMask[uFrameNum/8] & (1 << (uFrameNum%8))))
|
|
{
|
|
BG_CHK(uFrameNum < 256 && pTG->ECM.uFrameSize <=8); // shift below wont ovf 16 bits
|
|
if(!PutRecvBuf(pTG, lpbf, (fRetrans ? ((SLONG)(uFrameNum << pTG->ECM.uFrameSize)) : RECV_SEQ)))
|
|
{
|
|
ERRMSG((SZMOD "<<ERROR>> Zero return from PutRecvBuf in page\r\n"));
|
|
return actionERROR;
|
|
}
|
|
pTG->ECM.bRecvBadFrameMask[uFrameNum/8] &= ~(1 << (uFrameNum%8));
|
|
uFrameNum++;
|
|
lpbf = 0;
|
|
}
|
|
}
|
|
|
|
|
|
if(lpbf)
|
|
{
|
|
ERRMSG((SZMOD "<<ERROR>> ECMRecvPhC: Freeing leftover Buf 0x%08lx outside loop\r\n", lpbf));
|
|
MyFreeBuf(pTG, lpbf); // need to free after bad frames etc
|
|
}
|
|
|
|
if(uRet == RECV_EOF)
|
|
{
|
|
FComCriticalNeg(pTG, TRUE);
|
|
// cant mark end of page until we know if end of page or block etc.
|
|
// PutRecvBuf(NULL, RECV_ENDPAGE); // to mark end of Page
|
|
}
|
|
else
|
|
{
|
|
ERRMSG((SZMOD "<<ERROR>> DataRead Timeout or Error=%d\r\n", uRet));
|
|
BG_CHK(FALSE);
|
|
ICommFailureCode(pTG, T30FAILRE_MODEMRECV_PHASEC);
|
|
return actionERROR; // goto error;
|
|
}
|
|
|
|
faxTlog((SZMOD "ECM Page Recv Done.....len=(%ld, 0x%08x)\r\n", lTotalLen, lTotalLen));
|
|
ECHOPROTECT(0, 0);
|
|
return actionGONODE_F; // goto NodeF; // get post-message command
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BOOL FillInFrames(PThrdGlbl pTG, USHORT N, LONG sBufSize, USHORT uDataSize)
|
|
{
|
|
USHORT i;
|
|
LPBUFFER lpbf;
|
|
|
|
for(i=0; i<N; i++)
|
|
{
|
|
#ifdef IFK
|
|
TstartTimeOut(pTG, &pTG->T30.toBuf, WAITFORBUF_TIMEOUT);
|
|
while(!(lpbf = MyAllocBuf(pTG, sBufSize)))
|
|
{
|
|
if(!TcheckTimeOut(pTG, &pTG->T30.toBuf))
|
|
{
|
|
ERRMSG((SZMOD "<<ERROR>> Giving up on BufAlloc in T30-ECM after %ld millisecs\r\n", ((ULONG)WAITFORBUF_TIMEOUT)));
|
|
BG_CHK(FALSE);
|
|
return FALSE;
|
|
}
|
|
RETAILMSG((SZMOD "<<ERROR>> BufAlloc failed in T30-pTG->ECM. Trying again\r\n"));
|
|
IFProcSleep(100);
|
|
}
|
|
#else
|
|
if(!(lpbf = MyAllocBuf( pTG, sBufSize)))
|
|
return FALSE;
|
|
#endif
|
|
|
|
lpbf->wLengthData = uDataSize;
|
|
|
|
if(!PutRecvBuf(pTG, lpbf, RECV_SEQBAD))
|
|
{
|
|
ERRMSG((SZMOD "<<ERROR>> Zero return from PutRecvBuf in page\r\n"));
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef SWECM
|
|
|
|
USHORT ModemECMRecvMode(PThrdGlbl pTG, HMODEM h, USHORT uMod, ULONG ulTimeout)
|
|
{
|
|
if(!SWECMRecvSetup(pTG, TRUE))
|
|
{
|
|
BG_CHK(FALSE);
|
|
return RECV_ERROR;
|
|
}
|
|
return ModemRecvMode(pTG, h, uMod, FALSE, ulTimeout, ifrPIX_SWECM);
|
|
}
|
|
|
|
#endif //SWECM
|
|
|
|
|