#include <windows.h>
#include <stdio.h>
#include <io.h>
#include <limits.h>
#include <crtdbg.h>

#include "NDTSEnums.h"
#include "NDTSError.h"
#include "RQ.h"
#include "RQInternal.h"
#include "RawScan.h"
#include "RQStrings.h"
#include "RQError.h"
#include "RawScanProtected.h"
#include "SnapshotProtected.h"
#include "RawScanPools.h"
#include "DataCollection.h"
#include "NDTSCommonHAL.h"
#include "Collect.h"


BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
	int c;
	char *pName = globalState.iniFileName;

	(void)lpReserved;

	switch (ul_reason_for_call)
	{
		case DLL_PROCESS_ATTACH :
			// Get the path of the DLL itself and massage this into the name of the INI file
			// which may be alongside it
			GetModuleFileName(hModule, pName, 100);
			c = strlen(pName) - 3;
			pName[c++] = 'i';
			pName[c++] = 'n';
			pName[c++] = 'i';
			RQ_DLLInitialise() ;
			break ;
		case DLL_PROCESS_DETACH :
			RQ_DLLUninitialise() ;
			break ;
		case DLL_THREAD_ATTACH :
			break ;
		case DLL_THREAD_DETACH :
			break ;
    }

    return TRUE ;
}

// **************************************************************************************
 
void CALL_CONV RQ_DLLInitialise()
{
	NDTS_InitErrorService() ;
	RQ_SetLogLevel(RQ_GetDefaultValueInt(RQdef_FileLogLevel), RQ_GetDefaultValueInt(RQdef_AppLogLevel), RQ_GetDefaultValueInt(RQdef_DebuggerLogLevel));

	NDTS_HAL_Initialise() ;
	NDTS_RegisterGetCodeStringFunction(NDTS_ERROR_RQ_SDK_INDEX, &RQ_GetCodeString) ;
  
	RQ_PCIEnumerateProtected(/*pNumberOfCards, RQ_CTRapiDAQ */);
}

void CALL_CONV RQ_DLLUninitialise()
{
	if (pBoardStates != 0)
	{
		free(pBoardStates);
		pBoardStates = 0;
	}
}

RQ_API NDTS_Boolean CALL_CONV RQ_PCIEnumerate(unsigned long *pNumberOfCards)
{
	*pNumberOfCards = globalState.pciState.numberOfRapiDAQBoards;
	// this is now done in DLLInitialise so just return the number of cards we've identified
	//return RQ_PCIEnumerateProtected(pNumberOfCards, RQ_CTRapiDAQ);
	return NDTS_BTrue;
}

