// Contains the SDK specific C++ functions and provides getRoot() and the root setting for the C++ interface

#include <crtdbg.h>
#include <windows.h>

#include <string>
#include <vector>
#include <sstream>
#include <fstream>
#include <iostream>

#include "PropertiesInterface.h"
#include "PropertyInternal.h"
#include "IntPropertyInternal.h"
#include "EnumPropertyInternal.h"
#include "SIShadowPropertyInternal.h"
#include "SIStoragePropertyInternal.h"
#include "EventPropertyInternal.h"
#include "PropertiesCollection.h"
#include "NDTS2100Internal.h"
#include "NDTSError.h"
#include "ChangeHook.h"
#include "NonRegisterHardwareAccessClass.h"
#include "RegisterBasedHardwareAccess.h"

using namespace NDTS::SCO;
using namespace NDTS::NDTS2100;


NDTS2100_GlobalState NDTS::NDTS2100::globalState;

static const int numDigitalIOLines = 16;
static const int numAnalogueInputLines = 16;
static const int numAnalogueOutputLines = 16;


// Names for properties that require a list of enumerated types.
const int numFalseTrueNames = 2;
char *falseTrueNames[numFalseTrueNames] = {"False",	"True"};
const int numScanTriggerModeNames = 4;
char *scanTriggerModeNames[numScanTriggerModeNames] = {"Simple Trig",	"Encoder Trig",	"Free Running", "External Trigger"};
const int numIntTrigTCGNames = 2;
char *intTrigTCGNames[numIntTrigTCGNames] = {"No Int Trig TCG", "Int Trig TCG"} ;
const int numSimpleGainOrTCGNames = 2;
char *simpleGainOrTCGNames[numSimpleGainOrTCGNames] = {"Simple Gain", "TCG Curve"} ;
const int numRectNames = 4;
char *rectNames[numRectNames] = {"RF", "FW", "Pos", "Neg"} ;
const int numInputVoltsNames = 6;
char *inputVoltsNames[numInputVoltsNames] = {"100mV", "200mV", "500mV", "1V", "2V", "5V"};
const int numAnalogueInputNames = 6;
char *AnalogueInputNames[numAnalogueInputNames] = {"Analog Input 0", "Analog Input 1", "Input Calibration", "Input GND", "Input Aux0", "Input Aux1"};
const int numInputCouplingNames = 2;
char *InputCouplingNames[numInputCouplingNames] = {"DC", "AC"};
const int numInputImpedanceNames = 2;
char *InputImpedanceNames[numInputImpedanceNames] = {"1Meg", "500hm"};
//const int numAuxAnalogueInRangeNames = 4;
//char *auxAnalogueInRangeNames[numAuxAnalogueInRangeNames] = {"+-2V", "+-1V", "+-0.5V", "+-0.25V"};
const int numScanStorageOptionsStrings = 2;
char *scanStorageOptionsStrings[numScanStorageOptionsStrings] = {"Full A Scan", "Snapshot Summary"};
const int numGatePolarityNames = 3;
char *gatePolarityNames[numGatePolarityNames] = {"Bipolar", "Positive", "Negative"};
// Keep in sync with  ChangeHook::configureGate()
const int numTriggerGateNames = 9;
char *triggerGateNames[numTriggerGateNames] = {"Absolute", "Interface", "Gate 1", "Gate 2", "Gate 3", "Gate 4", "Gate 5", "Gate 6", "Gate 7"};
const int triggerGateEnumToValueMap[numTriggerGateNames] = {15, 0, 1, 2, 3, 4, 5, 6, 7};
const int numGateTrigModeNames = 2;
char *gateTrigModeNames[numGateTrigModeNames] = {"Level", "Edge"};
const int numGateDistanceMetricNames = 3;

