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.
578 lines
18 KiB
578 lines
18 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
rx_thrd.c
|
|
|
|
Abstract:
|
|
|
|
This module implements async. MR/MH page decoding in a separate thread.
|
|
|
|
Author:
|
|
|
|
Rafael Lisitsa (RafaelL) 14-Aug-1996
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
#define USE_DEBUG_CONTEXT DEBUG_CONTEXT_T30_MAIN
|
|
|
|
#include "prep.h"
|
|
|
|
#include "efaxcb.h"
|
|
#include "t30.h"
|
|
#include "hdlc.h"
|
|
#include "debug.h"
|
|
|
|
#include "tiff.h"
|
|
#include "..\..\..\tiff\src\fasttiff.h"
|
|
|
|
#include "glbproto.h"
|
|
#include "t30gl.h"
|
|
|
|
|
|
// 15 min.
|
|
#define WAIT_FOR_NEXT_STRIP_RX_TIMEOUT 900000
|
|
#define RET_NEXT_STRIP_RX_TIMEOUT 1
|
|
|
|
BOOL DecodeFaxPageAsync
|
|
(
|
|
PThrdGlbl pTG,
|
|
DWORD *RetFlags,
|
|
char *InFileName
|
|
);
|
|
|
|
|
|
DWORD PageAckThread(PThrdGlbl pTG)
|
|
{
|
|
DWORD RetCode = FALSE;
|
|
DWORD RetFlags = 0;
|
|
DWORD ThrdDoneRetCode;
|
|
char InFileName[_MAX_FNAME];
|
|
|
|
DEBUG_FUNCTION_NAME(_T("PageAckThread"));
|
|
//
|
|
// Set the appropriate PRTY for this thread
|
|
// I/O threads run at 15. TIFF - at 9...11
|
|
//
|
|
|
|
if (! SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_HIGHEST) )
|
|
{
|
|
DebugPrintEx( DEBUG_ERR,
|
|
"SetThreadPriority HIGHEST failed le=%x",
|
|
GetLastError());
|
|
goto error_exit;
|
|
}
|
|
|
|
// binary file has fixed name based on lineID; it is created and updated by T.30 RX I/O thread.
|
|
_fmemcpy (InFileName, gT30.TmpDirectory, gT30.dwLengthTmpDirectory);
|
|
_fmemcpy (&InFileName[gT30.dwLengthTmpDirectory], pTG->TiffConvertThreadParams.lpszLineID, 8);
|
|
sprintf (&InFileName[gT30.dwLengthTmpDirectory+8], ".RX");
|
|
|
|
do
|
|
{
|
|
RetFlags = 0;
|
|
|
|
ThrdDoneRetCode = DecodeFaxPageAsync ( pTG,
|
|
&RetFlags,
|
|
InFileName);
|
|
|
|
DebugPrintEx( DEBUG_MSG,
|
|
"DecodeFaxPageAsync RetFlags=%d",
|
|
RetFlags);
|
|
|
|
if ( RetFlags == RET_NEXT_STRIP_RX_TIMEOUT )
|
|
{
|
|
DebugPrintEx( DEBUG_MSG,
|
|
"TimeOut. Trying to delete file%s",
|
|
InFileName);
|
|
|
|
if (!DeleteFile(InFileName))
|
|
{
|
|
DebugPrintEx( DEBUG_ERR,
|
|
"Could not delete file %s, le = %x",
|
|
InFileName,
|
|
GetLastError());
|
|
}
|
|
return (FALSE);
|
|
}
|
|
|
|
// Signal that we finish process the page.
|
|
if (!SetEvent(pTG->ThrdDoneSignal))
|
|
{
|
|
DebugPrintEx( DEBUG_ERR,
|
|
"SetEvent(0x%lx) returns failure code: %ld",
|
|
(ULONG_PTR)pTG->ThrdDoneSignal,
|
|
(long) GetLastError());
|
|
RetCode = FALSE;
|
|
goto error_exit;
|
|
}
|
|
|
|
}
|
|
while (! pTG->ReqTerminate); // Handle the next page
|
|
|
|
|
|
if (!DeleteFile(InFileName))
|
|
{
|
|
DebugPrintEx( DEBUG_ERR,
|
|
"Could not delete file %s, le = %x",
|
|
InFileName,
|
|
GetLastError());
|
|
}
|
|
|
|
DebugPrintEx(DEBUG_MSG,"Terminated");
|
|
|
|
RetCode = TRUE;
|
|
|
|
error_exit:
|
|
|
|
pTG->AckTerminate = 1;
|
|
pTG->fOkToResetAbortReqEvent = 1;
|
|
|
|
if (!SetEvent(pTG->ThrdAckTerminateSignal))
|
|
{
|
|
DebugPrintEx( DEBUG_ERR,
|
|
"SetEvent(0x%lx) returns failure code: %ld",
|
|
(ULONG_PTR)pTG->ThrdAckTerminateSignal,
|
|
(long) GetLastError());
|
|
RetCode = FALSE;
|
|
}
|
|
|
|
DebugPrintEx(DEBUG_MSG,"PageAckThread EXITs");
|
|
|
|
return (RetCode);
|
|
}
|
|
|
|
|
|
BOOL DecodeFaxPageAsync
|
|
(
|
|
PThrdGlbl pTG,
|
|
DWORD *RetFlags,
|
|
char *InFileName
|
|
)
|
|
{
|
|
HANDLE InFileHandle;
|
|
DWORD AllowedBadFaxLines = gT30.MaxErrorLinesPerPage;
|
|
DWORD AllowedConsecBadLines = gT30.MaxConsecErrorLinesPerPage;
|
|
|
|
LPDWORD EndPtr;
|
|
LPDWORD EndBuffer;
|
|
|
|
LPDWORD lpdwResPtr;
|
|
LPDWORD lpdwRead;
|
|
BYTE ResBit;
|
|
BOOL fTestLength;
|
|
BOOL fError;
|
|
|
|
BOOL fFirstRead;
|
|
|
|
LPDWORD lpBuffer=NULL;
|
|
BOOL fLastReadBlockSync; // needs to be sync. fetched, updated by RX I/O thrd.
|
|
DWORD BytesReuse;
|
|
DWORD BytesDelta;
|
|
DWORD BytesToRead;
|
|
DWORD BytesHaveRead;
|
|
|
|
BOOL f1D;
|
|
|
|
DWORD PageCount;
|
|
DWORD NumHandles=2;
|
|
HANDLE HandlesArray[2];
|
|
DWORD WaitResult;
|
|
BOOL fRet=TRUE;
|
|
|
|
//
|
|
// At Start of Page
|
|
//
|
|
|
|
DEBUG_FUNCTION_NAME(_T("DecodeFaxPageAsync"));
|
|
|
|
HandlesArray[0] = pTG->AbortReqEvent;
|
|
HandlesArray[1] = pTG->ThrdSignal;
|
|
|
|
pTG->fTiffThreadRunning = 0;
|
|
|
|
|
|
do
|
|
{
|
|
WaitResult = WaitForMultipleObjects(NumHandles, HandlesArray, FALSE, WAIT_FOR_NEXT_STRIP_RX_TIMEOUT);
|
|
|
|
if (WaitResult == WAIT_TIMEOUT)
|
|
{
|
|
*RetFlags = RET_NEXT_STRIP_RX_TIMEOUT;
|
|
return FALSE;
|
|
}
|
|
|
|
if (WaitResult == WAIT_FAILED)
|
|
{
|
|
DebugPrintEx( DEBUG_ERR,
|
|
"WaitForMultipleObjects FAILED le=%lx",
|
|
GetLastError());
|
|
}
|
|
|
|
if ( pTG->ReqTerminate || ( WaitResult == WAIT_OBJECT_0) )
|
|
{
|
|
DebugPrintEx(DEBUG_MSG, "wait for next page ABORTED") ;
|
|
pTG->fOkToResetAbortReqEvent = 1;
|
|
return TRUE;
|
|
}
|
|
|
|
}
|
|
while (pTG->fPageIsBad); // pTG->fPageIsBad become FALSE when we call to RECV_STARTPAGE to get new page.
|
|
// The reason we wait for fPageIsBad: If the prev page was bad, we want to wait till clean-up was done.
|
|
|
|
pTG->fTiffThreadRunning = 1;
|
|
|
|
pTG->Lines = 0;
|
|
pTG->BadFaxLines = 0;
|
|
pTG->ConsecBadLines = 0;
|
|
pTG->iResScan = 0;
|
|
|
|
PageCount = pTG->PageCount;
|
|
|
|
fLastReadBlockSync = pTG->fLastReadBlock;
|
|
|
|
DebugPrintEx( DEBUG_MSG,
|
|
"waked up fLastReadBlockSync=%d",
|
|
fLastReadBlockSync);
|
|
|
|
if ( ( InFileHandle = CreateFileA(InFileName, GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ,
|
|
NULL, OPEN_EXISTING, 0, NULL) ) == INVALID_HANDLE_VALUE )
|
|
{
|
|
DebugPrintEx( DEBUG_ERR,
|
|
"PAGE COULD NOT open %s",
|
|
InFileName);
|
|
|
|
pTG->fPageIsBad = 1;
|
|
return FALSE;
|
|
}
|
|
|
|
fFirstRead = 1;
|
|
pTG->BytesOut = 0;
|
|
|
|
lpBuffer = MemAlloc(DECODE_BUFFER_SIZE);
|
|
if (!lpBuffer)
|
|
{
|
|
DebugPrintEx(DEBUG_ERR, "MemAlloc failed");
|
|
pTG->fPageIsBad = 1;
|
|
goto bad_exit;
|
|
}
|
|
|
|
// lpBuffer is DWORD aligned
|
|
lpdwResPtr = lpBuffer;
|
|
ResBit = 0;
|
|
|
|
EndBuffer = lpBuffer + ( DECODE_BUFFER_SIZE / sizeof(DWORD) );
|
|
|
|
//
|
|
// loop thru all blocks
|
|
//
|
|
do
|
|
{
|
|
//
|
|
// Read the next RAW block prepared by main I/O thread
|
|
//
|
|
DWORD tiffCompression;
|
|
BOOL HiRes;
|
|
|
|
if (fFirstRead)
|
|
{
|
|
lpdwRead = lpBuffer;
|
|
BytesReuse = 0;
|
|
BytesToRead = DECODE_BUFFER_SIZE;
|
|
fTestLength = DO_NOT_TEST_LENGTH;
|
|
}
|
|
else
|
|
{
|
|
BytesReuse = (DWORD)((EndBuffer - lpdwResPtr) * sizeof (DWORD));
|
|
CopyMemory( (char *) lpBuffer, (char *) lpdwResPtr, BytesReuse);
|
|
lpdwRead = lpBuffer + (BytesReuse / sizeof (DWORD) );
|
|
BytesToRead = DECODE_BUFFER_SIZE - BytesReuse;
|
|
fTestLength = DO_TEST_LENGTH;
|
|
}
|
|
|
|
lpdwResPtr = lpBuffer;
|
|
|
|
BytesDelta = pTG->BytesIn - pTG->BytesOut;
|
|
|
|
if (BytesDelta < DECODE_BUFFER_SIZE)
|
|
{
|
|
if (! fLastReadBlockSync)
|
|
{
|
|
DebugPrintEx( DEBUG_ERR,
|
|
"PAGE LOGIC. SYNC. file %s Bytes: IN:%d OUT:%d",
|
|
InFileName,
|
|
pTG->BytesIn,
|
|
pTG->BytesOut);
|
|
|
|
pTG->fPageIsBad = 1;
|
|
goto bad_exit;
|
|
}
|
|
}
|
|
|
|
if (fLastReadBlockSync)
|
|
{
|
|
if (BytesDelta < BytesToRead)
|
|
{
|
|
BytesToRead = BytesDelta;
|
|
}
|
|
}
|
|
|
|
if (! ReadFile(InFileHandle, lpdwRead, BytesToRead, &BytesHaveRead, NULL ) )
|
|
{
|
|
DebugPrintEx( DEBUG_ERR,
|
|
"PAGE COULD NOT READ file %s Bytes: IN:%d"
|
|
" OUT:%d WANTED:%d LE=%x",
|
|
InFileName,
|
|
pTG->BytesIn,
|
|
pTG->BytesOut,
|
|
BytesToRead,
|
|
GetLastError());
|
|
|
|
pTG->fPageIsBad = 1;
|
|
goto bad_exit;
|
|
}
|
|
|
|
if (BytesHaveRead != BytesToRead)
|
|
{
|
|
DebugPrintEx( DEBUG_ERR,
|
|
"PAGE ReadFile count=%d WANTED=%d file %s"
|
|
" Bytes: IN:%d OUT:%d",
|
|
BytesHaveRead,
|
|
BytesToRead,
|
|
InFileName,
|
|
pTG->BytesIn,
|
|
pTG->BytesOut);
|
|
|
|
pTG->fPageIsBad = 1;
|
|
goto bad_exit;
|
|
}
|
|
|
|
|
|
if ( fLastReadBlockSync && (BytesToRead == BytesDelta) )
|
|
{
|
|
EndPtr = lpBuffer + ( (BytesReuse + BytesToRead) / sizeof(DWORD) );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// leave 1000*4 = 4000 bytes ahead if not final block to make sure
|
|
// we always have one full line ahead.
|
|
//
|
|
EndPtr = EndBuffer - 1000;
|
|
}
|
|
|
|
pTG->BytesOut += BytesToRead;
|
|
|
|
DebugPrintEx( DEBUG_MSG,
|
|
"BytesIn=%d Out=%d Read=%d ResBit=%d StartPtr=%lx"
|
|
" EndPtr=%lx Reuse=%d",
|
|
pTG->BytesIn,
|
|
pTG->BytesOut,
|
|
BytesToRead,
|
|
ResBit,
|
|
lpBuffer,
|
|
EndPtr,
|
|
BytesReuse);
|
|
|
|
//
|
|
// find first EOL
|
|
//
|
|
|
|
f1D = 1;
|
|
|
|
if (! FindNextEol (lpdwResPtr, ResBit, EndBuffer, &lpdwResPtr, &ResBit, fTestLength, &fError) )
|
|
{
|
|
DebugPrintEx( DEBUG_ERR,
|
|
"Couldn't find EOL fTestLength=%d fError=%d",
|
|
fTestLength,
|
|
fError);
|
|
pTG->fPageIsBad = 1;
|
|
goto bad_exit;
|
|
}
|
|
|
|
//
|
|
// Scan the next segment
|
|
//
|
|
// if those settings change from one page to the other
|
|
// it has to be inside the loop, beause this thread
|
|
// gets all the pages and then dies
|
|
tiffCompression = pTG->TiffConvertThreadParams.tiffCompression;
|
|
HiRes = pTG->TiffConvertThreadParams.HiRes;
|
|
DebugPrintEx( DEBUG_MSG,
|
|
"Calling %s with compression=%d and resolution=%d",
|
|
(tiffCompression == TIFF_COMPRESSION_MR)?"ScanMrSegment":"ScanMhSegment",
|
|
tiffCompression,HiRes);
|
|
if (tiffCompression == TIFF_COMPRESSION_MR)
|
|
{
|
|
pTG->iResScan = ScanMrSegment(&lpdwResPtr,
|
|
&ResBit,
|
|
EndPtr,
|
|
EndBuffer,
|
|
&(pTG->Lines),
|
|
&(pTG->BadFaxLines),
|
|
&(pTG->ConsecBadLines),
|
|
AllowedBadFaxLines,
|
|
AllowedConsecBadLines,
|
|
&f1D,
|
|
pTG->TiffInfo.ImageWidth);
|
|
}
|
|
else
|
|
{
|
|
pTG->iResScan = ScanMhSegment(&lpdwResPtr,
|
|
&ResBit,
|
|
EndPtr,
|
|
EndBuffer,
|
|
&(pTG->Lines),
|
|
&(pTG->BadFaxLines),
|
|
&(pTG->ConsecBadLines),
|
|
AllowedBadFaxLines,
|
|
AllowedConsecBadLines,
|
|
pTG->TiffInfo.ImageWidth);
|
|
}
|
|
|
|
DebugPrintEx( DEBUG_MSG,
|
|
"%s returned: ResScan=%d Lines=%d "
|
|
"BadFaxLines=%d tAllowedBadFaxLines=%d "
|
|
"ConsecBadLines=%d AllowedConsecBadLines=%d "
|
|
"tpImageWidth=%d",
|
|
(tiffCompression == TIFF_COMPRESSION_MR)?"ScanMrSegment":"ScanMhSegment",
|
|
pTG->iResScan,
|
|
pTG->Lines,
|
|
pTG->BadFaxLines,
|
|
AllowedBadFaxLines,
|
|
pTG->ConsecBadLines,
|
|
AllowedConsecBadLines,
|
|
pTG->TiffInfo.ImageWidth);
|
|
|
|
if (pTG->iResScan == TIFF_SCAN_SUCCESS)
|
|
{
|
|
goto good_exit;
|
|
}
|
|
else if (pTG->iResScan == TIFF_SCAN_FAILURE)
|
|
{
|
|
DebugPrintEx( DEBUG_ERR,
|
|
"ScanSegment returns TIFF_SCAN_FAILURE");
|
|
pTG->fPageIsBad = 1;
|
|
goto bad_exit;
|
|
}
|
|
else if (pTG->iResScan != TIFF_SCAN_SEG_END)
|
|
{
|
|
DebugPrintEx( DEBUG_ERR,
|
|
"ScanSegment returns INVALID %d",
|
|
pTG->iResScan);
|
|
pTG->fPageIsBad = 1;
|
|
goto bad_exit;
|
|
}
|
|
|
|
//lNextBlock:
|
|
// here we make decision as to whether to do the next segment OR to block (not enough data avail).
|
|
if (fLastReadBlockSync && (pTG->BytesOut == pTG->BytesIn) )
|
|
{
|
|
//
|
|
// The class 2/2.0 standards say the modem is not supposed to include the RTC in the page data.
|
|
// So, for 2/2.0, finishing the page without finding RTC marks the page as good.
|
|
//
|
|
if ((pTG->ModemClass==MODEM_CLASS2) || (pTG->ModemClass==MODEM_CLASS2_0))
|
|
{
|
|
DebugPrintEx(DEBUG_MSG, "Didn't find RTC, but we're on class 2/2.0, so page is good");
|
|
goto good_exit;
|
|
}
|
|
|
|
DebugPrintEx( DEBUG_ERR,
|
|
"Didn't find RTC Bad=%d ConsecBad=%d Good=%d",
|
|
pTG->BadFaxLines,
|
|
pTG->ConsecBadLines,
|
|
pTG->Lines);
|
|
pTG->fPageIsBad = 1;
|
|
goto bad_exit;
|
|
}
|
|
|
|
|
|
DebugPrintEx( DEBUG_MSG,
|
|
"Done with next strip BytesIn=%d Out=%d"
|
|
" Lines=%d Bad=%d ConsecBad=%d Processed %d bytes \n",
|
|
pTG->BytesIn,
|
|
pTG->BytesOut,
|
|
pTG->Lines,
|
|
pTG->BadFaxLines,
|
|
pTG->ConsecBadLines,
|
|
(lpdwResPtr - lpBuffer) * sizeof(DWORD));
|
|
|
|
fLastReadBlockSync = pTG->fLastReadBlock;
|
|
|
|
if ( (pTG->BytesIn - pTG->BytesOut < DECODE_BUFFER_SIZE) && (! fLastReadBlockSync) )
|
|
{
|
|
DebugPrintEx(DEBUG_MSG,"Waiting for next strip to be avail.");
|
|
|
|
pTG->fTiffThreadRunning = 0;
|
|
|
|
WaitResult = WaitForMultipleObjects(NumHandles, HandlesArray, FALSE, WAIT_FOR_NEXT_STRIP_RX_TIMEOUT);
|
|
|
|
if (WaitResult == WAIT_TIMEOUT)
|
|
{
|
|
*RetFlags = RET_NEXT_STRIP_RX_TIMEOUT;
|
|
goto bad_exit;
|
|
}
|
|
|
|
if (WaitResult == WAIT_FAILED)
|
|
{
|
|
DebugPrintEx( DEBUG_ERR,
|
|
"WaitForMultipleObjects FAILED le=%lx",
|
|
GetLastError());
|
|
}
|
|
|
|
if ( pTG->ReqTerminate || ( WaitResult == WAIT_OBJECT_0) )
|
|
{
|
|
DebugPrintEx(DEBUG_MSG,"wait for next page ABORTED") ;
|
|
goto bad_exit;
|
|
}
|
|
|
|
pTG->fTiffThreadRunning = 1;
|
|
|
|
fLastReadBlockSync = pTG->fLastReadBlock;
|
|
|
|
DebugPrintEx( DEBUG_MSG,
|
|
"Waked up with next strip. fLastReadBlockSync=%d"
|
|
" BytesIn=%d Out=%d",
|
|
fLastReadBlockSync,
|
|
pTG->BytesIn,
|
|
pTG->BytesOut);
|
|
|
|
}
|
|
|
|
fFirstRead = 0;
|
|
|
|
}
|
|
while ( ! pTG->ReqTerminate );
|
|
|
|
DebugPrintEx(DEBUG_ERR, "Got Terminate request");
|
|
pTG->fPageIsBad = 1;
|
|
// fall through
|
|
|
|
bad_exit:
|
|
fRet=FALSE;
|
|
goto exit;
|
|
|
|
good_exit:
|
|
fRet=TRUE;
|
|
// fall through
|
|
|
|
exit:
|
|
CloseHandle(InFileHandle);
|
|
if (lpBuffer)
|
|
{
|
|
MemFree(lpBuffer);
|
|
lpBuffer=NULL;
|
|
}
|
|
return fRet;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|