timed transition appear to be working
This commit is contained in:
parent
166fd6d4bc
commit
966b168a74
3 changed files with 64 additions and 13 deletions
|
|
@ -17,6 +17,9 @@ type ActionScope = {
|
|||
|
||||
type EnteredScope = { enteredStates: Mode } & ActionScope;
|
||||
|
||||
type TimerElapseEvent = {state: string, timeDurMs: number};
|
||||
type Timers = [number, TimerElapseEvent][];
|
||||
|
||||
export function entryActions(simtime: number, state: ConcreteState, actionScope: ActionScope): ActionScope {
|
||||
for (const action of state.entryActions) {
|
||||
(actionScope = execAction(action, actionScope));
|
||||
|
|
@ -24,10 +27,10 @@ export function entryActions(simtime: number, state: ConcreteState, actionScope:
|
|||
// schedule timers
|
||||
// we store timers in the environment (dirty!)
|
||||
const environment = new Map(actionScope.environment);
|
||||
const timers: [number,string][] = [...(environment.get("_timers") || [])];
|
||||
const timers: Timers = [...(environment.get("_timers") || [])];
|
||||
for (const timeOffset of state.timers) {
|
||||
const futureSimTime = simtime + timeOffset; // point in simtime when after-trigger becomes enabled
|
||||
timers.push([futureSimTime, state.uid+'/'+timeOffset]);
|
||||
timers.push([futureSimTime, {state: state.uid, timeDurMs: timeOffset}]);
|
||||
}
|
||||
timers.sort((a,b) => a[0] - b[0]); // smallest futureSimTime comes first
|
||||
environment.set("_timers", timers);
|
||||
|
|
@ -40,8 +43,8 @@ export function exitActions(simtime: number, state: ConcreteState, actionScope:
|
|||
}
|
||||
// cancel timers
|
||||
const environment = new Map(actionScope.environment);
|
||||
const timers: [number,string][] = environment.get("_timers") || [];
|
||||
const filtered = timers.filter(([_, timerId]) => !timerId.startsWith(state.uid+'/'));
|
||||
const timers: Timers = environment.get("_timers") || [];
|
||||
const filtered = timers.filter(([_, {state: s}]) => s !== state.uid);
|
||||
environment.set("_timers", filtered);
|
||||
return {...actionScope, environment};
|
||||
}
|
||||
|
|
@ -185,12 +188,30 @@ export function execAction(action: Action, rt: ActionScope): ActionScope {
|
|||
throw new Error("should never reach here");
|
||||
}
|
||||
|
||||
export function handleEvent(simtime: number, event: string, statechart: Statechart, activeParent: ConcreteState, {environment, mode, ...raised}: RT_Statechart & RaisedEvents): RT_Statechart & RaisedEvents {
|
||||
export function handleEvent(simtime: number, event: string | TimerElapseEvent, statechart: Statechart, activeParent: ConcreteState, {environment, mode, ...raised}: RT_Statechart & RaisedEvents): RT_Statechart & RaisedEvents {
|
||||
const arenasFired = new Set<OrState>();
|
||||
for (const state of activeParent.children) {
|
||||
if (mode.has(state.uid)) {
|
||||
const outgoing = statechart.transitions.get(state.uid) || [];
|
||||
const triggered = outgoing.filter(transition => transition.label[0].trigger.kind === "event" && transition.label[0].trigger.event === event);
|
||||
let triggered;
|
||||
if (typeof event === 'string') {
|
||||
triggered = outgoing.filter(transition => {
|
||||
const trigger = transition.label[0].trigger;
|
||||
if (trigger.kind === "event") {
|
||||
return trigger.event === event;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
else {
|
||||
triggered = outgoing.filter(transition => {
|
||||
const trigger = transition.label[0].trigger;
|
||||
if (trigger.kind === "after") {
|
||||
return trigger.durationMs === event.timeDurMs;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
const enabled = triggered.filter(transition =>
|
||||
evalExpr(transition.label[0].guard, environment)
|
||||
);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ export type TimeRealTime = {
|
|||
scale: number, // time scale relative to wall-clock time
|
||||
}
|
||||
|
||||
// given a wall-clock time, how does it translate to simtime?
|
||||
export function getSimTime(currentMode: TimeMode, wallclktime: number): number {
|
||||
if (currentMode.kind === "paused") {
|
||||
return currentMode.simtime;
|
||||
|
|
@ -31,6 +32,14 @@ export function getSimTime(currentMode: TimeMode, wallclktime: number): number {
|
|||
}
|
||||
}
|
||||
|
||||
// given a simulated real time clock, how long will it take in wall-clock time duration until 'simtime' is the current time?
|
||||
export function getWallClkDelay(realtime: TimeRealTime, simtime: number, wallclktime: number): number {
|
||||
const currentSimTime = getSimTime(realtime, wallclktime);
|
||||
const simtimeDelay = simtime - currentSimTime;
|
||||
return Math.max(0, simtimeDelay / realtime.scale);
|
||||
}
|
||||
|
||||
// given a current simulated clock (paused or real time), switch to real time with given time scale
|
||||
export function setRealtime(currentMode: TimeMode, scale: number, wallclktime: number): TimeRealTime {
|
||||
if (currentMode.kind === "paused") {
|
||||
return {
|
||||
|
|
@ -54,6 +63,7 @@ export function setRealtime(currentMode: TimeMode, scale: number, wallclktime: n
|
|||
}
|
||||
}
|
||||
|
||||
// given a current simulated clock (paused or real time), switch to paused
|
||||
export function setPaused(currentMode: TimeMode, wallclktime: number): TimePaused {
|
||||
if (currentMode.kind === "paused") {
|
||||
return currentMode; // no change
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue