You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MacOS Swift中如何构造带1字参数的USB设备请求?

如何构造带1字参数的USB控制请求

我来帮你搞定这个USB请求的问题!要发送包含1字节请求码+1字(2字节)参数的请求,我们得先搞清楚IOUSBDevRequest的各个字段作用,再根据你的通信协议要求来调整代码。

先搞懂核心结构体的关键字段

IOUSBDevRequest是USB控制请求的核心结构体,几个关键字段你得重点关注:

  • bmRequestType: 决定请求的方向(主机→设备/设备→主机)、类型(标准/类/自定义)和接收者(设备/接口/端点)。你的代码里用了161(0xA1),这是设备到主机的请求方向,如果是你要给设备发数据,得改成0x21(主机到设备),这个一定要和协议匹配!
  • bRequest: 1字节的请求码,就是你定义的EsconRequest.ENABLE.rawValue(0x05)
  • wValue: 2字节的参数位,要是协议允许,直接把你的1字参数放这就行,不用额外缓冲区
  • wLength: 数据阶段要传输的字节数,要是用pData传数据,这个值必须和缓冲区长度一致
  • pData: 指向数据缓冲区的指针,用于数据阶段的收发

方案1:直接把参数放进wValue(最简单)

如果你的通信协议允许将1字参数放在Setup包的wValue字段里,这是最省事的方式,不需要额外的数据缓冲区:

func systemEnable(with parameter: UInt16) throws {
    guard let deviceInterface = self.deviceInfo.deviceInterfacePtrPtr?.pointee?.pointee else {
        throw EsconDeviceError.DeviceInterfaceNotFound
    }
    var kr: Int32 = 0
    
    // 构造请求:把1字参数直接赋值给wValue
    var request = IOUSBDevRequest(
        bmRequestType: 0x21, // 主机→设备的请求,根据你的协议调整
        bRequest: EsconRequest.ENABLE.rawValue,
        wValue: parameter,
        wIndex: 0, // 如果不需要指定接口/端点就设0
        wLength: 0, // 没有数据阶段,所以设0
        pData: nil,
        wLenDone: 0
    )
    
    kr = deviceInterface.DeviceRequest(self.deviceInfo.deviceInterfacePtrPtr, &request)
    if kr != kIOReturnSuccess {
        throw EsconDeviceError.RequestError(desc: "Enable Device request Error: \(kr)")
    }
}

方案2:数据阶段发送3字节(1字节请求码+2字节参数)

如果协议要求必须在数据阶段发送这3字节数据,那我们就得构造一个3字节的缓冲区,同时正确设置wLength:

func systemEnable(with parameter: UInt16) throws {
    guard let deviceInterface = self.deviceInfo.deviceInterfacePtrPtr?.pointee?.pointee else {
        throw EsconDeviceError.DeviceInterfaceNotFound
    }
    var kr: Int32 = 0
    
    // 构造3字节数据:第1字节是请求码,后2字节是参数(注意字节序,USB默认小端)
    var requestData = [UInt8](repeating: 0, count: 3)
    requestData[0] = EsconRequest.ENABLE.rawValue
    // 拆分UInt16为小端字节(LSB在前),如果协议要求大端就交换下面两行
    requestData[1] = UInt8(parameter & 0xFF)
    requestData[2] = UInt8((parameter >> 8) & 0xFF)
    
    var request = IOUSBDevRequest(
        bmRequestType: 0x21, // 主机→设备的请求
        bRequest: 0x00, // 要是数据阶段已经带请求码,这里按协议要求设值,可能是0
        wValue: 0,
        wIndex: 0,
        wLength: 3, // 数据阶段发送3字节
        pData: &requestData,
        wLenDone: 0
    )
    
    kr = deviceInterface.DeviceRequest(self.deviceInfo.deviceInterfacePtrPtr, &request)
    if kr != kIOReturnSuccess {
        throw EsconDeviceError.RequestError(desc: "Enable Device request Error: \(kr)")
    }
}

几个必注意的点

  • 方向别搞反:bmRequestType的方向位是关键,0xA1是设备给主机发数据,0x21是主机给设备发,一定要和你的通信文档匹配!
  • 字节序要正确:USB默认用小端序,要是你的协议要求大端,记得把参数的高低字节交换位置。
  • 字段要匹配:用pData的时候,wLength必须等于缓冲区的字节数,不然会触发传输错误。

内容的提问来源于stack exchange,提问作者Nandha Handharu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 03:57:53