// =====================================================================
//  $Id: TVmeMpx201aModule.cc,v 1.4 2004/03/07 10:30:31 goiwai Exp $
//  $Name: CLDAQ-1-14-03 $
//  $Log: TVmeMpx201aModule.cc,v $
//  Revision 1.4  2004/03/07 10:30:31  goiwai
//  ROOTに組みこむためのおまじないマクロを埋めこみました。
//  全てにおいて完全に動作するわけではありません。
//
//  Revision 1.3  2003/10/06 17:02:40  goiwai
//  *** empty log message ***
//
//  Revision 1.2  2003/07/30 16:19:12  goiwai
//  ファイルにコミットログをつけることにしました.
//
// =====================================================================
#include "TVmeMpx201aModule.hh"
#include "TDataSegment.hh"
#include "TDataElement.hh"

TVmeMpx201aModule::TVmeMpx201aModule( Toff_t offset, Tint mapsize, Tint nch )
  : TVmeModule( nch, offset, mapsize, tA16D16 )
{;}

Tvoid TVmeMpx201aModule::SetupCCDmeasurement( Tint rate, Tint nblock, Toff_t offset )
{
  Clear();
  SetSamplingRate( rate );
  // rate + 1 回につき一回AD変換を行う

  SetNumberOfBlock( nblock );
  /// 超注意！
  /// 1ブロックは2048サンプリングするという意味
  /// ブロック数をＮにすれば、2048×Ｎ個のデータがメモリに格納される
  /// ところが現在問題を抱えている
  /// それはデータをひとつずつ飛ばして読んでしまうのだ
  /// したがって、ブロック数をＮにしても1024×Ｎ個のデータしか得られない
  /// 例えばCCDの場合なんかは
  /// ピクセルに16本の外部クロックを入力してやり
  /// サンプリングレートを15に設定し、1ピクセルにつき1回のAD変換をさせる
  /// しかしながら上記の問題により、このままでは1ピクセルずつ飛ばした
  /// 値をメモリに格納してしまう。
  /// 
  /// 設定したサンプリングレートの２分の１になるようなもの。
  /// 
  /// 例えば、15にした場合は32本のクロックにつき一回
  /// サンプリングされるのだから32本毎にピークが来るようにする
  /// 
  /// ただし、メモリの量は該当分だけ必要になるので
  /// (読めないだけで飛ばした分もADはされている)
  /// かりに500×500のCCDであれば250K個のデータがあって、
  /// その間に読めないデータが入ってるので全部で500K個のデータがある
  /// 250ブロック必要になる


  SetDataCaptureMode( tTransientMode );
  SetEventSynchronisationMode( tExternalSynchronisationMode );
  SetOffsetAddressForDaughterBoard( offset );
  EnableAccessToDaughterBoard();

  return;
}

TVmeMpx201aModule::TVmeMpx201aModule( const TVmeMpx201aModule& right )
  : TVmeModule( right )
{;}

TVmeMpx201aModule::~TVmeMpx201aModule()
{;}

const TVmeMpx201aModule& TVmeMpx201aModule::operator=( const TVmeMpx201aModule& right )
{
  *( (TVmeModule*)this ) = *( (TVmeModule*)(&right) );
  return *this;
}

Tbool TVmeMpx201aModule::operator==( const TVmeMpx201aModule& right ) const
{
  return *( (TVmeModule*)this ) == *( (TVmeModule*)(&right) );
}

Tbool TVmeMpx201aModule::operator!=( const TVmeMpx201aModule& right ) const
{
  return *( (TVmeModule*)this ) != *( (TVmeModule*)(&right) );
}

Tint TVmeMpx201aModule::Clear()
{
  setBit( (TUshort*)( theBaseAddress + CONTROL_STATUS ), 4, 1 );
  setBit( (TUshort*)( theBaseAddress + CONTROL_STATUS ), 0, 0 );
  return theStatus = tStatusSuccess;
}

Tint TVmeMpx201aModule::Update()
{
  return Clear();
}

