diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a6fd1c7..5368b535 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,13 @@ All notable version changes will be recorded in this file. *** +### [v3.25.2] revision + +**Improve**: + - `Debug`: Support one-click to start debugging for `probe-rs` flasher. Require extension [probe-rs.probe-rs-debugger](https://marketplace.visualstudio.com/items?itemName=probe-rs.probe-rs-debugger) + +*** + ### [v3.25.1] revision **Improve**: diff --git a/package.json b/package.json index dc2cba1c..3960fe1f 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "homepage": "https://em-ide.com", "license": "MIT", "description": "A mcu development environment for 8051/AVR/STM8/Cortex-M/MIPS/RISC-V", - "version": "3.25.1", + "version": "3.25.2", "preview": false, "engines": { "vscode": "^1.67.0" @@ -114,12 +114,6 @@ "yaml": "^1.10.2" }, "contributes": { - "debuggers": [ - { - "type": "eide.cortex-debug", - "label": "EIDE (Cortex-Debug)" - } - ], "terminal": { "profiles": [ { diff --git a/src/EIDEProject.ts b/src/EIDEProject.ts index e2c35cb0..dcdfb22a 100644 --- a/src/EIDEProject.ts +++ b/src/EIDEProject.ts @@ -1685,10 +1685,14 @@ export abstract class AbstractProject implements CustomConfigurationProvider, Pr //-- + /** + * 检查文件是否已被排除 + * @param path 要执行检查的源文件的路径,可以为虚拟路径,比如 '\/abc.c' + */ isExcluded(path: string): boolean { - const excList = this.GetConfiguration().config.excludeList.map((excpath) => this.resolveEnvVar(excpath)); - const rePath = this.toRelativePath(path); - return excList.findIndex(excluded => rePath === excluded || rePath.startsWith(`${excluded}/`)) !== -1; + const excList = this.GetConfiguration().config.excludeList.map(p => this.resolveEnvVar(p)); + const rePath = VirtualSource.isVirtualPath(path) ? path : this.toRelativePath(path); + return excList.findIndex(p => rePath === p || rePath.startsWith(`${p}/`)) !== -1; } protected addExclude(path: string): boolean { diff --git a/src/StringTable.ts b/src/StringTable.ts index 485dd1df..0dea6507 100644 --- a/src/StringTable.ts +++ b/src/StringTable.ts @@ -459,6 +459,16 @@ export const view_str$env_desc$py3_cmd = [ //---------------Other--------------- +export const view_str$prompt$requireOtherExtension = [ + `请先安装扩展 "{}"`, + `Please install extension "{}" first.` +][langIndex]; + +export const view_str$prompt$debugCfgNotSupported = [ + `仅支持如下类型的动态调试配置 '{0}'. 当前类型 '{1}' 不受支持!`, + `Only the following type of dynamic debugging configurations '{0}' are supported. The current type '{1}' is not supported !` +][langIndex]; + export const view_str$prompt$install_dotnet_and_restart_vscode = [ `安装完.NET后,你需要完全重启VSCode以刷新系统环境变量`, `After installed .NET. You need to close all VSCode instance and restart it to refresh System Environment Variables.` diff --git a/src/extension.ts b/src/extension.ts index 614a825f..e9a24ef8 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -43,7 +43,8 @@ import { txt_install_now, txt_yes, view_str$prompt$feedback, rating_text, later_text, sponsor_author_text, view_str$prompt$install_dotnet_and_restart_vscode, view_str$prompt$install_dotnet_failed, - view_str$prompt$not_found_compiler + view_str$prompt$not_found_compiler, view_str$prompt$debugCfgNotSupported, not_support_no_arm_project, + view_str$prompt$requireOtherExtension } from './StringTable'; import { LogDumper } from './LogDumper'; import { StatusBarManager } from './StatusBarManager'; @@ -294,11 +295,17 @@ export async function activate(context: vscode.ExtensionContext) { subscriptions.push(vscode.commands.registerCommand('_cl.eide.statusbar.build', () => projectExplorer.BuildSolution(undefined, { not_rebuild: true }))); subscriptions.push(vscode.commands.registerCommand('_cl.eide.statusbar.flash', () => projectExplorer.UploadToDevice(undefined))); + // debug config providers + vscode.debug.registerDebugConfigurationProvider('cortex-debug', new ExternalDebugConfigProvider('cortex-debug'), + vscode.DebugConfigurationProviderTriggerKind.Dynamic); + vscode.debug.registerDebugConfigurationProvider('probe-rs-debug', new ExternalDebugConfigProvider('probe-rs-debug'), + vscode.DebugConfigurationProviderTriggerKind.Dynamic); + // vscode.debug.registerDebugConfigurationProvider('stm8-debug', new ExternalDebugConfigProvider('stm8-debug'), + // vscode.DebugConfigurationProviderTriggerKind.Dynamic); + // others vscode.workspace.registerTextDocumentContentProvider(VirtualDocument.scheme, VirtualDocument.instance()); vscode.workspace.registerTaskProvider(EideTaskProvider.TASK_TYPE_BASH, new EideTaskProvider()); - vscode.debug.registerDebugConfigurationProvider('eide.cortex-debug', new CortexDebugConfigProvider(), - vscode.DebugConfigurationProviderTriggerKind.Dynamic); // auto save project projectExplorer.enableAutoSave(true); @@ -1589,7 +1596,10 @@ class EideTerminalProvider implements vscode.TerminalProfileProvider { import { FileWatcher } from '../lib/node-utility/FileWatcher'; import { ToolchainManager, ToolchainName } from './ToolchainManager'; -import { JLinkOptions, JLinkProtocolType, OpenOCDFlashOptions, PyOCDFlashOptions, STLinkOptions } from './HexUploader'; +import { + JLinkOptions, JLinkProtocolType, OpenOCDFlashOptions, + PyOCDFlashOptions, STLinkOptions, ProbeRSFlashOptions, STVPFlasherOptions +} from './HexUploader'; import { AbstractProject } from './EIDEProject'; type MapViewParserType = 'memap' | 'builtin'; @@ -1890,7 +1900,13 @@ class MapViewEditorProvider implements vscode.CustomTextEditorProvider { //- Debug Config Provider //------------------------------------------------------------ -class CortexDebugConfigProvider implements vscode.DebugConfigurationProvider { +class ExternalDebugConfigProvider implements vscode.DebugConfigurationProvider { + + private debuggerType: string | undefined; + + constructor(debugType?: string) { + this.debuggerType = debugType; + } provideDebugConfigurations(folder: vscode.WorkspaceFolder | undefined, token?: vscode.CancellationToken): vscode.ProviderResult { @@ -1941,11 +1957,47 @@ class CortexDebugConfigProvider implements vscode.DebugConfigurationProvider { return result; } break; + // case 'IAR_STM8': + // case 'COSMIC_STM8': + // case 'SDCC': + // break; default: return result; } - const newDebugCfg = (prj: AbstractProject) => { + const toFmtRelativePath = (abspath: string) => { + let path = prj.ToRelativePath(abspath); + if (path) { + path = File.ToLocalPath(path); + return path.startsWith('.') ? path : `.${File.sep}${path}`; + } + return File.ToLocalPath(abspath); + }; + + const getSvdFile = (prj: AbstractProject) => { + const device = prj.GetPackManager().getCurrentDevInfo(); + if (device && device.svdPath) { + const svdpath = toFmtRelativePath(device.svdPath); + GlobalEvent.log_info(`[debug config] Use svd file: ${svdpath}`); + return svdpath; + } else { + const searchDirs = [ + prj.getRootDir(), + prj.getEideDir(), + File.from(prj.getRootDir().path, 'tools') + ]; + for (const d of searchDirs) { + const r = d.GetList([/\.svd$/i], File.EXCLUDE_ALL_FILTER); + if (r.length) { + const svdpath = toFmtRelativePath(r[0].path); + GlobalEvent.log_info(`[debug config] Use svd file: ${svdpath}`); + return svdpath; + } + } + } + }; + + const newCortexDebugCfg = (prj: AbstractProject) => { const dbgCfg: vscode.DebugConfiguration = { type: 'cortex-debug', @@ -1970,32 +2022,14 @@ class CortexDebugConfigProvider implements vscode.DebugConfigurationProvider { } dbgCfg['cwd'] = prj.getRootDir().path; - dbgCfg['executable'] = prj.getExecutablePathWithoutSuffix() + '.elf'; + dbgCfg['executable'] = toFmtRelativePath(prj.getExecutablePathWithoutSuffix() + '.elf'); dbgCfg['runToEntryPoint'] = 'main'; dbgCfg['liveWatch'] = { 'enabled': true, 'samplesPerSecond': 4 }; - const device = prj.GetPackManager().getCurrentDevInfo(); - if (device && device.svdPath) { - dbgCfg['svdFile'] = prj.ToRelativePath(device.svdPath) || device.svdPath; - GlobalEvent.log_info(`[debug config] Use svd file: ${dbgCfg['svdFile']}`); - } else { - const searchDirs = [ - prj.getRootDir(), - prj.getEideDir(), - File.from(prj.getRootDir().path, 'tools') - ]; - for (const d of searchDirs) { - const r = d.GetList([/\.svd$/i], File.EXCLUDE_ALL_FILTER); - if (r.length) { - dbgCfg['svdFile'] = prj.ToRelativePath(r[0].path) || r[0].path; - GlobalEvent.log_info(`[debug config] Use svd file: ${dbgCfg['svdFile']}`); - break; - } - } - } + dbgCfg['svdFile'] = getSvdFile(prj); return dbgCfg; }; @@ -2013,7 +2047,7 @@ class CortexDebugConfigProvider implements vscode.DebugConfigurationProvider { const flashertype = prj.getUploaderType(); if (flashertype == 'JLink') { - const dbgCfg = newDebugCfg(prj); + const dbgCfg = newCortexDebugCfg(prj); const flasherCfg = (flasherOpts); dbgCfg['name'] = 'Debug: JLINK'; dbgCfg['servertype'] = 'jlink'; @@ -2035,7 +2069,7 @@ class CortexDebugConfigProvider implements vscode.DebugConfigurationProvider { } else if (flashertype == 'OpenOCD') { - const dbgCfg = newDebugCfg(prj); + const dbgCfg = newCortexDebugCfg(prj); const flasherCfg = (flasherOpts); dbgCfg['name'] = 'Debug: OpenOCD'; dbgCfg['servertype'] = 'openocd'; @@ -2050,7 +2084,7 @@ class CortexDebugConfigProvider implements vscode.DebugConfigurationProvider { } else if (flashertype == 'pyOCD') { - const dbgCfg = newDebugCfg(prj); + const dbgCfg = newCortexDebugCfg(prj); const flasherCfg = (flasherOpts); dbgCfg['name'] = 'Debug: pyOCD'; dbgCfg['servertype'] = 'pyocd'; @@ -2104,7 +2138,7 @@ class CortexDebugConfigProvider implements vscode.DebugConfigurationProvider { if (p) cubeProgramerPath = NodePath.dirname(p); } - const dbgCfg = newDebugCfg(prj); + const dbgCfg = newCortexDebugCfg(prj); dbgCfg['name'] = 'Debug: STLink'; dbgCfg['servertype'] = 'stlink'; dbgCfg['interface'] = flasherCfg.proType == 'SWD' ? 'swd' : 'jtag'; @@ -2113,13 +2147,79 @@ class CortexDebugConfigProvider implements vscode.DebugConfigurationProvider { result.push(dbgCfg); } + else if (flashertype == 'probe-rs') { + const flasherCfg = (flasherOpts); + const dbgCfg: any = { + "type": "probe-rs-debug", + "request": "launch", + "name": "Debug: probe-rs", + "cwd": prj.getRootDir().path, + "connectUnderReset": false, + "chip": flasherCfg.target, + "wireProtocol": flasherCfg.protocol.toLowerCase() == 'swd' ? 'Swd' : 'Jtag', + "allowEraseAll": flasherCfg.allowEraseAll, + "flashingConfig": { + "flashingEnabled": true, + "haltAfterReset": true + }, + "coreConfigs": [ + { + "coreIndex": 0, + "svdFile": getSvdFile(prj), + "programBinary": toFmtRelativePath( + prj.getExecutablePathWithoutSuffix() + '.elf') + } + ] + }; + if (flasherCfg.speed) + dbgCfg['speed'] = flasherCfg.speed; + // parse '--probe VID:PID' or '--probe VID:PID:Serial' + if (flasherCfg.otherOptions) { + let m = /--probe (\w+\:\w+(?:\:\w+)?)/.exec(flasherCfg.otherOptions); + if (m && m.length > 1) { + dbgCfg['probe'] = m[1]; + } + } + result.push(dbgCfg); + } + + // else if (flashertype == 'STVP') { + // const flasherCfg = (flasherOpts); + // const dbgCfg: any = { + // "type": "stm8-debug", + // "request": "launch", + // "name": "Debug: STM8", + // "serverType": "st7", + // "executable": toFmtRelativePath(prj.getExecutablePath()), + // "cpu": flasherCfg.deviceName + // }; + // const searchDirs = [ + // prj.getRootDir(), + // prj.getEideDir(), + // File.from(prj.getRootDir().path, 'tools') + // ]; + // for (const d of searchDirs) { + // const r = d.GetList([/\.svd\.json$/i], File.EXCLUDE_ALL_FILTER); + // if (r.length) { + // const svdpath = toFmtRelativePath(r[0].path); + // GlobalEvent.log_info(`[debug config] Use svd file: ${svdpath}`); + // dbgCfg['svdFile'] = svdpath; + // } + // } + // } + else { - GlobalEvent.emit('msg', newMessage('Warning', - `Only support 'jlink', 'stlink', 'openocd', 'pyocd'. Not support this flasher: '${flashertype}' !`)); + const supported = ['jlink', 'stlink', 'openocd', 'pyocd', 'probe-rs']; + const msg = view_str$prompt$debugCfgNotSupported + .replace('{0}', supported.join(',')) + .replace('{1}', flashertype); + GlobalEvent.show_msgbox('Warning', msg); } - // GlobalEvent.log_info(`provide Cortex-Debug DebugConfig`); - // GlobalEvent.log_info(yaml.stringify(result)); + // filter by debugType + if (this.debuggerType) + return result.filter(cfg => cfg.type == this.debuggerType); + return result; } } @@ -2138,7 +2238,7 @@ async function startDebugging() { index: 0 }; - const cfgs = await (new CortexDebugConfigProvider()) + const cfgs = await (new ExternalDebugConfigProvider()) .provideDebugConfigurations(vscWorkspaceFolder); if (cfgs && cfgs.length > 0) { let cfg = cfgs[0];