///////////////////////////////////////////////////////////////////////////////////////
// Summer 2008 - made data collection thread independent of RQ and added support
// for the NDTS2100.  Use DC_ (Data Collection) prefix rather than RQT.

// April 2006 - Separate data collection thread to support SFD, WinRS, WinRS - Saab
// The threading code sits "above" the standard RapiDAQ code in rq.c / rqinternal.c
// The project compiles as a separate stand-alone RQT.dll.  It includes the 
// source files from the SDK directory.  These functions 
// contain common threading support for the two modes of operation and are not
// designed to be called directly from an application.
//
//
// There are two modes of operation: RawCollect and Snapshot.
// 
// RawCollect collects NDTS_RawScan data from the card.  The code is in RQRawCollect.c.
// this mode has been developed and tested with a DI unit for WinRS.
//
// Snapshot collects max, min etc. gate data according to the gate's snapshotSelection.  One B scan's
// worth of A scan is also collected according to the selection algorithm.  This mode has been
// developed and tested with a PRX card, firmware 2.x and an InspectionWare application 
// running as an SFD.  The code is in RQSnapshot.c

#ifndef dcTHREAD_H
#define dcTHREAD_H

#include <windows.h>
#include <stdio.h>
#include <io.h>
#include "SnapshotInternal.h"
#include "CollectInternal.h"
#include "DataCollectionError.h"
#include "CRCStatistics.h"
#include "RawScanMemoryBlockNodeProtected.h"

#define DC_PLX_TIMEOUT_FAST 10 // Timeout in mS to wait for plx interrupt if it is possible interrupts are not working
#define DC_PLX_TIMEOUT_SLOW 1000 // Timeout in mS to wait for plx interrupt when we know interrupts are working
#define DC_PAUSE_TIME DC_PLX_TIMEOUT_SLOW  // Time to Sleep in thread when paused
#define DC_TIME_TO_WAIT_FOR_THREAD (DC_PAUSE_TIME + 100) // Time to wait for the thread to run.  Must be greater than DC__TIME_PAUSE or DC__TIME_PLX_TIMEOUT_SLOW
#define DC_SAMPLE_DATA_AVAILABLE_MAX_WAIT			1.0f // Time to wait for Data Available after setting request data before giving up


typedef enum
{
	DC_SMSPause,
	DC_SMSCollect,
	DC_SMSSnapshot,
	DC_SMSShutdown,
	DC_SMSNotStarted,
} DC_StateMachineState;


typedef struct
{
	DC_StateMachineState currentThreadState;
	DC_StateMachineState requestedThreadState;
	HANDLE plxSemaphore; 
	unsigned long plxWaitTimeout;
	HANDLE threadHasRun; 
	CRITICAL_SECTION threadCriticalSection;
	unsigned long threadBankSwaps, appBankSwaps;
	DC_ReturnCode threadExitCode;
	DC_SnapshotState snapshotState;
	DC_CollectState collectState;
	unsigned long dataSamplingStatus ;
	DC_CRCState crcState ;
	DC_AssociatedSDK associatedSDK;  // This will normally be the same for each card.  
	DC_AScanDMATiming aScanDMATiming;

} DC_State;

// This creates the capture thread in the 'paused' state
// NB once the capture thread has been created, data capture from the RapiDAQ card must only be via the capture thread
// Must only be called from SnapshotInitialise / RawCollectInitialise
DC_API NDTS_Boolean DC_Initialise(DC_AssociatedSDK *pAssociatedSDK);

// Stop snapshot capture. Must only be called from SnapshotUninitialise / RawCollectUninitialise
DC_API NDTS_Boolean DC_Uninitialise();

// Sets thread state to start / pause execution.  
// Will block until the thread acknowledges the state change.  This may be up to one second 
// under normal conditions or up to five seconds if the thread can't be contacted.
// A thread should be stopped by calling Uninit, not by setting the state to shutdown.
DC_API NDTS_Boolean CALL_CONV DC_SetThreadState(unsigned long cardIndex, DC_StateMachineState state);

// Requests early bank swap and blocks until the capture thread has completed the bank swap and read the data.
// This MUST NOT be called within an DC_Lock() as the thread must be allowed to run and do the bank swap.
// Will return immediately with DC_NoDataAvailable if there is no data in the bank being filled.
NDTS_Boolean CALL_CONV DC_BankSwapAndUpdate(unsigned long cardIndex);
DC_State *DC_ReturnThreadStatePointer(unsigned long cardIndex);

// Function that is run in the thread.
static DWORD WINAPI DC_ThreadMain(LPVOID lpParameter);

// Called via a hook to DC_UpdateParameters 
void DC_UpdateParameters(unsigned long cardIndex);

// Yields the worker thread for card index.
NDTS_Boolean DC_YieldThread(unsigned long cardIndex) ;
NDTS_Boolean DC_UpdateDataSamplingStats(unsigned long cardIndex);
enum SRQCaller
{
	SRQThread,
	SRQApp
};
NDTS_Boolean DC_ServiceRapiDAQ(unsigned long cardIndex, enum SRQCaller caller);
	
void DC_Lock(unsigned long cardIndex);
void DC_Unlock(unsigned long cardIndex);




NDTS_Boolean CALL_CONV DC_ReadRawScanBlocks(unsigned long cardIndex, 
											unsigned long sourceByteOffset, 
											RawScan_CardBlockDescription* pSourceBlockDescriptionBegin, 
											RawScan_CardBlockDescription* pSourceBlockDescriptionEnd, 
											RawScan_MemoryHandle *pDestinationBlocks, 
											const unsigned long *pCRCTable, 
											unsigned long *pSourceBlocksRead) ; 

NDTS_Boolean CALL_CONV DC_FetchRawScanBytes(unsigned long cardIndex, 
											unsigned long begin, 
											unsigned long end, 
											unsigned long *pTransferCount) ;
NDTS_Boolean DC_ReadRawScanGateValues(unsigned long cardIndex, 
											  NDTS_RawScan *pRawScan, 
											  RawScan_CardBlockDescription *pDataBCardBlockDescriptions, 
											  unsigned long numberOfDescriptions);






#endif