Tint TVmeMpx201aModule::Initialize()
{
  return Clear();
}

Tvoid TVmeMpx201aModule::FillData( TDataElement& element, Tint channel )
{
  //theMemoryModule -> FillData( element, channel );
  // CSR?
  if ( channel < 0 || channel >= theNumberOfChannels ) {
    Tcerr << "TVmeMpx201aModule::FillData: invalid ID " << channel << Tendl;
    theStatus = -EFAULT;
    element.FillData( &theStatus, tTypeInt, 1 );
  } else {
    TUshort data = Read( channel );
    element.FillData( &data, tTypeUnsignedShort, 1 );
  }

  return;
}

Tvoid TVmeMpx201aModule::SetEventSynchronisationMode( Tsync_t mode )
{
  switch ( mode ) {
    case tScannerMode:
      setBit( (TUshort*)( theBaseAddress + CONTROL_STATUS ), 7, 0 );
      break;
    case tInternalSynchronisationMode:
      setBit( (TUshort*)( theBaseAddress + CONTROL_STATUS ), 7, 1 );
      setBit( (TUshort*)( theBaseAddress + CONTROL_STATUS ), 6, 1 );
      break;
    case tExternalSynchronisationMode:
      setBit( (TUshort*)( theBaseAddress + CONTROL_STATUS ), 7, 1 );
      setBit( (TUshort*)( theBaseAddress + CONTROL_STATUS ), 6, 0 );
      break;
    default:
      Tcerr << "TVmeMpx201aModule::SetEventSynchronisationMode: invalid mode" << Tendl;
      break;
  }

  return;
}

Tvoid TVmeMpx201aModule::SetDataCaptureMode( TdataCapture_t mode )
{
  switch ( mode ) {
    case tTransientMode:
      setBit( (TUshort*)( theBaseAddress + CONTROL_STATUS ), 5, 1 );
      break;
    case tContinuousMode:
      setBit( (TUshort*)( theBaseAddress + CONTROL_STATUS ), 5, 0 );
      break;
    default:
      Tcerr << "TVmeMpx201aModule::SetDataCaptureMode: invalid mode" << Tendl;
      break;
  }
  return;
}

TVmeMpx201aModule::Tsync_t TVmeMpx201aModule::GetEventSynchronisationMode() const
{
  Tbit d07 = getBit( (TUshort*)( theBaseAddress + CONTROL_STATUS ), 7 );
  Tbit d06 = getBit( (TUshort*)( theBaseAddress + CONTROL_STATUS ), 6 );

  if ( d07 == 0 ) {
    return tScannerMode;
  } else if ( d07 == 1 && d06 == 1 ) {
    return tInternalSynchronisationMode;
  } else if ( d07 == 1 && d06 == 0 ) {
    return tExternalSynchronisationMode;
  } else {
    return tModeUnknown;
  }
}

Tvoid TVmeMpx201aModule::SetNumberOfBlock( Tint nblock )
{
  if ( nblock < 0 || nblock > 0x7fff ) {
    Tcerr << "TVmeMpx201aModule::SetNumberOfBlock: invalid number" << Tendl;
    return;
  }
  *( (Tshort*)( theBaseAddress + BLOCK_COUNT ) ) = (Tshort)nblock;
  return;
}

Tvoid TVmeMpx201aModule::SetSamplingRate( Tint nsample )
{
  if ( nsample < 0 || nsample > 0x00ff ) {
    Tcerr << "TVmeMpx201aModule::SetSamplingRate: invalid number" << Tendl;
    return;
  }
  *( (Tshort*)( theBaseAddress + SAMPLE_RATE ) ) = (Tshort)nsample;
  return;
}

Toff_t TVmeMpx201aModule::GetOffsetAddressForDaughterBoard() const
{
  Tshort regval = *( (Tshort*)( theBaseAddress + VME_OFFSET_ADDRESS ) );
  regval &= 0xff80;
  Toff_t retval = regval;
  retval = retval << 16;
  return retval;
}

