// =====================================================================
//  $Id: TCamacModule.cc,v 1.5 2004/03/07 10:30:31 goiwai Exp $
//  $Name: CLDAQ-1-14-06 $
//  $Log: TCamacModule.cc,v $
//  Revision 1.5  2004/03/07 10:30:31  goiwai
//  ROOTに組みこむためのおまじないマクロを埋めこみました。
//  全てにおいて完全に動作するわけではありません。
//
//  Revision 1.4  2003/11/04 07:40:13  goiwai
//  CAMACドライバへインターフェース部分である CamacDriverInterface の名前
//  を TCamacDriverInterface に変更しました.
//  またこの型をTCamacModuleクラス内部に閉じ込めました.
//  その他,文法的に無意味な部分を修整しました.手元にハードがないので,動作
//  確認していませんが,もし動かなくなるようならこの部分が原因です.
//
//  Revision 1.3  2003/10/06 17:02:40  goiwai
//  *** empty log message ***
//
//  Revision 1.2  2003/07/30 16:19:10  goiwai
//  ファイルにコミットログをつけることにしました.
//
// =====================================================================
#include "TCamacModule.hh"
#include "TCamacCrateController.hh"

TCamacModule::TCamacModule( TCamacCrateController* cc7x00, Tint slot, Tint nch, Tdata_t datalen )
  : TModule( nch ),
    theCrateController( cc7x00 ), theDataLength( datalen ),
    theSlotNumber( slot ), theQ( 0 ), theX( 0 ), theCamacData( 0 )
{;}

TCamacModule::TCamacModule( const TCamacModule& right )
  : TModule( right ),
    theCrateController( right.theCrateController ),
    theDataLength( right.theDataLength ), 
    theSlotNumber( right.theSlotNumber ), 
    theQ( 0 ), theX( 0 ), theCamacData( 0 )
{;}

TCamacModule::~TCamacModule()
{;}

const TCamacModule& TCamacModule::operator=( const TCamacModule& right )
{
  *( (TModule*)this ) = *( (TModule*)(&right) );
  theCrateController = right.theCrateController;
  theDataLength = right.theDataLength;
  theSlotNumber = right.theSlotNumber;
  theQ = right.theQ;
  theX = right.theX;
  theCamacData = right.theCamacData;
  return *this;
}

Tbool TCamacModule::operator==( const TCamacModule& right ) const
{
  Tbool retval = Ttrue;
  retval &= ( *( (TModule*)this ) == *( (TModule*)(&right) ) );
  retval &= ( theCrateController == right.theCrateController );
  retval &= ( theSlotNumber == right.theSlotNumber );
  retval &= ( theDataLength == right.theDataLength );;
  return retval;
}

Tbool TCamacModule::operator!=( const TCamacModule& right ) const
{
  Tbool retval = Tfalse;
  retval |= ( *( (TModule*)this ) != *( (TModule*)(&right) ) );
  retval |= ( theCrateController != right.theCrateController );
  retval |= ( theSlotNumber != right.theSlotNumber );
  retval |= ( theDataLength != right.theDataLength );;
  return retval;
}

Tint TCamacModule::WaitInterrupt( Tint msec )
{
  TUint timeout = (TUint)( (Tdouble)HZ/(Tdouble)1000 * (Tdouble)msec );
  TUint mask = ( 1 << ( theSlotNumber  - 1 ) );
  TUint buffer[ 2 ] = { timeout, ~mask };

  errno ^= errno;
  ioctl( theCrateController -> GetFileDescriptor(), IOC_WAIT_LAM, &buffer );
  theStatus = -errno;
  theCrateController -> SetStatus( theStatus );

  return theStatus;
}

Tint TCamacModule::ReadInterrupt()
{
  errno ^= errno;
  ioctl( theCrateController -> GetFileDescriptor(), IOC_GET_LAM, &theCamacData );
  theStatus = -errno;
  theCrateController -> SetStatus( theStatus );

  return theStatus;
}

Tint TCamacModule::Clear()
{
  return execute( 0, tCamacClear );
}

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

Tint TCamacModule::Initialize()
{
  Clear();
  return DisableInterrupt();
}

Tint TCamacModule::TestInterrupt()
{
  return execute( 0, tCamacTestInterrupt );
}

Tint TCamacModule::ClearInterrupt()
{
  return execute( 0, tCamacClearInterrupt );
}

Tint TCamacModule::EnableInterrupt()
{
  return execute( 0, tCamacEnableInterrupt );
}

Tint TCamacModule::DisableInterrupt()
{
  return execute( 0, tCamacDisableInterrupt );
}

Tint TCamacModule::Read()
{
  return execute( 0, tCamacRead );
}

Tint TCamacModule::Read( Tint subaddress )
{
  return execute( subaddress, tCamacRead );
}

Tint TCamacModule::Write( Tint data )
{
  theCamacData = (TUint)data;
  return execute( 0, tCamacWrite );
}

TUint TCamacModule::generateNAF( Tint n, Tint a, Tint f )
{
  TUint naf = 0L;
  if ( theCrateController -> IsISA7000() )
    naf = ((f & 0x001f)<<16) + ((a & 0x000f)<<8) + (n & 0x001f);
  else
    naf = (((n-1) & 0x001f)<<9) + ((a & 0x000f)<<5) + (f & 0x0000001f);
  return naf;
}

Tint TCamacModule::execute( Tint subaddress, Tint function )
{
  TUint naf = generateNAF( theSlotNumber, subaddress, function );
  if ( theDataLength == t16bitModule ) {
    return execute16bit( naf );
  } else if ( theDataLength == t24bitModule ) {
    return execute24bit( naf );
  } else {
    return execute24bit( naf );
  }
}

Tint TCamacModule::execute16bit( TUint naf )
{
  struct TCamacDriverInterface camacdata;
  camacdata._naf = naf;
  camacdata._q = 0;
  camacdata._x = 0;
  camacdata._data._d16 = (TUshort)theCamacData;

  errno ^= errno;
  ioctl( theCrateController -> GetFileDescriptor(), IOC_CAM16, &camacdata );
  theStatus = -errno;
  theCrateController -> SetStatus( theStatus );

  theQ = (Tint)camacdata._q;
  theX = (Tint)camacdata._x;
  theCamacData = (TUint)( camacdata._data._d16 );

  return theStatus;
}

Tint TCamacModule::execute24bit( TUint naf )
{
  struct TCamacDriverInterface camacdata;
  camacdata._naf = naf;
  camacdata._q = 0;
  camacdata._x = 0;
  camacdata._data._d24 = theCamacData;

  errno ^= errno;
  ioctl( theCrateController -> GetFileDescriptor(), IOC_CAM24, &camacdata );
  theStatus = -errno;
  theCrateController -> SetStatus( theStatus );

  theQ = (Tint)camacdata._q;
  theX = (Tint)camacdata._x;
  theCamacData = camacdata._data._d24;

  return theStatus;
}

#ifdef __CLDAQ_ROOT_DLL
    ClassImp(TCamacModule)
#endif
