|
@@ -39,6 +39,19 @@ Element function filter(model : Element, set : Element, attribute_name : String,
|
|
|
|
|
|
return result!
|
|
|
|
|
|
+Element function filter_exists(model : Element, set : Element, attribute_name : String):
|
|
|
+ Element keys
|
|
|
+ String key
|
|
|
+ Element result
|
|
|
+
|
|
|
+ result = create_node()
|
|
|
+ while (read_nr_out(set) > 0):
|
|
|
+ key = set_pop(set)
|
|
|
+ if (element_neq(read_attribute(model, key, attribute_name), read_root())):
|
|
|
+ set_add(result, key)
|
|
|
+
|
|
|
+ return result!
|
|
|
+
|
|
|
Element function expand_state(model : Element, state : String):
|
|
|
String t
|
|
|
t = read_type(model, state)
|
|
@@ -87,6 +100,7 @@ Void function start_class(model : Element, data : Element, class : String):
|
|
|
class_handle = create_node()
|
|
|
dict_add(class_handle, "type", class)
|
|
|
dict_add(class_handle, "ID", cast_id2s(create_node()))
|
|
|
+ dict_add(class_handle, "timers", create_node())
|
|
|
|
|
|
// Add the current state of the class
|
|
|
String initial_state
|
|
@@ -147,6 +161,7 @@ Element function execute_transition(model : Element, data : Element, class : Str
|
|
|
|
|
|
// Raise events (if any)
|
|
|
Element events
|
|
|
+ String event
|
|
|
events = allAssociationDestinations(model, transition, "SCCD/transition_raises")
|
|
|
while (read_nr_out(events) > 0):
|
|
|
event = set_pop(events)
|
|
@@ -164,8 +179,6 @@ Float function step_class(model : Element, data : Element, class : String):
|
|
|
String state
|
|
|
Element transitions
|
|
|
String transition
|
|
|
- Float t_min
|
|
|
- Float t_current
|
|
|
|
|
|
states = set_copy(data["classes"][class]["states"])
|
|
|
new_states = create_node()
|
|
@@ -187,11 +200,70 @@ Float function step_class(model : Element, data : Element, class : String):
|
|
|
|
|
|
// Nothing found, so stay in the current state
|
|
|
set_add(new_states, state)
|
|
|
-
|
|
|
+
|
|
|
// Update states
|
|
|
dict_overwrite(data["classes"][class], "states", new_states)
|
|
|
+ reschedule_timeouts(model, data, class)
|
|
|
+
|
|
|
+ // Find minimum timer for this class, and return that
|
|
|
+ Float t_min
|
|
|
+ Float t_current
|
|
|
+ Element keys
|
|
|
+ String key
|
|
|
|
|
|
- return 1.0!
|
|
|
+ t_min = time() + 99999.0
|
|
|
+ keys = dict_keys(data["classes"][class]["timers"])
|
|
|
+ while (read_nr_out(keys) > 0):
|
|
|
+ key = set_pop(keys)
|
|
|
+ t_current = data["classes"][class]["timers"][key]
|
|
|
+ if (t_current < t_min):
|
|
|
+ t_min = t_current
|
|
|
+
|
|
|
+ return t_min!
|
|
|
+
|
|
|
+Void function reschedule_timeouts(model : Element, data : Element, class : String):
|
|
|
+ Element timed_transitions
|
|
|
+ Element old_timed_transitions
|
|
|
+ String transition
|
|
|
+ Element states
|
|
|
+ String state
|
|
|
+
|
|
|
+ timed_transitions = create_node()
|
|
|
+ states = dict_keys(data["classes"][class]["states"])
|
|
|
+ while (read_nr_out(states) > 0):
|
|
|
+ state = set_pop(states)
|
|
|
+
|
|
|
+ // NOTE this set_merge does not eliminate duplicates, though this should happen later on when adding the timer (see other NOTE)
|
|
|
+ timed_transitions = set_merge(timed_transitions, filter_exists(model, allOutgoingAssociationInstances(model, state, "SCCD/transition"), "after"))
|
|
|
+
|
|
|
+ // Remove timers that no longer exist
|
|
|
+ old_timed_transitions = dict_keys(data["classes"][class]["timers"])
|
|
|
+ while (read_nr_out(old_timed_transitions) > 0):
|
|
|
+ transition = set_pop(old_timed_transitions)
|
|
|
+
|
|
|
+ if (bool_not(set_in(timed_transitions, transition))):
|
|
|
+ // Transition is no longer scheduled for any state, so remove
|
|
|
+ dict_delete(data["classes"][class]["timers"], transition)
|
|
|
+
|
|
|
+ // Schedule timers that are not already scheduled
|
|
|
+ while (read_nr_out(timed_transitions) > 0):
|
|
|
+ transition = set_pop(timed_transitions)
|
|
|
+
|
|
|
+ // NOTE Normally, a timer will not be added twice here, as the previous occurence will already find it
|
|
|
+ if (bool_not(dict_in(data["classes"][class]["timers"], transition))):
|
|
|
+ // Not yet scheduled this transition: do so now
|
|
|
+ Element after
|
|
|
+ Float after_duration
|
|
|
+
|
|
|
+ after = read_attribute(model, transition, "after")
|
|
|
+ after = get_func_AL_model(import_node(after))
|
|
|
+ after_duration = after(data["classes"][class]["attributes"])
|
|
|
+
|
|
|
+ log("Schedule transition after " + cast_v2s(after_duration))
|
|
|
+
|
|
|
+ dict_add(data["classes"][class]["timers"], transition, float_addition(data["start_time"], after_duration))
|
|
|
+
|
|
|
+ return !
|
|
|
|
|
|
Float function step(model : Element, data : Element):
|
|
|
// Step through all classes
|
|
@@ -200,16 +272,19 @@ Float function step(model : Element, data : Element):
|
|
|
Float t_min
|
|
|
Float t_class
|
|
|
|
|
|
- t_min = 1.0
|
|
|
+ t_min = time() + 99999.0
|
|
|
classes = dict_keys(data["classes"])
|
|
|
|
|
|
+ // TODO this should use simulated time or something
|
|
|
+ dict_overwrite(data, "start_time", time())
|
|
|
+
|
|
|
while (read_nr_out(classes) > 0):
|
|
|
class = set_pop(classes)
|
|
|
t_class = step_class(model, data, class)
|
|
|
if (t_class < t_min):
|
|
|
t_min = t_class
|
|
|
|
|
|
- return t_min!
|
|
|
+ return float_subtraction(t_min, data["start_time"])!
|
|
|
|
|
|
Boolean function main(model : Element):
|
|
|
// Executes the provided SCCD model
|
|
@@ -246,6 +321,7 @@ Boolean function main(model : Element):
|
|
|
output("Processed event, ready for more!")
|
|
|
|
|
|
timeout = step(model, data)
|
|
|
+ log("Pausing for " + cast_v2s(timeout))
|
|
|
|
|
|
// We should never get here!
|
|
|
return False!
|