1 import wx |
|
2 import os |
1 import os |
3 import modules |
2 from POULibrary import POULibrary |
4 from ConfigTreeNode import ConfigTreeNode, opjimg |
3 from PythonFileCTNMixin import PythonFileCTNMixin |
5 from PLCControler import UndoBuffer |
|
6 from PythonEditor import PythonEditor |
|
7 |
4 |
8 from xml.dom import minidom |
5 class PythonLibrary(POULibrary): |
9 from xmlclass import * |
6 def GetName(self): |
10 import cPickle |
7 return "Python" |
11 |
8 |
12 PythonClasses = GenerateClassesFromXSD(os.path.join(os.path.dirname(__file__), "py_ext_xsd.xsd")) |
9 def GetLibraryPath(self): |
|
10 return os.path.join(os.path.split(__file__)[0], "pous.xml") |
13 |
11 |
14 class PythonCodeTemplate: |
12 def Generate_C(self, buildpath, varlist, IECCFLAGS): |
15 |
|
16 EditorType = PythonEditor |
|
17 |
|
18 def __init__(self): |
|
19 |
|
20 self.ConfNodeMethods.insert(0, |
|
21 {"bitmap" : opjimg("editPYTHONcode"), |
|
22 "name" : _("Edit Python File"), |
|
23 "tooltip" : _("Edit Python File"), |
|
24 "method" : "_OpenView"}, |
|
25 ) |
|
26 |
|
27 filepath = self.PythonFileName() |
|
28 |
|
29 self.PythonCode = PythonClasses["Python"]() |
|
30 if os.path.isfile(filepath): |
|
31 xmlfile = open(filepath, 'r') |
|
32 tree = minidom.parse(xmlfile) |
|
33 xmlfile.close() |
|
34 |
|
35 for child in tree.childNodes: |
|
36 if child.nodeType == tree.ELEMENT_NODE and child.nodeName == "Python": |
|
37 self.PythonCode.loadXMLTree(child, ["xmlns", "xmlns:xsi", "xsi:schemaLocation"]) |
|
38 self.CreatePythonBuffer(True) |
|
39 else: |
|
40 self.CreatePythonBuffer(False) |
|
41 self.OnCTNSave() |
|
42 |
|
43 def ConfNodePath(self): |
|
44 return os.path.join(self.CTNParent.ConfNodePath(), "modules", self.CTNType) |
|
45 |
|
46 def PythonFileName(self): |
|
47 return os.path.join(self.CTNPath(), "py_ext.xml") |
|
48 |
|
49 def GetFilename(self): |
|
50 if self.PythonBuffer.IsCurrentSaved(): |
|
51 return "py_ext" |
|
52 else: |
|
53 return "~py_ext~" |
|
54 |
|
55 def SetPythonCode(self, text): |
|
56 self.PythonCode.settext(text) |
|
57 |
|
58 def GetPythonCode(self): |
|
59 return self.PythonCode.gettext() |
|
60 |
|
61 def CTNTestModified(self): |
|
62 return self.ChangesToSave or not self.PythonIsSaved() |
|
63 |
|
64 def OnCTNSave(self): |
|
65 filepath = self.PythonFileName() |
|
66 |
|
67 text = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n" |
|
68 extras = {"xmlns":"http://www.w3.org/2001/XMLSchema", |
|
69 "xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance", |
|
70 "xsi:schemaLocation" : "py_ext_xsd.xsd"} |
|
71 text += self.PythonCode.generateXMLText("Python", 0, extras) |
|
72 |
|
73 xmlfile = open(filepath,"w") |
|
74 xmlfile.write(text.encode("utf-8")) |
|
75 xmlfile.close() |
|
76 |
|
77 self.MarkPythonAsSaved() |
|
78 return True |
|
79 |
|
80 #------------------------------------------------------------------------------- |
|
81 # Current Buffering Management Functions |
|
82 #------------------------------------------------------------------------------- |
|
83 |
|
84 """ |
|
85 Return a copy of the project |
|
86 """ |
|
87 def Copy(self, model): |
|
88 return cPickle.loads(cPickle.dumps(model)) |
|
89 |
|
90 def CreatePythonBuffer(self, saved): |
|
91 self.Buffering = False |
|
92 self.PythonBuffer = UndoBuffer(cPickle.dumps(self.PythonCode), saved) |
|
93 |
|
94 def BufferPython(self): |
|
95 self.PythonBuffer.Buffering(cPickle.dumps(self.PythonCode)) |
|
96 |
|
97 def StartBuffering(self): |
|
98 self.Buffering = True |
|
99 |
|
100 def EndBuffering(self): |
|
101 if self.Buffering: |
|
102 self.PythonBuffer.Buffering(cPickle.dumps(self.PythonCode)) |
|
103 self.Buffering = False |
|
104 |
|
105 def MarkPythonAsSaved(self): |
|
106 self.EndBuffering() |
|
107 self.PythonBuffer.CurrentSaved() |
|
108 |
|
109 def PythonIsSaved(self): |
|
110 return self.PythonBuffer.IsCurrentSaved() and not self.Buffering |
|
111 |
|
112 def LoadPrevious(self): |
|
113 self.EndBuffering() |
|
114 self.PythonCode = cPickle.loads(self.PythonBuffer.Previous()) |
|
115 |
|
116 def LoadNext(self): |
|
117 self.PythonCode = cPickle.loads(self.PythonBuffer.Next()) |
|
118 |
|
119 def GetBufferState(self): |
|
120 first = self.PythonBuffer.IsFirst() and not self.Buffering |
|
121 last = self.PythonBuffer.IsLast() |
|
122 return not first, not last |
|
123 |
|
124 def _GetClassFunction(name): |
|
125 def GetRootClass(): |
|
126 __import__("py_ext.modules." + name) |
|
127 return getattr(modules, name).RootClass |
|
128 return GetRootClass |
|
129 |
|
130 class RootClass(PythonCodeTemplate): |
|
131 |
|
132 # For root object, available Children Types are modules of the modules packages. |
|
133 CTNChildrenTypes = [(name, _GetClassFunction(name), help) for name, help in zip(modules.__all__,modules.helps)] |
|
134 |
|
135 def ConfNodePath(self): |
|
136 return os.path.join(self.CTNParent.ConfNodePath(), self.CTNType) |
|
137 |
|
138 def CTNGenerate_C(self, buildpath, locations): |
|
139 """ |
|
140 Generate C code |
|
141 @param current_location: Tupple containing confnode IEC location : %I0.0.4.5 => (0,0,4,5) |
|
142 @param locations: List of complete variables locations \ |
|
143 [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...) |
|
144 "NAME" : name of the variable (generally "__IW0_1_2" style) |
|
145 "DIR" : direction "Q","I" or "M" |
|
146 "SIZE" : size "X", "B", "W", "D", "L" |
|
147 "LOC" : tuple of interger for IEC location (0,1,2,...) |
|
148 }, ...] |
|
149 @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND |
|
150 """ |
|
151 current_location = self.GetCurrentLocation() |
|
152 # define a unique name for the generated C file |
|
153 location_str = "_".join(map(lambda x:str(x), current_location)) |
|
154 |
|
155 ctr = self.GetCTRoot() |
|
156 ctr.GetIECProgramsAndVariables() |
|
157 |
13 |
158 plc_python_filepath = os.path.join(os.path.split(__file__)[0], "plc_python.c") |
14 plc_python_filepath = os.path.join(os.path.split(__file__)[0], "plc_python.c") |
159 plc_python_file = open(plc_python_filepath, 'r') |
15 plc_python_file = open(plc_python_filepath, 'r') |
160 plc_python_code = plc_python_file.read() |
16 plc_python_code = plc_python_file.read() |
161 plc_python_file.close() |
17 plc_python_file.close() |
162 python_eval_fb_list = [] |
18 python_eval_fb_list = [] |
163 for v in ctr._VariablesList: |
19 for v in varlist: |
164 if v["vartype"] == "FB" and v["type"] in ["PYTHON_EVAL","PYTHON_POLL"]: |
20 if v["vartype"] == "FB" and v["type"] in ["PYTHON_EVAL","PYTHON_POLL"]: |
165 python_eval_fb_list.append(v) |
21 python_eval_fb_list.append(v) |
166 python_eval_fb_count = max(1, len(python_eval_fb_list)) |
22 python_eval_fb_count = max(1, len(python_eval_fb_list)) |
167 |
23 |
168 # prepare python code |
24 # prepare python code |
169 plc_python_code = plc_python_code % { |
25 plc_python_code = plc_python_code % { "python_eval_fb_count": python_eval_fb_count } |
170 "python_eval_fb_count": python_eval_fb_count, |
|
171 "location": location_str} |
|
172 |
26 |
173 Gen_Pythonfile_path = os.path.join(buildpath, "python_%s.c"%location_str) |
27 Gen_Pythonfile_path = os.path.join(buildpath, "py_ext.c") |
174 pythonfile = open(Gen_Pythonfile_path,'w') |
28 pythonfile = open(Gen_Pythonfile_path,'w') |
175 pythonfile.write(plc_python_code) |
29 pythonfile.write(plc_python_code) |
176 pythonfile.close() |
30 pythonfile.close() |
|
31 |
|
32 return (["py_ext"], [(Gen_Pythonfile_path, IECCFLAGS)], True), "" |
|
33 |
|
34 class PythonFile(PythonFileCTNMixin): |
|
35 def CTNGenerate_C(self, buildpath, locations): |
|
36 current_location = self.GetCurrentLocation() |
|
37 # define a unique name for the generated C file |
|
38 location_str = "_".join(map(lambda x:str(x), current_location)) |
177 |
39 |
178 runtimefile_path = os.path.join(buildpath, "runtime_%s.py"%location_str) |
40 runtimefile_path = os.path.join(buildpath, "runtime_%s.py"%location_str) |
179 runtimefile = open(runtimefile_path, 'w') |
41 runtimefile = open(runtimefile_path, 'w') |
180 runtimefile.write(self.GetPythonCode()) |
42 runtimefile.write(self.GetPythonCode()) |
181 runtimefile.close() |
43 runtimefile.close() |
182 |
44 |
183 matiec_flags = '"-I%s"'%os.path.abspath(self.GetCTRoot().GetIECLibPath()) |
45 return [], "", False, ("runtime_%s.py"%location_str, file(runtimefile_path,"rb")) |
184 |
46 |
185 return [(Gen_Pythonfile_path, matiec_flags)], "", True, ("runtime_%s.py"%location_str, file(runtimefile_path,"rb")) |
|