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 f5709632cd4ceac1c9d92e9f5b3be3d764ccbc89..5ef9b320dc1d5ae3f9ef926f718757a2398fa333 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 4ff978c9d138f611acd25a1b17890c3a2d3e06c1..25224e479e5695380087a2306b96864380654e31 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 2cb7990b013e1a370073370bb363e2239e2ed650..defb913f9e982d987dc407369dd00f8618bc685c 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 819d454d281e0d63694e66a3da0e6e8e9afc5d53..293ede6d03ec16bb2127adbd531b97ff07a54ded 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 b547857ec2d3d729d83ebd6c17ce83b6a846a63a..08688f53a73b24950428ef39fd7b7db5407b0078 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 61590b77a948eb8274a5f19abb810d569d958c0f..8277ab516aa0eff36460e88a82667888bffce966 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 5d76d016bd64b791c36d830596a896bebd06fa9a..6d7ee3735fdcaaa346442e0b4accf3a0765915c7 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 d765f08aef9e66393aa1038eff4e9e9419e7c504..cf6281cb21301b062e3989337705e18c2052a7e8 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 ea98f9b741b6e7e302430c51a3f5721cf0db00e5..71b4d680561b98de23edb3b5532e8871a8c2ff25 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 2d523ec054e269656fa419c3b3c6a20b68b98896..d88f998b65ea5da57568e75e67c42378595d6b1f 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 b73be2e3072a84b8d822974cd459802946a99e5b..b0251ddc30fcb22a93a9890c515f3e2de9c548d1 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 b3327be3673cc99ab5d04b653d780e9c2f688264..8af5ed6156a08b4e0680a7a66be8c669555dd355 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 70ecd1f95315fd7aa207c86ae4f6948b4436f594..ba8078ff7884d7cda5c23889a5cb971e1e81c9f5 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