/*************************************************************************** Name : FRAMING.C Comment : Functions: (see Prototypes just below) Copyright (c) Microsoft Corp. 1991 1992 1993 Revision Log Date Name Description -------- ----- --------------------------------------------------------- ***************************************************************************/ #include "prep.h" #include "encoder.h" #include "decoder.h" #include "class1.h" #include "debug.h" #include "glbproto.h" #define faxTlog(m) DEBUGMSG(ZONE_SWFRAME, m) #define faxT2log(m) DEBUGMSG(ZONE_SWFRAME2, m) #define FILEID FILEID_FRAMING #ifdef DEBUG # define ST_SWFRAME2(x) if(ZONE_SWFRAME2) { x; } #else # define ST_SWFRAME2(x) { } #endif BOOL FramingBufSetup(PThrdGlbl pTG, BOOL fOn); BOOL SWFramingSendSetup(PThrdGlbl pTG, BOOL fOn) { // If fOn=TRUE, Check that Recv framing is not ON. // Can't use Recv and Send framing simultaneously BG_CHK(!(fOn && pTG->Class1Modem.fRecvSWFraming)); if(fOn) { BG_CHK(!pTG->Class1Modem.fSendSWFraming); } else if(!pTG->Class1Modem.fSendSWFraming) { TRACE((SZMOD "<> SWFramingSendSetup(FALSE) called when not inited. Ignoring\r\n")); return TRUE; } if(!FramingBufSetup(pTG, fOn)) return FALSE; pTG->Class1Modem.fSendSWFraming = fOn; InitEncoder(pTG, pTG->Framing.EncodeState); return TRUE; } BOOL SWFramingRecvSetup(PThrdGlbl pTG, BOOL fOn) { // if fOn=TRUE Check that Send framing is not ON. // Can't use Recv and Send framing simultaneously BG_CHK(!(fOn && pTG->Class1Modem.fSendSWFraming)); if(fOn) { BG_CHK(!pTG->Class1Modem.fRecvSWFraming); } else if(!pTG->Class1Modem.fRecvSWFraming) { TRACE((SZMOD "<> SWFramingRecvSetup(FALSE) called when not inited. Ignoring\r\n")); return TRUE; } if(!FramingBufSetup(pTG, fOn)) return FALSE; pTG->Class1Modem.fRecvSWFraming = fOn; InitDecoder(pTG, pTG->Framing.DecodeState); return TRUE; } BOOL FramingBufSetup(PThrdGlbl pTG, BOOL fOn) { // UWORD uwJunk; if(fOn) { #ifdef SMM pTG->Framing.lpbBuf = pTG->bStaticFramingBuf; pTG->Framing.cbBufSize = FRAMEBUFINITIALSIZE; #else #error NYI ERROR: Code Not Complete--Have to pick GMEM_ flags (FIXED? SHARE?) ...also have to call IFProcSetResFlags(hinstMe)..... BG_CHK(pTG->Framing.lpbBuf==0); if(!(pTG->Framing.lpbBuf = IFMemAlloc(0, FRAMEBUFINITIALSIZE, &uwJunk))) { ERRMSG((SZMOD "<> Out of global memory!!)); // iModemSetError(MODEMERR_RESOURCES, ERR_OUT_OF_MEMORY, 0); return FALSE; } pTG->Framing.cbBufSize = uwJunk; #endif } else { BG_CHK(fOn == FALSE); #ifndef SMM BG_CHK(pTG->Framing.lpbBuf); IFMemFree(pTG->Framing.lpbBuf); #endif pTG->Framing.lpbBuf = 0; pTG->Framing.cbBufSize = 0; } pTG->Framing.cbBufCount = 0; pTG->Framing.lpbBufSrc = pTG->Framing.lpbBuf; pTG->Framing.swEOF = 0; return TRUE; } BOOL SWFramingSendFrame(PThrdGlbl pTG, LPBYTE lpb, USHORT uCount, USHORT uFlags) { WORD wCRC; USHORT cbDst; (MyDebugPrint(pTG, LOG_ALL, "iSW: lpb=%08lx c=%d f=%02x ", lpb, uCount, uFlags, lpb[0])); // always DLE-stuff here. Never zero-stuff BG_CHK(uFlags & SEND_ENDFRAME); BG_CHK(lpb && uCount); BG_CHK(uCount <= 260); // can add stuff to realloc the Dst buffer // to a bigger one as needed here wCRC = CalcCRC(pTG, lpb, uCount); faxT2log((SZMOD "CRC=%04x ", wCRC)); cbDst = HDLC_Encode(pTG, lpb, uCount, pTG->Framing.lpbBuf, &pTG->Framing.EncodeState); faxT2log((SZMOD "D1=%d ", cbDst)); cbDst += HDLC_Encode(pTG, (LPB)(&wCRC), 2, pTG->Framing.lpbBuf+cbDst, &pTG->Framing.EncodeState); faxT2log((SZMOD "D2=%d\r\n", cbDst)); BG_CHK(cbDst + pTG->ModemParams.InterframeFlags <= pTG->Framing.cbBufSize); cbDst += HDLC_AddFlags(pTG, pTG->Framing.lpbBuf+cbDst, pTG->ModemParams.InterframeFlags, &pTG->Framing.EncodeState); faxT2log((SZMOD "D3=%d f=%02x l=%02x\r\n", cbDst, pTG->Framing.lpbBuf[0], pTG->Framing.lpbBuf[cbDst-1])); // always DLE-stuff here. Never zero-stuff if(!FComFilterAsyncWrite(pTG, pTG->Framing.lpbBuf, cbDst, FILTER_DLEONLY)) { ERRMSG((SZMOD "<> DataWrite Timeout\r\n")); goto error; } if(uFlags & SEND_FINAL) { if(!SWFramingSendPostamble(pTG, pTG->Class1Modem.CurMod)) goto error; #ifdef CL0 if(pTG->ModemParams.Class == FAXCLASS0) { if(!FComDirectAsyncWrite(pTG, bDLEETXOK, 8)) goto error; } else #endif //CL0 { // if(!FComDirectAsyncWrite(bDLEETXCR, 3)) if(!FComDirectAsyncWrite(pTG, bDLEETX, 2)) goto error; } if(!iModemDrain(pTG)) goto error; SWFramingSendSetup(pTG, FALSE); FComOutFilterClose(pTG); FComOverlappedIO(pTG, FALSE); FComXon(pTG, FALSE); // critical. End of PhaseC EndMode(pTG); } return TRUE; error: SWFramingSendSetup(pTG, FALSE); FComOutFilterClose(pTG); FComOverlappedIO(pTG, FALSE); FComXon(pTG, FALSE); // critical. End of PhaseC (err) EndMode(pTG); return FALSE; } BOOL SWFramingSendFlags(PThrdGlbl pTG, USHORT uHowMany) { int cb, i; // must be signed (MyDebugPrint(pTG, LOG_ALL, "SENDING ECM Flags (%d).....\r\n", uHowMany)); for(i=0, cb = uHowMany; cb>0; i++, cb -= pTG->Framing.cbBufSize) { if(i<=1) HDLC_AddFlags(pTG, pTG->Framing.lpbBuf, pTG->Framing.cbBufSize, &pTG->Framing.EncodeState); // always DLE-stuff here. Never zero-stuff if(!FComFilterAsyncWrite(pTG, pTG->Framing.lpbBuf,(USHORT) min((USHORT)pTG->Framing.cbBufSize, (USHORT)cb), FILTER_DLEONLY)) { ERRMSG((SZMOD "<> PreFlagDataWrite Timeout\r\n")); return FALSE; } } return TRUE; } USHORT SWFramingRecvFrame(PThrdGlbl pTG, LPBYTE lpb, USHORT cbMax, ULONG ulTimeout, USHORT far* lpcbRecv) { USHORT cbDst, cbProduce, cbConsume, uRet; LPB lpbDst; (MyDebugPrint(pTG, LOG_ALL, "iSW: Buf=%08lx Src=%08lx cbSrc=%d cbMax=%d\r\n", pTG->Framing.lpbBuf, pTG->Framing.lpbBufSrc, pTG->Framing.cbBufCount, cbMax)); /**/ BG_CHK(pTG->Class1Modem.ModemMode == FRM); BG_CHK(pTG->Class1Modem.fRecvSWFraming); startTimeOut(pTG, &(pTG->Class1Modem.toRecv), ulTimeout); /**/ BG_CHK(lpb && cbMax && lpcbRecv); *lpcbRecv = 0; for(lpbDst=lpb, cbDst=cbMax ;; ) { if(pTG->Framing.cbBufCount == 0) { if(pTG->Framing.swEOF == 0) { pTG->Framing.lpbBufSrc = pTG->Framing.lpbBuf; // 4th arg must be FALSE for Class1 pTG->Framing.cbBufCount = FComFilterReadBuf(pTG, pTG->Framing.lpbBufSrc, pTG->Framing.cbBufSize, &(pTG->Class1Modem.toRecv), FALSE, &pTG->Framing.swEOF); faxT2log((SZMOD "f=%02x l=%02x\r\n", pTG->Framing.lpbBufSrc[0], pTG->Framing.lpbBufSrc[pTG->Framing.cbBufCount-1])); if(pTG->Framing.swEOF == -1) { #ifdef CL0 if(pTG->ModemParams.Class == FAXCLASS0) { TRACE((SZMOD "Got Class0 DLE-ETX\r\n")); pTG->Framing.swEOF = 1; } else #endif //CL0 { // See LONG comment under DDI.C ModemRecvData() // option (a) // ERRMSG((SZMOD "<> Got arbitrary DLE-ETX. Assuming END OF PAGE!!!\r\n")); // pTG->Framing.swEOF = 1; // option (b) ERRMSG((SZMOD "<> Got arbitrary DLE-ETX. Ignoring\r\n")); pTG->Framing.swEOF = 0; } } BG_CHK(pTG->Framing.swEOF == 0 || pTG->Framing.swEOF == 1 || pTG->Framing.swEOF == -2 || pTG->Framing.swEOF == -3); // check for progress BG_CHK(pTG->Framing.cbBufCount!=0 || pTG->Framing.swEOF!=0); } else { // pTG->Framing.swEOF != 0 BG_CHK(pTG->Framing.swEOF == 1 || pTG->Framing.swEOF == -2 || pTG->Framing.swEOF == -3); if(cbDst != cbMax) { ERRMSG((SZMOD "<> SWFramingRecv: Got EOF with partial frame %d bytes\r\n", cbMax-cbDst)); ST_SWFRAME2(D_HexPrint(lpb, (USHORT)(cbMax-cbDst))); uRet = RECV_BADFRAME; goto done; } if(pTG->Framing.swEOF == 1) // class1 eof { SWFramingRecvSetup(pTG, FALSE); EndMode(pTG); uRet = RECV_EOF; goto done; } else if(pTG->Framing.swEOF < 0) // error or timeout { SWFramingRecvSetup(pTG, FALSE); EndMode(pTG); uRet = ((pTG->Framing.swEOF == -2) ? RECV_ERROR : RECV_TIMEOUT); goto done; } } } // cbDst=space left in destination lpbDst=start of space // pTG->Framing.cbBufCount=bytes left in source pTG->Framing.lpbBufSrc=start of bytes cbConsume = HDLC_Decode(pTG, pTG->Framing.lpbBufSrc,(USHORT) min(pTG->Framing.cbBufCount, cbDst), lpbDst, &cbProduce, &pTG->Framing.DecodeState); BG_CHK(cbConsume <= pTG->Framing.cbBufCount && pTG->Framing.lpbBufSrc+cbConsume<=pTG->Framing.lpbBuf+pTG->Framing.cbBufSize); BG_CHK(cbProduce <= cbDst && lpbDst+cbProduce <= lpb+cbMax); faxT2log((SZMOD "iSW: C=%d P=%d fa=%d\r\n", cbConsume, cbProduce, pTG->Framing.DecodeState.flagabort)); pTG->Framing.cbBufCount -= cbConsume; pTG->Framing.lpbBufSrc += cbConsume; cbDst -= cbProduce; lpbDst += cbProduce; // check for progress. BG_CHK(pTG->Framing.DecodeState.flagabort==FLAG || // exits below cbProduce || cbConsume || // exits eventually pTG->Framing.cbBufCount==0); // exits or continues above if(pTG->Framing.DecodeState.flagabort == FLAG) { if((cbMax-cbDst)>=2 && (CalcCRC(pTG, lpb, (USHORT)(cbMax-cbDst)) == ((WORD)(~0xF0B8))) ) { cbDst += 2; if(cbMax <= cbDst) { ERRMSG(("GOOD Frame BAD Length!! cbMax=%d cbDst=%d, lpb[0]=%02x lpb[1]=%02x, CRC=%04x\r\n", cbMax, cbDst, lpb[0], lpb[1], CalcCRC(pTG, lpb, (USHORT)(cbMax+2-cbDst)))); BG_CHK(FALSE); // can't get good frame of 0 length! // must return RECV_BADFRAME here otherwise we break. // In HDLC.C the (RECV_OK swRead==0) pair gets converted // to RECV_ERROR and we quit receiving. On some modems // this can happen often. See BUG#1684 uRet = RECV_BADFRAME; } else uRet = RECV_OK; } else { BG_CHK(cbMax >= cbDst); #ifdef DEBUG if (cbMax-cbDst) { ERRMSG((SZMOD "<> BADFR: SWFrRecvFr: CbMax-cbDst = %d bytes\r\n", cbMax-cbDst)); } #endif ST_SWFRAME2(D_HexPrint(lpb, (USHORT)(cbMax-cbDst))); uRet = RECV_BADFRAME; } goto done; } else if(pTG->Framing.DecodeState.flagabort == ABORT) { lpbDst=lpb; cbDst=cbMax; } else if(cbDst == 0) { // bad frames can be very long ERRMSG((SZMOD "<> SWFramingRecv: Overflow. Got %d chars -- no flag\r\n", cbMax)); uRet = RECV_BADFRAME; goto done; } } done: *lpcbRecv = cbMax-cbDst; (MyDebugPrint(pTG, LOG_ALL, "xSW: uR=%d *lpcbR=%d\r\n", uRet, *lpcbRecv)); return uRet; } /********************* ECM Preamble and PostAmble: In T.4 appendix A it says that the Preamble must be 200ms +/1 100ms of flags, and the postamble must be 50ms max. However we also have recving modems that don't know they are getting ECM and need the 6eols to tell them when to stop recving. Also some of them lose large chunks of data at the end of PhaseC due to "carrier squelch", i.e. whne they lose carrier, they throw away the contents of their recv buffer. To get 240ms of flags, just multiply CurMod by 3 // #define SWFramingSendPreamble(b) \ // (FComDirectAsyncWrite(b00EOL, 2), SWFramingSendFlags(b + b + b)) Postamble must have *max* 50ms of flags, so let's say 30ms, which is 9 flags at 2400 and 54 at 14400. Just multiply CurMod by (3/8) to get correct number of flags // #define SWFramingSendPostamble(b) SWFramingSendFlags((b+b+b) >> 3) but with carrier squelch and all that, so few may not be safe. Murata sends out 44 flags at 2400 baud on closing. So lets just send out 80ms (just CurMod flags) This is the 80ms postamble // #define SWFramingSendPostamble(b) SWFramingSendFlags(b) // Fix for DSI bug -- drops last 500 bytes or so //// // #define SWFramingSendPostamble(b) SWFramingSendFlags(600) *********************/ BYTE b00EOL[3] = { 0x00, 0x80, 0 }; BYTE b6EOLs[10] = { 0x00, 0x08, 0x80, 0x00, 0x08, 0x80, 0x00, 0x08, 0x80, 0x00 }; BOOL SWFramingSendPreamble(PThrdGlbl pTG, USHORT uCurMod) { BOOL fRet = TRUE; #ifdef CL0 if(pTG->ModemParams.Class != FAXCLASS0) #endif //CL0 { // fix bug#1762. DataRace modem misses leading EOL unless // preceded by some zeros, and it then chews up all data // until an EOL, thereby eating up part of the first frame SendZeros1(pTG, 100); fRet = fRet && FComDirectAsyncWrite(pTG, b00EOL, 2); } fRet = fRet && SWFramingSendFlags(pTG, (USHORT)(uCurMod + uCurMod + uCurMod)); return fRet; } BOOL SWFramingSendPostamble(PThrdGlbl pTG, USHORT uCurMod) { BYTE bZero[50]; USHORT i; BOOL fRet = TRUE; // send 80ms of flags fRet &= SWFramingSendFlags(pTG, uCurMod); #ifdef CL0 if(pTG->ModemParams.Class != FAXCLASS0) #endif //CL0 { // then send 6EOLs fRet &= FComDirectAsyncWrite(pTG, b6EOLs, 9); // then send 250 or so 00s _fmemset(bZero, 0, 50); for (i=0; i<5; i++) fRet &= FComDirectAsyncWrite(pTG, bZero, 50); } return fRet; }