'use strict'; const os = require('os'); const util = require('util'); const EventEmitter = require('events'); let usb = null; /** * [USB Class Codes ] * @type {Object} * @docs http://www.usb.org/developers/defined_class */ const IFACE_CLASS = { AUDIO : 0x01, HID : 0x03, PRINTER: 0x07, HUB : 0x09 }; /** * [function USB] * @param {[type]} vid [description] * @param {[type]} pid [description] * @return {[type]} [description] */ function USB(vid, pid){ if (!usb) { usb = require('usb'); } EventEmitter.call(this); var self = this; this.device = null; if(vid && pid){ this.device = usb.findByIds(vid, pid); }else if(vid){ // Set spesific USB device from devices array as coming from USB.findPrinter() function. // for example // let devices = escpos.USB.findPrinter(); // => devices [ Device1, Device2 ]; // And Then // const device = new escpos.USB(Device1); OR device = new escpos.USB(Device2); this.device = vid; }else{ var devices = USB.findPrinter(); if(devices && devices.length) this.device = devices[0]; } if (!this.device) throw new Error('Can not find printer'); usb.on('detach', function(device){ if(device == self.device) { self.emit('detach' , device); self.emit('disconnect', device); self.device = null; } }); return this; }; /** * [findPrinter description] * @return {[type]} [description] */ USB.findPrinter = function(){ if (!usb) { usb = require('usb'); } return usb.getDeviceList().filter(function(device){ try{ return device.configDescriptor.interfaces.filter(function(iface){ return iface.filter(function(conf){ return conf.bInterfaceClass === IFACE_CLASS.PRINTER; }).length; }).length; }catch(e){ // console.warn(e) return false; } }); }; /** * getDevice */ USB.getDevice = function(vid, pid){ return new Promise((resolve, reject) => { const device = new USB(vid, pid); device.open(err => { if(err) return reject(err); resolve(device); }); }); }; /** * make USB extends EventEmitter */ util.inherits(USB, EventEmitter); /** * [open usb device] * @param {Function} callback [description] * @return {[type]} [description] */ USB.prototype.open = function (callback){ let self = this, counter = 0, index = 0; this.device.open(); this.device.interfaces.forEach(function(iface){ (function(iface){ iface.setAltSetting(iface.altSetting, function(){ try { // http://libusb.sourceforge.net/api-1.0/group__dev.html#gab14d11ed6eac7519bb94795659d2c971 // libusb_kernel_driver_active / libusb_attach_kernel_driver / libusb_detach_kernel_driver : "This functionality is not available on Windows." if ("win32" !== os.platform()) { if(iface.isKernelDriverActive()) { try { iface.detachKernelDriver(); } catch(e) { console.error("[ERROR] Could not detatch kernel driver: %s", e) } } } iface.claim(); // must be called before using any endpoints of this interface. iface.endpoints.filter(function(endpoint){ if(endpoint.direction == 'out' && !self.endpoint) { self.endpoint = endpoint; } }); if(self.endpoint) { self.emit('connect', self.device); callback && callback(null, self); } else if(++counter === this.device.interfaces.length && !self.endpoint){ callback && callback(new Error('Can not find endpoint from printer')); } } catch (e) { // Try/Catch block to prevent process from exit due to uncaught exception. // i.e LIBUSB_ERROR_ACCESS might be thrown by claim() if USB device is taken by another process // example: MacOS Parallels callback && callback(e); } }); })(iface); }); return this; }; /** * [function write] * @param {[type]} data [description] * @return {[type]} [description] */ USB.prototype.write = function(data, callback){ this.emit('data', data); this.endpoint.transfer(data, callback); return this; }; USB.prototype.close = function(callback){ if(this.device) { try { this.device.close(); usb.removeAllListeners('detach'); callback && callback(null); this.emit('close', this.device); } catch (e) { callback && callback(e); } } else { callback && callback(null); } return this; }; /** * [exports description] * @type {[type]} */ module.exports = USB;