Update: 在线版增加对HID的支持
This commit is contained in:
@@ -239,6 +239,9 @@ class App extends Component {
|
|||||||
id: 'command-burn-btn',
|
id: 'command-burn-btn',
|
||||||
displayText: Msg.Lang['nav.btn.burn'],
|
displayText: Msg.Lang['nav.btn.burn'],
|
||||||
preconditionFn: () => {
|
preconditionFn: () => {
|
||||||
|
if (!goog.isElectron && BOARD.web.com === 'hid') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return SELECTED_BOARD?.nav?.burn;
|
return SELECTED_BOARD?.nav?.burn;
|
||||||
},
|
},
|
||||||
callback: () => BU.initBurn(),
|
callback: () => BU.initBurn(),
|
||||||
|
|||||||
@@ -1573,7 +1573,6 @@
|
|||||||
"Mixly.HTMLTemplate",
|
"Mixly.HTMLTemplate",
|
||||||
"Mixly.MString",
|
"Mixly.MString",
|
||||||
"Mixly.Web.Serial",
|
"Mixly.Web.Serial",
|
||||||
"Mixly.Web.USB",
|
|
||||||
"Mixly.Web.Ampy"
|
"Mixly.Web.Ampy"
|
||||||
],
|
],
|
||||||
"provide": [
|
"provide": [
|
||||||
@@ -1629,6 +1628,17 @@
|
|||||||
"Mixly.Web.FS"
|
"Mixly.Web.FS"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"path": "/web/hid.js",
|
||||||
|
"require": [
|
||||||
|
"Mixly.Serial",
|
||||||
|
"Mixly.Registry",
|
||||||
|
"Mixly.Web"
|
||||||
|
],
|
||||||
|
"provide": [
|
||||||
|
"Mixly.Web.HID"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "/web/lms.js",
|
"path": "/web/lms.js",
|
||||||
"require": [
|
"require": [
|
||||||
@@ -1648,13 +1658,11 @@
|
|||||||
{
|
{
|
||||||
"path": "/web/serial.js",
|
"path": "/web/serial.js",
|
||||||
"require": [
|
"require": [
|
||||||
"Mixly.Serial",
|
"Mixly.Config",
|
||||||
"Mixly.Env",
|
"Mixly.Env",
|
||||||
"Mixly.Nav",
|
"Mixly.Web.SerialPort",
|
||||||
"Mixly.Msg",
|
"Mixly.Web.USB",
|
||||||
"Mixly.Debug",
|
"Mixly.Web.HID"
|
||||||
"Mixly.Registry",
|
|
||||||
"Mixly.Web"
|
|
||||||
],
|
],
|
||||||
"provide": [
|
"provide": [
|
||||||
"Mixly.Web.Serial"
|
"Mixly.Web.Serial"
|
||||||
@@ -1663,7 +1671,8 @@
|
|||||||
{
|
{
|
||||||
"path": "/web/serialport.js",
|
"path": "/web/serialport.js",
|
||||||
"require": [
|
"require": [
|
||||||
"Mixly.MString",
|
"Mixly.Serial",
|
||||||
|
"Mixly.Registry",
|
||||||
"Mixly.Web"
|
"Mixly.Web"
|
||||||
],
|
],
|
||||||
"provide": [
|
"provide": [
|
||||||
@@ -1675,10 +1684,6 @@
|
|||||||
"require": [
|
"require": [
|
||||||
"DAPjs",
|
"DAPjs",
|
||||||
"Mixly.Serial",
|
"Mixly.Serial",
|
||||||
"Mixly.Env",
|
|
||||||
"Mixly.Nav",
|
|
||||||
"Mixly.Msg",
|
|
||||||
"Mixly.Debug",
|
|
||||||
"Mixly.Registry",
|
"Mixly.Registry",
|
||||||
"Mixly.Web"
|
"Mixly.Web"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -33,11 +33,14 @@ class AmpyExt extends Ampy {
|
|||||||
|
|
||||||
#device_ = null;
|
#device_ = null;
|
||||||
#receiveTemp_ = [];
|
#receiveTemp_ = [];
|
||||||
#writeBuffer_ = false;
|
#writeBuffer_ = true;
|
||||||
#active_ = false;
|
#active_ = false;
|
||||||
constructor(device) {
|
#dataLength_ = 256;
|
||||||
|
constructor(device, writeBuffer = true, dataLength = 256) {
|
||||||
super();
|
super();
|
||||||
this.#device_ = device;
|
this.#device_ = device;
|
||||||
|
this.#writeBuffer_ = writeBuffer;
|
||||||
|
this.#dataLength_ = dataLength;
|
||||||
this.#addEventsListener_();
|
this.#addEventsListener_();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,16 +137,20 @@ class AmpyExt extends Ampy {
|
|||||||
async exec(str) {
|
async exec(str) {
|
||||||
if (this.#writeBuffer_) {
|
if (this.#writeBuffer_) {
|
||||||
const buffer = this.#device_.encode(str);
|
const buffer = this.#device_.encode(str);
|
||||||
const len = Math.ceil(buffer.length / 256);
|
const len = Math.ceil(buffer.length / this.#dataLength_);
|
||||||
for (let i = 0; i < len; i++) {
|
for (let i = 0; i < len; i++) {
|
||||||
const writeBuffer = buffer.slice(i * 256, Math.min((i + 1) * 256, buffer.length));
|
const start = i * this.#dataLength_;
|
||||||
|
const end = Math.min((i + 1) * this.#dataLength_, buffer.length);
|
||||||
|
const writeBuffer = buffer.slice(start, end);
|
||||||
await this.#device_.sendBuffer(writeBuffer);
|
await this.#device_.sendBuffer(writeBuffer);
|
||||||
await this.#device_.sleep(10);
|
await this.#device_.sleep(10);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (let i = 0; i < str.length / 60; i++) {
|
for (let i = 0; i < str.length / this.#dataLength_; i++) {
|
||||||
let newData = str.substring(i * 60, (i + 1) * 60);
|
const start = i * this.#dataLength_;
|
||||||
await this.#device_.sendString(newData);
|
const end = Math.min((i + 1) * this.#dataLength_, str.length);
|
||||||
|
let data = str.substring(start, end);
|
||||||
|
await this.#device_.sendString(data);
|
||||||
await this.#device_.sleep(10);
|
await this.#device_.sleep(10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ goog.require('Mixly.Debug');
|
|||||||
goog.require('Mixly.HTMLTemplate');
|
goog.require('Mixly.HTMLTemplate');
|
||||||
goog.require('Mixly.MString');
|
goog.require('Mixly.MString');
|
||||||
goog.require('Mixly.Web.Serial');
|
goog.require('Mixly.Web.Serial');
|
||||||
goog.require('Mixly.Web.USB');
|
|
||||||
goog.require('Mixly.Web.Ampy');
|
goog.require('Mixly.Web.Ampy');
|
||||||
goog.provide('Mixly.Web.BU');
|
goog.provide('Mixly.Web.BU');
|
||||||
|
|
||||||
@@ -37,7 +36,6 @@ const {
|
|||||||
const {
|
const {
|
||||||
Serial,
|
Serial,
|
||||||
BU,
|
BU,
|
||||||
USB,
|
|
||||||
Ampy
|
Ampy
|
||||||
} = Web;
|
} = Web;
|
||||||
|
|
||||||
@@ -61,11 +59,7 @@ BU.FILMWARE_LAYER = new HTMLTemplate(
|
|||||||
const BAUD = goog.platform() === 'darwin' ? 460800 : 921600;
|
const BAUD = goog.platform() === 'darwin' ? 460800 : 921600;
|
||||||
|
|
||||||
BU.requestPort = async () => {
|
BU.requestPort = async () => {
|
||||||
if (SELECTED_BOARD.web.com === 'usb') {
|
await Serial.requestPort();
|
||||||
await USB.requestPort();
|
|
||||||
} else {
|
|
||||||
await Serial.requestPort();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const readBinFile = (path, offset) => {
|
const readBinFile = (path, offset) => {
|
||||||
@@ -182,7 +176,7 @@ BU.burnByUSB = () => {
|
|||||||
$(".layui-layer-page").css("z-index","198910151");
|
$(".layui-layer-page").css("z-index","198910151");
|
||||||
$("#mixly-loader-btn").hide();
|
$("#mixly-loader-btn").hide();
|
||||||
let prevPercent = 0;
|
let prevPercent = 0;
|
||||||
USB.DAPLink.on(DAPjs.DAPLink.EVENT_PROGRESS, progress => {
|
Serial.DAPLink.on(DAPjs.DAPLink.EVENT_PROGRESS, progress => {
|
||||||
const nowPercent = Math.floor(progress * 100);
|
const nowPercent = Math.floor(progress * 100);
|
||||||
if (nowPercent > prevPercent) {
|
if (nowPercent > prevPercent) {
|
||||||
prevPercent = nowPercent;
|
prevPercent = nowPercent;
|
||||||
@@ -194,7 +188,7 @@ BU.burnByUSB = () => {
|
|||||||
const rightStr = (new Array(50 - nowProgressLen).fill('-')).join('');
|
const rightStr = (new Array(50 - nowProgressLen).fill('-')).join('');
|
||||||
statusBarTerminal.addValue(`[${leftStr}${rightStr}] ${nowPercent}%\n`);
|
statusBarTerminal.addValue(`[${leftStr}${rightStr}] ${nowPercent}%\n`);
|
||||||
});
|
});
|
||||||
USB.flash(buffer)
|
Serial.flash(buffer)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
layer.close(index);
|
layer.close(index);
|
||||||
layer.msg(Msg.Lang['shell.burnSucc'], { time: 1000 });
|
layer.msg(Msg.Lang['shell.burnSucc'], { time: 1000 });
|
||||||
@@ -212,7 +206,7 @@ BU.burnByUSB = () => {
|
|||||||
toolConfig.baudRates = prevBaud;
|
toolConfig.baudRates = prevBaud;
|
||||||
await serialport.setBaudRate(prevBaud);
|
await serialport.setBaudRate(prevBaud);
|
||||||
}
|
}
|
||||||
USB.DAPLink.removeAllListeners(DAPjs.DAPLink.EVENT_PROGRESS);
|
Serial.DAPLink.removeAllListeners(DAPjs.DAPLink.EVENT_PROGRESS);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
end: function () {
|
end: function () {
|
||||||
@@ -545,6 +539,14 @@ BU.uploadWithAmpy = (portName) => {
|
|||||||
mainStatusBarTabs.changeTo('output');
|
mainStatusBarTabs.changeTo('output');
|
||||||
const mainWorkspace = Workspace.getMain();
|
const mainWorkspace = Workspace.getMain();
|
||||||
const editor = mainWorkspace.getEditorsManager().getActive();
|
const editor = mainWorkspace.getEditorsManager().getActive();
|
||||||
|
let useBuffer = true, dataLength = 256;
|
||||||
|
if (BOARD.web.com === 'usb') {
|
||||||
|
useBuffer = false;
|
||||||
|
dataLength = 64;
|
||||||
|
} else if (BOARD.web.com === 'hid') {
|
||||||
|
useBuffer = true;
|
||||||
|
dataLength = 30;
|
||||||
|
}
|
||||||
const layerNum = layer.open({
|
const layerNum = layer.open({
|
||||||
type: 1,
|
type: 1,
|
||||||
title: Msg.Lang['shell.uploading'] + '...',
|
title: Msg.Lang['shell.uploading'] + '...',
|
||||||
@@ -554,7 +556,7 @@ BU.uploadWithAmpy = (portName) => {
|
|||||||
closeBtn: 0,
|
closeBtn: 0,
|
||||||
success: async function (layero, index) {
|
success: async function (layero, index) {
|
||||||
const serial = new Serial(portName);
|
const serial = new Serial(portName);
|
||||||
const ampy = new Ampy(serial);
|
const ampy = new Ampy(serial, useBuffer, dataLength);
|
||||||
const code = editor.getCode();
|
const code = editor.getCode();
|
||||||
let closePromise = Promise.resolve();
|
let closePromise = Promise.resolve();
|
||||||
if (statusBarSerial) {
|
if (statusBarSerial) {
|
||||||
|
|||||||
236
common/modules/mixly-modules/web/hid.js
Normal file
236
common/modules/mixly-modules/web/hid.js
Normal file
@@ -0,0 +1,236 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
class WebHID extends Serial {
|
||||||
|
static {
|
||||||
|
this.portToNameRegistry = new Registry();
|
||||||
|
this.nameToPortRegistry = new Registry();
|
||||||
|
|
||||||
|
this.getConfig = function () {
|
||||||
|
return Serial.getConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getSelectedPortName = function () {
|
||||||
|
return Serial.getSelectedPortName();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getCurrentPortsName = function () {
|
||||||
|
return Serial.getCurrentPortsName();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.refreshPorts = function () {
|
||||||
|
let portsName = [];
|
||||||
|
for (let name of this.nameToPortRegistry.keys()) {
|
||||||
|
portsName.push({ name });
|
||||||
|
}
|
||||||
|
Serial.renderSelectBox(portsName);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.requestPort = async function () {
|
||||||
|
const devices = await navigator.hid.requestDevice({
|
||||||
|
filters: []
|
||||||
|
});
|
||||||
|
this.addPort(devices[0]);
|
||||||
|
this.refreshPorts();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getPort = function (name) {
|
||||||
|
return this.nameToPortRegistry.getItem(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.addPort = function (device) {
|
||||||
|
if (this.portToNameRegistry.hasKey(device)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let name = '';
|
||||||
|
for (let i = 1; i <= 20; i++) {
|
||||||
|
name = `hid${i}`;
|
||||||
|
if (this.nameToPortRegistry.hasKey(name)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.portToNameRegistry.register(device, name);
|
||||||
|
this.nameToPortRegistry.register(name, device);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.removePort = function (device) {
|
||||||
|
if (!this.portToNameRegistry.hasKey(device)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const name = this.portToNameRegistry.getItem(device);
|
||||||
|
if (!name) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.portToNameRegistry.unregister(device);
|
||||||
|
this.nameToPortRegistry.unregister(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.addEventsListener = function () {
|
||||||
|
navigator?.hid?.addEventListener('connect', (event) => {
|
||||||
|
this.addPort(event.device);
|
||||||
|
this.refreshPorts();
|
||||||
|
});
|
||||||
|
|
||||||
|
navigator?.hid?.addEventListener('disconnect', (event) => {
|
||||||
|
event.device.onclose && event.device.onclose();
|
||||||
|
this.removePort(event.device);
|
||||||
|
this.refreshPorts();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.init = function () {
|
||||||
|
navigator?.hid?.getDevices().then((devices) => {
|
||||||
|
for (let device of devices) {
|
||||||
|
this.addPort(device);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.addEventsListener();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#device_ = null;
|
||||||
|
#keepReading_ = null;
|
||||||
|
#reader_ = null;
|
||||||
|
#writer_ = null;
|
||||||
|
#stringTemp_ = '';
|
||||||
|
constructor(port) {
|
||||||
|
super(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
#addEventsListener_() {
|
||||||
|
this.#addReadEventListener_();
|
||||||
|
}
|
||||||
|
|
||||||
|
async #addReadEventListener_() {
|
||||||
|
this.#device_.oninputreport = (event) => {
|
||||||
|
const { data, reportId } = event;
|
||||||
|
const length = Math.min(data.getUint8(0), data.byteLength);
|
||||||
|
let buffer = [];
|
||||||
|
for (let i = 1; i <= length; i++) {
|
||||||
|
buffer.push(data.getUint8(i));
|
||||||
|
}
|
||||||
|
this.onBuffer(buffer);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.#device_.onclose = () => {
|
||||||
|
if (!this.isOpened()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
super.close();
|
||||||
|
this.#stringTemp_ = '';
|
||||||
|
this.onClose(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async open(baud) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const portsName = Serial.getCurrentPortsName();
|
||||||
|
const currentPortName = this.getPortName();
|
||||||
|
if (!portsName.includes(currentPortName)) {
|
||||||
|
reject('无可用设备');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.isOpened()) {
|
||||||
|
resolve();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
baud = baud ?? this.getBaudRate();
|
||||||
|
this.#device_ = WebHID.getPort(currentPortName);
|
||||||
|
this.#device_.open()
|
||||||
|
.then(() => {
|
||||||
|
super.open(baud);
|
||||||
|
super.setBaudRate(baud);
|
||||||
|
this.onOpen();
|
||||||
|
this.#addEventsListener_();
|
||||||
|
resolve();
|
||||||
|
})
|
||||||
|
.catch(reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async close() {
|
||||||
|
if (!this.isOpened()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
super.close();
|
||||||
|
await this.#device_.close();
|
||||||
|
this.#stringTemp_ = '';
|
||||||
|
this.#device_.oninputreport = null;
|
||||||
|
this.#device_.onclose = null;
|
||||||
|
this.onClose(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
async setBaudRate(baud) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
async sendString(str) {
|
||||||
|
const buffer = this.encode(str);
|
||||||
|
return this.sendBuffer(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
async sendBuffer(buffer) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (buffer instanceof Uint8Array) {
|
||||||
|
let temp = new Uint8Array(buffer.length + 1);
|
||||||
|
temp[0] = buffer.length;
|
||||||
|
temp.set(buffer, 1);
|
||||||
|
buffer= temp;
|
||||||
|
} else {
|
||||||
|
buffer.unshift(buffer.length);
|
||||||
|
buffer = new Uint8Array(buffer);
|
||||||
|
}
|
||||||
|
this.#device_.sendReport(0, buffer)
|
||||||
|
.then(resolve)
|
||||||
|
.catch(reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async setDTRAndRTS(dtr, rts) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
async setDTR(dtr) {
|
||||||
|
return this.setDTRAndRTS(dtr, this.getRTS());
|
||||||
|
}
|
||||||
|
|
||||||
|
async setRTS(rts) {
|
||||||
|
return this.setDTRAndRTS(this.getDTR(), rts);
|
||||||
|
}
|
||||||
|
|
||||||
|
onBuffer(buffer) {
|
||||||
|
super.onBuffer(buffer);
|
||||||
|
for (let i = 0; i < buffer.length; i++) {
|
||||||
|
super.onByte(buffer[i]);
|
||||||
|
}
|
||||||
|
const string = this.decodeBuffer(buffer);
|
||||||
|
if (!string) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (let char of string) {
|
||||||
|
super.onChar(char);
|
||||||
|
if (['\r', '\n'].includes(char)) {
|
||||||
|
super.onString(this.#stringTemp_);
|
||||||
|
this.#stringTemp_ = '';
|
||||||
|
} else {
|
||||||
|
this.#stringTemp_ += char;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Web.HID = WebHID;
|
||||||
|
|
||||||
|
});
|
||||||
@@ -1,283 +1,84 @@
|
|||||||
goog.loadJs('web', () => {
|
goog.loadJs('web', () => {
|
||||||
|
|
||||||
goog.require('Mixly.Serial');
|
goog.require('Mixly.Config');
|
||||||
goog.require('Mixly.Env');
|
goog.require('Mixly.Env');
|
||||||
goog.require('Mixly.Nav');
|
goog.require('Mixly.Web.SerialPort');
|
||||||
goog.require('Mixly.Msg');
|
goog.require('Mixly.Web.USB');
|
||||||
goog.require('Mixly.Debug');
|
goog.require('Mixly.Web.HID');
|
||||||
goog.require('Mixly.Registry');
|
|
||||||
goog.require('Mixly.Web');
|
|
||||||
goog.provide('Mixly.Web.Serial');
|
goog.provide('Mixly.Web.Serial');
|
||||||
|
|
||||||
|
const { Config, Env, Web } = Mixly;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
Serial,
|
SerialPort,
|
||||||
Env,
|
USB,
|
||||||
Nav,
|
HID
|
||||||
Msg,
|
} = Web;
|
||||||
Debug,
|
|
||||||
Registry,
|
const { BOARD } = Config;
|
||||||
Web
|
|
||||||
} = Mixly;
|
let Device = SerialPort;
|
||||||
|
|
||||||
|
if (BOARD.web.com === 'usb') {
|
||||||
|
Device = USB;
|
||||||
|
} else if (BOARD.web.com === 'hid') {
|
||||||
|
Device = HID;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class WebSerial extends Serial {
|
class WebSerial extends Device {
|
||||||
static {
|
static {
|
||||||
this.portToNameRegistry = new Registry();
|
|
||||||
this.nameToPortRegistry = new Registry();
|
|
||||||
|
|
||||||
this.getConfig = function () {
|
this.getConfig = function () {
|
||||||
return Serial.getConfig();
|
return Device.getConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.getSelectedPortName = function () {
|
this.getSelectedPortName = function () {
|
||||||
return Serial.getSelectedPortName();
|
return Device.getSelectedPortName();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.getCurrentPortsName = function () {
|
this.getCurrentPortsName = function () {
|
||||||
return Serial.getCurrentPortsName();
|
return Device.getCurrentPortsName();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.refreshPorts = function () {
|
this.refreshPorts = function () {
|
||||||
let portsName = [];
|
return Device.refreshPorts();
|
||||||
for (let name of this.nameToPortRegistry.keys()) {
|
|
||||||
portsName.push({ name });
|
|
||||||
}
|
|
||||||
Serial.renderSelectBox(portsName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.requestPort = async function () {
|
this.requestPort = async function () {
|
||||||
const serialport = await navigator.serial.requestPort();
|
return Device.requestPort();
|
||||||
this.addPort(serialport);
|
|
||||||
this.refreshPorts();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.getPort = function (name) {
|
this.getPort = function (name) {
|
||||||
return this.nameToPortRegistry.getItem(name);
|
return Device.getPort(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.addPort = function (serialport) {
|
this.addPort = function (device) {
|
||||||
if (this.portToNameRegistry.hasKey(serialport)) {
|
return Device.addPort(device);
|
||||||
return;
|
|
||||||
}
|
|
||||||
let name = '';
|
|
||||||
for (let i = 1; i <= 20; i++) {
|
|
||||||
name = `serial${i}`;
|
|
||||||
if (this.nameToPortRegistry.hasKey(name)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
this.portToNameRegistry.register(serialport, name);
|
|
||||||
this.nameToPortRegistry.register(name, serialport);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.removePort = function (serialport) {
|
this.removePort = function (device) {
|
||||||
if (!this.portToNameRegistry.hasKey(serialport)) {
|
return Device.removePort(device);
|
||||||
return;
|
|
||||||
}
|
|
||||||
const name = this.portToNameRegistry.getItem(serialport);
|
|
||||||
if (!name) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.portToNameRegistry.unregister(serialport);
|
|
||||||
this.nameToPortRegistry.unregister(name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.addEventsListener = function () {
|
this.addEventsListener = function () {
|
||||||
navigator?.serial?.addEventListener('connect', (event) => {
|
return Device.addEventsListener();
|
||||||
this.addPort(event.target);
|
|
||||||
this.refreshPorts();
|
|
||||||
});
|
|
||||||
|
|
||||||
navigator?.serial?.addEventListener('disconnect', (event) => {
|
|
||||||
this.removePort(event.target);
|
|
||||||
this.refreshPorts();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Env.hasSocketServer) {
|
this.init = function () {
|
||||||
navigator?.serial?.getPorts().then((serialports) => {
|
if (!Env.hasSocketServer) {
|
||||||
for (let serialport of serialports) {
|
Device.init();
|
||||||
this.addPort(serialport);
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
this.addEventsListener();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
#serialport_ = null;
|
|
||||||
#keepReading_ = null;
|
|
||||||
#reader_ = null;
|
|
||||||
#writer_ = null;
|
|
||||||
#stringTemp_ = '';
|
|
||||||
constructor(port) {
|
constructor(port) {
|
||||||
super(port);
|
super(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
#addEventsListener_() {
|
|
||||||
this.#addReadEventListener_();
|
|
||||||
}
|
|
||||||
|
|
||||||
async #addReadEventListener_() {
|
|
||||||
const { readable } = this.#serialport_;
|
|
||||||
while (readable && this.#keepReading_) {
|
|
||||||
this.#reader_ = readable.getReader();
|
|
||||||
try {
|
|
||||||
while (true) {
|
|
||||||
const { value, done } = await this.#reader_.read();
|
|
||||||
value && this.onBuffer(value);
|
|
||||||
if (done) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
this.#keepReading_ = false;
|
|
||||||
Debug.error(error);
|
|
||||||
} finally {
|
|
||||||
this.#reader_ && this.#reader_.releaseLock();
|
|
||||||
await this.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async open(baud) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const portsName = Serial.getCurrentPortsName();
|
|
||||||
const currentPortName = this.getPortName();
|
|
||||||
if (!portsName.includes(currentPortName)) {
|
|
||||||
reject('无可用串口');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.isOpened()) {
|
|
||||||
resolve();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
baud = baud ?? this.getBaudRate();
|
|
||||||
this.#serialport_ = WebSerial.getPort(currentPortName);
|
|
||||||
this.#serialport_.open({ baudRate: baud })
|
|
||||||
.then(() => {
|
|
||||||
super.open(baud);
|
|
||||||
super.setBaudRate(baud);
|
|
||||||
this.#keepReading_ = true;
|
|
||||||
this.onOpen();
|
|
||||||
this.#addEventsListener_();
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
.catch(reject);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async #waitForUnlock_(timeout) {
|
|
||||||
while (
|
|
||||||
(this.#serialport_.readable && this.#serialport_.readable.locked) ||
|
|
||||||
(this.#serialport_.writable && this.#serialport_.writable.locked)
|
|
||||||
) {
|
|
||||||
await this.sleep(timeout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async close() {
|
|
||||||
if (!this.isOpened()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
super.close();
|
|
||||||
if (this.#serialport_.readable?.locked) {
|
|
||||||
this.#keepReading_ = false;
|
|
||||||
await this.#reader_?.cancel();
|
|
||||||
}
|
|
||||||
await this.#waitForUnlock_(400);
|
|
||||||
this.#reader_ = undefined;
|
|
||||||
await this.#serialport_.close();
|
|
||||||
this.#stringTemp_ = '';
|
|
||||||
this.onClose(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
async setBaudRate(baud) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (!this.isOpened()
|
|
||||||
|| this.getBaudRate() === baud
|
|
||||||
|| !this.baudRateIsLegal(baud)) {
|
|
||||||
resolve();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.close()
|
|
||||||
.then(() => this.open(baud))
|
|
||||||
.then(resolve)
|
|
||||||
.catch(reject);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async sendString(str) {
|
|
||||||
const buffer = this.encode(str);
|
|
||||||
return this.sendBuffer(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
async sendBuffer(buffer) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const { writable } = this.#serialport_;
|
|
||||||
const writer = writable.getWriter();
|
|
||||||
if (!(buffer instanceof Uint8Array)) {
|
|
||||||
buffer = new Uint8Array(buffer);
|
|
||||||
}
|
|
||||||
writer.write(buffer)
|
|
||||||
.then(() => {
|
|
||||||
writer.releaseLock();
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
writer.releaseLock();
|
|
||||||
reject();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async setDTRAndRTS(dtr, rts) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (!this.isOpened()) {
|
|
||||||
resolve();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.#serialport_.setSignals({
|
|
||||||
dataTerminalReady: dtr,
|
|
||||||
requestToSend: rts
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
super.setDTRAndRTS(dtr, rts);
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
.catch(reject);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async setDTR(dtr) {
|
|
||||||
return this.setDTRAndRTS(dtr, this.getRTS());
|
|
||||||
}
|
|
||||||
|
|
||||||
async setRTS(rts) {
|
|
||||||
return this.setDTRAndRTS(this.getDTR(), rts);
|
|
||||||
}
|
|
||||||
|
|
||||||
onBuffer(buffer) {
|
|
||||||
super.onBuffer(buffer);
|
|
||||||
for (let i = 0; i < buffer.length; i++) {
|
|
||||||
super.onByte(buffer[i]);
|
|
||||||
}
|
|
||||||
const string = this.decodeBuffer(buffer);
|
|
||||||
if (!string) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (let char of string) {
|
|
||||||
super.onChar(char);
|
|
||||||
if (['\r', '\n'].includes(char)) {
|
|
||||||
super.onString(this.#stringTemp_);
|
|
||||||
this.#stringTemp_ = '';
|
|
||||||
} else {
|
|
||||||
this.#stringTemp_ += char;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Web.Serial = WebSerial;
|
Web.Serial = WebSerial;
|
||||||
|
|
||||||
});
|
});
|
||||||
@@ -1,285 +1,275 @@
|
|||||||
goog.loadJs('web', () => {
|
goog.loadJs('web', () => {
|
||||||
|
|
||||||
goog.require('Mixly.MString');
|
goog.require('Mixly.Serial');
|
||||||
|
goog.require('Mixly.Registry');
|
||||||
goog.require('Mixly.Web');
|
goog.require('Mixly.Web');
|
||||||
goog.provide('Mixly.Web.SerialPort');
|
goog.provide('Mixly.Web.SerialPort');
|
||||||
|
|
||||||
const { MString, Web } = Mixly;
|
const {
|
||||||
|
Serial,
|
||||||
|
Registry,
|
||||||
|
Web
|
||||||
|
} = Mixly;
|
||||||
|
|
||||||
const { SerialPort } = Web;
|
|
||||||
|
|
||||||
SerialPort.output = [];
|
class WebSerialPort extends Serial {
|
||||||
SerialPort.inputBuffer = [];
|
static {
|
||||||
SerialPort.outputBuffer = [];
|
this.portToNameRegistry = new Registry();
|
||||||
SerialPort.refreshInputBuffer = false;
|
this.nameToPortRegistry = new Registry();
|
||||||
SerialPort.refreshOutputBuffer = true;
|
|
||||||
SerialPort.obj = null;
|
|
||||||
SerialPort.onDataLine = null;
|
|
||||||
SerialPort.keepReading = false;
|
|
||||||
|
|
||||||
SerialPort.encoder = new TextEncoder('utf8');
|
this.getConfig = function () {
|
||||||
SerialPort.decoder = new TextDecoder('utf8');
|
return Serial.getConfig();
|
||||||
SerialPort.dtr = false;
|
|
||||||
SerialPort.rts = false;
|
|
||||||
SerialPort.name = 'serialport';
|
|
||||||
|
|
||||||
SerialPort.connect = (baud = 115200, onDataLine = (message) => {}) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (SerialPort.isConnected()) {
|
|
||||||
resolve();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
navigator.serial.requestPort()
|
|
||||||
.then((device) => {
|
|
||||||
SerialPort.obj = device;
|
|
||||||
return device.open({ baudRate: baud });
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
SerialPort.keepReading = true;
|
|
||||||
SerialPort.onDataLine = onDataLine;
|
|
||||||
SerialPort.addReadEvent(onDataLine);
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
SerialPort.obj = null;
|
|
||||||
reject(error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
SerialPort.close = async () => {
|
this.getSelectedPortName = function () {
|
||||||
if (SerialPort.isConnected()) {
|
return Serial.getSelectedPortName();
|
||||||
SerialPort.keepReading = false;
|
|
||||||
if (!SerialPort.isConnected()) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
const serialObj = SerialPort.obj;
|
|
||||||
if (serialObj.readable && serialObj.readable.locked) {
|
this.getCurrentPortsName = function () {
|
||||||
try {
|
return Serial.getCurrentPortsName();
|
||||||
await SerialPort.reader.cancel();
|
}
|
||||||
SerialPort.reader.releaseLock();
|
|
||||||
} catch (error) {
|
this.refreshPorts = function () {
|
||||||
console.log(error);
|
let portsName = [];
|
||||||
|
for (let name of this.nameToPortRegistry.keys()) {
|
||||||
|
portsName.push({ name });
|
||||||
}
|
}
|
||||||
|
Serial.renderSelectBox(portsName);
|
||||||
}
|
}
|
||||||
if (serialObj.writable && serialObj.writable.locked) {
|
|
||||||
try {
|
this.requestPort = async function () {
|
||||||
SerialPort.writer.releaseLock();
|
const serialport = await navigator.serial.requestPort();
|
||||||
} catch (error) {
|
this.addPort(serialport);
|
||||||
console.log(error);
|
this.refreshPorts();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getPort = function (name) {
|
||||||
|
return this.nameToPortRegistry.getItem(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.addPort = function (serialport) {
|
||||||
|
if (this.portToNameRegistry.hasKey(serialport)) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
let name = '';
|
||||||
try {
|
for (let i = 1; i <= 20; i++) {
|
||||||
await serialObj.close();
|
name = `serial${i}`;
|
||||||
} catch (error) {
|
if (this.nameToPortRegistry.hasKey(name)) {
|
||||||
console.log(error);
|
continue;
|
||||||
}
|
}
|
||||||
SerialPort.obj = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SerialPort.isConnected = () => {
|
|
||||||
return SerialPort.obj ? true : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
SerialPort.readLine = () => {
|
|
||||||
var text = "", ch = '';
|
|
||||||
var endWithLF = false;
|
|
||||||
let i = 0;
|
|
||||||
do {
|
|
||||||
ch = SerialPort.readChar();
|
|
||||||
if (ch.length) {
|
|
||||||
if (ch === '\n') {
|
|
||||||
endWithLF = true;
|
|
||||||
} else {
|
|
||||||
text += ch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (ch.length && !endWithLF)
|
|
||||||
return { text: text, endWithLF: endWithLF };
|
|
||||||
}
|
|
||||||
|
|
||||||
SerialPort.readChar = () => {
|
|
||||||
var readBuf = [];
|
|
||||||
var buffLength = 0;
|
|
||||||
var text = "";
|
|
||||||
const len = SerialPort.outputBuffer.length;
|
|
||||||
/* UTF-8编码方式
|
|
||||||
* ------------------------------------------------------------
|
|
||||||
* |1字节 0xxxxxxx |
|
|
||||||
* |2字节 110xxxxx 10xxxxxx |
|
|
||||||
* |3字节 1110xxxx 10xxxxxx 10xxxxxx |
|
|
||||||
* |4字节 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
|
|
||||||
* |5字节 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx |
|
|
||||||
* |6字节 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx|
|
|
||||||
* ------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
for (var i = 0; i < len; i++) {
|
|
||||||
const data = SerialPort.outputBuffer.shift();
|
|
||||||
if ((data & 0x80) == 0x00) {
|
|
||||||
text = String.fromCharCode(data);
|
|
||||||
break;
|
|
||||||
} else if ((data & 0xc0) == 0x80) {
|
|
||||||
readBuf.push(data);
|
|
||||||
if (readBuf.length >= buffLength) {
|
|
||||||
text = SerialPort.decoder.decode(new Uint8Array(readBuf));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
this.portToNameRegistry.register(serialport, name);
|
||||||
let dataNum = data & 0xe0;
|
this.nameToPortRegistry.register(name, serialport);
|
||||||
switch (dataNum) {
|
}
|
||||||
case 0xfc:
|
|
||||||
buffLength = 6;
|
this.removePort = function (serialport) {
|
||||||
break;
|
if (!this.portToNameRegistry.hasKey(serialport)) {
|
||||||
case 0xf8:
|
return;
|
||||||
buffLength = 5;
|
|
||||||
break;
|
|
||||||
case 0xf0:
|
|
||||||
buffLength = 4;
|
|
||||||
break;
|
|
||||||
case 0xe0:
|
|
||||||
buffLength = 3;
|
|
||||||
break;
|
|
||||||
case 0xc0:
|
|
||||||
default:
|
|
||||||
buffLength = 2;
|
|
||||||
}
|
}
|
||||||
readBuf.push(data);
|
const name = this.portToNameRegistry.getItem(serialport);
|
||||||
|
if (!name) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.portToNameRegistry.unregister(serialport);
|
||||||
|
this.nameToPortRegistry.unregister(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.addEventsListener = function () {
|
||||||
|
navigator?.serial?.addEventListener('connect', (event) => {
|
||||||
|
this.addPort(event.target);
|
||||||
|
this.refreshPorts();
|
||||||
|
});
|
||||||
|
|
||||||
|
navigator?.serial?.addEventListener('disconnect', (event) => {
|
||||||
|
this.removePort(event.target);
|
||||||
|
this.refreshPorts();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.init = function () {
|
||||||
|
navigator?.serial?.getPorts().then((serialports) => {
|
||||||
|
for (let serialport of serialports) {
|
||||||
|
this.addPort(serialport);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.addEventsListener();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
SerialPort.startReadLine = (onDataLine = (message) => {}) => {
|
#serialport_ = null;
|
||||||
SerialPort.readLineTimer = window.setTimeout(() => {
|
#keepReading_ = null;
|
||||||
if (!SerialPort.keepReading) {
|
#reader_ = null;
|
||||||
window.clearTimeout(SerialPort.readLineTimer);
|
#writer_ = null;
|
||||||
|
#stringTemp_ = '';
|
||||||
|
constructor(port) {
|
||||||
|
super(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
#addEventsListener_() {
|
||||||
|
this.#addReadEventListener_();
|
||||||
|
}
|
||||||
|
|
||||||
|
async #addReadEventListener_() {
|
||||||
|
const { readable } = this.#serialport_;
|
||||||
|
while (readable && this.#keepReading_) {
|
||||||
|
this.#reader_ = readable.getReader();
|
||||||
|
try {
|
||||||
|
while (true) {
|
||||||
|
const { value, done } = await this.#reader_.read();
|
||||||
|
value && this.onBuffer(value);
|
||||||
|
if (done) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.#keepReading_ = false;
|
||||||
|
Debug.error(error);
|
||||||
|
} finally {
|
||||||
|
this.#reader_ && this.#reader_.releaseLock();
|
||||||
|
await this.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async open(baud) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const portsName = Serial.getCurrentPortsName();
|
||||||
|
const currentPortName = this.getPortName();
|
||||||
|
if (!portsName.includes(currentPortName)) {
|
||||||
|
reject('无可用串口');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.isOpened()) {
|
||||||
|
resolve();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
baud = baud ?? this.getBaudRate();
|
||||||
|
this.#serialport_ = WebSerialPort.getPort(currentPortName);
|
||||||
|
this.#serialport_.open({ baudRate: baud })
|
||||||
|
.then(() => {
|
||||||
|
super.open(baud);
|
||||||
|
super.setBaudRate(baud);
|
||||||
|
this.#keepReading_ = true;
|
||||||
|
this.onOpen();
|
||||||
|
this.#addEventsListener_();
|
||||||
|
resolve();
|
||||||
|
})
|
||||||
|
.catch(reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async #waitForUnlock_(timeout) {
|
||||||
|
while (
|
||||||
|
(this.#serialport_.readable && this.#serialport_.readable.locked) ||
|
||||||
|
(this.#serialport_.writable && this.#serialport_.writable.locked)
|
||||||
|
) {
|
||||||
|
await this.sleep(timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async close() {
|
||||||
|
if (!this.isOpened()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let endWithLF = false;
|
super.close();
|
||||||
do {
|
if (this.#serialport_.readable?.locked) {
|
||||||
const readObj = SerialPort.readLine();
|
this.#keepReading_ = false;
|
||||||
endWithLF = readObj.endWithLF;
|
await this.#reader_?.cancel();
|
||||||
const { text } = readObj;
|
|
||||||
SerialPort.output.push((SerialPort.output.length? SerialPort.output.pop() : '') + text);
|
|
||||||
if (endWithLF) {
|
|
||||||
const len = SerialPort.output.length;
|
|
||||||
SerialPort.output[len - 1] = MString.decode(SerialPort.output[len - 1]);
|
|
||||||
if (len) {
|
|
||||||
onDataLine(SerialPort.output[len - 1]);
|
|
||||||
}
|
|
||||||
SerialPort.output.push('');
|
|
||||||
}
|
|
||||||
} while (endWithLF);
|
|
||||||
while (SerialPort.output.length > 500) {
|
|
||||||
SerialPort.output.shift();
|
|
||||||
}
|
}
|
||||||
if (SerialPort.keepReading) {
|
await this.#waitForUnlock_(400);
|
||||||
SerialPort.startReadLine(onDataLine);
|
this.#reader_ = undefined;
|
||||||
}
|
await this.#serialport_.close();
|
||||||
}, 100);
|
this.#stringTemp_ = '';
|
||||||
}
|
this.onClose(1);
|
||||||
|
}
|
||||||
|
|
||||||
SerialPort.addReadEvent = async (onDataLine = (message) => {}) => {
|
async setBaudRate(baud) {
|
||||||
SerialPort.output = [];
|
return new Promise((resolve, reject) => {
|
||||||
SerialPort.inputBuffer = [];
|
if (!this.isOpened()
|
||||||
SerialPort.outputBuffer = [];
|
|| this.getBaudRate() === baud
|
||||||
SerialPort.refreshInputBuffer = false;
|
|| !this.baudRateIsLegal(baud)) {
|
||||||
SerialPort.refreshOutputBuffer = true;
|
resolve();
|
||||||
SerialPort.startReadLine(onDataLine);
|
return;
|
||||||
while (SerialPort.obj.readable && SerialPort.keepReading) {
|
}
|
||||||
SerialPort.reader = SerialPort.obj.readable.getReader();
|
this.close()
|
||||||
try {
|
.then(() => this.open(baud))
|
||||||
while (true) {
|
.then(resolve)
|
||||||
const { value, done } = await SerialPort.reader.read();
|
.catch(reject);
|
||||||
if (SerialPort.refreshOutputBuffer && value) {
|
});
|
||||||
SerialPort.outputBuffer = [ ...SerialPort.outputBuffer, ...value ];
|
}
|
||||||
}
|
|
||||||
if (SerialPort.refreshInputBuffer && value) {
|
async sendString(str) {
|
||||||
SerialPort.inputBuffer = [ ...SerialPort.inputBuffer, ...value ];
|
const buffer = this.encode(str);
|
||||||
}
|
return this.sendBuffer(buffer);
|
||||||
if (done) {
|
}
|
||||||
break;
|
|
||||||
}
|
async sendBuffer(buffer) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const { writable } = this.#serialport_;
|
||||||
|
const writer = writable.getWriter();
|
||||||
|
if (!(buffer instanceof Uint8Array)) {
|
||||||
|
buffer = new Uint8Array(buffer);
|
||||||
|
}
|
||||||
|
writer.write(buffer)
|
||||||
|
.then(() => {
|
||||||
|
writer.releaseLock();
|
||||||
|
resolve();
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
writer.releaseLock();
|
||||||
|
reject();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async setDTRAndRTS(dtr, rts) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (!this.isOpened()) {
|
||||||
|
resolve();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.#serialport_.setSignals({
|
||||||
|
dataTerminalReady: dtr,
|
||||||
|
requestToSend: rts
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
super.setDTRAndRTS(dtr, rts);
|
||||||
|
resolve();
|
||||||
|
})
|
||||||
|
.catch(reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async setDTR(dtr) {
|
||||||
|
return this.setDTRAndRTS(dtr, this.getRTS());
|
||||||
|
}
|
||||||
|
|
||||||
|
async setRTS(rts) {
|
||||||
|
return this.setDTRAndRTS(this.getDTR(), rts);
|
||||||
|
}
|
||||||
|
|
||||||
|
onBuffer(buffer) {
|
||||||
|
super.onBuffer(buffer);
|
||||||
|
for (let i = 0; i < buffer.length; i++) {
|
||||||
|
super.onByte(buffer[i]);
|
||||||
|
}
|
||||||
|
const string = this.decodeBuffer(buffer);
|
||||||
|
if (!string) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (let char of string) {
|
||||||
|
super.onChar(char);
|
||||||
|
if (['\r', '\n'].includes(char)) {
|
||||||
|
super.onString(this.#stringTemp_);
|
||||||
|
this.#stringTemp_ = '';
|
||||||
|
} else {
|
||||||
|
this.#stringTemp_ += char;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
|
||||||
console.log(error);
|
|
||||||
} finally {
|
|
||||||
SerialPort.reader.releaseLock();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SerialPort.AddOnConnectEvent = (onConnect) => {
|
Web.SerialPort = WebSerialPort;
|
||||||
navigator.serial.addEventListener('connect', (event) => {
|
|
||||||
onConnect();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
SerialPort.AddOnDisconnectEvent = (onDisconnect) => {
|
|
||||||
navigator.serial.addEventListener('disconnect', (event) => {
|
|
||||||
SerialPort.obj && SerialPort.close();
|
|
||||||
onDisconnect();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
SerialPort.writeString = async (str) => {
|
|
||||||
const buffer = SerialPort.encoder.encode(str);
|
|
||||||
await SerialPort.writeByteArr(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
SerialPort.writeByteArr = async (buffer) => {
|
|
||||||
const writer = SerialPort.obj.writable.getWriter();
|
|
||||||
await writer.write(new Int8Array(buffer).buffer);
|
|
||||||
writer.releaseLock();
|
|
||||||
await SerialPort.sleep(200);
|
|
||||||
}
|
|
||||||
|
|
||||||
SerialPort.writeCtrlA = async () => {
|
|
||||||
await SerialPort.writeByteArr([1, 13, 10]);
|
|
||||||
}
|
|
||||||
|
|
||||||
SerialPort.writeCtrlB = async () => {
|
|
||||||
await SerialPort.writeByteArr([2, 13, 10]);
|
|
||||||
}
|
|
||||||
|
|
||||||
SerialPort.writeCtrlC = async () => {
|
|
||||||
await SerialPort.writeByteArr([3, 13, 10]);
|
|
||||||
}
|
|
||||||
|
|
||||||
SerialPort.writeCtrlD = async () => {
|
|
||||||
await SerialPort.writeByteArr([3, 4]);
|
|
||||||
}
|
|
||||||
|
|
||||||
SerialPort.setBaudRate = async (baud) => {
|
|
||||||
SerialPort.keepReading = false;
|
|
||||||
const serialObj = SerialPort.obj;
|
|
||||||
await SerialPort.close();
|
|
||||||
await serialObj.open({ baudRate: baud - 0 });
|
|
||||||
SerialPort.obj = serialObj;
|
|
||||||
SerialPort.keepReading = true;
|
|
||||||
SerialPort.setSignals(SerialPort.dtr, SerialPort.rts);
|
|
||||||
SerialPort.addReadEvent(SerialPort.onDataLine);
|
|
||||||
}
|
|
||||||
|
|
||||||
SerialPort.setDTR = async (value) => {
|
|
||||||
SerialPort.dtr = value;
|
|
||||||
await SerialPort.obj.setSignals({ dataTerminalReady: value });
|
|
||||||
}
|
|
||||||
|
|
||||||
SerialPort.setRTS = async (value) => {
|
|
||||||
SerialPort.rts = value;
|
|
||||||
await SerialPort.obj.setSignals({ requestToSend: value });
|
|
||||||
}
|
|
||||||
|
|
||||||
SerialPort.setSignals = async (dtr, rts) => {
|
|
||||||
SerialPort.dtr = dtr;
|
|
||||||
SerialPort.rts = rts;
|
|
||||||
await SerialPort.obj.setSignals({ dataTerminalReady: dtr, requestToSend: rts });
|
|
||||||
}
|
|
||||||
|
|
||||||
SerialPort.sleep = (ms) => {
|
|
||||||
return new Promise(resolve => setTimeout(resolve, ms));
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
});
|
||||||
@@ -2,20 +2,12 @@ goog.loadJs('web', () => {
|
|||||||
|
|
||||||
goog.require('DAPjs');
|
goog.require('DAPjs');
|
||||||
goog.require('Mixly.Serial');
|
goog.require('Mixly.Serial');
|
||||||
goog.require('Mixly.Env');
|
|
||||||
goog.require('Mixly.Nav');
|
|
||||||
goog.require('Mixly.Msg');
|
|
||||||
goog.require('Mixly.Debug');
|
|
||||||
goog.require('Mixly.Registry');
|
goog.require('Mixly.Registry');
|
||||||
goog.require('Mixly.Web');
|
goog.require('Mixly.Web');
|
||||||
goog.provide('Mixly.Web.USB');
|
goog.provide('Mixly.Web.USB');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
Serial,
|
Serial,
|
||||||
Env,
|
|
||||||
Nav,
|
|
||||||
Msg,
|
|
||||||
Debug,
|
|
||||||
Registry,
|
Registry,
|
||||||
Web
|
Web
|
||||||
} = Mixly;
|
} = Mixly;
|
||||||
@@ -93,22 +85,25 @@ class USB extends Serial {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.addEventsListener = function () {
|
this.addEventsListener = function () {
|
||||||
navigator.usb.addEventListener('connect', (event) => {
|
navigator?.usb?.addEventListener('connect', (event) => {
|
||||||
this.addPort(event.device);
|
this.addPort(event.device);
|
||||||
this.refreshPorts();
|
this.refreshPorts();
|
||||||
});
|
});
|
||||||
|
|
||||||
navigator.usb.addEventListener('disconnect', (event) => {
|
navigator?.usb?.addEventListener('disconnect', (event) => {
|
||||||
this.removePort(event.device);
|
this.removePort(event.device);
|
||||||
this.refreshPorts();
|
this.refreshPorts();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
navigator.usb.getDevices().then((devices) => {
|
|
||||||
for (let device of devices) {
|
this.init = function () {
|
||||||
this.addPort(device);
|
navigator?.usb?.getDevices().then((devices) => {
|
||||||
}
|
for (let device of devices) {
|
||||||
});
|
this.addPort(device);
|
||||||
this.addEventsListener();
|
}
|
||||||
|
});
|
||||||
|
this.addEventsListener();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#device_ = null;
|
#device_ = null;
|
||||||
|
|||||||
Reference in New Issue
Block a user