浏览代码

Working use of statechart for connection with execute_MT and execute_AL

Yentl Van Tendeloo 8 年之前
父节点
当前提交
27e91c0874
共有 2 个文件被更改,包括 80 次插入49 次删除
  1. 15 2
      unit/test_all.py
  2. 65 47
      wrappers/modelverse.py

+ 15 - 2
unit/test_all.py

@@ -209,8 +209,15 @@ class TestModelverse(unittest.TestCase):
         transformation_add_AL({"PetriNet_Runtime": "test/PetriNet_Runtime"}, {"PetriNet_Runtime": "test/PetriNet_Runtime"}, "test/pn_simulate", open("integration/code/pn_simulate.alc").read())
         transformation_add_MT({"PetriNet_Runtime": "test/PetriNet_Runtime"}, {"PetriNet": "test/PetriNet"}, "test/pn_runtime_to_design", open("integration/code/pn_runtime_to_design.mvc").read(), add_tracability_R2D)
 
+        import log_output
         log = []
-        assert transformation_execute_MT("test/print_pn", {"PetriNet": "test/my_pn"}, {}, callback) == True
+        ctrl = log_output.Controller(log, keep_running=False)
+        thrd = threading.Thread(target=ctrl.start)
+        thrd.daemon = True
+        thrd.start()
+
+        assert transformation_execute_MT("test/print_pn", {"PetriNet": "test/my_pn"}, {}, (ctrl, "inp", "outp")) == None
+        thrd.join()
         assert set(log) == set(['"p1" --> 1',
                                 '"p2" --> 2',
                                 '"p3" --> 3'])
@@ -220,7 +227,13 @@ class TestModelverse(unittest.TestCase):
         assert transformation_execute_MT("test/pn_runtime_to_design", {"PetriNet_Runtime": "test/my_pn_RT"}, {"PetriNet": "test/my_pn"}) == True
 
         log = []
-        assert transformation_execute_MT("test/print_pn", {"PetriNet": "test/my_pn"}, {}, callback) == True
+        ctrl = log_output.Controller(log, keep_running=False)
+        thrd = threading.Thread(target=ctrl.start)
+        thrd.daemon = True
+        thrd.start()
+
+        assert transformation_execute_MT("test/print_pn", {"PetriNet": "test/my_pn"}, {}, (ctrl, "inp", "outp")) == None
+        thrd.join()
         assert set(log) == set(['"p1" --> 0',
                                 '"p2" --> 1',
                                 '"p3" --> 5'])

+ 65 - 47
wrappers/modelverse.py

@@ -8,6 +8,8 @@ import time
 import threading
 import Queue
 
+from sccd.runtime.statecharts_core import Event
+
 COMPILER_PATH = "interface/HUTN"
 
 MODE_UNCONNECTED = 0
@@ -62,12 +64,11 @@ class UnknownMetamodellingHierarchy(ModelverseException):
 # Helper functions and configuration: do not use yourself!
 taskname = None
 address = None
-last_output = None
 mode = MODE_UNCONNECTED
 prev_mode = None
 current_model = None
 registered_metamodels = {}
-outputs = []
+outputs = [None]
 
 def _output_thread(outputs):
     while taskname is None:
@@ -80,6 +81,38 @@ thrd = threading.Thread(target=_output_thread, args=[outputs])
 thrd.daemon = True
 thrd.start()
 
+def _exec_on_statechart(statechart):
+    def _exec_sc(controller, inport, outport):
+        op = controller.addOutputListener(outport)
+
+        while 1:
+            if len(outputs) > 1:
+                # Is an output message of the Mv, so put it in the SC
+                del outputs[0]
+                output_event = outputs[0]
+
+                print("Sending MV event: " + str(output_event))
+                if output_event == "Success" or output_event == "Failure":
+                    # Is a stop event!
+                    controller.addInput(Event("terminate", inport, []))
+                    break
+                else:
+                    # Is just a normal event!
+                    controller.addInput(Event("input", inport, [output_event]))
+
+            input_event = op.fetch(0)
+            if input_event is not None:
+                # Expand the event and make it HTTP input
+                print("Got SC event: " + str(input_event))
+                _input(input_event)
+                
+            time.sleep(0.01)
+        
+    thrd = threading.Thread(target=_exec_sc, args=statechart)
+    thrd.daemon = True
+    thrd.start()
+    return None
+
 def _get_metamodel(model):
     global registered_metamodels
     try:
@@ -129,7 +162,7 @@ def _goto_mode(new_mode, model_name=None):
 
 def _input(value, port=None):
     # Ugly json encoding of primitives
-    #print("[IN] %s" % value)
+    print("[IN] %s" % value)
     if port is None:
         port = taskname
     if isinstance(value, type([])):
@@ -182,22 +215,20 @@ def _compile_model(code):
 
 def _output(expected=None):
     try:
-        global last_output
-
-        while not outputs:
+        while len(outputs) < 2:
             time.sleep(0.01)
 
-        last_output = outputs.pop(0)
-        #print("[OUT] %s" % last_output)
+        del outputs[0]
+        print("[OUT] %s" % outputs[0])
     except:
         raise UnknownError()
 
-    if expected is not None and last_output != expected:
+    if expected is not None and _last_output() != expected:
         raise InterfaceMismatch(_last_output(), expected)
-    return last_output
+    return _last_output()
 
 def _last_output():
-    return last_output
+    return outputs[0]
 
 # Raise common exceptions
 def _handle_output(requested=None, split=None):
@@ -529,31 +560,18 @@ def transformation_execute_AL(operation_name, input_models_dict, output_models_d
     _handle_output("Success: ready for AL execution")
 
     if statechart is not None:
-        inputs = [None]
-        outputs = [None]
-        thrd = threading.Thread(target=exec_statechart, args=[statechart, inputs, outputs])
-        thrd.daemon = True
-        thrd.start()
-
-        # On this remote thread, we are running the statechart, producing output and consuming input
-        # We bind to this input and output by passing references to the function, which it must update to reflect the input/output queue
-
-        while 1:
-            # Poll for outputs to send
-            try:
-                outp = outputs[0].fetch(0)
-                print("Got SC output: " + str(outp))
-                _input(outp)
-            except Queue.Empty:
-                if not thrd.is_alive():
-                    # No more outputs, and the SC is not even alive anymore, so stop
-                    break
-
-    # Got termination message, so we are done!
-    if _output() == "Success":
-        return True
+        # We are to delegate this information to another statechart, which wants interaction
+        # As such, we continue on a different thread, where we pipe the information, and let this call return immediately
+        _exec_on_statechart(statechart)
+        return None
     else:
-        return False
+        # No statechart associated, so just wait until we are finished
+        while _output() not in ["Success", "Failure"]:
+            pass
+        if _last_output() == "Success":
+            return True
+        else:
+            return False
 
 def transformation_execute_MANUAL(operation_name, input_models_dict, output_models_dict, callback=lambda i: None):
     """Execute an existing model operation."""
@@ -592,19 +610,19 @@ def transformation_execute_MT(operation_name, input_models_dict, output_models_d
     _input(["transformation_execute", operation_name] + mv_dict_rep)
     _handle_output("Success: ready for MT execution")
 
-    # We are now executing, so everything we get is part of the dialog, except if it is the string for transformation termination
-    while _output() not in ["Success", "Failure"]:
-        mode = MODE_DIALOG
-        reply = callback(_last_output())
-        mode = MODE_MODELLING
-        if reply is not None:
-            _input(reply)
-
-    # Got termination message, so we are done!
-    if _last_output() == "Success":
-        return True
+    if statechart is not None:
+        # We are to delegate this information to another statechart, which wants interaction
+        # As such, we continue on a different thread, where we pipe the information, and let this call return immediately
+        _exec_on_statechart(statechart)
+        return None
     else:
-        return False
+        # No statechart associated, so just wait until we are finished
+        while _output() not in ["Success", "Failure"]:
+            pass
+        if _last_output() == "Success":
+            return True
+        else:
+            return False
 
 def transformation_list():
     """List existing model operations."""