diff --git a/src/arduino/arduino.ts b/src/arduino/arduino.ts index 73619a7b..865032d9 100644 --- a/src/arduino/arduino.ts +++ b/src/arduino/arduino.ts @@ -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. */ @@ -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) { @@ -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"); @@ -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) { @@ -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); @@ -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() { @@ -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)); + } } diff --git a/src/debug/configurationProvider.ts b/src/debug/configurationProvider.ts index c08546f2..614dc542 100644 --- a/src/debug/configurationProvider.ts +++ b/src/debug/configurationProvider.ts @@ -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"; @@ -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; } diff --git a/src/extension.ts b/src/extension.ts index c4112bd7..e999abae 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -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"); @@ -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) { } @@ -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) { } @@ -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;