在通过 Web Serial API读写数据中,我通过翻译一篇技术文档,学习了和串口交互的基本方法。
在本篇笔记中,想学以致用。有两个目标,第一个是将基础的读写方法封装一下,以求可以简单实用,第二个呢就是能在已封装的基础上,实际使用一下。
首先展示封装的代码,如果有需要,直接复制粘贴拿去用,代码里面有看不明的,欢迎翻看一下通过 Web Serial API读写数据,本篇内容都是基于它而来。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97export default class HandleSerial {
constructor (usbProductId, usbVendorId) {
if (!usbProductId || !usbVendorId) return;
this.usbProductId = usbProductId;
this.usbVendorId = usbVendorId;
this.support = false;
// 打开后的serilPort
this.port = '';
this.checkSupport()
}
test () {
console.log(this.usbProductId, this.usbVendorId)
console.log(this.support, 'ssss')
}
checkSupport () {
if ('serial' in navigator) {
this.support = true
} else {
this.support = true
}
}
listenOnConnectDevice (cb) {
navigator.serial.addEventListener('connect', () => {
if (cb) {
cb()
}
})
}
listenOnDisconnectDevice (cb) {
navigator.serial.addEventListener('disconnect', (event) => {
const {usbProductId, usbVendorId} = event.target.getInfo();
if (Number(usbProductId) === Number(this.usbProductId) && Number(usbVendorId) === Number(this.usbVendorId)) {
this.port = ''
if (cb) {
cb()
}
}
})
}
async connectSerial (openData) {
console.log(navigator, 'navigator.serial')
const hadAccessPortList = await navigator.serial.getPorts();
this._getPortByList(hadAccessPortList)
if (!this.port) {
const filters = [{
usbProductId: this.usbProductId,
usbVendorId: this.usbVendorId
}]
this.port = await navigator.serial.requestPort({
filters
})
}
if (this.port) {
// openData = {baudRate: 4} ,传参参考https://developer.mozilla.org/en-US/docs/Web/API/SerialPort/open
await this.port.open(openData)
}
return this.port
}
_getPortByList (portList) {
for (let i = 0; i < portList.length; i++) {
const eachPort = portList[i].getInfo()
if (Number(eachPort.usbProductId) === Number(this.usbProductId) && Number(eachPort.usbVendorId) === Number(this.usbVendorId)) {
this.port = portList[i];
break;
}
}
return
}
async writeData (data) {
if (!this.port) return;
const textEncoder = new TextEncoderStream();
const writableStreamClosed = textEncoder.readable.pipeTo(this.port.writable);
const writer = textEncoder.writable.getWriter()
await writer.write(data);
writer.close();
await writableStreamClosed;
await writer.releaseLock();
}
async readData () {
if (!this.port) return;
const textDecoder = new TextDecoderStream();
const readableStreamClosed = this.port.readable.pipeTo(textDecoder.writable);
const reader = textDecoder.readable.getReader();
const {value} = await reader.read();
reader.cancel();
await readableStreamClosed.catch(() => {})
await reader.releaseLock();
return value;
}
}
在使用时,首先引入代码(假设引入代码和HandleSerial.js在同一目录下),如下:
import HandleSerial from './HandleSerial.js'
如果需要在html文件的script
标签中通过src引入,可以对上面文件做如下改造
原代码1
2
3export default class HandleSerial {
......
}
改造后的代码1
2
3class HandleSerial {
......
}
然后直接做如下引用:<script src="./HandleSerial.js"></script>
引入之后,就可以开始使用,首先实例话,不管用哪种方式引入,接下来的用法都是一样的,usbProductId, usbVendorId必选,不知道的话可以直接找厂商去要
1 | const handleSerial = new HandleSerial(usbProductId, usbVendorId) |
实例话后首先检查当前浏览器是否支持串口设备的连接,如果支持,再继续连接或者写自己的逻辑
1 | if (handleSerial.support) { |
如果当前浏览器不支持串口设备,哪只能提醒用户去升级,不然我们没办法服务了。
浏览器支持串口设备的情况下,我们就可以来做接下来的工作。
首先,将设备的断开连接检测起来,以处理相应的逻辑
- 监听串口设备断开
listenOnDisconnectDevice
1 | function onSerialDisconnect() { |
监听串口设备连接
listenOnConnectDevice
如果没有监听串口设备,监听到串口设备,有可能是之前断开过,所以每次初始化重连是必要的1
2
3
4
5
6
7
8function onSerialConnect() {
if (handleSerial.port) {
handleSerial.port = ''
// 重连
}
// 串口设备连接时的业务逻辑
}
handleSerial.listenOnConnectDevice(onSerialConnect)提前做好监听功能后,就可以正式开始和串口交互了
连接
connectSerial
,需要传入openData
参数,openData的具体参数参考SerialPort.open()或者翻看这篇博客
基本参数如下:
- baudRate :每秒发送数据的速度
- dataBits: 每帧发送的数据量(7或者8)
- parity: parity模式,可选值有
none
,even
,odd
- bufferSize: 读写的buffer数据大小,不能超过16MB
- flowControl:流控制模式,
none
或者hardware
。
1 | const openData = {baudRate: 4} |
- 写入数据到串口设备
writeData
连接成功后,就可以给串口设备写入数据,具体数据,不同的设备可能要求不同,要根据设备要求来写,比如下面我们写入一个1.
1 | const writeData = 1 |
读取串口设备的数据
readData
如果我们的函数是在一个
async/awiat
函数中,我们可以这样做1
2const data = await handleSerial.readData()
// 处理逻辑如果不是,也可以这样
1 | handleSerial.readData().then((data) => { |
是不是感觉比直接写简单了很多。希望能对看到本文的用户有所帮助。