197 |
197 |
198 # TODO check if programs need to be declared separately |
198 # TODO check if programs need to be declared separately |
199 # "programs_declarations": "\n".join(["extern %(type)s %(C_path)s;" % |
199 # "programs_declarations": "\n".join(["extern %(type)s %(C_path)s;" % |
200 # p for p in self._ProgramList]), |
200 # p for p in self._ProgramList]), |
201 |
201 |
202 # TODO generate C code to observe/access HMI tree variables |
202 # C code to observe/access HMI tree variables |
203 svghmi_c_filepath = paths.AbsNeighbourFile(__file__, "svghmi.c") |
203 svghmi_c_filepath = paths.AbsNeighbourFile(__file__, "svghmi.c") |
204 svghmi_c_file = open(svghmi_c_filepath, 'r') |
204 svghmi_c_file = open(svghmi_c_filepath, 'r') |
205 svghmi_c_code = svghmi_c_file.read() |
205 svghmi_c_code = svghmi_c_file.read() |
206 svghmi_c_file.close() |
206 svghmi_c_file.close() |
207 svghmi_c_code = svghmi_c_code % { |
207 svghmi_c_code = svghmi_c_code % { |
208 "variable_decl_array": ",\n".join(variable_decl_array), |
208 "variable_decl_array": ",\n".join(variable_decl_array), |
209 "extern_variables_declarations": "\n".join(extern_variables_declarations), |
209 "extern_variables_declarations": "\n".join(extern_variables_declarations), |
210 "buffer_size": buf_index, |
210 "buffer_size": buf_index, |
211 "var_access_code": targets.GetCode("var_access.c"), |
211 "var_access_code": targets.GetCode("var_access.c"), |
212 "PLC_ticktime": self.GetCTRoot().GetTicktime() |
212 "PLC_ticktime": self.GetCTR().GetTicktime() |
213 } |
213 } |
214 |
214 |
215 gen_svghmi_c_path = os.path.join(buildpath, "svghmi.c") |
215 gen_svghmi_c_path = os.path.join(buildpath, "svghmi.c") |
216 gen_svghmi_c = open(gen_svghmi_c_path, 'w') |
216 gen_svghmi_c = open(gen_svghmi_c_path, 'w') |
217 gen_svghmi_c.write(svghmi_c_code) |
217 gen_svghmi_c.write(svghmi_c_code) |
218 gen_svghmi_c.close() |
218 gen_svghmi_c.close() |
219 |
219 |
220 return (["svghmi"], [(gen_svghmi_c_path, IECCFLAGS)], True), "" |
220 # Python based WebSocket HMITree Server |
|
221 svghmiserverfile = open(paths.AbsNeighbourFile(__file__, "svghmi_server.py"), 'r') |
|
222 svghmiservercode = svghmiserverfile.read() |
|
223 svghmiserverfile.close() |
|
224 |
|
225 runtimefile_path = os.path.join(buildpath, "runtime_svghmi.py") |
|
226 runtimefile = open(runtimefile_path, 'w') |
|
227 runtimefile.write(svghmiservercode) |
|
228 runtimefile.close() |
|
229 |
|
230 return ((["svghmi"], [(gen_svghmi_c_path, IECCFLAGS)], True), "", |
|
231 ("runtime_svghmi0.py", open(runtimefile_path, "rb"))) |
221 |
232 |
222 class SVGHMI(object): |
233 class SVGHMI(object): |
223 XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?> |
234 XSD = """<?xml version="1.0" encoding="utf-8" ?> |
224 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> |
235 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> |
225 <xsd:element name="SVGHMI"> |
236 <xsd:element name="SVGHMI"> |
226 <xsd:complexType> |
237 <xsd:complexType> |
227 <xsd:attribute name="enableHTTP" type="xsd:boolean" use="optional" default="false"/> |
238 <xsd:attribute name="enableHTTP" type="xsd:boolean" use="optional" default="false"/> |
228 <xsd:attribute name="bindAddress" type="xsd:string" use="optional" default="localhost"/> |
239 <xsd:attribute name="bindAddress" type="xsd:string" use="optional" default="localhost"/> |
243 "bitmap": "ImportSVG", # should be something different |
254 "bitmap": "ImportSVG", # should be something different |
244 "name": _("Inkscape"), |
255 "name": _("Inkscape"), |
245 "tooltip": _("Edit HMI"), |
256 "tooltip": _("Edit HMI"), |
246 "method": "_StartInkscape" |
257 "method": "_StartInkscape" |
247 }, |
258 }, |
|
259 |
|
260 # TODO : HMITree button |
|
261 # - can drag'n'drop variabes to Inkscape |
|
262 |
248 ] |
263 ] |
249 |
264 |
250 def _getSVGpath(self, project_path=None): |
265 def _getSVGpath(self, project_path=None): |
251 if project_path is None: |
266 if project_path is None: |
252 project_path = self.CTNPath() |
267 project_path = self.CTNPath() |
292 when _generate_softPLC have been called |
307 when _generate_softPLC have been called |
293 @param locations: ignored |
308 @param locations: ignored |
294 @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND |
309 @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND |
295 """ |
310 """ |
296 |
311 |
|
312 location_str = "_".join(map(str, self.GetCurrentLocation())) |
|
313 view_name = self.BaseParams.getName() |
|
314 |
297 svgfile = self._getSVGpath() |
315 svgfile = self._getSVGpath() |
|
316 |
|
317 res = ([], "", False) |
|
318 |
|
319 target_fname = "sghmi_"+location_str+".xhtml" |
|
320 |
|
321 target_path = os.path.join(self._getBuildPath(), target_fname) |
|
322 target_file = open(target_path, 'w') |
|
323 |
298 if os.path.exists(svgfile): |
324 if os.path.exists(svgfile): |
299 |
325 |
300 # TODO : move to __init__ |
326 # TODO : move to __init__ |
301 transform = XSLTransform(os.path.join(ScriptDirectory, "gen_index_xhtml.xslt"), |
327 transform = XSLTransform(os.path.join(ScriptDirectory, "gen_index_xhtml.xslt"), |
302 [("GetSVGGeometry", lambda *_ignored:self.GetSVGGeometry()), |
328 [("GetSVGGeometry", lambda *_ignored:self.GetSVGGeometry()), |
307 svgdom = etree.parse(svgfile) |
333 svgdom = etree.parse(svgfile) |
308 |
334 |
309 # call xslt transform on Inkscape's SVG to generate XHTML |
335 # call xslt transform on Inkscape's SVG to generate XHTML |
310 result = transform.transform(svgdom) |
336 result = transform.transform(svgdom) |
311 |
337 |
|
338 result.write(target_file, encoding="utf-8") |
312 # print(str(result)) |
339 # print(str(result)) |
313 # print(transform.xslt.error_log) |
340 # print(transform.xslt.error_log) |
314 |
341 |
315 # TODO |
342 # TODO |
316 # - Errors on HMI semantics |
343 # - Errors on HMI semantics |
317 # - ... maybe something to have a global view of what is declared in SVG. |
344 # - ... maybe something to have a global view of what is declared in SVG. |
318 |
345 |
319 else: |
346 else: |
320 # TODO : use default svg that expose the HMI tree as-is |
347 # TODO : use default svg that expose the HMI tree as-is |
321 pass |
348 target_file.write("""<!DOCTYPE html> |
322 |
349 <html> |
323 |
350 <body> |
324 res = ([], "", False) |
351 <h1> No SVG file provided </h1> |
325 |
352 </body> |
326 targetpath = os.path.join(self._getBuildPath(), "target.xhtml") |
353 </html> |
327 targetfile = open(targetpath, 'w') |
354 """) |
328 |
355 |
329 # TODO : DOM to string |
356 target_file.close() |
330 targetfile.write("TODO") |
357 |
331 targetfile.close() |
358 runtimefile_path = os.path.join(buildpath, "runtime_svghmi1_%s.py" % location_str) |
332 res += (("target.js", open(targetpath, "rb")),) |
359 runtimefile = open(runtimefile_path, 'w') |
333 |
360 runtimefile.write(""" |
334 # TODO add C code to expose HMI tree variables to shared memory |
361 def _runtime_svghmi1_%(location)s_start(): |
335 # TODO generate a description of shared memory (xml or CSV) |
362 svghmi_root.putChild('%(view_name)s',File('%(xhtml)s')) |
336 # that can be loaded by svghmi QTWeb* app or svghmi server |
363 |
337 |
364 """ % {"location": location_str, |
|
365 "xhtml": target_fname, |
|
366 "view_name": view_name}) |
|
367 |
|
368 runtimefile.close() |
|
369 |
|
370 res += (("runtime_svghmi1_%s.py" % location_str, open(runtimefile_path, "rb")),) |
338 |
371 |
339 return res |
372 return res |
340 |
373 |
341 def _ImportSVG(self): |
374 def _ImportSVG(self): |
342 dialog = wx.FileDialog(self.GetCTRoot().AppFrame, _("Choose a SVG file"), os.getcwd(), "", _("SVG files (*.svg)|*.svg|All files|*.*"), wx.OPEN) |
375 dialog = wx.FileDialog(self.GetCTRoot().AppFrame, _("Choose a SVG file"), os.getcwd(), "", _("SVG files (*.svg)|*.svg|All files|*.*"), wx.OPEN) |