740 lines
24 KiB
JavaScript
740 lines
24 KiB
JavaScript
goog.loadJs('web', () => {
|
||
|
||
goog.require('path');
|
||
goog.require('BoardId');
|
||
goog.require('FSWrapper');
|
||
goog.require('DAPWrapper');
|
||
goog.require('PartialFlashing');
|
||
goog.require('esptooljs');
|
||
goog.require('CryptoJS');
|
||
goog.require('JSZip');
|
||
goog.require('Mixly.Env');
|
||
goog.require('Mixly.LayerExt');
|
||
goog.require('Mixly.Config');
|
||
goog.require('Mixly.MFile');
|
||
goog.require('Mixly.Boards');
|
||
goog.require('Mixly.Msg');
|
||
goog.require('Mixly.Workspace');
|
||
goog.require('Mixly.Debug');
|
||
goog.require('Mixly.HTMLTemplate');
|
||
goog.require('Mixly.MString');
|
||
goog.require('Mixly.LayerFirmware');
|
||
goog.require('Mixly.LayerProgress');
|
||
goog.require('Mixly.Web.Serial');
|
||
goog.require('Mixly.Web.Ampy');
|
||
goog.require('Mixly.Web.KFlash');
|
||
goog.require('Mixly.Web.SerialTransport');
|
||
goog.provide('Mixly.Web.BU');
|
||
|
||
const {
|
||
Env,
|
||
Web,
|
||
LayerExt,
|
||
Config,
|
||
MFile,
|
||
Boards,
|
||
Msg,
|
||
Workspace,
|
||
Debug,
|
||
HTMLTemplate,
|
||
MString,
|
||
LayerFirmware,
|
||
LayerProgress
|
||
} = Mixly;
|
||
|
||
const {
|
||
Serial,
|
||
BU,
|
||
Ampy,
|
||
KFlash,
|
||
SerialTransport
|
||
} = Web;
|
||
|
||
const { BOARD, SELECTED_BOARD } = Config;
|
||
const { ESPLoader } = esptooljs;
|
||
|
||
|
||
BU.uploading = false;
|
||
BU.burning = false;
|
||
BU.firmwareLayer = new LayerFirmware({
|
||
width: 400,
|
||
title: Msg.Lang['nav.btn.burn'],
|
||
cancelValue: false,
|
||
skin: 'layui-anim layui-anim-scale',
|
||
cancel: false,
|
||
cancelDisplay: false
|
||
});
|
||
BU.firmwareLayer.bind('burn', (info) => {
|
||
const { web } = SELECTED_BOARD;
|
||
BU.burnWithEsptool(info, web.burn.erase);
|
||
});
|
||
BU.progressLayer = new LayerProgress({
|
||
width: 200,
|
||
cancelValue: false,
|
||
skin: 'layui-anim layui-anim-scale',
|
||
cancel: false,
|
||
cancelDisplay: false
|
||
});
|
||
|
||
if (['BBC micro:bit', 'Mithon CC'].includes(BOARD.boardType)) {
|
||
FSWrapper.setupFilesystem(path.join(Env.boardDirPath, 'build'));
|
||
}
|
||
|
||
BU.requestPort = async () => {
|
||
await Serial.requestPort();
|
||
}
|
||
|
||
const readBinFile = (path, offset) => {
|
||
return new Promise((resolve, reject) => {
|
||
fetch(path)
|
||
.then((response) => {
|
||
return response.blob();
|
||
})
|
||
.then((blob) => {
|
||
const reader = new FileReader();
|
||
reader.onload = function (event) {
|
||
resolve({
|
||
address: parseInt(offset),
|
||
data: event.target.result
|
||
});
|
||
};
|
||
reader.onerror = function (error) {
|
||
throw(error);
|
||
}
|
||
reader.readAsBinaryString(blob);
|
||
})
|
||
.catch((error) => {
|
||
reject(error);
|
||
});
|
||
});
|
||
}
|
||
|
||
const readBinFileAsArrayBuffer = (path, offset) => {
|
||
return new Promise((resolve, reject) => {
|
||
fetch(path)
|
||
.then((response) => {
|
||
return response.blob();
|
||
})
|
||
.then((blob) => {
|
||
const reader = new FileReader();
|
||
reader.onload = function (event) {
|
||
resolve({
|
||
address: parseInt(offset),
|
||
data: event.target.result
|
||
});
|
||
};
|
||
reader.onerror = function (error) {
|
||
throw(error);
|
||
}
|
||
reader.readAsArrayBuffer(blob);
|
||
})
|
||
.catch((error) => {
|
||
reject(error);
|
||
});
|
||
});
|
||
}
|
||
|
||
const decodeKfpkgFromArrayBuffer = async(arrayBuf) => {
|
||
const zip = await JSZip.loadAsync(arrayBuf);
|
||
const manifestEntry = zip.file('flash-list.json');
|
||
if (!manifestEntry) {
|
||
throw new Error('kfpkg is missing flash-list.json');
|
||
}
|
||
const manifestText = await manifestEntry.async('string');
|
||
const manifest = JSON.parse(manifestText);
|
||
|
||
const items = [];
|
||
for (const f of manifest.files || []) {
|
||
const entry = zip.file(f.bin);
|
||
if (!entry) {
|
||
throw new Error(`Missing files in package: ${f.bin}`);
|
||
}
|
||
const data = new Uint8Array(await entry.async('uint8array'));
|
||
items.push({
|
||
address: f.address >>> 0,
|
||
filename: f.bin,
|
||
sha256Prefix: !!f.sha256Prefix,
|
||
data
|
||
});
|
||
}
|
||
|
||
return { manifest, items };
|
||
}
|
||
|
||
BU.initBurn = async () => {
|
||
if (['BBC micro:bit', 'Mithon CC'].includes(BOARD.boardType)) {
|
||
await BU.burnWithDAP();
|
||
} else if (['MixGo AI'].includes(BOARD.boardType)) {
|
||
const { web } = SELECTED_BOARD;
|
||
const boardKey = Boards.getSelectedBoardKey();
|
||
if (!web?.burn?.binFile) {
|
||
return;
|
||
}
|
||
if (typeof web.burn.binFile !== 'object') {
|
||
return;
|
||
}
|
||
await BU.burnWithKFlash(web.burn.binFile, web.burn.erase);
|
||
} else {
|
||
const { web } = SELECTED_BOARD;
|
||
const boardKey = Boards.getSelectedBoardKey();
|
||
if (!web?.burn?.binFile) {
|
||
return;
|
||
}
|
||
if (typeof web.burn.binFile !== 'object') {
|
||
return;
|
||
}
|
||
if (web.burn.special && web.burn.special instanceof Array) {
|
||
BU.burnWithSpecialBin();
|
||
} else {
|
||
await BU.burnWithEsptool(web.burn.binFile, web.burn.erase);
|
||
}
|
||
}
|
||
}
|
||
|
||
BU.burnWithDAP = async () => {
|
||
const { mainStatusBarTabs } = Mixly;
|
||
let portName = Serial.getSelectedPortName();
|
||
if (!portName) {
|
||
try {
|
||
await BU.requestPort();
|
||
portName = Serial.getSelectedPortName();
|
||
if (!portName) {
|
||
return;
|
||
}
|
||
} catch (error) {
|
||
Debug.error(error);
|
||
return;
|
||
}
|
||
}
|
||
const statusBarSerial = mainStatusBarTabs.getStatusBarById(portName);
|
||
if (statusBarSerial) {
|
||
await statusBarSerial.close();
|
||
}
|
||
|
||
const { web } = SELECTED_BOARD;
|
||
const { burn } = web;
|
||
const hexStr = goog.readFileSync(path.join(Env.boardDirPath, burn.filePath));
|
||
const hex2Blob = new Blob([ hexStr ], { type: 'text/plain' });
|
||
const buffer = await hex2Blob.arrayBuffer();
|
||
if (!buffer) {
|
||
layer.msg(Msg.Lang['shell.bin.readFailed'], { time: 1000 });
|
||
return;
|
||
}
|
||
BU.burning = true;
|
||
BU.uploading = false;
|
||
const statusBarTerminal = mainStatusBarTabs.getStatusBarById('output');
|
||
statusBarTerminal.setValue(`${Msg.Lang['shell.burning']}...\n`);
|
||
mainStatusBarTabs.show();
|
||
mainStatusBarTabs.changeTo('output');
|
||
const port = Serial.getPort(portName);
|
||
const webUSB = new DAPjs.WebUSB(port);
|
||
const dapLink = new DAPjs.DAPLink(webUSB);
|
||
try {
|
||
await dapLink.connect();
|
||
await dapLink.setSerialBaudrate(115200);
|
||
} catch (error) {
|
||
Debug.error(error);
|
||
return;
|
||
}
|
||
let prevPercent = 0;
|
||
dapLink.on(DAPjs.DAPLink.EVENT_PROGRESS, progress => {
|
||
const nowPercent = Math.floor(progress * 100);
|
||
if (nowPercent > prevPercent) {
|
||
prevPercent = nowPercent;
|
||
} else {
|
||
return;
|
||
}
|
||
const nowProgressLen = Math.floor(nowPercent / 2);
|
||
const leftStr = new Array(nowProgressLen).fill('=').join('');
|
||
const rightStr = (new Array(50 - nowProgressLen).fill('-')).join('');
|
||
statusBarTerminal.addValue(`[${leftStr}${rightStr}] ${nowPercent}%\n`);
|
||
});
|
||
BU.progressLayer.title(`${Msg.Lang['shell.burning']}...`);
|
||
BU.progressLayer.show();
|
||
try {
|
||
await dapLink.flash(buffer);
|
||
BU.progressLayer.hide();
|
||
layer.msg(Msg.Lang['shell.burnSucc'], { time: 1000 });
|
||
statusBarTerminal.addValue(`==${Msg.Lang['shell.burnSucc']}==\n`);
|
||
} catch (error) {
|
||
Debug.error(error);
|
||
BU.progressLayer.hide();
|
||
statusBarTerminal.addValue(`==${Msg.Lang['shell.burnFailed']}==\n`);
|
||
} finally {
|
||
dapLink.removeAllListeners(DAPjs.DAPLink.EVENT_PROGRESS);
|
||
await dapLink.disconnect();
|
||
await webUSB.close();
|
||
await port.close();
|
||
}
|
||
}
|
||
|
||
BU.burnWithEsptool = async (binFile, erase) => {
|
||
const { mainStatusBarTabs } = Mixly;
|
||
let portName = Serial.getSelectedPortName();
|
||
if (!portName) {
|
||
try {
|
||
await BU.requestPort();
|
||
portName = Serial.getSelectedPortName();
|
||
if (!portName) {
|
||
return;
|
||
}
|
||
} catch (error) {
|
||
Debug.error(error);
|
||
return;
|
||
}
|
||
}
|
||
const port = Serial.getPort(portName);
|
||
if (['HIDDevice'].includes(port.constructor.name)) {
|
||
layer.msg(Msg.Lang['burn.notSupport'], { time: 1000 });
|
||
return;
|
||
}
|
||
const statusBarSerial = mainStatusBarTabs.getStatusBarById(portName);
|
||
if (statusBarSerial) {
|
||
await statusBarSerial.close();
|
||
}
|
||
const statusBarTerminal = mainStatusBarTabs.getStatusBarById('output');
|
||
statusBarTerminal.setValue(Msg.Lang['shell.burning'] + '...\n');
|
||
mainStatusBarTabs.show();
|
||
mainStatusBarTabs.changeTo('output');
|
||
BU.progressLayer.title(`${Msg.Lang['shell.burning']}...`);
|
||
BU.progressLayer.show();
|
||
let esploader = null;
|
||
let transport = null;
|
||
try {
|
||
const baudrate = Boards.getSelectedBoardConfigParam('BurnSpeed') ?? '460800';
|
||
const serial = new Serial(portName);
|
||
transport = new SerialTransport(serial, false);
|
||
esploader = new ESPLoader({
|
||
transport,
|
||
baudrate,
|
||
terminal: {
|
||
clean() {
|
||
statusBarTerminal.setValue(Msg.Lang['shell.burning'] + '...\n');
|
||
},
|
||
writeLine(data) {
|
||
statusBarTerminal.addValue(data + '\n');
|
||
},
|
||
write(data) {
|
||
statusBarTerminal.addValue(data);
|
||
}
|
||
}
|
||
});
|
||
await esploader.main();
|
||
} catch (error) {
|
||
Debug.error(error);
|
||
statusBarTerminal.addValue(`\n${error.toString()}\n`);
|
||
try {
|
||
await transport.disconnect();
|
||
} catch (error) {
|
||
Debug.error(error);
|
||
}
|
||
BU.progressLayer.hide();
|
||
statusBarTerminal.addValue(`==${Msg.Lang['shell.burnFailed']}==\n`);
|
||
return;
|
||
}
|
||
|
||
statusBarTerminal.addValue(Msg.Lang['shell.bin.reading'] + "...");
|
||
let firmwarePromise = [];
|
||
statusBarTerminal.addValue("\n");
|
||
for (let i of binFile) {
|
||
if (i.path && i.offset) {
|
||
let absolutePath = path.join(Env.boardDirPath, i.path);
|
||
firmwarePromise.push(readBinFile(absolutePath, i.offset));
|
||
}
|
||
}
|
||
let data = null;
|
||
try {
|
||
data = await Promise.all(firmwarePromise);
|
||
} catch (error) {
|
||
statusBarTerminal.addValue("Failed!\n" + Msg.Lang['shell.bin.readFailed'] + "!\n");
|
||
statusBarTerminal.addValue("\n" + error + "\n", true);
|
||
try {
|
||
await transport.disconnect();
|
||
} catch (error) {
|
||
Debug.error(error);
|
||
}
|
||
BU.progressLayer.hide();
|
||
statusBarTerminal.addValue(`==${Msg.Lang['shell.burnFailed']}==\n`);
|
||
return;
|
||
}
|
||
statusBarTerminal.addValue("Done!\n");
|
||
BU.burning = true;
|
||
BU.uploading = false;
|
||
const flashOptions = {
|
||
fileArray: data,
|
||
flashSize: 'keep',
|
||
eraseAll: erase,
|
||
compress: true,
|
||
calculateMD5Hash: (image) => CryptoJS.MD5(CryptoJS.enc.Latin1.parse(image))
|
||
};
|
||
try {
|
||
await esploader.writeFlash(flashOptions);
|
||
await transport.setDTR(false);
|
||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||
await transport.setDTR(true);
|
||
BU.progressLayer.hide();
|
||
layer.msg(Msg.Lang['shell.burnSucc'], { time: 1000 });
|
||
statusBarTerminal.addValue(`==${Msg.Lang['shell.burnSucc']}==\n`);
|
||
} catch (error) {
|
||
Debug.error(error);
|
||
BU.progressLayer.hide();
|
||
statusBarTerminal.addValue(`==${Msg.Lang['shell.burnFailed']}==\n`);
|
||
} finally {
|
||
try {
|
||
await transport.disconnect();
|
||
} catch (error) {
|
||
Debug.error(error);
|
||
}
|
||
}
|
||
}
|
||
|
||
BU.burnWithKFlash = async (binFile, erase) => {
|
||
const { mainStatusBarTabs } = Mixly;
|
||
let portName = Serial.getSelectedPortName();
|
||
if (!portName) {
|
||
try {
|
||
await BU.requestPort();
|
||
portName = Serial.getSelectedPortName();
|
||
if (!portName) {
|
||
return;
|
||
}
|
||
} catch (error) {
|
||
Debug.error(error);
|
||
return;
|
||
}
|
||
}
|
||
const port = Serial.getPort(portName);
|
||
if (['HIDDevice', 'USBDevice'].includes(port.constructor.name)) {
|
||
layer.msg(Msg.Lang['burn.notSupport'], { time: 1000 });
|
||
return;
|
||
}
|
||
const statusBarSerial = mainStatusBarTabs.getStatusBarById(portName);
|
||
if (statusBarSerial) {
|
||
await statusBarSerial.close();
|
||
}
|
||
const statusBarTerminal = mainStatusBarTabs.getStatusBarById('output');
|
||
statusBarTerminal.setValue(Msg.Lang['shell.burning'] + '...\n');
|
||
mainStatusBarTabs.show();
|
||
mainStatusBarTabs.changeTo('output');
|
||
BU.progressLayer.title(`${Msg.Lang['shell.burning']}...`);
|
||
BU.progressLayer.show();
|
||
|
||
let data = [];
|
||
try {
|
||
for (let i of binFile) {
|
||
if (i.path && i.offset) {
|
||
const extname = path.extname(i.path);
|
||
const absolutePath = path.join(Env.boardDirPath, i.path);
|
||
const info = await readBinFileAsArrayBuffer(absolutePath, i.offset);
|
||
if (extname === '.kfpkg') {
|
||
const result = await decodeKfpkgFromArrayBuffer(info.data);
|
||
data.push(...result.items);
|
||
} else {
|
||
data.push(info);
|
||
}
|
||
}
|
||
}
|
||
} catch (error) {
|
||
statusBarTerminal.addValue(`\n[ERROR] ${error}\n`, true);
|
||
BU.progressLayer.hide();
|
||
statusBarTerminal.addValue(`==${Msg.Lang['shell.burnFailed']}==\n`);
|
||
return;
|
||
}
|
||
let serial = null;
|
||
try {
|
||
serial = new Serial(portName);
|
||
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.appendLine(`==${Msg.Lang['shell.burnSucc']}==\n`);
|
||
} catch (error) {
|
||
statusBarTerminal.appendLine(`[ERROR] ${error.message}\n`);
|
||
BU.progressLayer.hide();
|
||
statusBarTerminal.appendLine(`==${Msg.Lang['shell.burnFailed']}==\n`);
|
||
} finally {
|
||
try {
|
||
serial && await serial.close();
|
||
} catch (error) {
|
||
Debug.error(error);
|
||
}
|
||
}
|
||
}
|
||
|
||
BU.getImportModulesName = (code) => {
|
||
// 正则表达式: 匹配 import 或 from 导入语句
|
||
const importRegex = /(?:import\s+([a-zA-Z0-9_]+)|from\s+([a-zA-Z0-9_]+)\s+import)/g;
|
||
|
||
let imports = [];
|
||
let match;
|
||
while ((match = importRegex.exec(code)) !== null) {
|
||
if (match[1]) {
|
||
imports.push(match[1]); // 'import module'
|
||
}
|
||
if (match[2]) {
|
||
imports.push(match[2]); // 'from module import ...'
|
||
}
|
||
}
|
||
return imports;
|
||
}
|
||
|
||
BU.getImportModules = (code) => {
|
||
let importsMap = {};
|
||
const libPath = SELECTED_BOARD.upload.libPath;
|
||
for (let i = libPath.length - 1; i >= 0; i--) {
|
||
const dirname = MString.tpl(libPath[i], { indexPath: Env.boardDirPath });
|
||
const map = goog.readJsonSync(path.join(dirname, 'map.json'));
|
||
if (!(map && map instanceof Object)) {
|
||
continue;
|
||
}
|
||
for (let key in map) {
|
||
importsMap[key] = structuredClone(map[key]);
|
||
importsMap[key]['__path__'] = path.join(dirname, map[key]['__name__']);
|
||
}
|
||
}
|
||
|
||
let usedMap = {};
|
||
let currentImports = BU.getImportModulesName(code);
|
||
while (currentImports.length) {
|
||
let temp = [];
|
||
for (let moduleName of currentImports) {
|
||
let moduleInfo = importsMap[moduleName];
|
||
if (!moduleInfo) {
|
||
continue;
|
||
}
|
||
usedMap[moduleName] = moduleInfo;
|
||
const moduleImports = moduleInfo['__require__'];
|
||
if (!moduleImports) {
|
||
continue;
|
||
}
|
||
for (let name of moduleImports) {
|
||
if (usedMap[name] || !importsMap[name] || temp.includes(name)) {
|
||
continue;
|
||
}
|
||
temp.push(name);
|
||
}
|
||
}
|
||
currentImports = temp;
|
||
}
|
||
return usedMap;
|
||
}
|
||
|
||
BU.initUpload = async () => {
|
||
let portName = Serial.getSelectedPortName();
|
||
if (!portName) {
|
||
try {
|
||
await BU.requestPort();
|
||
portName = Serial.getSelectedPortName();
|
||
if (!portName) {
|
||
return;
|
||
}
|
||
} catch (error) {
|
||
Debug.error(error);
|
||
return;
|
||
}
|
||
}
|
||
if (['BBC micro:bit', 'Mithon CC'].includes(BOARD.boardType)) {
|
||
await BU.uploadWithDAP(portName);
|
||
} else {
|
||
await BU.uploadWithAmpy(portName);
|
||
}
|
||
}
|
||
|
||
BU.uploadWithDAP = async (portName) => {
|
||
const { mainStatusBarTabs } = Mixly;
|
||
if (!portName) {
|
||
try {
|
||
await BU.requestPort();
|
||
portName = Serial.getSelectedPortName();
|
||
if (!portName) {
|
||
return;
|
||
}
|
||
} catch (error) {
|
||
Debug.error(error);
|
||
return;
|
||
}
|
||
}
|
||
let statusBarSerial = mainStatusBarTabs.getStatusBarById(portName);
|
||
if (statusBarSerial) {
|
||
await statusBarSerial.close();
|
||
}
|
||
|
||
const port = Serial.getPort(portName);
|
||
const statusBarTerminal = mainStatusBarTabs.getStatusBarById('output');
|
||
const dapWrapper = new DAPWrapper(port, {
|
||
event: () => {},
|
||
log: () => {}
|
||
});
|
||
const partialFlashing = new PartialFlashing(dapWrapper, {
|
||
event: () => {}
|
||
});
|
||
|
||
let boardId = 0x9901;
|
||
const boardKey = Boards.getSelectedBoardKey();
|
||
if (boardKey === 'micropython:nrf51822:v2') {
|
||
boardId = 0x9903;
|
||
}
|
||
|
||
BU.burning = false;
|
||
BU.uploading = true;
|
||
statusBarTerminal.setValue(Msg.Lang['shell.uploading'] + '...\n');
|
||
mainStatusBarTabs.show();
|
||
mainStatusBarTabs.changeTo('output');
|
||
const mainWorkspace = Workspace.getMain();
|
||
const editor = mainWorkspace.getEditorsManager().getActive();
|
||
const code = editor.getCode();
|
||
FSWrapper.writeFile('main.py', code);
|
||
const importsMap = BU.getImportModules(code);
|
||
for (let key in importsMap) {
|
||
const filename = importsMap[key]['__name__'];
|
||
const data = goog.readFileSync(importsMap[key]['__path__']);
|
||
FSWrapper.writeFile(filename, data);
|
||
}
|
||
BU.progressLayer.title(`${Msg.Lang['shell.uploading']}...`);
|
||
BU.progressLayer.show();
|
||
try {
|
||
let prevPercent = 0;
|
||
await partialFlashing.flashAsync(new BoardId(0x9900), FSWrapper, progress => {
|
||
const nowPercent = Math.floor(progress * 100);
|
||
if (nowPercent > prevPercent) {
|
||
prevPercent = nowPercent;
|
||
} else {
|
||
return;
|
||
}
|
||
const nowProgressLen = Math.floor(nowPercent / 2);
|
||
const leftStr = new Array(nowProgressLen).fill('=').join('');
|
||
const rightStr = (new Array(50 - nowProgressLen).fill('-')).join('');
|
||
statusBarTerminal.addValue(`[${leftStr}${rightStr}] ${nowPercent}%\n`);
|
||
});
|
||
BU.progressLayer.hide();
|
||
layer.msg(Msg.Lang['shell.uploadSucc'], { time: 1000 });
|
||
statusBarTerminal.addValue(`==${Msg.Lang['shell.uploadSucc']}==\n`);
|
||
if (!statusBarSerial) {
|
||
mainStatusBarTabs.add('serial', portName);
|
||
statusBarSerial = mainStatusBarTabs.getStatusBarById(portName);
|
||
}
|
||
statusBarSerial.setValue('');
|
||
mainStatusBarTabs.changeTo(portName);
|
||
await statusBarSerial.open();
|
||
} catch (error) {
|
||
await dapWrapper.disconnectAsync();
|
||
Debug.error(error);
|
||
BU.progressLayer.hide();
|
||
statusBarTerminal.addValue(`${error}\n`);
|
||
statusBarTerminal.addValue(`==${Msg.Lang['shell.uploadFailed']}==\n`);
|
||
}
|
||
}
|
||
|
||
BU.uploadWithAmpy = async (portName) => {
|
||
const { mainStatusBarTabs } = Mixly;
|
||
const statusBarTerminal = mainStatusBarTabs.getStatusBarById('output');
|
||
let statusBarSerial = mainStatusBarTabs.getStatusBarById(portName);
|
||
BU.burning = false;
|
||
BU.uploading = true;
|
||
statusBarTerminal.setValue(`${Msg.Lang['shell.uploading']}...\n`);
|
||
mainStatusBarTabs.show();
|
||
mainStatusBarTabs.changeTo('output');
|
||
const mainWorkspace = Workspace.getMain();
|
||
const editor = mainWorkspace.getEditorsManager().getActive();
|
||
const port = Serial.getPort(portName);
|
||
BU.progressLayer.title(`${Msg.Lang['shell.uploading']}...`);
|
||
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) {
|
||
const filename = importsMap[key]['__name__'];
|
||
const data = goog.readFileSync(importsMap[key]['__path__']);
|
||
libraries[filename] = {
|
||
data,
|
||
size: importsMap[key]['__size__']
|
||
};
|
||
}
|
||
let cwd = await ampy.cwd();
|
||
const rootInfo = await ampy.ls(cwd);
|
||
let rootMap = {};
|
||
for (let item of rootInfo) {
|
||
rootMap[item[0]] = item[1];
|
||
}
|
||
if (cwd === '/') {
|
||
cwd = '';
|
||
}
|
||
if (libraries && libraries instanceof Object) {
|
||
for (let key in libraries) {
|
||
if (rootMap[`${cwd}/${key}`] !== undefined && rootMap[`${cwd}/${key}`] === libraries[key].size) {
|
||
statusBarTerminal.addValue(`Writing ${key} (Skipped)\n`);
|
||
continue;
|
||
}
|
||
await ampy.put(key, libraries[key].data);
|
||
}
|
||
}*/
|
||
await ampy.exit();
|
||
await ampy.dispose();
|
||
BU.progressLayer.hide();
|
||
layer.msg(Msg.Lang['shell.uploadSucc'], { time: 1000 });
|
||
statusBarTerminal.appendLine(`==${Msg.Lang['shell.uploadSucc']}==\n`);
|
||
if (!statusBarSerial) {
|
||
mainStatusBarTabs.add('serial', portName);
|
||
statusBarSerial = mainStatusBarTabs.getStatusBarById(portName);
|
||
}
|
||
statusBarSerial.setValue('');
|
||
mainStatusBarTabs.changeTo(portName);
|
||
await statusBarSerial.open();
|
||
} catch (error) {
|
||
ampy.dispose();
|
||
BU.progressLayer.hide();
|
||
Debug.error(error);
|
||
statusBarTerminal.appendLine(`[ERROR] ${error.message}\n`);
|
||
statusBarTerminal.appendLine(`==${Msg.Lang['shell.uploadFailed']}==\n`);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @function 特殊固件的烧录
|
||
* @return {void}
|
||
**/
|
||
BU.burnWithSpecialBin = () => {
|
||
const { mainStatusBarTabs } = Mixly;
|
||
const statusBarTerminal = mainStatusBarTabs.getStatusBarById('output');
|
||
const firmwares = SELECTED_BOARD.web.burn.special;
|
||
let menu = [];
|
||
let firmwareMap = {};
|
||
for (let firmware of firmwares) {
|
||
if (!firmware?.name && !firmware?.binFile) continue;
|
||
menu.push({
|
||
id: firmware.name,
|
||
text: firmware.name
|
||
});
|
||
firmwareMap[firmware.name] = firmware.binFile;
|
||
}
|
||
BU.firmwareLayer.setMap(firmwareMap);
|
||
BU.firmwareLayer.setMenu(menu);
|
||
BU.firmwareLayer.show();
|
||
}
|
||
|
||
}); |