node-raspberrypi-usbboot
Advanced tools
Comparing version 0.2.7 to 0.2.8-fix-device-not-detaching-4e44ad6ddf66c8d00c9611d5e85bdeccc5baa1c0
@@ -0,1 +1,2 @@ | ||
/// <reference types="node" /> | ||
import { EventEmitter } from 'events'; | ||
@@ -5,7 +6,8 @@ export declare const isUsbBootCapableUSBDevice: (idVendor: number, idProduct: number) => boolean; | ||
portId: string; | ||
static readonly LAST_STEP: number; | ||
static readonly LAST_STEP = 41; | ||
private _step; | ||
constructor(portId: string); | ||
readonly progress: number; | ||
step: number; | ||
get progress(): number; | ||
get step(): number; | ||
set step(step: number); | ||
} | ||
@@ -12,0 +14,0 @@ export declare class UsbbootScanner extends EventEmitter { |
@@ -6,11 +6,4 @@ "use strict"; | ||
*/ | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.UsbbootScanner = exports.UsbbootDevice = exports.isUsbBootCapableUSBDevice = void 0; | ||
// tslint:disable:no-bitwise | ||
@@ -26,3 +19,3 @@ const usb = require("@balena.io/usb"); | ||
const POLLING_INTERVAL_MS = 2000; | ||
const TRANSFER_BLOCK_SIZE = Math.pow(1024, 2); | ||
const TRANSFER_BLOCK_SIZE = 1024 ** 2; | ||
// The equivalent of a NULL buffer, given that node-usb complains | ||
@@ -145,6 +138,6 @@ // if the data argument is not an instance of Buffer | ||
*/ | ||
const performControlTransfer = (device, bmRequestType, bRequest, wValue, wIndex, dataOrLength) => __awaiter(this, void 0, void 0, function* () { | ||
const performControlTransfer = async (device, bmRequestType, bRequest, wValue, wIndex, dataOrLength) => { | ||
const previousTimeout = device.timeout; | ||
device.timeout = USB_CONTROL_TRANSFER_TIMEOUT_MS; | ||
const result = yield bluebird_1.fromCallback((callback) => { | ||
const result = await bluebird_1.fromCallback((callback) => { | ||
device.controlTransfer(bmRequestType, bRequest, wValue, wIndex, dataOrLength, callback); | ||
@@ -154,3 +147,3 @@ }); | ||
return result; | ||
}); | ||
}; | ||
exports.isUsbBootCapableUSBDevice = (idVendor, idProduct) => { | ||
@@ -193,5 +186,5 @@ return (idVendor === USB_VENDOR_ID_BROADCOM_CORPORATION && | ||
}; | ||
const sendSize = (device, size) => __awaiter(this, void 0, void 0, function* () { | ||
yield performControlTransfer(device, usb.LIBUSB_REQUEST_TYPE_VENDOR, USB_REQUEST_CODE_GET_STATUS, size & USBBOOT_MESSAGE_MAX_BUFFER_LENGTH, size >> CONTROL_TRANSFER_INDEX_RIGHT_BIT_SHIFT, NULL_BUFFER); | ||
}); | ||
const sendSize = async (device, size) => { | ||
await performControlTransfer(device, usb.LIBUSB_REQUEST_TYPE_VENDOR, USB_REQUEST_CODE_GET_STATUS, size & USBBOOT_MESSAGE_MAX_BUFFER_LENGTH, size >> CONTROL_TRANSFER_INDEX_RIGHT_BIT_SHIFT, NULL_BUFFER); | ||
}; | ||
function* chunks(buffer, size) { | ||
@@ -202,3 +195,3 @@ for (let start = 0; start < buffer.length; start += size) { | ||
} | ||
const transfer = (endpoint, chunk) => __awaiter(this, void 0, void 0, function* () { | ||
const transfer = async (endpoint, chunk) => { | ||
endpoint.timeout = USB_BULK_TRANSFER_TIMEOUT_MS; | ||
@@ -210,3 +203,3 @@ for (let tries = 0; tries < 3; tries++) { | ||
try { | ||
yield bluebird_1.fromCallback(callback => { | ||
await bluebird_1.fromCallback((callback) => { | ||
endpoint.transfer(chunk, callback); | ||
@@ -223,22 +216,22 @@ }); | ||
} | ||
}); | ||
const epWrite = (buffer, device, endpoint) => __awaiter(this, void 0, void 0, function* () { | ||
}; | ||
const epWrite = async (buffer, device, endpoint) => { | ||
debug('Sending buffer size', buffer.length); | ||
yield sendSize(device, buffer.length); | ||
await sendSize(device, buffer.length); | ||
if (buffer.length > 0) { | ||
for (const chunk of chunks(buffer, TRANSFER_BLOCK_SIZE)) { | ||
debug('Sending chunk of size', chunk.length); | ||
yield transfer(endpoint, chunk); | ||
await transfer(endpoint, chunk); | ||
} | ||
} | ||
}); | ||
const epRead = (device, bytesToRead) => __awaiter(this, void 0, void 0, function* () { | ||
return yield performControlTransfer(device, usb.LIBUSB_REQUEST_TYPE_VENDOR | usb.LIBUSB_ENDPOINT_IN, USB_REQUEST_CODE_GET_STATUS, bytesToRead & USBBOOT_MESSAGE_MAX_BUFFER_LENGTH, bytesToRead >> CONTROL_TRANSFER_INDEX_RIGHT_BIT_SHIFT, bytesToRead); | ||
}); | ||
}; | ||
const epRead = async (device, bytesToRead) => { | ||
return await performControlTransfer(device, usb.LIBUSB_REQUEST_TYPE_VENDOR | usb.LIBUSB_ENDPOINT_IN, USB_REQUEST_CODE_GET_STATUS, bytesToRead & USBBOOT_MESSAGE_MAX_BUFFER_LENGTH, bytesToRead >> CONTROL_TRANSFER_INDEX_RIGHT_BIT_SHIFT, bytesToRead); | ||
}; | ||
const getDeviceId = (device) => { | ||
return `${device.busNumber}:${device.deviceAddress}`; | ||
}; | ||
const safeReadFile = (filename) => __awaiter(this, void 0, void 0, function* () { | ||
const safeReadFile = async (filename) => { | ||
try { | ||
return yield readFile(Path.join(__dirname, '..', 'blobs', filename)); | ||
return await readFile(Path.join(__dirname, '..', 'blobs', filename)); | ||
} | ||
@@ -248,7 +241,7 @@ catch (e) { | ||
} | ||
}); | ||
const getFileBuffer = (filename) => __awaiter(this, void 0, void 0, function* () { | ||
let buffer = yield safeReadFile(filename); | ||
}; | ||
const getFileBuffer = async (filename) => { | ||
let buffer = await safeReadFile(filename); | ||
if (buffer === undefined) { | ||
buffer = yield safeReadFile(Path.join('raspberrypi', filename)); | ||
buffer = await safeReadFile(Path.join('raspberrypi', filename)); | ||
} | ||
@@ -259,3 +252,3 @@ if (buffer === undefined) { | ||
return buffer; | ||
}); | ||
}; | ||
/** | ||
@@ -287,4 +280,4 @@ * @summary Create a boot message buffer | ||
}; | ||
const secondStageBoot = (device, endpoint) => __awaiter(this, void 0, void 0, function* () { | ||
const bootcodeBuffer = yield getFileBuffer('bootcode.bin'); | ||
const secondStageBoot = async (device, endpoint) => { | ||
const bootcodeBuffer = await getFileBuffer('bootcode.bin'); | ||
if (bootcodeBuffer === undefined) { | ||
@@ -294,7 +287,7 @@ throw new Error("Can't find bootcode.bin"); | ||
const bootMessage = createBootMessageBuffer(bootcodeBuffer.length); | ||
yield epWrite(bootMessage, device, endpoint); | ||
await epWrite(bootMessage, device, endpoint); | ||
debug(`Writing ${bootMessage.length} bytes`, devicePortId(device)); | ||
yield epWrite(bootcodeBuffer, device, endpoint); | ||
await epWrite(bootcodeBuffer, device, endpoint); | ||
// raspberrypi's sample code has a sleep(1) here, but it looks like it isn't required. | ||
const data = yield epRead(device, RETURN_CODE_LENGTH); | ||
const data = await epRead(device, RETURN_CODE_LENGTH); | ||
const returnCode = data.readInt32LE(0); | ||
@@ -304,3 +297,3 @@ if (returnCode !== RETURN_CODE_SUCCESS) { | ||
} | ||
}); | ||
}; | ||
class UsbbootDevice extends events_1.EventEmitter { | ||
@@ -323,2 +316,3 @@ constructor(portId) { | ||
} | ||
exports.UsbbootDevice = UsbbootDevice; | ||
// LAST_STEP is hardcoded here as it is depends on the bootcode.bin file we send to the pi. | ||
@@ -332,3 +326,2 @@ // List of steps: | ||
UsbbootDevice.LAST_STEP = 41; | ||
exports.UsbbootDevice = UsbbootDevice; | ||
class UsbbootScanner extends events_1.EventEmitter { | ||
@@ -397,38 +390,36 @@ constructor() { | ||
} | ||
attachDevice(device) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (this.attachedDeviceIds.has(getDeviceId(device))) { | ||
return; | ||
async attachDevice(device) { | ||
if (this.attachedDeviceIds.has(getDeviceId(device))) { | ||
return; | ||
} | ||
this.attachedDeviceIds.add(getDeviceId(device)); | ||
if (isRaspberryPiInMassStorageMode(device) && | ||
this.usbbootDevices.has(devicePortId(device))) { | ||
this.step(device, 41); | ||
return; | ||
} | ||
if (!isUsbBootCapableUSBDevice$(device)) { | ||
return; | ||
} | ||
debug('Found serial number', device.deviceDescriptor.iSerialNumber); | ||
debug('port id', devicePortId(device)); | ||
try { | ||
const { endpoint } = initializeDevice(device); | ||
if (device.deviceDescriptor.iSerialNumber === 0) { | ||
debug('Sending bootcode.bin', devicePortId(device)); | ||
this.step(device, 0); | ||
await secondStageBoot(device, endpoint); | ||
// The device will now detach and reattach with iSerialNumber 1. | ||
// This takes approximately 1.5 seconds | ||
} | ||
this.attachedDeviceIds.add(getDeviceId(device)); | ||
if (isRaspberryPiInMassStorageMode(device) && | ||
this.usbbootDevices.has(devicePortId(device))) { | ||
this.step(device, 41); | ||
return; | ||
else { | ||
debug('Second stage boot server', devicePortId(device)); | ||
await this.fileServer(device, endpoint, 2); | ||
} | ||
if (!isUsbBootCapableUSBDevice$(device)) { | ||
return; | ||
} | ||
debug('Found serial number', device.deviceDescriptor.iSerialNumber); | ||
debug('port id', devicePortId(device)); | ||
try { | ||
const { endpoint } = initializeDevice(device); | ||
if (device.deviceDescriptor.iSerialNumber === 0) { | ||
debug('Sending bootcode.bin', devicePortId(device)); | ||
this.step(device, 0); | ||
yield secondStageBoot(device, endpoint); | ||
// The device will now detach and reattach with iSerialNumber 1. | ||
// This takes approximately 1.5 seconds | ||
} | ||
else { | ||
debug('Second stage boot server', devicePortId(device)); | ||
yield this.fileServer(device, endpoint, 2); | ||
} | ||
device.close(); | ||
} | ||
catch (error) { | ||
debug('error', error, devicePortId(device)); | ||
this.remove(device); | ||
} | ||
}); | ||
device.close(); | ||
} | ||
catch (error) { | ||
debug('error', error, devicePortId(device)); | ||
this.remove(device); | ||
} | ||
} | ||
@@ -453,44 +444,51 @@ detachDevice(device) { | ||
} | ||
fileServer(device, endpoint, step) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
while (true) { | ||
this.step(device, step); | ||
step += 1; | ||
let data; | ||
try { | ||
data = yield epRead(device, FILE_MESSAGE_SIZE); | ||
async fileServer(device, endpoint, step) { | ||
while (true) { | ||
this.step(device, step); | ||
step += 1; | ||
let data; | ||
try { | ||
data = await epRead(device, FILE_MESSAGE_SIZE); | ||
} | ||
catch (error) { | ||
if (error.message === 'LIBUSB_ERROR_NO_DEVICE' || | ||
error.message === 'LIBUSB_ERROR_IO') { | ||
// Drop out if the device goes away | ||
break; | ||
} | ||
catch (error) { | ||
if (error.message === 'LIBUSB_ERROR_NO_DEVICE' || | ||
error.message === 'LIBUSB_ERROR_IO') { | ||
// Drop out if the device goes away | ||
break; | ||
} | ||
yield bluebird_1.delay(READ_ERROR_DELAY); | ||
continue; | ||
await bluebird_1.delay(READ_ERROR_DELAY); | ||
continue; | ||
} | ||
const message = parseFileMessageBuffer(data); | ||
debug('Received message', FileMessageCommand[message.command], message.filename, devicePortId(device)); | ||
if (message.command === FileMessageCommand.GetFileSize || | ||
message.command === FileMessageCommand.ReadFile) { | ||
const buffer = await getFileBuffer(message.filename); | ||
if (buffer === undefined) { | ||
debug(`Couldn't find ${message.filename}`, devicePortId(device)); | ||
await sendSize(device, 0); | ||
} | ||
const message = parseFileMessageBuffer(data); | ||
debug('Received message', FileMessageCommand[message.command], message.filename, devicePortId(device)); | ||
if (message.command === FileMessageCommand.GetFileSize || | ||
message.command === FileMessageCommand.ReadFile) { | ||
const buffer = yield getFileBuffer(message.filename); | ||
if (buffer === undefined) { | ||
debug(`Couldn't find ${message.filename}`, devicePortId(device)); | ||
yield sendSize(device, 0); | ||
else { | ||
if (message.command === FileMessageCommand.GetFileSize) { | ||
await sendSize(device, buffer.length); | ||
} | ||
else { | ||
if (message.command === FileMessageCommand.GetFileSize) { | ||
yield sendSize(device, buffer.length); | ||
} | ||
else { | ||
yield epWrite(buffer, device, endpoint); | ||
} | ||
await epWrite(buffer, device, endpoint); | ||
} | ||
} | ||
else if (message.command === FileMessageCommand.Done) { | ||
break; | ||
} | ||
} | ||
debug('File server done', devicePortId(device)); | ||
}); | ||
else if (message.command === FileMessageCommand.Done) { | ||
break; | ||
} | ||
} | ||
debug('File server done', devicePortId(device)); | ||
// On some computers, the rpi won't detach at this point. | ||
// If you try communicating with it, it will error, detach and reattach as expected. | ||
await bluebird_1.delay(2000); | ||
try { | ||
device.open(); | ||
} | ||
catch (_a) { | ||
// We expect LIBUSB_ERROR_IO here | ||
} | ||
} | ||
@@ -497,0 +495,0 @@ } |
@@ -7,2 +7,9 @@ # Change Log | ||
# v0.2.8 | ||
## (2020-06-11) | ||
* Update dependencies, target es2018 [Alexis Svinartchouk] | ||
* Update resin-lint to @balena/lint [Alexis Svinartchouk] | ||
* Fix fin not detaching after receiving files on some computers [Alexis Svinartchouk] | ||
## 0.2.7 - 2019-10-15 | ||
@@ -9,0 +16,0 @@ |
{ | ||
"name": "node-raspberrypi-usbboot", | ||
"version": "0.2.7", | ||
"version": "0.2.8-fix-device-not-detaching-4e44ad6ddf66c8d00c9611d5e85bdeccc5baa1c0", | ||
"description": "Transforms Raspberry Pi Compute Modules and Zeros to mass storage devices.", | ||
@@ -8,4 +8,4 @@ "main": "build/index.js", | ||
"scripts": { | ||
"prettier": "prettier --config ./node_modules/resin-lint/config/.prettierrc --write \"lib/**/*.ts\"", | ||
"lint": "resin-lint --typescript lib/*.ts", | ||
"prettier": "balena-lint --fix --typescript lib/*.ts", | ||
"lint": "balena-lint --typescript lib/*.ts", | ||
"build": "npm run lint && rimraf build && tsc", | ||
@@ -30,14 +30,15 @@ "prepublish": "npm run build" | ||
"@balena.io/usb": "^1.3.12", | ||
"@types/node": "^6.0.112", | ||
"@types/usb": "^1.5.1", | ||
"debug": "^3.1.0" | ||
"bluebird": "^3.7.2", | ||
"debug": "^4.1.1" | ||
}, | ||
"devDependencies": { | ||
"@types/bluebird": "^3.5.20", | ||
"@types/debug": "0.0.30", | ||
"resin-lint": "^3.0.1", | ||
"rimraf": "^2.6.2", | ||
"ts-node": "^6.0.3", | ||
"typescript": "^2.9.1" | ||
"@balena/lint": "^5.1.0", | ||
"@types/bluebird": "^3.5.32", | ||
"@types/debug": "^4.1.5", | ||
"@types/node": "^8.10.61", | ||
"@types/usb": "^1.5.1", | ||
"rimraf": "^3.0.2", | ||
"ts-node": "^8.10.2", | ||
"typescript": "^3.9.5" | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
3
27827933
8
+ Addedbluebird@^3.7.2
+ Addedbluebird@3.7.2(transitive)
+ Addeddebug@4.4.0(transitive)
- Removed@types/node@^6.0.112
- Removed@types/usb@^1.5.1
- Removed@types/node@6.14.13(transitive)
- Removed@types/usb@1.5.4(transitive)
Updateddebug@^4.1.1