84 lines
3.3 KiB
Python
84 lines
3.3 KiB
Python
import tkinter
|
|
import atexit
|
|
import sys
|
|
|
|
# load generated Statechart code
|
|
from srcgen.water_level_simulator import WaterLevelSimulator
|
|
# from srcgen.lock_controller import LockController
|
|
from srcgen.solution import Solution as LockController # Teacher's solution
|
|
|
|
from lib.yakindu.rx import Observer
|
|
from lib.controller import Controller, pretty_time
|
|
from lib.tracer import Tracer, format_trace_as_python_code
|
|
from lib.yakindu_helpers import YakinduTimerServiceAdapter, CallbackObserver, trace_output_events
|
|
from lib.realtime.realtime import WallClock
|
|
from lib.realtime.event_loop import EventLoopRealTimeSimulation
|
|
from lib.realtime.tk_event_loop import TkEventLoopAdapter
|
|
|
|
from gui import GUI
|
|
|
|
if __name__ == "__main__":
|
|
|
|
# read time scale from command line
|
|
try:
|
|
time_scale = float(sys.argv[1])
|
|
except:
|
|
time_scale = 1.0
|
|
print(f"TIME SCALE is {time_scale}")
|
|
|
|
|
|
sc = LockController()
|
|
wlvlsc = WaterLevelSimulator() # our environment is also modeled as a statechart :)
|
|
|
|
controller = Controller()
|
|
|
|
# We'll record input and output events
|
|
tracer = Tracer()
|
|
controller.input_tracers.append((sc, tracer.record_input_event))
|
|
trace_output_events(controller, sc, callback=tracer.record_output_event)
|
|
|
|
sc.timer_service = YakinduTimerServiceAdapter(controller)
|
|
wlvlsc.timer_service = YakinduTimerServiceAdapter(controller)
|
|
|
|
toplevel = tkinter.Tk()
|
|
|
|
wall_clock = WallClock(time_scale)
|
|
sim = EventLoopRealTimeSimulation(controller, TkEventLoopAdapter(toplevel), wall_clock)
|
|
|
|
gui = GUI(sim, sc, wlvlsc, toplevel)
|
|
|
|
sim.time_advance_callback = gui.time_changed
|
|
|
|
# output event handlers of LockController
|
|
sc.set_request_pending_observable.subscribe(CallbackObserver(gui.set_request_pending))
|
|
sc.open_flow_observable.subscribe(CallbackObserver(lambda side: gui.set_flow(side, True)))
|
|
sc.close_flow_observable.subscribe(CallbackObserver(lambda side: gui.set_flow(side, False)))
|
|
sc.open_doors_observable.subscribe(CallbackObserver(lambda side: gui.set_doors(side, True)))
|
|
sc.close_doors_observable.subscribe(CallbackObserver(lambda side: gui.set_doors(side, False)))
|
|
sc.green_light_observable.subscribe(CallbackObserver(gui.set_green_light))
|
|
sc.red_light_observable.subscribe(CallbackObserver(gui.set_red_light))
|
|
sc.set_sensor_broken_observable.subscribe(CallbackObserver(gui.set_sensor_broken))
|
|
|
|
# output event handlers of WaterLevelSimulator
|
|
wlvlsc.sensor_reading_observable.subscribe(CallbackObserver(gui.on_water_level_reading))
|
|
wlvlsc.real_water_level_observable.subscribe(CallbackObserver(gui.on_real_water_level))
|
|
|
|
def print_trace_on_exit():
|
|
print("End of simulation. Full I/O trace:")
|
|
print("{")
|
|
print(' "name": "interactive",')
|
|
print(' "input_events": ', end='')
|
|
print(format_trace_as_python_code(tracer.input_events, indent=4))
|
|
print(' "output_events": ', end='')
|
|
print(format_trace_as_python_code(tracer.output_events, indent=4))
|
|
print("}")
|
|
atexit.register(print_trace_on_exit)
|
|
|
|
wall_clock.record_start_time() # start_time is NOW!
|
|
|
|
# Enter default states
|
|
sc.enter()
|
|
wlvlsc.enter()
|
|
|
|
sim.poke() # schedule first simulator wakeup (in tk event loop)
|
|
toplevel.mainloop() # everything is controlled by tkinter's eventloop
|