merge: 合并master到develop
This commit is contained in:
@@ -41,10 +41,11 @@ class ContextMenu {
|
||||
}
|
||||
}
|
||||
|
||||
#selector_ = null;
|
||||
#menus_ = new Registry();
|
||||
#events_ = new Events(['getMenu']);
|
||||
constructor(selector, config = {}) {
|
||||
this.selector = selector;
|
||||
this.#selector_ = selector;
|
||||
this.menu = $.contextMenu({
|
||||
selector,
|
||||
build: ($trigger) => {
|
||||
@@ -67,20 +68,20 @@ class ContextMenu {
|
||||
return ContextMenu.generate(menu, $trigger, e);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
$.contextMenu('destroy', this.selector);
|
||||
this.#events_.reset();
|
||||
this.#menus_.reset();
|
||||
this.menu = null;
|
||||
this.selector = null;
|
||||
}
|
||||
|
||||
show() {
|
||||
$(this.selector).contextMenu();
|
||||
$(this.#selector_).contextMenu();
|
||||
}
|
||||
|
||||
hide() {
|
||||
$(this.selector).contextMenu('hide');
|
||||
$(this.#selector_).contextMenu('hide');
|
||||
}
|
||||
|
||||
dispose() {
|
||||
$.contextMenu('destroy', this.#selector_);
|
||||
this.#events_.reset();
|
||||
this.#menus_.reset();
|
||||
this.menu = null;
|
||||
this.#selector_ = null;
|
||||
}
|
||||
|
||||
bind(type, func) {
|
||||
|
||||
@@ -1,35 +1,66 @@
|
||||
goog.loadJs('common', () => {
|
||||
|
||||
goog.require('tippy');
|
||||
goog.require('Mixly.IdGenerator');
|
||||
goog.require('Mixly.ContextMenu');
|
||||
goog.provide('Mixly.DropdownMenu');
|
||||
|
||||
const { ContextMenu } = Mixly;
|
||||
const {
|
||||
IdGenerator,
|
||||
ContextMenu
|
||||
} = Mixly;
|
||||
|
||||
|
||||
class DropdownMenu extends ContextMenu {
|
||||
#contextMenu_ = null;
|
||||
#layer_ = null;
|
||||
static {
|
||||
this.$container = $('<div class="mixly-dropdown-menus"></div>');
|
||||
$(document.body).append(this.$container);
|
||||
}
|
||||
|
||||
#shown_ = false;
|
||||
constructor(selector) {
|
||||
#layer_ = null;
|
||||
#contextMenuId_ = '';
|
||||
#$contextMenuElem_ = null;
|
||||
constructor(elem) {
|
||||
const layer = tippy(elem, {
|
||||
allowHTML: true,
|
||||
content: '',
|
||||
trigger: 'click',
|
||||
interactive: true,
|
||||
maxWidth: 'none',
|
||||
offset: [0, 0],
|
||||
appendTo: document.body,
|
||||
arrow: false,
|
||||
placement: 'bottom-start',
|
||||
delay: 0,
|
||||
duration: [0, 0],
|
||||
onCreate: (instance) => {
|
||||
$(instance.popper).addClass('mixly-drapdown-menu');
|
||||
},
|
||||
onMount: () => {
|
||||
this.show();
|
||||
},
|
||||
onHide: () => {
|
||||
this.#shown_ && this.hide();
|
||||
}
|
||||
});
|
||||
|
||||
const contextMenuId = IdGenerator.generate();
|
||||
const selector = `body > .mixly-dropdown-menus > div[m-id="${contextMenuId}"]`;
|
||||
|
||||
super(selector, {
|
||||
trigger: 'none',
|
||||
appendTo: $(layer.popper).children().children(),
|
||||
zIndex: 1001,
|
||||
position: (opt) => {
|
||||
opt.$menu.css({
|
||||
top: 0,
|
||||
left: 0,
|
||||
position: 'relative',
|
||||
margin: 0
|
||||
});
|
||||
opt.$menu.css('margin', 0);
|
||||
},
|
||||
events: {
|
||||
show: (opt) => {
|
||||
opt.$menu.detach();
|
||||
$('body > .mixly-drapdown-menu > .tippy-box > .tippy-content').empty().append(opt.$menu);
|
||||
this.#layer_.setProps({});
|
||||
show: () => {
|
||||
this.#shown_ = true;
|
||||
this.#layer_.setProps({});
|
||||
},
|
||||
hide: (opt) => {
|
||||
hide: () => {
|
||||
this.#shown_ = false;
|
||||
if (this.#layer_.state.isShown) {
|
||||
this.#layer_.hide();
|
||||
@@ -38,33 +69,26 @@ class DropdownMenu extends ContextMenu {
|
||||
}
|
||||
});
|
||||
|
||||
this.#layer_ = tippy($(selector)[0], {
|
||||
allowHTML: true,
|
||||
content: '',
|
||||
trigger: 'click',
|
||||
interactive: true,
|
||||
maxWidth: 'none',
|
||||
offset: [ 0, 0 ],
|
||||
appendTo: document.body,
|
||||
arrow: false,
|
||||
placement: 'bottom-start',
|
||||
delay: 0,
|
||||
duration: [ 0, 0 ],
|
||||
onCreate: (instance) => {
|
||||
$(instance.popper).addClass('mixly-drapdown-menu');
|
||||
},
|
||||
onMount: (instance) => {
|
||||
this.show();
|
||||
},
|
||||
onHide: () => {
|
||||
this.#shown_ && this.hide();
|
||||
}
|
||||
});
|
||||
this.#$contextMenuElem_ = $(`<div m-id="${contextMenuId}"><div>`);
|
||||
DropdownMenu.$container.append(this.#$contextMenuElem_);
|
||||
this.#contextMenuId_ = contextMenuId;
|
||||
this.#layer_ = layer;
|
||||
}
|
||||
|
||||
show() {
|
||||
this.#$contextMenuElem_.contextMenu();
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.#$contextMenuElem_.contextMenu('hide');
|
||||
}
|
||||
|
||||
dispose() {
|
||||
super.dispose();
|
||||
this.#layer_.destroy();
|
||||
this.#layer_ = null;
|
||||
this.#$contextMenuElem_.remove();
|
||||
this.#$contextMenuElem_ = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ class EditorBlockly extends EditorBase {
|
||||
this.initBlockly = () => {
|
||||
const DEFAULT_CATEGORIES = HTMLTemplate.get('xml/default-categories.xml').render();
|
||||
const media = path.join(Env.srcDirPath, 'common/media/blockly');
|
||||
const renderer = ['geras', 'zelos'].includes(USER.blockRenderer) ? USER.blockRenderer : 'geras';
|
||||
const renderer = ['geras', 'zelos', 'thrasos'].includes(USER.blockRenderer) ? USER.blockRenderer : 'geras';
|
||||
this.editor = Blockly.inject(this.$blockly[0], {
|
||||
media,
|
||||
toolbox: DEFAULT_CATEGORIES,
|
||||
|
||||
@@ -22,7 +22,7 @@ Env.hasSocketServer = false;
|
||||
Env.hasCompiler = false;
|
||||
|
||||
/**
|
||||
* 获取当前mixly2.0的路径
|
||||
* 获取当前mixly的路径
|
||||
* @type {String}
|
||||
*/
|
||||
Env.clientPath = null;
|
||||
|
||||
@@ -16,7 +16,8 @@ goog.require('Mixly.Debug');
|
||||
goog.require('Mixly.API2');
|
||||
goog.require('Mixly.Electron.LibManager');
|
||||
goog.require('Mixly.Electron.File');
|
||||
goog.require('Mixly.WebSocket.Socket');
|
||||
goog.require('Mixly.WebCompiler.Loader');
|
||||
goog.require('Mixly.WebSocket.Loader');
|
||||
goog.provide('Mixly.Loader');
|
||||
|
||||
const {
|
||||
@@ -35,16 +36,20 @@ const {
|
||||
API2,
|
||||
Electron = {},
|
||||
Web = {},
|
||||
WebCompiler = {},
|
||||
WebSocket = {}
|
||||
} = Mixly;
|
||||
|
||||
const { LibManager, File } = goog.isElectron? Electron : Web;
|
||||
const { Socket } = WebSocket;
|
||||
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
if (!goog.isElectron && Env.hasSocketServer) {
|
||||
Socket.init();
|
||||
if (!goog.isElectron) {
|
||||
if (Env.hasSocketServer) {
|
||||
WebSocket.Loader.init();
|
||||
} else if (Env.hasCompiler) {
|
||||
WebCompiler.Loader.init();
|
||||
}
|
||||
}
|
||||
const app = new App($('body')[0]);
|
||||
Mixly.app = app;
|
||||
|
||||
@@ -7,9 +7,9 @@ goog.provide('Mixly.LocalStorage');
|
||||
const { MArray, LocalStorage } = Mixly;
|
||||
|
||||
LocalStorage.PATH = {
|
||||
USER: 'mixly2.0/user',
|
||||
BOARD: 'mixly2.0/boards/{{d.boardType}}/user',
|
||||
THIRD_PARTY: 'mixly2.0/boards/{{d.boardType}}/third_party/{{d.thirdPartyName}}'
|
||||
USER: 'mixly3.0/user',
|
||||
BOARD: 'mixly3.0/boards/{{d.boardType}}/user',
|
||||
THIRD_PARTY: 'mixly3.0/boards/{{d.boardType}}/third_party/{{d.thirdPartyName}}'
|
||||
};
|
||||
|
||||
LocalStorage.set = function (path, value) {
|
||||
|
||||
91
common/modules/mixly-modules/common/socket.js
Normal file
91
common/modules/mixly-modules/common/socket.js
Normal file
@@ -0,0 +1,91 @@
|
||||
goog.loadJs('common', () => {
|
||||
|
||||
goog.require('io');
|
||||
goog.require('Mixly');
|
||||
goog.provide('Mixly.Socket');
|
||||
|
||||
|
||||
class Socket {
|
||||
#socket_ = null;
|
||||
constructor(path, option) {
|
||||
this.#socket_ = io(path, option);
|
||||
}
|
||||
|
||||
#detectStatus_(status, callback) {
|
||||
window.setTimeout(() => {
|
||||
if (status.finished) {
|
||||
return;
|
||||
}
|
||||
if (this.isConnected()) {
|
||||
this.#detectStatus_(status, callback);
|
||||
} else {
|
||||
callback({
|
||||
error: 'socket is not connected'
|
||||
});
|
||||
status.finished = true;
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
emit(eventName, ...args) {
|
||||
const callback = args.pop();
|
||||
if (this.isConnected()) {
|
||||
let emitStatus = {
|
||||
finished: false
|
||||
};
|
||||
let status = this.#socket_.emit(eventName, ...args, (...callbackArgs) => {
|
||||
if (emitStatus.finished) {
|
||||
return;
|
||||
}
|
||||
emitStatus.finished = true;
|
||||
callback(...callbackArgs);
|
||||
});
|
||||
this.#detectStatus_(emitStatus, callback);
|
||||
return status;
|
||||
} else {
|
||||
callback({
|
||||
error: 'socket is not connected'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async emitAsync(eventName, ...args) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (this.isConnected()) {
|
||||
const callback = (...callbackArgs) => {
|
||||
if (callbackArgs[0].error) {
|
||||
reject(callbackArgs[0].error);
|
||||
return;
|
||||
}
|
||||
resolve(...callbackArgs);
|
||||
}
|
||||
let emitStatus = {
|
||||
finished: false
|
||||
};
|
||||
let status = this.#socket_.emit(eventName, ...args, (...callbackArgs) => {
|
||||
if (emitStatus.finished) {
|
||||
return;
|
||||
}
|
||||
emitStatus.finished = true;
|
||||
callback(...callbackArgs);
|
||||
});
|
||||
this.#detectStatus_(emitStatus, callback);
|
||||
} else {
|
||||
reject('socket is not connected');
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
getSocket() {
|
||||
return this.#socket_;
|
||||
}
|
||||
|
||||
isConnected() {
|
||||
return this.#socket_?.connected;
|
||||
}
|
||||
}
|
||||
|
||||
Mixly.Socket = Socket;
|
||||
|
||||
});
|
||||
@@ -86,6 +86,7 @@ class StatusBarsManager extends PagesManager {
|
||||
|
||||
#shown_ = false;
|
||||
#dropdownMenu_ = null;
|
||||
#$dropdownBtn_ = null;
|
||||
|
||||
constructor(element) {
|
||||
const managerHTMLTemplate = HTMLTemplate.get('html/statusbar/statusbars-manager.html');
|
||||
@@ -103,6 +104,7 @@ class StatusBarsManager extends PagesManager {
|
||||
this.tabId = tabHTMLTemplate.id;
|
||||
this.id = IdGenerator.generate();
|
||||
this.addEventsType(['show', 'hide', 'onSelectMenu', 'getMenu']);
|
||||
this.#$dropdownBtn_ = $tab.find('.statusbar-dropdown-menu > button');
|
||||
$tab.find('.statusbar-close > button').click(() => this.hide());
|
||||
this.#addDropdownMenu_();
|
||||
this.#addEventsListener_();
|
||||
@@ -146,7 +148,6 @@ class StatusBarsManager extends PagesManager {
|
||||
}
|
||||
|
||||
#addDropdownMenu_() {
|
||||
const selector = `div[m-id="${this.tabId}"] > .statusbar-dropdown-menu > .layui-btn`;
|
||||
let menu = new Menu();
|
||||
let serialChildMenu = new Menu(true);
|
||||
menu.add({
|
||||
@@ -240,7 +241,7 @@ class StatusBarsManager extends PagesManager {
|
||||
}
|
||||
return result;
|
||||
});
|
||||
this.#dropdownMenu_ = new DropdownMenu(selector);
|
||||
this.#dropdownMenu_ = new DropdownMenu(this.#$dropdownBtn_[0]);
|
||||
this.#dropdownMenu_.register('menu', menu);
|
||||
this.#dropdownMenu_.bind('getMenu', () => 'menu');
|
||||
}
|
||||
@@ -278,6 +279,9 @@ class StatusBarsManager extends PagesManager {
|
||||
|
||||
dispose() {
|
||||
StatusBarsManager.remove(this);
|
||||
this.#dropdownMenu_.dispose();
|
||||
this.#$dropdownBtn_.remove();
|
||||
this.#$dropdownBtn_ = null;
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
"Mixly.Web.FS",
|
||||
"Mixly.Web.File",
|
||||
"Mixly.Web.Serial",
|
||||
"Mixly.WebCompiler.ArduShell",
|
||||
"Mixly.WebSocket.File",
|
||||
"Mixly.WebSocket.Serial",
|
||||
"Mixly.WebSocket.ArduShell",
|
||||
@@ -190,6 +191,7 @@
|
||||
"path": "/common/dropdown-menu.js",
|
||||
"require": [
|
||||
"tippy",
|
||||
"Mixly.IdGenerator",
|
||||
"Mixly.ContextMenu"
|
||||
],
|
||||
"provide": [
|
||||
@@ -652,7 +654,8 @@
|
||||
"Mixly.API2",
|
||||
"Mixly.Electron.LibManager",
|
||||
"Mixly.Electron.File",
|
||||
"Mixly.WebSocket.Socket"
|
||||
"Mixly.WebCompiler.Loader",
|
||||
"Mixly.WebSocket.Loader"
|
||||
],
|
||||
"provide": [
|
||||
"Mixly.Loader"
|
||||
@@ -918,6 +921,16 @@
|
||||
"Mixly.RightSideBarsManager"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/common/socket.js",
|
||||
"require": [
|
||||
"io",
|
||||
"Mixly"
|
||||
],
|
||||
"provide": [
|
||||
"Mixly.Socket"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/common/statusbar-ampy.js",
|
||||
"require": [
|
||||
@@ -1428,6 +1441,7 @@
|
||||
{
|
||||
"path": "/electron/loader.js",
|
||||
"require": [
|
||||
"path",
|
||||
"Mixly.Url",
|
||||
"Mixly.Config",
|
||||
"Mixly.Env",
|
||||
@@ -1552,10 +1566,9 @@
|
||||
"FSWrapper",
|
||||
"DAPWrapper",
|
||||
"PartialFlashing",
|
||||
"ESPTool",
|
||||
"esptooljs",
|
||||
"AdafruitESPTool",
|
||||
"CryptoJS",
|
||||
"AvrUploader",
|
||||
"Mixly.Env",
|
||||
"Mixly.LayerExt",
|
||||
"Mixly.Config",
|
||||
@@ -1712,19 +1725,38 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/web-compiler/compiler.js",
|
||||
"path": "/web-compiler/arduino-shell.js",
|
||||
"require": [
|
||||
"Mixly.Url",
|
||||
"Mixly.Config",
|
||||
"Mixly.LayerExt",
|
||||
"layui",
|
||||
"avrbro",
|
||||
"esptooljs",
|
||||
"AdafruitESPTool",
|
||||
"CryptoJS",
|
||||
"dayjs.duration",
|
||||
"Mixly.Boards",
|
||||
"Mixly.MFile",
|
||||
"Mixly.Debug",
|
||||
"Mixly.LayerExt",
|
||||
"Mixly.Msg",
|
||||
"Mixly.Web.BU",
|
||||
"Mixly.Web.Serial"
|
||||
"Mixly.Workspace",
|
||||
"Mixly.LayerProgress",
|
||||
"Mixly.Web.Serial",
|
||||
"Mixly.WebCompiler"
|
||||
],
|
||||
"provide": [
|
||||
"Mixly.WebCompiler.Compiler"
|
||||
"Mixly.WebCompiler.ArduShell"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/web-compiler/loader.js",
|
||||
"require": [
|
||||
"Mixly.Debug",
|
||||
"Mixly.Config",
|
||||
"Mixly.StatusBarsManager",
|
||||
"Mixly.Socket",
|
||||
"Mixly.WebCompiler.ArduShell"
|
||||
],
|
||||
"provide": [
|
||||
"Mixly.WebCompiler.Loader"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1810,6 +1842,22 @@
|
||||
"Mixly.WebSocket.File"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/web-socket/loader.js",
|
||||
"require": [
|
||||
"Mixly.Debug",
|
||||
"Mixly.Config",
|
||||
"Mixly.StatusBarsManager",
|
||||
"Mixly.Socket",
|
||||
"Mixly.WebSocket.Serial",
|
||||
"Mixly.WebSocket.ArduShell",
|
||||
"Mixly.WebSocket.BU",
|
||||
"Mixly.WebSocket.Ampy"
|
||||
],
|
||||
"provide": [
|
||||
"Mixly.WebSocket.Loader"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/web-socket/serial.js",
|
||||
"require": [
|
||||
@@ -1824,25 +1872,9 @@
|
||||
"Mixly.WebSocket.Serial"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/web-socket/socket.js",
|
||||
"require": [
|
||||
"Mixly.Debug",
|
||||
"Mixly.StatusBarsManager",
|
||||
"Mixly.WebSocket",
|
||||
"Mixly.WebSocket.Serial",
|
||||
"Mixly.WebSocket.ArduShell",
|
||||
"Mixly.WebSocket.BU",
|
||||
"Mixly.WebSocket.Ampy"
|
||||
],
|
||||
"provide": [
|
||||
"Mixly.WebSocket.Socket"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/web-socket/web-socket.js",
|
||||
"require": [
|
||||
"io",
|
||||
"Mixly"
|
||||
],
|
||||
"provide": [
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
goog.loadJs('electron', () => {
|
||||
|
||||
goog.require('path');
|
||||
goog.require('Mixly.Url');
|
||||
goog.require('Mixly.Config');
|
||||
goog.require('Mixly.Env');
|
||||
@@ -32,7 +33,7 @@ Loader.onbeforeunload = function(reload = false) {
|
||||
window.location.reload(true);
|
||||
}
|
||||
}
|
||||
let href = Env.srcDirPath + '/index.html?' + Url.jsonToUrl({ boardType: BOARD.boardType ?? 'None' });
|
||||
let href = path.join(Env.srcDirPath, 'index.html') + '?' + Url.jsonToUrl({ boardType: BOARD.boardType ?? 'None' });
|
||||
let endPromise = [];
|
||||
const { mainStatusBarTabs } = Mixly;
|
||||
Serial.getCurrentPortsName().map((name) => {
|
||||
|
||||
399
common/modules/mixly-modules/web-compiler/arduino-shell.js
Normal file
399
common/modules/mixly-modules/web-compiler/arduino-shell.js
Normal file
@@ -0,0 +1,399 @@
|
||||
goog.loadJs('web', () => {
|
||||
|
||||
goog.require('layui');
|
||||
goog.require('avrbro');
|
||||
goog.require('esptooljs');
|
||||
goog.require('AdafruitESPTool');
|
||||
goog.require('CryptoJS');
|
||||
goog.require('dayjs.duration');
|
||||
goog.require('Mixly.Boards');
|
||||
goog.require('Mixly.Debug');
|
||||
goog.require('Mixly.LayerExt');
|
||||
goog.require('Mixly.Msg');
|
||||
goog.require('Mixly.Workspace');
|
||||
goog.require('Mixly.LayerProgress');
|
||||
goog.require('Mixly.Web.Serial');
|
||||
goog.require('Mixly.WebCompiler');
|
||||
goog.provide('Mixly.WebCompiler.ArduShell');
|
||||
|
||||
const {
|
||||
Boards,
|
||||
Debug,
|
||||
LayerExt,
|
||||
Msg,
|
||||
Workspace,
|
||||
LayerProgress,
|
||||
Web,
|
||||
WebCompiler
|
||||
} = Mixly;
|
||||
|
||||
const { Serial } = Web;
|
||||
const { layer } = layui;
|
||||
const { ESPLoader, Transport } = esptooljs;
|
||||
|
||||
|
||||
function hexToBinaryString (hex) {
|
||||
let binaryString = '';
|
||||
for (let i = 0; i < hex.length; i += 2) {
|
||||
const byte = parseInt(hex.substr(i, 2), 16);
|
||||
binaryString += String.fromCharCode(byte);
|
||||
}
|
||||
return binaryString;
|
||||
}
|
||||
|
||||
class WebCompilerArduShell {
|
||||
static {
|
||||
this.mixlySocket = null;
|
||||
this.socket = null;
|
||||
this.shell = null;
|
||||
|
||||
this.getSocket = function () {
|
||||
return this.socket;
|
||||
}
|
||||
|
||||
this.getMixlySocket = function () {
|
||||
return this.mixlySocket;
|
||||
}
|
||||
|
||||
this.init = function (mixlySocket) {
|
||||
this.mixlySocket = mixlySocket;
|
||||
this.socket = mixlySocket.getSocket();
|
||||
this.shell = new WebCompilerArduShell();
|
||||
const socket = this.socket;
|
||||
|
||||
socket.on('arduino.dataEvent', (data) => {
|
||||
if (data.length > 1000) {
|
||||
return;
|
||||
}
|
||||
const { mainStatusBarTabs } = Mixly;
|
||||
const statusBarTerminal = mainStatusBarTabs.getStatusBarById('output');
|
||||
statusBarTerminal.addValue(data);
|
||||
});
|
||||
|
||||
socket.on('arduino.errorEvent', (data) => {
|
||||
const { mainStatusBarTabs } = Mixly;
|
||||
const statusBarTerminal = mainStatusBarTabs.getStatusBarById('output');
|
||||
try {
|
||||
data = unescape(data.replace(/(_E[0-9A-F]{1}_[0-9A-F]{2}_[0-9A-F]{2})+/gm, '%$1'));
|
||||
data = unescape(data.replace(/\\(u[0-9a-fA-F]{4})/gm, '%$1'));
|
||||
} catch (error) {
|
||||
Debug.error(error);
|
||||
}
|
||||
statusBarTerminal.addValue(data);
|
||||
});
|
||||
}
|
||||
|
||||
this.initCompile = function () {
|
||||
if (!this.mixlySocket.isConnected()) {
|
||||
layer.msg(Msg.Lang['websocket.offline'], { time: 1000 });
|
||||
return;
|
||||
}
|
||||
const { mainStatusBarTabs } = Mixly;
|
||||
const statusBarTerminal = mainStatusBarTabs.getStatusBarById('output');
|
||||
mainStatusBarTabs.changeTo('output');
|
||||
mainStatusBarTabs.show();
|
||||
const mainWorkspace = Workspace.getMain();
|
||||
const editor = mainWorkspace.getEditorsManager().getActive();
|
||||
const code = editor.getCode();
|
||||
statusBarTerminal.setValue(`${Msg.Lang['shell.compiling']}...\n`);
|
||||
this.shell.compile(code)
|
||||
.then((info) => {
|
||||
this.endCallback(info.code, info.time);
|
||||
})
|
||||
.catch((error) => {
|
||||
Debug.error(error);
|
||||
statusBarTerminal.addValue(`\n==${Msg.Lang['shell.compileFailed']}==\n`);
|
||||
});
|
||||
}
|
||||
|
||||
this.initUpload = function () {
|
||||
if (!this.mixlySocket.isConnected()) {
|
||||
layer.msg(Msg.Lang['websocket.offline'], { time: 1000 });
|
||||
return;
|
||||
}
|
||||
const port = Serial.getSelectedPortName();
|
||||
if (!port) {
|
||||
layer.msg(Msg.Lang['statusbar.serial.noDevice'], {
|
||||
time: 1000
|
||||
});
|
||||
return;
|
||||
}
|
||||
const { mainStatusBarTabs } = Mixly;
|
||||
const statusBarTerminal = mainStatusBarTabs.getStatusBarById('output');
|
||||
mainStatusBarTabs.changeTo('output');
|
||||
mainStatusBarTabs.show();
|
||||
statusBarTerminal.setValue(`${Msg.Lang['shell.uploading']}...\n`);
|
||||
const mainWorkspace = Workspace.getMain();
|
||||
const editor = mainWorkspace.getEditorsManager().getActive();
|
||||
const code = editor.getCode();
|
||||
const statusBarSerial = mainStatusBarTabs.getStatusBarById(port);
|
||||
const closePromise = statusBarSerial ? statusBarSerial.close() : Promise.resolve();
|
||||
closePromise
|
||||
.then(() => {
|
||||
return this.shell.upload(port, code)
|
||||
})
|
||||
.then((info) => {
|
||||
this.endCallback(info.code, info.time);
|
||||
if (info.code || !Serial.portIsLegal(port)) {
|
||||
return;
|
||||
}
|
||||
mainStatusBarTabs.add('serial', port);
|
||||
mainStatusBarTabs.changeTo(port);
|
||||
const statusBarSerial = mainStatusBarTabs.getStatusBarById(port);
|
||||
statusBarSerial.open()
|
||||
.then(() => {
|
||||
const baudRates = code.match(/(?<=Serial.begin[\s]*\([\s]*)[0-9]*(?=[\s]*\))/g);
|
||||
if (!baudRates?.length) {
|
||||
return statusBarSerial.setBaudRate(9600);
|
||||
} else {
|
||||
return statusBarSerial.setBaudRate(baudRates[0] - 0);
|
||||
}
|
||||
})
|
||||
.catch(Debug.error);
|
||||
})
|
||||
.catch((error) => {
|
||||
Debug.error(error);
|
||||
statusBarTerminal.addValue(`\n==${Msg.Lang['shell.uploadFailed']}==\n`);
|
||||
});
|
||||
}
|
||||
|
||||
this.endCallback = function (code, time) {
|
||||
const { mainStatusBarTabs } = Mixly;
|
||||
const statusBarTerminal = mainStatusBarTabs.getStatusBarById('output');
|
||||
mainStatusBarTabs.changeTo('output');
|
||||
let message = '';
|
||||
if (code) {
|
||||
message = (this.shell.isCompiling() ? Msg.Lang['shell.compileFailed'] : Msg.Lang['shell.uploadFailed']);
|
||||
statusBarTerminal.addValue(`\n==${message}==\n`);
|
||||
} else {
|
||||
message = (this.shell.isCompiling() ? Msg.Lang['shell.compileSucc'] : Msg.Lang['shell.uploadSucc']);
|
||||
statusBarTerminal.addValue(`\n==${message}(${Msg.Lang['shell.timeCost']} ${
|
||||
dayjs.duration(time).format('HH:mm:ss.SSS')
|
||||
})==\n`);
|
||||
}
|
||||
layer.msg(message, { time: 1000 });
|
||||
}
|
||||
}
|
||||
|
||||
#running_ = false;
|
||||
#upload_ = false;
|
||||
#killing_ = false;
|
||||
#layer_ = null;
|
||||
|
||||
constructor() {
|
||||
this.#layer_ = new LayerProgress({
|
||||
width: 200,
|
||||
cancelValue: Msg.Lang['nav.btn.stop'],
|
||||
skin: 'layui-anim layui-anim-scale',
|
||||
cancel: () => {
|
||||
if (this.#killing_) {
|
||||
return false;
|
||||
}
|
||||
this.#layer_.title(`${Msg.Lang['shell.aborting']}...`);
|
||||
this.#killing_ = true;
|
||||
this.kill().catch(Debug.error);
|
||||
return false;
|
||||
},
|
||||
cancelDisplay: false
|
||||
});
|
||||
}
|
||||
|
||||
async compile(code) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
this.#running_ = true;
|
||||
this.#upload_ = false;
|
||||
this.#killing_ = false;
|
||||
this.showProgress();
|
||||
const key = Boards.getSelectedBoardCommandParam();
|
||||
const config = { key, code };
|
||||
const mixlySocket = WebCompilerArduShell.getMixlySocket();
|
||||
mixlySocket.emit('arduino.compile', config, (response) => {
|
||||
this.hideProgress();
|
||||
if (response.error) {
|
||||
reject(response.error);
|
||||
return;
|
||||
}
|
||||
const [error, result] = response;
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve(result);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async upload(port, code) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
this.#running_ = true;
|
||||
this.#upload_ = true;
|
||||
this.#killing_ = false;
|
||||
this.showProgress();
|
||||
const key = Boards.getSelectedBoardCommandParam();
|
||||
const config = { key, code };
|
||||
const mixlySocket = WebCompilerArduShell.getMixlySocket();
|
||||
mixlySocket.emit('arduino.upload', config, async (response) => {
|
||||
if (response.error) {
|
||||
this.hideProgress();
|
||||
reject(response.error);
|
||||
return;
|
||||
}
|
||||
const [error, result] = response;
|
||||
if (error) {
|
||||
this.hideProgress();
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
if (result.code !== 0) {
|
||||
this.hideProgress();
|
||||
resolve(result);
|
||||
return;
|
||||
}
|
||||
const { files } = result;
|
||||
try {
|
||||
const keys = Boards.getSelectedBoardKey().split(':');
|
||||
if (`${keys[0]}:${keys[1]}` === 'arduino:avr') {
|
||||
await this.uploadWithAvrbro(port, files);
|
||||
} else {
|
||||
await this.uploadWithEsptool(port, files);
|
||||
}
|
||||
} catch (error) {
|
||||
this.hideProgress();
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
this.hideProgress();
|
||||
result.files = null;
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async uploadWithEsptool(port, files) {
|
||||
const { mainStatusBarTabs } = Mixly;
|
||||
const statusBarTerminal = mainStatusBarTabs.getStatusBarById('output');
|
||||
let esploader = null;
|
||||
let transport = null;
|
||||
let baudrate = 115200;
|
||||
let eraseAll = true;
|
||||
try {
|
||||
const keys = Boards.getSelectedBoardKey().split(':');
|
||||
if (`${keys[0]}:${keys[1]}` === 'esp32:esp32') {
|
||||
baudrate = Boards.getSelectedBoardConfigParam('UploadSpeed');
|
||||
eraseAll = Boards.getSelectedBoardConfigParam('EraseFlash') === 'all';
|
||||
} else {
|
||||
baudrate = Boards.getSelectedBoardConfigParam('baud');
|
||||
eraseAll = Boards.getSelectedBoardConfigParam('wipe') === 'all';
|
||||
}
|
||||
transport = new Transport(Serial.getPort(port), false);
|
||||
esploader = new ESPLoader({
|
||||
transport,
|
||||
baudrate,
|
||||
terminal: {
|
||||
clean() {},
|
||||
writeLine(data) {
|
||||
statusBarTerminal.addValue(data + '\n');
|
||||
},
|
||||
write(data) {
|
||||
statusBarTerminal.addValue(data);
|
||||
}
|
||||
}
|
||||
});
|
||||
let chip = await esploader.main();
|
||||
} catch (error) {
|
||||
await transport.disconnect();
|
||||
throw new Error(error);
|
||||
}
|
||||
let data = [];
|
||||
statusBarTerminal.addValue("\n");
|
||||
for (let file of files) {
|
||||
if (file.data && file.offset) {
|
||||
data.push({
|
||||
address: parseInt(file.offset, 16),
|
||||
data: hexToBinaryString(file.data)
|
||||
});
|
||||
}
|
||||
}
|
||||
const flashOptions = {
|
||||
fileArray: data,
|
||||
flashSize: 'keep',
|
||||
eraseAll,
|
||||
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);
|
||||
await transport.disconnect();
|
||||
} catch (error) {
|
||||
await transport.disconnect();
|
||||
throw new Error(error);
|
||||
}
|
||||
}
|
||||
|
||||
async uploadWithAvrbro(port, files) {
|
||||
const key = Boards.getSelectedBoardKey();
|
||||
const boardId = key.split(':')[2];
|
||||
let boardName = '';
|
||||
if (boardId === 'uno') {
|
||||
boardName = 'uno';
|
||||
} else if (boardId === 'nano') {
|
||||
const cpu = Boards.getSelectedBoardConfigParam('cpu');
|
||||
if (cpu === 'atmega328old') {
|
||||
boardName = 'nano';
|
||||
} else {
|
||||
boardName = 'nano (new bootloader)';
|
||||
}
|
||||
} else if (boardId === 'pro') {
|
||||
boardName = 'pro-mini';
|
||||
} else if (boardId === 'mega') {
|
||||
boardName = 'mega';
|
||||
} else if (boardId === 'leonardo') {
|
||||
boardName = 'leonardo';
|
||||
}
|
||||
const buffer = avrbro.parseHex(files[0].data);
|
||||
await avrbro.flash(Serial.getPort(port), buffer, { boardName });
|
||||
}
|
||||
|
||||
async kill() {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const mixlySocket = WebCompilerArduShell.getMixlySocket();
|
||||
mixlySocket.emit('arduino.kill', (response) => {
|
||||
if (response.error) {
|
||||
reject(response.error);
|
||||
return;
|
||||
}
|
||||
const [error, result] = response;
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve(result);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
showProgress() {
|
||||
const message = this.isCompiling() ? Msg.Lang['shell.compiling'] : Msg.Lang['shell.uploading'];
|
||||
this.#layer_.title(`${message}...`);
|
||||
this.#layer_.show();
|
||||
}
|
||||
|
||||
hideProgress() {
|
||||
this.#layer_.hide();
|
||||
}
|
||||
|
||||
isUploading() {
|
||||
return this.#running_ && this.#upload_;
|
||||
}
|
||||
|
||||
isCompiling() {
|
||||
return this.#running_ && !this.#upload_;
|
||||
}
|
||||
}
|
||||
|
||||
WebCompiler.ArduShell = WebCompilerArduShell;
|
||||
|
||||
});
|
||||
@@ -1,184 +0,0 @@
|
||||
goog.loadJs('web', () => {
|
||||
|
||||
goog.require('Mixly.Url');
|
||||
goog.require('Mixly.Config');
|
||||
goog.require('Mixly.LayerExt');
|
||||
goog.require('Mixly.Boards');
|
||||
goog.require('Mixly.MFile');
|
||||
goog.require('Mixly.Msg');
|
||||
goog.require('Mixly.Web.BU');
|
||||
goog.require('Mixly.Web.Serial');
|
||||
goog.provide('Mixly.WebCompiler.Compiler');
|
||||
|
||||
const {
|
||||
WebCompiler,
|
||||
Url,
|
||||
Boards,
|
||||
MFile,
|
||||
Config,
|
||||
LayerExt,
|
||||
Msg,
|
||||
Web
|
||||
} = Mixly;
|
||||
const { SOFTWARE, BOARD } = Config;
|
||||
const { Compiler } = WebCompiler;
|
||||
const { BU, Serial } = Web;
|
||||
|
||||
const DEFAULT_CONFIG = {
|
||||
"enabled": true,
|
||||
"protocol": "http:",
|
||||
"ip": "localhost",
|
||||
"domain": null
|
||||
};
|
||||
|
||||
Compiler.CONFIG = { ...DEFAULT_CONFIG, ...(SOFTWARE?.webCompiler ?? {}) };
|
||||
const { CONFIG } = Compiler;
|
||||
let { hostname, protocol, port } = window.location;
|
||||
if (port) {
|
||||
port = ':' + port;
|
||||
}
|
||||
Compiler.protocol = protocol;
|
||||
Compiler.URL = Compiler.protocol + '//' + hostname + port + '/compile';
|
||||
|
||||
Compiler.compile = () => {
|
||||
const { mainStatusBarTabs } = Mixly;
|
||||
const statusBarTerminal = mainStatusBarTabs.getStatusBarById('output');
|
||||
mainStatusBarTabs.show();
|
||||
statusBarTerminal.setValue('');
|
||||
Compiler.generateCommand('compile', (error, obj, layerNum) => {
|
||||
layer.close(layerNum);
|
||||
let message = Msg.Lang['shell.compileSucc'];
|
||||
if (error) {
|
||||
message = Msg.Lang['shell.compileFailed'];
|
||||
}
|
||||
layer.msg(message, { time: 1000 });
|
||||
statusBarTerminal.addValue("==" + message + "(" + Msg.Lang['shell.timeCost'] + " " + obj.timeCost + ")==\n");
|
||||
});
|
||||
}
|
||||
|
||||
Compiler.upload = async () => {
|
||||
const { mainStatusBarTabs } = Mixly;
|
||||
const statusBarTerminal = mainStatusBarTabs.getStatusBarById('output');
|
||||
mainStatusBarTabs.show();
|
||||
statusBarTerminal.setValue('');
|
||||
BU.burning = false;
|
||||
BU.uploading = true;
|
||||
const board = Boards.getSelectedBoardCommandParam();
|
||||
const boardParam = board.split(':');
|
||||
const portName = 'web-serial';
|
||||
if (boardParam[1] === 'avr') {
|
||||
let boardUpload;
|
||||
switch (boardParam[2]) {
|
||||
case 'uno':
|
||||
boardUpload = 'uno';
|
||||
break;
|
||||
case 'nano':
|
||||
if (boardParam.length > 3 && boardParam[3] === 'cpu=atmega328old') {
|
||||
boardUpload = 'nanoOldBootloader';
|
||||
} else {
|
||||
boardUpload = 'nano';
|
||||
}
|
||||
break;
|
||||
case 'pro':
|
||||
boardUpload = 'proMini';
|
||||
break;
|
||||
}
|
||||
Serial.portClose(portName, async () => {
|
||||
mainStatusBarTabs.changeTo('output');
|
||||
try {
|
||||
await AvrUploader.connect(boardUpload, {});
|
||||
Compiler.generateCommand('upload', BU.uploadWithAvrUploader);
|
||||
} catch (error) {
|
||||
statusBarTerminal.addValue(error.toString() + '\n');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Serial.connect(portName, 115200, async (port) => {
|
||||
if (!port) {
|
||||
layer.msg(Msg.Lang['已取消连接'], { time: 1000 });
|
||||
return;
|
||||
}
|
||||
mainStatusBarTabs.changeTo('output');
|
||||
Compiler.generateCommand('upload', BU.uploadWithEsptool);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Compiler.generateCommand = (operate, endFunc = (errorMessage, data, layerNum) => {}) => {
|
||||
const code = MFile.getCode();
|
||||
let type;
|
||||
const boardType = Boards.getSelectedBoardCommandParam();
|
||||
let command = {
|
||||
board: encodeURIComponent(boardType),
|
||||
code: encodeURIComponent(code),
|
||||
visitorId: BOARD.visitorId.str32CRC32b,
|
||||
operate
|
||||
};
|
||||
const { mainStatusBarTabs } = Mixly;
|
||||
const statusBarTerminal = mainStatusBarTabs.getStatusBarById('output');
|
||||
let commandStr = Compiler.URL + '?' + Url.jsonToUrl(command);
|
||||
statusBarTerminal.setValue(Msg.Lang['shell.compiling'] + '...\n');
|
||||
console.log('send -> ', commandStr);
|
||||
const compileLayer = layer.open({
|
||||
type: 1,
|
||||
title: Msg.Lang['shell.compiling'] + "...",
|
||||
content: $('#mixly-loader-div'),
|
||||
shade: LayerExt.SHADE_NAV,
|
||||
closeBtn: 0,
|
||||
success: function () {
|
||||
$(".layui-layer-page").css("z-index", "198910151");
|
||||
$("#mixly-loader-btn").off("click").click(() => {
|
||||
layer.close(compileLayer);
|
||||
});
|
||||
},
|
||||
end: function () {
|
||||
$('#mixly-loader-div').css('display', 'none');
|
||||
$(".layui-layer-shade").remove();
|
||||
}
|
||||
});
|
||||
Compiler.sendCommand(compileLayer, commandStr, endFunc);
|
||||
}
|
||||
|
||||
Compiler.sendCommand = (layerType, command, endFunc = (errorMessage, data, layerNum) => {}) => {
|
||||
/*
|
||||
fetch(command).then(function(response) {
|
||||
console.log(response);
|
||||
if(response.ok) {
|
||||
return response.blob();
|
||||
}
|
||||
throw new Error('Network response was not ok.');
|
||||
}).then(function(myBlob) {
|
||||
var objectURL = URL.createObjectURL(myBlob);
|
||||
console.log(objectURL);
|
||||
}).catch(function(error) {
|
||||
console.log('There has been a problem with your fetch operation: ', error.message);
|
||||
});
|
||||
*/
|
||||
const { mainStatusBarTabs } = Mixly;
|
||||
const statusBarTerminal = mainStatusBarTabs.getStatusBarById('output');
|
||||
let req = new Request(command);
|
||||
fetch(req, {
|
||||
credentials: 'omit', // 设置不传递cookie
|
||||
mode: 'cors', // 设置请求不允许跨域
|
||||
}).then(res => {
|
||||
return res.text();
|
||||
}).then((data) => {
|
||||
const dataObj = JSON.parse(data);
|
||||
console.log(dataObj);
|
||||
if (dataObj.error) {
|
||||
statusBarTerminal.addValue(decodeURIComponent(dataObj.error));
|
||||
endFunc(true, null, layerType);
|
||||
} else {
|
||||
statusBarTerminal.addValue(decodeURIComponent(dataObj.compileMessage));
|
||||
endFunc(false, {
|
||||
data: dataObj.data,
|
||||
timeCost: decodeURIComponent(dataObj.timeCost)
|
||||
}, layerType);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
endFunc(true, error.toString(), layerType);
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
53
common/modules/mixly-modules/web-compiler/loader.js
Normal file
53
common/modules/mixly-modules/web-compiler/loader.js
Normal file
@@ -0,0 +1,53 @@
|
||||
goog.loadJs('web', () => {
|
||||
|
||||
goog.require('Mixly.Debug');
|
||||
goog.require('Mixly.Config');
|
||||
goog.require('Mixly.StatusBarsManager');
|
||||
goog.require('Mixly.Socket');
|
||||
goog.require('Mixly.WebCompiler.ArduShell');
|
||||
goog.provide('Mixly.WebCompiler.Loader');
|
||||
|
||||
const {
|
||||
Debug,
|
||||
Config,
|
||||
StatusBarsManager,
|
||||
Socket,
|
||||
WebCompiler
|
||||
} = Mixly;
|
||||
|
||||
const {
|
||||
Loader,
|
||||
ArduShell
|
||||
} = WebCompiler;
|
||||
|
||||
const { SOFTWARE } = Config;
|
||||
|
||||
|
||||
Loader.init = function () {
|
||||
let url = '';
|
||||
if (SOFTWARE.webCompiler?.url) {
|
||||
const info = new window.URL(SOFTWARE.webCompiler.url);
|
||||
if (info.hostname === 'default') {
|
||||
info.hostname = window.location.hostname;
|
||||
url = info.origin;
|
||||
} else {
|
||||
url = SOFTWARE.webCompiler.url;
|
||||
}
|
||||
} else {
|
||||
url = `wss://${window.location.host}`;
|
||||
}
|
||||
const mixlySocket = new Socket(`${url}/compile`, {
|
||||
path: '/mixly-socket/',
|
||||
reconnection: true,
|
||||
reconnectionDelayMax: 10000,
|
||||
transports: ['websocket'],
|
||||
protocols: ['my-protocol-v1']
|
||||
});
|
||||
|
||||
const socket = mixlySocket.getSocket();
|
||||
socket.on('connect', () => {});
|
||||
socket.on('disconnect', () => {});
|
||||
ArduShell.init(mixlySocket);
|
||||
}
|
||||
|
||||
});
|
||||
@@ -128,7 +128,7 @@ class WebSocketArduShell {
|
||||
statusBarSerial.open()
|
||||
.then(() => {
|
||||
const baudRates = code.match(/(?<=Serial.begin[\s]*\([\s]*)[0-9]*(?=[\s]*\))/g);
|
||||
if (!baudRates.length) {
|
||||
if (!baudRates?.length) {
|
||||
return statusBarSerial.setBaudRate(9600);
|
||||
} else {
|
||||
return statusBarSerial.setBaudRate(baudRates[0] - 0);
|
||||
|
||||
@@ -1,31 +1,48 @@
|
||||
goog.loadJs('web', () => {
|
||||
|
||||
goog.require('Mixly.Debug');
|
||||
goog.require('Mixly.Config');
|
||||
goog.require('Mixly.StatusBarsManager');
|
||||
goog.require('Mixly.WebSocket');
|
||||
goog.require('Mixly.Socket');
|
||||
goog.require('Mixly.WebSocket.Serial');
|
||||
goog.require('Mixly.WebSocket.ArduShell');
|
||||
goog.require('Mixly.WebSocket.BU');
|
||||
goog.require('Mixly.WebSocket.Ampy');
|
||||
goog.provide('Mixly.WebSocket.Socket');
|
||||
goog.provide('Mixly.WebSocket.Loader');
|
||||
|
||||
const {
|
||||
Debug,
|
||||
Config,
|
||||
StatusBarsManager,
|
||||
Socket,
|
||||
WebSocket
|
||||
} = Mixly;
|
||||
|
||||
const {
|
||||
Socket,
|
||||
Loader,
|
||||
Serial,
|
||||
ArduShell,
|
||||
BU,
|
||||
Ampy
|
||||
} = WebSocket;
|
||||
|
||||
const { SOFTWARE } = Config;
|
||||
|
||||
Socket.init = function () {
|
||||
const mixlySocket = new WebSocket('wss://127.0.0.1:4000', {
|
||||
|
||||
Loader.init = function () {
|
||||
let url = '';
|
||||
if (SOFTWARE.webSocket?.url) {
|
||||
const info = new window.URL(SOFTWARE.webSocket.url);
|
||||
if (info.hostname === 'default') {
|
||||
info.hostname = window.location.hostname;
|
||||
url = info.origin;
|
||||
} else {
|
||||
url = SOFTWARE.webSocket.url;
|
||||
}
|
||||
} else {
|
||||
url = `wss://${window.location.host}`;
|
||||
}
|
||||
const mixlySocket = new Socket(`${url}/all`, {
|
||||
path: '/mixly-socket/',
|
||||
reconnection: true,
|
||||
reconnectionDelayMax: 10000,
|
||||
@@ -1,91 +1,6 @@
|
||||
goog.loadJs('web', () => {
|
||||
|
||||
goog.require('io');
|
||||
goog.require('Mixly');
|
||||
goog.provide('Mixly.WebSocket');
|
||||
|
||||
|
||||
class WebSocket {
|
||||
#socket_ = null;
|
||||
constructor(path, option) {
|
||||
this.#socket_ = io(path, option);
|
||||
}
|
||||
|
||||
#detectStatus_(status, callback) {
|
||||
window.setTimeout(() => {
|
||||
if (status.finished) {
|
||||
return;
|
||||
}
|
||||
if (this.isConnected()) {
|
||||
this.#detectStatus_(status, callback);
|
||||
} else {
|
||||
callback({
|
||||
error: 'socket is not connected'
|
||||
});
|
||||
status.finished = true;
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
emit(eventName, ...args) {
|
||||
const callback = args.pop();
|
||||
if (this.isConnected()) {
|
||||
let emitStatus = {
|
||||
finished: false
|
||||
};
|
||||
let status = this.#socket_.emit(eventName, ...args, (...callbackArgs) => {
|
||||
if (emitStatus.finished) {
|
||||
return;
|
||||
}
|
||||
emitStatus.finished = true;
|
||||
callback(...callbackArgs);
|
||||
});
|
||||
this.#detectStatus_(emitStatus, callback);
|
||||
return status;
|
||||
} else {
|
||||
callback({
|
||||
error: 'socket is not connected'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async emitAsync(eventName, ...args) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (this.isConnected()) {
|
||||
const callback = (...callbackArgs) => {
|
||||
if (callbackArgs[0].error) {
|
||||
reject(callbackArgs[0].error);
|
||||
return;
|
||||
}
|
||||
resolve(...callbackArgs);
|
||||
}
|
||||
let emitStatus = {
|
||||
finished: false
|
||||
};
|
||||
let status = this.#socket_.emit(eventName, ...args, (...callbackArgs) => {
|
||||
if (emitStatus.finished) {
|
||||
return;
|
||||
}
|
||||
emitStatus.finished = true;
|
||||
callback(...callbackArgs);
|
||||
});
|
||||
this.#detectStatus_(emitStatus, callback);
|
||||
} else {
|
||||
reject('socket is not connected');
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
getSocket() {
|
||||
return this.#socket_;
|
||||
}
|
||||
|
||||
isConnected() {
|
||||
return this.#socket_?.connected;
|
||||
}
|
||||
}
|
||||
|
||||
Mixly.WebSocket = WebSocket;
|
||||
|
||||
});
|
||||
@@ -166,11 +166,13 @@ class AmpyExt extends Ampy {
|
||||
if (data.length < 1) {
|
||||
throw new Error(Msg.Lang['ampy.waitingFirstEOFTimeout']);
|
||||
}
|
||||
let start = data.toLowerCase().indexOf('>ok');
|
||||
if (start === -1){
|
||||
let start = data.toLowerCase().lastIndexOf('ok');
|
||||
if (start === -1) {
|
||||
start = 0;
|
||||
} else {
|
||||
start += 2;
|
||||
}
|
||||
data = data.substring(start + 3, data.length - 1);
|
||||
data = data.substring(start, data.length - 1);
|
||||
let dataError = await this.readUntil('\x04', true, timeout);
|
||||
if (dataError.length < 1) {
|
||||
throw new Error(Msg.Lang['ampy.secondEOFTimeout']);
|
||||
|
||||
@@ -5,10 +5,9 @@ goog.require('BoardId');
|
||||
goog.require('FSWrapper');
|
||||
goog.require('DAPWrapper');
|
||||
goog.require('PartialFlashing');
|
||||
goog.require('ESPTool');
|
||||
goog.require('esptooljs');
|
||||
goog.require('AdafruitESPTool');
|
||||
goog.require('CryptoJS');
|
||||
goog.require('AvrUploader');
|
||||
goog.require('Mixly.Env');
|
||||
goog.require('Mixly.LayerExt');
|
||||
goog.require('Mixly.Config');
|
||||
@@ -52,7 +51,7 @@ const { BOARD, SELECTED_BOARD } = Config;
|
||||
const {
|
||||
ESPLoader,
|
||||
Transport
|
||||
} = ESPTool;
|
||||
} = esptooljs;
|
||||
|
||||
BU.uploading = false;
|
||||
BU.burning = false;
|
||||
@@ -333,6 +332,9 @@ BU.burnWithEsptool = async (binFile, erase) => {
|
||||
};
|
||||
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`);
|
||||
@@ -660,6 +662,9 @@ BU.uploadWithAmpy = async (portName) => {
|
||||
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) {
|
||||
@@ -692,110 +697,6 @@ BU.uploadWithAmpy = async (portName) => {
|
||||
}
|
||||
}
|
||||
|
||||
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}
|
||||
|
||||
File diff suppressed because one or more lines are too long
1
common/modules/web-modules/avrbro.min.js
vendored
Normal file
1
common/modules/web-modules/avrbro.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
18
common/modules/web-modules/esptool.min.js
vendored
18
common/modules/web-modules/esptool.min.js
vendored
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user