/*
* Title:	PupeSimulateWin.cpp 
* Author:	M.Thomas BEAM Ltd
* Date:		2007-02-13
*
* Contents:	Status Display
*
* Mod Rec:
*
*/

#include <PupeSimulateWin.h>
#include <qlayout.h>
#include <qpushbutton.h>
#include <qvgroupbox.h>
#include <qmessagebox.h>
#include <qlabel.h>
#include <qfiledialog.h>
#include <qcheckbox.h>
#include <BFile.h>
#include <qgroupbox.h>
#include <qvbox.h>
#include <Globals.h>
#include <qgrid.h>
#include <TmsLib.h>

using namespace Tms;

PupeSimulateWin::PupeSimulateWin(QWidget* parent,Control& c) : ocontrol(c)  {
	QGridLayout*	grid;
	QButton*	fileSelectButton;
	QVGroupBox*	channelGroup;
	QVGroupBox*	testDataGroup;
	QVGroupBox*	internalTimingsGroup;
	QVGroupBox*	simulationGroup;
	QGroupBox*	tmsGroup;
	QWidget*	w;
	QGridLayout* 	v;
	BString		s;
	int		row = 0;
	
	setFixedWidth(600);

	grid = new QGridLayout(this, 5, 3);
        grid->setMargin(20);
        grid->setSpacing(20);

	channelGroup = new QVGroupBox("Pupe Channel", this, "channelGroup");
	w = new QWidget(channelGroup, "");
	v = new QGridLayout(w);
	v->setSpacing(10);
	row = 0;
	v->addWidget(new QLabel("All Channels", w), row, 0);
	v->addWidget(oallChannels = new QCheckBox("", w), row, 1);

	row++;
	v->addWidget(new QLabel("Channel Number", w), row, 0);
	v->addWidget(ochannel = new QSpinBox(1, 60, 1, w, ""), row, 1);
	ochannel->setWrapping(true);	
		

	internalTimingsGroup = new QVGroupBox("Internal Timing Control", channelGroup, "internalTimings");
	w = new QWidget(internalTimingsGroup,"internalTimingsW");
	v = new QGridLayout(w);

	v->setSpacing(10);
	row = 0;
	v->addMultiCellWidget(oadcSysclkSync = new QCheckBox("ADC Clock synchronised to SYSCLK",w,""),row,row,0,1); 
	v->addMultiCellWidget(odisableBlr = new QCheckBox("Disable Blr",w,""),row,row,2,3); 
	row++;
	row++;

	v->addWidget(oFref       = new QCheckBox("Fref",w,""),row,0);
	v->addWidget(oHChange    = new QCheckBox("H Change",w,""),row,1);
	v->addWidget(oInjection  = new QCheckBox("Injection",w,""),row,2);
	v->addWidget(oCalStop    = new QCheckBox("Cal Stop",w,""),row,3);
	row++;
	v->addWidget(oCalStart   = new QCheckBox("Cal Start",w,""),row,0);
	v->addWidget(oCycleStop  = new QCheckBox("Cycle Stop",w,""),row,1);
	v->addWidget(oCycleStart = new QCheckBox("Cycle Start",w,""),row,2);
	v->addWidget(oClock      = new QCheckBox("Clock",w,""),row,3);
	row++;
	oiApply = new QPushButton("Apply", internalTimingsGroup,"");
	oiApply->setMaximumWidth(200);


	testDataGroup = new QVGroupBox("Internal Test Data", channelGroup, "testData");
	w = new QWidget(testDataGroup, "testDataW");
	v = new QGridLayout(w);

	v->setSpacing(10);
	row = 0;
	v->addWidget(new QLabel("Test Data file",w), row, 0);
	v->addWidget(osimulationRamFilename = new QLineEdit(w,"ramfilename"), row, 1);
	v->addWidget(fileSelectButton 	= new QPushButton("Select",w,""), row,2);	
	row++;
	v->addWidget(oloadSimulationRam = new QPushButton("Load Test Data",w,""), row, 0);
	v->addWidget(oclearSimulationRam = new QPushButton("Clear Test Data",w,""), row, 1);

	// Simulation
	simulationGroup = new QVGroupBox("Overal Simulation", this, "simulation");
	w = new QWidget(simulationGroup, "simulationW");
	v = new QGridLayout(w);

	v->setSpacing(10);
	row = 0;
	v->addWidget(osimTiming  = new QCheckBox("Timing",w,""),row,0);
	v->addWidget(osimData    = new QCheckBox("SimData",w,""),row,1);
	v->addWidget(osimNextCycle = new QCheckBox("SimNextCycle",w,""),row,2);
	row++;
	osApply = new QPushButton("Apply", simulationGroup, "");
	osApply->setMaximumWidth(200);

	
	tmsGroup = new QVGroupBox("TMS Control", this, "tmsControl");
	w = new QWidget(tmsGroup, "tmsControlW");
	v = new QGridLayout(w);
	v->setSpacing(10);
	
	row = 0;
	v->addWidget(new QLabel("Initialse TMS System", w), row, 0);
	v->addWidget(oInitialise = new QPushButton("Initialise TMS",w), row, 1);
	oInitialise->setMaximumWidth(200);

	row++;	
	v->addWidget(new QLabel("Current Cycletype", w), row, 0);
	v->addWidget(ocycleType = new BQComboBox(w), row, 1);
	v->addWidget(oapplyCycleType = new QPushButton("Apply",w), row, 2);
	oapplyCycleType->setMaximumWidth(200);
	
	row = 0;
	grid->addWidget(channelGroup, row, 0);	row++;
	grid->addWidget(simulationGroup, row, 0);	row++;
	grid->addWidget(tmsGroup, row, 0);	row++;

	connect(fileSelectButton,SIGNAL(clicked()),this,SLOT(selectFile()));
	connect(oloadSimulationRam,SIGNAL(clicked()),this,SLOT(loadRam()));
	connect(oclearSimulationRam,SIGNAL(clicked()),this,SLOT(clearRam()));
	connect(oInitialise,SIGNAL(clicked()),this,SLOT(initialiseTMS()));
	connect(oiApply,SIGNAL(clicked()),this,SLOT(applyInternalTimings()));
	connect(osApply,SIGNAL(clicked()),this,SLOT(applySimulation()));
	connect(oapplyCycleType,SIGNAL(clicked()),this,SLOT(applyCycleType()));
        connect(oallChannels, SIGNAL(stateChanged(int)), this, SLOT(updateMaxChannels()));
	connect(ochannel,SIGNAL(valueChanged(int)),this,SLOT(updateTimingMask()));
	connect(&ocontrol,SIGNAL(newConnection()),this,SLOT(update()));
}
	
