/*******************************************************************************
 *	Pupe.h		Pupe management class
 *			T.Barnaby,	BEAM Ltd,	2007-02-13
 *******************************************************************************
 */
#ifndef Pupe_H
#define Pupe_H	1

#include <TmsLib.h>
#include <TmsD.h>
#include <BThread.h>
#include <BMutex.h>
#include <PllSynth.h>
#include <admxrc2.h>

using namespace Tms;

class Control;

const uint32_t	FpgaCycleInfoTableSize		= 512;
const uint32_t	FpgaCycleTimingTableSize	= 4096;
const uint32_t	FpgaCycleTimingTableMask	= (4096-1);
const uint32_t	FpgaBunchMeanTableSize		= 4096;

// Events
const uint8_t	EventCycleStart			= 0x01;
const uint8_t	EventCycleStop			= 0x02;
const uint8_t	EventCalibrationStart		= 0x04;
const uint8_t	EventCalibrationStop		= 0x08;
const uint8_t	EventInjection			= 0x10;
const uint8_t	EventHChange			= 0x20;
const uint8_t	EventDelay			= 0x40;

class Pupe;

struct PupeEvent {
	uint8_t		event;
	uint8_t		statePre;		// The state when the event occured
	uint8_t		statePost;		// The state after the event
	uint32_t	timingAddress;
	uint32_t	time;
	uint32_t	dataAddress;
};

class CycleInformationPeriodInternal : public CycleInformationPeriod {
public:
	BUInt32		dataAddress;
	PupeEvent	eventStart;
	PupeEvent	eventEnd;
	PupeEvent	eventStop;
};


/// PupeInterrupt thread class
class PupeInterruptThread : public BThread {
public:
			PupeInterruptThread(Pupe& pupe);
	void*		function();
private:
	Pupe&	opupe;
};

class Pupe {
public:
	enum			{ numChan = 3 };

				Pupe(Control& control, int slot, int board);
				~Pupe();

				// Per board functions			
	BError			init();
	BError			setMaster(int on);				///< Sets this board as a master for the timing bus
	BError			status();					///< Returns the boards status
	void			setStatus(BError err, int powerOff);		///< Sets the boards status
	BString			getName();

	BError			setNextCycle(PuChannel puChannel, BUInt32 cycleNumber, BString cycleType, CycleParam& params);

				// Per Pick-Up functions
	BError			setControlInfo(PuChannel puChannel, BUInt32 cycleNumber, CycleParam& params);
	BError			getStatusList(PuChannel puChannel, BList<NameValue>& statusList);
	BError			getStatus(PuChannel puChannel, PuStatus& puStatus);
	BError			getCycleInformation(BUInt32 cycleNumber, CycleInformation& cycleInformation);
	BError			getData(PuChannel puChannel, DataInfo dataInfo, Data& data, BUInt32& orbitNumber);
	BError			setTestMode(PuChannel puChannel, BUInt32 testOutput, BUInt32 timingDisableMask);
	BError			setTimingSignals(PuChannel puChannel, BUInt32 timingSignals);
	BError			captureDiagnostics(PuChannel puChannel, TestCaptureInfo captureInfo, BArray<BUInt64>& data);
	BError			setTestData(PuChannel puChannel, BInt32 on, BArray<BUInt32> data);	///< This function will set a PU channel to sample data from memory rather than the ADC's
	BError			setPupeConfig(PuChannel puPhysChannel, PupeConfig pupeConfig);
	BError			getPupeConfig(PuChannel puPhysChannel, PupeConfig& pupeConfig);
	BError			getTemperatures(double& tempInternal, double& tempFpga);


				// Internal functions
	void			cycleStart();		///< Start of cycle event
	void			cycleStop();		///< End of cycle event
	void			cycleError(int puChan);	///< An error occured

	BError			fpgaInterruptLoop();
	void			fpgaTriggerTimingInputs(TimingSig input);	///< Trigger a timing inputs
	
	int			getSlot();
	void			dumpState();
	int			adcPllLockCheck();				///< Checks the ADC PLL lock status
private:
	BError			setControlInfoPickUp(PuChannel puChannel, BUInt32 cycleNumber, CycleParam& params);
	PuStateTable*		getPuStateTable(CycleParam* params, BUInt32 period);
	BError			getSimData(DataInfo dataInfo, Data& data);	///< return simulated data
	BError			checkData(BUInt32 cycleNumber);
	BError			getEventList(BUInt32 pupeCycleNumber, BList<PupeEvent>& events);
	BError			eventsToPeriods(BUInt32 cycleNumber, BList<PupeEvent>& events, BList<CycleInformationPeriodInternal>& periods);
	void			printEventList(BList<PupeEvent>& events);

	BError			fpgaInit();
	BError			fpgaLoad();
	BError			fpgaConfig();
	void			fpgaClose();
	BError			fpgaShutdown();
	BError			fpgaGetInfo(BList<NameValue>& infoList);
	BError			fpgaReadData32(uint32_t fpgaOffset, void* toAddress, int nbytes);
	BError			fpgaReadData64(uint32_t fpgaOffset, void* toAddress, int nbytes);
	BError			fpgaWriteData64(void* fromAddress, uint32_t fpgaOffset, int nbytes);
	
	BError			fpgaCopyData(int pupeChan, uint32_t address, uint32_t nsamples, Data& data);
	BError			fpgaGetAverageData(int pupeChan, uint32_t timeMs, uint32_t timingAddress, uint32_t bunch, uint32_t numValues, Data& data);
	BError			fpgaGetAverageDataAll(int pupeChan, uint32_t timeMs, uint32_t timingAddress, uint32_t numBunches, uint32_t numValues, Data& data);
	void			dataAverage(uint32_t timeMs, Data& data);
	
	Control&		ocontrol;
	BMutex			olock;			///< Locks access to the FPGA
	BMutex			odiagLock;		///< Diagnostics capture lock
	int			oboard;
	int			oslot;			///< The bus slot the board is in
	int			omaster;
	int			osimulate;
	PupeConfig		opupeConfig;
	int			oinitialised;		///< The board has been initialised
	BError			ostatus;		///< The boards current status
	BUInt32			ocycleNumber;		///< The current PS cycle number
	BUInt32			ocycleCompletedNumber;	///< The last completed PS cycle number
	BUInt32			ocycleNumberNext;	///< The next PS cycle number
	BUInt32			opuCycleNumbers[3];	///< The board cycle numbers matching the PS cycle number
	BString			opuCycleTypes[3];		///< The current cycle type
	BString			ocycleTypeNext;		///< The next cycle type

	ADMXRC2_HANDLE		ofpgaCard;
	ADMXRC2_CARD_INFO	ocardInfo;
	ADMXRC2_DMADESC		odmabuf;
	int			opageSize;
	int			odmaBufferSize;		///< The DMA buffer size
	BUInt64*			odmaBuffer;		///< DMA buffer
	volatile uint32_t*	ofpga;
	volatile uint32_t*	ofpgaControl;
	PupeInterruptThread	ointerruptThread;
	BUInt32			oprocessingCycle;	///< We are processing a cycle

	CycleParam*		ocycleParams[3][8];	///< The cycle paramterstypes for the last 8 cycles for each channel

	PllSynth		opllSynth;		///< The Phase locked loop frequency synthesisor
	int			opllLocked;		///< The current PLL lock status
	
	uint64_t		ocycleInfoTable[FpgaCycleInfoTableSize];
	uint64_t		ocycleTimingTable[FpgaCycleTimingTableSize];

	uint32_t		ocycleCount;
	uint32_t		opllRefErrors;		///< The number of PLL reference lock errors
};

#endif
