#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 "NDTSError.h"
#include "RawScanOffline.h"

#define RQ_NUMBER_OF_FPGA_PAIRS						1

#define RQ_NUMBER_OF_SAMPLING_SYSTEMS				1

#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_PINGPONG_SEQUENCE_LENGTH					NDTS_MAXIMUM_NUMBER_OF_ELEMENTS
#define RQ_PINGPONG_ARRAY_SIZE						NDTS_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

// 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_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

	// Non sequenced (i.e. WinRS) always use the firmware specified below
	// DSP FPGA version 0xx has gate 7 curved, 1xx has normal gate 7
	// DSP FPGA version d has trigger holdoff but no array normalisation
	// DSP FPGA version e has trigger holdoff and array normalisation
	// DSP FPGA version x0f has some bug fixes gates with more than 14 peaks are handled properly
	// and the gate trigger holdoff timer is not reset if additional peaks are encountered
	// DSP FPGA version 110 has an issue fixed where largest peak is not evaluated correctly if a gate ends
	// with the signal above the threshold
	// DSP FPGA version 111 includes (faulty) CRC check
	// DSP FPGA version 112 includes (possibly working) CRC check
	// peripheral FPGA 0x00d has jittery encoder fixed
	// DSP FPGA version 113 includes TCG normalisation fix (bug 426)
	// DSP FPGA version 114 includes a working CRC check on the A Scan data.
	// DSP FPGA version 115 includes CRC check on the gated data.
	// DSP FPGA version 116 Initial gates work March 06 - DO NOT USE - bad memory writes
	// DSP FPGA version 117 BScan Sync pulse - DO NOT USE - bad memory writes
	// DSP FPGA version 118 has memory write fixed - DO NOT USE - doesn't write encoder data correctly
	// DSP FPGA version 119 updated with zero crossing gate fix (bug 691) and bank swapping race condition (bug 693) - DO NOT USE - doesn't write encoder data correctly
	// Peripheral FPGA 0x00E Jonathans March 06 work ?
	// Peripheral FPGA 0x00F Jonathans March 06 work ?
	// Peripheral FPGA 0x010 Jonathans March 06 work with zero crossing gates fix (bug 691)
	// DSP FPGA version 11A has encoder memory write bug fix - DO NOT USE DDS write fails.
	// DSP FPGA version 11B has DDS write bug fixed - DO NOT USE - bad memory writes
	// DSP FPGA version 11C has another memory write fix
	// DSP FPGA version 11D has BScan clock pulse for Faro arm fix (untested)
	// DSP FPGA version 11E has data full lockup (bug 710) fix
	// DSP FPGA version 11F disables Arm sync pulse on startup until enabled with the appropriate bit
	// DSP FPGA version 120 Bug 716 work in progress.  Holds off encoder triggers whilst a BScan is being written.  Makes tearing in CScan much better but may not be fully fixed?
	// Peripheral FPGA 0x011 Allows Arm clicks to be stored in encoders 4 and 5.  
	// Peripheral FPGA 0x012 writes encoder values continuously to raw scans when free running.
	// Peripheral FPGA 0x013 has dual encoder support although this is not currently used in WinRS
	// PER_V014 Fix to dual encoder count that could count twice on a change between encoders.
	// PER_V015 Added 1/256 resolution fractional clicks per B-scan.
	// DSP_V121.BIN 19 Oct 06 Force encoder data to be output with A-Scan and C-Scan data for the last element of B-Scan under all conditions.
	// DSP_V122.BIN upto 64K samples of range.
	// DSP_V123.BIN fix for "gate timings" for long ranges - never used in WinRS.
	// DSP_V124.BIN Store A Scan data as sign / magnitude and add test pattern A Scan for PCI freeze testing (bug 786)
	// DSP_V125.BIN Add bit to enable sign and magnitude output data format.  Corrected the test bit pattern
	// PER_V016 has a changed IO driver on the DI unit bus which makes the RS2A with a long cable for Brutus more reliable.

