@@ -35,6 +35,32 @@ import { Radio } from "./radio";
35
35
import { RangeSensor , State } from "./state" ;
36
36
import { ModuleWrapper } from "./wasm" ;
37
37
38
+ enum StopKind {
39
+ /**
40
+ * The main Wasm function returned control to us in a normal way.
41
+ */
42
+ Default = "default" ,
43
+ /**
44
+ * The program called panic.
45
+ */
46
+ Panic = "panic" ,
47
+ /**
48
+ * The program requested a reset.
49
+ */
50
+ Reset = "reset" ,
51
+ /**
52
+ * An internal mode where we do not display the stop state UI as we plan to immediately reset.
53
+ * Used for user-requested flash or reset.
54
+ */
55
+ BriefStop = "brief" ,
56
+ /**
57
+ * The user requested the program be interrupted.
58
+ *
59
+ * Note the program could finish for other reasons, but should always count as a user stop.
60
+ */
61
+ UserStop = "user" ,
62
+ }
63
+
38
64
export class PanicError extends Error {
39
65
constructor ( public code : number ) {
40
66
super ( "panic" ) ;
@@ -74,8 +100,6 @@ export class Board {
74
100
radio : Radio ;
75
101
dataLogging : DataLogging ;
76
102
77
- private panicTimeout : any ;
78
-
79
103
public serialInputBuffer : number [ ] = [ ] ;
80
104
81
105
private stoppedOverlay : HTMLDivElement ;
@@ -108,10 +132,19 @@ export class Board {
108
132
*/
109
133
private module : ModuleWrapper | undefined ;
110
134
/**
111
- * If undefined, then when main finishes we stay stopped.
112
- * Otherwise we perform the action then clear this field.
135
+ * Controls the action after the user program completes.
136
+ *
137
+ * Determined by a combination of user actions (stop, reset etc) and program actions.
113
138
*/
114
- private afterStopped : ( ( ) => void ) | undefined ;
139
+ private stopKind : StopKind = StopKind . Default ;
140
+ /**
141
+ * Timeout for a pending start call due to StopKind.Reset.
142
+ */
143
+ private pendingRestartTimeout : any ;
144
+ /**
145
+ * Timeout for the next frame of the panic animation.
146
+ */
147
+ private panicTimeout : any ;
115
148
116
149
constructor (
117
150
private notifications : Notifications ,
@@ -356,6 +389,8 @@ export class Board {
356
389
if ( this . modulePromise || this . module ) {
357
390
throw new Error ( "Module already exists!" ) ;
358
391
}
392
+ clearTimeout ( this . pendingRestartTimeout ) ;
393
+ this . pendingRestartTimeout = null ;
359
394
360
395
this . modulePromise = this . createModule ( ) ;
361
396
const module = await this . modulePromise ;
@@ -365,11 +400,17 @@ export class Board {
365
400
this . displayRunningState ( ) ;
366
401
await module . start ( ) ;
367
402
} catch ( e : any ) {
403
+ // Take care not to overwrite another kind of stop just because the program
404
+ // called restart or panic.
368
405
if ( e instanceof PanicError ) {
369
- panicCode = e . code ;
406
+ if ( this . stopKind === StopKind . Default ) {
407
+ this . stopKind = StopKind . Panic ;
408
+ panicCode = e . code ;
409
+ }
370
410
} else if ( e instanceof ResetError ) {
371
- const noChangeRestart = ( ) => { } ;
372
- this . afterStopped = noChangeRestart ;
411
+ if ( this . stopKind === StopKind . Default ) {
412
+ this . stopKind = StopKind . Reset ;
413
+ }
373
414
} else {
374
415
this . notifications . onInternalError ( e ) ;
375
416
}
@@ -386,30 +427,52 @@ export class Board {
386
427
this . modulePromise = undefined ;
387
428
this . module = undefined ;
388
429
389
- if ( panicCode !== undefined ) {
390
- this . displayPanic ( panicCode ) ;
391
- } else {
392
- if ( this . afterStopped ) {
393
- this . afterStopped ( ) ;
394
- this . afterStopped = undefined ;
395
- setTimeout ( ( ) => this . start ( ) , 0 ) ;
396
- } else {
430
+ switch ( this . stopKind ) {
431
+ case StopKind . Panic : {
432
+ if ( panicCode === undefined ) {
433
+ throw new Error ( "Must be set" ) ;
434
+ }
435
+ this . displayPanic ( panicCode ) ;
436
+ break ;
437
+ }
438
+ case StopKind . Reset : {
439
+ this . pendingRestartTimeout = setTimeout ( ( ) => this . start ( ) , 0 ) ;
440
+ break ;
441
+ }
442
+ case StopKind . BriefStop : {
443
+ // Skip the stopped state.
444
+ break ;
445
+ }
446
+ case StopKind . UserStop : /* Fall through */
447
+ case StopKind . Default : {
397
448
this . displayStoppedState ( ) ;
449
+ break ;
450
+ }
451
+ default : {
452
+ throw new Error ( "Unknown stop kind: " + this . stopKind ) ;
398
453
}
399
454
}
455
+ this . stopKind = StopKind . Default ;
400
456
}
401
457
402
- async stop (
403
- afterStopped : ( ( ) => void ) | undefined = undefined
404
- ) : Promise < void > {
405
- this . afterStopped = afterStopped ;
458
+ async stop ( brief : boolean = false ) : Promise < void > {
406
459
if ( this . panicTimeout ) {
407
460
clearTimeout ( this . panicTimeout ) ;
408
461
this . panicTimeout = null ;
409
462
this . display . clear ( ) ;
410
- this . displayStoppedState ( ) ;
463
+ if ( ! brief ) {
464
+ this . displayStoppedState ( ) ;
465
+ }
466
+ }
467
+ if ( this . pendingRestartTimeout ) {
468
+ clearTimeout ( this . pendingRestartTimeout ) ;
469
+ this . pendingRestartTimeout = null ;
470
+ if ( ! brief ) {
471
+ this . displayStoppedState ( ) ;
472
+ }
411
473
}
412
474
if ( this . modulePromise ) {
475
+ this . stopKind = brief ? StopKind . BriefStop : StopKind . UserStop ;
413
476
// Avoid this.module as we might still be creating it (async).
414
477
const module = await this . modulePromise ;
415
478
module . requestStop ( ) ;
@@ -422,11 +485,10 @@ export class Board {
422
485
423
486
/**
424
487
* An external reset.
425
- * reset() in MicroPython code throws ResetError.
426
488
*/
427
489
async reset ( ) : Promise < void > {
428
- const noChangeRestart = ( ) => { } ;
429
- this . stop ( noChangeRestart ) ;
490
+ await this . stop ( true ) ;
491
+ return this . start ( ) ;
430
492
}
431
493
432
494
async flash ( filesystem : Record < string , Uint8Array > ) : Promise < void > {
@@ -440,7 +502,7 @@ export class Board {
440
502
} ;
441
503
if ( this . modulePromise ) {
442
504
// If it's running then we need to stop before flash.
443
- return this . stop ( flashFileSystem ) ;
505
+ await this . stop ( true ) ;
444
506
}
445
507
flashFileSystem ( ) ;
446
508
return this . start ( ) ;
0 commit comments