From c725c419534d6db0baf1e1c7988e13f8a28390c4 Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Thu, 20 Feb 2025 11:14:06 +0100
Subject: [PATCH 01/34] refactor: use Tango 8 attr memorization (removed
 workaround)

---
 src/SingleShotAO.cpp | 14 ++-------
 src/SingleShotAO.h   | 70 --------------------------------------------
 2 files changed, 3 insertions(+), 81 deletions(-)

diff --git a/src/SingleShotAO.cpp b/src/SingleShotAO.cpp
index 8091197..21f3c40 100755
--- a/src/SingleShotAO.cpp
+++ b/src/SingleShotAO.cpp
@@ -505,9 +505,7 @@ void SingleShotAO::init_device()
 			std::string attr_name = kINITIAL + oss.str();
 			std::string name = "__" + attr_name;
 
-			// To be activated with Tango 8
-			//double l_val = yat4tango::PropertyHelper::get_memorized_attribute<double>(this,name);
-			double l_val = get_memorized_attribute<double>(name);
+			double l_val = yat4tango::PropertyHelper::get_memorized_attribute<double>(this,name);
 			m_manager->set_initial(l_cpt, l_val);
         }
 	    catch (...)
@@ -896,10 +894,7 @@ void SingleShotAO::write_speed(yat4tango::DynamicAttributeWriteCallbackData & cb
 			"could not write initial [unknown error]",
 			"SingleShotAO::write_initial");
 	}
-	// To be activated with Tango 8 
-	//yat4tango::PropertyHelper::set_memorized_attribute(this, l_attr_name, l_val);
-	std::string name = "__" + l_attr_name;
-	store_value_as_property(l_val, name);
+	yat4tango::PropertyHelper::set_memorized_attribute(this, l_attr_name, l_val);
 }
 
 
@@ -969,10 +964,7 @@ void SingleShotAO::write_initial(yat4tango::DynamicAttributeWriteCallbackData &
 			"could not write initial [unknown error]",
 			"SingleShotAO::write_initial");
 	}
-  // To be activated with Tango 8
-  //yat4tango::PropertyHelper::set_memorized_attribute(this, l_attr_name, l_val);
-  std::string name = "__" + l_attr_name;
-	store_value_as_property(l_val, name);
+	yat4tango::PropertyHelper::set_memorized_attribute(this, l_attr_name, l_val);
 }
 
 
diff --git a/src/SingleShotAO.h b/src/SingleShotAO.h
index 61f5f60..41ed361 100755
--- a/src/SingleShotAO.h
+++ b/src/SingleShotAO.h
@@ -279,76 +279,6 @@ protected :
 	//- channel number
 	unsigned short m_nb_chan;
 
-  // To be deleted with Tango 8
-  //- Template class to store a current value in a Device property.
-  //- \param value Value to store.
-  //- \param property_name Name to use.
-  template <class T>
-  void store_value_as_property(T value, std::string property_name)
-  {
-    Tango::DbDatum current_value(property_name);
-    current_value << value;
-    Tango::DbData db_data;
-    db_data.push_back(current_value);
-
-    try
-    {
-      get_db_device()->put_property(db_data);
-    }
-    catch(Tango::DevFailed &df)
-    {     
-      ERROR_STREAM << df << endl;
-      RETHROW_DEVFAILED(df,
-						"SOFTWARE_FAILURE",
-						"Error while storing properties in database",
-						"SingleShotAO::store_value_as_property");
-	  }
-  }
-
-  // To be deleted with Tango 8
-  //- Template class to get a memorized attribute stored as a Device property.
-  //- \param property_name Name od the property to read.
-  template <class T>
-  T get_memorized_attribute(const std::string& property_name)
-  {
-    T value;
-    if (!Tango::Util::instance()->_UseDb)
-    {
-      //- throw exception
-	    THROW_DEVFAILED("DEVICE_ERROR",
-	                  "No DATA BASE!",
-	                  "SingleShotAO::get_memorized_attribute");    
-    }
-
-    Tango::DbData	dev_prop;
-    dev_prop.push_back(Tango::DbDatum(property_name));
-	
-    try
-    {
-      get_db_device()->get_property(dev_prop);
-    }
-    catch (Tango::DevFailed &df)
-    {
-      //- rethrow exception
-      RETHROW_DEVFAILED(df,
-	                    "DEVICE_ERROR",
-	                    "could not get Device properties! [caught Tango::DevFailed]",
-	                    "SingleShotAO::get_memorized_attribute");
-    }
-
-    if (dev_prop[0].is_empty()==false)
-    {
-      dev_prop[0] >> value;
-    }
-    else
-    {
-      //- throw exception
-	    THROW_DEVFAILED("DATA_ERROR",
-	                  "No property stored in database!",
-	                  "SingleShotAO::get_memorized_attribute");
-    }
-    return value;
-  }
 };
 
 }	// namespace_ns
-- 
GitLab


From 2973a71d7efc461e125db40db5e6b36e3579d2cc Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Thu, 20 Feb 2025 16:07:13 +0100
Subject: [PATCH 02/34] refactor: rename get_device_property to
 get_device_properties and extract channel number logic

---
 src/SingleShotAO.cpp        | 72 +++++++++++++++++--------------------
 src/SingleShotAO.h          |  2 +-
 src/SingleShotAOManager.cpp |  2 --
 3 files changed, 34 insertions(+), 42 deletions(-)

diff --git a/src/SingleShotAO.cpp b/src/SingleShotAO.cpp
index 21f3c40..c312cc2 100755
--- a/src/SingleShotAO.cpp
+++ b/src/SingleShotAO.cpp
@@ -219,7 +219,7 @@ void SingleShotAO::init_device()
 	//--------------------------------------------
 	try 
 	{
-		get_device_property();
+		get_device_properties();
 	}
 	catch (const Tango::DevFailed& df)
 	{
@@ -543,12 +543,12 @@ void SingleShotAO::init_device()
 
 //+----------------------------------------------------------------------------
 //
-// method : 		SingleShotAO::get_device_property()
+// method : 		SingleShotAO::get_device_properties()
 // 
 // description : 	Read the device properties from database.
 //
 //-----------------------------------------------------------------------------
-void SingleShotAO::get_device_property()
+void SingleShotAO::get_device_properties()
 {
 	//	Initialize your default values here (if not done with  POGO).
 	//------------------------------------------------------------------
@@ -664,8 +664,7 @@ void SingleShotAO::always_executed_hook()
 //-----------------------------------------------------------------------------
 void SingleShotAO::read_attr_hardware(vector<long> &attr_list)
 {
-	//DEBUG_STREAM << "SingleShotAO::read_attr_hardware(vector<long> &attr_list) entering... "<< endl;
-	//	Add your own code here
+	// nothing to do
 }
 
 
@@ -678,7 +677,6 @@ void SingleShotAO::read_attr_hardware(vector<long> &attr_list)
 //-----------------------------------------------------------------------------
 void SingleShotAO::read_frequency(Tango::Attribute &attr)
 {
-	//DEBUG_STREAM << "SingleShotAO::read_frequency(Tango::Attribute &attr) entering... "<< endl;
 	attr.set_value(&m_frequency);
 }
 
@@ -757,6 +755,26 @@ Tango::ConstDevString SingleShotAO::dev_status()
 }
 
 
+//+------------------------------------------------------------------
+/**
+ * Extract the first number found in a string.
+ * Used for extracting the channel number from dynamic attribute names
+ * like "channelX", "speedX", "initialX" where X is the channel number.
+ * 
+ * @param str The input string to search for numbers
+ * @return The first number found in the string
+ * @throws DevFailed if no number is found in the string
+ */
+int extractNumber(const std::string &str)
+{
+	size_t pos = str.find_first_of("0123456789");
+	if (pos == std::string::npos)
+		raise_error("No number found in string", "extractNumber");
+
+	std::string numberStr = str.substr(pos);
+	return std::stoi(numberStr);
+}
+
 //+------------------------------------------------------------------
 /**
 *  method:  SingleShotAO::read_channel
@@ -768,15 +786,10 @@ Tango::ConstDevString SingleShotAO::dev_status()
 void SingleShotAO::read_channel(yat4tango::DynamicAttributeReadCallbackData & cbd)
 {
 	yat::AutoMutex<> guard(m_lock);
-
 	std::string l_attr_name = cbd.dya->get_name();
-
-	// name will be channelX
-	std::string l_str = l_attr_name.substr(7, 2);
-	yat::uint16 l_idx = atoi(l_str.c_str());
+	yat::uint16 l_idx = extractNumber(l_attr_name); // extract channel nb
 
     CHECK_MANAGER();
-	// choose tab depending on l_idx
 	double l_val = m_manager->get_channel(l_idx);
 	cbd.tga->set_value(&l_val);
 }
@@ -796,10 +809,7 @@ void SingleShotAO::write_channel(yat4tango::DynamicAttributeWriteCallbackData &
 	cbd.tga->get_write_value(l_val);
 
 	std::string l_attr_name = cbd.dya->get_name();
-
-	// name will be channelX
-	std::string l_str = l_attr_name.substr(7, 2);
-	yat::uint16 l_idx = atoi(l_str.c_str());
+	yat::uint16 l_idx = extractNumber(l_attr_name); // extract channel nb
 
     CHECK_MANAGER();
 	try
@@ -835,15 +845,10 @@ void SingleShotAO::write_channel(yat4tango::DynamicAttributeWriteCallbackData &
 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); // extract channel nb
 
-	// name will be speedX
-	std::string l_str = l_attr_name.substr(5, 2);
-	yat::uint16 l_idx = atoi(l_str.c_str());
-
-         CHECK_MANAGER();
-	// choose tab depending on l_idx
+    CHECK_MANAGER();
 	double l_val = m_manager->get_speed(l_idx);
 	cbd.tga->set_value(&l_val);
 }
@@ -859,16 +864,13 @@ void SingleShotAO::read_speed(yat4tango::DynamicAttributeReadCallbackData & cbd)
 //+------------------------------------------------------------------
 void SingleShotAO::write_speed(yat4tango::DynamicAttributeWriteCallbackData & cbd)
 {
-  DEBUG_STREAM << "SingleShotAO::write_speed(): entering... !" << endl;
+	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();
-
-	// name will be speedX
-	std::string l_str = l_attr_name.substr(5, 2);
-	yat::uint16 l_idx = atoi(l_str.c_str());
+	yat::uint16 l_idx = extractNumber(l_attr_name); // extract channel nb
 	if (l_val < 0)
 	{
 		l_val = -l_val;
@@ -909,15 +911,10 @@ void SingleShotAO::write_speed(yat4tango::DynamicAttributeWriteCallbackData & cb
 void SingleShotAO::read_initial(yat4tango::DynamicAttributeReadCallbackData & cbd)
 {
 	yat::AutoMutex<> guard(m_lock);
-
 	std::string l_attr_name = cbd.dya->get_name();
-
-	// name will be initialX
-	std::string l_str = l_attr_name.substr(7, 2);
-	yat::uint16 l_idx = atoi(l_str.c_str());
+	yat::uint16 l_idx = extractNumber(l_attr_name); // extract channel nb
 
 	CHECK_MANAGER();
-	// choose tab depending on l_idx
 	double l_val = m_manager->get_initial(l_idx);
 	cbd.tga->set_value(&l_val);
 }
@@ -933,16 +930,13 @@ void SingleShotAO::read_initial(yat4tango::DynamicAttributeReadCallbackData & cb
 //+------------------------------------------------------------------
 void SingleShotAO::write_initial(yat4tango::DynamicAttributeWriteCallbackData & cbd)
 {
-  DEBUG_STREAM << "SingleShotAO::write_initial(): entering... !" << endl;
+	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();
-
-	// name will be initialX
-	std::string l_str = l_attr_name.substr(7, 2);
-	yat::uint16 l_idx = atoi(l_str.c_str());
+	yat::uint16 l_idx = extractNumber(l_attr_name); // extract channel nb
 
 	CHECK_MANAGER();
 	try
diff --git a/src/SingleShotAO.h b/src/SingleShotAO.h
index 41ed361..d6d477f 100755
--- a/src/SingleShotAO.h
+++ b/src/SingleShotAO.h
@@ -219,7 +219,7 @@ public :
 /**
  *	Read the device properties from database
  */
-	 void get_device_property();
+	 void get_device_properties();
 //@}
 
 	//	Here is the end of the automatic code generation part
diff --git a/src/SingleShotAOManager.cpp b/src/SingleShotAOManager.cpp
index 1a71223..6e6c2e7 100755
--- a/src/SingleShotAOManager.cpp
+++ b/src/SingleShotAOManager.cpp
@@ -180,7 +180,6 @@ void SingleShotAOManager::process_message (yat::Message& msg)
 		//- THREAD_PERIODIC ------------------
 	case yat::TASK_PERIODIC:
 		{
-			//DEBUG_STREAM << "SingleShotAOManager::handle_message::THREAD_PERIODIC" << std::endl;
 			periodic_job_i();
 		}
 		break;
@@ -209,7 +208,6 @@ void SingleShotAOManager::periodic_job_i()
 		//test if a ramp step must occur
 		if (m_currentIndex[l_cpt] != -1)
 		{
-			//DEBUG_STREAM << "Current index for channel" << l_cpt << ": " << m_currentIndex[l_cpt] << endl;
 			m_isRunning[l_cpt] = true;
 			double l_val = 0;
 			l_val = m_ramps[l_cpt][m_currentIndex[l_cpt]];
-- 
GitLab


From d4c1f2526d1ff57ef2d8f6c587350a5b3cd68ad0 Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Thu, 20 Feb 2025 16:37:36 +0100
Subject: [PATCH 03/34] refactor: enhance extractNumber function to validate
 prefixes and improve error handling

---
 src/SingleShotAO.cpp | 49 +++++++++++++++++++++++++++++---------------
 1 file changed, 33 insertions(+), 16 deletions(-)

diff --git a/src/SingleShotAO.cpp b/src/SingleShotAO.cpp
index c312cc2..2c26d31 100755
--- a/src/SingleShotAO.cpp
+++ b/src/SingleShotAO.cpp
@@ -368,6 +368,7 @@ void SingleShotAO::init_device()
 		return;
 	}
 
+
 	// add dynamic attributes: channel, speed & initial for each channel
   	std::vector<yat4tango::DynamicAttributeInfo> l_dynAttrList;
 	for (unsigned int l_cpt = 0; l_cpt < m_nb_chan; l_cpt++)
@@ -476,9 +477,9 @@ void SingleShotAO::init_device()
 		
     	l_dynAttrList.push_back(dai_initial);
 	}
-
   	m_dyn_attr_manager->add_attributes(l_dynAttrList);
 
