Update: win7支持同时使用Serial和HID

This commit is contained in:
王立帮
2025-03-06 18:20:50 +08:00
parent 1590712159
commit fa3b4781e1
13 changed files with 277 additions and 127 deletions

View File

@@ -239,9 +239,6 @@ class App extends Component {
id: 'command-burn-btn',
displayText: Msg.Lang['nav.btn.burn'],
preconditionFn: () => {
if (!goog.isElectron && !goog.hasSocketServer && Serial.type !== 'serialport') {
return false;
}
return SELECTED_BOARD?.nav?.burn;
},
callback: () => BU.initBurn(),

View File

@@ -2,6 +2,7 @@ goog.loadJs('common', () => {
goog.require('Mixly.Config');
goog.require('Mixly.Events');
goog.require('Mixly.Registry');
goog.require('Mixly.Nav');
goog.require('Mixly.Msg');
goog.provide('Mixly.Serial');
@@ -9,6 +10,7 @@ goog.provide('Mixly.Serial');
const {
Config,
Events,
Registry,
Nav,
Msg
} = Mixly;
@@ -19,6 +21,8 @@ const { SELECTED_BOARD } = Config;
class Serial {
static {
this.portsName = [];
this.portToNameRegistry = new Registry();
this.nameToPortRegistry = new Registry();
this.DEFAULT_CONFIG = {
ctrlCBtn: false,
ctrlDBtn: false,
@@ -42,6 +46,14 @@ class Serial {
return this.portsName;
}
this.refreshPorts = function () {
let portsName = [];
for (let name of Serial.nameToPortRegistry.keys()) {
portsName.push({ name });
}
Serial.renderSelectBox(portsName);
}
this.getConfig = function () {
let config = SELECTED_BOARD?.serial ?? {};
return {

View File

@@ -840,6 +840,7 @@
"require": [
"Mixly.Config",
"Mixly.Events",
"Mixly.Registry",
"Mixly.Nav",
"Mixly.Msg"
],
@@ -1626,7 +1627,6 @@
"path": "/web/hid.js",
"require": [
"Mixly.Serial",
"Mixly.Registry",
"Mixly.Web"
],
"provide": [
@@ -1636,8 +1636,14 @@
{
"path": "/web/serial.js",
"require": [
"path",
"Mixly.Config",
"Mixly.Env",
"Mixly.Msg",
"Mixly.Registry",
"Mixly.Serial",
"Mixly.LayerExt",
"Mixly.HTMLTemplate",
"Mixly.Web.SerialPort",
"Mixly.Web.USB",
"Mixly.Web.USBMini",
@@ -1651,7 +1657,6 @@
"path": "/web/serialport.js",
"require": [
"Mixly.Serial",
"Mixly.Registry",
"Mixly.Debug",
"Mixly.Web"
],

View File

@@ -249,11 +249,15 @@ BU.burnWithEsptool = async (binFile, erase) => {
return;
}
}
const port = Serial.getPort(portName);
if (port instanceof window.HIDDevice || port instanceof window.USBDevice) {
layer.msg(Msg.Lang['burn.notSupport'], { time: 1000 });
return;
}
const statusBarSerial = mainStatusBarTabs.getStatusBarById(portName);
if (statusBarSerial) {
await statusBarSerial.close();
}
const port = Serial.getPort(portName);
const statusBarTerminal = mainStatusBarTabs.getStatusBarById('output');
statusBarTerminal.setValue(Msg.Lang['shell.burning'] + '...\n');
mainStatusBarTabs.show();
@@ -365,11 +369,15 @@ BU.burnWithAdafruitEsptool = async (binFile, erase) => {
return;
}
}
const port = Serial.getPort(portName);
if (port instanceof window.HIDDevice || port instanceof window.USBDevice) {
layer.msg(Msg.Lang['burn.notSupport'], { time: 1000 });
return;
}
const statusBarSerial = mainStatusBarTabs.getStatusBarById(portName);
if (statusBarSerial) {
await statusBarSerial.close();
}
const port = Serial.getPort(portName);
const statusBarTerminal = mainStatusBarTabs.getStatusBarById('output');
statusBarTerminal.setValue(Msg.Lang['shell.burning'] + '...\n');
mainStatusBarTabs.show();

View File

@@ -1,13 +1,11 @@
goog.loadJs('web', () => {
goog.require('Mixly.Serial');
goog.require('Mixly.Registry');
goog.require('Mixly.Web');
goog.provide('Mixly.Web.HID');
const {
Serial,
Registry,
Web
} = Mixly;
@@ -15,8 +13,6 @@ const {
class WebHID extends Serial {
static {
this.type = 'hid';
this.portToNameRegistry = new Registry();
this.nameToPortRegistry = new Registry();
this.getConfig = function () {
return Serial.getConfig();
@@ -31,11 +27,7 @@ class WebHID extends Serial {
}
this.refreshPorts = function () {
let portsName = [];
for (let name of this.nameToPortRegistry.keys()) {
portsName.push({ name });
}
Serial.renderSelectBox(portsName);
Serial.refreshPorts();;
}
this.requestPort = async function () {
@@ -52,35 +44,35 @@ class WebHID extends Serial {
}
this.getPort = function (name) {
return this.nameToPortRegistry.getItem(name);
return Serial.nameToPortRegistry.getItem(name);
}
this.addPort = function (device) {
if (this.portToNameRegistry.hasKey(device)) {
if (Serial.portToNameRegistry.hasKey(device)) {
return;
}
let name = '';
for (let i = 1; i <= 20; i++) {
name = `hid${i}`;
if (this.nameToPortRegistry.hasKey(name)) {
if (Serial.nameToPortRegistry.hasKey(name)) {
continue;
}
break;
}
this.portToNameRegistry.register(device, name);
this.nameToPortRegistry.register(name, device);
Serial.portToNameRegistry.register(device, name);
Serial.nameToPortRegistry.register(name, device);
}
this.removePort = function (device) {
if (!this.portToNameRegistry.hasKey(device)) {
if (!Serial.portToNameRegistry.hasKey(device)) {
return;
}
const name = this.portToNameRegistry.getItem(device);
const name = Serial.portToNameRegistry.getItem(device);
if (!name) {
return;
}
this.portToNameRegistry.unregister(device);
this.nameToPortRegistry.unregister(name);
Serial.portToNameRegistry.unregister(device);
Serial.nameToPortRegistry.unregister(name);
}
this.addEventsListener = function () {

View File

@@ -1,14 +1,29 @@
goog.loadJs('web', () => {
goog.require('path');
goog.require('Mixly.Config');
goog.require('Mixly.Env');
goog.require('Mixly.Msg');
goog.require('Mixly.Registry');
goog.require('Mixly.Serial');
goog.require('Mixly.LayerExt');
goog.require('Mixly.HTMLTemplate');
goog.require('Mixly.Web.SerialPort');
goog.require('Mixly.Web.USB');
goog.require('Mixly.Web.USBMini');
goog.require('Mixly.Web.HID');
goog.provide('Mixly.Web.Serial');
const { Config, Env, Web } = Mixly;
const {
Config,
Env,
Msg,
Registry,
Serial,
LayerExt,
HTMLTemplate,
Web
} = Mixly;
const {
SerialPort,
@@ -19,87 +34,165 @@ const {
const { BOARD } = Config;
let Device = SerialPort;
const platform = goog.platform();
const fullPlatform = goog.fullPlatform();
class WebSerial extends Serial {
static {
this.devicesRegistry = new Registry();
this.type = Serial.type;
this.DEVICES_SELECT_LAYER = new HTMLTemplate(
goog.get(path.join(Env.templatePath, 'html/devices-select-layer.html'))
);
this.getConfig = function () {
return Serial.getConfig();
}
this.getSelectedPortName = function () {
return Serial.getSelectedPortName();
}
this.getCurrentPortsName = function () {
return Serial.getCurrentPortsName();
}
this.refreshPorts = function () {
Serial.refreshPorts();
}
this.requestPort = function () {
if (this.devicesRegistry.length() < 1) {
throw Error('can not find any device handler');
} else if (this.devicesRegistry.length() === 1) {
const keys = this.devicesRegistry.keys();
return this.devicesRegistry.getItem(keys[0]).requestPort();
}
const msg = {
serialMsg: Msg.Lang['layer.devices.serial'],
serialStatus: this.devicesRegistry.hasKey('serial') ? '' : 'disabled',
hidMsg: Msg.Lang['layer.devices.hid'],
hidStatus: this.devicesRegistry.hasKey('hid') ? '' : 'disabled',
usbMsg: Msg.Lang['layer.devices.usb'],
usbStatus: (
this.devicesRegistry.hasKey('usb') || this.devicesRegistry.hasKey('usbmini')
) ? '' : 'disabled'
};
return new Promise((resolve, reject) => {
let selected = false;
const layerNum = LayerExt.open({
title: [Msg.Lang['layer.devices.select'], '36px'],
area: ['400px', '150px'],
max: false,
min: false,
content: this.DEVICES_SELECT_LAYER.render(msg),
shade: LayerExt.SHADE_ALL,
resize: false,
success: function (layero, index) {
$(layero).on('click', 'button', (event) => {
selected = true;
layer.close(layerNum);
const $btn = $(event.currentTarget);
let mId = $btn.attr('m-id');
if (mId === 'usb' && WebSerial.devicesRegistry.hasKey('usbmini')) {
mId = 'usbmini';
}
const Device = WebSerial.devicesRegistry.getItem(mId);
Device.requestPort().then(resolve).catch(reject);
});
},
end: function () {
if (!selected) {
reject('user not select any device');
}
$(`#layui-layer-shade${layerNum}`).remove();
}
});
});
}
this.getHandler = function (device) {
if (device instanceof window.SerialPort) {
return SerialPort;
} else if (device instanceof window.HIDDevice) {
return HID;
} else if (device instanceof window.USBDevice) {
if (this.devicesRegistry.hasKey('usbmini')) {
return USBMini;
} else {
return USB;
}
}
return null;
}
this.getPort = function (name) {
return Serial.nameToPortRegistry.getItem(name);
}
this.addPort = function (device) {
const handler = this.getHandler(device);
if (!handler) {
return;
}
handler.addPort(device);
}
this.removePort = function (device) {
const handler = this.getHandler(device);
if (!handler) {
return;
}
handler.removePort(device);
}
this.addEventsListener = function () {}
this.init = function () {
if (Env.hasSocketServer) {
return;
}
if (platform === 'win32' && fullPlatform !== 'win10') {
if (BOARD?.web?.devices?.hid) {
Device = HID;
} else if (BOARD?.web?.devices?.serial) {
Device = SerialPort;
} else if (BOARD?.web?.devices?.usb) {
this.devicesRegistry.register('hid', HID);
HID.init();
}
if (BOARD?.web?.devices?.serial) {
this.devicesRegistry.register('serial', SerialPort);
SerialPort.init();
}
if (BOARD?.web?.devices?.usb) {
if (['BBC micro:bit', 'Mithon CC'].includes(BOARD.boardType)) {
Device = USB;
} else {
Device = USBMini;
this.devicesRegistry.register('usb', USB);
USB.init();
}
}
} else if (platform === 'mobile') {
if (['BBC micro:bit', 'Mithon CC'].includes(BOARD.boardType)) {
Device = USB;
this.devicesRegistry.register('usb', USB);
USB.init();
} else {
Device = USBMini;
this.devicesRegistry.register('usbmini', USBMini);
USBMini.init();
}
} else {
if (BOARD?.web?.devices?.serial) {
Device = SerialPort;
this.devicesRegistry.register('serial', SerialPort);
SerialPort.init();
} else if (BOARD?.web?.devices?.usb) {
if (['BBC micro:bit', 'Mithon CC'].includes(BOARD.boardType)) {
Device = USB;
this.devicesRegistry.register('usb', USB);
USB.init();
} else {
Device = USBMini;
this.devicesRegistry.register('usbmini', USBMini);
USBMini.init();
}
} else if (BOARD?.web?.devices?.hid) {
Device = HID;
this.devicesRegistry.register('hid', HID);
HID.init();
}
}
class WebSerial extends Device {
static {
this.type = Device.type;
this.getConfig = function () {
return Device.getConfig();
}
this.getSelectedPortName = function () {
return Device.getSelectedPortName();
}
this.getCurrentPortsName = function () {
return Device.getCurrentPortsName();
}
this.refreshPorts = function () {
return Device.refreshPorts();
}
this.requestPort = async function () {
return Device.requestPort();
}
this.getPort = function (name) {
return Device.getPort(name);
}
this.addPort = function (device) {
return Device.addPort(device);
}
this.removePort = function (device) {
return Device.removePort(device);
}
this.addEventsListener = function () {
return Device.addEventsListener();
}
this.init = function () {
if (!Env.hasSocketServer) {
Device.init();
}
}
this.init();
@@ -107,6 +200,12 @@ class WebSerial extends Device {
constructor(port) {
super(port);
const device = WebSerial.getPort(port);
const handler = WebSerial.getHandler(device);
if (!handler) {
return;
}
return new handler(port);
}
}

View File

@@ -1,14 +1,12 @@
goog.loadJs('web', () => {
goog.require('Mixly.Serial');
goog.require('Mixly.Registry');
goog.require('Mixly.Debug');
goog.require('Mixly.Web');
goog.provide('Mixly.Web.SerialPort');
const {
Serial,
Registry,
Debug,
Web
} = Mixly;
@@ -17,8 +15,6 @@ const {
class WebSerialPort extends Serial {
static {
this.type = 'serialport';
this.portToNameRegistry = new Registry();
this.nameToPortRegistry = new Registry();
this.getConfig = function () {
return Serial.getConfig();
@@ -33,11 +29,7 @@ class WebSerialPort extends Serial {
}
this.refreshPorts = function () {
let portsName = [];
for (let name of this.nameToPortRegistry.keys()) {
portsName.push({ name });
}
Serial.renderSelectBox(portsName);
Serial.refreshPorts();;
}
this.requestPort = async function () {
@@ -47,7 +39,7 @@ class WebSerialPort extends Serial {
}
this.getPort = function (name) {
return this.nameToPortRegistry.getItem(name);
return Serial.nameToPortRegistry.getItem(name);
}
this.addPort = function (serialport) {
@@ -57,25 +49,25 @@ class WebSerialPort extends Serial {
let name = '';
for (let i = 1; i <= 20; i++) {
name = `serial${i}`;
if (this.nameToPortRegistry.hasKey(name)) {
if (Serial.nameToPortRegistry.hasKey(name)) {
continue;
}
break;
}
this.portToNameRegistry.register(serialport, name);
this.nameToPortRegistry.register(name, serialport);
Serial.portToNameRegistry.register(serialport, name);
Serial.nameToPortRegistry.register(name, serialport);
}
this.removePort = function (serialport) {
if (!this.portToNameRegistry.hasKey(serialport)) {
if (!Serial.portToNameRegistry.hasKey(serialport)) {
return;
}
const name = this.portToNameRegistry.getItem(serialport);
const name = Serial.portToNameRegistry.getItem(serialport);
if (!name) {
return;
}
this.portToNameRegistry.unregister(serialport);
this.nameToPortRegistry.unregister(name);
Serial.portToNameRegistry.unregister(serialport);
Serial.nameToPortRegistry.unregister(name);
}
this.addEventsListener = function () {

View File

@@ -14,9 +14,7 @@ const {
class USBMini extends Serial {
static {
this.type = 'usb';
this.portToNameRegistry = new Registry();
this.serialNumberToNameRegistry = new Registry();
this.nameToPortRegistry = new Registry();
this.getConfig = function () {
return Serial.getConfig();
@@ -31,11 +29,7 @@ class USBMini extends Serial {
}
this.refreshPorts = function () {
let portsName = [];
for (let name of this.nameToPortRegistry.keys()) {
portsName.push({ name });
}
Serial.renderSelectBox(portsName);
Serial.refreshPorts();;
}
this.requestPort = async function () {
@@ -47,11 +41,11 @@ class USBMini extends Serial {
}
this.getPort = function (name) {
return this.nameToPortRegistry.getItem(name);
return Serial.nameToPortRegistry.getItem(name);
}
this.addPort = function (device) {
if (this.portToNameRegistry.hasKey(device)) {
if (Serial.portToNameRegistry.hasKey(device)) {
return;
}
const { serialNumber } = device;
@@ -59,27 +53,27 @@ class USBMini extends Serial {
if (!name) {
for (let i = 1; i <= 20; i++) {
name = `usb${i}`;
if (this.nameToPortRegistry.hasKey(name)) {
if (Serial.nameToPortRegistry.hasKey(name)) {
continue;
}
break;
}
this.serialNumberToNameRegistry.register(serialNumber, name);
}
this.portToNameRegistry.register(device, name);
this.nameToPortRegistry.register(name, device);
Serial.portToNameRegistry.register(device, name);
Serial.nameToPortRegistry.register(name, device);
}
this.removePort = function (device) {
if (!this.portToNameRegistry.hasKey(device)) {
if (!Serial.portToNameRegistry.hasKey(device)) {
return;
}
const name = this.portToNameRegistry.getItem(device);
const name = Serial.portToNameRegistry.getItem(device);
if (!name) {
return;
}
this.portToNameRegistry.unregister(device);
this.nameToPortRegistry.unregister(name);
Serial.portToNameRegistry.unregister(device);
Serial.nameToPortRegistry.unregister(name);
}
this.addEventsListener = function () {

View File

@@ -15,9 +15,7 @@ const {
class USB extends Serial {
static {
this.type = 'usb';
this.portToNameRegistry = new Registry();
this.serialNumberToNameRegistry = new Registry();
this.nameToPortRegistry = new Registry();
this.getConfig = function () {
return Serial.getConfig();
@@ -32,11 +30,7 @@ class USB extends Serial {
}
this.refreshPorts = function () {
let portsName = [];
for (let name of this.nameToPortRegistry.keys()) {
portsName.push({ name });
}
Serial.renderSelectBox(portsName);
Serial.refreshPorts();;
}
this.requestPort = async function () {
@@ -48,11 +42,11 @@ class USB extends Serial {
}
this.getPort = function (name) {
return this.nameToPortRegistry.getItem(name);
return Serial.nameToPortRegistry.getItem(name);
}
this.addPort = function (device) {
if (this.portToNameRegistry.hasKey(device)) {
if (Serial.portToNameRegistry.hasKey(device)) {
return;
}
const { serialNumber } = device;
@@ -60,27 +54,27 @@ class USB extends Serial {
if (!name) {
for (let i = 1; i <= 20; i++) {
name = `usb${i}`;
if (this.nameToPortRegistry.hasKey(name)) {
if (Serial.nameToPortRegistry.hasKey(name)) {
continue;
}
break;
}
this.serialNumberToNameRegistry.register(serialNumber, name);
}
this.portToNameRegistry.register(device, name);
this.nameToPortRegistry.register(name, device);
Serial.portToNameRegistry.register(device, name);
Serial.nameToPortRegistry.register(name, device);
}
this.removePort = function (device) {
if (!this.portToNameRegistry.hasKey(device)) {
if (!Serial.portToNameRegistry.hasKey(device)) {
return;
}
const name = this.portToNameRegistry.getItem(device);
const name = Serial.portToNameRegistry.getItem(device);
if (!name) {
return;
}
this.portToNameRegistry.unregister(device);
this.nameToPortRegistry.unregister(name);
Serial.portToNameRegistry.unregister(device);
Serial.nameToPortRegistry.unregister(name);
}
this.addEventsListener = function () {

View File

@@ -389,5 +389,10 @@
"libManager.empty": "No data",
"wiki.home": "Homepage",
"wiki.pageNotFound": "Wiki page not found",
"wiki.open": "Open Wiki"
"wiki.open": "Open Wiki",
"layer.devices.serial": "Add Serial device",
"layer.devices.hid": "Add HID device",
"layer.devices.usb": "Add USB device",
"layer.devices.select": "Select device",
"burn.notSupport": "Unable to flash firmware with this device"
}

View File

@@ -389,5 +389,10 @@
"libManager.empty": "无数据",
"wiki.home": "首页",
"wiki.pageNotFound": "未找到Wiki页",
"wiki.open": "打开Wiki"
"wiki.open": "打开Wiki",
"layer.devices.serial": "添加Serial设备",
"layer.devices.hid": "添加HID设备",
"layer.devices.usb": "添加USB设备",
"layer.devices.select": "选择设备",
"burn.notSupport": "无法使用此设备烧录固件"
}

View File

@@ -389,5 +389,10 @@
"libManager.empty": "無資料",
"wiki.home": "首頁",
"wiki.pageNotFound": "未找到Wiki頁",
"wiki.open": "開啟Wiki"
"wiki.open": "開啟Wiki",
"layer.devices.serial": "新增Serial裝置",
"layer.devices.hid": "新增HID裝置",
"layer.devices.usb": "新增USB裝置",
"layer.devices.select": "選擇裝置",
"burn.notSupport": "無法使用此設備燒錄固件"
}

View File

@@ -0,0 +1,42 @@
<style>
div[m-id="{{d.mId}}"] {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 0 5px;
}
html[data-bs-theme=light] div[m-id="{{d.mId}}"] > button {
color: #000;
}
html[data-bs-theme=light] div[m-id="{{d.mId}}"] > button[disabled] {
color: #ccc;
}
html[data-bs-theme=light] div[m-id="{{d.mId}}"] > button:hover,
html[data-bs-theme=light] div[m-id="{{d.mId}}"] > button:active {
background-color: var(--app-light-color);
color: #fff;
}
html[data-bs-theme=dark] div[m-id="{{d.mId}}"] > button {
color: #fff;
}
html[data-bs-theme=dark] div[m-id="{{d.mId}}"] > button[disabled] {
color: #777;
}
html[data-bs-theme=dark] div[m-id="{{d.mId}}"] > button:hover,
html[data-bs-theme=dark] div[m-id="{{d.mId}}"] > button:active {
background-color: var(--app-dark-color);
color: #fff;
}
</style>
<div m-id="{{d.mId}}" class="page-item list-group">
<button type="button" m-id="serial" class="list-group-item list-group-item-action m-btn" {{d.serialStatus}}>{{d.serialMsg}}</button>
<button type="button" m-id="hid" class="list-group-item list-group-item-action m-btn" {{d.hidStatus}}>{{d.hidMsg}}</button>
<button type="button" m-id="usb" class="list-group-item list-group-item-action m-btn" {{d.usbStatus}}>{{d.usbMsg}}</button>
</div>