// Keep in sync with  ChangeHook::configureGate()
char *gateDistanceMetricNames[numGateDistanceMetricNames] = {"Leading Flank", "Trailing Flank", "Peak"};
const int numGatePeakSelectNames = 16;
char *gatePeakSelectNames[numGatePeakSelectNames] = {"Largest Peak", "Last Peak", "Peak 0", "Peak 1", "Peak 2", "Peak 3", "Peak 4", "Peak 5", "Peak 6", "Peak 7", "Peak 8", "Peak 9", "Peak 10", "Peak 11", "Peak 12", "Peak 13"};
const int gatePeakSelectEnumToValueMap[numGatePeakSelectNames] = {15, 14, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
const int numRectifierModeNames = 4;
char *rectModeNames[numRectifierModeNames] = {"Bipolar", "Fullwave", "Pos Halfwave", "Neg Halfwave"};
const int numSequenceStepControlNames = 2;
char *sequenceStepControlNames[numSequenceStepControlNames] = {"No Skip", "Skip"};
const int numSeqTrigEncSelectNames = 9;
char *SeqTrigEncSelectNames[numSeqTrigEncSelectNames] = {"Encoder 0", "Encoder 1", "Encoder 2", "Encoder 3", "Dual Encoder", "Pulse Counter 0", "Pulse Counter 1", "Pulse Counter 2", "Pulse Counter 3"};
const int numSignExtendStrings = 2;
char *signExtendStrings[numTriggerGateNames] = {"Extend", "No Extend"};
const int signExtendEnumToValueMap[numTriggerGateNames] = {1, 0};


// The contstructor is called once when the .dll is loaded because of the singleton design pattern and static instance variable
SDKPropertiesCollection::SDKPropertiesCollection(FactoryInternal *pFactoryPointer)
{
	this->pTcg = pFactoryPointer->getTCGInternal();
	//globalState.rawScan 
	globalState.isInitialised = false;
	globalState.pTcg = pTcg;

	// Set maxCards to number of cards found after init complete
	// Default to maxSteps to create and initialise settings for the maximum number of sets.  
	// Set number Of Steps to 1 on init complete
	for (int step=0; step < maxCards; step++)
	{
		globalState.numberOfSteps[step] = maxSteps;
	}

	// Create the root group
	int numGroups = 10;
	Property **ppSubGroups = new Property *[numGroups];
	//////////////////////////////////////////////////////////////////////////////////
	// Root of all settings
	//////////////////////////////////////////////////////////////////////////////////

	pRootGroup = new GroupPropertyInternal("Root", "The root of all the properties in this SDK", NDTS2100::PF_Group);
	SCO::GroupPropertyInternal *pCurrentSubGroup = 0;

	//////////////////////////////////////////////////////////////////////////////////
	// Special properties which we need to know the value of - created first
	// Not assigned to the tree until after the per card settings.
	//////////////////////////////////////////////////////////////////////////////////

	// IsScanning can be "Not Scanning" or "Scanning".  This is only used to control the trigger at the moment.
	// This is taken care of at the NDTS2100 level and the hardware only knows about the trigger mode
	hookObject.pIsScanningProp = new EnumPropertyInternal("Is Scanning",	"Set triggering for scanning or setting up",	NDTS2100::PF_Enum,		falseTrueNames,		numFalseTrueNames,		new DoNothing(0,0));
	// Number of cards starts as max cards and is then set to the number of cards found
	// The number of cards isn't known at this point because the properties may be constructed without accessing the hardware
	// The access type is set as though it is a read only property so that updateValue may be called once the number of cards is known.
	hookObject.pNumberOfCardsProp = new IntPropertyInternal("Number Of Cards",	"The number of NDTS2100 cards found on the PCI bus",	NDTS2100::PF_Int | NDTS2100::PF_RdOnly | NDTS2100::PF_NotCurrentlyValid,		maxCards,		1,		maxCards,		new DoNothing(0,0), readFromCacheUpdateAfterHardwareInit);

	// The sample frequency not taking into account drop samples.  Fixed at 200Mhz so set at default value and leave it there
	const double baseFreqMhz = (double)baseSampleFrequencyHz / 1000000.0;
	SIStoragePropertyInternal *pBaseSampleFreqSIProp = new SCO::SIStoragePropertyInternal("Base Sample Frequency",	"Base sampling frequency not taking into account drop samples, fixed at 200Mhz",		NDTS2100::PF_Double | NDTS2100::PF_RdOnly,		SI::Hertz,		SI::Mega,		baseFreqMhz,		baseFreqMhz,		baseFreqMhz);
    

	//////////////////////////////////////////////////////////////////////////////////
	// Per card array 
	// The root group contains a group that is created as an array 
	// where getPropertyByIndex(card) returns the settings for a particular card
	// The array is added to the root setting first so that the first entry of the root group 
	// is the per card settings and any changes to global properties doesn't affect this
	//////////////////////////////////////////////////////////////////////////////////

	SCO::GroupPropertyInternal *pCardArrayGroup  = new GroupPropertyInternal("Per Card Settings Array",		"Group indexed by card number with a sub-group for each card",		NDTS2100::PF_Group | NDTS2100::PF_NotCurrentlyValid);
	pRootGroup->addProperty(pCardArrayGroup);
	pCardArrayGroup->isArray = true;

	// At this point use maxCards rather than number of cards.  This ensures that the auto generated 
	// propertyVariables.h etc. get generated for all the cards.  Also, this is before hardware init.

	// We currently keep the properties for all the cards but it would be possible to 
	// delete the properties for cards greater than the number of cards found
	// in SDKPropertiesCollection::initialise() to reduce the memory requirements.
	for (int card = 0; card < maxCards; card++)
	{
		// There is a pCardSettingsGroup for each card. 
		SCO::GroupPropertyInternal *pCardSettingsGroup = new GroupPropertyInternal("Card Settings Group",		"Holds all the per card settings. There is one of these groups for each card",		NDTS2100::PF_Group | NDTS2100::PF_NotCurrentlyValid);
		pCardArrayGroup->addProperty(pCardSettingsGroup);

		SCO::GroupPropertyInternal *pStepArrayGroup = new GroupPropertyInternal("Per Step Settings Array",		"Group indexed by step number with a sub-group for each step. There is one of these gropus for each card",		NDTS2100::PF_Group | NDTS2100::PF_NotCurrentlyValid);
		pStepArrayGroup->isArray = true;
		pCardSettingsGroup->addProperty(pStepArrayGroup);
		for (int step=0; step < maxSteps; step++)
		{
			SCO::GroupPropertyInternal *pStepSettingsGroup = new GroupPropertyInternal("Step Settings Group",		"Holds all the per step settings.  There is one of these groups for each step of each card",		NDTS2100::PF_Group | NDTS2100::PF_NotCurrentlyValid);
			pStepArrayGroup->addProperty(pStepSettingsGroup);

			//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			// Per Gate settings
			// The per Gate settings are done in a similar way to the per card and per step settings 
			// The per Gate settings array is the first entry in the per step group so other changes to per step properties do not affect the per Gate array
			//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			SCO::GroupPropertyInternal *pGateArrayGroup = new GroupPropertyInternal("Per Gate Settings Array", "Group indexed by Gate number with a sub-group for each Gate.  There is one of these groups for each step",			NDTS2100::PF_Group | NDTS2100::PF_NotCurrentlyValid);
			pGateArrayGroup->isArray = true;
			pStepSettingsGroup->addProperty(pGateArrayGroup);
			for (int gate = 0; gate < maxGates; gate++)
			{
				pCurrentSubGroup = new GroupPropertyInternal("Gate Settings Group", "Holds all the per Gate settings.  There is one of these groups for each Gate of each step of each card",	NDTS2100::PF_Group | NDTS2100::PF_NotCurrentlyValid);
				pGateArrayGroup->addProperty(pCurrentSubGroup);

				IntPropertyInternal *pGateStart = new IntPropertyInternal("Gate Start Samples",	"The start time of the gate relative to the start of data capture (samples)",					NDTS2100::PF_Int | NDTS2100::PF_NotCurrentlyValid,			0,				0,			1 << 24,	new Reg(0x00301040, card, step, gate));
				pCurrentSubGroup->addProperty(pGateStart);    // Delay has an integer unit of samples that is proportional to the time in seconds and so is Proprtional not inverse
				pCurrentSubGroup->addProperty(new SIShadowPropertyInternal("Gate Start",	"The start time of the gate relative to the start of data capture",									NDTS2100::PF_Double,										SI::Seconds,	SI::Micro,	pGateStart, pBaseSampleFreqSIProp, SIShadowPropertyInternal::ProportionalRelationship));

				IntPropertyInternal *pGateStop = new IntPropertyInternal("Gate Stop Samples",	"The Stop time of the gate relative to the Stop of data capture (samples)",						NDTS2100::PF_Int | NDTS2100::PF_NotCurrentlyValid,			0,				0,			1 << 24,	new Reg(0x00301060, card, step, gate));
				pCurrentSubGroup->addProperty(pGateStop);    // Delay has an integer unit of samples that is proportional to the time in seconds and so is Proprtional not inverse
				pCurrentSubGroup->addProperty(new SIShadowPropertyInternal("Gate Stop",	"The Stop time of the gate relative to the Stop of data capture",										NDTS2100::PF_Double,										SI::Seconds,	SI::Micro,	pGateStop, pBaseSampleFreqSIProp, SIShadowPropertyInternal::ProportionalRelationship));

				// The Gate Attributes register is split into several bit fields
				BaseForPartReg *pRegGateAttributes = new BaseForPartReg(0x00301080, card, step, gate);
				pCurrentSubGroup->addProperty(new IntPropertyInternal("Gate Threshold",		"The threshold at which the gate triggers (0..2047)",		NDTS2100::PF_Int,		0,							0,							(1 << 11) - 1,							new PartReg(pRegGateAttributes, 0, 10)));

				hookObject.pGateTriggerGateProp[card][step][gate] = new EnumPropertyInternal("Gate Trigger Gate",	"The gate which triggers this gate (or absolute)",			NDTS2100::PF_Enum,		triggerGateNames,			numTriggerGateNames,		(int*)(triggerGateEnumToValueMap),		new PartReg(pRegGateAttributes, 12, 15));
				pCurrentSubGroup->addProperty(hookObject.pGateTriggerGateProp[card][step][gate]);
				pCurrentSubGroup->addProperty(new EnumPropertyInternal("Gate Polarity",		"The polarity which triggers the gate",						NDTS2100::PF_Enum,		gatePolarityNames,			numGatePolarityNames,												new PartReg(pRegGateAttributes, 18, 19)));     
				pCurrentSubGroup->addProperty(new EnumPropertyInternal("Gate Zero Crossing Trig Mode",	"The zero crossing trigger mode",				NDTS2100::PF_Enum,		falseTrueNames,				numFalseTrueNames,													new PartReg(pRegGateAttributes, 16, 16)));
				hookObject.pGateStoreOnlyWhenTriggeredProp[card][step][gate] = new EnumPropertyInternal("Gate Out If Not Trig",	"Enable gate output even if not triggered",				NDTS2100::PF_Enum,		falseTrueNames,				numFalseTrueNames,													new PartReg(pRegGateAttributes, 17, 17));
				pCurrentSubGroup->addProperty(hookObject.pGateStoreOnlyWhenTriggeredProp[card][step][gate]);
				pCurrentSubGroup->addProperty(new EnumPropertyInternal("Gate Trigger Mode",		"The gate trigger mode",								NDTS2100::PF_Enum,		gateTrigModeNames,			numGateTrigModeNames,												new PartReg(pRegGateAttributes, 20, 20)));
				hookObject.pGateDistanceMetricProp[card][step][gate] = new EnumPropertyInternal("Gate Distance Metric",	"The gate distance metric",								NDTS2100::PF_Enum,		gateDistanceMetricNames,	numGateDistanceMetricNames,											new PartReg(pRegGateAttributes, 21, 22));
				pCurrentSubGroup->addProperty(hookObject.pGateDistanceMetricProp[card][step][gate]);
				hookObject.pGateEnableProp[card][step][gate] = new EnumPropertyInternal("Gate Enable",	"The gate enable",								NDTS2100::PF_Enum,		falseTrueNames,				numFalseTrueNames,													new PartReg(pRegGateAttributes, 23, 23));
				pCurrentSubGroup->addProperty(hookObject.pGateEnableProp[card][step][gate]);
				pCurrentSubGroup->addProperty(new EnumPropertyInternal("Gate Amplitude Peak Select",	"The gate amplitude peak select",				NDTS2100::PF_Enum,		gatePeakSelectNames,		numGatePeakSelectNames,		(int*)(gatePeakSelectEnumToValueMap),	new PartReg(pRegGateAttributes, 24, 27)));
                pCurrentSubGroup->addProperty(new EnumPropertyInternal("Gate Distance Peak Select",		"The gate distance peak select",				NDTS2100::PF_Enum,		gatePeakSelectNames,		numGatePeakSelectNames,		(int*)(gatePeakSelectEnumToValueMap),	new PartReg(pRegGateAttributes, 28, 31)));
				pCurrentSubGroup->addProperty(new IntPropertyInternal("Gate Trailing Flank Holdoff",	"The gate trailing flank holdoff (0..256)",		NDTS2100::PF_Int,		0,							0,							1 << 7,									new Reg(0x003010a0, card, step, gate)));

			}
            
			//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			// Per Step settings
			// The per step settings are done in a similar way to the per group settings - except there is a pStepArrayGroup for each card.
			// Allocate settings for the max possible number of steps so the settings are there when the number of steps are increased
			// The per step settings array is the first entry in the per card group so other changes to per card properties do not affect the per step array
			//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

			SCO::GroupPropertyInternal *pAcquisitionGroup = new GroupPropertyInternal("Acquisition", "The main properties used for setting up a scan", NDTS2100::PF_Group    );
			pStepSettingsGroup->addProperty(pAcquisitionGroup);


			//////////////////////////////////////////////////////////////////////////////////
			// Input control - Input selection and filters
			//////////////////////////////////////////////////////////////////////////////////
			pCurrentSubGroup = new GroupPropertyInternal("Input Control", "Settings to control input selection (Sig Gen BEA etc.) and filtering on the inputs", NDTS2100::PF_Group);
			pAcquisitionGroup->addProperty(pCurrentSubGroup); 
			// Set:- Bit 1 TxRX Select (Through trans), Bit 3 - Sel R1, Bit 10 - A/D signal, Bit 22 Sig gen data, Bit 24 - 0DB attenuator before BEA gate
			int inputSelDefault = (1 << 1) | (1 << 3) | (1 << 10) | (1 << 22)| (1 << 24);
			pCurrentSubGroup->addProperty(new IntPropertyInternal("Input Selection Register",	"Input selection register for DSP FPGA",		NDTS2100::PF_Int,		inputSelDefault,		LONG_MIN,		LONG_MAX,		new Reg(0x00301000, card, step)));
			// Set:- Bit 7 - thru back end filter, Bit 8 - 500KHz BPF Front Filter, 15 - thru front end filter
			int filterDefault = (1 << 7) | (1 << 8) | (1 << 15);
			pCurrentSubGroup->addProperty(new IntPropertyInternal("Filter Control Register",	"Input selection register for DSP FPGA",		NDTS2100::PF_Int,		filterDefault,			LONG_MIN,		LONG_MAX,		new Reg(0x00301004, card, step)));
			

			//A Scan Sample Fequency
			//Drop samples is implemented as an int sample rate divider property visible to the app.  It has 16 bits in the 2100.  It only divides the A Scan sampling on the 2100 - gates should remain at 200Mhz
			hookObject.pSamplesDividerProp[card][step] = new IntPropertyInternal("A Scan Sample Rate Divider",		"Divide the base 200Mhz sample rate to give undersampling - 1=200Mhz, 2=100Mhz, 3=50Mhz etc.",				NDTS2100::PF_Int,		1,		1,		USHRT_MAX,		new ValueMinus1Reg(0x0030100c, card, step));
			//There is a proportional relationship between the samples divider and the BASE SI unit of seconds, even though the reporting SI unit is Hz. use ProportionalRelationship to consider sample divider i.e. if sample frequency = 200MHz, sample divider is 2, then 200MHz / 2 = 100MHz
			SIShadowPropertyInternal *pAScanSampleFreq = new SIShadowPropertyInternal("A Scan Sampling Frequency",	"The A Scan sampling frequency, taking into account samples divider",								NDTS2100::PF_Double | NDTS2100::PF_RdOnly,		SI::Hertz,		SI::Mega,		hookObject.pSamplesDividerProp[card][step],		pBaseSampleFreqSIProp,		SIShadowPropertyInternal::ProportionalRelationship);
            
            
			//////////////////////////////////////////////////////////////////////////////////
			// Basic scan control - Rep rate, range, etc.
			//////////////////////////////////////////////////////////////////////////////////
			pCurrentSubGroup = new GroupPropertyInternal("Scan", "Settings to control the scan", NDTS2100::PF_Group);
			pAcquisitionGroup->addProperty(pCurrentSubGroup);
			pCurrentSubGroup->addProperty(new EnumPropertyInternal("A Scan Rectifier Mode",			"A-Scan rectifier mode",									NDTS2100::PF_Enum,			rectModeNames,			numRectifierModeNames,				 new Reg(0x00301008, card, step)));
			pCurrentSubGroup->addProperty(hookObject.pSamplesDividerProp[card][step]);
			pCurrentSubGroup->addProperty(pAScanSampleFreq);

			//Minimum is 10 clock ticks (200Mhz clock / 5). This is never reached due to the safe samples limit.  Maximum is 2^23 * 2.  Default of 200000 (1Khz) is enough to fit the default A Scan range with plenty to spare and not be too slow - max is 23 bits
			hookObject.pAScanRepRateProp[card][step] = new IntPropertyInternal("A Scan Rep Rate Samp",	"A Scan Repetition Rate (samples)",						NDTS2100::PF_Int | NDTS2100::PF_NotCurrentlyValid,		defaultRepRateForNewStep,	10,		0x0800000 - 100,	new Reg(0x00301010, card, step));
			hookObject.pAScanRepRateProp[card][step]->isVisible = false;
			pCurrentSubGroup->addProperty(hookObject.pAScanRepRateProp[card][step]);
			pCurrentSubGroup->addProperty(new SIShadowPropertyInternal("A Scan Repetition Rate",	"The frequency at which A Scans are fired",					NDTS2100::PF_Double,	SI::Hertz,	SI::Kilo,	hookObject.pAScanRepRateProp[card][step],	pBaseSampleFreqSIProp,		SIShadowPropertyInternal::ProportionalRelationship));
		    
			hookObject.pAScanRangeProp[card][step] = new IntPropertyInternal("A Scan Range Samp",		"Number Of Samples Per A Scan",							NDTS2100::PF_Int | NDTS2100::PF_NotCurrentlyValid,		defaultRangeForNewStep,		2,		aScanRangeMax - 1,		new AScanRangeReg(0x0030101C, card, step));
			//hookObject.pAScanRangeProp[card][step]->isVisible = false;
			pCurrentSubGroup->addProperty(hookObject.pAScanRangeProp[card][step]);  
			pCurrentSubGroup->addProperty(new SIShadowPropertyInternal("A Scan Range", "The range covered by an A Scan",										NDTS2100::PF_Double,	SI::Seconds,	SI::Micro,		hookObject.pAScanRangeProp[card][step],		pAScanSampleFreq,		SIShadowPropertyInternal::ProportionalRelationship));
            
			//The A Scan range and delay in samples need to be made available to the application.  We create new properties that reads the value, rather than exposing hookObject.pAScanRangeProp
			hookObject.pAScanDelayProp[card][step] = new IntPropertyInternal("A Scan Start Delay Samp",		"Samples delay from trigger to start sampling",		NDTS2100::PF_Int | NDTS2100::PF_NotCurrentlyValid,		2500,		0,		0x0800000 - 100,		new Reg(0x0030102C, card, step));
			hookObject.pAScanDelayProp[card][step]->isVisible = false;
			pCurrentSubGroup->addProperty(hookObject.pAScanDelayProp[card][step]);    // Delay has an integer unit of samples that is proportional to the time in seconds and so is Proprtional not inverse
			pCurrentSubGroup->addProperty(new SIShadowPropertyInternal("A Scan Delay", "The time between a trigger and the start of collection of A Scan data", NDTS2100::PF_Double,	SI::Seconds,	SI::Micro,	hookObject.pAScanDelayProp[card][step],		pBaseSampleFreqSIProp,		SIShadowPropertyInternal::ProportionalRelationship));
            
			pCurrentSubGroup->addProperty(new EnumPropertyInternal("A Scan Sequence Step Control",		"A-Scan sequence step control",							NDTS2100::PF_Enum,		sequenceStepControlNames,		numSequenceStepControlNames,		new Reg(0x00301030, card, step)));
			pCurrentSubGroup->addProperty(new IntPropertyInternal("A Scan DC Offset Adjust",			"A-Scan DC offset adjust",								NDTS2100::PF_Int,		0,		LONG_MIN,		LONG_MAX,		new Reg(0x00301034, card, step)));
            

			//////////////////////////////////////////////////////////////////////////////////
			// Pulser control - currently just the pulse width
			//////////////////////////////////////////////////////////////////////////////////
			pCurrentSubGroup = new GroupPropertyInternal("Pulser",		"Settings to control the pulser",		NDTS2100::PF_Group);
			pAcquisitionGroup->addProperty(pCurrentSubGroup);

			IntPropertyInternal *pPulseWidth = new IntPropertyInternal("Pulse Width Samples",	"Transducer pulse width (samples)",		NDTS2100::PF_Int | NDTS2100::PF_NotCurrentlyValid,				200,				1,			1 << 15, new Reg(0x00301014, card, step));
			pPulseWidth->isVisible = false;
			pCurrentSubGroup->addProperty(pPulseWidth);
			pCurrentSubGroup->addProperty(new SIShadowPropertyInternal("A Scan Pulse Width",	"The width of the pulse that is fired",			NDTS2100::PF_Double,	SI::Seconds,	SI::Nano,	pPulseWidth,	pBaseSampleFreqSIProp,		SIShadowPropertyInternal::ProportionalRelationship, 1.0));
			pCurrentSubGroup->addProperty(new IntPropertyInternal("A Scan Pulse Train",		"A-Scan pulse train",						NDTS2100::PF_Int,		0,		LONG_MIN,		LONG_MAX,		new Reg(0x00301018, card, step)));
            

			//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			// Per card Gain and TCG 
			//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			pCurrentSubGroup = new GroupPropertyInternal("Gain",		"Settings to control the gain / TCG",			NDTS2100::PF_Group);
			pAcquisitionGroup->addProperty(pCurrentSubGroup);
			hookObject.pInterfaceTriggeredTCG[card][step] = new EnumPropertyInternal("Interface Triggered TCG",		"Trigger the TCG from the interface gate",		NDTS2100::PF_Enum,		intTrigTCGNames,			numIntTrigTCGNames,		new DoNothing(card, step));
			pCurrentSubGroup->addProperty(hookObject.pInterfaceTriggeredTCG[card][step]);
			hookObject.pSimpleGainOrTCG[card][step] = new EnumPropertyInternal("Simple Gain Or TCG",		"Use the simple gain value or a TCG curve",				NDTS2100::PF_Enum,		simpleGainOrTCGNames,		numSimpleGainOrTCGNames,	new DoNothing(card, step));
			pCurrentSubGroup->addProperty(hookObject.pSimpleGainOrTCG[card][step]);
			const int maxIntGain = (1<<12)-1;
			hookObject.pSimpleGain[card][step] = new IntPropertyInternal( "Simple Gain 0 to 4095",		"Gain to apply accross whole A Scan (12 bit)",			NDTS2100::PF_Int | NDTS2100::PF_NotCurrentlyValid,		1 << 11,			0,			maxIntGain,	new DoNothing(card, step));
			hookObject.pSimpleGain[card][step]->isVisible = true;
			pCurrentSubGroup->addProperty(hookObject.pSimpleGain[card][step]);
			pCurrentSubGroup->addProperty(new SIShadowPropertyInternal("Simple Gain",						"Gain when no TCG curve is applied",					NDTS2100::PF_Double,			SI::dB,					SI::NoPrefix,		hookObject.pSimpleGain[card][step],			0,		SIShadowPropertyInternal::ProportionalRelationship,		maxGainDecibels / maxIntGain));
		}

		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// Per card settings
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

		// Settings on the main per card tab in IW
		SCO::GroupPropertyInternal *pNDTS2100PerCardSettings = new GroupPropertyInternal("NDTS 2100 Per Card", "Main per card settings", NDTS2100::PF_Group);
		pCardSettingsGroup->addProperty(pNDTS2100PerCardSettings);
		
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// Sequence control
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		pCurrentSubGroup = new GroupPropertyInternal("Sequence Control",	"Controls the sequences for the card",	NDTS2100::PF_Group);
		pNDTS2100PerCardSettings->addProperty(pCurrentSubGroup);
		// Initialise the hardware with maxSteps and then set the number of steps to 1 once init is complete
		hookObject.pNumberOfStepsProp[card] = new IntPropertyInternal("Number Of Steps",			"The number of steps in a sequence",		NDTS2100::PF_Int,		maxSteps,		1,			maxSteps,			new SequenceControlReg(0x003050A4, card));
		pCurrentSubGroup->addProperty(hookObject.pNumberOfStepsProp[card]);  
	

		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// Pulser Voltage
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		pCurrentSubGroup = new GroupPropertyInternal("Pulser Voltage Control", "Controls the HV supply to the pulser", NDTS2100::PF_Group );
		pNDTS2100PerCardSettings->addProperty(pCurrentSubGroup);
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Pulser Voltage",	"The value of the HV control register",			NDTS2100::PF_Int,				100,				0,			1 << 16, new HVDac(card)));
		BaseForPartReg *pHvControl = new BaseForPartReg(0x00305018, card);
		pCurrentSubGroup->addProperty(new EnumPropertyInternal("Pulser HV Enable",			"Enable the high voltage",			NDTS2100::PF_Enum,										falseTrueNames,		numFalseTrueNames,		new PartReg(pHvControl, 0, 0)));		//PartReg(RegAddr, startBit, endBit)
		pCurrentSubGroup->addProperty(new EnumPropertyInternal("Pulser HV Discharge",		"Discharge the high voltage",		NDTS2100::PF_Enum,										falseTrueNames,		numFalseTrueNames,		new PartReg(pHvControl, 1, 1)));
		pCurrentSubGroup->addProperty(new EnumPropertyInternal("Pulser HV Feedback",		"HV feedback",						NDTS2100::PF_Enum | NDTS2100::PF_RdOnly,				falseTrueNames,		numFalseTrueNames,		new PartReg(pHvControl, 31, 31)));

 
        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// RAM Control
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		pCurrentSubGroup = new GroupPropertyInternal("RAM Control",		"RAM control",		NDTS2100::PF_Group);
		pNDTS2100PerCardSettings->addProperty(pCurrentSubGroup);
        BaseForPartReg *pRAMControl = new BaseForPartReg(0x00305028, card);	 
        
         
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// Sequence Repetition Control
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		pCurrentSubGroup = new GroupPropertyInternal("The Sequence Repetition Rate",		"Sequence Repetition Rate",		NDTS2100::PF_Group);
		pNDTS2100PerCardSettings->addProperty(pCurrentSubGroup);
		IntPropertyInternal *pSequenceRepRate = new IntPropertyInternal("Sequence Repetition Rate for Samples",		"Sequence Repetition Rate in samples",		NDTS2100::PF_Int | NDTS2100::PF_NotCurrentlyValid,		defaultRepRateForNewStep*8,		10,		LONG_MAX,		new Reg(0x00305020, card));
		pSequenceRepRate->isVisible = false;
		pCurrentSubGroup->addProperty(pSequenceRepRate);
        pCurrentSubGroup->addProperty(new SIShadowPropertyInternal("Sequence Repetition Rate",		"The frequency at which a complete sequence repeats",		NDTS2100::PF_Double,		SI::Hertz,		SI::Kilo,		pSequenceRepRate,		pBaseSampleFreqSIProp,		SIShadowPropertyInternal::ProportionalRelationship));

        
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// ADC Control
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		pCurrentSubGroup = new GroupPropertyInternal("ADC Control",		"The ADC control register and raw data",		NDTS2100::PF_Group);
		pNDTS2100PerCardSettings->addProperty(pCurrentSubGroup);

		// The serial control bus is represented by two properties, the address and the data.
		// The address must be set before the data register is read or written.
		// The address is the reigster address on the serial bus (e.g. 0xf for the Analog Input / CML enable / disable)
		// The address doesn't write anything to the hardware directly but just stores a value that the data property can use when it is accessed
		hookObject.p9230SerialAddressReg[card] = new IntPropertyInternal("AD 9230 Serial Control Address",	"The 8 bit address within the AD9230 to which the data register will be written to / read from",			NDTS2100::PF_Int,		0,		 0,		0xff, new DoNothing(card,0));
		pCurrentSubGroup->addProperty(hookObject.p9230SerialAddressReg[card]);
		hookObject.p9230SerialDataReg[card] = new IntPropertyInternal("AD 9230 Serial Control Data",	"The Data to read / write to the AD9230 ADC serial control register",			NDTS2100::PF_Int,		0,		 0,		0xff,		new SerialBusRegister(hookObject.p9230SerialAddressReg[card], 0x00305004, card, 0, 0), writeToHardwareEvenIfNoChangeReadFromHardware);
		pCurrentSubGroup->addProperty(hookObject.p9230SerialDataReg[card]);
		// The Raw ADC data register must be written to with any value then read from to retrieve the raw data from the ADC.
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Raw ADC Data",				"Raw ADC data",							NDTS2100::PF_Int,		0,		 0,		(1 << 12) - 1,		new Reg(0x00305008, card), writeToHardwareEvenIfNoChangeReadFromHardware));

		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// DDS Control
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		pCurrentSubGroup = new GroupPropertyInternal("DDS Control Register",		"The DDS control register, only for on board signal generator",		NDTS2100::PF_Group);
		pNDTS2100PerCardSettings->addProperty(pCurrentSubGroup);
		pCurrentSubGroup->addProperty(new IntPropertyInternal("DDS Control",		"DDS control",			NDTS2100::PF_Int,		0,		 0,		0xffff,		new DDSControlReg(0x0030500C, card)));
        
        
   	

		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// Sample Control
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		pCurrentSubGroup = new GroupPropertyInternal("The Sample Control",		"The sample control",		NDTS2100::PF_Group);
		pNDTS2100PerCardSettings->addProperty(pCurrentSubGroup);

		hookObject.pIsFullAScanCapture[card] = new EnumPropertyInternal("Is Full A Capture",	"Set full A Scan capture or snapshot summary mode",	NDTS2100::PF_Enum,		falseTrueNames,		numFalseTrueNames,		new DoNothing(0,0));
		pCurrentSubGroup->addProperty(hookObject.pIsFullAScanCapture[card]);

		BaseForPartReg *pSampleControl = new BaseForPartReg(0x00305044, card);
		pCurrentSubGroup->addProperty(new EnumPropertyInternal("Enable Test Data Pattern Gen Mode",		"enable test data pattern generation mode",							NDTS2100::PF_Enum,				falseTrueNames,					numFalseTrueNames,			new PartReg(pSampleControl, 0, 0)));
		pCurrentSubGroup->addProperty(new EnumPropertyInternal("Enable Sign Extend Data",				"enable sign extend data - default extend the sign to 16 bits",		NDTS2100::PF_Enum,				signExtendStrings,				numSignExtendStrings,		(int*)signExtendEnumToValueMap,		new PartReg(pSampleControl, 1, 1)));
        pCurrentSubGroup->addProperty(new EnumPropertyInternal("Enable Sign And Mag Data Output",		"enable sign and magnitude data output",							NDTS2100::PF_Enum,				falseTrueNames,					numFalseTrueNames,			new PartReg(pSampleControl, 2, 2)));

        
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// Shaft Encoder and Pulse Counter Output
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		pCurrentSubGroup = new GroupPropertyInternal("Shaft Encoder and Pulse Counter Outputs", "The shaft encoder and pulse counter 0, 1, 2, 3 outputs",		NDTS2100::PF_Group);
		pNDTS2100PerCardSettings->addProperty(pCurrentSubGroup);	
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Shaft Encoder 0 Output",		"Shaft encoder 0 output",			NDTS2100::PF_Int,		0,		LONG_MIN,		LONG_MAX,		new Reg(0x00305060, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Shaft Encoder 1 Output",		"Shaft encoder 1 output",			NDTS2100::PF_Int,		0,		LONG_MIN,		LONG_MAX,		new Reg(0x00305064, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Shaft Encoder 2 Output",		"Shaft encoder 2 output",			NDTS2100::PF_Int,		0,		LONG_MIN,		LONG_MAX,		new Reg(0x00305068, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Shaft Encoder 3 Output",		"Shaft encoder 3 output",			NDTS2100::PF_Int,		0,		LONG_MIN,		LONG_MAX,		new Reg(0x0030506C, card))); 
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Dual Encoder Counter",		"Dual encoder counter",				NDTS2100::PF_Int,		0,		LONG_MIN,		LONG_MAX,		new Reg(0x00305070, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Pulse Counter 0 Output",		"Digital I/O pulse counter 0",		NDTS2100::PF_Int,		0,		LONG_MIN,		LONG_MAX,		new Reg(0x00305074, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Pulse Counter 1 Output",		"Digital I/O pulse counter 1",		NDTS2100::PF_Int,		0,		LONG_MIN,		LONG_MAX,		new Reg(0x00305078, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Pulse Counter 2 Output",		"Digital I/O pulse counter 2",		NDTS2100::PF_Int,		0,		LONG_MIN,		LONG_MAX,		new Reg(0x0030507C, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Pulse Counter 3 Output",		"Digital I/O pulse counter 3",		NDTS2100::PF_Int,		0,		LONG_MIN,		LONG_MAX,		new Reg(0x00305080, card)));

        
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// Relay Control
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		pCurrentSubGroup = new GroupPropertyInternal("The Relay Control",		"The relay control",		NDTS2100::PF_Group);
		pNDTS2100PerCardSettings->addProperty(pCurrentSubGroup);
		pCurrentSubGroup->addProperty(new EnumPropertyInternal("Relay Control On",		"Relay control on or off",				NDTS2100::PF_Enum,			falseTrueNames,				numFalseTrueNames,			new Reg(0x003050A0, card)));
 

		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// Multi-Board Control
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		pCurrentSubGroup = new GroupPropertyInternal("The Multi-Board Control",		"The multi-board control",		NDTS2100::PF_Group);
		pNDTS2100PerCardSettings->addProperty(pCurrentSubGroup);
        BaseForPartReg *pMultiBoardControl = new BaseForPartReg(0x003050A8, card);
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Board ID Switch",					"The board ID switch",									NDTS2100::PF_Int,		0,		0,		15,		new PartReg(pMultiBoardControl, 0, 3)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Enable Encoder Transmission",		"Enable encoder 0-3 transmission",						NDTS2100::PF_Int,		0,		0,		15,		new PartReg(pMultiBoardControl, 4, 7)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Enable LVDS Link Channels",		"Enable LVDS link channels bit8=ch0 .. bit15=ch7",			NDTS2100::PF_Int,		0,		0,		255,	new PartReg(pMultiBoardControl, 8, 15)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Enable DMA Wait Other Boards",	"Enable DMA wait for other boards bit16=ch0..bit23=ch7",	NDTS2100::PF_Int,		0,		0,		255,	new PartReg(pMultiBoardControl, 16, 23)));
        

		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// DSP FPGA Version Number Control
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		pCurrentSubGroup = new GroupPropertyInternal("The DSP FPGA Version Control",		"The DSP FPGA version control",		NDTS2100::PF_Group);
		pNDTS2100PerCardSettings->addProperty(pCurrentSubGroup);
        BaseForPartReg *pDSPFPGAControl = new BaseForPartReg(0x00305FFC, card);
		pCurrentSubGroup->addProperty(new IntPropertyInternal("DSP FPGA Rev Number",				"The DSP FPGA revision number",							NDTS2100::PF_Int,		0,		0,		4095,		new PartReg(pDSPFPGAControl, 0, 11)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("DSP FPGA Ver Number",				"The DSP FPGA version number",							NDTS2100::PF_Int,		0,		0,		15,			new PartReg(pDSPFPGAControl, 12, 15)));
        

		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// Per card Scan Triggering
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		pCurrentSubGroup = new GroupPropertyInternal("Scan Triggering", "Controls how scans are collected when in scanning mode card", NDTS2100::PF_Group );
		pNDTS2100PerCardSettings->addProperty(pCurrentSubGroup);
		// When scanning, Scanning can use Simple (same as idle), Encoder trigger or free running trigger modes
		hookObject.pScanTriggerModeProp[card] = new EnumPropertyInternal("Scanning Trigger Mode",	"Which trigger mode to use when scanning",		NDTS2100::PF_Enum,		scanTriggerModeNames, numScanTriggerModeNames, new DoNothing(card, 0));	
		pCurrentSubGroup->addProperty(hookObject.pScanTriggerModeProp[card]);
		hookObject.pEncoderToTriggerOffProp[card] = new EnumPropertyInternal("Sequence Trigger Encoder Select",		"select the sequence trigger encoder",				NDTS2100::PF_Enum,			SeqTrigEncSelectNames,			numSeqTrigEncSelectNames,			new Reg(0x00305034, card));  
		pCurrentSubGroup->addProperty(hookObject.pEncoderToTriggerOffProp[card]);

		pCurrentSubGroup->addProperty(new IntPropertyInternal("Encoder Clicks Per Sequence",	"Encoder clicks between the running of each sequence",				NDTS2100::PF_Int,		50,			1,			(1 << 24) - 1,				new Reg(0x0030502C, card, 0, 0)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Fractional Encoder Clicks Per Sequence",		"Fractional clicks per Sequence n/65536 (16 bit)",		NDTS2100::PF_Int,		0,			0,			(1 << 16) - 1,				new Reg(0x00305030, card, 0, 0)));
        
		hookObject.pBScanRepRateSamplesProp[card] = new IntPropertyInternal("B Scan Rep Rate for Samples",			"B Scan repetition rate (samples)",				NDTS2100::PF_Int | NDTS2100::PF_NotCurrentlyValid,			99999999,		10,			LONG_MAX,				new Reg(0x00303020, card));
		hookObject.pBScanRepRateSamplesProp[card]->isVisible = false;
		pCurrentSubGroup->addProperty(hookObject.pBScanRepRateSamplesProp[card]);
		hookObject.pBScanRepRateSIProp[card] = new SIShadowPropertyInternal("B Scan Repetition Rate", "The frequency at which B Scans are captured when free running", NDTS2100::PF_Double    , SI::Hertz, SI::Kilo, hookObject.pBScanRepRateSamplesProp[card], pBaseSampleFreqSIProp, SIShadowPropertyInternal::ProportionalRelationship);
		pCurrentSubGroup->addProperty(hookObject.pBScanRepRateSIProp[card]);

// Moved to one snapshot for all cards
//		hookObject.pTakeSnapshotProp[card] = new EventPropertyInternal("Take Snapshot",	"Take a snapshot of the collected data",		NDTS2100::PF_Event | NDTS2100::PF_NotCurrentlyValid ,	new TakeSnapshot(pFactoryPointer->getSnapshotInternal(), card));
//		pCurrentSubGroup->addProperty(hookObject.pTakeSnapshotProp[card]);
		pCurrentSubGroup->addProperty(new IntPropertyInternal("B Scans in Snapshot",	"The number of B Scans in the currently collected snapshot",		NDTS2100::PF_Int | NDTS2100::PF_NotCurrentlyValid | NDTS2100::PF_RdOnly, new GetNumberOfBScansInSnapshot(pFactoryPointer->getSnapshotInternal(), card)));

		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// System FPGA - per card
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

		// Settings on the main per card tab in IW
		SCO::GroupPropertyInternal *pSystemFPGASettings = new GroupPropertyInternal("System FPGA", "Per card settings on the System FPGA", NDTS2100::PF_Group);
		pCardSettingsGroup->addProperty(pSystemFPGASettings);

		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// Flags
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		pCurrentSubGroup = new GroupPropertyInternal("Flags", "Flags that monitor or control the monitoring of under / over range values", NDTS2100::PF_Group );
		pSystemFPGASettings->addProperty(pCurrentSubGroup);
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Enable Auto Polling",	"Enable auto-polling",																NDTS2100::PF_Int,		1,			0,				1,			new Reg(0x00300010, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Under Range Flags", "Read Only flags that are active when a value is under range",							NDTS2100::PF_Int | NDTS2100::PF_RdOnly,		new Reg(0x00300014, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Over Range Flags", "Read Only flags that are active when a value is over range",								NDTS2100::PF_Int | NDTS2100::PF_RdOnly,		new Reg(0x00300018, card)));
		
		pCurrentSubGroup->addProperty(new IntPropertyInternal("System Monitor D0 Under Range", "A set flag means light LED DO when its value is under range",				NDTS2100::PF_Int,		0,		LONG_MIN,		LONG_MAX,		new Reg(0x0030001C, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("System Monitor D1 Under Range", "A set flag means light LED D1 when its value is under range",				NDTS2100::PF_Int,		0,		LONG_MIN,		LONG_MAX,		new Reg(0x00300020, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("System Monitor D2 Under Range", "A set flag means light LED D2 when its value is under range",				NDTS2100::PF_Int,		0,		LONG_MIN,		LONG_MAX,		new Reg(0x00300024, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("System Monitor D3 Under Range", "A set flag means light LED D3 when its value is under range",				NDTS2100::PF_Int,		0,		LONG_MIN,		LONG_MAX,		new Reg(0x00300028, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("System Monitor D4 Under Range", "A set flag means light LED D4 when its value is under range",				NDTS2100::PF_Int,		0,		LONG_MIN,		LONG_MAX,		new Reg(0x0030002C, card)));

		pCurrentSubGroup->addProperty(new IntPropertyInternal("System Monitor D0 Over Range", "A set flag means light LED DO when its value is over range",					NDTS2100::PF_Int,		0,		LONG_MIN,		LONG_MAX,		new Reg(0x00300030, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("System Monitor D1 Over Range", "A set flag means light LED D1 when its value is over range",					NDTS2100::PF_Int,		0,		LONG_MIN,		LONG_MAX,		new Reg(0x00300034, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("System Monitor D2 Over Range", "A set flag means light LED D2 when its value is over range",					NDTS2100::PF_Int,		0,		LONG_MIN,		LONG_MAX,		new Reg(0x00300038, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("System Monitor D3 Over Range", "A set flag means light LED D3 when its value is over range",					NDTS2100::PF_Int,		0,		LONG_MIN,		LONG_MAX,		new Reg(0x0030003C, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("System Monitor D4 Over Range", "A set flag means light LED D4 when its value is over range",					NDTS2100::PF_Int,		0,		LONG_MIN,		LONG_MAX,		new Reg(0x00300040, card)));
         
		pCurrentSubGroup->addProperty(new IntPropertyInternal("System Monitor OK Under Range", "A set flag means light LED OK when its value is under range",				NDTS2100::PF_Int,		0,		LONG_MIN,		LONG_MAX,		new Reg(0x00300044, card)));

		pCurrentSubGroup->addProperty(new IntPropertyInternal("System Monitor OK Over Range", "A set flag means light LED OK when its value is over range",					NDTS2100::PF_Int,		0,		LONG_MIN,		LONG_MAX,		new Reg(0x00300048, card)));
        
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// Values
		//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		pCurrentSubGroup = new GroupPropertyInternal("Monitor Values", "Actual values and limits", NDTS2100::PF_Group );
		pSystemFPGASettings->addProperty(pCurrentSubGroup);
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Raw 12V", "Reports the value of the Raw 12V supply",					NDTS2100::PF_Int | NDTS2100::PF_RdOnly,		new Reg(0x00300080, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Raw 5V",  "Reports the value of the Raw 5V supply",					NDTS2100::PF_Int | NDTS2100::PF_RdOnly,		new Reg(0x00300084, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Pos 12V",	 "Reports the value of the +12V supply",				NDTS2100::PF_Int | NDTS2100::PF_RdOnly,		new Reg(0x00300088, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Neg 12V",	 "Reports the value of the -12V supply",				NDTS2100::PF_Int | NDTS2100::PF_RdOnly,		new Reg(0x0030008C, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor pA5V",    "Reports the value of the pA5V supply",					NDTS2100::PF_Int | NDTS2100::PF_RdOnly,		new Reg(0x00300090, card)));
        pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor nA5V",    "Reports the value of the nA5V supply",					NDTS2100::PF_Int | NDTS2100::PF_RdOnly,		new Reg(0x00300094, card)));
        pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor pA2.5V",  "Reports the value of the pA2.5V supply",					NDTS2100::PF_Int | NDTS2100::PF_RdOnly,		new Reg(0x00300098, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor nA2.5V",  "Reports the value of the nA2.5V supply",					NDTS2100::PF_Int | NDTS2100::PF_RdOnly,		new Reg(0x0030009C, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor pD3V3",   "Reports the value of the pD3V3 supply",					NDTS2100::PF_Int | NDTS2100::PF_RdOnly,		new Reg(0x003000A0, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor pD2.5V",  "Reports the value of the pD2.5V supply",					NDTS2100::PF_Int | NDTS2100::PF_RdOnly,		new Reg(0x003000A4, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor pD1V2",   "Reports the value of the pD1V2 supply",					NDTS2100::PF_Int | NDTS2100::PF_RdOnly,		new Reg(0x003000A8, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor p2Vref",  "Reports the value of the p2Vref supply",					NDTS2100::PF_Int | NDTS2100::PF_RdOnly,		new Reg(0x003000AC, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Vcal Pos",   "Reports the value of the Vcal+ supply",				NDTS2100::PF_Int | NDTS2100::PF_RdOnly,		new Reg(0x003000B0, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Vcal Neg",	 "Reports the value of the Vcal- supply",				NDTS2100::PF_Int | NDTS2100::PF_RdOnly,		new Reg(0x003000B4, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Pulse Voltage",    "Reports the value of the Pulse Voltage supply",	NDTS2100::PF_Int | NDTS2100::PF_RdOnly,		new Reg(0x003000B8, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor HT",    "Reports the value of the HT supply",						NDTS2100::PF_Int | NDTS2100::PF_RdOnly,		new Reg(0x003000BC, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor pD1V8",   "Reports the value of the pD1V8 supply",					NDTS2100::PF_Int | NDTS2100::PF_RdOnly,		new Reg(0x003000C0, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor HV Control",  "Reports the value of the HV Control supply",			NDTS2100::PF_Int | NDTS2100::PF_RdOnly,		new Reg(0x003000C4, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor AVDD",    "Reports the value of the AVDD supply",					NDTS2100::PF_Int | NDTS2100::PF_RdOnly,		new Reg(0x003000C8, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor DRVDD",   "Reports the value of the DRVDD supply",					NDTS2100::PF_Int | NDTS2100::PF_RdOnly,		new Reg(0x003000CC, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor TCG Voltage",   "Reports the value of the TCG Voltage supply",		NDTS2100::PF_Int | NDTS2100::PF_RdOnly,		new Reg(0x003000D0, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor AIO 5V",   "Reports the value of the AIO 5V supply",					NDTS2100::PF_Int | NDTS2100::PF_RdOnly,		new Reg(0x003000D4, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor PCI 3V3",   "Reports the value of the PCI 3V3 supply",				NDTS2100::PF_Int | NDTS2100::PF_RdOnly,		new Reg(0x003000D8, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor PCI 2.5VCC",   "Reports the value of the PCI 2.5VCC supply",			NDTS2100::PF_Int | NDTS2100::PF_RdOnly,		new Reg(0x003000DC, card)));
        
        
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Min Raw 12V", "Sets the minimum of the Raw 12V supply below this value an alarm is generated",					NDTS2100::PF_Int,		0x7c0,		LONG_MIN,		LONG_MAX,		new Reg(0x00300100, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Min Raw 5V", "Sets the minimum of the Raw 5V supply below this value an alarm is generated",						NDTS2100::PF_Int,		0x770,		LONG_MIN,		LONG_MAX,		new Reg(0x00300104, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Min Pos 12V", "Sets the minimum of the +12V supply below this value an alarm is generated",						NDTS2100::PF_Int,		0x7d0,		LONG_MIN,		LONG_MAX,		new Reg(0x00300108, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Min Neg 12V", "Sets the minimum of the -12V supply below this value an alarm is generated",						NDTS2100::PF_Int,		0x7c0,		LONG_MIN,		LONG_MAX,		new Reg(0x0030010C, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Min pA5V", "Sets the minimum of the pA5V supply below this value an alarm is generated",							NDTS2100::PF_Int,		0x7f0,		LONG_MIN,		LONG_MAX,		new Reg(0x00300110, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Min nA5V", "Sets the minimum of the nA5V supply below this value an alarm is generated",							NDTS2100::PF_Int,		0x7b0,		LONG_MIN,		LONG_MAX,		new Reg(0x00300114, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Min pA2.5V", "Sets the minimum of the pA2.5V supply below this value an alarm is generated",						NDTS2100::PF_Int,		0x830,		LONG_MIN,		LONG_MAX,		new Reg(0x00300118, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Min nA2.5V", "Sets the minimum of the nA2.5V supply below this value an alarm is generated",						NDTS2100::PF_Int,		0x7c0,		LONG_MIN,		LONG_MAX,		new Reg(0x0030011C, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Min pD3V3", "Sets the minimum of the pD3V3 supply below this value an alarm is generated",						NDTS2100::PF_Int,		0x7a0,		LONG_MIN,		LONG_MAX,		new Reg(0x00300120, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Min pD2.5V", "Sets the minimum of the Raw 12V supply below this value an alarm is generated",					NDTS2100::PF_Int,		0x7b0,		LONG_MIN,		LONG_MAX,		new Reg(0x00300124, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Min pD1V2", "Sets the minimum of the pD1V2 supply below this value an alarm is generated",						NDTS2100::PF_Int,		0xb80,		LONG_MIN,		LONG_MAX,		new Reg(0x00300128, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Min p2Vref", "Sets the minimum of the p2Vref supply below this value an alarm is generated",						NDTS2100::PF_Int,		0x7d0,		LONG_MIN,		LONG_MAX,		new Reg(0x0030012C, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Min Vcal Pos", "Sets the minimum of the Vcal+ supply below this value an alarm is generated",					NDTS2100::PF_Int,		0x120,		LONG_MIN,		LONG_MAX,		new Reg(0x00300130, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Min Vcal Neg", "Sets the minimum of the Vcal- supply below this value an alarm is generated",					NDTS2100::PF_Int,		0x740,		LONG_MIN,		LONG_MAX,		new Reg(0x00300134, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Min Pulse Voltage", "Sets the minimum of the Pulse Voltage supply below this value an alarm is generated",		NDTS2100::PF_Int,		0xb70,		LONG_MIN,		LONG_MAX,		new Reg(0x00300138, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Min HT", "Sets the minimum of the HT supply below this value an alarm is generated",								NDTS2100::PF_Int,		0,			LONG_MIN,		LONG_MAX,		new Reg(0x0030013C, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Min pD1V8", "Sets the minimum of the pD1V8 supply below this value an alarm is generated",						NDTS2100::PF_Int,		0,			LONG_MIN,		LONG_MAX,		new Reg(0x00300140, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Min HV Control", "Sets the minimum of the HV Control supply below this value an alarm is generated",				NDTS2100::PF_Int,		0,			LONG_MIN,		LONG_MAX,		new Reg(0x00300144, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Min AVDD", "Sets the minimum of the AVDD supply below this value an alarm is generated",							NDTS2100::PF_Int,		0x700,		LONG_MIN,		LONG_MAX,		new Reg(0x00300148, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Min DRVDD", "Sets the minimum of the DRVDD supply below this value an alarm is generated",						NDTS2100::PF_Int,		0x700,		LONG_MIN,		LONG_MAX,		new Reg(0x0030014C, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Min TCG Voltage", "Sets the minimum of the TCG Voltage supply below this value an alarm is generated",			NDTS2100::PF_Int,		0,			LONG_MIN,		LONG_MAX,		new Reg(0x00300150, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Min AIO 5V", "Sets the minimum of the AIO 5V supply below this value an alarm is generated",						NDTS2100::PF_Int,		0x7f0,		LONG_MIN,		LONG_MAX,		new Reg(0x00300154, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Min PCI 3V3", "Sets the minimum of the PCI 3V3 supply below this value an alarm is generated",					NDTS2100::PF_Int,		0x7c0,		LONG_MIN,		LONG_MAX,		new Reg(0x00300158, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Min PCI 2.5VCC", "Sets the minimum of the PCI 2.5VCC supply below this value an alarm is generated",				NDTS2100::PF_Int,		0x7c0,		LONG_MIN,		LONG_MAX,		new Reg(0x0030015C, card)));


		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Max Raw 12V", "Sets the maximum of the Raw 12V supply below this value an alarm is generated",					NDTS2100::PF_Int,		0x7c6,		LONG_MIN,		LONG_MAX,		new Reg(0x00300180, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Max Raw 5V", "Sets the maximum of the Raw 5V supply below this value an alarm is generated",						NDTS2100::PF_Int,		0x7b5,		LONG_MIN,		LONG_MAX,		new Reg(0x00300184, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Max Pos 12V", "Sets the maximum of the +12V supply below this value an alarm is generated",						NDTS2100::PF_Int,		0x7df,		LONG_MIN,		LONG_MAX,		new Reg(0x00300188, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Max Neg 12V", "Sets the maximum of the -12V supply below this value an alarm is generated",						NDTS2100::PF_Int,		0x7cf,		LONG_MIN,		LONG_MAX,		new Reg(0x0030018C, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Max pA5V", "Sets the maximum of the pA5V supply below this value an alarm is generated",							NDTS2100::PF_Int,		0x7ff,		LONG_MIN,		LONG_MAX,		new Reg(0x00300190, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Max nA5V", "Sets the maximum of the nA5V supply below this value an alarm is generated",							NDTS2100::PF_Int,		0x7cf,		LONG_MIN,		LONG_MAX,		new Reg(0x00300194, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Max pA2.5V", "Sets the maximum of the pA2.5V supply below this value an alarm is generated",						NDTS2100::PF_Int,		0x83f,		LONG_MIN,		LONG_MAX,		new Reg(0x00300198, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Max nA2.5V", "Sets the maximum of the nA2.5V supply below this value an alarm is generated",						NDTS2100::PF_Int,		0x7cf,		LONG_MIN,		LONG_MAX,		new Reg(0x0030019C, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Max pD3V3", "Sets the maximum of the pD3V3 supply below this value an alarm is generated",						NDTS2100::PF_Int,		0x7af,		LONG_MIN,		LONG_MAX,		new Reg(0x003001A0, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Max pD2.5V", "Sets the maximum of the Raw 12V supply below this value an alarm is generated",					NDTS2100::PF_Int,		0x7cf,		LONG_MIN,		LONG_MAX,		new Reg(0x003001A4, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Max pD1V2", "Sets the maximum of the pD1V2 supply below this value an alarm is generated",						NDTS2100::PF_Int,		0xb9f,		LONG_MIN,		LONG_MAX,		new Reg(0x003001A8, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Max p2Vref", "Sets the maximum of the p2Vref supply below this value an alarm is generated",						NDTS2100::PF_Int,		0x7df,		LONG_MIN,		LONG_MAX,		new Reg(0x003001AC, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Max Vcal Pos", "Sets the maximum of the Vcal+ supply below this value an alarm is generated",					NDTS2100::PF_Int,		0x13f,		LONG_MIN,		LONG_MAX,		new Reg(0x003001B0, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Max Vcal Neg", "Sets the maximum of the Vcal- supply below this value an alarm is generated",					NDTS2100::PF_Int,		0x74f,		LONG_MIN,		LONG_MAX,		new Reg(0x003001B4, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Max Pulse Voltage", "Sets the maximum of the Pulse Voltage supply below this value an alarm is generated",		NDTS2100::PF_Int,		0xb7f,		LONG_MIN,		LONG_MAX,		new Reg(0x003001B8, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Max HT", "Sets the maximum of the HT supply below this value an alarm is generated",								NDTS2100::PF_Int,		0xf,		LONG_MIN,		LONG_MAX,		new Reg(0x003001BC, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Max pD1V8", "Sets the maximum of the pD1V8 supply below this value an alarm is generated",						NDTS2100::PF_Int,		0xf,		LONG_MIN,		LONG_MAX,		new Reg(0x003001C0, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Max HV Control", "Sets the maximum of the HV Control supply below this value an alarm is generated",				NDTS2100::PF_Int,		0xf,		LONG_MIN,		LONG_MAX,		new Reg(0x003001C4, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Max AVDD", "Sets the maximum of the AVDD supply below this value an alarm is generated",							NDTS2100::PF_Int,		0x71f,		LONG_MIN,		LONG_MAX,		new Reg(0x003001C8, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Max DRVDD", "Sets the maximum of the DRVDD supply below this value an alarm is generated",						NDTS2100::PF_Int,		0x70f,		LONG_MIN,		LONG_MAX,		new Reg(0x003001CC, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Max TCG Voltage", "Sets the maximum of the TCG Voltage supply below this value an alarm is generated",			NDTS2100::PF_Int,		0xf,		LONG_MIN,		LONG_MAX,		new Reg(0x003001D0, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Max AIO 5V", "Sets the maximum of the AIO 5V supply below this value an alarm is generated",						NDTS2100::PF_Int,		0x7ff,		LONG_MIN,		LONG_MAX,		new Reg(0x003001D4, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Max PCI 3V3", "Sets the maximum of the PCI 3V3 supply below this value an alarm is generated",					NDTS2100::PF_Int,		0x7cf,		LONG_MIN,		LONG_MAX,		new Reg(0x003001D8, card)));
		pCurrentSubGroup->addProperty(new IntPropertyInternal("Monitor Max PCI 2.5VCC", "Sets the maximum of the PCI 2.5VCC supply below this value an alarm is generated",				NDTS2100::PF_Int,		0x7cf,		LONG_MIN,		LONG_MAX,		new Reg(0x003001DC, card)));


	}
	//////////////////////////////////////////////////////////////////////////////////
	// Global settings 
	//////////////////////////////////////////////////////////////////////////////////
	pCurrentSubGroup = new GroupPropertyInternal("Global Scan Control", "Global settings to control scan collection",		NDTS2100::PF_Group | NDTS2100::PF_NotCurrentlyValid);
	pRootGroup->addProperty(pCurrentSubGroup);
	pCurrentSubGroup->addProperty(hookObject.pIsScanningProp);
	pCurrentSubGroup->addProperty(hookObject.pNumberOfCardsProp);
	pCurrentSubGroup->addProperty(pBaseSampleFreqSIProp);
	// Left cardIndex of zero in case we want to make TakeSnapshot per card again
	hookObject.pTakeSnapshotProp= new EventPropertyInternal("Take Snapshot",	"Take a snapshot of the collected data",		NDTS2100::PF_Event | NDTS2100::PF_NotCurrentlyValid ,	new TakeSnapshot(pFactoryPointer->getSnapshotInternal(), 0));
//	pCurrentSubGroup->addProperty(hookObject.pTakeSnapshotProp[card]);
	pCurrentSubGroup->addProperty(hookObject.pTakeSnapshotProp);

	pCurrentSubGroup->addProperty(new IntPropertyInternal("Maximum Number of Gates",	"The maximum number of gates",		NDTS2100::PF_Int | NDTS2100::PF_RdOnly,		maxGates, maxGates, maxGates,	0,	0));

	// Access any address for testing
	// The address must be set before the data register is read or written.
	// The address is the reigster address absolute value e.g. 0x00301234
	// The address doesn't write anything to the hardware directly but just stores a value that the data property can use when it is accessed
	IntPropertyInternal *pAnyRegAddressProp = new IntPropertyInternal("Address For Access Any Register On Card 0",	"Address to write to when using the access any address register",			NDTS2100::PF_Int,		0,		 INT_MIN,		INT_MAX, new DoNothing(0,0));
	pCurrentSubGroup->addProperty(pAnyRegAddressProp);
	pCurrentSubGroup->addProperty(new IntPropertyInternal("Data For Access Any Register On Card 0",	"The Data to read / write to the address set by address for access any register",			NDTS2100::PF_Int,		0,		 INT_MIN,		INT_MAX,		new AccessAnyAddressRegister(pAnyRegAddressProp, 0x00300000, 0, 0, 0), writeToHardwareEvenIfNoChangeReadFromHardware));
   

	//////////////////////////////////////////////////////////////////////////////////
	// Error log functions - used by the App to read the SDK error log
	//////////////////////////////////////////////////////////////////////////////////
	pCurrentSubGroup = new GroupPropertyInternal("Error Log", "Reading the SDK error log",		NDTS2100::PF_Group | NDTS2100::PF_NotCurrentlyValid);
	pRootGroup->addProperty(pCurrentSubGroup);
	pCurrentSubGroup->addProperty(new IntPropertyInternal("Lines In Log",	"The number of lines currently in the error log",		NDTS2100::PF_Int | NDTS2100::PF_NotCurrentlyValid | NDTS2100::PF_RdOnly,		new GetNumberOfErrorLogLines()));
	pCurrentSubGroup->addProperty(new EventPropertyInternal("Clear Log",	"Clear the entries from the log - call once the entries have been read",		NDTS2100::PF_Event | NDTS2100::PF_NotCurrentlyValid,	new ClearErrorLog()));

	//////////////////////////////////////////////////////////////////////////////////
	// Input and Output - only one IO card in a system connected to the master card (0)
	//////////////////////////////////////////////////////////////////////////////////
	// Create an array and SI shadow for the gain adjustment for each beam, i.e. the normalisation values
	pCurrentSubGroup = new GroupPropertyInternal("Input and Output",		"Digital and Analogue IO and encoders",		NDTS2100::PF_Group);
	pRootGroup->addProperty(pCurrentSubGroup);

	SCO::GroupPropertyInternal *pDIOArrayGroup = new GroupPropertyInternal("Digital IO Array", "Group indexed by IO number with a sub-group for each Digital.  There is one of these gropus for each card",		NDTS2100::PF_Group | NDTS2100::PF_NotCurrentlyValid);
	pDIOArrayGroup->isArray = true;
	pCurrentSubGroup->addProperty(pDIOArrayGroup);
	for (int i=0; i < numDigitalIOLines; i++)
	{
		GroupPropertyInternal *pDIOLineGroup = new GroupPropertyInternal("Digital IO Properties", "Group containing the properties for a single Digital Input / Output line",		NDTS2100::PF_Group | NDTS2100::PF_Array | NDTS2100::PF_NotCurrentlyValid);
		pDIOArrayGroup->addProperty(pDIOLineGroup);
		// here! temp address that gets ignored as the IO registers have not been defined.  
		// IO may be accessed via via LVDS rather than having a register each.  In this case, define a new Reg derived class that is similar to the SerialReg class
		pDIOLineGroup->addProperty(new IntPropertyInternal("Digital IO",	"Digital I/O Line - read if an input or write if an output",			NDTS2100::PF_Int | NDTS2100::PF_NotCurrentlyValid,		0,		0,		1,		new Reg(0x10400000 + 4*i, 0)));			//0x10400000 for dummy use, replace 0x10300000 in future
		pDIOLineGroup->addProperty(new IntPropertyInternal("Data Direction",	"Digital I/O Data Direction Register 1 for output 0 for input",		NDTS2100::PF_Int | NDTS2100::PF_NotCurrentlyValid,		0,		0,		1,		new Reg(0x10400000 + 4*i, 0)));
	}

	SCO::GroupPropertyInternal *pAinArrayGroup = new GroupPropertyInternal("Analogue Inputs Array", "Group indexed by IO number with a sub-group for each An In.  There is one of these gropus for each card",		NDTS2100::PF_Group | NDTS2100::PF_NotCurrentlyValid);
	pAinArrayGroup->isArray = true;
	pCurrentSubGroup->addProperty(pAinArrayGroup);
	for (int i=0; i < numAnalogueInputLines; i++)
	{
		GroupPropertyInternal *pAnalogueInputGroup = new GroupPropertyInternal("Analogue Input Group", "Auxilliary Analogue input not used for sampling a waveform.  Range of (0..65535)",		NDTS2100::PF_Group | NDTS2100::PF_Array | NDTS2100::PF_NotCurrentlyValid);
		pAinArrayGroup->addProperty(pAnalogueInputGroup);
		// here! temp address that gets ignored as the IO registers have not been defined.  
		// IO may be accessed via via LVDS rather than having a register each.  In this case, define a new Reg derived class that is similar to the SerialReg class
		pAnalogueInputGroup->addProperty(new IntPropertyInternal("Analogue Input",		"",		NDTS2100::PF_Int | NDTS2100::PF_NotCurrentlyValid,		new Reg(0x10400000 + 4*i, 0)));
	}

	SCO::GroupPropertyInternal *pAnalogueOutputArrayGroup = new GroupPropertyInternal("Analogue Outputs Array", "Group indexed by IO number with a sub-group for each An In.  There is one of these gropus for each card",		NDTS2100::PF_Group | NDTS2100::PF_NotCurrentlyValid);
	pAnalogueOutputArrayGroup->isArray = true;
	pCurrentSubGroup->addProperty(pAnalogueOutputArrayGroup);
	for (int i=0; i < numAnalogueOutputLines; i++)
	{
		GroupPropertyInternal *pAnalogueOutputGroup = new GroupPropertyInternal("Analogue Output Group",	"Auxilliary Analogue Output not used for sampling a waveform.  Range of (0..65535)",		NDTS2100::PF_Group | NDTS2100::PF_Array | NDTS2100::PF_NotCurrentlyValid);
		pAnalogueOutputArrayGroup->addProperty(pAnalogueOutputGroup);
		// here! temp address that gets ignored as the IO registers have not been defined.  
		// IO may be accessed via via LVDS rather than having a register each.  In this case, define a new Reg derived class that is similar to the SerialReg class
		pAnalogueOutputGroup->addProperty(new IntPropertyInternal("Analogue Output",	"",		NDTS2100::PF_Int | NDTS2100::PF_NotCurrentlyValid,		128,	0,		255,		new Reg(0x10400000  + 4*i, 0)));
	}

	SCO::GroupPropertyInternal *pEncoderValueArrayGroup = new GroupPropertyInternal("Encoder Values Array", "Group indexed by IO number with a sub-group for each An In.  There is one of these gropus for each card",		NDTS2100::PF_Group | NDTS2100::PF_NotCurrentlyValid);
	pEncoderValueArrayGroup->isArray = true;
	pCurrentSubGroup->addProperty(pEncoderValueArrayGroup);
	for (int i=0; i < maxEncoders; i++)
	{
		GroupPropertyInternal *pEncoderValueGroup = new GroupPropertyInternal("Encoder Value Group", "Encoder Value 32 bit signed",		NDTS2100::PF_Group | NDTS2100::PF_Array | NDTS2100::PF_NotCurrentlyValid);
		pEncoderValueArrayGroup->addProperty(pEncoderValueGroup);
		pEncoderValueGroup->addProperty(new IntPropertyInternal("Encoder Value",	"",		NDTS2100::PF_Int | NDTS2100::PF_NotCurrentlyValid,		new Reg(0x00303050 + 4*i, 0)));
	}

	SCO::GroupPropertyInternal *pEncoderResetArrayGroup = new GroupPropertyInternal("Encoder Resets Array", "Group indexed by IO number with a sub-group for each An In.  There is one of these gropus for each card",		NDTS2100::PF_Group | NDTS2100::PF_NotCurrentlyValid);
	pEncoderResetArrayGroup->isArray = true;
	pCurrentSubGroup->addProperty(pEncoderResetArrayGroup);
	for (int i=0; i < maxEncoders; i++)
	{
		GroupPropertyInternal *pEncoderResetGroup = new GroupPropertyInternal("Encoder Reset Group",	"Encoder Reset",		NDTS2100::PF_Group | NDTS2100::PF_Array | NDTS2100::PF_NotCurrentlyValid);
		pEncoderResetArrayGroup->addProperty(pEncoderResetGroup);
		pEncoderResetGroup->addProperty(new EventPropertyInternal("Encoder Reset",		"",		NDTS2100::PF_Int | NDTS2100::PF_NotCurrentlyValid,		new Reg(0x00303050 + 4*i, 0)));
	}

//	pRootGroup->setGroupHooks(dynamic_cast<GroupHooks*>(&hookObject));
	pRootGroup->setGroupHooks(&hookObject);
	hookObject.setTcg(pTcg);
}

SDKPropertiesCollection::~SDKPropertiesCollection(void)
{
	delete pRootGroup;
}

// Return the root setting - all the application needs
GroupProperty *SDKPropertiesCollection::getRoot()
{
	return dynamic_cast<NDTS::SCO::GroupProperty*>(pRootGroup);
}


void  SDKPropertiesCollection::initialise()
{
	// Initialise the TCG before sending the default values
	hookObject.pTcg->initialise();

	// initComplete sets all the default values
	pRootGroup->initComplete();

	// After the init, we know how many cards we have.  After ->initComplete, it is safe to updateValue
	hookObject.pNumberOfCardsProp->updateValue(globalState.numberOfCards);

	// Cards were initialised with number of steps set to max.
	// Set number of steps back to 1 as a sensible default
	for (int card=0; card < hookObject.pNumberOfCardsProp->getValue(); card++)
		hookObject.pNumberOfStepsProp[card]->setValue(1);

	// Apply ADC values here because it uses the ADC reg that is also accessible as a property
	for (int card=0; card < globalState.numberOfCards; card++)
	{
		// Set the AD9230 default values
		setADCReg(card, 0x0f, 0x02); // ain_config Bit 1 CML enable Bit 2 Analog input disable off 
		setADCReg(card, 0x14, 0x01); // output_mode 2's complement  
		setADCReg(card, 0x15, 0x04); // LVDS Fine adjust 2.75mA
		setADCReg(card, 0x17, 0x02); // Output clock delay 0.2nS
		setADCReg(card, 0x18, 0x00); // Input voltage range gain tweak (To be replaced by calibration algorithm)
	}

}

void SDKPropertiesCollection::setADCReg(int card, int addr, int data)
{
	hookObject.p9230SerialAddressReg[card]->setValue(addr);
	hookObject.p9230SerialDataReg[card]->setValue(data);
}



void  SDKPropertiesCollection::uninitialise()
{
	if (!globalState.isInitialised)
		return;
	globalState.isInitialised = false;
	// Turn off the DI unit relay on shutdown 	
//	NDTS_Boolean isOk = RQ_SetDIBoardState(globalState.cardIndex, NDTS_BTrue) ;
//	RQT_CollectUninitialise(globalState.cardIndex);
//	RQ_FreeRawScanData(&globalState.rawScan, RQ_FRSOAll) ;
//	RQ_Uninitialise(globalState.cardIndex);
}


