11//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+ }
538
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
839const 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 ) => {
1156 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+ // ================================================================================
17129 // Show a message on the screen (if available)
18130 showMessage : ( txt ) => {
19131 console . log ( `<COMMS> showMessage ${ JSON . stringify ( txt ) } ` ) ;
@@ -37,29 +149,32 @@ const Comms = {
37149 }
38150 } ,
39151 // Reset the device, if opt=="wipe" erase any saved code
40- reset : ( opt ) => new Promise ( ( resolve , reject ) => {
152+ reset : ( opt ) => {
41153 let tries = 8 ;
42- if ( Const . NO_RESET ) return resolve ( ) ;
154+ if ( Const . NO_RESET ) return Promise . resolve ( ) ;
43155 console . log ( "<COMMS> reset" ) ;
44- Puck . write ( `\x03\x10reset(${ opt == "wipe" ?"1" :"" } );\n` , function rstHandler ( result ) {
156+
157+ function rstHandler ( result ) {
45158 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" ) ;
47160 if ( result == "" && ( tries -- > 0 ) ) {
48161 console . log ( `<COMMS> reset: no response. waiting ${ tries } ...` ) ;
49- Puck . write ( "\x03" , rstHandler ) ;
162+ return Comms . write ( "\x03" ) . then ( rstHandler ) ;
50163 } else if ( result . endsWith ( "debug>" ) ) {
51164 console . log ( `<COMMS> reset: watch in debug mode, interrupting...` ) ;
52- Puck . write ( "\x03" , rstHandler ) ;
165+ return Comms . write ( "\x03" ) . then ( rstHandler ) ;
53166 } else {
54167 console . log ( `<COMMS> reset: rebooted - sending commands to clear out any boot code` ) ;
55168 // 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 ( ) {
57170 console . log ( `<COMMS> reset: complete.` ) ;
58- setTimeout ( resolve , 250 ) ;
171+ return new Promise ( resolve => setTimeout ( resolve , 250 ) )
59172 } ) ;
60173 }
61- } ) ;
62- } ) ,
174+ }
175+
176+ return Comms . write ( `\x03\x10reset(${ opt == "wipe" ?"1" :"" } );\n` ) . then ( rstHandler ) ;
177+ } ,
63178 // Upload a list of newline-separated commands that start with \x10
64179 // You should call Comms.write("\x10"+Comms.getProgressCmd()+"\n")) first
65180 uploadCommandList : ( cmds , currentBytes , maxBytes ) => {
@@ -103,13 +218,12 @@ const Comms = {
103218 ignore = true ;
104219 }
105220 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
107222 it just gave us the first line in the input buffer, but there may have been more.
108223 We take the next line (or undefined) and call ourselves again to handle that.
109224 Just in case, delay a little to give our previous command time to finish.*/
110-
111225 setTimeout ( function ( ) {
112- let connection = Puck . getConnection ( ) ;
226+ let connection = Comms . getConnection ( ) ;
113227 let newLineIdx = connection . received . indexOf ( "\n" ) ;
114228 let l = undefined ;
115229 if ( newLineIdx >= 0 ) {
@@ -126,7 +240,7 @@ const Comms = {
126240 }
127241 // Actually write the command with a 'print OK' at the end, and use responseHandler
128242 // 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 ) ;
130244 }
131245
132246 uploadCmd ( )
@@ -201,33 +315,30 @@ const Comms = {
201315 // Get Device ID, version, storage stats, and a JSON list of installed apps
202316 getDeviceInfo : ( noReset ) => {
203317 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+ }
210323
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" ) ;
226330 }
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+ } ;
228340
229- checkCtrlC ( result ) ;
230- } ) ;
341+ return checkCtrlC ( result ) ;
231342 } ) .
232343 then ( ( result ) => new Promise ( ( resolve , reject ) => {
233344 console . log ( "<COMMS> Ctrl-C gave" , JSON . stringify ( result ) ) ;
@@ -250,10 +361,10 @@ const Comms = {
250361 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` ;
251362 else // the default, files in Storage
252363 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 => {
254365 Progress . hide ( { sticky :true } ) ;
255366 if ( ! appListStr ) appListStr = "" ;
256- var connection = Puck . getConnection ( ) ;
367+ var connection = Comms . getConnection ( ) ;
257368 if ( connection ) {
258369 appListStr = appListStr + "\n" + connection . received ; // add *any* information we have received so far, including what was returned
259370 connection . received = "" ; // clear received data just in case
@@ -378,7 +489,7 @@ const Comms = {
378489 if ( result == "" && ( timeout -- ) ) {
379490 console . log ( "<COMMS> removeAllApps: no result - waiting some more (" + timeout + ")." ) ;
380491 // 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 ) ;
382493 } else {
383494 Progress . hide ( { sticky :true } ) ;
384495 if ( ! result || result . trim ( ) != "OK" ) {
@@ -390,7 +501,7 @@ const Comms = {
390501 }
391502 // Use write with newline here so we wait for it to finish
392503 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 ) ;
394505 } ) . then ( ( ) => new Promise ( resolve => {
395506 console . log ( "<COMMS> removeAllApps: Erase complete, waiting 500ms for 'reset()'" ) ;
396507 setTimeout ( resolve , 500 ) ;
@@ -416,25 +527,20 @@ const Comms = {
416527 let cmd = "load();\n" ;
417528 return Comms . write ( cmd ) ;
418529 } ,
419- // Check if we're connected
420- isConnected : ( ) => {
421- return ! ! Puck . getConnection ( ) ;
422- } ,
423530 // Force a disconnect from the device
424531 disconnectDevice : ( ) => {
425- let connection = Puck . getConnection ( ) ;
532+ let connection = Comms . getConnection ( ) ;
426533 if ( ! connection ) return ;
427534 connection . close ( ) ;
428535 } ,
429536 // call back when the connection state changes
430537 watchConnectionChange : cb => {
431- let connected = Puck . isConnected ( ) ;
538+ let connected = Comms . isConnected ( ) ;
432539
433540 //TODO Switch to an event listener when Puck will support it
434541 let interval = setInterval ( ( ) => {
435- if ( connected === Puck . isConnected ( ) ) return ;
436-
437- connected = Puck . isConnected ( ) ;
542+ if ( connected === Comms . isConnected ( ) ) return ;
543+ connected = Comms . isConnected ( ) ;
438544 cb ( connected ) ;
439545 } , 1000 ) ;
440546
@@ -446,18 +552,16 @@ const Comms = {
446552 // List all files on the device.
447553 // options can be undefined, or {sf:true} for only storage files, or {sf:false} for only normal files
448554 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 ;
461565 } ) ;
462566 } ) ;
463567 } ,
@@ -467,7 +571,7 @@ const Comms = {
467571 // Use "\xFF" to signal end of file (can't occur in StorageFiles anyway)
468572 let fileContent = "" ;
469573 let fileSize = undefined ;
470- let connection = Puck . getConnection ( ) ;
574+ let connection = Comms . getConnection ( ) ;
471575 connection . received = "" ;
472576 connection . cb = function ( d ) {
473577 let finished = false ;
@@ -535,33 +639,4 @@ ${Const.CONNECTION_DEVICE}.print("\\xFF");
535639 Comms . uploadCommandList ( cmds , 0 , cmds . length )
536640 ) ;
537641 } ,
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- }
567642} ;
0 commit comments