536 lines
18 KiB
C
536 lines
18 KiB
C
/***************************************************************************
|
|
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 "<<WARNING>> 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 "<<WARNING>> 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 "<<ERROR>> 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 "<<ERROR>> 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 "<<ERROR>> 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 "<<WARNING>> Got arbitrary DLE-ETX. Assuming END OF PAGE!!!\r\n"));
|
|
// pTG->Framing.swEOF = 1;
|
|
|
|
// option (b)
|
|
ERRMSG((SZMOD "<<WARNING>> 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 "<<WARNING>> 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 "<<WARNING>> 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 "<<WARNING>> 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;
|
|
}
|
|
|