|
|
|
@ -12,14 +12,13 @@ if (DEBUG) {
|
|
|
|
|
boot += "var _tm=Date.now()\n";
|
|
|
|
|
bootPost += "delete _tm;";
|
|
|
|
|
}
|
|
|
|
|
if (require('Storage').hash) { // new in 2v11 - helps ensure files haven't changed
|
|
|
|
|
let CRC = E.CRC32(require('Storage').read('setting.json'))+require('Storage').hash(/\.boot\.js/)+E.CRC32(process.env.GIT_COMMIT);
|
|
|
|
|
boot += `if(E.CRC32(require('Storage').read('setting.json'))+require('Storage').hash(/\\.boot\\.js/)+E.CRC32(process.env.GIT_COMMIT)!=${CRC})`;
|
|
|
|
|
} else {
|
|
|
|
|
let CRC = E.CRC32(require('Storage').read('setting.json'))+E.CRC32(require('Storage').list(/\.boot\.js/))+E.CRC32(process.env.GIT_COMMIT);
|
|
|
|
|
boot += `if(E.CRC32(require('Storage').read('setting.json'))+E.CRC32(require('Storage').list(/\\.boot\\.js/))+E.CRC32(process.env.GIT_COMMIT)!=${CRC})`;
|
|
|
|
|
if (FWVERSION < 216) {
|
|
|
|
|
E.showMessage(/*LANG*/"Please update Bangle.js firmware\n\nCurrent = "+process.env.VERSION,{title:"ERROR"});
|
|
|
|
|
throw new Error("Old firmware");
|
|
|
|
|
}
|
|
|
|
|
boot += `{eval(require('Storage').read('bootupdate.js'));print("Storage Updated!")}else{\n`;
|
|
|
|
|
let CRC = E.CRC32(require('Storage').read('setting.json'))+require('Storage').hash(/\.js$/)+E.CRC32(process.env.GIT_COMMIT);
|
|
|
|
|
boot += `if(E.CRC32(require('Storage').read('setting.json'))+require('Storage').hash(/\\.js$/)+E.CRC32(process.env.GIT_COMMIT)!=${CRC})`;
|
|
|
|
|
boot += `{eval(require('Storage').read('bootupdate.js'));}else{\n`;
|
|
|
|
|
boot += `E.setFlags({pretokenise:1});\n`;
|
|
|
|
|
boot += `var bleServices = {}, bleServiceOptions = { uart : true};\n`;
|
|
|
|
|
bootPost += `NRF.setServices(bleServices,bleServiceOptions);delete bleServices,bleServiceOptions;\n`; // executed after other boot code
|
|
|
|
@ -44,7 +43,7 @@ LoopbackA.setConsole(true);\n`;
|
|
|
|
|
boot += `
|
|
|
|
|
Bluetooth.line="";
|
|
|
|
|
Bluetooth.on('data',function(d) {
|
|
|
|
|
var l = (Bluetooth.line + d).split(/[\\n\\r]/);
|
|
|
|
|
let l = (Bluetooth.line + d).split(/[\\n\\r]/);
|
|
|
|
|
Bluetooth.line = l.pop();
|
|
|
|
|
l.forEach(n=>Bluetooth.emit("line",n));
|
|
|
|
|
});
|
|
|
|
@ -86,11 +85,8 @@ if (s.bleprivacy || (s.passkey!==undefined && s.passkey.length==6)) {
|
|
|
|
|
if (s.blename === false) boot+=`NRF.setAdvertising({},{showName:false});\n`;
|
|
|
|
|
if (s.whitelist && !s.whitelist_disabled) boot+=`NRF.on('connect', function(addr) { if (!NRF.ignoreWhitelist) { let whitelist = (require('Storage').readJSON('setting.json',1)||{}).whitelist; if (NRF.resolveAddress !== undefined) { let resolvedAddr = NRF.resolveAddress(addr); if (resolvedAddr !== undefined) addr = resolvedAddr + " (resolved)"; } if (!whitelist.includes(addr)) NRF.disconnect(); }});\n`;
|
|
|
|
|
if (s.rotate) boot+=`g.setRotation(${s.rotate&3},${s.rotate>>2});\n` // screen rotation
|
|
|
|
|
boot+=`Bangle.loadWidgets=function(){if(!global.WIDGETS)eval(require("Storage").read(".widcache"))};\n`;
|
|
|
|
|
// ================================================== FIXING OLDER FIRMWARES
|
|
|
|
|
if (FWVERSION<215.068) // 2v15.68 and before had compass heading inverted.
|
|
|
|
|
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);`;
|
|
|
|
|
|
|
|
|
|
// deleting stops us getting confused by our own decl. builtins can't be deleted
|
|
|
|
|
// this is a polyfill without fastloading capability
|
|
|
|
|
delete Bangle.showClock;
|
|
|
|
@ -98,18 +94,10 @@ if (!Bangle.showClock) boot += `Bangle.showClock = ()=>{load(".bootcde")};\n`;
|
|
|
|
|
delete Bangle.load;
|
|
|
|
|
if (!Bangle.load) boot += `Bangle.load = load;\n`;
|
|
|
|
|
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`;
|
|
|
|
|
|
|
|
|
|
// show timings
|
|
|
|
|
if (DEBUG) boot += `print(".boot0",0|(Date.now()-_tm),"ms");_tm=Date.now();\n`
|
|
|
|
|
// ================================================== BOOT.JS
|
|
|
|
|
// ================================================== .BOOT0
|
|
|
|
|
// Append *.boot.js files.
|
|
|
|
|
// Name files with a number - eg 'foo.5.boot.js' to enforce order (lowest first). Numbered files get placed before non-numbered
|
|
|
|
|
// These could change bleServices/bleServiceOptions if needed
|
|
|
|
@ -128,17 +116,47 @@ let bootFiles = require('Storage').list(/\.boot\.js$/).sort((a,b)=>{
|
|
|
|
|
});
|
|
|
|
|
// precalculate file size
|
|
|
|
|
bootPost += "}";
|
|
|
|
|
let fileSize = boot.length + bootPost.length;
|
|
|
|
|
bootFiles.forEach(bootFile=>{
|
|
|
|
|
// match the size of data we're adding below in bootFiles.forEach
|
|
|
|
|
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`
|
|
|
|
|
});
|
|
|
|
|
// write file in chunks (so as not to use up all RAM)
|
|
|
|
|
require('Storage').write('.boot0',boot,0,fileSize);
|
|
|
|
|
let fileOffset = boot.length;
|
|
|
|
|
bootFiles.forEach(bootFile=>{
|
|
|
|
|
let fileOffset,fileSize;
|
|
|
|
|
/* code to output a file, plus preable and postable
|
|
|
|
|
when called with dst==undefined it just increments
|
|
|
|
|
fileOffset so we can see ho wbig the file has to be */
|
|
|
|
|
let outputFile = (dst,src,pre,post) => {"ram";
|
|
|
|
|
if (DEBUG) {
|
|
|
|
|
if (dst) require('Storage').write(dst,`//${src}\n`,fileOffset);
|
|
|
|
|
fileOffset+=2+src.length+1;
|
|
|
|
|
}
|
|
|
|
|
if (pre) {
|
|
|
|
|
if (dst) require('Storage').write(dst,pre,fileOffset);
|
|
|
|
|
fileOffset+=pre.length;
|
|
|
|
|
}
|
|
|
|
|
let f = require('Storage').read(src);
|
|
|
|
|
if (src.endsWith("clkinfo.js") && f[0]!="(") {
|
|
|
|
|
/* we shouldn't have to do this but it seems sometimes (sched 0.28) folks have
|
|
|
|
|
used libraries which get added into the clockinfo, and we can't use them directly
|
|
|
|
|
to we have to rever back to eval. */
|
|
|
|
|
f = `eval(require('Storage').read(${E.toJS(src)}))`;
|
|
|
|
|
}
|
|
|
|
|
if (dst) {
|
|
|
|
|
// we can't just write 'f' in one go because it can be too big
|
|
|
|
|
let len = f.length;
|
|
|
|
|
let offset = 0;
|
|
|
|
|
while (len) {
|
|
|
|
|
let chunk = Math.min(len, 2048);
|
|
|
|
|
require('Storage').write(dst,f.substr(offset, chunk),fileOffset);
|
|
|
|
|
fileOffset+=chunk;
|
|
|
|
|
offset+=chunk;
|
|
|
|
|
len-=chunk;
|
|
|
|
|
}
|
|
|
|
|
} else
|
|
|
|
|
fileOffset+=f.length;
|
|
|
|
|
if (dst) require('Storage').write(dst,post,fileOffset);
|
|
|
|
|
fileOffset+=post.length;
|
|
|
|
|
if (DEBUG) {
|
|
|
|
|
if (dst) require('Storage').write(dst,`print(${E.toJS(src)},0|(Date.now()-_tm),"ms");_tm=Date.now();\n`,fileOffset);
|
|
|
|
|
fileOffset += 48+E.toJS(src).length;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
let outputFileComplete = (dst,fn) => {
|
|
|
|
|
// 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!
|
|
|
|
@ -146,33 +164,57 @@ bootFiles.forEach(bootFile=>{
|
|
|
|
|
// "//"+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.
|
|
|
|
|
if (DEBUG) {
|
|
|
|
|
require('Storage').write('.boot0',`//${bootFile}\n`,fileOffset);
|
|
|
|
|
fileOffset+=2+bootFile.length+1;
|
|
|
|
|
}
|
|
|
|
|
let bf = require('Storage').read(bootFile);
|
|
|
|
|
// 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).
|
|
|
|
|
let bflen = bf.length;
|
|
|
|
|
let bfoffset = 0;
|
|
|
|
|
while (bflen) {
|
|
|
|
|
let bfchunk = Math.min(bflen, 2048);
|
|
|
|
|
require('Storage').write('.boot0',bf.substr(bfoffset, bfchunk),fileOffset);
|
|
|
|
|
fileOffset+=bfchunk;
|
|
|
|
|
bfoffset+=bfchunk;
|
|
|
|
|
bflen-=bfchunk;
|
|
|
|
|
}
|
|
|
|
|
require('Storage').write('.boot0',";\n",fileOffset);
|
|
|
|
|
fileOffset+=2;
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
outputFile(dst,fn,"",";\n");
|
|
|
|
|
};
|
|
|
|
|
fileOffset = boot.length + bootPost.length;
|
|
|
|
|
bootFiles.forEach(fn=>outputFileComplete(undefined,fn)); // just get sizes
|
|
|
|
|
fileSize = fileOffset;
|
|
|
|
|
require('Storage').write('.boot0',boot,0,fileSize);
|
|
|
|
|
fileOffset = boot.length;
|
|
|
|
|
bootFiles.forEach(fn=>outputFileComplete('.boot0',fn));
|
|
|
|
|
require('Storage').write('.boot0',bootPost,fileOffset);
|
|
|
|
|
delete boot,bootPost,bootFiles;
|
|
|
|
|
// ================================================== .WIDCACHE for widgets
|
|
|
|
|
let widgetFiles = require("Storage").list(/\.wid\.js$/);
|
|
|
|
|
let widget = `// Made by bootupdate.js\nglobal.WIDGETS={};`, widgetPost = `var W=WIDGETS;WIDGETS={};
|
|
|
|
|
Object.keys(W).sort((a,b)=>(0|W[b].sortorder)-(0|W[a].sortorder)).forEach(k=>WIDGETS[k]=W[k]);`; // sort
|
|
|
|
|
if (DEBUG) widget+="var _tm=Date.now();";
|
|
|
|
|
outputFileComplete = (dst,fn) => {
|
|
|
|
|
outputFile(dst,fn,"try{",`}catch(e){print(${E.toJS(fn)},e,e.stack)}\n`);
|
|
|
|
|
};
|
|
|
|
|
fileOffset = widget.length + widgetPost.length;
|
|
|
|
|
widgetFiles.forEach(fn=>outputFileComplete(undefined,fn)); // just get sizes
|
|
|
|
|
fileSize = fileOffset;
|
|
|
|
|
require('Storage').write('.widcache',widget,0,fileSize);
|
|
|
|
|
fileOffset = widget.length;
|
|
|
|
|
widgetFiles.forEach(fn=>outputFileComplete('.widcache',fn));
|
|
|
|
|
require('Storage').write('.widcache',widgetPost,fileOffset);
|
|
|
|
|
delete widget,widgetPost,widgetFiles;
|
|
|
|
|
// ================================================== .clkinfocache for clockinfos
|
|
|
|
|
let ciFiles = require("Storage").list(/\.clkinfo\.js$/);
|
|
|
|
|
let ci = `// Made by bootupdate.js\n`;
|
|
|
|
|
if (DEBUG) ci+="var _tm=Date.now();";
|
|
|
|
|
outputFileComplete = (dst,fn) => {
|
|
|
|
|
outputFile(dst,fn,"try{let a=",`(),b=menu.find(x=>x.name===a.name);if(b)b.items=b.items.concat(a.items)else menu=menu.concat(a);}catch(e){print(${E.toJS(fn)},e,e.stack)}\n`);
|
|
|
|
|
};
|
|
|
|
|
fileOffset = ci.length;
|
|
|
|
|
ciFiles.forEach(fn=>outputFileComplete(undefined,fn)); // just get sizes
|
|
|
|
|
fileSize = fileOffset;
|
|
|
|
|
require('Storage').write('.clkinfocache',ci,0,fileSize);
|
|
|
|
|
fileOffset = ci.length;
|
|
|
|
|
ciFiles.forEach(fn=>outputFileComplete('.clkinfocache',fn));
|
|
|
|
|
delete ci,ciFiles;
|
|
|
|
|
// test with require("clock_info").load()
|
|
|
|
|
// ================================================== END
|
|
|
|
|
E.showMessage(/*LANG*/"Reloading...");
|
|
|
|
|
}
|
|
|
|
|
// .bootcde should be run automatically after if required, since
|
|
|
|
|
// we normally get called automatically from '.boot0'
|
|
|
|
|
eval(require('Storage').read('.boot0'));
|
|
|
|
|
/*
|
|
|
|
|
f = require("Storage").read("sched.clkinfo.js")
|
|
|
|
|
if (f.startsWith("Modules.addCached")) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*/
|