2021-05-26 15:21:52 +00:00
/ * T h i s r e w r i t e s b o o t 0 . j s b a s e d o n c u r r e n t s e t t i n g s . I f s e t t i n g s c h a n g e d t h e n i t
recalculates , but this avoids us doing a whole bunch of reconfiguration most
of the time . * /
2022-12-05 17:09:09 +00:00
{ // execute in our own scope so we don't have to free variables...
2022-04-10 19:35:46 +00:00
E . showMessage ( /*LANG*/ "Updating boot0..." ) ;
2022-12-05 17:09:09 +00:00
let s = require ( 'Storage' ) . readJSON ( 'setting.json' , 1 ) || { } ;
const BANGLEJS2 = process . env . HWVERSION == 2 ; // Is Bangle.js 2
const FWVERSION = parseFloat ( process . env . VERSION . replace ( "v" , "" ) . replace ( /\.(\d\d)$/ , ".0$1" ) ) ;
const DEBUG = s . bootDebug ; // we can set this to enable debugging output in boot0
let boot = "" , bootPost = "" ;
if ( DEBUG ) {
boot += "var _tm=Date.now()\n" ;
bootPost += "delete _tm;" ;
}
2021-10-26 09:23:39 +00:00
if ( require ( 'Storage' ) . hash ) { // new in 2v11 - helps ensure files haven't changed
2022-12-05 17:09:09 +00:00
let CRC = E . CRC32 ( require ( 'Storage' ) . read ( 'setting.json' ) ) + require ( 'Storage' ) . hash ( /\.boot\.js/ ) + E . CRC32 ( process . env . GIT _COMMIT ) ;
2022-01-05 16:37:18 +00:00
boot += ` if (E.CRC32(require('Storage').read('setting.json'))+require('Storage').hash(/ \\ .boot \\ .js/)+E.CRC32(process.env.GIT_COMMIT)!= ${ CRC } ) ` ;
2021-10-26 09:23:39 +00:00
} else {
2022-12-05 17:09:09 +00:00
let CRC = E . CRC32 ( require ( 'Storage' ) . read ( 'setting.json' ) ) + E . CRC32 ( require ( 'Storage' ) . list ( /\.boot\.js/ ) ) + E . CRC32 ( process . env . GIT _COMMIT ) ;
2022-01-05 16:37:18 +00:00
boot += ` if (E.CRC32(require('Storage').read('setting.json'))+E.CRC32(require('Storage').list(/ \\ .boot \\ .js/))+E.CRC32(process.env.GIT_COMMIT)!= ${ CRC } ) ` ;
2021-10-26 09:23:39 +00:00
}
boot += ` { eval(require('Storage').read('bootupdate.js')); throw "Storage Updated!"} \n ` ;
2021-05-26 15:21:52 +00:00
boot += ` E.setFlags({pretokenise:1}); \n ` ;
2021-10-26 09:23:39 +00:00
boot += ` var bleServices = {}, bleServiceOptions = { uart : true}; \n ` ;
2022-03-17 09:54:02 +00:00
bootPost += ` NRF.setServices(bleServices, bleServiceOptions);delete bleServices,bleServiceOptions; \n ` ; // executed after other boot code
2021-05-26 15:21:52 +00:00
if ( s . ble !== false ) {
if ( s . HID ) { // Human interface device
if ( s . HID == "joy" ) boot += ` Bangle.HID = E.toUint8Array(atob("BQEJBKEBCQGhAAUJGQEpBRUAJQGVBXUBgQKVA3UBgQMFAQkwCTEVgSV/dQiVAoECwMA=")); ` ;
2022-01-07 15:44:54 +00:00
else if ( s . HID == "com" ) boot += ` Bangle.HID = E.toUint8Array(atob("BQEJAqEBhQEJAaEABQkZASkFFQAlAZUFdQGBApUBdQOBAwUBCTAJMQk4FYElf3UIlQOBBgUMCjgCFYElf3UIlQGBBsDABQEJBqEBhQIFBxngKecVACUBdQGVCIECdQiVAYEBGQApcxUAJXOVBXUIgQDA")); `
2021-05-26 15:21:52 +00:00
else if ( s . HID == "kb" ) boot += ` Bangle.HID = E.toUint8Array(atob("BQEJBqEBBQcZ4CnnFQAlAXUBlQiBApUBdQiBAZUFdQEFCBkBKQWRApUBdQORAZUGdQgVACVzBQcZAClzgQAJBRUAJv8AdQiVArECwA==")); `
else /*kbmedia*/ boot += ` Bangle.HID = E.toUint8Array(atob("BQEJBqEBhQIFBxngKecVACUBdQGVCIEClQF1CIEBlQV1AQUIGQEpBZEClQF1A5EBlQZ1CBUAJXMFBxkAKXOBAAkFFQAm/wB1CJUCsQLABQwJAaEBhQEVACUBdQGVAQm1gQIJtoECCbeBAgm4gQIJzYECCeKBAgnpgQIJ6oECwA==")); ` ;
2021-10-26 09:23:39 +00:00
boot += ` bleServiceOptions.hid=Bangle.HID; \n ` ;
2021-05-26 15:21:52 +00:00
}
}
2023-01-31 22:18:15 +00:00
// settings.log 0-off, 1-display, 2-log, 3-both
if ( s . log >= 2 ) { // logging to file
2021-12-09 16:49:28 +00:00
boot += ` _DBGLOG=require("Storage").open("log.txt","a");
` ;
} if ( s . blerepl === false ) { // If not programmable, force terminal off Bluetooth
2023-01-31 22:18:15 +00:00
if ( s . log >= 2 ) boot += ` _DBGLOG=require("Storage").open("log.txt","a");
2021-12-09 16:49:28 +00:00
LoopbackB . on ( 'data' , function ( d ) { _DBGLOG . write ( d ) ; Terminal . write ( d ) ; } ) ;
LoopbackA . setConsole ( true ) ; \ n ` ;
2023-01-31 22:18:15 +00:00
else if ( s . log == 1 || s . log == 3 ) boot += ` Terminal.setConsole(true); \n ` ; // if showing debug, force REPL onto terminal
2021-05-26 15:21:52 +00:00
else boot += ` E.setConsole(null,{force:true}); \n ` ; // on new (2v05+) firmware we have E.setConsole which allows a 'null' console
/ * I f n o t p r o g r a m m a b l e a d d o u r o w n h a n d l e r f o r B l u e t o o t h d a t a
to allow Gadgetbridge commands to be received * /
boot += `
Bluetooth . line = "" ;
Bluetooth . on ( 'data' , function ( d ) {
2022-03-11 11:39:29 +00:00
var l = ( Bluetooth . line + d ) . split ( /[\\n\\r]/ ) ;
2021-05-26 15:21:52 +00:00
Bluetooth . line = l . pop ( ) ;
l . forEach ( n => Bluetooth . emit ( "line" , n ) ) ;
} ) ;
Bluetooth . on ( 'line' , function ( l ) {
if ( l . startsWith ( '\x10' ) ) l = l . slice ( 1 ) ;
if ( l . startsWith ( 'GB({' ) && l . endsWith ( '})' ) && global . GB )
try { global . GB ( JSON . parse ( l . slice ( 3 , - 1 ) ) ) ; } catch ( e ) { }
} ) ; \ n ` ;
} else {
2023-01-31 22:18:15 +00:00
if ( s . log >= 2 ) boot += ` _DBGLOG=require("Storage").open("log.txt","a");
2021-12-09 16:49:28 +00:00
LoopbackB . on ( 'data' , function ( d ) { _DBGLOG . write ( d ) ; Terminal . write ( d ) ; } ) ;
if ( ! NRF . getSecurityStatus ( ) . connected ) LoopbackA . setConsole ( ) ; \ n ` ;
2023-01-31 22:18:15 +00:00
else if ( s . log == 1 || s . log == 3 ) boot += ` if (!NRF.getSecurityStatus().connected) Terminal.setConsole(); \n ` ; // if showing debug, put REPL on terminal (until connection)
2021-05-26 15:21:52 +00:00
else boot += ` Bluetooth.setConsole(true); \n ` ; // else if no debug, force REPL to Bluetooth
}
// we just reset, so BLE should be on.
// Don't disconnect if something is already connected to us
if ( s . ble === false ) boot += ` if (!NRF.getSecurityStatus().connected) NRF.sleep(); \n ` ;
// Set time
if ( s . timeout !== undefined ) boot += ` Bangle.setLCDTimeout( ${ s . timeout } ); \n ` ;
if ( ! s . timeout ) boot += ` Bangle.setLCDPower(1); \n ` ;
boot += ` E.setTimeZone( ${ s . timezone } ); ` ;
// Draw out of memory errors onto the screen
boot += ` E.on('errorFlag', function(errorFlags) {
g . reset ( 1 ) . setColor ( "#ff0000" ) . setFont ( "6x8" ) . setFontAlign ( 0 , 1 ) . drawString ( errorFlags , g . getWidth ( ) / 2 , g . getHeight ( ) - 1 ) . flip ( ) ;
print ( "Interpreter error:" , errorFlags ) ;
E . getErrorFlags ( ) ; // clear flags so we get called next time
} ) ; \ n ` ;
// stop users doing bad things!
if ( global . save ) boot += ` global.save = function() { throw new Error("You can't use save() on Bangle.js without overwriting the bootloader!"); } \n ` ;
// Apply any settings-specific stuff
if ( s . options ) boot += ` Bangle.setOptions( ${ E . toJS ( s . options ) } ); \n ` ;
2021-11-23 20:27:37 +00:00
if ( s . brightness && s . brightness != 1 ) boot += ` Bangle.setLCDBrightness( ${ s . brightness } ); \n ` ;
2021-12-15 11:48:03 +00:00
if ( s . passkey !== undefined && s . passkey . length == 6 ) boot += ` NRF.setSecurity({passkey: ${ E . toJS ( s . passkey . toString ( ) ) } , mitm:1, display:1}); \n ` ;
2021-05-26 15:21:52 +00:00
if ( s . whitelist ) boot += ` NRF.on('connect', function(addr) { if (!(require('Storage').readJSON('setting.json',1)||{}).whitelist.includes(addr)) NRF.disconnect(); }); \n ` ;
2022-10-21 14:01:35 +00:00
if ( s . rotate ) boot += ` g.setRotation( ${ s . rotate & 3 } , ${ s . rotate >> 2 } ); \n ` // screen rotation
2022-11-01 10:16:28 +00:00
// ================================================== FIXING OLDER FIRMWARES
2022-11-17 19:24:41 +00:00
if ( FWVERSION < 215.068 ) // 2v15.68 and before had compass heading inverted.
2022-11-02 08:23:32 +00:00
boot += ` Bangle.on('mag',e=>{if(!isNaN(e.heading))e.heading=360-e.heading;});
Bangle . getCompass = ( c => ( ( ) => { e = c ( ) ; if ( ! isNaN ( e . heading ) ) e . heading = 360 - e . heading ; return e ; } ) ) ( Bangle . getCompass ) ; ` ;
2021-10-18 11:01:40 +00:00
2022-11-17 19:24:41 +00:00
// deleting stops us getting confused by our own decl. builtins can't be deleted
// this is a polyfill without fastloading capability
delete Bangle . showClock ;
if ( ! Bangle . showClock ) boot += ` Bangle.showClock = ()=>{load(".bootcde")}; \n ` ;
delete Bangle . load ;
if ( ! Bangle . load ) boot += ` Bangle.load = load; \n ` ;
2022-12-05 17:09:09 +00:00
let date = new Date ( ) ;
delete date . toLocalISOString ; // toLocalISOString was only introduced in 2v15
if ( ! date . toLocalISOString ) boot += ` Date.prototype.toLocalISOString = function() {
var o = this . getTimezoneOffset ( ) ;
var d = new Date ( this . getTime ( ) - o * 60000 ) ;
var sign = o > 0 ? "-" : "+" ;
o = Math . abs ( o ) ;
return d . toISOString ( ) . slice ( 0 , - 1 ) + sign + Math . floor ( o / 60 ) . toString ( ) . padStart ( 2 , 0 ) + ( o % 60 ) . toString ( ) . padStart ( 2 , 0 ) ;
} ; \ n ` ;
2022-11-11 15:30:41 +00:00
2022-12-05 17:09:09 +00:00
// show timings
if ( DEBUG ) boot += ` print(".boot0",0|(Date.now()-_tm),"ms");_tm=Date.now(); \n `
2022-11-01 10:16:28 +00:00
// ================================================== BOOT.JS
2021-05-26 15:21:52 +00:00
// Append *.boot.js files
2021-10-26 09:23:39 +00:00
// These could change bleServices/bleServiceOptions if needed
2022-12-05 17:09:09 +00:00
let bootFiles = require ( 'Storage' ) . list ( /\.boot\.js$/ ) . sort ( ( a , b ) => {
let getPriority = /.*\.(\d+)\.boot\.js$/ ;
let aPriority = a . match ( getPriority ) ;
let bPriority = b . match ( getPriority ) ;
2022-02-11 20:42:58 +00:00
if ( aPriority && bPriority ) {
return parseInt ( aPriority [ 1 ] ) - parseInt ( bPriority [ 1 ] ) ;
} else if ( aPriority && ! bPriority ) {
return - 1 ;
} else if ( ! aPriority && bPriority ) {
return 1 ;
}
2022-03-13 21:20:32 +00:00
return a == b ? 0 : ( a > b ? 1 : - 1 ) ;
2022-03-17 09:54:02 +00:00
} ) ;
// precalculate file size
2022-12-05 17:09:09 +00:00
let fileSize = boot . length + bootPost . length ;
2022-03-17 09:54:02 +00:00
bootFiles . forEach ( bootFile => {
// match the size of data we're adding below in bootFiles.forEach
2022-12-05 17:09:09 +00:00
if ( DEBUG ) fileSize += 2 + bootFile . length + 1 ; // `//${bootFile}\n` comment
fileSize += require ( 'Storage' ) . read ( bootFile ) . length + 2 ; // boot code plus ";\n"
if ( DEBUG ) fileSize += 48 + E . toJS ( bootFile ) . length ; // `print(${E.toJS(bootFile)},0|(Date.now()-_tm),"ms");_tm=Date.now();\n`
2022-03-17 09:54:02 +00:00
} ) ;
// write file in chunks (so as not to use up all RAM)
require ( 'Storage' ) . write ( '.boot0' , boot , 0 , fileSize ) ;
2022-12-05 17:09:09 +00:00
let fileOffset = boot . length ;
2022-03-17 09:54:02 +00:00
bootFiles . forEach ( bootFile => {
2021-08-26 12:51:31 +00:00
// we add a semicolon so if the file is wrapped in (function(){ ... }()
// with no semicolon we don't end up with (function(){ ... }()(function(){ ... }()
// which would cause an error!
2022-03-17 09:54:02 +00:00
// we write:
// "//"+bootFile+"\n"+require('Storage').read(bootFile)+";\n";
// but we need to do this without ever loading everything into RAM as some
// boot files seem to be getting pretty big now.
2022-12-05 17:09:09 +00:00
if ( DEBUG ) {
require ( 'Storage' ) . write ( '.boot0' , ` // ${ bootFile } \n ` , fileOffset ) ;
fileOffset += 2 + bootFile . length + 1 ;
}
let bf = require ( 'Storage' ) . read ( bootFile ) ;
2022-05-18 08:23:23 +00:00
// we can't just write 'bf' in one go because at least in 2v13 and earlier
// Espruino wants to read the whole file into RAM first, and on Bangle.js 1
// it can be too big (especially BTHRM).
2022-12-05 17:09:09 +00:00
let bflen = bf . length ;
let bfoffset = 0 ;
2022-05-18 08:23:23 +00:00
while ( bflen ) {
2022-12-05 17:09:09 +00:00
let bfchunk = Math . min ( bflen , 2048 ) ;
2022-05-18 08:23:23 +00:00
require ( 'Storage' ) . write ( '.boot0' , bf . substr ( bfoffset , bfchunk ) , fileOffset ) ;
fileOffset += bfchunk ;
bfoffset += bfchunk ;
bflen -= bfchunk ;
}
2022-03-18 10:20:27 +00:00
require ( 'Storage' ) . write ( '.boot0' , ";\n" , fileOffset ) ;
fileOffset += 2 ;
2022-12-05 17:09:09 +00:00
if ( DEBUG ) {
require ( 'Storage' ) . write ( '.boot0' , ` print( ${ E . toJS ( bootFile ) } ,0|(Date.now()-_tm),"ms");_tm=Date.now(); \n ` , fileOffset ) ;
fileOffset += 48 + E . toJS ( bootFile ) . length
}
2021-05-26 15:21:52 +00:00
} ) ;
2022-03-17 09:54:02 +00:00
require ( 'Storage' ) . write ( '.boot0' , bootPost , fileOffset ) ;
2022-04-10 19:35:46 +00:00
E . showMessage ( /*LANG*/ "Reloading..." ) ;
2022-12-05 17:09:09 +00:00
}
2021-07-26 14:53:46 +00:00
// .bootcde should be run automatically after if required, since
// we normally get called automatically from '.boot0'
2022-12-05 17:09:09 +00:00
eval ( require ( 'Storage' ) . read ( '.boot0' ) ) ;