Skip to content
Snippets Groups Projects
Keithley_6517.cpp 21.5 KiB
Newer Older
ELATTAOUI's avatar
ELATTAOUI committed
// ============================================================================
//
// = CONTEXT
//    TANGO Project - SCPI KeithleyElectrometer Support Library
//
// = FILENAME
//    Keithley_6517.cpp
//
// = AUTHOR
//    X. Elattaoui
//
// ============================================================================

// ============================================================================
// DEPENDENCIES
// ============================================================================
#include <iostream>
#include <sstream>
#include <string>
ELATTAOUI's avatar
ELATTAOUI committed
#include <math.h>   //- for ceil
#include <helpers/XString.h>
ELATTAOUI's avatar
ELATTAOUI committed
#include "Keithley_6517.h"
#include "KeithleySCPIProtocol.h"
/*
* Valid Range values for a K_6517
*/
static const std::string K6517_AMP_rangeStr[] = {"2E-11","2E-10","2E-9","2E-8","2E-7","2E-6","2E-5","2E-4","2E-3","2E-2"};
static const std::string K6517_VOLT_rangeStr[]= {"2","20","200"};
static const std::string K6517_OHM_rangeStr[] = {"2E14","2E13","2E12","2E11","2E10","2E9","2E8","2E7","2E6","2E5"};
static const std::string K6517_COU_rangeStr[] = {"2E-9","2E-8","2E-7","2E-6"};
/*
* Max Index Range value for a K_6517
*/
ELATTAOUI's avatar
ELATTAOUI committed
static const short K6517_AMP_rangeLimit = 10;
static const short K6517_VOLT_rangeLimit= 3;
static const short K6517_OHM_rangeLimit = 10;
static const short K6517_COU_rangeLimit = 4;
ELATTAOUI's avatar
ELATTAOUI committed

static const unsigned short MAX_SAVED_CONFIG = 9;

ELATTAOUI's avatar
ELATTAOUI committed
// ============================================================================
// Keithley_6517::Keithley_6517
// ============================================================================
Keithley_6517::Keithley_6517 (std::string& comLink_device_name):
AbstractElectrometerClass(comLink_device_name),
BUTEAU's avatar
BUTEAU committed
_kmode(""), _numPLC(0)
ELATTAOUI's avatar
ELATTAOUI committed
{
	std::cout << "Keithley_6517::Keithley_6517 <-" << std::endl;

	std::cout << "Keithley_6517::Keithley_6517 ->" << std::endl;
}

// ============================================================================
// Keithley_6517::~Keithley_6517
// ============================================================================
Keithley_6517::~Keithley_6517 (void)
{
	std::cout << "Keithley_6517::~Keithley_6517 <-" << std::endl;

	std::cout << "Keithley_6517::~Keithley_6517 ->" << std::endl;
}

ELATTAOUI's avatar
ELATTAOUI committed
// ============================================================================
// Keithley_6517::init_protocol
// ============================================================================
bool Keithley_6517::init_protocol (void)
{
  std::string description("");
  bool success = false;

  try
  {
	  //- build the keithley Electrometer protocol obj
	  _electrometerProtocol = new KeithleySCPIProtocol(_device_proxy_name);

    if (_electrometerProtocol)
    {
	    //- this model supports different mode (OhmMeter, VoltMeter and so on )
	    KeithleySCPIProtocol* _kscpi = dynamic_cast<KeithleySCPIProtocol*>(_electrometerProtocol);
	    if(_kscpi)
		    _kscpi->set_isDiffSuportedMode(true);

      success = _electrometerProtocol->build_communicationLink();
    }
  }
  catch(Tango::DevFailed& df)
  {
		description = "FAILED to create proxy on : " + _device_proxy_name;
		
		Tango::Except::re_throw_exception (df,
			(const char*)"COMMUNICATION_ERROR",
			description.c_str(),
			(const char*)"Keithley_6517::init_protocol");
  }
  catch(...)
  {
		description = "FAILED to create proxy on : " + _device_proxy_name + ". Caught [...].";
		
		Tango::Except::throw_exception (
			(const char*)"COMMUNICATION_ERROR",
			description.c_str(),
			(const char*)"Keithley_6517::init_protocol");
  }

  return success;
}
ELATTAOUI's avatar
ELATTAOUI committed

