@@ -49,6 +49,8 @@ export class Board {
4949 radio : Radio ;
5050 dataLogging : DataLogging ;
5151
52+ private panicTimeout : any ;
53+
5254 public serialInputBuffer : number [ ] = [ ] ;
5355
5456 private stoppedOverlay : HTMLDivElement ;
@@ -268,6 +270,11 @@ export class Board {
268270 }
269271
270272 async stop ( ) : Promise < void > {
273+ if ( this . panicTimeout ) {
274+ clearTimeout ( this . panicTimeout ) ;
275+ this . panicTimeout = null ;
276+ this . display . clear ( ) ;
277+ }
271278 const interrupt = ( ) => this . serialInputBuffer . push ( 3 , 4 ) ; // Ctrl-C, Ctrl-D.
272279 await this . operations . stop ( interrupt ) ;
273280 this . displayStoppedState ( ) ;
@@ -289,6 +296,110 @@ export class Board {
289296 return this . start ( ) ;
290297 }
291298
299+ panic ( code : number ) : void {
300+ // We should hang MicroPython here. I think ideally we'd stop it entirely so we do this without any WASM.
301+ // For now we just do the display animation.
302+ const sad = [
303+ [ 9 , 9 , 0 , 9 , 9 ] ,
304+ [ 9 , 9 , 0 , 9 , 9 ] ,
305+ [ 0 , 0 , 0 , 0 , 0 ] ,
306+ [ 0 , 9 , 9 , 9 , 0 ] ,
307+ [ 9 , 0 , 0 , 0 , 9 ] ,
308+ ] ;
309+ // Extracted via display.get_pixel.
310+ const digitFont = [
311+ [
312+ [ 0 , 9 , 9 , 0 , 0 ] ,
313+ [ 9 , 0 , 0 , 9 , 0 ] ,
314+ [ 9 , 0 , 0 , 9 , 0 ] ,
315+ [ 9 , 0 , 0 , 9 , 0 ] ,
316+ [ 0 , 9 , 9 , 0 , 0 ] ,
317+ ] ,
318+ [
319+ [ 0 , 0 , 9 , 0 , 0 ] ,
320+ [ 0 , 9 , 9 , 0 , 0 ] ,
321+ [ 0 , 0 , 9 , 0 , 0 ] ,
322+ [ 0 , 0 , 9 , 0 , 0 ] ,
323+ [ 0 , 9 , 9 , 9 , 0 ] ,
324+ ] ,
325+ [
326+ [ 9 , 9 , 9 , 0 , 0 ] ,
327+ [ 0 , 0 , 0 , 9 , 0 ] ,
328+ [ 0 , 9 , 9 , 0 , 0 ] ,
329+ [ 9 , 0 , 0 , 0 , 0 ] ,
330+ [ 9 , 9 , 9 , 9 , 0 ] ,
331+ ] ,
332+ [
333+ [ 9 , 9 , 9 , 9 , 0 ] ,
334+ [ 0 , 0 , 0 , 9 , 0 ] ,
335+ [ 0 , 0 , 9 , 0 , 0 ] ,
336+ [ 9 , 0 , 0 , 9 , 0 ] ,
337+ [ 0 , 9 , 9 , 0 , 0 ] ,
338+ ] ,
339+ [
340+ [ 0 , 0 , 9 , 9 , 0 ] ,
341+ [ 0 , 9 , 0 , 9 , 0 ] ,
342+ [ 9 , 0 , 0 , 9 , 0 ] ,
343+ [ 9 , 9 , 9 , 9 , 9 ] ,
344+ [ 0 , 0 , 0 , 9 , 0 ] ,
345+ ] ,
346+ [
347+ [ 9 , 9 , 9 , 9 , 9 ] ,
348+ [ 9 , 0 , 0 , 0 , 0 ] ,
349+ [ 9 , 9 , 9 , 9 , 0 ] ,
350+ [ 0 , 0 , 0 , 0 , 9 ] ,
351+ [ 9 , 9 , 9 , 9 , 0 ] ,
352+ ] ,
353+ [
354+ [ 0 , 0 , 0 , 9 , 0 ] ,
355+ [ 0 , 0 , 9 , 0 , 0 ] ,
356+ [ 0 , 9 , 9 , 9 , 0 ] ,
357+ [ 9 , 0 , 0 , 0 , 9 ] ,
358+ [ 0 , 9 , 9 , 9 , 0 ] ,
359+ ] ,
360+ [
361+ [ 9 , 9 , 9 , 9 , 9 ] ,
362+ [ 0 , 0 , 0 , 9 , 0 ] ,
363+ [ 0 , 0 , 9 , 0 , 0 ] ,
364+ [ 0 , 9 , 0 , 0 , 0 ] ,
365+ [ 9 , 0 , 0 , 0 , 0 ] ,
366+ ] ,
367+ [
368+ [ 0 , 9 , 9 , 9 , 0 ] ,
369+ [ 9 , 0 , 0 , 0 , 9 ] ,
370+ [ 0 , 9 , 9 , 9 , 0 ] ,
371+ [ 9 , 0 , 0 , 0 , 9 ] ,
372+ [ 0 , 9 , 9 , 9 , 0 ] ,
373+ ] ,
374+ [
375+ [ 0 , 9 , 9 , 9 , 0 ] ,
376+ [ 9 , 0 , 0 , 0 , 9 ] ,
377+ [ 0 , 9 , 9 , 9 , 0 ] ,
378+ [ 0 , 0 , 9 , 0 , 0 ] ,
379+ [ 0 , 9 , 0 , 0 , 0 ] ,
380+ ] ,
381+ ] ;
382+ // Three digit code with leading zero if required.
383+ // For larger values we just display the last three digits.
384+ let digits = code . toString ( ) ;
385+ digits = digits . slice ( - 3 ) ;
386+ const prefix = "0" . repeat ( 3 - digits . length ) ;
387+ digits = prefix + digits ;
388+ const frames = [
389+ sad ,
390+ ...Array . from ( digits ) . map ( ( d ) => digitFont [ parseInt ( d , 10 ) ] ) ,
391+ ] ;
392+ let nextFrameIndex = 0 ;
393+ const showNextFrame = ( ) => {
394+ this . display . show ( frames [ nextFrameIndex ++ % frames . length ] ) ;
395+ this . panicTimeout = setTimeout ( ( ) => {
396+ this . display . clear ( ) ;
397+ this . panicTimeout = setTimeout ( showNextFrame , 60 ) ;
398+ } , 600 ) ;
399+ } ;
400+ showNextFrame ( ) ;
401+ }
402+
292403 mute ( ) {
293404 this . audio . mute ( ) ;
294405 }
0 commit comments