+
 	// Get memorized values from database
 	for (unsigned int l_cpt = 0; l_cpt < m_nb_chan; l_cpt++)
 	{
@@ -757,21 +758,37 @@ Tango::ConstDevString SingleShotAO::dev_status()
 
 //+------------------------------------------------------------------
 /**
- * Extract the first number found in a string.
- * Used for extracting the channel number from dynamic attribute names
- * like "channelX", "speedX", "initialX" where X is the channel number.
+ * 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
- * @return The first number found in the string
- * @throws DevFailed if no number is found in the string
+ * @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)
+int extractNumber(const std::string &str, const char* prefix) 
 {
-	size_t pos = str.find_first_of("0123456789");
-	if (pos == std::string::npos)
-		raise_error("No number found in string", "extractNumber");
+	// 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);
 }
 
@@ -787,7 +804,7 @@ void SingleShotAO::read_channel(yat4tango::DynamicAttributeReadCallbackData & cb
 {
 	yat::AutoMutex<> guard(m_lock);
 	std::string l_attr_name = cbd.dya->get_name();
-	yat::uint16 l_idx = extractNumber(l_attr_name); // extract channel nb
+	yat::uint16 l_idx = extractNumber(l_attr_name, kCHANNEL); // extract channel nb
 
     CHECK_MANAGER();
 	double l_val = m_manager->get_channel(l_idx);
@@ -809,7 +826,7 @@ void SingleShotAO::write_channel(yat4tango::DynamicAttributeWriteCallbackData &
 	cbd.tga->get_write_value(l_val);
 
 	std::string l_attr_name = cbd.dya->get_name();
-	yat::uint16 l_idx = extractNumber(l_attr_name); // extract channel nb
+	yat::uint16 l_idx = extractNumber(l_attr_name, kCHANNEL); // extract channel nb
 
     CHECK_MANAGER();
 	try
@@ -846,7 +863,7 @@ 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); // extract channel nb
+	yat::uint16 l_idx = extractNumber(l_attr_name, kSPEED); // extract channel nb
 
     CHECK_MANAGER();
 	double l_val = m_manager->get_speed(l_idx);
@@ -870,7 +887,7 @@ void SingleShotAO::write_speed(yat4tango::DynamicAttributeWriteCallbackData & cb
 	cbd.tga->get_write_value(l_val);
 
 	std::string l_attr_name = cbd.dya->get_name();
-	yat::uint16 l_idx = extractNumber(l_attr_name); // extract channel nb
+	yat::uint16 l_idx = extractNumber(l_attr_name, kSPEED); // extract channel nb
 	if (l_val < 0)
 	{
 		l_val = -l_val;
@@ -912,7 +929,7 @@ void SingleShotAO::read_initial(yat4tango::DynamicAttributeReadCallbackData & cb
 {
 	yat::AutoMutex<> guard(m_lock);
 	std::string l_attr_name = cbd.dya->get_name();
-	yat::uint16 l_idx = extractNumber(l_attr_name); // extract channel nb
+	yat::uint16 l_idx = extractNumber(l_attr_name, kINITIAL); // extract channel nb
 
 	CHECK_MANAGER();
 	double l_val = m_manager->get_initial(l_idx);
@@ -936,7 +953,7 @@ void SingleShotAO::write_initial(yat4tango::DynamicAttributeWriteCallbackData &
 	cbd.tga->get_write_value(l_val);
 
 	std::string l_attr_name = cbd.dya->get_name();
-	yat::uint16 l_idx = extractNumber(l_attr_name); // extract channel nb
+	yat::uint16 l_idx = extractNumber(l_attr_name, kINITIAL); // extract channel nb
 
 	CHECK_MANAGER();
 	try
-- 
GitLab


From a6daeef3f0f14b53fc87feb99c51ca25cd624a3c Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Thu, 20 Feb 2025 17:39:46 +0100
Subject: [PATCH 04/34] refactor: improve code readability and structure in
 SingleShotAOManager

---
 src/SingleShotAOManager.cpp | 247 ++++++++++++++++++------------------
 1 file changed, 123 insertions(+), 124 deletions(-)

diff --git a/src/SingleShotAOManager.cpp b/src/SingleShotAOManager.cpp
index 6e6c2e7..7e70818 100755
--- a/src/SingleShotAOManager.cpp
+++ b/src/SingleShotAOManager.cpp
@@ -145,12 +145,12 @@ void SingleShotAOManager::init(asl::SingleShotAO * p_ssao, unsigned short p_nb_c
 		enable_periodic_msg(true);
 	}
 
-  // 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++)
+	// 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++)
 	{
 		m_currentIndex[l_cpt] = -1;
-    m_isRunning[l_cpt] = false;
+    	m_isRunning[l_cpt] = false;
 	}
 }
 
@@ -164,36 +164,39 @@ void SingleShotAOManager::process_message (yat::Message& msg)
 	switch (msg.type())
 	{
 		//- THREAD_INIT ----------------------
-	case yat::TASK_INIT:
+		case yat::TASK_INIT:
 		{
 			DEBUG_STREAM << "SingleShotAOManager::handle_message::THREAD_INIT::thread is starting up" << std::endl;
 		} 
 		break;
 
 		//- THREAD_EXIT ----------------------
-	case yat::TASK_EXIT:
+		case yat::TASK_EXIT:
 		{
 			DEBUG_STREAM << "SingleShotAOManager::handle_message::THREAD_EXIT::thread is quitting" << std::endl;
 		}
 		break;
 
 		//- THREAD_PERIODIC ------------------
-	case yat::TASK_PERIODIC:
+		case yat::TASK_PERIODIC:
 		{
 			periodic_job_i();
 		}
 		break;
 
 		//- THREAD_TIMEOUT -------------------
-	case yat::TASK_TIMEOUT:
+		case yat::TASK_TIMEOUT:
 		{
 			//- not used in this example
 		}
 		break;
+
 		//- UNHANDLED MSG --------------------
-	default:
-		DEBUG_STREAM << "SingleShotAOManager::handle_message::unhandled msg type received" << std::endl;
-		break;
+		default:
+		{
+			DEBUG_STREAM << "SingleShotAOManager::handle_message::unhandled msg type received" << std::endl;
+			break;
+		}
 	}
 }
 
@@ -202,53 +205,52 @@ void SingleShotAOManager::process_message (yat::Message& msg)
 // ============================================================================ 
 void SingleShotAOManager::periodic_job_i()
 {
-	//test all channels
+	// test all channels
 	for (unsigned int l_cpt = 0;l_cpt < m_nb_chan;l_cpt++)
 	{
-		//test if a ramp step must occur
-		if (m_currentIndex[l_cpt] != -1)
+		// test if a ramp step must occur
+		if (m_currentIndex[l_cpt] == -1)
 		{
-			m_isRunning[l_cpt] = true;
-			double l_val = 0;
-			l_val = m_ramps[l_cpt][m_currentIndex[l_cpt]];
-			DEBUG_STREAM << "Current value for channel" << l_cpt << ": " << l_val << endl;
-			try 
-			{
-				CHECK_SSAO();
-				m_ssao->write_scaled_channel((adl::ChanId)l_cpt, l_val);
-				m_channels[l_cpt] = l_val;
-			}
-			catch(const asl::DAQException& de)
-			{
-				Tango::DevFailed df = daq_to_tango_exception(de);
-				ERROR_STREAM << df<< 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");
-			}
-			
-			//check if there is another value
-			m_currentIndex[l_cpt] +=1;
-			if (m_currentIndex[l_cpt] == m_ramps[l_cpt].capacity())
-			{
-				m_currentIndex[l_cpt] = -1;
-				m_initials[l_cpt] = m_channels[l_cpt];
-				m_ramps[l_cpt].clear();
-			}
+			m_isRunning[l_cpt] = false;
+			continue;
 		}
-		else
+
+		m_isRunning[l_cpt] = true;
+		double l_val = 0;
+		l_val = m_ramps[l_cpt][m_currentIndex[l_cpt]];
+		DEBUG_STREAM << "Current value for channel" << l_cpt << ": " << l_val << endl;
+		try 
 		{
-			m_isRunning[l_cpt] = false;
+			CHECK_SSAO();
+			m_ssao->write_scaled_channel((adl::ChanId)l_cpt, l_val);
+			m_channels[l_cpt] = l_val;
+		}
+		catch(const asl::DAQException& de)
+		{
+			Tango::DevFailed df = daq_to_tango_exception(de);
+			ERROR_STREAM << df << 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");
+		}
+		
+		// check if there is another value
+		m_currentIndex[l_cpt] += 1;
+		if (m_currentIndex[l_cpt] == m_ramps[l_cpt].capacity())
+		{
+			m_currentIndex[l_cpt] = -1;
+			m_initials[l_cpt] = m_channels[l_cpt];
+			m_ramps[l_cpt].clear();
 		}
 	}
 }
@@ -266,8 +268,9 @@ double SingleShotAOManager::get_channel(ChannelId_t p_chIdx)
 // ============================================================================ 
 void SingleShotAOManager::write_channel(ChannelId_t p_chIdx, double p_val)
 {
-	DEBUG_STREAM << "write_channel : " << p_chIdx << " : " << p_val << " : " << endl;
+	DEBUG_STREAM << "write_channel " << p_chIdx << " : " << p_val << endl;
 
+	// if the speed is 0, write the value directly
 	if (m_speeds[p_chIdx] == 0.0)
 	{
 		try 
@@ -276,11 +279,12 @@ void SingleShotAOManager::write_channel(ChannelId_t p_chIdx, double p_val)
 			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" << endl;
 		}
 		catch(const asl::DAQException& de)
 		{
 			Tango::DevFailed df = daq_to_tango_exception(de);
-			ERROR_STREAM << df<< endl;
+			ERROR_STREAM << df << endl;
 			m_state = Tango::FAULT;
 			RETHROW_DEVFAILED(df,
 				"DRIVER_FAILURE",
@@ -295,83 +299,78 @@ void SingleShotAOManager::write_channel(ChannelId_t p_chIdx, double p_val)
 				"could not write channel [unknown error]",
 				"SingleShotAOManager::write_channel");
 		}
+		return;
 	}
-	else
+
+	// if a ramp is not 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;
+	}
+
+	// ramp determination
+	double l_delta = p_val - m_initials[p_chIdx];
+	bool isDown = false;
+	l_delta  = ((l_delta * m_frequency) / m_speeds[p_chIdx]) + 1;
+	if (l_delta < 0)
+	{
+		l_delta = -l_delta + 2;
+		isDown = true;
+	}
+	DEBUG_STREAM << "Computed ramp steps number : " << l_delta << endl;
+
+	yat::Buffer<double> l_buffer;
+	size_t ramp_size = (size_t)(ceil(l_delta));
+	l_buffer.capacity(ramp_size);
+	l_buffer.force_length(ramp_size);
+	
+	// check if ramp step is integer or not
+	bool isDeltaNotInt = (ramp_size != ((size_t)(floor(l_delta))));
+	DEBUG_STREAM << "Real ramp steps number : " << ramp_size << endl;
+
+	for (unsigned int l_cpt = 0; l_cpt < ramp_size; l_cpt++)
 	{
-		// check if a ramp is not running
-		if (!m_isRunning[p_chIdx])
+		if ((l_cpt == (ramp_size - 1)) && (isDeltaNotInt))
 		{
-			// check if initial = channel
-			if (m_initials[p_chIdx] != p_val)
-			{
-				if (m_frequency == 0)
-				{
-					THROW_DEVFAILED("DRIVER_FAILURE",
-						"could not set a ramp on this channel. The frequency is 0",
-						"SingleShotAOManager::write_channel");
-				}
-				
-				//ramp determination
-				double l_delta = p_val - m_initials[p_chIdx];
-				bool isDown = false;
-				l_delta  = ((l_delta * m_frequency) / m_speeds[p_chIdx])+1;
-				if (l_delta < 0)
-				{
-					l_delta = -l_delta + 2;
-					isDown = true;
-				}
-				DEBUG_STREAM << "Computed ramp steps number : " << l_delta << endl;
-								
-				yat::Buffer<double> l_buffer;
-        size_t ramp_size = (size_t)(ceil(l_delta));
-				l_buffer.capacity(ramp_size);
-				l_buffer.force_length(ramp_size);
-				
-				// check if ramp step is integer or not
-				bool isDeltaNotInt = false;
-				if (ramp_size != ((size_t)(floor(l_delta))))
-				{
-				  isDeltaNotInt = true;
-				}
-
-        DEBUG_STREAM << "Real ramp steps number : " << ramp_size << endl;
-
-				for (unsigned int l_cpt = 0; l_cpt < ramp_size; l_cpt++)
-				{
-				  if ((l_cpt == (ramp_size - 1)) && 
-              (isDeltaNotInt))
-				  {
-					  // add the setpoint value at the end of table
-					  l_buffer[l_cpt] = p_val;
-				  }
-				  else
-				  {
-					  if (isDown)
-					  {
-						  l_buffer[l_cpt] = m_initials[p_chIdx] - l_cpt*(m_speeds[p_chIdx]/m_frequency);
-					  }
-					  else
-					  {
-						  l_buffer[l_cpt] = m_initials[p_chIdx] + l_cpt*(m_speeds[p_chIdx]/m_frequency);
-					  }
-				  }
-          //DEBUG_STREAM << "Ramp buffer[" << l_cpt << "] = " << l_buffer[l_cpt] << endl;
-				}
-				m_ramps[p_chIdx].clear();
-				m_ramps[p_chIdx].capacity(0);
-				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
-			}
+			// add the setpoint value at the end of table
+			l_buffer[l_cpt] = p_val;
 		}
 		else
 		{
-			THROW_DEVFAILED("DEVICE_FAILURE",
-				"could not write channel : a ramp is still in progress on this channel",
-				"SingleShotAOManager::write_channel");
+			if (isDown)
+			{
+				l_buffer[l_cpt] = m_initials[p_chIdx] - l_cpt * (m_speeds[p_chIdx] / m_frequency);
+			}
+			else
+			{
+				l_buffer[l_cpt] = m_initials[p_chIdx] + l_cpt * (m_speeds[p_chIdx] / m_frequency);
+			}
 		}
+		//DEBUG_STREAM << "Ramp buffer[" << l_cpt << "] = " << l_buffer[l_cpt] << endl;
 	}
+	m_ramps[p_chIdx].clear();
+	m_ramps[p_chIdx].capacity(0);
+	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
 }
 
 // ============================================================================
-- 
GitLab


From 1e77157f3e973921d7bb72459c344de18248f346 Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Fri, 21 Feb 2025 11:07:01 +0100
Subject: [PATCH 05/34] cleanup: fix typos, formatting and improve comments in
 SingleShotAO and SingleShotAOManager

---
 src/SingleShotAO.cpp        | 23 ++++++++++++-----------
 src/SingleShotAOManager.cpp | 20 ++++++++++----------
 src/SingleShotAOManager.h   |  4 ++--
 3 files changed, 24 insertions(+), 23 deletions(-)

diff --git a/src/SingleShotAO.cpp b/src/SingleShotAO.cpp
index 2c26d31..65643b0 100755
--- a/src/SingleShotAO.cpp
+++ b/src/SingleShotAO.cpp
@@ -326,7 +326,6 @@ void SingleShotAO::init_device()
 		DEBUG_STREAM << "Failed to get frequency value. Maybe there is no value yet." << std::endl;
 	}
 	
-
 	// initialize the AO manager
 	//--------------------------------------------
 	try
@@ -348,6 +347,10 @@ void SingleShotAO::init_device()
 		return;
 	}
 
+
+	// Create dynamic attributes
+	//--------------------------------------------
+
   	// create dynamic attribute manager
 	try
 	{
@@ -495,8 +498,7 @@ void SingleShotAO::init_device()
 			double l_val = yat4tango::PropertyHelper::get_memorized_attribute<double>(this, name);
 			m_manager->set_speed(l_cpt, l_val);
 	  	}
-		catch (...)
-		{
+			catch (...) {
 			// nothing to do
 		}
 
@@ -903,16 +905,17 @@ void SingleShotAO::write_speed(yat4tango::DynamicAttributeWriteCallbackData & cb
 		ERROR_STREAM << df<< endl;
 		RETHROW_DEVFAILED(df,
 			"DRIVER_FAILURE",
-			"could not write initial [caught Tango::DevFailed]",
-			"SingleShotAO::write_initial");
+			"could not write speed [caught Tango::DevFailed]",
+			"SingleShotAO::write_speed");
 	}
 	catch(...)
 	{
-		ERROR_STREAM << "SingleShotAO::write_initial::unknown exception caught"<<std::endl;
+		ERROR_STREAM << "SingleShotAO::write_speed::unknown exception caught" << std::endl;
 		THROW_DEVFAILED("DRIVER_FAILURE",
-			"could not write initial [unknown error]",
-			"SingleShotAO::write_initial");
+			"could not write speed [unknown error]",
+			"SingleShotAO::write_speed");
 	}
+
 	yat4tango::PropertyHelper::set_memorized_attribute(this, l_attr_name, l_val);
 }
 
@@ -975,6 +978,7 @@ void SingleShotAO::write_initial(yat4tango::DynamicAttributeWriteCallbackData &
 			"could not write initial [unknown error]",
 			"SingleShotAO::write_initial");
 	}
+
 	yat4tango::PropertyHelper::set_memorized_attribute(this, l_attr_name, l_val);
 }
 
@@ -986,14 +990,12 @@ void SingleShotAO::write_initial(yat4tango::DynamicAttributeWriteCallbackData &
  *	description:	method to execute "Abort"
  *	Aborts ramps in progress.
  *
- *
  */
 //+------------------------------------------------------------------
 void SingleShotAO::abort()
 {
 	DEBUG_STREAM << "SingleShotAO::abort(): entering... !" << endl;
 
-	//	Add your own code to control device here
 	CHECK_MANAGER();
 	try
 	{
@@ -1014,7 +1016,6 @@ void SingleShotAO::abort()
 			"could not abort [unknown error]",
 			"SingleShotAO::abort");
 	}
-
 }
 
 }	//	namespace
diff --git a/src/SingleShotAOManager.cpp b/src/SingleShotAOManager.cpp
index 7e70818..e78806d 100755
--- a/src/SingleShotAOManager.cpp
+++ b/src/SingleShotAOManager.cpp
@@ -270,7 +270,7 @@ 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
+	// if the speed is 0, write the value directly and skip ramp
 	if (m_speeds[p_chIdx] == 0.0)
 	{
 		try 
@@ -279,21 +279,21 @@ void SingleShotAOManager::write_channel(ChannelId_t p_chIdx, double p_val)
 			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" << endl;
+			DEBUG_STREAM << "Speed is 0, writing directly the value" << std::endl;
 		}
-		catch(const asl::DAQException& de)
+		catch (const asl::DAQException &de)
 		{
 			Tango::DevFailed df = daq_to_tango_exception(de);
-			ERROR_STREAM << df << endl;
+			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(...)
+		catch (...)
 		{
-			ERROR_STREAM << "SingleShotAOManager::write_channel::unknown exception caught"<<std::endl;
+			ERROR_STREAM << "SingleShotAOManager::write_channel::unknown exception caught" << std::endl;
 			m_state = Tango::FAULT;
 			THROW_DEVFAILED("DRIVER_FAILURE",
 				"could not write channel [unknown error]",
@@ -302,7 +302,7 @@ void SingleShotAOManager::write_channel(ChannelId_t p_chIdx, double p_val)
 		return;
 	}
 
-	// if a ramp is not running, error
+	// if a ramp is running, error
 	if (m_isRunning[p_chIdx])
 	{
 		THROW_DEVFAILED("DEVICE_FAILURE",
@@ -428,8 +428,8 @@ void SingleShotAOManager::set_speed(ChannelId_t p_chIdx, Intial_t p_speed)
 // ============================================================================
 void SingleShotAOManager::abort()
 {
-	//test all channels and abort current ramps
-	for (unsigned int l_cpt = 0;l_cpt < m_nb_chan;l_cpt++)
+	// test all channels and abort current ramps
+	for (unsigned int l_cpt = 0; l_cpt < m_nb_chan; l_cpt++)
 	{
 		if (m_isRunning[l_cpt])
 		{
@@ -441,5 +441,5 @@ void SingleShotAOManager::abort()
 		}
 	}
 }
-} // namespace SingleShotAO_ns
 
+} // namespace SingleShotAO_ns
diff --git a/src/SingleShotAOManager.h b/src/SingleShotAOManager.h
index 27e73ce..05be89d 100755
--- a/src/SingleShotAOManager.h
+++ b/src/SingleShotAOManager.h
@@ -59,10 +59,10 @@ public:
   //- change period
   void write_frequency(double p_frequency);
 
-  //- get inital
+  //- get initial
   Intial_t get_initial(ChannelId_t p_chIdx);
 
-  //- set inital
+  //- set initial
   void set_initial(ChannelId_t p_chIdx, Intial_t p_initial);
 
   //- get speed
-- 
GitLab


From 29aa9c832bc5ef0d6921f5b2737097bf8d0c0a5d Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Fri, 21 Feb 2025 11:16:49 +0100
Subject: [PATCH 06/34] fix/feature: memorize values and apply memorized values
 at init

---
 src/SingleShotAO.cpp        | 45 +++++++++++++++++--------------------
 src/SingleShotAOManager.cpp | 17 ++++++++++++++
 src/SingleShotAOManager.h   |  5 ++++-
 3 files changed, 41 insertions(+), 26 deletions(-)

diff --git a/src/SingleShotAO.cpp b/src/SingleShotAO.cpp
index 65643b0..8b886ad 100755
--- a/src/SingleShotAO.cpp
+++ b/src/SingleShotAO.cpp
@@ -489,32 +489,25 @@ void SingleShotAO::init_device()
 		yat::OSStream oss;
 		oss << l_cpt;
 
-		// speed value
-		try
-	  	{
-		  	std::string attr_name = kSPEED + oss.str();
-      		std::string name = "__" + attr_name;
-
-			double l_val = yat4tango::PropertyHelper::get_memorized_attribute<double>(this, name);
-			m_manager->set_speed(l_cpt, l_val);
-	  	}
-			catch (...) {
-			// nothing to do
-		}
-
-		// initial value
-		try
+		// Helper function to get and set memorized attributes
+		auto applyMemorizedAttr = [&](const std::string& attrPrefix, 
+			void (SingleShotAOManager::*setter)(yat::uint16, double))
 		{
-			std::string attr_name = kINITIAL + oss.str();
-			std::string name = "__" + attr_name;
-
-			double l_val = yat4tango::PropertyHelper::get_memorized_attribute<double>(this,name);
-			m_manager->set_initial(l_cpt, l_val);
-        }
-	    catch (...)
-		{
-			//nothing to do
-		}
+			try {
+				std::string attrName = attrPrefix + oss.str();
+				double val = yat4tango::PropertyHelper::get_memorized_attribute<double>(this, attrName);
+				(m_manager->*setter)(l_cpt, val);
+			}
+			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)
     }
 
 	//- GO for task
@@ -850,6 +843,8 @@ void SingleShotAO::write_channel(yat4tango::DynamicAttributeWriteCallbackData &
 			"could not write channel [unknown error]",
 			"SingleShotAO::write_channel");
 	}
+
+	yat4tango::PropertyHelper::set_memorized_attribute(this, l_attr_name, l_val);
 }
 
 
diff --git a/src/SingleShotAOManager.cpp b/src/SingleShotAOManager.cpp
index e78806d..5d7b57a 100755
--- a/src/SingleShotAOManager.cpp
+++ b/src/SingleShotAOManager.cpp
@@ -263,6 +263,23 @@ double SingleShotAOManager::get_channel(ChannelId_t p_chIdx)
 	return m_channels[p_chIdx];
 }
 
+// ============================================================================
+// SingleShotAOManager::set_channel ()
+// ============================================================================ 
+void SingleShotAOManager::set_channel(ChannelId_t p_chIdx, double p_val)
+{
+	if (m_isRunning[p_chIdx])
+	{
+		THROW_DEVFAILED("DEVICE_FAILURE",
+						"could not write channel : a ramp is still in progress on this channel",
+						"SingleShotAOManager::set_channel");
+	}
+	else
+	{
+		m_channels[p_chIdx] = p_val;
+	}
+}
+
 // ============================================================================
 // SingleShotAOManager::write_channel ()
 // ============================================================================ 
diff --git a/src/SingleShotAOManager.h b/src/SingleShotAOManager.h
index 05be89d..ccabfce 100755
--- a/src/SingleShotAOManager.h
+++ b/src/SingleShotAOManager.h
@@ -52,7 +52,10 @@ public:
 
   //- get current channel value
   double get_channel(ChannelId_t p_chIdx);
