SVGHMI: Work In Progress : fixed pointer types in ctypes interface, cleaned up server startup and cleanup code, changed document type to XHTML, cleaner JS script : encapsulated in a function and in CDATA. svghmi
authorEdouard Tisserant
Wed, 18 Sep 2019 11:09:35 +0200
branchsvghmi
changeset 2779 75c6a31caca6
parent 2778 cdf23b10b8f7
child 2780 e468f18df200
SVGHMI: Work In Progress : fixed pointer types in ctypes interface, cleaned up server startup and cleanup code, changed document type to XHTML, cleaner JS script : encapsulated in a function and in CDATA.
svghmi/gen_index_xhtml.xslt
svghmi/gen_index_xhtml.ysl2
svghmi/svghmi.c
svghmi/svghmi.py
svghmi/svghmi_server.py
--- a/svghmi/gen_index_xhtml.xslt	Wed Sep 18 11:03:56 2019 +0200
+++ b/svghmi/gen_index_xhtml.xslt	Wed Sep 18 11:09:35 2019 +0200
@@ -1,6 +1,6 @@
 <?xml version="1.0"?>
-<xsl:stylesheet xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns:exsl="http://exslt.org/common" xmlns:ns="beremiz" xmlns:cc="http://creativecommons.org/ns#" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dc="http://purl.org/dc/elements/1.1/" extension-element-prefixes="ns" version="1.0" exclude-result-prefixes="ns">
-  <xsl:output method="xml"/>
+<xsl:stylesheet xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/1999/xhtml" xmlns:exsl="http://exslt.org/common" xmlns:ns="beremiz" xmlns:cc="http://creativecommons.org/ns#" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dc="http://purl.org/dc/elements/1.1/" extension-element-prefixes="ns" version="1.0" exclude-result-prefixes="ns">
+  <xsl:output method="xml" cdata-section-elements="script"/>
   <xsl:variable name="geometry" select="ns:GetSVGGeometry()"/>
   <xsl:variable name="hmitree" select="ns:GetHMITree()"/>
   <xsl:template match="@* | node()">
@@ -9,17 +9,44 @@
     </xsl:copy>
   </xsl:template>
   <xsl:template match="/">
-    <xsl:copy>
-      <xsl:comment>
-        <xsl:apply-templates mode="testgeo" select="$geometry"/>
-      </xsl:comment>
-      <xsl:comment>
-        <xsl:text>blah
+    <html xmlns="http://www.w3.org/1999/xhtml">
+      <head/>
+      <body style="margin:0;">
+        <xsl:copy>
+          <xsl:comment>
+            <xsl:apply-templates mode="testgeo" select="$geometry"/>
+          </xsl:comment>
+          <xsl:comment>
+            <xsl:apply-templates mode="testtree" select="$hmitree"/>
+          </xsl:comment>
+          <xsl:apply-templates select="@* | node()"/>
+        </xsl:copy>
+        <script>
+          <xsl:text>(function(){
 </xsl:text>
-        <xsl:apply-templates mode="testtree" select="$hmitree"/>
-      </xsl:comment>
-      <xsl:apply-templates select="@* | node()"/>
-    </xsl:copy>
+          <xsl:text>    var relative_URI = window.location.href.replace(/^http(s?:\/\/[^\/]*)\/.*$/, 'ws$1/ws');
+</xsl:text>
+          <xsl:text>    var ws = new WebSocket(relative_URI);
+</xsl:text>
+          <xsl:text>    ws.onmessage = function (evt) {
+</xsl:text>
+          <xsl:text>        var received_msg = evt.data;
+</xsl:text>
+          <xsl:text>        alert("Message is received..."+received_msg); 
+</xsl:text>
+          <xsl:text>    };
+</xsl:text>
+          <xsl:text>    ws.onopen = function (evt) {
+</xsl:text>
+          <xsl:text>        ws.send("test");
+</xsl:text>
+          <xsl:text>    };
+</xsl:text>
+          <xsl:text>})();
+</xsl:text>
+        </script>
+      </body>
+    </html>
   </xsl:template>
   <xsl:template mode="testgeo" match="bbox">
     <xsl:text>ID: </xsl:text>
--- a/svghmi/gen_index_xhtml.ysl2	Wed Sep 18 11:03:56 2019 +0200
+++ b/svghmi/gen_index_xhtml.ysl2	Wed Sep 18 11:09:35 2019 +0200
@@ -1,4 +1,7 @@
 include yslt_noindent.yml2
+
+// overrides yslt's output function to set CDATA
+decl output(method, cdata-section-elements="script");
 istylesheet 
             /* From Inkscape */
             xmlns:dc="http://purl.org/dc/elements/1.1/"
@@ -7,6 +10,7 @@
             xmlns:svg="http://www.w3.org/2000/svg"
             xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
             xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+            xmlns="http://www.w3.org/1999/xhtml"
 
             /* Our namespace to invoke python code */
             xmlns:ns="beremiz"
@@ -30,17 +34,34 @@
     }
 
     /* copy root node and add geometry as comment for a test */
