//
// A1526Control.cpp              
//
// Michael Tytgat, michael.tytgat@cern.ch
//
#include <A1526Control.h>
#include <TLatex.h>
#include <TMath.h>

using namespace std;
using namespace QtConcurrent;

A1526Control::A1526Control( MainWindow *parent )
{
  saving = false;
  gErrorIgnoreLevel = 5000; 
  //  myMainWindow = parent;
  myenviro = parent->getEnviro();
  //  myconsole = parent->getConsole();
  //  oconsole.setDevice(new TextEditIoDevice(myconsole, this));
  //  oconsole.setDevice( parent->getConsoleDevice() );
  //  oconsole = parent->getOConsole();
  name = parent->getName();

  // define all required measurements
  measurements << "DarkCurrent1" << "DarkCurrent2" << "DarkCurrent3"; 
  
  int vmax = 10000, rup = 5, rdown = 5;
  fstream readfile;
  readfile.open("A1526.dat");
  if ( !readfile.is_open() ) {
    print("No A1526.dat file found, using default settings for Vmax,Rup and Rdown\n");
  } else {
    readfile >> nslots;
    if ( nslots > MAXNSLOT ) {
      print("Maximum number of slots exceeded, check A1526.dat\n");
      parent->quit();
    }
    for ( unsigned int i = 0; i < nslots; i++ )
      readfile >> slot[i];
    readfile >> vmax >> rup >> rdown;
    readfile.close();
  }

  // Set the maximum number of threads to run simultaneously
  // One thread per HV channel for measurements + GUI threads
  QThreadPool *threadpool = QThreadPool::globalInstance();
  threadpool->setMaxThreadCount(nslots*6+5);
     
  //Test board presence
  for ( unsigned int i = 0; i < nslots; i++ ) 
    testBdPresence(slot[i]);
  
  //Set General parameters
  setVmax(vmax);
  setRup(rup);
  setRdown(rdown);
  
  print("Setting up A1526Control window\n");
  
  //Setting up the labels
  QLabel* ChLabels[nslots][6];
  char buffer[20];
  for ( unsigned short j = 0; j < nslots; j++ ) {
    for(unsigned short i = 0; i < 6; ++i) {
      sprintf(buffer, "Ch. %i-%i:", slot[j], i);
      ChLabels[j][i] = new QLabel(tr(buffer));
    }
  }
  QLabel* StatusLabel = new QLabel(tr("Status"));
  QLabel* RPCcodeLabel = new QLabel(tr("RPC code"));
  //RPCcodeLabel->setAlignment(Qt::AlignHCenter);
  QLabel* VvalLabel = new QLabel(tr("Set Voltage"));
  QLabel* VsetLabel = new QLabel(tr("Vset"));
  QLabel* VmonLabel = new QLabel(tr("Vmon"));
  QLabel* VeffLabel = new QLabel(tr("Veff"));
  QLabel* IsetLabel = new QLabel(tr("Iset"));
  QLabel* ImonLabel = new QLabel(tr("Imon"));
  QLabel* TimerLabel = new QLabel(tr("Program"));
  
  Canvas = new TCanvas("Canvas","HVtest graphs",200,10,700,500);
  //  myCanvasWindow = new CanvasWindow(,200,200);
  
  QString RPCcodesFromFile[nslots][6];
  readfile.open("RPCcodes.dat");
  if( !readfile.is_open() ) {
    print("No RPCcodes.dat file found, RPC code stays empty\n");
  } else {
    char buffer[50];
    for ( unsigned int j = 0; j < nslots; j++) {
      for ( unsigned int i = 0; i < 6; ++i) {
	readfile >> buffer;
	RPCcodesFromFile[j][i] = QString(buffer);
	buffer[0] = '\0';
      }
    }
    readfile.close();
  }

  // Setting up the On/Off, Vset, Vmon, Iset, Imon, etc... boxes
  for ( unsigned short j = 0; j < nslots ; j++) {
    for ( unsigned short i = 0; i < 6; ++i) {
      //	    char examplename[50] = "";
      //	    sprintf(examplename, "RE43-UGENT-%02i", (j*6+i)+1);
      RPCcodeString[j][i] = RPCcodesFromFile[j][i];
      RPCcode[j][i] = new RPCcodeEdit(this, RPCcodesFromFile[j][i], j, i);
      connect(RPCcode[j][i], SIGNAL(RPCcodeChanged(int, int)), this, 
	      SLOT(cleanGraphs(int, int)));
      //RPCcode[j][i]->setAlignment(Qt::AlignHCenter);
      OnOff[j][i] = new OnOffButton(this, "On/Off", slot[j], i);
      Status[j][i] = new QLineEdit;
      Status[j][i]->setReadOnly(true);
      Status[j][i]->setStyleSheet( "color:black; background-color:lightGray" );
      Vvalmode[j][i] = new VvalCheckBox();
      Vval[j][i] = new QVvalSpinBox(this, slot[j], i);
      Vval[j][i]->setStyleSheet( "color:black; background-color:white" );
      Vval[j][i]->setRange(0, vmax);
      Vset[j][i] = new QLineEdit;
      Vset[j][i]->setReadOnly(true);
      Vset[j][i]->setStyleSheet( "color:black; background-color:lightGray" );
      Vmon[j][i] = new QLineEdit;
      Vmon[j][i]->setReadOnly(true);
      Vmon[j][i]->setStyleSheet( "color:black; background-color:lightGray" );
      Veff[j][i] = new QLineEdit;
      Veff[j][i]->setReadOnly(true);
      Veff[j][i]->setStyleSheet( "color:black; background-color:lightGray" );
      Iset[j][i] = new QIsetSpinBox(this, slot[j], i);
      Iset[j][i]->setStyleSheet( "color:black; background-color:white" );
      Imon[j][i] = new QLineEdit;
      Imon[j][i]->setReadOnly(true);
      Imon[j][i]->setStyleSheet( "color:black; background-color:lightGray" );
      Graph[j][i] = new GraphPushButton(this, slot[j], i);
      A1526Timer[j][i] = new A1526TimerWindow(this, slot[j], i);
      connect(A1526Timer[j][i], SIGNAL(consolewrite(const QString)), parent,
	      SLOT(printc(const QString)));
      StartStopTimer[j][i] = new QPushButton("Start", this);  
      connect(StartStopTimer[j][i], SIGNAL(clicked()), 
	      A1526Timer[j][i], SLOT(start()));
      
      // Create the graphs we need
      initGraphs( j, i );
      setEnableGraph(j, i, false);
    }
  }
  
  // global start and stop button
  GlobalStartTimer = new QPushButton("Global Start", this);
  connect(GlobalStartTimer, SIGNAL(clicked()), this, SLOT(globalstart()));
  GlobalStopTimer = new QPushButton("Global Stop", this);
  connect(GlobalStopTimer, SIGNAL(clicked()), this, SLOT(globalstop()));


  // declare several signals to make things thread safer
  connect(this, SIGNAL(consolewrite(const QString)), parent,
	  SLOT(printc(const QString)));
  connect(this, SIGNAL(updateStatus(unsigned short, unsigned short, 
				    const QString, unsigned short)),
	  this, SLOT(updateStatus_(unsigned short, unsigned short,
				   const QString, unsigned short)));
  
  //RPC code is only changed after saving and cleaning the graphs
  connect(this, SIGNAL(graphsCleared(int, int)), this, 
	  SLOT(setNewRPCcode(int, int)));
    
  //The window layout
  QGridLayout *mylayout = new QGridLayout();
  mylayout->setColumnMinimumWidth(1, 200);
  mylayout->addWidget(RPCcodeLabel, 0, 1);
  mylayout->addWidget(StatusLabel, 0, 4);
  mylayout->addWidget(VvalLabel, 0, 6);
  mylayout->addWidget(VsetLabel, 0, 7);
  mylayout->addWidget(VmonLabel, 0, 8);
  mylayout->addWidget(VeffLabel, 0, 9);
  mylayout->addWidget(IsetLabel, 0, 10);
  mylayout->addWidget(ImonLabel, 0, 11);
  mylayout->addWidget(TimerLabel, 0, 13);
  for ( unsigned short j = 0; j < nslots; j++ ) {
    for( unsigned short i = 0; i < 6; ++i ) {
      mylayout->addWidget(ChLabels[j][i], i+1+7*j, 0);
      mylayout->addWidget(RPCcode[j][i], i+1+7*j, 1);
      mylayout->addWidget(OnOff[j][i], i+1+7*j, 3);
      mylayout->addWidget(Status[j][i], i+1+7*j, 4);
      mylayout->addWidget(Vvalmode[j][i], i+1+7*j, 5);
      mylayout->addWidget(Vval[j][i], i+1+7*j, 6);
      mylayout->addWidget(Vset[j][i], i+1+7*j, 7);
      mylayout->addWidget(Vmon[j][i], i+1+7*j, 8);
      mylayout->addWidget(Veff[j][i], i+1+7*j, 9);
      mylayout->addWidget(Iset[j][i], i+1+7*j, 10);
      mylayout->addWidget(Imon[j][i], i+1+7*j, 11);
      mylayout->addWidget(Graph[j][i], i+1+7*j, 12);
      mylayout->addWidget(StartStopTimer[j][i], i+1+7*j, 13);
    }
  }
  mylayout->addWidget(GlobalStartTimer, 1+nslots*7, 12);
  mylayout->addWidget(GlobalStopTimer, 1+nslots*7, 13);

  this->setLayout(mylayout);
  this->resize(1200,300);
  this->setWindowTitle("A1526 Control");

  updateWindow();

  // Get time0
  time(&startTime);
  struct tm * now = localtime(&startTime);
  int year = now->tm_year;
  int month = now->tm_mon;
  int day = now->tm_mday;
  int hour = now->tm_hour;
  int minut = now->tm_min;
  int sec = now->tm_sec;

  startTimeDa = new TDatime(year,month,day,hour,minut,sec);
  
  sprintf(timebuff, "%02i_%02i_%02i_%02i", month+1, day, hour, minut);
  timestring = timebuff;

  //Timer which calls the update function
  updateTimer = new QTimer(this);
  connect( updateTimer, SIGNAL(timeout()), this, SLOT(updateWindow()));
  updateTimer->start(UPDATE_TIME);
  
  //Timer which calls the write function
  writeTimer = new QTimer(this);
  connect( writeTimer, SIGNAL(timeout()), this, SLOT(write()));
  writeTimer->start(WRITE_TIME);
  
  // Timer which calls the save function
  saveTimer = new QTimer(this);
  connect( saveTimer, SIGNAL(timeout()), this, SLOT(save()));
  saveTimer->start(SAVE_TIME);  

}

//---------------------------------------------------------------
void A1526Control::globalstart()
{
  bool ok;

  QString measurementtype = QInputDialog::getItem(this, tr("Load Measurement"),
						  tr("Measurement Config:"),
						  measurements, 0, true, &ok);

  for ( unsigned short j = 0; j < nslots; j++ )
    for (unsigned short i = 0; i < 6; i++ ) 
      if ( !RPCcodeString[j][i].isEmpty() ) {
	A1526Timer[j][i]->stop();
	A1526Timer[j][i]->start(measurementtype);
	StartStopTimer[j][i]->setText("Stop");
      }
  
}

//---------------------------------------------------------------
void A1526Control::globalstop()
{
  for ( unsigned short j = 0; j < nslots; j++ )
    for (unsigned short i = 0; i < 6; i++ ) {
      if ( A1526Timer[j][i]->isRunning() ) 
	A1526Timer[j][i]->stop();
      StartStopTimer[j][i]->setText("Start");
    }
}


//---------------------------------------------------------------
// Create the graphs with Vset, Veff, Vmon, Imon
void A1526Control::initGraphs(int j, int i) 
{ 
  VmonGraphs[j][i] = new TGraph();
  VmonGraphs[j][i]->SetTitle("Vmon");
  VmonGraphs[j][i]->SetLineColor(kBlue+4);
  VmonGraphs[j][i]->SetFillColor(0);
  VsetGraphs[j][i] = new TGraph();
  VsetGraphs[j][i]->SetTitle("Vset");
  VsetGraphs[j][i]->SetLineColor(kOrange+1);
  VsetGraphs[j][i]->SetFillColor(0);
  VeffGraphs[j][i] = new TGraph();
  VeffGraphs[j][i]->SetTitle("Veff");
  VeffGraphs[j][i]->SetLineColor(kRed);
  VeffGraphs[j][i]->SetFillColor(0);
  VGraphs[j][i] = new TMultiGraph();
  VGraphs[j][i]->Add(VmonGraphs[j][i], "L");
  VGraphs[j][i]->Add(VsetGraphs[j][i], "L");
  VGraphs[j][i]->Add(VeffGraphs[j][i], "L");
  VGraphs[j][i]->SetName("Vmon, Veff, Vset");
  VGraphs[j][i]->SetTitle("Vmon, Veff, Vset vs Time; Time; Voltage (V)");
  
  // Initial values for vset and veff
  vsetval[j][i] = (int) getParameter(slot[j], i, "V0Set");
  veffval[j][i] = getVeff(vsetval[j][i]);
  
  /*
  //Set first point in vset graph
  VsetGraphs[j][i]->Set(1);
  VsetGraphs[j][i]->SetPoint(0, 0, vsetval[j][i]);
  VeffGraphs[j][i]->Set(1);
  VeffGraphs[j][i]->SetPoint(0, 0, veffval[j][i]);
  */
  
  //Create the Imon graphs
  ImonGraphs[j][i] = new TGraph();
  ImonGraphs[j][i]->SetName("Imon");
  ImonGraphs[j][i]->SetTitle("Imon vs Time; Time; Imon (#muA)");
  //	    ImonGraphs[j][i]->GetXaxis()->SetTitle("time (s)");
  //	    ImonGraphs[j][i]->GetYaxis()->SetTitle("Imon (#muA)");
  ImonGraphs[j][i]->SetFillColor(0);
  
  ImonGraphs2[j][i] = new TGraph();
  char buffer[50];
  if ( Vvalmode[j][i]->isChecked() ) 
    sprintf(buffer, "Imon at %i Veff", veffval[j][i]);
  else
    sprintf(buffer, "Imon at %i Vset", vsetval[j][i]);
  char* name = buffer;
  ImonGraphs2[j][i]->SetName(name);
  ImonGraphs2[j][i]->SetTitle("Imon vs Time; Time; Imon (#muA)");
  //	    ImonGraphs2[j][i]->GetXaxis()->SetTitle("time (s)");
  //	    ImonGraphs2[j][i]->GetYaxis()->SetTitle("Imon (#muA)");
  ImonGraphs2[j][i]->SetFillColor(0);
  enableImonGraphs2[j][i] = false;
  
  //Create the Imon vs Vset/Veff graphs
  IvsVGraphs[j][i] = new TGraphErrors();
  IvsVGraphs[j][i]->SetName("Imon vs Vset/Veff");
  IvsVGraphs[j][i]->SetTitle("Imon vs Vset/Veff; Vset/Veff (V); Imon (#muA)");
  //	    IvsVGraphs[j][i]->GetXaxis()->SetTitle("Vset (V)");
  //	    IvsVGraphs[j][i]->GetYaxis()->SetTitle("Imon (#muA)");
  IvsVGraphs[j][i]->SetFillColor(0);
  //  IvsVGraphs[j][i]->Set(1);

  // enviro graphs
  PenvGraph[j][i] = new TGraph();
  PenvGraph[j][i]->SetTitle("Environmental Pressure; Time; P_{env} (mbar)");
  PenvGraph[j][i]->SetLineColor(kBlue);
  PenvGraph[j][i]->SetFillColor(0);

  TenvGraph[j][i] = new TGraph();
  TenvGraph[j][i]->SetTitle("T_{env}");
  TenvGraph[j][i]->SetLineColor(kRed);
  TenvGraph[j][i]->SetFillColor(0);

  HenvGraph[j][i] = new TGraph();
  HenvGraph[j][i]->SetTitle("H_{env}");
  HenvGraph[j][i]->SetLineColor(kGreen);
  HenvGraph[j][i]->SetFillColor(0);

  TgasGraph[j][i] = new TGraph();
  TgasGraph[j][i]->SetTitle("T_{gas}");
  TgasGraph[j][i]->SetLineColor(kOrange);
  TgasGraph[j][i]->SetFillColor(0);

  HgasGraph[j][i] = new TGraph();
  HgasGraph[j][i]->SetTitle("H_{gas}");
  HgasGraph[j][i]->SetLineColor(kYellow);
  HgasGraph[j][i]->SetFillColor(0);

  TGraphs[j][i] = new TMultiGraph();
  TGraphs[j][i]->Add(TenvGraph[j][i]);
  TGraphs[j][i]->Add(TgasGraph[j][i]);
  TGraphs[j][i]->SetName("T_{env}, T_{gas}");
  TGraphs[j][i]->SetTitle("Environmental and RPC Gas Temperature vs Time; Time; Temperature (deg)");

  HGraphs[j][i] = new TMultiGraph();
  HGraphs[j][i]->Add(HenvGraph[j][i]);
  HGraphs[j][i]->Add(HgasGraph[j][i]);
  HGraphs[j][i]->SetName("H_{env}, H_{gas}");
  HGraphs[j][i]->SetTitle("Environmental and RPC Gas Humidity vs Time; Time; Humidity (%)");

}