RQ_API NDTS_Boolean CALL_CONV RQ_Initialise(unsigned long cardIndex)
{
	// Remove after IW integration here!
	return RQ_InitialiseSequenced(cardIndex);
	//int i = cardIndex; i++; return NDTS_BTrue;

	// Latest thinking is for the SDK to decide which FPGA images to use
	// If an INI file is found, check it otherwise user hard-coded defaults.
	// Other factory settings will be found in the INI file too.
	//return RQ_InitialiseProtected(cardIndex, NDTS_BTrue) ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_InitialiseNonSequenced(unsigned long cardIndex)
{
	if (!RQ_InitialiseProtected(cardIndex, RQ_AG100mV, NDTS_BFalse))
		return NDTS_BFalse;

	return NDTS_BTrue;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetInitialisationStatusCallback(void (*pfnInitStatusCallback)(RQ_InitialisationStep step, RQ_InitialisationStepStatus status))
{
	globalState.pfnInitStatusCallback = pfnInitStatusCallback ;

	return NDTS_BTrue ;
}
 
RQ_API NDTS_Boolean CALL_CONV RQ_Uninitialise(unsigned long cardIndex)
{
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;

	if (!pBoardState) 
		return NDTS_BFalse; 
	
	if (!pBoardState->isInitialised)
	{
		RQ_HandleRQError(RQ_Uninitialise_IsInitialisedFail) ;
		return NDTS_BFalse ;
	}


	// Once we get this far we should always return with the card fully uninitialised
	if (pBoardState->isSequence)
	{
		DC_SnapshotUninitialise();
	}
	else
	{
		DC_CollectUninitialise();
	}

	RQ_Lock(cardIndex) ; // don't try to lock the card until we know that it's initialised

	if (!pBoardState->isPCIInitialised)
	{
		RQ_HandleRQError(RQ_Uninitialise_IsPCIInitialisedFail) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	if (pBoardState->isDMAChannelOpen)
	{
		isOK = RQ_CloseDMAChannel(cardIndex) ;
		if (!isOK)
		{
			RQ_Unlock(cardIndex) ; // If this fails it will set its own error code
			return NDTS_BFalse ;
		}
	}

	isOK = NDTS_HAL_UninitialiseCard(NDTS_SIDRapiDAQ, cardIndex) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ; 
		return NDTS_BFalse ;
	}

	pBoardState->isPCIInitialised = NDTS_BFalse ;

	if (pBoardState->pTCGCurve != 0)
	{
		free(pBoardState->pTCGCurve) ;
		pBoardState->pTCGCurve = 0;
	}

	if (pBoardState->pPingPongSequence != 0)
	{
		free(pBoardState->pPingPongSequence) ;
		pBoardState->pPingPongSequence = 0;
		free(pBoardState->pReversePingPongSequenceDest) ;
		free(pBoardState->pReversePingPongSequenceSource) ;
		pBoardState->pReversePingPongSequenceSource = 0;
		pBoardState->pReversePingPongSequenceDest = 0;
	}


	// Make sure the card is always in a consistent state
	pBoardState->isInitialised = NDTS_BFalse ;
	{
		RQ_AnalogueInputRange range;
		for (range = 0; range < RQ_NUMBER_OF_ANALOGUE_GAIN_VALUES; range++)
		{
			pBoardState->isCalibrated[range] = NDTS_BFalse;
		}
	}
	pBoardState->isDMAChannelOpen = NDTS_BFalse;
	pBoardState->isPCIInitialised = NDTS_BFalse;

	free(pBoardState->ppUpdateSampleParametersHooks) ;
	pBoardState->ppUpdateSampleParametersHooks = 0 ;

	free(pBoardState->ppResetEncoderOutputHooks);
	pBoardState->numberOfResetEncoderOutputHooks = 0;

	free(pBoardState->ppGetEncoderOutputHooks);
	pBoardState->numberOfGetEncoderOutputHooks = 0;


	RQ_Unlock(cardIndex) ;

	RQ_DeleteCriticalSection(cardIndex) ;

	if (!RawScan_Uninitialise())
		return NDTS_BFalse ;

	// Multi card: the application / RS2A SDK shouldn't need to enumerate boards and call _Uninitiailise multiple times.
	// See comment in RQ_InitialiseDataCollection()
	_ASSERTE(cardIndex == 0);

	free(pBoardStates);
	pBoardStates = 0;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetIsInitialised(unsigned long cardIndex)
{
	if (cardIndex >= globalState.pciState.numberOfRapiDAQBoards) 
	{
		RQ_HandleRQError(RQ_ReturnBoardStatePointer_InvalidCardIndex) ;
		return NDTS_BFalse;
	}
	return pBoardStates[cardIndex].isInitialised;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetIsDiagnosticMode(unsigned long cardIndex, NDTS_Boolean flag, const char *pFilename)
{
	HANDLE fileHandle ;
	BOOL isWin32OK ;
	DWORD numBytesToWrite, numBytesWritten ;
	unsigned long systemVersionNumber,
			      samplingVersionNumber, samplingRevisionNumber,
				  peripheralVersionNumber, peripheralRevisionNumber ;
	char string[512] ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) 
		return NDTS_BFalse; 

	if (pBoardState->isInitialised)
		RQ_Lock(cardIndex) ;

	if (flag)
	{
		if (pFilename != 0)
			sprintf(pBoardState->diagnosticsFilename, "%s", pFilename) ;

		if (pBoardState->isInitialised)
		{
			RQ_GetSystemFirmwareVersion(cardIndex, &systemVersionNumber) ;
			RQ_GetSamplingFirmwareVersion(cardIndex, &samplingVersionNumber) ;
			RQ_GetSamplingFirmwareRevision(cardIndex, &samplingRevisionNumber) ;
			RQ_GetPeripheralFirmwareVersion(cardIndex, &peripheralVersionNumber) ;
			RQ_GetPeripheralFirmwareRevision(cardIndex, &peripheralRevisionNumber) ;
		}
		else
		{
			systemVersionNumber = 0;
			samplingVersionNumber = 0;
			samplingRevisionNumber = 0;
			peripheralVersionNumber = 0;
			peripheralRevisionNumber = 0;
		}

		sprintf(string, "%s\r\n\r\n", "Sonatest NDTS Data Acquisition Card Diagnostics") ;

		fileHandle = CreateFile(pBoardState->diagnosticsFilename, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0) ;
		if (fileHandle == INVALID_HANDLE_VALUE)
		{
			if (pBoardState->isInitialised)
				RQ_Unlock(cardIndex) ;

			RQ_HandleRQError(RQ_SetIsDiagnosticMode_GeneralError) ;
			return NDTS_BFalse ;
		}

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;

		if (pBoardState->isInitialised)
		{
			sprintf(string, "0x%04x:0x%04x:0x%04x:0x%04x:0x%04x\r\n\r\n", systemVersionNumber, samplingVersionNumber,
																          samplingRevisionNumber, peripheralVersionNumber, peripheralRevisionNumber) ;
			numBytesToWrite = strlen(string) ;

			isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
			if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
				goto Error ;
		}

		isWin32OK = CloseHandle(fileHandle) ;
		if (isWin32OK == FALSE)
		{
			if (pBoardState->isInitialised)
				RQ_Unlock(cardIndex) ;

			RQ_HandleRQError(RQ_SetIsDiagnosticMode_GeneralError) ;
			return NDTS_BFalse ;
		}
	}

	pBoardState->isDiagnosticsMode = flag ;

	if (pBoardState->isInitialised)
		RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;

Error:
	CloseHandle(fileHandle) ;
	if (pBoardState->isInitialised)
		RQ_Unlock(cardIndex) ;

	RQ_HandleRQError(RQ_SetIsDiagnosticMode_GeneralError) ;

	return NDTS_BFalse ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetSamplingFrequency(unsigned long cardIndex, unsigned long frequency)
{
	__int64 ftw ;
	NDTS_Boolean isOK ;
	int i ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) 
		return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if (frequency > RQ_MAXIMUM_SAMPLING_FREQUENCY || frequency < RQ_MINIMUM_SAMPLING_FREQUENCY)
	{
		RQ_HandleRQError(RQ_SetSamplingFrequency_InvalidFrequency) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	ftw = ((__int64) frequency * (__int64) 1 << 32) / (__int64) (4 * 66000000) ;

	for (i = 0 ; i < 4 ; i++)
	{
		isOK = RQ_SetDDSRegister(cardIndex, 0x000000ff & (unsigned long) (ftw >> (24 - (i << 3))), 4 + i) ;
		if (!isOK)
		{
			RQ_Unlock(cardIndex) ;
			return NDTS_BFalse ;
		}

		isOK = RQ_DDSWait(cardIndex) ;
		if (!isOK)
		{
			RQ_Unlock(cardIndex) ;
			return NDTS_BFalse ;
		}
	}

	for (i = 4 ; i < 6 ; i++)
	{
		isOK = RQ_SetDDSRegister(cardIndex, 0, 4 + i) ;
		if (!isOK)
		{
			RQ_Unlock(cardIndex) ;
			return NDTS_BFalse ;
		}

		isOK = RQ_DDSWait(cardIndex) ;
		if (!isOK)
		{
			RQ_Unlock(cardIndex) ;
			return NDTS_BFalse ;
		}
	}

	//isOK = RQ_SetSamplingRegister(cardIndex, RQ_NUMBER_OF_SCANS, 0) ;
	//if (!isOK)
	//	return NDTS_BFalse ;

	pBoardState->samplingFrequency = frequency ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetSamplingFrequency(unsigned long cardIndex, unsigned long *pFrequency)
{
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) 
		return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	*pFrequency = pBoardState->samplingFrequency ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}


RQ_API NDTS_Boolean CALL_CONV RQ_GetAScan(unsigned long cardIndex, short *pData, unsigned long aScanBufferBytes, unsigned long aScanIndex, unsigned long bScanIndex) 
{
	NDTS_Boolean isOK;
	unsigned long numA, numB;
	RQ_Lock(cardIndex);

	isOK = DC_WaitForBankSwap(cardIndex);
	if (!isOK) goto breakout;

	isOK = RQ_GetNumberOfAScansPerBScan(cardIndex, &numA);
	if (!isOK || aScanIndex >= numA)
		goto breakout;

	isOK = RQ_GetNumberOfBScansInSRAM(cardIndex, &numB) ;
	if (!isOK || bScanIndex >= numB)
		goto breakout;

	isOK = DC_GetAScanNoBankSwap(cardIndex, pData, aScanBufferBytes, aScanIndex, bScanIndex);
	if (!isOK) goto breakout;

breakout:
	DC_IndicateSampleDataDownloaded(cardIndex) ;
	RQ_Unlock(cardIndex) ;
	return isOK;
}

NDTS_Boolean CALL_CONV RQ_GetBScan(unsigned long cardIndex, short **ppData)
{
	NDTS_Boolean isOK, isAScanHeaderOK ;
	unsigned long numberOfAScanPerBScan, i, aScanHeader, numberOfBScansPerBank, numberOfBytesPerSample ;
	NDTS_SampleSize sampleSize ;
	NDTS_ScanStorage scanStorage ;

	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) 
		return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetScanStorageOptions(cardIndex, &scanStorage) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	if (scanStorage == NDTS_SSOneAScanMultipleCScan)
	{
		RQ_HandleRQError(RQ_GetBScan_NoBScansStored) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ; 
	}

	isOK = RQ_GetNumberOfBScansPerBank(cardIndex, &numberOfBScansPerBank) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	if (numberOfBScansPerBank != 1)
	{
		RQ_HandleRQError(RQ_GetBScan_InvalidNumberOfBScansPerBank) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ; 
	}

	if (!DC_WaitForBankSwap(cardIndex))
	{
		DC_IndicateSampleDataDownloaded(cardIndex) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_GetSampleStorageMode(cardIndex, &sampleSize) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	numberOfBytesPerSample = sampleSize == NDTS_SS12Bit ? 2 : 1 ;

	isOK = RQ_GetNumberOfAScansPerBScan(cardIndex, &numberOfAScanPerBScan) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	for (i = 0 ; i < numberOfAScanPerBScan ; i++)
	{
		isOK = RQ_GetSRAMLong(cardIndex, pBoardState->aScanOffsetThisStep[i], &aScanHeader) ;
		if (!isOK)
		{
			RQ_Unlock(cardIndex) ;
			return NDTS_BFalse ;
		}

		isAScanHeaderOK = RawScan_CheckAScanHeader(aScanHeader, i, 0) ;
		if (!isAScanHeaderOK)
		{
			RQ_HandleRQError(RQ_GetBScan_InternalDataFormatError) ;
			goto Error ;
		}

		// Bug 786 - DSP_124 has the A Scan data as sign and magnitude.  If this function is used in
		// non sequenced applications, the A Scans will need to be converted back.
		_ASSERTE(pBoardState->isSequence);

		isOK = NDTS_HAL_PerformDMATransfer(NDTS_SIDRapiDAQ, cardIndex, ppData[i], pBoardState->aScanOffsetThisStep[i], pBoardState->aScanSampleValuesThisStep[i] * numberOfBytesPerSample, NDTS_BTrue) ;
		if (!isOK)
		{
			RQ_Unlock(cardIndex) ;
			return NDTS_BFalse ;
		}
	}

	isOK = DC_IndicateSampleDataDownloaded(cardIndex) ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;

Error:
	DC_IndicateSampleDataDownloaded(cardIndex) ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BFalse ;
}



RQ_API NDTS_Boolean CALL_CONV RQ_LoadState(unsigned long cardIndex, const char *fileName, RQ_StoreValues values)
{
	int i ;
	NDTS_Boolean isSystemFPGALoaded, isSamplingFPGALoaded, isPeripheralFPGALoaded,
		        areGatesLoaded, isTCGCurveLoaded, isPingPongLoaded, isCurvedGateLoaded, 
		        isComplete ;
	const int stringLength = 512 ;
	char string[512], sectionHeaderString[512] ;
	int loadFromFileReturnCode ;
	HANDLE fileHandle ;
	BOOL isWin32OK ;
	DWORD numBytesRead ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	fileHandle = CreateFile(fileName, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0) ;

	if (fileHandle == INVALID_HANDLE_VALUE)
	{
		RQ_HandleRQError(RQ_LoadState_CannotOpenFile) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isSystemFPGALoaded = NDTS_BFalse ;
	isSamplingFPGALoaded = NDTS_BFalse ;
	isPeripheralFPGALoaded = NDTS_BFalse ;
	areGatesLoaded = NDTS_BFalse ;
	isTCGCurveLoaded = NDTS_BFalse ;
	isPingPongLoaded = NDTS_BFalse ;
	isCurvedGateLoaded = NDTS_BFalse ;

	isComplete = NDTS_BFalse ;

	do
	{
		isWin32OK = ReadFile(fileHandle, &string[0], 1, &numBytesRead, 0) ;
		if (!isWin32OK || numBytesRead != 1)
		{
			RQ_HandleRQError(RQ_LoadState_CannotReadFromFile) ;
			goto Error ;
		}
	}
	while (string[0] != '[') ;

	do
	{
		i = 0 ;

		do
		{
			isWin32OK = ReadFile(fileHandle, &string[i], 1, &numBytesRead, 0) ;
			if (!isWin32OK || numBytesRead != 1)
			{
				RQ_HandleRQError(RQ_LoadState_CannotReadFromFile) ;
				goto Error ;
			}

			i++ ;
		}
		while (string[i - 1] != 0x0a && i < stringLength) ;
		
		if (i == stringLength)
		{
			RQ_HandleRQError(RQ_LoadState_OversizedSectionHeaderStringLength) ;
			goto Error ;
		}

		string[i - 2] = 0 ;

		RQ_ExtractStringFromWhitespaceOrBrackets(string, sectionHeaderString) ;

		if (_stricmp(RQ_SystemFPGAString, sectionHeaderString) == 0 && 
			(values == RQ_SVAll || values == RQ_SVSystemParameters || values == RQ_SVAllParameters))
		{
			loadFromFileReturnCode = RQ_LoadFPGAFromFile(cardIndex, fileHandle) ;
			isSystemFPGALoaded = (loadFromFileReturnCode == 1 || loadFromFileReturnCode == 2) ? NDTS_BTrue : NDTS_BFalse ;
			isComplete = (loadFromFileReturnCode == 2) ? NDTS_BTrue : NDTS_BFalse ;
		}
		else if (_stricmp(RQ_SamplingFPGAString, sectionHeaderString) == 0 && 
			     (values == RQ_SVAll || values == RQ_SVSamplingParameters || values == RQ_SVAllParameters))
		{
			loadFromFileReturnCode = RQ_LoadFPGAFromFile(cardIndex, fileHandle) ;
			isSamplingFPGALoaded = (loadFromFileReturnCode == 1 || loadFromFileReturnCode == 2) ? NDTS_BTrue : NDTS_BFalse ;
			isComplete = (loadFromFileReturnCode == 2) ? NDTS_BTrue : NDTS_BFalse ;
		}
		else if (_stricmp(RQ_PeripheralFPGAString, sectionHeaderString) == 0 && 
			     (values == RQ_SVAll || values == RQ_SVPeripheralParameters || values == RQ_SVAllParameters))
		{
			loadFromFileReturnCode = RQ_LoadFPGAFromFile(cardIndex, fileHandle) ;
			isPeripheralFPGALoaded = (loadFromFileReturnCode == 1 || loadFromFileReturnCode == 2) ? NDTS_BTrue : NDTS_BFalse ;
			isComplete = (loadFromFileReturnCode == 2) ? NDTS_BTrue : NDTS_BFalse ;
		}
		else if (_stricmp(RQ_GateString, sectionHeaderString) == 0 && 
			     (values == RQ_SVAll || values == RQ_SVGates))
		{
			loadFromFileReturnCode = RQ_LoadGatesFromFile(cardIndex, fileHandle) ;
			areGatesLoaded = loadFromFileReturnCode == 1 || loadFromFileReturnCode == 2 ;
			isComplete = (loadFromFileReturnCode == 2) ? NDTS_BTrue : NDTS_BFalse;
		}
		else if (_stricmp(RQ_TCGString, sectionHeaderString) == 0 && 
			     (values == RQ_SVAll || values == RQ_SVTCG))
		{
			loadFromFileReturnCode = RQ_LoadTCGCurveFromFile(cardIndex, fileHandle) ;
			isTCGCurveLoaded = (loadFromFileReturnCode == 1 || loadFromFileReturnCode == 2) ? NDTS_BTrue : NDTS_BFalse ;
			isComplete = (loadFromFileReturnCode == 2) ? NDTS_BTrue : NDTS_BFalse ;
		}
		else if (_stricmp(RQ_PingPongString, sectionHeaderString) == 0 && 
			     (values == RQ_SVAll || values == RQ_SVPingPong))
		{
			loadFromFileReturnCode = RQ_LoadPingPongSequenceFromFile(cardIndex, fileHandle) ;
			isPingPongLoaded = (loadFromFileReturnCode == 1 || loadFromFileReturnCode == 2) ? NDTS_BTrue : NDTS_BFalse ;
			isComplete = (loadFromFileReturnCode == 2) ? NDTS_BTrue : NDTS_BFalse ;
		}
		else if (_stricmp(RQ_CurvedGateString, sectionHeaderString) == 0 && 
			     (values == RQ_SVAll || values == RQ_SVCurvedGate))
		{
			loadFromFileReturnCode = RQ_LoadCurvedGateDataFromFile(cardIndex, fileHandle) ;
			isCurvedGateLoaded = (loadFromFileReturnCode == 1 || loadFromFileReturnCode == 2) ? NDTS_BTrue : NDTS_BFalse ;
			isComplete = (loadFromFileReturnCode == 2) ? NDTS_BTrue : NDTS_BFalse ;
		}
	}
	while (!isComplete) ;

	isWin32OK = CloseHandle(fileHandle) ;
	if (isWin32OK == FALSE)
	{
		RQ_HandleRQError(RQ_LoadState_CannotCloseFile) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	if (values == RQ_SVSystemParameters && !isSystemFPGALoaded)
	{
		RQ_HandleRQError(RQ_LoadState_MissingSystemParameters) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	else if (values == RQ_SVSamplingParameters && !isSamplingFPGALoaded)
	{
		RQ_HandleRQError(RQ_LoadState_MissingSamplingParameters) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	else if (values == RQ_SVPeripheralParameters && !isPeripheralFPGALoaded)
	{
		RQ_HandleRQError(RQ_LoadState_MissingPeripheralParameters) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	else if (values == RQ_SVGates && !areGatesLoaded)
	{
		RQ_HandleRQError(RQ_LoadState_MissingGates) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	else if (values == RQ_SVTCG && !isTCGCurveLoaded)
	{
		RQ_HandleRQError(RQ_LoadState_MissingTCG) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	else if (values == RQ_SVPingPong && !isPingPongLoaded)
	{
		RQ_HandleRQError(RQ_LoadState_MissingPingPong) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	else if (values == RQ_SVCurvedGate && !isCurvedGateLoaded)
	{
		RQ_HandleRQError(RQ_LoadState_MissingCurvedGate) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	else
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BTrue ;
	}

Error :
	isWin32OK = CloseHandle(fileHandle) ;
	if (isWin32OK == FALSE)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SaveState(unsigned long cardIndex, const char *fileName, RQ_StoreValues values)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	char string[512] ;
	HANDLE fileHandle ;
	BOOL isWin32OK ;
	DWORD numBytesToWrite, numBytesWritten ;
	unsigned long i ;
	const RQ_Gate *pGate ;
	const unsigned short *pCurvedGateData ;
	unsigned long numberOfTCGValues ;
	const unsigned short *pTCGCurve ;
	const unsigned short *pPingPongSequence ;
	const unsigned short *reversePingPongSequence ;
	unsigned long peripheralVersion ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) 
return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if (_stricmp(".dab", &fileName[strlen(fileName) - 4]) != 0)
		sprintf(string, "%s.dab", fileName) ;
	else
		sprintf(string, "%s", fileName) ;
		
	fileHandle = CreateFile(string, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0) ;

	if (fileHandle == INVALID_HANDLE_VALUE)
	{
		RQ_HandleRQError(RQ_SaveState_CannotCreateFile) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}


	isOK = RQ_GetPeripheralFirmwareVersion(cardIndex, &peripheralVersion) ;
	if (!isOK)
		goto Error ;

	// System FPGA parameters

	if (values == RQ_SVAll || values == RQ_SVSystemParameters || values == RQ_SVAllParameters)
	{
		sprintf(string, "[%s]\r\n", RQ_SystemFPGAString) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;

		// RQ_SystemIOBank0String

		isOK = RQ_GetSystemIOBank0(cardIndex, &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = 0x%08x\r\n", RQ_SystemIOBank0String, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_SystemDDR0String

		isOK = RQ_GetSystemDDR0(cardIndex, &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %x\r\n", RQ_SystemDDR0String, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_SystemIOBank1String

		isOK = RQ_GetSystemIOBank1(cardIndex, &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = 0x%08x\r\n", RQ_SystemIOBank1String, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_SystemDDR1String

		isOK = RQ_GetSystemDDR1(cardIndex, &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %x\r\n", RQ_SystemDDR1String, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_SystemFirmwareRevisionString

		isOK = RQ_GetSystemFirmwareVersion(cardIndex, &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %x\r\n", RQ_SystemFirmwareRevisionString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;
	}



	// Sampling FPGA parameters

	if (values == RQ_SVAll || values == RQ_SVSamplingParameters || values == RQ_SVAllParameters)
	{
		sprintf(string, "\r\n[%s]\r\n", RQ_SamplingFPGAString) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_SampleFrequencyString

		isOK = RQ_GetSamplingFrequency(cardIndex, &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %d\r\n", RQ_SampleFrequencyString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_RectifierModeString

		isOK = RQ_GetRectifierMode(cardIndex, (RQ_Rectification *) &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %d\r\n", RQ_RectifierModeString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_StartDelayString

		isOK = RQ_GetStartDelay(cardIndex, &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %d\r\n", RQ_StartDelayString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_NumberOfSamplesString

		isOK = RQ_GetNumberOfSamples(cardIndex, &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %d\r\n", RQ_NumberOfSamplesString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_DropNumberOfSamplesString

		isOK = RQ_GetDropNumberOfSamples(cardIndex, &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %d\r\n", RQ_DropNumberOfSamplesString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_SampleStorageModeString

		isOK = RQ_GetSampleStorageMode(cardIndex, (NDTS_SampleSize *) &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %d\r\n", RQ_SampleStorageModeString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_TCGTriggerEventString

		isOK = RQ_GetTCGTriggerEvent(cardIndex, (RQ_TCGTriggerEvent *) &value) ;
		if (!isOK)
			goto Error ;

		if (value == 0xffffffff)
			sprintf(string, "%s = 0x%x\r\n", RQ_TCGTriggerEventString, value) ;
		else
			sprintf(string, "%s = %d\r\n", RQ_TCGTriggerEventString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_TCGEnableString

		isOK = RQ_GetTCGEnable(cardIndex, (NDTS_Boolean *) &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %d\r\n", RQ_TCGEnableString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_CScanBaseSRAMAddressString

		isOK = RQ_GetCScanBaseSRAMAddress(cardIndex, &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = 0x%08x\r\n", RQ_CScanBaseSRAMAddressString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;
			

		// NDTS_ScanStorageOptionsString

		isOK = RQ_GetScanStorageOptions(cardIndex, (NDTS_ScanStorage *) &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %d\r\n", NDTS_ScanStorageOptionsString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_NumberOfBScansPerBankString

		isOK = RQ_GetNumberOfBScansPerBank(cardIndex, &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %d\r\n", RQ_NumberOfBScansPerBankString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_NumberOfAScansPerBScanString

		isOK = RQ_GetNumberOfAScansPerBScan(cardIndex, &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %d\r\n", RQ_NumberOfAScansPerBScanString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;

		// RQ_SamplingFirmwareRevisionString

		isOK = RQ_GetSamplingFirmwareRevision(cardIndex, &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %x\r\n", RQ_SamplingFirmwareRevisionString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;

		// RQ_SamplingFirmwareVersionString

		isOK = RQ_GetSamplingFirmwareVersion(cardIndex, &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %x\r\n", RQ_SamplingFirmwareVersionString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;
	}


	// Peripheral FPGA parameters

	if (values == RQ_SVAll || values == RQ_SVPeripheralParameters || values == RQ_SVAllParameters)
	{
		sprintf(string, "\r\n[%s]\r\n", RQ_PeripheralFPGAString) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_InputCouplingString

		isOK = RQ_GetInputCoupling(cardIndex, (RQ_InputCoupling *) &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %d\r\n", RQ_InputCouplingString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_InputImpedanceString

		isOK = RQ_GetInputImpedance(cardIndex, (RQ_InputImpedance *) &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %d\r\n", RQ_InputImpedanceString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_AnalogueInputString

		isOK = RQ_GetAnalogueInput(cardIndex, (RQ_AnalogueInput *) &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %d\r\n", RQ_AnalogueInputString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_AnalogueInputRangeString

		isOK = RQ_GetAnalogueInputRange(cardIndex, (RQ_AnalogueInputRange *) &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %d\r\n", RQ_AnalogueInputRangeString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_AToDOutputPortFormatString

		isOK = RQ_GetAToDOutputPortFormat(cardIndex, &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %d\r\n", RQ_AToDOutputPortFormatString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_AToDOutputDataFormatString

		isOK = RQ_GetAToDOutputDataFormat(cardIndex, &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %d\r\n", RQ_AToDOutputDataFormatString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_AToDInputVoltageRangeString

		isOK = RQ_GetAToDInputVoltageRange(cardIndex, &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %d\r\n", RQ_AToDInputVoltageRangeString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_AToDVrefInputCharacteristicsString

		isOK = RQ_GetAToDVrefInputCharacteristics(cardIndex, &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %d\r\n", RQ_AToDVrefInputCharacteristicsString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_DDSKEYString

		isOK = RQ_GetDDSKEY(cardIndex, &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %d\r\n", RQ_DDSKEYString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_DDSFSKString

		isOK = RQ_GetDDSFSK(cardIndex, &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %d\r\n", RQ_DDSFSKString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_CalibrationVoltageString

		isOK = RQ_GetCalibrationVoltage(cardIndex, (RQ_CalibrationVoltage *) &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %d\r\n", RQ_CalibrationVoltageString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_AuxInputString

		isOK = RQ_GetAuxInput(cardIndex, (RQ_AuxInput *) &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %d\r\n", RQ_AuxInputString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_TriggerSelectString

		isOK = RQ_GetTriggerSelect(cardIndex, (RQ_Trigger *) &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %d\r\n", RQ_TriggerSelectString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_TransducerPulseWidthString

		isOK = RQ_GetTransducerPulseWidth(cardIndex, &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %d\r\n", RQ_TransducerPulseWidthString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_NumberOfPeriodsBetweenAScanTriggersString

		isOK = RQ_GetNumberOfPeriodsBetweenAScanTriggers(cardIndex, &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %d\r\n", RQ_NumberOfPeriodsBetweenAScanTriggersString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_NumberOfOversamplesString
		{
			unsigned long oldStep, step;
			sprintf(string, "%s = ", RQ_NumberOfOversamplesString);
			RQ_GetSequenceStep(cardIndex, &oldStep);
			for (step = 0; step < NDTS_MAXIMUM_NUMBER_OF_STEPS; step++)
			{
				unsigned long os;
				char thisOSval[10];
				RQ_SetSequenceStep(cardIndex, step);
				RQ_GetNumberOfOversamples(cardIndex, &os);
				sprintf(thisOSval, "%d,", os);
				strcat(string, thisOSval);
			}
			RQ_SetSequenceStep(cardIndex, oldStep);
		}

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_SensorArrayApertureSizeString

		isOK = RQ_GetSensorArrayApertureSize(cardIndex, (RQ_ApertureSize *) &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %d\r\n", RQ_SensorArrayApertureSizeString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;

		if (peripheralVersion == 1)
		{
			// RQ_SensorArrayDisableAperturePositionWrites

			isOK = RQ_GetSensorArrayDisableAperturePositionWrites(cardIndex, (NDTS_Boolean *) &value) ;
			if (!isOK)
				goto Error ;

			sprintf(string, "%s = %d\r\n", RQ_SensorArrayDisableAperturePositionWrites, value) ;

			numBytesToWrite = strlen(string) ;

			isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
			if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
				goto Error ;


			// RQ_SensorArrayDisableApertureDelayWrites

			isOK = RQ_GetSensorArrayDisableApertureDelayWrites(cardIndex, (NDTS_Boolean *) &value) ;
			if (!isOK)
				goto Error ;

			sprintf(string, "%s = %d\r\n", RQ_SensorArrayDisableApertureDelayWrites, value) ;

			numBytesToWrite = strlen(string) ;

			isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
			if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
				goto Error ;

			// RQ_SensorArrayEnableBScanModeString

			isOK = RQ_GetIsBScanModeEnabled(cardIndex, (NDTS_Boolean *) &value) ;
			if (!isOK)
				goto Error ;

			sprintf(string, "%s = %d\r\n", RQ_SensorArrayEnableBScanModeString, value) ;

			numBytesToWrite = strlen(string) ;

			isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
			if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
				goto Error ;
		}

		// RQ_NumberOfEncoderClicksPerBScanString

		isOK = RQ_GetNumberOfEncoderClicksPerBScan(cardIndex, &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %d\r\n", RQ_NumberOfEncoderClicksPerBScanString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_EncoderSelectString

		isOK = RQ_GetEncoderSelect(cardIndex, &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %d\r\n", RQ_EncoderSelectString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_PeripheralIOBank0String

		isOK = RQ_GetPeripheralIOBank0(cardIndex, &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = 0x%08x\r\n", RQ_PeripheralIOBank0String, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_PeripheralDDR0String

		isOK = RQ_GetPeripheralDDR0(cardIndex, &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %x\r\n", RQ_PeripheralDDR0String, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;

		
		// RQ_PeripheralFirmwareRevisionString

		isOK = RQ_GetPeripheralFirmwareRevision(cardIndex, &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %x\r\n", RQ_PeripheralFirmwareRevisionString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;


		// RQ_PeripheralFirmwareVersionString

		isOK = RQ_GetPeripheralFirmwareVersion(cardIndex, &value) ;
		if (!isOK)
			goto Error ;

		sprintf(string, "%s = %x\r\n", RQ_PeripheralFirmwareVersionString, value) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;
	}

	// Gates

	if (values == RQ_SVAll || values == RQ_SVGates)
	{
		sprintf(string, "\r\n[%s]\r\n", RQ_GateString) ;

		numBytesToWrite = strlen(string) ;

		isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
		if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
			goto Error ;

		for (i = 0 ; i < RQ_ReturnMaximumNumberOfGates(pBoardState->isSequence); i++)
		{
			isOK = RQ_GetGate(cardIndex, i, &pGate) ;
			if (!isOK)
				goto Error ;

			if (pGate->isEnabled)
			{
				sprintf(string, "\r\n[%s%d]\r\n", RQ_GateIdentifierPrefixString, i) ;

				numBytesToWrite = strlen(string) ;

				isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
				if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
					goto Error ;


				// RQ_GateStartString

				sprintf(string, "%s = %d\r\n", RQ_GateStartString, pGate->startCount) ;

				numBytesToWrite = strlen(string) ;

				isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
				if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
					goto Error ;


				// RQ_GateEndString

				sprintf(string, "%s = %d\r\n", RQ_GateEndString, pGate->stopCount) ;

				numBytesToWrite = strlen(string) ;

				isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
				if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
					goto Error ;
			

				// RQ_GateThresholdString

				sprintf(string, "%s = %d\r\n", RQ_GateThresholdString, pGate->threshold) ;

				numBytesToWrite = strlen(string) ;

				isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
				if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
					goto Error ;


				// RQ_GateTriggerString

				if (pGate->triggerGate == 0xffffffff)
					sprintf(string, "%s = 0x%x\r\n", RQ_GateTriggerString, pGate->triggerGate) ;
				else
					sprintf(string, "%s = %d\r\n", RQ_GateTriggerString, pGate->triggerGate) ;

				numBytesToWrite = strlen(string) ;

				isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
				if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
					goto Error ;


				// RQ_GateThresholdPolarityString

				sprintf(string, "%s = %d\r\n", RQ_GateThresholdPolarityString, pGate->thresholdPolarity) ;

				numBytesToWrite = strlen(string) ;

				isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
				if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
					goto Error ;


				// RQ_GateTriggerModeString

				sprintf(string, "%s = %d\r\n", RQ_GateTriggerModeString, pGate->triggerMode) ;

				numBytesToWrite = strlen(string) ;

				isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
				if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
					goto Error ;
				

				// RQ_GateDistanceMetricString

				sprintf(string, "%s = %d\r\n", RQ_GateDistanceMetricString, pGate->distanceMetric) ;

				numBytesToWrite = strlen(string) ;

				isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
				if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
					goto Error ;


				// RQ_GateEnableString

				sprintf(string, "%s = %d\r\n", RQ_GateEnableString, pGate->isEnabled) ;

				numBytesToWrite = strlen(string) ;

				isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
				if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
					goto Error ;


				// RQ_GateAmplitudePeakSelectString

				sprintf(string, "%s = %d\r\n", RQ_GateAmplitudePeakSelectString, pGate->amplitudePeakSelect) ;

				numBytesToWrite = strlen(string) ;

				isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
				if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
					goto Error ;

				// RQ_GateDistancePeakSelectString

				sprintf(string, "%s = %d\r\n", RQ_GateDistancePeakSelectString, pGate->distancePeakSelect) ;

				numBytesToWrite = strlen(string) ;

				isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
				if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
					goto Error ;
			}
		}
	}

	// TCG curve

	if (values == RQ_SVAll || values == RQ_SVTCG)
	{
		isOK = RQ_GetTCGValues(cardIndex, &pTCGCurve, &numberOfTCGValues) ;
		if (!isOK)
			goto Error ;

		if (pTCGCurve == 0 && values == RQ_SVTCG)
		{
			RQ_HandleRQError(RQ_SaveState_MissingTCG) ;
			RQ_Unlock(cardIndex) ;
			return NDTS_BFalse ;
		}
		else if (pTCGCurve != 0)
		{
			sprintf(string, "\r\n[%s]\r\n", RQ_TCGString) ;

			numBytesToWrite = strlen(string) ;

			isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
			if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
				goto Error ;

			/*
			sprintf(string, "%s = %d\r\n", RQ_NumberOfTCGValuesString, numberOfTCGValues) ;

			numBytesToWrite = strlen(string) ;

			isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
			if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
				goto Error ;
				*/

			for (i = 0 ; i < numberOfTCGValues ; i++)
			{
				sprintf(string, "%s%d = %d\r\n", RQ_TCGIndexPrefixString, i, pTCGCurve[i]) ;

				numBytesToWrite = strlen(string) ;

				isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
				if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
					goto Error ;
			}
		}
	}

	// PingPong sequence

	if (values == RQ_SVAll || values == RQ_SVPingPong)
	{
		isOK = RQ_GetPingPongSequence(cardIndex, &pPingPongSequence, &reversePingPongSequence) ;
		if (!isOK)
			goto Error ;

		if (pPingPongSequence == 0 && values == RQ_SVPingPong)
		{
			RQ_HandleRQError(RQ_SaveState_MissingPingPong) ;
			RQ_Unlock(cardIndex) ;
			return NDTS_BFalse ;
		}
		else if (pPingPongSequence != 0)
		{
			sprintf(string, "\r\n[%s]\r\n", RQ_PingPongString) ;

			numBytesToWrite = strlen(string) ;

			isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
			if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
				goto Error ;

			for (i = 0 ; i < RQ_PINGPONG_SEQUENCE_LENGTH ; i++)
			{
				sprintf(string, "%s%d = %d, %d\r\n", RQ_PingPongElementPrefixString, i, (unsigned long) pPingPongSequence[i], (unsigned long) reversePingPongSequence[i] ) ;

				numBytesToWrite = strlen(string) ;

				isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
				if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
					goto Error ;
			}
		}
	}

	// Curved gate data

	if (values == RQ_SVAll || values == RQ_SVCurvedGate)
	{
		isOK = RQ_GetCurvedGateData(cardIndex, &pCurvedGateData) ;
		if (!isOK)
			goto Error ;

		if (pCurvedGateData == 0 && values == RQ_SVPingPong)
		{
			RQ_HandleRQError(RQ_SaveState_MissingCurvedGate) ;
			RQ_Unlock(cardIndex) ;
			return NDTS_BFalse ;
		}
		else if (pCurvedGateData != 0)
		{
			sprintf(string, "\r\n[%s]\r\n", RQ_CurvedGateString) ;

			numBytesToWrite = strlen(string) ;

			isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
			if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
				goto Error ;

			for (i = 0 ; i < RQ_CURVED_GATE_NUMBER_OF_VALUES ; i++)
			{
				sprintf(string, "%s%d = %d\r\n", RQ_CurvedGateElementPrefixString, i, (unsigned long) pCurvedGateData[i]) ;

				numBytesToWrite = strlen(string) ;

				isWin32OK = WriteFile(fileHandle, (LPCVOID) string, numBytesToWrite, &numBytesWritten, 0) ;
				if (isWin32OK == FALSE || numBytesWritten != numBytesToWrite)
					goto Error ;
			}
		}
	}

	isWin32OK = CloseHandle(fileHandle) ;
	if (isWin32OK == FALSE)
	{
		RQ_HandleRQError(RQ_SaveState_CannotCloseFile) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;

Error :
	RQ_HandleRQError(RQ_SaveState_CannotWriteToFile) ;

	isWin32OK = CloseHandle(fileHandle) ;
	if (isWin32OK == FALSE)
	{
		RQ_HandleRQError(RQ_SaveState_CannotCloseFile) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isWin32OK = DeleteFile(fileName) ;
	if (isWin32OK == FALSE)
	{
		RQ_HandleRQError(RQ_SaveState_CannotDeleteInvalidFile) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	RQ_Unlock(cardIndex) ;

	return NDTS_BFalse ;
}


RQ_API NDTS_Boolean CALL_CONV RQ_SetValue(unsigned long cardIndex, const char *propertyName, unsigned long value)
{
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) 
		return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if (_stricmp(propertyName, RQ_SystemIOBank0String) == 0)
		isOK = RQ_SetSystemIOBank0(cardIndex, value) ;
	else if (_stricmp(propertyName, RQ_SystemDDR0String) == 0)
		isOK = RQ_SetSystemDDR0(cardIndex, value) ;
	else if (_stricmp(propertyName, RQ_SystemIOBank1String) == 0)
		isOK = RQ_SetSystemIOBank1(cardIndex, value) ;
	else if (_stricmp(propertyName, RQ_SystemDDR1String) == 0)
		isOK = RQ_SetSystemDDR1(cardIndex, value) ;
	else if (_stricmp(propertyName, RQ_SampleFrequencyString) == 0)
		isOK = RQ_SetSamplingFrequency(cardIndex, value) ;
	else if (_stricmp(propertyName, RQ_RectifierModeString) == 0)
		isOK = RQ_SetRectifierMode(cardIndex, (RQ_Rectification) value) ;
	else if (_stricmp(propertyName, RQ_StartDelayString) == 0)
		isOK = RQ_SetStartDelay(cardIndex, value) ;
	else if (_stricmp(propertyName, RQ_NumberOfSamplesString) == 0)
		isOK = RQ_SetNumberOfSamples(cardIndex, value) ;
	else if (_stricmp(propertyName, RQ_DropNumberOfSamplesString) == 0)
		isOK = RQ_SetDropNumberOfSamples(cardIndex, value) ;
	else if (_stricmp(propertyName, RQ_SampleStorageModeString) == 0)
		isOK = RQ_SetSampleStorageMode(cardIndex, (NDTS_SampleSize) value) ;
	else if (_stricmp(propertyName, RQ_TCGTriggerEventString) == 0)
		isOK = RQ_SetTCGTriggerEvent(cardIndex, (RQ_TCGTriggerEvent) value) ;
	else if (_stricmp(propertyName, RQ_TCGEnableString) == 0)
		isOK = RQ_SetTCGEnable(cardIndex, (NDTS_Boolean) value) ;
	else if (_stricmp(propertyName, RQ_CScanBaseSRAMAddressString) == 0)
		isOK = RQ_SetCScanBaseSRAMAddress(cardIndex, value) ;
	else if (_stricmp(propertyName, NDTS_ScanStorageOptionsString) == 0)
		isOK = RQ_SetScanStorageOptions(cardIndex, (NDTS_ScanStorage) value) ;
	else if (_stricmp(propertyName, RQ_NumberOfBScansPerBankString) == 0)
		isOK = RQ_SetNumberOfBScansPerBankInternal(cardIndex, value) ;
	else if (_stricmp(propertyName, RQ_NumberOfAScansPerBScanString) == 0)
		isOK = RQ_SetNumberOfAScansPerBScan(cardIndex, value) ;
	else if (_stricmp(propertyName, RQ_InputCouplingString) == 0)
		isOK = RQ_SetInputCoupling(cardIndex, (RQ_InputCoupling) value) ;
	else if (_stricmp(propertyName, RQ_InputImpedanceString) == 0)
		isOK = RQ_SetInputImpedance(cardIndex, (RQ_InputImpedance) value) ;
	else if (_stricmp(propertyName, RQ_AnalogueInputString) == 0)
		isOK = RQ_SetAnalogueInput(cardIndex, (RQ_AnalogueInput) value) ;
	else if (_stricmp(propertyName, RQ_AnalogueInputRangeString) == 0)
		isOK = RQ_SetAnalogueInputRange(cardIndex, (RQ_AnalogueInputRange) value) ;
	else if (_stricmp(propertyName, RQ_AToDOutputPortFormatString) == 0)
		isOK = RQ_SetAToDOutputPortFormat(cardIndex, value) ;
	else if (_stricmp(propertyName, RQ_AToDOutputDataFormatString) == 0)
		isOK = RQ_SetAToDOutputDataFormat(cardIndex, value) ;
	else if (_stricmp(propertyName, RQ_AToDInputVoltageRangeString) == 0)
		isOK = RQ_SetAToDInputVoltageRange(cardIndex, value) ;
	else if (_stricmp(propertyName, RQ_AToDVrefInputCharacteristicsString) == 0)
		isOK = RQ_SetAToDVrefInputCharacteristics(cardIndex, value) ;
	else if (_stricmp(propertyName, RQ_DDSKEYString) == 0)
		isOK = RQ_SetDDSKEY(cardIndex, value) ;
	else if (_stricmp(propertyName, RQ_DDSFSKString) == 0)
		isOK = RQ_SetDDSFSK(cardIndex, value) ;
	else if (_stricmp(propertyName, RQ_CalibrationVoltageString) == 0)
		isOK = RQ_SetCalibrationVoltage(cardIndex, (RQ_CalibrationVoltage) value) ;
	else if (_stricmp(propertyName, RQ_AuxInputString) == 0)
		isOK = RQ_SetAuxInput(cardIndex, (RQ_AuxInput) value) ;
	else if (_stricmp(propertyName, RQ_TriggerSelectString) == 0)
		isOK = RQ_SetTriggerSelect(cardIndex, (RQ_Trigger) value) ;
	else if (_stricmp(propertyName, RQ_TransducerPulseWidthString) == 0)
		isOK = RQ_SetTransducerPulseWidth(cardIndex, value) ;
	else if (_stricmp(propertyName, RQ_NumberOfPeriodsBetweenAScanTriggersString) == 0)
		isOK = RQ_SetNumberOfPeriodsBetweenAScanTriggers(cardIndex, value) ;
	else if (_stricmp(propertyName, RQ_NumberOfOversamplesString) == 0)
		isOK = RQ_SetNumberOfOversamples(cardIndex, value) ;
	else if (_stricmp(propertyName, RQ_SensorArrayNumberOfElementsString) == 0)
		isOK = RQ_SetSensorArrayNumberOfElements(cardIndex, value) ;
	else if (_stricmp(propertyName, RQ_SensorArrayApertureSizeString) == 0)
		isOK = RQ_SetSensorArrayApertureSize(cardIndex, (RQ_ApertureSize) value) ;
	else if (_stricmp(propertyName, RQ_NumberOfEncoderClicksPerBScanString) == 0)
		isOK = RQ_SetNumberOfEncoderClicksPerBScan(cardIndex, value) ;
	else if (_stricmp(propertyName, RQ_SensorArrayDisableAperturePositionWrites) == 0)
		isOK = RQ_SetSensorArrayDisableAperturePositionWrites(cardIndex, value) ;
	else if (_stricmp(propertyName, RQ_SensorArrayDisableApertureDelayWrites) == 0)
		isOK = RQ_SetSensorArrayDisableApertureDelayWrites(cardIndex, value) ;	
	else if (_stricmp(propertyName, RQ_EncoderSelectString) == 0)
		isOK = RQ_SetEncoderSelect(cardIndex, value) ;
	else
	{
		RQ_HandleRQError(RQ_SetValue_InvalidPropertyName) ;
		RQ_Unlock(cardIndex);
		return NDTS_BFalse ;
	}

	RQ_Unlock(cardIndex) ;

	return isOK ;
}


// System FPGA registers

RQ_API NDTS_Boolean CALL_CONV RQ_SetSystemIOBank0(unsigned long cardIndex, unsigned long iOBits)
{
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) 
		return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_SetSystemRegister(cardIndex, RQ_SYSTEM_IO_BANK_0, iOBits) ;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetSystemIOBank0(unsigned long cardIndex, unsigned long *iOBits)
{
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) 
		return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;
	
	isOK = RQ_GetSystemRegister(cardIndex, RQ_SYSTEM_IO_BANK_0, iOBits) ;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetSystemDDR0(unsigned long cardIndex, unsigned long directionBits)
{
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) 
		return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;
	
	isOK = RQ_SetSystemRegister(cardIndex, RQ_SYSTEM_DDR_0, directionBits) ;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetSystemDDR0(unsigned long cardIndex, unsigned long *pDirectionBits)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) 
		return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;
	
	isOK = RQ_GetSystemRegister(cardIndex, RQ_SYSTEM_DDR_0, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	*pDirectionBits = value ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetSystemIOBank1(unsigned long cardIndex, unsigned long iOBits)
{
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) 
		return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;
	
	isOK = RQ_SetSystemRegister(cardIndex, RQ_SYSTEM_IO_BANK_1, iOBits) ;
	
	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetSystemIOBank1(unsigned long cardIndex, unsigned long *iOBits)
{
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) 
		return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;
	
	isOK = RQ_GetSystemRegister(cardIndex, RQ_SYSTEM_IO_BANK_1, iOBits) ;
	
	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetSystemDDR1(unsigned long cardIndex, unsigned long directionBits)
{
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) 
		return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_SetSystemRegister(cardIndex, RQ_SYSTEM_DDR_1, directionBits) ;
	
	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetSystemDDR1(unsigned long cardIndex, unsigned long *direction)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) 
		return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetSystemRegister(cardIndex, RQ_SYSTEM_DDR_1, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	*direction = value ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetSamplingSystemIRQFlag(unsigned long cardIndex, unsigned long samplingSystemIndex, NDTS_Boolean *pFlag)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if (samplingSystemIndex >= RQ_NUMBER_OF_SAMPLING_SYSTEMS)
	{
		RQ_HandleRQError(RQ_GetSamplingSystemIRQFlag_InvalidSamplingSystemIndex) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_GetSystemRegister(cardIndex, RQ_SYSTEM_STATUS_REGISTER, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	*pFlag = (value & 0x00000010) != 0 ? NDTS_BTrue : NDTS_BFalse ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}


RQ_API NDTS_Boolean CALL_CONV RQ_GetSystemFirmwareVersion(unsigned long cardIndex, unsigned long *versionNumber)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	isOK = RQ_GetSystemRegister(cardIndex, RQ_SYSTEM_FPGA_VERSION_NUMBER, &value) ;
	if (!isOK)
		return NDTS_BFalse ;
	
	*versionNumber = value & 0x0000ffff ;

	return NDTS_BTrue ;
}


// Sampling FPGA registers

RQ_API NDTS_Boolean CALL_CONV RQ_SetCurvedGateData(unsigned long cardIndex, const unsigned short *gateData)
{
	int i ;
	unsigned long version ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetSamplingFirmwareVersion(cardIndex, &version) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	if (version == 0)
	{
		RQ_HandleRQError(RQ_SetCurvedGateData_InvalidFirmwareVersion) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	if (pBoardState->pCurvedGateData == 0)
		pBoardState->pCurvedGateData = malloc(sizeof(unsigned short) * RQ_CURVED_GATE_NUMBER_OF_VALUES) ;

	if (pBoardState->pCurvedGateData == 0)
	{
		RQ_HandleRQError(RQ_SetCurvedGateData_OutOfMemory) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	i = 0 ; 
	
	do
	{
		isOK = gateData[i] < 2048 ? NDTS_BTrue : NDTS_BFalse ;

		i++ ;
	}
	while (i < RQ_CURVED_GATE_NUMBER_OF_VALUES && isOK) ;

	if (!isOK)
	{
		RQ_HandleRQError(RQ_SetCurvedGateData_InvalidThresholdValue) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	for (i = 0 ; i < RQ_CURVED_GATE_NUMBER_OF_VALUES ; i++)
	{
		isOK = RQ_SetSamplingRegister(cardIndex, RQ_CURVED_GATE_DATA, (unsigned long) gateData[i]) ;
		if (!isOK)
		{
			RQ_Unlock(cardIndex) ;
			return NDTS_BFalse ;
		}

		pBoardState->pCurvedGateData[i] = gateData[i] ;
	}

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetCurvedGateData(unsigned long cardIndex, const unsigned short **gateData)
{
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	*gateData = pBoardState->pCurvedGateData ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_ReadRawADCData(unsigned long cardIndex, short *pValue)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_SetSamplingRegister(cardIndex, RQ_RAW_ADC_DATA, 0xffffffff) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_GetSamplingRegister(cardIndex, RQ_RAW_ADC_DATA, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	*pValue = (value & 0x00000800) == 0 ? (short) value : (short) ((value & 0xfffff7ff) - (RQ_RAW_ADC_VALUE_RANGE >> 1)) ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetNumberOfBScansInSRAM(unsigned long cardIndex, unsigned long *numberOfScans)
{
	NDTS_Boolean areSamplesAvailable ;
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = DC_GetIsSampleDataAvailable(cardIndex, &areSamplesAvailable) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	if (areSamplesAvailable == NDTS_BFalse)
	{
		RQ_HandleRQError(RQ_GetNumberOfBScansInSRAM_NoDataAvailable) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_GetSamplingRegister(cardIndex, RQ_BSCANS_IN_SRAM, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	
	*numberOfScans = (value & 0x00007fff) + 1 ;

	RQ_Unlock(cardIndex) ;
	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetRectifierMode(unsigned long cardIndex, RQ_Rectification mode)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if (mode != RQ_RBipolar && mode != RQ_RFullwave && 
		mode != RQ_RPosHalfwave && mode != RQ_RNegHalfwave)
	{
		RQ_HandleRQError(RQ_SetRectifierMode_InvalidMode) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_GetSamplingRegister(cardIndex, RQ_RECTIFIER_MODE, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	
	value &= 0xfffffffc ;
	value |= mode ;

	isOK = RQ_SetSamplingRegister(cardIndex, RQ_RECTIFIER_MODE, value) ;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetRectifierMode(unsigned long cardIndex, RQ_Rectification *mode)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetSamplingRegister(cardIndex, RQ_RECTIFIER_MODE, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	
	value &= 0x00000003 ;
	*mode = (RQ_Rectification) value ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

// When oversampling, sampleCountParam is at the oversampled rate, NOT sample frequency clock ticks.
// This is for consistency with RQ_SetNumberOfSamples and also the gate start / stop values.
// For example at 100Mhz clock, 4x oversampling, sampleCountParam = 400 means wait for four sets of 100 samples
// so the delay will be of 1uS.  The delay is truncated to a number of clock frequency ticks.

RQ_API NDTS_Boolean CALL_CONV RQ_SetStartDelay(unsigned long cardIndex, unsigned long delayInSamples)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	unsigned long oversamples;
	unsigned long delayInTicks;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetNumberOfOversamples(cardIndex, &oversamples);
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	delayInTicks = delayInSamples / oversamples;

	if (delayInTicks > RQ_SRAM_MAXIMUM_START_DELAY)
	{
		RQ_HandleRQError(RQ_SetStartDelay_InvalidDelay) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	value = pBoardState->rqTriggerControlShadow;

	// Register bits 15:0 delay bits 15:0.  Register bits 24:20 delay bits 20:16
	value &= 0xfe0f0000;
	value |= (delayInTicks & 0x0000ffff) | ((delayInTicks & 0x001f0000) << 4);

	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_TRIGGER_CONTROL, value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	pBoardState->rqTriggerControlShadow = value;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetStartDelay(unsigned long cardIndex, unsigned long *startDelay)
{
	unsigned long value ;
	//NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	// Trigger delay bits 0:15 in reg 0:15 and bits 16:20 in reg 20:24
	value = pBoardState->rqTriggerControlShadow &  0x0000ffff;
	value |= (pBoardState->rqTriggerControlShadow >> 4) & 0x001f0000;
	*startDelay = value ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

// When oversampling, numberOfSamples is the number of samples that will be stored in memory, NOT the number of clock ticks.
// For example at 100Mhz clock, 4x oversampling, numberOfSamples = 400 means store four sets of 100 samples
// covering a range of 1uS in time at a resolution of 0.25uS.

// 
// When dropping samples, the application should call this function with the number of samples to collect
// NOT the number of sample periods over which to collect data.
// E.g. if DropSamples is called with 3, the number of samples is divided by 4
// Call this function with 250 and the number of A Scan sample points collected will be 250 but they will be collected over a range of 1000 clock ticks


RQ_API NDTS_Boolean CALL_CONV RQ_SetNumberOfSamples(unsigned long cardIndex, unsigned long numberOfSamplesParam)
{
	unsigned long value, i, numberOfSamplesPerOversample ;
	NDTS_Boolean isOK ;
	NDTS_SampleSize sampleSize ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	int oversampleStepIndex;
	unsigned long numberOfSamples;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	oversampleStepIndex = (pBoardState->isSequence) ? pBoardState->currentSequenceStep : 0;
	numberOfSamplesPerOversample = numberOfSamplesParam / (pBoardState->oversampleCountThisStep[oversampleStepIndex]);

	isOK = RQ_GetSampleStorageMode(cardIndex, &sampleSize) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	// Current FPGA rounds to even number of samples

	if (sampleSize == NDTS_SS12Bit)
	{
		if ((numberOfSamplesPerOversample & 1) != 0)
			numberOfSamplesPerOversample++ ;
	}
	else
	{
		if ((numberOfSamplesPerOversample & 3) != 0)
			numberOfSamplesPerOversample += 3 ;
	}

	// numberOfSamplesParam may be rounded down by a few samples to numberOfSamples
	numberOfSamples = numberOfSamplesPerOversample * (pBoardState->oversampleCountThisStep[oversampleStepIndex]);

	// Always block range to  NDTS_MAXIMUM_NUMBER_OF_SAMPLES, although it would be possible to go higher when oversampling, this may
	// cause some buffers in the thread / hlprx to overflow.
	// Four is added to numberOfSamplesParam to make sure that the rounding below does not cause overflow
	if (numberOfSamplesParam + 4 > NDTS_MAXIMUM_NUMBER_OF_SAMPLES || numberOfSamplesPerOversample == 0)
	{
		RQ_HandleRQError(RQ_SetNumberOfSamples_InvalidNumberOfSamples) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_CheckSRAM(cardIndex, (NDTS_ScanStorage) -1, numberOfSamples, (NDTS_SampleSize) -1,
		                0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	if (pBoardState->isSequence)
	{
		pBoardState->aScanSamplePeriodsThisStep[pBoardState->currentSequenceStep] = numberOfSamples *  pBoardState->samplesDivider;
		pBoardState->aScanSampleValuesThisStep[pBoardState->currentSequenceStep] = numberOfSamples;
	}
	else
	{ 
		// Non sequenced - all the Ascans have the same range - fill the entire array in case the number of a per b increases
		for (i=0; i < NDTS_MAXIMUM_NUMBER_OF_ELEMENTS; i++)
		{
			pBoardState->aScanSamplePeriodsThisStep[i] = numberOfSamples * pBoardState->samplesDivider;
			pBoardState->aScanSampleValuesThisStep[i] = numberOfSamples;
		}
	}

	pBoardState->aScanOffsetThisStep[0] = 4;

	RQ_UpdateAllAScanOffsetThisStep(cardIndex, pBoardState);

	isOK = RQ_GetSampleStorageMode(cardIndex, &sampleSize) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_GetSamplingRegister(cardIndex, RQ_SRAM_CONTROL_SAMPLE_CONTROL, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	value &= ~(NDTS_MAXIMUM_NUMBER_OF_SAMPLES - 1) ;
	// The value written to the register is the number of four byte words to store for each A Scan.  
	// This is described in the A-Scan data area organisation.  The SRAM Control - Sample control description does not make it so clear.
	value |= (numberOfSamplesPerOversample >> (sampleSize == NDTS_SS12Bit ? 1 : 2)) + 1 ;

	isOK = RQ_SetSamplingRegister(cardIndex, RQ_SRAM_CONTROL_SAMPLE_CONTROL, value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	RQ_UpdateSampleParameters(cardIndex);

	RQ_Unlock(cardIndex) ;

	return isOK ;
}


void RQ_UpdateAllAScanOffsetThisStep(unsigned long cardIndex, RQ_State *pBoardState)
{
	unsigned int i;
	unsigned long bytesPerSample;
	unsigned long crcBytes = ((pBoardState->isCRCPresent) ? 4 : 0) ;

	NDTS_SampleSize sampleSize;
    RQ_GetSampleStorageMode(cardIndex, &sampleSize) ;
	bytesPerSample = sampleSize == NDTS_SS12Bit ? 2 : 1 ;

	for (i = 1; i < (unsigned int)((pBoardState->isSequence) ? NDTS_MAXIMUM_NUMBER_OF_STEPS : NDTS_MAXIMUM_NUMBER_OF_ELEMENTS); i++)
	{
		// pBoardState->aScanOffsetThisStep[i] = pBoardState->aScanOffsetThisStep[i-1] + 4 + bytesPerSample * pBoardState->aScanSamplesThisStep[i-1] + crcBytes ;
		// FROG need to take account of oversamples
		// Mark - shouldn't there be a "+ 4" in the expression below?
		pBoardState->aScanOffsetThisStep[i] = pBoardState->aScanOffsetThisStep[i-1] + // last ascan offset
			bytesPerSample * pBoardState->aScanSampleValuesThisStep[i-1] + // size of last ascan
											  4 * pBoardState->oversampleCountThisStep[pBoardState->isSequence ? i - 1 : 0] + // extra headers for oversamples
											  crcBytes ;
	}
}


RQ_API NDTS_Boolean CALL_CONV RQ_GetNumberOfSamples(unsigned long cardIndex, unsigned long *numberOfSamples)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	NDTS_SampleSize sampleSize ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetSampleStorageMode(cardIndex, &sampleSize) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_GetSamplingRegister(cardIndex, RQ_SRAM_CONTROL_SAMPLE_CONTROL, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	
	value &= NDTS_MAXIMUM_NUMBER_OF_SAMPLES - 1 ;
	*numberOfSamples = (value - 1) << (sampleSize == NDTS_SS12Bit ? 1 : 2) ;

	if (pBoardState->isSequence)
	{
		unsigned long currentStep ;
		RQ_GetSequenceStep(cardIndex, &currentStep);	
		*numberOfSamples *= (pBoardState->oversampleCountThisStep[currentStep]);
	}
	else
	{
		*numberOfSamples *= (pBoardState->oversampleCountThisStep[0]);
	}

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetDropNumberOfSamples(unsigned long cardIndex, unsigned long numberOfSamplesToDrop)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	unsigned long i;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	
	isOK = RQ_CheckSRAM(cardIndex, (NDTS_ScanStorage) -1, 0xffffffff, (NDTS_SampleSize) -1,
		                 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	if (numberOfSamplesToDrop > RQ_MAXIMUM_NUMBER_OF_SAMPLES_TO_DROP)
	{
		RQ_HandleRQError(RQ_SetDropNumberOfSamples_InvalidNumberOfSamples) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	pBoardState->samplesDivider = numberOfSamplesToDrop + 1;
	
	isOK = RQ_GetSamplingRegister(cardIndex, RQ_SRAM_CONTROL_SAMPLE_CONTROL, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	
	value &= 0xfff0ffff ;
	value |= numberOfSamplesToDrop << 16 ;

	isOK = RQ_SetSamplingRegister(cardIndex, RQ_SRAM_CONTROL_SAMPLE_CONTROL, value) ;


	for (i=0; i < NDTS_MAXIMUM_NUMBER_OF_ELEMENTS; i++)
	{
		pBoardState->aScanSamplePeriodsThisStep[i]  = pBoardState->aScanSampleValuesThisStep[i] * pBoardState->samplesDivider;
	}

	RQ_UpdateAllAScanOffsetThisStep(cardIndex, pBoardState);

/*

	// Update the range to reflect the new divider
	if (pBoardState->isSequence) 
		RQ_GetSequenceStep(cardIndex, &oldStep);

	for (i=0; i < (pBoardState->isSequence) ? NDTS_MAXIMUM_NUMBER_OF_STEPS : 1; i++)
	{
		if (pBoardState->isSequence) 
		{
				RQ_SetSequenceStep(cardIndex, i);
		}



		}


	isOK = RQ_GetSampleStorageMode(cardIndex, &sampleSize) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_GetSamplingRegister(cardIndex, RQ_SRAM_CONTROL_SAMPLE_CONTROL, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	value &= ~(NDTS_MAXIMUM_NUMBER_OF_SAMPLES - 1) ;
	// The value written to the register is the number of four byte words to store for each A Scan.  
	// This is described in the A-Scan data area organisation.  The SRAM Control - Sample control description does not make it so clear.
	value |= (numberOfSamplesPerOversample >> (sampleSize == NDTS_SS12Bit ? 1 : 2)) + 1 ;

	isOK = RQ_SetSamplingRegister(cardIndex, RQ_SRAM_CONTROL_SAMPLE_CONTROL, value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}


	if (pBoardState->isSequence) 
		RQ_SetSequenceStep(cardIndex, oldStep);

*/
	RQ_UpdateSampleParameters(cardIndex);

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetDropNumberOfSamples(unsigned long cardIndex, unsigned long *numberOfSamples)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetSamplingRegister(cardIndex, RQ_SRAM_CONTROL_SAMPLE_CONTROL, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	
	value &= 0x000f0000  ;
	*numberOfSamples = value >> 16 ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetSampleStorageMode(unsigned long cardIndex, NDTS_SampleSize storageMode)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if (storageMode != NDTS_SS12Bit && storageMode != NDTS_SS8Bit)
	{
		RQ_HandleRQError(RQ_SetSampleStorageMode_InvalidStorageMode) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_CheckSRAM(cardIndex, (NDTS_ScanStorage) -1, 0xffffffff, storageMode,
		                0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_GetSamplingRegister(cardIndex, RQ_SRAM_CONTROL_SAMPLE_CONTROL, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	value &= 0xffefffff ;
	value |= storageMode << 20 ;

	isOK = RQ_SetSamplingRegister(cardIndex, RQ_SRAM_CONTROL_SAMPLE_CONTROL, value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	RQ_UpdateSampleParameters(cardIndex) ;
	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetSampleStorageMode(unsigned long cardIndex, NDTS_SampleSize *storageMode)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetSamplingRegister(cardIndex, RQ_SRAM_CONTROL_SAMPLE_CONTROL, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	
	value &= 0x00100000 ;
	*storageMode = (NDTS_SampleSize) (value >> 20) ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetForceAScanTrigger(unsigned long cardIndex)
{
	unsigned long value ;
	RQ_Trigger triggerSelect ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	// Trigger select not used on sequence compatible FPGA and always returns 0 (external)
	if (!pBoardState->isSequence)
	{
		isOK = RQ_GetTriggerSelect(cardIndex, &triggerSelect) ;
		if (!isOK)
		{
			RQ_Unlock(cardIndex) ;
			return NDTS_BFalse ;
		}

		if (triggerSelect == RQ_TExternal)
		{
			RQ_HandleRQError(RQ_SetForceAScanTrigger_InvalidTriggerSource) ;
			RQ_Unlock(cardIndex) ;
			return NDTS_BFalse ;
		}
	}

	isOK = RQ_GetSamplingRegister(cardIndex, RQ_SRAM_CONTROL_SAMPLE_CONTROL, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	value &= 0x7fffffff ;
	value |= 1 << 31 ;

	isOK = RQ_SetSamplingRegister(cardIndex, RQ_SRAM_CONTROL_SAMPLE_CONTROL, value) ;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetTCGTriggerEvent(unsigned long cardIndex, RQ_TCGTriggerEvent event)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if (event != RQ_TCGTEInterfaceGate && event != RQ_TCGTEAbsolute)
	{
		RQ_HandleRQError(RQ_SetTCGTriggerGate_InvalidGateIndex) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_GetSamplingRegister(cardIndex, RQ_TCG_CONFIGURE, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	
	value &= 0xfffffffe ;
	value |= event != RQ_TCGTEAbsolute ? 0x00000000 : 0x00000001 ;

	isOK = RQ_SetSamplingRegister(cardIndex, RQ_TCG_CONFIGURE, value) ;

	RQ_UpdateSampleParameters(cardIndex);

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetTCGTriggerEvent(unsigned long cardIndex, RQ_TCGTriggerEvent *event)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetSamplingRegister(cardIndex, RQ_TCG_CONFIGURE, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	
	value &= 0x00000001 ;
	*event = (RQ_TCGTriggerEvent) value ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetTCGEnable(unsigned long cardIndex, NDTS_Boolean isEnabled)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if (isEnabled != NDTS_BTrue && isEnabled != NDTS_BFalse)
	{
		RQ_HandleRQError(RQ_SetTCGEnable_InvalidFlag) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	if (isEnabled && pBoardState->pTCGCurve == 0)
	{
		RQ_HandleRQError(RQ_SetTCGEnable_NoTCGCurve) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_GetSamplingRegister(cardIndex, RQ_TCG_CONFIGURE, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	
	value &= 0xfffffffd ;
	value |= (unsigned long) isEnabled << 1 ;

	isOK = RQ_SetSamplingRegister(cardIndex, RQ_TCG_CONFIGURE, value) ;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetTCGEnable(unsigned long cardIndex, NDTS_Boolean *isEnabled)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetSamplingRegister(cardIndex, RQ_TCG_CONFIGURE, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	
	value &= 0x00000002 ;
	*isEnabled = (NDTS_Boolean) value >> 1 ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}
/*
RQ_API NDTS_Boolean CALL_CONV RQ_GetIsSampleDataStoreInProgress(unsigned long cardIndex, NDTS_Boolean *isInProgress)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;

	if (!pBoardState) 
		return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetDataSamplingStatus(cardIndex, &value) ;
	if (isOK)
		*isInProgress = (value & 0x00000002) ? NDTS_BTrue : NDTS_BFalse ;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetHasNewTriggerOccured(unsigned long cardIndex, NDTS_Boolean *hasOccured)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

This is not safe as it will wipe out the clear on read bits.  Sort out by using RQ_GetDataSamplingStatus if this code is commented back in.
isOK = RQ_GetSamplingRegister(cardIndex, RQ_SAMPLE_DATA_STATUS, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	
	*hasOccured = (value & 0x00000004) != 0x00000000 ? NDTS_BTrue : NDTS_BFalse ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetHasNewTriggerOccuredBeforeProcessComplete(unsigned long cardIndex, NDTS_Boolean *hasOccured)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

This is not safe as it will wipe out the clear on read bits.  Sort out by using RQ_GetDataSamplingStatus if this code is commented back in.
	isOK = RQ_GetSamplingRegister(cardIndex, RQ_SAMPLE_DATA_STATUS, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	
	*hasOccured = (value & 0x00000008) != 0x00000000 ? NDTS_BTrue : NDTS_BFalse ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetIsDataFullError(unsigned long cardIndex, NDTS_Boolean *isFull)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

This is not safe as it will wipe out the clear on read bits.  Sort out by using RQ_GetDataSamplingStatus if this code is commented back in.
	isOK = RQ_GetSamplingRegister(cardIndex, RQ_SAMPLE_DATA_STATUS, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	
	*isFull = (value & 0x00000010) != 0x00000000 ? NDTS_BTrue : NDTS_BFalse ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}
*/
RQ_API NDTS_Boolean CALL_CONV RQ_GetHasSampleClockStabilised(unsigned long cardIndex, NDTS_Boolean *hasStabilised)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetSamplingRegister(cardIndex, RQ_SAMPLE_DATA_STATUS, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	
	*hasStabilised = (value & 0x00000100) ? NDTS_BFalse : NDTS_BTrue ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}
RQ_API NDTS_Boolean CALL_CONV RQ_SetCScanBaseSRAMAddress(unsigned long cardIndex, unsigned long address)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if ((address > RQ_SYSTEM_RAM_OFFSET - 4) || ((address & 0x00000003) != 0))
	{
		RQ_HandleRQError(RQ_SetCScanBaseSRAMAddress_InvalidAddress) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_GetSamplingRegister(cardIndex, RQ_CSCAN_DATA_SRAM_BASE, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	
	value &= 0xffc00000 ;
	value |= address ;

	isOK = RQ_SetSamplingRegister(cardIndex, RQ_CSCAN_DATA_SRAM_BASE, value) ;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetCScanBaseSRAMAddress(unsigned long cardIndex, unsigned long *address)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetSamplingRegister(cardIndex, RQ_CSCAN_DATA_SRAM_BASE, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	value &= 0x003fffff ;
	*address = value ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetAScanBaseSRAMAddress(unsigned long cardIndex, unsigned long *address)
{
	cardIndex;
	*address = 0;
	return NDTS_BTrue ;
}



RQ_API NDTS_Boolean CALL_CONV RQ_SetScanStorageOptions(unsigned long cardIndex, NDTS_ScanStorage storageOptions)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if (storageOptions != NDTS_SSMultipleAScanNoCScan && 
		storageOptions != NDTS_SSOneAScanMultipleCScan && 
		storageOptions != NDTS_SSMultipleAScanMultipleCScan &&
		storageOptions != NDTS_SSOneBScanMultipleCScan)
	{
		RQ_HandleRQError(RQ_SetScanStorageOptions_InvalidStorageOptions) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_CheckSRAM(cardIndex, storageOptions, 0xffffffff, (NDTS_SampleSize) -1,
		                0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_GetSamplingRegister(cardIndex, RQ_NUMBER_OF_SCANS, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	
	value &= 0x3fffffff ;
	value |= storageOptions << 30 ;

	isOK = RQ_SetSamplingRegister(cardIndex, RQ_NUMBER_OF_SCANS, value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	RQ_UpdateSampleParameters(cardIndex);
	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetScanStorageOptions(unsigned long cardIndex, NDTS_ScanStorage *storageOptions)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetSamplingRegister(cardIndex, RQ_NUMBER_OF_SCANS, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	value &= 0xc0000000 ;
	*storageOptions = (NDTS_ScanStorage) (value >> 30) ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetNumberOfBScansPerBank(unsigned long cardIndex, unsigned long numberOfScans)
{
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if (pBoardState->isAutomaticBScansPerBank)
	{
		RQ_HandleRQError(RQ_SetNumberOfBScansPerBank_Automatic) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	if(!RQ_SetNumberOfBScansPerBankInternal(cardIndex, numberOfScans))
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetNumberOfBScansPerBank(unsigned long cardIndex, unsigned long *numberOfScans)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetSamplingRegister(cardIndex, RQ_NUMBER_OF_SCANS, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	value &= 0x007fff00 ;
	*numberOfScans = (value >> 8) + 1 ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetNumberOfAScansPerBScan(unsigned long cardIndex, unsigned long numberOfScans)
{
	unsigned long value ;
	unsigned long totalOversamples = 0;
	NDTS_Boolean isOK ;
	unsigned i;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if (numberOfScans == 0 || numberOfScans > RQ_SRAM_MAXIMUM_NUMBER_OF_ASCANS_PER_BSCAN)
	{
		RQ_HandleRQError(RQ_SetNumberOfAScansPerBScan_InvalidNumber) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_CheckSRAM(cardIndex, (NDTS_ScanStorage) -1, 0xffffffff, (NDTS_SampleSize) -1,
		                numberOfScans, 0xffffffff, 0xffffffff, 0xffffffff) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_GetSamplingRegister(cardIndex, RQ_NUMBER_OF_SCANS, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	// For sequence mode we need to take account of the number of oversamples
	if (pBoardState->isSequence)
	{
		for (i = 0; i < numberOfScans; i++)
		{
			totalOversamples += pBoardState->oversampleCountThisStep[i];
		}
	}
	else
	{
		totalOversamples = pBoardState->oversampleCountThisStep[0] * numberOfScans;
	}

	value &= 0xffffff80 ;
	value |= totalOversamples - 1 ;

	isOK = RQ_SetSamplingRegister(cardIndex, RQ_NUMBER_OF_SCANS, value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	// FROG experimental
	isOK = RQ_SetSensorArrayNumberOfElements(cardIndex, totalOversamples) ;
	//isOK = RQ_SetSensorArrayNumberOfElements(cardIndex, numberOfScans) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	pBoardStates[cardIndex].numberOfAScansPerBScan = numberOfScans;
	RQ_UpdateSampleParameters(cardIndex);
	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetNumberOfAScansPerBScan(unsigned long cardIndex, unsigned long *numberOfScans)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetSamplingRegister(cardIndex, RQ_NUMBER_OF_SCANS, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	value &= 0x0000007f ;
	*numberOfScans = value + 1 ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetSyncPulseMode(unsigned long cardIndex, unsigned long mode)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if (mode > 1)
	{
		RQ_HandleRQError(RQ_SetSyncPuleMode_InvalidMode) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_GetSamplingRegister(cardIndex, RQ_NUMBER_OF_SCANS, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	
	value = (value & ~0x08000000) | (mode << 27) ;

	isOK = RQ_SetSamplingRegister(cardIndex, RQ_NUMBER_OF_SCANS, value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetSyncPulseMode(unsigned long cardIndex, unsigned long *pMode)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetSamplingRegister(cardIndex, RQ_NUMBER_OF_SCANS, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	*pMode = (value & 0x08000000) >> 27 ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetTCGValues(unsigned long cardIndex, const unsigned short *pTCGCurve, unsigned long numberOfValues)
{
	unsigned long i ;
	unsigned long regvalue;
	NDTS_Boolean isTCGEnabled ;
	NDTS_Boolean isOK ;
	// When using 16k of samples in the SFD app, a glitch of about 4 samples was sometimes observed after
	// the end of the replayed data.  It seems like the TCG is sometimes reading up to four extra samples
	// Copying 10 samples makes sure the glitch is covered
	unsigned int extraSamples = 10;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if (numberOfValues > RQ_MAXIMUM_NUMBER_OF_TCG_VALUES)
	{
		RQ_HandleRQError(RQ_SetTCGValues_InvalidNumberOfValues) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	// Determine whether TCG is enabled
	isOK = RQ_GetTCGEnable(cardIndex, &isTCGEnabled) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	// Read the TCG config register
	isOK = RQ_GetSamplingRegister(cardIndex, RQ_TCG_CONFIGURE, &regvalue);
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	regvalue &= 0xfffffffd; // disable

	isOK = RQ_SetSamplingRegister(cardIndex, RQ_TCG_CONFIGURE, regvalue);
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	regvalue |= 0x80000000; // reset load counter

	isOK = RQ_SetSamplingRegister(cardIndex, RQ_TCG_CONFIGURE, regvalue);
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	if (pBoardState->pTCGCurve != 0)
	{
		free(pBoardState->pTCGCurve) ;
		pBoardState->pTCGCurve = 0;
	}

	pBoardState->pTCGCurve = malloc(sizeof(unsigned short) * RQ_MAXIMUM_NUMBER_OF_TCG_VALUES) ;
	if (pBoardState->pTCGCurve == 0)
	{
		RQ_HandleRQError(RQ_SetTCGValues_OutOfMemory) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	for (i = 0 ; i < numberOfValues ; i++)
	{
		isOK = RQ_SetSamplingRegister(cardIndex, RQ_TCG_LOAD, (unsigned long) pTCGCurve[i]) ;
		if (!isOK)
		{
			RQ_Unlock(cardIndex) ;
			return NDTS_BFalse ;
		}

		pBoardState->pTCGCurve[i] = pTCGCurve[i] ;
	}

	if (numberOfValues + extraSamples > RQ_MAXIMUM_NUMBER_OF_TCG_VALUES)
	{
		extraSamples = RQ_MAXIMUM_NUMBER_OF_TCG_VALUES - numberOfValues;
	}

	// Extend the curve by a few values as DAC doesn't always seem to read exactly right number
	// of samples
	for (i = 0 ; i < extraSamples; i++)
	{
		isOK = RQ_SetSamplingRegister(cardIndex, RQ_TCG_LOAD, (unsigned long) pTCGCurve[numberOfValues-1]) ;
		if (!isOK)
		{
			RQ_Unlock(cardIndex) ;
			return NDTS_BFalse ;
		}

		pBoardState->pTCGCurve[i + numberOfValues] = pTCGCurve[numberOfValues-1] ;
	}
	
	for (i = numberOfValues + extraSamples; i < RQ_MAXIMUM_NUMBER_OF_TCG_VALUES ; i++)
		pBoardState->pTCGCurve[i] = 0 ;

	isOK = RQ_SetTCGEnable(cardIndex, isTCGEnabled) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	pBoardState->numberOfTCGValues = numberOfValues ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetTCGValues(unsigned long cardIndex, const unsigned short **pTCGCurve, unsigned long *pNumberOfValues)
{
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	*pTCGCurve = pBoardState->pTCGCurve ;
	*pNumberOfValues = pBoardState->numberOfTCGValues ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetTCGNormalisedStart(unsigned long cardIndex, unsigned long tCGModeMask, unsigned long tCGPointRatio)
{
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	// The tCGPointRatio is now per sequence step and so this function is not suitable for sequenced use.
	// The range of the TCG point ratio and the mode mask will be checked in the functions below
	if((pBoardState->isSequence))
	{
		RQ_HandleRQError(RQ_SetTCGNormalisedStart_TCGPointRatio) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	RQ_Lock(cardIndex) ;

	if (!RQ_SetTCGPointRatio(cardIndex, tCGPointRatio))
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse;
	}

	isOK = RQ_SetTCGStartInternal(cardIndex, tCGModeMask);

	RQ_Unlock(cardIndex) ;
	return isOK;
}

// This is intended to be called multiple times, once for each array element in the order of the pingpong sequence.
RQ_API NDTS_Boolean CALL_CONV RQ_SetTCGValuesNormalised(unsigned long cardIndex, 
														const unsigned short *pTCGCurve, 
														unsigned long numberOfValues)
{
	unsigned long i ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	for (i = 0 ; i < numberOfValues ; i++)
	{
		isOK = RQ_SetSamplingRegister(cardIndex, RQ_TCG_LOAD, (unsigned long) pTCGCurve[i]) ;
		if (!isOK)
		{
			RQ_Unlock(cardIndex) ;
			return NDTS_BFalse ;
		}
	}

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetTCGNormalisedFinish(unsigned long cardIndex)
{
	NDTS_Boolean isOK ;
	// When using 16k of samples in the SFD app, a glitch of about 4 samples was sometimes observed after
	// the end of the replayed data.  It seems like the TCG is sometimes reading up to four extra samples
	// Copying 10 samples makes sure the glitch is covered
	unsigned long regvalue;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetSamplingRegister(cardIndex, RQ_TCG_CONFIGURE, &regvalue);
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	regvalue &= 0x7ffffffd;
	regvalue |= 0x00000002; // enable

	isOK = RQ_SetSamplingRegister(cardIndex, RQ_TCG_CONFIGURE, regvalue);
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetSamplingFirmwareVersion(unsigned long cardIndex, unsigned long *versionNumber)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	isOK = RQ_GetSamplingRegister(cardIndex, RQ_SAMPLING_FPGA_VERSION_NUMBER, &value) ;
	if (!isOK)
		return NDTS_BFalse ;

	*versionNumber = (value & 0x0000f000) >> 12 ;
	
	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetSamplingFirmwareRevision(unsigned long cardIndex, unsigned long *revisionNumber)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	isOK = RQ_GetSamplingRegister(cardIndex, RQ_SAMPLING_FPGA_VERSION_NUMBER, &value) ;
	if (!isOK)
		return NDTS_BFalse ;
	
	*revisionNumber = value & 0x00000fff ;

	return NDTS_BTrue ;
}


// Peripheral FPGA registers

RQ_API NDTS_Boolean CALL_CONV RQ_SetInputCoupling(unsigned long cardIndex, RQ_InputCoupling inputCoupling)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if (inputCoupling != RQ_ICDC && inputCoupling != RQ_ICAC)
	{
		RQ_HandleRQError(RQ_SetInputCoupling_InvalidCoupling) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	value = pBoardState->peripheralRegisterShadow;
	//isOK = RQ_GetPeripheralRegister(cardIndex, RQ_PERIPHERAL_HARDWARE_CONTROL, &value) ;
	//if (!isOK)
	//{
	//	RQ_Unlock(cardIndex) ;
	//	return NDTS_BFalse ;
	//}
	
	value &= 0xfffffffe ;
	value |= (unsigned long) inputCoupling ;
	
	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_PERIPHERAL_HARDWARE_CONTROL, value) ;
	pBoardState->peripheralRegisterShadow  = value;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetInputCoupling(unsigned long cardIndex, RQ_InputCoupling *inputCoupling)
{
	unsigned long value ;
//	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	value = pBoardState->peripheralRegisterShadow;
	//isOK = RQ_GetPeripheralRegister(cardIndex, RQ_PERIPHERAL_HARDWARE_CONTROL, &value) ;
	//if (!isOK)
	//{
	//	RQ_Unlock(cardIndex) ;
	//	return NDTS_BFalse ;
	//}
	
	value &= 0x00000001 ;
	*inputCoupling = (RQ_InputCoupling) value ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetInputImpedance(unsigned long cardIndex, RQ_InputImpedance inputImpedance)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if (inputImpedance != RQ_II50Ohm && inputImpedance != RQ_II1MOhm)
	{
		RQ_HandleRQError(RQ_SetInputImpedance_InvalidInputImpedance) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	value = pBoardState->peripheralRegisterShadow ;
	//isOK = RQ_GetPeripheralRegister(cardIndex, RQ_PERIPHERAL_HARDWARE_CONTROL, &value) ;
	//if (!isOK)
	//{
	//	RQ_Unlock(cardIndex) ;
	//	return NDTS_BFalse ;
	//}
	
	value &= 0xfffffffd ;
	value |= (unsigned long) inputImpedance << 1 ;

	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_PERIPHERAL_HARDWARE_CONTROL, value) ;
	pBoardState->peripheralRegisterShadow = value;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetInputImpedance(unsigned long cardIndex, RQ_InputImpedance *inputImpedance)
{
	unsigned long value ;
//	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	value = pBoardState->peripheralRegisterShadow;
	//isOK = RQ_GetPeripheralRegister(cardIndex, RQ_PERIPHERAL_HARDWARE_CONTROL, &value) ;
	//if (!isOK)
	//{
	//	RQ_Unlock(cardIndex) ;
	//	return NDTS_BFalse ;
	//}
	
	value &= 0x00000002 ;
	*inputImpedance = (RQ_InputImpedance) (value >> 1) ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetAnalogueInput(unsigned long cardIndex, RQ_AnalogueInput analogueInput)
{
	unsigned long value;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if(analogueInput < 0 || analogueInput > 5)
	//if (analogueInput != RQ_AIInput1 && analogueInput != RQ_AIInput0 &&
	//	analogueInput != RQ_AIInputCalibration && analogueInput != RQ_AIInputGND)
	{
		RQ_HandleRQError(RQ_SetAnalogueInput_InvalidAnalogueInput) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	value = pBoardState->peripheralRegisterShadow;
	//isOK = RQ_GetPeripheralRegister(cardIndex, RQ_PERIPHERAL_HARDWARE_CONTROL, &value) ;
	//if (!isOK)
	//{
	//	RQ_Unlock(cardIndex) ;
	//	return NDTS_BFalse ;
	//}
	
	//value &= 0xFE7FFFC3;		//clean 32 bits with bit index 2-5, 23 and 24
	value &= 0xFE7FF003;			//clean 32 bits with bit index 2-11, 23 and 24

	//if input0, input1, gnd, cal
	if (analogueInput == RQ_AIInput1 || analogueInput == RQ_AIInput0 ||
	analogueInput == RQ_AIInputCalibration || analogueInput == RQ_AIInputGND)
	{
		value |= 1 << ((unsigned long) analogueInput + 2);
		value |= 1 << (pBoardState->analogueGainShadow + 6);
	}
	else
		value |= 1 << ((unsigned long)(analogueInput - RQ_AIInputAux0) + 23);

	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_PERIPHERAL_HARDWARE_CONTROL, value) ;
	pBoardState->peripheralRegisterShadow = value;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetAnalogueInput(unsigned long cardIndex, RQ_AnalogueInput *analogueInput)
{
	unsigned long value ;
//	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	value = pBoardState->peripheralRegisterShadow;
	//isOK = RQ_GetPeripheralRegister(cardIndex, RQ_PERIPHERAL_HARDWARE_CONTROL, &value) ;
	//if (!isOK)
	//{
	//	RQ_Unlock(cardIndex) ;
	//	return NDTS_BFalse ;
	//}
	
	value &= 0x0000003c ;
	value >>= 2 ;

	switch (value)
	{
	case 0x00000001 :
		*analogueInput = RQ_AIInput1 ;
		break ;
	case 0x00000002 :
		*analogueInput = RQ_AIInput0 ;
		break ;
	case 0x00000004 :
		*analogueInput = RQ_AIInputCalibration ;
		break ;
	case 0x0000008 :
		*analogueInput = RQ_AIInputGND ;
		break ;
	default :
		RQ_HandleRQError(RQ_GetAnalogueInput_InvalidInputFlags) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	} ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetAnalogueInputRange(unsigned long cardIndex, RQ_AnalogueInputRange analogueGain)
{
	unsigned long analogueInputValue;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex);
	if (!pBoardState) return NDTS_BFalse;

	// Bug 970 - can't calibrate once running as thread interferes with calibration process
	if (!pBoardState->isCalibrated[analogueGain])
	{
		RQ_HandleRQError(RQ_SetAnalogueInputRange_CantSelectRangeOnceRunningUnlessRQIniIsCalAll) ;
		return NDTS_BFalse ;
	}

    analogueInputValue = pBoardState->peripheralRegisterShadow;
	analogueInputValue &= 0x1800000;
    
	// The gain bits (input voltage range) should all be clear when using an Aux analogue input 
	if (analogueInputValue == 0x1000000 || analogueInputValue == 0x800000)
	{
		RQ_HandleRQError(RQ_SetAnalogueInputRange_RangeNotValidForAuxInput) ;
		return NDTS_BFalse ;
	}

	// If the input range is changed, the zero tweak is lost.  This prevents the zero tweak getting lost if it is set in the ini file and IW writes the same default range
	if ((int)pBoardState->inputRange == analogueGain)
		return NDTS_BTrue;


	RQ_Lock(cardIndex) ;

	if (analogueGain != RQ_AG100mV && analogueGain != RQ_AG200mV && analogueGain != RQ_AG500mV &&
		analogueGain != RQ_AG1V && analogueGain != RQ_AG2V && analogueGain != RQ_AG5V)
	{
		RQ_HandleRQError(RQ_SetAnalogueInputRange_InvalidAnalogueGain) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	pBoardState->inputRange = analogueGain;
	pBoardState->analogueGainShadow = analogueGain;
    
	isOK = RQ_SetAnalogueInputRangeInternal(cardIndex, analogueGain);
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_SetCalibrationGain(cardIndex, pBoardState->calibrationGains[analogueGain]) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_SetCalibrationOffset(cardIndex, pBoardState->calibrationOffsets[analogueGain]) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetAnalogueInputRange(unsigned long cardIndex, RQ_AnalogueInputRange *analogueGain)
{
	unsigned long value ;
//	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	value = pBoardState->peripheralRegisterShadow;
	//isOK = RQ_GetPeripheralRegister(cardIndex, RQ_PERIPHERAL_HARDWARE_CONTROL, &value) ;
	//if (!isOK)
	//{
	//	RQ_Unlock(cardIndex) ;
	//	return NDTS_BFalse ;
	//}
	
	value &= 0x00000fc0 ;
	value >>= 6 ;

	switch (value)
	{
	case 0x00000001 :
		*analogueGain = RQ_AG100mV ;
		break ;
	case 0x00000002 :
		*analogueGain = RQ_AG200mV ;
		break ;
	case 0x00000004 :
		*analogueGain = RQ_AG500mV ;
		break ;
	case 0x00000008 :
		*analogueGain = RQ_AG1V ;
		break ;
	case 0x00000010 :
		*analogueGain = RQ_AG2V ;
		break ;
	case 0x00000020 :
		*analogueGain = RQ_AG5V ;
		break ;
	default :
		//RQ_HandleRQError(RQ_GetAnalogueInputRange_InvalidGainFlags) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	} ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}


RQ_API NDTS_Boolean CALL_CONV RQ_SetAuxInput(unsigned long cardIndex, RQ_AuxInput auxInput)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if (auxInput != RQ_AxIInputNone && auxInput != RQ_AxIInputBoth &&
		auxInput != RQ_AxIInput0 && auxInput != RQ_AxIInput1)
	{
		RQ_HandleRQError(RQ_SetAuxInput_InvalidAuxInput) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	value = pBoardState->peripheralRegisterShadow;
	//isOK = RQ_GetPeripheralRegister(cardIndex, RQ_PERIPHERAL_HARDWARE_CONTROL, &value) ;
	//if (!isOK)
	//{
	//	RQ_Unlock(cardIndex) ;
	//	return NDTS_BFalse ;
	//}

	value &= 0xfe7fffff ;
	value |= (unsigned long) auxInput << 23 ;

	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_PERIPHERAL_HARDWARE_CONTROL, value) ;
	pBoardState->peripheralRegisterShadow = value;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetAuxInput(unsigned long cardIndex, RQ_AuxInput *auxInput)
{
	unsigned long value ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	value = pBoardState->peripheralRegisterShadow;
	//isOK = RQ_GetPeripheralRegister(cardIndex, RQ_PERIPHERAL_HARDWARE_CONTROL, &value) ;
	//if (!isOK)
	//{
	//	RQ_Unlock(cardIndex) ;
	//	return NDTS_BFalse ;
	//}

	value &= 0x01800000 ;

	switch (value >> 23)
	{
	case 0 :
		*auxInput = RQ_AxIInputNone ;
		break ;
	case 1 :
		*auxInput = RQ_AxIInput0 ;
		break ;
	case 2 :
		*auxInput = RQ_AxIInput1 ;
		break ;
	case 3 :
		*auxInput = RQ_AxIInputBoth ;
		break ;
	} ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetTriggerSelect(unsigned long cardIndex, RQ_Trigger triggerSelect)
{
	unsigned long value;
	NDTS_Boolean isOK ;
	RQ_Trigger previousTriggerSelect;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if (triggerSelect != RQ_TExternal && triggerSelect != RQ_TInternal && triggerSelect != RQ_TEncoder && triggerSelect != RQ_TFreeRunning)
	{
		RQ_HandleRQError(RQ_SetTriggerSelect_InvalidTrigger) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_GetTriggerSelect(cardIndex, &previousTriggerSelect);
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	value = pBoardState->rqTriggerControlShadow;
	value &= 0xfffeffff ;
	value |= (unsigned long) RQ_IsInternalTrigger(triggerSelect) << 16 ;

	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_TRIGGER_CONTROL, value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	pBoardState->rqTriggerControlShadow = value;

	value = pBoardState->rqBscanTriggerControlShadow;
	value &= 0x9fffffff ;
	value |= (unsigned long) (triggerSelect == RQ_TEncoder) << 30 ;
	value |= (unsigned long) (triggerSelect == RQ_TFreeRunning) << 29 ;

	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_BSCAN_TRIGGER_CONTROL, value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	pBoardState->rqBscanTriggerControlShadow = value;

	pBoardState->currentTriggerMode = triggerSelect;

	// Bug 947 - the bottom 28 bits are shared between encoder trigger settings and B Scan rep rate
	// If we have just switched to free running, write the B Scan Rep rate to these bits.
	// If we were free running and are now in encoder mode, using the rqBscanTriggerControlShadow above
	// will have restored the encoder settings.
	if (pBoardState->currentTriggerMode == RQ_TFreeRunning)
	{
		RQ_SetBScanRepetitionRate(cardIndex, pBoardState->bScanRepetitionRate); 
	}

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetTriggerSelect(unsigned long cardIndex, RQ_Trigger *triggerSelect)
{
	//unsigned long value, triggerIndex ;
	//NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	*triggerSelect = pBoardState->currentTriggerMode;
	return NDTS_BTrue;
}

// The pulseLength is in sampleClockPeriod / 2 steps.
// The RapiDAQ will generate a negative going pulse of the specified length.
// Applications normally specify the centre frequency of the probe.  
// (1) The application converts frequency to pulseLength using length = (1 / f) * sampleClockRate.
// (2) The probe seems to see the negative going pulse of one half of a waveform.
// (1) and (2) cancel each other out and the probe gets the frequency it expects.
// However, the negative going pulse on the scope appears half as wide as if the pulseLength were expressed in the sampleClockRate
RQ_API NDTS_Boolean CALL_CONV RQ_SetTransducerPulseWidth(unsigned long cardIndex, unsigned long pulseLength)
{
	unsigned long value, version ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetPeripheralFirmwareVersion(cardIndex, &version) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	if (version != 0 && version != 2)
	{
		RQ_HandleRQError(RQ_SetTransducerPulseWidth_InvalidFirmwareVersion) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	if (pulseLength < 5 && version == 2)
	{
		// On SFD, setting the width less than 5 results in the signal between PRX and RQ being too narrow and the system
		// fails to trigger reliably.
		pulseLength = 5; 
	}

	if (pulseLength > RQ_MAXIMUM_GENERATOR_PULSE_LENGTH)
	{
		RQ_HandleRQError(RQ_SetTransducerPulseWidth_InvalidWidth) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_GetPeripheralRegister(cardIndex, RQ_PULSE_GENERATOR, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	value &= 0xfffff000 ;
	value |= pulseLength ;

	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_PULSE_GENERATOR, value) ;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetTransducerPulseWidth(unsigned long cardIndex, unsigned long *pulseLength)
{
	unsigned long value, version ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetPeripheralFirmwareVersion(cardIndex, &version) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	if (version != 0 && version != 2)
	{
		RQ_HandleRQError(RQ_GetTransducerPulseWidth_InvalidFirmwareVersion) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_GetPeripheralRegister(cardIndex, RQ_PULSE_GENERATOR, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	value &= 0x00000fff ;
	*pulseLength = value ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetRepetitionRate(unsigned long cardIndex, unsigned long repetitionRateHz)
{
	unsigned long numberOfPeriods, samplingFrequency ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetSamplingFrequency(cardIndex, &samplingFrequency) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	numberOfPeriods = samplingFrequency / 5 / repetitionRateHz ;

	isOK = RQ_SetNumberOfPeriodsBetweenAScanTriggers(cardIndex, numberOfPeriods) ;
	if (isOK)
	{
		// Daniel Summer 07:-
		// There is potential for things getting out of sync if the sample frequency is changed.
		// It would probably be better to do everything using samples in the RQ SDK.
		// However, pBoardState->repetitionRate is only used in the get functions and the 
		// B Scan rep rate for the Faro Arm and works fine with WinRS.

		pBoardState->repetitionRate = repetitionRateHz ;
		pBoardState->repetitionTime = numberOfPeriods;
		RQ_Unlock(cardIndex) ;
		return NDTS_BTrue ;
	}
	else
	{
		RQ_Unlock(cardIndex) ;

		return NDTS_BFalse ;
	}
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetRepetitionRate(unsigned long cardIndex, unsigned long *pRepetitionRate)
{
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	*pRepetitionRate = pBoardState->repetitionRate;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetRepetitionTime(unsigned long cardIndex, unsigned long repetitionTime)
{
	NDTS_Boolean isOK ;
	unsigned long samplingFrequency, repetitionRate;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_SetNumberOfPeriodsBetweenAScanTriggers(cardIndex, repetitionTime);
	if (isOK)
	{
		RQ_GetSamplingFrequency(cardIndex, &samplingFrequency) ;
		repetitionRate = samplingFrequency / 5 / repetitionTime;

		pBoardState->repetitionTime = repetitionTime ;
		RQ_Unlock(cardIndex) ;

		return NDTS_BTrue ;
	}
	else
	{
		RQ_Unlock(cardIndex) ;

		return NDTS_BFalse ;
	}
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetRepetitionTime(unsigned long cardIndex, unsigned long *pRepetitionTime)
{
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	*pRepetitionTime = pBoardState->repetitionTime;

	RQ_Unlock(cardIndex) ;

	return RQ_OK ;
}

// Repetition rate is in Hz, it is only applicable to FreeRunning mode.
// Should add a get function
// Maybe add set / get repetitionTime functions
// Maybe more error checking:
// Check the max value
// The BScan Rep rate must be > AScanRepRate * number of AScans per BScan
// Maybe check that we are in free running but it is probably useful to set this value before entering free running
// otherwise get lots of errors due to data arriving too fast when entering free running mode?

RQ_API NDTS_Boolean CALL_CONV RQ_SetBScanRepetitionRate(unsigned long cardIndex, unsigned long repetitionRateHz)
{
	unsigned long numberOfPeriods, samplingFrequency, value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if (repetitionRateHz > RQ_ReturnMaxBScanRepRate(cardIndex))
	{
		RQ_HandleRQError(RQ_SetBScanRepetitionRate_RateTooHighForAScanRate) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_GetSamplingFrequency(cardIndex, &samplingFrequency) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	numberOfPeriods = samplingFrequency / 5 / repetitionRateHz ;

	value = pBoardState->rqBscanTriggerControlShadow;

	value &= 0xfc000000 ;
	value |= numberOfPeriods ;

	isOK =  RQ_SetPeripheralRegister(cardIndex, RQ_BSCAN_TRIGGER_CONTROL, value) ;
	// Bug 947 - the bottom 28 bits are shared between encoder trigger settings and B Scan rep rate.
	// rqBscanTriggerControlShadow is used to shadow these bits when in encoder mode so don't change
	// them to the B Scan rep rate.
	//pBoardState->rqBscanTriggerControlShadow = value;

	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	pBoardState->bScanRepetitionRate = repetitionRateHz;

	RQ_Unlock(cardIndex) ;
	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetBScanRepetitionRate(unsigned long cardIndex, unsigned long *pRepetitionRate)
{
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	*pRepetitionRate = pBoardState->bScanRepetitionRate;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_AutoSetBScanRepetitionRate(unsigned long cardIndex)
{
	NDTS_Boolean isOK ;

	RQ_Lock(cardIndex) ;

	isOK = RQ_SetBScanRepetitionRate(cardIndex, RQ_ReturnMaxBScanRepRate(cardIndex));
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	RQ_Unlock(cardIndex) ;
	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetNumberOfOversamples(unsigned long cardIndex, unsigned long oversamplingMultiplier)
{
	unsigned long value ;
	NDTS_Boolean isOK ;

	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if ((oversamplingMultiplier < 1) || (oversamplingMultiplier > 20) || (!pBoardState->isSequence))
	{
		RQ_HandleRQError(RQ_SetNumberOfOversamples_InvalidnumberOfOversamples) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_GetPeripheralRegister(cardIndex, RQ_ASCAN_CONTROL, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	value &= 0xf00fffff ;
	value |= ((oversamplingMultiplier - 1) << 20);

	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_ASCAN_CONTROL, value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	pBoardState->oversampleCountThisStep[pBoardState->isSequence ? pBoardState->currentSequenceStep : 0] = oversamplingMultiplier;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetSensorArrayApertureSize(unsigned long cardIndex, RQ_ApertureSize apertureSize)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if (apertureSize != RQ_AS8 && apertureSize != RQ_AS16 &&
		apertureSize != RQ_AS24 && apertureSize != RQ_AS32)
	{
		RQ_HandleRQError(RQ_SetSensorArrayApertureSize_InvalidApertureSize) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	
	isOK = RQ_GetPeripheralRegister(cardIndex, RQ_SENSOR_ARRAY_SETUP, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	value &= 0xfffffcff ;
	value |= (unsigned long) apertureSize << 8 ;

	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_SENSOR_ARRAY_SETUP, value) ;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetSensorArrayApertureSize(unsigned long cardIndex, RQ_ApertureSize *apertureSize)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetPeripheralRegister(cardIndex, RQ_SENSOR_ARRAY_SETUP, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	value &= 0x00000300 ;
	*apertureSize = (RQ_ApertureSize) (value >> 8) ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}


RQ_API NDTS_Boolean CALL_CONV RQ_SetSensorArrayDisableAperturePositionWrites(unsigned long cardIndex, NDTS_Boolean isDisabled)
{
	NDTS_Boolean isOK ;
	unsigned long version, value ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetPeripheralFirmwareVersion(cardIndex, &version) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	if (version != 1)
	{
		RQ_HandleRQError(RQ_SetSensorArrayDisableAperturePositionWrites_InvalidFirmwareVersion) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	if (isDisabled != NDTS_BTrue && isDisabled != NDTS_BFalse)
	{
		RQ_HandleRQError(RQ_SetSensorArrayDisableAperturePositionWrites_InvalidEnableFlag) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_GetPeripheralRegister(cardIndex, RQ_FOCUSING_UNIT_CONTROL, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	value &= 0xfffffbff ;
	value |= (unsigned long) isDisabled << 10 ;

	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_FOCUSING_UNIT_CONTROL, value) ;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetSensorArrayDisableAperturePositionWrites(unsigned long cardIndex, NDTS_Boolean *isDisabled)
{
	NDTS_Boolean isOK ;
	unsigned long version, value ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetPeripheralFirmwareVersion(cardIndex, &version) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	if (version != 1)
	{
		RQ_HandleRQError(RQ_GetSensorArrayDisableAperturePositionWrites_InvalidFirmwareVersion) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_GetPeripheralRegister(cardIndex, RQ_FOCUSING_UNIT_CONTROL, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	*isDisabled = (value & 0x00000400) != 0 ? NDTS_BTrue : NDTS_BFalse ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetSensorArrayDisableApertureDelayWrites(unsigned long cardIndex, NDTS_Boolean isDisabled)
{
	NDTS_Boolean isOK ;
	unsigned long version, value ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetPeripheralFirmwareVersion(cardIndex, &version) ; 
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	if (version != 1)
	{
		RQ_HandleRQError(RQ_SetSensorArrayDisableApertureDelayWrites_InvalidFirmwareVersion) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	if (isDisabled != NDTS_BTrue && isDisabled != NDTS_BFalse)
	{
		RQ_HandleRQError(RQ_SetSensorArrayDisableApertureDelayWrites_InvalidEnableFlag) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_GetPeripheralRegister(cardIndex, RQ_FOCUSING_UNIT_CONTROL, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	value &= 0xfffff7ff ;
	value |= (unsigned long) isDisabled << 11 ;

	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_FOCUSING_UNIT_CONTROL, value) ;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetSensorArrayDisableApertureDelayWrites(unsigned long cardIndex, NDTS_Boolean *isDisabled)
{
	unsigned long version, value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetPeripheralFirmwareVersion(cardIndex, &version) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	if (version != 1)
	{
		RQ_HandleRQError(RQ_GetSensorArrayDisableApertureDelayWrites_InvalidFirmwareVersion) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_GetPeripheralRegister(cardIndex, RQ_FOCUSING_UNIT_CONTROL, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	*isDisabled = (value & 0x00000800) != 0 ? NDTS_BTrue : NDTS_BFalse ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetIsBScanModeEnabled(unsigned long cardIndex, NDTS_Boolean isEnabled)
{
	unsigned long version, value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetPeripheralFirmwareVersion(cardIndex, &version) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	// The below should not matter
	/*
	if (version != 0)
	{
		RQ_HandleRQError(RQ_SetIsBScanModeEnabled_InvalidFirmwareVersion) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	*/

	if (isEnabled != NDTS_BTrue && isEnabled != NDTS_BFalse)
	{
		RQ_HandleRQError(RQ_SetIsBScanModeEnabled_InvalidFlag) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	
	isOK = RQ_GetPeripheralRegister(cardIndex, RQ_SENSOR_ARRAY_SETUP, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	value &= 0xffffefff ;
	value |= (unsigned long) isEnabled << 12 ;

	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_SENSOR_ARRAY_SETUP, value) ;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetIsBScanModeEnabled(unsigned long cardIndex, NDTS_Boolean *pIsEnabled)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetPeripheralRegister(cardIndex, RQ_SENSOR_ARRAY_SETUP, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	
	*pIsEnabled = (value & 0x00001000) != 0x00000000 ? NDTS_BTrue : NDTS_BFalse ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetSensorArrayIsProbeAttached(unsigned long cardIndex, NDTS_Boolean *isAttached)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetPeripheralRegister(cardIndex, RQ_SENSOR_ARRAY_SETUP, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	value &= 0x80000000 ;
	*isAttached = (NDTS_Boolean) (value >> 31) ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

/* elementNumber - the element number to fire at this sequence position
   effectivePosition - which element number this step corresponds to (lookup value for the destination when unravelling)

Example for a 64 element array with 8 effective element positions
elementNumber 4 sequencePosition 0 effectivePosition 0
elementNumber 18 sequencePosition 1 effectivePosition 2
elementNumber 32 sequencePosition 2 effectivePosition 4
elementNumber 46 sequencePosition 3 effectivePosition 6
elementNumber 11 sequencePosition 4 effectivePosition 1
elementNumber 25 sequencePosition 5 effectivePosition 3
elementNumber 39 sequencePosition 6 effectivePosition 5
elementNumber 53 sequencePosition 7 effectivePosition 7
*/
RQ_API NDTS_Boolean CALL_CONV RQ_SetPingPongSequenceElement(unsigned long cardIndex, unsigned long elementNumber, unsigned long sequencePosition, unsigned long effectivePosition)
{
//	unsigned long value ;
//	NDTS_Boolean isBScanModeEnabled ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if (elementNumber > RQ_PINGPONG_ARRAY_SIZE)
	{
		RQ_HandleRQError(RQ_SetPingPongSequenceElement_InvalidElementNumber) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	
	if (sequencePosition > RQ_PINGPONG_SEQUENCE_LENGTH - 1)
	{
		RQ_HandleRQError(RQ_SetPingPongSequenceElement_InvalidSequencePosition) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	/*
	isOK = RQ_GetSensorArrayEnableBScanMode(&isBScanModeEnabled) ;
	if (!isOK)
		return NDTS_BFalse ;

	if (isBScanModeEnabled == NDTS_BTrue)
	{
		RQ_HandleRQError(RQ_SetPingPongSequenceElementBScanModeEnabled) ;
		return NDTS_BFalse ;
	}
	*/

	if (pBoardState->pPingPongSequence == 0)
	{
		int i ;

		pBoardState->pPingPongSequence = malloc(sizeof(unsigned short) * RQ_PINGPONG_SEQUENCE_LENGTH) ;
		pBoardState->pReversePingPongSequenceDest = malloc(sizeof(unsigned short) * RQ_PINGPONG_SEQUENCE_LENGTH) ;
		pBoardState->pReversePingPongSequenceSource = malloc(sizeof(unsigned short) * RQ_PINGPONG_SEQUENCE_LENGTH) ;
		if (pBoardState->pPingPongSequence == 0 || pBoardState->pReversePingPongSequenceDest == 0 || pBoardState->pReversePingPongSequenceSource == 0)
		{
			RQ_HandleRQError(RQ_SetPingPongSequenceElement_OutOfMemory) ;
			RQ_Unlock(cardIndex) ;
			return NDTS_BFalse ;
		}

		for (i = 0 ; i < RQ_PINGPONG_SEQUENCE_LENGTH ; i++)
		{
			pBoardState->pPingPongSequence[i] = 0 ;
			pBoardState->pReversePingPongSequenceDest[i] = 0 ;
			pBoardState->pReversePingPongSequenceSource[i] = 0 ;
		}
	}
	// pPingPongSequence holds the un flipped element.  It is only used when applying flipping
	// Flipping is done at the lowest level, in SetPingPongElementRegister
	pBoardState->pPingPongSequence[sequencePosition] = (unsigned short) elementNumber ;
	pBoardState->pReversePingPongSequenceDest[sequencePosition] = (unsigned short) effectivePosition ;
	pBoardState->pReversePingPongSequenceSource[pBoardState->pReversePingPongSequenceDest[sequencePosition]] = (short)sequencePosition ;

	isOK = RQ_SetPingPongElementRegister(cardIndex, sequencePosition, elementNumber) ;
	
	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetPingPongSequence(unsigned long cardIndex, unsigned short *sequence,  unsigned short *reverseSequence)
{
	int i ;
	//NDTS_Boolean isBScanModeEnabled ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	/*
	isOK = RQ_GetSensorArrayEnableBScanMode(&isBScanModeEnabled) ;
	if (!isOK)
		return NDTS_BFalse ;
		*/

	/*
	isOK = RQ_SetSensorArrayEnableBScanMode(NDTS_BFalse) ;
	if (!isOK)
		return NDTS_BFalse ;
		*/

	for (i = 0 ; i < RQ_PINGPONG_SEQUENCE_LENGTH ; i++)
	{
		isOK = RQ_SetPingPongSequenceElement(cardIndex, sequence[i], i, reverseSequence[i]) ;
		if (!isOK)
		{
			RQ_Unlock(cardIndex) ;
			return NDTS_BFalse ;
		}
	}

	/*
	isOK = RQ_SetSensorArrayEnableBScanMode(isBScanModeEnabled) ;
	if (!isOK)
		return NDTS_BFalse ;
		*/

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetPingPongSequence(unsigned long cardIndex, const unsigned short **sequence, const unsigned short **reverseSequence)
{
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	*sequence = pBoardState->pPingPongSequence ;
	*reverseSequence = pBoardState->pReversePingPongSequenceDest ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetNumberOfEncoderClicksPerBScan(unsigned long cardIndex, unsigned long numberOfClicks)
{
	unsigned long value ;
	NDTS_Boolean isOK = NDTS_BTrue ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if (numberOfClicks == 0 || numberOfClicks > 65536)
	{
		RQ_HandleRQError(RQ_SetNumberOfEncoderClicksPerBScan_InvalidNumberOfClicks) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	value = pBoardState->rqBscanTriggerControlShadow;

	value &= 0xffff0000 ;
	value |= numberOfClicks - 1 ;

	// Bug 947 - the bottom 28 bits are shared between encoder trigger settings and B Scan rep rate
	// Don't overwrite the value in the card if free running
	if (pBoardState->currentTriggerMode != RQ_TFreeRunning)
	{
		isOK = RQ_SetPeripheralRegister(cardIndex, RQ_BSCAN_TRIGGER_CONTROL, value) ;
	}

	pBoardState->rqBscanTriggerControlShadow = value;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetNumberOfEncoderClicksPerBScan(unsigned long cardIndex, unsigned long *numberOfClicks)
{
	unsigned long value ;
	//NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	value = pBoardState->rqBscanTriggerControlShadow;

	value &= 0x0000ffff ;
	*numberOfClicks = value + 1 ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetFractionalNumberOfEncoderClicksPerBScan(unsigned long cardIndex, unsigned long numerator, unsigned long unityShift)
{
	unsigned long value ;
	NDTS_Boolean isOK = NDTS_BTrue;
	int shift ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if (numerator >= (1ul << unityShift))
	{
		RQ_HandleRQError(RQ_SetFractionalNumberOfEncoderClicksPerBScan_InvalidNumerator) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	shift = (int) RQ_FRACTIONAL_BSCAN_CLICKS_UNITY_SHIFT - (int) unityShift ;

	value = pBoardState->rqBscanTriggerControlShadow ;

	value &= 0xf00fffff ;
	value |= ((shift >= 0 ? numerator << shift : numerator >> (-shift)) & ~(1 << RQ_FRACTIONAL_BSCAN_CLICKS_UNITY_SHIFT)) << 20 ;

	// Bug 947 - the bottom 28 bits are shared between encoder trigger settings and B Scan rep rate
	// Don't overwrite the value in the card if free running
	if (pBoardState->currentTriggerMode != RQ_TFreeRunning)
	{
		isOK = RQ_SetPeripheralRegister(cardIndex, RQ_BSCAN_TRIGGER_CONTROL, value) ;
	}

	pBoardState->rqBscanTriggerControlShadow = value ;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetFractionalNumberOfEncoderClicksPerBScan(unsigned long cardIndex, unsigned long *pNumerator, unsigned long *pUnityShift)
{
	unsigned long value ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	value = pBoardState->rqBscanTriggerControlShadow ;

	*pNumerator = (value & 0x0ff00000) >> 20 ;
	*pUnityShift = RQ_FRACTIONAL_BSCAN_CLICKS_UNITY_SHIFT ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetEncoderSelect(unsigned long cardIndex, unsigned long encoderIndex)
{
	unsigned long value ;
	NDTS_Boolean isOK = NDTS_BTrue;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	// FT encoder 6 may be set for dual encoder mode
	if ((encoderIndex > RQ_NUMBER_OF_ENCODERS) && (encoderIndex != 0xffffffff))
	{
		RQ_HandleRQError(RQ_SetEncoderSelect_InvalidEncoderIndex) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	value = pBoardState->rqBscanTriggerControlShadow;

	value &= 0xfff8ffff ;
	value |= encoderIndex != 0xffffffff ? encoderIndex << 16 : 0x00000007 << 16 ;

	// Bug 947 - the bottom 28 bits are shared between encoder trigger settings and B Scan rep rate
	// Don't overwrite the value in the card if free running
	if (pBoardState->currentTriggerMode != RQ_TFreeRunning)
	{
		isOK = RQ_SetPeripheralRegister(cardIndex, RQ_BSCAN_TRIGGER_CONTROL, value) ;
	}

	pBoardState->rqBscanTriggerControlShadow = value;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetEncoderSelect(unsigned long cardIndex, unsigned long *encoderIndex)
{
	unsigned long value ;
	//NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	value = pBoardState->rqBscanTriggerControlShadow;

	value &= 0x00070000 ;
	// FT encoder 6 may be specified for dual encoder
	*encoderIndex = value >> 16 <= RQ_NUMBER_OF_ENCODERS ? value >> 16 : -1 ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetForceBScanTrigger(unsigned long cardIndex)
{
	unsigned long value ;
	RQ_Trigger triggerSelect ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetTriggerSelect(cardIndex, &triggerSelect) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	// Bug 947 - this function shouldn't be called when free running so it doesn't matter
	// if the B Scan bits get overwritten with the encoder bits.
	// Bug 743 - allow a force trigger in encoder mode
	if (triggerSelect != RQ_TInternal && triggerSelect != RQ_TEncoder)
	{
		RQ_HandleRQError(RQ_SetForceBScanTrigger_InvalidTriggerSource) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	value = pBoardState->rqBscanTriggerControlShadow;
	value &= 0x7fffffff ;
	value |= 1 << 31 ;

	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_BSCAN_TRIGGER_CONTROL, value) ;
	// pBoardState->rqBscanTriggerControlShadow = value;  Don't save bit 31 as set.  It is write only and if set will cause a trigger to be forced every time the register is written (e.g. in RQ_SetTriggerSelect()).

	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
/*
	// Once the trigger has been forced, swap banks 
	// This allows forceTrigger to be called if there is more than one B per bank without the app needing to 
	// be concerned with the Bscans per bank or forcing bank swaps.

	isWIN32OK = QueryPerformanceFrequency(&freqLarge) ;
	if (!isWIN32OK)
	{
		RQ_HandleRQError(RQ_SetForceBScanTrigger_QueryTimerFail) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	QueryPerformanceCounter(&countLargeA) ;

	while(!RQ_SetRequestEarlySampleData(cardIndex))
	{
		if (RQ_GetLastError(cardIndex) != RQ_SetRequestEarlySampleData_NoSampleData)
		{
			RQ_Unlock(cardIndex) ;
			return NDTS_BFalse ;
		}

		QueryPerformanceCounter(&countLargeB) ;
		numSeconds = (float) (countLargeB.QuadPart - countLargeA.QuadPart) / (float) freqLarge.QuadPart ;
		if (numSeconds > RQ_SAMPLE_DATA_AVAILABLE_MAX_WAIT)
		{
			RQ_HandleRQError(RQ_SetForceBScanTrigger_Timeout) ;
			RQ_Unlock(cardIndex) ;
			return NDTS_BFalse ;
		}
	}

	isOK = DC_WaitForBankSwap(cardIndex) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
*/
	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetEncoderOutput(unsigned long cardIndex, unsigned long encoderIndex, long *pPosition)
{
	NDTS_Boolean isOK ;
	unsigned long positionUL ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if (encoderIndex > RQ_NUMBER_OF_ENCODERS)
	{
		RQ_HandleRQError(RQ_GetEncoderOutput_InvalidEncoderIndex) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	// FT encoder 6 (dual mode) is read from encoder 0's register
	if (encoderIndex == RQ_NUMBER_OF_ENCODERS)
	{
		encoderIndex = 0;
	}

	isOK = RQ_GetPeripheralRegister(cardIndex, RQ_ENCODER_0_OUTPUT + (encoderIndex << 2), &positionUL) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	*pPosition = (long) positionUL ;
	{
		unsigned long i;
		for (i=0; i<pBoardState->numberOfGetEncoderOutputHooks; i++)
			(*pBoardState->ppGetEncoderOutputHooks[i])(cardIndex, encoderIndex, pPosition);
	}

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetResetEncoderOutput(unsigned long cardIndex, unsigned long encoderIndex)
{
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if (encoderIndex > RQ_NUMBER_OF_ENCODERS)
	{
		RQ_HandleRQError(RQ_SetResetEncoderOutput_InvalidEncoderIndex) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	// FT encoder 6 (dual mode) should be handled as encoder 0
	if (encoderIndex == RQ_NUMBER_OF_ENCODERS)
	{
		encoderIndex = 0;
	}

	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_ENCODER_0_OUTPUT + (encoderIndex << 2), 0) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	{
		unsigned long i;
		for (i=0; i<pBoardState->numberOfResetEncoderOutputHooks; i++)
			(*pBoardState->ppResetEncoderOutputHooks[i])(cardIndex, encoderIndex);
	}

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_AddGate(unsigned long cardIndex, const RQ_Gate *pGateParam)
{
	unsigned long numGates, stepCounter, endStep ;
	NDTS_Boolean isOK ;
    unsigned short gateSubtractValue ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	static NDTS_LogLevel dumpGatesLogLevel = NDTS_LLErr;
	RQ_Gate localGate;
	RQ_Gate *pGate = &localGate;
	if (!pBoardState) return NDTS_BFalse; 

	// If the gate is not enabled, set sensible values so the checks below don't fail and leave the gate enabled
	if (pGateParam->isEnabled)
		memcpy(pGate, pGateParam, sizeof(RQ_Gate));
	else
	{
		memset(pGate, 0, sizeof(RQ_Gate));
		pGate->index = pGateParam->index;
		pGate->triggerGate = RQ_GTAbsolute;
	}

	// Set a breakpoint and set dumpGatesLogLevel to 0 to write the gates to the debugger / log file.
	//NDTS_LogLine(dumpGatesLogLevel, "Add Gate index=%d, startCount=%d, stopCount=%d, threshold=%d, triggerGate=%d, thresholdPolarity=%d, triggerMode=%d, distanceMetric=%d, isEnabled=%d, amplitudePeakSelect=%d, distancePeakSelect=%d, storeGateValue=%d, snapshotSelection=%d",
	//	pGate->index, pGate->startCount, pGate->stopCount, pGate->threshold, pGate->triggerGate, pGate->thresholdPolarity, pGate->triggerMode, pGate->distanceMetric, pGate->isEnabled, pGate->amplitudePeakSelect, pGate->distancePeakSelect, pGate->storeGateValue, pGate->snapshotSelection) ;

	/* The user may want to set a gate start of zero.  Although this is impossible to do, it is better to set
	it to as early as possible.  E.G.
	start sent by caller                 0 1 2 3 4 5 6 7 8 9
	value written to reg for i/f gate    0 0 0 0 1 2 3 4 5 6  
	value written to reg for normal gate 0 0 0 0 0 1 2 3 4 5 

	Note that the situation is further complicated with over sampling in sequenced mode - see RawWriteGates()
	*/
	gateSubtractValue = RQ_ReturnGateSubtractValue(pGate);
	
	if (cardIndex >= globalState.pciState.numberOfRapiDAQBoards) return NDTS_BFalse;

	RQ_Lock(cardIndex) ;
	RQ_PauseSequence(cardIndex);

	isOK = RQ_GetNumberOfEnabledGatesThisChannel(cardIndex, pBoardState->currentSequenceStep, &numGates) ;
	if (!isOK)
	{
		goto fail;
	}
	// FROG this is wrong - it assumes we're adding a new gate whereas we may well be replacing an existing one
	isOK = RQ_CheckSRAM(cardIndex, (NDTS_ScanStorage) -1, 0xffffffff, (NDTS_SampleSize) -1,
		                0xffffffff, 0xffffffff, numGates + 1, 0xffffffff) ;
	if (!isOK)
	{
		goto fail;
	}

	if (pGate->index >= (int)RQ_ReturnMaximumNumberOfGates(pBoardState->isSequence))
	{
		RQ_HandleRQError(RQ_AddGate_InvalidGateIndex) ;
		goto fail;
	}

	if (pGate->startCount - gateSubtractValue > 65535 || pGate->startCount - gateSubtractValue < 0)
	{
		RQ_HandleRQError(RQ_AddGate_InvalidStartCount) ;
		goto fail;
	}

	if (pGate->stopCount - gateSubtractValue > 65535 || pGate->stopCount - gateSubtractValue < 0)
	{
		RQ_HandleRQError(RQ_AddGate_InvalidEndCount) ;
		goto fail;
	}

	if (pGate->threshold > 2047)
	{
		RQ_HandleRQError(RQ_AddGate_InvalidThreshold) ;
		goto fail;
	}

	if (pGate->triggerGate != RQ_GTGate0 && pGate->triggerGate != RQ_GTGate1 && 
		pGate->triggerGate != RQ_GTGate2 && pGate->triggerGate != RQ_GTGate3 && 
		pGate->triggerGate != RQ_GTGate4 && pGate->triggerGate != RQ_GTGate5 && 
		pGate->triggerGate != RQ_GTGate6 && pGate->triggerGate != RQ_GTGate7 && 
		pGate->triggerGate != RQ_GTGate8 && pGate->triggerGate != RQ_GTGate9 && 
		pGate->triggerGate != RQ_GTAbsolute ||
		(int) pGate->triggerGate == (int) pGate->index)
	{
		RQ_HandleRQError(RQ_AddGate_InvalidTriggerIndex) ;
		goto fail;
	}

	if (pGate->thresholdPolarity != RQ_GTPBipolar &&
		pGate->thresholdPolarity != RQ_GTPPositive &&
		pGate->thresholdPolarity != RQ_GTPNegative)
	{
		RQ_HandleRQError(RQ_AddGate_InvalidThresholdPolarity) ;
		goto fail;
	}

	if (pGate->triggerMode != RQ_GTMLevel && pGate->triggerMode != RQ_GTMEdge)
	{
		RQ_HandleRQError(RQ_AddGate_InvalidTriggerMode) ;
		goto fail;
	}
	if (pGate->storeGateValue != RQ_SGVOnlyWhenTriggered && pGate->storeGateValue != RQ_SGVAlways)
	{
		RQ_HandleRQError(RQ_AddGate_InvalidStoreGateValue) ;
		goto fail;
	}

	if (pGate->snapshotSelection < NDTS_PDSLatest || pGate->snapshotSelection > NDTS_PDSIndexed)
	{
		RQ_HandleRQError(RQ_AddGate_InvalidSnapshotSelection) ;
		goto fail;
	}

	if (pGate->storeGateValue == RQ_SGVAlways &&
		(	pGate->amplitudePeakSelect != RQ_GAPSLargestPeak ||
			pGate->distancePeakSelect!= RQ_GDPSLargestPeak  ||
			pGate->distanceMetric != RQ_GDMPeak))
	{
		RQ_HandleRQError(RQ_AddGate_RQ_SGVAlwaysNeedsLargestPeakSelected) ;
		goto fail;
	}

	if (pGate->index != 0 && 
		pGate->distanceMetric != RQ_GDMLeadingFlank && 
		pGate->distanceMetric != RQ_GDMTrailingFlank &&
		pGate->distanceMetric != RQ_GDMPeak &&
		pGate->distanceMetric != RQ_GDMLeadingZeroCrossing && 
		pGate->distanceMetric != RQ_GDMTrailingZeroCrossing) 
	{
		RQ_HandleRQError(RQ_AddGate_InvalidDistanceMetric) ;
		goto fail;
	}

	if (pGate->isEnabled != NDTS_BTrue && pGate->isEnabled != NDTS_BFalse)
	{
		RQ_HandleRQError(RQ_AddGate_InvalidEnable) ;
		goto fail;
	}

	if (pGate->index != 0 && 
		pGate->amplitudePeakSelect != RQ_GAPSPeak0 &&
		pGate->amplitudePeakSelect != RQ_GAPSPeak1 &&
		pGate->amplitudePeakSelect != RQ_GAPSPeak2 &&
		pGate->amplitudePeakSelect != RQ_GAPSPeak3 &&
		pGate->amplitudePeakSelect != RQ_GAPSPeak4 &&
		pGate->amplitudePeakSelect != RQ_GAPSPeak5 &&
		pGate->amplitudePeakSelect != RQ_GAPSPeak6 &&
		pGate->amplitudePeakSelect != RQ_GAPSPeak7 &&
		pGate->amplitudePeakSelect != RQ_GAPSPeak8 &&
		pGate->amplitudePeakSelect != RQ_GAPSPeak9 &&
		pGate->amplitudePeakSelect != RQ_GAPSPeak10 &&
		pGate->amplitudePeakSelect != RQ_GAPSPeak11 &&
		pGate->amplitudePeakSelect != RQ_GAPSPeak12 &&
		pGate->amplitudePeakSelect != RQ_GAPSPeak13 &&
		pGate->amplitudePeakSelect != RQ_GAPSLastPeak &&
		pGate->amplitudePeakSelect != RQ_GAPSLargestPeak)
	{
		RQ_HandleRQError(RQ_AddGate_InvalidAmplitudePeakSelect) ;
		goto fail;
	}

	if (pGate->index != 0 && 
		pGate->distancePeakSelect != RQ_GDPSPeak0 &&
		pGate->distancePeakSelect != RQ_GDPSPeak1 &&
		pGate->distancePeakSelect != RQ_GDPSPeak2 &&
		pGate->distancePeakSelect != RQ_GDPSPeak3 &&
		pGate->distancePeakSelect != RQ_GDPSPeak4 &&
		pGate->distancePeakSelect != RQ_GDPSPeak5 &&
		pGate->distancePeakSelect != RQ_GDPSPeak6 &&
		pGate->distancePeakSelect != RQ_GDPSPeak7 &&
		pGate->distancePeakSelect != RQ_GDPSPeak8 &&
		pGate->distancePeakSelect != RQ_GDPSPeak9 &&
		pGate->distancePeakSelect != RQ_GDPSPeak10 &&
		pGate->distancePeakSelect != RQ_GDPSPeak11 &&
		pGate->distancePeakSelect != RQ_GDPSPeak12 &&
		pGate->distancePeakSelect != RQ_GDPSPeak13 &&
		pGate->distancePeakSelect != RQ_GDPSLastPeak &&
		pGate->distancePeakSelect != RQ_GDPSLargestPeak)
	{
		RQ_HandleRQError(RQ_AddGate_InvalidDistancePeakSelect) ;
		goto fail;
	}

	// Done all the checks - now OK to update the BoardState - non sequenced, fill in all states with the same value
	endStep = pBoardState->isSequence ? 1 : NDTS_MAXIMUM_NUMBER_OF_ELEMENTS;
	for (stepCounter=0; stepCounter < endStep; stepCounter++)
	{
		unsigned long actualStep = (pBoardState->isSequence) ? pBoardState->currentSequenceStep : stepCounter ;
		unsigned long nGates ;
		unsigned long activeGateOrdinal = 0;
		unsigned char absGateNumber;

		pBoardState->storeGateValue[actualStep][pGate->index] = pGate->storeGateValue;
		pBoardState->gates[actualStep][pGate->index] = *pGate ;

		isOK = RQ_GetNumberOfEnabledGatesThisChannel(cardIndex, actualStep, &nGates);
		if (!isOK)
			goto fail;

		pBoardState->gateCountThisStep[actualStep] = (unsigned char)nGates;

		for (absGateNumber = 0; absGateNumber < RQ_ReturnMaximumNumberOfGates(pBoardState->isSequence); absGateNumber++)
		{
			if (pBoardState->gates[actualStep][absGateNumber].isEnabled == NDTS_BTrue)
			{
				pBoardState->unpackGate[actualStep][activeGateOrdinal++] = absGateNumber;
			}
		}
		for (; activeGateOrdinal < RQ_ReturnMaximumNumberOfGates(pBoardState->isSequence); activeGateOrdinal++)
		{
			pBoardState->unpackGate[actualStep][activeGateOrdinal] = 0;
		}
	}

	// RemoveAllGates may be called before other stuff is set up, so make sure it doesn't fail horribly
	if (pBoardState->isSequence && pBoardState->numberOfAScansPerBScan > NDTS_MAXIMUM_NUMBER_OF_STEPS)
	{
		pBoardState->numberOfAScansPerBScan = NDTS_MAXIMUM_NUMBER_OF_STEPS; 
	}
	RQ_UpdateSampleParameters(cardIndex);

	// Clear down all the gates and then enable the ones that we want
	if (pBoardState->isSequence)
	{
		unsigned long oldChannel;

		isOK = RQ_GetSequenceStep(cardIndex, &oldChannel);
		if (!isOK)
			goto fail;

		// When we write a gate we have to write the corresponding gates
		// for each step.  I.e. if we change step 3 gate 2 we must rewrite gate 2 for each step.
		// Oh hang on is there more to this - we write the gate data and then set a bit to do the transfer
		// operation.  I think that we should write all the steps and then transfer the lot in one go
		isOK = RQ_RawWriteGates(cardIndex, pGate->index);
		if (!isOK)
			goto fail;

		isOK = RQ_SetSequenceStep(cardIndex, oldChannel);
		if (!isOK)
			goto fail;
	}
	else
	{
		// for non-sequence mode operation just write the gate
		isOK = RQ_RawWriteGate(cardIndex, pGate);
		if (!isOK)
			goto fail;
	}

	RQ_ResumeSequence(cardIndex);
	RQ_Unlock(cardIndex) ;
	return isOK ;

fail:
	RQ_ResumeSequence(cardIndex);
	RQ_Unlock(cardIndex) ;
	return NDTS_BFalse;
}

RQ_API NDTS_Boolean CALL_CONV RQ_RemoveAllGates(unsigned long cardIndex)
{
	NDTS_Boolean isOK = NDTS_BTrue;
	unsigned long gateIndex;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	for (gateIndex = 0; gateIndex < RQ_ReturnMaximumNumberOfGates(pBoardState->isSequence); gateIndex++)
	{
		isOK = RQ_RemoveGate(cardIndex, gateIndex);
		if (isOK != NDTS_BTrue)
		{
			return isOK;
		}
	}
	return isOK;
}

RQ_API NDTS_Boolean CALL_CONV RQ_RemoveGate(unsigned long cardIndex, RQ_GateIndex index)
{
	RQ_Gate gate ;
	const RQ_Gate *pGate ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if (index >= (int)RQ_ReturnMaximumNumberOfGates(pBoardState->isSequence))
	{
		RQ_HandleRQError(RQ_RemoveGate_InvalidIndex) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_GetGate(cardIndex, index, &pGate) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	gate = *pGate ;

	gate.isEnabled = NDTS_BFalse ;

	isOK = RQ_AddGate(cardIndex, &gate) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	RQ_UpdateSampleParameters(cardIndex) ;
	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetGate(unsigned long cardIndex, RQ_GateIndex index, const RQ_Gate **ppGate)
{
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if (index >= (int)RQ_ReturnMaximumNumberOfGates(pBoardState->isSequence))
	{
		RQ_HandleRQError(RQ_GetGate_InvalidIndex) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	*ppGate = &pBoardState->gates[pBoardState->currentSequenceStep][index] ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetGate2(unsigned long cardIndex, unsigned long stepIndex, RQ_GateIndex index, RQ_Gate *pGate)
{
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex);
	if (pBoardState == NULL) return NDTS_BFalse; 

	RQ_Lock(cardIndex);

	if (index >= (int)RQ_ReturnMaximumNumberOfGates(pBoardState->isSequence))
	{
		RQ_HandleRQError(RQ_GetGate_InvalidIndex);
		RQ_Unlock(cardIndex);
		return NDTS_BFalse;
	}

	if (stepIndex >= NDTS_MAXIMUM_NUMBER_OF_ELEMENTS)
	{
		RQ_HandleRQError(RQ_GetGate_InvalidIndex);
		RQ_Unlock(cardIndex);
		return NDTS_BFalse;
	}

	*pGate = pBoardState->gates[stepIndex][index];

	RQ_Unlock(cardIndex);

	return NDTS_BTrue;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetNumberOfEnabledGatesThisChannel(unsigned long cardIndex, unsigned long channel, unsigned long *pNumberOfGates)
{
	unsigned long numGates, i ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	numGates = 0 ;

	for (i = 0 ; i < RQ_ReturnMaximumNumberOfGates(pBoardState->isSequence); i++)
		if (pBoardState->gates[channel][i].isEnabled == 1)
			numGates++ ;

	*pNumberOfGates = numGates ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetNumberOfEnabledGates(unsigned long cardIndex, unsigned long *pNumberOfGates)
{
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	return RQ_GetNumberOfEnabledGatesThisChannel(cardIndex, pBoardState->currentSequenceStep, pNumberOfGates);
}

/*


typedef struct 
{
	RQ_GateIndex index ;
	NDTS_Boolean wasAmplitudeMeasured ;
	NDTS_Boolean wasDistanceMeasured ;
	unsigned long amplitudeMetric ;
	unsigned long distanceMetric ;
} NDTS_GateOutput ;

//RQ_API NDTS_Boolean RQ_GetGateOutput(unsigned long bScanIndex, unsigned long aScanIndex, RQ_GateIndex gateIndex, NDTS_GateOutput *pGateOutput) ;

RQ_API NDTS_Boolean RQ_GetGateOutput(unsigned long bScanIndex, unsigned long aScanIndex, RQ_GateIndex gateIndex, NDTS_GateOutput *gateOutput)
{
	unsigned long numberOfBScansInMemory, numberOfAScansPerBScan, gateInternalIndex, i,
		          numberOfEnabledGates, gateOutputOffset, gateDataCardBaseAddress,
				  gateOutputData ;
	const RQ_Gate *pGate ;
	NDTS_Boolean isOK ;

	isOK = RQ_GetNumberOfBScansInSRAM(cardIndex, &numberOfBScansInMemory) ;
	if (!isOK)
		return NDTS_BFalse ;

	if (bScanIndex >= numberOfBScansInMemory)
	{
		RQ_HandleRQError(RQ_GetGateOutput_InvalidBScanIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_GetNumberOfAScansPerBScan(cardIndex, &numberOfAScansPerBScan) ;
	if (!isOK)
		return NDTS_BFalse ;

	if (aScanIndex >= numberOfAScansPerBScan)
	{
		RQ_HandleRQError(RQ_GetGateOutput_InvalidAScanIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_GetGate(gateIndex, &pGate) ;
	if (!isOK)
		return NDTS_BFalse ;

	if (pGate->isEnabled == 2) ** isEnabled is no longer set to 2 on init.
	{
		RQ_HandleRQError(RQ_GetGateOutputGateIsNotPresent) ;
		return NDTS_BFalse ;
	}

	if (!pGate->isEnabled)
	{
		RQ_HandleRQError(RQ_GetGateOutputGateIsNotEnabled) ;
		return NDTS_BFalse ;
	}

	numberOfEnabledGates = 0 ;

	for (i = 0 ; i < RQ_MAXIMUM_NUMBER_OF_GATES ; i++)
	{
		isOK = RQ_GetGate(i, &pGate) ;
		if (!isOK)
			return NDTS_BFalse ;

		if ((int) i == gateIndex)
			gateInternalIndex = numberOfEnabledGates ;

		if (pGate->isEnabled == NDTS_BTrue)
			numberOfEnabledGates++ ;
	}

	isOK = RQ_GetCScanBaseSRAMAddress(cardIndex, &gateDataCardBaseAddress) ;
	if (!isOK)
		return NDTS_BFalse ;
***CHANGE to use gates stride if this is commented back in***
	gateOutputOffset = bScanIndex * (numberOfAScansPerBScan * ((numberOfEnabledGates << 2) + 4) + RQ_NUMBER_OF_ENCODERS * 4) +
	                   4 + (gateInternalIndex << 2) ;

	gateOutputData = *(unsigned long *) (PCI_State->pPCIBar2VirtualAddress + gateDataCardBaseAddress + gateOutputOffset) ;
	To make this work with gate outputs value all the time - use something like RQ_ExtractIsGateValueValid
	gateOutput->wasAmplitudeMeasured = (gateOutputData & 0x20000000) != 0x00000000 ? NDTS_BTrue : NDTS_BFalse ;
	gateOutput->wasDistanceMeasured = (gateOutputData & 0x10000000) != 0x00000000 ? NDTS_BTrue : NDTS_BFalse ;

	gateOutput->amplitudeMetric = (gateOutputData & 0x0fff0000) >> 16 ;
	gateOutput->distanceMetric = gateOutputData & 0x00007fff ;

	gateOutput->index = gateIndex ;

	return NDTS_BTrue ;
}
*/

RQ_API NDTS_Boolean CALL_CONV RQ_SetPeripheralIOBank0(unsigned long cardIndex, unsigned long data)
{
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_PERIPHERAL_IO_BANK_0, data) ;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetPeripheralDDR0(unsigned long cardIndex, unsigned long directionBits)
{
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_PERIPHERAL_DDR_0, directionBits) ;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetPeripheralDDR0(unsigned long cardIndex, unsigned long *pDirectionBits)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetPeripheralRegister(cardIndex, RQ_PERIPHERAL_DDR_0, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	*pDirectionBits = value ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetPeripheralIOBank0(unsigned long cardIndex, unsigned long *ioBits)
{
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetPeripheralRegister(cardIndex, RQ_PERIPHERAL_IO_BANK_0, ioBits) ;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetPeripheralIOBank1(unsigned long cardIndex, unsigned long data)
{
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_PERIPHERAL_IO_BANK_1, data) ;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetPeripheralDDR1(unsigned long cardIndex, unsigned long directionBits)
{
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_PERIPHERAL_DDR_1, directionBits) ;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetPeripheralDDR1(unsigned long cardIndex, unsigned long *pDirectionBits)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetPeripheralRegister(cardIndex, RQ_PERIPHERAL_DDR_1, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	*pDirectionBits = value ;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetPeripheralIOBank1(unsigned long cardIndex, unsigned long *ioBits)
{
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetPeripheralRegister(cardIndex, RQ_PERIPHERAL_IO_BANK_1, ioBits) ;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetFocusingUnitControl(unsigned long cardIndex, unsigned long controlBus, unsigned long data)
{
	NDTS_Boolean isOK, hasTimedOut ;
	LARGE_INTEGER freqLarge, countLargeA, countLargeB ;
	float numSeconds ;
	unsigned long value, version ;
	BOOL isWIN32OK ;
	NDTS_Boolean isWriteComplete ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetPeripheralFirmwareVersion(cardIndex, &version) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	if (version != 1)
	{
		RQ_HandleRQError(RQ_SetFocusingUnitControl_InvalidFirmwareVersion) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	if (controlBus > 7)
	{
		RQ_HandleRQError(RQ_SetFocusingUnitControl_InvalidControlBus) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	if (data > 7)
	{
		RQ_HandleRQError(RQ_SetFocusingUnitControl_InvalidData) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_FOCUSING_UNIT_CONTROL, (controlBus << 8) | data) ;
	if (!isOK)
	{
		RQ_HandleRQError(RQ_SetFocusingUnitControl_InvalidData) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isWIN32OK = QueryPerformanceFrequency(&freqLarge) ;
	if (!isWIN32OK)
	{
		RQ_HandleRQError(RQ_SetFocusingUnitControl_QueryTimerFail) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	QueryPerformanceCounter(&countLargeA) ;

	do
	{
		QueryPerformanceCounter(&countLargeB) ;

		isOK = RQ_GetPeripheralRegister(cardIndex, RQ_FOCUSING_UNIT_CONTROL, &value) ;
		if (!isOK)
		{
			RQ_Unlock(cardIndex) ;
			return NDTS_BFalse ;
		}

		isWriteComplete = (value & 0x80000000) ? NDTS_BTrue : NDTS_BFalse ;

		numSeconds = (float) (countLargeB.QuadPart - countLargeA.QuadPart) / (float) freqLarge.QuadPart ;
		hasTimedOut = numSeconds > RQ_FOCUSING_UNIT_MAX_WAIT ? NDTS_BTrue : NDTS_BFalse ; 
	}
	while (isWriteComplete == NDTS_BFalse && !hasTimedOut) ;

	if (hasTimedOut)
	{
		RQ_HandleRQError(RQ_SetFocusingUnitControl_TimeOut) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}



/*


RQ_API NDTS_Boolean RQ_GetIRQSamplingFlags(unsigned long *samplingFlags)
{
	unsigned long value ;
	NDTS_Boolean isOK ;

	isOK = RQ_GetRegister(RQ_SYSTEM_STATUS_REGISTER, &value) ;
	
	value &= 0x000000f0 ;
	value >>= 4 ;

	*samplingFlags = value ;

	return isOK ;
}

/*
RQ_API unsigned char RQ_GetPeripheralHardwareStatus()
{
	unsigned long value ;

	value = RQ_GetRegister(PERIPHERAL_HARDWARE_STATUS) ;
	
	value &= 0x00000001 ;

	return (unsigned char) value ;
}
*/
/*
RQ_API NDTS_Boolean RQ_GetEncoderOutput(unsigned long *encoderPosition)
{
	return RQ_GetRegister(RQ__ENCODER_OUTPUT, encoderPosition) ;
}

RQ_API NDTS_Boolean RQ_GetPeripheralIOBank0(unsigned long *ioBits)
{
	return RQ_GetRegister(RQ_PERIPHERAL_IO_BANK_0, ioBits) ;
}

RQ_API NDTS_Boolean RQ_GetPeripheralIOBank1(unsigned long *ioBits)
{
	return RQ_GetRegister(RQ_PERIPHERAL_IO_BANK_1, ioBits) ;
}

RQ_API NDTS_Boolean RQ_GetPeripheralIOBank2(unsigned long *ioBits)
{
	unsigned long value ;
	NDTS_Boolean isOK ;

	isOK = RQ_GetRegister(RQ_PERIPHERAL_IO_BANK_0, &value) ;

	value &= 0x000000ff ;
	*ioBits = value ;
	
	return isOK ;
}
*/

RQ_API NDTS_Boolean CALL_CONV RQ_GetPeripheralFirmwareVersion(unsigned long cardIndex, unsigned long *versionNumber)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	isOK = RQ_GetPeripheralRegister(cardIndex, RQ_PERIPHERAL_FPGA_VERSION_NUMBER, &value) ;
	if (!isOK)
		return NDTS_BFalse ;
	
	*versionNumber = (value & 0x0000f000) >> 12 ;

	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetPeripheralFirmwareRevision(unsigned long cardIndex, unsigned long *revisionNumber)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	isOK = RQ_GetPeripheralRegister(cardIndex, RQ_PERIPHERAL_FPGA_VERSION_NUMBER, &value) ;
	if (!isOK)
		return NDTS_BFalse ;
	
	*revisionNumber = value & 0x00000fff ;

	return NDTS_BTrue ;
}

int RQ_LoadTCGCurveFromFile(unsigned long cardIndex, HANDLE fileHandle)
{
	int i ;
	const int stringLength = 512 ;
	char string[512], propertyString[512], valueString[512] ;
	char *pStopChar, *pTCGPrefixString ;
	unsigned short tcgCurve[RQ_MAXIMUM_NUMBER_OF_TCG_VALUES] ;
	unsigned long value ;
	int valueIndex, numTCGValues ;
	DWORD numBytesRead ;
	BOOL isWin32OK ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	numTCGValues = 0 ;

	do
	{
		i = 0 ;

		do
		{
			isWin32OK = ReadFile(fileHandle, &string[i], 1, &numBytesRead, 0) ;
			if (!isWin32OK || numBytesRead != 1)
				goto EndOfFile ;

			i++ ;
		}
		while (string[i - 1] != '=' && string[i - 1] != '[' && i < stringLength) ;

		if (i == stringLength)
		{
			RQ_HandleRQError(RQ_LoadTCGCurveFromFile_OversizedStringLength) ;
			RQ_Unlock(cardIndex) ;
			return 0 ;
		}

		if (string[i - 1] != '[')
		{
			string[i - 1] = 0 ;

			RQ_ExtractStringFromWhitespaceOrBrackets(string, propertyString) ;

			pTCGPrefixString = strstr(propertyString, RQ_TCGIndexPrefixString) ;

			if (pTCGPrefixString != 0)
			{
				i = strlen(propertyString) ;

				do
					i-- ;
				while (propertyString[i] >= '0' && propertyString[i] <= '9') ;

				valueIndex = atoi(&propertyString[i + 1]) ;

				if (valueIndex < 0 || valueIndex >= RQ_MAXIMUM_NUMBER_OF_TCG_VALUES)
				{
					RQ_HandleRQError(RQ_LoadTCGCurveFromFile_InvalidIndex) ;
					RQ_Unlock(cardIndex) ;
					return 0 ;
				}

				i = 0 ;

				do
				{
					isWin32OK = ReadFile(fileHandle, &string[i], 1, &numBytesRead, 0) ;
					if (!isWin32OK || numBytesRead != 1)
					{
						RQ_HandleRQError(RQ_LoadTCGCurveFromFile_ReadError) ;
						RQ_Unlock(cardIndex) ;
						return 0 ;
					}

					i++ ;
				}
				while (string[i - 1] != 0x0a) ;

				string[i - 1] = 0 ;

				RQ_ExtractStringFromWhitespaceOrBrackets(string, valueString) ;

				value = strtoul(valueString, &pStopChar, 0) ;

				if (value > 32767)
				{
					RQ_HandleRQError(RQ_LoadTCGCurveFromFile_InvalidTCGValue) ;
					RQ_Unlock(cardIndex) ;
					return 0 ;
				}

				tcgCurve[valueIndex] = (unsigned short) value ;
				numTCGValues++ ;
			}
		}
		else
		{
			RQ_HandleRQError(RQ_LoadTCGCurveFromFile_InvalidIndexPrefix) ;
			RQ_Unlock(cardIndex) ;
			return 0 ;
		}
	}
	while (string[i - 1] != '[') ;

	isOK = RQ_SetTCGValues(cardIndex, tcgCurve, numTCGValues) ? 1 : 0 ;

	RQ_Unlock(cardIndex) ;

	return isOK ;

EndOfFile :
	isOK = RQ_SetTCGValues(cardIndex, tcgCurve, numTCGValues) ? 2 : 0 ;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

int RQ_LoadPingPongSequenceFromFile(unsigned long cardIndex, HANDLE fileHandle)
{
	int i, noReverse ;
	const int stringLength = 512 ;
	char string[512], propertyString[512], valueString[512] ;
	char *pStopChar, *pPingPongPrefixString ;
	unsigned short pPingPongSequence[RQ_MAXIMUM_NUMBER_OF_TCG_VALUES] ;
	unsigned short reversePingPongSequence[RQ_MAXIMUM_NUMBER_OF_TCG_VALUES] ;
	unsigned long value ;
	int valueIndex ;
	DWORD numBytesRead ;
	BOOL isWin32OK ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	do
	{
		i = 0 ;

		do
		{
			isWin32OK = ReadFile(fileHandle, &string[i], 1, &numBytesRead, 0) ;
			if (!isWin32OK || numBytesRead != 1)
				goto EndOfFile ;

			i++ ;
		}
		while (string[i - 1] != '=' && string[i - 1] != '[' && i < stringLength) ;

		if (i == stringLength)
		{
			RQ_HandleRQError(RQ_LoadPingPongSequenceFromFile_OversizedStringLength) ;
			RQ_Unlock(cardIndex) ;
			return 0 ;
		}

		if (string[i - 1] != '[')
		{
			string[i - 1] = 0 ;

			RQ_ExtractStringFromWhitespaceOrBrackets(string, propertyString) ;

			pPingPongPrefixString = strstr(propertyString, RQ_PingPongElementPrefixString) ;

			if (pPingPongPrefixString != 0)
			{
				i = strlen(propertyString) ;

				do
					i-- ;
				while (propertyString[i] >= '0' && propertyString[i] <= '9') ;

				valueIndex = atoi(&propertyString[i + 1]) ;

				if (valueIndex < 0 || valueIndex >= RQ_PINGPONG_SEQUENCE_LENGTH)
				{
					RQ_HandleRQError(RQ_SetPingPongSequenceElement_InvalidSequencePosition) ;
					RQ_Unlock(cardIndex) ;
					return 0 ;
				}

				// Extract pingPong value
				i = 0 ;

				do
				{
					isWin32OK = ReadFile(fileHandle, &string[i], 1, &numBytesRead, 0) ;
					if (!isWin32OK || numBytesRead != 1)
					{
						RQ_HandleRQError(RQ_LoadPingPongSequenceFromFile_ReadError) ;
						RQ_Unlock(cardIndex) ;
						return 0 ;
					}

					i++ ;
				}
				// , separates ping pong from reverse ping pong
				while (string[i - 1] != ',' && string[i - 1] != 0x0a) ;
				noReverse = (string[i - 1] == 0x0a) ;
	
				string[i - 1] = 0 ;

				RQ_ExtractStringFromWhitespaceOrBrackets(string, valueString) ;

				value = strtoul(valueString, &pStopChar, 0) ;

				if (value >= RQ_PINGPONG_ARRAY_SIZE)
				{
					RQ_HandleRQError(RQ_LoadPingPongSequenceFromFile_InvalidElementIndex) ;
					RQ_Unlock(cardIndex) ;
					return 0 ;
				}

				pPingPongSequence[valueIndex] = (unsigned short) value ;

				// Reverse pingPong element not found - maybe an attempt to read 
				// a file that was written before the May 05 reverse ping pong version.
				// This is what the SDK would have done without a reverse ping pong table
				if (noReverse)
				{
					reversePingPongSequence[valueIndex] = (short)valueIndex ;
				}
				else
				{
					// Extract reverse pingPong value
					i = 0 ;

					do
					{
						isWin32OK = ReadFile(fileHandle, &string[i], 1, &numBytesRead, 0) ;
						if (!isWin32OK || numBytesRead != 1)
						{
							RQ_HandleRQError(RQ_LoadPingPongSequenceFromFile_ReadError) ;
							RQ_Unlock(cardIndex) ;
							return 0 ;
						}

						i++ ;
					}
					while (string[i - 1] != 0x0a) ;

					string[i - 1] = 0 ;

					RQ_ExtractStringFromWhitespaceOrBrackets(string, valueString) ;

					value = strtoul(valueString, &pStopChar, 0) ;

					if (value >= RQ_PINGPONG_ARRAY_SIZE)
					{
						RQ_HandleRQError(RQ_LoadPingPongSequenceFromFile_InvalidElementIndex) ;
						RQ_Unlock(cardIndex) ;
						return 0 ;
					}
					reversePingPongSequence[valueIndex] = (unsigned short) value ;
				}
			}
			else
			{
				RQ_HandleRQError(RQ_LoadPingPongSequenceFromFile_InvalidIndexPrefix) ;
				RQ_Unlock(cardIndex) ;
				return 0 ;
			}
		}
	}
	while (string[i - 1] != '[') ;

	isOK = RQ_SetPingPongSequence(cardIndex, pPingPongSequence, reversePingPongSequence) ? 1 : 0 ;

	RQ_Unlock(cardIndex) ;

	return isOK ;

EndOfFile :
	isOK = RQ_SetPingPongSequence(cardIndex, pPingPongSequence, reversePingPongSequence) ? 2 : 0 ;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetDIInterfaceBitsLow(unsigned long cardIndex)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetPeripheralRegister(cardIndex, RQ_SENSOR_ARRAY_SETUP, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	value &= 0xffffe3ff ;
	value |= 0x00000800 ;

	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_SENSOR_ARRAY_SETUP, value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	RQ_Unlock(cardIndex) ;
	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetDIBoardState(unsigned long cardIndex, NDTS_Boolean isOn)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetPeripheralRegister(cardIndex, RQ_PERIPHERAL_DDR_0, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	value |= 1 << RQ_DI_BOARD_FET_SWITCH_INDEX ;

	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_PERIPHERAL_DDR_0, value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_GetPeripheralRegister(cardIndex, RQ_PERIPHERAL_IO_BANK_0, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	if (isOn)
		value |= 1 << RQ_DI_BOARD_FET_SWITCH_INDEX ;
	else
		value &= ~(1 << RQ_DI_BOARD_FET_SWITCH_INDEX) ;

	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_PERIPHERAL_IO_BANK_0, value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	RQ_Unlock(cardIndex) ;
	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetWaterPumpState(unsigned long cardIndex, NDTS_Boolean isOn)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetPeripheralRegister(cardIndex, RQ_PERIPHERAL_DDR_0, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	value |= 1 << RQ_DI_BOARD_WATER_PUMP_INDEX ;

	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_PERIPHERAL_DDR_0, value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_GetPeripheralRegister(cardIndex, RQ_PERIPHERAL_IO_BANK_0, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	if (isOn)
		value |= 1 << RQ_DI_BOARD_WATER_PUMP_INDEX ;
	else
		value &= ~(1 << RQ_DI_BOARD_WATER_PUMP_INDEX) ;

	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_PERIPHERAL_IO_BANK_0, value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	RQ_Unlock(cardIndex) ;
	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetSerialNumber(unsigned long cardIndex, unsigned long *pSerialNumber)
{
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	*pSerialNumber = pBoardState->cardSerialNumber;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetZeroOffset(unsigned long cardIndex, int offset)
{
	int value;
	unsigned long finished;
	NDTS_Boolean isOK ;
	RQ_AnalogueInputRange range;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse;

	RQ_Lock(cardIndex) ;

	// FT The offset is an adjusment to the calibrated value
	if ((offset < -2048) || (offset > 2047)) return NDTS_BFalse;

	range = pBoardState->inputRange;
	pBoardState->zeroTweak[range] = offset;
	value = pBoardState->calibrationOffsets[range] + offset;
	if (value < 0) value = 0;
	if (value > 4095) value = 4095;

	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_CALIBRATION_DATA, (value & 0xfff) + 0x3000);
	if (!isOK) 
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse;
	}

	// wait for the offset to be acknowledged
	do
	{
		isOK = RQ_GetPeripheralRegister(cardIndex, RQ_CALIBRATION_DATA, &finished);
	} 
	while (isOK && (finished & 0x80000000));

	RQ_Unlock(cardIndex) ;

	return isOK;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetZeroOffset(unsigned long cardIndex, int *pOffset)
{
	RQ_AnalogueInputRange inputRange;
	NDTS_Boolean isOK = NDTS_BTrue ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetAnalogueInputRange(cardIndex, &inputRange);
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	*pOffset = pBoardState->zeroTweak[inputRange];

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue;
}

pfnLoggingCallback pfnLog = 0;

RQ_API void CALL_CONV RQ_SetLoggingCallback(pfnLoggingCallback pfn)
{
	pfnLog = pfn;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetTrailingFlankHoldoff(unsigned long cardIndex, unsigned long holdoff)
{
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	// write the holdoff value
	//isOK = RQ_SetPeripheralRegister(cardIndex, RQ_TRAILING_FLANK_HOLDOFF, (holdoff & 0x7f)) ;
	isOK = RQ_SetSamplingRegister(cardIndex, RQ_TRAILING_FLANK_HOLDOFF, holdoff) ;

	RQ_Unlock(cardIndex) ;

	return isOK;
}


RQ_API NDTS_Boolean CALL_CONV RQ_SetSequenceStep(unsigned long cardIndex, unsigned long step)
{
	NDTS_Boolean isOK ;

	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	//NDTS_LogLine(NDTS_LLDebug,"SetSequenceStep %d", step);
	if (!pBoardState->isSequence)
	{
		RQ_HandleRQError(RQ_SetSeqenceStep_NotSequenceCompatibleFirmware) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse;
	}

	if (step >= NDTS_MAXIMUM_NUMBER_OF_STEPS)
	{
		RQ_HandleRQError(RQ_SetSeqenceStep_StepGreaterThanMax) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse;
	}

	pBoardState->currentSequenceStep = step;

	// set number of steps
	isOK = RQ_SetSamplingRegister(cardIndex, RQ_SAMPLING_SEQUENCE_STEP_NUMBER, step) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_PERIPHERAL_SEQUENCE_STEP_NUMBER, step) ;
	
	RQ_Unlock(cardIndex) ;
	
	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetSequenceStep(unsigned long cardIndex, unsigned long *pStep) 
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if (!pBoardState->isSequence)
	{
		RQ_HandleRQError(RQ_GetSeqenceStep_NotSequenceCompatibleFirmware) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse;
	}

	isOK = RQ_GetPeripheralRegister(cardIndex, RQ_PERIPHERAL_SEQUENCE_STEP_NUMBER, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse;
	}

	*pStep = value & 0x1f;

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue;
}

// If increasing the number of sequence steps, ensure the settings for the new steps are set correctly immediately 
// after this is called.  The main settings that can cause problems are RQ_SetNumberOfSamples and RQ_SetStartDelay
// The HLSDK fills in appropriate default values.
RQ_API NDTS_Boolean CALL_CONV RQ_SetStepsInSequence(unsigned long cardIndex, unsigned long steps)
{
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if (!pBoardState->isSequence)
	{
		RQ_Unlock(cardIndex) ;
		RQ_HandleRQError(RQ_SetStepsInSequence_NotSequenceCompatibleFirmware) ;
		return NDTS_BFalse;
	}

	if (steps < 1 || steps > NDTS_MAXIMUM_NUMBER_OF_STEPS)
	{
		RQ_HandleRQError(RQ_SetStepsInSequence_StepOutOfRange) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse;
	}

	// note that we're running in sequence mode, so the RAM check isn't relevant
	// and the high-level API (HLPRX) should be used where appropriate

	// This determines the numbers that are attached to the ASCANs
	isOK = RQ_SetSamplingRegister(cardIndex, RQ_SAMPLING_SEQUENCE_CONTROL, steps - 1);
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	pBoardState->numberOfAScansPerBScan = steps;

	// don't need to worry about oversamples here - RQ_SetNumberOfAScansPerBScan factors it in
	isOK = RQ_SetNumberOfAScansPerBScan(cardIndex, steps);
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_PERIPHERAL_SEQUENCE_CONTROL, steps - 1);
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	RQ_UpdateSampleParameters(cardIndex);
	
	RQ_Unlock(cardIndex) ;
	return NDTS_BTrue ;

}

RQ_API NDTS_Boolean CALL_CONV RQ_GetStepsInSequence(unsigned long cardIndex, unsigned long *pSteps)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if (!pBoardState->isSequence)
	{
		RQ_HandleRQError(RQ_GetStepsInSequence_NotSequenceCompatibleFirmware) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse;
	}

	isOK = RQ_GetPeripheralRegister(cardIndex, RQ_PERIPHERAL_SEQUENCE_CONTROL, &value) ;

	*pSteps = (value & 0x1f) + 1;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_StartSequence(unsigned long cardIndex)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if (!pBoardState->isSequence)
	{
		RQ_HandleRQError(RQ_StartSequence_NotSequenceCompatibleFirmware) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse;
	}

	isOK = RQ_GetPeripheralRegister(cardIndex, RQ_PERIPHERAL_SEQUENCE_CONTROL, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	// set the start sequence bit
	value |= 0x80000000;

	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_PERIPHERAL_SEQUENCE_CONTROL, value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	
	pBoardState->sequenceState = RQ_SSRunning;
	RQ_Unlock(cardIndex) ;
	return NDTS_BTrue;
}

RQ_API NDTS_Boolean CALL_CONV RQ_StopSequence(unsigned long cardIndex)
{
	unsigned long value, loops ;
	NDTS_Boolean isSequenceRunning;
	LARGE_INTEGER freqLarge, countLargeA, countLargeB ;
	NDTS_Boolean isOK ;
	float timeInLoop;

	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if (!pBoardState->isSequence)
	{
		RQ_HandleRQError(RQ_StopSequence_NotSequenceCompatibleFirmware) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse;
	}

	isOK = RQ_GetPeripheralRegister(cardIndex, RQ_PERIPHERAL_SEQUENCE_CONTROL, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse;
	}
	// clear the start sequence bit
	value &= ~0x80000000;
	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_PERIPHERAL_SEQUENCE_CONTROL, value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse;
	}

	// Wait for any currently executing sequence to stop
	// If we get a timeout, exit and return true anyway because the sequence has been stopped but the firmware
	// has failed to acknowledge this.
	QueryPerformanceCounter(&countLargeA) ;
	QueryPerformanceFrequency(&freqLarge) ;
	loops = 0;
	do
	{
		if (!RQ_GetPeripheralRegister(cardIndex, RQ_PERIPHERAL_SEQUENCE_CONTROL, &value))
			return NDTS_BFalse;
		isSequenceRunning = ((value & 0x40000000) == 0) ? NDTS_BFalse : NDTS_BTrue;
		QueryPerformanceCounter(&countLargeB) ;
		timeInLoop = (float) (countLargeB.QuadPart - countLargeA.QuadPart) / (float) freqLarge.QuadPart ;
		loops++;
	}
	while (isSequenceRunning && timeInLoop < 1.0);
	//filelogt("rq.c Stopping sequence time %f loops %d\n", timeInLoop, loops);
	pBoardState->sequenceState = RQ_SSStopped;
	RQ_Unlock(cardIndex) ;
	return NDTS_BTrue;
}
 

RQ_API NDTS_Boolean CALL_CONV RQ_SetFlipArray(unsigned long cardIndex, unsigned short numberOfElementsForFlipping)
{
	unsigned short elementsToWrite, i ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	if (numberOfElementsForFlipping > RQ_PINGPONG_ARRAY_SIZE) 
	{
		RQ_HandleRQError(RQ_SetFlipArray_InvalidNumberOfElements) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	pBoardState->numberOfElementsForFlipping = numberOfElementsForFlipping ;

	elementsToWrite = (numberOfElementsForFlipping == 0) ? RQ_PINGPONG_SEQUENCE_LENGTH : numberOfElementsForFlipping ;
	for (i = 0 ; i < elementsToWrite ; i++)
	{
		// SetPingPongElementsRegister applies the flipping so all we do is re-write the ping pong table
		RQ_SetPingPongElementRegister(cardIndex, i, pBoardState->pPingPongSequence[i]) ;
	}

	RQ_Unlock(cardIndex) ;
	return NDTS_BTrue ;
}



/*
	This function allows the TCG curve to be set together with the input range.  -40 and -20dB attenuators 
	are available together with a +20dB amplifier.  These are switched in and out automatically to use the
	highest available gain, giving the best resolution for the TCG.
	I am assuming that the gain control is logarithmic, like the DI unit.  The range is nominally -30 to 
	+110dB, so the range is 10 to 90dB without the attenuators, corresponding to a count from 0 to 255.  
	Thus we have a resolution of 0.3dB.  For simplicity we shall expect a TCG table with 0.1dB per count
	and convert this as required.

	There's that whole thing about decimating the TCG table, but with
	relatively few channels (steps) this may not be necessary in most cases.
	Code to take care of this exists in RS2.  At present it is the responsibility
	of the caller to build the entire TCG table.
	NB this needs to be padded to whatever power-of-two size per channel
	based on the longest range.  Some helper functions would be useful.
*/
RQ_API void CALL_CONV RQ_SetGainTweaks(unsigned long cardIndex, short plus20, short minus20, short minus40)
{
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;

	pBoardState->tweakPlus20 = plus20;
	pBoardState->tweakMinus20 = minus20;
	pBoardState->tweakMinus40 = minus40;
}

RQ_API NDTS_Boolean CALL_CONV RQ_PrepareForSingleShotMode(unsigned long cardIndex)
{
	cardIndex++; //keep compiler happy
	return NDTS_BTrue;
	// Single shot mode doesn't work at the moment.
	// Switching to encoder triggering stop the free running mode and no samples are generated, causing lockup
	/*
	// Jonathan says:
	// stop the sequence
	// select trigger-by-encoder with encoder 6 or 7

	unsigned long value ;
	NDTS_Boolean isOK ;

	if (cardIndex >= globalState.pciState.numberOfRapiDAQBoards) return NDTS_BFalse;

	RQ_StopSequence(cardIndex);

	RQ_Lock(cardIndex) ;

	isOK = RQ_SetTriggerSelect(cardIndex, RQ_TEncoder) ;

	value = pBoardState->rqBscanTriggerControlShadow;
	//isOK = RQ_GetPeripheralRegister(cardIndex, RQ_BSCAN_TRIGGER_CONTROL, &value) ;
	//if (!isOK)
	//{
	//	RQ_Unlock(cardIndex) ;
	//	return NDTS_BFalse ;
	//}

	value &= 0x7ff8ffff ;
	value |= 0x00000007 << 16 ;
	
	Bug 947 - if this code is ever used it will probably be OK because bug 947 only applies to non sequenced firmware

	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_BSCAN_TRIGGER_CONTROL, value) ;
	pBoardState->rqBscanTriggerControlShadow = value;

	RQ_StartSequence(cardIndex);

	RQ_Unlock(cardIndex) ;

	return isOK ;
	*/
}

RQ_API NDTS_Boolean CALL_CONV RQ_SingleShotCapture(unsigned long cardIndex)
{
	cardIndex++; // keep compiler happy
	return NDTS_BTrue;
	// Single shot mode doesn't work
	/*
	unsigned long value;
	NDTS_Boolean isOK ;
	if (cardIndex >= globalState.pciState.numberOfRapiDAQBoards) return NDTS_BFalse;

	// force trigger by setting trigger control bit 31 = 1
	value = pBoardState->rqBscanTriggerControlShadow;
	//isOK = RQ_GetPeripheralRegister(cardIndex, RQ_BSCAN_TRIGGER_CONTROL, &value);
	//if (isOK != NDTS_BTrue)
	//{
	//	return isOK;
	//}

	value |= 0x80000000;
	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_BSCAN_TRIGGER_CONTROL, value);
		Bug 947 - if this code is ever used it will probably be OK because bug 947 only applies to non sequenced firmware
	pBoardState->rqBscanTriggerControlShadow = value;
	return isOK;
	*/
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetDigitalOutput(unsigned long cardIndex, unsigned long bit, NDTS_Boolean isOn)
{
	unsigned long value;
	NDTS_Boolean isOK;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	if (bit < 28 || bit > 31)
	{
		RQ_HandleRQError(RQ_SetDigitalOutput_InvalidBit);
		return NDTS_BFalse;
	}

	RQ_Lock(cardIndex);

	isOK = RQ_GetPeripheralRegister(cardIndex, RQ_PERIPHERAL_DDR_0, &value);
	if (!isOK)
	{
		RQ_Unlock(cardIndex);
		return NDTS_BFalse;
	}

	value |= 1 << bit;

	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_PERIPHERAL_DDR_0, value);
	if (!isOK)
	{
		RQ_Unlock(cardIndex);
		return NDTS_BFalse;
	}

	isOK = RQ_GetPeripheralRegister(cardIndex, RQ_PERIPHERAL_IO_BANK_0, &value);
	if (!isOK)
	{
		RQ_Unlock(cardIndex);
		return NDTS_BFalse;
	}

	if (isOn)
		value |= 1 << bit;
	else
		value &= ~(1 << bit);

	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_PERIPHERAL_IO_BANK_0, value);
	if (!isOK)
	{
		RQ_Unlock(cardIndex);
		return NDTS_BFalse;
	}

	RQ_Unlock(cardIndex);
	return NDTS_BTrue;
}



/////////////////////////////////////////////
// numberToCheckEitherSide is the number of scans to check either side of the current one. 
// E.g. numberToCheckEitherSide = 2 checks two samples before, current sample and two after, giving a 
// total window size of 5 samples.
// Set to zero to disable noise filtering
// proportionToTriggerOff is the proportion of the largest value that the other values in the window must
// be in order to be a valid sample rather than noise.  For example, 0.8 means that all the values in the 
// window must be within 80% of the max value.
RQ_API void CALL_CONV RQ_SetSampleNoiseFilter(unsigned long cardIndex, 	unsigned long numberToCheckEitherSide, float proportionToTriggerOff)
{
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;

	RQ_Lock(cardIndex);
	pBoardState->numberToCheckEitherSide = numberToCheckEitherSide;
	pBoardState->proportionToTriggerOff = proportionToTriggerOff ;
	RQ_UpdateSampleParameters(cardIndex) ;  // These values are part of a raw scan.  The SFD raw scan used for snapshots needs to be updated.
	RQ_Unlock(cardIndex);
}

RQ_API NDTS_Boolean CALL_CONV RQ_GetNumberOfOversamples(unsigned long cardIndex, unsigned long *pOversamplingMultiplier)
{
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex);
	*pOversamplingMultiplier = pBoardState->oversampleCountThisStep[pBoardState->isSequence ? pBoardState->currentSequenceStep : 0];
	RQ_Unlock(cardIndex);
	return NDTS_BTrue;
}


RQ_API NDTS_Boolean CALL_CONV RQ_GetDiagnosticsString(unsigned long cardIndex, char **ppString, unsigned long diagIndex)
{
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	*ppString = pBoardStates[cardIndex].ppDiagnosticStrings[diagIndex];

	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}



RQ_API NDTS_Boolean CALL_CONV RQ_SetNumberOfBScansPerBankIsAutomatic(unsigned long cardIndex, NDTS_Boolean isAutomatic) 
{
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) 
		return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;
	pBoardState->isAutomaticBScansPerBank = isAutomatic ;
	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue;
}

RQ_API NDTS_Boolean CALL_CONV RQ_ResetFirmware(unsigned long cardIndex) 
{
	// Reset sampling logic in firmware by writing to register SRAM Control - Number of Scans
	unsigned long value ;
	NDTS_Boolean isOK ;

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetSamplingRegister(cardIndex, RQ_NUMBER_OF_SCANS, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	isOK = RQ_SetSamplingRegister(cardIndex, RQ_NUMBER_OF_SCANS, 0) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	
	Sleep(100) ;

	isOK = RQ_SetSamplingRegister(cardIndex, RQ_NUMBER_OF_SCANS, value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	RQ_Unlock(cardIndex) ;

	return NDTS_BTrue ;
}
	
// Wrappers for the NDTS_ error logging functions that are common to all four SDK's
RQ_API RQ_ReturnCode RQ_GetLastError()
{
	return NDTS_GetLastError() ;
}

RQ_API unsigned long RQ_ReturnNumberOfErrorLogLines()
{
	return NDTS_ReturnNumberOfErrorLogLines() ;
}

NDTS_Boolean RQ_GetErrorLogLine(unsigned long lineNumber, char *pMessageBuffer, unsigned long numberOfBytesInMessageBuffer)
{
	return NDTS_GetErrorLogLine(lineNumber, pMessageBuffer, numberOfBytesInMessageBuffer) ;
}

RQ_API NDTS_Boolean RQ_ClearErrorLog() 
{
	return NDTS_ClearErrorLog() ;
}



RQ_API NDTS_Boolean CALL_CONV RQ_ConnectEncoderCounters4And5ToIO(unsigned long cardIndex, NDTS_Boolean useDIO)
{
	NDTS_Boolean isOK ;
	unsigned long value ;

	RQ_State *pBoardState ;
	pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;

	if (pBoardState == NULL)
	{
		return NDTS_BFalse; 
	}

	RQ_Lock(cardIndex) ;

	// Set the appropriate bit in the firmware

	value = pBoardState->rqBscanTriggerControlShadow;
	value &= 0xefffffff ;
	value |= (unsigned long) (useDIO == NDTS_BTrue) << 28 ;

	isOK = RQ_SetPeripheralRegister(cardIndex, RQ_BSCAN_TRIGGER_CONTROL, value) ;
	pBoardState->rqBscanTriggerControlShadow = value;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	// Bug 947 - the bottom 28 bits are shared between encoder trigger settings and B Scan rep rate
	// If we are currently free running, the B Scan rep rate will have got corrupted by the encoder settings in rqBscanTriggerControlShadow so restore it.
	if (pBoardState->currentTriggerMode == RQ_TFreeRunning)
	{
		RQ_SetBScanRepetitionRate(cardIndex, pBoardState->bScanRepetitionRate); 
	}


	if (useDIO == NDTS_BTrue)
	{
		// Set DDR as input for DIO bits 6 and 7.  0 is input
		isOK = RQ_GetPeripheralDDR0(cardIndex, &value) ;
		if (!isOK)
		{
			RQ_Unlock(cardIndex) ;
			return NDTS_BFalse ;
		}

		value &= 0xffffff3f ;

		isOK = RQ_SetPeripheralDDR0(cardIndex, value) ;
		if (!isOK)
		{
			RQ_Unlock(cardIndex) ;
			return NDTS_BFalse ;
		}
	}
	RQ_Unlock(cardIndex) ;
	return NDTS_BTrue ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_RewriteGates(unsigned long cardIndex, 	
											  unsigned long oldNumberOfOversamples, 	
											  unsigned long newNumberOfOversamples)
{
	unsigned long gateIndex, stepIndex;
	NDTS_Boolean ret = NDTS_BTrue;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	for (gateIndex = 0; gateIndex < RQ_ReturnMaximumNumberOfGates(pBoardState->isSequence); gateIndex++)
	{
		// Start and stop counts of the gates take oversampling into account as if it were a higher sample frequency
		// the start and stop values are adjusted to maintain the gate's position on the waveform
		for (stepIndex = 0; stepIndex < NDTS_MAXIMUM_NUMBER_OF_STEPS; stepIndex++)
		{
			RQ_Gate *pGate = &pBoardState->gates[stepIndex][gateIndex];
			pGate->startCount = (pGate->startCount * newNumberOfOversamples) / oldNumberOfOversamples;
			pGate->stopCount  = (pGate->stopCount  * newNumberOfOversamples) / oldNumberOfOversamples;
		}
		ret &= RQ_RawWriteGates(cardIndex, gateIndex);
	}

	return ret;
}
RQ_API NDTS_Boolean CALL_CONV RQ_GetHLPRXFirmwareRevisions(unsigned long *dsp, unsigned long *per)
{
	*dsp = RQ_GetDefaultValueInt(RQdef_DSPversion);
	*per = RQ_GetDefaultValueInt(RQdef_PERversion);
	return NDTS_BTrue;
}
RQ_API NDTS_Boolean CALL_CONV RQ_GetRS2AFirmwareRevisions(unsigned long *dsp, unsigned long *per)
{
	*dsp = RQ_DEFAULT_DSP_REV;
	*per = RQ_DEFAULT_PER_REV;
	return NDTS_BTrue;
}



RQ_API unsigned long RQ_ReturnMaximumNumberOfGates(NDTS_Boolean isSequence)
{
	return isSequence ? RQ_MAXIMUM_NUMBER_OF_GATES_SEQUENCED : RQ_MAXIMUM_NUMBER_OF_GATES_NON_SEQUENCED ;
}

/* Doesn't seem to be used anywhere and should be moved to memory factory if required
RQ_API NDTS_Boolean RQ_GetMemoryBlockSize(void *pData, int *pSize)
{
	int result = 0;

	// Preconditions.
	_ASSERTE(pData) ;pData;

#ifdef RQ_USE_BLOCK_PREAMBLE
	result = (*((int *)pData - 1));
#endif

	*pSize = result;

	return NDTS_BTrue;
}
*/

RQ_API NDTS_Boolean CALL_CONV RQ_GetOutOfRangeAccessCount(unsigned long cardIndex, unsigned long *pAccessCount)
{
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	isOK = RQ_GetSystemRegister(cardIndex, RQ_OUT_OF_RANGE_ACCESS_COUNT_REGISTER, pAccessCount) ;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}



RQ_API NDTS_Boolean CALL_CONV RQ_ClearOutOfRangeAccessCount(unsigned long cardIndex)
{
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	// This register is write only and is not shadowed.
	// The only current side effect of this is that the RQ_SetOnlyRespondToInRangeAccess bit is cleared
	// This is a benefit as it makes the card safe to use and also there is no point counting the accesses
	// if the card is going to lock up on the first out of range access
	isOK = RQ_SetSystemRegister(cardIndex, RQ_SYSTEM_COMMAND_REGISTER, (1 << 9)) ;

	RQ_Unlock(cardIndex) ;

	return isOK ;
}


RQ_API NDTS_Boolean CALL_CONV RQ_SetTestPatternMode(unsigned long cardIndex, NDTS_Boolean isTestPatternEnabled)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	// The test pattern was added at the same time as sign and magnitude A Scan encoding
	if (!pBoardState->isFirmwareSignAndMagCapable)				
	{
		RQ_HandleRQError(RQ_Initialise_FirmwareVersionTooOld) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	isOK = RQ_GetSamplingRegister(cardIndex, RQ_SRAM_CONTROL_SAMPLE_CONTROL, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	value &= 0xffbfffff ;
	value |= isTestPatternEnabled << 22 ;

	isOK = RQ_SetSamplingRegister(cardIndex, RQ_SRAM_CONTROL_SAMPLE_CONTROL, value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

RQ_API NDTS_Boolean CALL_CONV RQ_SetSignAndMagnitudeMode(unsigned long cardIndex, NDTS_Boolean isSignMagEnabled)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState) return NDTS_BFalse; 

	RQ_Lock(cardIndex) ;

	// The test pattern was added at the same time as sign and magnitude A Scan encoding
	if (!pBoardState->isFirmwareSignAndMagCapable)				
	{
		RQ_HandleRQError(RQ_Initialise_FirmwareVersionTooOld) ;
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	pBoardState->isSignAndMag = isSignMagEnabled;

	isOK = RQ_GetSamplingRegister(cardIndex, RQ_SRAM_CONTROL_SAMPLE_CONTROL, &value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	value &= 0xff7fffff ;
	value |= isSignMagEnabled << 23 ;

	isOK = RQ_SetSamplingRegister(cardIndex, RQ_SRAM_CONTROL_SAMPLE_CONTROL, value) ;
	if (!isOK)
	{
		RQ_Unlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	RQ_Unlock(cardIndex) ;

	return isOK ;
}

NDTS_Boolean RQ_DataFullRecovery(unsigned long cardIndex)
{
	int i;
	static int doSpecialRecovery = 0;
	unsigned long repRate = 0;
	NDTS_Boolean isOk;

	if (doSpecialRecovery)
	{
		for(i=0;i<10;i++)
		{
			Sleep(10);
			RQ_ResetFirmware(cardIndex);
			Sleep(10);
		}
	}

	// On a data full, need to read both banks of memory.  
	// Send bank read signal twice to the firmware, will replace the sleeps with DMA data reads when it is all working.
	// Sept 06 - set rep rate slow  whilst resetting so free running does not fill again during the reset.
	// Max period is 131072 so set slow rate to 200Hz
	//Adjusted sleeps from 100 to 10.

	// Also call RQ_ResetFirmware after the two downloads to ensure the firmware is fully reset
	isOk = RQ_GetRepetitionRate(cardIndex, &repRate) ;
	_ASSERTE(isOk); isOk;
	isOk = RQ_SetRepetitionRate(cardIndex, 200) ;
	_ASSERTE(isOk); isOk;

	Sleep(10);
	isOk = DC_IndicateSampleDataDownloaded(cardIndex) ;
	_ASSERTE(isOk); isOk;
	Sleep(10);
	isOk = DC_IndicateSampleDataDownloaded(cardIndex) ;
	_ASSERTE(isOk); isOk;
	isOk = RQ_ResetFirmware(cardIndex);
	_ASSERTE(isOk); isOk;
	isOk = RQ_SetRepetitionRate(cardIndex, repRate) ;
	_ASSERTE(isOk); isOk;
	return NDTS_BTrue;
}

unsigned long RQ_ReturnOversampleCountThisStep(unsigned long cardIndex, unsigned long aScanIndex)
{
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState)
		return 0;
	
	return pBoardState->oversampleCountThisStep[pBoardState->isSequence ? aScanIndex : 0];
}

unsigned long RQ_ReturnAScanSampleValuesThisStep(unsigned long cardIndex, unsigned long aScanIndex)
{
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState)
		return 0;
	
	return  pBoardState->aScanSampleValuesThisStep[aScanIndex];
}

unsigned long RQ_ReturnGateOffsetThisStep(unsigned long cardIndex, unsigned long aScanIndex)
{
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState)
		return 0;
	
	return pBoardState->gateOffsetThisStep[aScanIndex];
}

unsigned long RQ_ReturnGateBytesPerBScan(unsigned long cardIndex)
{
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState)
		return 0;
	
	return pBoardState->gateBytesPerBScan;
}

unsigned long RQ_ReturnAScanOffsetThisStep(unsigned long cardIndex, unsigned long aScanIndex)
{
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState)
		return 0;
	
	return  pBoardState->aScanOffsetThisStep[aScanIndex];
}

unsigned long RQ_ReturnAScanBytesPerBScan(unsigned long cardIndex)
{
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState)
		return 0;
	
	return pBoardState->aScanBytesPerBScan;
}


NDTS_SnapshotDataSelection RQ_ReturnSnapshotSelectionForGate(unsigned long cardIndex, unsigned long step, unsigned long gate)
{
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState)
		return 0;
	
	return pBoardState->gates[step][gate].snapshotSelection;
}

NDTS_Boolean RQ_ReturnIsSignAndMag(unsigned long cardIndex)
{
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pBoardState)
		return 0;
	
	return pBoardState->isSignAndMag;
}

