import { ILogger } from '@theia/core/lib/common/logger'; import { inject, injectable, named } from '@theia/core/shared/inversify'; import type { Port } from '../common/protocol'; import { ArduinoFirmwareUploader, FirmwareInfo, UploadCertificateParams, } from '../common/protocol/arduino-firmware-uploader'; import { spawnCommand } from './exec-util'; import { MonitorManager } from './monitor-manager'; import { arduinoFirmwareUploaderPath } from './resources'; @injectable() export class ArduinoFirmwareUploaderImpl implements ArduinoFirmwareUploader { @inject(ILogger) @named('fwuploader') private readonly logger: ILogger; @inject(MonitorManager) private readonly monitorManager: MonitorManager; async uploadCertificates(params: UploadCertificateParams): Promise { const { fqbn, address, urls } = params; return await this.runCommand([ 'certificates', 'flash', '-b', fqbn, '-a', address, ...urls.flatMap((url) => ['-u', url]), ]); } async list(fqbn?: string): Promise { const fqbnFlag = fqbn ? ['--fqbn', fqbn] : []; const firmwares: FirmwareInfo[] = JSON.parse( await this.runCommand([ 'firmware', 'list', ...fqbnFlag, '--format', 'json', ]) ) || []; return firmwares.reverse(); } async updatableBoards(): Promise { return (await this.list()).reduce( (a, b) => (a.includes(b.board_fqbn) ? a : [...a, b.board_fqbn]), [] as string[] ); } async availableFirmwares(fqbn: string): Promise { return await this.list(fqbn); } async flash(firmware: FirmwareInfo, port: Port): Promise { const board = { name: firmware.board_name, fqbn: firmware.board_fqbn, }; try { await this.monitorManager.notifyUploadStarted(board.fqbn, port); const output = await this.runCommand([ 'firmware', 'flash', '--fqbn', firmware.board_fqbn, '--address', port.address, '--module', `${firmware.module}@${firmware.firmware_version}`, ]); return output; } finally { await this.monitorManager.notifyUploadFinished(board.fqbn, port, port); // here the before and after ports are assumed to be always the same } } private onError(error: Error): void { this.logger.error(error); } private async runCommand(args: string[]): Promise { return await spawnCommand( arduinoFirmwareUploaderPath, args, this.onError.bind(this) ); } }