// ============================================================================
// Keithley_6517::range_up
// ============================================================================
void Keithley_6517::range_up (void) 
{

std::stringstream cmd_to_send;

	//- update range value from hardware
ELATTAOUI's avatar
ELATTAOUI committed
	this->get_ElectroMeterRange( );
ELATTAOUI's avatar
ELATTAOUI committed

	_range += 1;

	//- check range validity
	if(_kmode.find("CURR") != std::string::npos)
	{
		if(_range > K6517_AMP_rangeLimit)
		{
			_range = K6517_AMP_rangeLimit;
			throw electrometer::ElectrometerException("OUT_OF_RANGE", 
													"Range up limit reached.",
													"Keithley_6517::range_up( ).");
		}
		_rangeStr = K6517_AMP_rangeStr[_range];
	}
	else
	if (_kmode.find("VOLT") != std::string::npos)
	{
		if(_range > K6517_VOLT_rangeLimit)
		{
			_range = K6517_VOLT_rangeLimit;
			throw electrometer::ElectrometerException("OUT_OF_RANGE", 
													"Range up limit reached.",
													"Keithley_6517::range_up( ).");
		}
		_rangeStr = K6517_VOLT_rangeStr[_range];
	}
	else 
	if (_kmode.find("RES") != std::string::npos)
	{
		if(_range > K6517_OHM_rangeLimit)
		{
			_range = K6517_OHM_rangeLimit;
			throw electrometer::ElectrometerException("OUT_OF_RANGE", 
													"Range up limit reached.",
													"Keithley_6517::range_up( ).");
		}
		_rangeStr = K6517_OHM_rangeStr[_range];
	}
	else if (_kmode.find("CHAR") != std::string::npos)
	{
		if(_range > K6517_COU_rangeLimit)
		{
			_range = K6517_COU_rangeLimit;
			throw electrometer::ElectrometerException("OUT_OF_RANGE", 
													"Range up limit reached.",
													"Keithley_6517::range_up( ).");
		}
		_rangeStr = K6517_COU_rangeStr[_range];
	}
	else
		throw electrometer::ElectrometerException("UNKNOWN_MODE", 
												"Unable to find the electrometer mode used.",
												"Keithley_6517::range_up( ).");

	//- build and send the command
	cmd_to_send << _rangeStr << std::endl;
	_electrometerProtocol->set_range(cmd_to_send.str());
}

// ============================================================================
// Keithley_6517::range_down
// ============================================================================
void Keithley_6517::range_down (void) 
{

std::stringstream cmd_to_send;

	//- update range value from hardware
ELATTAOUI's avatar
ELATTAOUI committed
	this->get_ElectroMeterRange( );
ELATTAOUI's avatar
ELATTAOUI committed

	_range -= 1;

	if(_range < 0)
	{
		_range = 0;

		throw electrometer::ElectrometerException("OUT_OF_RANGE", 
												"Range down limit reached.",
												"Keithley_6517::range_down( ).");
	}

	//- check range validity
	if(_kmode.find("CURR") != std::string::npos)
		cmd_to_send << K6517_AMP_rangeStr[_range] << std::endl;
	else if (_kmode.find("VOLT") != std::string::npos)
		cmd_to_send << K6517_VOLT_rangeStr[_range] << std::endl;
	else if (_kmode.find("RES") != std::string::npos)
		cmd_to_send << K6517_OHM_rangeStr[_range] << std::endl;
	else if (_kmode.find("CHAR") != std::string::npos)
			cmd_to_send << K6517_COU_rangeStr[_range] << std::endl;
	else
		throw electrometer::ElectrometerException("UNKNOWN_MODE", 
												"Unable to find the electrometer mode used.",
												"Keithley_6517::range_down( ).");


	//- build and send the command
	_electrometerProtocol->set_range(cmd_to_send.str());
}

