Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 5dcc498

Browse files
author
Akos Kitta
committed
fix: show board info based on the selected port
include serial number of board if available Closes #1489 Closes #1435 Signed-off-by: Akos Kitta <a.kitta@arduino.cc>
1 parent 083a706 commit 5dcc498

File tree

5 files changed

+242
-49
lines changed

5 files changed

+242
-49
lines changed

‎arduino-ide-extension/src/browser/boards/boards-config.tsx‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { DisposableCollection } from '@theia/core/lib/common/disposable';
66
import {
77
Board,
88
Port,
9+
BoardConfig as ProtocolBoardConfig,
910
BoardWithPackage,
1011
} from '../../common/protocol/boards-service';
1112
import { NotificationCenter } from '../notification-center';
@@ -18,10 +19,7 @@ import { nls } from '@theia/core/lib/common';
1819
import { FrontendApplicationState } from '@theia/core/lib/common/frontend-application-state';
1920

2021
export namespace BoardsConfig {
21-
export interface Config {
22-
selectedBoard?: Board;
23-
selectedPort?: Port;
24-
}
22+
export type Config = ProtocolBoardConfig;
2523

2624
export interface Props {
2725
readonly boardsServiceProvider: BoardsServiceProvider;

‎arduino-ide-extension/src/browser/contributions/board-selection.ts‎

Lines changed: 20 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
InstalledBoardWithPackage,
2121
AvailablePorts,
2222
Port,
23+
getBoardInfo,
2324
} from '../../common/protocol';
2425
import { SketchContribution, Command, CommandRegistry } from './contribution';
2526
import { nls } from '@theia/core/lib/common';
@@ -49,52 +50,28 @@ export class BoardSelection extends SketchContribution {
4950
override registerCommands(registry: CommandRegistry): void {
5051
registry.registerCommand(BoardSelection.Commands.GET_BOARD_INFO, {
5152
execute: async () => {
52-
const { selectedBoard, selectedPort } =
53-
this.boardsServiceProvider.boardsConfig;
54-
if (!selectedBoard) {
55-
this.messageService.info(
56-
nls.localize(
57-
'arduino/board/selectBoardForInfo',
58-
'Please select a board to obtain board info.'
59-
)
60-
);
61-
return;
62-
}
63-
if (!selectedBoard.fqbn) {
64-
this.messageService.info(
65-
nls.localize(
66-
'arduino/board/platformMissing',
67-
"The platform for the selected '{0}' board is not installed.",
68-
selectedBoard.name
69-
)
70-
);
71-
return;
72-
}
73-
if (!selectedPort) {
74-
this.messageService.info(
75-
nls.localize(
76-
'arduino/board/selectPortForInfo',
77-
'Please select a port to obtain board info.'
78-
)
79-
);
53+
const boardInfo = await getBoardInfo(
54+
this.boardsServiceProvider.boardsConfig.selectedPort,
55+
this.boardsService.getState()
56+
);
57+
if (typeof boardInfo === 'string') {
58+
this.messageService.info(boardInfo);
8059
return;
8160
}
82-
const boardDetails = await this.boardsService.getBoardDetails({
83-
fqbn: selectedBoard.fqbn,
84-
});
85-
if (boardDetails) {
86-
const { VID, PID } = boardDetails;
87-
const detail = `BN: ${selectedBoard.name}
61+
const { BN, VID, PID, SN } = boardInfo;
62+
const detail = `
63+
BN: ${BN}
8864
VID: ${VID}
89-
PID: ${PID}`;
90-
await remote.dialog.showMessageBox(remote.getCurrentWindow(), {
91-
message: nls.localize('arduino/board/boardInfo', 'Board Info'),
92-
title: nls.localize('arduino/board/boardInfo', 'Board Info'),
93-
type: 'info',
94-
detail,
95-
buttons: [nls.localize('vscode/issueMainService/ok', 'OK')],
96-
});
97-
}
65+
PID: ${PID}
66+
SN: ${SN}
67+
`.trim();
68+
await remote.dialog.showMessageBox(remote.getCurrentWindow(), {
69+
message: nls.localize('arduino/board/boardInfo', 'Board Info'),
70+
title: nls.localize('arduino/board/boardInfo', 'Board Info'),
71+
type: 'info',
72+
detail,
73+
buttons: [nls.localize('vscode/issueMainService/ok', 'OK')],
74+
});
9875
},
9976
});
10077
}

‎arduino-ide-extension/src/common/protocol/boards-service.ts‎

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
Updatable,
1212
} from '../nls';
1313
import URI from '@theia/core/lib/common/uri';
14+
import { MaybePromise } from '@theia/core/lib/common/types';
1415

1516
export type AvailablePorts = Record<string, [Port, Array<Board>]>;
1617
export namespace AvailablePorts {
@@ -657,3 +658,107 @@ export function sanitizeFqbn(fqbn: string | undefined): string | undefined {
657658
const [vendor, arch, id] = fqbn.split(':');
658659
return `${vendor}:${arch}:${id}`;
659660
}
661+
662+
export interface BoardConfig {
663+
selectedBoard?: Board;
664+
selectedPort?: Port;
665+
}
666+
667+
export interface BoardInfo {
668+
/**
669+
* Board name. Could be `'Unknown board`'.
670+
*/
671+
BN: string;
672+
/**
673+
* Vendor ID.
674+
*/
675+
VID: string;
676+
/**
677+
* Product ID.
678+
*/
679+
PID: string;
680+
/**
681+
* Serial number.
682+
*/
683+
SN: string;
684+
}
685+
686+
export const selectPortForInfo = nls.localize(
687+
'arduino/board/selectPortForInfo',
688+
'Please select a port to obtain board info.'
689+
);
690+
export const nonSerialPort = nls.localize(
691+
'arduino/board/nonSerialPort',
692+
"Non-serial port, can't obtain info."
693+
);
694+
export const noNativeSerialPort = nls.localize(
695+
'arduino/board/noNativeSerialPort',
696+
"Native serial port, can't obtain info."
697+
);
698+
export const unknownBoard = nls.localize(
699+
'arduino/board/unknownBoard',
700+
'Unknown board'
701+
);
702+
703+
/**
704+
* The returned promise resolves to a `BoardInfo` if available to show in the UI or an info message explaining why showing the board info is not possible.
705+
*/
706+
export async function getBoardInfo(
707+
selectedPort: Port | undefined,
708+
availablePorts: MaybePromise<AvailablePorts>
709+
): Promise<BoardInfo | string> {
710+
if (!selectedPort) {
711+
return selectPortForInfo;
712+
}
713+
// IDE2 must show the board info based on the selected port.
714+
// https://github.com/arduino/arduino-ide/issues/1489
715+
// IDE 1.x supports only serial port protocol
716+
if (selectedPort.protocol !== 'serial') {
717+
return nonSerialPort;
718+
}
719+
const selectedPortKey = Port.keyOf(selectedPort);
720+
const state = await availablePorts;
721+
const boardListOnSelectedPort = Object.entries(state).filter(
722+
([portKey, [port]]) =>
723+
portKey === selectedPortKey && isNonNativeSerial(port)
724+
);
725+
726+
if (!boardListOnSelectedPort.length) {
727+
return noNativeSerialPort;
728+
}
729+
730+
const [, [port, boards]] = boardListOnSelectedPort[0];
731+
if (boardListOnSelectedPort.length > 1 || boards.length > 1) {
732+
console.warn(
733+
`Detected more than one available boards on the selected port : ${JSON.stringify(
734+
selectedPort
735+
)}. Detected boards were: ${JSON.stringify(
736+
boardListOnSelectedPort
737+
)}. Using the first one: ${JSON.stringify([port, boards])}`
738+
);
739+
}
740+
741+
const board = boards[0];
742+
const BN = board?.name ?? unknownBoard;
743+
const VID = readProperty('vid', port);
744+
const PID = readProperty('pid', port);
745+
const SN = readProperty('serialNumber', port);
746+
return { VID, PID, SN, BN };
747+
}
748+
749+
// serial protocol with one or many detected boards or available VID+PID properties from the port
750+
function isNonNativeSerial(port: Port): boolean {
751+
return !!(
752+
port.protocol === 'serial' &&
753+
port.properties?.['vid'] &&
754+
port.properties?.['pid']
755+
);
756+
}
757+
758+
function readProperty(property: string, port: Port): string {
759+
return falsyToNullString(port.properties?.[property]);
760+
}
761+
762+
function falsyToNullString(s: string | undefined): string {
763+
return !!s ? s : '(null)';
764+
}

‎arduino-ide-extension/src/test/common/boards-service.test.ts‎

Lines changed: 111 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
1+
import { Deferred } from '@theia/core/lib/common/promise-util';
2+
import { Mutable } from '@theia/core/lib/common/types';
13
import { expect } from 'chai';
2-
import { AttachedBoardsChangeEvent } from '../../common/protocol';
4+
import {
5+
AttachedBoardsChangeEvent,
6+
BoardInfo,
7+
getBoardInfo,
8+
noNativeSerialPort,
9+
nonSerialPort,
10+
Port,
11+
selectPortForInfo,
12+
unknownBoard,
13+
} from '../../common/protocol';
14+
import { firstToUpperCase } from '../../common/utils';
315

416
describe('boards-service', () => {
517
describe('AttachedBoardsChangeEvent', () => {
@@ -80,4 +92,102 @@ describe('boards-service', () => {
8092
);
8193
});
8294
});
95+
96+
describe('getBoardInfo', () => {
97+
const vid = '0x0';
98+
const pid = '0x1';
99+
const serialNumber = '1730323';
100+
const name = 'The Board';
101+
const fqbn = 'alma:korte:szolo';
102+
const selectedBoard = { name, fqbn };
103+
const selectedPort = (
104+
properties: Record<string, string> = {},
105+
protocol = 'serial'
106+
): Mutable<Port> => ({
107+
address: 'address',
108+
addressLabel: 'addressLabel',
109+
protocol,
110+
protocolLabel: firstToUpperCase(protocol),
111+
properties,
112+
});
113+
114+
it('should handle when no port is selected', async () => {
115+
const info = await getBoardInfo(undefined, never());
116+
expect(info).to.be.equal(selectPortForInfo);
117+
});
118+
119+
it("should handle when port protocol is not 'serial'", async () => {
120+
await Promise.allSettled(
121+
['network', 'teensy'].map(async (protocol) => {
122+
const selectedPort: Port = {
123+
address: 'address',
124+
addressLabel: 'addressLabel',
125+
protocolLabel: firstToUpperCase(protocol),
126+
protocol,
127+
};
128+
const info = await getBoardInfo(selectedPort, never());
129+
expect(info).to.be.equal(nonSerialPort);
130+
})
131+
);
132+
});
133+
134+
it("should not detect a port as non-native serial, if protocol is 'serial' but VID or PID is missing", async () => {
135+
const insufficientProperties: Record<string, string>[] = [
136+
{},
137+
{ vid },
138+
{ pid },
139+
{ VID: vid, pid: pid }, // case sensitive
140+
];
141+
for (const properties of insufficientProperties) {
142+
const port = selectedPort(properties);
143+
const info = await getBoardInfo(port, {
144+
[Port.keyOf(port)]: [port, []],
145+
});
146+
expect(info).to.be.equal(noNativeSerialPort);
147+
}
148+
});
149+
150+
it("should detect a port as non-native serial, if protocol is 'serial' and VID/PID are available", async () => {
151+
const port = selectedPort({ vid, pid });
152+
const info = await getBoardInfo(port, {
153+
[Port.keyOf(port)]: [port, []],
154+
});
155+
expect(typeof info).to.be.equal('object');
156+
const boardInfo = <BoardInfo>info;
157+
expect(boardInfo.VID).to.be.equal(vid);
158+
expect(boardInfo.PID).to.be.equal(pid);
159+
expect(boardInfo.SN).to.be.equal('(null)');
160+
expect(boardInfo.BN).to.be.equal(unknownBoard);
161+
});
162+
163+
it("should show the 'SN' even if no matching board was detected for the port", async () => {
164+
const port = selectedPort({ vid, pid, serialNumber });
165+
const info = await getBoardInfo(port, {
166+
[Port.keyOf(port)]: [port, []],
167+
});
168+
expect(typeof info).to.be.equal('object');
169+
const boardInfo = <BoardInfo>info;
170+
expect(boardInfo.VID).to.be.equal(vid);
171+
expect(boardInfo.PID).to.be.equal(pid);
172+
expect(boardInfo.SN).to.be.equal(serialNumber);
173+
expect(boardInfo.BN).to.be.equal(unknownBoard);
174+
});
175+
176+
it("should use the name of the matching board as 'BN' if available", async () => {
177+
const port = selectedPort({ vid, pid });
178+
const info = await getBoardInfo(port, {
179+
[Port.keyOf(port)]: [port, [selectedBoard]],
180+
});
181+
expect(typeof info).to.be.equal('object');
182+
const boardInfo = <BoardInfo>info;
183+
expect(boardInfo.VID).to.be.equal(vid);
184+
expect(boardInfo.PID).to.be.equal(pid);
185+
expect(boardInfo.SN).to.be.equal('(null)');
186+
expect(boardInfo.BN).to.be.equal(selectedBoard.name);
187+
});
188+
});
83189
});
190+
191+
function never<T>(): Promise<T> {
192+
return new Deferred<T>().promise;
193+
}

‎i18n/en.json‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@
1818
"installNow": "The \"{0} {1}\" core has to be installed for the currently selected \"{2}\" board. Do you want to install it now?",
1919
"noBoardsFound": "No boards found for \"{0}\"",
2020
"noFQBN": "The FQBN is not available for the selected board \"{0}\". Do you have the corresponding core installed?",
21+
"noNativeSerialPort": "Native serial port, can't obtain info.",
2122
"noPortsDiscovered": "No ports discovered",
2223
"noPortsSelected": "No ports selected for board: '{0}'.",
24+
"nonSerialPort": "Non-serial port, can't obtain info.",
2325
"noneSelected": "No boards selected.",
2426
"openBoardsConfig": "Select other board and port...",
2527
"platformMissing": "The platform for the selected '{0}' board is not installed.",
@@ -37,7 +39,8 @@
3739
"showAllPorts": "Show all ports",
3840
"succesfullyInstalledPlatform": "Successfully installed platform {0}:{1}",
3941
"succesfullyUninstalledPlatform": "Successfully uninstalled platform {0}:{1}",
40-
"typeOfPorts": "{0} ports"
42+
"typeOfPorts": "{0} ports",
43+
"unknownBoard": "Unknown board"
4144
},
4245
"boardsManager": "Boards Manager",
4346
"boardsType": {

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /