// ============================================================================ // // = CONTEXT // TANGO Project - NovelecProtocol Support Library // // = FILENAME // NovelecProtocol.cpp // // = AUTHOR // X. Elattaoui // // ============================================================================ // ============================================================================ // DEPENDENCIES // ============================================================================ #include <iostream> #include <sstream> #include <string> #include <Xstring.h> #include "NovelecProtocol.h" #include "TangoSerialLink.h" //- commands numbers static const short STATUS_CMD_NUM = 1; static const short ERRORS_CMD_NUM = 2; static const short MODE_CMD_NUM = 3; static const short ELECTROTYPE_CMD_NUM = 4; static const short POLARITY_CMD_NUM = 5; static const short FREQUENCY_CMD_NUM = 6; static const short GAIN_CMD_NUM = 7; static const short RANGE_CMD_NUM = 8; static const short RESPONSE_LGTH_CMD_NUM = 17; static const short CLEAR_ERRORS_CMD_NUM = 18; //- the specific new line character static const string END_OF_LINE = "\r\n"; //- modes allowed static const std::string mode_str[] = {"ERR : UNKNOWN MODE","ZERO V/F","OFFSET","LEAKAGE","TEST","MEASURE"}; static const std::string range_str[5][8]= { {"1e-11AcC","3e-11AcC","1e-10AcC","3e-10AcC", "OUT OF RANGE","OUT OF RANGE","OUT OF RANGE","OUT OF RANGE"}, {"1e-10AcC","3e-10AcC","1e-9AcC","3e-9AcC","1e-8AcC","3e-8AcC","1e-7AcC","3e-7AcC"}, {"1e-8AcC","3e-8AcC","1e-7AcC","3e-7AcC","1e-6AcC","3e-6AcC","1e-5AcC","3e-5AcC"}, {"1000MOhm","300MOhm","100MOhm","30MOhm","OUT OF RANGE","OUT OF RANGE","OUT OF RANGE","OUT OF RANGE"}, {"1000KOhm","300KOhm","100KOhm","30KOhm","OUT OF RANGE","OUT OF RANGE","OUT OF RANGE","OUT OF RANGE",} }; static const std::string frequency_str[]= {"3 Hz","10 Hz","100 Hz","1000 Hz"}; static const std::string gain_str[] = {"1","10","100"}; // ============================================================================ // NovelecProtocol::NovelecProtocol // ============================================================================ NovelecProtocol::NovelecProtocol (std::string& serial_device_name, unsigned short devAddress, unsigned short novelecType) : ElectrometerProtocol(), _devAdd(devAddress), _novType(novelecType) { _commDevName = serial_device_name; _rangeParameterNum = _novType + 2; _function = "Not updated"; _is_measure_mode_on = false; _is_explicite_resp_enabled = false; } // ============================================================================ // NovelecProtocol::~NovelecProtocol // ============================================================================ NovelecProtocol::~NovelecProtocol (void) { // std::cout << "NovelecProtocol::~NovelecProtocol <-" << std::endl; // std::cout << "NovelecProtocol::~NovelecProtocol ->" << std::endl; } // ============================================================================ // NovelecProtocol::build_communicationLink // ============================================================================ bool NovelecProtocol::build_communicationLink() { if (_commDevName.empty()) return false; _communication_link = new TangoSerialLink (_commDevName); if (!_communication_link) return false; return true; } // ============================================================================ // NovelecProtocol::NovelecProtocol // ============================================================================ void NovelecProtocol::init_MCCE2_for_communication(void) { std::stringstream explicite_resp; std::string tmp("no data"); //- CMD to enable PROG cmds this->switch_MCCE2_OFF(); //- this command is now called in the MCCE2 device ! //- Clear error registers this->clear_registers(); //- send cmd to have an explicite response : explicite_resp << _devAdd << " PROG " << RESPONSE_LGTH_CMD_NUM << " 1" << END_OF_LINE << std::endl; tmp = _communication_link->write_read(explicite_resp.str()); //- check only the command response check_command(tmp); //- if no error _is_explicite_resp_enabled = true; } // ============================================================================ // NovelecProtocol::switch_MCCE2_ON // ============================================================================ void NovelecProtocol::switch_MCCE2_ON (void) { std::stringstream cmd_to_send; std::string tmp("no data"); //- send cmd to have a explicite response : cmd_to_send << _devAdd << " MEASURE 1 " << END_OF_LINE << std::endl; tmp = _communication_link->write_read(cmd_to_send.str()); //- check only the command response check_command(tmp); _is_measure_mode_on = true; } // ============================================================================ // NovelecProtocol::switch_MCCE2_OFF // ============================================================================ void NovelecProtocol::switch_MCCE2_OFF (void) { std::stringstream cmd_to_send; std::string tmp("no data"); //- send cmd to have a explicite response : cmd_to_send << _devAdd << " MEASURE 0 " << END_OF_LINE << std::endl; tmp = _communication_link->write_read(cmd_to_send.str()); //- check only the command response check_command(tmp); _is_measure_mode_on = false; } // ============================================================================ // NovelecProtocol::get_mode // ============================================================================ std::string NovelecProtocol::get_mode (void) { std::stringstream cmd_to_send; std::string argout("no data"); std::string tmp("no data"); //- check if the MCCE2 is not in MEASURE mode to get/change any settings this->is_allowed(); //- send command to Novelec device cmd_to_send << _devAdd << " READ " << MODE_CMD_NUM << END_OF_LINE << std::endl; tmp = _communication_link->write_read(cmd_to_send.str()); //- check and extract the response argout = check_and_extract_data(tmp, MODE_CMD_NUM); //- check what is the response mode type if( _is_explicite_resp_enabled == false ) { short idx = XString<short>::convertFromString(argout); _function = mode_str[idx]; } else _function = argout; return _function; } // ============================================================================ // NovelecProtocol::get_value // ============================================================================ std::string NovelecProtocol::get_value (void) { std::stringstream cmd_to_send; std::string tmp("no data"); std::string value("-1"); short cmd_num = 13; //- default value for DEBUG !!! //- first get mode get_mode(); if( (_function.find("OFFSET") != std::string::npos) || (_function.find("V1") != std::string::npos) ) { cmd_num = 12; } else if( (_function.find("LEAKAGE") != std::string::npos) || (_function.find("V2") != std::string::npos) ) cmd_num = 11; else std::cout << "\t\t***WARN : Current mode : \"" << get_mode() << "\" has no value available." << std::endl; cmd_to_send << _devAdd << " READ " << cmd_num << END_OF_LINE << std::endl; tmp = _communication_link->write_read(cmd_to_send.str()); //- check only the command response value = check_and_extract_data(tmp, cmd_num); return value; } // ============================================================================ // NovelecProtocol::unable_zeroVF_func // ============================================================================ void NovelecProtocol::unable_zeroVF_func (void) { std::stringstream cmd_to_send; std::string cmdNumber(" 1"); //- PROG 1 -> = PROG FUNCTION std::string tmp("no data"); //- check if the MCCE2 is not in MEASURE mode to get/change any settings this->is_allowed(); //- send cmd to have a explicite response : cmd_to_send << _devAdd << " PROG 1 " << cmdNumber << END_OF_LINE << std::endl; tmp = _communication_link->write_read(cmd_to_send.str()); //- check only the command response check_command(tmp); } // ============================================================================ // NovelecProtocol::unable_offset_zeroV1_func // ============================================================================ void NovelecProtocol::unable_offset_zeroV1_func (void) { std::stringstream cmd_to_send; std::string cmdNumber(" 2"); //- PROG 1 -> = PROG FUNCTION std::string tmp("no data"); //- check if the MCCE2 is not in MEASURE mode to get/change any settings this->is_allowed(); //- send cmd to have a explicite response : cmd_to_send << _devAdd << " PROG 1 " << cmdNumber << END_OF_LINE << std::endl; tmp = _communication_link->write_read(cmd_to_send.str()); //- check only the command response check_command(tmp); } // ============================================================================ // NovelecProtocol::unable_leakage_zeroV2_func // ============================================================================ void NovelecProtocol::unable_leakage_zeroV2_func (void) { std::stringstream cmd_to_send; std::string cmdNumber(" 3"); //- PROG 1 -> = PROG FUNCTION std::string tmp("no data"); //- check if the MCCE2 is not in MEASURE mode to get/change any settings this->is_allowed(); //- send cmd to have a explicite response : cmd_to_send << _devAdd << " PROG 1 " << cmdNumber << END_OF_LINE << std::endl; tmp = _communication_link->write_read(cmd_to_send.str()); //- check only the command response check_command(tmp); } // ============================================================================ // NovelecProtocol::unable_test_func // ============================================================================ void NovelecProtocol::unable_test_func (void) { std::stringstream cmd_to_send; std::string cmdNumber(" 4"); //- PROG 1 -> = PROG FUNCTION std::string tmp("no data"); //- check if the MCCE2 is not in MEASURE mode to get/change any settings this->is_allowed(); //- send cmd to have a explicite response : cmd_to_send << _devAdd << " PROG 1 " << cmdNumber << END_OF_LINE << std::endl; tmp = _communication_link->write_read(cmd_to_send.str()); //- check only the command response check_command(tmp); } // ============================================================================ // NovelecProtocol::unable_measure_func // ============================================================================ void NovelecProtocol::unable_measure_func (void) { std::stringstream cmd_to_send; std::string cmdNumber(" 5"); //- PROG 1 -> = PROG FUNCTION std::string tmp("no data"); //- check if the MCCE2 is not in MEASURE mode to get/change any settings this->is_allowed(); //- send cmd to have a explicite response : cmd_to_send << _devAdd << " PROG 1 " << cmdNumber << END_OF_LINE << std::endl; tmp = _communication_link->write_read(cmd_to_send.str()); //- check only the command response check_command(tmp); } // ============================================================================ // NovelecProtocol::get_range // ============================================================================ std::string NovelecProtocol::get_range (void) { std::stringstream cmd_to_send; std::string argout("no data"); std::string tmp("no data"); //- send command to Novelec device cmd_to_send << _devAdd << " READ " << RANGE_CMD_NUM << END_OF_LINE << std::endl; tmp = _communication_link->write_read(cmd_to_send.str()); //- check and extract the response argout = check_and_extract_data(tmp, RANGE_CMD_NUM); //- check what is the response mode type short idx = -1; if( _is_explicite_resp_enabled == false ) { idx = XString<short>::convertFromString(argout); argout = range_str[_novType-1][idx]; } return argout; } // ============================================================================ // NovelecProtocol::set_range // ============================================================================ void NovelecProtocol::set_range (std::string value) { std::stringstream cmd_to_send; std::string tmp("no data"); //- check if the MCCE2 is not in MEASURE mode to get/change any settings this->is_allowed(); //- send command to Novelec device cmd_to_send << _devAdd << " PROG " << _rangeParameterNum << " " << value << END_OF_LINE << std::endl; tmp = _communication_link->write_read(cmd_to_send.str()); //- the novelec device send ACK/NAK response after a received command check_command(tmp); } // ============================================================================ // NovelecProtocol::get_polarity // ============================================================================ std::string NovelecProtocol::get_polarity (void) { std::stringstream cmd_to_send; std::string argout("no data"); std::string tmp("no data"); //- send command to Novelec device cmd_to_send << _devAdd << " READ " << POLARITY_CMD_NUM << END_OF_LINE << std::endl; tmp = _communication_link->write_read(cmd_to_send.str()); //- check and extract the response argout = check_and_extract_data(tmp, POLARITY_CMD_NUM); //- check what is the response mode type if( _is_explicite_resp_enabled == false ) { short idx = XString<short>::convertFromString(argout); if(idx < 0) argout = "negative"; else argout = "positive"; } return argout; } // ============================================================================ // NovelecProtocol::set_polarity // ============================================================================ void NovelecProtocol::set_polarity (std::string newPolarity) { std::stringstream cmd_to_send; std::string tmp("no data"); //- check if the MCCE2 is not in MEASURE mode to get/change any settings this->is_allowed(); //- send command to Novelec device cmd_to_send << _devAdd << " PROG 2" << " " << newPolarity << END_OF_LINE << std::endl; tmp = _communication_link->write_read(cmd_to_send.str()); //- the novelec device send ACK/NAK response after a received command check_command(tmp); } // ============================================================================ // NovelecProtocol::get_frequency // ============================================================================ std::string NovelecProtocol::get_frequency (void) { std::stringstream cmd_to_send; std::string argout("no data"); std::string tmp(""); //- send command to Novelec device cmd_to_send << _devAdd << " READ " << FREQUENCY_CMD_NUM << END_OF_LINE << std::endl; tmp = _communication_link->write_read(cmd_to_send.str()); //- check and extract the response argout = check_and_extract_data(tmp, FREQUENCY_CMD_NUM); //- check what is the response mode type if( _is_explicite_resp_enabled == false ) { short idx = XString<short>::convertFromString(argout); argout = frequency_str[idx]; } return argout; } // ============================================================================ // NovelecProtocol::set_frequency // ============================================================================ void NovelecProtocol::set_frequency (std::string newFrequency) { std::stringstream cmd_to_send; std::string tmp("no data"); //- check if the MCCE2 is not in MEASURE mode to get/change any settings this->is_allowed(); //- send command to Novelec device cmd_to_send << _devAdd << " PROG 9" << " " << newFrequency << END_OF_LINE << std::endl; tmp = _communication_link->write_read(cmd_to_send.str()); //- the novelec device send ACK/NAK response after a received command check_command(tmp); } // ============================================================================ // NovelecProtocol::get_gain // ============================================================================ std::string NovelecProtocol::get_gain (void) { std::stringstream cmd_to_send; std::string argout("no data"); std::string tmp("no data"); //- send command to Novelec device cmd_to_send << _devAdd << " READ " << GAIN_CMD_NUM << END_OF_LINE << std::endl; tmp = _communication_link->write_read(cmd_to_send.str()); //- check and extract the response argout = check_and_extract_data(tmp, GAIN_CMD_NUM); //- check what is the response mode type if( _is_explicite_resp_enabled == false ) { short idx = XString<short>::convertFromString(argout); argout = gain_str[idx]; } else //- erase wildcard char : response received is as this "*10xx" argout = argout.erase(argout.find('*'),1); return argout; } // ============================================================================ // NovelecProtocol::set_gain // ============================================================================ void NovelecProtocol::set_gain (std::string newGain) { std::stringstream cmd_to_send; std::string tmp("no data"); //- check if the MCCE2 is not in MEASURE mode to get/change any settings this->is_allowed(); //- send command to Novelec device cmd_to_send << _devAdd << " PROG 8" << " " << newGain << END_OF_LINE << std::endl; tmp = _communication_link->write_read(cmd_to_send.str()); //- the novelec device send ACK/NAK response after a received command check_command(tmp); } // ============================================================================ // NovelecProtocol::get_errors // ============================================================================ std::string NovelecProtocol::get_errors (void) { std::stringstream cmd_to_send; std::string argout("no data"); std::string tmp("no data"); //- send command to Novelec device cmd_to_send << _devAdd << " READ " << ERRORS_CMD_NUM << END_OF_LINE << std::endl; tmp = _communication_link->write_read(cmd_to_send.str()); //- check and extract the response argout = check_and_extract_data(tmp, ERRORS_CMD_NUM); return argout; } // ============================================================================ // NovelecProtocol::get_electrotype // ============================================================================ std::string NovelecProtocol::get_electrotype (void) { std::stringstream cmd_to_send; std::string argout("no data"); std::string tmp("no data"); //- send command to Novelec device cmd_to_send << _devAdd << " READ " << ELECTROTYPE_CMD_NUM << END_OF_LINE << std::endl; tmp = _communication_link->write_read(cmd_to_send.str()); //- check and extract the response argout = check_and_extract_data(tmp, ELECTROTYPE_CMD_NUM); //- check what is the response mode type if( _is_explicite_resp_enabled == true ) argout = argout.substr(argout.find(".")+1); return argout; } // ============================================================================ // NovelecProtocol::reset // ============================================================================ void NovelecProtocol::reset (void) { std::stringstream cmd_to_send; //- send command cmd_to_send << _devAdd << " RESET" << END_OF_LINE << std::endl; _communication_link->write(cmd_to_send.str()); //- there is no response from the device !!! } // ============================================================================ // NovelecProtocol::local // ============================================================================ void NovelecProtocol::local (void) { std::stringstream cmd_to_send; std::string tmp("no data"); //- check if the MCCE2 is not in MEASURE mode to get/change any settings this->is_allowed(); //- send command cmd_to_send << _devAdd << " LOCAL" << END_OF_LINE << std::endl; tmp = _communication_link->write_read(cmd_to_send.str()); //- check the response check_command(tmp); } // ============================================================================ // NovelecProtocol::remote // ============================================================================ void NovelecProtocol::remote (void) { std::stringstream cmd_to_send; std::string tmp("no data"); //- check if the MCCE2 is not in MEASURE mode to get/change any settings this->is_allowed(); //- send command cmd_to_send << _devAdd << " REMOTE" << END_OF_LINE << std::endl; tmp = _communication_link->write_read(cmd_to_send.str()); //- check the response check_command(tmp); } // ============================================================================ // NovelecProtocol::get_raw_status // ============================================================================ std::string NovelecProtocol::get_raw_status (void) { std::stringstream cmd_to_send; std::string argout("no data"); std::string tmp("no data"); //- send command to Novelec device cmd_to_send << _devAdd << " READ " << STATUS_CMD_NUM << END_OF_LINE << std::endl; tmp = _communication_link->write_read(cmd_to_send.str()); //- check and extract the response argout = check_and_extract_data(tmp, STATUS_CMD_NUM); return argout; } // ============================================================================ // NovelecProtocol::clear_registers // ============================================================================ void NovelecProtocol::clear_registers (void) { std::stringstream cmd_to_send; std::string tmp("no data"); //- send command cmd_to_send << _devAdd << " PROG " << CLEAR_ERRORS_CMD_NUM << " 1 " << END_OF_LINE << std::endl; tmp = _communication_link->write_read(cmd_to_send.str()); //- check the response check_command(tmp); } // ============================================================================ // NovelecProtocol::is_allowed // ============================================================================ void NovelecProtocol::is_allowed (void) { if(this-> _is_measure_mode_on) throw electrometer::ElectrometerException("COMMAND_NOT_ALLOWED", "Cannot change parameter(s) when MEASURE mode enabled : call MCCE2_OFF command.", "NovelecProtocol::check_command( )."); } // ============================================================================ // NovelecProtocol::check_command // This method read the device response and check and throw an // Electrometer Exception if the device response is a NAK. // Else, it returns the extracted response // ============================================================================ void NovelecProtocol::check_command (std::string response) { std::string data; //- A correct response is : // -> "address ACK " : if command well understood //- An invalid response is: "address NAK ..." if(response.find("NAK") != std::string::npos) { throw electrometer::ElectrometerException("COMMAND_NOT_UNDERSTOOD", "Bad formatted string command sent -> NAK received !", "NovelecProtocol::check_command( )."); } else if(response.find("ACK") != std::string::npos) data = response; else //- must not exist !!! throw electrometer::ElectrometerException("INVALID_DATA", "Invalid string received from Novelec device.", "NovelecProtocol::check_command( )."); } // ============================================================================ // NovelecProtocol::check_and_extract_data // This method read the device response and check and throw an // Electrometer Exception if the device response is a NAK. // Else, it returns the extracted response // ============================================================================ std::string NovelecProtocol::check_and_extract_data (std::string response, short cmd_sent) { std::string data; std::string cmd_sentStr; cmd_sentStr = XString<short>::convertToString(cmd_sent); //- A correct response is : // -> "address AWR ReadNum = data " : if there is a returned value //- An invalid response is: "address NAK ..." if(response.find("NAK") != std::string::npos) { throw electrometer::ElectrometerException("COMMAND_NOT_UNDERSTOOD", "Bad formatted string command sent -> NAK received !", "NovelecProtocol::check_and_extract_data( )."); } else if(response.find("AWR") != std::string::npos) { //- check if it is the received answer of the command sent if(response.find(cmd_sentStr) != std::string::npos) { //- extract data in the device response data = response.substr(response.find("=")+1); /* * check if the response is a short or explicite response * * To do so, check if char at idx 18 is a space or a letter : * if it is a space -> this is a short response * and must be converted to return the explicite response * else it is an explicite response and can be returned as this */ //- extract char response = response.substr(18,1); //- check what is this char a 'space' or 'letter' if(response.find(" ") != std::string::npos) _is_explicite_resp_enabled = false; else _is_explicite_resp_enabled = true; //- erase first and last space char data.erase(data.find_first_of(" "),1); data.erase(data.find_last_of(" ")); } else throw electrometer::ElectrometerException("SYNCHRONISATION_LOST", "The received response is not for the command previously sent.", "NovelecProtocol::check_and_extract_data( )."); } else //- must not exist !!! throw electrometer::ElectrometerException("INVALID_DATA", "Invalid string received from Novelec device.", "NovelecProtocol::check_and_extract_data( )."); return data; }