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

TVmeDaughterBoardMemoryModule::TVmeDaughterBoardMemoryModule( Toff_t offset, Tint mapsize, Tint nblock, Tint nch )
  : TVmeModule( nch, offset, mapsize, tA32D32 ),
    theNumberOfSampling( nblock * TVmeMpx201aModule::tBlock )
{;}

TVmeDaughterBoardMemoryModule::TVmeDaughterBoardMemoryModule( const TVmeMpx201aModule* mpx201a, Tint nch )
  : TVmeModule( nch, mpx201a->GetOffsetAddressForDaughterBoard(), mpx201a->GetMappingSizeOfDaughterBoard(), tA32D32 ),
    theNumberOfSampling( mpx201a->GetNumberOfBlock() * TVmeMpx201aModule::tBlock )
{;}

TVmeDaughterBoardMemoryModule::TVmeDaughterBoardMemoryModule( const TVmeDaughterBoardMemoryModule& right )
  : TVmeModule( right ),
    theNumberOfSampling( right.theNumberOfSampling )
{;}

TVmeDaughterBoardMemoryModule::~TVmeDaughterBoardMemoryModule()
{;}

const TVmeDaughterBoardMemoryModule& TVmeDaughterBoardMemoryModule::operator=( const TVmeDaughterBoardMemoryModule& right )
{
  *( (TVmeModule*)this ) = *( (TVmeModule*)(&right) );
  theNumberOfSampling = right.theNumberOfSampling;
  return *this;
}

Tbool TVmeDaughterBoardMemoryModule::operator==( const TVmeDaughterBoardMemoryModule& right ) const
{
  Tbool ret = Ttrue;
  ret &= ( *( (TVmeModule*)this ) == *( (TVmeModule*)(&right) ) );
  ret &= ( theNumberOfSampling == right.theNumberOfSampling );
  return ret;
}

Tbool TVmeDaughterBoardMemoryModule::operator!=( const TVmeDaughterBoardMemoryModule& right ) const
{
  Tbool ret = Tfalse;
  ret |= ( *( (TVmeModule*)this ) != *( (TVmeModule*)(&right) ) );
  ret |= ( theNumberOfSampling != right.theNumberOfSampling );
  return ret;
}

Tint TVmeDaughterBoardMemoryModule::Clear()
{
  Tlong* membase = (Tlong*)theBaseAddress;

  Tint nsample = theNumberOfSampling / 2;

  for ( Tint i = 0; i < nsample; i ++ ) {
    membase[ i ] = 0x0000;
  }
  return theStatus = tStatusSuccess;
}

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

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

Tvoid TVmeDaughterBoardMemoryModule::FillData( TDataElement& element, Tint channel )
{
  if ( channel < 0 || channel >= theNumberOfChannels ) {
    Tcerr << "TVmeDaughterBoardMemoryModule::FillData: invalid ID " << channel << Tendl;
    theStatus = -EFAULT;
    element.FillData( &theStatus, tTypeInt, 1 );
  } else {
    // 人間はすぐ忘れるのでメモしておきましょ
    // テストした環境
    // Pentium III(450MHz)が2個のった
    // Redhat8くらいでカーネルは Linux-2.4.20smp
    //
    // たとえば FADC を 16サンプリングに1回にAD変換するようにすると
    // 0から数えて
    // 15と31でADはされているようだ
    // ただし,15は読むことができない31は読める
    //
    // enum { tDataUnderflow = SHRT_MIN, tDataOverflow = SHRT_MAX };
    // データバッファは 16bit だけど
    // 読みだす対象のメモリは 32bit ずつインクリメントする
    // 32bitのデータは (& 0x0000fff0) されて
    // 0〜31bit のうち 4〜11bit目をあつかう
    // これが 0x7ff0 なら オーバーフロー 32767
    // 0x8000 なら アンダーフロー -32768

    // direct access, processing speed improve.
    Tlong* membase = (Tlong*)theBaseAddress;

    const Tint nsample = theNumberOfSampling / 2;
    Tshort* databuf = new Tshort[ nsample ];
    for ( Tint i = 0; i < nsample; i ++ ) {
      databuf[ i ] = modifyData( membase[ i ] );
    }
    element.FillData( databuf, tTypeShort, nsample );
    delete [] databuf;
  }

  return;
}

Tshort TVmeDaughterBoardMemoryModule::modifyData( Tlong databuf ) const
{
  if ( ( databuf & 0x0000fff0 ) == 0x7ff0 ) {
    // overflow
    return tDataOverflow;
  } else if ( ( databuf & 0x0000fff0 ) == 0x8000 ) {
    // underflow
    return tDataUnderflow;
  }
 
  Tshort retval = (Tshort)( databuf & 0x0000fff0 );
  Tbit sign = ( retval & 0x8000 ) >> 15;
  if ( sign == 1 ) {
    // case of negative value
    retval &= 0x7ff0;
    retval = retval >> 4;
  } else if ( sign == 0 ) {
    // case of positive value
    retval = retval >> 4;
    retval += 0x0800;
  } else {
    Tcerr << "TVmeDaughterBoardMemoryModule::modifyData: failed." << Tendl;
  }

  return retval;
}

#ifdef __CLDAQ_ROOT_DLL
    ClassImp(TVmeDaughterBoardMemoryModule)
#endif
