show timestamp of next timeout
This commit is contained in:
parent
f7f3923131
commit
e233fa9166
4 changed files with 40 additions and 11 deletions
|
|
@ -40,4 +40,10 @@ details {
|
||||||
}
|
}
|
||||||
/* details:not(:has(details)) > summary::marker {
|
/* details:not(:has(details)) > summary::marker {
|
||||||
color: white;
|
color: white;
|
||||||
} */
|
} */
|
||||||
|
|
||||||
|
.readonlyTextBox {
|
||||||
|
width: 56;
|
||||||
|
background-color:"#eee";
|
||||||
|
text-align: "right";
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { useEffect, useState } from "react";
|
||||||
|
|
||||||
import { ConcreteState, emptyStatechart, Statechart, stateDescription, Transition } from "../VisualEditor/ast";
|
import { ConcreteState, emptyStatechart, Statechart, stateDescription, Transition } from "../VisualEditor/ast";
|
||||||
import { handleInputEvent, initialize } from "../VisualEditor/interpreter";
|
import { handleInputEvent, initialize } from "../VisualEditor/interpreter";
|
||||||
|
import { TimerElapseEvent, Timers } from "@/VisualEditor/runtime_types";
|
||||||
import { Action, Expression } from "../VisualEditor/label_ast";
|
import { Action, Expression } from "../VisualEditor/label_ast";
|
||||||
import { BigStep, BigStepOutput, Environment, Mode } from "../VisualEditor/runtime_types";
|
import { BigStep, BigStepOutput, Environment, Mode } from "../VisualEditor/runtime_types";
|
||||||
import { VisualEditor } from "../VisualEditor/VisualEditor";
|
import { VisualEditor } from "../VisualEditor/VisualEditor";
|
||||||
|
|
@ -68,11 +69,18 @@ export function AST(props: {root: ConcreteState, transitions: Map<string, Transi
|
||||||
|
|
||||||
|
|
||||||
function formatTime(timeMs: number) {
|
function formatTime(timeMs: number) {
|
||||||
const leadingZeros = "00" + timeMs % 1000;
|
const leadingZeros = "00" + Math.floor(timeMs) % 1000;
|
||||||
const formatted = `${Math.floor(timeMs / 1000)}.${(leadingZeros).substring(leadingZeros.length-3)}`;
|
const formatted = `${Math.floor(timeMs / 1000)}.${(leadingZeros).substring(leadingZeros.length-3)}`;
|
||||||
return formatted;
|
return formatted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function compactTime(timeMs: number) {
|
||||||
|
if (timeMs % 1000 === 0) {
|
||||||
|
return `${timeMs / 1000}s`;
|
||||||
|
}
|
||||||
|
return `${timeMs} ms`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export function App() {
|
export function App() {
|
||||||
const [ast, setAST] = useState<Statechart>(emptyStatechart);
|
const [ast, setAST] = useState<Statechart>(emptyStatechart);
|
||||||
|
|
@ -180,6 +188,10 @@ export function App() {
|
||||||
setTime({kind: "paused", simtime: timestamp});
|
setTime({kind: "paused", simtime: timestamp});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// timestamp of next timed transition, in simulated time
|
||||||
|
const timers: Timers = (rt[rtIdx!]?.environment.get("_timers") || []);
|
||||||
|
const nextTimedTransition: [number, TimerElapseEvent] | undefined = timers[0];
|
||||||
|
|
||||||
return <div className="layoutVertical">
|
return <div className="layoutVertical">
|
||||||
<div className="panel">
|
<div className="panel">
|
||||||
|
|
||||||
|
|
@ -188,9 +200,11 @@ export function App() {
|
||||||
<button onClick={restart}>(re)start</button>
|
<button onClick={restart}>(re)start</button>
|
||||||
<button onClick={clear} disabled={rtIdx===null}>clear</button>
|
<button onClick={clear} disabled={rtIdx===null}>clear</button>
|
||||||
 
|
 
|
||||||
raise
|
{ast.inputEvents &&
|
||||||
{[...ast.inputEvents].map(event => <button disabled={rtIdx===null} onClick={() => raise(event)}>{event}</button>)}
|
<>raise
|
||||||
 
|
{[...ast.inputEvents].map(event => <button disabled={rtIdx===null} onClick={() => raise(event)}>{event}</button>)}
|
||||||
|
 </>
|
||||||
|
}
|
||||||
<input type="radio" name="paused" id="radio-paused" checked={time.kind==="paused"} disabled={rtIdx===null} onChange={e => onChangePaused(e.target.checked, performance.now())}/>
|
<input type="radio" name="paused" id="radio-paused" checked={time.kind==="paused"} disabled={rtIdx===null} onChange={e => onChangePaused(e.target.checked, performance.now())}/>
|
||||||
<label htmlFor="radio-paused">paused</label>
|
<label htmlFor="radio-paused">paused</label>
|
||||||
<input type="radio" name="realtime" id="radio-realtime" checked={time.kind==="realtime"} disabled={rtIdx===null} onChange={e => onChangePaused(!e.target.checked, performance.now())}/>
|
<input type="radio" name="realtime" id="radio-realtime" checked={time.kind==="realtime"} disabled={rtIdx===null} onChange={e => onChangePaused(!e.target.checked, performance.now())}/>
|
||||||
|
|
@ -200,7 +214,15 @@ export function App() {
|
||||||
<input type="number" min={0} id="number-timescale" disabled={rtIdx===null} value={timescale} style={{width:40}} onChange={e => onTimeScaleChange(e.target.value, performance.now())}/>
|
<input type="number" min={0} id="number-timescale" disabled={rtIdx===null} value={timescale} style={{width:40}} onChange={e => onTimeScaleChange(e.target.value, performance.now())}/>
|
||||||
 
|
 
|
||||||
<label htmlFor="time">time (s)</label>
|
<label htmlFor="time">time (s)</label>
|
||||||
<input id="time" disabled={rtIdx===null} value={displayTime} readOnly={true} style={{width:56, backgroundColor:"#eee", textAlign: "right"}}/>
|
<input id="time" disabled={rtIdx===null} value={displayTime} readOnly={true} className="readonlyTextBox" />
|
||||||
|
{nextTimedTransition &&
|
||||||
|
<>
|
||||||
|
 
|
||||||
|
next timeout (s):
|
||||||
|
<input id="time" disabled={rtIdx===null} value={formatTime(nextTimedTransition[0])} readOnly={true} className="readonlyTextBox"/>
|
||||||
|
<button>advance</button>
|
||||||
|
</>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
<div className="layout">
|
<div className="layout">
|
||||||
<main className="content">
|
<main className="content">
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { evalExpr } from "./actionlang_interpreter";
|
import { evalExpr } from "./actionlang_interpreter";
|
||||||
import { computeArena, ConcreteState, getDescendants, isOverlapping, OrState, Statechart, stateDescription, Transition } from "./ast";
|
import { computeArena, ConcreteState, getDescendants, isOverlapping, OrState, Statechart, stateDescription, Transition } from "./ast";
|
||||||
import { Action } from "./label_ast";
|
import { Action } from "./label_ast";
|
||||||
import { Environment, RaisedEvents, Mode, RT_Statechart, initialRaised, BigStepOutput } from "./runtime_types";
|
import { Environment, RaisedEvents, Mode, RT_Statechart, initialRaised, BigStepOutput, TimerElapseEvent, Timers } from "./runtime_types";
|
||||||
|
|
||||||
export function initialize(ast: Statechart): BigStepOutput {
|
export function initialize(ast: Statechart): BigStepOutput {
|
||||||
let {enteredStates, environment, ...raised} = enterDefault(0, ast.root, {
|
let {enteredStates, environment, ...raised} = enterDefault(0, ast.root, {
|
||||||
|
|
@ -17,9 +17,6 @@ type ActionScope = {
|
||||||
|
|
||||||
type EnteredScope = { enteredStates: Mode } & 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 {
|
export function entryActions(simtime: number, state: ConcreteState, actionScope: ActionScope): ActionScope {
|
||||||
for (const action of state.entryActions) {
|
for (const action of state.entryActions) {
|
||||||
(actionScope = execAction(action, actionScope));
|
(actionScope = execAction(action, actionScope));
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,13 @@ export type RaisedEvents = {
|
||||||
outputEvents: string[];
|
outputEvents: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Timers = Map<string, number>; // transition uid -> timestamp
|
// export type Timers = Map<string, number>; // transition uid -> timestamp
|
||||||
|
|
||||||
export const initialRaised: RaisedEvents = {
|
export const initialRaised: RaisedEvents = {
|
||||||
internalEvents: [],
|
internalEvents: [],
|
||||||
outputEvents: [],
|
outputEvents: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type TimerElapseEvent = { state: string; timeDurMs: number; };
|
||||||
|
export type Timers = [number, TimerElapseEvent][];
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue