@@ -16,12 +16,13 @@ function mlRunnerCustomOnEvent(
1616class MlEvent {
1717 eventValue : number ;
1818 eventLabel : string ;
19- hasOnEventHandler : boolean ;
19+ lastDuration : number ;
20+ onStopHandler : ( duration : number ) => void ;
2021
2122 constructor ( value : number , label : string ) {
2223 this . eventValue = value ;
2324 this . eventLabel = label ;
24- this . hasOnEventHandler = false ;
25+ this . lastDuration = 0 ;
2526 }
2627
2728 /**
@@ -35,13 +36,21 @@ class MlEvent {
3536 * @param body The code to run when the model predicts the label.
3637 */
3738 //% blockId=mlrunner_on_ml_event
38- //% block="on ML event $this"
39+ //% block="on $this start "
3940 onEvent ( body : ( ) => void ) : void {
40- this . hasOnEventHandler = true ;
4141 const wrappedBody = ( ) => {
42- if ( mlrunner . Action . prevAction !== this . eventValue ) {
42+ if (
43+ mlrunner . Action . prevActionInstance !== this ||
44+ mlrunner . deviceIsSim ( )
45+ ) {
4346 body ( ) ;
4447 }
48+ if (
49+ mlrunner . Action . prevActionInstance !== this &&
50+ mlrunner . deviceIsSim ( )
51+ ) {
52+ mlrunner . Action . maybeUpdateActionStats ( this ) ;
53+ }
4554 } ;
4655 if ( ! mlrunner . isRunning ( ) ) {
4756 mlrunner . startRunning ( ) ;
@@ -54,14 +63,21 @@ class MlEvent {
5463 }
5564
5665 //% blockId=mlrunner_is_ml_event
57- //% block="is % this action"
66+ //% block="is $ this action"
5867 isEvent ( ) : boolean {
5968 if ( ! mlrunner . isRunning ( ) ) {
6069 mlrunner . startRunning ( ) ;
6170 return false ;
6271 }
6372 return this . eventValue == mlrunner . currentActionId ( ) ;
6473 }
74+
75+ //% blockId=mlrunner_on_ml_event_stop
76+ //% block="on $this stop $duration"
77+ //% draggableParameters="reporter"
78+ onStop ( body : ( duration : number ) => void ) : void {
79+ this . onStopHandler = body ;
80+ }
6581}
6682
6783//% color=#2b64c3 weight=100 icon="\uf108" block="ML Runner" advanced=false
@@ -70,12 +86,31 @@ namespace mlrunner {
7086 //% fixedInstance
7187 export const None = new MlEvent ( 1 , "None" ) ;
7288 export let actions = [ None ] ;
73- export let prevAction : number = 0 ;
74- export let currentAction : number = 1 ;
89+ export let prevActionInstance : MlEvent = None ;
90+ export let currentAction : MlEvent = None ;
91+ export let lastActionTimestamp : number = 0 ;
92+
93+ export function maybeUpdateActionStats ( currentAction : MlEvent ) {
94+ if ( currentAction !== prevActionInstance ) {
95+ let now = input . runningTime ( ) ;
96+ prevActionInstance . lastDuration = now - lastActionTimestamp ;
97+
98+ if ( prevActionInstance . onStopHandler ) {
99+ prevActionInstance . onStopHandler ( prevActionInstance . lastDuration ) ;
100+ }
101+
102+ lastActionTimestamp = now ;
103+ prevActionInstance = currentAction ;
104+ }
105+ }
75106 }
76107
77108 let simIsRunning = false ;
78109
110+ export function deviceIsSim ( ) {
111+ return control . deviceName ( ) . slice ( 0 , 3 ) === "sim" ;
112+ }
113+
79114 /**
80115 * TS shim for C++ function init(), which initialize the ML model with
81116 * an address to a model blob.
@@ -127,7 +162,7 @@ namespace mlrunner {
127162
128163 //% shim=mlrunner::currentEventId
129164 export function currentActionId ( ) : number {
130- return Action . currentAction ;
165+ return Action . currentAction . eventValue ;
131166 }
132167
133168 // Start simulator code.
@@ -174,21 +209,13 @@ namespace mlrunner {
174209 }
175210
176211 function simulateAction ( eventValue : number ) {
177- // Set prevAction to 0 so that re-triggering the same action in the
178- // sim still runs the code in the action event handler.
179- Action . prevAction = 0 ;
180- Action . currentAction = eventValue ;
181212 const simulatedAction = Action . actions . find (
182213 ( action ) => action . eventValue === eventValue
183214 ) ;
184- if ( simulatedAction . hasOnEventHandler ) {
185- control . raiseEvent ( MlRunnerIds . MlRunnerInference , eventValue ) ;
186- } else {
187- Action . prevAction = simulatedAction . eventValue ;
188- }
189- basic . pause ( 500 ) ;
190- Action . prevAction = 0 ;
191- Action . currentAction = 1 ;
215+ Action . currentAction = simulatedAction ;
216+ // This will run the MLEvent onEvent block if it exists in the user's code.
217+ // Otherwise, control.onEvent in autogenerated.ts is fired.
218+ control . raiseEvent ( MlRunnerIds . MlRunnerInference , eventValue ) ;
192219 }
193220
194221 function handleMessage ( buffer : Buffer ) {
0 commit comments