Skip to content

Commit ef91a9f

Browse files
Alberto Iannacconefstasi
Alberto Iannaccone
authored andcommitted
firmware uploader service
1 parent 2e97723 commit ef91a9f

File tree

6 files changed

+138
-4
lines changed

6 files changed

+138
-4
lines changed

arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -365,16 +365,14 @@ export class ArduinoFrontendContribution
365365
);
366366
}
367367
}
368-
const { clangdUri, cliUri, lsUri, fwuploaderUri } =
369-
await this.executableService.list();
368+
const { clangdUri, cliUri, lsUri } = await this.executableService.list();
370369
const [clangdPath, cliPath, lsPath, cliConfigPath] = await Promise.all([
371370
this.fileService.fsPath(new URI(clangdUri)),
372371
this.fileService.fsPath(new URI(cliUri)),
373372
this.fileService.fsPath(new URI(lsUri)),
374373
this.fileService.fsPath(
375374
new URI(await this.configService.getCliConfigFileUri())
376375
),
377-
this.fileService.fsPath(new URI(fwuploaderUri)),
378376
]);
379377
this.languageServerFqbn = await Promise.race([
380378
new Promise<undefined>((_, reject) =>

arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,10 @@ import {
249249
UploadCertificateDialogWidget,
250250
} from './dialogs/certificate-uploader/upload-certificate-dialog';
251251
import { UploadCertificate } from './contributions/upload-certificate';
252+
import {
253+
ArduinoFirmwareUploader,
254+
ArduinoFirmwareUploaderPath,
255+
} from '../common/protocol/arduino-firmware-uploader';
252256

253257
const ElementQueries = require('css-element-queries/src/ElementQueries');
254258

@@ -534,6 +538,15 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
534538
)
535539
.inSingletonScope();
536540

541+
bind(ArduinoFirmwareUploader)
542+
.toDynamicValue((context) =>
543+
WebSocketConnectionProvider.createProxy(
544+
context.container,
545+
ArduinoFirmwareUploaderPath
546+
)
547+
)
548+
.inSingletonScope();
549+
537550
// File-system extension
538551
bind(FileSystemExt)
539552
.toDynamicValue((context) =>

arduino-ide-extension/src/browser/dialogs/certificate-uploader/upload-certificate-dialog.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
BoardsServiceProvider,
1010
} from '../../boards/boards-service-provider';
1111
import { ArduinoSelect } from '../../widgets/arduino-select';
12+
import { ArduinoFirmwareUploader } from '../../../common/protocol/arduino-firmware-uploader';
1213

1314
export const CertificateUploaderComponent = ({
1415
boardsServiceClient,
@@ -22,7 +23,6 @@ export const CertificateUploaderComponent = ({
2223
const [installFeedback, setInstallFeedback] = React.useState<
2324
'ok' | 'fail' | null
2425
>(null);
25-
2626
const [selectedBoard, setSelectedBoard] = React.useState<{
2727
label: string;
2828
value: string;
@@ -266,6 +266,9 @@ export class UploadCertificateDialogWidget extends ReactWidget {
266266
@inject(BoardsServiceProvider)
267267
protected readonly boardsServiceClient: BoardsServiceProvider;
268268

269+
@inject(ArduinoFirmwareUploader)
270+
protected readonly firmware: ArduinoFirmwareUploader;
271+
269272
constructor() {
270273
super();
271274
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
export const ArduinoFirmwareUploaderPath =
2+
'/services/arduino-firmware-uploader';
3+
export const ArduinoFirmwareUploader = Symbol('ArduinoFirmwareUploader');
4+
export type FirmwareInfo = {
5+
board_name: string;
6+
board_fqbn: string;
7+
module: string;
8+
firmware_version: string;
9+
Latest: boolean;
10+
};
11+
export interface ArduinoFirmwareUploader {
12+
list(fqbn?: string): Promise<FirmwareInfo[]>;
13+
flash(firmware: FirmwareInfo, port: string): Promise<string>;
14+
updatableBoards(): Promise<string[]>;
15+
availableFirmwares(fqbn: string): Promise<FirmwareInfo[]>;
16+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import {
2+
ArduinoFirmwareUploader,
3+
FirmwareInfo,
4+
} from '../common/protocol/arduino-firmware-uploader';
5+
import { injectable, inject, named } from 'inversify';
6+
import { ExecutableService } from '../common/protocol';
7+
import { getExecPath, spawnCommand } from './exec-util';
8+
import { ILogger } from '@theia/core/lib/common/logger';
9+
10+
@injectable()
11+
export class ArduinoFirmwareUploaderImpl implements ArduinoFirmwareUploader {
12+
@inject(ExecutableService)
13+
protected executableService: ExecutableService;
14+
15+
protected _execPath: string | undefined;
16+
17+
@inject(ILogger)
18+
@named('fwuploader')
19+
protected readonly logger: ILogger;
20+
21+
protected onError(error: any): void {
22+
this.logger.error(error);
23+
}
24+
25+
async getExecPath(): Promise<string> {
26+
if (this._execPath) {
27+
return this._execPath;
28+
}
29+
this._execPath = await getExecPath('arduino-fwuploader');
30+
return this._execPath;
31+
}
32+
33+
async runCommand(args: string[]): Promise<any> {
34+
const execPath = await this.getExecPath();
35+
const raw = await spawnCommand(
36+
`"${execPath}"`,
37+
args,
38+
this.onError.bind(this)
39+
);
40+
return JSON.parse(raw);
41+
}
42+
43+
async list(fqbn?: string): Promise<FirmwareInfo[]> {
44+
const fqbnFlag = fqbn ? ['--fqbn', fqbn] : [];
45+
return await this.runCommand([
46+
'firmware',
47+
'list',
48+
'--format',
49+
'json',
50+
...fqbnFlag,
51+
]);
52+
}
53+
54+
async updatableBoards(): Promise<string[]> {
55+
return (await this.list()).reduce(
56+
(a, b) => (a.includes(b.board_fqbn) ? a : [...a, b.board_fqbn]),
57+
[] as string[]
58+
);
59+
}
60+
61+
async availableFirmwares(fqbn: string): Promise<FirmwareInfo[]> {
62+
return await this.list(fqbn);
63+
}
64+
65+
async flash(firmware: FirmwareInfo, port: string): Promise<string> {
66+
return await this.runCommand([
67+
'firmware',
68+
'flash',
69+
'--fqbn',
70+
firmware.board_fqbn,
71+
'--address',
72+
port,
73+
'--module',
74+
`${firmware.module}@${firmware.firmware_version}`,
75+
]);
76+
}
77+
}

arduino-ide-extension/src/node/arduino-ide-backend-module.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import { ContainerModule } from 'inversify';
22
import { ArduinoDaemonImpl } from './arduino-daemon-impl';
3+
import {
4+
ArduinoFirmwareUploader,
5+
ArduinoFirmwareUploaderPath,
6+
} from '../common/protocol/arduino-firmware-uploader';
7+
38
import { ILogger } from '@theia/core/lib/common/logger';
49
import {
510
BackendApplicationContribution,
@@ -80,6 +85,7 @@ import {
8085
AuthenticationServiceClient,
8186
AuthenticationServicePath,
8287
} from '../common/protocol/authentication-service';
88+
import { ArduinoFirmwareUploaderImpl } from './arduino-firmware-uploader-impl';
8389

8490
export default new ContainerModule((bind, unbind, isBound, rebind) => {
8591
bind(BackendApplication).toSelf().inSingletonScope();
@@ -245,6 +251,18 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
245251
)
246252
.inSingletonScope();
247253

254+
bind(ArduinoFirmwareUploaderImpl).toSelf().inSingletonScope();
255+
bind(ArduinoFirmwareUploader).toService(ArduinoFirmwareUploaderImpl);
256+
bind(BackendApplicationContribution).toService(ArduinoFirmwareUploaderImpl);
257+
bind(ConnectionHandler)
258+
.toDynamicValue(
259+
(context) =>
260+
new JsonRpcConnectionHandler(ArduinoFirmwareUploaderPath, () =>
261+
context.container.get(ArduinoFirmwareUploader)
262+
)
263+
)
264+
.inSingletonScope();
265+
248266
// Logger for the Arduino daemon
249267
bind(ILogger)
250268
.toDynamicValue((ctx) => {
@@ -254,6 +272,15 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
254272
.inSingletonScope()
255273
.whenTargetNamed('daemon');
256274

275+
// Logger for the Arduino daemon
276+
bind(ILogger)
277+
.toDynamicValue((ctx) => {
278+
const parentLogger = ctx.container.get<ILogger>(ILogger);
279+
return parentLogger.child('fwuploader');
280+
})
281+
.inSingletonScope()
282+
.whenTargetNamed('fwuploader');
283+
257284
// Logger for the "serial discovery".
258285
bind(ILogger)
259286
.toDynamicValue((ctx) => {

0 commit comments

Comments
 (0)