From f8edf9f742a847b35b8d7c7a61ded390047a0b9a Mon Sep 17 00:00:00 2001
From: Alexander Schwinn <al.schwinn@gsi.de>
Date: Mon, 17 Jul 2017 16:55:33 +0200
Subject: [PATCH] Bug 1452 - Remove path to .silecsparam from instance-file

---
 .../src/xml/fesa/fesa_3_0_0/fesaTemplates.py  |  2 +-
 .../xml/fesa/fesa_3_0_0/generateFesaDesign.py | 13 ----
 .../src/xml/migration/2_0_xto2_1_x.py         |  9 +++
 .../migration2_0_Xto2_1_X/migrators.py        |  6 ++
 .../migration2_0_Xto2_1_X/testMigration.py    | 40 ++++++++++++-
 .../src/xml/migration/migrationBase.py        | 10 ++--
 .../generated_correct/AllTypesFESA.design     |  2 +-
 .../interface/core/SilecsService.cpp          | 60 +++++++++++++++++++
 .../interface/core/SilecsService.h            | 13 +++-
 .../interface/equipment/SilecsCluster.h       |  4 +-
 .../interface/equipment/SilecsPLC.cpp         |  3 +
 .../interface/equipment/SilecsPLC.h           |  2 +-
 silecs-diagnostic-cpp/Makefile.dep            |  4 +-
 13 files changed, 142 insertions(+), 26 deletions(-)

diff --git a/silecs-codegen/src/xml/fesa/fesa_3_0_0/fesaTemplates.py b/silecs-codegen/src/xml/fesa/fesa_3_0_0/fesaTemplates.py
index f570963..5ef9b32 100644
--- a/silecs-codegen/src/xml/fesa/fesa_3_0_0/fesaTemplates.py
+++ b/silecs-codegen/src/xml/fesa/fesa_3_0_0/fesaTemplates.py
@@ -241,7 +241,7 @@ hBottom = """
             static bool isInitialized(){ return Abstract${className}::isInitialized(); }
             static Silecs::PLC* getPLC(Device* pDevice)
             {
-                return Abstract${className}::theCluster()->getPLC(pDevice->plcHostName.get(),pDevice->parameterFile.get());
+                return Abstract${className}::theCluster()->getPLC(pDevice->plcHostName.get());
             }
     """
 
diff --git a/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateFesaDesign.py b/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateFesaDesign.py
index 4ff978c..25224e4 100644
--- a/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateFesaDesign.py
+++ b/silecs-codegen/src/xml/fesa/fesa_3_0_0/generateFesaDesign.py
@@ -216,18 +216,6 @@ class FESADesignGenerator3_0_0(object):
         dim = getOrCreateChildElement(array,'dim')
         dim.setContent('128')
         return fieldNode
-        
-    def getOrCreateParameterFileField(self,configurationNode):
-        fieldNode = getOrCreateNamedFirstChild(configurationNode,'field','parameterFile')
-        descriptionNode = getOrCreateChildElement(fieldNode,'description')
-        descriptionNode.setContent('ParameterFile of the PLC (*.silecsparam)')
-        array = getOrCreateChildElement(fieldNode,'array')
-        fillAttributes(array, {'type': 'char'})
-        dim = getOrCreateChildElement(array,'dim')
-        defaultNode = getOrCreateChildElement(fieldNode,'default')
-        defaultNode.setContent('../../../generated/client/MyControllerName.silecsparam')
-        dim.setContent('512')
-        return fieldNode
 
     def getOrCreatePLCClassVersionField(self,configurationNode,plcClassVersion):
         fieldNode = getOrCreateNamedFirstChild(configurationNode,'field','plcClassVersion')
@@ -349,7 +337,6 @@ class FESADesignGenerator3_0_0(object):
         acquisitionNode = getOrCreateChildElement(deviceDataNode,'acquisition')
         self.getOrCreatePLCHostNameField(configurationNode)
         self.getOrCreatePLCDeviceLabelField(configurationNode)
-        self.getOrCreateParameterFileField(configurationNode)
 
         for block in designClass.getDesignBlocks():
             for reg in block.getDesignRegisters():
