static const char *RcsId = "$Id: DevServ.cpp 13293 2009-04-07 10:53:56Z pascal_verdier $"; //+============================================================================= // // file : SingleShotAO.cpp // // description : C++ source for the SingleShotAO and its commands. // The class is derived from Device. It represents the // CORBA servant object which will be accessed from the // network. All commands which can be executed on the // SingleShotAO are implemented in this file. // // project : TANGO Device Server // // $Author: pascal_verdier $ // // $Revision: 13293 $ // // $Revision: 13293 $ // $Date: 2009-04-07 12:53:56 +0200 (Tue, 07 Apr 2009) $ // // SVN only: // $HeadURL: $ // // CVS only: // $Source$ // $Log$ // Revision 3.5 2007/10/24 12:07:35 pascal_verdier // Another spelling mistake correction // // Revision 3.4 2007/10/23 14:04:30 pascal_verdier // Spelling mistakes correction // // Revision 3.3 2005/03/02 14:06:15 pascal_verdier // namespace is different than class name. // // Revision 3.2 2004/11/08 11:33:16 pascal_verdier // if device property not found in database, it takes class property value if exists. // // Revision 3.1 2004/09/06 09:27:05 pascal_verdier // Modified for Tango 5 compatibility. // // // copyleft : Synchrotron SOLEIL // L'Orme des merisiers - Saint Aubin // BP48 - 91192 Gif sur Yvette // FRANCE // //-============================================================================= // // This file is generated by POGO // (Program Obviously used to Generate tango Object) // // (c) - Software Engineering Group - ESRF //============================================================================= //=================================================================== // // The following table gives the correspondence // between commands and method name. // // Command name| Method name // ---------------------------------------- // State | dev_state() // Status | dev_status() // Abort | abort() // //=================================================================== #include <tango.h> #include <yat4tango/Logging.h> #include <yat4tango/DeviceInfo.h> #include <SingleShotAO.h> #include <SingleShotAOClass.h> #include "SingleShotAOTypesAndConsts.h" namespace SingleShotAO_ns { //- check manager macro: #define CHECK_MANAGER() \ do \ { \ if (! m_manager) \ THROW_DEVFAILED("DEVICE_ERROR", \ "request aborted - the manager isn't accessible ", \ "SingleShotAO::check_manager"); \ } while (0) //+---------------------------------------------------------------------------- // // method : SingleShotAO::SingleShotAO(string &s) // // description : constructor for simulated SingleShotAO // // in : - cl : Pointer to the DeviceClass object // - s : Device name // //----------------------------------------------------------------------------- SingleShotAO::SingleShotAO(Tango::DeviceClass *cl,string &s) :TANGO_BASE_CLASS(cl,s.c_str()) { init_device(); } SingleShotAO::SingleShotAO(Tango::DeviceClass *cl,const char *s) :TANGO_BASE_CLASS(cl,s) { init_device(); } SingleShotAO::SingleShotAO(Tango::DeviceClass *cl,const char *s,const char *d) :TANGO_BASE_CLASS(cl,s,d) { init_device(); } //+---------------------------------------------------------------------------- // // method : SingleShotAO::delete_device() // // description : will be called at device destruction or at init command. // //----------------------------------------------------------------------------- void SingleShotAO::delete_device() { DEBUG_STREAM << "SingleShotAO::delete_device(): entering... !" << endl; // Make sure running processes are aborted properly if channels are running //-------------------------------------------- try { _abort(); } catch (Tango::DevFailed &df) { ERROR_STREAM << df << endl; RETHROW_DEVFAILED(df, "DRIVER_FAILURE", "could not abort [caught Tango::DevFailed]", "SingleShotAO::delete_device"); } catch (...) { ERROR_STREAM << "SingleShotAO::init::unknown exception caught" << std::endl; THROW_DEVFAILED("DRIVER_FAILURE", "could not abort [unknown error]", "SingleShotAO::delete_device"); } // Delete device allocated objects //-------------------------------------------- yat4tango::TraceHelper t("SingleShotAO::delete_device", this); if (m_manager) { m_manager->exit(); m_manager = NULL; } // Release the asl::SingleShotAO object //-------------------------------------------- if (m_ssao) { delete m_ssao; m_ssao = NULL; } // Remove dynamic attributes //-------------------------------------------- if (m_dyn_attr_manager) { try { m_dyn_attr_manager->remove_attributes(); } catch (...) { //- ignore any error } } // delete dynamic attributes manager if (m_dyn_attr_manager) { delete m_dyn_attr_manager; m_dyn_attr_manager = NULL; } // Remove the inner appender //-------------------------------------------- yat4tango::Logging::release(this); yat4tango::DeviceInfo::release(this); } //+---------------------------------------------------------------------------- // // method : SingleShotAO::init_device() // // description : will be called at device initialization. // //----------------------------------------------------------------------------- void SingleShotAO::init_device() { //- initialize the inner appender (first thing to do) try { INFO_STREAM << "Create the InnerAppender & FileAppender in order to manage logs." << endl; yat4tango::Logging::initialize(this); INFO_STREAM << "Create the DeviceInfo in order to manage info on versions." << endl; yat4tango::DeviceInfo::initialize(this, YAT_XSTR(PROJECT_NAME), YAT_XSTR(PROJECT_VERSION)); yat4tango::DeviceInfo::add_dependency(this, "ASL", ">=1.0"); } catch (Tango::DevFailed &df) { ERROR_STREAM << df << std::endl; m_state = Tango::FAULT; m_currStatus = "initialization failed - could not instantiate the InnerAppender"; return; } INFO_STREAM << "Initializing device"; //- trace/profile this method yat4tango::TraceHelper t("SingleShotAO::init_device", this); // construct the AO manager //-------------------------------------------- try { m_manager = new SingleShotAOManager(this); } catch (...) { ERROR_STREAM << "initialization failed - failed to create manager" << std::endl; m_currStatus = "initialization failed [failed to create manager]. See log for details"; m_state = Tango::FAULT; return; } // Initialise variables to default values //-------------------------------------------- //- init members m_ssao = NULL; critical_properties_missing = false; isInitOk = false; m_frequency = 0.0; m_dyn_attr_manager = NULL; m_state = Tango::INIT; // Initialise variables to default values //-------------------------------------------- try { get_device_property(); } catch (const Tango::DevFailed& df) { ERROR_STREAM << "SingleShotAO::init_device::Tango::DevFailed exception caught " << "while trying to read device properties from TANGO database" << std::endl; std::string error_msg = df.errors[0].desc; std::istringstream error_stream(error_msg); std::string line; std::getline(error_stream, line); // Read the first line ERROR_STREAM << line << std::endl; while (std::getline(error_stream, line)) { // Read the rest of the lines ERROR_STREAM << " - " << line << std::endl; } m_currStatus = error_msg; m_state = Tango::FAULT; return; } catch (...) { //- update internal state ERROR_STREAM << "SingleShotAO::init_device::unknown exception caught " << "while trying to read device properties from TANGO database" << std::endl; m_currStatus = "Failed to get property. See log for details"; m_state = Tango::FAULT; return; } //- abort initialization if properties missing if (critical_properties_missing) { ERROR_STREAM << "configuration error - unspecified or invalid device properties"; m_currStatus = "configuration error [unspecified or invalid device properties]. See log for details"; m_state = Tango::FAULT; return; } //- allocate the asl::SingleShotAO object m_ssao = new asl::SingleShotAO; if (m_ssao == 0) { m_currStatus = "Failed to create the SignleShotAO. See log for details"; m_state = Tango::FAULT; return; } try { //- initialze the hardware m_ssao->init(boardTypeId, boardNum); } catch(const asl::DAQException& de) { ERROR_STREAM << daq_to_tango_exception(de) << endl; m_currStatus = "Failed to init the SignleShotAO. See log for details"; m_state = Tango::FAULT; return; } catch(...) { ERROR_STREAM << "SingleShotAO::init_device::unknown exception caught"<<std::endl; m_currStatus = "Failed to init the SignleShotAO. See log for details"; m_state = Tango::FAULT; return; } // initialize channel number according to board type m_nb_chan = 0; if (boardType == k6208_BOARD_TYPE) { m_nb_chan = 8; } if (boardType == k6216_BOARD_TYPE) { m_nb_chan = 16; } INFO_STREAM << "Board has " << m_nb_chan << " channels" << endl; // test the manager if (!m_manager) { ERROR_STREAM << "initialization failed - the manager is not created" << std::endl; m_currStatus = "initialization failed [the manager is not created]. See log for details"; m_state = Tango::FAULT; return; } // get frequency value in database //-------------------------------------------- try { m_frequency = yat4tango::PropertyHelper::get_memorized_attribute<double>(this, "frequency"); DEBUG_STREAM << "Frequency : " << m_frequency << endl; } catch (...) { DEBUG_STREAM << "No memorized value found for frequency. Defaulting to " << m_frequency << "." << std::endl; } // initialize the AO manager //-------------------------------------------- try { m_manager->init(m_ssao, m_nb_chan, m_frequency, enableRamps); } catch (Tango::DevFailed & df) { ERROR_STREAM << df << std::endl; m_currStatus = "initialization failed - Manager initialization failed [see device log for details]"; m_state = Tango::FAULT; return; } catch (...) { ERROR_STREAM << "initialization failed - failed to initialize manager" << std::endl; m_currStatus = "initialization failed [failed to initialize manager]. See log for details"; m_state = Tango::FAULT; return; } // Remove existing dynamic attributes to avoid duplicates or other issues // -------------------------------------------- if (m_dyn_attr_manager) { try { m_dyn_attr_manager->remove_attributes(); delete m_dyn_attr_manager; m_dyn_attr_manager = NULL; DEBUG_STREAM << "Existing dynamic attributes manager cleaned up" << endl; } catch (...) { ERROR_STREAM << "Error cleaning up existing dynamic attributes manager, continuing..." << endl; // Continue anyway - we'll create a new one } } // Create dynamic attributes //-------------------------------------------- // create dynamic attribute manager try { m_dyn_attr_manager = new yat4tango::DynamicAttributeManager(this); } catch (Tango::DevFailed &e) { ERROR_STREAM << e << std::endl; m_currStatus = "Failed to create Dynamic Attribute Manager. See log for details"; m_state = Tango::FAULT; return; } catch (...) { ERROR_STREAM << "Failed to create Dynamic Attribute Manager" << std::endl; m_currStatus = "Failed to create Dynamic Attribute Manager. See log for details"; m_state = Tango::FAULT; return; } // add dynamic attributes: channel, speed & initial for each channel std::vector<yat4tango::DynamicAttributeInfo> l_dynAttrList; // Log how many attributes we're going to create INFO_STREAM << "Creating dynamic attributes for " << m_nb_chan << " channels."; INFO_STREAM << "Total attributes: " << m_nb_chan * (enableRamps ? 3 : 1) << endl; for (unsigned int l_cpt = 0; l_cpt < m_nb_chan; l_cpt++) { yat::OSStream oss; oss << l_cpt; // ╔═══════════════╗ // ║ Channel value ║ // ╚═══════════════╝ yat4tango::DynamicAttributeInfo dai_channel; dai_channel.dev = this; dai_channel.tai.name = kCHANNEL + oss.str(); dai_channel.tai.label = kCHANNEL + oss.str(); //- describe the dyn attr we want... dai_channel.tai.data_type = Tango::DEV_DOUBLE; dai_channel.tai.data_format = Tango::SCALAR; dai_channel.tai.writable = Tango::READ_WRITE; // soso dai_channel.tai.disp_level = Tango::OPERATOR; dai_channel.tai.unit = "V"; dai_channel.tai.standard_unit = "V"; dai_channel.tai.display_unit = "V"; dai_channel.tai.max_value = "10.0"; dai_channel.tai.min_value = "-10.0"; dai_channel.tai.description = "Output value for channel " + oss.str() + " (in measurementUnit)."; dai_channel.tai.format = "%5.3f"; dai_channel.cdb = false; //- read callback dai_channel.rcb = yat4tango::DynamicAttributeReadCallback::instanciate(const_cast<SingleShotAO&>(*this), &SingleShotAO::read_channel); //- write callback dai_channel.wcb = yat4tango::DynamicAttributeWriteCallback::instanciate(const_cast<SingleShotAO&>(*this), &SingleShotAO::write_channel); l_dynAttrList.push_back(dai_channel); // if enableRamps if false, skip speed and initial attributes if (!enableRamps) { DEBUG_STREAM << "Ramps are disabled. Skipping speed and initial attributes for channel " << l_cpt << std::endl; continue; } // ╔═══════════════╗ // ║ Speed value ║ // ╚═══════════════╝ yat4tango::DynamicAttributeInfo dai_speed; dai_speed.dev = this; dai_speed.tai.name = kSPEED + oss.str(); dai_speed.tai.label = kSPEED + oss.str(); //- describe the dyn attr we want... dai_speed.tai.data_type = Tango::DEV_DOUBLE; dai_speed.tai.data_format = Tango::SCALAR; dai_speed.tai.writable = Tango::READ_WRITE; dai_speed.tai.disp_level = Tango::OPERATOR; dai_speed.tai.unit = "V/s"; dai_speed.tai.standard_unit = "V/s"; dai_speed.tai.display_unit = "V/s"; dai_speed.tai.description = "Speed for ramp generation, in V/s. If speed is NULL, no ramp generated but direct write on channel output " + oss.str() + " (in measurementUnit)."; dai_speed.tai.format = "%5.3f"; //- cleanup tango db option: cleanup tango db when removing this dyn. attr. (i.e. erase its properties from db) dai_speed.cdb = false; //- read callback dai_speed.rcb = yat4tango::DynamicAttributeReadCallback::instanciate(const_cast<SingleShotAO&>(*this), &SingleShotAO::read_speed); //- write callback dai_speed.wcb = yat4tango::DynamicAttributeWriteCallback::instanciate(const_cast<SingleShotAO&>(*this), &SingleShotAO::write_speed); l_dynAttrList.push_back(dai_speed); // ╔═══════════════╗ // ║ Initial value ║ // ╚═══════════════╝ yat4tango::DynamicAttributeInfo dai_initial; dai_initial.dev = this; dai_initial.tai.name = kINITIAL + oss.str(); dai_initial.tai.label = kINITIAL + oss.str(); //- describe the dyn attr we want... dai_initial.tai.data_type = Tango::DEV_DOUBLE; dai_initial.tai.data_format = Tango::SCALAR; dai_initial.tai.writable = Tango::READ_WRITE; dai_initial.tai.disp_level = Tango::OPERATOR; dai_initial.tai.unit = "V"; dai_initial.tai.standard_unit = "V"; dai_initial.tai.display_unit = "V"; dai_initial.tai.description = "Initial value for ramp function, in V. Defaults to last written value in channel attribute " + oss.str() + "."; dai_initial.tai.format = "%5.3f"; //- cleanup tango db option: cleanup tango db when removing this dyn. attr. (i.e. erase its properties from db) dai_initial.cdb = false; //- read callback dai_initial.rcb = yat4tango::DynamicAttributeReadCallback::instanciate(const_cast<SingleShotAO&>(*this), &SingleShotAO::read_initial); //- write callback dai_initial.wcb = yat4tango::DynamicAttributeWriteCallback::instanciate(const_cast<SingleShotAO&>(*this), &SingleShotAO::write_initial); l_dynAttrList.push_back(dai_initial); } // Log the size of our attribute list before adding to manager INFO_STREAM << "Prepared " << l_dynAttrList.size() << " dynamic attributes for creation" << endl; // Add all attributes try { m_dyn_attr_manager->add_attributes(l_dynAttrList); INFO_STREAM << "Successfully added all dynamic attributes" << endl; } catch (Tango::DevFailed &df) { ERROR_STREAM << "Failed to add dynamic attributes: " << df << endl; m_currStatus = "Failed to add dynamic attributes. See log for details"; m_state = Tango::FAULT; return; } catch (...) { ERROR_STREAM << "Unknown exception when adding dynamic attributes" << endl; m_currStatus = "Failed to add dynamic attributes. Unknown error"; m_state = Tango::FAULT; return; } // Initialize maps in manager class for all channels try { for (unsigned int l_cpt = 0; l_cpt < m_nb_chan; l_cpt++) { // Initialize with default values m_manager->set_channel(l_cpt, 0.0); if (enableRamps) { m_manager->set_speed(l_cpt, 0.0); m_manager->set_initial(l_cpt, 0.0); } } } catch (Tango::DevFailed &df) { ERROR_STREAM << "Failed to initialize channel maps: " << df << endl; m_currStatus = "Failed to initialize channel maps. See log for details"; m_state = Tango::FAULT; return; } // Get memorized values from database for (unsigned int l_cpt = 0; l_cpt < m_nb_chan; l_cpt++) { yat::OSStream oss; oss << l_cpt; // Helper function to get and set memorized attributes auto applyMemorizedAttr = [&](const std::string& attrPrefix, void (SingleShotAOManager::*setter)(yat::uint16, double)) { std::string attrName = attrPrefix + oss.str(); try { double val = yat4tango::PropertyHelper::get_memorized_attribute<double>(this, attrName); DEBUG_STREAM << "Found memorized value for " << attrName << ": " << val << endl; // Write the value to the manager (that contains the "read" attributes values) (m_manager->*setter)(l_cpt, val); // Write the value to the "write" attributes using helper function setDynamicAttributeWriteValue(attrName, val); } catch (...) { DEBUG_STREAM << "No memorized value found for " << attrName << ". Setting default value." << std::endl; } }; // Get and set memorized values for speed, initial and channel if (enableRamps) { applyMemorizedAttr(kSPEED, &SingleShotAOManager::set_speed); applyMemorizedAttr(kINITIAL, &SingleShotAOManager::set_initial); } if (outputMemorizedChannelsAtInit) { applyMemorizedAttr(kCHANNEL, &SingleShotAOManager::write_channel_direct); // write memorized value to board output (directly, without ramp) } else { applyMemorizedAttr(kCHANNEL, &SingleShotAOManager::set_channel); // only apply memorized value to the device } } //- GO for task try { m_manager->go(); } catch (Tango::DevFailed & df) { ERROR_STREAM << df << std::endl; m_currStatus = "initialization failed [failed to go for manager]"; m_state = Tango::FAULT; return; } catch (...) { ERROR_STREAM << "initialization failed - failed to go for manager" << std::endl; m_currStatus = "initialization failed [failed to go for manager]. See log for details"; m_state = Tango::FAULT; return; } //- update internal state m_state = Tango::ON; m_currStatus = "Device ready to execute AO request."; isInitOk = true; } //+------------------------------------------------------------------ /** * method : SingleShotAO::get_device_property() * * description : Read the device properties from database. * * @throws DevFailed if any critical property is missing, not set, or invalid */ void SingleShotAO::get_device_property() { // Read device properties from database //------------------------------------------------------------------ Tango::DbData dev_prop; dev_prop.push_back(Tango::DbDatum("BoardNum")); dev_prop.push_back(Tango::DbDatum("BoardType")); dev_prop.push_back(Tango::DbDatum("EnableRamps")); dev_prop.push_back(Tango::DbDatum("OutputMemorizedChannelsAtInit")); // Call database and extract values //-------------------------------------------- if (Tango::Util::instance()->_UseDb==true) { get_db_device()->get_property(dev_prop); } Tango::DbDatum def_prop, cl_prop; SingleShotAOClass *ds_class = (static_cast<SingleShotAOClass *>(get_device_class())); int i = -1; //- <BoardNum> ----------------------- // Try to initialize BoardNum from class property cl_prop = ds_class->get_class_property(dev_prop[++i].name); if (cl_prop.is_empty()==false) cl_prop >> boardNum; else { // Try to initialize BoardNum from default device value def_prop = ds_class->get_default_device_property(dev_prop[i].name); if (def_prop.is_empty() == false) { def_prop >> boardNum_default; def_prop >> boardNum; } } // And try to extract BoardNum value from database if (dev_prop[i].is_empty() == false) dev_prop[i] >> boardNum; INFO_STREAM << "Raw BoardNum parsed: " << boardNum << endl; //- <BoardType> ----------------------- // Try to initialize BoardType from class property cl_prop = ds_class->get_class_property(dev_prop[++i].name); if (cl_prop.is_empty() == false) cl_prop >> boardType; else { // Try to initialize BoardType from default device value def_prop = ds_class->get_default_device_property(dev_prop[i].name); if (def_prop.is_empty() == false) { def_prop >> boardType_default; def_prop >> boardType; } } // And try to extract BoardType value from database if (dev_prop[i].is_empty() == false) dev_prop[i] >> boardType; INFO_STREAM << "Raw BoardType parsed: " << boardType << endl; //- <EnableRamps> ----------------------- // Try to initialize EnableRamps from class property cl_prop = ds_class->get_class_property(dev_prop[++i].name); if (cl_prop.is_empty() == false) cl_prop >> enableRamps; else { // Try to initialize EnableRamps from default device value def_prop = ds_class->get_default_device_property(dev_prop[i].name); if (def_prop.is_empty() == false) { def_prop >> enableRamps_default; def_prop >> enableRamps; } } // And try to extract EnableRamps value from database if (dev_prop[i].is_empty() == false) dev_prop[i] >> enableRamps; INFO_STREAM << "EnableRamps parsed: " << (enableRamps ? "true" : "false") << endl; //- <OutputMemorizedChannelsAtInit> ----------------------- // Try to initialize OutputMemorizedChannelsAtInit from class property cl_prop = ds_class->get_class_property(dev_prop[++i].name); if (cl_prop.is_empty() == false) cl_prop >> outputMemorizedChannelsAtInit; else { // Try to initialize OutputMemorizedChannelsAtInit from default device value def_prop = ds_class->get_default_device_property(dev_prop[i].name); if (def_prop.is_empty() == false) { def_prop >> outputMemorizedChannelsAtInit_default; def_prop >> outputMemorizedChannelsAtInit; } } // And try to extract OutputMemorizedChannelsAtInit value from database if (dev_prop[i].is_empty() == false) dev_prop[i] >> outputMemorizedChannelsAtInit; INFO_STREAM << "OutputMemorizedChannelsAtInit parsed: " << (outputMemorizedChannelsAtInit ? "true" : "false") << endl; // Create properties if empty and set default values //-------------------------------------------- DEBUG_STREAM << "Creating properties if empty" << endl; yat4tango::PropertyHelper::create_property_if_empty(this, dev_prop, boardNum_default, "BoardNum"); yat4tango::PropertyHelper::create_property_if_empty(this, dev_prop, boardType_default, "BoardType"); yat4tango::PropertyHelper::create_property_if_empty(this, dev_prop, enableRamps_default, "EnableRamps"); yat4tango::PropertyHelper::create_property_if_empty(this, dev_prop, outputMemorizedChannelsAtInit_default, "OutputMemorizedChannelsAtInit"); // Check critical properties being valid //-------------------------------------------- DEBUG_STREAM << "Checking if critical properties are valid:" << endl; critical_properties_missing = false; yat::OSStream errorMessages; errorMessages << "Critical properties are missing or invalid:" << endl; //- <BoardNum> ----------------------- // Case 1 (error): boardNum is set to the default value in the database if (boardNum == boardNum_default) { errorMessages << "Device property <BoardNum> is not set (default value " << boardNum_default << " needs to be replaced)" << endl; critical_properties_missing = true; } // Case 2 (error): boardNum is set to a value outside the valid range else if (boardNum < 0 || boardNum > 7) { boardNum = 0; errorMessages << "Device property <BoardNum> is invalid. Valid range is [0..7]" << endl; critical_properties_missing = true; } // Case 3 (ok): boardNum is set to a valid value else { INFO_STREAM << "BoardNum resolved to " << boardNum << endl; } //- <BoardType> ----------------------- // Case 1 (error): boardType is set to the default value in the database if (boardType == boardType_default || boardType == "") { errorMessages << "Device property <BoardType> is not set (default value " << boardType_default << " needs to be replaced)" << endl; critical_properties_missing = true; } // Case 2 (ok): boardType is set to a valid else if (boardType == "MAO_6208") { boardType = k6208_BOARD_TYPE; boardTypeId = adl::PCI6208; INFO_STREAM << "BoardType resolved to PCI6208" << endl; } else if (boardType == "MAO_6216") { boardType = k6216_BOARD_TYPE; boardTypeId = adl::PCI6216; INFO_STREAM << "BoardType resolved to PCI6216" << endl; } // Case 3 (error): boardType is set to an invalid value else { boardType = kDEFAULT_BOARD_TYPE; boardTypeId = adl::PCI6208; errorMessages << "Device property <BoardType> is invalid [supported hw: MAO_6208 or MAO_6216]" << endl; critical_properties_missing = true; } // If any critical property is missing or invalid, throw an exception if (critical_properties_missing) { DEBUG_STREAM << "Critical properties are missing, throwing exception." << endl; THROW_DEVFAILED("DEVICE_ERROR", errorMessages.str().c_str(), "SingleShotAO::get_device_property"); } else { DEBUG_STREAM << "All critical properties are valid." << endl; } } //+---------------------------------------------------------------------------- // // method : SingleShotAO::always_executed_hook() // // description : method always executed before any command is executed // //----------------------------------------------------------------------------- void SingleShotAO::always_executed_hook() { // nothing to do } //+---------------------------------------------------------------------------- // // method : SingleShotAO::read_attr_hardware // // description : Hardware acquisition for attributes. // //----------------------------------------------------------------------------- void SingleShotAO::read_attr_hardware(vector<long> &attr_list) { // nothing to do } //+---------------------------------------------------------------------------- // // method : SingleShotAO::read_frequency // // description : Extract real attribute values for Frequency acquisition result. // //----------------------------------------------------------------------------- void SingleShotAO::read_frequency(Tango::Attribute &attr) { attr.set_value(&m_frequency); } //+---------------------------------------------------------------------------- // // method : SingleShotAO::write_frequency // // description : Write Frequency attribute values to hardware. // //----------------------------------------------------------------------------- void SingleShotAO::write_frequency(Tango::WAttribute &attr) { DEBUG_STREAM << "SingleShotAO::write_frequency(Tango::WAttribute &attr) entering... "<< endl; if (dev_state() != Tango::ON) { THROW_DEVFAILED("DEVICE_ERROR", "could not write frequency. The state must be ON.", "SingleShotAO::write_frequency"); } CHECK_MANAGER(); attr.get_write_value(m_frequency); m_manager->write_frequency(m_frequency); yat4tango::PropertyHelper::set_memorized_attribute(this, "frequency", m_frequency); } //+------------------------------------------------------------------ /** * method: SingleShotAO::dev_state * * description: method to execute "State" * This command gets the device state (stored in its <i>device_state</i> data member) and returns it to the caller. * * @return State Code * */ //+------------------------------------------------------------------ Tango::DevState SingleShotAO::dev_state() { if (isInitOk) { CHECK_MANAGER(); m_state = m_manager->get_state(); } return m_state; } //+------------------------------------------------------------------ /** * method: SingleShotAO::dev_status * * description: method to execute "Status" * This command gets the device status (stored in its <i>device_status</i> data member) and returns it to the caller. * * @return Status description * */ //+------------------------------------------------------------------ Tango::ConstDevString SingleShotAO::dev_status() { static std::string s = ""; yat::OSStream oss; if (isInitOk) { CHECK_MANAGER(); oss << m_manager->get_status() << std::endl; } else { oss << m_currStatus.c_str() << std::endl; } s = oss.str(); return s.c_str(); } //+------------------------------------------------------------------ /** * Extract the number from a dynamic attribute name with a specific prefix. * Used for parsing dynamic attribute names like "channelX", "speedX", "initialX" * where X is the channel number. * * @param str The input string to search for numbers * @param prefix The expected prefix (e.g., "channel", "speed", "initial") * @return The number found after the prefix * @throws DevFailed if string doesn't start with prefix or no number is found */ int extractNumber(const std::string &str, const char* prefix) { // Validate string starts with the given prefix if (str.find(prefix) != 0) { THROW_DEVFAILED("DEVICE_ERROR", "String must start with the expected prefix", "SingleShotAO::extractNumber"); } // Find first digit after the prefix size_t pos = strlen(prefix); // Extract and convert the number std::string numberStr = str.substr(pos); if (numberStr.empty() || !isdigit(numberStr[0])) { THROW_DEVFAILED("DEVICE_ERROR", "No number found after prefix", "SingleShotAO::extractNumber"); } return std::stoi(numberStr); } //+------------------------------------------------------------------ /** * method: SingleShotAO::read_channel * * description: method to execute "read_channel" for dynamic attributes * */ //+------------------------------------------------------------------ void SingleShotAO::read_channel(yat4tango::DynamicAttributeReadCallbackData & cbd) { yat::AutoMutex<> guard(m_lock); std::string l_attr_name = cbd.dya->get_name(); yat::uint16 l_idx = extractNumber(l_attr_name, kCHANNEL); // extract channel nb CHECK_MANAGER(); double l_val = m_manager->get_channel(l_idx); cbd.tga->set_value(&l_val); } //+------------------------------------------------------------------ /** * method: SingleShotAO::write_channel * * description: method to execute "write_channel" for dynamic attributes * */ //+------------------------------------------------------------------ void SingleShotAO::write_channel(yat4tango::DynamicAttributeWriteCallbackData & cbd) { double l_val; cbd.tga->get_write_value(l_val); cbd.tga->set_write_value(l_val); std::string l_attr_name = cbd.dya->get_name(); yat::uint16 l_idx = extractNumber(l_attr_name, kCHANNEL); // extract channel nb CHECK_MANAGER(); try { m_manager->write_channel(l_idx, l_val); } catch(Tango::DevFailed& df) { ERROR_STREAM << df<< endl; RETHROW_DEVFAILED(df, "DRIVER_FAILURE", "could not write channel [caught Tango::DevFailed]", "SingleShotAO::write_channel"); } catch(...) { ERROR_STREAM << "SingleShotAOManager::write_channel::unknown exception caught"<<std::endl; THROW_DEVFAILED("DRIVER_FAILURE", "could not write channel [unknown error]", "SingleShotAO::write_channel"); } DEBUG_STREAM << "SingleShotAO::write_channel(): channel " << l_idx << " value set to " << l_val << endl; yat4tango::PropertyHelper::set_memorized_attribute(this, l_attr_name, l_val); // Update the initial attribute to match the channel value std::string initialAttrName = kINITIAL + std::to_string(l_idx); yat4tango::PropertyHelper::set_memorized_attribute(this, initialAttrName, l_val); setDynamicAttributeWriteValue(initialAttrName, l_val); DEBUG_STREAM << "SingleShotAO::write_channel(): memorized attribute " << l_attr_name << " set to " << l_val << endl; } //+------------------------------------------------------------------ /** * method: SingleShotAO::read_speed * * description: method to execute "read_speed" for dynamic attributes * */ //+------------------------------------------------------------------ void SingleShotAO::read_speed(yat4tango::DynamicAttributeReadCallbackData & cbd) { yat::AutoMutex<> guard(m_lock); std::string l_attr_name = cbd.dya->get_name(); yat::uint16 l_idx = extractNumber(l_attr_name, kSPEED); // extract channel nb CHECK_MANAGER(); double l_val = m_manager->get_speed(l_idx); cbd.tga->set_value(&l_val); } //+------------------------------------------------------------------ /** * method: SingleShotAO::write_speed * * description: method to execute "write_speed" for dynamic attributes * */ //+------------------------------------------------------------------ void SingleShotAO::write_speed(yat4tango::DynamicAttributeWriteCallbackData & cbd) { DEBUG_STREAM << "SingleShotAO::write_speed(): entering... !" << endl; double l_val; cbd.tga->get_write_value(l_val); std::string l_attr_name = cbd.dya->get_name(); yat::uint16 l_idx = extractNumber(l_attr_name, kSPEED); // extract channel nb if (l_val < 0) { l_val = -l_val; } CHECK_MANAGER(); try { m_manager->set_speed(l_idx, l_val); } catch(Tango::DevFailed& df) { ERROR_STREAM << df<< endl; RETHROW_DEVFAILED(df, "DRIVER_FAILURE", "could not write speed [caught Tango::DevFailed]", "SingleShotAO::write_speed"); } catch(...) { ERROR_STREAM << "SingleShotAO::write_speed::unknown exception caught" << std::endl; THROW_DEVFAILED("DRIVER_FAILURE", "could not write speed [unknown error]", "SingleShotAO::write_speed"); } yat4tango::PropertyHelper::set_memorized_attribute(this, l_attr_name, l_val); } //+------------------------------------------------------------------ /** * method: SingleShotAO::read_initial * * description: method to execute "read_initial" for dynamic attributes * */ //+------------------------------------------------------------------ void SingleShotAO::read_initial(yat4tango::DynamicAttributeReadCallbackData & cbd) { yat::AutoMutex<> guard(m_lock); std::string l_attr_name = cbd.dya->get_name(); yat::uint16 l_idx = extractNumber(l_attr_name, kINITIAL); // extract channel nb CHECK_MANAGER(); double l_val = m_manager->get_initial(l_idx); cbd.tga->set_value(&l_val); } //+------------------------------------------------------------------ /** * method: SingleShotAO::write_initial * * description: method to execute "write_initial" for dynamic attributes * */ //+------------------------------------------------------------------ void SingleShotAO::write_initial(yat4tango::DynamicAttributeWriteCallbackData & cbd) { DEBUG_STREAM << "SingleShotAO::write_initial(): entering... !" << endl; double l_val; cbd.tga->get_write_value(l_val); std::string l_attr_name = cbd.dya->get_name(); yat::uint16 l_idx = extractNumber(l_attr_name, kINITIAL); // extract channel nb CHECK_MANAGER(); try { m_manager->set_initial(l_idx, l_val); } catch(Tango::DevFailed& df) { ERROR_STREAM << df<< endl; RETHROW_DEVFAILED(df, "DRIVER_FAILURE", "could not write initial [caught Tango::DevFailed]", "SingleShotAO::write_initial"); } catch(...) { ERROR_STREAM << "SingleShotAO::write_initial::unknown exception caught"<<std::endl; THROW_DEVFAILED("DRIVER_FAILURE", "could not write initial [unknown error]", "SingleShotAO::write_initial"); } yat4tango::PropertyHelper::set_memorized_attribute(this, l_attr_name, l_val); } //+------------------------------------------------------------------ /** * set the write value of a dynamic attribute * used to keep read and write values in sync */ bool SingleShotAO::setDynamicAttributeWriteValue(const std::string& attrName, double value) { try { Tango::DeviceImpl* dev = static_cast<Tango::DeviceImpl*>(this); Tango::DevDouble val_to_write = value; // Get the attribute Tango::WAttribute& attr = dev->get_device_attr()->get_w_attr_by_name(attrName.c_str()); // Set the write value attr.set_write_value(&val_to_write, 1); DEBUG_STREAM << "Set write value for " << attrName << " to " << value << endl; return true; } catch (Tango::DevFailed &df) { ERROR_STREAM << "Failed to set write value for " << attrName << ": " << df << endl; return false; } catch (...) { ERROR_STREAM << "Unknown exception setting write value for " << attrName << endl; return false; } } //+------------------------------------------------------------------ /** * method: SingleShotAO::abort * * description: method to execute "Abort" * Aborts ramps in progress. * */ //+------------------------------------------------------------------ void SingleShotAO::abort() { DEBUG_STREAM << "SingleShotAO::abort(): entering... !" << endl; try { _abort(); } catch(Tango::DevFailed& df) { ERROR_STREAM << df<< endl; RETHROW_DEVFAILED(df, "DRIVER_FAILURE", "could not abort [caught Tango::DevFailed]", "SingleShotAO::abort"); } catch(...) { ERROR_STREAM << "SingleShotAO::abort::unknown exception caught"<< std::endl; THROW_DEVFAILED("DRIVER_FAILURE", "could not abort [unknown error]", "SingleShotAO::abort"); } } void SingleShotAO::_abort() { CHECK_MANAGER(); // memorize the current initial_values and value of channels for (unsigned int l_cpt = 0; l_cpt < m_nb_chan; l_cpt++) { if (m_manager->is_running(l_cpt)) { DEBUG_STREAM << "Channel " << l_cpt << " is running. Memorizing values..." << std::endl; double l_val_channel = m_manager->get_channel(l_cpt); std::string l_channel_attr_name = kCHANNEL + std::to_string(l_cpt); yat4tango::PropertyHelper::set_memorized_attribute(this, l_channel_attr_name, l_val_channel); setDynamicAttributeWriteValue(l_channel_attr_name, l_val_channel); DEBUG_STREAM << "Memorizing " << l_channel_attr_name << " to " << l_val_channel << std::endl; std::string l_initial_attr_name = kINITIAL + std::to_string(l_cpt); yat4tango::PropertyHelper::set_memorized_attribute(this, l_initial_attr_name, l_val_channel); setDynamicAttributeWriteValue(l_initial_attr_name, l_val_channel); DEBUG_STREAM << "Memorizing " << l_initial_attr_name << " to " << l_val_channel << std::endl; } } m_manager->abort(); } } // namespace