#define RQ_DEFAULT_DSP_REV  0x125;
#define RQ_DEFAULT_PER_REV 0x016;



	/////////////////////////////
	// This struct should be broken into sub structures.  
	// Suggested headings for the structs are below.
	/////////////////////////////

	typedef struct 
	{
		/////////////////////////////
		// Diagnostics
		/////////////////////////////
		NDTS_Boolean isDebugMode ;
		NDTS_Boolean isDiagnosticsMode ;
		char diagnosticsFilename[512] ;
		char ppDiagnosticStrings[NUMBER_OF_DIAGNOSTIC_STRINGS][DIAGNOSTIC_STRING_SIZE]; // Read by InspectionWare - general debugging strings

		/////////////////////////////
		// Lock
		/////////////////////////////	
		CRITICAL_SECTION criticalSection ;
		unsigned long lockEntryCount;


		/////////////////////////////
		// Initialisation
		/////////////////////////////
		NDTS_Boolean isPCIInitialised ;
		NDTS_Boolean isDMAChannelOpen ;
		NDTS_Boolean isInitialised ;

		/////////////////////////////
		// Calibration
		/////////////////////////////
		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] ;
		unsigned long calibrationFlags;
		unsigned long inputRange;
		unsigned long zeroTweak[6]; // user-defined deviation from calibrated zero
		unsigned long cardSerialNumber;

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

		/////////////////////////////
		// PingPong
		/////////////////////////////
		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 ;


		/////////////////////////////
		// Sequence
		/////////////////////////////
		NDTS_Boolean isSequence;
		RQ_SequenceState sequenceState;
		unsigned long currentSequenceStep; // initialise to 0
		unsigned long pauseSequenceEntryCount;

		/////////////////////////////
		// Settings ?? 
		/////////////////////////////
		unsigned long numberOfBScansPerBank;
		unsigned long numberOfAScansPerBScan;
		unsigned long bScanRepetitionRate;
		unsigned long samplingFrequency ;
		unsigned long repetitionRate ;
		unsigned long repetitionTime;
		NDTS_Boolean isAutomaticBScansPerBank;


		/////////////////////////////
		// ShadowRegisters
		/////////////////////////////
		unsigned long peripheralRegisterShadow;
		RQ_Trigger currentTriggerMode;
		unsigned long rqBscanTriggerControlShadow;
		unsigned long rqTriggerControlShadow;
		unsigned long analogueGainShadow;



		/////////////////////////////
		// ScanMemoryLayout
		/////////////////////////////
		// For non sequenced - this is the same number for each A Scan in a B Scan.

		// aScanSamplesThisStep has been replaced by these two values 
		// The number of clock periods over which this A Scan is collected
		unsigned long aScanSamplePeriodsThisStep[NDTS_MAXIMUM_NUMBER_OF_ELEMENTS];

		// The number of sample values stored for an A Scan
		// aScanSamplePeriodsThisStep = aScanSampleValuesThisStep * samplesDivider
		// This does not have anything to do with oversampling
		unsigned long aScanSampleValuesThisStep[NDTS_MAXIMUM_NUMBER_OF_ELEMENTS];


		// The number of aScanSamples has been divided by this ammount because DropSamples were called
		// E.g. if DropSamples is called with 3, the number of samples is divided by 4
		// so if the rangs is set to 1000, aScanSamplesThisStep will be set to 250
		unsigned long samplesDivider;

		unsigned long aScanOffsetThisStep[NDTS_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[NDTS_MAXIMUM_NUMBER_OF_ELEMENTS];
		unsigned char gateCountThisStep[NDTS_MAXIMUM_NUMBER_OF_ELEMENTS]; // initialise all to 1
		unsigned long gateBytesPerBScan;
		unsigned long numberOfBytesPerSample;
		unsigned long numberOfActiveGatesThisChannel[NDTS_MAXIMUM_NUMBER_OF_ELEMENTS];
		unsigned char unpackGate[NDTS_MAXIMUM_NUMBER_OF_ELEMENTS][NDTS_MAXIMUM_NUMBER_OF_GATES_COMPILE_TIME];
		NDTS_Boolean isSignAndMag;
		NDTS_Boolean isFirmwareSignAndMagCapable;
		NDTS_Boolean isCRCPresent;


		/////////////////////////////
		// Gates
		/////////////////////////////
		RQ_StoreGateValue storeGateValue[NDTS_MAXIMUM_NUMBER_OF_ELEMENTS][NDTS_MAXIMUM_NUMBER_OF_GATES_COMPILE_TIME];  
		RQ_Gate gates[NDTS_MAXIMUM_NUMBER_OF_ELEMENTS][NDTS_MAXIMUM_NUMBER_OF_GATES_COMPILE_TIME] ;


		/////////////////////////////
		// NoiseFilter
		/////////////////////////////
		unsigned long numberToCheckEitherSide;
		float proportionToTriggerOff;

		/////////////////////////////
		// Hooks
		/////////////////////////////
		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);

		/////////////////////////////
		// Oversampling
		/////////////////////////////	
		unsigned long oversampleCountThisStep[NDTS_MAXIMUM_NUMBER_OF_STEPS];

	} 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 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, NDTS_RawScan *pRawScan, NDTS_Boolean copyLiveNumberOfBScans);

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) ;

// 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);

// Fetches the number of B Scan that have been completely captured in the current bank
RQ_API NDTS_Boolean CALL_CONV RQ_GetNumberOfBScansCapturedInBank(unsigned long cardIndex, unsigned long *pNumberOfBScans) ;


RQ_API unsigned long CALL_CONV RQ_ReturnOversampleCountThisStep(unsigned long cardIndex, unsigned long aScanIndex);
RQ_API unsigned long CALL_CONV RQ_ReturnAScanSampleValuesThisStep(unsigned long cardIndex, unsigned long aScanIndex);
RQ_API unsigned long CALL_CONV RQ_ReturnGateOffsetThisStep(unsigned long cardIndex, unsigned long aScanIndex);
RQ_API unsigned long CALL_CONV RQ_ReturnGateBytesPerBScan(unsigned long cardIndex);
RQ_API unsigned long CALL_CONV RQ_ReturnAScanOffsetThisStep(unsigned long cardIndex, unsigned long aScanIndex);
RQ_API unsigned long CALL_CONV RQ_ReturnAScanBytesPerBScan(unsigned long cardIndex);
RQ_API NDTS_Boolean CALL_CONV RQ_ReturnIsSignAndMag(unsigned long cardIndex);
RQ_API NDTS_SnapshotDataSelection CALL_CONV RQ_ReturnSnapshotSelectionForGate(unsigned long cardIndex, unsigned long step, unsigned long gate);

//RQ_API NDTS_Boolean RQ_AddRawScanToCard(unsigned long cardIndex, NDTS_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
