Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
busticated committed Feb 19, 2020
1 parent f3c68b1 commit 95e181f
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 52 deletions.
8 changes: 7 additions & 1 deletion src/cli/usb.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,13 @@ module.exports = ({ commandProcessor, root }) => {

commandProcessor.createCommand(usb, 'dfu', 'Put a device into the DFU mode', {
params: '[devices...]',
options: commonOptions,
options: {
'confirm': {
description: 'Wait until all targeted devices are confirmed to be in DFU mode',
boolean: true
},
...commonOptions
},
examples: {
'$0 $command my_device': 'Put a device named "my_device" into the DFU mode',
'$0 $command --all': 'Put all devices connected to the host computer into the DFU mode'
Expand Down
8 changes: 6 additions & 2 deletions src/cli/usb.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -196,20 +196,23 @@ describe('USB Command-Line Interface', () => {
expect(argv.clierror).to.equal(undefined);
expect(argv.params).to.eql({ devices: [] });
expect(argv.all).to.equal(false);
expect(argv.confirm).to.equal(false);
});

it('Parses optional arguments', () => {
const argv = commandProcessor.parse(root, ['usb', 'dfu', 'my-device']);
expect(argv.clierror).to.equal(undefined);
expect(argv.params).to.eql({ devices: ['my-device'] });
expect(argv.all).to.equal(false);
expect(argv.confirm).to.equal(false);
});

it('Parses options flags', () => {
const argv = commandProcessor.parse(root, ['usb', 'dfu', '--all']);
const argv = commandProcessor.parse(root, ['usb', 'dfu', '--all', '--confirm']);
expect(argv.clierror).to.equal(undefined);
expect(argv.params).to.eql({ devices: [] });
expect(argv.all).to.equal(true);
expect(argv.confirm).to.equal(true);
});

it('Includes help with examples', () => {
Expand All @@ -220,7 +223,8 @@ describe('USB Command-Line Interface', () => {
'Usage: particle usb dfu [options] [devices...]',
'',
'Options:',
' --all Send the command to all devices connected to the host computer [boolean]',
' --confirm Wait until all targeted devices are confirmed to be in DFU mode [boolean]',
' --all Send the command to all devices connected to the host computer [boolean]',
'',
'Examples:',
' particle usb dfu my_device Put a device named "my_device" into the DFU mode',
Expand Down
113 changes: 64 additions & 49 deletions src/cmd/usb.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const { spin } = require('../app/ui');
const { asyncMapSeries } = require('../lib/utilities');
const { delay, asyncMapSeries } = require('../lib/utilities');
const { getDevice, formatDeviceInfo } = require('./device-util');
const { getUsbDevices, openUsbDevice, openUsbDeviceById } = require('./usb-util');
const { systemSupportsUdev, udevRulesInstalled, installUdevRules } = require('./udev');
Expand Down Expand Up @@ -108,15 +108,30 @@ module.exports = class UsbCommand {
});
}

dfu(args) {
return this._forEachUsbDevice(args, usbDevice => {
if (!usbDevice.isInDfuMode) {
dfu(args){
const self = this;
const { confirm } = args;
const options = { dfuMode: true };
const enterDFU = (usbDevice) => {
if (!usbDevice.isInDfuMode){
return usbDevice.enterDfuMode();
}
}, { dfuMode: true })
.then(() => {
console.log('Done.');
});
};

return self._forEachUsbDevice(args, enterDFU, options)
.then(function getStatus(){
if (!confirm){
return;
}
return self._openUsbDevices(args, options)
.then(usbDevices => usbDevices.every(d => d.isInDfuMode))
.then(isInDFUMode => {
if (!isInDFUMode){
return delay(2000).then(getStatus);
}
});
})
.then(() => console.log('Done.'));
}

reset(args) {
Expand Down Expand Up @@ -159,48 +174,12 @@ module.exports = class UsbCommand {
.then(() => console.log('Done.'));
}

_forEachUsbDevice(args, func, { dfuMode = false } = {}) {
const deviceIds = args.params.devices;
_forEachUsbDevice(args, func, { dfuMode = false } = {}){
const msg = 'Getting device information...';
const operation = this._openUsbDevices(args, { dfuMode });
let lastError = null;
return Promise.resolve().then(() => {
const openUsbDevices = [];
let p = null;
if (args.all) {
// Open all attached devices
p = getUsbDevices()
.then(usbDevices => {
return asyncMapSeries(usbDevices, (usbDevice) => {
return openUsbDevice(usbDevice, { dfuMode })
.then(() => openUsbDevices.push(usbDevice))
.catch(e => lastError = e); // Skip the device and remember the error
});
});
} else if (deviceIds.length === 0) {
// Open a single device. Fail if multiple devices are detected
p = getUsbDevices()
.then(usbDevices => {
if (usbDevices.length === 0) {
throw new Error('No devices found');
}
if (usbDevices.length > 1) {
throw new Error('Found multiple devices. Please specify the ID or name of one of them');
}
const usbDevice = usbDevices[0];
return openUsbDevice(usbDevice, { dfuMode })
.then(() => openUsbDevices.push(usbDevice));
});
} else {
// Open specific devices
p = asyncMapSeries(deviceIds, (id) => {
return openUsbDeviceById({ id, dfuMode, api: this._api, auth: this._auth })
.then(usbDevice => openUsbDevices.push(usbDevice))
.catch(e => lastError = e);
});
}
return p.then(() => openUsbDevices);
})
return spin(operation, msg)
.then(usbDevices => {
// Send the command to each device
const p = usbDevices.map(usbDevice => {
return Promise.resolve()
.then(() => func(usbDevice))
Expand All @@ -210,10 +189,46 @@ module.exports = class UsbCommand {
return spin(Promise.all(p), 'Sending a command to the device...');
})
.then(() => {
if (lastError) {
if (lastError){
throw lastError;
}
});
}

_openUsbDevices(args, { dfuMode = false } = {}){
const deviceIds = args.params.devices;
return Promise.resolve()
.then(() => {
if (args.all){
return getUsbDevices()
.then(usbDevices => {
return asyncMapSeries(usbDevices, (usbDevice) => {
return openUsbDevice(usbDevice, { dfuMode })
.then(() => usbDevice);
});
});
}

if (deviceIds.length === 0){
return getUsbDevices()
.then(usbDevices => {
if (usbDevices.length === 0){
throw new Error('No devices found');
}
if (usbDevices.length > 1){
throw new Error('Found multiple devices. Please specify the ID or name of one of them');
}
const usbDevice = usbDevices[0];
return openUsbDevice(usbDevice, { dfuMode })
.then(() => [usbDevice]);
});
}

return asyncMapSeries(deviceIds, (id) => {
return openUsbDeviceById({ id, dfuMode, api: this._api, auth: this._auth })
.then(usbDevice => usbDevice);
});
});
}
};

0 comments on commit 95e181f

Please sign in to comment.