#include <windows.h>
#include <stdio.h>
#include <io.h>
#include <limits.h>
#include <crtdbg.h>
#include <assert.h>
#include "RawScanOfflineInternal.h"
#include "RawScanProtected.h"
#include "RawScanInternal.h"
#include "RawScan.h"


const short untriggeredAmpGateReturnValue = 0;
const short untriggeredDepthGateReturnValue = 0;

void CALL_CONV RawScan_BuildNoiseArray(NDTS_RawScan *pRawScan, unsigned long channelIndex, unsigned long gateIndex)
{
#define NDTS_NOISE_ARRAY_MAX_BSCANS 1000
	static const unsigned long maxBScansToFilter = NDTS_NOISE_ARRAY_MAX_BSCANS;
	unsigned long bscan, numberToCheckEitherSide, windowSize, validFloats ;
	static float gateAmpVals[NDTS_NOISE_ARRAY_MAX_BSCANS];

	RawScan_RawScanProtected *pRawInternal = RawScan_ReturnRawScanInternal(pRawScan) ;
	numberToCheckEitherSide = pRawInternal->numberToCheckEitherSide;
	windowSize = numberToCheckEitherSide*2 + 1;

	if (pOfflineState->sampleNoiseSize < pRawScan->numberOfBScans)
	{
		free(pOfflineState->pIsThisSampleNoise) ;
		pOfflineState->sampleNoiseSize = pRawScan->numberOfBScans ;
		pOfflineState->pIsThisSampleNoise = malloc(sizeof(NDTS_Boolean) * pOfflineState->sampleNoiseSize);
	}	
	if (windowSize >= pRawScan->numberOfBScans) windowSize = pRawScan->numberOfBScans-1;

	validFloats = (pRawScan->numberOfBScans < maxBScansToFilter) ? pRawScan->numberOfBScans  : maxBScansToFilter;
	// Copy the gate values to an array once before the loop 
	for (bscan = 0; bscan < validFloats; bscan++) 
	{
		gateAmpVals[bscan] = (float)abs(RawScan_ExtractGateAmplitudeValue(pRawScan, bscan, channelIndex, gateIndex));
	}

	for (bscan = 0; bscan < pRawScan->numberOfBScans; bscan++) 
	{
		if (numberToCheckEitherSide == 0 || bscan > maxBScansToFilter)
		{
			// The window is too big for the number of scans 
			pOfflineState->pIsThisSampleNoise[bscan] = NDTS_BFalse;
		}
		else
		{
			int i ;
			int firstToCheck = bscan - numberToCheckEitherSide;
			int lastToCheck  = bscan + numberToCheckEitherSide;
			NDTS_Boolean isNoise = NDTS_BFalse ;
			float fThisValueScaled = gateAmpVals[bscan] * pRawInternal->proportionToTriggerOff ;
			if (firstToCheck < 0)
			{
				lastToCheck = windowSize ;
				firstToCheck = 0;

			}
			if (lastToCheck >= (int)pRawScan->numberOfBScans) 
			{
				firstToCheck = pRawScan->numberOfBScans - windowSize;
				lastToCheck = pRawScan->numberOfBScans - 1;
			}

			for (i = firstToCheck ; i <= lastToCheck; i++)
			{
				// We could save the calls to NDTS_ExtractGateAmplitudeValue() in an array if these calls are slowing things down.
				// It would also be possible to reduce the number of floating point calculations.  However, we are 
				// copying a full A Scans worth of samples for every calculation so this extra penalty should be OK.
				float amp = gateAmpVals[i]; 
				if (fThisValueScaled > amp)
				{
					static int noiseFilterHits = 0;
//					static mesRate = 100;
//					if (noiseFilterHits % mesRate == 0)
//						filelogt("Got spike %d on bscan %d amp %f B amp %f position %d", noiseFilterHits, bscan, amp, gateAmpVals[bscan], i);
					isNoise = NDTS_BTrue;
					break;
				}
			}
			pOfflineState->pIsThisSampleNoise[bscan] = isNoise ;
		}
	}
}
unsigned long RawScan_ExtractCalculateEnabledGateIndex(NDTS_RawScan *pRawScan,  unsigned long step, unsigned long gateIndex)
{
	unsigned long enabledGateIndex = 0;
	unsigned long i;

#ifndef _DEBUG
	// Baoti      bn gh hgn   22 crashes here without the if below
	// Daniel 28/11/06 - Seems to be OK now but leave this in for release build just in case.
	if (!pRawScan->ppGateSettings[step][gateIndex].isGateEnabled) return 0;
#endif
	_ASSERTE(pRawScan->ppGateSettings[step][gateIndex].isGateEnabled) ;

	// convert the gate number to the index of enabled gates (i.e. the outputs that will appear in the
	// gate output table
	for (i = 0; i < gateIndex; i++)
		if (pRawScan->ppGateSettings[step][i].isGateEnabled== NDTS_BTrue)
			enabledGateIndex++;

	return enabledGateIndex;
}

