USB device send/receive data

后端 未结 2 1759
半阙折子戏
半阙折子戏 2021-02-02 03:04

I have implemented function to detect USB device. It works and now i need to send/read data.

I started look over a lot of obj-c sources and found only one

2条回答
  •  清酒与你
    2021-02-02 03:55

    After a lot of questions on stackoverflow and learning sources i figure it out:

    First define not implemented functions

    import Foundation
    
    import IOKit
    import IOKit.usb
    import IOKit.usb.IOUSBLib
    
    //from IOUSBLib.h
    let kIOUSBDeviceUserClientTypeID = CFUUIDGetConstantUUIDWithBytes(nil,
                                                                      0x9d, 0xc7, 0xb7, 0x80, 0x9e, 0xc0, 0x11, 0xD4,
                                                                      0xa5, 0x4f, 0x00, 0x0a, 0x27, 0x05, 0x28, 0x61)
    let kIOUSBDeviceInterfaceID = CFUUIDGetConstantUUIDWithBytes(nil,
                                                                 0x5c, 0x81, 0x87, 0xd0, 0x9e, 0xf3, 0x11, 0xD4,
                                                                 0x8b, 0x45, 0x00, 0x0a, 0x27, 0x05, 0x28, 0x61)
    
    //from IOCFPlugin.h
    let kIOCFPlugInInterfaceID = CFUUIDGetConstantUUIDWithBytes(nil,
                                                                0xC2, 0x44, 0xE8, 0x58, 0x10, 0x9C, 0x11, 0xD4,
                                                                0x91, 0xD4, 0x00, 0x50, 0xE4, 0xC6, 0x42, 0x6F)
    
    
    /*!
     @defined USBmakebmRequestType
     @discussion Macro to encode the bRequest field of a Device Request.  It is used when constructing an IOUSBDevRequest.
     */
    
    func USBmakebmRequestType(direction:Int, type:Int, recipient:Int) -> UInt8 {
        return UInt8((direction & kUSBRqDirnMask) << kUSBRqDirnShift)|UInt8((type & kUSBRqTypeMask) << kUSBRqTypeShift)|UInt8(recipient & kUSBRqRecipientMask)
    }
    

    Then create our class:

    extension Notification.Name {
        static let dfuDeviceConnected = Notification.Name("DFUDeviceConnected")
        static let dfuDeviceDisconnected = Notification.Name("DFUDeviceDisconnected")
    }
    
    class DFUDevice: NSObject {
    let vendorId = 0x0483
    let productId = 0xdf11
    
    static let sharedInstance = DFUDevice()
    
    var deviceInterfacePtrPtr: UnsafeMutablePointer?>?
    var plugInInterfacePtrPtr: UnsafeMutablePointer?>?
    var interfacePtrPtr:UnsafeMutablePointer?>?
    
    private func rawDeviceAdded(iterator: io_iterator_t) {
        var score:Int32 = 0
        var kr:Int32 = 0
    
        while case let usbDevice = IOIteratorNext(iterator), usbDevice != 0 {
            // io_name_t imports to swift as a tuple (Int8, ..., Int8) 128 ints
            // although in device_types.h it's defined:
            // typedef  char io_name_t[128];
            var deviceNameCString: [CChar] = [CChar](repeating: 0, count: 128)
            let deviceNameResult = IORegistryEntryGetName(usbDevice, &deviceNameCString)
    
            if(deviceNameResult != kIOReturnSuccess) {
                print("Error getting device name")
            }
    
            let deviceName = String.init(cString: &deviceNameCString)
            print("usb Device Name: \(deviceName)")
    
            // Get plugInInterface for current USB device
            let plugInInterfaceResult = IOCreatePlugInInterfaceForService(
                usbDevice,
                kIOUSBDeviceUserClientTypeID,
                kIOCFPlugInInterfaceID,
                &plugInInterfacePtrPtr,
                &score)
    
            // USB device object is no longer needed.
            IOObjectRelease(usbDevice)
    
            // Dereference pointer for the plug-in interface
            guard plugInInterfaceResult == kIOReturnSuccess,
                let plugInInterface = plugInInterfacePtrPtr?.pointee?.pointee else {
                    print("Unable to get Plug-In Interface")
                    continue
            }
    
            // use plug in interface to get a device interface
            let deviceInterfaceResult = withUnsafeMutablePointer(to: &deviceInterfacePtrPtr) {
                $0.withMemoryRebound(to: Optional.self, capacity: 1) {
                    plugInInterface.QueryInterface(
                        plugInInterfacePtrPtr,
                        CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID),
                        $0)
                }
            }
    
            // dereference pointer for the device interface
            guard deviceInterfaceResult == kIOReturnSuccess,
                let deviceInterface = deviceInterfacePtrPtr?.pointee?.pointee else {
                    print("Unable to get Device Interface")
                    continue
            }
    
            kr = deviceInterface.USBDeviceOpen(deviceInterfacePtrPtr)
    
            if (kr != kIOReturnSuccess)
            {
                print("Could not open device (error: \(kr))")
                continue
            }
            else if (kr == kIOReturnExclusiveAccess)
            {
                // this is not a problem as we can still do some things
                continue
            }
    
            self.connected()
        }
    }
    
    private func rawDeviceRemoved(iterator: io_iterator_t) {
        var kr:Int32 = 0
    
        while case let usbDevice = IOIteratorNext(iterator), usbDevice != 0 {
            // USB device object is no longer needed.
            kr = IOObjectRelease(usbDevice)
    
            if (kr != kIOReturnSuccess)
            {
                print("Couldn’t release raw device object (error: \(kr))")
                continue
            }
    
            self.disconnected()
    
        }
    }
    
    func getStatus() throws -> [UInt8] {
        guard let deviceInterface = self.deviceInterfacePtrPtr?.pointee?.pointee else {
            throw DFUDeviceError.DeviceInterfaceNotFound
        }
    
        var kr:Int32 = 0
        let length:Int = 6
        var requestPtr:[UInt8] = [UInt8](repeating: 0, count: length)
        var request = IOUSBDevRequest(bmRequestType: USBmakebmRequestType(direction: kUSBIn, type: kUSBDevice, recipient: kUSBStandard),
                                      bRequest: DFUREQUEST.GETSTATUS.rawValue,
                                      wValue: 0,
                                      wIndex: 0,
                                      wLength: UInt16(length),
                                      pData: &requestPtr,
                                      wLenDone: 255)
    
        kr = deviceInterface.DeviceRequest(self.deviceInterfacePtrPtr, &request)
    
        if (kr != kIOReturnSuccess) {
            throw DFUDeviceError.RequestError(desc: "Get device status request error: \(kr)")
        }
    
        return requestPtr
    }
    
    
    
    private func configureDevice() -> Int32 {
        var kr:Int32 = 0
    
        guard let deviceInterface = deviceInterfacePtrPtr?.pointee?.pointee else {
            print("Unable to get Device Interface")
            return -1
        }
    
        var numConfig:UInt8 = 0
    
        kr = deviceInterface.GetNumberOfConfigurations(deviceInterfacePtrPtr, &numConfig)
        if numConfig == 0 {
            print("Device Number Of Configurations: 0")
            return -1
        }
    
        var configPtr:IOUSBConfigurationDescriptorPtr?
    
        // set first configuration as active
        kr = deviceInterface.GetConfigurationDescriptorPtr(deviceInterfacePtrPtr, 0, &configPtr)
        if (kr != kIOReturnSuccess)
        {
            print("Couldn’t get configuration descriptor for index (error: %x)\n", kr);
            return -1
        }
    
        guard let config = configPtr?.pointee else {
            return -1
        }
    
        //Set the device’s configuration. The configuration value is found in
        //the bConfigurationValue field of the configuration descriptor
    
        kr = deviceInterface.SetConfiguration(deviceInterfacePtrPtr, config.bConfigurationValue)
        if (kr != kIOReturnSuccess)
        {
            print("Couldn’t set configuration to value (error: %x)\n", kr);
            return -1
        }
    
        return kIOReturnSuccess
    }
    
    
    func connected() {
        NotificationCenter.default.post(name: .dfuDeviceConnected, object: nil)
        globalLogPost("DFU device has been device connected")
    }
    
    func disconnected() {
        NotificationCenter.default.post(name: .dfuDeviceDisconnected, object: nil)
        globalLogPost("DFU device has been disconnected")
    }
    
    func initUsb() {
        var matchedIterator:io_iterator_t = 0
        var removalIterator:io_iterator_t = 0
        let notifyPort:IONotificationPortRef = IONotificationPortCreate(kIOMasterPortDefault)
        IONotificationPortSetDispatchQueue(notifyPort, DispatchQueue(label: "IODetector"))
    
        let matchingDict = IOServiceMatching(kIOUSBDeviceClassName)
            as NSMutableDictionary
        matchingDict[kUSBVendorID] = NSNumber(value: self.vendorId)
        matchingDict[kUSBProductID] = NSNumber(value: self.productId)
    
        let matchingCallback:IOServiceMatchingCallback = { (userData, iterator) in
            let this = Unmanaged
                .fromOpaque(userData!).takeUnretainedValue()
            this.rawDeviceAdded(iterator: iterator)
        }
    
        let removalCallback: IOServiceMatchingCallback = {
            (userData, iterator) in
            let this = Unmanaged
                .fromOpaque(userData!).takeUnretainedValue()
            this.rawDeviceRemoved(iterator: iterator)
        }
    
        let selfPtr = Unmanaged.passUnretained(self).toOpaque()
    
        IOServiceAddMatchingNotification(notifyPort, kIOFirstMatchNotification, matchingDict, matchingCallback, selfPtr, &matchedIterator)
        IOServiceAddMatchingNotification(notifyPort, kIOTerminatedNotification, matchingDict, removalCallback, selfPtr, &removalIterator)
    
        self.rawDeviceAdded(iterator: matchedIterator)
        self.rawDeviceRemoved(iterator: removalIterator)
    
        RunLoop.current.run()
    }
    }
    

    You can look on method getStatus where i create a USBRequest and send it to device. Then in requestPtr:[UInt8] i received answer from device. Thank you for helping guys.

    We can use ore device pointer anywhere in project, for example:

    func upload(value:UInt16, length:UInt16) throws -> [UInt8] {
            guard let deviceInterface = DFUDevice.sharedInstance.deviceInterfacePtrPtr?.pointee?.pointee else {
                throw DFUDeviceError.DeviceInterfaceNotFound
            }
            var kr:Int32 = 0
            var requestPtr:[UInt8] = [UInt8](repeating: 0, count: Int(length))
    
            var request = IOUSBDevRequest(bmRequestType: 161,
                                          bRequest: DFUREQUEST.UPLOAD.rawValue,
                                          wValue: value,
                                          wIndex: 0,
                                          wLength: length,
                                          pData: &requestPtr,
                                          wLenDone: 255)
    
            kr = deviceInterface.DeviceRequest(DFUDevice.sharedInstance.deviceInterfacePtrPtr, &request)
    
            if (kr != kIOReturnSuccess) {
                throw DFUDeviceError.RequestError(desc: "Upload request error: \(kr), request data: \(request)")
            }
    
            return requestPtr
        }
    

提交回复
热议问题