svghmi/svghmi.py
branchsvghmi
changeset 2817 45bbfb2e120f
parent 2816 d813ecfe8941
child 2818 65f32c94d7ec
equal deleted inserted replaced
2816:d813ecfe8941 2817:45bbfb2e120f
    55         if nodetype in ["HMI_NODE", "HMI_ROOT"]:
    55         if nodetype in ["HMI_NODE", "HMI_ROOT"]:
    56             self.children = []
    56             self.children = []
    57 
    57 
    58     def pprint(self, indent = 0):
    58     def pprint(self, indent = 0):
    59         res = ">"*indent + pformat(self.__dict__, indent = indent, depth = 1) + "\n"
    59         res = ">"*indent + pformat(self.__dict__, indent = indent, depth = 1) + "\n"
    60         if hasattr(self, "children"): 
    60         if hasattr(self, "children"):
    61             res += "\n".join([child.pprint(indent = indent + 1)
    61             res += "\n".join([child.pprint(indent = indent + 1)
    62                               for child in self.children])
    62                               for child in self.children])
    63             res += "\n"
    63             res += "\n"
    64             
    64 
    65         return res
    65         return res
    66 
    66 
    67     def place_node(self, node):
    67     def place_node(self, node):
    68         best_child = None
    68         best_child = None
    69         known_best_match = 0
    69         known_best_match = 0
    70         for child in self.children : 
    70         for child in self.children:
    71             if child.path is not None:
    71             if child.path is not None:
    72                 in_common = 0
    72                 in_common = 0
    73                 for child_path_item, node_path_item in izip(child.path, node.path):
    73                 for child_path_item, node_path_item in izip(child.path, node.path):
    74                     if child_path_item == node_path_item:
    74                     if child_path_item == node_path_item:
    75                         in_common +=1
    75                         in_common +=1
    80                     best_child = child
    80                     best_child = child
    81         if best_child is not None and best_child.nodetype == "HMI_NODE":
    81         if best_child is not None and best_child.nodetype == "HMI_NODE":
    82             best_child.place_node(node)
    82             best_child.place_node(node)
    83         else:
    83         else:
    84             self.children.append(node)
    84             self.children.append(node)
    85             
    85 
    86     def etree(self, add_hash=False):
    86     def etree(self, add_hash=False):
    87 
    87 
    88         attribs = dict(name=self.name)
    88         attribs = dict(name=self.name)
    89         if self.path is not None:
    89         if self.path is not None:
    90             attribs["path"] = ".".join(self.path)
    90             attribs["path"] = ".".join(self.path)
    95         if add_hash:
    95         if add_hash:
    96             attribs["hash"] = ",".join(map(str,self.hash()))
    96             attribs["hash"] = ",".join(map(str,self.hash()))
    97 
    97 
    98         res = etree.Element(self.nodetype, **attribs)
    98         res = etree.Element(self.nodetype, **attribs)
    99 
    99 
   100         if hasattr(self, "children"): 
   100         if hasattr(self, "children"):
   101             for child_etree in imap(lambda c:c.etree(), self.children):
   101             for child_etree in imap(lambda c:c.etree(), self.children):
   102                 res.append(child_etree)
   102                 res.append(child_etree)
   103 
   103 
   104         return res
   104         return res
   105 
   105 
   106     def traverse(self):
   106     def traverse(self):
   107         yield self
   107         yield self
   108         if hasattr(self, "children"): 
   108         if hasattr(self, "children"):
   109             for c in self.children:
   109             for c in self.children:
   110                 for yoodl in c.traverse():
   110                 for yoodl in c.traverse():
   111                     yield yoodl
   111                     yield yoodl
   112 
   112 
   113 
   113 
   114     def hash(self):
   114     def hash(self):
   115         """ Produce a hash, any change in HMI tree structure change that hash """
   115         """ Produce a hash, any change in HMI tree structure change that hash """
   116         s = hashlib.new('md5')
   116         s = hashlib.new('md5')
   117         self._hash(s)
   117         self._hash(s)
   118         # limit size to HMI_HASH_SIZE as in svghmi.c
   118         # limit size to HMI_HASH_SIZE as in svghmi.c
   119         return map(ord,s.digest())[:8] 
   119         return map(ord,s.digest())[:8]
   120 
   120 
   121     def _hash(self, s):
   121     def _hash(self, s):
   122         s.update(str((self.name,self.nodetype)))
   122         s.update(str((self.name,self.nodetype)))
   123         if hasattr(self, "children"): 
   123         if hasattr(self, "children"):
   124             for c in self.children:
   124             for c in self.children:
   125                 c._hash(s)
   125                 c._hash(s)
   126 
   126 
   127 # module scope for HMITree root
   127 # module scope for HMITree root
   128 # so that CTN can use HMITree deduced in Library
   128 # so that CTN can use HMITree deduced in Library
   129 # note: this only works because library's Generate_C is 
   129 # note: this only works because library's Generate_C is
   130 #       systematicaly invoked before CTN's CTNGenerate_C
   130 #       systematicaly invoked before CTN's CTNGenerate_C
   131 
   131 
   132 hmi_tree_root = None
   132 hmi_tree_root = None
   133 
   133 
   134 hmi_tree_updated = None
   134 on_hmitree_update = None
   135 
   135 
   136 class SVGHMILibrary(POULibrary):
   136 class SVGHMILibrary(POULibrary):
   137     def GetLibraryPath(self):
   137     def GetLibraryPath(self):
   138          return paths.AbsNeighbourFile(__file__, "pous.xml")
   138          return paths.AbsNeighbourFile(__file__, "pous.xml")
   139 
   139 
   140     def Generate_C(self, buildpath, varlist, IECCFLAGS):
   140     def Generate_C(self, buildpath, varlist, IECCFLAGS):
   141         global hmi_tree_root, hmi_tree_updated, hmi_tree_unique_id 
   141         global hmi_tree_root, on_hmitree_update, hmi_tree_unique_id
   142 
   142 
   143         """
   143         """
   144         PLC Instance Tree:
   144         PLC Instance Tree:
   145           prog0
   145           prog0
   146            +->v1 HMI_INT
   146            +->v1 HMI_INT
   177         # Filter known HMI types
   177         # Filter known HMI types
   178         hmi_types_instances = [v for v in varlist if v["derived"] in HMI_TYPES]
   178         hmi_types_instances = [v for v in varlist if v["derived"] in HMI_TYPES]
   179 
   179 
   180         hmi_tree_root = HMITreeNode(None, "/", "HMI_ROOT")
   180         hmi_tree_root = HMITreeNode(None, "/", "HMI_ROOT")
   181 
   181 
   182         # add special nodes 
   182         # add special nodes
   183         map(lambda (n,t): hmi_tree_root.children.append(HMITreeNode(None,n,t)), [
   183         map(lambda (n,t): hmi_tree_root.children.append(HMITreeNode(None,n,t)), [
   184                 ("plc_status", "HMI_PLC_STATUS"),
   184                 ("plc_status", "HMI_PLC_STATUS"),
   185                 ("current_page", "HMI_CURRENT_PAGE")])
   185                 ("current_page", "HMI_CURRENT_PAGE")])
   186 
   186 
   187         # deduce HMI tree from PLC HMI_* instances
   187         # deduce HMI tree from PLC HMI_* instances
   198             else:
   198             else:
   199                 name = path[-1]
   199                 name = path[-1]
   200             new_node = HMITreeNode(path, name, derived, v["type"], v["vartype"], **kwargs)
   200             new_node = HMITreeNode(path, name, derived, v["type"], v["vartype"], **kwargs)
   201             hmi_tree_root.place_node(new_node)
   201             hmi_tree_root.place_node(new_node)
   202 
   202 
   203         if hmi_tree_updated is not None:
   203         if on_hmitree_update is not None:
   204             hmi_tree_updated()
   204             on_hmitree_update()
   205 
   205 
   206         variable_decl_array = []
   206         variable_decl_array = []
   207         extern_variables_declarations = []
   207         extern_variables_declarations = []
   208         buf_index = 0
   208         buf_index = 0
   209         item_count = 0
   209         item_count = 0
   241         # C code to observe/access HMI tree variables
   241         # C code to observe/access HMI tree variables
   242         svghmi_c_filepath = paths.AbsNeighbourFile(__file__, "svghmi.c")
   242         svghmi_c_filepath = paths.AbsNeighbourFile(__file__, "svghmi.c")
   243         svghmi_c_file = open(svghmi_c_filepath, 'r')
   243         svghmi_c_file = open(svghmi_c_filepath, 'r')
   244         svghmi_c_code = svghmi_c_file.read()
   244         svghmi_c_code = svghmi_c_file.read()
   245         svghmi_c_file.close()
   245         svghmi_c_file.close()
   246         svghmi_c_code = svghmi_c_code % { 
   246         svghmi_c_code = svghmi_c_code % {
   247             "variable_decl_array": ",\n".join(variable_decl_array),
   247             "variable_decl_array": ",\n".join(variable_decl_array),
   248             "extern_variables_declarations": "\n".join(extern_variables_declarations),
   248             "extern_variables_declarations": "\n".join(extern_variables_declarations),
   249             "buffer_size": buf_index,
   249             "buffer_size": buf_index,
   250             "item_count": item_count,
   250             "item_count": item_count,
   251             "var_access_code": targets.GetCode("var_access.c"),
   251             "var_access_code": targets.GetCode("var_access.c"),
   443             # call xslt transform on Inkscape's SVG to generate XHTML
   443             # call xslt transform on Inkscape's SVG to generate XHTML
   444             try:
   444             try:
   445                 result = transform.transform(svgdom)
   445                 result = transform.transform(svgdom)
   446             except XSLTApplyError as e:
   446             except XSLTApplyError as e:
   447                 self.FatalError("SVGHMI " + view_name  + ": " + e.message)
   447                 self.FatalError("SVGHMI " + view_name  + ": " + e.message)
   448            
   448 
   449             result.write(target_file, encoding="utf-8")
   449             result.write(target_file, encoding="utf-8")
   450             # print(str(result))
   450             # print(str(result))
   451             # print(transform.xslt.error_log)
   451             # print(transform.xslt.error_log)
   452 
   452 
   453             # TODO
   453             # TODO
   454             #   - Errors on HMI semantics
   454             #   - Errors on HMI semantics
   455             #   - ... maybe something to have a global view of what is declared in SVG.
   455             #   - ... maybe something to have a global view of what is declared in SVG.
   456 
   456 
   457         else:
   457         else:
   458             # TODO : use default svg that expose the HMI tree as-is 
   458             # TODO : use default svg that expose the HMI tree as-is
   459             target_file.write("""<!DOCTYPE html>
   459             target_file.write("""<!DOCTYPE html>
   460 <html>
   460 <html>
   461 <body>
   461 <body>
   462 <h1> No SVG file provided </h1>
   462 <h1> No SVG file provided </h1>
   463 </body>
   463 </body>