// =====================================================================
//  $Id: TRs232cModule.cc,v 1.4 2004/03/07 10:30:31 goiwai Exp $
//  $Name: CLDAQ-1-14-06 $
//  $Log: TRs232cModule.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:11  goiwai
//  ファイルにコミットログをつけることにしました.
//
// =====================================================================
#include "TRs232cModule.hh"
#include "TDataElement.hh"

static const Tchar _CR = '\x0d';
static const Tchar _LF = '\x0a';

TRs232cModule::TRs232cModule( const Tstring devfile, Tint nchannel )
  : TModule( nchannel ), 
    theFileDescriptor( -1 ), 
    theDeviceFile( devfile ),
    theSerialPort()
{
  if ( !IsOpen() ) {
    Open();
  }
}

TRs232cModule::TRs232cModule( Tint nchannel, Tstring devfile )
  : TModule( nchannel ), 
    theFileDescriptor( -1 ), 
    theDeviceFile( devfile ),
    theSerialPort()
{
  if ( !IsOpen() ) {
    Open();
  }
}

TRs232cModule::TRs232cModule( const TRs232cModule& right )
  : TModule( right ), 
    theFileDescriptor( -1 ), 
    theDeviceFile( right.theDeviceFile ), 
    theSerialPort( right.theSerialPort )
{
  if ( !IsOpen() ) {
    Open();
  }
}

TRs232cModule::~TRs232cModule()
{
  Close();
}

const TRs232cModule& TRs232cModule::operator=( const TRs232cModule& right )
{
  *( (TModule*)this ) = *( (TModule*)(&right) );
  if ( IsOpen() ) {
    Close();
  }
  theFileDescriptor = -1;
  theDeviceFile = right.theDeviceFile;
  theSerialPort = right.theSerialPort;
  Open();
  return *this;
}

Tbool TRs232cModule::operator==( const TRs232cModule& right ) const
{
  Tbool retval = Ttrue;
  retval &= ( *( (TModule*)this ) == *( (TModule*)(&right) ) );
  retval &= ( theDeviceFile == right.theDeviceFile );
  return retval;
}

Tbool TRs232cModule::operator!=( const TRs232cModule& right ) const
{
  Tbool retval = Tfalse;
  retval |= ( *( (TModule*)this ) != *( (TModule*)(&right) ) );
  retval |= ( theDeviceFile != right.theDeviceFile );
  return retval;
}

Tint TRs232cModule::Clear()
{
  for ( Tint ch = 0; ch < theNumberOfChannels; ch ++ ) {
    DoClearMethod( ch );
  }
  return theStatus = tStatusSuccess;
}

Tint TRs232cModule::Update()
{
  for ( Tint ch = 0; ch < theNumberOfChannels; ch ++ ) {
    DoUpdateMethod( ch );
  }
  return theStatus = tStatusSuccess;
}

Tint TRs232cModule::Initialize()
{
  for ( Tint ch = 0; ch < theNumberOfChannels; ch ++ ) {
    DoInitializeMethod( ch );
  }
  return theStatus = tStatusSuccess;
}

Tvoid TRs232cModule::FillData( TDataElement& element, Tint channel )
{
  if ( channel < 0 || channel >= theNumberOfChannels ) {
    theStatus = -EFAULT;
    Tcerr << "TRs232cModule::FillData: invalid ID " << channel << Tendl;
    element.FillData( &theStatus, tTypeInt, 1 );
  } else {
    Tstring accept = DoReadMethod( channel );
    Tdouble databuf;
    if ( modifyData( accept, databuf ) ) {
      element.FillData( &databuf, tTypeDouble, 1 );
    } else {
      element.FillData( &accept, tTypeString, 1 );
    }
  }
  return;
}

Tint TRs232cModule::Open()
{
  theFileDescriptor = open( theDeviceFile.c_str(), O_RDWR );
  if ( theFileDescriptor == -1 ) {
    perror( "TRs232cModule::Open" );
    exit( theStatus = -errno );
  }


  if( ioctl( theFileDescriptor, TCGETA, &theSerialPort ) == -1 ) {
    perror( "TRs232cModule::Open" );
    exit( theStatus = -errno );
  }

  struct termio termbuf = theSerialPort;
  termbuf.c_lflag &= ~ECHO;
  //
  // DEFAULT SPEED.これは問題あるかもしんない
  termbuf.c_cflag |= B9600;
  //
  //
  termbuf.c_cflag |= CS8;
  termbuf.c_cflag |= CREAD;
  termbuf.c_iflag |= ICRNL;
  termbuf.c_iflag |= ICANON;
  termbuf.c_iflag |= INLCR;
  termbuf.c_iflag &= ~OPOST;
  termbuf.c_oflag |= OCRNL;
  termbuf.c_oflag &= ~BRKINT;
  termbuf.c_oflag &= ~ISTRIP;
  termbuf.c_oflag &= ~IMAXBEL;
  termbuf.c_cflag &= ~PARENB;

  if ( ioctl( theFileDescriptor, TCSETA, &termbuf ) == -1 ) {
    perror( "TRs232cModule::Open" );
    exit( theStatus = -errno );
  }

  return theStatus = tStatusSuccess;
}

Tint TRs232cModule::Write( const Tstring& token )
{
  if ( write( theFileDescriptor, token.c_str(), token.size() ) != (Tint)token.size() ) {
    perror( "TRs232cModule::Write" );
    exit( theStatus = -errno );
  }
  if ( token[ token.size() - 1 ] != _LF ) {
    if ( write( theFileDescriptor, &_LF, 1 ) != 1 ) {
      perror( "TRs232cModule::Write" );
      exit( theStatus = -errno );
    }
  }
  return theStatus = tStatusSuccess;
}

Tstring TRs232cModule::Read()
{

  Tstring answer;
  Tchar cbuf;
  while ( read( theFileDescriptor, &cbuf, 1 ) == 1 && cbuf != _LF ) {
    answer += cbuf;
  }
  theStatus = tStatusSuccess;
  return answer;
}

Tint TRs232cModule::Close()
{
  if ( IsOpen() ) {
    if ( ioctl( theFileDescriptor, TCSETA, &theSerialPort ) == -1 ) {
      perror( "TRs232cModule::Close" );
      exit( theStatus = -errno );
    }
    close( theFileDescriptor );
    theFileDescriptor = -1;
  }
  return theStatus = tStatusSuccess;
}

#ifdef __CLDAQ_ROOT_DLL
    ClassImp(TRs232cModule)
#endif
