py_ext/PythonFileCTNMixin.py
author Edouard Tisserant
Tue, 14 May 2013 18:41:33 +0900
changeset 1132 28f96aa9c070
parent 1124 b1705000eba1
child 1144 21475ee0e688
permissions -rw-r--r--
Rewrote py_ext and wxglade generators in a clean factored way, added C skeleton for python access to PLC global vars
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")))