// ============================================================================
// Keithley_6517::get_integratedValue
// ============================================================================
std::vector<double> Keithley_6517::get_integratedValue (void) 
{
  return 	_electrometerProtocol->get_integratedValue( );
}  

// ============================================================================
// Keithley_6517::get_fetchValue
// ============================================================================
std::vector<double> Keithley_6517::get_fetchValue (void) 
{
  return 	_electrometerProtocol->get_fetchValue( );
}  

// ============================================================================
// Keithley_6517::setAmperMeterMode 
// ============================================================================
void Keithley_6517::setAmperMeterMode (void) 
{
	_electrometerProtocol->setAmperMeterMode( );
}

// ============================================================================
// Keithley_6517::setVoltMeterMode
// ============================================================================
void Keithley_6517::setVoltMeterMode (void) 
{
	_electrometerProtocol->setVoltMeterMode( );
}

// ============================================================================
// Keithley_6517::setOhmMeterMode
// ============================================================================
void Keithley_6517::setOhmMeterMode (void) 
{
	_electrometerProtocol->setOhmMeterMode( );
}

// ============================================================================
// Keithley_6517::setCoulombMeterMode
// ============================================================================
void Keithley_6517::setCoulombMeterMode (void) 
{
	_electrometerProtocol->setCoulombMeterMode( );
}
  
// ============================================================================
// Keithley_6517::enable_VSourceOutput
// ============================================================================
void Keithley_6517::enable_VSourceOutput (void) 
{
	KeithleySCPIProtocol* _kscpi = dynamic_cast<KeithleySCPIProtocol*>(_electrometerProtocol);
	if(_kscpi)
		_kscpi->setVSourceOutputON();
}
  
// ============================================================================
// Keithley_6517::disable_VSourceOutput
// ============================================================================
void Keithley_6517::disable_VSourceOutput (void) 
{
	KeithleySCPIProtocol* _kscpi = dynamic_cast<KeithleySCPIProtocol*>(_electrometerProtocol);
	if(_kscpi)
		_kscpi->setVSourceOutputOFF();
}
ELATTAOUI's avatar
ELATTAOUI committed

ELATTAOUI's avatar
ELATTAOUI committed
// ============================================================================
// Keithley_6517::set_VSourceValue
// ============================================================================
void Keithley_6517::set_VSourceValue (double volts) 
{
	KeithleySCPIProtocol* _kscpi = dynamic_cast<KeithleySCPIProtocol*>(_electrometerProtocol);
	if(_kscpi)
		_kscpi->setVSourceValue(volts);
}

// ============================================================================
// Keithley_6517::set_VSourceValue
// ============================================================================
double Keithley_6517::get_VSourceValue (void) 
{
  std::string response("");
  double volts;

	KeithleySCPIProtocol* _kscpi = dynamic_cast<KeithleySCPIProtocol*>(_electrometerProtocol);
	if(_kscpi)
		response = _kscpi->getVSourceValue();

	volts = XString<double>::convertFromString(response);

  return volts;
}

