#ifndef DheVfeSlowData_HH
#define DheVfeSlowData_HH

// Throughout, the bit numbering is 1-570

#include <string>
#include <iostream>

#include "UtlPack.hh"


class DheVfeSlowData {

public:
  enum {
    maxBits=570
  };

  DheVfeSlowData();

  bool enableRamFull() const;
  void enableRamFull(bool b);

  bool enableDataOut() const;
  void enableDataOut(bool b);

  bool enableTransmission() const;
  void enableTransmission(bool b);

  bool enableOutDiscriminator() const;
  void enableOutDiscriminator(bool b);

  unsigned header() const;
  void     header(unsigned h);

  bool bypassChip() const;
  void bypassChip(bool b);

  bool enableOutTrgInt() const;
  void enableOutTrgInt(bool b);

  bool enableTrgInt() const;
  void enableTrgInt(bool b);

  bool enableTrgExt() const;
  void enableTrgExt(bool b);

  bool enableOutRazInt() const;
  void enableOutRazInt(bool b);

  bool enableRazInt() const;
  void enableRazInt(bool b);

  bool enableRazExt() const;
  void enableRazExt(bool b);

  unsigned validTriggerLo() const;
  unsigned validTriggerHi() const;
  void     validTrigger(unsigned l, unsigned h);

  unsigned dac0() const;
  void     dac0(unsigned d);

  unsigned dac1() const;
  void     dac1(unsigned d);

  bool onOtaDac() const;
  void onOtaDac(bool b);

  bool onDac() const;
  void onDac(bool b);

  bool onOtaBg() const;
  void onOtaBg(bool b);

  unsigned testLo() const;
  unsigned testHi() const;
  void     test(unsigned l, unsigned h);

  unsigned preampGain(unsigned p) const;
  void     preampGain(unsigned p, unsigned g);

  bool onPa() const;
  void onPa(bool b);

  bool onBuffer() const;
  void onBuffer(bool b);

  bool onSs() const;
  void onSs(bool b);

  bool onW() const;
  void onW(bool b);

  bool onOtaQ() const;
  void onOtaQ(bool b);

  bool onFsb() const;
  void onFsb(bool b);

  bool onDiscriminator() const;
  void onDiscriminator(bool b);

  bool validDc() const;
  void validDc(bool b);

  bool sw50f() const;
  void sw50f(bool b);

  bool sw100f() const;
  void sw100f(bool b);

  bool sw100k() const;
  void sw100k(bool b);

  bool sw50k() const;
  void sw50k(bool b);

  bool choixCaisson() const;
  void choixCaisson(bool b);

  unsigned swSsc() const;
  void     swSsc(unsigned s);

  bool dataBit(unsigned b) const;
  void dataBit(unsigned b, bool a);

  std::ostream& print(std::ostream &o, std::string s="") const;


private:
  UtlPack _data[(maxBits+31)/32];
};


#ifdef CALICE_DAQ_ICC


DheVfeSlowData::DheVfeSlowData() {

  // Random choice of defaults for now
  for(unsigned i(0);i<(maxBits+31)/32;i++) {
    _data[i].halfWord(0,i);
    _data[i].halfWord(1,(~i)&0xffff);
  }
}

bool DheVfeSlowData::enableRamFull() const {
  return dataBit(1);
}

void DheVfeSlowData::enableRamFull(bool b) {
  dataBit(1,b);
}

bool DheVfeSlowData::enableDataOut() const {
  return dataBit(2);
}

void DheVfeSlowData::enableDataOut(bool b) {
  dataBit(2,b);
}

bool DheVfeSlowData::enableTransmission() const {
  return dataBit(3);
}

void DheVfeSlowData::enableTransmission(bool b) {
  dataBit(3,b);
}

bool DheVfeSlowData::enableOutDiscriminator() const {
  return dataBit(4);
}

void DheVfeSlowData::enableOutDiscriminator(bool b) {
  dataBit(4,b);
}