int CALL_CONV RawScan_ExtractSelectSpecificBScanIndex(NDTS_RawScan *pRawScan, unsigned long step, NDTS_SnapshotDataSelection selection, unsigned long gateIndex, short *pAmplitude, short *pDepth)
{
	int bScanIndex;
	unsigned long bscan, numberOfBScans ;
	short target, thisValue;

	_ASSERTE(pRawScan) ;
	_ASSERTE(pAmplitude) ;
	_ASSERTE(pDepth) ;

	numberOfBScans = pRawScan->numberOfBScans ;

	if (RawScan_ReturnIsSelectionGateDependent(selection))
		RawScan_BuildNoiseArray(pRawScan, step, gateIndex);

	bScanIndex = -1 ;  // return -1 if no suitable scan is found
	switch (selection)
	{
	case NDTS_PDSLatest:
		bScanIndex = numberOfBScans - 1;
	break;
	// Algorithms use >= rather than > because when selecting a gate followed by an AScan of the same gate,
	// the array will have been updated on the check for the gate and if the test were > it would not
	// trigger again to update the AScan.  This also means that if there are two sample sets with the same max,
	// the later one gets selected.
	case NDTS_PDSMax:
		target = pAmplitude[gateIndex];
		for (bscan = 0; bscan < numberOfBScans; bscan++) // Loop from 0 because first point may be the non noise max
		{
			thisValue = RawScan_ExtractGateAmplitudeValue(pRawScan, bscan, step, gateIndex);
			if ((abs(thisValue) >= abs(target)) && !pOfflineState->pIsThisSampleNoise[bscan])
			{
				bScanIndex = bscan;
				target = thisValue;
			}
		}
	break;

	case NDTS_PDSMin:
		target = pAmplitude[gateIndex] ;
		for (bscan = 0; bscan < numberOfBScans; bscan++)
		{
			thisValue = RawScan_ExtractGateAmplitudeValue(pRawScan, bscan, step, gateIndex);
			if ((abs(thisValue) <= abs(target)) && !pOfflineState->pIsThisSampleNoise[bscan])
			{
				bScanIndex = bscan;
				target = thisValue;
			}
		}
	break;

	case NDTS_PDSFurthest:
		target = pDepth[gateIndex] ;
		for (bscan = 0; bscan < numberOfBScans; bscan++)
		{
			thisValue = RawScan_ExtractGateDepthValue(pRawScan,  bscan, step, gateIndex);
			if (thisValue >= target && !pOfflineState->pIsThisSampleNoise[bscan])
			{
				bScanIndex = bscan;
				target = thisValue;
			}
		}
	break;

	case NDTS_PDSNearest:
		target = pDepth[gateIndex] ;
		for (bscan = 0; bscan < numberOfBScans; bscan++)
		{
			thisValue = RawScan_ExtractGateDepthValue(pRawScan, bscan, step, gateIndex);
			if (thisValue <= target && !pOfflineState->pIsThisSampleNoise[bscan])
			{
				bScanIndex = bscan;
				target = thisValue;
			}
		}
	break;

	case NDTS_PDSIndexed:
		bScanIndex = gateIndex;
		break;

	default:
		bScanIndex = 0;
		break;

	}
	return bScanIndex;
}

