#ifndef MpsConfiguration_HH
#define MpsConfiguration_HH

#include <iostream>
#include <fstream>

#include "RcdHeader.hh"
#include "RcdUserRW.hh"

#include "SubInserter.hh"
#include "SubAccessor.hh"

#include "MpsLaserCoordinates.hh"



class MpsConfiguration  : public RcdUserRW {

public:
  MpsConfiguration(unsigned s) {
    _location.siteNumber(s);
    _location.usbDaqBroadcast(true);
    _location.sensorBroadcast(true);
    _location.label(1);
    
    _discriminatorThreshold[0]=150;
    _discriminatorThreshold[1]=150;

    if(MPS_LOCATION==MpsLocation::birmingham) {
      _discriminatorThreshold[0]=152;
      _discriminatorThreshold[1]=152;
    }
    if(MPS_LOCATION==MpsLocation::desy) {
      _discriminatorThreshold[0]=140;
      _discriminatorThreshold[1]=140;
    }
  }

  virtual ~MpsConfiguration() {
  }

  virtual bool record(RcdRecord &r) {
    if(doPrint(r.recordType())) {
      std::cout << "MpsConfiguration::record()" << std::endl;
      r.RcdHeader::print(std::cout," ") << std::endl;
    }
    
    
    // Check record type
    switch (r.recordType()) {
      
      // Sequence start 
    case RcdHeader::sequenceStart: {
      _runNumberInSequence=0;
      break;
    }

      // Run start 
    case RcdHeader::runStart: {

      // Access the IlcRunStart
      SubAccessor accessor(r);
      std::vector<const IlcRunStart*>
        v(accessor.extract<IlcRunStart>());
      assert(v.size()==1);

      if(doPrint(r.recordType(),1)) {
	std::cout << "MpsConfiguration::record()  runStart"
		  << ", found 1 IlcRunStart object" << std::endl;
	v[0]->print(std::cout," ") << std::endl;
      }

      _runType=v[0]->runType();

      if(doPrint(r.recordType(),1)) {
	std::cout << "MpsConfiguration::record()  runStart"
		  << ", has " << _vLocation.size()
		  << " MpsLocation objects stored" << std::endl;

	if(doPrint(r.recordType(),2)) {
	  for(unsigned i(0);i<_vLocation.size();i++) {
	    _vLocation[i].print(std::cout," ") << std::endl;
	  }
	}
      }

      break;
    }

      // Run end
    case RcdHeader::runEnd: {
      _runNumberInSequence++;
      break;
    }
      
      // Configuration start 
    case RcdHeader::configurationStart: {
 
      // Access the IlcConfigurationStart
      SubAccessor accessor(r);
      std::vector<const IlcConfigurationStart*>
        v(accessor.extract<IlcConfigurationStart>());
      assert(v.size()==1);

      if(doPrint(r.recordType(),1)) {
	std::cout << "MpsConfiguration::record()  configurationStart"
		  << ", found 1 IlcConfigurationStart object" << std::endl;
	v[0]->print(std::cout," ") << std::endl;
      }

      _configurationNumber=v[0]->configurationNumberInRun();

      // Get version number
      const UtlPack ver(_runType.version());

      SubInserter inserter(r);

      // Put the overall configuration control into the record
      MpsReadoutConfigurationData *c(inserter.insert<MpsReadoutConfigurationData>(true));

      // Set up the USB_DAQ configuration vector
      std::vector< MpsLocationData<MpsUsbDaqConfigurationData> > u;

      // Set up the sensor PCB configuration
      std::vector< MpsLocationData<MpsPcb1ConfigurationData> > p;
      
      // Set up the sensor configuration
      std::vector< MpsLocationData<MpsSensor1ConfigurationData> > s;
      
      // Set up the laser configuration
      std::vector< MpsLaserConfigurationData > l;

      ////////////////////////////////////////////////////////////////////////////////////////

      // Now do specific settings for daq and slw runs
      if(_runType.majorType()==IlcRunType::daq ||
	 _runType.majorType()==IlcRunType::slw) {

	// Turn off all readout
	c->usbDaqEnableAll(false);
	c->usbDaqIoEnableAll(false);
	c->pcbEnableAll(false);
	c->sensorEnableAll(false);
      }
      
      ////////////////////////////////////////////////////////////////////////////////////////

      // Now do specific settings for usb runs
      if(_runType.majorType()==IlcRunType::usb) {

	// Turn off PCB and sensor readout
	c->usbDaqEnableAll(true);
	c->pcbEnableAll(false);
	c->sensorEnableAll(false);

	// Only read PMTs if master
	c->usbDaqIoEnableAll(false);
	for(unsigned i(0);i<_vLocation.size();i++) {
	  c->usbDaqIoEnable(i,_vLocation[i].usbDaqMaster());
	}
	
	// Add a USB_DAQ configuration object
	u.push_back(MpsLocationData<MpsUsbDaqConfigurationData>());
	u[0].location(_location);

	u[0].usbDaqBroadcast(true);
	u[0].data()->spillModeInhibitReadout(true);
	u[0].data()->spillModeHistoryEnable(true);

	// Set up separate master and slave configurations
	if(_vLocation.size()>1) {
	  u[0].usbDaqBroadcast(false);
	  u[0].usbDaqMasterBroadcast(true);
	    
	  u.push_back(MpsLocationData<MpsUsbDaqConfigurationData>());
	  u[1].location(_location);
	    
	  u[1].usbDaqBroadcast(false);
	  u[1].usbDaqSlaveBroadcast(true);
	  
	  u[1].data()->spillModeInhibitReadout(true);
	  u[1].data()->spillModeHistoryEnable(false);
	}

	u[0].data()->discriminatorThreshold(0,_discriminatorThreshold[0]);
	u[0].data()->discriminatorThreshold(1,_discriminatorThreshold[1]);
	
	switch(_runType.type()) {
	  
	case IlcRunType::usbTest: {
	  break;
	}
	case IlcRunType::usbPmtThreshold: {

	  // Set the thresholds on master
	  u[0].data()->discriminatorThreshold(0,ver.word());
	  u[0].data()->discriminatorThreshold(1,ver.word());

	  break;
	}
	case IlcRunType::usbPmtThresholdScan: {

	  // Set the thresholds
	  const unsigned steps((ver.word())%100+1);
	  const unsigned step(_configurationNumber%steps);
	  u[0].data()->discriminatorThreshold(0,100+step*(100/steps));
	  u[0].data()->discriminatorThreshold(1,100+step*(100/steps));
	  break;
	}
	  
	default: {
	  // We missed a run type
	  assert(false);
	  break;
	}
	};
      }


      ///////////////////////////////////////////////////////////////////////////////////////

      if(_runType.majorType()==IlcRunType::mps) {

	// Set up what to read out
	c->usbDaqEnableAll(true);
	c->usbDaqIoEnableAll(false);
	c->pcbEnableAll(true);
	c->sensorEnableAll(true);

	// Turn off PCB and sensor readout for missing PCBs
	for(unsigned i(0);i<_vLocation.size();i++) {
	  c->pcbEnable(i,_vLocation[i].sensorId()!=31);
	  c->sensorEnable(i,_vLocation[i].sensorId()!=31);
	}

	// Add one of every object
	u.push_back(MpsLocationData<MpsUsbDaqConfigurationData>());
	u[0].location(_location);
	u[0].data()->discriminatorThreshold(0,_discriminatorThreshold[0]);
	u[0].data()->discriminatorThreshold(1,_discriminatorThreshold[1]);
	
	p.push_back(MpsLocationData<MpsPcb1ConfigurationData>());
	p[0].location(_location);

	if(_configurationNumber==0) setSensorConfiguration(s,*c);

	switch(_runType.type()) {
	  
	case IlcRunType::mpsTest: {
	  break;
	}
	case IlcRunType::mpsExpert: {
	  break;
	}
	case IlcRunType::mpsNoise: {
	  /* Original
	  if(_configurationNumber==0) {
	    for(unsigned i(0);i<s.size();i++) {
	      for(unsigned j(0);j<4;j++) {
		if(ver.bit(j)) s[i].data()->maskRegion(j,true);
	      }
	      if(ver.bit(4)) s[i].data()->maskInvert();
	    }
	  } else {
	    s.clear();
	  }
	  
	  if(ver.bit(5)) u[0].data()->pixelEnable12(false);
	  if(ver.bit(6)) u[0].data()->pixelEnable34(false);

	  u[0].data()->hitOverride(ver.bit(7));
	  */

	  if(_configurationNumber==0) {


	    for(unsigned i(0);i<s.size();i++) {
	      s[i].data()->maskRegion(0,true);
	      s[i].data()->maskRegion(2,true);
	      s[i].data()->maskRegion(3,true);

	      for(unsigned j(0);j<7;j++) {
		if(ver.bit(j)) {
		  for(unsigned y(0);y<168;y++) {
		    for(unsigned x(42+6*j);x<(48+6*j);x++) {
		      s[i].data()->mask(x,y,true);
		    }
		  }
		}
	      }
	    }


	  } else {
	    s.clear();
	  }


	  break;
	}
	case IlcRunType::mpsPcbConfigurationScan: {
	  if(ver.bits(0,4)<32) {
	    unsigned dac(ver.bits(0,4));

	    if(dac==21 || dac==22 || dac==23 ||
	       dac==25 || dac==27 || dac==30) {

	      if(dac==21) {
		p[0].data()->samplerThreshold(p[0].data()->samplerThresholdValue(),
					      p[0].data()->samplerThresholdCommonMode()
					      -100+2*(_configurationNumber%100));
	      }	      
	      if(dac==22) {
		p[0].data()->debugThreshold(p[0].data()->debugThresholdValue(),
					    p[0].data()->debugThresholdCommonMode()
					    -100+2*(_configurationNumber%100));
	      }	      
	      if(dac==23) {
		p[0].data()->shaperThreshold(p[0].data()->shaperThresholdValue(),
					     p[0].data()->shaperThresholdCommonMode()
					     -100+2*(_configurationNumber%100));
	      }	      
	      if(dac==25) {
		p[0].data()->samplerThreshold(p[0].data()->samplerThresholdValue()
					      -100+2*(_configurationNumber%100),
					      p[0].data()->samplerThresholdCommonMode());
	      }	      
	      if(dac==27) {
		p[0].data()->debugThreshold(p[0].data()->debugThresholdValue()
					    -100+2*(_configurationNumber%100),
					    p[0].data()->debugThresholdCommonMode());
	      }
	      if(dac==30) {
		p[0].data()->shaperThreshold(p[0].data()->shaperThresholdValue()
					     -100+2*(_configurationNumber%100),
					     p[0].data()->shaperThresholdCommonMode());
	      }	      

	    } else {


	      if(dac!=24) {
		p[0].data()->dac(dac,p[0].data()->dac(dac)-100+2*(_configurationNumber%100));
	      } else {
		p[0].data()->dac(dac,p[0].data()->dac(dac)-1000+20*(_configurationNumber%100));
	      }
	    }



	  } else {
	    const unsigned steps(2*ver.halfByte(0)+1);	  
	    
	    if(_configurationNumber==0) {
	      _nominalPcbConfiguration=*(p[0].data());
	    } else if(_configurationNumber==(32*steps+1)) {
	      *(p[0].data())=_nominalPcbConfiguration;
	    } else {
	      const unsigned nDac((_configurationNumber-1)/steps);
	      const unsigned nStep((_configurationNumber-1)%steps);
	      unsigned value(_nominalPcbConfiguration.dac(nDac));
	      value+=(nStep-(ver.halfByte(0)+1))*(2048/steps);
	      p[0].data()->dac(nDac,value);
	    }
	  }
	  break;
	}
	case IlcRunType::mpsThreshold: {
	  /*
	  p[0].data()->vth12Pos(2048+ver.word());
	  p[0].data()->vth12Neg(2048-ver.word());
	  p[0].data()->vth34Pos(2048+ver.word());
	  p[0].data()->vth34Neg(2048-ver.word());
	  */
	  //u[0].data()->pixelEnable12(false);
	  //u[0].data()->pixelEnable34(false);
	  /*
          for(unsigned i(0);i<s.size();i++) {
	      s[i].data()->maskRegion(2,true);
	      s[i].data()->maskRegion(3,true);
	  }
	  */	  
	  for(unsigned i(0);i<_vLocation.size();i++) {
	    c->usbDaqIoEnable(i,false);
	    c->pcbEnable(     i,true);
	    c->sensorEnable(  i,true);
	  }

	  p[0].data()->shaperThreshold( 4*ver.word());
	  p[0].data()->samplerThreshold(8*ver.word());
          /*
          u[0].data()->pixelEnable12(false);
          p[0].data()->shaperThreshold(ver.word());
          p[0].data()->samplerThreshold(ver.word());
	  */
	  break;
	}
	case IlcRunType::mpsThresholdScan: {
	  //u[0].data()->pixelEnable12(false);
	  //u[0].data()->pixelEnable34(false);

	  // Only set sensor configuration at first time
	  // as it doesn't change
	  /*
	  if(_configurationNumber==0) {
	    for(unsigned i(0);i<s.size();i++) {
	      //s[i].data()->trimRegion(0,8);
	      //s[i].data()->trimRegion(1,8);
	      //s[i].data()->maskRegion(0,true);
	      //s[i].data()->maskRegion(1,true);

	      //s[i].data()->maskRegion(2,true);
	      //s[i].data()->maskRegion(3,true);
	    }
	  } else {
	    s.clear();
	  }
	  */

	  // TEMP ONLY UNTIL USING ONE (MASTER) BOARD
	  /*
	  for(unsigned i(0);i<_vLocation.size();i++) {
	    c->usbDaqIoEnable(i, _vLocation[i].usbDaqMaster());
	    c->pcbEnable(     i,!_vLocation[i].usbDaqMaster());
	    c->sensorEnable(  i,!_vLocation[i].usbDaqMaster());
	  }
	  */
	  for(unsigned i(0);i<_vLocation.size();i++) {
	    c->usbDaqIoEnable(i,false);
	    c->pcbEnable(     i,true);
	    c->sensorEnable(  i,true);
	  }

	  const unsigned steps(ver.word()+1);	  
	  const unsigned nStepV(steps-(_configurationNumber%steps)-1);
	  //const unsigned nStepC(_configurationNumber/steps);

	  int offset=0;
	  unsigned commonMode(3*1024);
	  p[0].data()->shaperThreshold( offset+(int)nStepV*(1000/steps),commonMode);
	  p[0].data()->samplerThreshold(offset+(int)nStepV*(1000/steps),commonMode);

	  thresholdScan(ver,*(p[0].data()));



	  //by Jamie - 29/11/2007 10.25 am
	  /*
	  int offset=ver.word();
          p[0].data()->shaperThreshold( offset+_configurationNumber);
	  p[0].data()->samplerThreshold(offset+_configurationNumber);
	  */	  

	  /*
	  p[0].data()->shaperThreshold(-128+(int)nStepV*(512/steps),2048-256+nStepC*(512/steps));
	  p[0].data()->samplerThreshold( 384-(int)nStepV*(512/steps),2048-256+nStepC*(512/steps));
	  */

	  //Jamie - sanity check! 16:51
	  // p[0].data()->shaperThreshold(100+_configurationNumber);

	  //if((_configurationNumber%2)==0) {
	  /*
	    p[0].data()->vth12Pos(2048+nStep*(256/steps));
	    p[0].data()->vth12Neg(2048-nStep*(256/steps));
	    p[0].data()->vth34Pos(2048+nStep*(256/steps));
	    p[0].data()->vth34Neg(2048-nStep*(256/steps));
	  */
	    //p[0].data()->vth12Pos(2048    +nStep*(512/steps));
	    //p[0].data()->vth12Neg(2048);
	    //p[0].data()->vth34Pos(2048);
	    //p[0].data()->vth34Neg(2048-512+nStep*(512/steps));
	    //} else {
	    //p[0].data()->vth12Pos(2048);
	    //p[0].data()->vth12Neg(2048-512+nStep*(512/steps));
	    //p[0].data()->vth34Pos(2048    +nStep*(512/steps));
	    //p[0].data()->vth34Neg(2048);
	    //}
	  break;
	}
	case IlcRunType::mpsTrim: {
	  for(unsigned i(0);i<s.size();i++) {
	    s[i].data()->trimQuadrant(ver.bits(4,5),ver.halfByte(0));
	  }
	  break;
	}
	case IlcRunType::mpsTrimScan: {
	  for(unsigned i(0);i<s.size();i++) {
	    s[i].data()->trimSensor(_configurationNumber%16);
	    s[i].data()->maskSensor(true);

	    for(unsigned y(0);y<168;y++) {
	      for(unsigned region(0);region<4;region++) {
		s[i].data()->mask(42*region+((_configurationNumber/16)%42),y,false);
	      }
	    }
	  }

	  p[0].data()->shaperThreshold(100);
	  p[0].data()->samplerThreshold(140);

	  // 2D trim and general threshold scan
	  /*
	  for(unsigned i(0);i<s.size();i++) {
	    s[i].data()->maskSensor(false);
	  }

	  if(_configurationNumber==0 || _configurationNumber==257) {
	    for(unsigned i(0);i<s.size();i++) {
	      s[i].data()->trimRegion(0,7);
	      s[i].data()->trimRegion(1,7);
	      s[i].data()->trimRegion(2,7);
	      s[i].data()->trimRegion(3,7);
	    }
	    p[0].data()->shaperThreshold(10*(ver.halfByte(0)+1));
	    p[0].data()->samplerThreshold(10*(ver.halfByte(1)+1));
	      
	  } else {
	    for(unsigned i(0);i<s.size();i++) {
	      s[i].data()->trimRegion(0,(_configurationNumber-1)%16);
	      s[i].data()->trimRegion(1,(_configurationNumber-1)%16);
	      s[i].data()->trimRegion(2,(_configurationNumber-1)%16);
	      s[i].data()->trimRegion(3,(_configurationNumber-1)%16);
	    }  
	    p[0].data()->shaperThreshold(10*(ver.halfByte(0)+1)+10*((_configurationNumber-1)/16-8));
	    p[0].data()->samplerThreshold(10*(ver.halfByte(1)+1)+10*((_configurationNumber-1)/16-8));
	  }
	  */

	  break;
	}
	case IlcRunType::mpsHitOverride: {
	  u[0].data()->spillCycleCount(10);
	  u[0].data()->hitOverride(true);

	  for(unsigned i(0);i<s.size();i++) {
	    s[i].data()->maskSensor(true);
	  }

	  //u[0].data()->pixelEnable12(false);
	  //u[0].data()->pixelEnable34(false);
	  //u[0].data()->monoPOR(true);


	  //p[0].data()->readFile("Pcb1ConfigurationData.txt");
	  /*
	  const unsigned steps(ver.word()+1);
	  const unsigned nStep(_configurationNumber%steps);

	  p[0].data()->shaperThreshold(-256+nStep*(512/steps));
	  p[0].data()->samplerThreshold(-256+nStep*(512/steps));

	  u[0].data()->spillModeInhibitSpill((_configurationNumber%2)==0);
	  u[0].data()->spillModeFillSrams((_configurationNumber%2)==0);
	  */
	  /*
	  Offset stack pointer true
	    Offset stack pointer value=18 (or 19)
	  */


	  //u[0].data()->clockPhase(0,nStep*(256/steps));
	  //u[0].data()->clockPhase(1,nStep*(256/steps));
	  //u[0].data()->senseDelay(24+nStep*(256/steps));

	  /*
	  p[0].data()->shaperThreshold(-4000+nStep*(8000/steps));
	  p[0].data()->samplerThreshold(-4000+nStep*(8000/steps));
	  */

	    /*
	  const unsigned steps(ver.word()+1);
	  const unsigned nStep(_configurationNumber);
	  //p[0].data()->iSenseBias(2048-256+nStep*(512/steps));
	  p[0].data()->iSenseColRef(2048-256+nStep*(512/steps));
	  */

	  break;
	}
	case IlcRunType::mpsBeamThresholdScan: {

	  // Only read PMTs if master
	  c->usbDaqIoEnableAll(false);
	  for(unsigned i(0);i<_vLocation.size();i++) {
	    c->usbDaqIoEnable(i,_vLocation[i].usbDaqMaster());
	  }
	



	  const unsigned nSensors(_vLocation.size()-1);
	  //const unsigned nSteps(10);
	  //Jamie, 16/12/07 - this was 16 steps when we wanted to start at 100...
	  const unsigned nSteps(13);
	  const unsigned nCycle(nSensors*nSteps);
	  const unsigned iCycle(_configurationNumber%(nCycle+1));

	  if(iCycle==0) {
	    // Do nothing; this is for all at nominal thresholds
    
	  } else {

	    // Figure out which sensor to change and what threshold
	    const unsigned iSensor(((iCycle-1)/nSteps)%nSensors);
	    const unsigned iStep((iCycle-1)%nSteps);
	    
	    assert(p.size()==1);
	    p.push_back(MpsLocationData<MpsPcb1ConfigurationData>());

	    unsigned j(0);
	    for(unsigned i(0);i<_vLocation.size();i++) {
	      if(!_vLocation[i].usbDaqMaster()) {
		if(j==iSensor) p[1].location(_vLocation[i]);
		j++;
	      }
	    }

	    p[1].write(true);

	    // Select on low or high threshold scan using bit 0
	    if(ver.bit(0)) {
 	      p[1].data()->shaperThreshold(  50+10*iStep);
 	      p[1].data()->samplerThreshold(100+20*iStep);
	      
	    } else {
	      
	      //if(ver.bit(1)){
		
		p[1].data()->shaperThreshold( 80+10*iStep);
		p[1].data()->samplerThreshold(160+20*iStep);
		
		std::cout<<"SANITY: shaper threhold = "<<(80+10*iStep)<<std::endl; 	      
		std::cout<<"SANITY: sampler threhold = "<<(160+20*iStep)<<std::endl; 	      

		/*
	      }else{
		//p[1].data()->shaperThreshold( 100+100*iStep);
		//p[1].data()->samplerThreshold(200+200*iStep);
		
		// we want to modify the ranges of this scan so that they: 
		//  shapers: 100-300 in 10 steps
		//  samplers: 100-600 in 10 steps
		p[1].data()->shaperThreshold( 100+20*iStep);
		p[1].data()->samplerThreshold(100+50*iStep);
		std::cout<<"SANITY: shaper threhold = "<<(100+20*iStep)<<std::endl; 	      
		std::cout<<"SANITY: sampler threhold = "<<(100+50*iStep)<<std::endl; 	      
	      }
		*/
	    }
	  }

	  // Allow to run into the mpsBeam settings
	}
	case IlcRunType::mpsBeam: {

	  // Only read PMTs if master
	  c->usbDaqIoEnableAll(false);
	  for(unsigned i(0);i<_vLocation.size();i++) {
	    c->usbDaqIoEnable(i,_vLocation[i].usbDaqMaster());
	  }
	

	  // Only load masks and trims on first configuration
	  /*
	  if(_configurationNumber>0) {
	    s.clear();
	  } else {
	    if(ver.word()==124) {
	      for(unsigned i(0);i<s.size();i++) {
		if(s[i].sensorId()==6) s[i].data()->maskSensor(true);
	      }
	    }
	  }
	  */

	  //if(_configurationNumber==0) {
	    for(unsigned i(0);i<_vLocation.size();i++) {
	      c->usbDaqIoEnable(i, _vLocation[i].usbDaqMaster());
	      c->pcbEnable(     i,!_vLocation[i].usbDaqMaster());
	      c->sensorEnable(  i,!_vLocation[i].usbDaqMaster());
	    }
	    //}
	  
	  if(true) {
	    // Only read out PMTs of masters
	    u[0].usbDaqBroadcast(false);
	    u[0].usbDaqMasterBroadcast(true);
	    u[0].data()->spillModeInhibitReadout(true);
	    u[0].data()->spillModeHistoryEnable(true);
	    
	    u.push_back(MpsLocationData<MpsUsbDaqConfigurationData>());
	    u[1].location(_location);

	    u[1].usbDaqBroadcast(false);
	    u[1].usbDaqSlaveBroadcast(true);
	    u[1].data()->spillModeHistoryEnable(false);

	    u[1].data()->discriminatorThreshold(0,0);
	    u[1].data()->discriminatorThreshold(1,0);
	    
	    /// note: trial lower threshold value:
	    //p[0].data()->shaperThreshold( 120);
	    //p[0].data()->samplerThreshold(200);
	    //p[0].data()->shaperThreshold((int)nStepV*20);
	    //p[0].data()->samplerThreshold((int)nStepV*20);
	    
	    // Only read out PMTs of particular board
	    /*
	    u[0].data()->spillModeHistoryEnable(false);

	    u[0].data()->discriminatorThreshold(0,0);
	    u[0].data()->discriminatorThreshold(1,0);
	    
	    u.push_back(MpsLocationData<MpsUsbDaqConfigurationData>());
	    u[1].location(_location);
	    u[1].usbDaqBroadcast(false);
	    u[1].usbDaqAddress(8);
	    u[1].data()->spillModeHistoryEnable(true);

	    u[1].data()->discriminatorThreshold(0,140);
	    u[1].data()->discriminatorThreshold(1,140);
	    */

	  } else {

	    // No PMT readout (TEMP)
	    u[0].data()->spillModeHistoryEnable(false);
	  }

	  break;
	}
	case IlcRunType::mpsCosmicsThresholdScan: {
	
	  const unsigned nSensors(_vLocation.size()-1);
	  unsigned nSteps(13);
	  if(ver.bit(0)) nSteps=10;
	  const unsigned nCycle(nSensors*nSteps);
	  const unsigned iCycle(_configurationNumber%(nCycle+1));

	  if(iCycle==0) {
	    // Do nothing; this is for all at nominal thresholds
    
	  } else {

	    // Figure out which sensor to change and what threshold
	    const unsigned iSensor(((iCycle-1)/nSteps)%nSensors);
	    const unsigned iStep((iCycle-1)%nSteps);
	    
	    assert(p.size()==1);
	    p.push_back(MpsLocationData<MpsPcb1ConfigurationData>());

	    unsigned j(0);
	    for(unsigned i(0);i<_vLocation.size();i++) {
	      if(!_vLocation[i].usbDaqMaster()) {
		if(j==iSensor) p[1].location(_vLocation[i]);
		j++;
	      }
	    }

	    p[1].write(true);

	    // Select on low or high threshold scan using bit 0
	    if(ver.bit(0)) {
 	      p[1].data()->shaperThreshold(  50+10*iStep);
 	      p[1].data()->samplerThreshold(100+20*iStep);
	      
	    } else {
	      p[1].data()->shaperThreshold( 80+10*iStep);
	      p[1].data()->samplerThreshold(160+20*iStep);
	    }
	  }

	  // Allow to run into the mpsCosmics settings
	}
	case IlcRunType::mpsCosmics: {
	  
	  // Only read PMTs if master
	  c->usbDaqIoEnableAll(false);
	  for(unsigned i(0);i<_vLocation.size();i++) {
	    c->usbDaqIoEnable(i,_vLocation[i].usbDaqMaster());
	  }

	  // Only read out PMTs of masters
	  u[0].usbDaqBroadcast(false);
	  u[0].usbDaqMasterBroadcast(true);
	  u[0].data()->spillModeInhibitReadout(true);
	  u[0].data()->spillModeHistoryEnable(true);
	  
	  u.push_back(MpsLocationData<MpsUsbDaqConfigurationData>());
	  u[1].location(_location);
	  
	  u[1].usbDaqBroadcast(false);
	  u[1].usbDaqSlaveBroadcast(true);
	  u[1].data()->spillModeHistoryEnable(false);
	  
	  u[1].data()->discriminatorThreshold(0,0);
	  u[1].data()->discriminatorThreshold(1,0);

	  break;
	}
	case IlcRunType::mpsSourceThresholdScan: {

	  // Only read PMTs if master
	  c->usbDaqIoEnableAll(false);
	  for(unsigned i(0);i<_vLocation.size();i++) {
	    c->usbDaqIoEnable(i,_vLocation[i].usbDaqMaster());
	  }
	
	  u[0].data()->spillModeHistoryEnable(true);

	  const unsigned steps(ver.word()+1);	  
	  const unsigned nStepV(_configurationNumber%steps);
	  //const unsigned nStepC(_configurationNumber/steps);
	  p[0].data()->shaperThreshold((int)nStepV*20);
	  p[0].data()->samplerThreshold((int)nStepV*20);

	  break;
	}
	case IlcRunType::mpsSource: {

	  // Only read PMTs if master
	  c->usbDaqIoEnableAll(false);
	  for(unsigned i(0);i<_vLocation.size();i++) {
	    c->usbDaqIoEnable(i,_vLocation[i].usbDaqMaster());
	  }
	
	  u[0].data()->spillModeHistoryEnable(true);

	  p[0].data()->shaperThreshold(100);
	  p[0].data()->samplerThreshold(50);
	  break;
	}
	case IlcRunType::mpsMaskThresholdScan: {
	  u[0].data()->spillCycleCount(18);

	  s.clear();
	  if(_configurationNumber==0) {
	    s.push_back(MpsLocationData<MpsSensor1ConfigurationData>());
	    s[0].location(_location);
	    s[0].data()->maskSensor(true);
	    s[0].data()->trimSensor(0);
	    
	    for(unsigned x(_runNumberInSequence%42);x<168;x+=42) {
	      for(unsigned y(42*((_runNumberInSequence/42)%4));y<42*(1+((_runNumberInSequence/42)%4));y++) {
		s[0].data()->mask(x,y,false);
	      }
	    }
	  }

	  thresholdScan(ver,*(p[0].data()));

	  break;
	}
	case IlcRunType::mpsMonostableLengthScan: {
	  p[0].data()->shaperThreshold(100);
	  p[0].data()->samplerThreshold(100);

	  const unsigned steps(ver.word()+1);
	  const unsigned nStep(_configurationNumber%steps);
	  p[0].data()->i12MSOBias1(nStep*(4096/steps));
	  p[0].data()->i34MSOBias1(nStep*(4096/steps));
	  p[0].data()->i34MSOBias2(nStep*(4096/steps));
	  break;
	}
	case IlcRunType::mpsConfigurationTest: {
	  unsigned short *ptr((unsigned short*)u[0].data());
	  for(unsigned j(0);j<sizeof(MpsUsbDaqConfigurationData)/2;j++) {
	    ptr[j]=(rand()&0xffff);
	  }
	  u[0].data()->spillCycleCount(rand()%8192);
	  u[0].data()->clockPhase(0,rand()%256);
	  u[0].data()->clockPhase(1,rand()%256);
	  u[0].data()->clockPhase(2,rand()%256);
	  u[0].data()->senseDelay(rand()%256);
	  u[0].data()->timeStampPrescale(rand()%256);
	  u[0].data()->spillMode(rand()%256);
	  u[0].data()->masterClockResetDuration(rand()%256);
	  u[0].data()->sramFillClockSleep(rand()%256);
	  u[0].data()->readoutColumnOrder(rand()%256);
	  u[0].data()->staticTimeStampGray(rand()%8192);
	  u[0].data()->readoutStartIndex(rand()%4);
	  u[0].data()->stackPointerOffset(rand()%19);
	  u[0].data()->testTriggerMode(rand()%16);
	  u[0].data()->discriminatorThreshold(0,rand()%256);
	  u[0].data()->discriminatorThreshold(1,rand()%256);

	  u[0].data()->zeroBools();
	  UtlPack rndm(rand());
	  u[0].data()->debugReset200Hold(rndm.bit( 0));
	  u[0].data()->debugReset600Hold(rndm.bit( 1));
	  u[0].data()->debugDiodeResetHold(rndm.bit( 2));
	  u[0].data()->hitOverride(rndm.bit( 3));
	  u[0].data()->monoPOR(rndm.bit( 4));
	  u[0].data()->pixelEnable12(rndm.bit( 5));
	  u[0].data()->pixelEnable34(rndm.bit( 6));
	  u[0].data()->senseEnable(rndm.bit( 7));
	  u[0].data()->debugHitInEnable(rndm.bit( 8));
	  u[0].data()->fastPhiOverride(rndm.bit( 9));
	  u[0].data()->readEnableOverride(rndm.bit(10));
	  u[0].data()->initBPolarity(rndm.bit(11));
	  u[0].data()->rstBPolarity(rndm.bit(12));
	  u[0].data()->fwdBPolarity(rndm.bit(13));
	  u[0].data()->slowSpillPhi(rndm.bit(14));
	  u[0].data()->timeStampOverride(rndm.bit(15));

	  for(unsigned i(0);i<32;i++) {
	    p[0].data()->dac(i,(rand()%4096));
	  }

	  if(ver.bit(0)) {
	    for(unsigned i(0);i<s.size();i++) {
	      unsigned short *ptr((unsigned short*)s[i].data());
	      for(unsigned j(0);j<sizeof(MpsSensor1ConfigurationData)/2;j++) {
		ptr[j]=(rand()&0xffff);
	      }
	    }
	  }

	  break;
	}
	case IlcRunType::mpsUsbDaqConfigurationScan: {

	  if(ver.halfByte(0)==0) {
	    double multiplier(0.1*(_configurationNumber%100));
	    u[0].data()->diodeResetDuration( (unsigned)(u[0].data()->diodeResetDuration() *multiplier));
	    u[0].data()->shaperResetDuration((unsigned)(u[0].data()->shaperResetDuration()*multiplier));
	    u[0].data()->sampleResetDuration((unsigned)(u[0].data()->sampleResetDuration()*multiplier));
	  }
	  break;
	}
	case IlcRunType::mpsLaser: {
	  u[0].data()->spillCycleCount(1999);
	  if(MPS_LOCATION==MpsLocation::imperial) u[0].data()->spillCycleCount(9);

	  // Turn on laser
	  u[0].data()->testTriggerMode(8);
	  u[0].data()->testTriggerStart(104);
	  u[0].data()->testTriggerStop(154);
	  
	  p[0].data()->shaperThreshold( 511);
	  p[0].data()->samplerThreshold(511);

	  MpsLaserConfigurationData l;

	  // Don't move laser
	  l.stageX(999999);
	  l.stageY(999999);
	  inserter.insert<MpsLaserConfigurationData>(l);
	  break;
	}
	case IlcRunType::mpsLaserPosition: {
	  u[0].data()->spillCycleCount(1999);
	  if(MPS_LOCATION==MpsLocation::imperial) u[0].data()->spillCycleCount(9);

	  // Turn on laser
	  u[0].data()->testTriggerMode(8);
	  u[0].data()->testTriggerStart(104);
	  u[0].data()->testTriggerStop(154);	  

	  p[0].data()->shaperThreshold( 511);
	  p[0].data()->samplerThreshold(511);

	  MpsLaserConfigurationData l;
	  l.stageX(1000*((int)ver.bits(0,3)-8));
	  l.stageY(1000*((int)ver.bits(4,7)-8));
	  inserter.insert<MpsLaserConfigurationData>(l);
	  break;
	}
	case IlcRunType::mpsLaserPositionScan: {
	  u[0].data()->spillCycleCount(1999);
	  if(MPS_LOCATION==MpsLocation::imperial) u[0].data()->spillCycleCount(9);

	  // Turn on laser
	  if(!ver.bit(7)) enableLaser(*(u[0].data()));

	  p[0].data()->shaperThreshold( 25,2048);
	  //p[0].data()->shaperThreshold( -10+10*_runNumberInSequence,3072);
	  p[0].data()->samplerThreshold(500,2048);

	  /*	  
	  p[0].data()->shaperThreshold( 500,3072);
	  if(_runNumberInSequence==0) p[0].data()->samplerThreshold(160,3072);
	  if(_runNumberInSequence==1) p[0].data()->samplerThreshold(120,3072);
	  if(_runNumberInSequence==2) p[0].data()->samplerThreshold( 80,3072);
	  if(_runNumberInSequence==3) p[0].data()->samplerThreshold( 40,3072);
	  */

	  MpsLaserConfigurationData l;
	  l.numberOfPulses(16);

	  MpsLaserCoordinates lc;
	  lc.print() << std::endl;

	  /*
	  const unsigned steps(ver.word()+1);

	  //const double centreLocalX(lc.localX(60));
	  //const double centreLocalY(lc.localY(29));
	  //const double centreLocalX(lc.localX(41));
	  //const double centreLocalY(lc.localY(100));
	  const double centreLocalX(lc.localX(63));
	  const double centreLocalY(lc.localY(126));

	  std::cout << "Centre local position " << centreLocalX << ", " << centreLocalY << std::endl;

	  const double totalSize(0.15);
	  const double stepSize(totalSize/steps);

	  std::cout << "Total, step size = " << totalSize << ", " << stepSize << std::endl;

	  const double startLocalX(centreLocalX-0.5*totalSize+0.5*stepSize);
	  const double startLocalY(centreLocalY+0.5*totalSize-0.5*stepSize);

	  std::cout << "Start local position " << startLocalX << ", " << startLocalY << std::endl;

	  // Local y is negative wrt pixel y
	  const double localX(startLocalX+stepSize*( _configurationNumber%steps       ));
	  const double localY(startLocalY-stepSize*((_configurationNumber/steps)%steps));

	  std::cout << "Local position " << localX << ", " << localY << std::endl;

	  l.stageX(lc.stageX(localX,localY));
	  l.stageY(lc.stageY(localX,localY));
	  */

	  unsigned centrePixelX(63);
	  unsigned centrePixelY(126);

	  for(unsigned i(0);i<s.size();i++) {
	    s[i].data()->maskSensor(true);
	    s[i].data()->mask(centrePixelX,centrePixelY,false);

	    if(ver.bit(5)) {
	      s[i].data()->mask(centrePixelX-1,centrePixelY-1,false);
	      s[i].data()->mask(centrePixelX  ,centrePixelY-1,false);
	      s[i].data()->mask(centrePixelX+1,centrePixelY-1,false);
	      s[i].data()->mask(centrePixelX-1,centrePixelY  ,false);
	      s[i].data()->mask(centrePixelX+1,centrePixelY  ,false);
	      s[i].data()->mask(centrePixelX-1,centrePixelY+1,false);
	      s[i].data()->mask(centrePixelX  ,centrePixelY+1,false);
	      s[i].data()->mask(centrePixelX+1,centrePixelY+1,false);
	    }
	  }

	  const int centreStageX(lc.stageX(centrePixelX,centrePixelY));
	  const int centreStageY(lc.stageY(centrePixelX,centrePixelY));

	  std::cout << "Centre stage position " << centreStageX << ", " << centreStageY << std::endl;

	  // Coarse scan; 150x150mu in 30mu steps
	  if(ver.halfByte(0)==0) {
	    const unsigned steps=5;
	    l.stageX(centreStageX-60+30*((_configurationNumber/steps)%steps));
	    l.stageY(centreStageY-60+30*( _configurationNumber%steps       ));
	  }

	  // Medium scan; 150x150mu in 10mu steps
	  if(ver.halfByte(0)==1) {
	    const unsigned steps=15;
	    l.stageX(centreStageX-70+10*((_configurationNumber/steps)%steps));
	    l.stageY(centreStageY-70+10*( _configurationNumber%steps       ));
	  }

	  // Detailed scan; 150x150mu in 5mu steps
	  if(ver.halfByte(0)==2) {
	    const unsigned steps=30;
	    l.stageX(centreStageX-72+5*((_configurationNumber/steps)%steps));
	    l.stageY(centreStageY-72+5*( _configurationNumber%steps       ));
	  }

	  // Cross scan in x; 150mu in 5mu steps
	  if(ver.halfByte(0)==3) {
	    l.stageX(centreStageX);
	    //l.stageY(centreStageY-72+5*_configurationNumber);
	    l.stageY(centreStageY+73-5*_configurationNumber);
	  }

	  // Cross scan in y; 150mu in 5mu steps
	  if(ver.halfByte(0)==4) {
	    l.stageX(centreStageX-72+5*_configurationNumber);
	    l.stageY(centreStageY);
	  }

	  // Detailed cross scan in x; 150mu in 1mu steps
	  if(ver.halfByte(0)==5) {
	    l.stageX(centreStageX);
	    l.stageY(centreStageY-75+1*_configurationNumber);
	  }

	  // Detailed cross scan in y; 150mu in 1mu steps
	  if(ver.halfByte(0)==6) {
	    l.stageX(centreStageX-75+1*_configurationNumber);
	    l.stageY(centreStageY);
	  }

	  // Very fine detail scan; 75x75mu
	  if(ver.halfByte(0)==7) {
	    const unsigned steps=75;
	    l.stageX(centreStageX-37+1*((_configurationNumber/steps)%steps));
	    l.stageY(centreStageY-37+1*( _configurationNumber%steps       ));
	  }

	  // Very fine detail scan; 150x150mu
	  if(ver.halfByte(0)==8) {
	    const unsigned steps=150;
	    l.stageX(centreStageX-75+1*((_configurationNumber/steps)%steps));
	    l.stageY(centreStageY-75+1*( _configurationNumber%steps       ));
	  }

	  // Move in pixel Y first
	  //l.stageX(startStageX+( _configurationNumber%steps       ));
	  //l.stageY(startStageY+((_configurationNumber/steps)%steps));

	  std::cout << "Requested stage position " << std::endl;
	  l.print() << std::endl;

	  inserter.insert<MpsLaserConfigurationData>(l);
	  break;
	}
	case IlcRunType::mpsLaserThreshold: {
	  u[0].data()->spillCycleCount(1999);
	  if(MPS_LOCATION==MpsLocation::imperial) u[0].data()->spillCycleCount(9);

	  // Turn on laser
	  if((_configurationNumber%2)==0) {
	    u[0].data()->testTriggerMode(8);
	    u[0].data()->testTriggerStart(104);
	    u[0].data()->testTriggerStop(154);
	  }

	  p[0].data()->shaperThreshold( 4*ver.word(),3072);
	  p[0].data()->samplerThreshold(8*ver.word(),3072);

	  MpsLaserConfigurationData l;

	  // Don't move laser
	  l.stageX(999999);
	  l.stageY(999999);
	  inserter.insert<MpsLaserConfigurationData>(l);
	  break;
	}
	case IlcRunType::mpsLaserThresholdScan: {

	  // Define target pixel
	  unsigned centrePixelX(63);
	  unsigned centrePixelY(126);
	  //unsigned centrePixelX(21);
	  //unsigned centrePixelY(42);

	  /*
	  centrePixelX+=(_runNumberInSequence%5)-2;
	  centrePixelY+=(_runNumberInSequence/5)-2;
	  */

	  /*
	  if(_runNumberInSequence==1) {centrePixelX--;centrePixelY--;}
	  if(_runNumberInSequence==2) {               centrePixelY--;}
	  if(_runNumberInSequence==3) {centrePixelX++;centrePixelY--;}
	  if(_runNumberInSequence==4) {centrePixelX--;               }
	  if(_runNumberInSequence==5) {centrePixelX++;               }
	  if(_runNumberInSequence==6) {centrePixelX--;centrePixelY++;}
	  if(_runNumberInSequence==7) {              ;centrePixelY++;}
	  if(_runNumberInSequence==8) {centrePixelX++;centrePixelY++;}
	  */

	  if(!ver.bit(6)) {
	    for(unsigned i(0);i<s.size();i++) {
	      s[i].data()->maskSensor(true);
	      s[i].data()->mask(centrePixelX,centrePixelY,false);

	      if(ver.bit(5)) {
		s[i].data()->mask(centrePixelX-1,centrePixelY-1,false);
		s[i].data()->mask(centrePixelX  ,centrePixelY-1,false);
		s[i].data()->mask(centrePixelX+1,centrePixelY-1,false);
		s[i].data()->mask(centrePixelX-1,centrePixelY  ,false);
		s[i].data()->mask(centrePixelX+1,centrePixelY  ,false);
		s[i].data()->mask(centrePixelX-1,centrePixelY+1,false);
		s[i].data()->mask(centrePixelX  ,centrePixelY+1,false);
		s[i].data()->mask(centrePixelX+1,centrePixelY+1,false);
	      }
	    }
	  }

	  /*
	  if(ver.bit(5)) {
	    for(unsigned i(0);i<s.size();i++) {
	      s[i].data()->maskSensor(true);
	      //s[i].data()->maskColumn(centrePixelX,false);
	      s[i].data()->maskRow(centrePixelY,false);
	    }
	  }
	  */

	  u[0].data()->spillCycleCount(1999);
	  if(MPS_LOCATION==MpsLocation::imperial) u[0].data()->spillCycleCount(9);

	  // Turn on laser
	  if(!ver.bit(7)) enableLaser(*(u[0].data()));

	  thresholdScan(ver,*(p[0].data()));

	  MpsLaserCoordinates lc;
	  lc.print() << std::endl;

	  int stageX(lc.stageX(centrePixelX,centrePixelY));
	  int stageY(lc.stageY(centrePixelX,centrePixelY));

	  if(_runNumberInSequence== 0) {stageY+= 0;stageX-= 0;}
	  if(_runNumberInSequence== 1) {stageY+= 0;stageX-= 5;}
	  if(_runNumberInSequence== 2) {stageY+= 5;stageX-= 5;}
	  if(_runNumberInSequence== 3) {stageY+= 0;stageX-=10;}
	  if(_runNumberInSequence== 4) {stageY+= 5;stageX-=10;}
	  if(_runNumberInSequence== 5) {stageY+=10;stageX-=10;}
	  if(_runNumberInSequence== 6) {stageY+= 0;stageX-=15;}
	  if(_runNumberInSequence== 7) {stageY+= 5;stageX-=15;}
	  if(_runNumberInSequence== 8) {stageY+=10;stageX-=15;}
	  if(_runNumberInSequence== 9) {stageY+=15;stageX-=15;}
	  if(_runNumberInSequence==10) {stageY+= 0;stageX-=20;}
	  if(_runNumberInSequence==11) {stageY+= 5;stageX-=20;}
	  if(_runNumberInSequence==12) {stageY+=10;stageX-=20;}
	  if(_runNumberInSequence==13) {stageY+=15;stageX-=20;}
	  if(_runNumberInSequence==14) {stageY+=20;stageX-=20;}
	  if(_runNumberInSequence==15) {stageY+= 0;stageX-=25;}
	  if(_runNumberInSequence==16) {stageY+= 5;stageX-=25;}
	  if(_runNumberInSequence==17) {stageY+=10;stageX-=25;}
	  if(_runNumberInSequence==18) {stageY+=15;stageX-=25;}
	  if(_runNumberInSequence==19) {stageY+=20;stageX-=25;}
	  if(_runNumberInSequence==20) {stageY+=25;stageX-=25;}


	  l.push_back(MpsLaserConfigurationData());

	  // Don't move laser
	  //l[0].stageX(999999);
	  //l[0].stageY(999999);

	  l[0].stageX(stageX);
	  l[0].stageY(stageY);
	  break;
	}
	case IlcRunType::mpsLaserCoordinates: {
	  u[0].data()->spillCycleCount(1999);
	  if(MPS_LOCATION==MpsLocation::imperial) u[0].data()->spillCycleCount(9);

	  // Turn on laser
	  if(!ver.bit(7)) {
	    u[0].data()->testTriggerMode(8);
	    u[0].data()->testTriggerStart(104);
	    u[0].data()->testTriggerStop(154);
	  }

	  MpsLaserConfigurationData l;

	  MpsLaserCoordinates lc;
	  lc.print() << std::endl;

	  std::vector<unsigned> vCentrePixelX;
	  std::vector<unsigned> vCentrePixelY;

	  p[0].data()->shaperThreshold(  70,3072);
	  p[0].data()->samplerThreshold(120,3072);

	  const unsigned sensor(4);

	  //vCentrePixelX.push_back(10);vCentrePixelY.push_back(90);
	    
	  // Non-DPW
	  if(sensor==4) {
	    p[0].data()->shaperThreshold( 100,3072);
	    p[0].data()->samplerThreshold(600,3072);
	    
	    vCentrePixelX.push_back( 14);vCentrePixelY.push_back(129);
	    vCentrePixelX.push_back( 61);vCentrePixelY.push_back(127);
	    vCentrePixelX.push_back( 23);vCentrePixelY.push_back(148);
	    vCentrePixelX.push_back( 15);vCentrePixelY.push_back(127);
	    vCentrePixelX.push_back( 56);vCentrePixelY.push_back( 39);
	    vCentrePixelX.push_back( 37);vCentrePixelY.push_back( 92);
	    vCentrePixelX.push_back( 36);vCentrePixelY.push_back( 94);
	    vCentrePixelX.push_back( 71);vCentrePixelY.push_back(140);
	    vCentrePixelX.push_back( 75);vCentrePixelY.push_back(144);

	    vCentrePixelX.push_back( 17);vCentrePixelY.push_back( 17);
	    vCentrePixelX.push_back( 27);vCentrePixelY.push_back( 27);
	  }

	  /*
	  unsigned centrePixelX(60);
	  unsigned centrePixelY(60);
	  //unsigned centrePixelX(30);
	  //unsigned centrePixelY(30);

	  if(_runNumberInSequence==1) {centrePixelX= 64;centrePixelY= 19;}
	  if(_runNumberInSequence==2) {centrePixelX= 64;centrePixelY=148;}
	  if(_runNumberInSequence==3) {centrePixelX= 19;centrePixelY=148;}
	  if(_runNumberInSequence==4) {centrePixelX= 32;centrePixelY= 93;}
	  if(_runNumberInSequence==5) {centrePixelX= 51;centrePixelY= 93;}
	  if(_runNumberInSequence==6) {centrePixelX= 51;centrePixelY= 74;}
	  if(_runNumberInSequence==7) {centrePixelX= 32;centrePixelY= 74;}
	  if(_runNumberInSequence==8) {centrePixelX= 19;centrePixelY= 19;}
	  */

	  unsigned centrePixelX(0);
	  unsigned centrePixelY(0);

	  if(_runNumberInSequence>=vCentrePixelX.size()) {
	    centrePixelX=24+40*( _runNumberInSequence%4   );
	    centrePixelY=24+40*((_runNumberInSequence/4)%4);
	  } else {
	    centrePixelX=vCentrePixelX[_runNumberInSequence];
	    centrePixelY=vCentrePixelY[_runNumberInSequence];
	  }

	  std::cout << "Centre pixel position " << centrePixelX << ", " << centrePixelY << std::endl;

	  const int centreStageX(lc.stageX(centrePixelX,centrePixelY));
	  const int centreStageY(lc.stageY(centrePixelX,centrePixelY));

	  std::cout << "Centre stage position " << centreStageX << ", " << centreStageY << std::endl;

	  const int startStageX(centreStageX-75);
	  const int startStageY(centreStageY-75);

	  std::cout << "Start  stage position " << startStageX << ", " << startStageY << std::endl;

	  const unsigned steps(ver.halfByte(0)+1);
	  l.stageX(startStageX+(150/steps)*((_configurationNumber/steps)%steps));
	  l.stageY(startStageY+(150/steps)*( _configurationNumber%steps       ));

	  std::cout << "Requested stage position " << std::endl;
	  l.print() << std::endl;


	  
	  /*
	  unsigned steps(9 );
	  unsigned majorStep(_configurationNumber/steps);
	  unsigned minorStep(_configurationNumber%steps);
	  int dMajor(3000),dMinor(25);

	  int x(0),y(0);
	  if(majorStep==0) {x+= dMajor;y+= dMajor;}
	  if(majorStep==1) {x+=-dMajor;y+= dMajor;}
	  if(majorStep==2) {x+=-dMajor;y+=-dMajor;}
	  if(majorStep==3) {x+= dMajor;y+=-dMajor;}

	  if(minorStep==0) {x+= dMinor;y+= dMinor;}
	  if(minorStep==1) {x+=      0;y+= dMinor;}
	  if(minorStep==2) {x+=-dMinor;y+= dMinor;}
	  if(minorStep==3) {x+=-dMinor;y+=      0;}
	  if(minorStep==4) {x+=      0;y+=      0;}
	  if(minorStep==5) {x+= dMinor;y+=      0;}
	  if(minorStep==6) {x+= dMinor;y+=-dMinor;}
	  if(minorStep==7) {x+=      0;y+=-dMinor;}
	  if(minorStep==8) {x+=-dMinor;y+=-dMinor;}

	  l.stageX(x);
	  l.stageY(y);
	  */

	  // Don't move laser
	  //l.stageX(999999);
	  //l.stageY(999999);

	  inserter.insert<MpsLaserConfigurationData>(l);

	  break;
	}
	case IlcRunType::mpsLaserTimeScan: {

	  //c->usbDaqIoEnableAll(true);


	  // Turn on laser
	  if(!ver.bit(7)) enableLaser(*(u[0].data()));

	  // Define target pixel
	  //unsigned centrePixelX(60);
	  //unsigned centrePixelY(29);
	  unsigned centrePixelX(63);
	  unsigned centrePixelY(126);

	  if(!ver.bit(6)) {
	    for(unsigned i(0);i<s.size();i++) {
	      s[i].data()->maskSensor(true);
	      s[i].data()->mask(centrePixelX,centrePixelY,false);
	    }
	  }

	  u[0].data()->spillCycleCount(1999);
	  if(MPS_LOCATION==MpsLocation::imperial) u[0].data()->spillCycleCount(9);

	  unsigned commonMode(2*1024);
	  p[0].data()->shaperThreshold(  20,commonMode);
	  p[0].data()->samplerThreshold(160,commonMode);

	  // Turn on laser
	  /*
	  u[0].data()->testTriggerStart( 80+_configurationNumber);
	  u[0].data()->testTriggerStop( 130+_configurationNumber);
	  */
	  u[0].data()->spillCycleStart(7020+_configurationNumber);


	  MpsLaserCoordinates lc;
	  lc.print() << std::endl;

	  l.push_back(MpsLaserConfigurationData());
	  l[0].stageX(lc.stageX(centrePixelX,centrePixelY));
	  l[0].stageY(lc.stageY(centrePixelX,centrePixelY));

	  break;
	}
	  
	default: {
	  // We missed a run type
	  assert(false);
	  break;
	}
	};
      }

      ///////////////////////////////////////////////////////////////////////////////////////
      
      if(doPrint(r.recordType(),1)) {
	std::cout << "MpsConfiguration::record()  configurationStart"
		  << ", MpsReadoutConfiguration object put in record" << std::endl;
	c->print(std::cout," ") << std::endl << std::endl;
      }

      // Put the configurations into the record
      if(doPrint(r.recordType(),1)) {
	std::cout << "MpsConfiguration::record()  configurationStart"
		  << ", number of MpsUsbDaqConfiguration objects put in record = "
		  << u.size() << std::endl;
      }
      for(unsigned i(0);i<u.size();i++) {
	if(doPrint(r.recordType(),2)) {
	  u[i].print(std::cout,"  ") << std::endl;
	}
	inserter.insert< MpsLocationData<MpsUsbDaqConfigurationData> >(u[i]);
      }
      if(doPrint(r.recordType(),1)) std::cout << std::endl;
      
      if(doPrint(r.recordType(),1)) {
	std::cout << "MpsConfiguration::record()  configurationStart"
		  << ", number of MpsPcb1Configuration objects put in record = "
		  << p.size() << std::endl;
      }
      for(unsigned i(0);i<p.size();i++) {
	if(doPrint(r.recordType(),2)) {
	  p[i].print(std::cout,"  ") << std::endl;
	}
	inserter.insert< MpsLocationData<MpsPcb1ConfigurationData> >(p[i]);
      }
      if(doPrint(r.recordType(),1)) std::cout << std::endl;
      
      if(doPrint(r.recordType(),1)) {
	std::cout << "MpsConfiguration::record()  configurationStart"
		  << ", number of MpsSensor1Configuration objects put in record = "
		  << s.size() << std::endl;
      }
      for(unsigned i(0);i<s.size();i++) {
	if(doPrint(r.recordType(),2)) {
	  s[i].print(std::cout,"  ") << std::endl;
	}
	inserter.insert< MpsLocationData<MpsSensor1ConfigurationData> >(s[i]);
      }
      if(doPrint(r.recordType(),1)) std::cout << std::endl;

      if(doPrint(r.recordType(),1)) {
	std::cout << "MpsConfiguration::record()  configurationStart"
		  << ", number of MpsLaserConfiguration objects put in record = "
		  << l.size() << std::endl;
      }
      assert(l.size()<=1);
      for(unsigned i(0);i<l.size();i++) {
	if(doPrint(r.recordType(),2)) {
	  l[i].print(std::cout,"  ") << std::endl;
	}
	inserter.insert< MpsLaserConfigurationData >(l[i]);
      }
      if(doPrint(r.recordType(),1)) std::cout << std::endl;

      break;
    }

    // Do nothing for other record types      
    default: {
      break;
    }
    };
    
    return true;
  }

