static const char *RcsId = "$Header: /users/chaize/newsvn/cvsroot/InputOutput/ADLINK/ContinuousAO/src/ContinuousAO.cpp,v 1.8 2005-06-15 10:22:16 abeilleg Exp $";
//+=============================================================================
//
// file :	  ContinuousAO.cpp
//
// description :  C++ source for the ContinuousAO and its commands. 
//		  The class is derived from Device. It represents the
//		  CORBA servant object which will be accessed from the
//		  network. All commands which can be executed on the
//		  ContinuousAO are implemented in this file.
//
// project :	  TANGO Device Server
//
// $Author: abeilleg $
//
// $Revision: 1.8 $
//
// $Log: not supported by cvs2svn $
// Revision 1.7  2005/04/21 08:33:44  abeilleg
// update state in always_exe_hk
//
// Revision 1.6  2005/01/25 10:12:58  abeilleg
// status changed.
//
// Revision 1.5  2005/01/20 13:21:51  abeilleg
// following ASL modifications (states management).
//
// Revision 1.4  2004/12/21 13:06:59  abeilleg
// minor bugs fixed
//
//
// copyleft :	  Synchrotron SOLEIL
//		  L'Orme des Merisiers
//		  Saint-Aubin - BP 48

//
//-=============================================================================
//
//		This file is generated by POGO
//	(Program Obviously used to Generate tango Object)
//
//	   (c) - Software Engineering Group - ESRF
//=============================================================================


