diff --git a/n-link-core/components/CalcInfo.vue b/n-link-core/components/CalcInfo.vue
index f30684a..898cc86 100644
--- a/n-link-core/components/CalcInfo.vue
+++ b/n-link-core/components/CalcInfo.vue
@@ -36,6 +36,10 @@
+
@@ -73,6 +77,10 @@ export default class FileView extends Vue {
const file = e.target.files?.[0];
if (file) this.$devices.uploadOsFile(this.dev, file);
}
+
+ copyLogs() {
+ navigator.clipboard.writeText(this.$devices.devices[this.dev].log).catch(alert);
+ }
}
diff --git a/web/components/devices.ts b/web/components/devices.ts
index 21bbeba..3773f0e 100644
--- a/web/components/devices.ts
+++ b/web/components/devices.ts
@@ -11,8 +11,6 @@ const PID = 0xe012;
/// The USB vendor ID used by all CX II calculators.
const PID_CX2 = 0xe022;
-async function promisified(...a: any[]): Promise {
-}
type WorkerExt = Worker & { rpc: RpcProvider };
export type Device = {
@@ -25,6 +23,7 @@ export type Device = {
progress?: Progress;
queue?: Cmd[];
running?: boolean;
+ log: string;
};
async function downloadFile(
@@ -178,6 +177,7 @@ class Devices extends Vue implements GenericDevices {
name: device.productName,
isCxIi: device.productId === PID_CX2,
needsDrivers: false,
+ log: '',
} as Device);
} catch (e) {
console.error(e);
@@ -189,7 +189,10 @@ class Devices extends Vue implements GenericDevices {
await device.open();
const worker: Worker & Partial = new UsbWorker();
const sab = new SharedArrayBuffer(10000);
- const compat = new UsbCompat(sab);
+ const writeMessage = (messages: any[]) => {
+ this.devices[dev].log += messages.map(message => ['string', 'number'].includes(typeof message) ? message : JSON.stringify(message)).join(' ') + '\n';
+ };
+ const compat = new UsbCompat(sab, writeMessage);
const id = compat.addDevice(device);
const rpc = new RpcProvider((message, transfer: any) =>
worker.postMessage(message, transfer)
@@ -203,6 +206,10 @@ class Devices extends Vue implements GenericDevices {
}
rpc.dispatch(data);
};
+ rpc.registerSignalHandler('log', (messages: any[]) => {
+ console.log(messages.join(' '));
+ writeMessage(messages);
+ });
this.$set(this.devices[dev], 'worker', worker as WorkerExt);
await rpc.rpc('init', {id, sab, vid: device.vendorId, pid: device.productId});
diff --git a/web/components/impl.ts b/web/components/impl.ts
index 97dd7a3..9f7e1ab 100644
--- a/web/components/impl.ts
+++ b/web/components/impl.ts
@@ -85,9 +85,11 @@ let count = 0;
export default class UsbCompat {
devices: Record = {};
arr: SharedArrayBuffer;
+ log: (data: any[]) => void;
- constructor(arr: SharedArrayBuffer) {
+ constructor(arr: SharedArrayBuffer, log: (data: any[]) => void) {
this.arr = arr;
+ this.log = log;
}
addDevice(dev: USBDevice) {
@@ -154,8 +156,10 @@ export default class UsbCompat {
}
async processCmd(cmd: Cmd) {
+ this.log(['in:', cmd]);
console.log(cmd);
const msg = await this._processCmd(cmd);
+ this.log(['out:', msg]);
console.log(msg);
const encoded = encoder.encode(msg);
diff --git a/web/components/usb.worker.ts b/web/components/usb.worker.ts
index 24fe9ca..e9f5017 100644
--- a/web/components/usb.worker.ts
+++ b/web/components/usb.worker.ts
@@ -4,7 +4,6 @@ import { RpcProvider } from 'worker-rpc';
// eslint-disable-next-line import/no-absolute-path
import type { Calculator } from 'web-libnspire';
-console.log('worker!');
const ctx: Worker = self as any;
const module = import('@/web-libusb/web-libnspire/pkg');
let calc: Calculator | undefined;
@@ -13,6 +12,13 @@ const rpcProvider = new RpcProvider((message, transfer: any) =>
);
ctx.onmessage = (e) => rpcProvider.dispatch(e.data);
+const origLog = console.log;
+console.log = (...args: any[]) => {
+ origLog(...args);
+ rpcProvider.signal('log', args);
+};
+
+console.log('worker!');
type Path = { path: string };
type Data = { data: Uint8Array };
type SrcDest = { src: string; dest: string };