PupeSimulateWin::~PupeSimulateWin() {}



void PupeSimulateWin::selectFile() {
    QString s = QFileDialog::getOpenFileName(
                    "/usr/tms/data",
                    "Tms Channel Test Data File (*.psd)",
                    this,
                    "open file dialog",
                    "Choose a file" );
	osimulationRamFilename->setText(s);
}
	
void PupeSimulateWin::show() {
	QWidget::show();
	update();
}	


void PupeSimulateWin::update() {
	Tms::Simulation	simulation;
	
	if (! isVisible())
		return;
	if (updateMaxChannels())
		return;
	if (updateTimingMask())
		return;
	if (updateControlList())
		return;
	
	if(ocontrol.getSimulation(simulation))
		return;
	
	osimTiming->setChecked(simulation.timing);
	osimData->setChecked(simulation.data);
	osimNextCycle->setChecked(simulation.setNextCycle);
}


BError	PupeSimulateWin::updateMaxChannels() {
	BError	err;
	Tms::ConfigInfo	info;

	if(oallChannels->isChecked()){
		ochannel->setEnabled(false);
	}
	else {
		ochannel->setEnabled(true);
		if (err = ocontrol.getConfiguration(info)) {
			return err;
		}
		ochannel->setMaxValue(info.puReferences.size());
	}
	return err;
}

