#ifndef AhcConfiguration_HH
#define AhcConfiguration_HH

#include <iostream>
#include <fstream>

// dual/inc/rcd
#include "RcdHeader.hh"
#include "RcdUserRW.hh"

// dual/inc/sub
#include "SubInserter.hh"
#include "SubAccessor.hh"
//#include "SubModifier.hh"

// online/inc/crc
#include "CrcConfiguration.hh"
#include "CrcReadoutConfigurationData.hh"
#include "AhcVfeSlowControlsFile.hh"


class AhcConfiguration : public CrcConfiguration {

public:
  AhcConfiguration() : CrcConfiguration(0xac) {
    _readoutConfiguration.crateNumber(0xac);
    
  }

  virtual ~AhcConfiguration() {
  }

  virtual bool record(RcdRecord &r) {
    if(doPrint(r.recordType())) {
      std::cout << "AhcConfiguration::record()" << std::endl;
      r.RcdHeader::print(std::cout," ") << std::endl;
    }
    
    // Do underlying CRC configuration
    assert(CrcConfiguration::record(r));
    
    // Check record type
    switch (r.recordType()) {
      
      // Start up
    case RcdHeader::startUp: {
      assert(readDacValues(r));
      assert(ahcDacConfiguration(r));
      break;
    }

      
      // Run start 
    case RcdHeader::runStart: {

      // Enable/disable CRCs here
      //for(unsigned s(2);s<=21;s++) _readoutConfiguration.slotEnable(s,false);

      if(doPrint(r.recordType(),1))
	_readoutConfiguration.print(std::cout," ") << std::endl;

      break;
    }
      
      
      // Configuration start 
    case RcdHeader::configurationStart: {
      
      if(_runType.type()==DaqRunType::ahcDacScan) assert(ahcDacConfiguration(r));
      if(_runType.type()==DaqRunType::ahcDacScanAsic) assert(ahcDacConfiguration(r));

      // Handle the ones which need work
      if(_runType.majorType()==DaqRunType::ahc ||
	 _runType.majorType()==DaqRunType::beam ||
	 _runType.majorType()==DaqRunType::cosmics) {

	ahcReadoutConfiguration(r);
	ahcBeConfiguration(r);
	ahcBeTrgConfiguration(r);
	ahcFeConfiguration(r);
	ahcVfeConfiguration(r);
      }
      
      break;
    }
      
      // Run end
    case RcdHeader::runEnd: {
      if(_runType.type()==DaqRunType::ahcDacScan) assert(ahcDacConfiguration(r));
      if(_runType.type()==DaqRunType::ahcDacScanAsic) assert(ahcDacConfiguration(r));
      break;
    }

      // Shut down
    case RcdHeader::shutDown: {
      assert(ahcDacConfiguration(r));
      break;
    }
      
    default: {
      break;
    }
    };
    
    return true;
  }
  
  
  virtual bool readDacValues(const RcdRecord &r) {

    // NEED TO GENERALISE TO MORE THAN JUST SLOT 12
    _location.slotNumber(12);

    // Clear vector for DAC data
    _vDac.clear();

    // Disable all slots initially
    for(unsigned i(2);i<=21;i++) _readoutConfiguration.slotEnable(i,false);

    // Enable slot 12 only
    _readoutConfiguration.crateNumber(0xac);
    _readoutConfiguration.slotEnable(12,true);

    // Beni's code to read in DAC values
    std::ifstream configFile;
    char buffer[512];
    
    std::string* dacFileName[8];
    for (int fe =0;fe<8;fe++) dacFileName[fe] = new std::string("");
    
    std::cout << "loading of DAC values" << std::endl;
    
    configFile.open("DAC.cfg");
    while (configFile.good())
      {
	configFile >> buffer;
	if (buffer[0] == '#')
	  configFile.getline(buffer,sizeof(buffer));
	else
	  {
	    int _FE;
	    sscanf(buffer,"%d",&_FE);
	      
	    std::string dummy;
	    
	    configFile >> dummy;
	    *(dacFileName[_FE]) = dummy;
	    
	    while (configFile.good())
	      {
		configFile >> _FE >>dummy;
		*(dacFileName[_FE]) = dummy;
	      }
	  }
      }

    // Look for FEs with a file and hence DAC values
    for(unsigned f(0);f<8;f++) {
      if(*(dacFileName[f])!="") {
	AhcVfeStartUpData data;
	AhcVfeSlowControlsFile file;
	if(file.read(*(dacFileName[f]),data,f)) {

	  // If loading DAC, also enable FE
	  _readoutConfiguration.slotFeEnable(12,f,true);

	  // Now put DAC values into vector
	  if(f==0) _location.crcComponent(CrcLocation::fe0);
	  if(f==1) _location.crcComponent(CrcLocation::fe1);
	  if(f==2) _location.crcComponent(CrcLocation::fe2);
	  if(f==3) _location.crcComponent(CrcLocation::fe3);
	  if(f==4) _location.crcComponent(CrcLocation::fe4);
	  if(f==5) _location.crcComponent(CrcLocation::fe5);
	  if(f==6) _location.crcComponent(CrcLocation::fe6);
	  if(f==7) _location.crcComponent(CrcLocation::fe7);
	  _vDac.push_back(CrcLocationData<AhcVfeStartUpData>(_location,data));
	}
      }
    }

    // By hand, set locations for PIN diode readout
    _pinLocation[0].crateNumber(0xac);
    _pinLocation[0].slotNumber(12);
    _pinLocation[0].crcComponent(CrcLocation::fe0);

    // Disable other PIN for now
    _pinLocation[1].crateNumber(0);

    // Enable corresponding FEs
    for(unsigned i(0);i<2;i++) {
      if(_pinLocation[i].crateNumber()==0xac) {

	if(doPrint(r.recordType(),1)) {
	  std::cout << " PIN diode " << i << " location" <<std::endl;
	  _pinLocation[i].print(std::cout,"  ") << std::endl;
	}

	_readoutConfiguration.slotFeEnable(_pinLocation[i].slotNumber(),
					   _pinLocation[i].crcComponent(),true);
      }
    }

    if(doPrint(r.recordType(),1))
      _readoutConfiguration.print(std::cout," ") << std::endl;
    
    return true;
  }


