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

我开始查看了许多obj-c来源,并在Apple文档中发现了一个很好的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#,而且我也不是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/

10-12 14:46
查看更多