Skip to content

Commit

Permalink
Merge pull request #200 from makermelissa/serial-file-transfer
Browse files Browse the repository at this point in the history
Revamped USB file transfer using REPL
  • Loading branch information
makermelissa authored Jun 20, 2024
2 parents a0f4b7c + ac90abe commit 7cc4f1f
Show file tree
Hide file tree
Showing 13 changed files with 832 additions and 212 deletions.
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@
<button class="purple-button ok-button">Ok</button>
</div>
</div>
<div class="popup-modal shadow prompt" data-popup-modal="progress">
<div class="popup-modal shadow prompt" data-popup-modal="progress" data-tabbable="false">
<div class="label centered" id="status"></div>
<div class="label centered" id="percentage"></div>
<progress value="0"></progress>
Expand Down
2 changes: 1 addition & 1 deletion js/common/dialogs.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ class GenericModal {
this._modalLayerId = modalLayers.length;
modal.style.zIndex = BLACKOUT_ZINDEX + 1 + (this._modalLayerId * 2);

if (!this._trap){
if (!this._trap && modal.dataset.tabbable !== "false"){
this._trap = focusTrap.createFocusTrap(modal, {
initialFocus: () => modal,
allowOutsideClick: true,
Expand Down
4 changes: 2 additions & 2 deletions js/common/file_dialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ class FileDialog extends GenericModal {
this._addFile({path: "..", isDir: true}, "fa-folder-open");
}
if (!this._fileHelper) {
console.log("no client");
console.error("no client");
return;
}

Expand All @@ -196,7 +196,7 @@ class FileDialog extends GenericModal {
this._addFile(fileObj);
}
} catch (e) {
console.log(e);
console.error(e);
}
this._setElementValue('fileNameField', "");
this._setElementEnabled('okButton', this._validSelectableFolder());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class FileTransferClient {

async loadDirHandle(preferSaved = true) {
if (preferSaved) {
const result = await loadSavedDirHandle();
const result = await this.loadSavedDirHandle();
if (!result) {
return true;
}
Expand Down
119 changes: 119 additions & 0 deletions js/common/repl-file-transfer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import {FileOps} from '@adafruit/circuitpython-repl-js';

class FileTransferClient {
constructor(connectionStatusCB, repl) {
this.connectionStatus = connectionStatusCB;
this._dirHandle = null;
this._fileops = new FileOps(repl, false);
this._isReadOnly = null;
}

async readOnly() {
await this._checkConnection();
return this._isReadOnly;
}

async _checkConnection() {
if (!this.connectionStatus(true)) {
throw new Error("Unable to perform file operation. Not Connected.");
}

if (this._isReadOnly === null) {
this._isReadOnly = await this._fileops.isReadOnly();
}
}

async _checkWritable() {
if (await this.readOnly()) {
throw new Error("File System is Read Only.");
}
}

async readFile(path, raw = false) {
await this._checkConnection();
let contents = await this._fileops.readFile(path, raw);
if (contents === null) {
return raw ? null : "";
}
return contents;
}

async writeFile(path, offset, contents, modificationTime, raw = false) {
await this._checkConnection();
await this._checkWritable();

if (!raw) {
let encoder = new TextEncoder();
let same = contents.slice(0, offset);
let different = contents.slice(offset);
offset = encoder.encode(same).byteLength;
contents = encoder.encode(different);
} else if (offset > 0) {
contents = contents.slice(offset);
}

return await this._fileops.writeFile(path, contents, offset, modificationTime, raw);
}

async makeDir(path, modificationTime = Date.now()) {
await this._checkConnection();
await this._checkWritable();

return await this._fileops.makeDir(path, modificationTime);
}

// Returns an array of objects, one object for each file or directory in the given path
async listDir(path) {
await this._checkConnection();
return await this._fileops.listDir(path);
}

// Deletes the file or directory at the given path. Directories must be empty.
async delete(path) {
await this._checkConnection();
await this._checkWritable();

return await this._fileops.delete(path);
}

// Moves the file or directory from oldPath to newPath.
async move(oldPath, newPath) {
await this._checkConnection();
await this._checkWritable();

return await this._fileops.move(oldPath, newPath);
}

async versionInfo() {
// Possibly open /boot_out.txt and read the version info
let versionInfo = {};
console.log("Reading version info");
let bootout = await this.readFile('/boot_out.txt', false);
console.log(bootout);
if (!bootout) {
return null;
}

// Add these items as they are found
const searchItems = {
version: /Adafruit CircuitPython (.*?) on/,
build_date: /on ([0-9]{4}-[0-9]{2}-[0-9]{2});/,
board_name: /; (.*?) with/,
mcu_name: /with (.*?)\r?\n/,
board_id: /Board ID:(.*?)\r?\n/,
uid: /UID:([0-9A-F]{12})\r?\n/,
}

for (const [key, regex] of Object.entries(searchItems)) {
const match = bootout.match(regex);

if (match) {
versionInfo[key] = match[1];
}
}

return versionInfo;
}
}

export {FileTransferClient};
9 changes: 4 additions & 5 deletions js/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { python } from "@codemirror/lang-python";
import { syntaxHighlighting, indentUnit } from "@codemirror/language";
import { classHighlighter } from "@lezer/highlight";

import { Terminal } from 'xterm';
import { FitAddon } from 'xterm-addon-fit';
import { WebLinksAddon } from 'xterm-addon-web-links';
import { Terminal } from '@xterm/xterm';
import { FitAddon } from '@xterm/addon-fit';
import { WebLinksAddon } from '@xterm/addon-web-links';

import state from './state.js'
import { BLEWorkflow } from './workflows/ble.js';
Expand Down Expand Up @@ -443,15 +443,14 @@ async function saveFileContents(path) {
let oldUnchanged = unchanged;
unchanged = doc.length;
try {
console.log("write");
if (await workflow.writeFile(path, contents, offset)) {
setFilename(workflow.currentFilename);
setSaved(true);
} else {
await showMessage(`Saving file '${workflow.currentFilename} failed.`);
}
} catch (e) {
console.log("write failed", e, e.stack);
console.error("write failed", e, e.stack);
unchanged = Math.min(oldUnchanged, unchanged);
if (currentTimeout != null) {
clearTimeout(currentTimeout);
Expand Down
2 changes: 1 addition & 1 deletion js/workflows/ble.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* This class will encapsulate all of the workflow functions specific to BLE
*/

import {FileTransferClient} from 'ble-file-transfer-js';
import {FileTransferClient} from '@adafruit/ble-file-transfer-js';

import {CONNTYPE, CONNSTATE} from '../constants.js';
import {Workflow} from './workflow.js';
Expand Down
Loading

0 comments on commit 7cc4f1f

Please sign in to comment.