Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
Keithley_617.cpp 17.63 KiB
// ============================================================================
//
// = CONTEXT
//    TANGO Project - DDC KeithleyElectrometer Support Library
//
// = FILENAME
//    Keithley_617.cpp
//
// = AUTHOR
//    X. Elattaoui
//
// ============================================================================

// ============================================================================
// DEPENDENCIES
// ============================================================================
#include <iostream>
#include <stdexcept>
#include <sstream>
#include <string>
#include <Xstring.h>
#include "Keithley_617.h"
#include "KeithleyDDCProtocol.h"
/*
* Valid Range values for a K_617
*/
static const std::string K617_AmpRangeValue[] = {"AUTO ON","2E-12","2E-11","2E-10","2E-9","2E-8","2E-7","2E-6","2E-5","2E-4","2E-3","2E-2", "AUTO OFF"};
static const std::string K617_VoltRangeValue[]= {"AUTO ON","2E-1","2","20","200","200","200","200","200","200","200","200", "AUTO OFF"};
static const std::string K617_OhmRangeValue[] = {"AUTO ON","2E3","2E4","2E5","2E6","2E7","2E8","2E9","2E10","2E11","2E11","2E11", "AUTO OFF"};
static const std::string K617_CouRangeValue[] = {"AUTO ON","2E-10","2E-9","2E-10","2E-10","2E-10","2E-10","2E-10","2E-10","2E-10","2E-10","2E-10", "AUTO OFF"};
static const std::string K617_XfdbRangeValue[]= {"AUTO ON","2E-1","2","20","20","20","20","20","20","20","20","20", "AUTO OFF"};
static const std::string K617_VonIRangeValue[]= {"AUTO ON","200E12","20E12","2E12","200E9","20E9","2E9","200E6","20E6","2E6","200E3","200E3", "AUTO OFF"};
/*
* Range limit
*/
static short K617_rangeLimit = 12;

/*
* Trigger Mode limit
*/
static short K617_triggerModeLimit = 7;

