diff --git a/index.html b/index.html
index 4f10992..96d1ece 100644
--- a/index.html
+++ b/index.html
@@ -313,6 +313,11 @@
Select USB Host Folder
+
diff --git a/js/workflows/usb.js b/js/workflows/usb.js
index 36605ad..be11f99 100644
--- a/js/workflows/usb.js
+++ b/js/workflows/usb.js
@@ -83,6 +83,7 @@ class USBWorkflow extends Workflow {
async connect() {
let result;
+ this._clearStatus();
if (result = await super.connect() instanceof Error) {
return result;
}
@@ -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) {
@@ -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);
@@ -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');
@@ -165,14 +166,14 @@ 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);
@@ -180,7 +181,12 @@ class USBWorkflow extends Workflow {
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);
@@ -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();
@@ -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);
}
diff --git a/sass/layout/_layout.scss b/sass/layout/_layout.scss
index ef987e4..d66b06f 100644
--- a/sass/layout/_layout.scss
+++ b/sass/layout/_layout.scss
@@ -151,6 +151,14 @@
}
}
+.connect-status-content {
+ background-color: #eebbbb;
+ color: #222222;
+ border-radius: 10px;
+ padding: 10px;
+ margin: 10px;
+}
+
.popup-modal {
#message {
a {