Skip to content

Allow printing defmt output to the RTT console #880

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1134,10 +1134,11 @@
"type": {
"enum": [
"console",
"binary"
"binary",
"defmt"
],
"default": "console",
"description": "'console' with text input/output, 'binary' is for converting byte stream to other data types",
"description": "'console' with text input/output, 'binary' is for converting byte stream to other data types, 'defmt' uses defmt-print",
"type": "string"
},
"prompt": {
Expand Down
3 changes: 2 additions & 1 deletion src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -456,13 +456,14 @@ export class RTTServerHelper {
});
}

public emitConfigures(cfg: RTTConfiguration, obj: EventEmitter): boolean {
public emitConfigures(cfg: RTTConfiguration, executable: string, obj: EventEmitter): boolean {
let ret = false;
if (cfg.enabled) {
for (const dec of cfg.decoders) {
if (dec.tcpPort || dec.tcpPorts) {
obj.emit('event', new RTTConfigureEvent({
type: 'socket',
executable: executable,
decoder: dec
}));
ret = true;
Expand Down
7 changes: 5 additions & 2 deletions src/frontend/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { MemoryContentProvider } from './memory_content_provider';
import Reporting from '../reporting';

import { CortexDebugConfigurationProvider } from './configprovider';
import { JLinkSocketRTTSource, SocketRTTSource, SocketSWOSource, PeMicroSocketSource } from './swo/sources/socket';
import { JLinkSocketRTTSource, SocketRTTSource, SocketSWOSource, PeMicroSocketSource, DefmtSocketRTTSource } from './swo/sources/socket';
import { FifoSWOSource } from './swo/sources/fifo';
import { FileSWOSource } from './swo/sources/file';
import { SerialSWOSource } from './swo/sources/serial';
Expand Down Expand Up @@ -770,7 +770,7 @@ export class CortexDebugExtension {
private receivedRTTConfigureEvent(e: vscode.DebugSessionCustomEvent) {
if (e.body.type === 'socket') {
const decoder: RTTCommonDecoderOpts = e.body.decoder;
if ((decoder.type === 'console') || (decoder.type === 'binary')) {
if ((decoder.type === 'console') || (decoder.type === 'binary') || (decoder.type === 'defmt')) {
Reporting.sendEvent('RTT', 'Source', 'Socket: Console');
this.rttCreateTerninal(e, decoder as RTTConsoleDecoderOpts);
} else {
Expand All @@ -793,6 +793,7 @@ export class CortexDebugExtension {
// state.
private createRTTSource(e: vscode.DebugSessionCustomEvent, tcpPort: string, channel: number): Promise<SocketRTTSource> {
const mySession = CDebugSession.GetSession(e.session);
const wsPath = e.session.workspaceFolder.uri.fsPath;
return new Promise((resolve, reject) => {
let src = mySession.rttPortMap[channel];
if (src) {
Expand All @@ -801,6 +802,8 @@ export class CortexDebugExtension {
}
if (mySession.config.servertype === 'jlink') {
src = new JLinkSocketRTTSource(tcpPort, channel);
} else if (e.body.decoder.type === 'defmt') {
src = new DefmtSocketRTTSource(tcpPort, channel, e.body.executable, wsPath);
} else {
src = new SocketRTTSource(tcpPort, channel);
}
Expand Down
35 changes: 35 additions & 0 deletions src/frontend/swo/sources/socket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { parseHostPort } from '../../../common';
import * as vscode from 'vscode';
import { TextDecoder } from 'util';
import { setFlagsFromString } from 'v8';
import * as ChildProcess from 'child_process';
import * as Path from 'path';

const TimerInterval = 250;
export class SocketSWOSource extends EventEmitter implements SWORTTSource {
Expand Down Expand Up @@ -135,6 +137,39 @@ export class SocketRTTSource extends SocketSWOSource {
}
}

export class DefmtSocketRTTSource extends SocketRTTSource {
private process: ChildProcess.ChildProcess;
private executable: string;
private cwd: string;

protected processData(buffer: Buffer): void {
this.process.stdin.write(buffer);
}

public start(timeout = (1000 * 60 * 5)): Promise<void> {
this.process = ChildProcess.spawn(
'defmt-print',['-e', this.executable], { cwd: this.cwd }
);

this.process.on('error', (e) => {
(e as any).message = `Failed to launch defmt-print (is it installed?)`;
this.emit('error', e);
this.dispose();
});

this.process.stdout.on('data', (buffer) => this.emit('data', buffer));

return super.start(timeout);
}

constructor(tcpPort: string, public readonly channel: number, executable: string, wsPath: string) {
super(tcpPort, channel);

this.cwd = wsPath;
this.executable = Path.relative(wsPath, executable);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@haneefdm I checked the source of defmt and probe-rs. This is because by default, defmt's message is compressed. The detailed info is stored in .elf file, that's why the executable is needed: without .elf, the message cannot be parsed.

See https://github.com/knurling-rs/defmt/blob/main/decoder/src/lib.rs#L157 . The Table is what's stored in .elf file

}
}

export class JLinkSocketRTTSource extends SocketRTTSource {
constructor(tcpPort: string, public readonly channel: number) {
super(tcpPort, channel);
Expand Down
2 changes: 1 addition & 1 deletion src/jlink.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,6 @@ export class JLinkServerController extends EventEmitter implements GDBServerCont
}
public debuggerLaunchStarted(): void {}
public debuggerLaunchCompleted(): void {
this.rttHelper.emitConfigures(this.args.rttConfig, this);
this.rttHelper.emitConfigures(this.args.rttConfig, this.args.executable, this);
}
}
2 changes: 1 addition & 1 deletion src/openocd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ export class OpenOCDServerController extends EventEmitter implements GDBServerCo
this.session = obj;
}
public debuggerLaunchCompleted(): void {
const hasRtt = this.rttHelper.emitConfigures(this.args.rttConfig, this);
const hasRtt = this.rttHelper.emitConfigures(this.args.rttConfig, this.args.executable, this);
if (this.args.ctiOpenOCDConfig?.enabled) {
this.ctiStopResume(CTIAction.init);
}
Expand Down