/*******************************************************************************
 *	Gen.cpp		Signal Generator classes
 *			T.Barnaby,	BEAM Ltd,	2006-09-12
 *******************************************************************************
 */

#include <Gen.h>
#include <BArray.h>
#include <TmsLib.h>
#include <math.h>

#define AVG_PRINT	0

const double	pllFrequency	= 125e6;	// The PLL frequency
const int	defaultFrefGain	= 4096;		// The default PLL FREF gain
const int	defaultPllGain	= 9;		// The default PLL feedback gain (In shifts to the right)

using namespace Tms;

BString PNameValueList::getValue(BString name){
	BString*	s;
	
	if(s = find(name)){
		return *s;
	}
	return "";
}

void PNameValueList::setValue(BString name, BString value){
	BString*	s;
	
	if(s = find(name)){
		*s = value;
		return;
	}
	else {
		append(PNameValue(name, value));
//		BList<GenParam>::append(GenParam(name, value));
	}
}

Gen::Gen(){
	osampleRate = 125000000.0;
	ofref = 437000.0;
	ophaseTableFile = 0;
	ouseMsbFref = 0;
	opllInitialFrequencyDelay = 0;
	ophaseDelay = 0;
	ophaseDelayAll = -1;
}

Gen::~Gen(){
}

BError Gen::init(PNameValueList& params){
	BError	err;
	BString	s;
	
	oparams = params;
	
	if((s = params.getValue("fileName")) != "")
		ofileName = s;

	if((s = params.getValue("sampleRate")) != "")
		osampleRate = atof(s);

	if((s = params.getValue("fref")) != "")
		ofref = atof(s);

	if((s = params.getValue("phaseTableFile")) != "")
		ophaseTableFile = 1;

	if((s = params.getValue("useMsbFref")) != "")
		ouseMsbFref = atoi(s);

	if((s = params.getValue("pllInitialFrequencyDelay")) != "")
		opllInitialFrequencyDelay = atoi(s);

	if((s = params.getValue("phaseDelay")) != "")
		ophaseDelay = atoi(s);

	if((s = params.getValue("phaseDelayAll")) != "")
		ophaseDelayAll = atoi(s);

	if((s = params.getValue("name")) != "")
		oname = s;

	if((s = params.getValue("info")) != "")
		ocycleParam.info = s + " ";

	return ofile.open(ofileName, "w");
}

BList<BString> Gen::getTypes(){
	BList<BString>	sl;
	
	sl.append("Beam1: Beam with 4 particle bunches at harmonic 8.");
	sl.append("Beam2: Beam with 4 particle bunches at harmonic 8. Beam then moves to 4 particle bunches at harmonic 16.");
	sl.append("Beam3: Beam with 4 particle bunches at harmonic 8. Beam then moves to 8 particle bunches at harmonic 16.");
	sl.append("Test1: Beam with 4 particle bunches at harmonic 8. Beam then moves to 8 particle bunches at harmonic 16.");
	
	return sl;
}

BError Gen::generate(BString cycleType){
	BError	err;
	
	if(cycleType == "Beam1")
		err = genBeam1();
	else if(cycleType == "Beam2")
		err = genBeam2();
	else if(cycleType == "Beam3")
		err = genBeam3();
	else if(cycleType == "Test1")
		err = genTest1();
	else
		err.set(1, "Unknown cycle type");

	if(!err && ophaseTableFile){
		BFile		f;
		unsigned int	s;
		unsigned int	n;
		TmsPhase	p;

		for(s = 0; s < ocycleParam.stateTable.size(); s++){
			f.open(BString("phaseTable") + s + ".txt", "w");
			for(n = 0; n < ocycleParam.stateTable[s].phaseTable.size(); n++){
				p.value = ocycleParam.stateTable[s].phaseTable[n];

				f.printf("%d ", p.lo1);
				f.printf("%d ", p.lo2);
				f.printf("%d ", p.gate);
				f.printf("%d ", p.blr);
				f.printf("%d ", p.meanFilter1);
				f.printf("%d\n", p.meanFilter2);
			}
			f.close();
		}
	}
	
	return err;
}

