Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use serial identify in case the device does not support control request #732

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 123 additions & 8 deletions src/cmd/serial.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ const FlashCommand = require('./flash');
const usbUtils = require('./usb-util');
const { platformForId } = require('../lib/platform');
const { FirmwareModuleDisplayNames } = require('particle-usb');
const semver = require('semver');

const IDENTIFY_COMMAND_TIMEOUT = 20000;


// TODO: DRY this up somehow
Expand Down Expand Up @@ -259,18 +262,40 @@ module.exports = class SerialCommand extends CLICommandBase {
// Obtain system firmware version
fwVer = device.firmwareVersion;


// If the device is a cellular device, obtain imei and iccid
try {
const features = platformForId(device.platformId).features;
if (features.includes('cellular')) {
const cellularMetrics = await device.getCellularInfo();
cellularImei = cellularMetrics.imei;
cellularIccid = cellularMetrics.iccid;

const features = platformForId(device.platformId).features;
if (features.includes('cellular')) {
// since from 6.x onwards we can't use serial to get imei, we use control request
if (semver.gte(fwVer, '6.0.0')) {
try {
const cellularInfo = await device.getCellularInfo({ timeout: 2000 });
if (!cellularInfo) {
throw new VError('No data returned from control request for device info');
}
cellularImei = cellularInfo.imei;
cellularIccid = cellularInfo.iccid;
} catch (err) {
// ignore and move on to get other fields
throw new VError(ensureError(err), 'Could not get device info');
}
} else {
try {
const cellularInfo = await this.getDeviceInfoFromSerial(deviceFromSerialPort);
if (!cellularInfo) {
throw new VError('No data returned from serial port for device info');
}
cellularImei = cellularInfo.imei;
cellularIccid = cellularInfo.iccid;
} catch (err) {
// ignore and move on to get other fields
throw new VError(ensureError(err), 'Could not get device info, ensure the device is in listening mode');
}
}
} catch (err) {
// ignore and move on to get other fields
}


// Print whatever was obtained from the device
this._printIdentifyInfo({
deviceId,
Expand Down Expand Up @@ -1087,5 +1112,95 @@ module.exports = class SerialCommand extends CLICommandBase {
);
process.exit(0);
}

getDeviceInfoFromSerial(device){
return this._issueSerialCommand(device, 'i', IDENTIFY_COMMAND_TIMEOUT)
.then((data) => {
const matches = data.match(/Your (core|device) id is\s+(\w+)/);

if (matches && matches.length === 3){
return matches[2];
}

const electronMatches = data.match(/\s+([a-fA-F0-9]{24})\s+/);

if (electronMatches && electronMatches.length === 2){
const info = { id: electronMatches[1] };
const imeiMatches = data.match(/IMEI: (\w+)/);

if (imeiMatches){
info.imei = imeiMatches[1];
}

const iccidMatches = data.match(/ICCID: (\w+)/);

if (iccidMatches){
info.iccid = iccidMatches[1];
}

return info;
}
});
}

/* eslint-enable max-statements */

/**
* Sends a command to the device and retrieves the response.
* @param devicePort The device port to send the command to
* @param command The command text
* @param timeout How long in milliseconds to wait for a response
* @returns {Promise} to send the command.
* The serial port should not be open, and is closed after the command is sent.
* @private
*/
_issueSerialCommand(device, command, timeout){
if (!device){
throw new VError('No serial port identified');
}
const failDelay = timeout || 5000;

let serialPort;
return new Promise((resolve, reject) => {
serialPort = new SerialPort({ path: device.port, ...SERIAL_PORT_DEFAULTS });
const parser = new SerialBatchParser({ timeout: 250 });
serialPort.pipe(parser);

const failTimer = setTimeout(() => {
reject(timeoutError);
}, failDelay);

parser.on('data', (data) => {
clearTimeout(failTimer);
resolve(data.toString());
});

serialPort.open((err) => {
if (err){
console.error('Serial err: ' + err);
console.error('Serial problems, please reconnect the device.');
reject('Serial problems, please reconnect the device.');
return;
}

serialPort.write(command, (werr) => {
if (werr){
reject(err);
}
});
});
})
.finally(() => {
if (serialPort){
serialPort.removeAllListeners('open');

if (serialPort.isOpen){
return new Promise((resolve) => {
serialPort.close(resolve);
});
}
}
});
}
};

2 changes: 1 addition & 1 deletion src/cmd/serial.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe('Serial Command', () => {
describe('identifyDevice', () => {
it('identifies a cellular device with dvos over serial', async () => {
const deviceId = '1234456789abcdef';
const fwVer = '5.4.0';
const fwVer = '6.1.0';
const imei = '1234';
const iccid = '5678';
const wifiDeviceFromSerialPort = {
Expand Down
Loading