webUsb初识

webUSB初识 --派大星的开发日记

个人开发记录笔记,仅个人理解,有错误还请指出

概述

WebUSB API 提供了一种将非标准化通用串行总线(USB)兼容设备服务暴露到Web的方法,使USB设备更安全、更易于使用。这项技术目前是实验性的,并且仅在支持的浏览器的安全上下文中(HTTPS)可用。

概念和用法

  • USB是连接到计算机的有线外设的事实标准,包括键盘、鼠标、视频设备等。
  • 除了标准化设备外,还有许多需要自定义驱动程序的非标准化设备,这些设备之前无法从Web访问。
  • WebUSB允许这些非标准化USB设备在Web中可用,无需下载和安装驱动程序。

接口

  • USB:提供从网页中查找和连接USB设备的属性和方法。
  • USBConnectionEvent:传递给USBconnectdisconnect事件的事件类型。
  • USBDevice:提供对已配对的USB设备的元数据的访问以及控制方法。
  • USBInTransferResultUSBOutTransferResult:表示数据传输的结果。
  • USBIsochronousInTransferPacketUSBIsochronousOutTransferPacket:表示同步端点上数据传输的单个包的状态。
  • USBIsochronousInTransferResultUSBIsochronousOutTransferResult:表示同步端点上数据传输的结果。
  • USBConfiguration:提供有关USB设备的特定配置及其支持的接口的信息。
  • USBInterfaceUSBAlternateInterface:提供USB设备所提供的接口信息。
  • USBEndPoint:提供有关USB设备所提供的端点的信息。

设备获取 --需要用户授权

连接设备
let fetchDevices = async () => {
    let devices = await navigator.usb.requestDevice({
        filters: [
            //可以添加`在这里插入代码片`显示条件
        ]
    })
    console.log(devices);
};
let btn = document.getElementById('btn');
btn.onclick = fetchDevices;
查找已连接的设备
navigator.usb.getDevices().then((devices) => {
  devices.forEach((device) => {
    console.log(device.productName); 
    console.log(device.manufacturerName);
  });
});
返回的数据均是USBdevice实例
实例属性
  • USBDevice.configuration:只读,当前选择的配对USB设备的接口的USBConfiguration对象。
  • USBDevice.configurations:只读,设备特定接口的数组,用于控制配对的USB设备。
  • USBDevice.deviceClass:只读,用于加载与设备兼容的USB驱动程序的三个属性之一。
  • USBDevice.deviceProtocol:只读,用于加载与设备兼容的USB驱动程序的三个属性之一。
  • USBDevice.deviceSubclass:只读,用于加载与设备兼容的USB驱动程序的三个属性之一。
  • USBDevice.deviceVersionMajor:只读,设备在语义版本控制方案中的主要版本号。
  • USBDevice.deviceVersionMinor:只读,设备在语义版本控制方案中的次要版本号。
  • USBDevice.deviceVersionSubminor:只读,设备在语义版本控制方案中的修订版本号。
  • USBDevice.manufacturerName:只读,USB设备的制造商名称。
  • USBDevice.opened:只读,表示是否已与配对的USB设备开始会话。
  • USBDevice.productId:只读,制造商定义的识别USB设备的代码。
  • USBDevice.productName:只读,制造商定义的识别USB设备的名称。
  • USBDevice.serialNumber:只读,制造商定义的特定USB设备的序列号。
  • USBDevice.usbVersionMajor:只读,设备支持的USB协议版本的主要部分。
  • USBDevice.usbVersionMinor:只读,设备支持的USB协议版本的次要部分。
  • USBDevice.usbVersionSubminor:只读,设备支持的USB协议版本的修订部分。
  • USBDevice.vendorId:只读,usb.org官方分配的供应商ID。
实例方法,在次只介绍常用的几个
  • transferIn(endpointNumber)

    • 参数:endpointNumber(必需)- 要从中接收数据的端点的编号。

    • 返回值:Promise<USBInTransferResult> - 解析为包含传输结果的对象。

  • transferOut(endpointNumber, data)

    • 参数:endpointNumber(必需)- 要发送数据到的端点的编号;

    • data(必需)- 要发送的数据。

    • 返回值:Promise<USBOutTransferResult> - 解析为包含传输结果的对象。

  • selectConfiguration(configurationValue)

    • 参数:configurationValue(必需)- 要选择的配置的编号。

    • 返回值:Promise<void> - 当配置被成功选择时解决。

  • open()

    • 参数:无

    • 返回值:Promise<void> - 当设备会话成功开始时解决。

  • claimInterface(interfaceNumber)

    • 参数:interfaceNumber(必需)- 要声明独占访问的接口编号。

    • 返回值:Promise<void> - 当接口被成功声明为独占时解决。

  • controlTransferIn(setup)

    • 参数:setup(必需)- 控制传输的参数,包括请求类型、请求、值、索引和长度。

    • 返回值:Promise<USBInTransferResult> - 解析为包含控制传输结果的对象。

  • controlTransferOut(setup)

    • 参数:setup(必需)- 控制传输的参数,包括请求类型、请求、值、索引和长度。

    • 返回值:Promise<USBOutTransferResult> - 解析为包含控制传输结果的对象。

  • close()

    • 参数:无

    • 返回值:Promise<void> - 当所有打开的接口被释放并且设备会话结束时解决。

  • selectAlternateInterface(interfaceNumber, alternateSetting)

    • 参数:interfaceNumber(必需)- 接口编号;alternateSetting(必需)- 选择的替代接口设置。

    • 返回值:Promise<void> - 当指定的替代接口被成功选择时解决。

