-
Notifications
You must be signed in to change notification settings - Fork 59
HID device communication
Create HIDDeviceMonitor
object globally, set vid
and pid
of devices and reportSize for communication and run monitor in new thread for listen HID devices
import Cocoa
import USBDeviceSwift
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
//make sure that rfDeviceMonitor always exist
let rfDeviceMonitor = HIDDeviceMonitor([
HIDMonitorData(vendorId: 0x0483, productId: 0x5742)
], reportSize: 64)
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application
let rfDeviceDaemon = Thread(target: self.rfDeviceMonitor, selector:#selector(self.rfDeviceMonitor.start), object: nil)
rfDeviceDaemon.start()
}
}
note - start
function using RunLoop
that blocks thread don't run monitor in Main
thread
There are three global notifications:
HIDDeviceDataReceived
HIDDeviceConnected
HIDDeviceDisconnected
Listen them in our ViewController:
class ViewController: NSViewController {
deinit {
NotificationCenter.default.removeObserver(self)
}
var connectedDevice:RFDevice?
var devices:[RFDevice] = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
NotificationCenter.default.addObserver(self, selector: #selector(self.usbConnected), name: .HIDDeviceConnected, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.usbDisconnected), name: .HIDDeviceDisconnected, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.hidReadData), name: .HIDDeviceDataReceived, object: nil)
}
func usbConnected(notification: NSNotification) {
guard let nobj = notification.object as? NSDictionary else {
return
}
guard let deviceInfo:HIDDevice = nobj["device"] as? HIDDevice else {
return
}
}
func usbDisconnected(notification: NSNotification) {
guard let nobj = notification.object as? NSDictionary else {
return
}
guard let id:String = nobj["id"] as? String else {
return
}
}
func hidReadData(notification: Notification) {
let obj = notification.object as! NSDictionary
let data = obj["data"] as! Data
}
}
HIDDevice
has all basic info:
id
- kIOHIDLocationIDKey - property converted to `String
vendorId
- kIOHIDVendorIDKey - property converted to Int
productId
- kIOHIDProductIDKey - property converted to Int
reportSize
- device specific
device
- reference to IOHIDDevice
name
- kIOHIDProductKey - property converted to String
To get additional properites from device use IOHIDDeviceGetProperty. Example:
IOHIDDeviceGetProperty(HIDDevice.device, kIOHIDMaxInputReportSizeKey as CFString) as? Int
func write(_ data: Data) {
var bytesArray = [UInt8](data)
let reportId:UInt8 = 2
bytesArray.insert(reportId, at: 0)
bytesArray.append(0)// hack every report should end with 0 byte
if (bytesArray.count > self.deviceInfo.reportSize) {
print("Output data too large for USB report")
return
}
let correctData = Data(bytes: UnsafePointer<UInt8>(bytesArray), count: self.deviceInfo.reportSize)
IOHIDDeviceSetReport(
self.deviceInfo.device,
kIOHIDReportTypeOutput,
CFIndex(reportId),
(correctData as NSData).bytes.bindMemory(to: UInt8.self, capacity: correctData.count),
correctData.count
)
}
See full example in RaceflightControllerHIDExample
folder