HID device communication - Arti3DPlayer/USBDeviceSwift GitHub Wiki

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

Send command to USB device example:

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

⚠️ **GitHub.com Fallback** ⚠️