  virtual bool ahcDacConfiguration(RcdRecord &r) {

    SubInserter inserter(r);
    
    if(doPrint(r.recordType(),1)) std::cout
      << " Number of AhcVfeStartUpData subrecords inserted = "
      << _vDac.size() << std::endl << std::endl;
    
    for(unsigned i(0);i<_vDac.size();i++) {
      CrcLocationData<AhcVfeStartUpData> data(_vDac[i]);

      // Now do the readout periods, soft triggers and modes
      const unsigned char v(_runType.version());

      // DAC scan to be used with SiPM ON
      if(_runType.type()==DaqRunType::ahcDacScan) {
	if(_configurationNumber>0) {

	  for(unsigned i(0);i<12;i++) {
	    for(unsigned j(0);j<18;j++) {
	      int dac(data.data()->dac(i,j));
	      //if((_configurationNumber%2)==1) { // Increment
		dac+=(_configurationNumber+1)/2;
		if(dac>255) dac=255;
		data.data()->dac(i,j,dac);
		/*
	      } else {                          // Decrement
		dac-=(_configurationNumber+1)/2;
		if(dac<0) dac=0;
		data.data()->dac(i,j,dac);
	      }
		*/
	    }
	  }
	}
      }

      // DAC scan to be used with SiPM OFF !!!
      if(_runType.type()==DaqRunType::ahcDacScanAsic) {
	if(_configurationNumber>0) {

	  for(unsigned i(0);i<12;i++) {
	    for(unsigned j(0);j<18;j++) {
	      int dac;
	      dac+=256/(v+1);
	    }
	  }
	}
      }

      if(doPrint(r.recordType(),1)) data.print(std::cout,"  ") << std::endl;
      inserter.insert< CrcLocationData<AhcVfeStartUpData> >(data);
    }

    return true;
  }

