@shuttle-lib/core
Version:
NPM package to interact with the Shuttle devices
145 lines • 5.44 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Shuttle = void 0;
const events_1 = require("events");
const products_1 = require("./products");
const lib_1 = require("./lib");
class Shuttle extends events_1.EventEmitter {
/** Vendor ids for the Shuttle devices */
static get vendorIds() {
return products_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_1.PRODUCTS)) {
if (product.vendorId === deviceInfo.vendorId && product.productId === deviceInfo.productId) {
return {
product,
productId: product.vendorId,
interface: product.productId,
};
}
}
// 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 shuttle = data.readInt8(0);
if (shuttle !== this._shuttleState) {
this._shuttleState = shuttle;
this.emit('shuttle', shuttle);
}
const jog = data.readUint8(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 = data.readUInt16LE(3);
for (let i = 0; i < found.product.buttonBits.length; i++) {
const button = Boolean((0, lib_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,
interface: found.interface,
};
}
/** 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_1.literal)({
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