NDTS_GateOutput RawScan_ExtractReturnGateValue(NDTS_RawScan *pRawScan, unsigned long bScanIndex, unsigned long aScanIndex, unsigned long gateIndex, unsigned long oversampleIndex)
{	
	NDTS_GateOutput *pGateData ;
	RawScan_RawScanProtected *pRawInternal = RawScan_ReturnRawScanInternal(pRawScan) ;
	unsigned long enabledGateIndex ;
	RawScan_MemoryHandle *pGateValuesBody ;
	NDTS_Boolean isOK ;
	
	_ASSERTE(pRawScan) ;
	_ASSERTE(!pRawInternal->isLargeGateOutputData);

	// Get the gate result body.
	isOK = RawScan_GetRawScanGateValuesBody(pRawScan, bScanIndex, &pGateValuesBody) ;
	_ASSERTE(isOK) ;

	pGateData = (NDTS_GateOutput *)(pGateValuesBody->p + 
								  pRawInternal->gateOffsetThisStep[aScanIndex] +
								  oversampleIndex * (4 + 4 * pRawScan->numberOfGates[aScanIndex])) ;

	enabledGateIndex = RawScan_ExtractCalculateEnabledGateIndex(pRawScan, aScanIndex, gateIndex) ;
	
	return pGateData[enabledGateIndex] ;
}

/*
short RawScan_ExtractGateDepthValue(NDTS_RawScan *pRawScan, unsigned long bScanIndex, unsigned long step, unsigned long gateIndex)
{
	short bestFitAmp = 0, bestFitDepth = untriggeredDepthGateReturnValue;
	unsigned long i;
	RawScan_RawScanProtected *pRawScanInternal = RawScan_ReturnRawScanInternal(pRawScan) ;
	RawScan_GateDistanceMetric metric = pRawScan->ppGates[step][gateIndex].distanceMetric;

	_ASSERTE(pRawScan) ;
	// At least check the oversampleCountThisStep is 1 if trying to get to work with DI unit rather than prx.
	_ASSERTE(pRawScan->isSequence);
	_ASSERTE(!pRawInternal->gateOutputDataFormatisLargeGateOutputData);

	// Compare the oversamples looking for the  value according to the gate's metric
	// Don't try to noise filter at this stage as there are not likely to be many valid gate values and noise filtering needs at least three valid values
	for (i = 0; i < pRawScanInternal->oversampleCountThisStep[step]; i++)
	{
		if (RawScan_ExtractIsGateValueValid(pRawScan, bScanIndex, step, gateIndex, NDTS_BFalse, i))
		{
			NDTS_GateOutput gateData = RawScan_ExtractReturnGateValue(pRawScan, bScanIndex, step, gateIndex, i);
			// The depths appear in reverse order - see Frog's comments in RawScan_GetAScanNoBankSwap
			short depth = (short)(gateData.distanceMetric * pRawScanInternal->oversampleCountThisStep[step] + pRawScanInternal->oversampleCountThisStep[step] - (i + 1));
			metric;
			if (bestFitDepth == untriggeredDepthGateReturnValue || 
				metric != NDTS_GDMPeak &&  depth < bestFitDepth   || 
				metric == NDTS_GDMPeak && (short)gateData.amplitudeMetric > bestFitAmp)
			{
				bestFitDepth = depth;
				bestFitAmp = (short)gateData.amplitudeMetric;
			}
		}
	}
	return bestFitDepth;
}
*/