  virtual bool ahcReadoutConfiguration(RcdRecord &r) {

    SubInserter inserter(r);
    CrcReadoutConfigurationData
      *b(inserter.insert<CrcReadoutConfigurationData>(true));
    *b=_readoutConfiguration;
    
    // Now do the readout periods, soft triggers and modes
    const unsigned char v(_runType.version());

    switch(_runType.type()) {

    case DaqRunType::ahcTest: {
      b->vmePeriod(0);
      b->bePeriod(0);
      b->fePeriod(1);
      break;
    }
      
    case DaqRunType::ahcCmNoise:
    case DaqRunType::ahcPmNoise: {
     if((v%4)==1) {
        b->beSoftTrigger(true);
      }
      if((v%4)==2) {
        b->feBroadcastSoftTrigger(true);
      }
      if((v%4)==3) {
        b->feSoftTrigger(0,true);
        b->feSoftTrigger(1,true);
        b->feSoftTrigger(2,true);
        b->feSoftTrigger(3,true);
        b->feSoftTrigger(4,true);
        b->feSoftTrigger(5,true);
        b->feSoftTrigger(6,true);
        b->feSoftTrigger(7,true);
      }

      b->vlinkBlt(((v/4)%2)!=1);

      b->vmePeriod(v/8);
      b->bePeriod(v/8);
      b->fePeriod(v/8);
      break;
    }

    case DaqRunType::ahcAnalogOut:
    case DaqRunType::ahcDacScan:
    case DaqRunType::ahcCmAsic:
    case DaqRunType::ahcCmAsicVcalibScan:
    case DaqRunType::ahcCmAsicHoldScan:
    case DaqRunType::ahcPmAsic:
    case DaqRunType::ahcPmAsicVcalibScan:
    case DaqRunType::ahcPmAsicHoldScan:
    case DaqRunType::ahcCmLed:
    case DaqRunType::ahcCmLedVcalibScan:
    case DaqRunType::ahcCmLedHoldScan:
    case DaqRunType::ahcPmLed:
    case DaqRunType::ahcPmLedVcalibScan:
    case DaqRunType::ahcPmLedHoldScan: {
      b->beSoftTrigger(true);
      b->vlinkBlt(true);
      break;
    }

    case DaqRunType::ahcBeam:
    case DaqRunType::ahcBeamHoldScan:
    case DaqRunType::ahcBeamStage:
    case DaqRunType::ahcBeamStageScan:
    case DaqRunType::ahcCosmics:
    case DaqRunType::beamTest:
    case DaqRunType::beamNoise:
    case DaqRunType::beamData:
    case DaqRunType::beamHoldScan:
    case DaqRunType::cosmicsTest:
    case DaqRunType::cosmicsNoise:
    case DaqRunType::cosmicsData:
    case DaqRunType::cosmicsHoldScan: {
      if((_configurationNumber%3)<2) {
	b->beSoftTrigger(true);
      } else {
	b->becPeriod(16);
	b->fePeriod(16);
	//b->bePeriod(1);
	//b->fePeriod(1);
      }
      b->vlinkBlt(true);
      break;
    }
      
    case DaqRunType::ahcCosmicsHoldScan: {
      b->vlinkBlt(true);
      break;
    }

    default: {
      break;
    }
    };

    if(doPrint(r.recordType(),1)) b->print(std::cout," ") << std::endl;

    return true;
  }

