UNPKG

@shuttle-lib/core

Version:

NPM package to interact with the Shuttle devices

150 lines 5.77 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Shuttle = void 0; const eventemitter3_1 = require("eventemitter3"); const products_js_1 = require("./products.js"); const lib_js_1 = require("./lib.js"); class Shuttle extends eventemitter3_1.EventEmitter { /** Vendor ids for the Shuttle devices */ static get vendorIds() { return products_js_1.VENDOR_IDS; } constructor(_device, _deviceInfo, _devicePath) { super(); this._device = _device; this._deviceInfo = _deviceInfo; this._devicePath = _devicePath; this._buttonStates = new Map(); this._shuttleState = 0; this._jogState = 0; this._initialized = false; this._disconnected = false; this.product = this._setupDevice(_deviceInfo); } _setupDevice(deviceInfo) { const findProduct = () => { for (const product of Object.values(products_js_1.PRODUCTS)) { if (product.vendorId === deviceInfo.vendorId && product.productId === deviceInfo.productId && product.interface === deviceInfo.interface) { return { product, vendorId: deviceInfo.vendorId, productId: deviceInfo.productId, interface: deviceInfo.interface, }; } } // else: throw new Error(`Unknown/Unsupported Shuttle device: "${deviceInfo.product}" (vendorId: "${deviceInfo.vendorId}", productId: "${deviceInfo.productId}", interface: "${deviceInfo.interface}").\nPlease report this as an issue on our github page!`); }; const found = findProduct(); for (let i = 0; i < found.product.buttonBits.length; i++) { if (!this._buttonStates.has(i)) this._buttonStates.set(i, false); } this._device.on('data', (data) => { const dataView = (0, lib_js_1.uint8ArrayToDataView)(data); const shuttle = dataView.getInt8(0); if (shuttle !== this._shuttleState) { this._shuttleState = shuttle; this.emit('shuttle', shuttle); } const jog = dataView.getUint8(1); if (jog !== this._jogState) { let delta = jog - this._jogState; if (this._jogState > 250 && jog < 5) { delta += 256; // fix overflow } else if (this._jogState < 5 && jog > 250) { delta -= 256; // fix underflow } this._jogState = jog; this.emit('jog', delta, jog); } const buttons = dataView.getUint16(3, true); for (let i = 0; i < found.product.buttonBits.length; i++) { const button = Boolean((0, lib_js_1.getBit)(buttons, found.product.buttonBits[i])); if (button !== this._buttonStates.get(i)) { this._buttonStates.set(i, button); if (button) this.emit('down', i); else this.emit('up', i); } } }); this._device.on('error', (err) => { if ((err + '').match(/could not read from/)) { // The device has been disconnected this._triggerHandleDeviceDisconnected(); } else if ((err + '').match(/WebHID disconnected/)) { this._triggerHandleDeviceDisconnected(); } else { this.emit('error', err); } }); return { ...found.product, productId: found.productId, vendorId: found.vendorId, }; } /** Initialize the device. This ensures that the essential information from the device about its state has been received. */ async init() { // Nothing to do here, but keeping this as a placeholder for future use. this._initialized = true; } /** Closes the device. Subsequent commands will raise errors. */ async close() { await this._handleDeviceDisconnected(); } /** Various information about the device and its capabilities */ get info() { this.ensureInitialized(); return (0, lib_js_1.literal)({ productModelId: this.product.productModelId, name: this.product.name, vendorId: this.product.vendorId, productId: this.product.productId, interface: this.product.interface, }); } /** * Returns an object with current Button states */ getButtons() { return new Map(this._buttonStates); // Make a copy } _triggerHandleDeviceDisconnected() { this._handleDeviceDisconnected().catch((error) => { this.emit('error', error); }); } /** (Internal function) Called when there has been detected that the device has been disconnected */ async _handleDeviceDisconnected() { if (!this._disconnected) { this._disconnected = true; await this._device.close(); this.emit('disconnected'); } } get hidDevice() { return this._device; } get deviceInfo() { return this._deviceInfo; } get devicePath() { return this._devicePath; } /** Check that the .init() function has run, throw otherwise */ ensureInitialized() { if (!this._initialized) throw new Error('Shuttle.init() must be run first!'); } } exports.Shuttle = Shuttle; //# sourceMappingURL=Shuttle.js.map