/****************************************
 * To handle the messages of this class *
 ****************************************/
void A1526Control::printc(const char* format, ...)
{
  //  *oconsole << 
  QString premessage, message;
  premessage.sprintf("A1526Control:\t");
  va_list args;
  va_start(args, format);
  //*oconsole << 
  message.vsprintf(format, args);
  va_end(args);

  emit consolewrite(premessage+message);
  //  oconsole->flush();
}

//---------------------------------------------------------------
void A1526Control::print(const char* format, ...)
{
  va_list args;
  va_start(args, format);
  printf("A1526Control:\t");
  vprintf(format, args);
  //  printf("\n");
  va_end(args);
}

/**************************************************
 * Test board presence and get the parameter list *
 **************************************************/
void A1526Control::testBdPresence( unsigned short slotnr )
{
  unsigned short serNumb;
  unsigned char fmwMax, fmwMin;
  char Model[15], Descr[80];
  char* ParNameList = (char*) NULL;
  CAENHVRESULT result; 

  result = CAENHVTestBdPresence(name, slotnr, &NrOfCh, Model, Descr, 
				&serNumb, &fmwMin, &fmwMax);
  if( result != CAENHV_OK ) 
    print("CAENHVTestBdPreset: %s (num. 0x%x)\n", 
	  CAENHVGetError(name), result);
  else { 
    print("Slot %d: Mod. %s %s (Nr.Ch: %d  Ser. %d Rel. %d.%d\n)",
	  slotnr,Model,Descr,NrOfCh, serNumb,fmwMax,fmwMin);
    result = CAENHVGetChParamInfo(name, slotnr, 0, &ParNameList);
    if( result != CAENHV_OK ) 
      print("CAENHVGetChParamInfo: %s (num. 0x%x)", 
	    CAENHVGetError(name), result);
    else {
      char (*par)[MAX_PARAM_NAME];
      par = (char (*)[MAX_PARAM_NAME])ParNameList;
      int i=1;
      printf("A1526Control:\t Parameters: %s", par[0]);
      while (par[i][0]) {
	printf(", %s", par[i]);
	++i;
      }
      printf("\n");
    }
  }
}

/*******************************
 * Get parameter for a channel *
 *******************************/
float A1526Control::getParameter( unsigned short slotnr, unsigned short ch, 
				  const char* parameter ) 
{
  unsigned short ChNum, ChList[1]; //ChNum is the number of channels to be changed, ChList is the list of these channels
  unsigned long tipo;
  float fParValList[1];
  unsigned long lParValList[1];
  CAENHVRESULT result;
  
  ChNum = 1;
  ChList[0] = ch;
  
  result = CAENHVGetChParamProp(name, slotnr, ChList[0], parameter, 
				"Type", &tipo);
  if( result != CAENHV_OK ){
    printc("CAENHVGetChParamProp: %s (num. 0x%x)\n", 
	   CAENHVGetError(name), result);
    return -1;
  } else {
    if( tipo == PARAM_TYPE_NUMERIC ){
      result = CAENHVGetChParam(name , slotnr, parameter, ChNum, 
				ChList, fParValList);
      if( result != CAENHV_OK ){
	printc("CAENHVGetChParam: %s (num. 0x%x)\n", 
	       CAENHVGetError(name), result);
	return -1;
      } else return fParValList[0];
    } else { 
      result = CAENHVGetChParam(name , slotnr, parameter, ChNum, ChList, 
				lParValList);
      if( result != CAENHV_OK ){
	printc("CAENHVGetChParam: %s (num. 0x%x)\n", 
	       CAENHVGetError(name), result);
	return -1;
      } else return lParValList[0];
    }
  }
}

/******************************  
 * Set parameter of a channel *
 ******************************/ 
void A1526Control::setParameter(unsigned short slotnr, unsigned short ch, 
				const char* parameter, float value) 
{
  // ChNum is the number of channels to be changed, 
  // ChList is the list of these channels
  unsigned short ChNum, ChList[1]; 
  float fParVal = value;
  unsigned long tipo;
  unsigned long lParVal = value;
  CAENHVRESULT result;
  ChNum = 1;
  ChList[0] = ch;

  result = CAENHVGetChParamProp("SY1527", slotnr, ChList[0], parameter, "Type", 
				&tipo);
  if( result != CAENHV_OK ) 
    printc("CAENHVGetChParamProp: %s (num. 0x%x)\n", 
	   CAENHVGetError("SY1527"), result);
  else {
    if ( tipo == PARAM_TYPE_NUMERIC ) 
      result = CAENHVSetChParam("SY1527", slotnr, parameter, ChNum, 
				ChList, &fParVal);
    else 
      result = CAENHVSetChParam("SY1527", slotnr, parameter, ChNum, 
				ChList, &lParVal);
    if( result != CAENHV_OK ) 
      printc("CAENHVSetChParam: %s (num. 0x%x)\n", CAENHVGetError("SY1527"), 
	     result);
  }
}

/****************************************
 * Update all the values of this window *
 ****************************************/