  virtual bool ahcBeConfiguration(RcdRecord &r) {

    // Define vector for configuration data
    std::vector< CrcLocationData<CrcBeConfigurationData> > vBcd;

    _location.slotBroadcast(true);
    _location.crcComponent(CrcLocation::be);
    vBcd.push_back(CrcLocationData<CrcBeConfigurationData>(_location));

    const unsigned char v(_runType.version());

    switch(_runType.type()) {
    case DaqRunType::ahcTest: {
      vBcd[0].data()->j0TriggerEnable(true);
      vBcd[0].data()->j0BypassEnable(false);
      break;
    }
      
    case DaqRunType::ahcCmNoise:
    case DaqRunType::ahcPmNoise: {
      vBcd[0].data()->j0TriggerEnable((v%4)==0);
      vBcd[0].data()->j0BypassEnable(false);
      break;
    }
      
    case DaqRunType::ahcAnalogOut:
    case DaqRunType::ahcDacScan:
    case DaqRunType::ahcCmAsic:
    case DaqRunType::ahcCmAsicVcalibScan:
    case DaqRunType::ahcCmAsicHoldScan:
    case DaqRunType::ahcCmLed:
    case DaqRunType::ahcCmLedVcalibScan:
    case DaqRunType::ahcCmLedHoldScan:
    case DaqRunType::ahcPmAsic:
    case DaqRunType::ahcPmAsicVcalibScan:
    case DaqRunType::ahcPmAsicHoldScan:
    case DaqRunType::ahcPmLed:
    case DaqRunType::ahcPmLedVcalibScan:
    case DaqRunType::ahcPmLedHoldScan: {
      vBcd[0].data()->j0TriggerEnable(false);
      vBcd[0].data()->j0BypassEnable(false);
      break;
    }
      
    case DaqRunType::ahcCosmicsHoldScan: {
      vBcd[0].data()->j0TriggerEnable(true);
      vBcd[0].data()->j0BypassEnable(false);
      break;
    }
      
    case DaqRunType::ahcBeam:
    case DaqRunType::ahcBeamHoldScan:
    case DaqRunType::ahcBeamStage:
    case DaqRunType::ahcBeamStageScan:
    case DaqRunType::ahcCosmics:

    case DaqRunType::beamTest:
    case DaqRunType::beamNoise:
    case DaqRunType::beamData:
    case DaqRunType::beamHoldScan:

    case DaqRunType::cosmicsTest:
    case DaqRunType::cosmicsNoise:
    case DaqRunType::cosmicsData:
    case DaqRunType::cosmicsHoldScan: {
      vBcd[0].data()->j0TriggerEnable((_configurationNumber%3)==2);
      vBcd[0].data()->j0BypassEnable(false);
      break;
    }

    default: {
      vBcd[0].data()->j0TriggerEnable(true);
      vBcd[0].data()->j0BypassEnable(false);
      break;
    }
    };

    // Load configuration into record
    SubInserter inserter(r);
    
    if(doPrint(r.recordType(),1)) std::cout
      << " Number of CrcBeConfigurationData subrecords inserted = "
      << vBcd.size() << std::endl << std::endl;
    
    for(unsigned i(0);i<vBcd.size();i++) {
      if(doPrint(r.recordType(),1)) vBcd[i].print(std::cout,"  ") << std::endl;
      inserter.insert< CrcLocationData<CrcBeConfigurationData> >(vBcd[i]);
    }
    
    return true;
  }
  
