Fixed node exports and refactored node example

This commit is contained in:
Rob Moran
2018-01-06 19:04:17 +00:00
parent c2a6968a59
commit d6529fc89c
4 changed files with 136 additions and 106 deletions

View File

@@ -30,36 +30,12 @@ var readline = require("readline");
var crc = require("crc-32");
var JSZip = require("jszip");
var progress = require("progress");
var Bluetooth = require("webbluetooth").Bluetooth;
var SecureDfu = require("../").SecureDfu;
var webbluetooth = require("webbluetooth");
var SecureDfu = require("../");
var bluetoothDevices = [];
var progressBar = null;
function logError(error) {
console.log(error.message || error);
process.exit();
}
function handleDeviceFound(bluetoothDevice, selectFn) {
var discovered = bluetoothDevices.some(device => {
return (device.id === bluetoothDevice.id);
});
if (discovered) return;
if (bluetoothDevices.length === 0) {
process.stdin.setRawMode(true);
console.log("Select a device to update:");
}
bluetoothDevices.push({ id: bluetoothDevice.id, select: selectFn });
console.log(`${bluetoothDevices.length}: ${bluetoothDevice.name}`);
}
var bluetooth = new Bluetooth({
deviceFound: handleDeviceFound
});
process.stdin.setEncoding("utf8");
// Determine manifest URL or file path
function getFileName() {
return new Promise((resolve) => {
if (process.argv[2]) {
@@ -75,6 +51,56 @@ function getFileName() {
});
}
// Use a custom Bluetooth instance to control device selection
function findDevice() {
var bluetoothDevices = [];
process.stdin.on("readable", () => {
var input = process.stdin.read();
if (input === "\u0003") {
process.exit();
} else {
var index = parseInt(input);
if (index && index <= bluetoothDevices.length) {
process.stdin.setRawMode(false);
bluetoothDevices[index - 1].select();
bluetoothDevices = [];
}
}
});
function handleDeviceFound(bluetoothDevice, selectFn) {
var discovered = bluetoothDevices.some(device => {
return (device.id === bluetoothDevice.id);
});
if (discovered) return;
if (bluetoothDevices.length === 0) {
process.stdin.setRawMode(true);
console.log("Select a device to update:");
}
bluetoothDevices.push({ id: bluetoothDevice.id, select: selectFn });
console.log(`${bluetoothDevices.length}: ${bluetoothDevice.name}`);
}
var bluetooth = new webbluetooth.Bluetooth({
deviceFound: handleDeviceFound
});
return bluetooth.requestDevice({
acceptAllDevices: true,
optionalServices: [SecureDfu.SERVICE_UUID]
});
}
// Load a file, returning a buffer
function loadFile(fileName) {
var file = fs.readFileSync(fileName);
return new Uint8Array(file).buffer;
}
// Download a file, returning a buffer
function downloadFile(url) {
return new Promise((resolve, reject) => {
console.log("Downloading file...");
@@ -98,38 +124,68 @@ function downloadFile(url) {
});
}
function loadFile(fileName) {
return new Promise((resolve) => {
var file = fs.readFileSync(fileName);
resolve(new Uint8Array(file).buffer);
});
// Firmware zip file wrapper
function Firmware(zipFile) {
this.zipFile = zipFile;
}
Firmware.prototype.load = function() {
try {
return this.zipFile.file("manifest.json").async("string")
.then(content => {
this.manifest = JSON.parse(content).manifest;
return this;
});
} catch(e) {
throw new Error("Unable to find manifest, is this a proper DFU package?");
}
};
Firmware.prototype.getImage = function(types) {
for (var type of types) {
if (this.manifest[type]) {
var entry = this.manifest[type];
var result = {
type: type,
initFile: entry.dat_file,
imageFile: entry.bin_file
};
return this.zipFile.file(result.initFile).async("arraybuffer")
.then(data => {
result.initData = data;
return this.zipFile.file(result.imageFile).async("arraybuffer")
})
.then(data => {
result.imageData = data;
return result;
});
}
}
}
function updateFirmware(dfu, package, manifest, device, type) {
var init = null;
// Update device using image containing init packet and data
function updateFirmware(dfu, device, image) {
console.log(`Using firmware: ${image.imageFile}`);
return package.file(manifest.dat_file).async("arraybuffer")
.then(data => {
init = data;
return package.file(manifest.bin_file).async("arraybuffer");
})
.then(data => {
console.log(`Using firmware: ${manifest.bin_file}`);
progressBar = new progress(`Updating ${type} [:bar] :percent :etas`, {
complete: "=",
incomplete: " ",
width: 20,
total: data.byteLength
});
return dfu.update(device, init, data);
var progressBar = new progress(`Updating ${image.type} [:bar] :percent :etas`, {
complete: "=",
incomplete: " ",
width: 20,
total: image.imageData.byteLength
});
dfu.addEventListener(SecureDfu.EVENT_PROGRESS, event => {
if (event.object === "firmware") {
progressBar.update(event.currentBytes / event.totalBytes);
}
});
return dfu.update(device, image.initData, image.imageData);
}
function update() {
var firmware = null;
var device = null;
var dfu = null;
var package = null;
var manifest = null;
getFileName()
.then(fileName => {
@@ -141,71 +197,45 @@ function update() {
return JSZip.loadAsync(file);
})
.then(zipFile => {
try {
package = zipFile;
return zipFile.file("manifest.json").async("string");
} catch(e) {
throw new Error("Unable to find manifest, is this a proper DFU package?");
}
firmware = new Firmware(zipFile);
return firmware.load();
})
.then(content => {
manifest = JSON.parse(content).manifest;
dfu = new SecureDfu(crc.buf, bluetooth);
dfu.addEventListener(SecureDfu.EVENT_PROGRESS, event => {
if (progressBar && event.object === "firmware") {
progressBar.update(event.currentBytes / event.totalBytes);
}
});
.then(() => {
console.log("Scanning for DFU devices...");
return bluetooth.requestDevice({
acceptAllDevices: true,
optionalServices: [SecureDfu.SERVICE_UUID]
});
return findDevice();
})
.then(device => {
console.log(`${device.name} selected, connecting...`);
return dfu.setDfuMode(device);
})
.then(device => {
if (device) return device;
.then(selectedDevice => {
console.log(`${selectedDevice.name} selected, connecting...`);
console.log("DFU mode set");
// Use default bluetooth instance
dfu = new SecureDfu(crc.buf, webbluetooth.bluetooth);
return dfu.setDfuMode(selectedDevice);
})
.then(selectedDevice => {
if (selectedDevice) return selectedDevice;
console.log("DFU mode set, reconnecting...");
return dfu.requestDevice();
})
.then(selectedDevice => {
device = selectedDevice;
for (var type of ["softdevice", "bootloader", "softdevice_bootloader"]) {
if (manifest[type]) {
return updateFirmware(dfu, package, manifest[type], device, type);
}
}
return firmware.getImage(["softdevice", "bootloader", "softdevice_bootloader"]);
})
.then(() => {
if (manifest.application) {
return updateFirmware(dfu, package, manifest.application, device, "application");
}
.then(image => {
if (image) return updateFirmware(dfu, device, image);
})
.then(() => firmware.getImage(["application"]))
.then(image => {
if (image) return updateFirmware(dfu, device, image);
})
.then(() => {
console.log("Update complete!");
process.exit();
})
.catch(logError);
.catch(error => {
console.log(error.message || error);
process.exit();
});
}
process.stdin.setEncoding('utf8');
process.stdin.on('readable', () => {
var input = process.stdin.read();
if (input === '\u0003') {
process.exit();
} else {
var index = parseInt(input);
if (index && index <= bluetoothDevices.length) {
process.stdin.setRawMode(false);
bluetoothDevices[index - 1].select();
}
}
});
update();

View File

@@ -23,4 +23,4 @@
* SOFTWARE.
*/
module.exports = require("./lib/secure-dfu");
module.exports = require("./lib/");

View File

@@ -5,7 +5,7 @@
"homepage": "https://github.com/thegecko/web-bluetooth-dfu",
"author": "Rob Moran <github@thegecko.org>",
"license": "MIT",
"types": "./types/secure-dfu.d.ts",
"types": "./types/index.d.ts",
"main": "./index.js",
"browser": {
"./index.js": "./dist/secure-dfu.js"

View File

@@ -23,5 +23,5 @@
* SOFTWARE.
*/
import dfu = require("./secure-dfu");
module.exports = dfu.SecureDfu;
import { SecureDfu } from "./secure-dfu";
export = SecureDfu;