Skip to content

Added status message area to USB connect workflow #334

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,11 @@ <h1>Select USB Host Folder</h1>
</p>
</div>
</section>
<section>
<div class="connect-status" hidden>
<div class="connect-status-content"></div>
</div>
</section>
</div>
</div>
<div class="popup-modal shadow closable" data-popup-modal="device-discovery">
Expand Down
89 changes: 69 additions & 20 deletions js/workflows/usb.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ class USBWorkflow extends Workflow {

async connect() {
let result;
this._clearStatus();
if (result = await super.connect() instanceof Error) {
return result;
}
Expand All @@ -100,6 +101,7 @@ class USBWorkflow extends Workflow {
// the device on the stored port is currently connected by checking if the
// readable and writable properties are null.

// Can throw a Security Error if permissions are not granted
let allDevices = await navigator.serial.getPorts();
let connectedDevices = [];
for (let device of allDevices) {
Expand All @@ -112,7 +114,8 @@ class USBWorkflow extends Workflow {

if (connectedDevices.length == 1) {
device = connectedDevices[0];
console.log(await device.getInfo());
deviceInfo = await device.getInfo()
console.log(`Got previously connected device: ${deviceInfo}`);
try {
// Attempt to connect to the saved device. If it's not found, this will fail.
await this._switchToDevice(device);
Expand All @@ -121,37 +124,35 @@ class USBWorkflow extends Workflow {
await device.forget();

console.log("Failed to automatically connect to saved device. Prompting user to select a device.");
// If the user doesn't select a port, an exception is thrown
device = await navigator.serial.requestPort();
console.log(device);
}
} else {
console.log('Requesting any serial device...');
try {
device = await navigator.serial.requestPort();
} catch (e) {
console.log(e);
return false;
}
console.log('No previously connected device. Prompting user to select a device.');
// If the user doesn't select a port, an exception is thrown
device = await navigator.serial.requestPort();
}
console.log(`Selected device: ${device}`);


// If we didn't automatically use a saved device
if (!this._serialDevice) {
console.log('> Requested ', device);
await this._switchToDevice(device);
}
console.log(this._serialDevice);

if (this._serialDevice != null) {
console.log(`Current serial device is: ${this._serialDevice}. Proceeding to step 2.`);
this.connectionStep(2);
return true;
}

console.log("Couldn't connect to serial port");
return false;
}

async showConnect(documentState) {
let p = this.connectDialog.open();
let modal = this.connectDialog.getModal();

btnRequestSerialDevice = modal.querySelector('#requestSerialDevice');
btnSelectHostFolder = modal.querySelector('#selectHostFolder');
btnUseHostFolder = modal.querySelector('#useHostFolder');
Expand All @@ -165,22 +166,27 @@ class USBWorkflow extends Workflow {

btnRequestSerialDevice.disabled = true;
btnSelectHostFolder.disabled = true;
this._clearStatus();
let serialConnect = async (event) => {
try {
this._clearStatus();
await this.connectToSerial();
} catch (e) {
//console.log(e);
//alert(e.message);
//alert("Unable to connect to device. Make sure it is not already in use.");
// TODO: I think this also occurs if the user cancels the requestPort dialog
console.log('connectToSerial() returned error: ', e);
this._showStatus(this._suggestSerialConnectActions(e))
}
};
btnRequestSerialDevice.removeEventListener('click', serialConnect);
btnRequestSerialDevice.addEventListener('click', serialConnect);

btnSelectHostFolder.removeEventListener('click', this._btnSelectHostFolderCallback)
this._btnSelectHostFolderCallback = async (event) => {
await this._selectHostFolder();
try {
this._clearStatus();
await this._selectHostFolder();
} catch (e) {
this._showStatus(this._suggestFileConnectActions(e))
}
};
btnSelectHostFolder.addEventListener('click', this._btnSelectHostFolderCallback);

Expand Down Expand Up @@ -269,9 +275,8 @@ class USBWorkflow extends Workflow {

this._serialDevice = device;
console.log("switch to", this._serialDevice);
await this._serialDevice.open({baudRate: 115200}); // TODO: Will fail if something else is already connected or it isn't found.

// Start the read loop
await this._serialDevice.open({baudRate: 115200}); // Throws if something else is already connected or it isn't found.
console.log("Starting Read Loop")
this._readLoopPromise = this._readSerialLoop().catch(
async function(error) {
await this.onDisconnected();
Expand Down Expand Up @@ -368,6 +373,50 @@ print(binascii.hexlify(microcontroller.cpu.uid).decode('ascii').upper())`
console.log("Read Loop Stopped. Closing Serial Port.");
}

_clearStatus(modal) {
try {
const modal = this.connectDialog.getModal();
modal.querySelector('.connect-status').hidden = true;
} catch (e) {
console.log("Modal not active on _clearStatus()", e);
}
}

_showStatus(message) {
try {
const modal = this.connectDialog.getModal();
const statusBox = modal.querySelector('.connect-status');
statusBox.hidden = false;
let statusContentBox = statusBox.querySelector('.connect-status-content')
statusContentBox.innerHTML = message
} catch (e) {
console.log("Modal not active on _setStatus()", e);
}
}

// Analyzes the error returned from the WebSerial API and returns human readable feedback.
_suggestSerialConnectActions(error) {
if (error.name == "NetworkError" && error.message.includes("Failed to open serial port")) {
return "The serial port could not be opened. Make sure the correct port is selected and no other program is using it. For more information, see the JavaScript console.";
} else if (error.name == "NotFoundError" && error.message.includes("No port selected")) {
return "No serial port was selected. Press the 'Connect to Device' button to try again.";
} else if (error.name == "SecurityError") {
return "Permissions to access the serial port were not granted. Please check your browser settings and try again.";
}
return `Connect to Serial Port returned error: ${error}`;
}

// Analyzes the error from the FSAPI and returns human readable feedback
_suggestFileConnectActions(error) {
if (error.name == "SecurityError") {
return "Permissions to access the filesystem were not granted. Please check your browser settings and try again.";
} else if (error.name == "AbortError") {
return "No folder selected. Press the 'Select New Folder' button to try again.";
}
return `Connect to Filesystem returned error: ${error}`;

}

async showInfo(documentState) {
return await this.infoDialog.open(this, documentState);
}
Expand Down
8 changes: 8 additions & 0 deletions sass/layout/_layout.scss
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,14 @@
}
}

.connect-status-content {
background-color: #eebbbb;
color: #222222;
border-radius: 10px;
padding: 10px;
margin: 10px;
}

.popup-modal {
#message {
a {
Expand Down