#!/usr/bin/python # Copyright 2016 CERN and GSI # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. import os import sys import time import zlib import glob import re import datetime import socket import iecommon import fesaTemplates import fesaGeneral import iefiles from iecommon import * from fesaGeneral import * import libxml2 def findBlockServerSetActionName(fesaRoot, blockName): properties = fesaRoot.xpathEval("/equipment-model/interface/device-interface/*/*[@name='" + blockName + "']") for property in properties: return property.xpathEval("set-action/server-action-ref")[0].prop("server-action-name-ref") raise Exception("Error: Server Action for Block '" + blockName + "' not found") #------------------------------------------------------------------------- # Generates the H source file containing general methods # to synchronise the FESA fields and related PLC registers # of the FESA server #------------------------------------------------------------------------- def genHSource(className, silecsRoot, fesaRoot, sourcePath,logTopics): source = fesaTemplates.genHTop(className) for block in silecsRoot.xpathEval('//Block'): if block.prop('mode') == 'WRITE-ONLY' or block.prop('mode') == 'READ-WRITE': serverActionName = findBlockServerSetActionName(fesaRoot,getFesaName(block)) source += fesaTemplates.genHTopBlock(className, serverActionName) source += fesaTemplates.genHTop2(className) for block in silecsRoot.xpathEval('//Block'): if block.prop('mode') == 'READ-ONLY': source += fesaTemplates.genHBlock('RO', block.prop('name'),getFesaName(block) ) elif block.prop('mode') == 'WRITE-ONLY': source += fesaTemplates.genHBlock('WO', block.prop('name'),getFesaName(block)) else: # READ-WRITE source += fesaTemplates.genHBlock('RW', block.prop('name'),getFesaName(block)) source += fesaTemplates.genHBottom(className) for block in silecsRoot.xpathEval('//Block'): source += fesaTemplates.genHDeclBlocks(block.prop('name')) source += fesaTemplates.genHClosing(className) # Create output directory if necessary if not os.path.exists(sourcePath): os.makedirs(sourcePath) iecommon.logDebug("Create directory %s" %sourcePath, logTopics) # Write to file and save sourceFile = sourcePath + "/"+ className + ".h" iecommon.logInfo("Generate header file: " + sourceFile, logTopics) fdesc = open(sourceFile, "w") fdesc.write(source) fdesc.close() iecommon.logInfo('Header file for '+className+' generated successfully', logTopics) #------------------------------------------------------------------------- # Generates the C++ source file containing general # methods to synchronise the FESA fields and related PLC # registers of the FESA server #------------------------------------------------------------------------- def genCppSource(className, silecsRoot, fesaRoot, sourcePath,logTopics): finalSource = fesaTemplates.genCTop(className) blockList = silecsRoot.xpathEval('//Block') for block in blockList: finalSource += fesaTemplates.genCGlobal(className, block.prop('name')) finalSource += fesaTemplates.genCPart1(className) for block in blockList: finalSource += fesaTemplates.genCBlockConstr(block.prop('name'), className) finalSource += fesaTemplates.genCPart2(className) for block in blockList: regList = block.xpathEval('Register') if (block.prop('mode') == 'WRITE-ONLY' or block.prop('mode') == 'READ-WRITE') and regList[0].prop('synchro') == 'SLAVE': # just set the fields if block is WO or RW and register synchronisation is SLAVE # WARNING: In order to have multiplexed FESA fields, the corresponding SILECS registers' synchro mode must be 'NONE' finalSource += fesaTemplates.genCSetPLC(className, block.prop('name')) finalSource += fesaTemplates.genCPart3(className) for block in blockList: regList = block.xpathEval('Register') if (block.prop('mode') == 'READ-ONLY' or block.prop('mode') == 'READ-WRITE') and regList[0].prop('synchro') == 'MASTER': # just get the fields if block is RO or RW and register synchronisation is MASTER # WARNING: In order to have multiplexed FESA fields, the corresponding SILECS registers' synchro mode must be 'NONE' finalSource += fesaTemplates.genCGetPLC(className, block.prop('name')) finalSource += fesaTemplates.genCPart4(className) for block in blockList: source = '' #compute one source at a time flagReg = False flagDim1 = False flagDim2 = False if block.prop('mode') != 'WRITE-ONLY': finalSource += fesaTemplates.genCCommonGet(block.prop('name'),className) regList = block.xpathEval('Register') source += fesaTemplates.cRecv for reg in regList: type = reg.prop('format') if type == 'string': # string register flagReg = True if (reg.prop('array-dim1')) and int(reg.prop('array-dim1')) > 1: # string array flagDim1 = True source += fesaTemplates.genCGetStringArrayReg(reg.prop('name'), getFesaName(reg)) else: # simple string source += fesaTemplates.genCGetStringReg(reg.prop('name'), getFesaName(reg)) else: # not string register # uppercasing of type fesaType = iecommon.getFesaDataType(type) type = iecommon.getSilecsDataType(type) if type[0] == 'u': type = type[:2].upper() + type[2:] # first two characters if unsigned if reg.prop('array-dim2') and int(reg.prop('array-dim2')) > 1: # 2D array flagReg = True flagDim2 = True flagDim1 = True source += fesaTemplates.genCGetUnsignedArray2DReg(reg.prop('name'), getFesaName(reg), fesaType, type) elif (reg.prop('array-dim1')) and int(reg.prop('array-dim1')) > 1: # array flagReg = True flagDim1 = True source += fesaTemplates.genCGetUnsignedArrayReg(reg.prop('name'), getFesaName(reg), fesaType, type) else: # scalar source += fesaTemplates.genCGetScalarReg(reg.prop('name'), getFesaName(reg), type) elif type[0] == 'd': # date type if reg.prop('array-dim2') and int(reg.prop('array-dim2')) > 1: flagReg = True flagDim2 = True flagDim1 = True source += fesaTemplates.genCGetArray2DReg(reg.prop('name'), getFesaName(reg), 'Date') elif (reg.prop('array-dim1')) and int(reg.prop('array-dim1')) > 1: # array flagReg = True flagDim1 = True source += fesaTemplates.genCGetArrayReg(reg.prop('name'), getFesaName(reg), 'Date') else: # scalar source += fesaTemplates.genCGetScalarReg(reg.prop('name'), getFesaName(reg), 'Date') else: type = type[:1].upper() + type[1:] # only first character if not unsigned if reg.prop('array-dim2') and int(reg.prop('array-dim2')) > 1: # 2D array flagReg = True flagDim2 = True flagDim1 = True source += fesaTemplates.genCGetArray2DReg(reg.prop('name'), getFesaName(reg), type) elif (reg.prop('array-dim1')) and int(reg.prop('array-dim1')) > 1: # array flagReg = True flagDim1 = True source += fesaTemplates.genCGetArrayReg(reg.prop('name'), getFesaName(reg), type) else: # scalar source += fesaTemplates.genCGetScalarReg(reg.prop('name'), getFesaName(reg), type) source += '\n\t}' # closing bracket for block #Add data declatation on top if needed and append the final source if flagReg == True: finalSource += fesaTemplates.cRegVar if flagDim1 == True: finalSource += fesaTemplates.cGetArrayVar if flagDim2 == True: finalSource += fesaTemplates.cGetArray2DVar finalSource += '\n' + source source = '' #compute one source at a time flagReg = False flagDim1 = False flagDim2 = False if block.prop('mode') != 'READ-ONLY': finalSource += fesaTemplates.genCCommonSet(block.prop('name'),className) regList = block.xpathEval('Register') for reg in regList: type = reg.prop('format') if type == 'string': flagReg = True if (reg.prop('array-dim1')) and int(reg.prop('array-dim1')) > 1: # string array flagDim1 = True source += fesaTemplates.genCSetStringArrayReg(reg.prop('name'), getFesaName(reg)) else: # simple string source += fesaTemplates.genCSetStringReg(reg.prop('name'), getFesaName(reg)) else: # not string register # uppercasing of type type = iecommon.getSilecsDataType(type) lowerType = type+'_t' # store lowercase type for unsigned registers (fesa type) if type[0] == 'u': # unsigned type type = type[:2].upper() + type[2:] # first two characters if unsigned if reg.prop('array-dim2') and int(reg.prop('array-dim2')) > 1: # 2D array flagReg = True flagDim2 = True flagDim1 = True source += fesaTemplates.genCSetUnsignedArray2DReg(reg.prop('name'), getFesaName(reg), type) elif (reg.prop('array-dim1')) and int(reg.prop('array-dim1')) > 1: # array flagReg = True flagDim1 = True source += fesaTemplates.genCSetUnsignedArrayReg(reg.prop('name'), getFesaName(reg), type) else: # scalar source += fesaTemplates.genCSetScalarUReg(reg.prop('name'), getFesaName(reg), type, lowerType) else: # signed type type = type[:1].upper() + type[1:] # only first character if not unsigned if reg.prop('array-dim2') and int(reg.prop('array-dim2')) > 1: # 2D array flagReg = True flagDim2 = True flagDim1 = True source += fesaTemplates.genCSetArray2DReg(reg.prop('name'), getFesaName(reg), type) elif (reg.prop('array-dim1')) and int(reg.prop('array-dim1')) > 1: # array flagReg = True flagDim1 = True source += fesaTemplates.genCSetArrayReg(reg.prop('name'), getFesaName(reg), type) else: # scalar source += fesaTemplates.genCSetScalarReg(reg.prop('name'), getFesaName(reg), type) source += fesaTemplates.cSend source += '\n\t}' # closing bracket for block #Add data declatation on top if needed and append the final source if flagReg == True: finalSource += fesaTemplates.cRegVar if flagDim1 == True: finalSource += fesaTemplates.cSetArrayVar if flagDim2 == True: finalSource += fesaTemplates.cSetArray2DVar finalSource += '\n' + source source = '' #compute one source at a time flagReg = False flagDim1 = False flagDim2 = False finalSource += fesaTemplates.genCDatatypeSet(block.prop('name'),getFesaName(block), className) regList = block.xpathEval('Register') for reg in regList: type = reg.prop('format') if type == 'string': flagReg = True if (reg.prop('array-dim1')) and int(reg.prop('array-dim1')) > 1: # string array flagDim1 = True source += fesaTemplates.genCSetStringArrayRegData(reg.prop('name'), getFesaName(reg)) else: # simple string source += fesaTemplates.genCSetStringRegData(reg.prop('name'), getFesaName(reg)) else: # not string register # uppercasing of type fesaType = iecommon.getFesaDataType(type) type = iecommon.getSilecsDataType(type) lowerType = type+'_t' # store lowercase type for unsigned registers (fesa type) if type[0] == 'u': # unsigned type type = type[:2].upper() + type[2:] # first two characters if unsigned if reg.prop('array-dim2') and int(reg.prop('array-dim2')) > 1: # 2D array flagReg = True flagDim2 = True flagDim1 = True source += fesaTemplates.genCSetUnsignedArray2DRegData(reg.prop('name'), getFesaName(reg), fesaType, type) elif (reg.prop('array-dim1')) and int(reg.prop('array-dim1')) > 1: # array flagReg = True flagDim1 = True source += fesaTemplates.genCSetUnsignedArrayRegData(reg.prop('name'), getFesaName(reg), type) else: # scalar source += fesaTemplates.genCSetScalarURegData(reg.prop('name'), getFesaName(reg), type, lowerType) else: # signed type type = type[:1].upper() + type[1:] # only first character if not unsigned if reg.prop('array-dim2') and int(reg.prop('array-dim2')) > 1: # 2D array flagReg = True flagDim2 = True flagDim1 = True source += fesaTemplates.genCSetArray2DRegData(reg.prop('name'), getFesaName(reg), fesaType, type) elif (reg.prop('array-dim1')) and int(reg.prop('array-dim1')) > 1: # array flagReg = True flagDim1 = True source += fesaTemplates.genCSetArrayRegData(reg.prop('name'), getFesaName(reg), type) else: # scalar source += fesaTemplates.genCSetScalarRegData(reg.prop('name'), getFesaName(reg), type) source += fesaTemplates.cSend source += '\n\t}' # closing bracket for block #Add data declatation on top if needed and append the final source if flagReg == True: finalSource += fesaTemplates.cRegVar if flagDim1 == True: finalSource += fesaTemplates.cSetArrayVar if flagDim2 == True: finalSource += fesaTemplates.cSetArray2DVar finalSource += '\n' + source finalSource += '\n}\n' # closing bracket for class # Write to file and save sourceFile = sourcePath + "/" + className + ".cpp" iecommon.logInfo("Generate source file: " + sourceFile, logTopics) fdesc = open(sourceFile, "w") fdesc.write(finalSource) fdesc.close() iecommon.logInfo('Source file for '+className+' generated successfully', logTopics) def genCppFiles(className, workspacePath, silecsDesignFilePath,logTopics={'errorlog': True}): fesaCommonDirectory = iefiles.getFesa3CommonDirectory(workspacePath,className) iecommon.logInfo("fesaCommonDirectory:" + fesaCommonDirectory,logTopics) if not os.path.exists(fesaCommonDirectory ): os.makedirs(fesaCommonDirectory) silecsDesignFilePath = iefiles.getSilecsDesignFilePath(workspacePath,className) fesaDesignFilePath = workspacePath + "/" + className + "/src/" + className + ".design" silecsRoot = libxml2.parseFile(silecsDesignFilePath) fesaRoot = libxml2.parseFile(fesaDesignFilePath) genHSource(className, silecsRoot, fesaRoot, fesaCommonDirectory,logTopics) genCppSource(className, silecsRoot, fesaRoot, fesaCommonDirectory,logTopics)