svghmi/svghmi_server.py
author Edouard Tisserant
Mon, 30 Sep 2019 13:26:11 +0200
branchsvghmi
changeset 2788 2ed9ff826d03
parent 2779 75c6a31caca6
child 2798 ddb2c4668a6b
permissions -rw-r--r--
SVGHMI: Work in progress. C side mostly implemented, neither built nor tested.
#!/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_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.c_char_p]  # data ptr
# TODO multiclient : switch to arrays

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):
        # pass message to the C side recieve_message()
        svghmi_recv_dispatch(len(msg), msg)

        # TODO multiclient : pass client index as well


    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)

class HMIWebSocketServerFactory(WebSocketServerFactory):
    protocol = HMIProtocol

svghmi_root = None
svghmi_listener = None
svghmi_send_thread = None

def SendThreadProc():
   global svghmi_session
   size = ctypes.c_uint32()
   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 \
         svghmi_session.sendMessage(ctypes.string_at(ptr,size)) == 0:
         pass

       # 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()))

    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")
    svghmi_send_thread.start()


# Called by PLCObject at stop
def _runtime_svghmi0_stop():
    global svghmi_listener, svghmi_root, svghmi_send_thread
    svghmi_root.delEntity("ws")
    svghmi_root = None
    svghmi_listener.stopListening()
    svghmi_listener = None
    # plc cleanup calls svghmi_(locstring)_cleanup and unlocks send thread
    svghmi_send_thread.join()
    svghmi_send_thread = None