feat(core): 优化在线版下ampy和kflash的进度显示
This commit is contained in:
@@ -98,6 +98,44 @@ class EditorAce extends EditorBase {
|
||||
}
|
||||
}
|
||||
|
||||
replaceLine(lineNumber, newContent) {
|
||||
const session = this.#editor_.getSession();
|
||||
const totalLines = session.getLength();
|
||||
let targetLine = lineNumber < 0 ? totalLines + lineNumber : lineNumber;
|
||||
if (targetLine < 0) {
|
||||
targetLine = 0;
|
||||
} else if (targetLine >= totalLines) {
|
||||
targetLine = totalLines - 1;
|
||||
}
|
||||
const cursorPos = this.#editor_.getCursorPosition();
|
||||
const oldLine = session.getLine(targetLine);
|
||||
const range = new ace.Range(targetLine, 0, targetLine, oldLine.length);
|
||||
session.replace(range, newContent);
|
||||
if (cursorPos.row > targetLine) {
|
||||
this.#editor_.moveCursorTo(cursorPos.row, cursorPos.column);
|
||||
} else if (cursorPos.row === targetLine) {
|
||||
const newCol = Math.min(cursorPos.column, newContent.length);
|
||||
this.#editor_.moveCursorTo(targetLine, newCol);
|
||||
} else {
|
||||
this.#editor_.moveCursorTo(cursorPos.row, cursorPos.column);
|
||||
}
|
||||
this.#editor_.renderer.scrollCursorIntoView(null, 0.5);
|
||||
}
|
||||
|
||||
appendLine(text) {
|
||||
const session = this.#editor_.getSession();
|
||||
const totalLines = session.getLength();
|
||||
const lastLineIndex = totalLines - 1;
|
||||
const lastLineText = session.getLine(lastLineIndex);
|
||||
if (lastLineText.trim()) {
|
||||
session.insert({ row: totalLines, column: 0 }, `\n${text}`);
|
||||
} else {
|
||||
const range = new ace.Range(lastLineIndex, 0, lastLineIndex, lastLineText.length);
|
||||
session.replace(range, text);
|
||||
}
|
||||
this.scrollToBottom();
|
||||
}
|
||||
|
||||
getValue() {
|
||||
return this.#destroyed_ ? '' : this.#editor_.getValue();
|
||||
}
|
||||
|
||||
@@ -1560,6 +1560,7 @@
|
||||
"path",
|
||||
"Mustache",
|
||||
"Mixly.Env",
|
||||
"Mixly.Events",
|
||||
"Mixly.Msg",
|
||||
"Mixly.Ampy",
|
||||
"Mixly.Web"
|
||||
|
||||
@@ -3,6 +3,7 @@ goog.loadJs('web', () => {
|
||||
goog.require('path');
|
||||
goog.require('Mustache');
|
||||
goog.require('Mixly.Env');
|
||||
goog.require('Mixly.Events');
|
||||
goog.require('Mixly.Msg');
|
||||
goog.require('Mixly.Ampy');
|
||||
goog.require('Mixly.Web');
|
||||
@@ -10,6 +11,7 @@ goog.provide('Mixly.Web.Ampy');
|
||||
|
||||
const {
|
||||
Env,
|
||||
Events,
|
||||
Msg,
|
||||
Ampy,
|
||||
Web
|
||||
@@ -37,6 +39,7 @@ class AmpyExt extends Ampy {
|
||||
#writeBuffer_ = true;
|
||||
#active_ = false;
|
||||
#dataLength_ = 256;
|
||||
#events_ = new Events(['message', 'replaceMessage'])
|
||||
constructor(device, writeBuffer = true, dataLength = 256) {
|
||||
super();
|
||||
this.#device_ = device;
|
||||
@@ -56,6 +59,25 @@ class AmpyExt extends Ampy {
|
||||
});
|
||||
}
|
||||
|
||||
bind(...args) {
|
||||
return this.#events_.bind(...args);
|
||||
}
|
||||
|
||||
message(message) {
|
||||
this.#events_.run('message', message);
|
||||
}
|
||||
|
||||
replaceMessage(lineNumber, message) {
|
||||
this.#events_.run('replaceMessage', lineNumber, message);
|
||||
}
|
||||
|
||||
getProgressMessage(name, percent) {
|
||||
const sended = parseInt(percent * 45);
|
||||
const left = percent === 0 ? '' : Array(sended).fill('=').join('');
|
||||
const right = percent === 100 ? '' : Array(45 - sended).fill('-').join('');
|
||||
return `${name} → |${left}${right}| ${(percent * 100).toFixed(1)}%`;
|
||||
}
|
||||
|
||||
isActive() {
|
||||
return this.#active_;
|
||||
}
|
||||
@@ -235,6 +257,8 @@ class AmpyExt extends Ampy {
|
||||
if (!this.isActive()) {
|
||||
throw new Error(Msg.Lang['ampy.portIsNotOpen']);
|
||||
}
|
||||
this.message(`Writing ${filename}...\n`);
|
||||
this.message(this.getProgressMessage('', 0));
|
||||
await this.exec(`file = open('${filename}', 'wb')`, timeout);
|
||||
let buffer = null;
|
||||
if (data.constructor === String) {
|
||||
@@ -245,8 +269,15 @@ class AmpyExt extends Ampy {
|
||||
buffer = data;
|
||||
}
|
||||
const len = Math.ceil(buffer.length / 64);
|
||||
if (!len) {
|
||||
this.replaceMessage(-1, this.getProgressMessage('', 1));
|
||||
}
|
||||
let sendedLength = 0;
|
||||
for (let i = 0; i < len; i++) {
|
||||
const writeBuffer = buffer.slice(i * 64, Math.min((i + 1) * 64, buffer.length));
|
||||
sendedLength += writeBuffer.length;
|
||||
const percent = sendedLength / buffer.length;
|
||||
this.replaceMessage(-1, this.getProgressMessage('', percent));
|
||||
let writeStr = '';
|
||||
for (let num of writeBuffer) {
|
||||
let numStr = num.toString(16);
|
||||
@@ -258,6 +289,7 @@ class AmpyExt extends Ampy {
|
||||
await this.exec(`file.write(b'${writeStr}')`, timeout);
|
||||
}
|
||||
await this.exec('file.close()', timeout);
|
||||
this.message('\n');
|
||||
}
|
||||
|
||||
async ls(directory = '/', longFormat = true, recursive = false, timeout = 5000) {
|
||||
@@ -387,6 +419,8 @@ class AmpyExt extends Ampy {
|
||||
this.#active_ = false;
|
||||
await this.#device_.dispose();
|
||||
this.#device_ = null;
|
||||
this.#events_.reset();
|
||||
this.#events_ = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -418,9 +418,7 @@ BU.burnWithKFlash = async (binFile, erase) => {
|
||||
mainStatusBarTabs.changeTo('output');
|
||||
BU.progressLayer.title(`${Msg.Lang['shell.burning']}...`);
|
||||
BU.progressLayer.show();
|
||||
statusBarTerminal.addValue(Msg.Lang['shell.bin.reading'] + "...");
|
||||
statusBarTerminal.addValue("\n");
|
||||
|
||||
|
||||
let data = [];
|
||||
try {
|
||||
for (let i of binFile) {
|
||||
@@ -437,30 +435,32 @@ BU.burnWithKFlash = async (binFile, erase) => {
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
statusBarTerminal.addValue("Failed!\n" + Msg.Lang['shell.bin.readFailed'] + "!\n");
|
||||
statusBarTerminal.addValue("\n" + error + "\n", true);
|
||||
statusBarTerminal.addValue(`\n[ERROR] ${error}\n`, true);
|
||||
BU.progressLayer.hide();
|
||||
statusBarTerminal.addValue(`==${Msg.Lang['shell.burnFailed']}==\n`);
|
||||
return;
|
||||
}
|
||||
statusBarTerminal.addValue("Done!\n");
|
||||
let serial = null;
|
||||
try {
|
||||
serial = new Serial(portName);
|
||||
const kflash = new KFlash(serial, (message) => {
|
||||
const kflash = new KFlash(serial);
|
||||
kflash.bind('message', (message) => {
|
||||
statusBarTerminal.addValue(message);
|
||||
});
|
||||
kflash.bind('replaceMessage', (lineNumber, message) => {
|
||||
statusBarTerminal.replaceLine(lineNumber, message);
|
||||
});
|
||||
await kflash.enter();
|
||||
for (let item of data) {
|
||||
await kflash.write(item.data, item.address, item.sha256Prefix ?? true, item?.filename ?? 'main.bin');
|
||||
}
|
||||
BU.progressLayer.hide();
|
||||
layer.msg(Msg.Lang['shell.burnSucc'], { time: 1000 });
|
||||
statusBarTerminal.addValue(`==${Msg.Lang['shell.burnSucc']}==\n`);
|
||||
statusBarTerminal.appendLine(`==${Msg.Lang['shell.burnSucc']}==\n`);
|
||||
} catch (error) {
|
||||
statusBarTerminal.addValue(`[ERROR] ${error.message}\n`);
|
||||
statusBarTerminal.appendLine(`[ERROR] ${error.message}\n`);
|
||||
BU.progressLayer.hide();
|
||||
statusBarTerminal.addValue(`==${Msg.Lang['shell.burnFailed']}==\n`);
|
||||
statusBarTerminal.appendLine(`==${Msg.Lang['shell.burnFailed']}==\n`);
|
||||
} finally {
|
||||
try {
|
||||
serial && await serial.close();
|
||||
@@ -640,7 +640,7 @@ BU.uploadWithAmpy = async (portName) => {
|
||||
let statusBarSerial = mainStatusBarTabs.getStatusBarById(portName);
|
||||
BU.burning = false;
|
||||
BU.uploading = true;
|
||||
statusBarTerminal.setValue(Msg.Lang['shell.uploading'] + '...\n');
|
||||
statusBarTerminal.setValue(`${Msg.Lang['shell.uploading']}...\n`);
|
||||
mainStatusBarTabs.show();
|
||||
mainStatusBarTabs.changeTo('output');
|
||||
const mainWorkspace = Workspace.getMain();
|
||||
@@ -650,12 +650,21 @@ BU.uploadWithAmpy = async (portName) => {
|
||||
BU.progressLayer.show();
|
||||
const serial = new Serial(portName);
|
||||
const ampy = new Ampy(serial);
|
||||
ampy.bind('message', (message) => {
|
||||
statusBarTerminal.addValue(message);
|
||||
});
|
||||
ampy.bind('replaceMessage', (lineNumber, message) => {
|
||||
statusBarTerminal.replaceLine(lineNumber, message);
|
||||
});
|
||||
const code = editor.getCode();
|
||||
let closePromise = Promise.resolve();
|
||||
if (statusBarSerial) {
|
||||
closePromise = statusBarSerial.close();
|
||||
}
|
||||
try {
|
||||
await closePromise;
|
||||
await ampy.enter();
|
||||
await ampy.put('main.py', code);
|
||||
/*const importsMap = BU.getImportModules(code);
|
||||
let libraries = {};
|
||||
for (let key in importsMap) {
|
||||
@@ -665,13 +674,8 @@ BU.uploadWithAmpy = async (portName) => {
|
||||
data,
|
||||
size: importsMap[key]['__size__']
|
||||
};
|
||||
}*/
|
||||
await closePromise;
|
||||
await ampy.enter();
|
||||
statusBarTerminal.addValue('Writing main.py ');
|
||||
await ampy.put('main.py', code);
|
||||
statusBarTerminal.addValue('Done!\n');
|
||||
/*const cwd = await ampy.cwd();
|
||||
}
|
||||
let cwd = await ampy.cwd();
|
||||
const rootInfo = await ampy.ls(cwd);
|
||||
let rootMap = {};
|
||||
for (let item of rootInfo) {
|
||||
@@ -683,19 +687,17 @@ BU.uploadWithAmpy = async (portName) => {
|
||||
if (libraries && libraries instanceof Object) {
|
||||
for (let key in libraries) {
|
||||
if (rootMap[`${cwd}/${key}`] !== undefined && rootMap[`${cwd}/${key}`] === libraries[key].size) {
|
||||
statusBarTerminal.addValue(`Skip ${key}\n`);
|
||||
statusBarTerminal.addValue(`Writing ${key} (Skipped)\n`);
|
||||
continue;
|
||||
}
|
||||
statusBarTerminal.addValue(`Writing ${key} `);
|
||||
await ampy.put(key, libraries[key].data);
|
||||
statusBarTerminal.addValue('Done!\n');
|
||||
}
|
||||
}*/
|
||||
await ampy.exit();
|
||||
await ampy.dispose();
|
||||
BU.progressLayer.hide();
|
||||
layer.msg(Msg.Lang['shell.uploadSucc'], { time: 1000 });
|
||||
statusBarTerminal.addValue(`==${Msg.Lang['shell.uploadSucc']}==\n`);
|
||||
statusBarTerminal.appendLine(`==${Msg.Lang['shell.uploadSucc']}==\n`);
|
||||
if (!statusBarSerial) {
|
||||
mainStatusBarTabs.add('serial', portName);
|
||||
statusBarSerial = mainStatusBarTabs.getStatusBarById(portName);
|
||||
@@ -707,8 +709,8 @@ BU.uploadWithAmpy = async (portName) => {
|
||||
ampy.dispose();
|
||||
BU.progressLayer.hide();
|
||||
Debug.error(error);
|
||||
statusBarTerminal.addValue(`${error}\n`);
|
||||
statusBarTerminal.addValue(`==${Msg.Lang['shell.uploadFailed']}==\n`);
|
||||
statusBarTerminal.appendLine(`[ERROR] ${error.message}\n`);
|
||||
statusBarTerminal.appendLine(`==${Msg.Lang['shell.uploadFailed']}==\n`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ class MAIXLoader {
|
||||
|
||||
#port_ = null;
|
||||
#readedBuffer_ = [];
|
||||
#events_ = new Events('message');
|
||||
#events_ = new Events(['message', 'replaceMessage']);
|
||||
|
||||
constructor(port) {
|
||||
this.#port_ = port;
|
||||
@@ -117,6 +117,10 @@ class MAIXLoader {
|
||||
this.#events_.run('message', message);
|
||||
}
|
||||
|
||||
replaceMessage(lineNumber, message) {
|
||||
this.#events_.run('replaceMessage', lineNumber, message);
|
||||
}
|
||||
|
||||
async write(packet) {
|
||||
let handlePacket = [];
|
||||
|
||||
@@ -251,9 +255,9 @@ class MAIXLoader {
|
||||
|
||||
getProgressMessage(name, percent) {
|
||||
const sended = parseInt(percent * 45);
|
||||
const left = Array(sended).fill('=').join('');
|
||||
const right = Array(45 - sended).fill('-').join('');
|
||||
return `${name}: |${left}${right}| ${(percent * 100).toFixed(1)}%\n\n`;
|
||||
const left = percent === 0 ? '' : Array(sended).fill('=').join('');
|
||||
const right = percent === 100 ? '' : Array(45 - sended).fill('-').join('');
|
||||
return `${name}: |${left}${right}| ${(percent * 100).toFixed(1)}%`;
|
||||
}
|
||||
|
||||
async flashDataFrame(data, address = 0x80000000) {
|
||||
@@ -261,6 +265,7 @@ class MAIXLoader {
|
||||
const dataLength = data.length;
|
||||
let sendedLength = 0;
|
||||
const len = Math.ceil(dataLength / this.DATAFRAME_SIZE);
|
||||
this.message('\n');
|
||||
for (let i = 0; i < len; i++) {
|
||||
let start = i * this.DATAFRAME_SIZE;
|
||||
let end = Math.min(start + this.DATAFRAME_SIZE, dataLength);
|
||||
@@ -286,12 +291,18 @@ class MAIXLoader {
|
||||
await this.write(packet);
|
||||
if (await this.recvDebug()) {
|
||||
sendedLength += chunk.length;
|
||||
this.message(this.getProgressMessage('Downloading ISP', sendedLength / dataLength));
|
||||
const message = this.getProgressMessage('Downloading ISP', sendedLength / dataLength);
|
||||
if (i > 0) {
|
||||
this.replaceMessage(-1, message);
|
||||
} else {
|
||||
this.message(message);
|
||||
}
|
||||
address += this.DATAFRAME_SIZE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.message('\n\n');
|
||||
}
|
||||
|
||||
async installFlashBootloader(data) {
|
||||
@@ -390,7 +401,7 @@ class MAIXLoader {
|
||||
}
|
||||
|
||||
async flashFirmware(firmware, aesKey = null, address = 0, sha256Prefix = true, filename = '') {
|
||||
this.message(`[INFO] Writing ${filename} into ${this.formatHex(address)}\n\n`);
|
||||
this.message(`[INFO] Writing ${filename} into ${this.formatHex(address)}\n`);
|
||||
let firmwareBin = Array.from(new Uint8Array(firmware));
|
||||
if (sha256Prefix) {
|
||||
const aesCipherFlag = 0x00;
|
||||
@@ -432,18 +443,25 @@ class MAIXLoader {
|
||||
await this.write(packet);
|
||||
if (await this.recvDebug()) {
|
||||
sendedLength += chunkLength;
|
||||
this.message(this.getProgressMessage('Programming BIN', sendedLength / dataLength));
|
||||
const message = this.getProgressMessage('Programming BIN', sendedLength / dataLength);
|
||||
if (i > 0) {
|
||||
this.replaceMessage(-1, message);
|
||||
} else {
|
||||
this.message(`\n${message}`);
|
||||
}
|
||||
address += this.ISP_FLASH_DATA_FRAME_SIZE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.message('\n\n');
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this.#port_ = null;
|
||||
this.#events_.reset();
|
||||
this.#events_ = null;
|
||||
this.#readedBuffer_ = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,10 +469,13 @@ class KFlash {
|
||||
#port_ = null;
|
||||
#loader_ = null;
|
||||
|
||||
constructor(port, messageCallback) {
|
||||
constructor(port) {
|
||||
this.#port_ = port;
|
||||
this.#loader_ = new MAIXLoader(port);
|
||||
this.#loader_.bind('message', messageCallback);
|
||||
}
|
||||
|
||||
bind(...args) {
|
||||
return this.#loader_.bind(...args);
|
||||
}
|
||||
|
||||
async enter() {
|
||||
@@ -462,7 +483,7 @@ class KFlash {
|
||||
}
|
||||
|
||||
async write(firmware, address = 0x0, sha256Prefix = true, filename = '') {
|
||||
this.#loader_.message('[INFO] Trying to Enter the ISP Mode...\n');
|
||||
this.#loader_.message('[INFO] Trying to Enter the ISP Mode...');
|
||||
let retryCount = 0;
|
||||
while (true) {
|
||||
try {
|
||||
@@ -500,6 +521,7 @@ class KFlash {
|
||||
|
||||
dispose() {
|
||||
this.#loader_.dispose();
|
||||
this.#loader_ = null;
|
||||
this.#port_ = null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user