Files
mixly3-server/mixly/common/modules/mixly-modules/web-socket/serial.js
2026-01-24 16:12:04 +08:00

360 lines
11 KiB
JavaScript

goog.loadJs('web', () => {
goog.require('Mixly.Serial');
goog.require('Mixly.Env');
goog.require('Mixly.Msg');
goog.require('Mixly.Debug');
goog.require('Mixly.Registry');
goog.require('Mixly.WebSocket');
goog.provide('Mixly.WebSocket.Serial');
const {
Serial,
Env,
Msg,
Debug,
Registry,
WebSocket
} = Mixly;
class WebSocketSerial extends Serial {
static {
this.eventRegistry = new Registry();
this.mixlySocket = null;
this.socket = null;
this.getConfig = function () {
return Serial.getConfig();
}
this.getSelectedPortName = function () {
return Serial.getSelectedPortName();
}
this.getCurrentPortsName = function () {
return Serial.getCurrentPortsName();
}
this.renderSelectBox = function (ports) {
return Serial.renderSelectBox(ports);
}
this.getPorts = async function () {
return new Promise((resolve, reject) => {
if (this.socket.connected) {
this.socket.emit('serial.getPorts', (response) => {
const [error, result] = response;
if (error) {
reject(error);
} else {
resolve(result);
}
});
} else {
resolve([]);
}
});
}
this.refreshPorts = function () {
this.getPorts()
.then((ports) => {
Serial.renderSelectBox(ports);
})
.catch(Debug.error);
}
this.init = function (mixlySocket) {
this.mixlySocket = mixlySocket;
this.socket = mixlySocket.getSocket();
const socket = this.socket;
socket.on('serial.attachEvent', () => {
this.refreshPorts();
});
socket.on('serial.detachEvent', () => {
this.refreshPorts();
});
socket.on('serial.bufferEvent', (port, buffer) => {
const eventName = `${port}-buffer`;
if (!this.eventRegistry.hasKey(eventName)) {
return;
}
const event = this.eventRegistry.getItem(eventName);
event(buffer);
});
socket.on('serial.stringEvent', (port, str) => {
const eventName = `${port}-string`;
if (!this.eventRegistry.hasKey(eventName)) {
return;
}
const event = this.eventRegistry.getItem(eventName);
event(str);
});
socket.on('serial.errorEvent', (port, error) => {
const eventName = `${port}-error`;
if (!this.eventRegistry.hasKey(eventName)) {
return;
}
const event = this.eventRegistry.getItem(eventName);
event(error);
});
socket.on('serial.openEvent', (port) => {
const eventName = `${port}-open`;
if (!this.eventRegistry.hasKey(eventName)) {
return;
}
const event = this.eventRegistry.getItem(eventName);
event();
});
socket.on('serial.closeEvent', (port, code) => {
const eventName = `${port}-close`;
if (!this.eventRegistry.hasKey(eventName)) {
return;
}
const event = this.eventRegistry.getItem(eventName);
event(code);
});
}
this.getSocket = function () {
return this.socket;
}
this.getMixlySocket = function () {
return this.mixlySocket;
}
this.getEventRegistry = function () {
return this.eventRegistry;
}
}
constructor(port) {
super(port);
this.#addEventsListener_();
const socket = WebSocketSerial.getSocket();
if (socket.connected) {
socket.emit('serial.create', port);
}
}
#addEventsListener_() {
const port = this.getPortName();
const eventRegistry = WebSocketSerial.getEventRegistry();
eventRegistry.register(`${port}-buffer`, (buffer) => {
this.onBuffer(buffer);
});
eventRegistry.register(`${port}-string`, (str) => {
this.onString(str);
});
eventRegistry.register(`${port}-error`, (error) => {
this.onError(error);
this.onClose(1);
});
eventRegistry.register(`${port}-open`, () => {
this.onOpen();
});
eventRegistry.register(`${port}-close`, (code) => {
this.onClose(code);
});
}
async open(baud) {
return new Promise((resolve, reject) => {
const portsName = Serial.getCurrentPortsName();
const currentPort = this.getPortName();
if (!portsName.includes(currentPort)) {
reject('无可用串口');
return;
}
if (this.isOpened()) {
resolve();
return;
}
baud = baud ?? this.getBaudRate();
const mixlySocket = WebSocketSerial.getMixlySocket();
mixlySocket.emit('serial.open', currentPort, baud, (response) => {
if (response.error) {
reject(response.error);
return;
}
const [error, result] = response;
if (error) {
this.onError(error);
reject(error);
} else {
super.open(baud);
this.setBaudRate(baud);
resolve(result);
}
});
});
}
async close() {
return new Promise((resolve, reject) => {
if (!this.isOpened()) {
resolve();
return;
}
super.close();
const mixlySocket = WebSocketSerial.getMixlySocket();
mixlySocket.emit('serial.close', this.getPortName(), (response) => {
if (response.error) {
this.onClose(1);
resolve(response.error);
return;
}
const [error, result] = response;
if (error) {
reject(error);
} else {
resolve(result);
}
});
});
}
async setBaudRate(baud) {
return new Promise((resolve, reject) => {
if (!this.isOpened()
|| this.getRawBaudRate() === baud
|| !this.baudRateIsLegal(baud)) {
resolve();
return;
}
const mixlySocket = WebSocketSerial.getMixlySocket();
mixlySocket.emit('serial.setBaudRate', this.getPortName(), baud, (response) => {
if (response.error) {
reject(response.error);
return;
}
const [error,] = response;
if (error) {
reject(error);
} else {
super.setBaudRate(baud);
this.setDTRAndRTS(this.getDTR(), this.getRTS()).finally(resolve);
}
});
});
}
async send(data) {
return new Promise((resolve, reject) => {
if (!this.isOpened()) {
resolve();
return;
}
const mixlySocket = WebSocketSerial.getMixlySocket();
mixlySocket.emit('serial.send', this.getPortName(), data, (response) => {
if (response.error) {
reject(response.error);
return;
}
const [error, result] = response;
if (error) {
reject(error);
} else {
resolve(result);
}
});
});
}
async sendString(str) {
return this.send(str);
}
async sendBuffer(buffer) {
return this.send(buffer);
}
async setDTRAndRTS(dtr, rts) {
return new Promise((resolve, reject) => {
if (!this.isOpened()) {
resolve();
return;
}
const mixlySocket = WebSocketSerial.getMixlySocket();
mixlySocket.emit('serial.setDTRAndRTS', this.getPortName(), dtr, rts, (response) => {
if (response.error) {
reject(response.error);
return;
}
const [error, result] = response;
if (error) {
reject(error);
} else {
super.setDTRAndRTS(dtr, rts);
resolve(result);
}
});
});
}
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);
}
}
async #awaitDispose_() {
return new Promise((resolve, reject) => {
const mixlySocket = WebSocketSerial.getMixlySocket();
mixlySocket.emit('serial.dispose', this.getPortName(), (response) => {
if (response.error) {
resolve();
return;
}
const [error, result] = response;
if (error) {
reject(error);
} else {
resolve(result);
}
});
});
}
async dispose() {
const port = this.getPortName();
const eventRegistry = WebSocketSerial.getEventRegistry();
eventRegistry.unregister(`${port}-buffer`);
eventRegistry.unregister(`${port}-string`);
eventRegistry.unregister(`${port}-error`);
eventRegistry.unregister(`${port}-open`);
eventRegistry.unregister(`${port}-close`);
await super.dispose();
await this.#awaitDispose_();
}
}
WebSocket.Serial = WebSocketSerial;
});