ELATTAOUI's avatar
ELATTAOUI committed
// ============================================================================
ELATTAOUI's avatar
ELATTAOUI committed
// Keithley_6517::update_range
ELATTAOUI's avatar
ELATTAOUI committed
// ============================================================================
ELATTAOUI's avatar
ELATTAOUI committed
//void Keithley_6517::update_range (void) 
std::string Keithley_6517::get_ElectroMeterRange (void) 
ELATTAOUI's avatar
ELATTAOUI committed
{
std::string range_str("");
double rangeValueReturned	= 0;
double rangeValueCalculated	= 0;
double delta = 0;

	/**
	*	NOTE : SCPI models return a range value +/- 5%
	*/
	//- get device mode 
ELATTAOUI's avatar
ELATTAOUI committed
	_kmode = AbstractElectrometerClass::get_ElectroMeterMode();
ELATTAOUI's avatar
ELATTAOUI committed
	
	//- get range from hardware
	range_str = _electrometerProtocol->get_range( );
	//- convert range in decimal value
	rangeValueReturned = XString<double>::convertFromString(range_str);

	//- find and return the index
	short idx = 0;
	short idx_limit = 0;

	if(_kmode.find("CURR") != std::string::npos)
		idx_limit = K6517_AMP_rangeLimit;
	else if (_kmode.find("VOLT") != std::string::npos)
		idx_limit = K6517_VOLT_rangeLimit;
	else if (_kmode.find("RES") != std::string::npos)
		idx_limit = K6517_OHM_rangeLimit;
	else if (_kmode.find("CHAR") != std::string::npos)
		idx_limit = K6517_COU_rangeLimit;
	else
		throw electrometer::ElectrometerException("UNKNOWN_MODE", 
												"Unable to find the electrometer mode used.",
ELATTAOUI's avatar
ELATTAOUI committed
												"Keithley_6517::get_ElectroMeterRange( ).");
ELATTAOUI's avatar
ELATTAOUI committed

	
  //- find the range index
ELATTAOUI's avatar
ELATTAOUI committed
	for ( idx = 0; idx < idx_limit ; idx++ )
ELATTAOUI's avatar
ELATTAOUI committed
	{
ELATTAOUI's avatar
ELATTAOUI committed
		if( _kmode.find("CURR") != std::string::npos )
ELATTAOUI's avatar
ELATTAOUI committed
		{
			rangeValueCalculated = XString<double>::convertFromString(K6517_AMP_rangeStr[idx]);
			delta = rangeValueCalculated * 5 / 100;
			if( (rangeValueCalculated + delta) >= rangeValueReturned && (rangeValueCalculated - delta) <= rangeValueReturned)
				break;
		}
ELATTAOUI's avatar
ELATTAOUI committed
		else if ( _kmode.find("VOLT") != std::string::npos )
ELATTAOUI's avatar
ELATTAOUI committed
		{
			rangeValueCalculated = XString<double>::convertFromString(K6517_VOLT_rangeStr[idx]);
			delta = rangeValueCalculated * 5 / 100;
			if( (rangeValueCalculated + delta) >= rangeValueReturned && (rangeValueCalculated - delta) <= rangeValueReturned)
				break;
		}
ELATTAOUI's avatar
ELATTAOUI committed
		else if ( _kmode.find("RES") != std::string::npos )
ELATTAOUI's avatar
ELATTAOUI committed
		{
			rangeValueCalculated = XString<double>::convertFromString(K6517_OHM_rangeStr[idx]);
			delta = rangeValueCalculated * 5 / 100;
			if( (rangeValueCalculated + delta) >= rangeValueReturned && (rangeValueCalculated - delta) <= rangeValueReturned)
				break;
		}
ELATTAOUI's avatar
ELATTAOUI committed
		else if ( _kmode.find("CHAR") != std::string::npos )
ELATTAOUI's avatar
ELATTAOUI committed
		{
			rangeValueCalculated = XString<double>::convertFromString(K6517_COU_rangeStr[idx]);
			delta = rangeValueCalculated * 5 / 100;
			if( (rangeValueCalculated + delta) >= rangeValueReturned && (rangeValueCalculated - delta) <= rangeValueReturned)
				break;
		}
	}

	//- throw if index not found
ELATTAOUI's avatar
ELATTAOUI committed
	if( idx == idx_limit )
ELATTAOUI's avatar
ELATTAOUI committed
		throw electrometer::ElectrometerException("INTERNAL_ERROR", 
										"Failed to get range index.",
ELATTAOUI's avatar
ELATTAOUI committed
										"Keithley_6517::get_ElectroMeterRange( ).");
ELATTAOUI's avatar
ELATTAOUI committed

	//- update the range with the index found
	this->_range = idx;
ELATTAOUI's avatar
ELATTAOUI committed

  return range_str;
ELATTAOUI's avatar
ELATTAOUI committed
}
ELATTAOUI's avatar
ELATTAOUI committed

