我正在将旧的 C 程序移植到 macOS 上的 Swift。我的问题是向 USB HID 设备发送固定的 7 字节报告。在 C 中,这工作正常,但我无法使其在 Swift 中工作。我注意到,在 C 中,数据包的大小是正确的,7,在 swift 中总是多 1 个字节。
这里是原始的C代码:
int size;
char report[7] = {0x81, 0x61, 0xf5, 0x33, 0x04, 0x00, 0x28};
size = sizeof(report); // this returns 7
result = (*myhidInterface)->setReport(myhidInterface, kIOHIDReportTypeOutput, 0, report, sizeof(report), 1000, NULL, NULL, NULL); // IOReturn returns 0
这有效并更改字节的值,使设备反应良好。
在 Swift 中我尝试了不同的解决方案,但我无法使其工作,大小始终是 8 个字节。
其中之一是:
var report = [UInt8](repeating: 0, count: 7)
report = [0x81, 0x61, 0xf5, 0x33, 0x04, 0x00, 0x28] // the bytes are there if a print the report
let mySize = MemoryLayout.size(ofValue: report) // this return always 8 and not 7
result = myHIDDevInt!.setReport(hidDevInterface, kIOHIDReportTypeOutput, zero, &report, mySize, athousand, nil, nil, nil) // even in this case the return is 0, so no error
but it is not working.
我也尝试过获取一个指针并将其传递给设备调用的 setReport 函数,但没有成功:
MemoryLayout<UInt8>.alignment)
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)
....
mySize = UInt32(MemoryLayout.size(ofValue: ptr)) // even this reports 8 and not 7.
result = myHIDDevInt!.setReport(hidDevInterface, kIOHIDReportTypeOutput, zero, &report, mySize, athousand, nil, nil, nil)
即使在这种情况下,对设备的调用也不会报告错误。
我也尝试在设备调用中写入 7,但没有成功。
我想像 C 中那样发送 7 的大小。我认为它会很快改变报告的内容,更好的字节顺序。
我也注意到,与 swift 相比,下面这样的二元运算在 C 中给出了不同的结果:
int arg; // size id 4 bytes
unsigned char theByte2; // size is 1 byte
arg = 1813;
theByte2 = (arg >> 8) & 0xff; // this return 0x61
在 Swift 中
var UInt8: theByte2 = 0 // size 1 byte
var arg: Int = 0 // size 4 bytes
arg = 1813
theByte2 = UInt8(((arg >> 8) & 0xff)) // this report 0x07
我在这里做错了什么?有没有办法在 swift 中发送 7 个字节而不是 8 个字节?
您错误地计算了缓冲区的大小。
MemoryLayout.size(ofValue: report)
正在计算Array结构体实例的大小,它只是包装了一个指针,而不是指向的缓冲区。无论指向的缓冲区大小如何,在 64 位机器上它始终是 64 位。MemoryLayout.size(ofValue: ptr)
正在计算指针本身的大小。同样,它也将始终是 64 位。您可以使用类似
report * MemoryLayout<UInt8>.stride
的内容,但没有必要,因为 Array
上有更好的 API 可以为您计算此值。查看数组文档的“访问底层存储”部分。
IOHIDDevice.setReport
如何导入 Swift 的具体细节,但使用它应该看起来像这样:
let report: [UInt8] = [0x81, 0x61, 0xf5, 0x33, 0x04, 0x00, 0x28]
report.withUnsafeBytes { buffer in
myHIDDevInt!.setReport(
hidDevInterface,
kIOHIDReportTypeOutput,
zero,
buffer.baseAddress,
buffer.count,
athousand, nil, nil, nil
)
}