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] 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