possible file transfer

This commit is contained in:
2025-11-29 22:54:40 +00:00
parent 836e0f70aa
commit 5762bcb549
4 changed files with 284 additions and 38 deletions

View File

@@ -2,10 +2,10 @@
import { parseXml, XmlDocument, XmlElement, XmlText } from "@rgrove/parse-xml";
export type versionNotes = {
title: string;
date: Date | string;
link: string;
html: string;
title: string;
date: Date | string;
link: string;
html: string;
}
export default class Updater {
@@ -17,17 +17,24 @@ export default class Updater {
private readonly _updaterServiceUUID: string = "71a4438e-fd52-4b15-b3d2-ec0e3e561900";
private readonly _updaterVersionCharactersiticUUID: string = "71a4438e-fd52-4b15-b3d2-ec0e3e561910";
private readonly _updaterCommandCharacterisitcUUID: string = "71a4438e-fd52-4b15-b3d2-ec0e3e561920";
private readonly _updateFileCharacteristicUUID: string = "71a4438e-fd52-4b15-b3d2-ec0e3e561930";
public file: Int8Array;
private _fileSize: number;
private _fileProgress: number = 0;
private _packetSize: number;
constructor(archiveURL: string = "/", feedType: string = "atom", bleObject?: BLECentralPlugin.BLECentralPluginStatic) {
constructor(archiveURL: string = "/", feedType: string = "atom", bleObject?: BLECentralPlugin.BLECentralPluginStatic, packetSize: number = 512) {
this.archiveURL = archiveURL;
this.feedType = feedType;
if (bleObject) {
this.bleObject = bleObject;
}
this._packetSize = packetSize;
}
/*
FEEDS
*/
@@ -42,7 +49,7 @@ export default class Updater {
// atom feeds
private atomGetVersionDetails(entry: XmlElement): versionNotes {
let outEntry: versionNotes = {title: "", date: new Date, link: "", html: ""};
let outEntry: versionNotes = { title: "", date: new Date, link: "", html: "" };
entry.children.forEach((elm) => {
let element = elm as XmlElement;
if (element.name == "title") {
@@ -54,7 +61,7 @@ export default class Updater {
else if (element.name == "link") {
outEntry.link = element.attributes["href"];
} else if (element.name == "content") {
outEntry.html = (element.children[0] as XmlText).text;
outEntry.html = (element.children[0] as XmlText).text;
}
})
@@ -80,7 +87,7 @@ export default class Updater {
// rss feeds
private rssGetVersionDetails(entry: XmlElement): versionNotes {
let outEntry: versionNotes = {title: "", date: new Date, link: "", html: ""};
let outEntry: versionNotes = { title: "", date: new Date, link: "", html: "" };
entry.children.forEach((elm) => {
let element = elm as XmlElement;
if (element.name == "title") {
@@ -92,7 +99,7 @@ export default class Updater {
else if (element.name == "link") {
outEntry.link = (element.children[0] as XmlText).text;
} else if (element.name == "content") {
outEntry.html = (element.children[0] as XmlText).text;
outEntry.html = (element.children[0] as XmlText).text;
}
})
@@ -114,11 +121,11 @@ export default class Updater {
})
return output;
}
public async getArchive(): Promise<versionNotes[]> {
if (this.feedType == "atom") {
return this.atomGetArchive()
} else if (this.feedType == "rss"){
} else if (this.feedType == "rss") {
return this.rssGetArchive()
}
}
@@ -138,16 +145,17 @@ export default class Updater {
private async readVersionNumber(): Promise<string> {
return new Promise((resolve, reject) => {
this.bleObject.read(
this.bleDeviceId,
this._updaterServiceUUID,
this._updaterVersionCharactersiticUUID,
(rawData: ArrayBuffer) => {
resolve(this.bytesToString(rawData));
},
(error: string) => {
reject(`Error: ${error}`);
}
)});
this.bleDeviceId,
this._updaterServiceUUID,
this._updaterVersionCharactersiticUUID,
(rawData: ArrayBuffer) => {
resolve(this.bytesToString(rawData));
},
(error: string) => {
reject(`Error: ${error}`);
}
)
});
}
private async getLatestVersion(): Promise<string> {
@@ -169,7 +177,7 @@ export default class Updater {
// compare with latest version
const latestVersion = await this.getLatestVersion();
if (deviceVersion != latestVersion) {
return true;
return true;
}
// update
return false;
@@ -178,7 +186,7 @@ export default class Updater {
public async getBoardVersion(): Promise<string> {
return await this.readVersionNumber();
}
/*
FILE FLASHING
*/
@@ -188,6 +196,7 @@ export default class Updater {
const res = await fetch(`http://cors.emaker.limited/?url=${this.archiveURL}/download/${version.title}/firmware.bin`);
let buf = await res.arrayBuffer();
this.file = new Int8Array(buf);
this._fileSize = this.file.byteLength;
return true;
} catch {
return false;
@@ -195,11 +204,86 @@ export default class Updater {
}
public getFileSize(): number {
return this.file.byteLength;
return this._fileSize;
}
// public async flashFirmware(): Promise<boolean> {
// }
private async sendNextPacket(): Promise<boolean> {
let packet = this.file.slice(this._fileProgress, this._fileProgress+this._packetSize);
return new Promise((resolve, reject) => {
this.bleObject.write(this.bleDeviceId, this._updaterServiceUUID, this._updateFileCharacteristicUUID, packet.buffer,
() => {
resolve(true);
},
(error) => {
reject(error);
}
)
});
}
private async sendEndCmd(agree: boolean): Promise<void> {
const buffer = new ArrayBuffer(1);
let view = new Int8Array(buffer);
view[0] = agree ? 3 : 4;
await this.bleObject.withPromises.write(this.bleDeviceId, this._updaterServiceUUID, this._updaterCommandCharacterisitcUUID, buffer);
return;
}
// start and autoconnect before you run this function, so that you can have an "uninterrupted" connection when the board reboots
public async flashFirmware(progressCallback: (message: string) => void): Promise<boolean> {
// write filesize to board
// await notify from cmd - ready
// send a packet
// check for error
// write file length
return new Promise(async (resolve, reject) => {
const buffer = new ArrayBuffer(4)
let view = new Int32Array(buffer);
view[0] = this._fileSize;
await this.bleObject.withPromises.write(this.bleDeviceId, this._updaterServiceUUID, this._updaterCommandCharacterisitcUUID, buffer);
// start notify
this.bleObject.startNotification(this.bleDeviceId, this._updaterServiceUUID, this._updaterCommandCharacterisitcUUID,
async (rawData: ArrayBuffer): Promise<void> => {
let dataView = new Int8Array(rawData);
if (dataView[0] == 1) {
// send file
await this.sendNextPacket();
progressCallback(`Sending (${Math.floor((this._fileProgress *100)/this._fileSize)})`);
} else if (dataView[0] == 2) {
// done logic
if (this._fileProgress >= this._fileSize) {
// send agree
await this.sendEndCmd(true);
progressCallback(`Complete!`);
this.bleObject.stopNotification(this.bleDeviceId,
this._updaterServiceUUID, this._updaterCommandCharacterisitcUUID,
() => {
// success
resolve(true);
},
(error) => {
reject("Error: Failed to stop notify");
}
);
} else {
// send disagree
await this.sendEndCmd(false);
progressCallback(`Error, starting over`);
this._fileProgress = 0;
}
} else if (dataView[0] == 15) {
// error cmd
progressCallback(`Error on remote`);
reject("Error on remote");
} else {
// no command
progressCallback(`Error on remote`);
reject("Error: command does not exist");
}
}, () => { reject("Error: Failed to start notify"); });
});
}
}