From b89a368bd996b3cbfdbf728c9af8d9fa51329472 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 16 Dec 2022 10:04:27 +0000 Subject: [PATCH] Removed duplication in node.js apps with 2 new libraries, added an 'app test' program - not finished yet --- bin/apploader.js | 42 +++---------- bin/firmwaremaker.js | 59 +++--------------- bin/firmwaremaker_c.js | 63 ++++--------------- bin/lib/apploader.js | 82 ++++++++++++++++++++++++ bin/lib/emulator.js | 115 ++++++++++++++++++++++++++++++++++ bin/runapptests.js | 138 +++++++++++++++++++++++++++++++++++++++++ bin/thumbnailer.js | 123 +++++++++--------------------------- 7 files changed, 392 insertions(+), 230 deletions(-) create mode 100644 bin/lib/apploader.js create mode 100644 bin/lib/emulator.js create mode 100755 bin/runapptests.js diff --git a/bin/apploader.js b/bin/apploader.js index 26c4c1f095..d4a5f828e7 100755 --- a/bin/apploader.js +++ b/bin/apploader.js @@ -14,7 +14,6 @@ for Noble. var SETTINGS = { pretokenise : true }; -var APPSDIR = __dirname+"/../apps/"; var noble; ["@abandonware/noble", "noble"].forEach(module => { if (!noble) try { @@ -37,36 +36,18 @@ function ERROR(msg) { process.exit(1); } -//eval(require("fs").readFileSync(__dirname+"../core/js/utils.js")); -var AppInfo = require("../core/js/appinfo.js"); -global.Const = { - /* Are we only putting a single app on a device? If so - apps should all be saved as .bootcde and we write info - about the current app into app.info */ - SINGLE_APP_ONLY : false, -}; var deviceId = "BANGLEJS2"; -var apps = []; -var dirs = require("fs").readdirSync(APPSDIR, {withFileTypes: true}); -dirs.forEach(dir => { - var appsFile; - if (dir.name.startsWith("_example") || !dir.isDirectory()) - return; - try { - appsFile = require("fs").readFileSync(APPSDIR+dir.name+"/metadata.json").toString(); - } catch (e) { - ERROR(dir.name+"/metadata.json does not exist"); - return; - } - apps.push(JSON.parse(appsFile)); -}); +var apploader = require("./lib/apploader.js"); var args = process.argv; var bangleParam = args.findIndex(arg => /-b\d/.test(arg)); if (bangleParam!==-1) { deviceId = "BANGLEJS"+args.splice(bangleParam, 1)[0][2]; } +apploader.init({ + DEVICEID : deviceId +}); if (args.length==3 && args[2]=="list") cmdListApps(); else if (args.length==3 && args[2]=="devices") cmdListDevices(); else if (args.length==4 && args[2]=="install") cmdInstallApp(args[3]); @@ -90,7 +71,7 @@ process.exit(0); } function cmdListApps() { - console.log(apps.map(a=>a.id).join("\n")); + console.log(apploader.apps.map(a=>a.id).join("\n")); } function cmdListDevices() { var foundDevices = []; @@ -113,19 +94,10 @@ function cmdListDevices() { } function cmdInstallApp(appId, deviceAddress) { - var app = apps.find(a=>a.id==appId); + var app = apploader.apps.find(a=>a.id==appId); if (!app) ERROR(`App ${JSON.stringify(appId)} not found`); if (app.custom) ERROR(`App ${JSON.stringify(appId)} requires HTML customisation`); - return AppInfo.getFiles(app, { - fileGetter:function(url) { - console.log(__dirname+"/"+url); - return Promise.resolve(require("fs").readFileSync(__dirname+"/../"+url).toString("binary")); - }, - settings : SETTINGS, - device : { id : deviceId } - }).then(files => { - //console.log(files); - var command = files.map(f=>f.cmd).join("\n")+"\n"; + return apploader.getAppFilesString(app).then(command => { bangleSend(command, deviceAddress).then(() => process.exit(0)); }); } diff --git a/bin/firmwaremaker.js b/bin/firmwaremaker.js index 1dc5ec0735..4535c4a5e6 100755 --- a/bin/firmwaremaker.js +++ b/bin/firmwaremaker.js @@ -1,17 +1,12 @@ -#!/usr/bin/env nodejs +#!/usr/bin/env node /* Mashes together a bunch of different apps to make a single firmware JS file which can be uploaded. */ -var SETTINGS = { - pretokenise : true -}; - var path = require('path'); var ROOTDIR = path.join(__dirname, '..'); -var APPDIR = ROOTDIR+'/apps'; var OUTFILE = ROOTDIR+'/firmware.js'; -var DEVICE = "BANGLEJS"; +var DEVICEID = "BANGLEJS"; var APPS = [ // IDs of apps to install "boot","launch","mclock","setting", "about","alarm","widbat","widbt","welcome" @@ -19,53 +14,17 @@ var APPS = [ // IDs of apps to install var MINIFY = true; var fs = require("fs"); -global.Const = { - /* Are we only putting a single app on a device? If so - apps should all be saved as .bootcde and we write info - about the current app into app.info */ - SINGLE_APP_ONLY : false, -}; +var apploader = require("./lib/apploader.js"); +apploader.init({ + DEVICEID : DEVICEID +}); -var AppInfo = require(ROOTDIR+"/core/js/appinfo.js"); var appfiles = []; -function fileGetter(url) { - console.log("Loading "+url) - if (MINIFY) { - /*if (url.endsWith(".js")) { - var f = url.slice(0,-3); - console.log("MINIFYING "+f); - const execSync = require('child_process').execSync; - // --config PRETOKENISE=true - // --minify - code = execSync(`espruino --config SET_TIME_ON_WRITE=false --minify --board BANGLEJS ${f}.js -o ${f}.min.js`); - console.log(code.toString()); - url = f+".min.js"; - }*/ - if (url.endsWith(".json")) { - var f = url.slice(0,-5); - console.log("MINIFYING JSON "+f); - var j = eval("("+fs.readFileSync(url).toString("binary")+")"); - var code = JSON.stringify(j); - //console.log(code); - url = f+".min.json"; - fs.writeFileSync(url, code); - } - } - return Promise.resolve(fs.readFileSync(url).toString("binary")); -} - Promise.all(APPS.map(appid => { - try { - var app = JSON.parse(fs.readFileSync(APPDIR + "/" + appid + "/metadata.json").toString()); - } catch (e) { - throw new Error(`App ${appid} not found`); - } - return AppInfo.getFiles(app, { - fileGetter : fileGetter, - settings : SETTINGS, - device : { id : DEVICE } - }).then(files => { + var app = apploader.apps.find(a => a.id==appid); + if (!app) throw new Error(`App ${appid} not found`); + return apploader.getAppFiles(app).then(files => { appfiles = appfiles.concat(files); }); })).then(() => { diff --git a/bin/firmwaremaker_c.js b/bin/firmwaremaker_c.js index 08fc6fe834..54b63d5d9b 100755 --- a/bin/firmwaremaker_c.js +++ b/bin/firmwaremaker_c.js @@ -7,25 +7,20 @@ to populate Storage initially. Bangle.js 1 doesn't really have anough flash space for this, but we have enough on v2. */ -var SETTINGS = { - pretokenise : true -}; - -var DEVICE = process.argv[2]; +var DEVICEID = process.argv[2]; var path = require('path'); +var fs = require("fs"); var ROOTDIR = path.join(__dirname, '..'); -var APPDIR = ROOTDIR+'/apps'; -var MINIFY = true; var OUTFILE, APPS; -if (DEVICE=="BANGLEJS") { +if (DEVICEID=="BANGLEJS") { var OUTFILE = path.join(ROOTDIR, '../Espruino/libs/banglejs/banglejs1_storage_default.c'); var APPS = [ // IDs of apps to install "boot","launch","mclock","setting", "about","alarm","sched","widbat","widbt","welcome" ]; -} else if (DEVICE=="BANGLEJS2") { +} else if (DEVICEID=="BANGLEJS2") { var OUTFILE = path.join(ROOTDIR, '../Espruino/libs/banglejs/banglejs2_storage_default.c'); var APPS = [ // IDs of apps to install "boot","launch","antonclk","setting", @@ -37,16 +32,12 @@ if (DEVICE=="BANGLEJS") { console.log(" bin/firmwaremaker_c.js BANGLEJS2"); process.exit(1); } -console.log("Device = ",DEVICE); - +console.log("Device = ",DEVICEID); -var fs = require("fs"); -global.Const = { - /* Are we only putting a single app on a device? If so - apps should all be saved as .bootcde and we write info - about the current app into app.info */ - SINGLE_APP_ONLY : false, -}; +var apploader = require("./lib/apploader.js"); +apploader.init({ + DEVICEID : DEVICEID +}); function atob(input) { @@ -84,31 +75,8 @@ function atob(input) { return new Uint8Array(output); } -var AppInfo = require(ROOTDIR+"/core/js/appinfo.js"); var appfiles = []; -function fileGetter(url) { - console.log("Loading "+url) - if (MINIFY) { - if (url.endsWith(".json")) { - var f = url.slice(0,-5); - console.log("MINIFYING JSON "+f); - var j = eval("("+fs.readFileSync(url).toString("binary")+")"); - var code = JSON.stringify(j); - //console.log(code); - url = f+".min.json"; - fs.writeFileSync(url, code); - } - } - var blob = fs.readFileSync(url); - var data; - if (url.endsWith(".js") || url.endsWith(".json")) - data = blob.toString(); // allow JS/etc to be written in UTF-8 - else - data = blob.toString("binary") - return Promise.resolve(data); -} - // If file should be evaluated, try and do it... function evaluateFile(file) { var hsStart = 'require("heatshrink").decompress(atob("'; @@ -132,16 +100,9 @@ function evaluateFile(file) { } Promise.all(APPS.map(appid => { - try { - var app = JSON.parse(fs.readFileSync(APPDIR + "/" + appid + "/metadata.json").toString()); - } catch (e) { - throw new Error(`App ${appid} not found`); - } - return AppInfo.getFiles(app, { - fileGetter : fileGetter, - settings : SETTINGS, - device : { id : DEVICE } - }).then(files => { + var app = apploader.apps.find(a => a.id==appid); + if (!app) throw new Error(`App ${appid} not found`); + return apploader.getAppFiles(app).then(files => { appfiles = appfiles.concat(files); }); })).then(() => { diff --git a/bin/lib/apploader.js b/bin/lib/apploader.js new file mode 100644 index 0000000000..6bf74eb7e9 --- /dev/null +++ b/bin/lib/apploader.js @@ -0,0 +1,82 @@ +/* Node.js library with utilities to handle using the app loader from node.js */ + +var DEVICEID = "BANGLEJS2"; +var MINIFY = true; // minify JSON? +var BASE_DIR = __dirname + "/../.."; +var APPSDIR = BASE_DIR+"/apps/"; + +//eval(require("fs").readFileSync(__dirname+"../core/js/utils.js")); +var Espruino = require(__dirname + "/../../core/lib/espruinotools.js"); +//eval(require("fs").readFileSync(__dirname + "/../../core/lib/espruinotools.js").toString()); +//eval(require("fs").readFileSync(__dirname + "/../../core/js/utils.js").toString()); +var AppInfo = require(__dirname+"/../../core/js/appinfo.js"); + +var SETTINGS = { + pretokenise : true +}; +global.Const = { + /* Are we only putting a single app on a device? If so + apps should all be saved as .bootcde and we write info + about the current app into app.info */ + SINGLE_APP_ONLY : false, +}; + +var apps = []; + +// call with {DEVICEID:"BANGLEJS/BANGLEJS2"} +exports.init = function(options) { + if (options.DEVICEID) + DEVICEID = options.DEVICEID; + // Load app metadata + var dirs = require("fs").readdirSync(APPSDIR, {withFileTypes: true}); + dirs.forEach(dir => { + var appsFile; + if (dir.name.startsWith("_example") || !dir.isDirectory()) + return; + try { + appsFile = require("fs").readFileSync(APPSDIR+dir.name+"/metadata.json").toString(); + } catch (e) { + ERROR(dir.name+"/metadata.json does not exist"); + return; + } + apps.push(JSON.parse(appsFile)); + }); +}; + +exports.AppInfo = AppInfo; +exports.apps = apps; + +// used by getAppFiles +function fileGetter(url) { + url = BASE_DIR+"/"+url; + console.log("Loading "+url) + var data; + if (MINIFY && url.endsWith(".json")) { + var f = url.slice(0,-5); + console.log("MINIFYING JSON "+f); + var j = eval("("+require("fs").readFileSync(url).toString("binary")+")"); + data = JSON.stringify(j); + } else { + var blob = require("fs").readFileSync(url); + if (url.endsWith(".js") || url.endsWith(".json")) + data = blob.toString(); // allow JS/etc to be written in UTF-8 + else + data = blob.toString("binary") + } + return Promise.resolve(data); +} + +exports.getAppFiles = function(app) { + return AppInfo.getFiles(app, { + fileGetter:fileGetter, + settings : SETTINGS, + device : { id : DEVICEID } + }); +}; + +// Get all the files for this app as a string of Storage.write commands +exports.getAppFilesString = function(app) { + return exports.getAppFiles(app).then(files => { + return files.map(f=>f.cmd).join("\n")+"\n" + }) +}; diff --git a/bin/lib/emulator.js b/bin/lib/emulator.js new file mode 100644 index 0000000000..f7c82ec3c8 --- /dev/null +++ b/bin/lib/emulator.js @@ -0,0 +1,115 @@ +/* Node.js library with utilities to handle using the emulator from node.js */ + +var EMULATOR = "banglejs2"; +var DEVICEID = "BANGLEJS2"; + +var BASE_DIR = __dirname + "/../.."; +var DIR_IDE = BASE_DIR + "/../EspruinoWebIDE"; + +/* we factory reset ONCE, get this, then we can use it to reset +state quickly for each new app */ +var factoryFlashMemory; + +// Log of messages from app +var appLog = ""; +var lastOutputLine = ""; + +function onConsoleOutput(txt) { + appLog += txt + "\n"; + lastOutputLine = txt; +} + +exports.init = function(options) { + if (options.EMULATOR) + EMULATOR = options.EMULATOR; + if (options.DEVICEID) + DEVICEID = options.DEVICEID; + + eval(require("fs").readFileSync(DIR_IDE + "/emu/emulator_"+EMULATOR+".js").toString()); + eval(require("fs").readFileSync(DIR_IDE + "/emu/emu_"+EMULATOR+".js").toString()); + eval(require("fs").readFileSync(DIR_IDE + "/emu/common.js").toString()/*.replace('console.log("EMSCRIPTEN:"', '//console.log("EMSCRIPTEN:"')*/); + + jsRXCallback = function() {}; + jsUpdateGfx = function() {}; + + factoryFlashMemory = new Uint8Array(FLASH_SIZE); + factoryFlashMemory.fill(255); + + exports.flashMemory = flashMemory; + exports.GFX_WIDTH = GFX_WIDTH; + exports.GFX_HEIGHT = GFX_HEIGHT; + exports.tx = jsTransmitString; + exports.idle = jsIdle; + exports.stopIdle = jsStopIdle; + exports.getGfxContents = jsGetGfxContents; + + return new Promise(resolve => { + setTimeout(function() { + console.log("Emulator Loaded..."); + jsInit(); + jsIdle(); + console.log("Emulator Factory reset"); + exports.tx("Bangle.factoryReset()\n"); + factoryFlashMemory.set(flashMemory); + console.log("Emulator Ready!"); + + resolve(); + },0); + }); +}; + +// Factory reset +exports.factoryReset = function() { + exports.flashMemory.set(factoryFlashMemory); + exports.tx("reset()\n"); + appLog=""; +}; + +// Transmit a string +exports.tx = function() {}; // placeholder +exports.idle = function() {}; // placeholder +exports.stopIdle = function() {}; // placeholder +exports.getGfxContents = function() {}; // placeholder + +exports.flashMemory = undefined; // placeholder +exports.GFX_WIDTH = undefined; // placeholder +exports.GFX_HEIGHT = undefined; // placeholder + +// Get last line sent to console +exports.getLastLine = function() { + return lastOutputLine; +}; + +// Gets the screenshot as RGBA Uint32Array +exports.getScreenshot = function() { + var rgba = new Uint8Array(exports.GFX_WIDTH*exports.GFX_HEIGHT*4); + exports.getGfxContents(rgba); + var rgba32 = new Uint32Array(rgba.buffer); + return rgba32; +} + +// Write the screenshot to a file options={errorIfBlank} +exports.writeScreenshot = function(imageFn, options) { + options = options||{}; + return new Promise((resolve,reject) => { + var rgba32 = exports.getScreenshot(); + + if (options.errorIfBlank) { + var firstPixel = rgba32[0]; + var blankImage = rgba32.every(col=>col==firstPixel); + if (blankImage) reject("Image is blank"); + } + + var Jimp = require("jimp"); + let image = new Jimp(exports.GFX_WIDTH, exports.GFX_HEIGHT, function (err, image) { + if (err) throw err; + let buffer = image.bitmap.data; + buffer.set(new Uint8Array(rgba32.buffer)); + image.write(imageFn, (err) => { + if (err) return reject(err); + console.log("Image written as "+imageFn); + resolve(); + }); + }); + }); +} diff --git a/bin/runapptests.js b/bin/runapptests.js new file mode 100755 index 0000000000..8a415b109d --- /dev/null +++ b/bin/runapptests.js @@ -0,0 +1,138 @@ +#!/usr/bin/node +/* + +This allows us to test apps using the Bangle.js emulator + +IT IS UNFINISHED + +It searches for `test.json` in each app's directory and will +run them in sequence. + +TODO: + +* more code to test with +* run tests that we have found and loaded (currently we just use TEST) +* documentation +* actual tests +* detecting 'Uncaught Error' +* logging of success/fail +* ... + +*/ + +// A si +var TEST = { + app : "android", + tests : [ { + load : "messagesgui.app.js", + steps : [ + {t:"gb", "obj":{"t":"notify","id":1234,"src":"Twitter","title":"A Name","body":"message contents"}}, + {t:"cmd", "js":"X='hello';"}, + {t:"eval", "js":"X", eq:"hello"} + ] + }] +}; + +var EMULATOR = "banglejs2"; +var DEVICEID = "BANGLEJS2"; + +var BASE_DIR = __dirname + "/.."; +var APP_DIR = BASE_DIR + "/apps"; +var DIR_IDE = BASE_DIR + "/../EspruinoWebIDE"; + + +if (!require("fs").existsSync(DIR_IDE)) { + console.log("You need to:"); + console.log(" git clone https://github.com/espruino/EspruinoWebIDE"); + console.log("At the same level as this project"); + process.exit(1); +} + +var apploader = require(BASE_DIR+"/bin/lib/apploader.js"); +apploader.init({ + DEVICEID : DEVICEID +}); +var emu = require(BASE_DIR+"/bin/lib/emulator.js"); + +// Last set of text received +var lastTxt; + +function ERROR(s) { + console.error(s); + process.exit(1); +} + +function runTest(test) { + var app = apploader.apps.find(a=>a.id==test.app); + if (!app) ERROR(`App ${JSON.stringify(test.app)} not found`); + if (app.custom) ERROR(`App ${JSON.stringify(appId)} requires HTML customisation`); + return apploader.getAppFilesString(app).then(command => { + // What about dependencies?? + test.tests.forEach((subtest,subtestIdx) => { + console.log(`==============================`); + console.log(`"${test.app}" Test ${subtestIdx}`); + console.log(`==============================`); + emu.factoryReset(); + console.log("Sending app "+test.app); + emu.tx(command); + console.log("Sent app"); + emu.tx(test.load ? `load(${JSON.stringify(test.load)})\n` : "load()\n"); + console.log("App Loaded."); + var ok = true; + subtest.steps.forEach(step => { + if (ok) switch(step.t) { + case "cmd" : emu.tx(`${step.js}\n`); break; + case "gb" : emu.tx(`GB(${JSON.stringify(step.obj)})\n`); break; + case "tap" : emu.tx(`Bangle.emit(...)\n`); break; + case "eval" : + emu.tx(`\x10print(JSON.stringify(${step.js}))\n`); + var result = emu.getLastLine(); + var expected = JSON.stringify(step.eq); + console.log("GOT "+result); + if (result!=expected) { + console.log("EXPECTED "+expected); + ok = false; + } + break; + // tap/touch/drag/button press + // delay X milliseconds? + case "screenshot" : + console.log("Compare screenshots"); + break; + default: ERROR("Unknown step type "+step.t); + } + }); + }); + emu.stopIdle(); + }); +} + + +emu.init({ + EMULATOR : EMULATOR, + DEVICEID : DEVICEID +}).then(function() { + // Emulator is now loaded + console.log("Loading tests"); + var tests = []; + apploader.apps.forEach(app => { + var testFile = APP_DIR+"/"+app.id+"/test.json"; + if (!require("fs").existsSync(testFile)) return; + var test = JSON.parse(require("fs").readFileSync(testFile).toString()); + test.app = app.id; + tests.push(test); + }); + // Running tests + runTest(TEST); +}); +/* + if (erroredApps.length) { + erroredApps.forEach(app => { + console.log(`::error file=${app.id}::${app.id}`); + console.log("::group::Log"); + app.log.split("\n").forEach(line => console.log(`\u001b[38;2;255;0;0m${line}`)); + console.log("::endgroup::"); + }); + process.exit(1); + } +*/ diff --git a/bin/thumbnailer.js b/bin/thumbnailer.js index 0895098e9d..e9eb2ff61e 100755 --- a/bin/thumbnailer.js +++ b/bin/thumbnailer.js @@ -7,6 +7,9 @@ var DEVICEID = "BANGLEJS2"; var EMULATOR = "banglejs1"; var DEVICEID = "BANGLEJS"; +var emu = require("./lib/emulator.js"); +var apploader = require("./lib/apploader.js"); + var singleAppId; if (process.argv.length!=3 && process.argv.length!=2) { @@ -20,126 +23,58 @@ if (process.argv.length!=3 && process.argv.length!=2) { if (process.argv.length==3) singleAppId = process.argv[2]; -if (!require("fs").existsSync(__dirname + "/../../EspruinoWebIDE")) { - console.log("You need to:"); - console.log(" git clone https://github.com/espruino/EspruinoWebIDE"); - console.log("At the same level as this project"); - process.exit(1); -} - -eval(require("fs").readFileSync(__dirname + "/../../EspruinoWebIDE/emu/emulator_"+EMULATOR+".js").toString()); -eval(require("fs").readFileSync(__dirname + "/../../EspruinoWebIDE/emu/emu_"+EMULATOR+".js").toString()); -eval(require("fs").readFileSync(__dirname + "/../../EspruinoWebIDE/emu/common.js").toString()); - -var SETTINGS = { - pretokenise : true -}; -var Const = { -}; -module = undefined; -var Espruino = require(__dirname + "/../core/lib/espruinotools.js"); -//eval(require("fs").readFileSync(__dirname + "/../core/lib/espruinotools.js").toString()); -eval(require("fs").readFileSync(__dirname + "/../core/js/utils.js").toString()); -eval(require("fs").readFileSync(__dirname + "/../core/js/appinfo.js").toString()); -var apps = JSON.parse(require("fs").readFileSync(__dirname+"/../apps.json")); - -/* we factory reset ONCE, get this, then we can use it to reset -state quickly for each new app */ -var factoryFlashMemory = new Uint8Array(FLASH_SIZE); -// Log of messages from app -var appLog = ""; // List of apps that errored var erroredApps = []; -jsRXCallback = function() {}; -jsUpdateGfx = function() {}; - function ERROR(s) { console.error(s); process.exit(1); } -function onConsoleOutput(txt) { - appLog += txt + "\n"; -} - function getThumbnail(appId, imageFn) { console.log("Thumbnail for "+appId); - var app = apps.find(a=>a.id==appId); + var app = apploader.apps.find(a=>a.id==appId); if (!app) ERROR(`App ${JSON.stringify(appId)} not found`); if (app.custom) ERROR(`App ${JSON.stringify(appId)} requires HTML customisation`); - return new Promise(resolve => { - AppInfo.getFiles(app, { - fileGetter:function(url) { - console.log(__dirname+"/"+url); - return Promise.resolve(require("fs").readFileSync(__dirname+"/../"+url).toString("binary")); - }, - settings : SETTINGS, - device : { id : DEVICEID } - }).then(files => { - console.log(`AppInfo returned for ${appId}`);//, files); - flashMemory.set(factoryFlashMemory); - jsTransmitString("reset()\n"); - console.log("Uploading..."); - jsTransmitString("g.clear()\n"); - var command = files.map(f=>f.cmd).join("\n")+"\n"; - command += `load("${appId}.app.js")\n`; - appLog = ""; - jsTransmitString(command); - console.log("Done."); - jsTransmitString("Bangle.setLCDMode();clearInterval();clearTimeout();\n"); - jsStopIdle(); - - var rgba = new Uint8Array(GFX_WIDTH*GFX_HEIGHT*4); - jsGetGfxContents(rgba); - var rgba32 = new Uint32Array(rgba.buffer); - var firstPixel = rgba32[0]; - var blankImage = rgba32.every(col=>col==firstPixel) - - if (appLog.replace("Uncaught Storage Updated!", "").indexOf("Uncaught")>=0) - erroredApps.push( { id : app.id, log : appLog } ); - - if (!blankImage) { - var Jimp = require("jimp"); - let image = new Jimp(GFX_WIDTH, GFX_HEIGHT, function (err, image) { - if (err) throw err; - let buffer = image.bitmap.data; - buffer.set(rgba); - image.write(imageFn, (err) => { - if (err) throw err; - console.log("Image written as "+imageFn); - resolve(true); - }); - }); - } else { - console.log("Image is empty"); - resolve(false); - } - + return apploader.getAppFilesString(app).then(command => { + console.log(`AppInfo returned for ${appId}`);//, files); + emu.factoryReset(); + console.log("Uploading..."); + emu.tx("g.clear()\n"); + command += `load("${appId}.app.js")\n`; + appLog = ""; + emu.tx(command); + console.log("Done."); + emu.tx("Bangle.setLCDMode();clearInterval();clearTimeout();\n"); + emu.stopIdle(); + + return emu.writeScreenshot(imageFn, { errorIfBlank : true }).then(() => console.log("X")).catch( err => { + console.log("Error", err); }); }); } var screenshots = []; +apploader.init({ + EMULATOR : EMULATOR, + DEVICEID : DEVICEID +}); // wait until loaded... -setTimeout(function() { - console.log("Loaded..."); - jsInit(); - jsIdle(); - console.log("Factory reset"); - jsTransmitString("Bangle.factoryReset()\n"); - factoryFlashMemory.set(flashMemory); - console.log("Ready!"); - +emu.init({ + EMULATOR : EMULATOR, + DEVICEID : DEVICEID +}).then(function() { if (singleAppId) { + console.log("Single Screenshot"); getThumbnail(singleAppId, "screenshots/"+singleAppId+"-"+EMULATOR+".png"); return; } - var appList = apps.filter(app => (!app.type || app.type=="clock") && !app.custom); + console.log("Screenshot ALL"); + var appList = apploader.apps.filter(app => (!app.type || app.type=="clock") && !app.custom); appList = appList.filter(app => !app.screenshots && app.supports.includes(DEVICEID)); var promise = Promise.resolve();