Tvoid TVmeMpx201aModule::SetOffsetAddressForDaughterBoard( Toff_t offset )
{
  if ( offset >= (Toff_t)0x00800000 || offset <= (Toff_t)0xff800000 ) {
    // A31 to A23
    // 0x00800000 - 0xff800000
    //offset = offset & 0xff8
    //setBit( (TUshort*)( theBaseAddress + CONTROL_STATUS ), 0, 1 );
    // be variableness in future.
    Tshort s = (Tshort)( ( offset & 0xff800000 ) >> 16 );
    *( (Tshort*)( theBaseAddress + VME_OFFSET_ADDRESS ) ) = s;
  } else {
    Tcerr << "bad address." << Tendl;
  }

  return;
}

Tvoid TVmeMpx201aModule::SetPage( Tint id )
{
  if ( id < 0 || id > 7 ) {
    Tcerr << "TVmeMpx201aModule::SetPage: invalid ID" << Tendl;
    return;
  }
  *( (Tshort*)( theBaseAddress + CONTROL_STATUS ) ) |= (Tshort)id;
  return;
}

Tint TVmeMpx201aModule::GetMappingSizeOfDaughterBoard() const
{
  Tint nblock = GetNumberOfBlock();
  // 2048 × ブロック数 × 2バイト(1サンプリング2バイト)
  return tBlock * nblock * Tsizeof( Tshort );
}

Tvoid TVmeMpx201aModule::NextEventProcedure()
{
  DisableAcquisition();
  SetMemoryBlockFullFlag( 0 );
  SetDataOverFlowFlag( 0 );
  EnableSystemFailure();
  SetScanCompleteFlag( 0 );
  return;
}

TUshort TVmeMpx201aModule::Read( Tint ch )
{
  TUshort data = 0x00;
  switch ( ch ) {
    case tIdRegister:
      data = *( (TUshort*)( theBaseAddress + ID ) );
      break;
    case tDeviceTypeRegister:
      data = *( (TUshort*)( theBaseAddress + DEVICE_TYPE ) );
      break;
    case tControlStatusRegister:
      data = *( (TUshort*)( theBaseAddress + CONTROL_STATUS ) );
      break;
    case tVmeOffsetAddressRegister:
      data = *( (TUshort*)( theBaseAddress + VME_OFFSET_ADDRESS ) );
      break;
    case tPageSetAddressRegister:
      data = *( (TUshort*)( theBaseAddress + PAGE_SET ) );
      break;
    case tReserved:
      data = *( (TUshort*)( theBaseAddress + RESERVED ) );
      break;
    case tTestModeRegister:
      data = *( (TUshort*)( theBaseAddress + TEST_MODE ) );
      break;
    case tTestDataRegister:
      data = *( (TUshort*)( theBaseAddress + TEST_DATA ) );
      break;
    case tInterruptConfigurationRegister:
      data = *( (TUshort*)( theBaseAddress + INTERRUPT ) );
      break;
    case tBlockCounterRegister:
      data = *( (TUshort*)( theBaseAddress + BLOCK_COUNT ) );
      break;
    case tAcquisitionPointerRegister:
      data = *( (TUshort*)( theBaseAddress + DAQ_POINTER ) );
      break;
    case tSampleRateRegister:
      data = *( (TUshort*)( theBaseAddress + SAMPLE_RATE ) );
      break;
    case tFrontPorchRegister:
      data = *( (TUshort*)( theBaseAddress + FRONT_PORCH ) );
      break;
    case tFrameLengthRegister:
      data = *( (TUshort*)( theBaseAddress + FRAME_LENGTH ) );
      break;
    case tRowLengthRegister:
      data = *( (TUshort*)( theBaseAddress + ROW_LENGTH ) );
      break;
    default:
      break;
  }
  data &= 0x00ff;
  return data;
}

#ifdef __CLDAQ_ROOT_DLL
    ClassImp(TVmeMpx201aModule)
#endif