/* Daniel Summer 08 - Re wrote the above function so that RawScan doesn't need to know about gates
  Changed pRawScan->ppGates[step][gateIndex].distanceMetric to use pRawScan->isDistanceMetricPeak
  The function is only used when oversampling.  Oversampling is only implemented on the PRX. The changes have not been tested.
  I also don't think this is correct for a trailing edge or trailing zero in either the old or the new code.
  */
short RawScan_ExtractGateDepthValue(NDTS_RawScan *pRawScan, unsigned long bScanIndex, unsigned long step, unsigned long gateIndex)
{
	short bestFitAmp = 0, bestFitDepth = untriggeredDepthGateReturnValue;
	unsigned long i;
	RawScan_RawScanProtected *pRawScanInternal = RawScan_ReturnRawScanInternal(pRawScan) ;
	NDTS_Boolean isDistanceMetricPeak = pRawScan->ppGateSettings[step][gateIndex].isDistanceMetricPeak;  

	_ASSERTE(pRawScan) ;
	// At least check the oversampleCountThisStep is 1 if trying to get to work with DI unit rather than prx.
	_ASSERTE(pRawScan->isSequence);
	_ASSERTE(!pRawScanInternal->isLargeGateOutputData);

	// Compare the oversamples looking for the  value according to the gate's metric
	// Don't try to noise filter at this stage as there are not likely to be many valid gate values and noise filtering needs at least three valid values
	for (i = 0; i < pRawScanInternal->oversampleCountThisStep[step]; i++)
	{
		if (RawScan_ExtractIsGateValueValid(pRawScan, bScanIndex, step, gateIndex, NDTS_BFalse, i))
		{
			NDTS_GateOutput gateData = RawScan_ExtractReturnGateValue(pRawScan, bScanIndex, step, gateIndex, i);
			// The depths appear in reverse order - see Frog's comments in RawScan_GetAScanNoBankSwap
			short depth = (short)(gateData.distanceMetric * pRawScanInternal->oversampleCountThisStep[step] + pRawScanInternal->oversampleCountThisStep[step] - (i + 1));
			if (bestFitDepth == untriggeredDepthGateReturnValue || 
				!isDistanceMetricPeak &&  depth < bestFitDepth   || 
				isDistanceMetricPeak && (short)gateData.amplitudeMetric > bestFitAmp)
			{
				bestFitDepth = depth;
				bestFitAmp = (short)gateData.amplitudeMetric;
			}
		}
	}
	return bestFitDepth;
}

void RawScan_ExtractGateDepthValues(NDTS_RawScan *pRawScan, unsigned long step, short *pAmplitude, short *pDepth)
{
	// extract the gate depth outputs for each enabled gate
	unsigned long packedGate, unpackedGate ;

	packedGate = 0 ;
	for (unpackedGate = 0; unpackedGate < NDTS_MAXIMUM_NUMBER_OF_GATES_COMPILE_TIME; unpackedGate++)
	{
		RawScanGateSettings  *pGateSettings = &(pRawScan->ppGateSettings[step][unpackedGate]);
		if (pGateSettings->isGateEnabled == NDTS_BTrue)
		{
			int bScanIndex = RawScan_ExtractSelectSpecificBScanIndex(pRawScan, step, pGateSettings->snapshotSelection, unpackedGate, pAmplitude, pDepth);
			if (bScanIndex != -1)
				pDepth[unpackedGate] = RawScan_ExtractGateDepthValue(pRawScan, bScanIndex, step, unpackedGate);

			packedGate++ ;
		}
		else
			pDepth[unpackedGate] = untriggeredDepthGateReturnValue;
	}
}

