objective-c - USB 设备发送/接收数据

标签 objective-c swift macos cocoa

我已经实现了检测 USB 设备的功能。它有效,现在我需要发送/读取数据。

我开始查看大量 obj-c 源,但只找到一个好的 article在苹果文档中,描述了我们如何将包发送到我们的 USB 设备:

IOReturn WriteToDevice(IOUSBDeviceInterface **dev, UInt16 deviceAddress,
                        UInt16 length, UInt8 writeBuffer[])
{

    IOUSBDevRequest     request;
    request.bmRequestType = USBmakebmRequestType(kUSBOut, kUSBVendor,
                                                kUSBDevice);
    request.bRequest = 0xa0;
    request.wValue = deviceAddress;
    request.wIndex = 0;
    request.wLength = length;
    request.pData = writeBuffer;

    return (*dev)->DeviceRequest(dev, &request);
}

但我没有找到如何使用 Swift 创建和发送数据的方法。 Swift 上的结构如下所示:

public struct IOUSBDevRequest {
    public var bmRequestType: UInt8
    public var bRequest: UInt8
    public var wValue: UInt16
    public var wIndex: UInt16
    public var wLength: UInt16
    public var pData: UnsafeMutableRawPointer!
    public var wLenDone: UInt32
    public init()

    public init(bmRequestType: UInt8, bRequest: UInt8, wValue: UInt16, wIndex: UInt16, wLength: UInt16, pData: UnsafeMutableRawPointer!, wLenDone: UInt32)
}

我搞不懂pDatazwLenDone是什么参数。

这是我需要发送的数据:

{         
'direction':'in',         
'recipient':'device',
'requestType':  'standard',
'request':      6,         
'value':        0x300,         
'index':        0,         
'length':       255
}

下一个问题是:我如何接收数据。我知道答案在这篇文章中,但我无法将其转换为 Swift。

这是我可以在 Swift 3 上转换的内容。我的类检测到 USB 设备,获取他的配置:

class DFUDevice: NSObject {
let vendorId = 0x0483
let productId = 0xdf11

static let sharedInstance = DFUDevice()

var deviceName:String = ""

private func deviceAdded(iterator: io_iterator_t) {
    var plugInInterfacePtrPtr: UnsafeMutablePointer<UnsafeMutablePointer<IOCFPlugInInterface>?>?
    var deviceInterfacePtrPtr: UnsafeMutablePointer<UnsafeMutablePointer<IOUSBDeviceInterface>?>?
    var configPtr:IOUSBConfigurationDescriptorPtr?

    var score: 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")
        }

        self.deviceName = String.init(cString: &deviceNameCString)
        print("usb Device Name: \(deviceName)")

        // Get plugInInterface for current USB device

        let plugInInterfaceResult = IOCreatePlugInInterfaceForService(
            usbDevice,
            kIOUSBDeviceUserClientTypeID,
            kIOCFPlugInInterfaceID,
            &plugInInterfacePtrPtr,
            &score)

        // 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<LPVOID>.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
        }

        var ret = deviceInterface.USBDeviceOpen(deviceInterfacePtrPtr)
        if (ret == kIOReturnSuccess)
        {
            // set first configuration as active
            ret = deviceInterface.GetConfigurationDescriptorPtr(deviceInterfacePtrPtr, 0, &configPtr)
            if (ret != kIOReturnSuccess)
            {
                print("Could not set active configuration (error: %x)\n", ret);
                continue
            }
            guard let config = configPtr?.pointee else {
                continue
            }

            if config.bLength > 0 {
                //HERE I NEED SEND DATA

            } else {
                print("ConfigurationDescriptor not valid")
            }
            print(config.bLength)
        }
        else if (ret == kIOReturnExclusiveAccess)
        {
            // this is not a problem as we can still do some things
        }
        else
        {
            print("Could not open device (error: %x)\n", ret)
            continue
        }

        IOObjectRelease(usbDevice)
    }
}


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<DFUDevice>
            .fromOpaque(userData!).takeUnretainedValue()
        this.deviceAdded(iterator: iterator)
        this.connected(iterator: iterator)
    }

    let removalCallback: IOServiceMatchingCallback = {
        (userData, iterator) in
        let this = Unmanaged<DFUDevice>
            .fromOpaque(userData!).takeUnretainedValue()
        this.disconnected(iterator: iterator)
    }

    let selfPtr = Unmanaged.passUnretained(self).toOpaque()

    IOServiceAddMatchingNotification(notifyPort, kIOFirstMatchNotification, matchingDict, matchingCallback, selfPtr, &matchedIterator)
    IOServiceAddMatchingNotification(notifyPort, kIOTerminatedNotification, matchingDict, removalCallback, selfPtr, &removalIterator)

    self.deviceAdded(iterator: matchedIterator)
    self.deviceAdded(iterator: removalIterator)

    RunLoop.current.run()
    }
}

我这样调用它:

let DFUDeviceDaemon = Thread(target: DFUDevice.sharedInstance, selector:#selector(DFUDevice.initUsb), object: nil)
DFUDeviceDaemon.start()

最佳答案

您引用的文章有一个名为 WriteToDevice 的函数。它的一个参数是

UInt8 writeBuffer[]

这个 writeBuffer,你要发送的数据,是一个 C 字节数组:

uint8_t msgLength = 3;
uint8_t writeBuffer[msgLength];
writeBuffer[0] = 0x41; // ASCII 'A'
writeBuffer[1] = 0x42; // ASCII 'B'
writeBuffer[2] = 0x43; // ASCII 'C'

您需要发送什么字节?这实际上取决于另一端的设备——制造商的技术数据应该告诉您这一点。 要将 C 数组作为 NSData 传递,这可能就是 pData,您可以使用:

NSData *data = [NSData dataWithBytes:&writeBuffer length:3];

(z)wLenDone 可能就是我所说的 msgLength,3。C 数组不知道它们自己的长度,所以大多数函数需要将长度作为一个单独的参数。

至于接收数据,我猜这发生在 matchingCallback 中:您使用迭代器接收字节然后解析它们。

对评论的回答:

我不熟悉 C#,也不是这方面的专家,但也许这会有所帮助:

var package = new UsbSetupPacket( 
(byte)(UsbCtrlFlags.Direction_In |
       UsbCtrlFlags.Recipient_Device | 
       UsbCtrlFlags.RequestType_Standard),  // Index
6,                      // length of data, second phase
0x200,                  // Request
0,                      // RequestType
(short)length);         // Value

一些观察:对 C# 一无所知,但包不应该被类型化为 struct 吗? RequestType 为 0,因此您不会收到任何响应——这是您想要的吗?还是您想将 UsbCtrlFlags.RequestType_Standard 作为第四个参数发送?为什么将长度作为值发送?

无论如何,您现在要做的是将包发送到 USB 设备,看看会发生什么。

关于objective-c - USB 设备发送/接收数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41038150/

相关文章:

iphone - 获取两个位置之间的路线方向

ios - 使用字符进行字符串格式化会崩溃

ios - 飞行模式下的 NSHTTPURLResponse 状态码 200

macos - 如何将 CGEventKeyboardSetUnicodeString 与多个字符一起使用?

macos - Gradle在Mac中为JAVA_HOME获取错误的值

ios - 如何在NSMutableDictionary中比较NSArray的元素?

iphone - UIScrollView - 如何消除滚动之前的延迟?

ios - 从firebase存储中快速上传人物图像

objective-c - 嵌入 NSSplitView 的 NSScrollView 中的 NSView 的自动布局

ios - 此类对于使用 RestKit v0.20.0 的键文本不符合键值编码