unsigned DheVfeSlowData::header() const {
  UtlPack result;
  for(unsigned i(0);i<8;i++) {
    result.bit(i,dataBit(i+5));
  }
  return result.word();
}

void DheVfeSlowData::header(unsigned h) {
  assert(h<256);

  UtlPack head(h);
  for(unsigned i(0);i<8;i++) {
    dataBit(i+5,head.bit(i));
  }
}

bool DheVfeSlowData::bypassChip() const {
  return dataBit(13);
}

void DheVfeSlowData::bypassChip(bool b) {
  dataBit(13,b);
}

bool DheVfeSlowData::enableOutTrgInt() const {
  return dataBit(14);
}

void DheVfeSlowData::enableOutTrgInt(bool b) {
  dataBit(14,b);
}

bool DheVfeSlowData::enableTrgInt() const {
  return dataBit(15);
}

void DheVfeSlowData::enableTrgInt(bool b) {
  dataBit(15,b);
}

bool DheVfeSlowData::enableTrgExt() const {
  return dataBit(16);
}

void DheVfeSlowData::enableTrgExt(bool b) {
  dataBit(16,b);
}

bool DheVfeSlowData::enableOutRazInt() const {
  return dataBit(17);
}

void DheVfeSlowData::enableOutRazInt(bool b) {
  dataBit(17,b);
}

bool DheVfeSlowData::enableRazInt() const {
  return dataBit(18);
}

void DheVfeSlowData::enableRazInt(bool b) {
  dataBit(18,b);
}

bool DheVfeSlowData::enableRazExt() const {
  return dataBit(19);
}

void DheVfeSlowData::enableRazExt(bool b) {
  dataBit(19,b);
}

unsigned DheVfeSlowData::validTriggerLo() const {
  UtlPack result;
  for(unsigned i(0);i<32;i++) {
    result.bit(i,dataBit(i+20));
  }
  return result.word();
}

unsigned DheVfeSlowData::validTriggerHi() const {
  UtlPack result;
  for(unsigned i(0);i<32;i++) {
    result.bit(i,dataBit(i+20+32));
  }
  return result.word();
}

void DheVfeSlowData::validTrigger(unsigned l, unsigned h) {
  UtlPack lo(l),hi(h);
  for(unsigned i(0);i<32;i++) {
    dataBit(i+20   ,lo.bit(i));
    dataBit(i+20+32,hi.bit(i));
  }
}

unsigned DheVfeSlowData::dac0() const {
  UtlPack result;
  for(unsigned i(0);i<10;i++) {
    result.bit(i,dataBit(i+84));
  }
  return result.word();
}

void DheVfeSlowData::dac0(unsigned d) {
  assert(d<1024);

  UtlPack dac(d);
  for(unsigned i(0);i<10;i++) {
    dataBit(i+84,dac.bit(i));
  }
}

unsigned DheVfeSlowData::dac1() const {
  UtlPack result;
  for(unsigned i(0);i<10;i++) {
    result.bit(i,dataBit(i+94));
  }
  return result.word();
}

void DheVfeSlowData::dac1(unsigned d) {
  assert(d<1024);

  UtlPack dac(d);
  for(unsigned i(0);i<10;i++) {
    dataBit(i+94,dac.bit(i));
  }
}

bool DheVfeSlowData::onOtaDac() const {
  return dataBit(104);
}

void DheVfeSlowData::onOtaDac(bool b) {
  dataBit(104,b);
}

bool DheVfeSlowData::onDac() const {
  return dataBit(105);
}

void DheVfeSlowData::onDac(bool b) {
  dataBit(105,b);
}

bool DheVfeSlowData::onOtaBg() const {
  return dataBit(106);
}

void DheVfeSlowData::onOtaBg(bool b) {
  dataBit(106,b);
}

unsigned DheVfeSlowData::testLo() const {
  UtlPack result;
  for(unsigned i(0);i<32;i++) {
    result.bit(i,dataBit(i+107));
  }
  return result.word();
}