// ============================================================================
// Keithley_6517::get_averagecount
// ============================================================================
std::string Keithley_6517::get_averagecount (void) 
{
  std::string averCountStr("");

	//- this model needs to prefix this command with the current mode
	KeithleySCPIProtocol* _kscpi = dynamic_cast<KeithleySCPIProtocol*>(_electrometerProtocol);
	if(_kscpi)
		averCountStr = _kscpi->get_averagecount_K6517();

  return averCountStr;
}

// ============================================================================
// Keithley_6517::set_averagecount
// ============================================================================
void Keithley_6517::set_averagecount (std::string nbAverCountStr) 
{
	//- this model needs to prefix this command with the current mode
	KeithleySCPIProtocol* _kscpi = dynamic_cast<KeithleySCPIProtocol*>(_electrometerProtocol);
	if(_kscpi)
		_kscpi->set_averagecount_K6517(nbAverCountStr);

}

// ============================================================================
// Keithley_6517::get_averagecontrol
// ============================================================================
std::string Keithley_6517::get_averagecontrol (void) 
{
  std::string nbAverCtrlStr("");

	//- this model needs to prefix this command with the current mode
	KeithleySCPIProtocol* _kscpi = dynamic_cast<KeithleySCPIProtocol*>(_electrometerProtocol);
	if(_kscpi)
		nbAverCtrlStr = _kscpi->get_averagecontrol_K6517();

  return nbAverCtrlStr;
}

// ============================================================================
// Keithley_6517::set_averagecontrol
// ============================================================================
void Keithley_6517::set_averagecontrol (std::string nbAverCtrlStr) 
{
	//- this model needs to prefix this command with the current mode
	KeithleySCPIProtocol* _kscpi = dynamic_cast<KeithleySCPIProtocol*>(_electrometerProtocol);
	if(_kscpi)
		_kscpi->set_averagecontrol_K6517(nbAverCtrlStr);
}

// ============================================================================
// Keithley_6517::averageStateON
// ============================================================================
void Keithley_6517::averageStateON (void) 
{
	//- this model needs to prefix this command with the current mode
	KeithleySCPIProtocol* _kscpi = dynamic_cast<KeithleySCPIProtocol*>(_electrometerProtocol);
	if(_kscpi)
		_kscpi->averageStateON_K6517();
}

// ============================================================================
// Keithley_6517::averageStateOFF
// ============================================================================
void Keithley_6517::averageStateOFF (void) 
{
	//- this model needs to prefix this command with the current mode
	KeithleySCPIProtocol* _kscpi = dynamic_cast<KeithleySCPIProtocol*>(_electrometerProtocol);
	if(_kscpi)
		_kscpi->averageStateOFF_K6517();
}

// ============================================================================
// Keithley_6517::set_knplc
// ============================================================================
ELATTAOUI's avatar
ELATTAOUI committed
void Keithley_6517::set_knplc (double numPLC) 
ELATTAOUI's avatar
ELATTAOUI committed
{
std::stringstream cmd_to_send;

  if(numPLC <= 0 || numPLC > 10.0)
	{
		throw electrometer::ElectrometerException("OUT_OF_RANGE", 
												"Invalid number of PLC.\n Please enter a value in the range 0.01 to 10.0.",
												"Keithley_6517::set_knplc( ).");
	}
  //- just for internal use
  _numPLC = numPLC;

  cmd_to_send << numPLC << std::endl;
  //- default conversion rate
  _electrometerProtocol->set_knplc(cmd_to_send.str());
}  

// ============================================================================
// Keithley_6517::set_triggercount
// ============================================================================
void Keithley_6517::set_triggercount (short trigCounts) 
{
std::stringstream cmd_to_send;

  if(trigCounts == 0 || trigCounts > 99999)
	{
		throw electrometer::ElectrometerException("OUT_OF_RANGE", 
												"Invalid trigger count.\n Please enter a value in the range 1 to 99999 or set -1 for INFinite.",
												"Keithley_6517::set_triggercount( ).");
	}
  if(trigCounts < 0)
    cmd_to_send << "INF" << std::endl;
  else
    cmd_to_send << trigCounts << std::endl;

  //- just for internal use
  _trigCounts = trigCounts;
  //- default conversion rate
  _electrometerProtocol->set_triggercount(cmd_to_send.str());
}  