void A1526Control::updateWindow()
{
  for ( unsigned short j = 0; j < nslots; ++j ) {
    for( unsigned short channel = 0; channel < 6; ++channel ) {
      //      unsigned short slot = (j==0?slot1:slot2);
      getStatus(slot[j], channel);

      // If Veff should be kept fixed, adjust Vset if needed
      if ( Vvalmode[j][channel]->isChecked() ) 
	changeVset( slot[j], channel, getVset(veffval[j][channel]));
      
      float imon = getParameter(slot[j], channel, "IMon");
      int vmon = (int) getParameter(slot[j], channel, "VMon");
      vsetval[j][channel] = (int) getParameter(slot[j], channel, "V0Set");
      int vset = vsetval[j][channel];
      int veff;
      if ( Vvalmode[j][channel]->isChecked() ) 
	veff = veffval[j][channel];
      else {
	veff = getVeff(vsetval[j][channel]);
	veffval[j][channel] = getVeff(vsetval[j][channel]);
      }
      Vset[j][channel]->setText(QString::number(vset).append(" V"));
      Vmon[j][channel]->setText(QString::number(vmon).append(" V"));
      Veff[j][channel]->setText(QString::number(veff).append(" V"));
      Imon[j][channel]->setText(QString::number(imon, 'f', IPRECISION).append(QString::fromUtf8(" \u03BCA")));
      if(!(Vval[j][channel]->isChanging() || Vval[j][channel]->hasFocus()) || A1526Timer[j][channel]->isRunning()) {
	if ( Vvalmode[j][channel]->isChecked() ) 
	  Vval[j][channel]->setValue(veff);
	else
	  Vval[j][channel]->setValue(vset);
      	//Vset[j][channel]->setValue((int)getParameter(slot[j], channel, "V0Set"));
      }
      if(!(Iset[j][channel]->isChanging() || Vval[j][channel]->hasFocus()) || A1526Timer[j][channel]->isRunning()) 
	Iset[j][channel]->setValue(getParameter(slot[j], channel, "I0Set"));
    }
  }  
}

//---------------------------------------------------------------
// Write values to graphs and to a file 
void A1526Control::write()
{
  //Mutex is used for making the program thread-safe
  QMutexLocker locker(&mutex); 

  for (unsigned short j = 0; j < nslots; ++j ) {
    for (unsigned short channel = 0; channel < 6; ++channel ) {
      QString RPCcodeString = RPCcode[j][channel]->text();
      if ( (!RPCcodeString.isEmpty()) && (enableGraph[j][channel]) ) {
	time(&now);
	int mytime = (int) difftime(now, startTime); 
	int vmon = (int) getParameter(slot[j], channel, "VMon");
	int vset = (int) getParameter(slot[j], channel, "V0Set");
	int veff = (int) getVeff(vset);
	float imon = getParameter(slot[j], channel, "IMon");
	
	// write to file
	if (WRITETOFILE) {
	  ofstream myfile;
	  QByteArray ba = RPCcodeString.toLatin1();
	  char buffer[50];
	  sprintf(buffer, "data/%s.txt", ba.data());
	  char* filename = buffer;
	  myfile.open(filename, fstream::app);
	  myfile << mytime << "\t" 
		 << vset << "\t" << veff << "\t" << vmon << "\t" 
		 << imon << endl;
	  myfile.close();
	}

	// enviro graphs
	Int_t points = PenvGraph[j][channel]->GetN();
	PenvGraph[j][channel]->Set(++points);
	PenvGraph[j][channel]->SetPoint(points-1, (Double_t) mytime, myenviro->getPenv());
  
	points = TenvGraph[j][channel]->GetN();
	TenvGraph[j][channel]->Set(++points);
	TenvGraph[j][channel]->SetPoint(points-1, (Double_t) mytime, myenviro->getTenv());

	points = HenvGraph[j][channel]->GetN();
	HenvGraph[j][channel]->Set(++points);
	HenvGraph[j][channel]->SetPoint(points-1, (Double_t) mytime, myenviro->getHenv());

	points = TgasGraph[j][channel]->GetN();
	TgasGraph[j][channel]->Set(++points);
	TgasGraph[j][channel]->SetPoint(points-1, (Double_t) mytime, myenviro->getTgas());
	
	points = HgasGraph[j][channel]->GetN();
	HgasGraph[j][channel]->Set(++points);
	HgasGraph[j][channel]->SetPoint(points-1, (Double_t) mytime, myenviro->getHgas());	

	// HV related graphs
	points = VsetGraphs[j][channel]->GetN();
	VsetGraphs[j][channel]->Set(points+1);
	VsetGraphs[j][channel]->SetPoint(points, (Double_t) mytime, 
					 (Double_t) vset);
	VeffGraphs[j][channel]->Set(points+1);
	VeffGraphs[j][channel]->SetPoint(points, (Double_t) mytime, 
					 (Double_t) veff);
	points = ImonGraphs[j][channel]->GetN();
	ImonGraphs[j][channel]->Set(points+1);
	ImonGraphs[j][channel]->SetPoint(points, (Double_t) mytime, 
					 (Double_t) imon);
	VmonGraphs[j][channel]->Set(points+1);
	VmonGraphs[j][channel]->SetPoint(points, (Double_t) mytime, 
					 (Double_t) vmon);
	
	// update the current measurement graphs only when channel
	// is not ramping and not in error mode
	//getStatus[j][channel];
	//	if ( (Statusval[j][channel] == 1) || (Statusval[j][channel] == 0) ) {
	if ( enableImonGraphs2[j][channel] ) {
	  points = ImonGraphs2[j][channel]->GetN();
	  ImonGraphs2[j][channel]->Set(points+1);
	  ImonGraphs2[j][channel]->SetPoint(points, (Double_t) mytime, 
					    (Double_t) imon);
	}
	if ( ImonGraphs2[j][channel]->GetN() > 0 ) {
	  Double_t meanI = ImonGraphs2[j][channel]->GetMean((Int_t) 2);
	  Double_t meanIsigma = ImonGraphs2[j][channel]->GetRMS((Int_t) 2);
	  points = IvsVGraphs[j][channel]->GetN();
	  if ( points == 0 ) 
	    IvsVGraphs[j][channel]->Set(++points);
	  //	  IvsVGraphs[j][channel]->RemovePoint(points-1);
	  if ( Vvalmode[j][channel]->isChecked() ) 
	    IvsVGraphs[j][channel]->SetPoint(points-1, 
					     veffval[j][channel], meanI);
	  else
	    IvsVGraphs[j][channel]->SetPoint(points-1, 
					     vsetval[j][channel], meanI);
	  IvsVGraphs[j][channel]->SetPointError(points-1, 0., meanIsigma);
	}
     
      }
    }
  }
}

/*****************************
 * Save graphs in root-files *
 *****************************/	
void A1526Control::save() 
{
  if (saving) return;
  QMutexLocker locker2(&mutex2);
  saving = true;
  //printc("Saving RPCcodes.dat and ROOT files ...\n");
  QFuture<void> future = QtConcurrent::run(this, &A1526Control::save_);
}

//---------------------------------------------------------------

void A1526Control::save_()
{
  //QMutexLocker locker2(&mutex2);

  //printc("Writing RPCcodes.dat\n");
  ofstream writefile;
  writefile.open("RPCcodes.dat", ios::trunc);
  for(unsigned short j = 0; j < nslots; ++j){
    for(unsigned short channel = 0; channel < 6; ++channel){
      QByteArray ba = RPCcodeString[j][channel].toLatin1();
      writefile << ba.data() << endl;
    }
  }
  writefile.close();

  //printc("Saving the rootfiles\n");
  //time_t startsave, endsave;
  //time (&startsave);

  for (unsigned short j = 0; j < nslots; ++j) {
    for(unsigned short channel = 0; channel < 6; ++channel) {
      //printc("Saving channel %i - %i\n", slot[j], channel);
      saveij_(j, channel);
    }
  }
  
  //time(&endsave);
  //int savetime = difftime(endsave, startsave); 
  //printc("Vmon and imon data are saved (time needed to save: %is)\n", 
  //	 savetime);

  saving = false;
}