-    template "/" {
-      xsl:copy {
-          comment {
-              apply "$geometry", mode="testgeo";
+    template "/" 
+      html xmlns="http://www.w3.org/1999/xhtml" {
+          head;
+          body style="margin:0;" {
+              xsl:copy {
+                  comment {
+                      apply "$geometry", mode="testgeo";
+                  }
+                  comment {
+                      apply "$hmitree", mode="testtree";
+                  }
+                  apply "@* | node()";
+              }
+              script
+                  ||
+                  (function(){
+                      var relative_URI = window.location.href.replace(/^http(s?:\/\/[^\/]*)\/.*$/, 'ws$1/ws');
+                      var ws = new WebSocket(relative_URI);
+                      ws.onmessage = function (evt) {
+                          var received_msg = evt.data;
+                          alert("Message is received..."+received_msg); 
+                      };
+                      ws.onopen = function (evt) {
+                          ws.send("test");
+                      };
+                  })();
+                  ||
           }
-          comment {
-              | blah
-              apply "$hmitree", mode="testtree";
-          }
-          apply "@* | node()";
-      }
     }
 
     template "bbox", mode="testgeo"{
--- a/svghmi/svghmi.c	Wed Sep 18 11:03:56 2019 +0200
+++ b/svghmi/svghmi.c	Wed Sep 18 11:09:35 2019 +0200
@@ -179,7 +179,7 @@
 }
 
 /* PYTHON CALLS */
-int svghmi_send_collect(uint32_t *size, void *ptr){
+int svghmi_send_collect(uint32_t *size, char **ptr){
 
     int do_collect;
     pthread_mutex_lock(&svghmi_send_WakeCondLock);
@@ -202,7 +202,7 @@
     }
 }
 
-int svghmi_recv_dispatch(uint32_t size, void* ptr){
+int svghmi_recv_dispatch(uint32_t size, char *ptr){
     printf("%%*s",size,ptr);
     /* TODO something with ptr and size
         - subscribe
--- a/svghmi/svghmi.py	Wed Sep 18 11:03:56 2019 +0200
+++ b/svghmi/svghmi.py	Wed Sep 18 11:09:35 2019 +0200
@@ -165,8 +165,6 @@
             new_node = HMITreeNode(path, path[-1], v["derived"], v["type"], v["vartype"])
             hmi_tree_root.place_node(new_node)
 
-        print(hmi_tree_root.pprint())
-
         variable_decl_array = []
         extern_variables_declarations = []
         buf_index = 0
@@ -366,6 +364,9 @@
 def _runtime_svghmi1_%(location)s_start():
     svghmi_root.putChild('%(view_name)s',File('%(xhtml)s'))
 
+def _runtime_svghmi1_%(location)s_stop():
+    svghmi_root.delEntity('%(view_name)s')
+
         """ % {"location": location_str,
                "xhtml": target_fname,
                "view_name": view_name})
--- a/svghmi/svghmi_server.py	Wed Sep 18 11:03:56 2019 +0200
+++ b/svghmi/svghmi_server.py	Wed Sep 18 11:09:35 2019 +0200
@@ -25,14 +25,14 @@
 svghmi_send_collect.restype = ctypes.c_int # error or 0
 svghmi_send_collect.argtypes = [
     ctypes.POINTER(ctypes.c_uint32),  # size
-    ctypes.POINTER(ctypes.c_void_p)]  # data ptr
+    ctypes.POINTER(ctypes.c_char_p)]  # data ptr
 # TODO multiclient : switch to arrays
 
 svghmi_recv_dispatch = PLCBinary.svghmi_recv_dispatch
 svghmi_recv_dispatch.restype = ctypes.c_int # error or 0
 svghmi_recv_dispatch.argtypes = [
-    ctypes.c_uint32,                  # size
-    ctypes.POINTER(ctypes.c_void_p)]  # data ptr
+    ctypes.c_uint32,         # size
+    ctypes.c_char_p]  # data ptr
 # TODO multiclient : switch to arrays
 
 class HMISession(object):
@@ -59,15 +59,13 @@
         # svghmi_sessions.remove(self)
 
     def onMessage(self, msg):
-        # TODO :  pass it to the C side recieve_message()
-        #    update HMITree
-        #        - values
-        #        - refresh rates / subsriptions
+        # pass message to the C side recieve_message()
+        c_string = ctypes.c_char_p(msg)
+        c_string_pointer = ctypes.c_void_p(ctypes.addressof(c_string))
+        svghmi_recv_dispatch(len(msg), msg)
 
         # TODO multiclient : pass client index as well
 
-        #
-        svghmi_recv_dispatch(len(msg), ctypes.c_void_p.from_buffer_copy(msg))
 
     def sendMessage(self, msg):
         self.sendMessage(msg, True)
@@ -92,6 +90,9 @@
         print msg
         #self.sendMessage(msg, binary)
 
+class HMIWebSocketServerFactory(WebSocketServerFactory):
+    protocol = HMIProtocol
+
 svghmi_root = None
 svghmi_listener = None
 svghmi_send_thread = None
@@ -99,7 +100,7 @@
 def SendThreadProc():
    global svghmi_session
    size = ctypes.c_uint32()
-   ptr = ctypes.c_void_p()
+   ptr = ctypes.c_char_p()
    res = 0
    while svghmi_send_collect(ctypes.byref(size), ctypes.byref(ptr)) == 0 and \
          svghmi_session is not None and \
@@ -109,20 +110,15 @@
        # TODO multiclient : dispatch to sessions
 
 
+
 # Called by PLCObject at start
 def _runtime_svghmi0_start():
     global svghmi_listener, svghmi_root, svghmi_send_thread
 
     svghmi_root = Resource()
+    svghmi_root.putChild("ws", WebSocketResource(HMIWebSocketServerFactory()))
 
-    wsfactory = WebSocketServerFactory()
-    wsfactory.protocol = HMIProtocol
-
-    svghmi_root.putChild("ws", WebSocketResource(wsfactory))
-
-    sitefactory = Site(svghmi_root)
-
-    svghmi_listener = reactor.listenTCP(8008, sitefactory)
+    svghmi_listener = reactor.listenTCP(8008, Site(svghmi_root))
 
     # start a thread that call the C part of SVGHMI
     svghmi_send_thread = Thread(target=SendThreadProc, name="SVGHMI Send")