diff --git a/silecs-codegen/src/xml/migration/2_0_xto2_1_x.py b/silecs-codegen/src/xml/migration/2_0_xto2_1_x.py
index 2cb7990..defb913 100644
--- a/silecs-codegen/src/xml/migration/2_0_xto2_1_x.py
+++ b/silecs-codegen/src/xml/migration/2_0_xto2_1_x.py
@@ -30,10 +30,19 @@ class Migration(MigrationBase):
         super(Migration, self).__init__()
 
     def migrateClass(self, context, projectDir ):
+        modified = false
         #modified = fesaClassIncludeHeaderMigrator(context,self.silecsDocument)
         #removeSilecsDesignGenCode(context, self.silecsDocument)
         #modified |= fesaClassMakeSpecificMigrator(self.silecsDocument)
+        
+        fesaClassName = os.path.dirname(projectDir)
+        fesaDocument = os.path.join("src", fesaClassName + ".design")
+        if os.path.isfile(fesaDocument):
+            contextFesa = self._parse(fesaDocument)
+            modified |= removeFesaConfigurationFieldParameterFile(contextFesa)
         self.updateFESAMakeSpecific()
+        
+        
         return modified
     
     def migrateDeployUnit(self, context, projectDir ):
diff --git a/silecs-codegen/src/xml/migration/migration2_0_Xto2_1_X/migrators.py b/silecs-codegen/src/xml/migration/migration2_0_Xto2_1_X/migrators.py
index 819d454..293ede6 100644
--- a/silecs-codegen/src/xml/migration/migration2_0_Xto2_1_X/migrators.py
+++ b/silecs-codegen/src/xml/migration/migration2_0_Xto2_1_X/migrators.py
@@ -75,3 +75,9 @@ def removeSilecsDeployGenCode(context, projectDir):
         shutil.rmtree(controllerFolder)
     if os.path.isdir(wrapperFolder):
         shutil.rmtree(wrapperFolder)
+        
+def removeFesaConfigurationFieldParameterFile(context):
+    paramFields = context.xpathEval("//field[@name='parameterFile']")
+    for paramField in paramFields:
+        paramField.unlinkNode()
+        
diff --git a/silecs-codegen/src/xml/migration/migration2_0_Xto2_1_X/testMigration.py b/silecs-codegen/src/xml/migration/migration2_0_Xto2_1_X/testMigration.py
index b547857..08688f5 100644
--- a/silecs-codegen/src/xml/migration/migration2_0_Xto2_1_X/testMigration.py
+++ b/silecs-codegen/src/xml/migration/migration2_0_Xto2_1_X/testMigration.py
@@ -33,6 +33,44 @@ def testFesaClassMakeSpecificMigrator():
     fesaClassMakeSpecificMigrator(makefileSpecific)
     assertFileEqual(makefileSpecific,makefileSpecificCorrect)
     
+def testremoveFesaConfigurationFieldParameterFile():
+    FesaDocOld = '''<?xml version="1.0" encoding="UTF-8"?>
+<equipment-model xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="file:/opt/fesa/fesa-model-gsi/4.2.0/xml/design/design-gsi.xsd">
+    <data>
+        <device-data>
+            <configuration>
+                <field name="parameterFile" id="_170711152634_36"><description>ParameterFile of the PLC (*.silecsparam)</description><array type="char"><dim>512</dim></array><default>../../../generated/client/MyControllerName.silecsparam</default></field><field name="plcDeviceLabel" id="_170711152634_37"><description>Name of the related SILECS instance within the PLC mapping</description><array type="char"><dim>128</dim></array></field><field name="plcHostName" id="_170711152634_38"><description>Hostname of the PLC that contains the related SILECS class device</description><array type="char"><dim>128</dim></array></field><GSI-detailed-status-labels-field name="detailedStatus_labels" id="_170503152015_8">
+                    <array2D type="char">
+                        <custom-constant-dim1 constant-name-ref="DETAILED_STATUS_SIZE"/>
+                        <custom-constant-dim2 constant-name-ref="MAX_DETAILED_STATUS_LABEL_LENGTH"/>
+                    </array2D>
+                    <default>{myStatusLabel1,myStatusLabel2}</default>
+                </GSI-detailed-status-labels-field>
+                <GSI-detailed-status-severity-field name="detailedStatus_severity" id="_170503152015_9">
+                    <custom-type-array data-type-name-ref="DETAILED_STATUS_SEVERITY">
+                        <custom-constant-dim constant-name-ref="DETAILED_STATUS_SIZE"/>
+                    </custom-type-array>
+                    <default>{INFO,INFO}</default>
+                </GSI-detailed-status-severity-field>
+                <GSI-module-status-labels-field name="moduleStatus_labels" id="_170503152015_10">
+                    <array2D type="char">
+                        <custom-constant-dim1 constant-name-ref="MODULE_STATUS_SIZE"/>
+                        
+                        <custom-constant-dim2 constant-name-ref="MAX_MODULE_STATUS_LABEL_LENGTH"/>
+                    </array2D>
+                    <default>{myModule1,myModule2}</default>
+                </GSI-module-status-labels-field>
+            </configuration>
+        </device-data>
+    </data>
+</equipment-model>
+'''
+    context = libxml2.parseDoc(FesaDocOld)
+    removeFesaConfigurationFieldParameterFile(context)
+    paramFields = context.xpathEval("//field[@name='parameterFile']")
+    assertEqual(len(paramFields),0)
+    
 def runTests():