//---------------------------------------------------------------
 
void A1526Control::saveij_( int j, int channel ) 
{
  char buffer10[100], buffer11[100], buffer12[100], buffer1[100], 
    buffer2[100], buffer3[100], buffer4[100], buffer5[100],buffer6[100];
  char *Ifilename, *I2filename, *Vfilename, *IvsVfilename,
    *rootfilename, *directorystring;

  QMutexLocker locker3(&mutex3);

  if ( (!RPCcodeString[j][channel].isEmpty()) && (enableGraph[j][channel]) ) {

    time(&now);
    Double_t mytime = (Double_t) difftime(now, startTime); 
    /*
    Int_t points = VsetGraphs[j][channel]->GetN();
    VsetGraphs[j][channel]->Set(points+1);
    VsetGraphs[j][channel]->SetPoint(points, mytime, vsetval[j][channel]);
    */

    QByteArray ba = RPCcodeString[j][channel].toLatin1();
    if (SAVEGRAPHS) {
      sprintf(buffer10, "graphs/%s-Enviro-P_%s.%s", ba.data(),
	      GraphFilenameTag[j][channel].toAscii().data(), FORMAT);
      sprintf(buffer11, "graphs/%s-Enviro-T_%s.%s", ba.data(),
	      GraphFilenameTag[j][channel].toAscii().data(), FORMAT);
      sprintf(buffer12, "graphs/%s-Enviro-H_%s.%s", ba.data(),
	      GraphFilenameTag[j][channel].toAscii().data(), FORMAT);
      sprintf(buffer1, "graphs/%s-Imon_%s.%s", ba.data(), 
	      GraphFilenameTag[j][channel].toAscii().data(), FORMAT);
      Ifilename = buffer1;
      if ( Vvalmode[j][channel]->isChecked() ) {
	sprintf(buffer6, "graphs/%s-Imon_vs_Veff_%s.%s", ba.data(), 
		GraphFilenameTag[j][channel].toAscii().data(), FORMAT);    
	sprintf(buffer2, "graphs/%s-Imon-%iVeff_%s.%s", ba.data(), 
		veffval[j][channel], 
		GraphFilenameTag[j][channel].toAscii().data(), FORMAT);
      }
      else {
	sprintf(buffer6, "graphs/%s-Imon_vs_Vset_%s.%s", ba.data(), 
		GraphFilenameTag[j][channel].toAscii().data(), FORMAT);
	sprintf(buffer2, "graphs/%s-Imon-%iVset_%s.%s", ba.data(), 
		vsetval[j][channel], 
		GraphFilenameTag[j][channel].toAscii().data(), FORMAT);
      }
      IvsVfilename = buffer6;
      I2filename = buffer2;
      sprintf(buffer3, "graphs/%s-Vall_%s.%s", ba.data(), 
	      GraphFilenameTag[j][channel].toAscii().data(), FORMAT);
      Vfilename = buffer3;
    }
    sprintf(buffer4, "rootfiles/%s_%s.root", ba.data(), 
	    GraphFilenameTag[j][channel].toAscii().data());
    rootfilename = buffer4;
    
    TFile* file = new TFile(rootfilename,"UPDATE");
    sprintf(buffer5, "/%s", timestring);
    directorystring = buffer5;
    if(!file->cd(directorystring)){
      TDirectory* directory = file->mkdir(timestring, timestring);
      directory->cd();
    }
    
    //    locker.unlock();
    //usleep(10); //Give some time for the other thread
    //locker.relock();
    
    if (SAVEGRAPHS){

      // enviro graphs
      Canvas->Clear();
      Canvas->SetFillColor(0);
      PenvGraph[j][channel]->Draw("AL");
      PenvGraph[j][channel]->GetXaxis()->SetTimeDisplay(1);
      PenvGraph[j][channel]->GetXaxis()->SetTimeOffset(startTimeDa->Convert());
      PenvGraph[j][channel]->GetXaxis()->SetLabelOffset(0.02);
      PenvGraph[j][channel]->GetXaxis()->SetLabelSize(0.02);
      PenvGraph[j][channel]->GetXaxis()->SetTimeFormat("#splitline{%Y\/%m\/%d}{%H:%M}");
      Canvas->SaveAs(buffer10);

      Canvas->Clear();
      Canvas->SetFillColor(0);
      TMultiGraph *temp1 = (TMultiGraph*) TGraphs[j][channel]->Clone();
      temp1->Draw("AL");
      temp1->GetXaxis()->SetTimeDisplay(1);
      temp1->GetXaxis()->SetTimeOffset(startTimeDa->Convert());
      temp1->GetXaxis()->SetLabelOffset(0.02);
      temp1->GetXaxis()->SetLabelSize(0.02);
      temp1->GetXaxis()->SetTimeFormat("#splitline{%Y\/%m\/%d}{%H:%M}");
      TLegend* leg1 = Canvas->BuildLegend(.89, .91, .99, .99);
      leg1->SetFillColor(0);
      Canvas->SaveAs(buffer11);
      delete temp1;

      Canvas->Clear();
      Canvas->SetFillColor(0);
      TMultiGraph *temp2 = (TMultiGraph*) HGraphs[j][channel]->Clone();
      temp2->Draw("AL");
      temp2->GetHistogram()->SetMinimum(0.);
      temp2->GetHistogram()->SetMaximum(105.);
      temp2->GetXaxis()->SetTimeDisplay(1);
      temp2->GetXaxis()->SetTimeOffset(startTimeDa->Convert());
      temp2->GetXaxis()->SetLabelOffset(0.02);
      temp2->GetXaxis()->SetLabelSize(0.02);
      temp2->GetXaxis()->SetTimeFormat("#splitline{%Y\/%m\/%d}{%H:%M}");
      TLegend* leg2 = Canvas->BuildLegend(.89, .91, .99, .99);
      leg2->SetFillColor(0);
      Canvas->SaveAs(buffer12);
      delete temp2;
      
      // HV related graphs
      Canvas->Clear();
      Canvas->SetFillColor(0);
      ImonGraphs[j][channel]->Draw("AL*");
      ImonGraphs[j][channel]->GetHistogram()->SetMinimum(0.);
      //      ImonGraphs[j][channel]->GetYaxis()->SetLimits(0, ImonGraphs[j][channel]->GetYaxis()->GetXmax());
      ImonGraphs[j][channel]->GetXaxis()->SetTimeDisplay(1);
      ImonGraphs[j][channel]->GetXaxis()->SetTimeOffset(startTimeDa->Convert());
      ImonGraphs[j][channel]->GetXaxis()->SetLabelOffset(0.02);
      ImonGraphs[j][channel]->GetXaxis()->SetLabelSize(0.02);
      ImonGraphs[j][channel]->GetXaxis()->SetTimeFormat("#splitline{%Y\/%m\/%d}{%H:%M}");      
      Canvas->SaveAs(Ifilename);

      if ( ImonGraphs2[j][channel]->GetN() > 0 ) {
	Canvas->Clear();
	Canvas->SetFillColor(0);
	ImonGraphs2[j][channel]->Draw("AL*");
	ImonGraphs2[j][channel]->GetHistogram()->SetMinimum(0.);
	//	ImonGraphs2[j][channel]->GetYaxis()->SetLimits(0, ImonGraphs2[j][channel]->GetYaxis()->GetXmax());
	ImonGraphs2[j][channel]->GetXaxis()->SetTimeDisplay(1);
	ImonGraphs2[j][channel]->GetXaxis()->SetTimeOffset(startTimeDa->Convert());
	ImonGraphs2[j][channel]->GetXaxis()->SetLabelOffset(0.02);
	ImonGraphs2[j][channel]->GetXaxis()->SetLabelSize(0.02);
	ImonGraphs2[j][channel]->GetXaxis()->SetTimeFormat("#splitline{%Y\/%m\/%d}{%H:%M}");      
	Canvas->SaveAs(I2filename);
      }

      if ( IvsVGraphs[j][channel]->GetN() > 0 ) {
	Canvas->Clear();
	Canvas->SetFillColor(0);
	IvsVGraphs[j][channel]->Draw("AL*");
	IvsVGraphs[j][channel]->GetHistogram()->SetMinimum(0.);
	//	IvsVGraphs[j][channel]->GetYaxis()->SetLimits(0, IvsVGraphs[j][channel]->GetYaxis()->GetXmax());
	Canvas->SaveAs(IvsVfilename);
      }

      Canvas->Clear();
      Canvas->SetFillColor(0);
      //Graph is copied because of a ROOT-bug
      TMultiGraph *temp = (TMultiGraph*) VGraphs[j][channel]->Clone();	
      temp->Draw("A");	       
      temp->GetHistogram()->SetMinimum(0.);
      //      Double_t lowx, y;
      //VsetGraphs[j][channel]->GetPoint(0, lowx, y);
      //temp->GetXaxis()->SetLimits(lowx, mytime);
      TLegend* leg = Canvas->BuildLegend(.89, .91, .99, .99);
      leg->SetFillColor(0);
      temp->GetXaxis()->SetTimeDisplay(1);
      temp->GetXaxis()->SetTimeOffset(startTimeDa->Convert());
      temp->GetXaxis()->SetLabelOffset(0.02);
      temp->GetXaxis()->SetLabelSize(0.02);
      temp->GetXaxis()->SetTimeFormat("#splitline{%Y\/%m\/%d}{%H:%M}");      
      Canvas->SaveAs(Vfilename);
      delete temp;
    }
        
    ImonGraphs[j][channel]->Write("",TObject::kOverwrite);
    ImonGraphs2[j][channel]->Write("",TObject::kOverwrite);
      //else 
      //ImonGraphs2[j][channel]->Write();
      //replaceGraph[j][channel] = true;//Next time this Imon graph will be overwritten
    IvsVGraphs[j][channel]->Write("", TObject::kOverwrite);
    VGraphs[j][channel]->Write("",TObject::kOverwrite);
    
    file->Close();

  }
}

