diff --git a/lib/usb_connection.js b/lib/usb_connection.js index 6b0806a5..16458b50 100644 --- a/lib/usb_connection.js +++ b/lib/usb_connection.js @@ -119,39 +119,58 @@ USB.Connection.prototype.open = function() { return reject(e, self); } // Set interface settings - self.intf.setAltSetting(2, function(error) { - if (error) { - return reject(error, self); - } - self.epIn = self.intf.endpoints[0]; - self.epOut = self.intf.endpoints[1]; - if (!self.epIn || !self.epOut) { - return reject(new Error('Device endpoints were not able to be loaded'), self); - } - - // Map desciptions - self.device.getStringDescriptor(self.device.deviceDescriptor.iSerialNumber, function(error, data) { - if (error) { - return reject(error, self); + return self.setAltSetting() + .then(() => { + self.epIn = self.intf.endpoints[0]; + self.epOut = self.intf.endpoints[1]; + if (!self.epIn || !self.epOut) { + return reject(new Error('Device endpoints were not able to be loaded'), self); } - self.serialNumber = data; - // Register this connection with daemon (keeps track of active remote processes) - Daemon.register(self); + // Map desciptions + self.device.getStringDescriptor(self.device.deviceDescriptor.iSerialNumber, function(error, data) { + if (error) { + return reject(error, self); + } - // If the USB Pipe isn't enabled on the other end (ie it is booting) - self.epIn.on('error', function(err) { - // Close the device resources - self._close(); - // Catch the error and return if we haven't already - return reject(err); + self.serialNumber = data; + // Register this connection with daemon (keeps track of active remote processes) + Daemon.register(self); + + // If the USB Pipe isn't enabled on the other end (ie it is booting) + self.epIn.on('error', function(err) { + // Close the device resources + self._close(); + // Catch the error and return if we haven't already + return reject(err); + }); + + // Start receiving messages + self._receiveMessages(); + // If all is well, resolve the promise with the valid connection + return resolve(self); }); + }) + .catch(reject); + }); +}; - // Start receiving messages - self._receiveMessages(); - // If all is well, resolve the promise with the valid connection - return resolve(self); - }); +USB.Connection.prototype.setAltSetting = function() { + return new Promise((resolve, reject) => { + // Set interface settings + this.intf.setAltSetting(0, (error) => { + if (error) { + return reject(error, this); + } else { + // Set interface settings + this.intf.setAltSetting(2, (error) => { + if (error) { + return reject(error, this); + } else { + return resolve(); + } + }); + } }); }); }; diff --git a/test/unit/usb_connection.js b/test/unit/usb_connection.js index 9422bf4e..eb4aa608 100644 --- a/test/unit/usb_connection.js +++ b/test/unit/usb_connection.js @@ -92,6 +92,101 @@ exports['USB.Connection.prototype._write'] = { }, }; +exports['USB.Connection.prototype.open'] = { + setUp: function(done) { + var self = this; + this.sandbox = sinon.sandbox.create(); + this.err = this.sandbox.stub(logs, 'err'); + this.processExit = this.sandbox.stub(process, 'exit'); + this.usbConnection = new USB.Connection({}); + this.usbConnection.epOut = new Emitter(); + this.usbConnection.epOut.transfer = this.sandbox.spy(); + this.usbConnection.epIn = new Emitter(); + this.usbConnection.epIn.startPoll = this.sandbox.spy(); + this.closeFunc = this.sandbox.spy(this.usbConnection, '_close'); + this.fakeInterface = { + claim: function() {}, + setAltSetting: function(arg1, cb) { + cb(); + }, + endpoints: [self.usbConnection.epIn, self.usbConnection.epOut], + }; + this.sandbox.stub(this.usbConnection, 'device', { + open: function() {}, + interface: function() { + return self.fakeInterface; + }, + getStringDescriptor: function(arg1, cb) { + cb(); + }, + deviceDescriptor: { + iSerialNumber: 'blah', + } + }); + this.openDevice = this.sandbox.spy(this.usbConnection.device, 'open'); + this.interface = this.sandbox.spy(this.usbConnection.device, 'interface'); + this.claim = this.sandbox.spy(this.fakeInterface, 'claim'); + this.setAltSetting = this.sandbox.spy(this.fakeInterface, 'setAltSetting'); + this.getStringDescriptor = this.sandbox.spy(this.usbConnection.device, 'getStringDescriptor'); + this.daemonRegister = this.sandbox.spy(Daemon, 'register'); + done(); + }, + + tearDown: function(done) { + this.sandbox.restore(); + done(); + }, + + standardOpen: function(test) { + test.expect(11); + + this.usbConnection.open() + .then(() => { + test.ok(this.openDevice.calledOnce); + test.ok(this.interface.calledOnce); + test.ok(this.interface.alwaysCalledWith(0)); + test.ok(this.claim.calledOnce); + test.ok(this.setAltSetting.calledTwice); + test.equal(this.setAltSetting.firstCall.args[0], 0); + test.equal(this.setAltSetting.secondCall.args[0], 2); + test.ok(this.getStringDescriptor.calledOnce); + test.ok(this.daemonRegister.calledOnce); + test.equal(this.closeFunc.called, false); + test.ok(this.usbConnection.epIn.startPoll.calledOnce); + test.done(); + }) + .catch(function() { + // It should not error + test.fail(); + }); + }, + + setAltSettingFails: function(test) { + test.expect(9); + + this.connectionAltSetting = this.sandbox.stub(this.usbConnection, 'setAltSetting').returns(Promise.reject('bad usb things')); + + this.usbConnection.open() + .then(() => { + // It should not succeed + test.fail(); + }) + .catch((err) => { + test.ok(err); + test.ok(this.openDevice.calledOnce); + test.equal(this.interface.called, true); + test.equal(this.claim.called, true); + test.equal(this.setAltSetting.called, false); + test.equal(this.getStringDescriptor.called, false); + test.equal(this.daemonRegister.called, false); + test.equal(this.closeFunc.called, false); + test.equal(this.usbConnection.epIn.startPoll.called, false); + test.done(); + }); + }, + +}; + exports['USB.Connection.prototype._receiveMessages'] = { setUp: function(done) { this.sandbox = sinon.sandbox.create();