-    testFesaClassMakeSpecificMigrator()
+    #testFesaClassMakeSpecificMigrator()
+    testremoveFesaConfigurationFieldParameterFile()
     # print deployDoc # for debugging
diff --git a/silecs-codegen/src/xml/migration/migrationBase.py b/silecs-codegen/src/xml/migration/migrationBase.py
index 61590b7..8277ab5 100644
--- a/silecs-codegen/src/xml/migration/migrationBase.py
+++ b/silecs-codegen/src/xml/migration/migrationBase.py
@@ -117,12 +117,12 @@ class MigrationBase(object):
     def migrateDeployUnit(self, context, projectDir):
         return False
     
-    def _parse(self, silecsDocument):
-        if not FileUtils.fileExists(silecsDocument):
-            raise IOError("File not found: %r" % silecsDocument)
+    def _parse(self, document):
+        if not FileUtils.fileExists(document):
+            raise IOError("File not found: %r" % document)
         else:
-            print("Parsing file: %r" % silecsDocument)
-            return libxml2.parseFile(silecsDocument)
+            print("Parsing file: %r" % document)
+            return libxml2.parseFile(document)
 
     def _saveFile(self, context, silecsDocument):
         with open(silecsDocument, 'w') as fd:
diff --git a/silecs-codegen/src/xml/test/generated_correct/AllTypesFESA.design b/silecs-codegen/src/xml/test/generated_correct/AllTypesFESA.design
index 5d76d01..6d7ee37 100644
--- a/silecs-codegen/src/xml/test/generated_correct/AllTypesFESA.design
+++ b/silecs-codegen/src/xml/test/generated_correct/AllTypesFESA.design
@@ -563,7 +563,7 @@
     <data>
         <device-data>
             <configuration>
-                <field name="parameterFile"><description>ParameterFile of the PLC (*.silecsparam)</description><array type="char"><dim>512</dim></array><default>../../../generated/client/MyControllerName.silecsparam</default></field><field name="plcDeviceLabel"><description>Name of the related SILECS instance within the PLC mapping</description><array type="char"><dim>128</dim></array></field><field name="plcHostName"><description>Hostname of the PLC that contains the related SILECS class device</description><array type="char"><dim>128</dim></array></field><GSI-detailed-status-labels-field name="detailedStatus_labels">
+                <field name="plcDeviceLabel"><description>Name of the related SILECS instance within the PLC mapping</description><array type="char"><dim>128</dim></array></field><field name="plcHostName"><description>Hostname of the PLC that contains the related SILECS class device</description><array type="char"><dim>128</dim></array></field><GSI-detailed-status-labels-field name="detailedStatus_labels">
                     <array2D type="char">
                         <custom-constant-dim1 constant-name-ref="DETAILED_STATUS_SIZE"/>
                         <custom-constant-dim2 constant-name-ref="MAX_DETAILED_STATUS_LABEL_LENGTH"/>
diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/SilecsService.cpp b/silecs-communication-cpp/src/silecs-communication/interface/core/SilecsService.cpp
index d765f08..cf6281c 100644
--- a/silecs-communication-cpp/src/silecs-communication/interface/core/SilecsService.cpp
+++ b/silecs-communication-cpp/src/silecs-communication/interface/core/SilecsService.cpp
@@ -19,6 +19,10 @@
 #include <silecs-communication/interface/utility/StringUtilities.h>
 #include <unistd.h>
 
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+
+
 /* ----------------------------------------------------------------------
  * RELEASE
  * 3.1.0: initial
@@ -70,6 +74,9 @@ namespace Silecs
 	const std::string Service::semverMinor_ = STRINGIFY(MINOR); //Minor release, backward compatible
 	const std::string Service::semverPatch_ = STRINGIFY(PATCH); //Bug fixes, backward compatible
 
+    const std::string Service::paramFilesPath_ = "/dsc/data/silecs/" + Service::semverMajor_ + ".m.p/delivery/";
+    const std::string Service::paramFilesPathFallback_ = "/acc/dsc/oper/data/silecs/" + Service::semverMajor_ + ".m.p/delivery/";
+
 
 } // namespace
 
@@ -207,6 +214,59 @@ namespace Silecs
 		return semverPatch_;
 	}
 
+	const std::string Service::getBinaryFolderPath()
+	{
+		char buf[1024] = {0};
+		ssize_t size = readlink("/proc/self/exe", buf, sizeof(buf));
+		if (size == 0 || size == sizeof(buf))
+		{
+			throw SilecsException(__FILE__, __LINE__, "Failed to get binary folder");
+		}
+		std::string path(buf, size);
+		boost::system::error_code ec;
+		boost::filesystem::path binaryPath( boost::filesystem::canonical( path, boost::filesystem::current_path(), ec));
+		boost::filesystem::path dir = binaryPath.parent_path();
+		return dir.make_preferred().string();
+	}
+
+	const std::string Service::getParamFile( std::string controllerName )
+	{
+		// directly next to the binary, used on GSI frontends
+		std::string localParameterFile1 = getBinaryFolderPath() + "/" + controllerName + ".silecsparam";
+
+		if (access(localParameterFile1.c_str(), F_OK) != -1)
+		{
+			LOG(DEBUG) << "Using local param file: " << localParameterFile1;
+			return localParameterFile1;
+		}
+
+		// if FESA-class is not deployed yet and started on development-system ( used on GSI development-systems )
+		std::string localParameterFile2 = getBinaryFolderPath() + "/../../../generated-silecs/client/"+ controllerName + ".silecsparam";
+		//for debugging printf("localParameterFile2: %s",localParameterFile2.c_str());
+		if (access(localParameterFile2.c_str(), F_OK) != -1)
+		{
+			LOG(DEBUG) << "Using local param file: " << localParameterFile2;
+			return localParameterFile2;
+		}
+
+		std::string globalParameterFile1 = paramFilesPath_ + controllerName + "/params/" + controllerName + ".silecsparam";
+		if (access(globalParameterFile1.c_str(), F_OK) != -1)
+		{
+			LOG(DEBUG) << "Using global param file: " << globalParameterFile1;
+			return globalParameterFile1;
+		}
+
+		std::string globalParameterFile2 = paramFilesPathFallback_ + controllerName + "/params/" + controllerName + ".silecsparam";
+		if (access(globalParameterFile2.c_str(), F_OK) != -1)
+		{
+			LOG(DEBUG) << "Using global fallback param file: " << globalParameterFile2;
+			return globalParameterFile2;
+		}
+
+		std::string message = "No parameter-file found for controller '" + controllerName + "'";
+		throw SilecsException(__FILE__, __LINE__, message.c_str());
+	}
+
 	bool Service::withInputAccess(AccessType& accessType)
 	{ return (accessType != Output);
 	}
diff --git a/silecs-communication-cpp/src/silecs-communication/interface/core/SilecsService.h b/silecs-communication-cpp/src/silecs-communication/interface/core/SilecsService.h
index ea98f9b..71b4d68 100644
--- a/silecs-communication-cpp/src/silecs-communication/interface/core/SilecsService.h
+++ b/silecs-communication-cpp/src/silecs-communication/interface/core/SilecsService.h
@@ -129,6 +129,12 @@ namespace Silecs
          */
 		static std::string getSemverPatch();
 
+        /*!
+         * \brief get the parameter-file for this controller
+         * \return path to the parameter-file
+         */
+		static const std::string getParamFile( std::string controllerName );
+
         /*!
          * \brief Use this method to propagate the input arguments to the SILECS library (-plcLog in particular)
          */
