Skip to content

Commit c24810f

Browse files
authored
Merge pull request #843 from particle-iot/feature/tachyon-picker
Feature/tachyon picker
2 parents c787510 + bceffec commit c24810f

File tree

6 files changed

+132
-116
lines changed

6 files changed

+132
-116
lines changed

src/cmd/backup-restore-tachyon.js

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ module.exports = class BackupRestoreTachyonCommand extends CLICommandBase {
2222
}
2323

2424
async backup({ 'output-dir': outputDir = process.cwd(), 'log-dir': logDir = this._logsDir } = {}) {
25-
const { id: deviceId } = await getEDLDevice({ ui: this.ui });
25+
const device = await getEDLDevice({ ui: this.ui });
2626
const outputDirExist = await fs.exists(outputDir);
2727
const logDirExist = await fs.exists(logDir);
2828
if (!outputDirExist) {
@@ -33,18 +33,18 @@ module.exports = class BackupRestoreTachyonCommand extends CLICommandBase {
3333
}
3434

3535
const startTime = new Date();
36-
const outputLog = path.join(logDir, `tachyon_${deviceId}_backup_${Date.now()}.log`);
36+
const outputLog = path.join(logDir, `tachyon_${device.id}_backup_${Date.now()}.log`);
3737

38-
this.ui.stdout.write(`Backing up NV data from device ${deviceId}...${os.EOL}`);
38+
this.ui.stdout.write(`Backing up NV data from device ${device.id}...${os.EOL}`);
3939
this.ui.stdout.write(`Logs will be saved to ${outputLog}${os.EOL}`);
40-
addLogHeaders({ outputLog, startTime, deviceId, commandName: 'Tachyon backup' });
40+
addLogHeaders({ outputLog, startTime, deviceId: device.id, commandName: 'Tachyon backup' });
4141
try {
4242
const { firehosePath, xmlFile } = await prepareFlashFiles({
4343
logFile: outputLog,
4444
ui: this.ui,
4545
partitionsList: PARTITIONS_TO_BACKUP,
4646
dir: outputDir,
47-
deviceId,
47+
device,
4848
operation: 'read'
4949
});
5050
const files = [
@@ -58,9 +58,10 @@ module.exports = class BackupRestoreTachyonCommand extends CLICommandBase {
5858
ui: this.ui,
5959
currTask: 'Backup',
6060
skipReset: true,
61+
serialNumber: device.serialNumber
6162
});
6263
await qdl.run();
63-
this.ui.stdout.write(`Backing up NV data from device ${deviceId} complete!${os.EOL}`);
64+
this.ui.stdout.write(`Backing up NV data from device ${device.id} complete!${os.EOL}`);
6465
} catch (error) {
6566
this.ui.stdout.write(`An error ocurred while trying to backing up your tachyon ${os.EOL}`);
6667
this.ui.stdout.write(`Error: ${error.message} ${os.EOL}`);
@@ -74,23 +75,23 @@ module.exports = class BackupRestoreTachyonCommand extends CLICommandBase {
7475
'input-dir': inputDir = process.cwd(),
7576
'log-dir': logDir = this._logsDir,
7677
} = {}) {
77-
const { id: deviceId } = await getEDLDevice({ ui: this.ui });
78+
const device = await getEDLDevice({ ui: this.ui });
7879
if (!await fs.exists(logDir)) {
7980
await fs.mkdir(logDir, { recursive: true });
8081
}
8182

8283
const startTime = new Date();
83-
const outputLog = path.join(logDir, `tachyon_${deviceId}_restore_${Date.now()}.log`);
84-
this.ui.stdout.write(`Restoring NV data to device ${deviceId}...${os.EOL}`);
84+
const outputLog = path.join(logDir, `tachyon_${device.id}_restore_${Date.now()}.log`);
85+
this.ui.stdout.write(`Restoring NV data to device ${device.id}...${os.EOL}`);
8586
this.ui.stdout.write(`Logs will be saved to ${outputLog}${os.EOL}`);
86-
addLogHeaders({ outputLog, startTime, deviceId, commandName: 'Tachyon restore' });
87+
addLogHeaders({ outputLog, startTime, deviceId: device.id, commandName: 'Tachyon restore' });
8788
try {
8889
const { firehosePath, xmlFile } = await prepareFlashFiles({
8990
logFile: outputLog,
9091
ui: this.ui,
9192
partitionsList: PARTITIONS_TO_BACKUP,
92-
inputDir,
93-
deviceId,
93+
dir: inputDir,
94+
device,
9495
operation: 'program',
9596
checkFiles: true
9697
});
@@ -105,9 +106,10 @@ module.exports = class BackupRestoreTachyonCommand extends CLICommandBase {
105106
ui: this.ui,
106107
currTask: 'Restore',
107108
skipReset: true,
109+
serialNumber: device.serialNumber,
108110
});
109111
await qdl.run();
110-
this.ui.stdout.write(`Restoring NV data to device ${deviceId} complete!${os.EOL}`);
112+
this.ui.stdout.write(`Restoring NV data to device ${device.id} complete!${os.EOL}`);
111113

112114
} catch (error) {
113115
this.ui.stdout.write(`An error ocurred while trying to restore up your tachyon ${os.EOL}`);

src/cmd/flash.js

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ module.exports = class FlashCommand extends CLICommandBase {
7474
}
7575

7676
//returns true if successful or false if failed
77-
async flashTachyon({ files, skipReset, output, verbose=true }) {
77+
async flashTachyon({ device, files, skipReset, output, verbose=true }) {
7878
let zipFile;
7979
let includeDir = '';
8080
let updateFolder = '';
@@ -114,8 +114,11 @@ module.exports = class FlashCommand extends CLICommandBase {
114114
this.ui.write(`${os.EOL}Starting download. See logs at: ${outputLog}${os.EOL}`);
115115
}
116116
const startTime = new Date();
117-
const { id: deviceId } = await getEDLDevice({ ui: this.ui });
118-
addLogHeaders({ outputLog, startTime, deviceId, commandName: 'Tachyon Flash' });
117+
if (!device) {
118+
device = await getEDLDevice({ ui: this.ui });
119+
}
120+
121+
addLogHeaders({ outputLog, startTime, deviceId: device.id, commandName: 'Tachyon Flash' });
119122
addManifestInfoLog({ outputLog, manifest: manifestInfo });
120123
const qdl = new QdlFlasher({
121124
files: filesToProgram,
@@ -125,7 +128,8 @@ module.exports = class FlashCommand extends CLICommandBase {
125128
ui: this.ui,
126129
outputLogFile: outputLog,
127130
skipReset,
128-
currTask: 'OS'
131+
currTask: 'OS',
132+
serialNumber: device.serialNumber
129133
});
130134
await qdl.run();
131135
fs.appendFileSync(outputLog, `OS Download complete.${os.EOL}`);
@@ -136,22 +140,26 @@ module.exports = class FlashCommand extends CLICommandBase {
136140
}
137141
}
138142

139-
async flashTachyonXml({ files, skipReset, output }) {
143+
async flashTachyonXml({ device, files, skipReset, output }) {
140144
try {
141145
const zipFile = files.find(f => f.endsWith('.zip'));
142146
const xmlFile = files.find(f => f.endsWith('.xml'));
143-
const { id: deviceId } = await getEDLDevice({ ui: this.ui });
147+
if (!device) {
148+
device = await getEDLDevice({ ui: this.ui });
149+
}
150+
144151

145152
const firehoseFile = await this._getFirehoseFileFromZip(zipFile);
146153
// add log headers
147154
const startTime = new Date();
148-
addLogHeaders({ outputLog: output, startTime, deviceId, commandName: 'Tachyon Flash XML' });
155+
addLogHeaders({ outputLog: output, startTime, deviceId: device.id, commandName: 'Tachyon Flash XML' });
149156
const qdl = new QdlFlasher({
150157
files: [firehoseFile, xmlFile],
151158
ui: this.ui,
152159
outputLogFile: output,
153160
skipReset,
154-
currTask: 'Configuration file'
161+
currTask: 'Configuration file',
162+
serialNumber: device.serialNumber
155163
});
156164

157165
await qdl.run();

src/cmd/identify-tachyon.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ module.exports = class IdentifyTachyonCommand extends CLICommandBase {
1515
}
1616

1717
async identify() {
18-
const { id: deviceId } = await getEDLDevice({ ui: this.ui });
19-
const outputLog = path.join(os.tmpdir(), `tachyon_${deviceId}_identify_${Date.now()}.log`);
18+
const device = await getEDLDevice({ ui: this.ui });
19+
const outputLog = path.join(os.tmpdir(), `tachyon_${device.id}_identify_${Date.now()}.log`);
2020

2121
try {
22-
const tachyonInfo = await getTachyonInfo({ outputLog, ui: this.ui });
22+
const tachyonInfo = await getTachyonInfo({ outputLog, ui: this.ui, device });
2323
this.printIdentification(tachyonInfo);
2424
} catch (error) {
2525
this.ui.stdout.write(`An error ocurred while trying to identify your tachyon ${os.EOL}`);

src/cmd/setup-tachyon.js

Lines changed: 19 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,10 @@ const { sha512crypt } = require('sha512crypt-node');
1414
const DownloadManager = require('../lib/download-manager');
1515
const { platformForId, PLATFORMS } = require('../lib/platform');
1616
const path = require('path');
17-
const { getEdlDevices } = require('particle-usb');
18-
const { delay } = require('../lib/utilities');
1917
const semver = require('semver');
20-
const { prepareFlashFiles, getTachyonInfo, promptWifiNetworks } = require('../lib/tachyon-utils');
18+
const { prepareFlashFiles, getTachyonInfo, promptWifiNetworks, getEDLDevice } = require('../lib/tachyon-utils');
2119
const { supportedCountries } = require('../lib/supported-countries');
2220

23-
24-
const DEVICE_READY_WAIT_TIME = 500; // ms
2521
const showWelcomeMessage = (ui) => `
2622
===================================================================================
2723
Particle Tachyon Setup Command
@@ -50,7 +46,7 @@ module.exports = class SetupTachyonCommands extends CLICommandBase {
5046
spinnerMixin(this);
5147
this._setupApi();
5248
this.ui = ui || this.ui;
53-
this.deviceId = null;
49+
this.device = null;
5450
this._baseDir = settings.ensureFolder();
5551
this._logsDir = path.join(this._baseDir, 'logs');
5652

@@ -81,12 +77,11 @@ module.exports = class SetupTachyonCommands extends CLICommandBase {
8177
// step 2 get device info
8278
this._formatAndDisplaySteps("Now let's get the device info", 2);
8379
this.ui.write('');
84-
const { deviceId, usbVersion } = await this._verifyDeviceInEDLMode();
85-
this.deviceId = deviceId;
86-
this.usbVersion = usbVersion;
80+
const device = await getEDLDevice({ ui: this.ui, showSetupMessage: true });
81+
this.device = device;
8782
// ensure logs dir
8883
await fs.ensureDir(this._logsDir);
89-
this.outputLog = path.join(this._logsDir, `tachyon_flash_${this.deviceId}_${Date.now()}.log`);
84+
this.outputLog = path.join(this._logsDir, `tachyon_flash_${this.device.id}_${Date.now()}.log`);
9085
await fs.ensureFile(this.outputLog);
9186
this.ui.write(`${os.EOL}Starting Process. See logs at: ${this.outputLog}${os.EOL}`);
9287
const deviceInfo = await this._getDeviceInfo();
@@ -111,55 +106,18 @@ module.exports = class SetupTachyonCommands extends CLICommandBase {
111106
config.packagePath = await this._downloadStep(config); // step 6
112107
this.product = await this._getProductDetails(config.productId);
113108
config.registrationCode = await this._registerDeviceStep(config); // step 7
114-
config.esim = await this._getESIMProfiles({ deviceId: this.deviceId, country: config.country, productId: config.productId }); // after add device to product
109+
config.esim = await this._getESIMProfiles({ deviceId: this.device.id, country: config.country, productId: config.productId }); // after add device to product
115110
const { xmlPath } = await this._configureConfigAndSaveStep(config); // step 8
116111
const flashSuccess = await this._flashStep(config.packagePath, xmlPath, config); // step 9
117112
await this._finalStep(flashSuccess, config); // step 10
118113
}
119114

120-
async _verifyDeviceInEDLMode() {
121-
let edlDevices = [];
122-
let device;
123-
let messageShown = false;
124-
while (edlDevices.length === 0) {
125-
try {
126-
edlDevices = await getEdlDevices();
127-
if (edlDevices.length > 0) {
128-
device = edlDevices[0];
129-
break;
130-
}
131-
if (!messageShown) {
132-
const message = `${this.ui.chalk.bold('Before we get started, we need to power on your Tachyon board')}:` +
133-
`${os.EOL}${os.EOL}` +
134-
`1. Plug the USB-C cable into your computer and the Tachyon board.${os.EOL}` +
135-
` The red light should turn on!${os.EOL}${os.EOL}` +
136-
`2. Put the Tachyon device into ${this.ui.chalk.bold('system update')} mode:${os.EOL}` +
137-
` - Hold the button next to the red LED for 3 seconds.${os.EOL}` +
138-
` - When the light starts flashing yellow, release the button.${os.EOL}`;
139-
this.ui.stdout.write(message);
140-
this.ui.stdout.write(os.EOL);
141-
messageShown = true;
142-
}
143-
} catch (error) {
144-
// ignore error
145-
}
146-
await delay(DEVICE_READY_WAIT_TIME);
147-
}
148-
if (messageShown) {
149-
this.ui.stdout.write(`Your device is now in ${this.ui.chalk.bold('system update')} mode!${os.EOL}`);
150-
await delay(1000); // give the user a moment to read the message
151-
}
152-
return {
153-
deviceId: device.id,
154-
usbVersion: device.usbVersion
155-
};
156-
}
157-
158115
async _getDeviceInfo() {
159116
try {
160117
return await this.ui.showBusySpinnerUntilResolved('Getting device info', getTachyonInfo({
161118
outputLog: this.outputLog,
162119
ui: this.ui,
120+
device: this.device
163121
}));
164122
} catch (error) {
165123
// If this fails, the flash won't work so abort early.
@@ -177,10 +135,10 @@ module.exports = class SetupTachyonCommands extends CLICommandBase {
177135
this.ui.write(` - Region: ${deviceInfo.region}`);
178136
this.ui.write(` - OS Version: ${deviceInfo.osVersion}`);
179137
let usbWarning = '';
180-
if (this.usbVersion.major <= 2) {
138+
if (this.device.usbVersion.major <= 2) {
181139
usbWarning = this.ui.chalk.yellow(' (use a USB 3.0 port and USB-C cable for faster flashing)');
182140
}
183-
this.ui.write(` - USB Version: ${this.usbVersion.major}.${this.usbVersion.minor}${usbWarning}`);
141+
this.ui.write(` - USB Version: ${this.device.usbVersion.major}.${this.device.usbVersion.minor}${usbWarning}`);
184142
}
185143

186144
async _verifyLogin() {
@@ -385,17 +343,18 @@ module.exports = class SetupTachyonCommands extends CLICommandBase {
385343
const { path: configBlobPath, configBlob } = await this._runStepWithTiming(
386344
'Creating the configuration file to write to the Tachyon device...',
387345
9,
388-
() => this._createConfigBlob(config, this.deviceId)
346+
() => this._createConfigBlob(config, this.device.id)
389347
);
390348

391349
const { xmlFile: xmlPath } = await prepareFlashFiles({
392350
logFile: this.outputLog,
393351
ui: this.ui,
394352
partitionsList: ['misc'],
395353
dir: path.dirname(configBlobPath),
396-
deviceId: this.deviceId,
354+
deviceId: this.device.id,
397355
operation: 'program',
398-
checkFiles: true
356+
checkFiles: true,
357+
device: this.device
399358
});
400359
// Save the config file if requested
401360
if (config.saveConfig) {
@@ -407,7 +366,7 @@ module.exports = class SetupTachyonCommands extends CLICommandBase {
407366

408367
async _flashStep(packagePath, xmlPath, config) {
409368
let message = `Heads up: this is a large image and flashing will take about 2 minutes to complete.${os.EOL}`;
410-
const slowUsb = this.usbVersion.major <= 2;
369+
const slowUsb = this.device.usbVersion.major <= 2;
411370
if (slowUsb) {
412371
message = `Heads up: this is a large image and flashing will take about 8 minutes to complete.${os.EOL}` +
413372
this.ui.chalk.yellow(`${os.EOL}The device is connected to a slow USB port. Connect a USB Type-C cable directly to a USB 3.0 port to shorten this step to 2 minutes.${os.EOL}`);
@@ -471,7 +430,7 @@ module.exports = class SetupTachyonCommands extends CLICommandBase {
471430

472431
_consoleLink() {
473432
const baseUrl = `https://console${settings.isStaging ? '.staging' : ''}.particle.io`;
474-
return `${baseUrl}/${this.product.slug}/devices/${this.deviceId}`;
433+
return `${baseUrl}/${this.product.slug}/devices/${this.device.id}`;
475434
}
476435

477436
async _runStepWithTiming(stepDesc, stepNumber, asyncTask, minDuration = 2000) {
@@ -675,8 +634,8 @@ module.exports = class SetupTachyonCommands extends CLICommandBase {
675634
}
676635

677636
async _getRegistrationCode(productId) {
678-
await this._assignDeviceToProduct({ productId: productId, deviceId: this.deviceId });
679-
const data = await this.api.getRegistrationCode({ productId, deviceId: this.deviceId });
637+
await this._assignDeviceToProduct({ productId: productId, deviceId: this.device.id });
638+
const data = await this.api.getRegistrationCode({ productId, deviceId: this.device.id });
680639
return data.registration_code;
681640
}
682641

@@ -733,9 +692,9 @@ module.exports = class SetupTachyonCommands extends CLICommandBase {
733692
const flashCommand = new FlashCommand();
734693

735694
if (!skipFlashingOs) {
736-
await flashCommand.flashTachyon({ files: [packagePath], skipReset: true, output: this.outputLog, verbose: false });
695+
await flashCommand.flashTachyon({ device: this.device, files: [packagePath], skipReset: true, output: this.outputLog, verbose: false });
737696
}
738-
await flashCommand.flashTachyonXml({ files, skipReset, output: this.outputLog });
697+
await flashCommand.flashTachyonXml({ device: this.device, files, skipReset, output: this.outputLog });
739698
return true;
740699
}
741700

src/lib/qdl.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const os = require('os');
1111
const TACHYON_STORAGE_TYPE = 'ufs';
1212

1313
class QdlFlasher {
14-
constructor({ files, includeDir, updateFolder, zip, ui, outputLogFile, skipReset=false, currTask=null }) {
14+
constructor({ files, includeDir, updateFolder, zip, ui, outputLogFile, skipReset=false, currTask=null, serialNumber }) {
1515
this.files = files;
1616
this.includeDir = includeDir;
1717
this.updateFolder = updateFolder;
@@ -27,11 +27,15 @@ class QdlFlasher {
2727
this.preparingDownload = false;
2828
this.skipReset = skipReset;
2929
this.currTask = currTask;
30+
this.serialNumber = serialNumber;
3031
}
3132

3233
async run() {
3334
let qdlProcess;
3435
try {
36+
if (!this.serialNumber) {
37+
throw new Error('serial Number not provided yet'); // this helps to know if I've implemented everything
38+
}
3539
const qdlPath = await this.getExecutable();
3640
const qdlArguments = this.buildArgs({ files: this.files, includeDir: this.includeDir, zip: this.zip });
3741
this.progressBar = this.ui.createProgressBar();
@@ -91,6 +95,7 @@ class QdlFlasher {
9195
const { tachyonFlashChunkSize } = settings;
9296
return [
9397
'--storage', TACHYON_STORAGE_TYPE,
98+
'--serial', this.serialNumber,
9499
...(tachyonFlashChunkSize ? ['--out-chunk-size', tachyonFlashChunkSize] : []),
95100
...(zip ? ['--zip', zip] : []),
96101
...(includeDir ? ['--include', includeDir] : []),

0 commit comments

Comments
 (0)