Skip to content
This repository has been archived by the owner on Aug 6, 2024. It is now read-only.

Commit

Permalink
Merge pull request #40 from leaphy-robotics/development
Browse files Browse the repository at this point in the history
enhancement: add debugging for uploading and more feedback for uploading
  • Loading branch information
koen1711 authored Sep 23, 2023
2 parents b7fe552 + 8312fdc commit 6ea3e44
Show file tree
Hide file tree
Showing 13 changed files with 179 additions and 22 deletions.
6 changes: 5 additions & 1 deletion src/app/effects/backend.wired.effects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {VariableDialog} from "../modules/core/dialogs/variable/variable.dialog";
import {UploadDialog} from "../modules/core/dialogs/upload/upload.dialog";
import {Router} from "@angular/router";
import {CodeEditorState} from "../state/code-editor.state";
import {DebugInformationDialog} from "../modules/core/dialogs/debug-information/debug-information.dialog";

declare var Blockly: any;

Expand Down Expand Up @@ -270,7 +271,10 @@ export class BackendWiredEffects {

break;
case 'open-log-file':
alert("To open the log, go to the console of your browser");
// Open a module to view the log file so .op
this.dialog.open(DebugInformationDialog, {
width: '450px', disableClose: false,
});
break;
case 'restore-workspace':
var input = document.createElement('input');
Expand Down
6 changes: 5 additions & 1 deletion src/app/modules/core/core.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import { LanguageSelectDialog } from './dialogs/language-select/language-select.
import {NameFileDialog} from "./dialogs/name-file/name-file.dialog";
import {VariableDialog} from "./dialogs/variable/variable.dialog";
import {UploadDialog} from "./dialogs/upload/upload.dialog";
import {DebugInformationDialog} from "./dialogs/debug-information/debug-information.dialog";
import {DragDropModule} from "@angular/cdk/drag-drop";
@NgModule({
declarations: [
ConnectWiredDialog,
Expand All @@ -30,12 +32,14 @@ import {UploadDialog} from "./dialogs/upload/upload.dialog";
NameFileDialog,
VariableDialog,
UploadDialog,
DebugInformationDialog,
InfoDialog
],
imports: [
CommonModule,
SharedModule,
NgOptimizedImage
NgOptimizedImage,
DragDropModule
],
entryComponents: [ConnectWiredDialog, ConnectCloudDialog, ConfirmEditorDialog, StatusMessageDialog, CreditsDialog, LanguageSelectDialog, InfoDialog],
exports: [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<div class="container">

<div id="header">
{{ "UPLOAD_OUTPUT" | translate}}
<button mat-stroked-button class="icon-button" (click)="onCloseClicked()">
<mat-icon>close</mat-icon>
</button>
</div>
<div class="upload-log">
<div class="upload-log-item" *ngFor="let item of (robotWiredState.uploadLog$ | async)">
<div class="upload-log-data">{{item}}</div>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
.container {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}

.upload-log-item {
display: flex;
flex-direction: row;
justify-content: right;
align-items: center;
max-width: 100%;
width: 100%;
height: fit-content;
border-bottom: 1px solid black;
}

.upload-log-data {
max-width: 99%;
flex: 1 0 auto;
padding-left: 5px;
color: black;
word-break: break-all;
}

.upload-log {
width: 100%;
height: 50vh;
margin: 0;
overflow-y: scroll;
background-color: lightgray;
}

#header:hover {
cursor: grab;
}

#header {
background-color: var(--leaphy-color-primary);
color: var(--leaphy-color-light);
display: flex;
justify-content: space-between;
align-items: center;
padding-left: 10px;
width: 100%;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';

import { DebugInformationDialog } from './debug-information.dialog';

describe('NameFileComponent', () => {
let component: DebugInformationDialog;
let fixture: ComponentFixture<DebugInformationDialog>;

beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ DebugInformationDialog ]
})
.compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(DebugInformationDialog);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import {Component} from '@angular/core';
import {MatDialogRef} from '@angular/material/dialog';
import {RobotWiredState} from "../../../../state/robot.wired.state";

@Component({
selector: 'debug-information',
templateUrl: './debug-information.dialog.html',
styleUrls: ['./debug-information.dialog.scss']
})
export class DebugInformationDialog {

constructor(
public dialogRef: MatDialogRef<DebugInformationDialog>,
public robotWiredState: RobotWiredState,
) {

}

public onCloseClicked() {
this.dialogRef.close();
}


protected readonly document = document;
}
2 changes: 1 addition & 1 deletion src/app/modules/core/dialogs/upload/upload.dialog.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
</pre>
<div id="return-options" class="hidden">
<button class="block-environment" (click)="returnBlockEnvironment()">{{ "LEAVE_UPLOADING" | translate }}</button>
<button class="help-environment" (click)="returnHelpEnvironment()">{{ "UPLOADING_ISSUE_HELP" | translate }}</button>
<button id="helpEnviroment" class="help-environment hidden" (click)="returnHelpEnvironment()">{{ "UPLOADING_ISSUE_HELP" | translate }}</button>
</div>
</div>
4 changes: 4 additions & 0 deletions src/app/modules/core/dialogs/upload/upload.dialog.scss
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,7 @@
justify-content: center;
height: 100%;
}

.failed-upload {
color: red;
}
14 changes: 11 additions & 3 deletions src/app/modules/core/dialogs/upload/upload.dialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ import {RobotWiredState} from "../../../../state/robot.wired.state";
styleUrls: ['./upload.dialog.scss']
})
export class UploadDialog {
private upload = new ArduinoUploader();
private upload = new ArduinoUploader(this.robotWiredState);

statusMessage: string = '';
progressBarWidth: number = 0;
uploadFailed: boolean = false;

constructor(
public dialogRef: MatDialogRef<UploadDialog>,
private dialogState: DialogState,
Expand All @@ -32,7 +34,6 @@ export class UploadDialog {
public async startUpload(source_code: string, board: string, libraries: string) {
console.log("Starting upload");
this.dialogState.setIsSerialOutputListening(false);
const uploader = new ArduinoUploader();
function makeRequest(source_code, board, libraries) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
Expand Down Expand Up @@ -101,10 +102,12 @@ export class UploadDialog {
this.progressBarWidth += 25;
} catch (error) {
if (error.toString() === 'Error: No device selected') {
this.uploadFailed = true;
this.onUpdate('NO_DEVICE_SELECTED')
this.showReturnOptions();
console.error(error);
} else {
this.uploadFailed = true;
this.onUpdate('DRIVER_ERROR')
this.showReturnOptions();
console.error(error);
Expand All @@ -116,6 +119,7 @@ export class UploadDialog {
await this.upload.upload(hex, (message: string) => { this.onUpdate(message) });
} catch (error) {
// close dialog
this.uploadFailed = true;
this.showReturnOptions();
console.error(error);

Expand All @@ -142,7 +146,10 @@ export class UploadDialog {
document.getElementById("return-options").classList.remove("hidden");
document.getElementById("upload-progress-bar").classList.add("hidden");
document.getElementById("return-options").classList.add("return-options");

if (this.uploadFailed) {
document.getElementById("upload-status").classList.add("failed-upload");
document.getElementById("helpEnviroment").classList.remove("hidden");
}
}

returnBlockEnvironment() {
Expand All @@ -158,6 +165,7 @@ export class UploadDialog {
onError(error: string) {
document.getElementById("error-message").innerText = error;
document.getElementById("error-message").classList.remove("hidden");
this.uploadFailed = true;
}

protected readonly document = document;
Expand Down
36 changes: 22 additions & 14 deletions src/app/services/webserial/ArduinoUploader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,24 @@ import { Requests, Responses, Signature } from './stk500'
import { convertArrayToHex, delay, includesAll } from './utils'
import { parse } from 'intel-hex'
import {Buffer} from "buffer";
import {RobotWiredState} from "../../state/robot.wired.state";

class Arduino {
port = null
isUploading = false
serialOptions = null
readStream = null
writeStream = null
robotWiredState: RobotWiredState

/**
* Create a new Arduino instance.
* @param serialOptions The options to use when opening the serial port.
* @param robotWiredState The appstate to use
*/
constructor(serialOptions = { baudRate: 115200 }) {
constructor(robotWiredState: RobotWiredState, serialOptions = { baudRate: 115200 }) {
this.serialOptions = serialOptions
this.robotWiredState = robotWiredState
}

/**
Expand All @@ -26,15 +30,15 @@ class Arduino {
try {
port = await navigator.serial.requestPort({filters: [{usbVendorId: 0x1a86}, {usbVendorId: 9025}, {usbVendorId: 2341}, {usbVendorId: 0x0403}]});
} catch (error) {
console.error(error)
console.log(error)
throw new Error('No device selected')
}
if (port === this.port)
return
try {
await port.open(this.serialOptions)
} catch (error) {
console.error(error)
console.log(error)
throw new Error('Connecting to device')
}
this.port = port
Expand All @@ -48,6 +52,7 @@ class Arduino {
async upload(program: string, callback = (message: string) => {}) {
if (this.isUploading)
throw new Error('Arduino is already uploading')
this.robotWiredState.clearUploadLog()
this.isUploading = true

this.readStream = this.port.readable.getReader();
Expand All @@ -59,11 +64,11 @@ class Arduino {
if (response === null) {
response = await this.attemptOldBootloader();
if (response !== null) {
console.log("Using old bootloader")
this.robotWiredState.addToUploadLog("Using old bootloader")
}
}
else {
console.log("Using new bootloader")
this.robotWiredState.addToUploadLog("Using new bootloader")
}

if (response === null) {
Expand Down Expand Up @@ -129,7 +134,7 @@ class Arduino {
response = await this.send([Requests.GET_SYNC], 500)
break
} catch (error) {
console.log(error)
this.robotWiredState.addToUploadLog(error.toString())
}
}
if (response === null) {
Expand All @@ -154,6 +159,7 @@ class Arduino {
try {
await this.reset(this.serialOptions.baudRate);
} catch (error) {
this.robotWiredState.addToUploadLog("Could not connect to Arduino: Reset failed (new bootloader)")
callback("COULD_NOT_CONNECT")
throw new Error('Could not connect to Arduino: Reset failed')
}
Expand All @@ -162,7 +168,7 @@ class Arduino {
response = await this.send([Requests.GET_SYNC], 500)
break;
} catch (error) {
console.log(error)
this.robotWiredState.addToUploadLog(error.toString())
}
}
if (response === null) {
Expand All @@ -171,6 +177,7 @@ class Arduino {
this.readStream = null;
this.writeStream = null;
callback("COULD_NOT_CONNECT")
this.robotWiredState.addToUploadLog("Could not connect to Arduino (new bootloader)")
throw new Error('Could not connect to Arduino')
}
return response
Expand All @@ -185,7 +192,7 @@ class Arduino {
*/
async send(command, timeoutMs = 1000) {
const buffer = new Uint8Array([...command, Requests.CRC_EOP]);
console.log("Sending: " + convertArrayToHex(buffer).join(' '));
this.robotWiredState.addToUploadLog("Sending: " + convertArrayToHex(buffer).join(' '))
await this.writeBuffer(buffer);

const timeoutPromise = new Promise((resolve, _) => {
Expand All @@ -203,9 +210,10 @@ class Arduino {

if (result instanceof Uint8Array) {
const answer = Array.from(result);
if (answer.includes(Responses.NOT_IN_SYNC))
if (answer.includes(Responses.NOT_IN_SYNC)) {
this.robotWiredState.addToUploadLog("Arduino is not in sync")
throw new Error('Arduino is not in sync');
else
} else
returnBuffer = new Uint8Array([...returnBuffer, ...answer]);
if (answer.includes(Responses.IN_SYNC))
IN_SYNC = true;
Expand Down Expand Up @@ -238,7 +246,7 @@ class Arduino {
*/
async receive() {
const { value } = await this.readStream.read()
console.log("Received: " + convertArrayToHex(value).join(' '))
this.robotWiredState.addToUploadLog("Received: " + convertArrayToHex(value).join(' '))
return value
}

Expand Down Expand Up @@ -312,7 +320,7 @@ class Arduino {
* @returns {Promise<void>}
*/
async clearReadBuffer() {
console.log("Clearing read buffer");
this.robotWiredState.addToUploadLog("Clearing read buffer");
const timeoutPromise = new Promise((resolve, _) => {
setTimeout(() => {
resolve("Timeout");
Expand All @@ -326,7 +334,7 @@ class Arduino {

let i = 1;
while (true) {
console.log("Attempt #" + i);
this.robotWiredState.addToUploadLog("Attempt #" + i);
const promise = new Promise(async (resolve, _) => {
while (true) {
const result = await Promise.race([this.readStream.read(), timeoutPromise]);
Expand All @@ -343,7 +351,7 @@ class Arduino {
throw new Error('Timeout');
i++;
}
console.log("Read buffer cleared");
this.robotWiredState.addToUploadLog("Read buffer cleared");
}

/**
Expand Down
Loading

0 comments on commit 6ea3e44

Please sign in to comment.