-	  
+
+  //- set channel
+  void set_channel(ChannelId_t p_chIdx, double p_val);
+
   //- write channel
   void write_channel(ChannelId_t p_chIdx, double p_val);
 
-- 
GitLab


From bcce86f18b6007a4810b3a8f142f6d1ff5d890b6 Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Fri, 21 Feb 2025 13:46:00 +0100
Subject: [PATCH 07/34] cleanup(doc): format HTML documentation files

---
 doc/doc_html/Attributes.html       | 165 ++++++++------------
 doc/doc_html/Description.html      | 147 +++---------------
 doc/doc_html/DevCommands.html      | 232 ++++++++++-------------------
 doc/doc_html/DevCommandsFrame.html |  33 ++--
 doc/doc_html/DevCommandsList.html  |  31 ++--
 doc/doc_html/DevCommandsTable.html | 183 ++++++++---------------
 doc/doc_html/Properties.html       | 204 ++++++++++---------------
 doc/doc_html/TangoDevStates.html   | 177 +++++++---------------
 doc/doc_html/index.html            | 178 ++++++----------------
 9 files changed, 435 insertions(+), 915 deletions(-)

diff --git a/doc/doc_html/Attributes.html b/doc/doc_html/Attributes.html
index 1c88911..9a6dff5 100755
--- a/doc/doc_html/Attributes.html
+++ b/doc/doc_html/Attributes.html
@@ -1,114 +1,69 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<HTML>
-<HEAD>
-<Title> Tango Device Server User's Guide </Title>
-</HEAD>
-<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#0000FF" VLINK="#7F00FF" ALINK="#FF0000">
+<html>
+<head>
 
-<P><!-------TITLE------></P>
+	<title> Tango Device Server User's Guide </title>
+</head>
 
-<TABLE BORDER="0" WIDTH="100%">
-    <TR>
-        <TD ALIGN="left">
-			<A HREF="http://www.esrf.fr/" TARGET=new>
-			<IMG SRC="http://www.esrf.fr/gifs/logo/80.gif" BORDER=0 Height="60"></A>
-		</Td>
-        <TD ALIGN="center">
-			<A HREF="http://www.elettra.trieste.it/" TARGET=new>
-			<IMG SRC="http://www.esrf.fr/computing/cs/tango/elettra_logo.gif" BORDER=0 Height="60"></A>
+<body>
+	<center>
+		<h1>
+			SingleShotAO Generic Device <br>
+			Device Attributes Description <br><Br>
+			SingleShotAO Class <br>
+		</h1>
+		<b>
+			Revision: - Author: buteau
+		</b>
+	</center>
 
-		</Td>
-        <TD ALIGN="center">
-			<A HREF="http://www.synchrotron-soleil.fr/" TARGET=new>
-			<IMG SRC="http://www.esrf.fr/computing/cs/tango/soleil_logo.gif" BORDER=0 Height="60"></A>
-		</Td>
-        <TD ALIGN="right">
-			<A HREF="http://www.cells.es/" TARGET=new>
-			<IMG SRC="http://www.esrf.fr/computing/cs/tango/alba.jpg" BORDER=0 Height="54"></A>
-		</Td>
-        <TD ALIGN="right">
-			<A HREF="http://www.desy.de/html/home/index_eng.html" TARGET=new>
-			<IMG SRC="http://www.esrf.fr/computing/cs/tango/desy.gif" BORDER=0 Height="60"></A>
-		</Td>
-    	 <Td>
-			<H2><FONT COLOR="#7F00FF">
-			<Center><A HREF="http://www.tango-controls.org/" TARGET="_top">
-					 TANGO </a> <Br> Device Server
-			</Center></FONT>
-		</Td>
-    </TR>
-</TABLE>
+	<table Border=2 Cellpadding=3 CELLSPACING=0 WIDTH="100%">
+		<tr BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+			<td COLSPAN=4>
+				<font Size=+2><center><b>Scalar Attributes</b></center></font>
+			</td>
+		</tr>
+		<tr BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+			<td>
+				<center><b>Attribute name</b>
+			</td>
+			</center>
+			<td>
+				<center><b>Data Type</b>
+			</td>
+			</center>
+			<td>
+				<center><b>R/W Type</b>
+			</td>
+			</center>
+			<td>
+				<center><b>Expert</b>
+			</td>
+			</center>
+		<tr>
+			<td><b>frequency</b>: <font Size=-1>Sampling frequency for
+					ramp generation on the board output channels, in
+					Hz.</font>
+			</td>
+			<td>
+				<center>
+					<font Size=-1>DEV_DOUBLE</font>
+				</center>
+			</td>
+			<td>
+				<center>
+					<font Size=-1>READ_WRITE</font>
+				</center>
+			</td>
+			<td>
+				<center>
+					<font Size=-1>Yes</font>
+				</center>
+			</td>
+		</tr>
 
-<HR WIDTH="100%"></H5>
-<Br>
-<center>
-<h1>
-SingleShotAO Generic Device		<Br>
-Device Attributes Description 		<Br> <Br>
-SingleShotAO Class	<Br>
-</h1>
-<b>
-Revision:  - Author: buteau
-</b>
+	</table>
 </center>
 
-
-<Br>
-<Table Border=2 Cellpadding=3 CELLSPACING=0 WIDTH="100%">
-<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
-<Td COLSPAN=4> <Font Size=+2><Center><b>Scalar Attributes</b></td></Font></Center>
-<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
-<Td><Center><b>Attribute name</b></td></Center>
-<Td><Center><b>Data Type</b></td></Center>
-<Td><Center><b>R/W Type</b></td></Center>
-<Td><Center><b>Expert</b></td></Center>
-<Tr><Td><b>frequency</b>: <Font Size=-1>Sampling frequency for ramp generation on the board output channels, in Hz.</Font></Td>
-<Td><Center><Font Size=-1>DEV_DOUBLE</Font></Center></Td><Td><Center><Font Size=-1>READ_WRITE</Font></Center></Td><Td><Center><Font Size=-1>Yes</Font></Center></Td></Tr>
-
-</Table>
-</Center>
-<Br><Br><Br><Br><Br>
-
-<!--- html Footer --->
-
-<Center>
-<Font size=-1>
-<br>
-<br>
-<TABLE BORDER="1" WIDTH="100%">
-    <Tr>
-		<!--- Hosted by Sourceforge --->
-        <Td Align="Center">
-			<Font size=-1>
-			<b>TANGO</b> is an open source project hosted by :<br>
-			<A href="http://sourceforge.net" Target="new">
-					<IMG title="Sourceforge logo"
-						alt="Sourceforge logo small"
-						src="http://www.esrf.fr/computing/cs/tango/sourceforge.gif"
-						border=0> </a>
-			</Font>
-		</Td>
-		<!--- 2 Sourceforge Repositories --->
-		<Td Align="Center">
-			<Font size=-1>
-			Core and Tools :
-			<a href="http://tango-cs.cvs.sourceforge.net/tango-cs/" Target="new">
-			CVS repository</a> on
-			<a href="https://sourceforge.net/projects/tango-cs" Target=new>
-			tango-cs project</a>
-
-			<br>
-
-			Device Servers :
-			<a href="http://tango-ds.cvs.sourceforge.net/tango-ds/" Target="new">
-					CVS repository</a> on
-			<a href="https://sourceforge.net/projects/tango-ds" Target=new>
-					tango-ds project</a>
-			</Font>
-		</Td>
-    </Tr>
-</Table>
-</Font>
-</Center>
 </body>
 </html>
diff --git a/doc/doc_html/Description.html b/doc/doc_html/Description.html
index e9447e2..b63c5d3 100755
--- a/doc/doc_html/Description.html
+++ b/doc/doc_html/Description.html
@@ -1,129 +1,26 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<HTML>
-<HEAD>
-<Title> Tango Device Server User s Guide </Title>
-</HEAD>
-<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#0000FF" VLINK="#7F00FF" ALINK="#FF0000">
+<html>
+
+<head>
+    <title> Tango Device Server User s Guide </title>
+</head>
+
+<body>
+    <center>
+        <h1>
+            SingleShotAO Generic Device <br>
+            Device Description <br> <br>
+            SingleShotAO Class <br>
+        </h1>
+        <b>
+            Revision: - Author: buteau
+        </b>
+    </center>
+
+    <center>
+        ADLink boards support for single shot AO operations [PCI-6208 and
+        compatible boards]
+    </center>
 
-<P><!-------TITLE------></P>
-<TABLE BORDER="0" WIDTH="100%">
-    <TR>
-        <TD ALIGN="left">
-            <A HREF="http://www.esrf.fr/" TARGET=new>
-            <IMG SRC="http://www.esrf.fr/gifs/logo/80.gif" BORDER=0 Height="60"></A>
-
-        </TD>
-        <TD ALIGN="center">
-            <A HREF="http://www.elettra.trieste.it/" TARGET=new>
-            <IMG SRC="http://www.esrf.fr/computing/cs/tango/elettra_logo.gif" BORDER=0 Height="60"></A>
-        </TD>
-        <TD ALIGN="center">
-            <A HREF="http://www.synchrotron-soleil.fr/" TARGET=new>
-            <IMG SRC="http://www.esrf.fr/computing/cs/tango/soleil_logo.gif" BORDER=0 Height="60"></A>
-        </TD>
-
-        <TD ALIGN="center">
-            <A HREF="http://www.cells.es/" TARGET=new>
-            <IMG SRC="http://www.esrf.fr/computing/cs/tango/alba.jpg" BORDER=0 Height="45"></A>
-        </TD>
-        <TD ALIGN="Right">
-            <H2><FONT COLOR="#7F00FF">
-            <Br><Center><A HREF="http://www.tango-controls.org/" TARGET="_top"> TANGO </a> 
-            </Center></FONT>
-
-       </TD>
-    </TR>
-    <TR>
-        <TD ALIGN="left">
-            <A HREF="http://www.desy.de/html/home/index_eng.html" TARGET=new>
-            <IMG SRC="http://www.esrf.fr/computing/cs/tango/desy.gif" BORDER=0 Height="44"></A>
-        </TD>
-        <TD ALIGN="center">
-            <A HREF="http://www.maxlab.lu.se/maxlab/max4/index.html" TARGET=new>
-
-            <IMG SRC="http://www.esrf.fr/computing/cs/tango/maxlab.gif" BORDER=0 Height="40"></A>
-        </TD>
-        <TD ALIGN="center">
-            <A HREF="http://www.frm2.tum.de/en/index.html" TARGET=new>
-            <IMG SRC="http://www.esrf.fr/computing/cs/tango/frm-2.jpg" BORDER=0 Height="45"></A>
-        </TD>
-            <TD>
-            <!-- Empty -->
-        </TD>
-
-        <TD ALIGN="Right">
-            <H2><FONT COLOR="#7F00FF">
-            <Center> Device Servers
-            </Center></FONT>
-        </TD>
-    </TR>
-</TABLE>
-
-<HR WIDTH="100%"></H5>
-
-
-
-
-<HR WIDTH="100%"></H5>
-<Br>
-<center>
-<h1>
-SingleShotAO Generic Device		<Br>
-Device Description 		<Br> <Br>
-SingleShotAO Class	<Br>
-</h1>
-<b>
-Revision:  - Author: buteau
-</b>
-</center>
-
-
-<Center>
-ADLink boards support for single shot AO operations [PCI-6208 and compatible boards]
-<Br>
-<Br>
-</Center>
-
-<!--- html Footer --->
-
-<Center>
-<Font size=-1>
-<br>
-<br>
-<TABLE BORDER="1" WIDTH="100%">
-    <Tr>
-		<!--- Hosted by Sourceforge --->
-        <Td Align="Center">
-			<Font size=-1>
-			<b>TANGO</b> is an open source project hosted by :<br>
-			<A href="http://sourceforge.net" Target="new">
-					<IMG title="Sourceforge logo"
-						alt="Sourceforge logo small"
-						src="http://www.esrf.fr/computing/cs/tango/sourceforge.gif"
-						border=0> </a>
-			</Font>
-		</Td>
-		<!--- 2 Sourceforge Repositories --->
-		<Td Align="Center">
-			<Font size=-1>
-			Core and Tools :
-			<a href="http://tango-cs.cvs.sourceforge.net/tango-cs/" Target="new">
-			CVS repository</a> on
-			<a href="https://sourceforge.net/projects/tango-cs" Target=new>
-			tango-cs project</a>
-
-			<br>
-
-			Device Servers :
-			<a href="http://tango-ds.cvs.sourceforge.net/tango-ds/" Target="new">
-					CVS repository</a> on
-			<a href="https://sourceforge.net/projects/tango-ds" Target=new>
-					tango-ds project</a>
-			</Font>
-		</Td>
-    </Tr>
-</Table>
-</Font>
-</Center>
 </body>
 </html>
diff --git a/doc/doc_html/DevCommands.html b/doc/doc_html/DevCommands.html
index 306b671..9dbd3bf 100755
--- a/doc/doc_html/DevCommands.html
+++ b/doc/doc_html/DevCommands.html
@@ -1,162 +1,90 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
 <HTML>
+
 <HEAD>
-<Title> Tango Device Server User's Guide </Title>
+    <Title> Tango Device Server User's Guide </Title>
 </HEAD>
-<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#0000FF" VLINK="#7F00FF" ALINK="#FF0000">
-
-<P><!-------TITLE------></P>
-
-<TABLE BORDER="0" WIDTH="100%">
-    <TR>
-        <TD ALIGN="left">
-			<A HREF="http://www.esrf.fr/" TARGET=new>
-			<IMG SRC="http://www.esrf.fr/gifs/logo/80.gif" BORDER=0 Height="60"></A>
-		</Td>
-        <TD ALIGN="center">
-			<A HREF="http://www.elettra.trieste.it/" TARGET=new>
-			<IMG SRC="http://www.esrf.fr/computing/cs/tango/elettra_logo.gif" BORDER=0 Height="60"></A>
-
-		</Td>
-        <TD ALIGN="center">
-			<A HREF="http://www.synchrotron-soleil.fr/" TARGET=new>
-			<IMG SRC="http://www.esrf.fr/computing/cs/tango/soleil_logo.gif" BORDER=0 Height="60"></A>
-		</Td>
-        <TD ALIGN="right">
-			<A HREF="http://www.cells.es/" TARGET=new>
-			<IMG SRC="http://www.esrf.fr/computing/cs/tango/alba.jpg" BORDER=0 Height="54"></A>
-		</Td>
-        <TD ALIGN="right">
-			<A HREF="http://www.desy.de/html/home/index_eng.html" TARGET=new>
-			<IMG SRC="http://www.esrf.fr/computing/cs/tango/desy.gif" BORDER=0 Height="60"></A>
-		</Td>
-    	 <Td>
-			<H2><FONT COLOR="#7F00FF">
-			<Center><A HREF="http://www.tango-controls.org/" TARGET="_top">
-					 TANGO </a> <Br> Device Server
-			</Center></FONT>
-		</Td>
-    </TR>
-</TABLE>
 
-<HR WIDTH="100%"></H5>
-<Br>
-<center>
-<h1>
-SingleShotAO Generic Device		<Br>
-Device Commands Description 		<Br> <Br>
-SingleShotAO Class	<Br>
-</h1>
-<b>
-Revision:  - Author: buteau
-</b>
-</center>
+<BODY>
+    <center>
+        <h1>
+            SingleShotAO Generic Device <br>
+            Device Commands Description <br> <br>
+            SingleShotAO Class <br>
+        </h1>
+        <b>
+            Revision: - Author: buteau
+        </b>
+    </center>
 
+    <h2>1 - Init</h2>
+    <ul>
+        <Li><Strong>Description: </Strong><br>
+            This command re-initialises a device keeping the same network connection. <br>
+            After an Init command executed on a device, it is not necessary for the client to re-connect to the device. <br>
+            This command first calls the device <i>delete_device()</i> method and then executes its <i>init_device()</i> method. <br>
+            For C++ device server, all the memory allocated in the <i>init_device()</i> method must be freed in the <i>delete_device()</i> method.<br>
+            The language device destructor automatically calls the <i>delete_device()</i> method.<br>
+        </Li>
+        <Li><Strong>Argin: DEV_VOID</Strong></Li>
+        <Li><Strong>Argout: DEV_VOID</Strong></Li>
+        <Li><Strong>Command allowed for: </Strong>
+            <Ul>
+                <Li>Tango::FAULT</Li>
+                <Li>Tango::ON</Li>
+                <Li>Tango::INIT</Li>
+                <Li>Tango::MOVING</Li>
+            </Ul>
+        </Li>
+    </ul> 
+     
 
-<Br>
-<Br>
-<Br>
-<A NAME="Init"><!-- --></A>
-<A NAME="Init"><!-- --></A>
-<h2>1 - Init</h2>
-<ul>
-<Li><Strong>Description: </Strong> This commands re-initialise a device keeping the same network connection.<Br>
-After an Init command executed on a device, it is not necessary for client to re-connect to the device.<Br>
-This command first calls the device <i> delete_device() </i>method and then execute its <i> init_device()</i> method.<Br>
-For C++ device server, all the memory allocated in the <i> nit_device() </i> method must be freed in the <i> delete_device() </i> method.<Br>
-The language device desctructor automatically calls the <i> delete_device() </i> method.<Br>&nbsp
-<Li><Strong>Argin:<Br>DEV_VOID</Strong>
- : none.<Br>&nbsp
-<Li><Strong>Argout:<Br>DEV_VOID</Strong>
- : none.<Br>&nbsp
-<Li><Strong>Command allowed for: </Strong><Ul>
-<Li>Tango::FAULT<Li>Tango::ON<Li>Tango::INIT<Li>Tango::MOVING</Ul>
-<Br>&nbsp
-</ul><Br>
-<Br>
-<A NAME="State"><!-- --></A>
-<A NAME="State"><!-- --></A>
-<h2>2 - State</h2>
-<ul>
-<Li><Strong>Description: </Strong> This command gets the device state (stored in its <i>device_state</i> data member) and returns it to the caller.<Br>&nbsp
-<Li><Strong>Argin:<Br>DEV_VOID</Strong>
- : none.<Br>&nbsp
-<Li><Strong>Argout:<Br>DEV_STATE</Strong>
- : State Code<Br>&nbsp
-<Li><Strong>Command allowed for: </Strong><Ul>
-<Li>Tango::FAULT<Li>Tango::ON<Li>Tango::INIT<Li>Tango::MOVING</Ul>
-<Br>&nbsp
-</ul><Br>
-<Br>
-<A NAME="Status"><!-- --></A>
-<A NAME="Status"><!-- --></A>
-<h2>3 - Status</h2>
-<ul>
-<Li><Strong>Description: </Strong> This command gets the device status (stored in its <i>device_status</i> data member) and returns it to the caller.<Br>&nbsp
-<Li><Strong>Argin:<Br>DEV_VOID</Strong>
- : none.<Br>&nbsp
-<Li><Strong>Argout:<Br>CONST_DEV_STRING</Strong>
- : Status description<Br>&nbsp
-<Li><Strong>Command allowed for: </Strong><Ul>
-<Li>Tango::FAULT<Li>Tango::ON<Li>Tango::INIT<Li>Tango::MOVING</Ul>
-<Br>&nbsp
-</ul><Br>
-<Br>
-<A NAME="Abort"><!-- --></A>
-<A NAME="Abort"><!-- --></A>
-<h2>4 - Abort</h2>
-<ul>
-<Li><Strong>Description: </Strong> Aborts ramps in progress.<Br>&nbsp
-<Li><Strong>Argin:<Br>DEV_VOID</Strong>
- : <Br>&nbsp
-<Li><Strong>Argout:<Br>DEV_VOID</Strong>
- : <Br>&nbsp
-<Li><Strong>Command allowed for: </Strong><Ul>
-<Li>Tango::FAULT<Li>Tango::ON<Li>Tango::INIT<Li>Tango::MOVING</Ul>
-<Br>&nbsp
-</ul><Br>
-<Br>
+    <h2>2 - State</h2>
+    <ul>
+        <Li><Strong>Description: </Strong> This command gets the device state (stored in its <i>device_state</i> data member) and returns it to the caller.
+        <Li><Strong>Argin: DEV_VOID</Strong></Li>
+        <Li><Strong>Argout: DEV_STATE</Strong></Li>
+        <Li><Strong>Command allowed for: </Strong>
+            <Ul>
+                <Li>Tango::FAULT</Li>
+                <Li>Tango::ON</Li>
+                <Li>Tango::INIT</Li>
+                <Li>Tango::MOVING</Li>
+            </Ul>
+        </Li>
+    </ul> 
+     
 