void Gen::setPhaseDelay(){
	BUInt32		n;
	
	ocycleParam.getdefaultPickupPositions(ocycleParam.frefPhaseDelay);
	if(ophaseDelayAll >= 0){
		for(n = 0; n < ocycleParam.frefPhaseDelay.size(); n++){
			ocycleParam.frefPhaseDelay[n] = ophaseDelayAll;
		}
	}
	else {
		for(n = 0; n < ocycleParam.frefPhaseDelay.size(); n++){
			ocycleParam.frefPhaseDelay[n] += ophaseDelay;
		}
	}
}

BError Gen::genBeam1(){
	BError			err;
	CycleParamState		st;
	BList<CycleParamState>	cpl;

	// Set up base parameters
	ocycleParam.cycleType		= oname;
	ocycleParam.info		+= "Beam with 4 particle bunches at harmonic 8.";
	ocycleParam.channel		= 0;
	ocycleParam.pllCycleStartFrequency	= int(pow(2.0, 32) / (pllFrequency / ofref));
	ocycleParam.pllInitialFrequency	= int(pow(2.0, 32) / (pllFrequency / ofref));
	ocycleParam.pllInitialFrequencyDelay	= opllInitialFrequencyDelay;
	ocycleParam.pllFrefGain		= defaultFrefGain;
	ocycleParam.pllGain		= defaultPllGain;
	ocycleParam.pllDdsMinimum	= 0;
	ocycleParam.pllDdsMaximum	= 0;

	// Set up Positions
	setPhaseDelay();

	// Set up States
	ocycleParam.getDefaultState(st);

	st.period = CyclePeriodCalibration;
	st.loHarmonic = 8;
	st.loPhase = 0.0;
	st.bunchMask = 0x3C;
	st.mean1Mask = 0x3C;
	st.mean2Mask = 0x04;
	st.blrPhase = 0.85;
	cpl.append(st);

	st.period = CyclePeriodEvent0;
	st.loHarmonic = 8;
	st.loPhase = 0.0;
	st.bunchMask = 0x3C;
	st.mean1Mask = 0x3C;
	st.mean2Mask = 0x04;
	st.blrPhase = 0.85;
	cpl.append(st);
	
	if(err = ocycleParam.setStates(cpl))
		return err;
	
	ofile.writeString(ocycleParam.getString());
	
	ofile.close();
	
	return err;
}

BError Gen::genBeam2(){
	BError			err;
	CycleParamState		st;
	BList<CycleParamState>	cpl;

	// Set up base parameters
	ocycleParam.cycleType		= oname;
	ocycleParam.info		+= "Beam with 4 particle bunches at harmonic 8. Beam then moves to 4 particle bunches at harmonic 16.";
	ocycleParam.channel		= 0;
	ocycleParam.pllCycleStartFrequency	= int(pow(2.0, 32) / (pllFrequency / ofref));
	ocycleParam.pllInitialFrequency	= int(pow(2.0, 32) / (pllFrequency / ofref));
	ocycleParam.pllInitialFrequencyDelay	= opllInitialFrequencyDelay;
	ocycleParam.pllFrefGain		= defaultFrefGain;
	ocycleParam.pllGain		= defaultPllGain;
	ocycleParam.pllDdsMinimum	= 0;
	ocycleParam.pllDdsMaximum	= 0;

	// Set up Positions
	setPhaseDelay();

	// Set up States
	ocycleParam.getDefaultState(st);

	st.period = CyclePeriodCalibration;
	st.loHarmonic = 8;
	st.loPhase = 0.0;
	st.bunchMask = 0x3C;
	st.mean1Mask = 0x3C;
	st.mean2Mask = 0x04;
	st.blrPhase = 0.85;
	cpl.append(st);

	st.period = CyclePeriodEvent0;
	st.loHarmonic = 8;
	st.loPhase = 0.0;
	st.bunchMask = 0x3C;
	st.mean1Mask = 0x3C;
	st.mean2Mask = 0x04;
	st.blrPhase = 0.85;
	cpl.append(st);
	
	st.period = CyclePeriodEvent1;
	st.loHarmonic = 16;
	st.loPhase = 0.0;
	st.bunchMask = 0x3C;
	st.mean1Mask = 0x3C;
	st.mean2Mask = 0x04;
	st.blrPhase = 0.85;
	cpl.append(st);

	if(err = ocycleParam.setStates(cpl))
		return err;
	
	ofile.writeString(ocycleParam.getString());
	
	ofile.close();
	
	return err;
}