@@ -154,7 +160,9 @@ namespace Silecs
 		std::string whichArgs();
 		void printArgs();
 
-		static const std::string getParamsFilesPath();
+		// returns folder of the binary which currently uses this library
+		static const std::string getBinaryFolderPath();
+
 		static bool withInputAccess(AccessType& accessType);
 		static bool withOutputAccess(AccessType& accessType);
 		static bool fileExists(std::string filename);
@@ -170,6 +178,9 @@ namespace Silecs
 		static const std::string semverMinor_; //Minor release, backward compatible
 		static const std::string semverPatch_; //Bug fixes, backward compatible
 
+		static const std::string paramFilesPath_; // Location of all parameter-files (CERN-only)
+		static const std::string paramFilesPathFallback_; // Fallback-Location of all parameter-files (CERN-only)
+
 		static bool isShutingDown_;
 	};
 
diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.h
index 2d523ec..d88f998 100644
--- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.h
+++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsCluster.h
@@ -106,10 +106,10 @@ namespace Silecs
          * The related class/version must be deployed in that PLC (else generate an Exception).
          * The PLC connection is disabled for the time being.
          * \param plcID host-name or IP-address of the PLC
-         * \param parameterFile parameterFile whixch should be used to configure this PLC
+         * \param parameterFile optional parameterFile which should be used to configure this PLC
          * \return Reference of the PLC object
          */
-		PLC* getPLC(std::string plcID, string parameterFile);
+		PLC* getPLC(std::string plcID, string parameterFile = "");
 
         /*!
          * \brief Provides the list of the PLCs attached to the Cluster (using getPLC() method)
diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.cpp b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.cpp
index b73be2e..b0251dd 100644
--- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.cpp
+++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.cpp
@@ -50,6 +50,9 @@ namespace Silecs
 
 			LOG(ALLOC) << "PLC (create): " << name_ << "/ " << IPaddr_;
 
+			if( parameterFile_.empty() )
+				parameterFile_ = Service::getParamFile(plcName);
+
 			// Upload the parameters file and build the PLC configuration
 			extractDatabase();
 
diff --git a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.h b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.h
index b3327be..8af5ed6 100644
--- a/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.h
+++ b/silecs-communication-cpp/src/silecs-communication/interface/equipment/SilecsPLC.h
@@ -382,7 +382,7 @@ namespace Silecs
         friend class CNVSendBlockMode;
         friend class CNVSendDeviceMode;
 
-		PLC(Cluster* theCluster, std::string plcName, std::string plcIPaddr, string parameterFile);
+		PLC(Cluster* theCluster, std::string plcName, std::string plcIPaddr, string parameterFile = "");
 		virtual ~PLC();
 
 		inline PLCBrand& getBrandID() { return brandID_; }
diff --git a/silecs-diagnostic-cpp/Makefile.dep b/silecs-diagnostic-cpp/Makefile.dep
index 70ecd1f..ba8078f 100644
--- a/silecs-diagnostic-cpp/Makefile.dep
+++ b/silecs-diagnostic-cpp/Makefile.dep
@@ -1,3 +1,4 @@
+CPU ?=x86_64
 BOOST_VERSION ?= 1.54.0
 RBAC_VERSION ?= 6.1.0
 SILECS_COMM_VERSION = 1.0.2
@@ -26,6 +27,7 @@ DEPENDENT_COMPILER_OPTIONS += -I/usr/include/QtGui
 DEPENDENT_LINKER_OPTIONS += -L$(RBACK_HOME)/lib
 DEPENDENT_LINKER_OPTIONS += -L$(SILECS_COMM_HOME)/lib/$(CPU)
 DEPENDENT_LINKER_OPTIONS += -L$(SNAP7_BASE)/build/bin/$(CPU)-linux -lsnap7
+DEPENDENT_LINKER_OPTIONS += -L$(BOOST_HOME)/lib/$(CPU)
 DEPENDENT_LINKER_OPTIONS += -L/usr/lib64 -lxml2
 DEPENDENT_LINKER_OPTIONS += -lsilecs-comm
-DEPENDENT_LINKER_OPTIONS += -lstdc++ -lxml2 -lcurl -lQtGui -lQtCore
+DEPENDENT_LINKER_OPTIONS += -lstdc++ -lxml2 -lboost_system -lboost_filesystem -lcurl -lQtGui -lQtCore
-- 
GitLab