BError PupeSimulateWin::updateTimingMask() {
	BError			err;
	Tms::PuChannel		puChannel;
	Tms::PupeConfig		pupeConfig;

	if(err = ocontrol.getPuChannel(ochannel->value(), puChannel)){
		warningDialog("Pupe Update Timing Mask - ",err);
		return err;
	}
	if(err = ocontrol.getPupeConfig(puChannel, pupeConfig)){
		warningDialog("Pupe Update Timing Mask - ",err);
		return err;
	}

	oadcSysclkSync->setChecked(pupeConfig.adcSysclkSync);
	odisableBlr->setChecked(pupeConfig.disableBlr);
	
	UInt32	mask = pupeConfig.internalTimingMask;
	oClock->setChecked(mask & TimingSigClock);
	oCycleStart->setChecked(mask & TimingSigCycleStart);
	oCycleStop->setChecked(mask & TimingSigCycleStop);
	oCalStart->setChecked(mask &  TimingSigCalStart);
	oCalStop->setChecked(mask & TimingSigCalStop);
	oInjection->setChecked(mask & TimingSigInjection);
	oHChange->setChecked(mask & TimingSigHChange);
	oFref->setChecked(mask & TimingSigFRef);
	return err;
}


BError PupeSimulateWin::updateControlList() {
	BError		err;
	BIter		i;
	int 		n = 0;
	UInt32 		cycleNumber;
	BString		cycleType;
	BList<CycleParamItem> l;
	
	if (err = ocontrol.getControlList(l)) {
		warningDialog("Pupe Get Control List - ",err);
		return err;
	}
	if (err = ocontrol.getCycleInfo(cycleNumber,cycleType)) {
		warningDialog("Pupe Get Control Info -",err);
		return err;
	}

	ocycleType->clear();
	for (l.start(i);! l.isEnd(i);l.next(i)) {
		ocycleType->insertItem(l[i].cycleType.retStr());
		if (l[i].cycleType == cycleType) {
			ocycleType->setCurrentItem(n);
		}	
		n++;	
	}
	return err;
}



void PupeSimulateWin::loadRam() {
	BError			err;
	BFile			f;
	BString			fname;
	Tms::PuChannel		puChannel;
	BArray< UInt32 >   	 data;
	int			nb;
	unsigned int		c;
	unsigned int		cmax;
	
	if(oallChannels->isChecked()){
		c = 1;
		cmax = ochannel->maxValue();
	}
	else {
		cmax = c = ochannel->value();
	}
	
	fname = osimulationRamFilename->text().ascii();

	if (err = f.open(fname,"r")) {
		warningDialog("Pupe Test Data - Loading",err);
		return;
	}
	data.resize(1024);
	if((nb = f.read(&data[0], 1024 * sizeof(UInt32))) <= 0){
		err.set(1, BString("Error: Reading 1024 32bit data items from file: ") + fname);
		warningDialog("Pupe Test Data",err);
		return;		
	}
	data.resize(nb / sizeof(UInt32));

	for(; c <= cmax; c++){
		if(err = ocontrol.getPuChannel(c, puChannel)){
			warningDialog(BString("Pupe Load Test Data Channel: ") + c + " : ", err);
			return;
		}

		if (err = ocontrol.setTestData(puChannel,true,data)) {
			warningDialog(BString("Pupe Load Test Data Channel: ") + c + " : ", err);
			return;
		}
	}
	gstatusbar->message("Ram Loaded",2000);
}

void PupeSimulateWin::initialiseTMS() {
	BError	err;

	if (err = ocontrol.initialiseServer()) {
		warningDialog("Initialising Server",err);
		return;
	}
	update();
	gstatusbar->message("TMS initialised",2000);
}