  virtual bool ahcBeTrgConfiguration(RcdRecord &r) {

    // Set location
    _location.crcComponent(CrcLocation::beTrg);
 
    // Define vectors for configuration data
    std::vector<TrgReadoutConfigurationData> vTrd;
    std::vector< CrcLocationData<CrcBeTrgConfigurationData> > vTcd;

    // Turn trigger off for all CRCs
    if(_configurationNumber==0) {
      _location.slotBroadcast(true);
      vTcd.push_back(CrcLocationData<CrcBeTrgConfigurationData>(_location));
      vTcd[0].data()->inputEnable(0);
      vTcd[0].data()->generalEnable(0);
    }

    // Override if trigger slot is in this crate
    if(_trgLocation.slotNumber()>0) {
      vTrd.push_back(TrgReadoutConfigurationData());

      const unsigned char v(_runType.version());

      switch(_runType.type()) {

      case DaqRunType::ahcTest: {
	break;
      }
      
      case DaqRunType::ahcCmNoise:
      case DaqRunType::ahcPmNoise: {
	vTrd[0].beTrgSquirt(true);
	vTrd[0].readPeriod(v/8);

	if((v%4)==0) {
	  unsigned t(vTcd.size());
	  vTcd.push_back(CrcLocationData<CrcBeTrgConfigurationData>(_trgLocation));
	  vTcd[t].data()->inputEnable(0);
	  vTcd[t].data()->generalEnable(1);

	  vTrd[0].clearBeTrgTrigger(true);
	  vTrd[0].beTrgSoftTrigger(true);
	}
	break;
      }
      
      case DaqRunType::ahcCosmicsHoldScan: {
	vTrd[0].clearBeTrgTrigger(true);
	vTrd[0].beTrgSquirt(true);
	
	unsigned t(vTcd.size());
	vTcd.push_back(CrcLocationData<CrcBeTrgConfigurationData>(_trgLocation));
	vTcd[t].data()->generalEnable(1);
	
	vTcd[t].data()->inputEnable(1<<13);
	//vTcd[t].data()->inputEnable(0x100ffff);
	//vTcd[t].data()->inputEnable(0x3001000);
	//vTcd[t].data()->andEnable(0,0x0100);
	break;
      }

      case DaqRunType::ahcBeam:
      case DaqRunType::ahcBeamHoldScan:
      case DaqRunType::ahcBeamStage:
      case DaqRunType::ahcBeamStageScan:
      case DaqRunType::ahcCosmics:
	
      case DaqRunType::beamTest:
      case DaqRunType::beamNoise:
      case DaqRunType::beamData:
      case DaqRunType::beamHoldScan:
	
      case DaqRunType::cosmicsTest:
      case DaqRunType::cosmicsNoise:
      case DaqRunType::cosmicsData:
      case DaqRunType::cosmicsHoldScan: {
	if((_configurationNumber%3)!=2) {
	  vTrd[0].enable(false);

	} else {
	  vTrd[0].clearBeTrgTrigger(true);
	  vTrd[0].beTrgSquirt(true);
	  vTrd[0].readPeriod(16);
	  vTrd[0].readcPeriod(16);
	  
	  unsigned t(vTcd.size());
	  vTcd.push_back(CrcLocationData<CrcBeTrgConfigurationData>(_trgLocation));
	  vTcd[t].data()->generalEnable(1);

	  if((v&0x80)==0) { // Normal cosmic trigger
	    vTcd[t].data()->inputEnable(1<<13);
	    //vTcd[t].data()->inputEnable(0x0002000);
	    //vTcd[t].data()->inputEnable(0x100ffff);
	    //vTcd[t].data()->inputEnable(0x3001000);
	    //vTcd[t].data()->andEnable(0,0x0100);
	  } else { // Oscillator
	    vTcd[t].data()->inputEnable(0x1000000);
	    vTcd[t].data()->oscillationPeriod(40000); // 1kHz
	  }
	}
	break;
      }
	
      default: {
	break;
      }
      };
    }

    // Load configuration into record
    SubInserter inserter(r);

    if(doPrint(r.recordType(),1)) std::cout
      << " Number of TrgReadoutConfigurationData subrecords inserted = "
      << vTrd.size() << std::endl << std::endl;
    assert(vTrd.size()<=1);

    for(unsigned i(0);i<vTrd.size();i++) {
      if(doPrint(r.recordType(),1)) vTrd[i].print(std::cout,"  ") << std::endl;
      inserter.insert<TrgReadoutConfigurationData>(vTrd[i]);
    }

    if(doPrint(r.recordType(),1)) std::cout
      << " Number of CrcBeTrgConfigurationData subrecords inserted = "
      << vTcd.size() << std::endl << std::endl;
    assert(vTcd.size()<=2);

    for(unsigned i(0);i<vTcd.size();i++) {
      if(doPrint(r.recordType(),1)) vTcd[i].print(std::cout,"  ") << std::endl;
      inserter.insert< CrcLocationData<CrcBeTrgConfigurationData> >(vTcd[i]);
    }

    return true;
  }
  
  virtual bool ahcFeConfiguration(RcdRecord &r) {
    SubInserter inserter(r);
    
    CrcLocationData<CrcFeConfigurationData>
      *d(inserter.insert< CrcLocationData<CrcFeConfigurationData> >(true));

    _location.slotBroadcast(true);
    _location.crcComponent(CrcLocation::feBroadcast);
    d->location(_location);

    AhcVfeControl vc(0);
    vc.ledSel(false);

    const unsigned char v(_runType.version());

    switch(_runType.type()) {

    case DaqRunType::ahcTest: {
      d->data()->calibEnable(true);
      break;
    }

    case DaqRunType::ahcAnalogOut: {
      d->data()->calibEnable(true);
      vc.ledSel(true);
      vc.swHoldIn(true);

      if((v&0x80)==0) { //CM
	//d->data()->holdStart(83);
	//d->data()->dacData(CrcFeConfigurationData::boardA,20000);
	d->data()->dacData(CrcFeConfigurationData::boardB,19000);
      } else { // PM
	//d->data()->holdStart(113);
	//d->data()->dacData(CrcFeConfigurationData::boardA,25000);
	d->data()->dacData(CrcFeConfigurationData::boardB,30000);
      }
      //d->data()->calibWidth(d->data()->holdStart()+128);

      d->data()->vfeMplexClockPulses((v+1)%32);
      break;
    }

    case DaqRunType::ahcCmAsic: {
      d->data()->calibEnable(true);
      d->data()->holdStart(11);
      d->data()->calibWidth(d->data()->holdStart()+128);

      d->data()->dacData(CrcFeConfigurationData::boardA,0);
      d->data()->dacData(CrcFeConfigurationData::boardB,0);

      if((v&0x40)==0) d->data()->dacData(CrcFeConfigurationData::boardA,64*(v%64));
      if((v&0x80)==0) d->data()->dacData(CrcFeConfigurationData::boardB,64*(v%64));
      break;
    }

    case DaqRunType::ahcCmAsicVcalibScan: {
      d->data()->calibEnable(true);
      d->data()->holdStart(11);
      d->data()->calibWidth(d->data()->holdStart()+128);

      unsigned steps(v+1);
      if((_configurationNumber%2)==0) {
	d->data()->dacData(CrcFeConfigurationData::boardA,(_configurationNumber/2)*(4096/steps));
	d->data()->dacData(CrcFeConfigurationData::boardB,0);
      } else {
	d->data()->dacData(CrcFeConfigurationData::boardA,0);
	d->data()->dacData(CrcFeConfigurationData::boardB,(_configurationNumber/2)*(4096/steps));
      }
      break;
    }

    case DaqRunType::ahcCmAsicHoldScan: {
      d->data()->calibEnable(true);
      d->data()->dacData(CrcFeConfigurationData::boardA,2048);
      d->data()->dacData(CrcFeConfigurationData::boardB,2048);

      unsigned steps(v+1);
      d->data()->holdStart(_configurationNumber*(256/steps));
      d->data()->calibWidth(d->data()->holdStart()+128);
      break;
    }

    case DaqRunType::ahcPmAsic: {
      d->data()->calibEnable(true);
      d->data()->holdStart(70);
      d->data()->calibWidth(d->data()->holdStart()+128);

      d->data()->dacData(CrcFeConfigurationData::boardA,0);
      d->data()->dacData(CrcFeConfigurationData::boardB,0);

      if((v&0x40)==0) d->data()->dacData(CrcFeConfigurationData::boardA,128*(v%64));
      if((v&0x80)==0) d->data()->dacData(CrcFeConfigurationData::boardB,128*(v%64));
      break;
    }

    case DaqRunType::ahcPmAsicVcalibScan: {
      d->data()->calibEnable(true);
      d->data()->holdStart(70);
      d->data()->calibWidth(d->data()->holdStart()+128);

      unsigned steps(v+1);
      if((_configurationNumber%2)==0) {
	d->data()->dacData(CrcFeConfigurationData::boardA,(_configurationNumber/2)*(8192/steps));
	d->data()->dacData(CrcFeConfigurationData::boardB,0);
      } else {
	d->data()->dacData(CrcFeConfigurationData::boardA,0);
	d->data()->dacData(CrcFeConfigurationData::boardB,(_configurationNumber/2)*(8192/steps));
      }
      break;
    }

    case DaqRunType::ahcPmAsicHoldScan: {
      d->data()->calibEnable(true);
      d->data()->dacData(CrcFeConfigurationData::boardA,4096);
      d->data()->dacData(CrcFeConfigurationData::boardB,4096);

      unsigned steps(v+1);
      d->data()->holdStart(_configurationNumber*(512/steps));
      d->data()->calibWidth(d->data()->holdStart()+128);
      break;
    }

    case DaqRunType::ahcCmLed: {
      d->data()->calibEnable(true);
      d->data()->holdStart(83);
      d->data()->calibWidth(d->data()->holdStart()+128);

      d->data()->dacData(CrcFeConfigurationData::boardA,0);
      d->data()->dacData(CrcFeConfigurationData::boardB,0);

      if((v&0x80)==0) d->data()->dacData(CrcFeConfigurationData::boardB,512*(v%128));

      vc.ledSel(true);
      break;
    }

    case DaqRunType::ahcCmLedVcalibScan: {
      d->data()->calibEnable(true);
      d->data()->holdStart(83);
      d->data()->calibWidth(d->data()->holdStart()+128);

      unsigned steps(v+1);
      d->data()->dacData(CrcFeConfigurationData::boardA,0);
      d->data()->dacData(CrcFeConfigurationData::boardB,_configurationNumber*(65536/steps));

      vc.ledSel(true);
      break;
    }

    case DaqRunType::ahcCmLedHoldScan: {
      d->data()->calibEnable(true);
      d->data()->dacData(CrcFeConfigurationData::boardA,0);
      d->data()->dacData(CrcFeConfigurationData::boardB,19000);

      d->data()->holdStart(70+_configurationNumber);
      d->data()->calibWidth(d->data()->holdStart()+128);

      vc.ledSel(true);
      break;
    }

    case DaqRunType::ahcPmLed: {
      d->data()->calibEnable(true);
      d->data()->holdStart(113);
      d->data()->calibWidth(d->data()->holdStart()+128);

      d->data()->dacData(CrcFeConfigurationData::boardA,0);
      d->data()->dacData(CrcFeConfigurationData::boardB,0);

      if((v&0x80)==0) d->data()->dacData(CrcFeConfigurationData::boardB,512*(v%128));

      vc.ledSel(true);
      break;
    }

    case DaqRunType::ahcPmLedVcalibScan: {
      d->data()->calibEnable(true);
      d->data()->holdStart(113);
      d->data()->calibWidth(d->data()->holdStart()+128);

      unsigned steps(v+1);
      d->data()->dacData(CrcFeConfigurationData::boardA,0);
      d->data()->dacData(CrcFeConfigurationData::boardB,_configurationNumber*(65536/steps));

      vc.ledSel(true);
      break;
    }

    case DaqRunType::ahcPmLedHoldScan: {
      d->data()->calibEnable(true);

      d->data()->dacData(CrcFeConfigurationData::boardA,0);
      d->data()->dacData(CrcFeConfigurationData::boardB,25000);

      d->data()->holdStart(70+2*_configurationNumber);
      d->data()->calibWidth(d->data()->holdStart()+128);

      vc.ledSel(true);
      break;
    }

    case DaqRunType::ahcBeam:
    case DaqRunType::ahcBeamStage:
    case DaqRunType::ahcBeamStageScan:
    case DaqRunType::ahcCosmics:

    case DaqRunType::beamTest:
    case DaqRunType::beamNoise:
    case DaqRunType::beamData:

    case DaqRunType::cosmicsTest:
    case DaqRunType::cosmicsNoise:
    case DaqRunType::cosmicsData:
    case DaqRunType::cosmicsHoldScan: {
      if((_configurationNumber%3)!=1) {
	d->data()->holdStart(9);
      } else {
	d->data()->calibEnable(true);
	d->data()->holdStart(113);
	d->data()->calibWidth(d->data()->holdStart()+128);
	d->data()->dacData(CrcFeConfigurationData::boardA,0);
	d->data()->dacData(CrcFeConfigurationData::boardB,25000);
	vc.ledSel(true);
      }
      break;
    }

    case DaqRunType::ahcBeamHoldScan:
    case DaqRunType::beamHoldScan: {
      if((_configurationNumber%3)==0) {
	d->data()->holdStart(9);
     } else if((_configurationNumber%3)==2) {
	unsigned short hold[16]={1,2,3,4,5,6,8,10,15,20,30,40,50,100,150,200};
	d->data()->holdStart(hold[(_configurationNumber/3)%16]);
	d->data()->calibWidth(d->data()->holdStart()+128);
      } else {
	d->data()->calibEnable(true);
	d->data()->holdStart(113);
	d->data()->calibWidth(d->data()->holdStart()+128);
	d->data()->dacData(CrcFeConfigurationData::boardA,0);
	d->data()->dacData(CrcFeConfigurationData::boardB,25000);
	vc.ledSel(true);
      }
      break;
    }

    case DaqRunType::ahcCosmicsHoldScan: {
      d->data()->calibEnable(true);

      d->data()->dacData(CrcFeConfigurationData::boardA,0);
      d->data()->dacData(CrcFeConfigurationData::boardB,25000);

      vc.ledSel(true);

      unsigned short hold[16]={1,2,3,4,5,6,7,8,9,10,15,20,30,40,50,100};
      d->data()->holdStart(hold[_configurationNumber%16]);
      d->data()->calibWidth(d->data()->holdStart()+128);
      break;
    }

    default: {
      break;
    }
    };
  
    // Write in VFE control
    d->data()->vfeControl(vc.data());

    if(doPrint(r.recordType(),2)) {
      d->print(std::cout," ");
      vc.print(std::cout," ") << std::endl;
    }

    return true;
  }

