TL;DR: When Workbench hangs when trying to put a device into DFU mode, end the task and then retry. To reset a device without pressing the button or unplugging it you can use particle usb reset
.
Internally, Workbench uses particle usb dfu
to place devices into DFU mode. If you specify the device name in the project, I believe it will specify the name of the device as an additional argument to particle usb dfu
.
In my experience, when a request to place a device into DFU mode hangs, the device has made it into DFU mode but Particle CLI does not realize and eventually times out after a minute.
If you send a SIGTERM to particle usb dfu
with ^C and then attempt to run particle usb dfu
again, the subsequent invocation will realize that the device is DFU mode.
I managed to sporadically reproduce this on a photon running 2.0.1 using particle-cli 2.10.0. I’m uncertain if the use of a USB hub influences particle usb dfu
to hang more often.
$ particle usb listen # Put photon in listening mode
Done.
$ particle identify # Get deviceID and deviceOS version
Your device id is [REDACTED]
Your system firmware version is 2.0.1
$ system_profiler SPUSBDataType # Verify that photon is present on USB
--- Wait 5 minutes ---
$ particle usb dfu # Put photon in DFU mode. Fails.
# Hangs for one minute, and then the following error is printed:
TimeoutError [VError]
at RequestSender.delay (/Users/nrobinson/.particle/node_modules/particle-cli/node_modules/particle-usb/lib/device.js:106:13)
at /Users/nrobinson/.particle/node_modules/particle-cli/node_modules/particle-usb/lib/device.js:212:17
at async Promise.all (index 0)
at async CLI.runCommand (/Users/nrobinson/.particle/node_modules/particle-cli/dist/app/cli.js:160:7)
at async CLI.run (/Users/nrobinson/.particle/node_modules/particle-cli/dist/app/cli.js:190:14) {
jse_shortmsg: '',
jse_info: {},
message: ''
}
$ particle usb reset # Reset the device. Succeeds.
Here are the commands again, but simplified:
$ particle usb listen
$ particle identify
$ system_profiler SPUSBDataType
$ particle usb dfu
$ particle usb reset
Looking at ~/.particle/node_modules/particle-cli/node_modules/particle-usb/lib/device.js
, the error happens in the enterDfuMode
method:
enterDfuMode({
timeout = _config.globalOptions.requestTimeout
} = {}) {
if (this.isInDfuMode) {
return;
}
return this.timeout(timeout, async s => {
await s.sendRequest(_request.Request.DFU_MODE);
await s.close();
let isInDfuMode;
while (!isInDfuMode) {
try {
await s.open({
includeDfu: true
});
isInDfuMode = s.device.isInDfuMode;
} catch (error) {// device is reconnecting, ignore
}
await s.close();
await s.delay(500);
}
});
}
Line 212 is await s.delay(500);
Update:
In ~/.particle/node_modules/particle-cli/node_modules/particle-usb/lib/device-base.js
the open()
method is defined beginning on line 158.
I changed all instances of this._log.trace
to console.log
.
When reproduced:
$ particle usb dfu
▌ Getting device information...Opening device
Device ID: [REDACTED]
Firmware version: 2.0.1
Device is open
▀ Sending a command to the device...Opening device
Device ID: [REDACTED]
Firmware version: 2.0.1
Device is open
▌ Sending a command to the device...Opening device
Device ID: [REDACTED]
Firmware version: 2.0.1
Device is open
▌ Sending a command to the device...Opening device
Device ID: [REDACTED]
Firmware version: 2.0.1
Device is open
▌ Sending a command to the device...Opening device
Device ID: [REDACTED]
▌ Sending a command to the device...Opening device
Device ID: [REDACTED]
▌ Sending a command to the device...Opening device
Device ID: [REDACTED]
▌ Sending a command to the device...Opening device
Device ID: [REDACTED]
▄ Sending a command to the device...Opening device
Device ID: [REDACTED]
▄ Sending a command to the device...Opening device
Device ID: [REDACTED]
▄ Sending a command to the device...Opening device
# Repeats for many lines
TimeoutError [VError]
at RequestSender.delay (/Users/nrobinson/.particle/node_modules/particle-cli/node_modules/particle-usb/lib/device.js:106:13)
at /Users/nrobinson/.particle/node_modules/particle-cli/node_modules/particle-usb/lib/device.js:212:17
at async Promise.all (index 0)
at async CLI.runCommand (/Users/nrobinson/.particle/node_modules/particle-cli/dist/app/cli.js:160:7)
at async CLI.run (/Users/nrobinson/.particle/node_modules/particle-cli/dist/app/cli.js:190:14) {
jse_shortmsg: '',
jse_info: {},
message: ''
}
I then tried adding console.log(error)
on line 209 in the catch block in device.js
:
$ particle usb dfu
▌ Getting device information...Opening device
Device ID: [REDACTED]
Firmware version: 2.0.1
Device is open
▀ Sending a command to the device...Opening device
Device ID: [REDACTED]
Firmware version: 2.0.1
Device is open
▌ Sending a command to the device...Opening device
Device ID: [REDACTED]
Firmware version: 2.0.1
Device is open
▌ Sending a command to the device...Opening device
Device ID: [REDACTED]
Firmware version: 2.0.1
Device is open
▄ Sending a command to the device...Opening device
Device ID: [REDACTED]
▌ Sending a command to the device...UsbError [VError]: Unknown interface
at /Users/nrobinson/.particle/node_modules/particle-cli/node_modules/particle-usb/lib/usb-device-node.js:140:25
at new Promise (<anonymous>)
at new F (/Users/nrobinson/.particle/node_modules/particle-cli/node_modules/@babel/runtime-corejs2/node_modules/core-js/library/modules/_export.js:36:28)
at UsbDevice.claimInterface (/Users/nrobinson/.particle/node_modules/particle-cli/node_modules/particle-usb/lib/usb-device-node.js:135:12)
at Dfu.open (/Users/nrobinson/.particle/node_modules/particle-cli/node_modules/particle-usb/lib/dfu.js:168:21)
at /Users/nrobinson/.particle/node_modules/particle-cli/node_modules/particle-usb/lib/device-base.js:192:26
at async openDeviceById (/Users/nrobinson/.particle/node_modules/particle-cli/node_modules/particle-usb/lib/device-base.js:1039:3)
at async RequestSender.open (/Users/nrobinson/.particle/node_modules/particle-cli/node_modules/particle-usb/lib/device.js:79:19)
at async /Users/nrobinson/.particle/node_modules/particle-cli/node_modules/particle-usb/lib/device.js:204:11
at async Promise.all (index 0) {
jse_shortmsg: 'Unknown interface',
jse_info: {},
message: 'Unknown interface'
}
▄ Sending a command to the device...Opening device
Device ID: [REDACTED]
UsbError [VError]: Unknown interface
at /Users/nrobinson/.particle/node_modules/particle-cli/node_modules/particle-usb/lib/usb-device-node.js:140:25
at new Promise (<anonymous>)
at new F (/Users/nrobinson/.particle/node_modules/particle-cli/node_modules/@babel/runtime-corejs2/node_modules/core-js/library/modules/_export.js:36:28)
at UsbDevice.claimInterface (/Users/nrobinson/.particle/node_modules/particle-cli/node_modules/particle-usb/lib/usb-device-node.js:135:12)
at Dfu.open (/Users/nrobinson/.particle/node_modules/particle-cli/node_modules/particle-usb/lib/dfu.js:168:21)
at /Users/nrobinson/.particle/node_modules/particle-cli/node_modules/particle-usb/lib/device-base.js:192:26
at async openDeviceById (/Users/nrobinson/.particle/node_modules/particle-cli/node_modules/particle-usb/lib/device-base.js:1039:3)
at async RequestSender.open (/Users/nrobinson/.particle/node_modules/particle-cli/node_modules/particle-usb/lib/device.js:79:19)
at async /Users/nrobinson/.particle/node_modules/particle-cli/node_modules/particle-usb/lib/device.js:204:11
at async Promise.all (index 0) {
jse_shortmsg: 'Unknown interface',
jse_info: {},
message: 'Unknown interface'
}
# Repeats for many lines
TimeoutError [VError]
at RequestSender.delay (/Users/nrobinson/.particle/node_modules/particle-cli/node_modules/particle-usb/lib/device.js:106:13)
at /Users/nrobinson/.particle/node_modules/particle-cli/node_modules/particle-usb/lib/device.js:213:17
at async Promise.all (index 0)
at async CLI.runCommand (/Users/nrobinson/.particle/node_modules/particle-cli/dist/app/cli.js:160:7)
at async CLI.run (/Users/nrobinson/.particle/node_modules/particle-cli/dist/app/cli.js:190:14) {
jse_shortmsg: '',
jse_info: {},
message: ''
}
To resolve this bug, I think it would be good for enterDfuMode()
to catch the UsbError
:
catch (error) {
console.log(error);
if (error instanceof _error.UsbError) {
console.log("Aborted!");
return;
}
}
When reproduced:
$ particle usb dfu
▌ Getting device information...Opening device
Device ID: [REDACTED]
Firmware version: 2.0.1
Device is open
▀ Sending a command to the device...Opening device
Device ID: [REDACTED]
Firmware version: 2.0.1
Device is open
▌ Sending a command to the device...Opening device
Device ID: [REDACTED]
Firmware version: 2.0.1
Device is open
▌ Sending a command to the device...Opening device
Device ID: [REDACTED]
Firmware version: 2.0.1
Device is open
▄ Sending a command to the device...Opening device
▌ Sending a command to the device...Device ID: [REDACTED]
UsbError [VError]: Unknown interface
at /Users/nrobinson/.particle/node_modules/particle-cli/node_modules/particle-usb/lib/usb-device-node.js:140:25
at new Promise (<anonymous>)
at new F (/Users/nrobinson/.particle/node_modules/particle-cli/node_modules/@babel/runtime-corejs2/node_modules/core-js/library/modules/_export.js:36:28)
at UsbDevice.claimInterface (/Users/nrobinson/.particle/node_modules/particle-cli/node_modules/particle-usb/lib/usb-device-node.js:135:12)
at Dfu.open (/Users/nrobinson/.particle/node_modules/particle-cli/node_modules/particle-usb/lib/dfu.js:168:21)
at /Users/nrobinson/.particle/node_modules/particle-cli/node_modules/particle-usb/lib/device-base.js:192:26
at async openDeviceById (/Users/nrobinson/.particle/node_modules/particle-cli/node_modules/particle-usb/lib/device-base.js:1039:3)
at async RequestSender.open (/Users/nrobinson/.particle/node_modules/particle-cli/node_modules/particle-usb/lib/device.js:79:19)
at async /Users/nrobinson/.particle/node_modules/particle-cli/node_modules/particle-usb/lib/device.js:204:11
at async Promise.all (index 0) {
jse_shortmsg: 'Unknown interface',
jse_info: {},
message: 'Unknown interface'
}
Aborted!
Done.
The photon successfully enters DFU mode and particle usb dfu
catches the error and aborts.
Interestingly enough, I can occasionally trigger a hang by simply running particle usb dfu
soon after manually resetting the photon.
Also, I’m looking at particle-usb on GitHub, and the latest release is v1.2.2, yet particle-cli v2.10.0 is uses particle-usb 1.2.1, but I doubt that impacts this issue.
I have opened an issue in particle-usb.