  static void addLocation(MpsLocation l) {
    l.write(true);
    _vLocation.push_back(l);
  }

  void enableLaser(MpsUsbDaqConfigurationData &u) {
    /*
      // Triggering laser from USB_DAQ
      u.testTriggerMode(8);
      u.testTriggerStart(104-32);
      u.testTriggerStop(154-32);
    */

    // Triggering USB_DAQ from laser
    //u.spillModeHistoryEnable(true);
    u.triggerSource(2);
    //u.triggerSource(0);
    u.spillCycleStart(7030); // 7027 gives hit at timestamp 0
  }

  void thresholdScan(UtlPack v, MpsPcb1ConfigurationData &p) const {
    unsigned steps(400);
    if(v.halfByte(0)==0) steps=  8;
    if(v.halfByte(0)==1) steps= 10;
    if(v.halfByte(0)==2) steps= 20;
    if(v.halfByte(0)==3) steps= 40;
    if(v.halfByte(0)==4) steps= 80;
    if(v.halfByte(0)==5) steps=100;
    if(v.halfByte(0)==6) steps=200;
    
    const unsigned nStep(steps-(_configurationNumber%steps)-1);
    
    const int offset=-100;
    const unsigned commonMode(2*1024);
    
    p.shaperThreshold(   offset+(int)nStep*(400/steps),commonMode);
    p.samplerThreshold(  offset+(int)nStep*(400/steps),commonMode);
  }
  
  void setSensorConfiguration(std::vector< MpsLocationData<MpsSensor1ConfigurationData> > &s,
			      MpsReadoutConfigurationData &c) {
    s.clear();
    for(unsigned i(0);i<_vLocation.size();i++) {
      if(c.sensorEnable(i)) {
	unsigned j(s.size());
	s.push_back(MpsLocationData<MpsSensor1ConfigurationData>());
	s[j].location(_vLocation[i]);
	
	std::ostringstream sout;
	sout << "cfg/MpsSensor1ConfigurationDataSensor" << std::setfill('0')
	     << std::setw(2) << (unsigned)_vLocation[i].sensorId() << ".cfg";
	
	std::cout << sout.str() << std::endl;
	s[j].data()->readFile(sout.str());
      }
    }
  }


private:
  MpsLocation _location;

  unsigned _runNumberInSequence;
  IlcRunType _runType;
  unsigned _configurationNumber;

  unsigned short _discriminatorThreshold[2];

  MpsPcb1ConfigurationData _nominalPcbConfiguration;
  static std::vector<MpsLocation> _vLocation;

  std::pair<unsigned,unsigned> _centrePixel;
};

std::vector<MpsLocation> MpsConfiguration::_vLocation;

#endif
