Can list HW, build for it and upload

This commit is contained in:
Christian Weichel 2019-05-07 12:43:07 +02:00
parent 95ed43c9c4
commit b2d16ff9a4
7 changed files with 119 additions and 38 deletions

View File

@ -75,10 +75,11 @@ export class ArduinoFrontendContribution extends DefaultFrontendApplicationContr
registry.registerCommand(ArduinoCommands.UPLOAD, { registry.registerCommand(ArduinoCommands.UPLOAD, {
isVisible: widget => this.isArduinoEditor(widget), isVisible: widget => this.isArduinoEditor(widget),
isEnabled: widget => this.isArduinoEditor(widget), isEnabled: widget => this.isArduinoEditor(widget),
execute: widget => { execute: async widget => {
const uri = this.toUri(widget); const uri = this.toUri(widget);
if (uri) { if (uri) {
this.messageService.info(`Uploading ${uri.toString()}`); const result = await this.coreService.upload({ uri: uri.toString() });
console.log('upload result', result);
} }
} }
}); });

View File

@ -4,40 +4,60 @@ import * as React from 'react';
import { BoardsService, AttachedBoard } from '../../common/protocol/boards-service'; import { BoardsService, AttachedBoard } from '../../common/protocol/boards-service';
export class ConnectedBoards extends React.Component<ConnectedBoards.Props, ConnectedBoards.State> { export class ConnectedBoards extends React.Component<ConnectedBoards.Props, ConnectedBoards.State> {
static TOOLBAR_ID: 'connected-boards-toolbar'; static TOOLBAR_ID: 'connected-boards-toolbar';
constructor(props: ConnectedBoards.Props) {
super(props);
this.state = { boardsLoading: false };
}
render(): React.ReactNode { render(): React.ReactNode {
let label = "no board available";
if (this.state.boardsLoading) {
label = "Loading ...";
} else if (!!this.state.current) {
label = this.state.current.name;
}
let content = [];
if (!!this.state.boards) {
content = this.state.boards.map((b, i) => <option value={i} key={i}>{b.name}</option>);
} else {
content = [ <option key="loading" value="0">{label}</option> ];
}
return <div className={ConnectedBoards.Styles.CONNECTED_BOARDS_CLASS}> return <div className={ConnectedBoards.Styles.CONNECTED_BOARDS_CLASS}>
{this.select(this.state ? this.state.boards : undefined, this.state ? this.state.current : undefined)} <select disabled={!this.state.boards} onChange={this.onBoardSelect.bind(this)}>
{ content }
</select>
</div>; </div>;
} }
componentDidMount(): void { componentDidMount(): void {
this.props.boardsService.attachedBoards().then(result => { this.reloadBoards();
const { boards } = result;
this.setState({ boards });
});
} }
private select(boards: AttachedBoard[] | undefined, current: AttachedBoard | undefined): React.ReactNode { protected async reloadBoards() {
// Initial pessimistic. this.setState({ boardsLoading: true, boards: undefined, current: undefined });
const options = [<option>Loading...</option>]; const { boards } = await this.props.boardsService.getAttachedBoards()
this.setState({ boards, boardsLoading: false });
if (boards) { if (boards) {
options.length = 0; this.selectBoard(boards[0]);
options.push(...boards.map(b => b.name).map(name => <option value={name} key={name}>{name}</option>));
} }
const onChange = (event: React.ChangeEvent<HTMLSelectElement>) => { }
const current = (boards || []).find(board => board.name === event.target.value);
this.setState({ current }); protected async onBoardSelect(evt: React.ChangeEvent<HTMLSelectElement>) {
}; const selectedBoard = (this.state.boards || [])[parseInt(evt.target.value, 10)];
return <select if (!selectedBoard) {
onChange={onChange} return;
value={current ? current.name : 'Loading...'} }
name={current ? current.name : 'Loading...'} this.selectBoard(selectedBoard);
> }
{options}
</select> protected async selectBoard(board: AttachedBoard) {
await this.props.boardsService.selectBoard(board);
this.setState({ current: board });
} }
} }
@ -49,6 +69,7 @@ export namespace ConnectedBoards {
} }
export interface State { export interface State {
boardsLoading: boolean;
boards?: AttachedBoard[]; boards?: AttachedBoard[];
current?: AttachedBoard; current?: AttachedBoard;
} }

