|
|
/***************************************************************************
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
|