/****************
 * Clean graphs *
 ****************/
void A1526Control::cleanGraphs(int j, int i)
{
  QMutexLocker locker(&mutex);

  RPCcode[j][i]->setReadOnly(true);
  RPCcode[j][i]->setStyleSheet( "color:black; background-color:lightGray" );
  printc("Saving the rootfiles and cleaning the graphs of channel %i - %i before changing the RPC codes\n", slot[j], i); 
  QFuture<void> future = 
    QtConcurrent::run(this, &A1526Control::cleanGraphs_, j, i);
}

void A1526Control::cleanGraphs_(int j, int i) 
{	    

  // Mutex is used for making the program thread-safe
  QMutexLocker locker(&mutex); 

  // Set last point in Vset graph before saving/deleting
  /*
  time(&now);
  Double_t mytime = (Double_t) difftime(now, startTime); 
  Int_t points = VsetGraphs[j][i]->GetN();
  VsetGraphs[j][i]->Set(points+1);
  VsetGraphs[j][i]->SetPoint(points, mytime, vsetval[j][i]);
  */
  
  saveij_(j, i);
  
  resetGraphs(slot[j], i);

  emit graphsCleared(j, i);
}

void A1526Control::resetGraphs( unsigned short slot, unsigned short i ) 
{
  QMutexLocker locker(&mutex4);

  unsigned short j = getSlotIndex(slot);

  // remove it all and start over
  delete VGraphs[j][i];
  delete ImonGraphs[j][i];
  delete ImonGraphs2[j][i];
  delete IvsVGraphs[j][i];
  delete TGraphs[j][i];
  delete HGraphs[j][i];
  delete PenvGraph[j][i];

  initGraphs(j, i);

}

//---------------------------------------------------------------

void A1526Control::showGraphs( int j, int i )
{
  TGraph theGraphs = *ImonGraphs[j][i];

  if ( !GraphWindow[j][i] ) {
    //delete GraphWindow[j][i];
    char title[100];
    sprintf(title, "Slot %i Channel %i", slot[j], i);
    GraphWindow[j][i] = new TQtWidget();
  }
  GraphWindow[j][i]->cd();
  //  theGraphs.Draw("ap");
  ImonGraphs[j][i]->Draw("AL*");

  GraphWindow[j][i]->Refresh();
  GraphWindow[j][i]->show();

  //update();

  /*  Canvas->cd();
  Canvas->Clear();
  VmonGraphs[j][i]->Draw("al");
  Canvas->Modified();
  Canvas->Update();
  */
  /*
  TCanvas* canvas = myCanvasWindow->getCanvas();
  canvas->cd();
  VGraphs[j][i]->Draw("A");
  canvas->Modified();
  canvas->Update();
  */
}

//---------------------------------------------------------------
void A1526Control::changeVvalmode( unsigned short slot, unsigned short channel,
				   bool veffon )
{
  unsigned short j = getSlotIndex(slot);

  printc("Changing Vvalmode of channel %i-%i to %i\n", 
	   slot, channel, (int) veffon );

  Vvalmode[j][channel]->setChecked(veffon);
}

