Web Serial Api 串口 实现(物流秤)

采用Web Serial Api 实现串口通讯

业务需求要和物流秤进行数据对接,实现数据可以定制化显示,和后台系统互通,Web Serial Api目前只适用于谷歌、火狐等。后端语言均可以实现。

什么是网络串行 API?

串行端口是一种双向通信接口,允许逐字节发送和接收数据。

Web Serial API 为网站提供了一种使用 JavaScript 读取和写入串行设备的方法。串行设备通过用户系统上的串行端口或通过模拟串行端口的可移动 USB 和蓝牙设备连接。

换句话说,Web Serial API 通过允许网站与串行设备(例如微控制器和 3D 打印机)进行通信,从而在 Web 和物理世界之间架起了一座桥梁。

此 API 也是WebUSB的绝佳伴侣,因为操作系统要求应用程序使用其高级串行 API 而不是低级 USB API 与某些串行端口进行通信。

Html部分

<html>
<head>
    <title>
        测试串口
    </title>
</head>
<body>
<form id="myForm">
    <table cellspacing="5" cellpadding="10">
        <tr>
            <td>波特率</td>
            <td>
                <select name="baudRate">
                    <option value="300">300</option>
                    <option value="600">600</option>
                    <option value="1200">1200</option>
                    <option value="2400">2400</option>
                    <option value="4800">4800</option>
                    <option value="9600" selected>9600</option>
                    <option value="19200">19200</option>
                    <option value="38400">38400</option>
                    <option value="57600">57600</option>
                    <option value="115200">115200</option>
                </select>
            </td>
        </tr>
        <tr>
            <td>数据位</td>
            <td>
                <select name="dataBits">
                    <option value="5">5</option>
                    <option value="6">6</option>
                    <option value="7">7</option>
                    <option value="8" selected="">8</option>
                </select>
            </td>
        </tr>
        <tr>
            <td>校验位</td>
            <td>
                <select name="parity">
                    <option value="none" selected="">None</option>
                    <option value="odd">Odd</option>
                    <option value="even">Even</option>
                </select>
            </td>
        </tr>
        <tr>
            <td>停止位</td>
            <td>
                <select name="stopBits" lay-filter="stopBits">
                    <option value="1" selected="">1</option>
                    <option value="2">2</option>
                </select>
            </td>
        </tr>
        <tr>
            <td>接收信息区域</td>
            <td>
                <textarea rows="6" cols="90" name="getMessageArea"></textarea>
            </td>
        </tr>
    </table>
</form>
<div>
    <button id="connect">打开串口</button>&nbsp;&nbsp;
    <button id="close">关闭串口</button>
</div>
</body>
<script type="application/javascript" src="jquery-3-3-1.min.js"></script>
<script type="application/javascript" src="lineBreakTransformer.js"></script>
<script type="application/javascript" src="serial-reader.js"></script>
<script>
    let serialReader = new SerialReader();

    //初始化扫码机
    const initSweep = async () => {
        try {
            var baudRate = $("#myForm").find("select[name='baudRate']").val();
            var parity = $("#myForm").find("select[name='parity']").val();
            var dataBits = $("#myForm").find("select[name='dataBits']").val();
            var stopBits = $("#myForm").find("select[name='stopBits']").val();

            await serialReader.initSweepPrinter(baudRate, dataBits, stopBits, parity);
        } catch (e) {
            console.error('扫码机读取失败', e);
        }
    }

    //连接串口
    $('#connect').click(function () {
        initSweep();
    });

    //断开
    $('#close').click(function () {
        serialReader.disconnect().then(() => {
            console.log('断开成功!');
        });
    });
</script>
</html>

serial-reader.js(封装成一个类)

class SerialReader {
    port;//串口
    reader;//读取
    inputDone;

    constructor() {
        if (!("serial" in navigator)) {
            alert('当前浏览器不支持串口');
            return;
        }
        this.filtersSweep = [
			{ usbVendorId: 0x2341, usbProductId: 0x0043 },//指定显示的设备ID,好像只有USB接口才有
		];//串口识别码-扫码机
    }

    //初始化
    initSweepPrinter = async (baudRate, dataBits, stopBits, parity) => {
        let requestOptions = {filters: this.filtersSweep};
		
        this.port = await navigator.serial.requestPort(requestOptions);

        await this.port.open({
            baudRate: baudRate,// 一个正的、非零的值,表示串口通信应该建立的波特率
            dataBits: dataBits,// 7或8的整数值,表示每帧的数据位数。默认值为8
            stopBits: stopBits,// 1或2的整数值,表示帧结束时的停止位数。默认值为1。
            parity: parity,// 奇偶校验模式为“none”、“偶”或“奇”。默认值为none。
            bufferSize: 255, // 一个无符号长整数,指示要建立的读和写缓冲区的大小。如果未通过,默认值为255。
            flowControl: 'none', // 流控制类型,“none”或“hardware”。默认值为none。
        });

        const decoder = new TextDecoderStream();
        this.inputDone = this.port.readable.pipeTo(decoder.writable);
        // this.reader = decoder.readable.pipeThrough(new TransformStream(new LineBreakTransformer())).getReader();//USB好像需要特殊处理,没有测试过
        this.reader = decoder.readable.getReader();//显示器接头直接返回数据

        console.log('连接成功');

        return new Promise(async (resolve, reject) => {
            while (true) {
                const {value, done} = await this.reader.read();
                if (value) {
                	$('#myForm').find("textarea[name='getMessageArea']").append(value)
                    console.log('扫码机数据 = ', value);
                    resolve(value);
                }
                if (done) {
                    this.reader.releaseLock();
                    break;
                }
            }
        })
    }

    //断开
    disconnect = async () => {
        return new Promise(async (resolve, reject) => {
            if (this.reader && this.port && this.inputDone) {
                await this.reader.cancel();
                await this.inputDone.catch(() => { });
                this.reader = null;
                this.inputDone = null;
                await this.port.close();
                this.port = null;
                resolve();
            }
        })
    }
}

LineBreakTransformer.js(好像只有USB接口设备需要这样处理)

// 将原本可能截断成多个字符串的内容按顺序合并一个字符串
class LineBreakTransformer {
    constructor() {
        // 保存流数据直到新行出现的容器
        this.container = "";
    }

    transform(chunk, controller) {
        // 将新块追加到现有块。
        this.container += chunk;
        // 对于每一行分段,将解析后的行发送出去。
        const lines = this.container.split("\r");
        this.container = lines.pop();
        lines.forEach((line) => controller.enqueue(line));
    }

    flush(controller) {
        // 当流关闭时,清除所有剩余的块。
        controller.enqueue(this.container);
    }
}

Web是罗列出来所有的串口列表,后端是直接指定串口的名字

Web是罗列出来所有的串口列表,后端是直接指定串口的名字

串口都是成对的,一个接收,一个发送串口都是成对的,一个接收,一个发送

参考资料:

  1. Web Serial API
  2. Web Serial API 方法文档
  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值