py_ext/PythonFileCTNMixin.py
author Laurent Bessard
Tue, 14 May 2013 18:43:52 +0200
changeset 1137 c37f8d379ab0
parent 1132 28f96aa9c070
child 1144 21475ee0e688
permissions -rw-r--r--
Merged
import os
from PLCControler import UndoBuffer
from PythonEditor import PythonEditor

from xml.dom import minidom
from xmlclass import GenerateClassesFromXSD
import cPickle

from CodeFileTreeNode import CodeFile

PythonClasses = GenerateClassesFromXSD(os.path.join(os.path.dirname(__file__), "py_ext_xsd.xsd")) 

class PythonFileCTNMixin(CodeFile):
    
    CODEFILE_NAME = "PyFile"
    SECTIONS_NAMES = [
        "globals",
        "init",
        "cleanup",
        "start",
        "stop"]
    EditorType = PythonEditor
    
    def __init__(self):
        CodeFile.__init__(self)
        
        filepath = self.PythonFileName()
        
        python_code = PythonClasses["Python"]()
        if os.path.isfile(filepath):
            xmlfile = open(filepath, 'r')
            tree = minidom.parse(xmlfile)
            xmlfile.close()
            
            for child in tree.childNodes:
                if child.nodeType == tree.ELEMENT_NODE and child.nodeName == "Python":
                    python_code.loadXMLTree(child, ["xmlns", "xmlns:xsi", "xsi:schemaLocation"])
                    self.CodeFile.globals.settext(python_code.gettext())
                    os.remove(filepath)
                    self.CreateCodeFileBuffer(False)
                    self.OnCTNSave()
    
    def CodeFileName(self):
        return os.path.join(self.CTNPath(), "pyfile.xml")
    
    def PythonFileName(self):
        return os.path.join(self.CTNPath(), "py_ext.xml")

    PreSectionsTexts = {}
    PostSectionsTexts = {}
    def GetSection(self,section):
        return self.PreSectionsTexts.get(section,"") + "\n" + \
               getattr(self.CodeFile, section).gettext() + "\n" + \
               self.PostSectionsTexts.get(section,"")
        

    def CTNGenerate_C(self, buildpath, locations):
        current_location = self.GetCurrentLocation()
        # define a unique name for the generated C file
        location_str = "_".join(map(lambda x:str(x), current_location))
        
        
        # Generate Beremiz python runtime variables code
        config = self.GetCTRoot().GetProjectConfigNames()[0]
        variables_str = ""
        for variable in self.CodeFile.variables.variable:
            global_name = "%s_%s" % (config.upper(), variable.getname().upper())
            variables_str += "# global_var:%s python_var:%s type:%s initial:%s\n" % (
                global_name,
                variable.getname(),
                variable.gettype(),
                str(variable.getinitial()))

        # Runtime calls (start, stop, init, and cleanup)
        rtcalls = ""
        for section in self.SECTIONS_NAMES:
            if section != "globals":
                rtcalls += "def _runtime_%s_%s():\n" % (location_str, section)
                sectiontext = self.GetSection(section).strip()
                if sectiontext:
                    rtcalls += '    ' + \
                        sectiontext.strip().replace('\n', '\n    ')+"\n"
                else:
                    rtcalls += "    pass\n\n"
        
        text = """\
#!/usr/bin/env python
# -*- coding: utf-8 -*-
## Code generated by Beremiz python mixin confnode
##        
        
## Code for PLC global variable access
%s
        
## User code in "global" scope
%s

## Beremiz python runtime calls
%s

"""%(   # variables
        variables_str,
        # globals
        self.GetSection("globals"),
        # Beremiz python runtime functions
        rtcalls)

        runtimefile_path = os.path.join(buildpath, 
            "runtime_%s.py"%location_str)
        runtimefile = open(runtimefile_path, 'w')
        runtimefile.write(text.encode('utf-8'))
        runtimefile.close()

        text = """\
/* 
 * Code generated by Beremiz py_ext confnode 
 * for safe global variables access
 */
#include "iec_types_all.h"
"""
        
        # Adding variables
        text += "/* User variables reference */\n"
        for variable in self.CodeFile.variables.variable:
            var_infos = {
                "name": variable.getname(),
                "global": "%s__%s" % (config.upper(),
                                      variable.getname().upper()),
                "type": "__IEC_%s_t" % variable.gettype()}
            text += "extern %(type)s %(global)s;\n" % var_infos
            text += "%(type)s __buffer_%(name)s;\n" % var_infos
        text += "\n"
        
        # Adding Beremiz confnode functions
        text += "/* Beremiz confnode functions */\n"
        text += "int __init_%s(int argc,char **argv)\n{\n"%location_str
        text += "/*TODO*/\n"
        text += "  return 0;\n}\n\n"
        
        text += "void __cleanup_%s(void)\n{\n"%location_str
        text += "/*TODO*/\n"
        text += "\n}\n\n"
        
        text += "void __retrieve_%s(void)\n{\n"%location_str
        text += "/*TODO*/\n"
        text += "\n}\n\n"
        
        text += "void __publish_%s(void)\n{\n"%location_str
        text += "/*TODO*/\n"
        text += "\n}\n\n"
        
        Gen_PyCfile_path = os.path.join(buildpath, "PyCFile_%s.c"%location_str)
        pycfile = open(Gen_PyCfile_path,'w')
        pycfile.write(text)
        pycfile.close()
        
        matiec_flags = '"-I%s"'%os.path.abspath(
            self.GetCTRoot().GetIECLibPath())
        
        return ([(Gen_PyCfile_path, matiec_flags)],
                "",
                False,
                ("runtime_%s.py"%location_str, file(runtimefile_path,"rb")))