//---------------------------------------------------------------
// Change Vset/Veff for a channel 
void A1526Control::changeVval(unsigned short slot, unsigned short channel, 
			      float voltage )
{
  //Mutex is used for making the program thread-safe
  QMutexLocker locker(&mutex); 

  unsigned short j = getSlotIndex(slot);

  /*
  //Set point in Vset/Veff graph before changing
  time(&now);
  Double_t mytime = (Double_t) difftime(now, startTime); 
  Int_t points = VsetGraphs[j][channel]->GetN();
  VsetGraphs[j][channel]->Set(points+1);
  VsetGraphs[j][channel]->SetPoint(points, mytime, vsetval[j][channel]);
  */

  // Update Imov vs V graph before changing (if vset is not zero)
  if ( (enableGraph[j][channel]) && (ImonGraphs2[j][channel]->GetN() > 0) ) {
    //  if (vset[j][channel] != 0){
    Double_t meanI = ImonGraphs2[j][channel]->GetMean((Int_t) 2);
    Double_t meanIsigma = ImonGraphs2[j][channel]->GetRMS((Int_t) 2);
    Int_t points = IvsVGraphs[j][channel]->GetN();
    //    IvsVGraphs[j][channel]->RemovePoint(points-1);
    if ( points == 0 ) 
      IvsVGraphs[j][channel]->Set(++points);
    if ( Vvalmode[j][channel]->isChecked() ) 
      IvsVGraphs[j][channel]->SetPoint(points-1, veffval[j][channel], meanI);
    else
      IvsVGraphs[j][channel]->SetPoint(points-1, vsetval[j][channel], meanI);
    IvsVGraphs[j][channel]->SetPointError(points-1, 0., meanIsigma);
  }
  
  // check if we use HVeff setting
  float newvoltage;
  if ( Vvalmode[j][channel]->isChecked() ) {
    veffval[j][channel] = voltage;
    newvoltage = getVset(voltage);
  }
  else 
    newvoltage = voltage;
  
  changeVset( slot, channel, newvoltage );

  /*
  //Set point in Vset graph after changing
  time (&now);
  mytime = (Double_t) difftime (now,startTime); 
  points = VsetGraphs[j][channel]->GetN();
  VsetGraphs[j][channel]->Set(points+1);
  VsetGraphs[j][channel]->SetPoint(points, mytime, voltage);
  */

  saveij_( j, channel );

  /*
  // Save old and create new Imon graph
  QString RPCcodeString = RPCcode[j][channel]->text();
  if ( (!RPCcodeString.isEmpty()) && (enableGraph[j][channel]) ) {
    QByteArray ba = RPCcodeString.toLatin1();
    char buffer[100], buffer2[100], buffer3[100], buffer4[100];
    if ( Vvalmode[j][channel]->isChecked() )
      sprintf(buffer4, "graphs/%s-Imon_vs_Veff_%s.%s", ba.data(), 
	      GraphFilenameTag[j][channel].toAscii().data(), FORMAT);
    else
      sprintf(buffer4, "graphs/%s-Imon_vs_Vset_%s.%s", ba.data(), 
	      GraphFilenameTag[j][channel].toAscii().data(), FORMAT);
    char* IvsVfilename = buffer4;
    if ( Vvalmode[j][channel]->isChecked() ) 
      sprintf(buffer, "graphs/%s-Imon-%iVeff_%s.%s", ba.data(), 
	      veffval[j][channel], 
	      GraphFilenameTag[j][channel].toAscii().data(), FORMAT);
    else
      sprintf(buffer, "graphs/%s-Imon-%iVset_%s.%s", ba.data(), 
	      vsetval[j][channel], 
	      GraphFilenameTag[j][channel].toAscii().data(), FORMAT);
    char* I2filename = buffer;
    sprintf(buffer2, "rootfiles/%s_%s.root", ba.data(), 
	    GraphFilenameTag[j][channel].toAscii().data());
    char* rootfilename = buffer2;
    TFile* file = new TFile(rootfilename,"UPDATE");
    sprintf(buffer3, "/%s", timestring);
    char* directorystring = buffer3;
    if(!file->cd(directorystring)){
      TDirectory* directory = file->mkdir(timestring, timestring);
      directory->cd();
    }
    
    if (SAVEGRAPHS) {
      Canvas->Clear();
      Canvas->SetFillColor(0);
      ImonGraphs2[j][channel]->Draw("AL*");
      Canvas->SaveAs(I2filename);
      
      Canvas->Clear();
      Canvas->SetFillColor(0);
      IvsVGraphs[j][channel]->Draw("AL*");
      Canvas->SaveAs(IvsVfilename);
    }
    //if (replaceGraph[j][channel]) 
    ImonGraphs2[j][channel]->Write("",TObject::kOverwrite);
    //else 
    //  ImonGraphs2[j][channel]->Write();
    IvsVGraphs[j][channel]->Write("", TObject::kOverwrite);
    file->Close();
  
  */

  // add new point to IvsVGraph
  if ( (enableGraph[j][channel]) && (ImonGraphs2[j][channel]->GetN() > 0) ) {
    IvsVGraphs[j][channel]->Set(IvsVGraphs[j][channel]->GetN()+1); 
  }

  delete ImonGraphs2[j][channel];
  ImonGraphs2[j][channel] = new TGraph();
  //replaceGraph[j][channel] = false;
  char buffer[50];
  if ( Vvalmode[j][channel]->isChecked() ) 
    sprintf(buffer, "Imon at %i Veff", (int) voltage);
  else
    sprintf(buffer, "Imon at %i Vset", (int) voltage);
  char* name = buffer;
  ImonGraphs2[j][channel]->SetName(name);
  ImonGraphs2[j][channel]->SetTitle("Imon vs Time; Time; Imon (#muA)");
  //    ImonGraphs2[j][channel]->GetXaxis()->SetTitle("time (s)");
  //    ImonGraphs2[j][channel]->GetYaxis()->SetTitle("Imon (#muA)");
  ImonGraphs2[j][channel]->SetFillColor(0);
}

//---------------------------------------------------------------
// Change Vset for a channel
void A1526Control::changeVset( unsigned short slotnr, unsigned short channel, 
			       float voltage )
{
  if ( (int) getParameter(slotnr, channel, "V0Set") != (int) voltage ) {
    printc("Changing VSET of channel %i-%i to %i V\n", 
	   slotnr, channel, (int) voltage);
    setParameter(slotnr, channel, "V0Set", voltage);

    if ( voltage < 0 ) cout << vsetval[getSlotIndex(slotnr)][channel] << "  " 
			    << veffval[getSlotIndex(slotnr)][channel] << endl;
  }
}

//---------------------------------------------------------------
// Set Iset for a channel 
void A1526Control::changeIset( unsigned short slotnr, unsigned short channel, 
			       float current )
{
  if( getParameter(slotnr, channel, "I0Set") != current ) {
    printc("Changing ISET of channel %i-%i to %i0 nA\n", slotnr, channel, 
	   (int) (current*100.));
    setParameter(slotnr, channel, "I0Set", current);
  }
}

/************************
 * Switch channel on/off *
 ************************/
void A1526Control::changeOnOff(unsigned short slotnr, unsigned short channel )
{
  bool oldStatus = getStatus(slotnr, channel);
  if (oldStatus) { 
    printc("Switching channel %i-%i off\n", slotnr, channel);
    setParameter(slotnr, channel, "Pw", false);
  } else {
    printc("Switching channel %i-%i on\n", slotnr, channel);
    setParameter(slotnr, channel, "Pw", true);
  }
}

/*******************************
 * Get the status of a channel *
 *******************************/
