#include <crtdbg.h>
#include "DataSamplingStatusInternal.h"
#include "ThreadInternal.h"
#include "NDTSCommonHal.h"
#include "DataCollectionErrorInternal.h"

NDTS_Boolean CALL_CONV DC_SetSamplingRegister(unsigned long cardIndex, unsigned long value)
{
	DC_AssociatedSDK *pSdk = &(DC_ReturnThreadStatePointer(cardIndex)->associatedSDK) ;

	unsigned long addr = pSdk->addressOfDataSamplingStatusRegister;
	unsigned long sid = pSdk->SID;
	if (!pSdk->isRealHardwareFound)
	{
		return NDTS_BTrue;
	}

	return NDTS_HAL_SetWord(sid, cardIndex, addr, value) ;
}



DC_API NDTS_Boolean CALL_CONV DC_IndicateSampleDataDownloaded(unsigned long cardIndex)
{
	unsigned long value;

	// Always read the sample status register by calling DC_GetDataSamplingStatus() to preserve the clear on read bits
	DC_GetDataSamplingStatus(cardIndex, &value) ;

	return DC_SetSamplingRegister(cardIndex, value | 0x01) ;
}


DC_API NDTS_Boolean CALL_CONV DC_GetDataSamplingStatus(unsigned long cardIndex, unsigned long *pValue)
{
	DC_State *pThreadState = DC_ReturnThreadStatePointer(cardIndex) ;
	DC_AssociatedSDK *pSdk = &(pThreadState->associatedSDK);

	_ASSERTE(pValue) ;

	if (!pSdk->isRealHardwareFound)
	{
		*pValue = 0x03; // Data available
		return NDTS_BTrue;
	}


	pSdk->fpLock(cardIndex);

	if(NDTS_HAL_GetWord(pSdk->SID, cardIndex, pSdk->addressOfDataSamplingStatusRegister, pValue) == NDTS_BFalse)
	{
		pSdk->fpUnlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	// New triggered occured.
	if(*pValue & 0x04)
		pThreadState->dataSamplingStatus |= 0x04 ;

	// Delayed trigger occured.
	if(*pValue & 0x08)
	{
		OutputDebugString("Delayed trigger occured\n") ;
		pThreadState->dataSamplingStatus |= 0x08 ;
	}

	// Data full error.
	if(*pValue & 0x10)
	{
		OutputDebugString("Data full error\n") ;
		pThreadState->dataSamplingStatus |= 0x10 ;
	}

	pSdk->fpUnlock(cardIndex) ;

	return NDTS_BTrue ;
}

DC_API NDTS_Boolean CALL_CONV DC_SetDataSamplingStatus(unsigned long cardIndex, unsigned long value)
{
	DC_AssociatedSDK *pSdk = &(DC_ReturnThreadStatePointer(cardIndex)->associatedSDK) ;
	if (!pSdk->isRealHardwareFound)
	{
		return NDTS_BTrue;
	}
	pSdk->fpLock(cardIndex);

	if(DC_SetSamplingRegister(cardIndex, value) == NDTS_BFalse)
	{
		pSdk->fpUnlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	pSdk->fpUnlock(cardIndex) ;

	return NDTS_BTrue ;
}



DC_API NDTS_Boolean CALL_CONV DC_ClearDataSamplingStatusFlags(unsigned long cardIndex)
{
	DC_State *pThreadState = DC_ReturnThreadStatePointer(cardIndex) ;
	DC_AssociatedSDK *pSdk = &(pThreadState->associatedSDK) ;
	if (!pSdk->isRealHardwareFound)
	{
		return NDTS_BTrue;
	}
	pSdk->fpLock(cardIndex);

	pThreadState->dataSamplingStatus = 0 ;
	
	pSdk->fpUnlock(cardIndex) ;

	return NDTS_BTrue ;
}

NDTS_Boolean CALL_CONV DC_ReturnDataSamplingStatusFlagSet(unsigned long cardIndex, unsigned long mask)
{
	DC_State *pThreadState = DC_ReturnThreadStatePointer(cardIndex) ;

	NDTS_Boolean result ;
	
	result = (pThreadState->dataSamplingStatus & mask) ? NDTS_BTrue : NDTS_BFalse ;

	// Clear the flag now we have explicly read it.
	pThreadState->dataSamplingStatus = pThreadState->dataSamplingStatus & ~mask ;

	return result ;
}

DC_API NDTS_Boolean CALL_CONV DC_GetNewTriggerOccured(unsigned long cardIndex, NDTS_Boolean *pValue)
{
	unsigned long tmp ;
	DC_State *pThreadState = DC_ReturnThreadStatePointer(cardIndex) ;
	DC_AssociatedSDK *pSdk = &(pThreadState->associatedSDK) ;
	_ASSERTE(pValue) ;

	pSdk->fpLock(cardIndex);

	if(DC_GetDataSamplingStatus(cardIndex, &tmp) == NDTS_BFalse)
	{
		pSdk->fpUnlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	*pValue = DC_ReturnDataSamplingStatusFlagSet(cardIndex, 0x04) ;

	pSdk->fpUnlock(cardIndex) ;

	return NDTS_BTrue ;
}

DC_API NDTS_Boolean CALL_CONV DC_GetDelayedTriggerOccured(unsigned long cardIndex, NDTS_Boolean *pValue)
{
	unsigned long tmp ;
	DC_State *pThreadState = DC_ReturnThreadStatePointer(cardIndex) ;
	DC_AssociatedSDK *pSdk = &(pThreadState->associatedSDK) ;
	_ASSERTE(pValue) ;

	pSdk->fpLock(cardIndex);

	if(DC_GetDataSamplingStatus(cardIndex, &tmp) == NDTS_BFalse)
	{
		pSdk->fpUnlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	*pValue = DC_ReturnDataSamplingStatusFlagSet(cardIndex, 0x08) ;

	pSdk->fpUnlock(cardIndex) ;

	return NDTS_BTrue ;
}

DC_API NDTS_Boolean CALL_CONV DC_GetDataFullError(unsigned long cardIndex, NDTS_Boolean *pValue)
{
	unsigned long tmp ;
	DC_State *pThreadState = DC_ReturnThreadStatePointer(cardIndex) ;
	DC_AssociatedSDK *pSdk = &(pThreadState->associatedSDK) ;
	_ASSERTE(pValue) ;

	pSdk->fpLock(cardIndex);

	if(DC_GetDataSamplingStatus(cardIndex, &tmp) == NDTS_BFalse)
	{
		pSdk->fpUnlock(cardIndex) ;
		return NDTS_BFalse ;
	}

	*pValue = DC_ReturnDataSamplingStatusFlagSet(cardIndex, 0x10) ;

	pSdk->fpUnlock(cardIndex) ;

	return NDTS_BTrue ;
}




DC_API NDTS_Boolean CALL_CONV DC_GetIsSampleDataAvailable(unsigned long cardIndex, NDTS_Boolean *isAvailable)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	DC_State *pThreadState = DC_ReturnThreadStatePointer(cardIndex) ;
	DC_AssociatedSDK *pSdk = &(pThreadState->associatedSDK) ;

	pSdk->fpLock(cardIndex) ;

	isOK = DC_GetDataSamplingStatus(cardIndex, &value) ;
	if (!isOK)
	{
		pSdk->fpUnlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	
	*isAvailable = (value & 0x00000001) == 0x00000001 ? NDTS_BTrue : NDTS_BFalse ;

	pSdk->fpUnlock(cardIndex) ;

	return NDTS_BTrue ;
}

DC_API NDTS_Boolean CALL_CONV DC_GetIsSomeDataSampled(unsigned long cardIndex, NDTS_Boolean *pSomeDataSampled)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	DC_State *pThreadState = DC_ReturnThreadStatePointer(cardIndex) ;
	DC_AssociatedSDK *pSdk = &(pThreadState->associatedSDK) ;

	if (!pSdk->isRealHardwareFound)
	{
		*pSomeDataSampled = NDTS_BTrue;
		return NDTS_BTrue;
	}
	pSdk->fpLock(cardIndex) ;

	isOK = DC_GetDataSamplingStatus(cardIndex, &value) ;
	if (!isOK)
	{
		pSdk->fpUnlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	
	*pSomeDataSampled = (value & 0x00000002) == 0x00000002 ? NDTS_BTrue : NDTS_BFalse ;

	pSdk->fpUnlock(cardIndex) ;

	return NDTS_BTrue ;
}

DC_API NDTS_Boolean CALL_CONV DC_SetRequestEarlySampleData(unsigned long cardIndex)
{
	NDTS_Boolean isOK;
	DC_State *pThreadState = DC_ReturnThreadStatePointer(cardIndex) ;
	DC_AssociatedSDK *pSdk = &(pThreadState->associatedSDK) ;
	unsigned long value ;

	if (!pSdk->isRealHardwareFound)
	{
		return NDTS_BTrue;
	}
	pSdk->fpLock(cardIndex) ;

	isOK = DC_GetDataSamplingStatus(cardIndex, &value) ;
	if(isOK)
	{
		// Don't do a bank swap if the read bank is empty or is full (and the firmware has already swapped banks).
		// Also don't do if data full
		if(((value & 0x01) == 0x00) && ((value & 0x02) == 0x02) && ((value & 0x10) == 0x00))
		{
			// Also check we don't have a data full error.
			isOK = DC_SetSamplingRegister(cardIndex, value | 0x02) ;
		}
		else
		{
			if ((value & 0x10) == 0x10) 
				DC_HandleError(DC_SetRequestEarlySampleData_DataFullError) ;
			else if ((value & 0x01) == 01) 
				DC_HandleError(DC_SetRequestEarlySampleData_OneBankAlreadyFull) ;
			else
				DC_HandleError(DC_SetRequestEarlySampleData_NoEarlySampleData) ;

			pSdk->fpUnlock(cardIndex) ;
			return NDTS_BFalse;
		}
	}

	pSdk->fpUnlock(cardIndex) ;

	return isOK ;
}

// The sequence compatible threading code had an unsafe version of DC_GetSamplingStatus.  It has been removed during the merge
// as the threading code is not complete.  Look at the head of the SFD15 branch to see what it did.
DC_API NDTS_Boolean CALL_CONV DC_GetSamplingStatus(unsigned long cardIndex, 
	NDTS_Boolean *pIsDataAvailable, 
	NDTS_Boolean *pSomeDataSampled, 
	NDTS_Boolean *pNewTriggerOccured,
	NDTS_Boolean *pTriggerOccurredBeforeProcessComplete, 
	NDTS_Boolean *pDataFullError)
{
	unsigned long value ;
	NDTS_Boolean isOK ;
	NDTS_Boolean isFlagSet ;
	DC_State *pThreadState = DC_ReturnThreadStatePointer(cardIndex) ;
	DC_AssociatedSDK *pSdk = &(pThreadState->associatedSDK) ;

	pSdk->fpLock(cardIndex) ;

	isOK = DC_GetDataSamplingStatus(cardIndex, &value) ;
	if (!isOK)
	{
		pSdk->fpUnlock(cardIndex) ;
		return NDTS_BFalse ;
	}
	
	if (pIsDataAvailable != 0)
		*pIsDataAvailable = (value & 0x01) ? NDTS_BTrue : NDTS_BFalse ;

	if (pSomeDataSampled != 0)
		*pSomeDataSampled = (value & 0x02) ? NDTS_BTrue : NDTS_BFalse ;

	if (pNewTriggerOccured != 0)
	{
		isOK = DC_GetNewTriggerOccured(cardIndex, &isFlagSet) ;
		if (!isOK)
		{
			pSdk->fpUnlock(cardIndex) ;
			return NDTS_BFalse ;
		}

		*pNewTriggerOccured = isFlagSet ;
	}

	if (pTriggerOccurredBeforeProcessComplete != 0)
	{
		isOK = DC_GetDelayedTriggerOccured(cardIndex, &isFlagSet) ;
		if (!isOK)
		{
			pSdk->fpUnlock(cardIndex) ;
			return NDTS_BFalse ;
		}

		*pTriggerOccurredBeforeProcessComplete = isFlagSet ;
	}

	if (pDataFullError != 0)
	{
		isOK = DC_GetDataFullError(cardIndex, &isFlagSet) ;
		if (!isOK)
		{
			pSdk->fpUnlock(cardIndex) ;
			return NDTS_BFalse ;
		}

		*pDataFullError = isFlagSet ;
	}

	pSdk->fpUnlock(cardIndex) ;

	return NDTS_BTrue ;
}