// ============================================================================
// Keithley_617::Keithley_617
// ============================================================================
Keithley_617::Keithley_617 (std::string& comLink_device_name):AbstractElectrometerClass(comLink_device_name) 
{
	std::cout << "Keithley_617::Keithley_617 <-" << std::endl;

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

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

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

// ============================================================================
// Keithley_617::init_protocol
// ============================================================================
bool Keithley_617::init_protocol (void)
{
  std::string description("");
  bool success = false;
  try
  {
	  //- build the keithley Electrometer protocol obj
  	_electrometerProtocol = new KeithleyDDCProtocol (_device_proxy_name);
    
    if(_electrometerProtocol)
      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_617::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_617::init_protocol");
  }
  return success;
}

// ============================================================================
// Keithley_617::autoRange_off
// ============================================================================
void Keithley_617::autoRange_off (void) 
{

	//- send the appropriate command
	KeithleyDDCProtocol* _kddc = dynamic_cast<KeithleyDDCProtocol*>(_electrometerProtocol);
	if(_kddc)
		_kddc->autoRange_OFF_forK617_6512();
}

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

std::stringstream cmd_to_send;

	// force read of range on instrument to update _range variable 
	_range += 1;

	if(_range > K617_rangeLimit)
	{
		_range = K617_rangeLimit;
		throw electrometer::ElectrometerException("OUT_OF_RANGE", 
												"Range up limit reached.",
												"Keithley_617::range_up( ).");
	}

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

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

std::stringstream cmd_to_send;

	// force read of range on instrument to update _range variable 
	_range -= 1;

	if(_range < 0)
	{
		_range = 0;
		throw electrometer::ElectrometerException("OUT_OF_RANGE", 
												"Range down limit reached.",
												"Keithley_617::range_down( ).");
	}

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

// ============================================================================
// Keithley_617::get_ElectroMeterRange
// ============================================================================
std::string Keithley_617::get_ElectroMeterRange (void) 
{
	// force read of range on instrument to update _range variable
	return _rangeStr;
}

// ============================================================================
// Keithley_617::set_buffer_size()
// ============================================================================
void Keithley_617::set_buffer_size (short ) 
{

		throw electrometer::ElectrometerException("COMMAND_NOT_SUPPORTED", 
												"The 617 Keithley device buffer size cannot be set (it stores up to 100 points internally.)",
												"Keithley_617::set_triggerMode( ).");

}

// ============================================================================
// Keithley_617::set_triggerMode
// ============================================================================
void Keithley_617::set_triggerMode (short trigMod) 
{
  if(trigMod<0 || trigMod>K617_triggerModeLimit)
		throw electrometer::ElectrometerException("OUT_OF_RANGE", 
												"Trigger mode value invalid. Please enter a value in the range 0 - 7.",
												"Keithley_617::set_triggerMode( ).");

  std::stringstream cmd_to_send;

  //- just for internal use
  _trigMod = trigMod;

  cmd_to_send << "T" << trigMod << "X" << std::endl;

  _electrometerProtocol->set_triggerMode(cmd_to_send.str());
}

// ============================================================================
// Keithley_617::get_ElectroMeterMode
// ============================================================================
std::string Keithley_617::get_ElectroMeterMode (void) 
{
	// force read of mode on instrument to update _mode variable
	return _mode;
}

// ============================================================================
// Keithley_617::setAmperMeterMode (617 & 6512 Keithley DDC models
// ============================================================================
void Keithley_617::setAmperMeterMode (void) 
{
	_electrometerProtocol->setAmperMeterMode( );
}

// ============================================================================
// Keithley_617::setAmperMeterMode (617 & 6512 Keithley DDC models
// ============================================================================
void Keithley_617::setVoltMeterMode (void) 
{
	_electrometerProtocol->setVoltMeterMode( );
}

// ============================================================================
// Keithley_617::setAmperMeterMode (617 & 6512 Keithley DDC models
// ============================================================================
void Keithley_617::setOhmMeterMode (void) 
{
	_electrometerProtocol->setOhmMeterMode( );
}

// ============================================================================
// Keithley_617::setAmperMeterMode (617 & 6512 Keithley DDC models
// ============================================================================
void Keithley_617::setCoulombMeterMode (void) 
{
	_electrometerProtocol->setCoulombMeterMode( );
}

// ============================================================================
// Keithley_617::init_keithley : command to perform an integration cycle
// ============================================================================
void Keithley_617::init_keithley (void) 
{
  //- set trigger mode
  this->set_triggerMode(_trigMod);
  //- default conversion rate
  _electrometerProtocol->set_conversionRate( );
  //- force readings with no prefix
  _electrometerProtocol->disable_readingWithPrefix();
  //- force readings from device buffer
  _electrometerProtocol->enable_readingsFromBuffer_K617_6512();
  //- enable SRQ on buffer full
  _electrometerProtocol->enable_SRQBufferFull ();
}

// ============================================================================
// Keithley_617::electrometer_status
// ============================================================================
std::string Keithley_617::electrometer_status (void)
{
	std::string kconfig("undefined configuration");
	std::string argout("");
	std::string tmp("");

	try
	{
		kconfig = _electrometerProtocol->get_raw_status();
		std::string modelNum = kconfig.substr(0,3);
		if(modelNum.find("617") == std::string::npos)
		{
			set_electroState(ALARM);
			argout = "Invalid error status string received";
			return argout;
		}


		//- IDDC Error : Set when an illegal device dependent command (IDDC) such as HlX is received ("H" is illegal).
		tmp = kconfig.substr(3,1);
		short iddc = XString<short>::convertFromString(tmp);
		if(iddc)
		{
			argout += "IDDC error : illegal device dependent command received.\n";
		}
		//- IDDCO Error : Set when an illegal device-dependent command option (IDDCO) such as T9X is received ("9" is illegal).
		tmp = kconfig.substr(4,1);
		short iddco = XString<short>::convertFromString(tmp);
		if(iddco)
		{
			argout += "IDDCO error : an illegal device-dependent command option received.\n";
		}
		//- Remote Error : Set when a programming command is received when REN is false.
		tmp = kconfig.substr(5,1);
		short remote = XString<short>::convertFromString(tmp);
		if(remote)
		{
			argout += "REMOTE error : programming command is received when REN is false\n";
		}
		//- Trigger Overrun Error : Set when a trigger is received when the instrument is still processing a reading from a previous trigger.
		tmp = kconfig.substr(7,1);
		short trigg = XString<short>::convertFromString(tmp);
		if(trigg)
		{
			argout += "Trigger error : Trigger received while instrument is still processing a reading from a previous trigger.\n";
		}
		//- Number Error : Set when an Out of range calibration or voltage source value is received.
		tmp = kconfig.substr(8,1);
		short numErr = XString<short>::convertFromString(tmp);
		if(numErr)
		{
			argout += "Number error : Out of range calibration or voltage source value is received.\n";
		}

		if( argout.empty() )
			argout = "No error.";

		argout = "Keithley Type " + modelNum + " Error Status :\n" + argout;

	}
	catch(...)
	{
		set_electroState(ALARM);
	
		throw electrometer::ElectrometerException("UNKNOWN_ERROR", 
												"Cannot extract device error status.",
												"Keithley_617::electrometer_status( ).");
	}

	set_electroState(ON);
	return argout;
}

// ============================================================================
// Keithley_617::get_configuration
// ============================================================================
std::string Keithley_617::get_configuration (void)
{ 
	std::string _kstatus("undefined status");
	std::string argout("undefined status");
	std::string tmp("");

	//- read keithley status from HW	
	_kstatus = _electrometerProtocol->get_DDC_configuration();

	//- build status
	try
	{
		//- model number :
		std::string modelNum = _kstatus.substr(0,3);
//    std::cout<< "\n617 status = " << modelNum << std::endl;
    //- if not expected data (here model number)
		if(modelNum.find("617") == std::string::npos)
		{
			set_electroState(ALARM);
			argout = "Invalid status string received";
			return argout;
		}
		argout = "Keithley Type : " + modelNum + "\n";
		//- Functions and associate range :
		tmp = _kstatus.substr(3,1);
		short func = XString<short>::convertFromString(tmp);
		//- Range :
		tmp = _kstatus.substr(4,2);
		 _range = XString<short>::convertFromString(tmp);
		if(!func)
		{
			_mode = "Function : VOLTS";
			argout += _mode + "\n";
			_rangeStr = K617_VoltRangeValue[_range];
		}
		else
			if(func == 1)
			{
				_mode = "Function : AMPS";
			    argout += _mode + "\n";
				_rangeStr = K617_AmpRangeValue[_range];
				argout	 += _rangeStr + "\n";
			}
		else
			if(func == 2)
			{
				_mode = "Function : OHMS";
			    argout += _mode + "\n";
				_rangeStr = K617_OhmRangeValue[_range];
			}
		else
			if(func == 3)
			{
				_mode = "Function : COULOMBS";
			    argout += _mode + "\n";
				_rangeStr = K617_CouRangeValue[_range];
			}
		else
			if(func == 4)
			{
				_mode = "Function : XFDBK";
			    argout += _mode + "\n";
				_rangeStr = K617_XfdbRangeValue[_range];
			}
		else
			if(func == 5)
			{
				_mode = "Function : V/I";
			    argout += _mode + "\n";
				_rangeStr = K617_XfdbRangeValue[_range];
			}
		//- Range :
		argout += "RANGE : " + _rangeStr + "\n";
		//- Zero check state
		tmp = _kstatus.substr(6,1);
		if(XString<short>::convertFromString(tmp))
			argout += "Zero Check : ON\n";
		else
			argout += "Zero Check : OFF\n";
		//- Zero correct state
		tmp = _kstatus.substr(7,1);
		if(XString<short>::convertFromString(tmp))
			argout += "Zero Correct : ON\n";
		else
			argout += "Zero Correct : OFF\n";
		//- Suppress
		tmp = _kstatus.substr(8,1);
		if(XString<short>::convertFromString(tmp))
			argout += "Suppress : ON\n";
		else
			argout += "Suppress : OFF\n";
		//- Trigger
		tmp = _kstatus.substr(9,1);
    _trigMod = XString<short>::convertFromString(tmp);
		if(!_trigMod)
			argout += "Trigger : Continuous on Talk\n";
		else
			if(_trigMod == 1)
				argout += "Trigger :One-Shot on Talk\n";
		else
			if(_trigMod == 2)
				argout += "Trigger :Continuous on Get\n";
		else
			if(_trigMod == 3)
				argout += "Trigger :One-Shot on Get\n";
		else
			if(_trigMod == 4)
				argout += "Trigger :Continuous on \"X\"\n";
		else
			if(_trigMod == 5)
				argout += "Trigger :One-Shot on \"X\"\n";
		else
			if(_trigMod == 6)
				argout += "Trigger :Continuous on External\n";
		else
			if(_trigMod == 7)
				argout += "Trigger :One-Shot on External\n";
		//- Voltage Source
		tmp = _kstatus.substr(10,1);
		if(XString<short>::convertFromString(tmp))
			argout += "Voltage Source Operate : ON\n";
		else
			argout += "Voltage Source Operate : OFF\n";
		//- Read Mode
		tmp = _kstatus.substr(11,1);
		if(!XString<short>::convertFromString(tmp))
			argout += "Read Mode : Electrometer\n";
		else
			if(XString<short>::convertFromString(tmp) == 1)
				argout += "Read Mode : Data Store\n";
		else
			if(XString<short>::convertFromString(tmp) == 2)
				argout += "Read Mode : Maximum\n";
		else
			if(XString<short>::convertFromString(tmp) == 3)
				argout += "Read Mode : Minimum\n";
		else
			if(XString<short>::convertFromString(tmp) == 4)
				argout += "Read Mode :Voltage Source\n";
		//- Display :
		tmp = _kstatus.substr(13,1);
		if(!XString<short>::convertFromString(tmp))
			argout += "Display : Electrometer\n";
		else
			argout += "Display : Voltage Source\n";
		//- Data Store
		tmp = _kstatus.substr(14,1);
		if(!XString<short>::convertFromString(tmp))
			argout += "Data Store : Conversion Rate\n";
		else
			if(XString<short>::convertFromString(tmp) == 1)
				argout += "Data Store : 1 RDG/Sec\n";
		else
			if(XString<short>::convertFromString(tmp) == 2)
				argout += "Data Store : 1 RDG/10Sec\n";
		else
			if(XString<short>::convertFromString(tmp) == 3)
				argout += "Data Store : 1 RDG/Min\n";
		else
			if(XString<short>::convertFromString(tmp) == 4)
				argout += "Data Store : 1 RDG/10Min\n";
		else
			if(XString<short>::convertFromString(tmp) == 5)
				argout += "Data Store : 1 RDG/1Hr\n";
		else
			if(XString<short>::convertFromString(tmp) == 6)
				argout += "Data Store : Trig Button\n";
		else
			if(XString<short>::convertFromString(tmp) == 7)
				argout += "Data Store : Disabled\n";
		//- SRQ Mask
		tmp = _kstatus.substr(15,2);
		if(!XString<short>::convertFromString(tmp))
			argout += "SRQ Data Mask : SRQ Disabled\n";
		else
			if(XString<short>::convertFromString(tmp) == 1)
				argout += "SRQ Data Mask : Reading Overflow\n";
		else
			if(XString<short>::convertFromString(tmp) == 2)
				argout += "SRQ Data Mask : Data Store Full\n";
		else
			if(XString<short>::convertFromString(tmp) == 8)
				argout += "SRQ Data Mask : Reading Done\n";
		else
			if(XString<short>::convertFromString(tmp) == 16)
				argout += "SRQ Data Mask : Ready\n";
		else
			if(XString<short>::convertFromString(tmp) == 32)
				argout += "SRQ Data Mask : Error\n";
		//- EOI & Bus Hold Off
		tmp = _kstatus.substr(17,1);
		if(!XString<short>::convertFromString(tmp))
			argout += "EOI & Bus Hold Off : EOI and Hold-Off\n";
		else
		if(XString<short>::convertFromString(tmp) == 1)
			argout += "EOI & Bus Hold Off : No EOI and Hold-Off\n";
		else
		if(XString<short>::convertFromString(tmp) == 2)
			argout += "EOI & Bus Hold Off : EOI and no Hold-Off\n";
		else
		if(XString<short>::convertFromString(tmp) == 3)
			argout += "EOI & Bus Hold Off : No EOI and no Hold-Off\n";
	}
	catch(std::out_of_range)
	{
		set_electroState(ALARM);
	
		throw electrometer::ElectrometerException("OUT_OF_RANGE", 
												"Cannot extract device status [find or substr failed !].",
												"Keithley_617::get_configuration( ).");
	}

	set_electroState(ON);
	return argout;
}