bool A1526Control::getStatus( unsigned short slotnr, unsigned short channel ) 
{

  unsigned int j = getSlotIndex(slotnr);

  Statusval[j][channel] = -1; // default value

  int bitfield = (int) getParameter(slotnr, channel, "Status");
  if (bitfield == -1) {
    //    Status[j][channel]->setText("ERROR");
    //Status[j][channel]->setStyleSheet( "color:white; background-color:darkGray" );
    emit updateStatus(j, channel, "ERROR", 4 );
    return false;
  }
  if ((bitfield & 0x01) == 0x01) {
    Statusval[j][channel] = 1;
    //    Status[j][channel]->setText("ON");
    //Status[j][channel]->setStyleSheet( "color:black; background-color:green" );
    emit updateStatus(j, channel, "ON", 2 );
    if ( !OnOff[j][channel]->ReadOnly() ) 
      OnOff[j][channel]->setText("switch OFF");
    if ((bitfield & 0x02) == 0x02) {
      Statusval[j][channel] = 2;
      //      Status[j][channel]->setText("UP");
      //Status[j][channel]->setStyleSheet( "color:black; background-color:yellow" );
      emit updateStatus(j, channel, "UP", 3 );
    } else if((bitfield & 0x04) == 0x04){
      Statusval[j][channel] = 3;
      //      Status[j][channel]->setText("DOWN");
      //Status[j][channel]->setStyleSheet( "color:black; background-color:yellow" );
      emit updateStatus(j, channel, "DOWN", 3 );
    }
    if((bitfield & 0x08) == 0x08){
      Statusval[j][channel] = 4;
      //      Status[j][channel]->setText("OVERCURRENT");
      //Status[j][channel]->setStyleSheet( "color:white; background-color:darkRed" );
      emit updateStatus(j, channel, "OVERCURRENT", 5 );
      printc("Channel %i-%i in OVERCURRENT condition\n", slotnr, channel);
    } else if((bitfield & 0x10) == 0x10){
      Statusval[j][channel] = 5;
      //      Status[j][channel]->setText("OVERVOLTAGE");
      //Status[j][channel]->setStyleSheet( "color:white; background-color:darkRed" );
      emit updateStatus(j, channel, "OVERVOLTAGE", 5 );
      printc("Channel %i-%i in OVERVOLTAGE condition\n", slotnr, channel);
    } else if((bitfield & 0x20) == 0x20){
      Statusval[j][channel] = 6;
      //      Status[j][channel]->setText("UNDERVOLTAGE");
      //Status[j][channel]->setStyleSheet( "color:white; background-color:red" );
      emit updateStatus(j, channel, "UNDERVOLTAGE", 6 );
      printc("Channel %i-%i in UNDERVOLTAGE condition\n", slotnr, channel);
    } else if((bitfield & 0x80) == 0x80){
      Statusval[j][channel] = 7;
      //      Status[j][channel]->setText("MAXV");
      //Status[j][channel]->setStyleSheet( "color:white; background-color:red" );
      emit updateStatus(j, channel, "MAXV", 6 );
      printc("Channel %i-%i in has reached maximum voltage\n", slotnr, channel);
    }

    //    cout << "getStatus " << j << " " << channel << " " << Statusval[j][channel] << endl;
    return true;
  }
  else {
    Statusval[j][channel] = 0;
    //    Status[j][channel]->setText("OFF");
    //Status[j][channel]->setStyleSheet( "color:black; background-color:lightGray" );
    emit updateStatus(j, channel, "OFF", 0 );
    if (!OnOff[j][channel]->ReadOnly()) OnOff[j][channel]->setText("switch ON");
    if((bitfield & 0x40) == 0x40){
      //      Status[j][channel]->setText("EXTTRIP");
      //Status[j][channel]->setStyleSheet( "color:white; background-color:black");
      emit updateStatus(j, channel, "EXTTRIP", 7 );
      printc("Channel %i-%i is OFF due to external TRIP line signal\n", slotnr, 
	     channel);
    } else if((bitfield & 0x200) == 0x200){
      //      Status[j][channel]->setText("INTTRIP");
      //Status[j][channel]->setStyleSheet( "color:white; background-color:black");
      emit updateStatus(j, channel, "INTTRIP", 7);
      printc("Channel %i-%i is OFF due to internal OVERCURRENT condition\n", 
	     slotnr, channel);
    } else if((bitfield & 0x100) == 0x100){
      //      Status[j][channel]->setText("EXT_DIS");
      //Status[j][channel]->setStyleSheet( "color:white; background-color:black");
      emit updateStatus(j, channel, "EXT_DIS", 7);
      printc("Channel %i-%i disabled by board INTERLOCK protection\n", 
	     slotnr, channel);
    }
    return false;
  }
}

/***************************************************
 * Set VSet and Iset read-only for a given channel *
 ***************************************************/
void A1526Control::setReadOnly(unsigned short slotnr, 
			       unsigned short channel, bool readonly){
  unsigned int j = getSlotIndex(slotnr);
  Vvalmode[j][channel]->setEnabled(!readonly);
  Vval[j][channel]->setReadOnly(readonly);
  Iset[j][channel]->setReadOnly(readonly);
  RPCcode[j][channel]->setReadOnly(readonly);
  OnOff[j][channel]->setReadOnly(readonly);
  if (readonly) {
    Vval[j][channel]->setStyleSheet( "color:black; background-color:lightGray" );
    Iset[j][channel]->setStyleSheet( "color:black; background-color:lightGray" );
    RPCcode[j][channel]->setStyleSheet( "color:black; background-color:lightGray" );
    StartStopTimer[j][channel]->setText("Stop");
  } else {
    Vval[j][channel]->setStyleSheet( "color:black; background-color:white" );
    Iset[j][channel]->setStyleSheet( "color:black; background-color:white" );
    RPCcode[j][channel]->setStyleSheet( "color:black; background-color:white" );
    StartStopTimer[j][channel]->setText("Start");
  }
}

/*****************************************
 * Set VMax, Ramp up and Ramp down speed *
 *****************************************/
void A1526Control::setVmax(int vmax) 
{
  for ( unsigned int j = 0; j < nslots; j++ ) 
    for( unsigned int i = 0; i < 6; ++i)
      setParameter(slot[j], i, "SVMax", (float) vmax);
}

void A1526Control::setRup(int speed) 
{
  for ( unsigned int j = 0; j < nslots; j++ ) 
    for(int i=0; i < 6; ++i)
      setParameter(slot[j], i, "RUp", (float) speed);
}

void A1526Control::setRdown(int speed)
{
  for ( unsigned int j = 0; j < nslots; j++ ) 
    for(int i=0; i < 6; ++i)
      setParameter(slot[j], i, "RDWn", (float) speed);
}

/*****************************************************
 * Delete A1526Timers when A1526Control is destroyed *
 *****************************************************/
A1526Control::~A1526Control()
{
  for( unsigned int j = 0; j < nslots; ++j)
    for( unsigned int i = 0; i < 6; ++i )
      delete A1526Timer[j][i];
}

//---------------------------------------------------------------

unsigned int A1526Control::getSlotIndex( unsigned int slotnr ) 
{
  for ( unsigned int j = 0; j < nslots; j++ )
    if ( slot[j] == slotnr ) return j;

  return -1;
}

//---------------------------------------------------------------
// Compute HVeff from Vset
int A1526Control::getVeff( int vset ) 
{
  return (int) (vset * P_REF/myenviro->getPenv()
		*(myenviro->getTenv()+273.)/T_REF+0.5);
}

//---------------------------------------------------------------
// Compute Vset from HVeff
int A1526Control::getVset( int veff )
{
  return (int) (veff/P_REF*myenviro->getPenv()
		/(myenviro->getTenv()+273.)*T_REF+0.5);
}

//---------------------------------------------------------------
void A1526Control::updateStatus_( unsigned short j, unsigned short i,
				  const QString text, 
				  unsigned short sheet )
{
  Status[j][i]->setText(text);
  Status[j][i]->setStyleSheet(stylesheets[sheet]);
}

//---------------------------------------------------------------
float A1526Control::getImonMean( unsigned short slot, unsigned short channel )
{
  return ImonGraphs2[getSlotIndex(slot)][channel]->GetMean((Int_t)2);
}

//---------------------------------------------------------------
float A1526Control::getImonRMS( unsigned short slot, unsigned short channel )
{
  return ImonGraphs2[getSlotIndex(slot)][channel]->GetRMS((Int_t)2);
}

//---------------------------------------------------------------
float A1526Control::getImonMin( unsigned short slot, unsigned short channel )
{
  Double_t n = ImonGraphs2[getSlotIndex(slot)][channel]->GetN();
  Double_t* y = ImonGraphs2[getSlotIndex(slot)][channel]->GetY();
  return TMath::MinElement(n, y);
}

//---------------------------------------------------------------
float A1526Control::getImonMax( unsigned short slot, unsigned short channel )
{
  Double_t n = ImonGraphs2[getSlotIndex(slot)][channel]->GetN();
  Double_t* y = ImonGraphs2[getSlotIndex(slot)][channel]->GetY();
  return TMath::MaxElement(n, y);
}