void PupeSimulateWin::applyInternalTimings() {
	BError	err;
	Tms::PuChannel		puChannel;
	Tms::PupeConfig		pupeConfig;
	unsigned int		c;
	unsigned int		cmax;
	
	if(oallChannels->isChecked()){
		c = 1;
		cmax = ochannel->maxValue();
	}
	else {
		cmax = c = ochannel->value();
	}

	pupeConfig.internalTimingMask = 
		oClock->isChecked() << 0 |       
		oCycleStart->isChecked() << 1 |       
		oCycleStop->isChecked() << 2 |       
		oCalStart->isChecked() << 3 |       
		oCalStop->isChecked() << 4 |       
		oInjection->isChecked() << 5 |       
		oHChange->isChecked() << 6 |       
		oFref->isChecked() << 7;


	pupeConfig.adcSysclkSync = oadcSysclkSync->isChecked();
	pupeConfig.disableBlr = odisableBlr->isChecked();

	for(; c <= cmax; c++){
		if(err = ocontrol.getPuChannel(c, puChannel)){
			warningDialog(BString("Pupe Apply Timings Channel: ") + c + " : ", err);
			return;
		}

		if(err = ocontrol.setPupeConfig(puChannel, pupeConfig)){
			warningDialog(BString("Pupe Apply Timings Channel: ") + c + " : ", err);
			return;
		}
	}
	gstatusbar->message("Internal Timings Applied",2000);
}

void PupeSimulateWin::applySimulation(){
	BError 		err;
	Tms::Simulation	simulation;
	
	simulation.timing = osimTiming->isChecked();
	simulation.data = osimData->isChecked();
	simulation.setNextCycle = osimNextCycle->isChecked();
	simulation.cycleType = "";
	
	if(err = ocontrol.setSimulation(simulation)){
		warningDialog("Setting Simulation", err);
		return;
	}
	update();
}

void PupeSimulateWin::applyCycleType() {
	BError 	err;
	BString	ct;
	BString msg;
	UInt32	cycleNumber;
	BString	cycleType;

#ifdef ZAP
	// Get current cycle info
	if(err = ocontrol.getCycleInfo(cycleNumber,cycleType)){
		warningDialog("Setting Cycle Type - GetCycleInfo",err);
		return;
	}
		
	cycleType = ocycleType->currentText().ascii();	
	cycleNumber++;

	// Set NextCycle type
	if(err = ocontrol.setNextCycle(cycleNumber, cycleType)){
		warningDialog("Setting Cycle Type - SetNextCycle",err);
		return;
	}
	msg.printf("Next CycleType (%s)\n",cycleType.retStr()); 
	gstatusbar->message(msg.retStr(),2000);
#else
	Tms::Simulation	simulation;
	UInt32		cn;
	int		to = 20;
	
	simulation.timing = osimTiming->isChecked();
	simulation.data = osimData->isChecked();
	simulation.setNextCycle = osimNextCycle->isChecked();
	simulation.cycleType = ocycleType->currentText().ascii();
	
	if(err = ocontrol.setSimulation(simulation)){
		warningDialog("Setting Simulation", err);
		return;
	}

	if(err = ocontrol.getCycleInfo(cycleNumber, cycleType)){
		warningDialog("Setting Cycle Type - GetCycleInfo",err);
		return;
	}
	cn = cycleNumber;
	while((cn == cycleNumber) && to--){
		if(err = ocontrol.getCycleInfo(cn, cycleType)){
			warningDialog("Setting Cycle Type - GetCycleInfo",err);
			return;
		}
		usleep(100000);
	}

	update();
#endif
}



void	PupeSimulateWin::clearRam() {
	BError			err;
	Tms::PuChannel		puChannel;
	BArray< UInt32 >   	data;
	unsigned int		c;
	unsigned int		cmax;
	
	if(oallChannels->isChecked()){
		c = 1;
		cmax = ochannel->maxValue();
	}
	else {
		cmax = c = ochannel->value();
	}

	for(; c <= cmax; c++){
		if(err = ocontrol.getPuChannel(c, puChannel)){
			warningDialog(BString("Pupe Clear Test Data Channel: ") + c + " : ", err);
			return;
		}
		if(err = ocontrol.setTestData(puChannel, 0, data)){
			warningDialog(BString("Pupe Clear Test Data Channel: ") + c + " : ", err);
			return;
		}
	}
	gstatusbar->message("Ram Cleared",2000);
}

void	PupeSimulateWin::warningDialog(BString title, BError err){
	BString	m;
	
	m = BString("<h5>") + title + "</h5><p>" + err.getString() + "</p>";
	QMessageBox::warning(this, "Warning", m.retStr());
}





