Skip to content
Merged
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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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**:
Expand Down
8 changes: 1 addition & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -114,12 +114,6 @@
"yaml": "^1.10.2"
},
"contributes": {
"debuggers": [
{
"type": "eide.cortex-debug",
"label": "EIDE (Cortex-Debug)"
}
],
"terminal": {
"profiles": [
{
Expand Down
10 changes: 7 additions & 3 deletions src/EIDEProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1685,10 +1685,14 @@ export abstract class AbstractProject implements CustomConfigurationProvider, Pr

//--

/**
* 检查文件是否已被排除
* @param path 要执行检查的源文件的路径,可以为虚拟路径,比如 '\<virual_root\>/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 {
Expand Down
10 changes: 10 additions & 0 deletions src/StringTable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.`
Expand Down
170 changes: 135 additions & 35 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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';
Expand Down Expand Up @@ -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<vscode.DebugConfiguration[]> {
Expand Down Expand Up @@ -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',
Expand All @@ -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;
};
Expand All @@ -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 = (<JLinkOptions>flasherOpts);
dbgCfg['name'] = 'Debug: JLINK';
dbgCfg['servertype'] = 'jlink';
Expand All @@ -2035,7 +2069,7 @@ class CortexDebugConfigProvider implements vscode.DebugConfigurationProvider {
}

else if (flashertype == 'OpenOCD') {
const dbgCfg = newDebugCfg(prj);
const dbgCfg = newCortexDebugCfg(prj);
const flasherCfg = (<OpenOCDFlashOptions>flasherOpts);
dbgCfg['name'] = 'Debug: OpenOCD';
dbgCfg['servertype'] = 'openocd';
Expand All @@ -2050,7 +2084,7 @@ class CortexDebugConfigProvider implements vscode.DebugConfigurationProvider {
}

else if (flashertype == 'pyOCD') {
const dbgCfg = newDebugCfg(prj);
const dbgCfg = newCortexDebugCfg(prj);
const flasherCfg = (<PyOCDFlashOptions>flasherOpts);
dbgCfg['name'] = 'Debug: pyOCD';
dbgCfg['servertype'] = 'pyocd';
Expand Down Expand Up @@ -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';
Expand All @@ -2113,13 +2147,79 @@ class CortexDebugConfigProvider implements vscode.DebugConfigurationProvider {
result.push(dbgCfg);
}

else if (flashertype == 'probe-rs') {
const flasherCfg = (<ProbeRSFlashOptions>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 = (<STVPFlasherOptions>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;
}
}
Expand All @@ -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];
Expand Down