-<!--- html Footer --->
+    <h2>3 - Status</h2>
+    <ul>
+        <Li><Strong>Description: </Strong> This command gets the device status (stored in its <i>device_status</i> data member) and returns it to the caller.</Li>
+        <Li><Strong>Argin: DEV_VOID</Strong></Li>
+        <Li><Strong>Argout: CONST_DEV_STRING</Strong></Li>
+        <Li><Strong>Command allowed for: </Strong>
+            <Ul>
+                <Li>Tango::FAULT</Li>
+                <Li>Tango::ON</Li>
+                <Li>Tango::INIT</Li>
+                <Li>Tango::MOVING</Li>
+            </Ul>
+        </Li>
+    </ul> 
+     
 
-<Center>
-<Font size=-1>
-<br>
-<br>
-<TABLE BORDER="1" WIDTH="100%">
-    <Tr>
-		<!--- Hosted by Sourceforge --->
-        <Td Align="Center">
-			<Font size=-1>
-			<b>TANGO</b> is an open source project hosted by :<br>
-			<A href="http://sourceforge.net" Target="new">
-					<IMG title="Sourceforge logo"
-						alt="Sourceforge logo small"
-						src="http://www.esrf.fr/computing/cs/tango/sourceforge.gif"
-						border=0> </a>
-			</Font>
-		</Td>
-		<!--- 2 Sourceforge Repositories --->
-		<Td Align="Center">
-			<Font size=-1>
-			Core and Tools :
-			<a href="http://tango-cs.cvs.sourceforge.net/tango-cs/" Target="new">
-			CVS repository</a> on
-			<a href="https://sourceforge.net/projects/tango-cs" Target=new>
-			tango-cs project</a>
-
-			<br>
-
-			Device Servers :
-			<a href="http://tango-ds.cvs.sourceforge.net/tango-ds/" Target="new">
-					CVS repository</a> on
-			<a href="https://sourceforge.net/projects/tango-ds" Target=new>
-					tango-ds project</a>
-			</Font>
-		</Td>
-    </Tr>
-</Table>
-</Font>
-</Center>
+    <h2>4 - Abort</h2>
+    <ul>
+        <Li><Strong>Description: </Strong> Aborts ramps in progress.</Li>
+        <Li><Strong>Argin: DEV_VOID</Strong></Li>
+        <Li><Strong>Argout: DEV_VOID</Strong></Li>
+        <Li><Strong>Command allowed for: </Strong>
+            <Ul>
+                <Li>Tango::FAULT</Li>
+                <Li>Tango::ON</Li>
+                <Li>Tango::INIT</Li>
+                <Li>Tango::MOVING</Li>
+            </Ul>
+        </Li>
+    </ul> 
 </body>
-</html>
+
+</html>
\ No newline at end of file
diff --git a/doc/doc_html/DevCommandsFrame.html b/doc/doc_html/DevCommandsFrame.html
index a696d50..8938ab2 100755
--- a/doc/doc_html/DevCommandsFrame.html
+++ b/doc/doc_html/DevCommandsFrame.html
@@ -1,19 +1,20 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<HTML>
-<HEAD>
-<Title> Tango Device Server User's Guide </Title>
-</HEAD>
+<html>
+    <head>
+        <title> Tango Device Server User's Guide </title>
+    </head>
 
-<FRAMESET cols="20%,80%">
-<FRAME src="DevCommandsList.html" name="DevCommandsList">
-<FRAME src="DevCommands.html" name="DevCommands">
-</FRAMESET>
-<NOFRAMES>
-<H2>
-Frame Alert</H2>
+    <frameset cols="20%,80%">
+        <frame src="DevCommandsList.html" name="DevCommandsList">
+        <frame src="DevCommands.html" name="DevCommands">
+    </frameset>
+    <noframes>
+        <h2>
+            Frame Alert</h2>
 
-<P>
-This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client.
-<BR>
-Link to <A HREF="DevCommands.html">Non-frame version.</A></NOFRAMES>
-</HTML>
+        <p>
+            This document is designed to be viewed using the frames feature. If
+            you see this message, you are using a non-frame-capable web client.
+            <br>
+            Link to <a HREF="DevCommands.html">Non-frame version.</a></noframes>
+    </html>
diff --git a/doc/doc_html/DevCommandsList.html b/doc/doc_html/DevCommandsList.html
index dff7f08..c69789b 100755
--- a/doc/doc_html/DevCommandsList.html
+++ b/doc/doc_html/DevCommandsList.html
@@ -1,18 +1,17 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
-<HTML><HEAD>
-<TITLE>Commands
-</TITLE></HEAD>
-<BODY BGCOLOR="white">
-<FONT size="+1" ID="FrameHeadingFont">
-<B>Commands:</B></FONT>
-<Br>
-<Br>
-<Br>
-<A Href="DevCommands.html#Init" TARGET="DevCommands"> Init</a><Br>
-<A Href="DevCommands.html#State" TARGET="DevCommands"> State</a><Br>
-<A Href="DevCommands.html#Status" TARGET="DevCommands"> Status</a><Br>
-<A Href="DevCommands.html#Abort" TARGET="DevCommands"> Abort</a><Br>
+<html><head>
+        <title>Commands
+        </title></head>
+    <body BGCOLOR="white">
+        <font size="+1" ID="FrameHeadingFont">
+            <b>Commands:</b></font>
+        <br>
+        <br>
+        <br>
+        <a Href="DevCommands.html#Init" TARGET="DevCommands"> Init</a><br>
+        <a Href="DevCommands.html#State" TARGET="DevCommands"> State</a><br>
+        <a Href="DevCommands.html#Status" TARGET="DevCommands"> Status</a><br>
+        <a Href="DevCommands.html#Abort" TARGET="DevCommands"> Abort</a><br>
 
-
-</BODY>
-</HTML>
+    </body>
+</html>
diff --git a/doc/doc_html/DevCommandsTable.html b/doc/doc_html/DevCommandsTable.html
index 7c2194a..4cd1eb4 100755
--- a/doc/doc_html/DevCommandsTable.html
+++ b/doc/doc_html/DevCommandsTable.html
@@ -1,126 +1,63 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<HTML>
-<HEAD>
-<Title> Tango Device Server User's Guide </Title>
-</HEAD>
-<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#0000FF" VLINK="#7F00FF" ALINK="#FF0000">
+<html>
+
+<head>
+    <title> Tango Device Server User's Guide </title>
+</head>
+
+<body>
+    <center>
+        <h1>
+            SingleShotAO Generic Device <br>
+            Device Commands Description <br><br>
+            SingleShotAO Class <br>
+        </h1>
+        <b>
+            Revision: - Author: buteau
+        </b>
+    </center>
+
+    <center>
+        <br><a Href="DevCommandsFrame.html"> More Details on commands.... </a><br><br>
+
+        <table Border=2 Cellpadding=3 CELLSPACING=0 WIDTH="100%">
+            <tr BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+                <td COLSPAN=3>
+                    <font Size=+2><center>
+                        <b>Device Commands for Operator Level</b>
+                    </center></font>
+                </td>
+            </tr>
+
+            <tr BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+                <td><b>Command name</b></td>
+                <td><b>Argument In</b></td>
+                <td><b>Argument Out</b></td>
+            </tr>
+            <tr>
+                <td><b>Init</b></td>
+                <td>DEV_VOID</td>
+                <td>DEV_VOID</td>
+            </tr>
+            <tr>
+                <td><b>State</b></td>
+                <td>DEV_VOID</td>
+                <td>DEV_STATE</td>
+            </tr>
+            <tr>
+                <td><b>Status</b></td>
+                <td>DEV_VOID</td>
+                <td>CONST_DEV_STRING</td>
+            </tr>
+            <tr>
+                <td><b>Abort</b></td>
+                <td>DEV_VOID</td>
+                <td>DEV_VOID</td>
+            </tr>
+
+        </table>
+    </center>
 
-<P><!-------TITLE------></P>
-
-<TABLE BORDER="0" WIDTH="100%">
-    <TR>
-        <TD ALIGN="left">
-			<A HREF="http://www.esrf.fr/" TARGET=new>
-			<IMG SRC="http://www.esrf.fr/gifs/logo/80.gif" BORDER=0 Height="60"></A>
-		</Td>
-        <TD ALIGN="center">
-			<A HREF="http://www.elettra.trieste.it/" TARGET=new>
-			<IMG SRC="http://www.esrf.fr/computing/cs/tango/elettra_logo.gif" BORDER=0 Height="60"></A>
-
-		</Td>
-        <TD ALIGN="center">
-			<A HREF="http://www.synchrotron-soleil.fr/" TARGET=new>
-			<IMG SRC="http://www.esrf.fr/computing/cs/tango/soleil_logo.gif" BORDER=0 Height="60"></A>
-		</Td>
-        <TD ALIGN="right">
-			<A HREF="http://www.cells.es/" TARGET=new>
-			<IMG SRC="http://www.esrf.fr/computing/cs/tango/alba.jpg" BORDER=0 Height="54"></A>
-		</Td>
-        <TD ALIGN="right">
-			<A HREF="http://www.desy.de/html/home/index_eng.html" TARGET=new>
-			<IMG SRC="http://www.esrf.fr/computing/cs/tango/desy.gif" BORDER=0 Height="60"></A>
-		</Td>
-    	 <Td>
-			<H2><FONT COLOR="#7F00FF">
-			<Center><A HREF="http://www.tango-controls.org/" TARGET="_top">
-					 TANGO </a> <Br> Device Server
-			</Center></FONT>
-		</Td>
-    </TR>
-</TABLE>
-
-<HR WIDTH="100%"></H5>
-<Br>
-<center>
-<h1>
-SingleShotAO Generic Device		<Br>
-Device Commands Description 		<Br> <Br>
-SingleShotAO Class	<Br>
-</h1>
-<b>
-Revision:  - Author: buteau
-</b>
-</center>
-
-
-<Center>
-<Br><Br>
-<A Href="DevCommandsFrame.html"> More Details on commands.... </a><Br>
-<Br> <Br>
-<Table Border=2 Cellpadding=3 CELLSPACING=0 WIDTH="100%">
-<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
-<Td COLSPAN=3> <Font Size=+2><Center><b>Device Commands for Operator Level</b></td></Font></Center>
-<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
-<Td><Center><b>Command name</b></td></Center>
-<Td><Center><b>Argument In</b></td></Center>
-<Td><Center><b>Argument Out</b></td></Center>
-<Tr><Td><b>Init</b></Td>
-<Td><Font Size=-1>DEV_VOID</Font></Td>
-<Td><Font Size=-1>DEV_VOID</Font></Td>
-<Tr><Td><b>State</b></Td>
-<Td><Font Size=-1>DEV_VOID</Font></Td>
-<Td><Font Size=-1>DEV_STATE</Font></Td>
-<Tr><Td><b>Status</b></Td>
-<Td><Font Size=-1>DEV_VOID</Font></Td>
-<Td><Font Size=-1>CONST_DEV_STRING</Font></Td>
-<Tr><Td><b>Abort</b></Td>
-<Td><Font Size=-1>DEV_VOID</Font></Td>
-<Td><Font Size=-1>DEV_VOID</Font></Td>
-
-
-
-</Table></Center>
-
-<!--- html Footer --->
-
-<Center>
-<Font size=-1>
-<br>
-<br>
-<TABLE BORDER="1" WIDTH="100%">
-    <Tr>
-		<!--- Hosted by Sourceforge --->
-        <Td Align="Center">
-			<Font size=-1>
-			<b>TANGO</b> is an open source project hosted by :<br>
-			<A href="http://sourceforge.net" Target="new">
-					<IMG title="Sourceforge logo"
-						alt="Sourceforge logo small"
-						src="http://www.esrf.fr/computing/cs/tango/sourceforge.gif"
-						border=0> </a>
-			</Font>
-		</Td>
-		<!--- 2 Sourceforge Repositories --->
-		<Td Align="Center">
-			<Font size=-1>
-			Core and Tools :
-			<a href="http://tango-cs.cvs.sourceforge.net/tango-cs/" Target="new">
-			CVS repository</a> on
-			<a href="https://sourceforge.net/projects/tango-cs" Target=new>
-			tango-cs project</a>
-
-			<br>
-
-			Device Servers :
-			<a href="http://tango-ds.cvs.sourceforge.net/tango-ds/" Target="new">
-					CVS repository</a> on
-			<a href="https://sourceforge.net/projects/tango-ds" Target=new>
-					tango-ds project</a>
-			</Font>
-		</Td>
-    </Tr>
-</Table>
-</Font>
-</Center>
 </body>
-</html>
+
+</html>
\ No newline at end of file
diff --git a/doc/doc_html/Properties.html b/doc/doc_html/Properties.html
index 3f676a0..388a562 100755
--- a/doc/doc_html/Properties.html
+++ b/doc/doc_html/Properties.html
@@ -1,144 +1,94 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
 <HTML>
+
 <HEAD>
-<Title> Tango Device Server User's Guide </Title>
+    <Title> Tango Device Server User's Guide </Title>
 </HEAD>
-<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#0000FF" VLINK="#7F00FF" ALINK="#FF0000">
-
-<P><!-------TITLE------></P>
-
-<TABLE BORDER="0" WIDTH="100%">
-    <TR>
-        <TD ALIGN="left">
-			<A HREF="http://www.esrf.fr/" TARGET=new>
-			<IMG SRC="http://www.esrf.fr/gifs/logo/80.gif" BORDER=0 Height="60"></A>
-		</Td>
-        <TD ALIGN="center">
-			<A HREF="http://www.elettra.trieste.it/" TARGET=new>
-			<IMG SRC="http://www.esrf.fr/computing/cs/tango/elettra_logo.gif" BORDER=0 Height="60"></A>
-
-		</Td>
-        <TD ALIGN="center">
-			<A HREF="http://www.synchrotron-soleil.fr/" TARGET=new>
-			<IMG SRC="http://www.esrf.fr/computing/cs/tango/soleil_logo.gif" BORDER=0 Height="60"></A>
-		</Td>
-        <TD ALIGN="right">
-			<A HREF="http://www.cells.es/" TARGET=new>
-			<IMG SRC="http://www.esrf.fr/computing/cs/tango/alba.jpg" BORDER=0 Height="54"></A>
-		</Td>
-        <TD ALIGN="right">
-			<A HREF="http://www.desy.de/html/home/index_eng.html" TARGET=new>
-			<IMG SRC="http://www.esrf.fr/computing/cs/tango/desy.gif" BORDER=0 Height="60"></A>
-		</Td>
-    	 <Td>
-			<H2><FONT COLOR="#7F00FF">
-			<Center><A HREF="http://www.tango-controls.org/" TARGET="_top">
-					 TANGO </a> <Br> Device Server
-			</Center></FONT>
-		</Td>
-    </TR>
-</TABLE>
-
-<HR WIDTH="100%"></H5>
-<Br>
-<center>
-<h1>
-SingleShotAO Generic Device		<Br>
-Properties Description 		<Br> <Br>
-SingleShotAO Class	<Br>
-</h1>
-<b>
-Revision:  - Author: buteau
-</b>
-</center>
-
-
-<Center>
-<Br> <Br> <Br> 
-<Table Border=2 Cellpadding=3 CELLSPACING=0 WIDTH="100%">
-<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
-<Td COLSPAN=3> <Font Size=+2><Center><b>Device Properties</b></td></Font></Center>
-<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
-<Td><Center><b>Property name</b></td></Center>
-<Td><Center><b>Property type</b></td></Center>
-<Td><Center><b>Description</b></td></Center>
-<Tr><Td><b><a href=#Dev_DefaultValues>BoardNum </a></b></Td>
-<Td><Font Size=-1>Tango::DEV_SHORT</Font></Td>
-<Td><Font Size=-1>The the board identifier in the cPCI crate [valid range is 0...7 - no default value] .</Font></Td></Tr>
 
-<Tr><Td><b><a href=#Dev_DefaultValues>BoardType </a></b></Td>
-<Td><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></Td></Tr>
+<BODY>
+    <center>
+        <h1>
+            SingleShotAO Generic Device <Br>
+            Properties Description <Br><Br>
+            SingleShotAO Class <Br>
+        </h1>
+        <b>
+            Revision: - Author: buteau
+        </b>
+    </center>
 
-</Table>
 
-</Center>
-<Br><Br><Br>
-<Br><Br><Br>
-
-<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">
-        <Td><b>Property Name</b></td>
-        <td><b>Default Values</b></td>
-    </Tr>
+    <Center>
+        <Table Border=2 Cellpadding=3 CELLSPACING=0 WIDTH="100%">
+            <TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+                <Td COLSPAN=3>
+                    <Font Size=+2>
+                        <Center><b>Device Properties</b>
+                </td>
+                </Font>
+    </Center>
+    <TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+        <Td>
+            <Center><b>Property name</b>
+        </td>
+        </Center>
+        <Td>
+            <Center><b>Property type</b>
+        </td>
+        </Center>
+        <Td>
+            <Center><b>Description</b>
+        </td>
+        </Center>
     <Tr>
-        <Td>BoardNum</Td>
-        <td>No default value</td>
+        <Td><b><a href=#Dev_DefaultValues>BoardNum </a></b></Td>
+        <Td>
+            <Font Size=-1>Tango::DEV_SHORT</Font>
+        </Td>
+        <Td>
+            <Font Size=-1>The the board identifier in the cPCI crate [valid range is 0...7 - no default value] .</Font>
+        </Td>
     </Tr>
+
     <Tr>
-        <Td>BoardType</Td>
-        <td>No default value</td>
+        <Td><b><a href=#Dev_DefaultValues>BoardType </a></b></Td>
+        <Td>
+            <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>
+        </Td>
     </Tr>
-</Table>
 
-<Br><Br><Br>
-<Center><b>
-There is no Class properties.<Br><Br>
-</Center></b>
-<Br> <Br> <Br> 
+    </Table>
 
-<!--- html Footer --->
+    </Center>
 