unsigned DheVfeSlowData::testHi() const {
  UtlPack result;
  for(unsigned i(0);i<32;i++) {
    result.bit(i,dataBit(i+107+32));
  }
  return result.word();
}

void DheVfeSlowData::test(unsigned l, unsigned h) {
  UtlPack lo(l),hi(h);
  for(unsigned i(0);i<32;i++) {
    dataBit(i+107   ,lo.bit(i));
    dataBit(i+107+32,hi.bit(i));
  }
}

unsigned DheVfeSlowData::preampGain(unsigned p) const {
  assert(p<64);

  UtlPack result;
  for(unsigned i(0);i<6;i++) {
    result.bit(i,dataBit(i+171+6*p));
  }
  return result.word();
}

void DheVfeSlowData::preampGain(unsigned p, unsigned g) {
  assert(p<64 && g<64);

  UtlPack gain(g);
  for(unsigned i(0);i<6;i++) {
    dataBit(i+171+6*p,gain.bit(i));
  }
}

bool DheVfeSlowData::onPa() const {
  return dataBit(555);
}

void DheVfeSlowData::onPa(bool b) {
  dataBit(555,b);
}

bool DheVfeSlowData::onBuffer() const {
  return dataBit(556);
}

void DheVfeSlowData::onBuffer(bool b) {
  dataBit(556,b);
}

bool DheVfeSlowData::onSs() const {
  return dataBit(557);
}

void DheVfeSlowData::onSs(bool b) {
  dataBit(557,b);
}

bool DheVfeSlowData::onW() const {
  return dataBit(558);
}

void DheVfeSlowData::onW(bool b) {
  dataBit(558,b);
}

bool DheVfeSlowData::onOtaQ() const {
  return dataBit(559);
}

void DheVfeSlowData::onOtaQ(bool b) {
  dataBit(559,b);
}

bool DheVfeSlowData::onFsb() const {
  return dataBit(560);
}

void DheVfeSlowData::onFsb(bool b) {
  dataBit(560,b);
}

bool DheVfeSlowData::onDiscriminator() const {
  return dataBit(561);
}

void DheVfeSlowData::onDiscriminator(bool b) {
  dataBit(561,b);
}

bool DheVfeSlowData::validDc() const {
  return dataBit(562);
}

void DheVfeSlowData::validDc(bool b) {
  dataBit(562,b);
}

bool DheVfeSlowData::sw50f() const {
  return dataBit(563);
}

void DheVfeSlowData::sw50f(bool b) {
  dataBit(563,b);
}

bool DheVfeSlowData::sw100f() const {
  return dataBit(564);
}

void DheVfeSlowData::sw100f(bool b) {
  dataBit(564,b);
}

bool DheVfeSlowData::sw100k() const {
  return dataBit(565);
}

void DheVfeSlowData::sw100k(bool b) {
  dataBit(565,b);
}

bool DheVfeSlowData::sw50k() const {
  return dataBit(566);
}

void DheVfeSlowData::sw50k(bool b) {
  dataBit(566,b);
}

bool DheVfeSlowData::choixCaisson() const {
  return dataBit(567);
}

void DheVfeSlowData::choixCaisson(bool b) {
  dataBit(567,b);
}

unsigned DheVfeSlowData::swSsc() const {
  UtlPack result;
  for(unsigned i(0);i<3;i++) {
    result.bit(i,dataBit(i+568));
  }
  return result.word();
}

void DheVfeSlowData::swSsc(unsigned s) {
  assert(s<8);

  UtlPack ssc(s);
  for(unsigned i(0);i<3;i++) {
    dataBit(i+568,ssc.bit(i));
  }
}

bool DheVfeSlowData::dataBit(unsigned b) const {
  assert(b>0 && b<571);
  return _data[(b-1)/32].bit((b-1)%32);
}

void DheVfeSlowData::dataBit(unsigned b, bool a) {
  assert(b>0 && b<571);
  _data[(b-1)/32].bit((b-1)%32,a);
}

