// =====================================================================
//  $Id: TVmeModule.cc,v 1.4 2004/03/07 10:30:31 goiwai Exp $
//  $Name: CLDAQ-1-14-03 $
//  $Log: TVmeModule.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 "TVmeModule.hh"

TVmeModule::TVmeModule( Tint nch, Toff_t offset, Tint mapsize, TvmeTransfer_t mode )
  : TModule( nch ),
    theMappedSize( mapsize ), theTransferMode( mode ),
    theFileDescriptor( -1 ), theBaseAddress( 0 ), 
    theOffsetAddress( offset )
{
  theFileDescriptor = open( ( TvmeDevices[ theTransferMode ] ).c_str(), O_RDWR );
  if ( theFileDescriptor == -1 ) {
    perror( "TVmeModule::TVmeModule" );
    exit( EXIT_FAILURE );
  }
  theStatus = -errno;


  Tvoid* base = 0;
  if ( ( base = mmap( 0, theMappedSize, PROT_READ|PROT_WRITE, MAP_SHARED, theFileDescriptor, theOffsetAddress ) ) == MAP_FAILED ) {
    perror( "TVmeModule::TVmeModule" );
    exit( EXIT_FAILURE );
  }
  theBaseAddress = (Tcaddr_t)base;
  theStatus = -errno;
}

TVmeModule::TVmeModule( const TVmeModule& right )
  : TModule( right ),
    theMappedSize( right.theMappedSize ),
    theTransferMode( right.theTransferMode ),
    theFileDescriptor( -1 ), theBaseAddress( 0 ),
    theOffsetAddress( right.theOffsetAddress )
{
  theFileDescriptor = open( ( TvmeDevices[ theTransferMode ] ).c_str(), O_RDWR );
  if ( theFileDescriptor == -1 ) {
    perror( "TVmeModule::TVmeModule" );
    exit( EXIT_FAILURE );
  }
  theStatus = -errno;

  Tvoid* base = 0;
  if ( ( base = mmap( 0, theMappedSize, PROT_READ|PROT_WRITE, MAP_SHARED, theFileDescriptor, theOffsetAddress ) ) == MAP_FAILED ) {
    perror( "TVmeModule::TVmeModule" );
    exit( EXIT_FAILURE );
  }
  theBaseAddress = (Tcaddr_t)base;  
  theStatus = -errno;
}

TVmeModule::~TVmeModule()
{
  munmap( theBaseAddress, theMappedSize );
  theStatus = -errno;
  close( theFileDescriptor );
  theStatus = -errno;
}

const TVmeModule& TVmeModule::operator=( const TVmeModule& right )
{
  *( (TModule*)this ) = *( (TModule*)(&right) );
  theMappedSize = right.theMappedSize;
  theTransferMode = right.theTransferMode;
  theFileDescriptor = -1;
  theBaseAddress = 0;
  theOffsetAddress = right.theOffsetAddress;

  theFileDescriptor = open( ( TvmeDevices[ theTransferMode ] ).c_str(), O_RDWR );
  if ( theFileDescriptor == -1 ) {
    perror( "TVmeModule::operator=" );
    exit( EXIT_FAILURE );
  }
  theStatus = -errno;

  Tvoid* base = 0;
  if ( ( base = mmap( 0, theMappedSize, PROT_READ|PROT_WRITE, MAP_SHARED, theFileDescriptor, theOffsetAddress ) ) == MAP_FAILED ) {
    perror( "TVmeModule::operator=" );
    exit( EXIT_FAILURE );
  }
  theBaseAddress = (Tcaddr_t)base;  
  theStatus = errno;
  return *this;
}

Tbool TVmeModule::operator==( const TVmeModule& right ) const
{
  Tbool ret = Ttrue;
  ret &= ( *( (TModule*)this ) == *( (TModule*)(&right) ) );
  ret &= ( theMappedSize == right.theMappedSize );
  ret &= ( theTransferMode == right.theTransferMode );
  ret &= ( theOffsetAddress == right.theOffsetAddress );
  return ret;
}

Tbool TVmeModule::operator!=( const TVmeModule& right ) const
{
  Tbool ret = Tfalse;
  ret |= ( *( (TModule*)this ) != *( (TModule*)(&right) ) );
  ret |= ( theMappedSize != right.theMappedSize );
  ret |= ( theTransferMode != right.theTransferMode );
  ret |= ( theOffsetAddress != right.theOffsetAddress );
  return ret;
}

Tvoid TVmeModule::showBit( TUshort data, const Tstring comment ) const
{
  TUshort bit;

  Tcout << "0x";
  Tcout.setf( ios::left );
  Tcout.width( 10 );
  Tcout << hex << data << ": ";
  static const Tint nbits = 16;

  for ( int i = 0; i < nbits; i ++ ) {
    bit = data & 0x8000;
    bit = bit >> ( nbits - 1 );
    Tcout << bit;
    data = data << 1;
  }

  if ( comment.empty() )
    Tcout << Tendl;
  else
    Tcout << "   <--- " << comment << Tendl;

  return;
}

Tvoid TVmeModule::setBit( TUshort* ptr, Tint nbit, Tbit bit )
{
  if ( nbit < 0 || nbit > 15 ) {
    Tcerr << "TVmeModule::setBit: invalid channel" << Tendl;
    return;
  }

  TUshort mask = 0x0001;
  mask = mask << nbit;

  if ( bit == 1 ) {
    *ptr |= mask;
  } else if ( bit == 0 ) {
    mask = ~mask;
    *ptr &= mask;
  } else {
    Tcerr <<  "TVmeModule::setBit: set 0 or 1" << Tendl;
    return;
  }

  return;
}

Tbit TVmeModule::getBit( TUshort* ptr, Tint nbit ) const
{
  if ( nbit < 0 || nbit > 15 ) {
    Tcerr << "TVmeModule::getBit: invalid channel" << Tendl;
    return 0;
  }

  TUshort data = *ptr;
  data = data >> nbit;
  data &= 0x00001;

  return data;
}

#ifdef __CLDAQ_ROOT_DLL
    ClassImp(TVmeModule)
#endif