-<Center>
-<Font size=-1>
-<br>
-<br>
-<TABLE BORDER="1" WIDTH="100%">
-    <Tr>
-		<!--- Hosted by Sourceforge --->
-        <Td Align="Center">
-			<Font size=-1>
-			<b>TANGO</b> is an open source project hosted by :<br>
-			<A href="http://sourceforge.net" Target="new">
-					<IMG title="Sourceforge logo"
-						alt="Sourceforge logo small"
-						src="http://www.esrf.fr/computing/cs/tango/sourceforge.gif"
-						border=0> </a>
-			</Font>
-		</Td>
-		<!--- 2 Sourceforge Repositories --->
-		<Td Align="Center">
-			<Font size=-1>
-			Core and Tools :
-			<a href="http://tango-cs.cvs.sourceforge.net/tango-cs/" Target="new">
-			CVS repository</a> on
-			<a href="https://sourceforge.net/projects/tango-cs" Target=new>
-			tango-cs project</a>
+    <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">
+            <Td><b>Property Name</b></td>
+            <td><b>Default Values</b></td>
+        </Tr>
+        <Tr>
+            <Td>BoardNum</Td>
+            <td>No default value</td>
+        </Tr>
+        <Tr>
+            <Td>BoardType</Td>
+            <td>No default value</td>
+        </Tr>
+    </Table>
+
+    <Br><Br><Br>
+    <Center><b>
+            There is no Class properties.<Br><Br>
+    </Center></b>
+    <Br> <Br> <Br>
 
-			<br>
 
-			Device Servers :
-			<a href="http://tango-ds.cvs.sourceforge.net/tango-ds/" Target="new">
-					CVS repository</a> on
-			<a href="https://sourceforge.net/projects/tango-ds" Target=new>
-					tango-ds project</a>
-			</Font>
-		</Td>
-    </Tr>
-</Table>
-</Font>
-</Center>
 </body>
-</html>
+
+</html>
\ No newline at end of file
diff --git a/doc/doc_html/TangoDevStates.html b/doc/doc_html/TangoDevStates.html
index 7d7aef3..57cc435 100755
--- a/doc/doc_html/TangoDevStates.html
+++ b/doc/doc_html/TangoDevStates.html
@@ -1,124 +1,59 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<HTML>
-<HEAD>
-<Title> Tango Device Server User's Guide </Title>
-</HEAD>
-<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#0000FF" VLINK="#7F00FF" ALINK="#FF0000">
+<html>
+
+<head>
+    <title> Tango Device Server User's Guide </title>
+</head>
+
+<body>
+    <center>
+        <h1>
+            SingleShotAO Generic Device <br>
+            Device States Description <br> <br>
+            SingleShotAO Class <br>
+        </h1>
+        <b>
+            Revision: - Author: buteau
+        </b>
+    </center>
+
+    <center>
+        <table Border=2 Cellpadding=3 CELLSPACING=0 WIDTH="100%">
+            <tr BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+                <td COLSPAN=2>
+                    <font Size=+2><center>
+                        <b>States</b>
+                    </center></font>
+                </td>
+            </tr>
+
+            <tr BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+                <td><center><b>Names</b></center></td>
+                <td><center><b>Descriptions</b></center></td>
+            </tr>
+
+            <tr>
+                <td><b>FAULT</b></td>
+                <td><font Size=-1>Hardware / driver failure or fatal error occurred</font></td>
+            </tr>
+
+            <tr>
+                <td><b>ON</b></td>
+                <td><font Size=-1>Device ready to execute AO request</font></td>
+            </tr>
+
+            <tr>
+                <td><b>INIT</b></td>
+                <td><font Size=-1>Device initialization in progress</font></td>
+            </tr>
+
+            <tr>
+                <td><b>MOVING</b></td>
+                <td><font Size=-1>Ramp generation in progress</font></td>
+            </tr>
+        </table>
+    </center>
 
-<P><!-------TITLE------></P>
-
-<TABLE BORDER="0" WIDTH="100%">
-    <TR>
-        <TD ALIGN="left">
-			<A HREF="http://www.esrf.fr/" TARGET=new>
-			<IMG SRC="http://www.esrf.fr/gifs/logo/80.gif" BORDER=0 Height="60"></A>
-		</Td>
-        <TD ALIGN="center">
-			<A HREF="http://www.elettra.trieste.it/" TARGET=new>
-			<IMG SRC="http://www.esrf.fr/computing/cs/tango/elettra_logo.gif" BORDER=0 Height="60"></A>
-
-		</Td>
-        <TD ALIGN="center">
-			<A HREF="http://www.synchrotron-soleil.fr/" TARGET=new>
-			<IMG SRC="http://www.esrf.fr/computing/cs/tango/soleil_logo.gif" BORDER=0 Height="60"></A>
-		</Td>
-        <TD ALIGN="right">
-			<A HREF="http://www.cells.es/" TARGET=new>
-			<IMG SRC="http://www.esrf.fr/computing/cs/tango/alba.jpg" BORDER=0 Height="54"></A>
-		</Td>
-        <TD ALIGN="right">
-			<A HREF="http://www.desy.de/html/home/index_eng.html" TARGET=new>
-			<IMG SRC="http://www.esrf.fr/computing/cs/tango/desy.gif" BORDER=0 Height="60"></A>
-		</Td>
-    	 <Td>
-			<H2><FONT COLOR="#7F00FF">
-			<Center><A HREF="http://www.tango-controls.org/" TARGET="_top">
-					 TANGO </a> <Br> Device Server
-			</Center></FONT>
-		</Td>
-    </TR>
-</TABLE>
-
-<HR WIDTH="100%"></H5>
-<Br>
-<center>
-<h1>
-SingleShotAO Generic Device		<Br>
-Device States Description 		<Br> <Br>
-SingleShotAO Class	<Br>
-</h1>
-<b>
-Revision:  - Author: buteau
-</b>
-</center>
-
-
-<Center>
-<Br> <Br> <Br> 
-<Table Border=2 Cellpadding=3 CELLSPACING=0 WIDTH="100%">
-<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
-<Td COLSPAN=2> <Font Size=+2><Center><b>States</b></td></Font></Center>
-<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
-<Td><Center><b>Names</b></td></Center>
-<Td><Center><b>Descriptions</b></td></Center>
-<Tr><Td><b>FAULT</b></Td>
-<Td><Font Size=-1>Hardware / driver failure or fatal error occurred</Font></Td></Tr>
-
-<Tr><Td><b>ON</b></Td>
-<Td><Font Size=-1>Device ready to execute AO request</Font></Td></Tr>
-
-<Tr><Td><b>INIT</b></Td>
-<Td><Font Size=-1>Device initialization in progress</Font></Td></Tr>
-
-<Tr><Td><b>MOVING</b></Td>
-<Td><Font Size=-1>Ramp generation in progress</Font></Td></Tr>
-
-
-
-
-</Table>
-</Center>
-
-<!--- html Footer --->
-
-<Center>
-<Font size=-1>
-<br>
-<br>
-<TABLE BORDER="1" WIDTH="100%">
-    <Tr>
-		<!--- Hosted by Sourceforge --->
-        <Td Align="Center">
-			<Font size=-1>
-			<b>TANGO</b> is an open source project hosted by :<br>
-			<A href="http://sourceforge.net" Target="new">
-					<IMG title="Sourceforge logo"
-						alt="Sourceforge logo small"
-						src="http://www.esrf.fr/computing/cs/tango/sourceforge.gif"
-						border=0> </a>
-			</Font>
-		</Td>
-		<!--- 2 Sourceforge Repositories --->
-		<Td Align="Center">
-			<Font size=-1>
-			Core and Tools :
-			<a href="http://tango-cs.cvs.sourceforge.net/tango-cs/" Target="new">
-			CVS repository</a> on
-			<a href="https://sourceforge.net/projects/tango-cs" Target=new>
-			tango-cs project</a>
-
-			<br>
-
-			Device Servers :
-			<a href="http://tango-ds.cvs.sourceforge.net/tango-ds/" Target="new">
-					CVS repository</a> on
-			<a href="https://sourceforge.net/projects/tango-ds" Target=new>
-					tango-ds project</a>
-			</Font>
-		</Td>
-    </Tr>
-</Table>
-</Font>
-</Center>
 </body>
-</html>
+
+</html>
\ No newline at end of file
diff --git a/doc/doc_html/index.html b/doc/doc_html/index.html
index abd508c..43e3bc5 100755
--- a/doc/doc_html/index.html
+++ b/doc/doc_html/index.html
@@ -1,142 +1,60 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<HTML>
-<HEAD>
-<Title> Tango Device Server User's Guide </Title>
-</HEAD>
-<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#0000FF" VLINK="#7F00FF" ALINK="#FF0000">
-
-<P><!-------TITLE------></P>
-<TABLE BORDER="0" WIDTH="100%">
-    <TR>
-        <TD ALIGN="left">
-			<A HREF="http://www.esrf.fr/" TARGET=new>
-			<IMG SRC="http://www.esrf.fr/gifs/logo/80.gif" BORDER=0 Height="60"></A>
-		</Td>
-        <TD ALIGN="center">
-			<A HREF="http://www.elettra.trieste.it/" TARGET=new>
-			<IMG SRC="http://www.esrf.fr/computing/cs/tango/elettra_logo.gif" BORDER=0 Height="60"></A>
-
-		</Td>
-        <TD ALIGN="center">
-			<A HREF="http://www.synchrotron-soleil.fr/" TARGET=new>
-			<IMG SRC="http://www.esrf.fr/computing/cs/tango/soleil_logo.gif" BORDER=0 Height="60"></A>
-		</Td>
-        <TD ALIGN="right">
-			<A HREF="http://www.cells.es/" TARGET=new>
-			<IMG SRC="http://www.esrf.fr/computing/cs/tango/alba.jpg" BORDER=0 Height="54"></A>
-		</Td>
-        <TD ALIGN="right">
-			<A HREF="http://www.desy.de/html/home/index_eng.html" TARGET=new>
-			<IMG SRC="http://www.esrf.fr/computing/cs/tango/desy.gif" BORDER=0 Height="60"></A>
-		</Td>
-    	 <Td>
-			<H2><FONT COLOR="#7F00FF">
-			<Center><A HREF="http://www.tango-controls.org/" TARGET="_top">
-					 TANGO </a> <Br> Device Server
-			</Center></FONT>
-		</Td>
-    </TR>
-</TABLE>
+<html>
+
+<head>
+	<title> Tango Device Server User's Guide </title>
+</head>
+	
+<body>
+	<center>
+		<h1>
+			SingleShotAO Generic Device <br>
+			User's Guide <br><Br>
+			SingleShotAO Class <br>
+		</h1>
+		<b>
+			Revision: - Author: buteau <br>
+			Implemented in C++
+		</b>
+	</center>
+
+	<h2>Introduction:</h2>
+	<ul>
+		<li>ADLink boards support for single shot AO operations [PCI-6208 and compatible boards]</li>
+	</ul>
 
-<HR WIDTH="100%"></H5>
-<center>
-<h1>
-SingleShotAO Generic Device <Br>
-User's Guide <Br><Br>
-SingleShotAO Class<Br>
+	<h2>Class Identification:</h2>
+	<ul>
+		<li><b>Contact :</b> at synchrotron-soleil.fr - buteau</li>
+		<li><b>Class Family :</b> InputOutput</li>
+		<li><b>Platform :</b> All Platforms</li>
+		<li><b>Bus :</b> Compact PCI</li>
+	</ul>
 
-</h1>
-<b>
-Revision:  - Author: buteau <Br>
- Implemented in C++
-</b>
-</center>
-<Br>
-<Br>
-<Br>
-<Br>
-<h2>Introduction:</h2>
-<ul>
-	ADLink boards support for single shot AO operations [PCI-6208 and compatible boards]<Br>
-</ul>
-<Br><h2>Class Identification:</h2>
-<ul>
-	<li><b>Contact      :</b>	 at synchrotron-soleil.fr - buteau
-	<li><b>Class Family :</b>	InputOutput
-	<li><b>Platform     :</b>	All Platforms
-	<li><b>Bus          :</b>	Compact PCI
-</ul><Br>
-<h2>Class Inheritance:</h2>
+	<h2>Class Inheritance:</h2>
 	<ul>
-		<li> <a href="http://www.esrf.fr/computing/cs/tango/tango_doc/kernel_doc/cpp_doc/"> TANGO_BASE_CLASS</a></li>
+		<li> <a
+				href="http://www.esrf.fr/computing/cs/tango/tango_doc/kernel_doc/cpp_doc/">
+				TANGO_BASE_CLASS</a></li>
 		<ul>
 			<li> SingleShotAO</li>
-			</ul>
 		</ul>
 	</ul>
-</ul>
-<Br>
-<Br>
-<h2>Class Description:</h2>
-<ul>
-	<li> <a href=Description.html>      Device description.</a>
-	<li> <a href=Properties.html>       Properties description</a>
-	<li> <a href=TangoDevStates.html>   States description</a>
-	<li> <a href=DevCommandsTable.html> Commands description</a>
-	<li> <a href=Attributes.html>       Attributes description</a>
-</ul>
-<Br>
-<Br>
-<Br>
-<h2>Conclusion:</h2>
-<ul>
-	The device server is ready for distribution application programmers.<Br>
-	The author will be interested in any feedback which arise from their
-	usage of this device server.
-</ul>
-<Br>
-
 
-<!--- html Footer --->
-
-<Center>
-<Font size=-1>
-<br>
-<br>
-<TABLE BORDER="1" WIDTH="100%">
-    <Tr>
-		<!--- Hosted by Sourceforge --->
-        <Td Align="Center">
-			<Font size=-1>
-			<b>TANGO</b> is an open source project hosted by :<br>
-			<A href="http://sourceforge.net" Target="new">
-					<IMG title="Sourceforge logo"
-						alt="Sourceforge logo small"
-						src="http://www.esrf.fr/computing/cs/tango/sourceforge.gif"
-						border=0> </a>
-			</Font>
-		</Td>
-		<!--- 2 Sourceforge Repositories --->
-		<Td Align="Center">
-			<Font size=-1>
-			Core and Tools :
-			<a href="http://tango-cs.cvs.sourceforge.net/tango-cs/" Target="new">
-			CVS repository</a> on
-			<a href="https://sourceforge.net/projects/tango-cs" Target=new>
-			tango-cs project</a>
-
-			<br>
+	<h2>Class Description:</h2>
+	<ul>
+		<li> <a href=Description.html> Device description.</a> </li>
+		<li> <a href=Properties.html> Properties description</a> </li>
+		<li> <a href=TangoDevStates.html> States description</a> </li>
+		<li> <a href=DevCommandsTable.html> Commands description</a> </li>
+		<li> <a href=Attributes.html> Attributes description</a> </li>
+	</ul>
+	
+	<h2>Conclusion:</h2>
+	<ul>
+		<li>The device server is ready for distribution application programmers.</li>
+		<li>The author will be interested in any feedback which arise from their usage of this device server.</li>
+	</ul>
 
-			Device Servers :
-			<a href="http://tango-ds.cvs.sourceforge.net/tango-ds/" Target="new">
-					CVS repository</a> on
-			<a href="https://sourceforge.net/projects/tango-ds" Target=new>
-					tango-ds project</a>
-			</Font>
-		</Td>
-    </Tr>
-</Table>
-</Font>
-</Center>
 </body>
 </html>
-- 
GitLab


From 854209fd040c83f0f911d4a68979b89fc65d6b8e Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Fri, 21 Feb 2025 13:53:27 +0100
Subject: [PATCH 08/34] chore(doc): add dynamic attributes to HTML
 documentation

---
 doc/doc_html/Attributes.html | 87 ++++++++++++++++++++++++++++++++----
 1 file changed, 79 insertions(+), 8 deletions(-)

diff --git a/doc/doc_html/Attributes.html b/doc/doc_html/Attributes.html
index 9a6dff5..63ac70c 100755
--- a/doc/doc_html/Attributes.html
+++ b/doc/doc_html/Attributes.html
@@ -25,21 +25,18 @@
 		</tr>
 		<tr BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
 			<td>
-				<center><b>Attribute name</b>
+				<center><b>Attribute name</b></center>
 			</td>
-			</center>
 			<td>
-				<center><b>Data Type</b>
+				<center><b>Data Type</b></center>
 			</td>
-			</center>
 			<td>
-				<center><b>R/W Type</b>
+				<center><b>R/W Type</b></center>
 			</td>
-			</center>
 			<td>
-				<center><b>Expert</b>
+				<center><b>Expert</b></center>
 			</td>
-			</center>
+		</tr>
 		<tr>
 			<td><b>frequency</b>: <font Size=-1>Sampling frequency for
 					ramp generation on the board output channels, in
@@ -61,7 +58,81 @@
 				</center>
 			</td>
 		</tr>
+	</table>
 
+	<br>
+
+	<table Border=2 Cellpadding=3 CELLSPACING=0 WIDTH="100%">
+		<tr BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+			<td COLSPAN=4>
+				<center>
+					<font Size=+2><b>Dynamic Scalar Attributes</b></font><br>
+					X is the channel number ranging from 0 to N-1 (<b>MAO_6208</b>: 8 channels, <b>MAO_6216</b>: 10 channels)
+				</center>
+			</td>
+		</tr>
+		<tr BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+			<td>
+				<center><b>Attribute name</b></center>
+			</td>
+			<td>
+				<center><b>Data Type</b></center>
+			</td>
+			<td>
+				<center><b>R/W Type</b></center>
+			</td>
+			<td>
+				<center><b>Description</b></center>
+			</td>
+		</tr>
+		<tr>
+			<td><b>channelX</b></td>
+			<td>
+				<center>
+					<font Size=-1>DEV_DOUBLE</font>
+				</center>
+			</td>
+			<td>
+				<center>
+					<font Size=-1>READ_WRITE</font>
+				</center>
+			</td>
+			<td>
+				<font Size=-1>Output value for channel X (in V). Valid range: [-10V, +10V]</font>
+			</td>
+		</tr>
+		<tr>
+			<td><b>speedX</b></td>
+			<td>
+				<center>
+					<font Size=-1>DEV_DOUBLE</font>
+				</center>
+			</td>
+			<td>
+				<center>
+					<font Size=-1>READ_WRITE</font>
+				</center>
+			</td>
+			<td>
+				<font Size=-1>Speed for ramp generation on channel X (in V/s). If speed is 0, no ramp is generated but direct write on channel output.</font>
+			</td>
+		</tr>
+		<tr>
+			<td><b>initialX</b></td>
+			<td>
+				<center>
+					<font Size=-1>DEV_DOUBLE</font>
+				</center>
+			</td>
+			<td>
+				<center>
+					<font Size=-1>READ_WRITE</font>
+				</center>
+			</td>
+			<td>
+				<font Size=-1>Initial value for ramp function on channel X (in V). Defaults to last written value in channel attribute.</font>
+			</td>
+		</tr>
 	</table>
 </center>
 
-- 
GitLab


From 4a82daf289fa54ec4f6c4b8205e9d0799f8fa96e Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Fri, 21 Feb 2025 13:57:58 +0100
Subject: [PATCH 09/34] feature/fix: memorize channel values on abort and abort
 on init

---
 src/SingleShotAO.cpp        | 50 ++++++++++++++++++++++++++++++++++---
 src/SingleShotAO.h          |  3 +++
 src/SingleShotAOManager.cpp |  8 ++++++
 src/SingleShotAOManager.h   |  3 +++
 4 files changed, 60 insertions(+), 4 deletions(-)

diff --git a/src/SingleShotAO.cpp b/src/SingleShotAO.cpp
index 8b886ad..cc7f5b6 100755
--- a/src/SingleShotAO.cpp
+++ b/src/SingleShotAO.cpp
@@ -348,6 +348,28 @@ void SingleShotAO::init_device()
 	}
 
 
