diff --git a/conanfile.py b/conanfile.py index 24ed6063f55fb5d67730e12e73c6a39ca033e49d..27e48016421a5d8a67dbf1d44cd19a3996736385 100644 --- a/conanfile.py +++ b/conanfile.py @@ -3,7 +3,7 @@ from conan import ConanFile class SingleShotAORecipe(ConanFile): name = "singleshotao" executable = "ds_SingleShotAO" - version = "2.1.0" + version = "2.2.0" package_type = "application" user = "soleil" python_requires = "base/[>=1.0]@soleil/stable" diff --git a/doc/doc_html/Properties.html b/doc/doc_html/Properties.html index 388a56248f2e70d9f938fcba1ca06732088d501b..95f05a3877d88c537c66c17dae16e9d4ed1748fd 100755 --- a/doc/doc_html/Properties.html +++ b/doc/doc_html/Properties.html @@ -56,16 +56,34 @@ <Font Size=-1>Tango::DEV_STRING</Font> </Td> <Td> - <Font Size=-1>The board type [MAO_xxxx - where <xxxx> is the ADlink board identifier - e.g. MAO_6208 - no - default value]</Font> + <Font Size=-1>The board type [MAO_xxxx - where <xxxx> is the ADlink board identifier - e.g. MAO_6208 - no default value]</Font> </Td> </Tr> - </Table> + <Tr> + <Td><b><a href=#Dev_DefaultValues>EnableRamps </a></b></Td> + <Td> + <Font Size=-1>Tango::DEV_BOOLEAN</Font> + </Td> + <Td> + <Font Size=-1>Whether to enable or disable the ramp generation on the board output channels. If false, the speedX and initialX dynamic attributes will not be created for every channel, and the changes will happen instantly. [true/false - default value is true]</Font> + </Td> + + </Tr> + <Tr> + <Td><b><a href=#Dev_DefaultValues>OutputMemorizedChannelsAtInit </a></b></Td> + <Td> + <Font Size=-1>Tango::DEV_BOOLEAN</Font> + </Td> + <Td> + <Font Size=-1>Whether to send the memorized values for the channels to the board at the device initialization (the device attribute will show the last memorized value regardless) [true/false - default value is false]</Font> + </Td> + </Tr> + </Table> + </Center> - <A name=Dev_DefaultValues><!--- ---></a> <Font Size=+1>Device Properties Default Values:</Font><Br> <Table Border=2 Cellpadding=2 CELLSPACING=2> <tr BGCOLOR="#CCCCFF" CLASS="TableHeadingColor"> @@ -80,6 +98,14 @@ <Td>BoardType</Td> <td>No default value</td> </Tr> + <Tr> + <Td>EnableRamps</Td> + <td>true</td> + </Tr> + <Tr> + <Td>OutputMemorizedChannelsAtInit</Td> + <td>false</td> + </Tr> </Table> <Br><Br><Br> diff --git a/src/SingleShotAO.cpp b/src/SingleShotAO.cpp index 699767f450ef72a93a22bc09255b2ef0e5f2a0f9..0c95671623c494fb0aacbc5281a2b8bff72db363 100755 --- a/src/SingleShotAO.cpp +++ b/src/SingleShotAO.cpp @@ -216,8 +216,7 @@ void SingleShotAO::init_device() 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, "Dependency Name", YAT_XSTR(dependency_name_PROJECT_VERSION)); - // TODO: Add dependencies + yat4tango::DeviceInfo::add_dependency(this, "ASL", ">=1.0"); } catch (Tango::DevFailed &df) { @@ -247,7 +246,7 @@ void SingleShotAO::init_device() //-------------------------------------------- try { - get_device_properties(); + get_device_property(); } catch (const Tango::DevFailed& df) { @@ -319,6 +318,7 @@ void SingleShotAO::init_device() m_nb_chan = 16; } + INFO_STREAM << "Board has " << m_nb_chan << " channels" << endl; // construct the AO manager //-------------------------------------------- @@ -361,7 +361,7 @@ void SingleShotAO::init_device() //-------------------------------------------- try { - m_manager->init(m_ssao, m_nb_chan, m_frequency); + m_manager->init(m_ssao, m_nb_chan, m_frequency, enableRamps); } catch (Tango::DevFailed & df) { @@ -378,6 +378,23 @@ void SingleShotAO::init_device() 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 //-------------------------------------------- @@ -405,6 +422,11 @@ void SingleShotAO::init_device() // 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; @@ -429,8 +451,7 @@ void SingleShotAO::init_device() 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 = "%1.1f"; - dai_channel.memorized = true; + dai_channel.tai.format = "%2.1f"; dai_channel.cdb = false; //- read callback @@ -443,6 +464,12 @@ void SingleShotAO::init_device() 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 ║ @@ -461,10 +488,9 @@ void SingleShotAO::init_device() 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 = "%1.1f"; + dai_speed.tai.format = "%2.1f"; //- cleanup tango db option: cleanup tango db when removing this dyn. attr. (i.e. erase its properties from db) - dai_speed.memorized = true; dai_speed.cdb = false; //- read callback @@ -495,10 +521,9 @@ void SingleShotAO::init_device() 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 = "%1.2f"; + dai_initial.tai.format = "%2.1f"; //- cleanup tango db option: cleanup tango db when removing this dyn. attr. (i.e. erase its properties from db) - dai_initial.memorized = true; dai_initial.cdb = false; //- read callback @@ -511,8 +536,52 @@ void SingleShotAO::init_device() l_dynAttrList.push_back(dai_initial); } - m_dyn_attr_manager->add_attributes(l_dynAttrList); + + // 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++) @@ -524,21 +593,37 @@ void SingleShotAO::init_device() auto applyMemorizedAttr = [&](const std::string& attrPrefix, void (SingleShotAOManager::*setter)(yat::uint16, double)) { - try { + try + { std::string attrName = attrPrefix + oss.str(); 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 (...) { + catch (...) + { // nothing to do } }; // Get and set memorized values for speed, initial and channel - applyMemorizedAttr(kSPEED, &SingleShotAOManager::set_speed); - applyMemorizedAttr(kINITIAL, &SingleShotAOManager::set_initial); - applyMemorizedAttr(kCHANNEL, &SingleShotAOManager::set_channel); - // TODO: add a property to call write_channel instead of set_channel (false by default) + 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 @@ -570,60 +655,87 @@ void SingleShotAO::init_device() //+---------------------------------------------------------------------------- // -// method : SingleShotAO::get_device_properties() +// method : SingleShotAO::get_device_property() // // description : Read the device properties from database. // //----------------------------------------------------------------------------- -void SingleShotAO::get_device_properties() +void SingleShotAO::get_device_property() { - // Initialize your default values here (if not done with POGO). - //------------------------------------------------------------------ - - // Read device properties from database.(Automatic code generation) + // 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 + // 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())); + } + + Tango::DbDatum def_prop, cl_prop; + SingleShotAOClass *ds_class = (static_cast<SingleShotAOClass *>(get_device_class())); int i = -1; - // Try to initialize BoardNum from class property + //- <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 + // 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; } - // And try to extract BoardNum value from database + // 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; - // Try to initialize BoardType from class property + //- <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 + // 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; } - // And try to extract BoardType value from database + // 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; + } + // 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; + } + // 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; - // End of Automatic code generation - //------------------------------------------------------------------ - + // Check critical properties being present + //-------------------------------------------- critical_properties_missing = false; - if (dev_prop[0].is_empty()) { ERROR_STREAM << "Required device property <BoardNum> is missing" << endl; @@ -634,17 +746,21 @@ void SingleShotAO::get_device_properties() ERROR_STREAM << "Required device property <BoardType> is missing" << endl; critical_properties_missing = true; } - - if (critical_properties_missing) { + if (critical_properties_missing) + { return; } + // Check critical properties being valid + //-------------------------------------------- //- <BoardNum> ----------------------- - if (boardNum > 7) + if (boardNum < 0 || boardNum > 7) { boardNum = 0; ERROR_STREAM << "device property <BoardNum> is invalid. Valid range is [0..7]" << endl; critical_properties_missing = true; + } else { + INFO_STREAM << "BoardNum resolved to " << boardNum << endl; } //- <BoardType> ----------------------- @@ -652,11 +768,13 @@ void SingleShotAO::get_device_properties() { 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; } else { @@ -665,7 +783,6 @@ void SingleShotAO::get_device_properties() ERROR_STREAM << "device property <BoardType> is invalid [supported hw: MAO_6208 or MAO_6216]" << endl; critical_properties_missing = true; } - } @@ -850,6 +967,7 @@ void SingleShotAO::write_channel(yat4tango::DynamicAttributeWriteCallbackData & { 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 @@ -874,8 +992,16 @@ void SingleShotAO::write_channel(yat4tango::DynamicAttributeWriteCallbackData & "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; } @@ -1009,6 +1135,40 @@ void SingleShotAO::write_initial(yat4tango::DynamicAttributeWriteCallbackData & } +//+------------------------------------------------------------------ +/** + * 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 @@ -1049,15 +1209,20 @@ void SingleShotAO::_abort() // 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)) { + 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); - yat4tango::PropertyHelper::set_memorized_attribute(this, kCHANNEL + std::to_string(l_cpt), l_val_channel); - DEBUG_STREAM << "Memorizing channel " << l_cpt << " to " << l_val_channel << std::endl; - - yat4tango::PropertyHelper::set_memorized_attribute(this, kINITIAL + std::to_string(l_cpt), l_val_channel); - DEBUG_STREAM << "Memorizing initial " << l_cpt << " to " << l_val_channel << std::endl; + 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(); diff --git a/src/SingleShotAO.h b/src/SingleShotAO.h index 8e259d076f2b50dd42d185e749c98991515fe2d1..17e2b74745fc27ed2ef311a644cf782ac711aeb2 100755 --- a/src/SingleShotAO.h +++ b/src/SingleShotAO.h @@ -110,6 +110,14 @@ public : * The board type [MAO_xxxx - where <xxxx> is the ADlink board identifier - e.g. MAO_6208 - no default value] */ string boardType; +/** + * Whether to enable or disable the ramp generation on the board output channels. If false, the speedX and initialX dynamic attributes will not be created for every channel, and the changes will happen instantly. [true/false - default value is true] + */ + Tango::DevBoolean enableRamps; +/** + * Whether to write the memorized values to the board at the device initialization. [true/false - default value is false] + */ + Tango::DevBoolean outputMemorizedChannelsAtInit; //@} /** @@ -219,7 +227,7 @@ public : /** * Read the device properties from database */ - void get_device_properties(); + void get_device_property(); //@} // Here is the end of the automatic code generation part @@ -282,6 +290,10 @@ protected : void _abort(); + // set the write value of a dynamic attribute + // used to keep read and write values in sync + bool setDynamicAttributeWriteValue(const std::string& attrName, double value); + }; } // namespace_ns diff --git a/src/SingleShotAOClass.cpp b/src/SingleShotAOClass.cpp index e93187a49bbddf85c1b6bd09b993937ab31c7516..d5b5ee1100d9220b2d02867394a5fc86a84424c6 100755 --- a/src/SingleShotAOClass.cpp +++ b/src/SingleShotAOClass.cpp @@ -87,7 +87,8 @@ __declspec(dllexport) #endif - Tango::DeviceClass *_create_SingleShotAO_class(const char *name) { + Tango::DeviceClass *_create_SingleShotAO_class(const char *name) + { return SingleShotAO_ns::SingleShotAOClass::init(name); } } @@ -369,10 +370,14 @@ void SingleShotAOClass::set_default_property() string prop_def; vector<string> vect_data; + // Set Default Class Properties + // ... + // Set Default Device Properties + //- <BoardNum> ----------------------- prop_name = "BoardNum"; - prop_desc = "The the board identifier in the cPCI crate [valid range is 0...7 - no default value] ."; + prop_desc = "The board identifier in the cPCI crate [valid range is 0...7 - no default value]."; prop_def = ""; vect_data.clear(); if (prop_def.length()>0) @@ -385,6 +390,7 @@ void SingleShotAOClass::set_default_property() else add_wiz_dev_prop(prop_name, prop_desc); + //- <BoardType> ----------------------- prop_name = "BoardType"; prop_desc = "The board type [MAO_xxxx - where <xxxx> is the ADlink board identifier - e.g. MAO_6208 - no default value]"; prop_def = ""; @@ -399,7 +405,40 @@ void SingleShotAOClass::set_default_property() else add_wiz_dev_prop(prop_name, prop_desc); + //- <EnableRamps> ----------------------- + prop_name = "EnableRamps"; + prop_desc = "Whether to enable or disable the ramp generation on the board output channels. If false, the speedX and initialX dynamic attributes will not be created for every channel, and the changes will happen instantly. [true/false - default value is true]"; + prop_def = "true"; + vect_data.clear(); + vect_data.push_back("true"); + if (prop_def.length() > 0) + { + Tango::DbDatum data(prop_name); + data << vect_data; + dev_def_prop.push_back(data); + add_wiz_dev_prop(prop_name, prop_desc, prop_def); + } + else + add_wiz_dev_prop(prop_name, prop_desc); + + //- <OutputMemorizedChannelsAtInit> ----------------------- + prop_name = "OutputMemorizedChannelsAtInit"; + prop_desc = "Whether to send the memorized values for the channels to the board at the device initialization (the device attribute will show the last memorized value regardless) [true/false - default value is false]"; + prop_def = "false"; + vect_data.clear(); + vect_data.push_back("false"); + if (prop_def.length() > 0) + { + Tango::DbDatum data(prop_name); + data << vect_data; + dev_def_prop.push_back(data); + add_wiz_dev_prop(prop_name, prop_desc, prop_def); + } + else + add_wiz_dev_prop(prop_name, prop_desc); } + + //+---------------------------------------------------------------------------- // // method : SingleShotAOClass::write_class_property @@ -431,107 +470,6 @@ void SingleShotAOClass::write_class_property() str_desc.push_back("ADLink boards support for single shot AO operations [PCI-6208 and compatible boards]"); description << str_desc; data.push_back(description); - - // put cvs or svn location - string filename(classname); - filename += "Class.cpp"; - - // Create a string with the class ID to - // get the string into the binary - string class_id(ClassId); - - // check for cvs information - string src_path(CvsPath); - start = src_path.find("/"); - if (start!=string::npos) - { - end = src_path.find(filename); - if (end>start) - { - string strloc = src_path.substr(start, end-start); - // Check if specific repository - start = strloc.find("/cvsroot/"); - if (start!=string::npos && start>0) - { - string repository = strloc.substr(0, start); - if (repository.find("/segfs/")!=string::npos) - strloc = "ESRF:" + strloc.substr(start, strloc.length()-start); - } - Tango::DbDatum cvs_loc("cvs_location"); - cvs_loc << strloc; - data.push_back(cvs_loc); - } - } - // check for svn information - else - { - string src_path(SvnPath); - start = src_path.find("://"); - if (start!=string::npos) - { - end = src_path.find(filename); - if (end>start) - { - header = "$HeadURL: "; - start = header.length(); - string strloc = src_path.substr(start, (end-start)); - - Tango::DbDatum svn_loc("svn_location"); - svn_loc << strloc; - data.push_back(svn_loc); - } - } - } - - // Get CVS or SVN revision tag - - // CVS tag - string tagname(TagName); - header = "$Name: "; - start = header.length(); - string endstr(" $"); - - end = tagname.find(endstr); - if (end!=string::npos && end>start) - { - string strtag = tagname.substr(start, end-start); - Tango::DbDatum cvs_tag("cvs_tag"); - cvs_tag << strtag; - data.push_back(cvs_tag); - } - - // SVN tag - string svnpath(SvnPath); - header = "$HeadURL: "; - start = header.length(); - - end = svnpath.find(endstr); - if (end!=string::npos && end>start) - { - string strloc = svnpath.substr(start, end-start); - - string tagstr ("/tags/"); - start = strloc.find(tagstr); - if ( start!=string::npos ) - { - start = start + tagstr.length(); - end = strloc.find(filename); - string strtag = strloc.substr(start, end-start-1); - - Tango::DbDatum svn_tag("svn_tag"); - svn_tag << strtag; - data.push_back(svn_tag); - } - } - - // Get URL location - string httpServ(HttpServer); - if (httpServ.length()>0) - { - Tango::DbDatum db_doc_url("doc_url"); - db_doc_url << httpServ; - data.push_back(db_doc_url); - } // Put inheritance Tango::DbDatum inher_datum("InheritedFrom"); @@ -540,8 +478,7 @@ void SingleShotAOClass::write_class_property() inher_datum << inheritance; data.push_back(inher_datum); - // Call database and and values - //-------------------------------------------- + // Call database and add values get_db_class()->put_property(data); } diff --git a/src/SingleShotAOManager.cpp b/src/SingleShotAOManager.cpp index e0519ecd5ca25bf68afb2c6869375887558b664b..e988c22e0a795552feb5c5148354bf61fb39f2dc 100755 --- a/src/SingleShotAOManager.cpp +++ b/src/SingleShotAOManager.cpp @@ -128,7 +128,7 @@ void SingleShotAOManager::write_frequency(double p_frequency) // ============================================================================ // SingleShotAOManager::init () // ============================================================================ -void SingleShotAOManager::init(asl::SingleShotAO * p_ssao, unsigned short p_nb_chan, double p_frequency) +void SingleShotAOManager::init(asl::SingleShotAO * p_ssao, unsigned short p_nb_chan, double p_frequency, bool p_enable_ramps) { m_ssao = p_ssao; CHECK_SSAO(); @@ -145,6 +145,8 @@ void SingleShotAOManager::init(asl::SingleShotAO * p_ssao, unsigned short p_nb_c enable_periodic_msg(true); } + m_enable_ramps = p_enable_ramps; + // initialize channel indexes (-1 means no ramp in progress) // and ramp states for (unsigned int l_cpt = 0; l_cpt < m_nb_chan; l_cpt++) @@ -248,6 +250,7 @@ void SingleShotAOManager::periodic_job_i() m_currentIndex[l_cpt] += 1; if (m_currentIndex[l_cpt] == m_ramps[l_cpt].capacity()) { + DEBUG_STREAM << "Ramp finished for channel" << l_cpt << endl; m_currentIndex[l_cpt] = -1; m_initials[l_cpt] = m_channels[l_cpt]; m_ramps[l_cpt].clear(); @@ -281,67 +284,43 @@ void SingleShotAOManager::set_channel(ChannelId_t p_chIdx, double p_val) } // ============================================================================ -// SingleShotAOManager::write_channel () +// SingleShotAOManager::write_channel_direct () // ============================================================================ -void SingleShotAOManager::write_channel(ChannelId_t p_chIdx, double p_val) +void SingleShotAOManager::write_channel_direct(ChannelId_t p_chIdx, double p_val) { - DEBUG_STREAM << "write_channel " << p_chIdx << " : " << p_val << endl; - - // if the speed is 0, write the value directly and skip ramp - if (m_speeds[p_chIdx] == 0.0) + try { - try - { - CHECK_SSAO(); - m_ssao->write_scaled_channel((adl::ChanId)p_chIdx, p_val); - m_channels[p_chIdx] = p_val; - m_initials[p_chIdx] = p_val; - DEBUG_STREAM << "Speed is 0, writing directly the value" << std::endl; - } - catch (const asl::DAQException &de) - { - Tango::DevFailed df = daq_to_tango_exception(de); - ERROR_STREAM << df << std::endl; - m_state = Tango::FAULT; - RETHROW_DEVFAILED(df, - "DRIVER_FAILURE", - "could not write channel [caught asl::DAQException]", - "SingleShotAOManager::write_channel"); - } - catch (...) - { - ERROR_STREAM << "SingleShotAOManager::write_channel::unknown exception caught" << std::endl; - m_state = Tango::FAULT; - THROW_DEVFAILED("DRIVER_FAILURE", - "could not write channel [unknown error]", - "SingleShotAOManager::write_channel"); - } - return; + CHECK_SSAO(); + m_ssao->write_scaled_channel((adl::ChanId)p_chIdx, p_val); + m_channels[p_chIdx] = p_val; + m_initials[p_chIdx] = p_val; + DEBUG_STREAM << "Writing directly the value" << std::endl; } - - // if a ramp is running, error - if (m_isRunning[p_chIdx]) + catch (const asl::DAQException &de) { - THROW_DEVFAILED("DEVICE_FAILURE", - "could not write channel : a ramp is still in progress on this channel", - "SingleShotAOManager::write_channel"); + Tango::DevFailed df = daq_to_tango_exception(de); + ERROR_STREAM << df << std::endl; + m_state = Tango::FAULT; + RETHROW_DEVFAILED(df, + "DRIVER_FAILURE", + "could not write channel [caught asl::DAQException]", + "SingleShotAOManager::write_channel_direct"); } - - // if frequency = 0, error - if (m_frequency == 0) + catch (...) { + ERROR_STREAM << "SingleShotAOManager::write_channel_direct::unknown exception caught" << std::endl; + m_state = Tango::FAULT; THROW_DEVFAILED("DRIVER_FAILURE", - "could not set a ramp on this channel. The frequency is 0", - "SingleShotAOManager::write_channel"); - } - - // if initial = channel, skip - if (m_initials[p_chIdx] == p_val) - { - DEBUG_STREAM << "Initial value is the same as the given value, skipping" << endl; - return; + "could not write channel [unknown error]", + "SingleShotAOManager::write_channel_direct"); } +} +// ============================================================================ +// SingleShotAOManager::start_channel_ramp () +// ============================================================================ +void SingleShotAOManager::start_channel_ramp(ChannelId_t p_chIdx, double p_val) +{ // ramp determination double l_delta = p_val - m_initials[p_chIdx]; bool isDown = false; @@ -387,7 +366,47 @@ void SingleShotAOManager::write_channel(ChannelId_t p_chIdx, double p_val) m_ramps[p_chIdx].force_length(0); m_currentIndex[p_chIdx] = 0; m_ramps[p_chIdx] = l_buffer; - //m_channels[p_chIdx] = m_ramps[p_chIdx][0]; -- soso on ne met rien ici => à l'application +} + +// ============================================================================ +// SingleShotAOManager::write_channel () +// ============================================================================ +void SingleShotAOManager::write_channel(ChannelId_t p_chIdx, double p_val) +{ + DEBUG_STREAM << "write_channel " << p_chIdx << " : " << p_val << endl; + + // if the speed is 0, write the value directly and skip ramp + if (m_speeds[p_chIdx] == 0.0 || !m_enable_ramps) + { + write_channel_direct(p_chIdx, p_val); + return; + } + + // if a ramp is running, error + if (m_isRunning[p_chIdx]) + { + THROW_DEVFAILED("DEVICE_FAILURE", + "could not write channel : a ramp is still in progress on this channel", + "SingleShotAOManager::write_channel"); + } + + // if frequency = 0, error + if (m_frequency == 0) + { + THROW_DEVFAILED("DRIVER_FAILURE", + "could not set a ramp on this channel. The frequency is 0", + "SingleShotAOManager::write_channel"); + } + + // if initial = channel, skip + if (m_initials[p_chIdx] == p_val) + { + DEBUG_STREAM << "Initial value is the same as the given value, skipping" << endl; + return; + } + + // Create and start a ramp + start_channel_ramp(p_chIdx, p_val); } // ============================================================================ @@ -409,6 +428,12 @@ void SingleShotAOManager::set_initial(ChannelId_t p_chIdx, Intial_t p_initial) "could not write initial : a ramp is still in progress on this channel", "SingleShotAOManager::set_initial"); } + else if (!m_enable_ramps) + { + THROW_DEVFAILED("DEVICE_FAILURE", + "could not write initial : ramps are disabled", + "SingleShotAOManager::set_initial"); + } else { m_initials[p_chIdx] = p_initial; @@ -434,6 +459,12 @@ void SingleShotAOManager::set_speed(ChannelId_t p_chIdx, Intial_t p_speed) "could not write speed : a ramp is still in progress on this channel", "SingleShotAOManager::set_speed"); } + else if (!m_enable_ramps) + { + THROW_DEVFAILED("DEVICE_FAILURE", + "could not write speed : ramps are disabled", + "SingleShotAOManager::set_speed"); + } else { m_speeds[p_chIdx] = p_speed; diff --git a/src/SingleShotAOManager.h b/src/SingleShotAOManager.h index a021036cde359e9046c6de08ae373a3bdadcf3e7..325e00f42a054178f0923c6f0936f514ed262892 100755 --- a/src/SingleShotAOManager.h +++ b/src/SingleShotAOManager.h @@ -48,17 +48,25 @@ public: std::string get_status (); //- init - void init(asl::SingleShotAO * p_ssao, unsigned short p_nb_chan, double p_frequency); + void init(asl::SingleShotAO *p_ssao, unsigned short p_nb_chan, double p_frequency, bool p_enable_ramps); //- get current channel value double get_channel(ChannelId_t p_chIdx); //- set channel + // Updates the value for the channel in the device without sending it to hardware void set_channel(ChannelId_t p_chIdx, double p_val); //- write channel + // Writes value to the channel to the device and the hardware, with a ramp if speed is not null and EnableRamps property is true void write_channel(ChannelId_t p_chIdx, double p_val); + //- write a channel directly (without ramp) + void write_channel_direct(ChannelId_t p_chIdx, double p_val); + + //- create and start a ramp for channel + void start_channel_ramp(ChannelId_t p_chIdx, double p_val); + //- change period void write_frequency(double p_frequency); @@ -100,7 +108,10 @@ private: //- frequency double m_frequency; - + + //-enable ramps + bool m_enable_ramps; + //- initial buffer for all channels std::map<ChannelId_t, Intial_t> m_initials;