//===================================================================
//
//	The folowing table gives the correspondance
//	between commands and method's name.
//
//	Command's name	|	Method's name
//	----------------------------------------
//	State	|	dev_state()
//	Status	|	dev_status()
//	Start	|	start()
//	Stop	|	stop()
//	SetAOScaledData	|	set_aoscaled_data()
//
//===================================================================
#include <ContinuousAO.h>
#include <TangoExceptionsHelper.h>
#include <asl/ASLExceptionsHandler.h>
#include <asl/AOData.h>
#include <math.h>
namespace ContinuousAO
{

//+----------------------------------------------------------------------------
//
// method :		ContinuousAO::ContinuousAO(string &s)
// 
// description :	constructor for simulated ContinuousAO
//
// in : - cl : Pointer to the DeviceClass object
//	- s : Device name 
//
//-----------------------------------------------------------------------------
ContinuousAO::ContinuousAO(Tango::DeviceClass *cl,string &s):Tango::Device_2Impl(cl,s.c_str())
{
	init_device();
}

ContinuousAO::ContinuousAO(Tango::DeviceClass *cl,const char *s):Tango::Device_2Impl(cl,s)
{
	init_device();
}

ContinuousAO::ContinuousAO(Tango::DeviceClass *cl,const char *s,const char *d)
:Tango::Device_2Impl(cl,s,d)
{
	init_device();
}
//+----------------------------------------------------------------------------
//
// method :		ContinuousAO::delete_device()
// 
// description :	will be called at device destruction or at init command.
//
//-----------------------------------------------------------------------------
void ContinuousAO::delete_device()
{
	//	Delete device's allocated object
  if(ao)
  {
    delete ao;
    ao = 0;
  }
  if(ch0)
  {
    delete ch0;
    ch0 = 0;
  }
  if(ch1)
  {
    delete ch1;
    ch1 = 0;
  }
  if(ch2)
  {
    delete ch2;
    ch2 = 0;
  }
  if(ch3)
  {
    delete ch3;
    ch3 = 0;
  }
  if(ch4)
  {
    delete ch4;
    ch4 = 0;
  }
  if(ch5)
  {
    delete ch5;
    ch5 = 0;
  }
  if(ch6)
  {
    delete ch6;
    ch6 = 0;
  }
  if(ch7)
  {
    delete ch7;
    ch7 = 0;
  }
}

//+----------------------------------------------------------------------------
//
// method :		ContinuousAO::init_device()
// 
// description :	will be called at device initialization.
//
//-----------------------------------------------------------------------------
void ContinuousAO::init_device()
{
  INFO_STREAM << "ContinuousAO::ContinuousAO() create device " << device_name << endl;
  
  ao = 0;
  ch0 = 0;
  ch1 = 0;
  ch2 = 0;
  ch3 = 0;
  ch4 = 0;
  ch5 = 0;
  ch6 = 0;
  ch7 = 0;
  m_error_message = "An error has occured";
  
  // Initialise variables to default values
  //--------------------------------------------
  get_device_property();
  
  //- create a continuous analog output daq
  ao = new ADLinkContinuousAO(this);
  
  //- check memory allocation
  if (ao == 0)
  {
	on_fault("ContinuousAO::init_device\nout of memory error while initializing ADLinkContinuousAO");
	return;
  }
  
  asl::ContinuousAOConfig config;
  ch0 = new double[bufferDepth];
  ch1 = new double[bufferDepth];
  ch2 = new double[bufferDepth];
  ch3 = new double[bufferDepth];
  ch4 = new double[bufferDepth];
  ch5 = new double[bufferDepth];
  ch6 = new double[bufferDepth];
  ch7 = new double[bufferDepth];
  if(ch0 == 0 || ch1 == 0 || ch2 == 0 || ch3 == 0 || ch4 == 0 || ch5 == 0 ||ch6 == 0 || ch7 == 0)
  {
	on_fault("ContinuousAO::init_device\nout of memory error while initializing channel's datas");
	return;
  }
  
  
  // default waveform for group A (channel 0 to 3)
  asl::AOScaledData default_waveformA(bufferDepth);
  double max_valA;
  if(aORefSource == adl::external_reference)
    max_valA = aORefA ;
  else
    max_valA = 10.0;
  
  // fill buffer with a sin signal 
  for (unsigned long i = 0; i < bufferDepth; i++)
  {
    (default_waveformA)[i] = ::sin((double)i * 2. * 3.14159 / (double) bufferDepth) * max_valA;
  }
  
  ACE_OS::memcpy(ch0, default_waveformA.base(), default_waveformA.size());
  ACE_OS::memcpy(ch1, default_waveformA.base(), default_waveformA.size());
  ACE_OS::memcpy(ch2, default_waveformA.base(), default_waveformA.size());
  ACE_OS::memcpy(ch3, default_waveformA.base(), default_waveformA.size());
  
  // default waveform for group A (channel 4 to 7)
  asl::AOScaledData default_waveformB(bufferDepth);
  double max_valB;
  if(aORefSource == adl::external_reference)
    max_valB = aORefB;
  else
    max_valB = 10.0;
  
  // fill buffer with a square signal 
  for (i = 0; i < bufferDepth/2; i++)
  {
    default_waveformB[i] = max_valB - 0.01;
  }
  for (i = bufferDepth/2; i < bufferDepth; i++)
  {
    default_waveformB[i] = -max_valB + 0.01;
  }
  ACE_OS::memcpy(ch4, default_waveformB.base(), default_waveformB.size());
  ACE_OS::memcpy(ch5, default_waveformB.base(), default_waveformB.size());
  ACE_OS::memcpy(ch6, default_waveformB.base(), default_waveformB.size());
  ACE_OS::memcpy(ch7, default_waveformB.base(), default_waveformB.size());
  
  //--------------------------channels config------------------------------------ 
  asl::ActiveAOChannel ac;
  
  // configure all channels
  ac.polarity = (adl::OutputPolarity)polarity;
  ac.volt_ref_src = (adl::VoltageReferenceSource)aORefSource;
  ac.volt_ref = 10.0;
  
  //- active/config. channel 0
  if(channel0Enable)
  {
    ac.id = 0;
    if(aORefSource == adl::external_reference)
      ac.volt_ref = aORefA;
    config.add_active_channel(ac);
    
    if(channel0Waveform.empty())
    {
      WARN_STREAM<<"No waveform is saved in database for channel 0, using a default one"<<endl;
      config.set_channel_periodic_data(0, default_waveformA);
    }
    else if(channel0Waveform.size() != bufferDepth)
    {
      WARN_STREAM<<"The waveform saved in database for channel 0 has a different size from property BufferDepth, "<<
        "using default waveform"<<endl;
      config.set_channel_periodic_data(0, default_waveformA);
    }
    else //put waveform of the Tango database in ch0
    {
      // copy the input data in a buffer of type asl::AOScaledData
      asl::AOScaledData data(bufferDepth);
      for(int i=0; i<bufferDepth; i++)
        data[i] = channel0Waveform[i]; 
      // put the waveform in the configuration
      config.set_channel_periodic_data(0, data);
      //cpy data in the attribute of the device
      ::memcpy(ch0, data.base(), data.size());
    }
  }
  //- active/config. channel 1
 if(channel1Enable)
  {
    ac.id = 1;
    if(aORefSource == adl::external_reference)
      ac.volt_ref = aORefA;
    config.add_active_channel(ac);
    
    if(channel1Waveform.empty())
    {
      WARN_STREAM<<"No waveform is saved in database for channel 1, using a default one"<<endl;
      config.set_channel_periodic_data(1, default_waveformA);
    }
    else if(channel1Waveform.size() != bufferDepth)
    {
      WARN_STREAM<<"The waveform saved in database for channel 1 has a different size from property BufferDepth, "<<
        "using default waveform"<<endl;
      config.set_channel_periodic_data(1, default_waveformA);
    }
    else //put waveform of the Tango database in ch1
    {
      // copy the input data in a buffer of type asl::AOScaledData
      asl::AOScaledData data(bufferDepth);
      for(int i=0; i<bufferDepth; i++)
        data[i] = channel1Waveform[i]; 
      // put the waveform in the configuration
      config.set_channel_periodic_data(1, data);
      //cpy data in the attribute of the device
      ::memcpy(ch1, data.base(), data.size());
    }
  }
  //- active/config. channel 2
  if(channel2Enable)
  {
    ac.id = 2;
    if(aORefSource == adl::external_reference)
      ac.volt_ref = aORefA;
    config.add_active_channel(ac);
    config.set_channel_periodic_data(2, default_waveformA);
    
    if(channel2Waveform.empty())
    {
      WARN_STREAM<<"No waveform is saved in database for channel 2, using a default one"<<endl;
      config.set_channel_periodic_data(2, default_waveformA);
    }
    else if(channel2Waveform.size() != bufferDepth)
    {
      WARN_STREAM<<"The waveform saved in database for channel 2 has a different size from property BufferDepth, "<<
        "using default waveform"<<endl;
      config.set_channel_periodic_data(2, default_waveformA);
    }
    else //put waveform of the Tango database in ch2
    {
      // copy the input data in a buffer of type asl::AOScaledData
      asl::AOScaledData data(bufferDepth);
      for(int i=0; i<bufferDepth; i++)
        data[i] = channel2Waveform[i]; 
      // put the waveform in the configuration
      config.set_channel_periodic_data(2, data);
      //cpy data in the attribute of the device
      ::memcpy(ch2, data.base(), data.size());
    }
  }
  //- active/config. channel 3
  if(channel3Enable)
  {
    ac.id = 3;
    if(aORefSource == adl::external_reference)
      ac.volt_ref = aORefA;
    config.add_active_channel(ac);
    
    if(channel3Waveform.empty())
    {
      WARN_STREAM<<"No waveform is saved in database for channel 3, using a default one"<<endl;
      config.set_channel_periodic_data(3, default_waveformA);
    }
    else if(channel3Waveform.size() != bufferDepth)
    {
      WARN_STREAM<<"The waveform saved in database for channel 3 has a different size from property BufferDepth, "<<
        "using default waveform"<<endl;
      config.set_channel_periodic_data(3, default_waveformA);
    }
    else //put waveform of the Tango database in ch3
    {
      // copy the input data in a buffer of type asl::AOScaledData
      asl::AOScaledData data(bufferDepth);
      for(int i=0; i<bufferDepth; i++)
        data[i] = channel3Waveform[i]; 
      // put the waveform in the configuration
      config.set_channel_periodic_data(3, data);
      //cpy data in the attribute of the device
      ::memcpy(ch3, data.base(), data.size());
    }
  }
  //- active/config. channel 4
  if(channel4Enable)
  {
    ac.id = 4;
    if(aORefSource == adl::external_reference)
      ac.volt_ref = aORefB;
    config.add_active_channel(ac);
    
    if(channel4Waveform.empty())
    {
      WARN_STREAM<<"No waveform is saved in database for channel 4, using a default one"<<endl;
      config.set_channel_periodic_data(4, default_waveformB);
    }
    else if(channel4Waveform.size() != bufferDepth)
    {
      WARN_STREAM<<"The waveform saved in database for channel 4 has a different size from property BufferDepth, "<<
        "using default waveform"<<endl;
      config.set_channel_periodic_data(4, default_waveformB);
    }
    else //put waveform of the Tango database in ch4
    {
      // copy the input data in a buffer of type asl::AOScaledData
      asl::AOScaledData data(bufferDepth);
      for(int i=0; i<bufferDepth; i++)
        data[i] = channel4Waveform[i]; 
      // put the waveform in the configuration
      config.set_channel_periodic_data(4, data);
      //cpy data in the attribute of the device
      ::memcpy(ch4, data.base(), data.size());
    }
  }
  //- active/config. channel 5
  if(channel5Enable)
  {
    ac.id = 5;
    if(aORefSource == adl::external_reference)
      ac.volt_ref = aORefB;
    config.add_active_channel(ac);
  
    if(channel5Waveform.empty())
    {
      WARN_STREAM<<"No waveform is saved in database for channel 5, using a default one"<<endl;
      config.set_channel_periodic_data(5, default_waveformB);
    }
    else if(channel5Waveform.size() != bufferDepth)
    {
      WARN_STREAM<<"The waveform saved in database for channel 5 has a different size from property BufferDepth, "<<
        "using default waveform"<<endl;
      config.set_channel_periodic_data(5, default_waveformB);
    }
    else //put waveform of the Tango database in ch5
    {
      // copy the input data in a buffer of type asl::AOScaledData
      asl::AOScaledData data(bufferDepth);
      for(int i=0; i<bufferDepth; i++)
        data[i] = channel5Waveform[i]; 
      // put the waveform in the configuration
      config.set_channel_periodic_data(5, data);
      //cpy data in the attribute of the device
      ::memcpy(ch5, data.base(), data.size());
    }
  }
  //- active/config. channel 6
  if(channel6Enable)
  {
    ac.id = 6;
    if(aORefSource == adl::external_reference)
      ac.volt_ref = aORefB;
    config.add_active_channel(ac);
    
    if(channel6Waveform.empty())
    {
      WARN_STREAM<<"No waveform is saved in database for channel 6, using a default one"<<endl;
      config.set_channel_periodic_data(6, default_waveformB);
    }
    else if(channel6Waveform.size() != bufferDepth)
    {
      WARN_STREAM<<"The waveform saved in database for channel 6 has a different size from property BufferDepth, "<<
        "using default waveform"<<endl;
      config.set_channel_periodic_data(6, default_waveformB);
    }
    else //put waveform of the Tango database in ch6
    {
      // copy the input data in a buffer of type asl::AOScaledData
      asl::AOScaledData data(bufferDepth);
      for(int i=0; i<bufferDepth; i++)
        data[i] = channel6Waveform[i]; 
      // put the waveform in the configuration
      config.set_channel_periodic_data(6, data);
      //cpy data in the attribute of the device
      ::memcpy(ch6, data.base(), data.size());
    }
  }
  //- active/config. channel 7
  if(channel7Enable)
  {
    ac.id = 7;
    if(aORefSource == adl::external_reference)
      ac.volt_ref = aORefB;
    config.add_active_channel(ac);
    
    if(channel7Waveform.empty())
    {
      WARN_STREAM<<"No waveform is saved in database for channel 7, using a default one"<<endl;
      config.set_channel_periodic_data(7, default_waveformB);
    }
    else if(channel7Waveform.size() != bufferDepth)
    {
      WARN_STREAM<<"The waveform saved in database for channel 7 has a different size from property BufferDepth, "<<
        "using default waveform"<<endl;
      config.set_channel_periodic_data(7, default_waveformB);
    }
    else //put waveform of the Tango database in ch7
    {
      // copy the input data in a buffer of type asl::AOScaledData
      asl::AOScaledData data(bufferDepth);
      for(int i=0; i<bufferDepth; i++)
        data[i] = channel7Waveform[i]; 
      // put the waveform in the configuration
      config.set_channel_periodic_data(7, data);
      //cpy data in the attribute of the device
      ::memcpy(ch7, data.base(), data.size());
    }
  }
  //--------------------------------start trigger config---------------------------------
  if(startTrigger)
  {
    config.set_trigger_source((adl::AIOTriggerSource)startTriggerSource);
    config.set_trigger_mode(adl::ao_post);
    if(startTriggerSource == adl::external_digital)
    {
      config.set_trigger_polarity((adl::AOTriggerPolarity)dTRIGPolarity);
    }
    else if(startTriggerSource == adl::external_analog)
    {
      config.set_analog_trigger_source(adl::analog_trigger_ext);
      config.set_analog_trigger_condition((adl::AnalogTriggerCondition)aTRIGSelection);
      unsigned short level;
      if(aTRIGLevel>=0)
        level = (aTRIGLevel / 0.078125) + 127;
      else // v < 0
        level = (-aTRIGLevel / 0.078125);
      //the voltage is converted in digital value (8 bits of resolution on EXTATRIG with +/-10 V (256/20 = 0.078125))
      config.set_analog_low_level_condition(level);
      config.set_analog_high_level_condition(level);
    }
  }  
  //--------------------------------stop trigger config---------------------------------
  if(stopTrigger)
  {
    config.set_stop_mode(adl::wait_end_waveform);
    config.set_stop_source ((adl::StopSource)stopTriggerSource);
  }
  
  config.set_output_rate(frequency);
  
  DEBUG_STREAM<<"ContinuousAO::init_device : init acq"<<std::endl;
  try{
	ao->init(adl::DAQ2502, boardNum);
	
	DEBUG_STREAM<<"ContinuousAO::init_device : config acq"<<std::endl;
	try{
		ao->configure(config);	 
	}
	catch (...)
	{
	  on_fault("ContinuousAO::init_device\nError while configuring driver");
	  return;
	}
  }
  catch (...)
  {
	on_fault("ContinuousAO::init_device\nError while initializing the driver");
	return;
  }

  //ao->configure(config);	
}


//+----------------------------------------------------------------------------
//
// method :		ContinuousAO::readDeviceProperies()
// 
// description :	Read the device properties from database.
//
//-----------------------------------------------------------------------------
void ContinuousAO::get_device_property()
{
  //	Initialize your default values here.
  //------------------------------------------
  boardNum =  0;
  frequency = 50000.0; //50 kHz
  
  startTrigger = 0; //no start trigger
  stopTrigger = 0;  //no stop trigger
  
  string default_start_source = "DTRIG";
  startTriggerSource = adl::external_digital;
  
  string default_stop_source = "AFI1";
  stopTriggerSource = adl::afi1_termination;
  
  string default_atrig_select = "BELOW";
  aTRIGSelection = adl::below_low_level;
  
  aTRIGLevel = 5.0;
  
  string default_dtrig_pol = "RISING";
  dTRIGPolarity = adl::ao_rising_edge ;
  
  aORefA = 10.0;
  aORefB = 10.0;
  
  string default_pol = "BP";
  polarity = adl::bipolar;   
  
  string default_aoref = "INTERN";
  aORefSource = adl::internal_reference;

  channel0Enable = 1;
  channel1Enable = 0;
  channel2Enable = 0;
  channel3Enable = 0;
  channel4Enable = 0;
  channel5Enable = 0;
  channel6Enable = 0;
  channel7Enable = 0;

  bufferDepth = 4096;
  
  //	Read device properties from database.(Automatic code generation)
  //-------------------------------------------------------------
	Tango::DbData	data;
	data.push_back(Tango::DbDatum("BoardNum"));
	data.push_back(Tango::DbDatum("Frequency"));
	data.push_back(Tango::DbDatum("StartTrigger"));
	data.push_back(Tango::DbDatum("StopTrigger"));
	data.push_back(Tango::DbDatum("StartTriggerSource"));
	data.push_back(Tango::DbDatum("StopTriggerSource"));
	data.push_back(Tango::DbDatum("ATRIGSelection"));
	data.push_back(Tango::DbDatum("ATRIGLevel"));
	data.push_back(Tango::DbDatum("DTRIGPolarity"));
	data.push_back(Tango::DbDatum("AORefA"));
	data.push_back(Tango::DbDatum("AORefB"));
	data.push_back(Tango::DbDatum("Polarity"));
	data.push_back(Tango::DbDatum("AORefSource"));
	data.push_back(Tango::DbDatum("Channel0Enable"));
	data.push_back(Tango::DbDatum("Channel1Enable"));
	data.push_back(Tango::DbDatum("Channel2Enable"));
	data.push_back(Tango::DbDatum("Channel3Enable"));
	data.push_back(Tango::DbDatum("Channel4Enable"));
	data.push_back(Tango::DbDatum("Channel5Enable"));
	data.push_back(Tango::DbDatum("Channel6Enable"));
	data.push_back(Tango::DbDatum("Channel7Enable"));
	data.push_back(Tango::DbDatum("BufferDepth"));
	data.push_back(Tango::DbDatum("Channel0Waveform"));
	data.push_back(Tango::DbDatum("Channel1Waveform"));
	data.push_back(Tango::DbDatum("Channel2Waveform"));
	data.push_back(Tango::DbDatum("Channel3Waveform"));
	data.push_back(Tango::DbDatum("Channel4Waveform"));
	data.push_back(Tango::DbDatum("Channel5Waveform"));
	data.push_back(Tango::DbDatum("Channel6Waveform"));
	data.push_back(Tango::DbDatum("Channel7Waveform"));

	//	Call database and extract values
	//--------------------------------------------
	get_db_device()->get_property(data);
	if (data[0].is_empty()==false)	data[0]  >>  boardNum;
	if (data[1].is_empty()==false)	data[1]  >>  frequency;
	if (data[2].is_empty()==false)	data[2]  >>  startTrigger;
	if (data[3].is_empty()==false)	data[3]  >>  stopTrigger;
	if (data[4].is_empty()==false)	data[4]  >>  startTriggerSource;
	if (data[5].is_empty()==false)	data[5]  >>  stopTriggerSource;
	if (data[6].is_empty()==false)	data[6]  >>  aTRIGSelection;
	if (data[7].is_empty()==false)	data[7]  >>  aTRIGLevel;
	if (data[8].is_empty()==false)	data[8]  >>  dTRIGPolarity;
	if (data[9].is_empty()==false)	data[9]  >>  aORefA;
	if (data[10].is_empty()==false)	data[10]  >>  aORefB;
	if (data[11].is_empty()==false)	data[11]  >>  polarity;
	if (data[12].is_empty()==false)	data[12]  >>  aORefSource;
	if (data[13].is_empty()==false)	data[13]  >>  channel0Enable;
	if (data[14].is_empty()==false)	data[14]  >>  channel1Enable;
	if (data[15].is_empty()==false)	data[15]  >>  channel2Enable;
	if (data[16].is_empty()==false)	data[16]  >>  channel3Enable;
	if (data[17].is_empty()==false)	data[17]  >>  channel4Enable;
	if (data[18].is_empty()==false)	data[18]  >>  channel5Enable;
	if (data[19].is_empty()==false)	data[19]  >>  channel6Enable;
	if (data[20].is_empty()==false)	data[20]  >>  channel7Enable;
	if (data[21].is_empty()==false)	data[21]  >>  bufferDepth;
	if (data[22].is_empty()==false)	data[22]  >>  channel0Waveform;
	if (data[23].is_empty()==false)	data[23]  >>  channel1Waveform;
	if (data[24].is_empty()==false)	data[24]  >>  channel2Waveform;
	if (data[25].is_empty()==false)	data[25]  >>  channel3Waveform;
	if (data[26].is_empty()==false)	data[26]  >>  channel4Waveform;
	if (data[27].is_empty()==false)	data[27]  >>  channel5Waveform;
	if (data[28].is_empty()==false)	data[28]  >>  channel6Waveform;
	if (data[29].is_empty()==false)	data[29]  >>  channel7Waveform;


  //	End of Automatic code generation
  //-------------------------------------------------------------
  Tango::DbData data_put;
  //-------------------------------------------------------------
  if (data[0].is_empty()==false)
  {
    unsigned short bnum;
    data[0]  >>  bnum;
    //check value
    if(bnum<0 || bnum>= 7)//num max of boards in chassis
    {
      WARN_STREAM<<"ContinuousAO::get_device_property: the value of BoardNum is invalid"
        <<"using default value "<<boardNum<<endl;
    }
    else
    {
      boardNum = bnum;
    }
  }
  else
  {
    Tango::DbDatum  property("BoardNum");
    property << boardNum;
    data_put.push_back(property);
    WARN_STREAM<<"BoardNum property is not set in database, loading default value in database:"
      <<boardNum<<endl;
  }
  //-------------------------------------------------------------
  if (data[1].is_empty()==false)
  {
    data[1]  >>  frequency;   
  }
  else
  {
    Tango::DbDatum  property("Frequency");
    property << frequency;
    data_put.push_back(property);
    WARN_STREAM<<"Frequency property is not set in database, loading default value in database:"
      <<frequency<<endl;
  }
  //-------------------------------------------------------------
  if (data[2].is_empty()==false)
  {
    data[2]  >>  startTrigger;	 
  }
  else
  {
    Tango::DbDatum  property("StartTrigger");
    property << startTrigger;
    data_put.push_back(property);
    WARN_STREAM<<"StartTrigger property is not set in database, loading default value in database:"
      <<startTrigger<<endl;
  }
  //-------------------------------------------------------------
  if (data[3].is_empty()==false)
  {
    data[3]  >>  stopTrigger; 
  }
  else
  {
    Tango::DbDatum  property("StopTrigger");
    property << stopTrigger;
    data_put.push_back(property);
    WARN_STREAM<<"StopTrigger property is not set in database, loading default value in database:"
      <<stopTrigger<<endl;
  }
  //-------------------------------------------------------------
  if (data[4].is_empty()==false)
  {
    data[4]  >>  startTriggerSource;
    string start_source;
    data[4]  >>  start_source;
    if(start_source == "DTRIG")
      startTriggerSource = adl::external_digital;
    else if(start_source == "ATRIG")
      startTriggerSource = adl::external_analog;
    else
      WARN_STREAM<<"ContinuousAO::get_device_property: the value of StartTriggerSource is not valid"
      <<"using default value "<<default_start_source<<endl;
  }
  else
  {
    Tango::DbDatum  property("StartTriggerSource");
    property << default_start_source;
    data_put.push_back(property);
    WARN_STREAM<<"StartTriggerSource property is not set in database, loading default value in database:"
      <<default_start_source<<endl;
  }
  //-------------------------------------------------------------
  if (data[5].is_empty()==false)
  {
    string stop_source; 
    data[5]  >>  stop_source;
    if(stop_source == "ATRIG")
      stopTriggerSource = adl::analog_trigger_termination;
    else if(stop_source == "AFI0")
      stopTriggerSource = adl::afi0_termination;
    else if(stop_source == "AFI1")
      stopTriggerSource = adl::afi1_termination;
    else
      WARN_STREAM<<"ContinuousAO::get_device_property: the value of StopTriggerSource is not valid"
      <<"using default value "<<default_stop_source<<endl;
  }
  else
  {
    Tango::DbDatum  property("StopTriggerSource");
    property << default_stop_source;
    data_put.push_back(property);
    WARN_STREAM<<"StopTriggerSource property is not set in database, loading default value in database:"
      <<default_stop_source<<endl;
  }
  //-------------------------------------------------------------
  if (data[6].is_empty()==false)
  {
    string atrig_select;
    data[6]  >>  atrig_select;
    if(atrig_select == "BELOW")
      aTRIGSelection = adl::below_low_level;
    else if(atrig_select == "ABOVE")
      aTRIGSelection = adl::above_high_level;
    else
      WARN_STREAM<<"ContinuousAO::get_device_property: the value of ATRIGSelection is not valid"
      <<"using default value "<<default_atrig_select<<endl;
  }
  else
  {
    Tango::DbDatum  property("ATRIGSelection");
    property << default_atrig_select;
    data_put.push_back(property);
    WARN_STREAM<<"ATRIGSelection property is not set in database, loading default value in database:"
      <<default_atrig_select<<endl;
  }
  //-------------------------------------------------------------
  if (data[7].is_empty()==false)
  {
    data[7]  >>  aTRIGLevel;
  }
  else
  {
    Tango::DbDatum  property("ATRIGLevel");
    property << aTRIGLevel;
    data_put.push_back(property);
    WARN_STREAM<<"ATRIGLevel property is not set in database, loading default value in database:"
      <<aTRIGLevel<<endl;
  }
  //-------------------------------------------------------------
  if (data[8].is_empty()==false)
  {
    string dtrig_pol;
    data[8]  >>  dtrig_pol;
    if(dtrig_pol == "RISING")
      dTRIGPolarity = adl::ao_rising_edge;
    else if(dtrig_pol == "FALLING")
      dTRIGPolarity = adl::ao_falling_edge;
    else
      WARN_STREAM<<"ContinuousAO::get_device_property: the value of DTRIGPolarity is not valid"
      <<"using default value "<<default_dtrig_pol<<endl;
  }
  else
  {
    Tango::DbDatum  property("DTRIGPolarity");
    property << default_dtrig_pol;
    data_put.push_back(property);
    WARN_STREAM<<"DTRIGPolarity property is not set in database, loading default value in database:"
      <<default_dtrig_pol<<endl;
  }
  //-------------------------------------------------------------
  if (data[9].is_empty()==false)
  {
    double ref;
    data[9]  >>  ref;
    if(ref >= -10.0 || ref <= 10.0)
      aORefA = ref;
    else
      WARN_STREAM<<"ContinuousAO::get_device_property: the value of AORefA is not valid"
      <<"using default value "<<aORefA<<endl;
  }
  else
  {
    Tango::DbDatum  property("AORefA");
    property << aORefA;
    data_put.push_back(property);
    WARN_STREAM<<"AORefA property is not set in database, loading default value in database:"
      <<aORefA<<endl;
  }
  //-------------------------------------------------------------
  if (data[10].is_empty()==false)
  {
    double ref;
    data[9]  >>  ref;
    if(ref >= -10.0 || ref <= 10.0)
      aORefB = ref;
    else
      WARN_STREAM<<"ContinuousAO::get_device_property: the value of AORefB is not valid"
      <<"using default value "<<aORefB<<endl;
  }
  else
  {
    Tango::DbDatum  property("AORefB");
    property << aORefB;
    data_put.push_back(property);
    WARN_STREAM<<"AORefB property is not set in database, loading default value in database:"
      <<aORefB<<endl;
  }
  //-------------------------------------------------------------
  if (data[11].is_empty()==false)
  {
    string pol;
    data[11]  >>  pol;
    if(pol == "BP")
      polarity = adl::bipolar;
    else if(pol == "UP")
      polarity = adl::unipolar;
    else
      WARN_STREAM<<"ContinuousAO::get_device_property: the value of Polarity is not valid"
      <<"using default value "<<default_pol<<endl;
  }
  else
  {
    Tango::DbDatum  property("Polarity");
    property << default_pol;
    data_put.push_back(property);
    WARN_STREAM<<"Polarity property is not set in database, loading default value in database:"
      <<default_pol<<endl;
  }
  //-------------------------------------------------------------
  if (data[12].is_empty()==false)	
  {
    string aoref;
    data[12]  >>  aoref;
    if(aoref == "INTERN")
      aORefSource = adl::internal_reference;
    else if(aoref == "EXTERN")
      aORefSource = adl::external_reference;
    else
      WARN_STREAM<<"ContinuousAO::get_device_property: the value of AORefSource is not valid"
      <<"using default value "<<default_aoref<<endl;
  }
  else
  {
    Tango::DbDatum  property("AORefSource");
    property << default_aoref;
    data_put.push_back(property);
    WARN_STREAM<<"AORefSource property is not set in database, loading default value in database:"
      <<default_aoref<<endl;
  }
  //-------------------------------------------------------------
  if (data[13].is_empty()==false)
  {
    data[13]  >>  channel0Enable;
  }
  else
  {
    Tango::DbDatum  property("Channel0Enable");
    property << channel0Enable;
    data_put.push_back(property);
    WARN_STREAM<<"Channel0Enable property is not set in database, loading default value in database:"
      <<channel0Enable<<endl;
  }
  //-------------------------------------------------------------
  if (data[14].is_empty()==false)
  {
    data[14]  >>  channel1Enable;
  }
  else
  {
    Tango::DbDatum  property("Channel1Enable");
    property << channel1Enable;
    data_put.push_back(property);
    WARN_STREAM<<"Channel1Enable property is not set in database, loading default value in database:"
      <<channel1Enable<<endl;
  }
  //-------------------------------------------------------------
  if (data[15].is_empty()==false)
  {
    data[15]  >>  channel2Enable;
  }
  else
  {
    Tango::DbDatum  property("Channel2Enable");
    property << channel2Enable;
    data_put.push_back(property);
    WARN_STREAM<<"Channel2Enable property is not set in database, loading default value in database:"
      <<channel2Enable<<endl;
  }
  //-------------------------------------------------------------
  if (data[16].is_empty()==false)
  {
    data[16]  >>  channel3Enable;
  }
  else
  {
    Tango::DbDatum  property("Channel3Enable");
    property << channel3Enable;
    data_put.push_back(property);
    WARN_STREAM<<"Channel3Enable property is not set in database, loading default value in database:"
      <<channel3Enable<<endl;
  }
  //-------------------------------------------------------------
  if (data[17].is_empty()==false)
  {
    data[17]  >>  channel4Enable;
  }
  else
  {
    Tango::DbDatum  property("Channel4Enable");
    property << channel4Enable;
    data_put.push_back(property);
    WARN_STREAM<<"Channel4Enable property is not set in database, loading default value in database:"
      <<channel4Enable<<endl;
  }
  //-------------------------------------------------------------
  if (data[18].is_empty()==false)
  {
    data[18]  >>  channel5Enable;
  }
  else
  {
    Tango::DbDatum  property("Channel5Enable");
    property << channel5Enable;
    data_put.push_back(property);
    WARN_STREAM<<"Channel5Enable property is not set in database, loading default value in database:"
      <<channel5Enable<<endl;
  }
  //-------------------------------------------------------------
  if (data[19].is_empty()==false)
  {
    data[19]  >>  channel6Enable;
  }
  else
  {
    Tango::DbDatum  property("Channel6Enable");
    property << channel6Enable;
    data_put.push_back(property);
    WARN_STREAM<<"Channel6Enable property is not set in database, loading default value in database:"
      <<channel6Enable<<endl;
  }
  //-------------------------------------------------------------
  if (data[20].is_empty()==false)
  {
    data[20]  >>  channel7Enable;
  }
  else
  {
    Tango::DbDatum  property("Channel7Enable");
    property << channel7Enable;
    data_put.push_back(property);
    WARN_STREAM<<"Channel7Enable property is not set in database, loading default value in database:"
      <<channel7Enable<<endl;
  }
  //-------------------------------------------------------------
  if (data[21].is_empty()==false)
  {
    data[21]  >>  bufferDepth;
  }
  else
  {
    Tango::DbDatum  property("BufferDepth");
    property << bufferDepth;
    data_put.push_back(property);
    WARN_STREAM<<"BufferDepth property is not set in database, loading default value in database:"
      <<bufferDepth<<endl;
  }
  //update database for not initiliazed properties
  get_db_device()->put_property(data_put);
}
//+----------------------------------------------------------------------------
//
// method :		ContinuousAO::always_executed_hook()
// 
// description :	method always executed before any command is executed
//
//-----------------------------------------------------------------------------
void ContinuousAO::always_executed_hook()
{
	set_internal_state();
}

//+----------------------------------------------------------------------------
//
// method :		ContinuousAO::read_attr_hardware()
// 
// description :	Hardware acquisition for attributes.
//
//-----------------------------------------------------------------------------
void ContinuousAO::read_attr_hardware(vector<long> &attr_list)
{
	DEBUG_STREAM << "In read_attr_hardware for " << attr_list.size();
	DEBUG_STREAM << " attribute(s)" << endl;
	
	//	Add your own code here
	//---------------------------------
  ao->lock_data();

  err_ctr = ao->err_ctr;
  
  ao->unlock_data();
 
}

//+----------------------------------------------------------------------------
//
// method :		ContinuousAO::read_attr()
// 
// description :	Extract real attribute values from
//					hardware acquisition result.
//
//-----------------------------------------------------------------------------
void ContinuousAO::read_attr(Tango::Attribute &attr)
{
	string &attr_name = attr.get_name();

	DEBUG_STREAM << "In read_attr for attribute " << attr_name << endl;

  //	Switch on attribute name
  //---------------------------------
  if (attr_name == "channel0")
  {
    if(channel0Enable)
      attr.set_value(ch0, bufferDepth);
    else 
      attr.set_quality(Tango::ATTR_INVALID);
  }
  else if (attr_name == "channel1")
  {
    if(channel1Enable)
      attr.set_value(ch1, bufferDepth);
    else 
      attr.set_quality(Tango::ATTR_INVALID);
  }
  else if (attr_name == "channel2")
  {
    if(channel2Enable)
      attr.set_value(ch2, bufferDepth);
    else 
      attr.set_quality(Tango::ATTR_INVALID);
  }
  else if (attr_name == "channel3")
  {
    if(channel3Enable)
      attr.set_value(ch3, bufferDepth);
    else 
      attr.set_quality(Tango::ATTR_INVALID);
  }
  else if (attr_name == "channel4")
  {
    if(channel4Enable)
      attr.set_value(ch4, bufferDepth);
    else 
      attr.set_quality(Tango::ATTR_INVALID);
  }
  else if (attr_name == "channel5")
  {
    if(channel5Enable)
      attr.set_value(ch5, bufferDepth);
    else 
      attr.set_quality(Tango::ATTR_INVALID);
  }
  else if (attr_name == "channel6")
  {
    if(channel6Enable)
      attr.set_value(ch6, bufferDepth);
    else 
      attr.set_quality(Tango::ATTR_INVALID);
  }
  else if (attr_name == "channel7")
  { 
    if(channel7Enable)
      attr.set_value(ch7, bufferDepth);
    else 
      attr.set_quality(Tango::ATTR_INVALID);
  }
  else if (attr_name == "errorCounter")
  {
    attr.set_value(&err_ctr);
  }
	else if (attr_name == "useBoardFifo")
	{
    // the information about data loading on fifo in available only after Start command.
    if(get_state() == Tango::RUNNING)
      attr.set_value(&use_fifo);
    else
      attr.set_quality(Tango::ATTR_INVALID);
	}
	else
	if (attr_name == "channel0Enable")
	{
		attr.set_value(&channel0Enable);
	}
	else
	if (attr_name == "channel1Enable")
	{
		attr.set_value(&channel1Enable);
	}
	else
	if (attr_name == "channel2Enable")
	{
		attr.set_value(&channel2Enable);
	}
	else
	if (attr_name == "channel3Enable")
	{
		attr.set_value(&channel3Enable);
	}
	else
	if (attr_name == "channel4Enable")
	{
		attr.set_value(&channel4Enable);
	}
	else
	if (attr_name == "channel5Enable")
	{
		attr.set_value(&channel5Enable);
	}
	else
	if (attr_name == "channel6Enable")
	{
		attr.set_value(&channel6Enable);
	}
	else
	if (attr_name == "channel7Enable")
	{
		attr.set_value(&channel7Enable);
	}
}

//+------------------------------------------------------------------
/**
 *	method:	ContinuousAO::start
 *
 *	description:	method to execute "Start"
 *	start the generation.
 *
 *
 */
//+------------------------------------------------------------------
void ContinuousAO::start()
{
  DEBUG_STREAM << "ContinuousAO::start(): entering... !" << endl;
  
  ao->lock_data();

  ao->err_ctr = 0;
  
  ao->unlock_data();

  _ASL_TRY_ACTION
    (
    ao->start(),
    "start", 
    "ContinuousAO::start",
    set_internal_state()
    );
  
  // get if the output data have been loaded in the onboard FIFO.
  // depends on the size of the buffer.
  use_fifo = ao->use_board_fifo();
  
}

//+------------------------------------------------------------------
/**
 *	method:	ContinuousAO::stop
 *
 *	description:	method to execute "Stop"
 *	stop the generation.
 *
 *
 */
//+------------------------------------------------------------------
void ContinuousAO::stop()
{
	DEBUG_STREAM << "ContinuousAO::stop(): entering... !" << endl;

	_ASL_TRY_ACTION
    (
    ao->stop(),
    "stop", 
    "ContinuousAO::stop",
    set_internal_state()
    );

}

//+------------------------------------------------------------------
/**
 *	method:	ContinuousAO::set_aoscaled_data
 *
 *	description:	method to execute "SetAOScaledData"
 *	Give one period of the signal to generated of a specified channel in volts.
 *
 * @param	argin	The channel number ,in string).  The output data in volts ,in double)
 *
 */
//+------------------------------------------------------------------
void ContinuousAO::set_aoscaled_data(const Tango::DevVarDoubleStringArray *argin)
{
  DEBUG_STREAM << "ContinuousAO::set_aoscaled_data(): entering... !" << endl;
  
  if((*argin).svalue.length() != 1)
  {
    Tango::Except::throw_exception(
      (const char*)("OPERATION_NOT_ALLOWED"),
      (const char*)("The size of the string argument must be 1"),
      (const char*)("ContinuousAO::set_aoscaled_data")
      );
  }
  Tango::DevVarStringArray chan_dvsa = (*argin).svalue;
  string chan_s = chan_dvsa[0];
  char chan = chan_s[0];
  if(chan < '0' || chan > '7')
  {
    Tango::Except::throw_exception(
      (const char*)("OPERATION_NOT_ALLOWED"),
      (const char*)("The string argument must be between 0 and 7"),
      (const char*)("ContinuousAO::set_aoscaled_data")
      );
  }
  if((*argin).dvalue.length() != bufferDepth)
  {
    Tango::Except::throw_exception(
      (const char*)("OPERATION_NOT_ALLOWED"),
      (const char*)("The depth of the given buffer must be the same as specified in Device Properties"),
      (const char*)("ContinuousAO::set_aoscaled_data")
      );
  }
  
  // stop the current generation
  _ASL_TRY_ACTION
    (
    ao->stop(),
    "stop", 
    "ContinuousAO::set_aoscaled_data",
    set_internal_state()
    );
  
  // get the configuration
  asl::ContinuousAOConfig config = ao->configuration();
  
  // copy the input data in a buffer of type asl::AOScaledData
  asl::AOScaledData data(bufferDepth);
  ::memcpy(data.base(), (*argin).dvalue.get_buffer(), ((*argin).dvalue.length())*sizeof(double));
  
  //NB: if a chan hasn't been enable with properties, 'ao' will do nothing
  config.set_channel_periodic_data(chan - '0', data);
  
  // copy the new data in the attributes of the device.
  switch(chan)
  {
  case '0':
    ::memcpy(ch0, data.base(), data.size());
    //save the waveform in the database
    save_waveform(ch0, "Channel0Waveform");
    break;
  case '1':
    ::memcpy(ch1, data.base(), data.size());
    //save the waveform in the database
    save_waveform(ch1, "Channel1Waveform");
    break;
  case '2':
    ::memcpy(ch2, data.base(), data.size());
    //save the waveform in the database
    save_waveform(ch2, "Channel2Waveform");
    break;
  case '3':
    ::memcpy(ch3, data.base(), data.size());
    //save the waveform in the database
    save_waveform(ch3, "Channel3Waveform");
    break;
  case '4':
    ::memcpy(ch4, data.base(), data.size());
    //save the waveform in the database
    save_waveform(ch4, "Channel4Waveform");
    break;
  case '5':
    ::memcpy(ch5, data.base(), data.size());
    //save the waveform in the database
    save_waveform(ch5, "Channel5Waveform");
    break;
  case '6':
    ::memcpy(ch6, data.base(), data.size());
    //save the waveform in the database
    save_waveform(ch6, "Channel6Waveform");
    break;
  case '7':
    ::memcpy(ch7, data.base(), data.size());
    //save the waveform in the database
    save_waveform(ch7, "Channel7Waveform");
    break;
  default:
    Tango::Except::throw_exception(
      (const char*)("OPERATION_NOT_ALLOWED"),
      (const char*)("The string argument must be between 0 and 7"),
      (const char*)("ContinuousAO::set_aoscaled_data")
      );
    break;
  }
  
  // give the configuration with a new channel
  _ASL_TRY_ACTION
    (
    ao->configure(config),
    "configure", 
    "ContinuousAO::set_aoscaled_data",
    set_internal_state()
    );

}
//+------------------------------------------------------------------
/**
*	method: ContinuousAO::set_internal_state
*/
//+------------------------------------------------------------------
void  ContinuousAO::set_internal_state(void)
{
  if(ao == 0)
  {
    set_state(Tango::UNKNOWN);
    set_status("The acquisition was not initialized properly");
  }
  else
  {
    switch(ao->state())
    {
    case asl::ContinuousAO::STANDBY:
      set_state(Tango::STANDBY);
      set_status("The generation is stopped");
      break;
    case asl::ContinuousAO::RUNNING:
    case asl::ContinuousAO::ABORTING:
      set_state(Tango::RUNNING);
      set_status("The generation is running");
      break;
    case asl::ContinuousAO::FAULT:
      set_state(Tango::FAULT);
	  set_status(m_error_message);
      break;
    case asl::ContinuousAO::UNKNOWN:    
    default:
      set_state(Tango::UNKNOWN);
      set_status("The generation is in an unknown state");
      break;
    }
  }
}
//+------------------------------------------------------------------
/**
*	method: ContinuousAO::save_waveform
* Save a waveform in tango database
*/
//+------------------------------------------------------------------
void ContinuousAO::save_waveform(double* waveform, string wfm_channel)
{
  // cpy the waveform in a double vector 
  vector<double> vec;
  for(int i=0; i<bufferDepth; i++)
    vec.push_back(waveform[i]);

  //put the vector in a DBDatum
  Tango::DbDatum dbdatum(wfm_channel);
  dbdatum << vec;

  // put it in a DbData
  Tango::DbData db_data;
  db_data.push_back(dbdatum);
  
  get_db_device()->get_dbase()->set_timeout_millis(30000);

  // put the waveform in the database 
  _DEV_TRY
    (	  
    get_db_device()->put_property(db_data),
    "put_property",
    "ContinuousAO::save_waveform",
    );
}

void ContinuousAO::on_fault(std::string p_error_message)
{
   m_error_message = p_error_message;
   set_state(Tango::FAULT);
}
}	//	namespace