1
1
//Puck.debug=3;
2
- console . log ( "=============================================" )
3
- console . log ( "Type 'Puck.debug=3' for full BLE debug info" )
4
- console . log ( "=============================================" )
2
+ console . log ( "================================================" )
3
+ console . log ( "Type 'Comms.debug()' to enable Comms debug info" )
4
+ console . log ( "================================================" )
5
+
6
+ /*
7
+
8
+ Puck = {
9
+ /// Are we writing debug information? 0 is no, 1 is some, 2 is more, 3 is all.
10
+ debug : UART.debug,
11
+ /// Used internally to write log information - you can replace this with your own function
12
+ log : function(level, s) { if (level <= this.debug) console.log("<UART> "+s)},
13
+ /// Called with the current send progress or undefined when done - you can replace this with your own function
14
+ writeProgress : function() {},
15
+ connect : UART.connect,
16
+ write : UART.write,
17
+ eval : UART.eval,
18
+ isConnected : () => UART.isConnected() && UART.getConnection().isOpen,
19
+ getConnection : UART.getConnection,
20
+ close : UART.close,
21
+ RECEIVED_NOT_IN_DATA_HANDLER : true, // hack for Comms.on
22
+ };
23
+ // FIXME: disconnected event?
24
+ */
25
+
26
+ /// Add progress handler so we get nice upload progress shown
27
+ {
28
+ let COMMS = ( typeof UART !== undefined ) ?UART :Puck ;
29
+ COMMS . writeProgress = function ( charsSent , charsTotal ) {
30
+ if ( charsSent === undefined || charsTotal < 10 ) {
31
+ Progress . hide ( ) ;
32
+ return ;
33
+ }
34
+ let percent = Math . round ( charsSent * 100 / charsTotal ) ;
35
+ Progress . show ( { percent : percent } ) ;
36
+ } ;
37
+ }
5
38
6
- // TODO: Add Comms.write/eval which return promises, and move over to using those
7
- // FIXME: use UART lib so that we handle errors properly
8
39
const Comms = {
9
- // Write the given data, returns a promise
10
- write : ( data ) => new Promise ( ( resolve , reject ) => {
40
+ // ================================================================================
41
+ // Low Level Comms
42
+ /// enable debug print statements
43
+ debug : ( ) => {
44
+ if ( typeof UART !== undefined )
45
+ UART . debug = 3 ;
46
+ else
47
+ Puck . debug = 3 ;
48
+ } ,
49
+
50
+ /** Write the given data, returns a promise containing the data received immediately after sending the command
51
+ options = {
52
+ waitNewLine : bool // wait for a newline (rather than just 300ms of inactivity)
53
+ }
54
+ */
55
+ write : ( data , options ) => {
11
56
if ( data === undefined ) throw new Error ( "Comms.write(undefined) called!" )
12
- return Puck . write ( data , function ( result ) {
13
- if ( result === null ) return reject ( "" ) ;
14
- resolve ( result ) ;
15
- } ) ;
16
- } ) ,
57
+ options = options || { } ;
58
+ if ( typeof UART !== undefined ) { // New method
59
+ return UART . write ( data , undefined , ! ! options . waitNewLine ) ;
60
+ } else { // Old method
61
+ return new Promise ( ( resolve , reject ) =>
62
+ Puck . write ( data , result => {
63
+ if ( result === null ) return reject ( "" ) ;
64
+ resolve ( result ) ;
65
+ } , ! ! options . waitNewLine )
66
+ ) ;
67
+ }
68
+ } ,
69
+ /// Evaluate the given expression, return the result as a promise
70
+ eval : ( expr ) => {
71
+ if ( expr === undefined ) throw new Error ( "Comms.eval(undefined) called!" )
72
+ if ( typeof UART === undefined ) { // New method
73
+ return UART . eval ( expr ) ;
74
+ } else { // Old method
75
+ return new Promise ( ( resolve , reject ) =>
76
+ Puck . eval ( expr , result => {
77
+ if ( result === null ) return reject ( "" ) ;
78
+ resolve ( result ) ;
79
+ } )
80
+ ) ;
81
+ }
82
+ } ,
83
+ /// Return true if we're connected, false if not
84
+ isConnected : ( ) => {
85
+ if ( typeof UART !== undefined ) { // New method
86
+ return UART . isConnected ( ) ;
87
+ } else { // Old method
88
+ return Puck . isConnected ( ) ;
89
+ }
90
+ } ,
91
+ /// Get the currently active connection object
92
+ getConnection : ( ) => {
93
+ if ( typeof UART !== undefined ) { // New method
94
+ return UART . getConnection ( ) ;
95
+ } else { // Old method
96
+ return Puck . getConnection ( ) ;
97
+ }
98
+ } ,
99
+ // Faking EventEmitter
100
+ handlers : { } ,
101
+ on : function ( id , callback ) { // calling with callback=undefined will disable
102
+ if ( id != "data" ) throw new Error ( "Only data callback is supported" ) ;
103
+ var connection = Puck . getConnection ( ) ;
104
+ if ( ! connection ) throw new Error ( "No active connection" ) ;
105
+ /* This is a bit of a mess - the Puck.js lib only supports one callback with `.on`. If you
106
+ do Puck.getConnection().on('data') then it blows away the default one which is used for
107
+ .write/.eval and you can't get it back unless you reconnect. So rather than trying to fix the
108
+ Puck lib we just copy in the default handler here. */
109
+ if ( callback === undefined ) {
110
+ connection . on ( "data" , function ( d ) { // the default handler
111
+ if ( ! Puck . RECEIVED_NOT_IN_DATA_HANDLER ) {
112
+ connection . received += d ;
113
+ connection . hadData = true ;
114
+ }
115
+ if ( connection . cb ) connection . cb ( d ) ;
116
+ } ) ;
117
+ } else {
118
+ connection . on ( "data" , function ( d ) {
119
+ if ( ! Puck . RECEIVED_NOT_IN_DATA_HANDLER ) {
120
+ connection . received += d ;
121
+ connection . hadData = true ;
122
+ }
123
+ if ( connection . cb ) connection . cb ( d ) ;
124
+ callback ( d ) ;
125
+ } ) ;
126
+ }
127
+ } ,
128
+ // ================================================================================
17
129
// Show a message on the screen (if available)
18
130
showMessage : ( txt ) => {
19
131
console . log ( `<COMMS> showMessage ${ JSON . stringify ( txt ) } ` ) ;
@@ -37,29 +149,32 @@ const Comms = {
37
149
}
38
150
} ,
39
151
// Reset the device, if opt=="wipe" erase any saved code
40
- reset : ( opt ) => new Promise ( ( resolve , reject ) => {
152
+ reset : ( opt ) => {
41
153
let tries = 8 ;
42
- if ( Const . NO_RESET ) return resolve ( ) ;
154
+ if ( Const . NO_RESET ) return Promise . resolve ( ) ;
43
155
console . log ( "<COMMS> reset" ) ;
44
- Puck . write ( `\x03\x10reset(${ opt == "wipe" ?"1" :"" } );\n` , function rstHandler ( result ) {
156
+
157
+ function rstHandler ( result ) {
45
158
console . log ( "<COMMS> reset: got " + JSON . stringify ( result ) ) ;
46
- if ( result === null ) return reject ( "Connection failed" ) ;
159
+ if ( result === null ) return Promise . reject ( "Connection failed" ) ;
47
160
if ( result == "" && ( tries -- > 0 ) ) {
48
161
console . log ( `<COMMS> reset: no response. waiting ${ tries } ...` ) ;
49
- Puck . write ( "\x03" , rstHandler ) ;
162
+ return Comms . write ( "\x03" ) . then ( rstHandler ) ;
50
163
} else if ( result . endsWith ( "debug>" ) ) {
51
164
console . log ( `<COMMS> reset: watch in debug mode, interrupting...` ) ;
52
- Puck . write ( "\x03" , rstHandler ) ;
165
+ return Comms . write ( "\x03" ) . then ( rstHandler ) ;
53
166
} else {
54
167
console . log ( `<COMMS> reset: rebooted - sending commands to clear out any boot code` ) ;
55
168
// see https://github.com/espruino/BangleApps/issues/1759
56
- Puck . write ( "\x10clearInterval();clearWatch();global.Bangle&&Bangle.removeAllListeners();E.removeAllListeners();global.NRF&&NRF.removeAllListeners();\n" , function ( ) {
169
+ return Comms . write ( "\x10clearInterval();clearWatch();global.Bangle&&Bangle.removeAllListeners();E.removeAllListeners();global.NRF&&NRF.removeAllListeners();\n" ) . then ( function ( ) {
57
170
console . log ( `<COMMS> reset: complete.` ) ;
58
- setTimeout ( resolve , 250 ) ;
171
+ return new Promise ( resolve => setTimeout ( resolve , 250 ) )
59
172
} ) ;
60
173
}
61
- } ) ;
62
- } ) ,
174
+ }
175
+
176
+ return Comms . write ( `\x03\x10reset(${ opt == "wipe" ?"1" :"" } );\n` ) . then ( rstHandler ) ;
177
+ } ,
63
178
// Upload a list of newline-separated commands that start with \x10
64
179
// You should call Comms.write("\x10"+Comms.getProgressCmd()+"\n")) first
65
180
uploadCommandList : ( cmds , currentBytes , maxBytes ) => {
@@ -103,13 +218,12 @@ const Comms = {
103
218
ignore = true ;
104
219
}
105
220
if ( ignore ) {
106
- /* Here we have to poke around inside the Puck.js library internals. Basically
221
+ /* Here we have to poke around inside the Comms library internals. Basically
107
222
it just gave us the first line in the input buffer, but there may have been more.
108
223
We take the next line (or undefined) and call ourselves again to handle that.
109
224
Just in case, delay a little to give our previous command time to finish.*/
110
-
111
225
setTimeout ( function ( ) {
112
- let connection = Puck . getConnection ( ) ;
226
+ let connection = Comms . getConnection ( ) ;
113
227
let newLineIdx = connection . received . indexOf ( "\n" ) ;
114
228
let l = undefined ;
115
229
if ( newLineIdx >= 0 ) {
@@ -126,7 +240,7 @@ const Comms = {
126
240
}
127
241
// Actually write the command with a 'print OK' at the end, and use responseHandler
128
242
// to deal with the response. If OK we call uploadCmd to upload the next block
129
- Puck . write ( `${ cmd } ;${ Comms . getProgressCmd ( currentBytes / maxBytes ) } ${ Const . CONNECTION_DEVICE } .println("OK")\n` , responseHandler , true /* wait for a newline*/ ) ;
243
+ return Comms . write ( `${ cmd } ;${ Comms . getProgressCmd ( currentBytes / maxBytes ) } ${ Const . CONNECTION_DEVICE } .println("OK")\n` , { waitNewLine : true } ) . then ( responseHandler ) ;
130
244
}
131
245
132
246
uploadCmd ( )
@@ -201,33 +315,30 @@ const Comms = {
201
315
// Get Device ID, version, storage stats, and a JSON list of installed apps
202
316
getDeviceInfo : ( noReset ) => {
203
317
Progress . show ( { title :`Getting device info...` , sticky :true } ) ;
204
- return new Promise ( ( resolve , reject ) => {
205
- Puck . write ( "\x03" , ( result ) => {
206
- if ( result === null ) {
207
- Progress . hide ( { sticky :true } ) ;
208
- return reject ( "" ) ;
209
- }
318
+ return Comms . write ( "\x03" ) . then ( result => {
319
+ if ( result === null ) {
320
+ Progress . hide ( { sticky :true } ) ;
321
+ return Promise . reject ( "No response" ) ;
322
+ }
210
323
211
- let interrupts = 0 ;
212
- const checkCtrlC = result => {
213
- if ( result . endsWith ( "debug>" ) ) {
214
- if ( interrupts > 3 ) {
215
- console . log ( "<COMMS> can't interrupt watch out of debug mode, giving up." , result ) ;
216
- reject ( "" ) ;
217
- return ;
218
- }
219
- console . log ( "<COMMS> watch was in debug mode, interrupting." , result ) ;
220
- // we got a debug prompt - we interrupted the watch while JS was executing
221
- // so we're in debug mode, issue another ctrl-c to bump the watch out of it
222
- Puck . write ( "\x03" , checkCtrlC ) ;
223
- interrupts ++ ;
224
- } else {
225
- resolve ( result ) ;
324
+ let interrupts = 0 ;
325
+ const checkCtrlC = result => {
326
+ if ( result . endsWith ( "debug>" ) ) {
327
+ if ( interrupts > 3 ) {
328
+ console . log ( "<COMMS> can't interrupt watch out of debug mode, giving up." , result ) ;
329
+ return Promise . reject ( "Stuck in debug mode" ) ;
226
330
}
227
- } ;
331
+ console . log ( "<COMMS> watch was in debug mode, interrupting." , result ) ;
332
+ // we got a debug prompt - we interrupted the watch while JS was executing
333
+ // so we're in debug mode, issue another ctrl-c to bump the watch out of it
334
+ return Comms . write ( "\x03" ) . then ( checkCtrlC ) ;
335
+ interrupts ++ ;
336
+ } else {
337
+ return result ;
338
+ }
339
+ } ;
228
340
229
- checkCtrlC ( result ) ;
230
- } ) ;
341
+ return checkCtrlC ( result ) ;
231
342
} ) .
232
343
then ( ( result ) => new Promise ( ( resolve , reject ) => {
233
344
console . log ( "<COMMS> Ctrl-C gave" , JSON . stringify ( result ) ) ;
@@ -250,10 +361,10 @@ const Comms = {
250
361
cmd = `\x10${ device } .print("[");if (!require("fs").statSync("APPINFO"))require("fs").mkdir("APPINFO");require("fs").readdirSync("APPINFO").forEach(f=>{var j=JSON.parse(require("fs").readFileSync("APPINFO/"+f))||"{}";${ device } .print(JSON.stringify({id:f.slice(0,-5),version:j.version,files:j.files,data:j.data,type:j.type})+",")});${ device } .println(${ finalJS } )\n` ;
251
362
else // the default, files in Storage
252
363
cmd = `\x10${ device } .print("[");require("Storage").list(/\\.info$/).forEach(f=>{var j=require("Storage").readJSON(f,1)||{};${ device } .print(JSON.stringify({id:f.slice(0,-5),version:j.version,files:j.files,data:j.data,type:j.type})+",")});${ device } .println(${ finalJS } )\n` ;
253
- Puck . write ( cmd , ( appListStr , err ) => {
364
+ Comms . write ( cmd , { waitNewLine : true } ) . then ( appListStr => {
254
365
Progress . hide ( { sticky :true } ) ;
255
366
if ( ! appListStr ) appListStr = "" ;
256
- var connection = Puck . getConnection ( ) ;
367
+ var connection = Comms . getConnection ( ) ;
257
368
if ( connection ) {
258
369
appListStr = appListStr + "\n" + connection . received ; // add *any* information we have received so far, including what was returned
259
370
connection . received = "" ; // clear received data just in case
@@ -378,7 +489,7 @@ const Comms = {
378
489
if ( result == "" && ( timeout -- ) ) {
379
490
console . log ( "<COMMS> removeAllApps: no result - waiting some more (" + timeout + ")." ) ;
380
491
// send space and delete - so it's something, but it should just cancel out
381
- Puck . write ( " \u0008" , handleResult , true /* wait for newline */ ) ;
492
+ Comms . write ( " \u0008" , { waitNewLine : true } ) . then ( handleResult ) ;
382
493
} else {
383
494
Progress . hide ( { sticky :true } ) ;
384
495
if ( ! result || result . trim ( ) != "OK" ) {
@@ -390,7 +501,7 @@ const Comms = {
390
501
}
391
502
// Use write with newline here so we wait for it to finish
392
503
let cmd = `\x10E.showMessage("Erasing...");require("Storage").eraseAll();${ Const . CONNECTION_DEVICE } .println("OK");reset()\n` ;
393
- Puck . write ( cmd , handleResult , true /* wait for newline */ ) ;
504
+ Comms . write ( cmd , { waitNewLine : true } ) . then ( handleResult ) ;
394
505
} ) . then ( ( ) => new Promise ( resolve => {
395
506
console . log ( "<COMMS> removeAllApps: Erase complete, waiting 500ms for 'reset()'" ) ;
396
507
setTimeout ( resolve , 500 ) ;
@@ -416,25 +527,20 @@ const Comms = {
416
527
let cmd = "load();\n" ;
417
528
return Comms . write ( cmd ) ;
418
529
} ,
419
- // Check if we're connected
420
- isConnected : ( ) => {
421
- return ! ! Puck . getConnection ( ) ;
422
- } ,
423
530
// Force a disconnect from the device
424
531
disconnectDevice : ( ) => {
425
- let connection = Puck . getConnection ( ) ;
532
+ let connection = Comms . getConnection ( ) ;
426
533
if ( ! connection ) return ;
427
534
connection . close ( ) ;
428
535
} ,
429
536
// call back when the connection state changes
430
537
watchConnectionChange : cb => {
431
- let connected = Puck . isConnected ( ) ;
538
+ let connected = Comms . isConnected ( ) ;
432
539
433
540
//TODO Switch to an event listener when Puck will support it
434
541
let interval = setInterval ( ( ) => {
435
- if ( connected === Puck . isConnected ( ) ) return ;
436
-
437
- connected = Puck . isConnected ( ) ;
542
+ if ( connected === Comms . isConnected ( ) ) return ;
543
+ connected = Comms . isConnected ( ) ;
438
544
cb ( connected ) ;
439
545
} , 1000 ) ;
440
546
@@ -446,18 +552,16 @@ const Comms = {
446
552
// List all files on the device.
447
553
// options can be undefined, or {sf:true} for only storage files, or {sf:false} for only normal files
448
554
listFiles : ( options ) => {
449
- return new Promise ( ( resolve , reject ) => {
450
- Puck . write ( "\x03" , ( result ) => {
451
- if ( result === null ) return reject ( "" ) ;
452
- let args = "" ;
453
- if ( options && options . sf !== undefined ) args = `undefined,{sf:${ options . sf } }` ;
454
- //use encodeURIComponent to serialize octal sequence of append files
455
- Puck . eval ( `require("Storage").list(${ args } ).map(encodeURIComponent)` , ( files , err ) => {
456
- if ( files === null ) return reject ( err || "" ) ;
457
- files = files . map ( decodeURIComponent ) ;
458
- console . log ( "<COMMS> listFiles" , files ) ;
459
- resolve ( files ) ;
460
- } ) ;
555
+ return Comms . write ( " \x03" ) . then ( result => {
556
+ if ( result === null ) return Promise . reject ( "Ctrl-C failed" ) ;
557
+ let args = "" ;
558
+ if ( options && options . sf !== undefined ) args = `undefined,{sf:${ options . sf } }` ;
559
+ //use encodeURIComponent to serialize octal sequence of append files
560
+ return Comms . eval ( `require("Storage").list(${ args } ).map(encodeURIComponent)` , ( files , err ) => {
561
+ if ( files === null ) return Promise . reject ( err || "" ) ;
562
+ files = files . map ( decodeURIComponent ) ;
563
+ console . log ( "<COMMS> listFiles" , files ) ;
564
+ return files ;
461
565
} ) ;
462
566
} ) ;
463
567
} ,
@@ -467,7 +571,7 @@ const Comms = {
467
571
// Use "\xFF" to signal end of file (can't occur in StorageFiles anyway)
468
572
let fileContent = "" ;
469
573
let fileSize = undefined ;
470
- let connection = Puck . getConnection ( ) ;
574
+ let connection = Comms . getConnection ( ) ;
471
575
connection . received = "" ;
472
576
connection . cb = function ( d ) {
473
577
let finished = false ;
@@ -535,33 +639,4 @@ ${Const.CONNECTION_DEVICE}.print("\\xFF");
535
639
Comms . uploadCommandList ( cmds , 0 , cmds . length )
536
640
) ;
537
641
} ,
538
- // Faking EventEmitter
539
- handlers : { } ,
540
- on : function ( id , callback ) { // calling with callback=undefined will disable
541
- if ( id != "data" ) throw new Error ( "Only data callback is supported" ) ;
542
- var connection = Puck . getConnection ( ) ;
543
- if ( ! connection ) throw new Error ( "No active connection" ) ;
544
- /* This is a bit of a mess - the Puck.js lib only supports one callback with `.on`. If you
545
- do Puck.getConnection().on('data') then it blows away the default one which is used for
546
- .write/.eval and you can't get it back unless you reconnect. So rather than trying to fix the
547
- Puck lib we just copy in the default handler here. */
548
- if ( callback === undefined ) {
549
- connection . on ( "data" , function ( d ) { // the default handler
550
- if ( ! Puck . RECEIVED_NOT_IN_DATA_HANDLER ) {
551
- connection . received += d ;
552
- connection . hadData = true ;
553
- }
554
- if ( connection . cb ) connection . cb ( d ) ;
555
- } ) ;
556
- } else {
557
- connection . on ( "data" , function ( d ) {
558
- if ( ! Puck . RECEIVED_NOT_IN_DATA_HANDLER ) {
559
- connection . received += d ;
560
- connection . hadData = true ;
561
- }
562
- if ( connection . cb ) connection . cb ( d ) ;
563
- callback ( d ) ;
564
- } ) ;
565
- }
566
- }
567
642
} ;
0 commit comments