  virtual bool ahcVfeConfiguration(RcdRecord &r) {
    SubInserter inserter(r);
 
    CrcLocationData<AhcVfeConfigurationData>
      *d(inserter.insert< CrcLocationData<AhcVfeConfigurationData> >(true));

    d->crateNumber(_location.crateNumber());
    d->slotBroadcast(true);
    d->crcComponent(CrcLocation::feBroadcast);
    d->label(1);

    AhcVfeShiftRegister calibMode; // Default

    AhcVfeShiftRegister physicsMode;
    physicsMode.shapingCapacitor(0,true);
    physicsMode.shapingCapacitor(1,true);
    physicsMode.shapingCapacitor(2,true);
    physicsMode.gainCapacitor(1,true);
    physicsMode.injectionResistor(true);
       
    const unsigned char v(_runType.version());

    switch(_runType.type()) {

    case DaqRunType::ahcTest: {
      break;
    }
      
    case DaqRunType::ahcAnalogOut: {
      if((v&0x80)==0) { 
	for(unsigned h(0);h<12;h++) d->data()->shiftRegister(h,calibMode);
      } else {
	for(unsigned h(0);h<12;h++) d->data()->shiftRegister(h,physicsMode);
      }
      break;
    }

    case DaqRunType::ahcCmNoise:
    case DaqRunType::ahcCmAsic:
    case DaqRunType::ahcCmAsicVcalibScan:
    case DaqRunType::ahcCmAsicHoldScan:
    case DaqRunType::ahcCmLed:
    case DaqRunType::ahcCmLedVcalibScan:
    case DaqRunType::ahcCmLedHoldScan: {
      for(unsigned h(0);h<12;h++) d->data()->shiftRegister(h,calibMode);
      break;
    }
      
    case DaqRunType::ahcDacScan:
    case DaqRunType::ahcPmNoise:
    case DaqRunType::ahcPmAsic:
    case DaqRunType::ahcPmAsicVcalibScan:
    case DaqRunType::ahcPmAsicHoldScan:
    case DaqRunType::ahcPmLed:
    case DaqRunType::ahcPmLedVcalibScan:
    case DaqRunType::ahcPmLedHoldScan:
    case DaqRunType::ahcBeam:
    case DaqRunType::ahcBeamHoldScan:
    case DaqRunType::ahcBeamStage:
    case DaqRunType::ahcBeamStageScan:
    case DaqRunType::ahcCosmics:

    case DaqRunType::beamTest:
    case DaqRunType::beamData:
    case DaqRunType::beamHoldScan:
    case DaqRunType::beamStage:
    case DaqRunType::beamStageScan:

    case DaqRunType::cosmicsTest:
    case DaqRunType::cosmicsData:
    case DaqRunType::cosmicsHoldScan: {
      for(unsigned h(0);h<12;h++) d->data()->shiftRegister(h,physicsMode);
      break;
    }

    default: {
      break;
    }
    };

    if(doPrint(r.recordType(),2)) d->print(std::cout," ") << std::endl;


    // Now do the PIN diodes; the SR is the same for all runs
    for(unsigned i(0);i<2;i++) {
      if(_pinLocation[i].crateNumber()==0xac) {

	d=inserter.insert< CrcLocationData<AhcVfeConfigurationData> >(true);
	d->location(_pinLocation[i]);
	
	AhcVfeShiftRegister pinMode;
	pinMode.gainCapacitor(1,true); 
	pinMode.gainCapacitor(3,false); // SR default setting = calib mode

    
	for(unsigned h(0);h<12;h++) d->data()->shiftRegister(h,pinMode);
    
	if(doPrint(r.recordType(),2)) d->print(std::cout," ") << std::endl;
      }
    }

    return true;
  }


protected:
  CrcLocation _pinLocation[2];  
  CrcReadoutConfigurationData _readoutConfiguration;
  std::vector< CrcLocationData<AhcVfeStartUpData> > _vDac;
};

#endif
