Files
mixly3/common/modules/mixly-modules/web/serialport.js
2024-07-19 10:16:00 +08:00

285 lines
8.4 KiB
JavaScript

goog.loadJs('web', () => {
goog.require('Mixly.MString');
goog.require('Mixly.Web');
goog.provide('Mixly.Web.SerialPort');
const { MString, Web } = Mixly;
const { SerialPort } = Web;
SerialPort.output = [];
SerialPort.inputBuffer = [];
SerialPort.outputBuffer = [];
SerialPort.refreshInputBuffer = false;
SerialPort.refreshOutputBuffer = true;
SerialPort.obj = null;
SerialPort.onDataLine = null;
SerialPort.keepReading = false;
SerialPort.encoder = new TextEncoder('utf8');
SerialPort.decoder = new TextDecoder('utf8');
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 () => {
if (SerialPort.isConnected()) {
SerialPort.keepReading = false;
if (!SerialPort.isConnected()) {
return;
}
const serialObj = SerialPort.obj;
if (serialObj.readable && serialObj.readable.locked) {
try {
await SerialPort.reader.cancel();
SerialPort.reader.releaseLock();
} catch (error) {
console.log(error);
}
}
if (serialObj.writable && serialObj.writable.locked) {
try {
SerialPort.writer.releaseLock();
} catch (error) {
console.log(error);
}
}
try {
await serialObj.close();
} catch (error) {
console.log(error);
}
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;
}
} else {
let dataNum = data & 0xe0;
switch (dataNum) {
case 0xfc:
buffLength = 6;
break;
case 0xf8:
buffLength = 5;
break;
case 0xf0:
buffLength = 4;
break;
case 0xe0:
buffLength = 3;
break;
case 0xc0:
default:
buffLength = 2;
}
readBuf.push(data);
}
}
return text;
}
SerialPort.startReadLine = (onDataLine = (message) => {}) => {
SerialPort.readLineTimer = window.setTimeout(() => {
if (!SerialPort.keepReading) {
window.clearTimeout(SerialPort.readLineTimer);
return;
}
let endWithLF = false;
do {
const readObj = SerialPort.readLine();
endWithLF = readObj.endWithLF;
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) {
SerialPort.startReadLine(onDataLine);
}
}, 100);
}
SerialPort.addReadEvent = async (onDataLine = (message) => {}) => {
SerialPort.output = [];
SerialPort.inputBuffer = [];
SerialPort.outputBuffer = [];
SerialPort.refreshInputBuffer = false;
SerialPort.refreshOutputBuffer = true;
SerialPort.startReadLine(onDataLine);
while (SerialPort.obj.readable && SerialPort.keepReading) {
SerialPort.reader = SerialPort.obj.readable.getReader();
try {
while (true) {
const { value, done } = await SerialPort.reader.read();
if (SerialPort.refreshOutputBuffer && value) {
SerialPort.outputBuffer = [ ...SerialPort.outputBuffer, ...value ];
}
if (SerialPort.refreshInputBuffer && value) {
SerialPort.inputBuffer = [ ...SerialPort.inputBuffer, ...value ];
}
if (done) {
break;
}
}
} catch (error) {
console.log(error);
} finally {
SerialPort.reader.releaseLock();
}
}
}
SerialPort.AddOnConnectEvent = (onConnect) => {
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));
}
});