short RawScan_ExtractGateAmplitudeValue(NDTS_RawScan *pRawScan, unsigned long bScanIndex, unsigned long step, unsigned long gateIndex)
{
	unsigned long i;
	short value = untriggeredAmpGateReturnValue;
	RawScan_RawScanProtected *pRawInternal = RawScan_ReturnRawScanInternal(pRawScan) ;

	_ASSERTE(pRawScan) ;
	// At least check the oversampleCountThisStep if trying to get to work DI unit rather than prx.
	_ASSERTE(pRawScan->isSequence);
	_ASSERTE(!pRawInternal->isLargeGateOutputData);


	// Choose the largest amplitude value from the oversamples because a gate's amplitude metric is always peak based.
	for (i = 0; i < pRawInternal->oversampleCountThisStep[step]; i++)
	{
		if (RawScan_ExtractIsGateValueValid(pRawScan, bScanIndex, step, gateIndex, NDTS_BTrue, i))
		{
			NDTS_GateOutput gateData = RawScan_ExtractReturnGateValue(pRawScan, bScanIndex, step, gateIndex, i);
			if (value == untriggeredAmpGateReturnValue || gateData.amplitudeMetric > value)
			{
				value = (short)gateData.amplitudeMetric;
			}
		}
	}
	return value;
}

void RawScan_ExtractGateAmplitudeValues(NDTS_RawScan *pRawScan, unsigned long step, short *pAmplitude, short *pDepth)
{
	// extract the gate Amplitude outputs for each enabled gate
	unsigned long packedGate, unpackedGate ;

	_ASSERTE(pRawScan) ;
	_ASSERTE(pDepth) ;

	for (packedGate = 0, unpackedGate = 0; unpackedGate < NDTS_MAXIMUM_NUMBER_OF_GATES_COMPILE_TIME; unpackedGate++)
	{
		RawScanGateSettings  *pGateSettings  = &(pRawScan->ppGateSettings[step][unpackedGate]);
		if (pGateSettings->isGateEnabled == NDTS_BTrue)
		{
			int bScanIndex = RawScan_ExtractSelectSpecificBScanIndex(pRawScan, step, pGateSettings->snapshotSelection, unpackedGate, pAmplitude, pDepth);
			if (bScanIndex != -1)
				pAmplitude[unpackedGate] = RawScan_ExtractGateAmplitudeValue(pRawScan, bScanIndex, step, unpackedGate);

			packedGate++;
		}
		else
			pAmplitude[unpackedGate] = untriggeredAmpGateReturnValue;
	}
}


NDTS_Boolean RawScan_ExtractIsGateValueValid(NDTS_RawScan *pRawScan, unsigned long bScanIndex, unsigned long step, unsigned long gateIndex, NDTS_Boolean isMetricAmplitude, unsigned long oversampleIndex)
{
	if (!(pRawScan->ppGateSettings[step][gateIndex].isGateEnabled)) return NDTS_BFalse;

	if ((pRawScan->ppGateSettings[step][gateIndex]).storeGateOnlyWhenTriggered)
	{
		NDTS_GateOutput gateData = RawScan_ExtractReturnGateValue(pRawScan, bScanIndex, step, gateIndex, oversampleIndex);
		return (isMetricAmplitude) ? gateData.wasAmplitudeMeasured : gateData.wasDistanceMeasured;
	}
	else
	{
		// If a SGVAlways gate was triggered by another gate and that gate failed to trigger,
		// data is probably garbage.  Do output value if this gate didn't trigger
		int gateToCheck = pRawScan->ppGateSettings[step][gateIndex].triggerGate;
		while (gateToCheck != RAW_SCAN_GATE_TRIGGER_ABSOLUTE)  
		{
			NDTS_GateOutput gateData = RawScan_ExtractReturnGateValue(pRawScan, bScanIndex, step, gateToCheck, oversampleIndex);
			if ((isMetricAmplitude && !gateData.wasAmplitudeMeasured) || 
				(!isMetricAmplitude && !gateData.wasDistanceMeasured))
				return NDTS_BFalse;
			gateToCheck = pRawScan->ppGateSettings[step][gateToCheck].triggerGate;
		}
		return NDTS_BTrue;
	}
}



NDTS_Boolean RawScan_ReturnIsSelectionGateDependent(NDTS_SnapshotDataSelection selection)
{
	return (selection == NDTS_PDSMax || selection == NDTS_PDSMin ||	selection == NDTS_PDSFurthest || selection == NDTS_PDSNearest) ;
}


