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