Skip to content

[ATL-1533] Firmware&Certificate Uploader #469

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

Merged
merged 17 commits into from
Aug 25, 2021
Merged
Prev Previous commit
Next Next commit
firmware uploader service
  • Loading branch information
Alberto Iannaccone authored and fstasi committed Aug 23, 2021
commit ef91a9ff49252d7b57846577daba5d96bcbd491c
Original file line number Diff line number Diff line change
Expand Up @@ -365,16 +365,14 @@ export class ArduinoFrontendContribution
);
}
}
const { clangdUri, cliUri, lsUri, fwuploaderUri } =
await this.executableService.list();
const { clangdUri, cliUri, lsUri } = await this.executableService.list();
const [clangdPath, cliPath, lsPath, cliConfigPath] = await Promise.all([
this.fileService.fsPath(new URI(clangdUri)),
this.fileService.fsPath(new URI(cliUri)),
this.fileService.fsPath(new URI(lsUri)),
this.fileService.fsPath(
new URI(await this.configService.getCliConfigFileUri())
),
this.fileService.fsPath(new URI(fwuploaderUri)),
]);
this.languageServerFqbn = await Promise.race([
new Promise<undefined>((_, reject) =>
Expand Down
13 changes: 13 additions & 0 deletions arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,10 @@ import {
UploadCertificateDialogWidget,
} from './dialogs/certificate-uploader/upload-certificate-dialog';
import { UploadCertificate } from './contributions/upload-certificate';
import {
ArduinoFirmwareUploader,
ArduinoFirmwareUploaderPath,
} from '../common/protocol/arduino-firmware-uploader';

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

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

bind(ArduinoFirmwareUploader)
.toDynamicValue((context) =>
WebSocketConnectionProvider.createProxy(
context.container,
ArduinoFirmwareUploaderPath
)
)
.inSingletonScope();

// File-system extension
bind(FileSystemExt)
.toDynamicValue((context) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
BoardsServiceProvider,
} from '../../boards/boards-service-provider';
import { ArduinoSelect } from '../../widgets/arduino-select';
import { ArduinoFirmwareUploader } from '../../../common/protocol/arduino-firmware-uploader';

export const CertificateUploaderComponent = ({
boardsServiceClient,
Expand All @@ -22,7 +23,6 @@ export const CertificateUploaderComponent = ({
const [installFeedback, setInstallFeedback] = React.useState<
'ok' | 'fail' | null
>(null);

const [selectedBoard, setSelectedBoard] = React.useState<{
label: string;
value: string;
Expand Down Expand Up @@ -266,6 +266,9 @@ export class UploadCertificateDialogWidget extends ReactWidget {
@inject(BoardsServiceProvider)
protected readonly boardsServiceClient: BoardsServiceProvider;

@inject(ArduinoFirmwareUploader)
protected readonly firmware: ArduinoFirmwareUploader;

constructor() {
super();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export const ArduinoFirmwareUploaderPath =
'/services/arduino-firmware-uploader';
export const ArduinoFirmwareUploader = Symbol('ArduinoFirmwareUploader');
export type FirmwareInfo = {
board_name: string;
board_fqbn: string;
module: string;
firmware_version: string;
Latest: boolean;
};
export interface ArduinoFirmwareUploader {
list(fqbn?: string): Promise<FirmwareInfo[]>;
flash(firmware: FirmwareInfo, port: string): Promise<string>;
updatableBoards(): Promise<string[]>;
availableFirmwares(fqbn: string): Promise<FirmwareInfo[]>;
}
77 changes: 77 additions & 0 deletions arduino-ide-extension/src/node/arduino-firmware-uploader-impl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import {
ArduinoFirmwareUploader,
FirmwareInfo,
} from '../common/protocol/arduino-firmware-uploader';
import { injectable, inject, named } from 'inversify';
import { ExecutableService } from '../common/protocol';
import { getExecPath, spawnCommand } from './exec-util';
import { ILogger } from '@theia/core/lib/common/logger';

@injectable()
export class ArduinoFirmwareUploaderImpl implements ArduinoFirmwareUploader {
@inject(ExecutableService)
protected executableService: ExecutableService;

protected _execPath: string | undefined;

@inject(ILogger)
@named('fwuploader')
protected readonly logger: ILogger;

protected onError(error: any): void {
this.logger.error(error);
}

async getExecPath(): Promise<string> {
if (this._execPath) {
return this._execPath;
}
this._execPath = await getExecPath('arduino-fwuploader');
return this._execPath;
}

async runCommand(args: string[]): Promise<any> {
const execPath = await this.getExecPath();
const raw = await spawnCommand(
`"${execPath}"`,
args,
this.onError.bind(this)
);
return JSON.parse(raw);
}

async list(fqbn?: string): Promise<FirmwareInfo[]> {
const fqbnFlag = fqbn ? ['--fqbn', fqbn] : [];
return await this.runCommand([
'firmware',
'list',
'--format',
'json',
...fqbnFlag,
]);
}

async updatableBoards(): Promise<string[]> {
return (await this.list()).reduce(
(a, b) => (a.includes(b.board_fqbn) ? a : [...a, b.board_fqbn]),
[] as string[]
);
}

async availableFirmwares(fqbn: string): Promise<FirmwareInfo[]> {
return await this.list(fqbn);
}

async flash(firmware: FirmwareInfo, port: string): Promise<string> {
return await this.runCommand([
'firmware',
'flash',
'--fqbn',
firmware.board_fqbn,
'--address',
port,
'--module',
`${firmware.module}@${firmware.firmware_version}`,
]);
}
}
27 changes: 27 additions & 0 deletions arduino-ide-extension/src/node/arduino-ide-backend-module.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { ContainerModule } from 'inversify';
import { ArduinoDaemonImpl } from './arduino-daemon-impl';
import {
ArduinoFirmwareUploader,
ArduinoFirmwareUploaderPath,
} from '../common/protocol/arduino-firmware-uploader';

import { ILogger } from '@theia/core/lib/common/logger';
import {
BackendApplicationContribution,
Expand Down Expand Up @@ -80,6 +85,7 @@ import {
AuthenticationServiceClient,
AuthenticationServicePath,
} from '../common/protocol/authentication-service';
import { ArduinoFirmwareUploaderImpl } from './arduino-firmware-uploader-impl';

export default new ContainerModule((bind, unbind, isBound, rebind) => {
bind(BackendApplication).toSelf().inSingletonScope();
Expand Down Expand Up @@ -245,6 +251,18 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
)
.inSingletonScope();

bind(ArduinoFirmwareUploaderImpl).toSelf().inSingletonScope();
bind(ArduinoFirmwareUploader).toService(ArduinoFirmwareUploaderImpl);
bind(BackendApplicationContribution).toService(ArduinoFirmwareUploaderImpl);
bind(ConnectionHandler)
.toDynamicValue(
(context) =>
new JsonRpcConnectionHandler(ArduinoFirmwareUploaderPath, () =>
context.container.get(ArduinoFirmwareUploader)
)
)
.inSingletonScope();

// Logger for the Arduino daemon
bind(ILogger)
.toDynamicValue((ctx) => {
Expand All @@ -254,6 +272,15 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
.inSingletonScope()
.whenTargetNamed('daemon');

// Logger for the Arduino daemon
bind(ILogger)
.toDynamicValue((ctx) => {
const parentLogger = ctx.container.get<ILogger>(ILogger);
return parentLogger.child('fwuploader');
})
.inSingletonScope()
.whenTargetNamed('fwuploader');

// Logger for the "serial discovery".
bind(ILogger)
.toDynamicValue((ctx) => {
Expand Down