+	// Make sure running processes are aborted properly
+	//--------------------------------------------
+	try
+	{
+		_abort();
+	}
+	catch (Tango::DevFailed &df)
+	{
+		ERROR_STREAM << df << endl;
+		RETHROW_DEVFAILED(df,
+						  "DRIVER_FAILURE",
+						  "could not abort [caught Tango::DevFailed]",
+						  "SingleShotAO::init");
+	}
+	catch (...)
+	{
+		ERROR_STREAM << "SingleShotAO::init::unknown exception caught" << std::endl;
+		THROW_DEVFAILED("DRIVER_FAILURE",
+						"could not abort [unknown error]",
+						"SingleShotAO::init");
+	}
+
 	// Create dynamic attributes
 	//--------------------------------------------
 
@@ -990,11 +1012,9 @@ void SingleShotAO::write_initial(yat4tango::DynamicAttributeWriteCallbackData &
 void SingleShotAO::abort()
 {
 	DEBUG_STREAM << "SingleShotAO::abort(): entering... !" << endl;
-
-	CHECK_MANAGER();
 	try
 	{
-		m_manager->abort();
+		_abort();
 	}
 	catch(Tango::DevFailed& df)
 	{
@@ -1006,11 +1026,33 @@ void SingleShotAO::abort()
 	}
 	catch(...)
 	{
-		ERROR_STREAM << "SingleShotAOManager::abort::unknown exception caught"<<std::endl;
+		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);
+			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;
+
+			double l_val_initial = m_manager->get_initial(l_cpt);
+			yat4tango::PropertyHelper::set_memorized_attribute(this, kINITIAL + std::to_string(l_cpt), l_val_initial);
+			DEBUG_STREAM << "Memorizing initial " << l_cpt << " to " << l_val_initial << std::endl;
+		}
+	}
+	m_manager->abort();
+}
+
 }	//	namespace
diff --git a/src/SingleShotAO.h b/src/SingleShotAO.h
index d6d477f..8e259d0 100755
--- a/src/SingleShotAO.h
+++ b/src/SingleShotAO.h
@@ -279,6 +279,9 @@ protected :
 	//- channel number
 	unsigned short m_nb_chan;
 
+	
+	void	_abort();
+
 };
 
 }	// namespace_ns
diff --git a/src/SingleShotAOManager.cpp b/src/SingleShotAOManager.cpp
index 5d7b57a..e0519ec 100755
--- a/src/SingleShotAOManager.cpp
+++ b/src/SingleShotAOManager.cpp
@@ -440,6 +440,14 @@ void SingleShotAOManager::set_speed(ChannelId_t p_chIdx, Intial_t p_speed)
 	}
 }
 
+// ============================================================================
+// SingleShotAOManager::is_running ()
+// ============================================================================
+bool SingleShotAOManager::is_running(ChannelId_t p_chIdx)
+{
+	return m_isRunning[p_chIdx];
+}
+
 // ============================================================================
 // SingleShotAOManager::abort ()
 // ============================================================================
diff --git a/src/SingleShotAOManager.h b/src/SingleShotAOManager.h
index ccabfce..a021036 100755
--- a/src/SingleShotAOManager.h
+++ b/src/SingleShotAOManager.h
@@ -74,6 +74,9 @@ public:
   //- set speed
   void set_speed(ChannelId_t p_chIdx, Intial_t p_speed);
 
+  //- is running
+  bool is_running(ChannelId_t p_chIdx);
+
   //- abort
   void abort();
 
-- 
GitLab


From a9fd52415c2455043f4e7da54a5a8b0e3d5f221e Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Fri, 21 Feb 2025 14:34:48 +0100
Subject: [PATCH 10/34] fix: abort in delete_device (and inherently in init and
 exit)

---
 src/SingleShotAO.cpp | 70 ++++++++++++++++++++++++--------------------
 1 file changed, 39 insertions(+), 31 deletions(-)

diff --git a/src/SingleShotAO.cpp b/src/SingleShotAO.cpp
index cc7f5b6..699767f 100755
--- a/src/SingleShotAO.cpp
+++ b/src/SingleShotAO.cpp
@@ -129,7 +129,32 @@ SingleShotAO::SingleShotAO(Tango::DeviceClass *cl,const char *s,const char *d)
 //-----------------------------------------------------------------------------
 void SingleShotAO::delete_device()
 {
-	//	Delete device allocated objects
+	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)
@@ -138,14 +163,16 @@ void SingleShotAO::delete_device()
 		m_manager = NULL;
 	}
 
-	//- release the asl::SingleShotAO object
+	// Release the asl::SingleShotAO object
+	//--------------------------------------------
 	if (m_ssao) 
 	{
 		delete m_ssao;
 		m_ssao = NULL;
 	}
 
-	// remove dynamic attributes 
+	// Remove dynamic attributes
+	//--------------------------------------------
 	if (m_dyn_attr_manager)
 	{
 		try
@@ -165,7 +192,8 @@ void SingleShotAO::delete_device()
 		m_dyn_attr_manager = NULL;
 	}
 
-	//- remove the inner appender
+	// Remove the inner appender
+	//--------------------------------------------
 	yat4tango::Logging::release(this);
 	yat4tango::DeviceInfo::release(this);
 }
@@ -315,17 +343,20 @@ void SingleShotAO::init_device()
 		return;
 	}
 
+
 	// get frequency value in database
+	//--------------------------------------------
 	try
 	{
-		m_frequency = yat4tango::PropertyHelper::get_memorized_attribute<double>(this,"frequency");
+		m_frequency = yat4tango::PropertyHelper::get_memorized_attribute<double>(this, "frequency");
 		DEBUG_STREAM << "Frequency : " << m_frequency << endl;
 	}
 	catch (...)
 	{
 		DEBUG_STREAM << "Failed to get frequency value. Maybe there is no value yet." << std::endl;
 	}
-	
+
+
 	// initialize the AO manager
 	//--------------------------------------------
 	try
@@ -348,28 +379,6 @@ void SingleShotAO::init_device()
 	}
 
 
-	// Make sure running processes are aborted properly
-	//--------------------------------------------
-	try
-	{
-		_abort();
-	}
-	catch (Tango::DevFailed &df)
-	{
-		ERROR_STREAM << df << endl;
-		RETHROW_DEVFAILED(df,
-						  "DRIVER_FAILURE",
-						  "could not abort [caught Tango::DevFailed]",
-						  "SingleShotAO::init");
-	}
-	catch (...)
-	{
-		ERROR_STREAM << "SingleShotAO::init::unknown exception caught" << std::endl;
-		THROW_DEVFAILED("DRIVER_FAILURE",
-						"could not abort [unknown error]",
-						"SingleShotAO::init");
-	}
-
 	// Create dynamic attributes
 	//--------------------------------------------
 
@@ -1047,9 +1056,8 @@ void SingleShotAO::_abort()
 			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;
 
-			double l_val_initial = m_manager->get_initial(l_cpt);
-			yat4tango::PropertyHelper::set_memorized_attribute(this, kINITIAL + std::to_string(l_cpt), l_val_initial);
-			DEBUG_STREAM << "Memorizing initial " << l_cpt << " to " << l_val_initial << 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;
 		}
 	}
 	m_manager->abort();
-- 
GitLab


From 4fe5634255053686359f6da63ceddf23db5951fd Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Fri, 21 Feb 2025 14:48:05 +0100
Subject: [PATCH 11/34] bump: update version to 2.1.0

---
 conanfile.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/conanfile.py b/conanfile.py
index 479a146..24ed606 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.0.4"
+    version = "2.1.0"
     package_type = "application"
     user = "soleil"
     python_requires = "base/[>=1.0]@soleil/stable"
-- 
GitLab


From 3d756be15fa57fa37dc46c56a26138a47743e2ea Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Fri, 21 Feb 2025 16:35:50 +0100
Subject: [PATCH 12/34] fix: update format precision for channelX and speedX
 attributes to match initialX attributes

---
 src/SingleShotAO.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/SingleShotAO.cpp b/src/SingleShotAO.cpp
index 699767f..ee7b789 100755
--- a/src/SingleShotAO.cpp
+++ b/src/SingleShotAO.cpp
@@ -429,7 +429,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.tai.format = "%1.2f";
 		dai_channel.memorized = true;
 		dai_channel.cdb = false;
 
@@ -461,7 +461,7 @@ 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 = "%1.2f";
 
 		//- cleanup tango db option: cleanup tango db when removing this dyn. attr. (i.e. erase its properties from db)
 		dai_speed.memorized = true;
-- 
GitLab


From 915889e15d7f6e1d89442db101d42456127f3040 Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Fri, 21 Feb 2025 16:40:59 +0100
Subject: [PATCH 13/34] fix: rename get_device_properties back to
 get_device_property for consistency (+ add comments)

---
 src/SingleShotAO.cpp | 45 +++++++++++++++++++++-----------------------
 src/SingleShotAO.h   |  2 +-
 2 files changed, 22 insertions(+), 25 deletions(-)

diff --git a/src/SingleShotAO.cpp b/src/SingleShotAO.cpp
index ee7b789..96a72ba 100755
--- a/src/SingleShotAO.cpp
+++ b/src/SingleShotAO.cpp
@@ -247,7 +247,7 @@ void SingleShotAO::init_device()
 	//--------------------------------------------
 	try 
 	{
-		get_device_properties();
+		get_device_property();
 	}
 	catch (const Tango::DevFailed& df)
 	{
@@ -570,57 +570,52 @@ 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"));
 
-	//	Call database and extract values
+	// Call database and extract values
 	//--------------------------------------------
-	if (Tango::Util::instance()->_UseDb==true)
+	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
+	// 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;
 
-	//	Try to initialize BoardType from class property
+	// 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;
 
-
-
-	//	End of Automatic code generation
-	//------------------------------------------------------------------
+	// Check critical properties being present
+	//--------------------------------------------
 
 	critical_properties_missing = false;
 
@@ -639,8 +634,11 @@ void SingleShotAO::get_device_properties()
 		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;
@@ -665,7 +663,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;
 	}
-
 }
 
 
diff --git a/src/SingleShotAO.h b/src/SingleShotAO.h
index 8e259d0..7faa182 100755
--- a/src/SingleShotAO.h
+++ b/src/SingleShotAO.h
@@ -219,7 +219,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
-- 
GitLab


From 1085d8888f3e1935e49ac54ab85630cf9c67c76f Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Fri, 21 Feb 2025 16:58:02 +0100
Subject: [PATCH 14/34] feat: add EnableRamps and WriteMemorizedValuesAtInit
 properties with default values (do nothing so far)

---
 doc/doc_html/Properties.html |  34 ++++++++-
 src/SingleShotAO.cpp         |  31 ++++++++
 src/SingleShotAO.h           |   8 ++
 src/SingleShotAOClass.cpp    | 144 ++++++++++-------------------------
 4 files changed, 109 insertions(+), 108 deletions(-)

diff --git a/doc/doc_html/Properties.html b/doc/doc_html/Properties.html
index 388a562..b0ca154 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>WriteMemorizedValuesAtInit </a></b></Td>
+        <Td>
+            <Font Size=-1>Tango::DEV_BOOLEAN</Font>
+        </Td>
+        <Td>
+            <Font Size=-1>Whether to write the memorized values to the board at the device initialization. [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>WriteMemorizedValuesAtInit</Td>
+            <td>false</td>
+        </Tr>
     </Table>
 
     <Br><Br><Br>
diff --git a/src/SingleShotAO.cpp b/src/SingleShotAO.cpp
index 96a72ba..56cb44d 100755
--- a/src/SingleShotAO.cpp
+++ b/src/SingleShotAO.cpp
@@ -582,6 +582,8 @@ void SingleShotAO::get_device_property()
 	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("WriteMemorizedValuesAtInit"));
 
 	// Call database and extract values
 	//--------------------------------------------
@@ -592,6 +594,7 @@ void SingleShotAO::get_device_property()
 	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;
@@ -603,6 +606,7 @@ void SingleShotAO::get_device_property()
 	// And try to extract BoardNum value from database
 	if (dev_prop[i].is_empty()==false)	dev_prop[i]  >>  boardNum;
 
+	//- <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;
@@ -614,6 +618,33 @@ void SingleShotAO::get_device_property()
 	// And try to extract BoardType value from database
 	if (dev_prop[i].is_empty()==false)	dev_prop[i]  >>  boardType;
 
+	//- <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;
+
+	//- <WriteMemorizedValuesAtInit> -----------------------
+	//	Try to initialize WriteMemorizedValuesAtInit from class property
+	cl_prop = ds_class->get_class_property(dev_prop[++i].name);
+	if (cl_prop.is_empty() == false) cl_prop >> writeMemorizedValuesAtInit;
+	else
+	{
+		//	Try to initialize WriteMemorizedValuesAtInit from default device value
+		def_prop = ds_class->get_default_device_property(dev_prop[i].name);
+		if (def_prop.is_empty() == false) def_prop >> writeMemorizedValuesAtInit;
+	}
+	//	And try to extract WriteMemorizedValuesAtInit value from database
+	if (dev_prop[i].is_empty() == false) dev_prop[i] >> writeMemorizedValuesAtInit;
+
+
 	// Check critical properties being present
 	//--------------------------------------------
 
diff --git a/src/SingleShotAO.h b/src/SingleShotAO.h
index 7faa182..f77367e 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	writeMemorizedValuesAtInit;
 //@}
 
 /**
diff --git a/src/SingleShotAOClass.cpp b/src/SingleShotAOClass.cpp
index e93187a..87816eb 100755
--- a/src/SingleShotAOClass.cpp
+++ b/src/SingleShotAOClass.cpp
@@ -369,10 +369,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 +389,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 +404,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);
+	
+	//- <WriteMemorizedValuesAt> -----------------------
+	prop_name = "WriteMemorizedValuesAtInit";
+	prop_desc = "Whether to write the memorized values to the board at the device initialization. [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 +469,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 +477,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);
 }
 
-- 
GitLab


From a1e6b1c7fff680f637fdbd2f3031cc36943c6520 Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Fri, 21 Feb 2025 17:01:31 +0100
Subject: [PATCH 15/34] feat: write memorized value at init if
 writeMemorizedValuesAtInit is true (instead of just set_channel)

---
 src/SingleShotAO.cpp | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/SingleShotAO.cpp b/src/SingleShotAO.cpp
index 56cb44d..dd92d5a 100755
--- a/src/SingleShotAO.cpp
+++ b/src/SingleShotAO.cpp
@@ -537,8 +537,10 @@ void SingleShotAO::init_device()
 		// 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 (writeMemorizedValuesAtInit)
+			applyMemorizedAttr(kCHANNEL, &SingleShotAOManager::write_channel);
+		else
+			applyMemorizedAttr(kCHANNEL, &SingleShotAOManager::set_channel);
     }
 
 	//- GO for task
-- 
GitLab


From 2fbc7f47a8820d8af04f917b601c49f85bc442ee Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Fri, 21 Feb 2025 17:26:14 +0100
Subject: [PATCH 16/34] feat: deactive ramp functionnality if enableRamps is
 false (don't create speed and initial attributes at init, and set changes
 instantly)

---
 src/SingleShotAO.cpp        | 23 ++++++++++++++++-------
 src/SingleShotAOManager.cpp | 18 ++++++++++++++++--
 src/SingleShotAOManager.h   |  7 +++++--
 3 files changed, 37 insertions(+), 11 deletions(-)

diff --git a/src/SingleShotAO.cpp b/src/SingleShotAO.cpp
index dd92d5a..5bce000 100755
--- a/src/SingleShotAO.cpp
+++ b/src/SingleShotAO.cpp
@@ -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)
 	{
@@ -443,6 +443,11 @@ 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  ║
@@ -535,12 +540,16 @@ void SingleShotAO::init_device()
 		};
 
 		// Get and set memorized values for speed, initial and channel
-		applyMemorizedAttr(kSPEED, &SingleShotAOManager::set_speed);
-		applyMemorizedAttr(kINITIAL, &SingleShotAOManager::set_initial); 
-		if (writeMemorizedValuesAtInit)
-			applyMemorizedAttr(kCHANNEL, &SingleShotAOManager::write_channel);
-		else
-			applyMemorizedAttr(kCHANNEL, &SingleShotAOManager::set_channel);
+		if (enableRamps) {
+			applyMemorizedAttr(kSPEED, &SingleShotAOManager::set_speed);
+			applyMemorizedAttr(kINITIAL, &SingleShotAOManager::set_initial); 
+		}
+
+		if (writeMemorizedValuesAtInit) {
+			applyMemorizedAttr(kCHANNEL, &SingleShotAOManager::write_channel); // write memorized value to board output
+		} else {
+			applyMemorizedAttr(kCHANNEL, &SingleShotAOManager::set_channel); // only apply memorized value to the device
+		}
     }
 
 	//- GO for task
diff --git a/src/SingleShotAOManager.cpp b/src/SingleShotAOManager.cpp
index e0519ec..0eb1333 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++)
@@ -288,7 +290,7 @@ 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)
+	if (m_speeds[p_chIdx] == 0.0 || !m_enable_ramps)
 	{
 		try 
 		{
@@ -409,6 +411,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 +442,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 a021036..5351b59 100755
--- a/src/SingleShotAOManager.h
+++ b/src/SingleShotAOManager.h
@@ -48,7 +48,7 @@ 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);
@@ -100,7 +100,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;
 
-- 
GitLab


From 9547d4baa7101eac7b0ea23562f1be24fe3ff15c Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Fri, 21 Feb 2025 17:27:51 +0100
Subject: [PATCH 17/34] bump: update version to 2.2.0

---
 conanfile.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/conanfile.py b/conanfile.py
index 24ed606..27e4801 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"
-- 
GitLab


From acaf27f501d07516df4cb72b913951affc84d7e3 Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Fri, 21 Feb 2025 17:35:14 +0100
Subject: [PATCH 18/34] feat: add logging for parsed device properties in
 get_device_property method

---
 src/SingleShotAO.cpp | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/src/SingleShotAO.cpp b/src/SingleShotAO.cpp
index 5bce000..b5ed3f3 100755
--- a/src/SingleShotAO.cpp
+++ b/src/SingleShotAO.cpp
@@ -601,6 +601,7 @@ void SingleShotAO::get_device_property()
 	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;
@@ -616,6 +617,7 @@ void SingleShotAO::get_device_property()
 	}
 	// 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
@@ -628,39 +630,37 @@ void SingleShotAO::get_device_property()
 	}
 	// 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
-	{
+	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;
 
 	//- <WriteMemorizedValuesAtInit> -----------------------
 	//	Try to initialize WriteMemorizedValuesAtInit from class property
 	cl_prop = ds_class->get_class_property(dev_prop[++i].name);
 	if (cl_prop.is_empty() == false) cl_prop >> writeMemorizedValuesAtInit;
-	else
-	{
+	else {
 		//	Try to initialize WriteMemorizedValuesAtInit from default device value
 		def_prop = ds_class->get_default_device_property(dev_prop[i].name);
 		if (def_prop.is_empty() == false) def_prop >> writeMemorizedValuesAtInit;
 	}
 	//	And try to extract WriteMemorizedValuesAtInit value from database
 	if (dev_prop[i].is_empty() == false) dev_prop[i] >> writeMemorizedValuesAtInit;
-
+	INFO_STREAM << "WriteMemorizedValuesAtInit parsed: " << (writeMemorizedValuesAtInit ? "true" : "false") << endl;
 
 	// Check critical properties being present
 	//--------------------------------------------
-
 	critical_properties_missing = false;
-
 	if (dev_prop[0].is_empty())
 	{
 		ERROR_STREAM << "Required device property <BoardNum> is missing" << endl;
@@ -671,20 +671,20 @@ void SingleShotAO::get_device_property()
 		ERROR_STREAM << "Required device property <BoardType> is missing" << endl;
 		critical_properties_missing = true;
 	}
-
 	if (critical_properties_missing) {
 		return;
 	}
 
 	// Check critical properties being valid
 	//--------------------------------------------
-
 	//- <BoardNum> -----------------------
 	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> -----------------------
@@ -692,11 +692,13 @@ void SingleShotAO::get_device_property()
 	{
 		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
 	{
-- 
GitLab


From 64fc34e7f901f62dd54aa092b5354ffdbd13aa66 Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Mon, 17 Mar 2025 18:20:47 +0100
Subject: [PATCH 19/34] feat: rename WriteMemorizedValuesAtInit to
 OutputMemorizedChannelsAtInit and update documentation

---
 doc/doc_html/Properties.html |  6 +++---
 src/SingleShotAO.cpp         | 20 ++++++++++----------
 src/SingleShotAO.h           |  2 +-
 src/SingleShotAOClass.cpp    |  6 +++---
 4 files changed, 17 insertions(+), 17 deletions(-)

diff --git a/doc/doc_html/Properties.html b/doc/doc_html/Properties.html
index b0ca154..95f05a3 100755
--- a/doc/doc_html/Properties.html
+++ b/doc/doc_html/Properties.html
@@ -72,12 +72,12 @@
     </Tr>
 
     <Tr>
-        <Td><b><a href=#Dev_DefaultValues>WriteMemorizedValuesAtInit </a></b></Td>
+        <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 write the memorized values to the board at the device initialization. [true/false - default value is false]</Font>
+            <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>
@@ -103,7 +103,7 @@
             <td>true</td>
         </Tr>
         <Tr>
-            <Td>WriteMemorizedValuesAtInit</Td>
+            <Td>OutputMemorizedChannelsAtInit</Td>
             <td>false</td>
         </Tr>
     </Table>
diff --git a/src/SingleShotAO.cpp b/src/SingleShotAO.cpp
index b5ed3f3..748d7f1 100755
--- a/src/SingleShotAO.cpp
+++ b/src/SingleShotAO.cpp
@@ -545,7 +545,7 @@ void SingleShotAO::init_device()
 			applyMemorizedAttr(kINITIAL, &SingleShotAOManager::set_initial); 
 		}
 
-		if (writeMemorizedValuesAtInit) {
+		if (outputMemorizedChannelsAtInit) {
 			applyMemorizedAttr(kCHANNEL, &SingleShotAOManager::write_channel); // write memorized value to board output
 		} else {
 			applyMemorizedAttr(kCHANNEL, &SingleShotAOManager::set_channel); // only apply memorized value to the device
@@ -594,7 +594,7 @@ void SingleShotAO::get_device_property()
 	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("WriteMemorizedValuesAtInit"));
+	dev_prop.push_back(Tango::DbDatum("OutputMemorizedChannelsAtInit"));
 
 	// Call database and extract values
 	//--------------------------------------------
@@ -645,18 +645,18 @@ void SingleShotAO::get_device_property()
 	if (dev_prop[i].is_empty() == false) dev_prop[i] >> enableRamps;
 	INFO_STREAM << "EnableRamps parsed: " << (enableRamps ? "true" : "false") << endl;
 
-	//- <WriteMemorizedValuesAtInit> -----------------------
-	//	Try to initialize WriteMemorizedValuesAtInit from class property
+	//- <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 >> writeMemorizedValuesAtInit;
+	if (cl_prop.is_empty() == false) cl_prop >> outputMemorizedChannelsAtInit;
 	else {
-		//	Try to initialize WriteMemorizedValuesAtInit from default device value
+		//	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 >> writeMemorizedValuesAtInit;
+		if (def_prop.is_empty() == false) def_prop >> outputMemorizedChannelsAtInit;
 	}
-	//	And try to extract WriteMemorizedValuesAtInit value from database
-	if (dev_prop[i].is_empty() == false) dev_prop[i] >> writeMemorizedValuesAtInit;
-	INFO_STREAM << "WriteMemorizedValuesAtInit parsed: " << (writeMemorizedValuesAtInit ? "true" : "false") << endl;
+	//	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;
 
 	// Check critical properties being present
 	//--------------------------------------------
diff --git a/src/SingleShotAO.h b/src/SingleShotAO.h
index f77367e..7cee441 100755
--- a/src/SingleShotAO.h
+++ b/src/SingleShotAO.h
@@ -117,7 +117,7 @@ public :
 /**
  *  Whether to write the memorized values to the board at the device initialization. [true/false - default value is false]
  */
-	Tango::DevBoolean	writeMemorizedValuesAtInit;
+	Tango::DevBoolean	outputMemorizedChannelsAtInit;
 //@}
 
 /**
diff --git a/src/SingleShotAOClass.cpp b/src/SingleShotAOClass.cpp
index 87816eb..29a1ef5 100755
--- a/src/SingleShotAOClass.cpp
+++ b/src/SingleShotAOClass.cpp
@@ -420,9 +420,9 @@ void SingleShotAOClass::set_default_property()
 	else
 		add_wiz_dev_prop(prop_name, prop_desc);
 	
-	//- <WriteMemorizedValuesAt> -----------------------
-	prop_name = "WriteMemorizedValuesAtInit";
-	prop_desc = "Whether to write the memorized values to the board at the device initialization. [true/false - default value is false]";
+	//- <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");
-- 
GitLab


From 2c69e3b7c591c5cc9563e950096954a8b0a35a6d Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Mon, 17 Mar 2025 18:21:51 +0100
Subject: [PATCH 20/34] feat: add ASL dependency in info attribute (hardcoded
 version because I could not find a variable for the version)

---
 src/SingleShotAO.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/SingleShotAO.cpp b/src/SingleShotAO.cpp
index 748d7f1..3257a7b 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)
 	{
-- 
GitLab


From 646f4650d6e3e4a4818b6be371dec2521b8cbfe5 Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Mon, 17 Mar 2025 18:22:45 +0100
Subject: [PATCH 21/34] feat: added logging and consolidate dynamic attribute
 management

---
 src/SingleShotAO.cpp | 66 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 65 insertions(+), 1 deletion(-)

diff --git a/src/SingleShotAO.cpp b/src/SingleShotAO.cpp
index 3257a7b..cb204a0 100755
--- a/src/SingleShotAO.cpp
+++ b/src/SingleShotAO.cpp
@@ -318,6 +318,7 @@ void SingleShotAO::init_device()
 		m_nb_chan = 16;
 	}
 
+	INFO_STREAM << "Board has " << m_nb_chan << " channels" << endl;
 
 	// construct the AO manager
 	//--------------------------------------------
@@ -377,6 +378,20 @@ 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
 	//--------------------------------------------
@@ -404,6 +419,17 @@ 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;
+
+	// if enableRamps if false, skip speed and initial attributes
+	if (!enableRamps)
+	{
+		INFO_STREAM << "Ramps are disabled. Skipping speed and initial attributes" << std::endl;
+	}
+
 	for (unsigned int l_cpt = 0; l_cpt < m_nb_chan; l_cpt++)
 	{
 		yat::OSStream oss;
@@ -515,8 +541,45 @@ 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++)
@@ -531,6 +594,7 @@ void SingleShotAO::init_device()
 			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;
 				(m_manager->*setter)(l_cpt, val);
 			}
 			catch (...) {
-- 
GitLab


From 5551cf17caf5eefd2a2e6aa40bbe3f2b8d645dde Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Mon, 24 Mar 2025 17:50:41 +0100
Subject: [PATCH 22/34] refactor: split write_channel method into
 write_channel_direct and start_channel_ramp

---
 src/SingleShotAO.cpp        |   5 +-
 src/SingleShotAOManager.cpp | 121 ++++++++++++++++++++----------------
 src/SingleShotAOManager.h   |   6 ++
 3 files changed, 79 insertions(+), 53 deletions(-)

diff --git a/src/SingleShotAO.cpp b/src/SingleShotAO.cpp
index cb204a0..7bcea21 100755
--- a/src/SingleShotAO.cpp
+++ b/src/SingleShotAO.cpp
@@ -609,7 +609,7 @@ void SingleShotAO::init_device()
 		}
 
 		if (outputMemorizedChannelsAtInit) {
-			applyMemorizedAttr(kCHANNEL, &SingleShotAOManager::write_channel); // write memorized value to board output
+			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
 		}
@@ -978,8 +978,11 @@ 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);
+	yat4tango::PropertyHelper::set_memorized_attribute(this, kINITIAL + std::to_string(l_idx), l_val);
+	DEBUG_STREAM << "SingleShotAO::write_channel(): memorized attribute " << l_attr_name << " set to " << l_val << endl;
 }
 
 
diff --git a/src/SingleShotAOManager.cpp b/src/SingleShotAOManager.cpp
index 0eb1333..e988c22 100755
--- a/src/SingleShotAOManager.cpp
+++ b/src/SingleShotAOManager.cpp
@@ -250,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();
@@ -283,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 || !m_enable_ramps)
+	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;
@@ -389,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);
 }
 
 // ============================================================================
diff --git a/src/SingleShotAOManager.h b/src/SingleShotAOManager.h
index 5351b59..25c002e 100755
--- a/src/SingleShotAOManager.h
+++ b/src/SingleShotAOManager.h
@@ -59,6 +59,12 @@ public:
   //- write channel
   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);
 
-- 
GitLab


From e3d05be346d74b5a50b53dae0f9be0eb234fbf70 Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Tue, 25 Mar 2025 10:26:35 +0100
Subject: [PATCH 23/34] fix: always synchronize read and write values (except
 during ramps)

---
 src/SingleShotAO.cpp | 61 +++++++++++++++++++++++++++++++++++++-------
 src/SingleShotAO.h   |  4 +++
 2 files changed, 56 insertions(+), 9 deletions(-)

diff --git a/src/SingleShotAO.cpp b/src/SingleShotAO.cpp
index 7bcea21..76ce807 100755
--- a/src/SingleShotAO.cpp
+++ b/src/SingleShotAO.cpp
@@ -455,7 +455,6 @@ void SingleShotAO::init_device()
 		dai_channel.tai.min_value = "-10.0";
 		dai_channel.tai.description = "Output value for channel " + oss.str() + " (in measurementUnit).";
 		dai_channel.tai.format = "%1.2f";
-		dai_channel.memorized = true;
 		dai_channel.cdb = false;
 
 		//- read callback
@@ -494,7 +493,6 @@ void SingleShotAO::init_device()
 		dai_speed.tai.format = "%1.2f";
 
 		//- 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
@@ -528,7 +526,6 @@ void SingleShotAO::init_device()
 		dai_initial.tai.format = "%1.2f";
 
 		//- 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
@@ -595,7 +592,12 @@ void SingleShotAO::init_device()
 				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 (...) {
 				// nothing to do
@@ -954,6 +956,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
@@ -981,7 +984,12 @@ void SingleShotAO::write_channel(yat4tango::DynamicAttributeWriteCallbackData &
 	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);
-	yat4tango::PropertyHelper::set_memorized_attribute(this, kINITIAL + std::to_string(l_idx), 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;
 }
 
@@ -1116,6 +1124,37 @@ 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
@@ -1160,11 +1199,15 @@ void SingleShotAO::_abort()
 			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 7cee441..17e2b74 100755
--- a/src/SingleShotAO.h
+++ b/src/SingleShotAO.h
@@ -290,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
-- 
GitLab


From d77c4643378126b3d588ba492a619170dae27130 Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Wed, 26 Mar 2025 11:30:58 +0100
Subject: [PATCH 24/34] fix: applied requested changes (by @langlois in !3)

---
 src/SingleShotAO.cpp      | 75 +++++++++++++++++++++++----------------
 src/SingleShotAOClass.cpp |  3 +-
 src/SingleShotAOManager.h |  2 ++
 3 files changed, 49 insertions(+), 31 deletions(-)

diff --git a/src/SingleShotAO.cpp b/src/SingleShotAO.cpp
index 76ce807..0c95671 100755
--- a/src/SingleShotAO.cpp
+++ b/src/SingleShotAO.cpp
@@ -380,14 +380,17 @@ void SingleShotAO::init_device()
 
 	// Remove existing dynamic attributes to avoid duplicates or other issues
 	// --------------------------------------------
-	if (m_dyn_attr_manager) {
-		try {
+	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 (...) {
+		catch (...)
+		{
 			ERROR_STREAM << "Error cleaning up existing dynamic attributes manager, continuing..." << endl;
 			// Continue anyway - we'll create a new one
 		}
@@ -424,12 +427,6 @@ void SingleShotAO::init_device()
 	INFO_STREAM << "Creating dynamic attributes for " << m_nb_chan << " channels.";
 	INFO_STREAM << "Total attributes: " << m_nb_chan * (enableRamps ? 3 : 1) << endl;
 
-	// if enableRamps if false, skip speed and initial attributes
-	if (!enableRamps)
-	{
-		INFO_STREAM << "Ramps are disabled. Skipping speed and initial attributes" << std::endl;
-	}
-
 	for (unsigned int l_cpt = 0; l_cpt < m_nb_chan; l_cpt++)
 	{
 		yat::OSStream oss;
@@ -454,7 +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.2f";
+		dai_channel.tai.format = "%2.1f";
 		dai_channel.cdb = false;
 
 		//- read callback
@@ -468,7 +465,8 @@ void SingleShotAO::init_device()
 		l_dynAttrList.push_back(dai_channel);
 
 		// if enableRamps if false, skip speed and initial attributes
-		if (!enableRamps) {
+		if (!enableRamps)
+		{
 			DEBUG_STREAM << "Ramps are disabled. Skipping speed and initial attributes for channel " << l_cpt << std::endl;
 			continue;
 		}
@@ -490,7 +488,7 @@ 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.2f";
+		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.cdb = false;
@@ -523,7 +521,7 @@ 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.cdb = false;
@@ -543,17 +541,20 @@ void SingleShotAO::init_device()
 	INFO_STREAM << "Prepared " << l_dynAttrList.size() << " dynamic attributes for creation" << endl;
 	
 	// Add all attributes
-	try {
+	try 
+	{
   		m_dyn_attr_manager->add_attributes(l_dynAttrList);
 		INFO_STREAM << "Successfully added all dynamic attributes" << endl;
 	}
-	catch (Tango::DevFailed &df) {
+	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 (...) {
+	catch (...) 
+	{
 		ERROR_STREAM << "Unknown exception when adding dynamic attributes" << endl;
 		m_currStatus = "Failed to add dynamic attributes. Unknown error";
 		m_state = Tango::FAULT;
@@ -561,17 +562,21 @@ void SingleShotAO::init_device()
 	}
 
 	// Initialize maps in manager class for all channels
-	try {
-		for (unsigned int l_cpt = 0; l_cpt < m_nb_chan; l_cpt++) {
+	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) {
+			if (enableRamps)
+			{
 				m_manager->set_speed(l_cpt, 0.0);
 				m_manager->set_initial(l_cpt, 0.0);
 			}
 		}
 	}
-	catch (Tango::DevFailed &df) {
+	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;
@@ -588,7 +593,8 @@ 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;
@@ -599,18 +605,21 @@ void SingleShotAO::init_device()
 				// 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
-		if (enableRamps) {
+		if (enableRamps)
+		{
 			applyMemorizedAttr(kSPEED, &SingleShotAOManager::set_speed);
 			applyMemorizedAttr(kINITIAL, &SingleShotAOManager::set_initial); 
 		}
 
-		if (outputMemorizedChannelsAtInit) {
+		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
@@ -663,7 +672,8 @@ void SingleShotAO::get_device_property()
 
 	// Call database and extract values
 	//--------------------------------------------
-	if (Tango::Util::instance()->_UseDb==true) {
+	if (Tango::Util::instance()->_UseDb==true)
+	{
 		get_db_device()->get_property(dev_prop);
 	}
 
@@ -736,7 +746,8 @@ void SingleShotAO::get_device_property()
 		ERROR_STREAM << "Required device property <BoardType> is missing" << endl;
 		critical_properties_missing = true;
 	}
-	if (critical_properties_missing) {
+	if (critical_properties_missing)
+	{
 		return;
 	}
 
@@ -1131,7 +1142,8 @@ void SingleShotAO::write_initial(yat4tango::DynamicAttributeWriteCallbackData &
  */
 bool SingleShotAO::setDynamicAttributeWriteValue(const std::string& attrName, double value)
 {
-    try {
+    try
+	{
         Tango::DeviceImpl* dev = static_cast<Tango::DeviceImpl*>(this);
         Tango::DevDouble val_to_write = value;
         
@@ -1142,12 +1154,14 @@ bool SingleShotAO::setDynamicAttributeWriteValue(const std::string& attrName, do
         DEBUG_STREAM << "Set write value for " << attrName << " to " << value << endl;
         return true;
     }
-    catch (Tango::DevFailed &df) {
+    catch (Tango::DevFailed &df)
+	{
         ERROR_STREAM << "Failed to set write value for " << attrName 
                     << ": " << df << endl;
         return false;
     }
-    catch (...) {
+    catch (...)
+	{
         ERROR_STREAM << "Unknown exception setting write value for " 
                     << attrName << endl;
         return false;
@@ -1195,7 +1209,8 @@ 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);
diff --git a/src/SingleShotAOClass.cpp b/src/SingleShotAOClass.cpp
index 29a1ef5..d5b5ee1 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);
 	}
 }
diff --git a/src/SingleShotAOManager.h b/src/SingleShotAOManager.h
index 25c002e..325e00f 100755
--- a/src/SingleShotAOManager.h
+++ b/src/SingleShotAOManager.h
@@ -54,9 +54,11 @@ public:
   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)
-- 
GitLab


From 481c3c032eec8638acb73b56c7e3d61aea54334d Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Tue, 22 Apr 2025 14:37:35 +0200
Subject: [PATCH 25/34] fix: update format for channel attributes to use three
 decimal digits (%5.3f)

---
 src/SingleShotAO.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/SingleShotAO.cpp b/src/SingleShotAO.cpp
index 0c95671..e21ee35 100755
--- a/src/SingleShotAO.cpp
+++ b/src/SingleShotAO.cpp
@@ -451,7 +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 = "%2.1f";
+		dai_channel.tai.format = "%5.3f";
 		dai_channel.cdb = false;
 
 		//- read callback
@@ -488,7 +488,7 @@ 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 = "%2.1f";
+		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;
@@ -521,7 +521,7 @@ 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 = "%2.1f";
+		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;
-- 
GitLab


From c84bae851f672b1a807c7ad34bf600f797a84b1f Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Tue, 22 Apr 2025 15:41:07 +0200
Subject: [PATCH 26/34] fix: improve debug messages for missing attribute
 values

---
 src/SingleShotAO.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/SingleShotAO.cpp b/src/SingleShotAO.cpp
index e21ee35..e6145dc 100755
--- a/src/SingleShotAO.cpp
+++ b/src/SingleShotAO.cpp
@@ -353,7 +353,7 @@ void SingleShotAO::init_device()
 	}
 	catch (...)
 	{
-		DEBUG_STREAM << "Failed to get frequency value. Maybe there is no value yet." << std::endl;
+		DEBUG_STREAM << "No memorized value found for frequency. Defaulting to " << m_frequency << "." << std::endl;
 	}
 
 
@@ -607,7 +607,7 @@ void SingleShotAO::init_device()
 			}
 			catch (...)
 			{
-				// nothing to do
+				DEBUG_STREAM << "No memorized value found for " << attrName << ". Setting default value." << std::endl;
 			}
 		};
 
-- 
GitLab


From 3a0041bbe2167c25b2f4dfff9fcee047297f3335 Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Tue, 22 Apr 2025 15:58:31 +0200
Subject: [PATCH 27/34] fix: create properties in init if they don't exist, and
 validate properties values

---
 src/SingleShotAO.cpp      | 85 ++++++++++++++++++++++++++-------------
 src/SingleShotAOClass.cpp |  6 ++-
 2 files changed, 60 insertions(+), 31 deletions(-)