std::ostream& DheVfeSlowData::print(std::ostream &o, std::string s) const {
  o << s << "DheVfeSlowData::print()" << std::endl;

  for(unsigned i(0);i<(maxBits+31)/32;i++) {
    o << s << " Word " << std::setw(2) << " = "
      << printHex(_data[i]) << std::endl;
  }
  o << s << std::endl;

  o << s << " Enables: ram full ";
  if(enableRamFull()) o << "t"; else o << "f";
  o << ", data out ";
  if(enableDataOut()) o << "t"; else o << "f";
  o << ", transmission ";
  if(enableTransmission()) o << "t"; else o << "f";
  o << ", out discriminator ";
  if(enableOutDiscriminator()) o << "t"; else o << "f";
  o << std::endl << s << "        out trigger int ";
  if(enableOutTrgInt()) o << "t"; else o << "f";
  o << ", trigger int ";
  if(enableTrgInt()) o << "t"; else o << "f";
  o << ", trigger ext ";
  if(enableTrgExt()) o << "t"; else o << "f";
  o << ", out raz int ";
  if(enableOutRazInt()) o << "t"; else o << "f";
  o << ", raz int ";
  if(enableRazInt()) o << "t"; else o << "f";
  o << ", raz ext ";
  if(enableRazExt()) o << "t"; else o << "f";
  o << std::endl;

  o << s << " ON settings: ota DAC ";
  if(onOtaDac()) o << "t"; else o << "f";
  o << ", DAC ";
  if(onDac()) o << "t"; else o << "f";
  o << ", ota bg ";
  if(onOtaBg()) o << "t"; else o << "f";
  o << ", ota pa ";
  if(onPa()) o << "t"; else o << "f";
  o << ", buffer ";
  if(onBuffer()) o << "t"; else o << "f";
  o << ", ss ";
  if(onSs()) o << "t"; else o << "f";
  o << std::endl << s << "        w ";
  if(onW()) o << "t"; else o << "f";
  o << ", ota q ";
  if(onOtaQ()) o << "t"; else o << "f";
  o << ", fsb ";
  if(onFsb()) o << "t"; else o << "f";
  o << ", discriminator ";
  if(onDiscriminator()) o << "t"; else o << "f";
  o << std::endl;

  o << s << " Header = " << std::setw(5) << header() << std::endl;  

  o << s << " Bypass chip set ";
  if(validDc()) o << "t"; else o << "f";
  o << std::endl;

  o << s << " Valid trigger: hi = 0x"
    << std::setw(8) << std::hex << validTriggerHi() << ", lo = 0x"
    << std::setw(8) << std::hex << validTriggerLo() << std::endl;

  o << s << " Test register: hi = 0x"
    << std::setw(8) << std::hex << testHi() << ", lo = 0x"
    << std::setw(8) << std::hex << testLo() << std::dec << std::endl;

  o << s << " DAC0 = " << std::setw(5) << dac0()
    << ", DAC1 = " << std::setw(5) << dac1() << std::endl;

  o << s << " Valid DC set ";
  if(validDc()) o << "t"; else o << "f";
  o << std::endl;

  o << s << " SW settings: 50f ";
  if(sw50f()) o << "t"; else o << "f";
  o << ", 100f ";
  if(sw100f()) o << "t"; else o << "f";
  o << ", 100k ";
  if(sw100k()) o << "t"; else o << "f";
  o << ", 50k ";
  if(sw50k()) o << "t"; else o << "f";
  o << std::endl;

  o << s << " Choix caisson set ";
  if(choixCaisson()) o << "t"; else o << "f";
  o << std::endl;

  o << s << " Sw SSC = " << swSsc();  

  for(unsigned i(0);i<64;i++) {
    if((i%16)==0) o << std::endl << s << " Preamps " << std::setw(2)
		    << i << "-" << i+15
		    << ", gains = " << std::setw(2) << preampGain(i);
    else o << ", " << std::setw(2) << preampGain(i);
  }
  o << std::endl;

  return o;
}

#endif
#endif