大致流程

/**
 * 请求用户选择USB设备
 * @returns {Promise<USBDevice>} 选中的USB设备对象
 */
let fetchDevices = async () => {
    try {
        // 根据条件过滤设备
        // filters: [
        //   { vendorId: 0x2341 }, // 供应商ID,用于匹配特定供应商的设备
        //   { productId: 0x1234 }, // 产品ID,用于匹配特定产品的设备
        //   { classCode: 0x02 }, // 设备类代码,用于匹配特定类别的设备
        //   { subclass: 0x01 }, // 子类代码,用于匹配特定子类的设备
        //   { protocolCode: 0x01 } // 协议代码,用于匹配特定协议的设备
        // ]
        let device = await navigator.usb.requestDevice({
            filters: [
                { vendorId: 0x2341 } // 示例vendorId,需要替换成实际值
            ]
        });
        console.log('选中的设备:', device);
        return device;
    } catch (error) {
        console.error('选择设备失败:', error);
    }
};

/**
 * 打开USB设备会话
 * @param {USBDevice} device - USB设备对象
 * @returns {Promise<void>}
 */
let openDevice = async (device) => {
    try {
        await device.open();
        console.log('设备会话已打开');
    } catch (error) {
        console.error('打开设备会话失败:', error);
    }
};

/**
 * 声明USB设备的接口
 * @param {USBDevice} device - USB设备对象
 * @param {number} interfaceNumber - 接口编号
 * @returns {Promise<void>}
 */
let claimInterface = async (device, interfaceNumber) => {
    try {
        await device.claimInterface(interfaceNumber);
        console.log('接口已声明');
    } catch (error) {
        console.error('声明接口失败:', error);
    }
};

/**
 * 向USB设备发送控制传输数据
 * @param {USBDevice} device - USB设备对象
 * @param {number} endpointNumber - 端点编号
 * @param {Uint8Array} data - 要发送的数据
 * @returns {Promise<void>}
 */
let sendControlTransferOut = async (device, endpointNumber, data) => {
    try {
        // controlTransferOut参数说明:
        // requestType: 'standard' | 'class' | 'vendor' - 控制传输的类型
        //   - 'standard': 标准请求,用于基本控制操作
        //   - 'class': 类请求,针对特定USB设备类
        //   - 'vendor': 供应商请求,供应商自定义的请求
        // recipient: 'device' | 'interface' | 'endpoint' | 'other' - 控制传输的接收者
        //   - 'device': 接收者为USB设备
        //   - 'interface': 接收者为USB设备的特定接口
        //   - 'endpoint': 接收者为USB设备的特定端点
        //   - 'other': 其他类型的接收者
        const result = await device.controlTransferOut({
            requestType: 'vendor', // 供应商定义的控制传输
            recipient: 'device', // 控制传输的接收者为设备
            request: 0x01, // 请求码,供应商定义
            value: 0x00, // 值,供应商定义
            index: 0x00, // 索引,供应商定义
            length: data.byteLength
        }, data);
        console.log('控制传输输出成功', result);
    } catch (error) {
        console.error('控制传输输出失败:', error);
    }
};

/**
 * 关闭USB设备会话
 * @param {USBDevice} device - USB设备对象
 * @returns {Promise<void>}
 */
let closeDevice = async (device) => {
    try {
        await device.close();
        console.log('设备会话已关闭');
    } catch (error) {
        console.error('关闭设备会话失败:', error);
    }
};

// 主函数:执行发送数据的整体流程
let sendDataToDevice = async () => {
    const device = await fetchDevices(); // 请求设备
    if (device) {
        await openDevice(device); // 打开设备会话
        await claimInterface(device, 0); // 声明接口,这里以接口编号0为例
        const dataToSend = new Uint8Array([0x01, 0x02, 0x03, 0x04]); // 要发送的数据
        await sendControlTransferOut(device, 0x01, dataToSend); // 发送数据
        await closeDevice(device); // 关闭设备会话
    }
};

// 执行主函数
sendDataToDevice();

interface写入数据的时候,记得要有out权限哦,in/out一样是不可以的。如果遇到了无法解决的问题,记得试一下webHid

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值