macOS下Swift向USB HID设备发送7字节报告异常求助
macOS下Swift移植USB HID报告发送问题解决
问题概述
将旧C程序移植到Swift时,向USB HID设备发送7字节固定报告的功能始终失效。C代码可正常工作,但Swift中出现两个核心问题:
- 错误计算报告长度,始终得到8字节而非7字节
- 位运算结果与C不一致
正常工作的C代码
int size; char report[7] = {0x81, 0x61, 0xf5, 0x33, 0x04, 0x00, 0x28}; size = sizeof(report); // 返回7 result = (*myhidInterface)->setReport(myhidInterface, kIOHIDReportTypeOutput, 0, report, sizeof(report), 1000, NULL, NULL, NULL); // IOReturn返回0
Swift尝试的方案及问题
方案一:使用数组存储报告
var report = [UInt8](repeating: 0, count: 7) report = [0x81, 0x61, 0xf5, 0x33, 0x04, 0x00, 0x28] // 字节内容正确 let mySize = MemoryLayout.size(ofValue: report) // 返回8(错误:这是Swift数组对象的内存大小,不是元素总字节数) result = myHIDDevInt!.setReport(hidDevInterface, kIOHIDReportTypeOutput, 0, &report, mySize, 1000, nil, nil, nil) // 无报错但功能失效
方案二:使用指针操作
// 指针初始化代码(片段) let ptr = UnsafeMutablePointer<UInt8>.allocate(capacity: 7) ptr.initializeMemory(as: UInt8.self, repeating: 0, count: 7) // 填充字节代码(片段) ptr.storeBytes(of: 0x81, as: UInt8.self) var offsetPointer = ptr + 1 offsetPointer.storeBytes(of: 0x61, as: UInt8.self) offsetPointer = ptr + 2 offsetPointer.storeBytes(of: 0xf5, as: UInt8.self) // ... 其余字节填充 let mySize = UInt32(MemoryLayout.size(ofValue: ptr)) // 返回8(错误:这是指针本身的内存大小,不是指向的缓冲区大小) result = myHIDDevInt!.setReport(hidDevInterface, kIOHIDReportTypeOutput, 0, ptr, mySize, 1000, nil, nil, nil) // 无报错但功能失效
位运算差异问题
C代码(结果符合预期)
int arg; // 32位整数 unsigned char theByte2; // 1字节 arg = 1813; // 注:此处arg值存在笔误,实际应传入24853(0x6115)才能得到0x61 theByte2 = (arg >> 8) & 0xff; // 返回0x61
Swift代码(结果错误)
var theByte2: UInt8 = 0 var arg: Int = 0 // macOS默认64位整数 arg = 1813 theByte2 = UInt8(((arg >> 8) & 0xff)) // 返回0x07
解决方案
1. 修正报告长度计算
无论使用数组还是指针,都需要直接指定实际的报告字节数(7),而非计算对象/指针的内存大小:
- 数组方式:用
report.count直接获取元素个数(每个UInt8占1字节),转换为UInt32传入setReport - 指针方式:直接传入
UInt32(7)作为长度
修正后的数组方案代码:
var report: [UInt8] = [0x81, 0x61, 0xf5, 0x33, 0x04, 0x00, 0x28] let mySize = UInt32(report.count) // 正确得到7 result = myHIDDevInt!.setReport(hidDevInterface, kIOHIDReportTypeOutput, 0, &report, mySize, 1000, nil, nil, nil)
2. 统一位运算的整数类型
将Swift中的arg类型改为Int32,匹配C中int的32位宽度,确保移位运算逻辑一致:
var theByte2: UInt8 = 0 var arg: Int32 = 24853 // 对应0x6115,与C逻辑匹配 theByte2 = UInt8(((arg >> 8) & 0xff)) // 返回0x61
内容的提问来源于stack exchange,提问作者Karterilla
相关产品推荐
相关产品推荐