diff --git a/src/SingleShotAO.cpp b/src/SingleShotAO.cpp
index e6145dc..19b614b 100755
--- a/src/SingleShotAO.cpp
+++ b/src/SingleShotAO.cpp
@@ -593,9 +593,9 @@ void SingleShotAO::init_device()
 		auto applyMemorizedAttr = [&](const std::string& attrPrefix, 
 			void (SingleShotAOManager::*setter)(yat::uint16, double))
 		{
+			std::string attrName = attrPrefix + oss.str();
 			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;
 
@@ -652,14 +652,14 @@ void SingleShotAO::init_device()
 	isInitOk = true;
 }
 
-
-//+----------------------------------------------------------------------------
-//
-// method : 		SingleShotAO::get_device_property()
-// 
-// description : 	Read the device properties from database.
-//
-//-----------------------------------------------------------------------------
+//+------------------------------------------------------------------
+/**
+ * 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
@@ -733,38 +733,54 @@ void SingleShotAO::get_device_property()
 	if (dev_prop[i].is_empty() == false) dev_prop[i] >> outputMemorizedChannelsAtInit;
 	INFO_STREAM << "OutputMemorizedChannelsAtInit parsed: " << (outputMemorizedChannelsAtInit ? "true" : "false") << endl;
 
-	// Check critical properties being present
+	// Create properties if empty and set default values
 	//--------------------------------------------
-	critical_properties_missing = false;
-	if (dev_prop[0].is_empty())
-	{
-		ERROR_STREAM << "Required device property <BoardNum> is missing" << endl;
-		critical_properties_missing = true;
-	}
-	if (dev_prop[1].is_empty())
-	{
-		ERROR_STREAM << "Required device property <BoardType> is missing" << endl;
-		critical_properties_missing = true;
-	}
-	if (critical_properties_missing)
-	{
-		return;
-	}
+	DEBUG_STREAM << "Creating properties if empty" << endl;
+	yat4tango::PropertyHelper::create_property_if_empty(this, dev_prop, boardNum, "BoardNum");
+	yat4tango::PropertyHelper::create_property_if_empty(this, dev_prop, boardType, "BoardType");
+	yat4tango::PropertyHelper::create_property_if_empty(this, dev_prop, enableRamps, "EnableRamps");
+	yat4tango::PropertyHelper::create_property_if_empty(this, dev_prop, outputMemorizedChannelsAtInit, "OutputMemorizedChannelsAtInit");
 
 	// Check critical properties being valid
 	//--------------------------------------------
+	DEBUG_STREAM << "Checking if critical properties are valid:" << endl;
+	critical_properties_missing = false;
+	yat::OSStream errorMessages;
+
 	//- <BoardNum> -----------------------
-	if (boardNum < 0 || boardNum > 7)
+	Tango::DbDatum &boardNumDatum = Tango::DbDatum("BoardNum");
+	std::string defaultBoardNum_str;
+	def_prop = ds_class->get_default_device_property(boardNumDatum.name);
+	if (def_prop.is_empty() == false) def_prop >> defaultBoardNum_str;
+	Tango::DevShort defaultBoardNum = atoi(defaultBoardNum_str.c_str());
+	if (boardNum == defaultBoardNum)
+	{
+		errorMessages << "Device property <BoardNum> is not set (default value " << defaultBoardNum << " needs to be replaced)" << endl;
+		ERROR_STREAM << "Device property <BoardNum> is not set (default value " << defaultBoardNum << " needs to be replaced)" << endl;
+		critical_properties_missing = true;
+	}
+	else if (boardNum < 0 || boardNum > 7)
 	{
 		boardNum = 0;
-		ERROR_STREAM << "device property <BoardNum> is invalid. Valid range is [0..7]" << endl;
+		errorMessages << "Device property <BoardNum> is invalid. Valid range is [0..7]" << endl;
+		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> -----------------------
-	if (boardType == "MAO_6208")
+	Tango::DbDatum &boardTypeDatum = Tango::DbDatum("BoardType");
+	std::string defaultBoardType;
+	def_prop = ds_class->get_default_device_property(boardTypeDatum.name);
+	if (def_prop.is_empty() == false) def_prop >> defaultBoardType;
+	if (boardType == defaultBoardType)
+	{
+		errorMessages << "Device property <BoardType> is not set (default value " << defaultBoardType << " needs to be replaced)" << endl;
+		ERROR_STREAM << "Device property <BoardType> is not set (default value " << defaultBoardType << " needs to be replaced)" << endl;
+		critical_properties_missing = true;
+	}
+	else if (boardType == "MAO_6208")
 	{
 		boardType = k6208_BOARD_TYPE;
 		boardTypeId = adl::PCI6208;
@@ -780,9 +796,20 @@ void SingleShotAO::get_device_property()
 	{
 		boardType = kDEFAULT_BOARD_TYPE;
 		boardTypeId = adl::PCI6208;
-		ERROR_STREAM << "device property <BoardType> is invalid [supported hw: MAO_6208 or MAO_6216]" << endl;
+		errorMessages << "Device property <BoardType> is invalid [supported hw: MAO_6208 or MAO_6216]" << endl;
+		ERROR_STREAM << "Device property <BoardType> is invalid [supported hw: MAO_6208 or MAO_6216]" << endl;
 		critical_properties_missing = true;
 	}
+
+	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;
+	}
 }
 
 
diff --git a/src/SingleShotAOClass.cpp b/src/SingleShotAOClass.cpp
index d5b5ee1..d780498 100755
--- a/src/SingleShotAOClass.cpp
+++ b/src/SingleShotAOClass.cpp
@@ -378,8 +378,9 @@ void SingleShotAOClass::set_default_property()
 	//- <BoardNum> -----------------------
 	prop_name = "BoardNum";
 	prop_desc = "The board identifier in the cPCI crate [valid range is 0...7 - no default value].";
-	prop_def  = "";
+	prop_def  = "-1";
 	vect_data.clear();
+	vect_data.push_back("-1");
 	if (prop_def.length()>0)
 	{
 		Tango::DbDatum	data(prop_name);
@@ -393,8 +394,9 @@ void SingleShotAOClass::set_default_property()
 	//- <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  = "";
+	prop_def = "TO_BE_DEFINED";
 	vect_data.clear();
+	vect_data.push_back("TO_BE_DEFINED");
 	if (prop_def.length()>0)
 	{
 		Tango::DbDatum	data(prop_name);
-- 
GitLab


From 1dc39827d610f6d390c0eacb0e59bbb3f84cff0f Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Tue, 22 Apr 2025 18:33:50 +0200
Subject: [PATCH 28/34] fix: move SingleShotAOManager construction to dtart of
 init_device to allow init after an error in get_device_property()

---
 src/SingleShotAO.cpp | 47 ++++++++++++++++++++++----------------------
 1 file changed, 24 insertions(+), 23 deletions(-)

diff --git a/src/SingleShotAO.cpp b/src/SingleShotAO.cpp
index 19b614b..e101a12 100755
--- a/src/SingleShotAO.cpp
+++ b/src/SingleShotAO.cpp
@@ -231,6 +231,30 @@ void SingleShotAO::init_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;
+	}
+
+	// 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;
+	}
+	
+
 	// Initialise variables to default values
 	//--------------------------------------------
 
@@ -320,29 +344,6 @@ void SingleShotAO::init_device()
 
 	INFO_STREAM << "Board has " << m_nb_chan << " channels" << endl;
 
-	// 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;
-	}
-
-	// 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
 	//--------------------------------------------
-- 
GitLab


From ca7a47a167e40cc80aa77961815fb98d0e54ec28 Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Wed, 23 Apr 2025 14:18:13 +0200
Subject: [PATCH 29/34] fix: enhance error handling and add comments in
 get_device_property()

---
 src/SingleShotAO.cpp | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/src/SingleShotAO.cpp b/src/SingleShotAO.cpp
index e101a12..b90b3c5 100755
--- a/src/SingleShotAO.cpp
+++ b/src/SingleShotAO.cpp
@@ -737,6 +737,8 @@ void SingleShotAO::get_device_property()
 	// Create properties if empty and set default values
 	//--------------------------------------------
 	DEBUG_STREAM << "Creating properties if empty" << endl;
+	// boardNum, boardType, enableRamps and outputMemorizedChannelsAtInit variables
+	// contain the default values at this point if the properties are not set in the database.
 	yat4tango::PropertyHelper::create_property_if_empty(this, dev_prop, boardNum, "BoardNum");
 	yat4tango::PropertyHelper::create_property_if_empty(this, dev_prop, boardType, "BoardType");
 	yat4tango::PropertyHelper::create_property_if_empty(this, dev_prop, enableRamps, "EnableRamps");
@@ -747,8 +749,11 @@ void SingleShotAO::get_device_property()
 	DEBUG_STREAM << "Checking if critical properties are valid:" << endl;
 	critical_properties_missing = false;
 	yat::OSStream errorMessages;
+	errorMessages << "\nCritical properties are missing or invalid:\n" << endl;
 
 	//- <BoardNum> -----------------------
+	// Case 1 (error): boardNum is set to the default value in the database
+	// (compare the current value with the default value)
 	Tango::DbDatum &boardNumDatum = Tango::DbDatum("BoardNum");
 	std::string defaultBoardNum_str;
 	def_prop = ds_class->get_default_device_property(boardNumDatum.name);
@@ -757,20 +762,24 @@ void SingleShotAO::get_device_property()
 	if (boardNum == defaultBoardNum)
 	{
 		errorMessages << "Device property <BoardNum> is not set (default value " << defaultBoardNum << " needs to be replaced)" << endl;
-		ERROR_STREAM << "Device property <BoardNum> is not set (default value " << defaultBoardNum << " 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;
-		ERROR_STREAM << "Device property <BoardNum> is invalid. Valid range is [0..7]" << endl;
 		critical_properties_missing = true;
-	} else {
+	}
+	// 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
+	// (compare the current value with the default value)
 	Tango::DbDatum &boardTypeDatum = Tango::DbDatum("BoardType");
 	std::string defaultBoardType;
 	def_prop = ds_class->get_default_device_property(boardTypeDatum.name);
@@ -778,9 +787,9 @@ void SingleShotAO::get_device_property()
 	if (boardType == defaultBoardType)
 	{
 		errorMessages << "Device property <BoardType> is not set (default value " << defaultBoardType << " needs to be replaced)" << endl;
-		ERROR_STREAM << "Device property <BoardType> is not set (default value " << defaultBoardType << " 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;
@@ -793,15 +802,16 @@ void SingleShotAO::get_device_property()
 		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;
-		ERROR_STREAM << "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;
-- 
GitLab


From e9bc2d6945d4d3e7f4749b29bfa9d2e5b26ddd30 Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Wed, 23 Apr 2025 14:30:03 +0200
Subject: [PATCH 30/34] refactor: improve clarity by removing redundancy in
 get_device_property() for default properties values

---
 src/SingleShotAO.cpp | 69 ++++++++++++++++++++++++--------------------
 src/SingleShotAO.h   | 20 +++++++++++--
 2 files changed, 56 insertions(+), 33 deletions(-)

diff --git a/src/SingleShotAO.cpp b/src/SingleShotAO.cpp
index b90b3c5..d56848a 100755
--- a/src/SingleShotAO.cpp
+++ b/src/SingleShotAO.cpp
@@ -671,6 +671,7 @@ void SingleShotAO::get_device_property()
 	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)
@@ -689,23 +690,31 @@ void SingleShotAO::get_device_property()
 	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;
+		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;
+	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;
+	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;
+		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;
+	if (dev_prop[i].is_empty() == false) dev_prop[i] >> boardType;
 	INFO_STREAM << "Raw BoardType parsed: " << boardType << endl;
 
 	//- <EnableRamps> -----------------------
@@ -715,7 +724,11 @@ void SingleShotAO::get_device_property()
 	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;
+		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;
@@ -728,40 +741,38 @@ void SingleShotAO::get_device_property()
 	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;
+		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;
-	// boardNum, boardType, enableRamps and outputMemorizedChannelsAtInit variables
-	// contain the default values at this point if the properties are not set in the database.
-	yat4tango::PropertyHelper::create_property_if_empty(this, dev_prop, boardNum, "BoardNum");
-	yat4tango::PropertyHelper::create_property_if_empty(this, dev_prop, boardType, "BoardType");
-	yat4tango::PropertyHelper::create_property_if_empty(this, dev_prop, enableRamps, "EnableRamps");
-	yat4tango::PropertyHelper::create_property_if_empty(this, dev_prop, outputMemorizedChannelsAtInit, "OutputMemorizedChannelsAtInit");
+	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 << "\nCritical properties are missing or invalid:\n" << endl;
+	errorMessages << "Critical properties are missing or invalid:" << endl;
 
 	//- <BoardNum> -----------------------
 	// Case 1 (error): boardNum is set to the default value in the database
-	// (compare the current value with the default value)
-	Tango::DbDatum &boardNumDatum = Tango::DbDatum("BoardNum");
-	std::string defaultBoardNum_str;
-	def_prop = ds_class->get_default_device_property(boardNumDatum.name);
-	if (def_prop.is_empty() == false) def_prop >> defaultBoardNum_str;
-	Tango::DevShort defaultBoardNum = atoi(defaultBoardNum_str.c_str());
-	if (boardNum == defaultBoardNum)
-	{
-		errorMessages << "Device property <BoardNum> is not set (default value " << defaultBoardNum << " needs to be replaced)" << endl;
+	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
@@ -779,14 +790,9 @@ void SingleShotAO::get_device_property()
 
 	//- <BoardType> -----------------------
 	// Case 1 (error): boardType is set to the default value in the database
-	// (compare the current value with the default value)
-	Tango::DbDatum &boardTypeDatum = Tango::DbDatum("BoardType");
-	std::string defaultBoardType;
-	def_prop = ds_class->get_default_device_property(boardTypeDatum.name);
-	if (def_prop.is_empty() == false) def_prop >> defaultBoardType;
-	if (boardType == defaultBoardType)
-	{
-		errorMessages << "Device property <BoardType> is not set (default value " << defaultBoardType << " needs to be replaced)" << endl;
+	if (boardType == boardType_default)
+	{
+		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 
@@ -811,6 +817,7 @@ void SingleShotAO::get_device_property()
 		critical_properties_missing = true;
 	}
 
+
 	// If any critical property is missing or invalid, throw an exception
 	if (critical_properties_missing)
 	{
diff --git a/src/SingleShotAO.h b/src/SingleShotAO.h
index 17e2b74..2d680ca 100755
--- a/src/SingleShotAO.h
+++ b/src/SingleShotAO.h
@@ -121,10 +121,26 @@ public :
 //@}
 
 /**
- *	@name Device properties
- *	Device property member data.
+ *	@name Device properties default values
+ *	Device properties default values.
  */
 //@{
+/**
+ *	Default value for boardNum property
+ */
+	Tango::DevShort	boardNum_default;
+/**
+ * 	Default value for boardType property
+ */
+	string	boardType_default;
+/**
+ *	Default value for enableRamps property
+ */
+	Tango::DevBoolean	enableRamps_default;
+/**
+ *	Default value for outputMemorizedChannelsAtInit property
+ */
+	Tango::DevBoolean	outputMemorizedChannelsAtInit_default;
 //@}
 
 /**@name Constructors
-- 
GitLab


From ccec3c51eec6851a706924e4da9804095889ebca Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Wed, 23 Apr 2025 14:59:47 +0200
Subject: [PATCH 31/34] fix: improve error logging for get_device_property in
 init_device (logs and status)

---
 src/SingleShotAO.cpp | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/src/SingleShotAO.cpp b/src/SingleShotAO.cpp
index d56848a..12080ad 100755
--- a/src/SingleShotAO.cpp
+++ b/src/SingleShotAO.cpp
@@ -277,8 +277,15 @@ void SingleShotAO::init_device()
 		ERROR_STREAM << "SingleShotAO::init_device::Tango::DevFailed exception caught "
 			<< "while trying to read device properties from TANGO database"
 			<< std::endl;
-		ERROR_STREAM << df << std::endl;
-		m_currStatus = "Failed to get property. See log for details";
+		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;
 	}
-- 
GitLab


From 4a660db36380f0f0395587da4b3362e1ddb3273b Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Wed, 23 Apr 2025 15:01:37 +0200
Subject: [PATCH 32/34] fix: handle empty boardType in get_device_property() to
 improve error handling

---
 src/SingleShotAO.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/SingleShotAO.cpp b/src/SingleShotAO.cpp
index 12080ad..9a61cc0 100755
--- a/src/SingleShotAO.cpp
+++ b/src/SingleShotAO.cpp
@@ -797,7 +797,7 @@ void SingleShotAO::get_device_property()
 
 	//- <BoardType> -----------------------
 	// Case 1 (error): boardType is set to the default value in the database
-	if (boardType == boardType_default)
+	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;
-- 
GitLab


From 24152f1e0e70daae45b3d28e4de3a929330bac71 Mon Sep 17 00:00:00 2001
From: MALFREYT <alexandre.malfreyt@synchrotron-soleil.fr>
Date: Wed, 23 Apr 2025 18:27:41 +0200
Subject: [PATCH 33/34] refactor: revert e9bc2d69 partially to prevent pogo
 interference (get default values later in get_device_property)

---
 src/SingleShotAO.cpp | 60 ++++++++++++++++++++++++--------------------
 1 file changed, 33 insertions(+), 27 deletions(-)

diff --git a/src/SingleShotAO.cpp b/src/SingleShotAO.cpp
index 9a61cc0..112ac3e 100755
--- a/src/SingleShotAO.cpp
+++ b/src/SingleShotAO.cpp
@@ -253,7 +253,7 @@ void SingleShotAO::init_device()
 		m_state = Tango::FAULT;
 		return;
 	}
-	
+
 
 	// Initialise variables to default values
 	//--------------------------------------------
@@ -681,83 +681,89 @@ void SingleShotAO::get_device_property()
 
 	// Call database and extract values
 	//--------------------------------------------
-	if (Tango::Util::instance()->_UseDb==true)
+	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;
+	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 {
+	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;
+	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 {
+	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;
+	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 {
+	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;
+	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 {
+	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;
+	if (dev_prop[i].is_empty() == false)
+		dev_prop[i] >> outputMemorizedChannelsAtInit;
 	INFO_STREAM << "OutputMemorizedChannelsAtInit parsed: " << (outputMemorizedChannelsAtInit ? "true" : "false") << endl;
 
+	// Get default values from class
+	//--------------------------------------------
+	ds_class->get_default_device_property(std::string("BoardNum")) >> boardNum_default;
+	ds_class->get_default_device_property(std::string("BoardType")) >> boardType_default;
+	ds_class->get_default_device_property(std::string("EnableRamps")) >> enableRamps_default;
+	ds_class->get_default_device_property(std::string("OutputMemorizedChannelsAtInit")) >> outputMemorizedChannelsAtInit_default;
 
 	// Create properties if empty and set default values
 	//--------------------------------------------
-- 
GitLab


From 256f61e96f4de7c14eaef93633ed50f279cf4f7a Mon Sep 17 00:00:00 2001
From: Florent Langlois <florent.langlois@synchrotron-soleil.fr>
Date: Thu, 24 Apr 2025 11:41:37 +0200
Subject: [PATCH 34/34] set version to 2.1.0

---
 conanfile.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/conanfile.py b/conanfile.py
index 27e4801..24ed606 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.2.0"
+    version = "2.1.0"
     package_type = "application"
     user = "soleil"
     python_requires = "base/[>=1.0]@soleil/stable"
-- 
GitLab