BError Gen::genBeam3(){
	BError			err;
	CycleParamState		st;
	BList<CycleParamState>	cpl;

	// Set up base parameters
	ocycleParam.cycleType		= oname;
	ocycleParam.info		+= "Beam with 4 particle bunches at harmonic 8. Beam then moves to 4 particle bunches at harmonic 16.";
	ocycleParam.channel		= 0;
	ocycleParam.pllCycleStartFrequency	= int(pow(2.0, 32) / (pllFrequency / ofref));
	ocycleParam.pllInitialFrequency	= int(pow(2.0, 32) / (pllFrequency / ofref));
	ocycleParam.pllInitialFrequencyDelay	= opllInitialFrequencyDelay;
	ocycleParam.pllFrefGain		= defaultFrefGain;
	ocycleParam.pllGain		= defaultPllGain;
	ocycleParam.pllDdsMinimum	= 0;
	ocycleParam.pllDdsMaximum	= 0;

	// Set up Positions
	setPhaseDelay();

	// Set up States
	ocycleParam.getDefaultState(st);

	st.period = CyclePeriodCalibration;
	st.loHarmonic = 8;
	st.loPhase = 0.0;
	st.bunchMask = 0x3C;
	st.mean1Mask = 0x3C;
	st.mean2Mask = 0x04;
	st.blrPhase = 0.85;
	cpl.append(st);

	st.period = CyclePeriodEvent0;
	st.loHarmonic = 8;
	st.loPhase = 0.0;
	st.bunchMask = 0x3C;
	st.mean1Mask = 0x3C;
	st.mean2Mask = 0x04;
	st.blrPhase = 0.85;
	cpl.append(st);
	
	st.period = CyclePeriodEvent1;
	st.loHarmonic = 16;
	st.loPhase = 0.0;
	st.bunchMask = 0x03C0;
	st.mean1Mask = 0x03C0;
	st.mean2Mask = 0x0040;
	st.blrPhase = 0.85;
	cpl.append(st);

	if(err = ocycleParam.setStates(cpl))
		return err;
	
	ofile.writeString(ocycleParam.getString());
	
	ofile.close();
	
	return err;
}

BError Gen::genTest1(){
	BError			err;
	CycleParamState		st;
	BList<CycleParamState>	cpl;

	// Set up base parameters
	ocycleParam.cycleType		= oname;
	ocycleParam.info		+= "Beam with 4 particle bunches at harmonic 8. Beam then moves to 4 particle bunches at harmonic 16.";
	ocycleParam.channel		= 0;
	ocycleParam.pllCycleStartFrequency	= int(pow(2.0, 32) / (pllFrequency / ofref));
	ocycleParam.pllInitialFrequency	= int(pow(2.0, 32) / (pllFrequency / ofref));
	ocycleParam.pllInitialFrequencyDelay	= opllInitialFrequencyDelay;
	ocycleParam.pllFrefGain		= defaultFrefGain;
	ocycleParam.pllGain		= defaultPllGain;
	ocycleParam.pllDdsMinimum	= 0;
	ocycleParam.pllDdsMaximum	= 0;

	// Set up Positions
	setPhaseDelay();

	// Set up States
	ocycleParam.getDefaultState(st);

	st.period = CyclePeriodCalibration;
	st.loHarmonic = 8;
	st.loPhase = 0.0;
	st.bunchMask = 0x3C;
	st.mean1Mask = 0x3C;
	st.mean2Mask = 0x04;
	st.blrPhase = 0.85;
	cpl.append(st);

	st.period = CyclePeriodEvent0;
	st.loHarmonic = 8;
	st.loPhase = 0.0;
	st.bunchMask = 0x3C;
	st.mean1Mask = 0x3C;
	st.mean2Mask = 0x04;
	st.blrPhase = 0.85;
	cpl.append(st);
	
	st.period = CyclePeriodEvent1;
	st.loHarmonic = 16;
	st.loPhase = 0.0;
	st.bunchMask = 0x03C0;
	st.mean1Mask = 0x03C0;
	st.mean2Mask = 0x0040;
	st.blrPhase = 0.85;
	cpl.append(st);

	if(err = ocycleParam.setStates(cpl))
		return err;
	
	ofile.writeString(ocycleParam.getString());
	
	ofile.close();
	
	return err;
}