// ============================================================================
// Keithley_6517::set_buffer_size
// ============================================================================
void Keithley_6517::set_buffer_size (short size) 
{
std::stringstream cmd_to_send;

  if(size < 1 || size > 10000)
	{
		throw electrometer::ElectrometerException("OUT_OF_RANGE", 
												"Invalid buffer size. \nPlease enter a value in the range 1 to 10000.",
												"Keithley_6517::set_buffer_size( ).");
	}
  //- just for internal use
  _size = size;

  cmd_to_send << size << std::endl;
  //- default conversion rate
  _electrometerProtocol->set_buffer_size(cmd_to_send.str());
}  

// ============================================================================
// Keithley_6517::set_integrationTime
// ============================================================================
void Keithley_6517::set_integrationTime (double seconds) 
{
  //- set the number of Power Line Cycle(s) -> Fast integration
  _numPLC = 0.05;
  //- set the number of trigger(s) ~ buffer size
  _trigCounts = (short)ceil(seconds / _numPLC);

  if(_trigCounts > 99999)
    _trigCounts = 99999;
}

// ============================================================================
// Keithley_6517::init_keithley : command to perform an integration cycle
// ============================================================================
void Keithley_6517::init_keithley (void) 
{
  //- clear all registers
  _electrometerProtocol->clear_registers();
  //- get data only (no timestamp info ... wanted!)
  _electrometerProtocol->read_data_with_no_timestamp();
  //- Set integration rate in line cycles
  this->set_knplc(_numPLC);
  //- Set trigger model to take to N readings
  this->set_triggercount(_trigCounts);
  //- Set buffer size
  this->set_buffer_size(_size);
  //- clear previous data
  _electrometerProtocol->clear_buffer();
  //- Store raw input
//  _electrometerProtocol->store_raw_input();
  //- Start storing on next reading
  _electrometerProtocol->start_storing();
  //- Enable SRQ on buffer full
  _electrometerProtocol->enable_SRQBufferFull();
  //- Trigger readings
  _electrometerProtocol->init_keithley();
}

ELATTAOUI's avatar
ELATTAOUI committed
// ============================================================================
// Keithley_6517:: THIS MODEL DOES NOT SUPPORT THESE COMMANDS 
// ============================================================================
// ============================================================================
// Keithley_6517::auto_zero_on
// ============================================================================
void Keithley_6517::auto_zero_on (void) 
{
	throw electrometer::ElectrometerException("COMMAND_NOT_SUPPORTED", 
		"This Keithley 6517 does bot support this command.",
		"Keithley_6517::auto_zero_on( ).");
}
// ============================================================================
// Keithley_6517::auto_zero_off
// ============================================================================
void Keithley_6517::auto_zero_off (void) 
{
	throw electrometer::ElectrometerException("COMMAND_NOT_SUPPORTED", 
		"This Keithley 6517 does bot support this command.",
		"Keithley_6517::auto_zero_off( ).");
}

// ============================================================================
// Keithley_6517::save_configuration
// ============================================================================
void Keithley_6517::save_configuration (unsigned short memoryIdx) 
{
  if( memoryIdx > MAX_SAVED_CONFIG )
	{
		throw electrometer::ElectrometerException("OUT_OF_RANGE", 
												"Index of saved configuration must be in the range [0-2].",
												"Keithley_6487::save_configuration( ).");
	}
	_electrometerProtocol->save_configuration(memoryIdx);
}
ELATTAOUI's avatar
ELATTAOUI committed

// ============================================================================
// Keithley_6517::restore_configuration
// ============================================================================
void Keithley_6517::restore_configuration (unsigned short memoryIdx) 
{
  if( memoryIdx > MAX_SAVED_CONFIG )
	{
		throw electrometer::ElectrometerException("OUT_OF_RANGE", 
												"Index of saved configuration must be in the range [0-9].",
												"Keithley_6517::restore_configuration( ).");
	}
	_electrometerProtocol->restore_configuration(memoryIdx);
}