|
1 import wx |
|
2 import os |
|
3 from xml.dom import minidom |
|
4 import cPickle |
|
5 |
|
6 from xmlclass import * |
|
7 |
|
8 from ConfigTree import ConfigTreeNode, opjimg |
|
9 from CFileEditor import CFileEditor |
|
10 from PLCControler import PLCControler, UndoBuffer, LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY |
|
11 |
|
12 CFileClasses = GenerateClassesFromXSD(os.path.join(os.path.dirname(__file__), "cext_xsd.xsd")) |
|
13 |
|
14 TYPECONVERSION = {"BOOL" : "X", "SINT" : "B", "INT" : "W", "DINT" : "D", "LINT" : "L", |
|
15 "USINT" : "B", "UINT" : "W", "UDINT" : "D", "ULINT" : "L", "REAL" : "D", "LREAL" : "L", |
|
16 "STRING" : "B", "BYTE" : "B", "WORD" : "W", "DWORD" : "D", "LWORD" : "L", "WSTRING" : "W"} |
|
17 |
|
18 class _Cfile: |
|
19 XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?> |
|
20 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> |
|
21 <xsd:element name="CExtension"> |
|
22 <xsd:complexType> |
|
23 <xsd:attribute name="CFLAGS" type="xsd:string" use="required"/> |
|
24 <xsd:attribute name="LDFLAGS" type="xsd:string" use="required"/> |
|
25 </xsd:complexType> |
|
26 </xsd:element> |
|
27 </xsd:schema> |
|
28 """ |
|
29 EditorType = CFileEditor |
|
30 |
|
31 def __init__(self): |
|
32 filepath = self.CFileName() |
|
33 |
|
34 self.CFile = CFileClasses["CFile"]() |
|
35 if os.path.isfile(filepath): |
|
36 xmlfile = open(filepath, 'r') |
|
37 tree = minidom.parse(xmlfile) |
|
38 xmlfile.close() |
|
39 |
|
40 for child in tree.childNodes: |
|
41 if child.nodeType == tree.ELEMENT_NODE and child.nodeName == "CFile": |
|
42 self.CFile.loadXMLTree(child, ["xmlns", "xmlns:xsi", "xsi:schemaLocation"]) |
|
43 self.CreateCFileBuffer(True) |
|
44 else: |
|
45 self.CreateCFileBuffer(False) |
|
46 self.OnPlugSave() |
|
47 |
|
48 def CFileName(self): |
|
49 return os.path.join(self.PlugPath(), "cfile.xml") |
|
50 |
|
51 def GetBaseTypes(self): |
|
52 return self.GetPlugRoot().GetBaseTypes() |
|
53 |
|
54 def GetDataTypes(self, basetypes = False, only_locatables = False): |
|
55 return self.GetPlugRoot().GetDataTypes(basetypes=basetypes, only_locatables=only_locatables) |
|
56 |
|
57 def GetSizeOfType(self, type): |
|
58 return TYPECONVERSION.get(self.GetPlugRoot().GetBaseType(type), None) |
|
59 |
|
60 def SetVariables(self, variables): |
|
61 self.CFile.variables.setvariable([]) |
|
62 for var in variables: |
|
63 variable = CFileClasses["variables_variable"]() |
|
64 variable.setname(var["Name"]) |
|
65 variable.settype(var["Type"]) |
|
66 variable.setclass(var["Class"]) |
|
67 self.CFile.variables.appendvariable(variable) |
|
68 |
|
69 def GetVariables(self): |
|
70 datas = [] |
|
71 for var in self.CFile.variables.getvariable(): |
|
72 datas.append({"Name" : var.getname(), "Type" : var.gettype(), "Class" : var.getclass()}) |
|
73 return datas |
|
74 |
|
75 def GetVariableLocationTree(self): |
|
76 '''See ConfigTreeNode.GetVariableLocationTree() for a description.''' |
|
77 |
|
78 current_location = ".".join(map(str, self.GetCurrentLocation())) |
|
79 |
|
80 vars = [] |
|
81 input = memory = output = 0 |
|
82 for var in self.CFile.variables.getvariable(): |
|
83 var_size = self.GetSizeOfType(var.gettype()) |
|
84 var_location = "" |
|
85 if var.getclass() == "input": |
|
86 var_class = LOCATION_VAR_INPUT |
|
87 if var_size is not None: |
|
88 var_location = "%%I%s%s.%d"%(var_size, current_location, input) |
|
89 input += 1 |
|
90 elif var.getclass() == "memory": |
|
91 var_class = LOCATION_VAR_INPUT |
|
92 if var_size is not None: |
|
93 var_location = "%%M%s%s.%d"%(var_size, current_location, memory) |
|
94 memory += 1 |
|
95 else: |
|
96 var_class = LOCATION_VAR_OUTPUT |
|
97 if var_size is not None: |
|
98 var_location = "%%Q%s%s.%d"%(var_size, current_location, output) |
|
99 output += 1 |
|
100 vars.append({"name": var.getname(), |
|
101 "type": var_class, |
|
102 "size": var_size, |
|
103 "IEC_type": var.gettype(), |
|
104 "var_name": var.getname(), |
|
105 "location": var_location, |
|
106 "description": "", |
|
107 "children": []}) |
|
108 |
|
109 return {"name": self.BaseParams.getName(), |
|
110 "type": LOCATION_CONFNODE, |
|
111 "location": self.GetFullIEC_Channel(), |
|
112 "children": vars} |
|
113 |
|
114 def SetPartText(self, name, text): |
|
115 if name == "Includes": |
|
116 self.CFile.includes.settext(text) |
|
117 elif name == "Globals": |
|
118 self.CFile.globals.settext(text) |
|
119 elif name == "Init": |
|
120 self.CFile.initFunction.settext(text) |
|
121 elif name == "CleanUp": |
|
122 self.CFile.cleanUpFunction.settext(text) |
|
123 elif name == "Retrieve": |
|
124 self.CFile.retrieveFunction.settext(text) |
|
125 elif name == "Publish": |
|
126 self.CFile.publishFunction.settext(text) |
|
127 |
|
128 def GetPartText(self, name): |
|
129 if name == "Includes": |
|
130 return self.CFile.includes.gettext() |
|
131 elif name == "Globals": |
|
132 return self.CFile.globals.gettext() |
|
133 elif name == "Init": |
|
134 return self.CFile.initFunction.gettext() |
|
135 elif name == "CleanUp": |
|
136 return self.CFile.cleanUpFunction.gettext() |
|
137 elif name == "Retrieve": |
|
138 return self.CFile.retrieveFunction.gettext() |
|
139 elif name == "Publish": |
|
140 return self.CFile.publishFunction.gettext() |
|
141 return "" |
|
142 |
|
143 ConfNodeMethods = [ |
|
144 {"bitmap" : os.path.join("images", "EditCfile"), |
|
145 "name" : _("Edit C File"), |
|
146 "tooltip" : _("Edit C File"), |
|
147 "method" : "_OpenView"}, |
|
148 ] |
|
149 |
|
150 def PlugTestModified(self): |
|
151 return self.ChangesToSave or not self.CFileIsSaved() |
|
152 |
|
153 def OnPlugSave(self): |
|
154 filepath = self.CFileName() |
|
155 |
|
156 text = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n" |
|
157 extras = {"xmlns":"http://www.w3.org/2001/XMLSchema", |
|
158 "xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance", |
|
159 "xsi:schemaLocation" : "cext_xsd.xsd"} |
|
160 text += self.CFile.generateXMLText("CFile", 0, extras) |
|
161 |
|
162 xmlfile = open(filepath,"w") |
|
163 xmlfile.write(text.encode("utf-8")) |
|
164 xmlfile.close() |
|
165 |
|
166 self.MarkCFileAsSaved() |
|
167 return True |
|
168 |
|
169 def PlugGenerate_C(self, buildpath, locations): |
|
170 """ |
|
171 Generate C code |
|
172 @param current_location: Tupple containing confnode IEC location : %I0.0.4.5 => (0,0,4,5) |
|
173 @param locations: List of complete variables locations \ |
|
174 [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...) |
|
175 "NAME" : name of the variable (generally "__IW0_1_2" style) |
|
176 "DIR" : direction "Q","I" or "M" |
|
177 "SIZE" : size "X", "B", "W", "D", "L" |
|
178 "LOC" : tuple of interger for IEC location (0,1,2,...) |
|
179 }, ...] |
|
180 @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND |
|
181 """ |
|
182 current_location = self.GetCurrentLocation() |
|
183 # define a unique name for the generated C file |
|
184 location_str = "_".join(map(str, current_location)) |
|
185 |
|
186 text = "/* Code generated by Beremiz c_ext confnode */\n\n" |
|
187 |
|
188 # Adding includes |
|
189 text += "/* User includes */\n" |
|
190 text += self.CFile.includes.gettext() |
|
191 text += "\n" |
|
192 |
|
193 text += """/* Beremiz c_ext confnode includes */ |
|
194 #ifdef _WINDOWS_H |
|
195 #include "iec_types.h" |
|
196 #else |
|
197 #include "iec_std_lib.h" |
|
198 #endif |
|
199 |
|
200 """ |
|
201 |
|
202 # Adding variables |
|
203 vars = [] |
|
204 inputs = memories = outputs = 0 |
|
205 for variable in self.CFile.variables.variable: |
|
206 var = {"Name" : variable.getname(), "Type" : variable.gettype()} |
|
207 if variable.getclass() == "input": |
|
208 var["location"] = "__I%s%s_%d"%(self.GetSizeOfType(var["Type"]), location_str, inputs) |
|
209 inputs += 1 |
|
210 elif variable.getclass() == "memory": |
|
211 var["location"] = "__M%s%s_%d"%(self.GetSizeOfType(var["Type"]), location_str, memories) |
|
212 memories += 1 |
|
213 else: |
|
214 var["location"] = "__Q%s%s_%d"%(self.GetSizeOfType(var["Type"]), location_str, outputs) |
|
215 outputs += 1 |
|
216 vars.append(var) |
|
217 text += "/* Beremiz c_ext confnode user variables definition */\n" |
|
218 base_types = self.GetPlugRoot().GetBaseTypes() |
|
219 for var in vars: |
|
220 if var["Type"] in base_types: |
|
221 prefix = "IEC_" |
|
222 else: |
|
223 prefix = "" |
|
224 text += "%s%s beremiz%s;\n"%(prefix, var["Type"], var["location"]) |
|
225 text += "%s%s *%s = &beremiz%s;\n"%(prefix, var["Type"], var["location"], var["location"]) |
|
226 text += "/* User variables reference */\n" |
|
227 for var in vars: |
|
228 text += "#define %s beremiz%s\n"%(var["Name"], var["location"]) |
|
229 text += "\n" |
|
230 |
|
231 # Adding user global variables and routines |
|
232 text += "/* User internal user variables and routines */\n" |
|
233 text += self.CFile.globals.gettext() |
|
234 |
|
235 # Adding Beremiz confnode functions |
|
236 text += "/* Beremiz confnode functions */\n" |
|
237 text += "int __init_%s(int argc,char **argv)\n{\n"%location_str |
|
238 text += self.CFile.initFunction.gettext() |
|
239 text += " return 0;\n" |
|
240 text += "\n}\n\n" |
|
241 |
|
242 text += "void __cleanup_%s(void)\n{\n"%location_str |
|
243 text += self.CFile.cleanUpFunction.gettext() |
|
244 text += "\n}\n\n" |
|
245 |
|
246 text += "void __retrieve_%s(void)\n{\n"%location_str |
|
247 text += self.CFile.retrieveFunction.gettext() |
|
248 text += "\n}\n\n" |
|
249 |
|
250 text += "void __publish_%s(void)\n{\n"%location_str |
|
251 text += self.CFile.publishFunction.gettext() |
|
252 text += "\n}\n\n" |
|
253 |
|
254 Gen_Cfile_path = os.path.join(buildpath, "CFile_%s.c"%location_str) |
|
255 cfile = open(Gen_Cfile_path,'w') |
|
256 cfile.write(text) |
|
257 cfile.close() |
|
258 |
|
259 matiec_flags = '"-I%s"'%os.path.abspath(self.GetPlugRoot().GetIECLibPath()) |
|
260 |
|
261 return [(Gen_Cfile_path, str(self.CExtension.getCFLAGS() + matiec_flags))],str(self.CExtension.getLDFLAGS()),True |
|
262 |
|
263 |
|
264 #------------------------------------------------------------------------------- |
|
265 # Current Buffering Management Functions |
|
266 #------------------------------------------------------------------------------- |
|
267 |
|
268 """ |
|
269 Return a copy of the cfile model |
|
270 """ |
|
271 def Copy(self, model): |
|
272 return cPickle.loads(cPickle.dumps(model)) |
|
273 |
|
274 def CreateCFileBuffer(self, saved): |
|
275 self.Buffering = False |
|
276 self.CFileBuffer = UndoBuffer(cPickle.dumps(self.CFile), saved) |
|
277 |
|
278 def BufferCFile(self): |
|
279 self.CFileBuffer.Buffering(cPickle.dumps(self.CFile)) |
|
280 |
|
281 def StartBuffering(self): |
|
282 self.Buffering = True |
|
283 |
|
284 def EndBuffering(self): |
|
285 if self.Buffering: |
|
286 self.CFileBuffer.Buffering(cPickle.dumps(self.CFile)) |
|
287 self.Buffering = False |
|
288 |
|
289 def MarkCFileAsSaved(self): |
|
290 self.EndBuffering() |
|
291 self.CFileBuffer.CurrentSaved() |
|
292 |
|
293 def CFileIsSaved(self): |
|
294 return self.CFileBuffer.IsCurrentSaved() and not self.Buffering |
|
295 |
|
296 def LoadPrevious(self): |
|
297 self.EndBuffering() |
|
298 self.CFile = cPickle.loads(self.CFileBuffer.Previous()) |
|
299 |
|
300 def LoadNext(self): |
|
301 self.CFile = cPickle.loads(self.CFileBuffer.Next()) |
|
302 |
|
303 def GetBufferState(self): |
|
304 first = self.CFileBuffer.IsFirst() and not self.Buffering |
|
305 last = self.CFileBuffer.IsLast() |
|
306 return not first, not last |
|
307 |
|
308 class RootClass: |
|
309 |
|
310 PlugChildsTypes = [("C_File",_Cfile, "C file")] |
|
311 |
|
312 def PlugGenerate_C(self, buildpath, locations): |
|
313 return [],"",False |
|
314 |
|
315 |