goog.loadJs('web', () => { goog.require('path'); goog.require('BoardId'); goog.require('FSWrapper'); goog.require('DAPWrapper'); goog.require('PartialFlashing'); goog.require('ESPTool'); goog.require('AdafruitESPTool'); goog.require('CryptoJS'); goog.require('AvrUploader'); 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.Web.Serial'); goog.require('Mixly.Web.Ampy'); goog.provide('Mixly.Web.BU'); const { Env, Web, LayerExt, Config, MFile, Boards, Msg, Workspace, Debug, HTMLTemplate, MString, LayerFirmware } = Mixly; const { Serial, BU, Ampy } = Web; const { BOARD, SELECTED_BOARD } = Config; const { ESPLoader, Transport } = ESPTool; 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 boardKey = Boards.getSelectedBoardKey(); const { web } = SELECTED_BOARD; if (boardKey.indexOf('micropython:esp32s2') !== -1) { BU.burnWithAdafruitEsptool(info, web.burn.erase); } else { BU.burnWithEsptool(info, web.burn.erase); } }); const BAUD = goog.platform() === 'darwin' ? 460800 : 921600; 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); }); }); } BU.initBurn = () => { if (['BBC micro:bit', 'Mithon CC'].includes(BOARD.boardType)) { BU.burnByUSB(); } 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 { if (boardKey.indexOf('micropython:esp32s2') !== -1) { BU.burnWithAdafruitEsptool(web.burn.binFile, web.burn.erase); } else { BU.burnWithEsptool(web.burn.binFile, web.burn.erase); } } } } BU.burnByUSB = 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`); }); layer.open({ type: 1, title: `${Msg.Lang['shell.burning']}...`, content: $('#mixly-loader-div'), shade: LayerExt.SHADE_NAV, resize: false, closeBtn: 0, success: async (layero, index) => { $('#mixly-loader-btn').hide(); try { await dapLink.flash(buffer); layer.close(index); layer.msg(Msg.Lang['shell.burnSucc'], { time: 1000 }); statusBarTerminal.addValue(`==${Msg.Lang['shell.burnSucc']}==\n`); } catch (error) { Debug.error(error); layer.close(index); statusBarTerminal.addValue(`==${Msg.Lang['shell.burnFailed']}==\n`); } finally { dapLink.removeAllListeners(DAPjs.DAPLink.EVENT_PROGRESS); await dapLink.disconnect(); await webUSB.close(); await port.close(); } }, end: function () { $('#mixly-loader-btn').css('display', 'inline-block'); $('#mixly-loader-div').css('display', 'none'); } }); } 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', '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'); let esploader = null; let transport = null; try { transport = new Transport(port, false); esploader = new ESPLoader({ transport, baudrate: BAUD, terminal: { clean() { statusBarTerminal.setValue(''); }, writeLine(data) { statusBarTerminal.addValue(data + '\n'); }, write(data) { statusBarTerminal.addValue(data); } } }); let chip = await esploader.main(); } catch (error) { Debug.error(error); statusBarTerminal.addValue(`\n${error.toString()}\n`); await transport.disconnect(); 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); // statusBarTerminal.addValue(`${Msg.Lang['读取固件'] + ' ' // + Msg.Lang['路径']}:${absolutePath}, ${Msg.Lang['偏移']}:${i.offset}\n`); 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" + e + "\n", true); await transport.disconnect(); 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)) }; layer.open({ type: 1, title: Msg.Lang['shell.burning'] + '...', content: $('#mixly-loader-div'), shade: LayerExt.SHADE_NAV, resize: false, closeBtn: 0, success: async function (layero, index) { let cancel = false; $("#mixly-loader-btn").off().click(async () => { cancel = true; try { await transport.disconnect(); } catch (error) { layer.close(index); Debug.error(error); } }); try { await esploader.writeFlash(flashOptions); layer.msg(Msg.Lang['shell.burnSucc'], { time: 1000 }); statusBarTerminal.addValue(`==${Msg.Lang['shell.burnSucc']}==\n`); } catch (error) { Debug.error(error); statusBarTerminal.addValue(`==${Msg.Lang['shell.burnFailed']}==\n`); } finally { layer.close(index); if (!cancel) { await transport.disconnect(); } } } }); } BU.burnWithAdafruitEsptool = 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'); let esploader = null; let transport = null; let espStub = null; try { await port.open({ baudRate: 115200 }); esploader = new AdafruitESPTool.ESPLoader(port, { log(...args) { statusBarTerminal.addValue(args.join('') + '\n'); }, debug(...args) { statusBarTerminal.addValue(args.join('') + '\n'); }, error(...args) { statusBarTerminal.addValue(args.join('') + '\n'); } }); await esploader.initialize(); espStub = await esploader.runStub(); } catch (error) { Debug.error(error); statusBarTerminal.addValue(`\n${error.toString()}\n`); await port.close(); 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); // statusBarTerminal.addValue(`${Msg.Lang['读取固件'] + ' ' // + Msg.Lang['路径']}:${absolutePath}, ${Msg.Lang['偏移']}:${i.offset}\n`); firmwarePromise.push(readBinFileAsArrayBuffer(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" + e + "\n", true); await espStub.disconnect(); await espStub.port.close(); return; } statusBarTerminal.addValue("Done!\n"); BU.burning = true; BU.uploading = false; const layerNum = layer.open({ type: 1, title: Msg.Lang['shell.burning'] + '...', content: $('#mixly-loader-div'), shade: LayerExt.SHADE_NAV, resize: false, closeBtn: 0, success: async function (layero, index) { let cancel = false; $("#mixly-loader-btn").hide(); try { if (erase) { await espStub.eraseFlash(); } for (let file of data) { await espStub.flashData( file.data, (bytesWritten, totalBytes) => { const percent = Math.floor((bytesWritten / totalBytes) * 100) + '%'; statusBarTerminal.addValue(`Writing at 0x${(file.address + bytesWritten).toString(16)}... (${percent})\n`); }, file.address, true ); } await espStub.disconnect(); await espStub.port.close(); cancel = true; layer.msg(Msg.Lang['shell.burnSucc'], { time: 1000 }); statusBarTerminal.addValue(`==${Msg.Lang['shell.burnSucc']}==\n`); } catch (error) { Debug.error(error); statusBarTerminal.addValue(`==${Msg.Lang['shell.burnFailed']}==\n`); } finally { layer.close(index); if (!cancel) { await espStub.disconnect(); await espStub.port.close(); } } }, end: function () { $(`#layui-layer-shade${layerNum}`).remove(); } }); } 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)) { BU.uploadByUSB(portName); } else { BU.uploadWithAmpy(portName); } } BU.uploadByUSB = 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); } const layerNum = layer.open({ type: 1, title: Msg.Lang['shell.uploading'] + '...', content: $('#mixly-loader-div'), shade: LayerExt.SHADE_NAV, resize: false, closeBtn: 0, success: async function (layero, index) { $('#mixly-loader-btn').hide(); 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`); }); layer.close(index); 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(); layer.close(index); console.error(error); statusBarTerminal.addValue(`${error}\n`); statusBarTerminal.addValue(`==${Msg.Lang['shell.uploadFailed']}==\n`); } BU.burning = false; BU.uploading = false; }, end: function () { $('#mixly-loader-btn').css('display', 'inline-block'); $('#mixly-loader-div').css('display', 'none'); $(`#layui-layer-shade${layerNum}`).remove(); } }); } BU.uploadWithAmpy = (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); const layerNum = layer.open({ type: 1, title: Msg.Lang['shell.uploading'] + '...', content: $('#mixly-loader-div'), shade: LayerExt.SHADE_NAV, resize: false, closeBtn: 0, success: async function (layero, index) { $('#mixly-loader-btn').hide(); const serial = new Serial(portName); const ampy = new Ampy(serial); const code = editor.getCode(); let closePromise = Promise.resolve(); if (statusBarSerial) { closePromise = statusBarSerial.close(); } try { /*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__'] }; }*/ 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(); const rootInfo = await ampy.ls(cwd); let rootMap = {}; for (let item of rootInfo) { rootMap[item[0]] = item[1]; } 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`); continue; } statusBarTerminal.addValue(`Writing ${key} `); await ampy.put(key, libraries[key].data); statusBarTerminal.addValue('Done!\n'); } }*/ await ampy.exit(); await ampy.dispose(); layer.close(index); 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) { ampy.dispose(); layer.close(index); Debug.error(error); statusBarTerminal.addValue(`${error}\n`); statusBarTerminal.addValue(`==${Msg.Lang['shell.uploadFailed']}==\n`); } BU.burning = false; BU.uploading = false; }, end: function () { $('#mixly-loader-btn').css('display', 'inline-block'); $('#mixly-loader-div').css('display', 'none'); $(`#layui-layer-shade${layerNum}`).remove(); } }); } function hexToBuf (hex) { var typedArray = new Uint8Array(hex.match(/[\da-f]{2}/gi).map(function (h) { return parseInt(h, 16) })); return typedArray.buffer; } BU.uploadWithEsptool = async (endType, obj, layerType) => { const portName = 'web-serial'; const portObj = Serial.portsOperator[portName]; const { serialport, toolConfig } = portObj; let prevBaud = toolConfig.baudRates; if (prevBaud !== 115200) { toolConfig.baudRates = 115200; await serialport.setBaudRate(toolConfig.baudRates); } const { mainStatusBarTabs } = Mixly; const statusBarTerminal = mainStatusBarTabs.getStatusBarById('output'); let firmwareData = obj.data; if (endType || typeof firmwareData !== 'object') { statusBarTerminal.addValue(Msg.Lang['shell.bin.readFailed'] + "!\n"); layer.close(layerType); return; } layer.title(Msg.Lang['shell.uploading'] + '...', layerType); statusBarTerminal.addValue(Msg.Lang['shell.bin.reading'] + "... "); let firmwareList = []; for (let i of firmwareData) { if (!i.offset || !i.data) { continue; } const firmware = { offset: i.offset, binBuf: hexToBuf(i.data) }; firmwareList.push(firmware); } statusBarTerminal.addValue("Done!\n"); BU.burning = true; BU.uploading = false; statusBarTerminal.addValue(Msg.Lang['shell.uploading'] + '...\n'); mainStatusBarTabs.show(); mainStatusBarTabs.changeTo('output'); try { SerialPort.refreshOutputBuffer = false; SerialPort.refreshInputBuffer = true; await espTool.reset(); if (await clickSync()) { // await clickErase(); for (let i of firmwareList) { await clickProgram(i.offset, i.binBuf); } } layer.close(layerType); layer.msg(Msg.Lang['shell.uploadSucc'], { time: 1000 }); statusBarTerminal.addValue(`==${Msg.Lang['shell.uploadSucc']}==\n`); Serial.reset(portName, 'upload'); mainStatusBarTabs.changeTo(portName); } catch (error) { Debug.error(error); layer.close(layerType); statusBarTerminal.addValue(`==${Msg.Lang['shell.uploadFailed']}==\n`); } finally { SerialPort.refreshOutputBuffer = true; SerialPort.refreshInputBuffer = false; const code = MFile.getCode(); const baudRateList = code.match(/(?<=Serial.begin[\s]*\([\s]*)[0-9]*(?=[\s]*\))/g); if (baudRateList && Serial.BAUDRATES.includes(baudRateList[0]-0)) { prevBaud = baudRateList[0]-0; } if (toolConfig.baudRates !== prevBaud) { toolConfig.baudRates = prevBaud; await serialport.setBaudRate(prevBaud); } } } BU.uploadWithAvrUploader = async (endType, obj, layerType) => { let firmwareData = obj.data; const { mainStatusBarTabs } = Mixly; const statusBarTerminal = mainStatusBarTabs.getStatusBarById('output'); if (endType || typeof firmwareData !== 'object') { statusBarTerminal.addValue(Msg.Lang['shell.bin.readFailed'] + "!\n"); layer.close(layerType); return; } statusBarTerminal.addValue(Msg.Lang['shell.uploading'] + '...\n'); layer.title(Msg.Lang['shell.uploading'] + '...', layerType); let uploadSucMessageShow = true; AvrUploader.upload(firmwareData[0].data, (progress) => { if (progress >= 100 && uploadSucMessageShow) { statusBarTerminal.addValue(`==${Msg.Lang['shell.uploadSucc']}==\n`); layer.msg(Msg.Lang['shell.uploadSucc'], { time: 1000 }); layer.close(layerType); uploadSucMessageShow = false; } }, true) .catch((error) => { layer.close(layerType); statusBarTerminal.addValue(`==${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(); } });