// ============================================================================
//
// = CONTEXT
//    TANGO Project - SCPI KeithleyElectrometer Support Library
//
// = FILENAME
//    Keithley_6487.cpp
//
// = AUTHOR
//    X. Elattaoui
//
// ============================================================================
static long KEITHLEY_MODEL = 6487;

// ============================================================================
// DEPENDENCIES
// ============================================================================
#include <iostream>
#include <sstream>
#include <string>
#include <Xstring.h>
#include "Keithley_6487.h"
#include "KeithleySCPIProtocol.h"
/*
* Valid Range values for a K_6487
*/
static const std::string K6487_rangeValue[8] = {"2E-2","2E-3","2E-4","2E-5","2E-6","2E-7","2E-8","2E-9"};
/*
* Max Index Range value for a K_6487
*/
static const short K6487_rangeLimit = 7;

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

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

	//- this model does not support different mode (OhmMeter, VoltMeter and so on )
	KeithleySCPIProtocol* _kscpi = dynamic_cast<KeithleySCPIProtocol*>(_electrometerProtocol);
	if(_kscpi)
		_kscpi->set_isDiffSuportedMode(false);

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

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

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

// ============================================================================
// Keithley_6487::range_up
// ============================================================================
void Keithley_6487::range_up (void) 
{
std::stringstream cmd_to_send;
	
	//- update range index from hardware
	update_range( );

	_range += 1;

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

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

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

std::stringstream cmd_to_send;

	//- update range index from hardware
	update_range( );

	_range -= 1;

	if(_range < 0)
	{
		_range = 0;
		throw electrometer::ElectrometerException("OUT_OF_RANGE", 
												"Range down limit reached.",
												"Keithley_6487::range_down( ).");
	}
	_rangeStr = K6487_rangeValue[_range];
	cmd_to_send << _range << std::endl;
	_electrometerProtocol->set_range(cmd_to_send.str());
}

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

// ============================================================================
// Keithley_6487::get_integratedValue
// ============================================================================
std::vector<double> Keithley_6487::get_integratedValue (void) 
{
 	KeithleySCPIProtocol* _kscpi = dynamic_cast<KeithleySCPIProtocol*>(_electrometerProtocol);
	if(!_kscpi)
		throw electrometer::ElectrometerException("INTERNAL_ERROR", 
												"Dynamic cast failed !.",
												"Keithley_6487::get_integratedValue( ).");

  return 	_kscpi->get_integratedValue( );
}  

// ============================================================================
// Keithley_6487::get_fetchValue
// ============================================================================
std::vector<double> Keithley_6487::get_fetchValue (void) 
{
 	KeithleySCPIProtocol* _kscpi = dynamic_cast<KeithleySCPIProtocol*>(_electrometerProtocol);
	if(!_kscpi)
		throw electrometer::ElectrometerException("INTERNAL_ERROR", 
												"Dynamic cast failed !.",
												"Keithley_6487::get_fetchValue( ).");

  return 	_kscpi->get_fetchValue( );
}  

// ============================================================================
// Keithley_6487::update_range
// ============================================================================
void Keithley_6487::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 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;
	for(idx=0; idx<K6487_rangeLimit ; idx++)
	{
		rangeValueCalculated = XString<double>::convertFromString(K6487_rangeValue[idx]);
		delta = rangeValueCalculated * 5 / 100;
		if( (rangeValueCalculated + delta) >= rangeValueReturned && (rangeValueCalculated - delta) <= rangeValueReturned)
			break;
	}

	//- throw if index not found
	if(idx == K6487_rangeLimit)
		throw electrometer::ElectrometerException("INTERNAL_ERROR", 
										"Failed to get range index.",
										"Keithley_6487::update_range( ).");
	
	//- update range with the index found
	this->_range = idx;
		
}