// ============================================================================ // // = CONTEXT // TANGO Project - SCPI KeithleyElectrometer Support Library // // = FILENAME // Keithley_6517.cpp // // = AUTHOR // X. Elattaoui // // ============================================================================ static long KEITHLEY_MODEL = 6517; // ============================================================================ // DEPENDENCIES // ============================================================================ #include <iostream> #include <sstream> #include <string> #include <math.h> //- for ceil #include <Xstring.h> #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 */ static const short K6517_AMP_rangeLimit = 9; static const short K6517_VOLT_rangeLimit= 2; static const short K6517_OHM_rangeLimit = 9; static const short K6517_COU_rangeLimit = 3; // ============================================================================ // Keithley_6517::Keithley_6517 // ============================================================================ Keithley_6517::Keithley_6517 (std::string& comLink_device_name): AbstractElectrometerClass(comLink_device_name), _kmode("") { std::cout << "Keithley_6517::Keithley_6517 <-" << std::endl; //- build the keithley Electrometer obj _electrometerProtocol = new KeithleySCPIProtocol(_device_proxy_name); //- this model supports different mode (OhmMeter, VoltMeter and so on ) KeithleySCPIProtocol* _kscpi = dynamic_cast<KeithleySCPIProtocol*>(_electrometerProtocol); if(_kscpi) _kscpi->set_isDiffSuportedMode(true); 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; } // ============================================================================ // Keithley_6517::range_up // ============================================================================ void Keithley_6517::range_up (void) { std::stringstream cmd_to_send; //- update range value from hardware update_range( ); _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 update_range( ); _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::update_range // ============================================================================ void Keithley_6517::update_range (void) { std::string range_str(""); double rangeValueReturned = 0; double rangeValueCalculated = 0; double delta = 0; /** * NOTE : SCPI models return a range value +/- 5% */ //- get device mode _kmode = get_ElectroMeterMode(); //- 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.", "Keithley_6517::update_range( )."); //- find the range index for(idx=0; idx<idx_limit ; idx++) { if(_kmode.find("CURR") != std::string::npos) { rangeValueCalculated = XString<double>::convertFromString(K6517_AMP_rangeStr[idx]); delta = rangeValueCalculated * 5 / 100; if( (rangeValueCalculated + delta) >= rangeValueReturned && (rangeValueCalculated - delta) <= rangeValueReturned) break; } else if (_kmode.find("VOLT") != std::string::npos) { rangeValueCalculated = XString<double>::convertFromString(K6517_VOLT_rangeStr[idx]); delta = rangeValueCalculated * 5 / 100; if( (rangeValueCalculated + delta) >= rangeValueReturned && (rangeValueCalculated - delta) <= rangeValueReturned) break; } else if (_kmode.find("RES") != std::string::npos) { rangeValueCalculated = XString<double>::convertFromString(K6517_OHM_rangeStr[idx]); delta = rangeValueCalculated * 5 / 100; if( (rangeValueCalculated + delta) >= rangeValueReturned && (rangeValueCalculated - delta) <= rangeValueReturned) break; } else if (_kmode.find("CHAR") != std::string::npos) { 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 if(idx == idx_limit) throw electrometer::ElectrometerException("INTERNAL_ERROR", "Failed to get range index.", "Keithley_6517::update_range( )."); //- update the range with the index found this->_range = idx; } // ============================================================================ // 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 // ============================================================================ void Keithley_6517::set_knplc (float numPLC) { std::stringstream cmd_to_send; if(numPLC <= 0 || numPLC > 10.0) { // std::cout << "Keithley_6517::set_knplc -> " << numPLC << std::endl; 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(); } // ============================================================================ // 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( )."); }