From 7e5c8be4537c9479334935089a71623bca89f3e3 Mon Sep 17 00:00:00 2001 From: Yaya-Cout Date: Sat, 14 Jun 2025 10:57:23 +0200 Subject: [PATCH 1/5] Fix corrupted slotInfo magik handling --- Numworks.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Numworks.js b/Numworks.js index 77df5a1..1e25bf7 100644 --- a/Numworks.js +++ b/Numworks.js @@ -376,7 +376,7 @@ class Numworks { } if (!magikFound) { data["magik"] = false; - console.warn("No usermand magic") + console.warn("No userland magic") return data } @@ -516,7 +516,7 @@ class Numworks { const magik = 0xBADBEEEF; // Hack to handle corrupted slotInfo magik on old Upsilon Bootloader versions (pre 1.0.13) - data["slot"]["magik"] = (dv.getUint32(0x00, false) == magik) || (data["slot"]["magik"] = dv.getUint24(0x01, false) == 0xDBEEEF08); + data["slot"]["magik"] = (dv.getUint32(0x00, false) == magik) || ((dv.getUint32(0x00, false) & 0x00FFFFFF) == (magik & 0x00FFFFFF)); // Check if the data is valid if (data["slot"]["magik"]) { // Check if the end magic is present From 7a0c2e33366152f3e8812ab9c58fd1b741592ba8 Mon Sep 17 00:00:00 2001 From: Yaya-Cout Date: Sat, 14 Jun 2025 13:04:45 +0200 Subject: [PATCH 2/5] [Storage] Handle UTF-8 scripts --- Storage.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Storage.js b/Storage.js index 9712f78..b22423f 100644 --- a/Storage.js +++ b/Storage.js @@ -14,7 +14,7 @@ class Storage { } async __encodePyRecord(record) { - var content = new TextEncoder("utf-8").encode(record.code); + var content = new TextEncoder("utf-8").encode(record.code.normalize('NFKD')); record.data = new Blob([ concatTypedArrays( @@ -48,7 +48,9 @@ class Storage { var name = record.name + "." + record.type; var encoded_name = concatTypedArrays( - encoder.encode(name), + // We remove non-ASCII characters as they often cause calculator crashs + // Upsilon.js don't support reading non-ASCII filenames + encoder.encode(name.replace(/[^\x00-\x7F]/g, "")), new Uint8Array([0]) ); @@ -165,7 +167,9 @@ class Storage { var dv = new DataView(await record.data.arrayBuffer()); record.autoImport = dv.getUint8(0) !== 0; - record.code = this.__readString(dv, 1, record.data.size - 1).content; + + var codeDataview = new DataView(await record.data.slice(1, record.data.size - 1).arrayBuffer()); + record.code = new TextDecoder("utf-8").decode(codeDataview); delete record.data; From 9cc867fed3aa5027dee09eafa54178fe3d4b1ccb Mon Sep 17 00:00:00 2001 From: Yaya-Cout Date: Sat, 14 Jun 2025 13:06:05 +0200 Subject: [PATCH 3/5] [Package] Update version to 1.5.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b6b81a6..c7fd356 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "upsilon.js", - "version": "1.4.2", + "version": "1.5.0", "description": "Utility classes to interact with a Numworks calculator using WebUSB.", "main": "index.js", "scripts": { From a3533faf719d5b5369be3619ff44a2b66f1ca7d8 Mon Sep 17 00:00:00 2001 From: Yaya-Cout Date: Thu, 7 Aug 2025 13:51:44 +0200 Subject: [PATCH 4/5] Fix Epsilon 24.2.1 installStorage not working --- Numworks.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Numworks.js b/Numworks.js index 1e25bf7..30b962d 100644 --- a/Numworks.js +++ b/Numworks.js @@ -679,7 +679,12 @@ class Numworks { */ async __retrieveStorage(address, size) { this.device.startAddress = address; - return await this.device.do_upload(this.transferSize, size + 8); + + await this.device.device_.selectAlternateInterface(this.device.intfNumber, 1); + let data = await this.device.do_upload(this.transferSize, size + 8); + await this.device.device_.selectAlternateInterface(this.device.intfNumber, 0); + + return data } /** @@ -690,7 +695,10 @@ class Numworks { */ async __flashStorage(address, data) { this.device.startAddress = address; + + await this.device.device_.selectAlternateInterface(this.device.intfNumber, 1); await this.device.do_download(this.transferSize, data, false); + await this.device.device_.selectAlternateInterface(this.device.intfNumber, 0); } /** From 3493f56bf5bf756c85f4f9ba87b77ec3dd44a561 Mon Sep 17 00:00:00 2001 From: Yaya-Cout Date: Fri, 8 Aug 2025 11:52:32 +0200 Subject: [PATCH 5/5] Only set alternate interface starting with Epsilon 24.2.0 --- Numworks.js | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/Numworks.js b/Numworks.js index 30b962d..260850e 100644 --- a/Numworks.js +++ b/Numworks.js @@ -674,15 +674,21 @@ class Numworks { * * @param address Storage address * @param size Storage size. + * @param version Calculator version * * @return The storage, as a Blob. */ - async __retrieveStorage(address, size) { - this.device.startAddress = address; + async __retrieveStorage(address, size, version) { + if (version >= "24.2.0") { + await this.device.device_.selectAlternateInterface(this.device.intfNumber, 1); + } - await this.device.device_.selectAlternateInterface(this.device.intfNumber, 1); + this.device.startAddress = address; let data = await this.device.do_upload(this.transferSize, size + 8); - await this.device.device_.selectAlternateInterface(this.device.intfNumber, 0); + + if (version >= "24.2.0") { + await this.device.device_.selectAlternateInterface(this.device.intfNumber, 0); + } return data } @@ -692,13 +698,19 @@ class Numworks { * * @param address Storage address * @param data Storage data. + * @param version Calculator version */ - async __flashStorage(address, data) { - this.device.startAddress = address; + async __flashStorage(address, data, version) { + if (version >= "24.2.0") { + await this.device.device_.selectAlternateInterface(this.device.intfNumber, 1); + } - await this.device.device_.selectAlternateInterface(this.device.intfNumber, 1); + this.device.startAddress = address; await this.device.do_download(this.transferSize, data, false); - await this.device.device_.selectAlternateInterface(this.device.intfNumber, 0); + + if (version >= "24.2.0") { + await this.device.device_.selectAlternateInterface(this.device.intfNumber, 0); + } } /** @@ -713,7 +725,7 @@ class Numworks { let pinfo = await this.getPlatformInfo(); let storage_blob = await storage.encodeStorage(pinfo["storage"]["size"]); - await this.__flashStorage(pinfo["storage"]["address"], await storage_blob.arrayBuffer()); + await this.__flashStorage(pinfo["storage"]["address"], await storage_blob.arrayBuffer(), pinfo["version"]); callback(); } @@ -726,7 +738,7 @@ class Numworks { async backupStorage() { let pinfo = await this.getPlatformInfo(); - let storage_blob = await this.__retrieveStorage(pinfo["storage"]["address"], pinfo["storage"]["size"]); + let storage_blob = await this.__retrieveStorage(pinfo["storage"]["address"], pinfo["storage"]["size"], pinfo["version"]); let storage = new Numworks.Storage();