I'm using IOKit to connect to a custom USB HID device. I'm using XCode 14 and running Swift/SwiftUI. So far I have had great success reading from the device with IOHIDDeviceGetReport and this can be done repeatedly with no issues. However, when I use IOHIDDeviceSetReport, I can only successfully set the report to the device one time correctly but any subsequent call to this function would just end up with an I/O Timeout. Any calls using IOHIDDeviceGetReport still works fine so the USB Device is still functioning correctly, but I couldn't receive any additional IOHIDDeviceSetReport call. If I unplug the USB and plug it in again, I can once again successfully send a command. This is, of course, not very practical for the end user to have to unplug and plug the device in after a single set command, and I don't quite understand what's going on with this.
Here's my SetOutputReport function to call the IOHIDDeviceSetReport. The IOHIDDevice must already be connected and opened before calling this function so it's not nil.
I don't have this "one shot send command" problem on the PC (Windows 7, 10, 11) or Android (v.11,12,13,14) implementation of this Custom USB HID device. It seems like there's something at the lower level of IOHIDDeviceSetReport on macOS which might be done differently than what's available on the PC or Android.
Many searches on the web yielded no useful results. There's an IOHIDDeviceSetReportWithCallback function and it also seems only to work one time as well.
private func SetOutputReport(dev: IOHIDDevice? ,reportID: Int, data:[UInt8], reportLength: Int) -> String{
let inputReportID = reportID
var buffer = data
buffer[0] = UInt8(inputReportID)
let bufferPointer = UnsafeMutablePointer<UInt8>.allocate(capacity: buffer.count)
bufferPointer.initialize(from: &buffer, count: buffer.count)
//print(bufferPointer[0])
let bufferLength: CFIndex = buffer.count
var success: IOReturn = kIOReturnError
if(dev != nil){
success = IOHIDDeviceSetReport(dev!, kIOHIDReportTypeOutput, CFIndex(buffer[0]), bufferPointer, bufferLength)
}
print("Set report result \(krToString(success))")
return krToString(success)
}