// ============================================================================ // // = CONTEXT // TANGO Project - SCPI KeithleyElectrometer Support Library // // = FILENAME // Keithley_6485.cpp // // = AUTHOR // X. Elattaoui // // ============================================================================ // ============================================================================ // DEPENDENCIES // ============================================================================ #include <iostream> #include <sstream> #include <string> #include <math.h> //- for ceil #include <Xstring.h> #include "Keithley_6485.h" #include "KeithleySCPIProtocol.h" /* * Valid Range values for a K_6485 */ static const std::string K6485_rangeValue[] = {"2E-9","2E-8","2E-7","2E-6","2E-5","2E-4","2E-3","2E-2"}; /* * Max Index Range value for a K_6485 */ static const short K6485_rangeLimit = 8; static const unsigned short MAX_SAVED_CONFIG = 2; // ============================================================================ // Keithley_6485::Keithley_6485 // ============================================================================ Keithley_6485::Keithley_6485 (std::string& comLink_device_name) : AbstractElectrometerClass(comLink_device_name) { std::cout << "Keithley_6485::Keithley_6485 <-" << std::endl; _numPLC = 0.1; _trigCounts = 1; _size = 0; std::cout << "Keithley_6485::Keithley_6485 ->" << std::endl; } // ============================================================================ // Keithley_6485::~Keithley_6485 // ============================================================================ Keithley_6485::~Keithley_6485 (void) { std::cout << "Keithley_6485::~Keithley_6485 <-" << std::endl; std::cout << "Keithley_6485::~Keithley_6485 ->" << std::endl; } // ============================================================================ // Keithley_6485::init_protocol // ============================================================================ bool Keithley_6485::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(false); success = _electrometerProtocol->build_communicationLink(); set_knplc(_numPLC); } } 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_6485::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_6485::init_protocol"); } return success; } // ============================================================================ // Keithley_6485::range_up // ============================================================================ void Keithley_6485::range_up (void) { std::stringstream cmd_to_send; //- update range index from hardware this->get_ElectroMeterRange( ); _range += 1; if(_range > K6485_rangeLimit) { _range = K6485_rangeLimit; throw electrometer::ElectrometerException("OUT_OF_RANGE", "Range up limit reached.", "Keithley_6485::range_up( )."); } //- build and send the command _rangeStr = K6485_rangeValue[_range]; cmd_to_send << _rangeStr << std::endl; _electrometerProtocol->set_range(cmd_to_send.str()); } // ============================================================================ // Keithley_6485::range_down // ============================================================================ void Keithley_6485::range_down (void) { std::stringstream cmd_to_send; //- update range index from hardware this->get_ElectroMeterRange( ); _range -= 1; if(_range < 0) { _range=0; throw electrometer::ElectrometerException("OUT_OF_RANGE", "Range down limit reached.", "Keithley_6485::range_down( )."); } //- build and send the command _rangeStr = K6485_rangeValue[_range]; cmd_to_send << _rangeStr << std::endl; _electrometerProtocol->set_range(cmd_to_send.str()); } // ============================================================================ // Keithley_6485::update_range // ============================================================================ //void Keithley_6485::update_range (void) std::string Keithley_6485::get_ElectroMeterRange (void) { /** * NOTE : SCPI models return a range value +/- 5% */ //- get range from hardware std::string range_str = _electrometerProtocol->get_range( ); //- convert range in decimal value double rangeValueReturned = XString<double>::convertFromString(range_str); //- find and return the index short idx = 0; for(idx=0; idx<K6485_rangeLimit ; idx++) { double rangeValueCalculated = XString<double>::convertFromString(K6485_rangeValue[idx]); double delta = rangeValueCalculated * 5 / 100; if( (rangeValueCalculated + delta) >= rangeValueReturned && (rangeValueCalculated - delta) <= rangeValueReturned) break; } //- throw if index not found if(idx == K6485_rangeLimit) throw electrometer::ElectrometerException("INTERNAL_ERROR", "Failed to get range index.", "Keithley_6485::get_ElectroMeterRange( )."); //- update range with index found this->_range = idx; return range_str; } // ============================================================================ // Keithley_6485::get_integratedValue // ============================================================================ std::vector<double> Keithley_6485::get_integratedValue (void) { KeithleySCPIProtocol* _kscpi = dynamic_cast<KeithleySCPIProtocol*>(_electrometerProtocol); if(!_kscpi) throw electrometer::ElectrometerException("INTERNAL_ERROR", "Dynamic cast failed !.", "Keithley_6485::get_integratedValue( )."); return _electrometerProtocol->get_integratedValue( ); } // ============================================================================ // Keithley_6485::get_fetchValue // ============================================================================ std::vector<double> Keithley_6485::get_fetchValue (void) { KeithleySCPIProtocol* _kscpi = dynamic_cast<KeithleySCPIProtocol*>(_electrometerProtocol); if(!_kscpi) throw electrometer::ElectrometerException("INTERNAL_ERROR", "Dynamic cast failed !.", "Keithley_6485::get_fetchValue( )."); return _kscpi->get_fetchValue( ); } // ============================================================================ // Keithley_6485::set_knplc // ============================================================================ void Keithley_6485::set_knplc (double numPLC) { std::stringstream cmd_to_send; if(numPLC <= 0 || numPLC > 5.0) { throw electrometer::ElectrometerException("OUT_OF_RANGE", "Invalid number of PLC.\n Please enter a value in the range 0.01 to 5.0.", "Keithley_6485::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_6485::set_triggercount // ============================================================================ void Keithley_6485::set_triggercount (short trigCounts) { std::stringstream cmd_to_send; if(trigCounts == 0 || trigCounts > 2500) { throw electrometer::ElectrometerException("OUT_OF_RANGE", "Invalid trigger count.\n Please enter a value in the range 1 to 2500 or set -1 for INFinite.", "Keithley_6485::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_6485::set_buffer_size // ============================================================================ void Keithley_6485::set_buffer_size (short size) { std::stringstream cmd_to_send; if(size < 1 || size > 2500) { throw electrometer::ElectrometerException("OUT_OF_RANGE", "Invalid buffer size. \nPlease enter a value in the range 1 to 2500.", "Keithley_6485::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_6485::set_integrationTime // ============================================================================ void Keithley_6485::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 > 2500) _trigCounts = 2500; } // ============================================================================ // Keithley_6485::init_keithley : command to perform an integration cycle // ============================================================================ void Keithley_6485::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(); } // ============================================================================ // Keithley_6485::save_configuration // ============================================================================ void Keithley_6485::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_6485::save_configuration( )."); } _electrometerProtocol->save_configuration(memoryIdx); } // ============================================================================ // Keithley_6485::restore_configuration // ============================================================================ void Keithley_6485::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-2].", "Keithley_6485::restore_configuration( )."); } _electrometerProtocol->restore_configuration(memoryIdx); }