// ppGateOutputs is [nSteps][ngates]
// The gates are packed
// The array shape specified by the caller is used.  If nGates or nSteps are wrong, the array is zero padded or truncated to fit.
// Called from within HLPRX_GetGateValuesFromSnapshot()

RAW_SCAN_API NDTS_Boolean CALL_CONV RawScan_ExtractFullBScanGateValuesSequenced(unsigned long bScanIndex, NDTS_RawScan *pRawScan, NDTS_GateOutput *pGateData, int nSteps, int nGates)
{
	int packedGateIndex, stepIndex ;
	unsigned char *pGatesBaseAddressThisStep ;
	RawScan_RawScanProtected *pRawInternal = RawScan_ReturnRawScanInternal(pRawScan) ;
	RawScan_MemoryHandle *pGateValuesBody ;
	NDTS_Boolean isOK ;
	NDTS_GateOutput blank;
	memset(&blank, 0, sizeof(blank));

	_ASSERTE(pRawScan->isSequence);
	_ASSERTE(pRawInternal->pDataB != 0);
	_ASSERTE(bScanIndex < pRawScan->numberOfBScans) ;
	_ASSERTE(!pRawInternal->isLargeGateOutputData);

	// Get the gate result body.
	isOK = RawScan_GetRawScanGateValuesBody(pRawScan, bScanIndex, &pGateValuesBody) ;
	if(!isOK) 
		return NDTS_BFalse ; 
	
	for (stepIndex = 0; stepIndex < nSteps; stepIndex++)
	{
		pGatesBaseAddressThisStep = pGateValuesBody->p + pRawInternal->gateOffsetThisStep[pRawInternal->RPPS[stepIndex]];
		for (packedGateIndex = 0; packedGateIndex < nGates; packedGateIndex++)
		{
			int activeGatesThisStep = (int)pRawScan->numberOfGates[pRawInternal->RPPS[stepIndex]];
			if (stepIndex < (int)pRawScan->numberOfAScansInBScan && packedGateIndex < activeGatesThisStep)
			{
				pGateData[stepIndex*nGates + packedGateIndex] = *(NDTS_GateOutput *) (pGatesBaseAddressThisStep + 4 * packedGateIndex) ; 
			}
			else
			{
				pGateData[stepIndex*nGates + packedGateIndex] = blank;
			}
		}
	}

	return NDTS_BTrue ;
}


// Similar to above but only extracts the gates for one step
RAW_SCAN_API NDTS_Boolean CALL_CONV RawScan_ExtractOneStepGateValuesSequenced(unsigned long bScanIndex, unsigned long stepIndex, NDTS_RawScan *pRawScan, NDTS_GateOutput *pGateData, int nGates)
{
	int packedGateIndex;
	unsigned char *pGatesBaseAddressThisStep ;
	RawScan_RawScanProtected *pRawInternal = RawScan_ReturnRawScanInternal(pRawScan) ;
	RawScan_MemoryHandle *pGateValuesBody ;
	NDTS_Boolean isOK ;
	NDTS_GateOutput blank;
	memset(&blank, 0, sizeof(blank));

	_ASSERTE(pRawScan->isSequence);
	_ASSERTE(pRawInternal->pDataB != 0);
	_ASSERTE(bScanIndex < pRawScan->numberOfBScans) ;
	_ASSERTE(!pRawInternal->isLargeGateOutputData);

	// Get the gate result body.
	isOK = RawScan_GetRawScanGateValuesBody(pRawScan, bScanIndex, &pGateValuesBody) ;
	if(!isOK) 
		return NDTS_BFalse ; 

	pGatesBaseAddressThisStep = pGateValuesBody->p + pRawInternal->gateOffsetThisStep[pRawInternal->RPPS[stepIndex]];
	for (packedGateIndex = 0; packedGateIndex < nGates; packedGateIndex++)
	{
		int activeGatesThisStep = (int)pRawScan->numberOfGates[pRawInternal->RPPS[stepIndex]];
		if (stepIndex < (int)pRawScan->numberOfAScansInBScan && packedGateIndex < activeGatesThisStep)
		{
			pGateData[packedGateIndex] = *(NDTS_GateOutput *) (pGatesBaseAddressThisStep + 4 * packedGateIndex) ; 
		}
		else
		{
			pGateData[packedGateIndex] = blank;
		}
	}

	return NDTS_BTrue ;
}


