UNPKG

@ginden/blinkstick-v2

Version:
119 lines 4.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.LibUsbTransport = void 0; const usb_transport_1 = require("./usb-transport"); const node_util_1 = require("node:util"); const tsafe_1 = require("tsafe"); const utils_1 = require("../utils"); function isDeviceOpen(device) { return Boolean(device.interfaces); } /** * @summary UsbTransport implementation using the 'usb' (libusb) library. * @category Adapters */ class LibUsbTransport extends usb_transport_1.UsbTransport { constructor(device, minimalDeviceInfo) { super(); this.device = device; this.minimalDeviceInfo = minimalDeviceInfo; this.wIndex = 0; } /** * Creates a new instance of LibUsbTransport from a USB device. */ static async buildFromDevice(device) { const minimimalDeviceInfo = await LibUsbTransport.calculateMinimalDeviceInfo(device); const iface = device.interfaces?.[0]; (0, tsafe_1.assert)(iface, 'Device must have at least one interface'); if (iface.isKernelDriverActive()) { iface.detachKernelDriver(); } iface.claim(); return new LibUsbTransport(device, minimimalDeviceInfo); } /** * Calculates minimal device information from a USB device. * This includes vendorId, productId, release, manufacturer, product, and serialNumber. */ static async calculateMinimalDeviceInfo(device) { if (isDeviceOpen(device)) { const desc = device.deviceDescriptor; const [manufacturer, product, serialNumber] = (await Promise.all([ (0, node_util_1.promisify)((cb) => device.getStringDescriptor(desc.iManufacturer, cb))(), (0, node_util_1.promisify)((cb) => device.getStringDescriptor(desc.iProduct, cb))(), (0, node_util_1.promisify)((cb) => device.getStringDescriptor(desc.iSerialNumber, cb))(), ])); return { vendorId: desc.idVendor, productId: desc.idProduct, release: desc.bcdDevice, manufacturer, product, serialNumber, }; } else { try { device.open(); return await LibUsbTransport.calculateMinimalDeviceInfo(device); } finally { device.close(); } } } async sendFeatureReport(data) { const buffer = (0, utils_1.asBuffer)(data); const reportId = buffer[0]; // HID reports start with reportId const bmRequestType = 0x20; const wValue = (3 << 8) | reportId; // 3 = Feature report type const ret = await new Promise((resolve, reject) => { this.device.controlTransfer(bmRequestType, 0x09, // bRequest: SET_REPORT wValue, // wValue: (3=Feature) << 8 | reportId this.wIndex, // wIndex: interface number buffer, (err, b) => (err ? reject(err) : resolve(b))); }); if (typeof ret === 'number') { return ret; // If the return type is a number, return it directly } return ret.length; } async getFeatureReport(reportId, reportLength) { const ret = await new Promise((resolve, reject) => { this.device.controlTransfer(0xa1, // bmRequestType: Device to host | Class | Interface 0x01, // bRequest: GET_REPORT (3 << 8) | reportId, // wValue: (3=Feature) << 8 | reportId this.wIndex, // wIndex: interface number reportLength, (err, data) => (err ? reject(err) : resolve(data))); }); if (!Buffer.isBuffer(ret)) { throw Object.assign(new Error('Expected a Buffer from getFeatureReport'), { returnValue: ret, }); } return ret; } getDeviceInfo() { return this.minimalDeviceInfo; } async close() { return new Promise((resolve, reject) => { try { this.device.interfaces?.forEach((iface) => { if (iface.isKernelDriverActive()) { iface.detachKernelDriver(); } iface.release(true, () => { }); // release w/ callback to avoid warning }); this.device.close(); resolve(); } catch (err) { reject(err); } }); } } exports.LibUsbTransport = LibUsbTransport; //# sourceMappingURL=lib-usb-transport.js.map