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
相关产品推荐
相关产品推荐

