Skip to content

Commit

Permalink
Merge pull request #732 from particle-iot/bug/sc-127690/imei-missing-…
Browse files Browse the repository at this point in the history
…from-particle-identify

use serial identify in case the device does not support control request
  • Loading branch information
hugomontero authored May 9, 2024
2 parents f240d35 + f153515 commit 7a1fd32
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 9 deletions.
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

0 comments on commit 7a1fd32

Please sign in to comment.