#ifndef RQPROTECTED_H
#define RQPROTECTED_H

#ifdef __cplusplus
extern "C" {
#endif

	// This file contains protected declarations i.e. DLL components that are exported
	// but not part of the public API
	// RQInternal.h contains non-exported declarations that are only visible within the DLL
	// RQ.h contains public declarations that form the public API

#include <stdarg.h>
#include <windows.h>

#include "RQ.h"
#include "RQError.h"
#include "RQCardBlockDescriptionsProtected.h"
#include "NDTSError.h"

#define RQ_NUMBER_OF_FPGA_PAIRS						1

#define RQ_NUMBER_OF_SAMPLING_SYSTEMS				1

#define RQ_SAMPLE_DATA_AVAILABLE_MAX_WAIT			1.0f
#define RQ_GATE_SETUP_MAX_WAIT						0.001f
#define RQ_DDS_MAX_WAIT								0.100f
#define RQ_CALIBRATION_WRITE_MAX_WAIT				0.001f
#define RQ_FOCUSING_UNIT_MAX_WAIT					0.001f

#define RQ_SRAM_MAXIMUM_START_DELAY					2097152  // 2^21 (16 + 5)
#define RQ_SRAM_MAXIMUM_NUMBER_OF_SAMPLES			65536 // was 16384 before DSP_v224
#define RQ_SRAM_MAXIMUM_NUMBER_OF_BSCANS			4096
#define RQ_SRAM_MAXIMUM_NUMBER_OF_ASCANS_PER_BSCAN	RQ_MAXIMUM_NUMBER_OF_ELEMENTS
#define RQ_MAXIMUM_GENERATOR_PULSE_LENGTH			4095

#define RQ_MAXIMUM_NUMBER_OF_TCG_VALUES				32768

#define RQ_PINGPONG_SEQUENCE_LENGTH					RQ_MAXIMUM_NUMBER_OF_ELEMENTS
#define RQ_PINGPONG_ARRAY_SIZE						RQ_MAXIMUM_NUMBER_OF_ELEMENTS

#define RQ_CURVED_GATE_NUMBER_OF_VALUES				4096
#define RQ_CURVED_GATE_MAXIMUM_ELEMENT				2047

#define RQ_RAW_ADC_VALUE_RANGE						4096

#define RQ_SRAM_BANK_SIZE							0x00400000

// Bits used for special functions on RS1 / RS2 hardware.  
// See \\fs1\Ndts\technical\RapiDAQ\Documentation\1.0-PIO0-Assignment-and-wiring-for-RS2.doc

#define RQ_DI_BOARD_FET_SWITCH_INDEX				28
#define RQ_DI_BOARD_WATER_PUMP_INDEX				29

#define RQ_MAXIMUM_RPN_SEQUENCE_LENGTH				256

#define RQ_MAXIMUM_SAMPLING_FREQUENCY				100000000
#define RQ_MINIMUM_SAMPLING_FREQUENCY				40000000

#define TCG_HOLDING_BUFFER_SIZE (256L * 1024L)

#define MAX_SDK_HOOKS 5

// Time between writing a new value to the A/D and checking the output
#define CALIBRATION_SETTLE_TIME_MS 10


typedef struct 
{
	unsigned long *pCRCTable ;
	RQ_CRCStatistics statistics ;
	void (*pCRCBadScanHook)(const RQ_BadAScanStatistics *pAScanStatistics, const RQ_BadCScanStatistics *pCScanStatistics, void* pContext) ;
	void *pCRCBadScanHookContext ;
	NDTS_Boolean isGatesCRCPresent ;
} RQ_CRCState ;

typedef struct 
{
	NDTS_Boolean isDebugMode ;
	NDTS_Boolean isDiagnosticsMode ;
	char diagnosticsFilename[512] ;
	NDTS_Boolean isPCIInitialised ;
	NDTS_Boolean isDMAChannelOpen ;
	NDTS_Boolean isInitialised ;
	NDTS_Boolean isCalibrated[RQ_NUMBER_OF_ANALOGUE_GAIN_VALUES];
	short calibrationOffsets[RQ_NUMBER_OF_ANALOGUE_GAIN_VALUES] ;
	short calibrationGains[RQ_NUMBER_OF_ANALOGUE_GAIN_VALUES] ;
	RQ_Gate gates[RQ_MAXIMUM_NUMBER_OF_ELEMENTS][RQ_MAXIMUM_NUMBER_OF_GATES_COMPILE_TIME] ;
	unsigned long samplingFrequency ;
	unsigned long repetitionRate ;
	unsigned long repetitionTime;
	unsigned short *pTCGCurve ;
	unsigned long numberOfTCGValues ;
	unsigned short *pPingPongSequence ;				// Element that is fired - this is the non flipped version of the element
													// and is used to re-write the ping pong sequence when flipping is turned on / off
	unsigned short *pReversePingPongSequenceDest ;  // Use this when extracting and writing to a destination
	unsigned short *pReversePingPongSequenceSource ;  // OR use this when extracting and reading from a source
	unsigned short numberOfElementsForFlipping ;	// If this is non zero flip the array index 0 = numberOfElementsForFlipping.. numberOfElementsForFlipping = 0
	unsigned short *pCurvedGateData ;
	//unsigned long rawScanDataArrayLength ;
	//unsigned long numberOfBufferedScanData ;
	CRITICAL_SECTION criticalSection ;
	unsigned long cardSerialNumber;
	unsigned long calibrationFlags;
	unsigned long inputRange;
	unsigned long zeroTweak[6]; // user-defined deviation from calibrated zero
	RQ_CRCState crcState ;
	char ppDiagnosticStrings[NUMBER_OF_DIAGNOSTIC_STRINGS][DIAGNOSTIC_STRING_SIZE]; // Read by InspectionWare - general debugging strings
	NDTS_Boolean isSequence;
	RQ_SequenceState sequenceState;

	// Sequence compatible fields
	short tweakPlus20;
	short tweakMinus20;
	short tweakMinus40;
	short tcgHoldingBuffer[TCG_HOLDING_BUFFER_SIZE];
	unsigned long maxTCGPoints;

	unsigned long currentSequenceStep; // initialise to 0
	unsigned long numberOfBScansPerBank;
	unsigned long numberOfAScansPerBScan;
	unsigned long peripheralRegisterShadow;
	RQ_Trigger currentTriggerMode;
	unsigned long rqBscanTriggerControlShadow;
	unsigned long rqTriggerControlShadow;

	unsigned long aScanSamplesThisStep[RQ_MAXIMUM_NUMBER_OF_ELEMENTS];
	unsigned long aScanOffsetThisStep[RQ_MAXIMUM_NUMBER_OF_ELEMENTS];
	// A-scan header + data + encoder values + CRC.
	unsigned long aScanBytesPerBScan;
	// In bytes: Points to the first byte of Gate 0 Data Word.
	unsigned long gateOffsetThisStep[RQ_MAXIMUM_NUMBER_OF_ELEMENTS];
	unsigned char gateCountThisStep[RQ_MAXIMUM_NUMBER_OF_ELEMENTS]; // initialise all to 1
	unsigned long gateBytesPerBScan;
	unsigned long numberOfBytesPerSample;
	unsigned long numberOfActiveGatesThisChannel[RQ_MAXIMUM_NUMBER_OF_ELEMENTS];
	unsigned char unpackGate[RQ_MAXIMUM_NUMBER_OF_ELEMENTS][RQ_MAXIMUM_NUMBER_OF_GATES_COMPILE_TIME];
	RQ_StoreGateValue storeGateValue[RQ_MAXIMUM_NUMBER_OF_ELEMENTS][RQ_MAXIMUM_NUMBER_OF_GATES_COMPILE_TIME];  
	unsigned long numberToCheckEitherSide;
	float proportionToTriggerOff;
	//unsigned long numberOfOversamples[RQ_MAXIMUM_NUMBER_OF_STEPS];
	NDTS_Boolean isAutomaticBScansPerBank;
	unsigned long lockEntryCount;
	unsigned long pauseSequenceEntryCount;
	unsigned long dataSamplingStatus ;

	unsigned long numberOfUpdateSampleParametersHooks;
	void (**ppUpdateSampleParametersHooks)(unsigned long cardIndex);
	unsigned long numberOfGetEncoderOutputHooks;
	void (**ppGetEncoderOutputHooks)(unsigned long cardIndex, unsigned long encoderIndex, long *pPosition);
	unsigned long numberOfResetEncoderOutputHooks;
	void (**ppResetEncoderOutputHooks)(unsigned long cardIndex, unsigned long encoderIndex);
	unsigned long oversampleCountThisStep[RQ_MAXIMUM_NUMBER_OF_STEPS];
	unsigned long bScanRepetitionRate;
	int bScansPerSecond;
} RQ_State ;

/*
typedef struct 
{
	HANDLE hDevice ;
	DEVICE_LOCATION device ;
	DMA_CHANNEL_DESC dmaDesc ;
	DMA_TRANSFER_ELEMENT dmaData ;
	PCI_MEMORY pciBuffer ; 
	U32 pCommonBuffer ;
	U32 pPCIBar2VirtualAddress ;
} PCI_State ;
*/

typedef enum 
{
	RQ_RTaddressPattern,
	RQ_RTallOnes,
	RQ_RTallZeros,
	RQ_RTRunAllPatterns,  // New patterns must be before this entry to be included in run all patterns
	RQ_RTNumberOfValues 
} RQ_RAMTestType ;

typedef enum 
{
	RQ_RTADMA,
	RQ_RTA32bit,
	RQ_RTA16bit, // 16 and 8 bit not currently implemented
	RQ_RTA8bit,
	RQ_RTA32bitSlow,
	RQ_RTARunAllAccess,  // New access types above this to be in run all
	RQ_RTANumberOfValues 
} RQ_RAMTestAccess ;
#define SLOW_WORDS_MICRO_SLEEP 1

typedef struct 
{
    unsigned long baseAddress ;  // Base address in bytes
    unsigned long size ;         // Size in bytes
	RQ_RAMTestType testType ;
	RQ_RAMTestAccess accessType ;
	unsigned long numLoops ;
	NDTS_Boolean testPassed ;
	unsigned long failedAddress ;
	unsigned long failedData ;
	RQ_RAMTestType failedTestType ;  // Useful for test all
	RQ_RAMTestAccess failedAccessType ;
	unsigned long failedLoopNumber ;
} RQ_RAMTestParams ;

// Debug information for RQ_DumpBinFiles
typedef struct 
{
	RQ_RAMTestAccess accessType ;
	NDTS_Boolean verifyOnly;
	NDTS_Boolean testPassed;
	unsigned long failedAddress ;
	unsigned long failedData ;
} RQ_DumpBinParams ;



// Old
//RQ_API PCI_State *pPCIStates ;
RQ_API RQ_State *pBoardStates ;

RQ_API NDTS_Boolean CALL_CONV RQ_SetRegister(unsigned long cardIndex, unsigned long offset, unsigned long value) ;
RQ_API NDTS_Boolean CALL_CONV RQ_GetRegister(unsigned long cardIndex, unsigned long offset, unsigned long *value) ;

RQ_API NDTS_Boolean CALL_CONV RQ_PCISetSecondaryID(unsigned long value);

RQ_API NDTS_Boolean CALL_CONV RQ_InitialiseProtected(unsigned long cardIndex, NDTS_Boolean doCalibrate, NDTS_Boolean isSequenced) ;
RQ_API NDTS_Boolean CALL_CONV RQ_PCIInitialise(unsigned long cardIndex) ;

RQ_API NDTS_Boolean CALL_CONV RQ_PCIEnumerateProtected();

RQ_API NDTS_Boolean CALL_CONV RQ_StructuresInitialise(unsigned long cardIndex, RQ_SamplingFirmwareVersion sfv, RQ_PeripheralFirmwareVersion pfv) ;

RQ_API void CALL_CONV RQ_Lock(unsigned long cardIndex) ;
RQ_API void CALL_CONV RQ_Unlock(unsigned long cardIndex) ;
RQ_API void CALL_CONV RQ_PauseSequence(unsigned long cardIndex);
RQ_API void CALL_CONV RQ_ResumeSequence(unsigned long cardIndex);

RQ_API NDTS_Boolean CALL_CONV RQ_DumpBinFiles(unsigned long cardIndex, char *fileNameA, char *fileNameB, RQ_DumpBinParams *testParams) ;

RQ_API NDTS_Boolean CALL_CONV RQ_SetSamplingRegister(unsigned long cardIndex, unsigned long offset, unsigned long value) ;
RQ_API NDTS_Boolean CALL_CONV RQ_GetSamplingRegister(unsigned long cardIndex, unsigned long offset, unsigned long *value) ;

RQ_API NDTS_Boolean CALL_CONV RQ_SetAToDOutputPortFormat(unsigned long cardIndex, unsigned long outputPortFormat) ;
RQ_API NDTS_Boolean CALL_CONV RQ_GetAToDOutputPortFormat(unsigned long cardIndex, unsigned long *pOutputPortFormat) ;
RQ_API NDTS_Boolean CALL_CONV RQ_SetAToDOutputDataFormat(unsigned long cardIndex, unsigned long outputDataFormat) ;
RQ_API NDTS_Boolean CALL_CONV RQ_GetAToDOutputDataFormat(unsigned long cardIndex, unsigned long *pOutputDataFormat) ;
RQ_API NDTS_Boolean CALL_CONV RQ_SetAToDInputVoltageRange(unsigned long cardIndex, unsigned long inputVoltageRange) ;
RQ_API NDTS_Boolean CALL_CONV RQ_GetAToDInputVoltageRange(unsigned long cardIndex, unsigned long *pInputVoltageRange) ;
RQ_API NDTS_Boolean CALL_CONV RQ_SetAToDVrefInputCharacteristics(unsigned long cardIndex, unsigned long inputCharacteristics) ;
RQ_API NDTS_Boolean CALL_CONV RQ_GetAToDVrefInputCharacteristics(unsigned long cardIndex, unsigned long *pInputCharacteristics) ;

RQ_API NDTS_Boolean RQ_CalibrateInput(unsigned long cardIndex, RQ_AnalogueInputRange inp, unsigned long numSamples, short* samples, short* offset, short* gain);

RQ_API NDTS_Boolean CALL_CONV RQ_GetEEPROM(unsigned long cardIndex, unsigned long offset, unsigned long *value);
RQ_API NDTS_Boolean CALL_CONV RQ_SetEEPROM(unsigned long cardIndex, unsigned long offset, unsigned long value);
RQ_API NDTS_Boolean CALL_CONV RQ_GetEEPROMvalues(unsigned long cardIndex);
RQ_API NDTS_Boolean CALL_CONV RQ_RAMTest(unsigned long cardIndex, RQ_RAMTestParams *pParams) ;

RQ_API NDTS_Boolean CALL_CONV RQ_RawWriteGate(unsigned long cardIndex, const RQ_Gate *pGate);

typedef void (*pfnLoggingCallback)(char *pString);
RQ_API void CALL_CONV RQ_SetLoggingCallback(pfnLoggingCallback pfn);

RQ_API NDTS_Boolean CALL_CONV RQ_ClearTCGCurve(unsigned long cardIndex) ;
RQ_API NDTS_Boolean  CALL_CONV RQ_SubmitTCGCurve(unsigned long cardIndex, unsigned long channelIndex, short *pCurve, unsigned long nPts, short gain) ;
RQ_API NDTS_Boolean CALL_CONV RQ_SetEnhancedTCG(unsigned long cardIndex) ;
RQ_API unsigned long CALL_CONV RQ_ReturnNumberOfRapiDAQBoards() ;
RQ_API RQ_State *RQ_ReturnBoardStatePointer(unsigned long cardIndex) ;
RQ_API NDTS_Boolean CALL_CONV RQ_SetUpdateSampleParametersHook(unsigned long cardIndex, void (*pFN)(unsigned long cardIndex)) ;
RQ_API NDTS_Boolean CALL_CONV RQ_SetGetEncoderOutputHook(unsigned long cardIndex, void (*pFN)(unsigned long cardIndex, unsigned long encoderIndex, long *pPosition));
RQ_API NDTS_Boolean CALL_CONV RQ_SetResetEncoderOutputHook(unsigned long cardIndex, void (*pFN)(unsigned long cardIndex, unsigned long encoderIndex));
RQ_API NDTS_Boolean RQ_CopyStateToRawScan(unsigned long cardIndex, RQ_RawScan *pRawScan, NDTS_Boolean copyLiveNumberOfBScans);
// Used in call to RQ_ReadRawScanBlocks().
// Allocate scattered memory blocks for raw scan data A.
// Free the scattered memory allocated by above function.
// Same functions for the gate results data
RQ_API NDTS_Boolean CALL_CONV RQ_GetRawScanNoBankSwap(unsigned long cardIndex, RQ_RawScan *pRawScan) ;
RQ_API NDTS_Boolean RQ_ReadRawScanGateValues(unsigned long cardIndex, 
											  RQ_RawScan *pRawScan, 
											  RQ_CardBlockDescription *pDataBCardBlockDescriptions, 
											  unsigned long numberOfDescriptions);
NDTS_Boolean CALL_CONV RQ_ReadRawScanBScans(unsigned long cardIndex,
											RQ_RawScan *pRawScan,
											RQ_CardBlockDescription* pSourceBlockDescriptionBegin, 
											unsigned long numberOfDescriptions, 
											const unsigned long *pCRCTable);

RQ_API NDTS_Boolean CALL_CONV RQ_ClearDataSamplingStatusFlags(unsigned long cardIndex) ;
RQ_API NDTS_Boolean CALL_CONV RQ_GetNewTriggerOccured(unsigned long cardIndex, NDTS_Boolean *pValue) ;
RQ_API NDTS_Boolean CALL_CONV RQ_GetDelayedTriggerOccured(unsigned long cardIndex, NDTS_Boolean *pValue) ;
RQ_API NDTS_Boolean CALL_CONV RQ_GetDataFullError(unsigned long cardIndex, NDTS_Boolean *pValue) ; 
RQ_API NDTS_Boolean CALL_CONV RQ_GetDataSamplingStatus(unsigned long cardIndex, unsigned long *pValue) ;
RQ_API NDTS_Boolean CALL_CONV RQ_SetDataSamplingStatus(unsigned long cardIndex, unsigned long value) ;
RQ_API NDTS_Boolean CALL_CONV RQ_SetSamplingRegisterBits(unsigned long cardIndex, unsigned long offset, unsigned long mask) ;
RQ_API NDTS_Boolean CALL_CONV RQ_ClearSamplingRegisterBits(unsigned long cardIndex, unsigned long offset, unsigned long mask) ;
RQ_API NDTS_Boolean CALL_CONV RQ_WaitForBankSwap(unsigned long cardIndex) ;

// Should only be called by HLSDK
RQ_API NDTS_Boolean CALL_CONV RQ_InitialiseSequenced(unsigned long cardIndex);
RQ_API void RQ_GetLogLevel(NDTS_LogLevel *pFile, NDTS_LogLevel *pApp, NDTS_LogLevel *pDebugger);
RQ_API void RQ_SetLogLevel(NDTS_LogLevel file, NDTS_LogLevel app, NDTS_LogLevel debugger);

RQ_API int RQ_GetSonatestSerialMuxValue();
// Returns gain in dB from -20 to +40
RQ_API int RQ_GetSonatestSerialMuxGain(unsigned long oneBasedChannel);
// Returns 1 for 1Mhz high pass filter, zero for no filter
RQ_API int RQ_GetSonatestSerialMuxFilter(unsigned long oneBasedChannel);
// Returns a voltage level to clamp at
RQ_API int RQ_GetSonatestSerialMuxVoltageClamp();

NDTS_Boolean RQ_SetAnalogueInputRangeInternal(unsigned long cardIndex, RQ_AnalogueInputRange analogueGain);


//RQ_API NDTS_Boolean RQ_AddRawScanToCard(unsigned long cardIndex, RQ_RawScan *pRawScan) ;

// Busy wait polling the performance timr
// Done as a macro so it can also be used inline in the HLSDK
#define RQ_BUSYMICROSLEEP(X)\
{\
	LARGE_INTEGER frequency, zeroCount, countNow  ;\
	static int firstTime = 1;\
	static float scale ;\
	float microTime = X ;\
	if (firstTime)\
	{\
		firstTime = 0; \
		QueryPerformanceFrequency(&frequency) ;\
		scale = 1000000.0f / (float)(frequency.QuadPart) ;\
	}\
\
    QueryPerformanceCounter(&zeroCount) ;\
	do\
	{\
		QueryPerformanceCounter(&countNow) ;\
		if (countNow.QuadPart < zeroCount.QuadPart)\
		{\
			/* Start delay again if timer wraps */ \
			zeroCount.QuadPart = 0 ;\
		}\
	}\
	while(microTime > (scale * (float) (countNow.QuadPart - zeroCount.QuadPart))) ;\
}\


#ifdef __cplusplus
}
#endif


#endif