View File

@ -3,7 +3,10 @@ import { ArduinoComponent } from "./arduino-component";
export const BoardsServicePath = '/services/boards-service'; export const BoardsServicePath = '/services/boards-service';
export const BoardsService = Symbol('BoardsService'); export const BoardsService = Symbol('BoardsService');
export interface BoardsService { export interface BoardsService {
attachedBoards(): Promise<{ boards: AttachedBoard[] }>; getAttachedBoards(): Promise<{ boards: AttachedBoard[] }>;
selectBoard(board: AttachedBoard): Promise<void>;
getSelectBoard(): Promise<AttachedBoard | undefined>;
search(options: { query?: string }): Promise<{ items: Board[] }>; search(options: { query?: string }): Promise<{ items: Board[] }>;
install(board: Board): Promise<void>; install(board: Board): Promise<void>;
} }

View File

@ -2,10 +2,17 @@ export const CoreServicePath = '/services/core-service';
export const CoreService = Symbol('CoreService'); export const CoreService = Symbol('CoreService');
export interface CoreService { export interface CoreService {
compile(options: CoreService.Compile.Options): Promise<void>; compile(options: CoreService.Compile.Options): Promise<void>;
upload(): Promise<void>; upload(options: CoreService.Upload.Options): Promise<void>;
} }
export namespace CoreService { export namespace CoreService {
export namespace Upload {
export interface Options {
readonly uri: string;
}
}
export namespace Compile { export namespace Compile {
export interface Options { export interface Options {
readonly uri: string; readonly uri: string;

View File

@ -33,13 +33,13 @@ export class ArduinoDaemon implements BackendApplicationContribution {
}); });
if (daemon.stdout) { if (daemon.stdout) {
daemon.stdout.on('data', data => { daemon.stdout.on('data', data => {
this.toolOutputService.publishNewOutput("daeomn", data.toString()); this.toolOutputService.publishNewOutput("daemon", data.toString());
DaemonLog.log(this.logger, data.toString()); DaemonLog.log(this.logger, data.toString());
}); });
} }
if (daemon.stderr) { if (daemon.stderr) {
daemon.stderr.on('data', data => { daemon.stderr.on('data', data => {
this.toolOutputService.publishNewOutput("daeomn error", data.toString()); this.toolOutputService.publishNewOutput("daemon error", data.toString());
DaemonLog.log(this.logger, data.toString()); DaemonLog.log(this.logger, data.toString());
}); });
} }

View File

@ -10,7 +10,9 @@ export class BoardsServiceImpl implements BoardsService {
@inject(CoreClientProvider) @inject(CoreClientProvider)
protected readonly coreClientProvider: CoreClientProvider; protected readonly coreClientProvider: CoreClientProvider;
public async attachedBoards(): Promise<{ boards: AttachedBoard[] }> { protected selectedBoard: AttachedBoard | undefined;
public async getAttachedBoards(): Promise<{ boards: AttachedBoard[] }> {
const { client, instance } = await this.coreClientProvider.getClient(); const { client, instance } = await this.coreClientProvider.getClient();
const req = new BoardListReq(); const req = new BoardListReq();
@ -36,6 +38,14 @@ export class BoardsServiceImpl implements BoardsService {
return { boards: serialBoards.concat(networkBoards) }; return { boards: serialBoards.concat(networkBoards) };
} }
async selectBoard(board: AttachedBoard): Promise<void> {
this.selectedBoard = board;
}
async getSelectBoard(): Promise<AttachedBoard | undefined> {
return this.selectedBoard;
}
async search(options: { query?: string }): Promise<{ items: Board[] }> { async search(options: { query?: string }): Promise<{ items: Board[] }> {
const { client, instance } = await this.coreClientProvider.getClient(); const { client, instance } = await this.coreClientProvider.getClient();

View File

@ -2,10 +2,11 @@ import { inject, injectable } from 'inversify';
import { FileSystem } from '@theia/filesystem/lib/common/filesystem'; import { FileSystem } from '@theia/filesystem/lib/common/filesystem';
import { CoreService } from '../common/protocol/core-service'; import { CoreService } from '../common/protocol/core-service';
import { CompileReq, CompileResp } from './cli-protocol/compile_pb'; import { CompileReq, CompileResp } from './cli-protocol/compile_pb';
import { BoardsService } from '../common/protocol/boards-service'; import { BoardsService, AttachedSerialBoard } from '../common/protocol/boards-service';
import { CoreClientProvider } from './core-client-provider'; import { CoreClientProvider } from './core-client-provider';
import * as path from 'path'; import * as path from 'path';
import { ToolOutputServiceServer } from '../common/protocol/tool-output-service'; import { ToolOutputServiceServer } from '../common/protocol/tool-output-service';
import { UploadReq, UploadResp } from './cli-protocol/upload_pb';
@injectable() @injectable()
export class CoreServiceImpl implements CoreService { export class CoreServiceImpl implements CoreService {
@ -32,16 +33,19 @@ export class CoreServiceImpl implements CoreService {
const sketchpath = path.dirname(sketchFilePath); const sketchpath = path.dirname(sketchFilePath);
const { client, instance } = await this.coreClientProvider.getClient(uri); const { client, instance } = await this.coreClientProvider.getClient(uri);
// const boards = await this.boardsService.connectedBoards();
// if (!boards.current) { const currentBoard = await this.boardsService.getSelectBoard();
// throw new Error(`No selected board. The connected boards were: ${boards.boards}.`); if (!currentBoard) {
// } throw new Error("no board selected");
// https://github.com/cmaglie/arduino-cli/blob/bd5e78701e7546787649d3cca6b21c5d22d0e438/cli/compile/compile.go#L78-L88 }
if (!currentBoard.fqbn) {
throw new Error(`selected board (${currentBoard.name}) has no FQBN`);
}
const compilerReq = new CompileReq(); const compilerReq = new CompileReq();
compilerReq.setInstance(instance); compilerReq.setInstance(instance);
compilerReq.setSketchpath(sketchpath); compilerReq.setSketchpath(sketchpath);
compilerReq.setFqbn('arduino:avr:uno'/*boards.current.name*/); compilerReq.setFqbn(currentBoard.fqbn!);
compilerReq.setPreprocess(false); compilerReq.setPreprocess(false);
compilerReq.setVerbose(true); compilerReq.setVerbose(true);
compilerReq.setQuiet(false); compilerReq.setQuiet(false);
@ -57,8 +61,43 @@ export class CoreServiceImpl implements CoreService {
}); });
} }
upload(): Promise<void> { async upload(options: CoreService.Upload.Options): Promise<void> {
throw new Error("Method not implemented."); console.log('upload', options);
const { uri } = options;
const sketchFilePath = await this.fileSystem.getFsPath(options.uri);
if (!sketchFilePath) {
throw new Error(`Cannot resolve filesystem path for URI: ${uri}.`);
}
const sketchpath = path.dirname(sketchFilePath);
const currentBoard = await this.boardsService.getSelectBoard();
if (!currentBoard) {
throw new Error("no board selected");
}
if (!currentBoard.fqbn) {
throw new Error(`selected board (${currentBoard.name}) has no FQBN`);
}
const { client, instance } = await this.coreClientProvider.getClient(uri);
const req = new UploadReq();
req.setInstance(instance);
req.setSketchPath(sketchpath);
req.setFqbn(currentBoard.fqbn);
if (AttachedSerialBoard.is(currentBoard)) {
req.setPort(currentBoard.port);
} else {
throw new Error("can only upload to serial boards");
}
const result = client.upload(req);
return new Promise<void>((resolve, reject) => {
result.on('data', (cr: UploadResp) => {
this.toolOutputService.publishNewOutput("upload", new Buffer(cr.getOutStream_asU8()).toString());
this.toolOutputService.publishNewOutput("upload error", new Buffer(cr.getErrStream_asU8()).toString());
});
result.on('error', error => reject(error));
result.on('end', () => resolve());
});
} }
} }