Skip to content
This repository was archived by the owner on Oct 1, 2024. It is now read-only.

Unify verify, upload, and uploadUsingProgrammer to a single code path #1133

Closed
wants to merge 3 commits into from
Closed
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
198 changes: 58 additions & 140 deletions src/arduino/arduino.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ import { SerialMonitor } from "../serialmonitor/serialMonitor";
import { UsbDetector } from "../serialmonitor/usbDetector";
import { ProgrammerManager } from "./programmerManager";

export enum BuildMode {
Verify = "Verify",
Upload = "Upload",
UploadUsingProgrammer = "Upload (w/programmer)",
};

/**
* Represent an Arduino application based on the official Arduino IDE.
*/
Expand Down Expand Up @@ -93,7 +99,7 @@ export class ArduinoApp {
}
}

public async upload() {
public async buildSketch(mode: BuildMode, output: string = "") {
const dc = DeviceContext.getInstance();
const boardDescriptor = this.getBoardBuildString();
if (!boardDescriptor) {
Expand All @@ -109,7 +115,7 @@ export class ArduinoApp {
await this.getMainSketch(dc);
}

if ((!dc.configuration || !/upload_method=[^=,]*st[^,]*link/i.test(dc.configuration)) && !dc.port) {
if (this.configRequiresSerialForUpload(mode) && !dc.port) {
const choice = await vscode.window.showInformationMessage(
"Serial port is not specified. Do you want to select a serial port for uploading?",
"Yes", "No");
Expand All @@ -120,12 +126,10 @@ export class ArduinoApp {
}

arduinoChannel.show();
arduinoChannel.start(`Upload sketch - ${dc.sketch}`);
arduinoChannel.start(`${mode} sketch - ${dc.sketch}`);

const serialMonitor = SerialMonitor.getInstance();

const needRestore = await serialMonitor.closeSerialMonitor(dc.port);
UsbDetector.getInstance().pauseListening();
await vscode.workspace.saveAll(false);

if (dc.prebuild) {
Expand All @@ -141,146 +145,35 @@ export class ArduinoApp {
}

const appPath = path.join(ArduinoWorkspace.rootPath, dc.sketch);
const args = ["--upload", "--board", boardDescriptor];
if (dc.port) {
args.push("--port", dc.port);
}
args.push(appPath);
if (VscodeSettings.getInstance().logLevel === "verbose") {
args.push("--verbose");
}
if (dc.output) {
const outputPath = path.resolve(ArduinoWorkspace.rootPath, dc.output);
const dirPath = path.dirname(outputPath);
if (!util.directoryExistsSync(dirPath)) {
Logger.notifyUserError("InvalidOutPutPath", new Error(constants.messages.INVALID_OUTPUT_PATH + outputPath));
return;
}

args.push("--pref", `build.path=${outputPath}`);
arduinoChannel.info(`Please see the build logs in Output path: ${outputPath}`);
const args = [];
if (mode === BuildMode.Verify) {
args.push("--verify");
} else {
const msg = "Output path is not specified. Unable to reuse previously compiled files. Upload could be slow. See README.";
arduinoChannel.warning(msg);
}
await util.spawn(this._settings.commandPath, arduinoChannel.channel, args).then(async () => {
UsbDetector.getInstance().resumeListening();
if (needRestore) {
await serialMonitor.openSerialMonitor();
}
arduinoChannel.end(`Uploaded the sketch: ${dc.sketch}${os.EOL}`);
}, (reason) => {
arduinoChannel.error(`Exit with code=${reason.code}${os.EOL}`);
});
}

public async uploadUsingProgrammer() {
const dc = DeviceContext.getInstance();
const boardDescriptor = this.getBoardBuildString();
if (!boardDescriptor) {
return;
}

const selectProgrammer = this.getProgrammerString();
if (!selectProgrammer) {
return;
}
args.push("--upload");

if (!ArduinoWorkspace.rootPath) {
vscode.window.showWarningMessage("Cannot find the sketch file.");
return;
}

if (!dc.sketch || !util.fileExistsSync(path.join(ArduinoWorkspace.rootPath, dc.sketch))) {
await this.getMainSketch(dc);
}
if (!dc.port) {
const choice = await vscode.window.showInformationMessage(
"Serial port is not specified. Do you want to select a serial port for uploading?",
"Yes", "No");
if (choice === "Yes") {
vscode.commands.executeCommand("arduino.selectSerialPort");
if (dc.port) {
args.push("--port", dc.port);
}
return;
}

arduinoChannel.show();
arduinoChannel.start(`Upload sketch - ${dc.sketch}`);

const serialMonitor = SerialMonitor.getInstance();

const needRestore = await serialMonitor.closeSerialMonitor(dc.port);
UsbDetector.getInstance().pauseListening();
await vscode.workspace.saveAll(false);

const appPath = path.join(ArduinoWorkspace.rootPath, dc.sketch);
const args = ["--upload", "--board", boardDescriptor, "--port", dc.port, "--useprogrammer",
"--pref", "programmer=" + selectProgrammer, appPath];
if (VscodeSettings.getInstance().logLevel === "verbose") {
args.push("--verbose");
}
if (dc.output) {
const outputPath = path.resolve(ArduinoWorkspace.rootPath, dc.output);
const dirPath = path.dirname(outputPath);
if (!util.directoryExistsSync(dirPath)) {
Logger.notifyUserError("InvalidOutPutPath", new Error(constants.messages.INVALID_OUTPUT_PATH + outputPath));
return;
}
if (mode === BuildMode.UploadUsingProgrammer) {
const programmer = this.getProgrammerString();
if (!programmer) {
return;
}

args.push("--pref", `build.path=${outputPath}`);
arduinoChannel.info(`Please see the build logs in Output path: ${outputPath}`);
} else {
const msg = "Output path is not specified. Unable to reuse previously compiled files. Upload could be slow. See README.";
arduinoChannel.warning(msg);
}
await util.spawn(this._settings.commandPath, arduinoChannel.channel, args).then(async () => {
UsbDetector.getInstance().resumeListening();
if (needRestore) {
await serialMonitor.openSerialMonitor();
args.push("--useprogrammer", "--pref", "programmer=" + programmer);
}
arduinoChannel.end(`Uploaded the sketch: ${dc.sketch}${os.EOL}`);
}, (reason) => {
arduinoChannel.error(`Exit with code=${reason.code}${os.EOL}`);
});
}

public async verify(output: string = "") {
const dc = DeviceContext.getInstance();
const boardDescriptor = this.getBoardBuildString();
if (!boardDescriptor) {
return;
}

if (!ArduinoWorkspace.rootPath) {
vscode.window.showWarningMessage("Cannot find the sketch file.");
return;
}

if (!dc.sketch || !util.fileExistsSync(path.join(ArduinoWorkspace.rootPath, dc.sketch))) {
await this.getMainSketch(dc);
}

await vscode.workspace.saveAll(false);
args.push("--board", boardDescriptor)

arduinoChannel.start(`Verify sketch - ${dc.sketch}`);

if (dc.prebuild) {
arduinoChannel.info(`Run prebuild command: ${dc.prebuild}`);
const prebuildargs = dc.prebuild.split(" ");
const prebuildCommand = prebuildargs.shift();
try {
await util.spawn(prebuildCommand, arduinoChannel.channel, prebuildargs, { shell: true, cwd: ArduinoWorkspace.rootPath });
} catch (ex) {
arduinoChannel.error(`Run prebuild failed: \n${ex.error}`);
return;
}
}
args.push(appPath);

const appPath = path.join(ArduinoWorkspace.rootPath, dc.sketch);
const args = ["--verify", "--board", boardDescriptor, appPath];
if (VscodeSettings.getInstance().logLevel === "verbose") {
args.push("--verbose");
}

if (output || dc.output) {
const outputPath = path.resolve(ArduinoWorkspace.rootPath, output || dc.output);
const dirPath = path.dirname(outputPath);
Expand All @@ -290,28 +183,37 @@ export class ArduinoApp {
}

args.push("--pref", `build.path=${outputPath}`);

arduinoChannel.info(`Please see the build logs in Output path: ${outputPath}`);
} else {
const msg = "Output path is not specified. Unable to reuse previously compiled files. Verify could be slow. See README.";
const msg = `Output path is not specified. Unable to reuse previously compiled files. ${mode} could be slow. See README.`;
arduinoChannel.warning(msg);
}

arduinoChannel.show();
// we need to return the result of verify
// we need to return the result of the process
let restoreSerial: boolean = false;
try {
if (mode !== BuildMode.Verify) {
restoreSerial = await serialMonitor.closeSerialMonitor(dc.port);
UsbDetector.getInstance().pauseListening();
}

await util.spawn(this._settings.commandPath, arduinoChannel.channel, args);
arduinoChannel.end(`Finished verify sketch - ${dc.sketch}${os.EOL}`);
arduinoChannel.end(`${mode} finished - ${dc.sketch}${os.EOL}`);
return true;
} catch (reason) {
const msg = reason.code ?
`Exit with code=${reason.code}${os.EOL}` :
reason.message ?
reason.message :
JSON.stringify(reason);
reason.message ? reason.message : JSON.stringify(reason);
arduinoChannel.error(msg);
return false;
} finally {
if (mode !== BuildMode.Verify) {
UsbDetector.getInstance().resumeListening();
if (restoreSerial) {
await serialMonitor.openSerialMonitor();
}
}
}

}

public tryToUpdateIncludePaths() {
Expand Down Expand Up @@ -760,4 +662,20 @@ Please make sure the folder is not occupied by other procedures .`);
throw new Error("No sketch file was found.");
}
}

private configRequiresSerialForUpload(mode: BuildMode): boolean {
const dc = DeviceContext.getInstance();

if (mode === BuildMode.Verify) {
return false;
} else if (mode === BuildMode.UploadUsingProgrammer) {
// Currently all programmer configurations require a selected serial port
return true;
}

// Certain boards allow configuration of the STLink programmers as part of the board
// config and use during the regular upload, rather than "Upload using programmer"
// https://github.com/microsoft/vscode-arduino/issues/595
return (!dc.configuration || !/upload_method=[^=,]*st[^,]*link/i.test(dc.configuration));
}
}
4 changes: 2 additions & 2 deletions src/debug/configurationProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import * as path from "path";
import * as vscode from "vscode";

import { ArduinoApp } from "../arduino/arduino";
import { BuildMode } from "../arduino/arduino";
import ArduinoActivator from "../arduinoActivator";
import ArduinoContext from "../arduinoContext";

Expand Down Expand Up @@ -136,7 +136,7 @@ export class ArduinoDebugConfigurationProvider implements vscode.DebugConfigurat
config.program = path.join(ArduinoWorkspace.rootPath, outputFolder, `${path.basename(dc.sketch)}.elf`);

// always compile elf to make sure debug the right elf
if (!await ArduinoContext.arduinoApp.verify(outputFolder)) {
if (!await ArduinoContext.arduinoApp.buildSketch(BuildMode.Verify, outputFolder)) {
vscode.window.showErrorMessage("Failure to verify the program, please check output for details.");
return false;
}
Expand Down
7 changes: 4 additions & 3 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const completionProviderModule = impor("./langService/completionProvider") as ty
import * as Logger from "./logger/logger";
const nsatModule =
impor("./nsat") as typeof import ("./nsat");
import { BuildMode } from "./arduino/arduino";
import { SerialMonitor } from "./serialmonitor/serialMonitor";
const usbDetectorModule = impor("./serialmonitor/usbDetector") as typeof import ("./serialmonitor/usbDetector");

Expand Down Expand Up @@ -121,7 +122,7 @@ export async function activate(context: vscode.ExtensionContext) {
location: vscode.ProgressLocation.Window,
title: "Arduino: Verifying...",
}, async () => {
await arduinoContextModule.default.arduinoApp.verify();
await arduinoContextModule.default.arduinoApp.buildSketch(BuildMode.Verify);
});
} catch (ex) {
}
Expand All @@ -142,7 +143,7 @@ export async function activate(context: vscode.ExtensionContext) {
location: vscode.ProgressLocation.Window,
title: "Arduino: Uploading...",
}, async () => {
await arduinoContextModule.default.arduinoApp.upload();
await arduinoContextModule.default.arduinoApp.buildSketch(BuildMode.Upload);
});
} catch (ex) {
}
Expand Down Expand Up @@ -177,7 +178,7 @@ export async function activate(context: vscode.ExtensionContext) {
if (!status.compile) {
status.compile = "upload";
try {
await arduinoContextModule.default.arduinoApp.uploadUsingProgrammer();
await arduinoContextModule.default.arduinoApp.buildSketch(BuildMode.UploadUsingProgrammer);
} catch (ex) {
}
delete status.compile;
Expand Down