// Similar to above for large gates
RAW_SCAN_API NDTS_Boolean CALL_CONV RawScan_ExtractOneStepLargeGateValuesSequenced(unsigned long bScanIndex, unsigned long stepIndex, NDTS_RawScan *pRawScan, NDTS_GateOutputLarge *pGateData, int nGates)
{
	int packedGateIndex;
	unsigned char *pGatesBaseAddressThisStep ;
	RawScan_RawScanProtected *pRawInternal = RawScan_ReturnRawScanInternal(pRawScan) ;
	RawScan_MemoryHandle *pGateValuesBody ;
	NDTS_Boolean isOK ;
	NDTS_GateOutputLarge blank;
	memset(&blank, 0, sizeof(blank));

	_ASSERTE(pRawScan->isSequence);
	_ASSERTE(pRawInternal->pDataB != 0);
	_ASSERTE(bScanIndex < pRawScan->numberOfBScans) ;
	_ASSERTE(pRawInternal->isLargeGateOutputData);

	// Get the gate result body.
	isOK = RawScan_GetRawScanGateValuesBody(pRawScan, bScanIndex, &pGateValuesBody) ;
	if(!isOK) 
		return NDTS_BFalse ; 

	pGatesBaseAddressThisStep = pGateValuesBody->p + pRawInternal->gateOffsetThisStep[pRawInternal->RPPS[stepIndex]];
	for (packedGateIndex = 0; packedGateIndex < nGates; packedGateIndex++)
	{
		int activeGatesThisStep = (int)pRawScan->numberOfGates[pRawInternal->RPPS[stepIndex]];
		if (stepIndex < (int)pRawScan->numberOfAScansInBScan && packedGateIndex < activeGatesThisStep)
		{
			pGateData[packedGateIndex] = *(NDTS_GateOutputLarge *) (pGatesBaseAddressThisStep + 4 * packedGateIndex) ; 
		}
		else
		{
			pGateData[packedGateIndex] = blank;
		}
	}

	return NDTS_BTrue ;
}


// Add parameter checking and a wrapper if exposed to applications
RAW_SCAN_API NDTS_Boolean CALL_CONV RawScan_ExtractEncoderValuesProtected(unsigned long bScanIndex, NDTS_RawScan *pRawScan, long *pEncoderValues, int nEncoders)
{
	RawScan_RawScanProtected *pRawInternal = RawScan_ReturnRawScanInternal(pRawScan) ;
	NDTS_Boolean isOK ;
	long *pEncoderBlock, i ;
	RawScan_MemoryHandle *pGateValuesTrailer ;

	// Preconditions
	_ASSERTE(pRawScan) ;
	_ASSERTE(pEncoderValues) ;
	pRawInternal = pRawInternal ;	// so it builds in release.
	_ASSERTE(pRawInternal->pDataB != 0);

	_ASSERTE(bScanIndex < pRawScan->numberOfBScans);
	
	isOK = RawScan_GetRawScanGateValuesTrailer(pRawScan, bScanIndex, &pGateValuesTrailer) ;
	if(!isOK) 
		return NDTS_BFalse ; 

	pEncoderBlock = (long *)(pGateValuesTrailer->p) ;
	_ASSERTE(pEncoderBlock) ;

	for(i = 0; i < nEncoders; i++)
	{
		pEncoderValues[i] = (i < (int)pRawInternal->numberOfEncodersSupportedByHardware) ? *(pEncoderBlock + i) : 0;
	}
	
	return NDTS_BTrue;
}


