svghmi/svghmi_server.py
author Edouard Tisserant
Thu, 12 Sep 2019 12:56:47 +0200
branchsvghmi
changeset 2774 9857b4b0d979
parent 2773 6e5e752372c8
child 2775 3b93409ba22c
permissions -rw-r--r--
SVGHMI: WIP for python<->C data exchange
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# This file is part of Beremiz
# Copyright (C) 2019: Edouard TISSERANT
# See COPYING file for copyrights details.

from __future__ import absolute_import

from twisted.web.server import Site
from twisted.web.resource import Resource
from twisted.internet import reactor
from twisted.web.static import File

from autobahn.twisted.websocket import WebSocketServerFactory, WebSocketServerProtocol
from autobahn.twisted.resource import  WebSocketResource

# TODO multiclient :
# session list lock
# svghmi_sessions = []

svghmi_session = None

svghmi_send_collect = PLCBinary.svghmi_send_collect
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
# 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.POINTER(ctypes.c_uint32),  # size
    ctypes.POINTER(ctypes.c_void_p)]  # data ptr
# TODO multiclient : switch to arrays

def SendThreadProc():
   assert(svghmi_session)
   size = ctypes.c_uint32()
   ptr = ctypes.c_void_p()
   while res == 0:
       res = svghmi_send_collect(ctypes.byref(size), ctypes.byref(ptr))

   # TODO multiclient : dispatch to sessions
   svghmi_session.sendMessage(ctypes.string_at(ptr,size))

class HMISession(object):
    def __init__(self, protocol_instance):
        global svghmi_session
        
        # TODO: kill existing session for robustness
        assert(svghmi_session is None)

        svghmi_session = self
        self.protocol_instance = protocol_instance

        # TODO multiclient :
        # svghmi_sessions.append(self)
        # get a unique bit index amont other svghmi_sessions,
        # so that we can match flags passed by C->python callback
    
    def __del__(self):
        global svghmi_session
        assert(svghmi_session)
        svghmi_session = None

        # TODO multiclient :
        # svghmi_sessions.remove(self)

    def onMessage(self, msg):
        # TODO :  pass it to the C side recieve_message()
        #    update HMITree
        #        - values
        #        - refresh rates / subsriptions

        # TODO multiclient : pass client index as well
        pass
         
    def sendMessage(self, msg):
        self.sendMessage(msg, True)

class HMIProtocol(WebSocketServerProtocol):

    def __init__(self, *args, **kwargs):
        self._hmi_session = None
        WebSocketServerProtocol.__init__(self, *args, **kwargs)

    def onOpen(self):
        self._hmi_session = HMISession(self)
        print "open"

    def onClose(self, wasClean, code, reason):
        del self._hmi_session
        self._hmi_session = None
        print "close"

    def onMessage(self, msg, isBinary):
        self._hmi_session.onMessage(msg)
        print msg
        #self.sendMessage(msg, binary)
     
svghmi_root = None
svghmi_listener = None

# Called by PLCObject at start
def _runtime_svghmi0_start():
    global svghmi_listener, svghmi_root

    svghmi_root = Resource()

    wsfactory = WebSocketServerFactory()
    wsfactory.protocol = HMIProtocol

    # svghmi_root.putChild("",File(".svg"))
    svghmi_root.putChild("ws",WebSocketResource(wsfactory))

    sitefactory = Site(svghmi_root)

    svghmi_listener = reactor.listenTCP(8008, sitefactory)

    # TODO
    # start a thread that call the C part of SVGHMI


# Called by PLCObject at stop
def _runtime_svghmi0_stop():
    global svghmi_listener
    svghmi_listener.stopListening()