Korzystanie z Androida do komunikacji z urządzeniem USB HID

Jestem nowym użytkownikiem USB i Androida, więc proszę mi wybaczyć, jeśli nie wyjaśnię się jasno.

Mam urządzenie USB HID, z którym mogę się komunikować w systemie Windows. Próbuję nawiązać komunikację przy użyciu tabletu Acer Iconia A500 z systemem Android 3.1.

Jestem w stanie znaleźć urządzenie, wyliczyć je, uzyskać jego jedyny dostępny interfejs, uzyskać jedyny dostępny punkt końcowy (0) i określić, jaki to jest typ punktu końcowego (przerwanie transferu z urządzenia na host).

Moje rozumienie specyfikacji USB polega na tym, że wszystkie urządzenia HID są wymagane w minimalnym stopniu, aby mieć punkt końcowy sterowania (punkt końcowy 0) i punkt końcowy przerwania IN. Ale wydaje się, że punkt końcowy 0 jest tutaj punktem końcowym przerwania, a nie punktem końcowym sterowania.

Aby jednak urządzenie mogło wyliczyć, musi pomyślnie przesłać dane deskryptora przez punkt kontrolny. Dochodzę do wniosku, że punkt kontrolny musi więc zostać znaleziony (i użyty), ponieważ host faktycznie wylicza urządzenie.

Tak dalece, jak jestem w stanie kontynuować, jak wspomniano powyżej, jedynym interfejsem / punktem końcowym przedstawionym mi na poziomie aplikacji jest typ przerwania przechodzący z urządzenia do hosta. Brak punktu końcowego dostępnego dla mojej aplikacji przechodzącej z hosta do urządzenia, przerywanie lub sterowanie. Tak więc urządzenie czeka, aż zostanie mu powiedziane, co ma zrobić, a host czeka, aż coś się wydarzy w urządzeniu. Niezbyt stymulujący.

Pamiętaj, że to urządzenie prawidłowo reaguje na połączenie z systemem Windows, np. Jestem w stanie wysłać raport zawierający 13 bajtów danych, co powoduje, że urządzenie zapala diodę LED. Wygląda więc na to, że jest zgodny ze specyfikacją USB HID. W akcie desperacji próbowałem użyć tego jednego punktu końcowego jako zarówno punktu końcowego kontroli, jak i przerwanego punktu końcowego OUT, używając controltransfer () i UsbRequest () do przesłania danych do urządzenia, bez odpowiedzi w żadnym przypadku.

Moje pytanie brzmi: „Punktem końcowym transferu sterowania jest (?) Używany do skonfigurowania urządzenia, dlaczego nie mogę go znaleźć i użyć?”

Dzięki za wgląd, poniżej znajduje się odpowiedni kod, w razie potrzeby mogę uwzględnić resztę:

private UsbManager mUsbManager;
private UsbDevice mDevice;
private UsbDeviceConnection mConnectionRead;
private UsbDeviceConnection mConnectionWrite;
private UsbEndpoint mEndpointRead;
private UsbEndpoint mEndpointWrite;

    // check for existing devices
    for (UsbDevice device :  mUsbManager.getDeviceList().values())
    {
        //Need to filter for my device when other HIDs are also connected, but for now...           
        String devName = device.getDeviceName();
        if (DEBUG == 1){
        Toast.makeText(UsbHidDeviceTesterActivity.this, "My device got connected: " + devName, Toast.LENGTH_LONG).show();
        }
        //mDevice = device;
        setHIDDevice(device);
    }

private boolean setHIDDevice(UsbDevice device)
{    
    UsbInterface usbInterfaceRead = null;
    UsbInterface usbInterfaceWrite = null;
    UsbEndpoint ep1 = null;
    UsbEndpoint ep2 = null;
    boolean UsingSingleInterface = true;

    mDevice = device;

    //This HID device is using a single interface
    if (UsingSingleInterface)
    {
        //usbInterfaceRead = device.getInterface(0x00);//only 1 EP on this interface
        usbInterfaceRead = findInterface(device);

        //Try getting an interface at next index
        //usbInterfaceWrite = device.getInterface(0x01);//throws exception

        // Try using the same interface for reading and writing
        usbInterfaceWrite = usbInterfaceRead;

        int endPointCount = usbInterfaceWrite.getEndpointCount();
        if (DEBUG == 2)
        {
            Toast.makeText(UsbHidDeviceTesterActivity.this, "Endpoints: " + endPointCount, Toast.LENGTH_LONG).show();
            //Toast.makeText(UsbHidDeviceTesterActivity.this, "Interface: " + usbInterfaceRead, Toast.LENGTH_LONG).show();
        }

        if (endPointCount == 1)//only getting 1 endpoint
        {
            ep1 = usbInterfaceRead.getEndpoint(0);
            //As an act of desperation try equating ep2 to this read EP, so that we can later attempt to write to it anyway
            ep2 = usbInterfaceRead.getEndpoint(0);
        }
        else if (endPointCount == 2)
        {
            ep1 = usbInterfaceRead.getEndpoint(0);
            ep2 = usbInterfaceRead.getEndpoint(1);
        }
    }

    else        // ! UsingSingleInterface
    {
        usbInterfaceRead = device.getInterface(0x00);
        usbInterfaceWrite = device.getInterface(0x01);
        if ((usbInterfaceRead.getEndpointCount() == 1) && (usbInterfaceWrite.getEndpointCount() == 1))
        {
            ep1 = usbInterfaceRead.getEndpoint(0);
            ep2 = usbInterfaceWrite.getEndpoint(0);
        }
        if (DEBUG == 3)
        {
            Toast.makeText(UsbHidDeviceTesterActivity.this, "Using Dual Interface", Toast.LENGTH_LONG).show();
        }
    }

    //because ep1 = ep2 this will now not cause a return unless no ep is found at all
    if ((ep1 == null) || (ep2 == null))
    {
        if (DEBUG == 4)
        {
            Toast.makeText(UsbHidDeviceTesterActivity.this, "One EP is null", Toast.LENGTH_LONG).show();
        }
        return false;
    }

    // Determine which endpoint is the read, and which is the write
    if (ep1.getType() == UsbConstants.USB_ENDPOINT_XFER_INT)//I am getting a return of 3, which is an interrupt transfer
    {
        if (ep1.getDirection() == UsbConstants.USB_DIR_IN)//I am getting a return of 128, which is a device-to-host endpoint
        {
            mEndpointRead = ep1;
            if (DEBUG == 5)
            {
                Toast.makeText(UsbHidDeviceTesterActivity.this, "EP1 type: " + ep1.getType(), Toast.LENGTH_LONG).show();
            }
        }
        if (ep1.getDirection() == UsbConstants.USB_DIR_OUT)//nope
        {
            mEndpointWrite = ep1;
            if (DEBUG == 6)
            {
                Toast.makeText(UsbHidDeviceTesterActivity.this, "EP1 is a write", Toast.LENGTH_LONG).show();
            }
        }
    }

    if (ep2.getType() == UsbConstants.USB_ENDPOINT_XFER_INT)
    {
        if (ep2.getDirection() == UsbConstants.USB_DIR_IN)
        {
            //Try treating it as a write anyway             
            //mEndpointRead = ep2;
            mEndpointWrite = ep2;
        }
        else if (ep2.getDirection() == UsbConstants.USB_DIR_OUT)
        {
            //usbEndpointWrite = ep2;
            mEndpointWrite = ep2;
        }
    }

    //check that we should be able to read and write
    if ((mEndpointRead == null) || (mEndpointWrite == null))
    {
        return false;
    }
    if (device != null)
    {
        UsbDeviceConnection connection = mUsbManager.openDevice(device);
        if (connection != null && connection.claimInterface(usbInterfaceRead, true))
        {
            Log.d(TAG, "open SUCCESS");
            mConnectionRead = connection;
            // Start the read thread
            //Comment out while desperately attempting to write on this connection/interface
            //Thread thread = new Thread(this);
            //thread.start();

        }
        else
        {
            Log.d(TAG, "open FAIL");
            mConnectionRead = null;
        }
     }
    if (UsingSingleInterface)
    {
        mConnectionWrite = mConnectionRead;
    }
    else //! UsingSingleInterface
    {
        mConnectionWrite = mUsbManager.openDevice(device);
        mConnectionWrite.claimInterface(usbInterfaceWrite, true);
    }
    return true;
}

// searches for an interface on the given USB device
 private UsbInterface findInterface(UsbDevice device) {
    Log.d(TAG, "findInterface " + device);
    int count = device.getInterfaceCount();
    if (DEBUG == 7)
    {
        Toast.makeText(UsbHidDeviceTesterActivity.this, "Interface count: " + count, Toast.LENGTH_LONG).show();
    }

    for (int i = 0; i < count; i++) {
        UsbInterface intf = device.getInterface(i);
        String InterfaceInfo = intf.toString();
        Log.d(TAG, "Interface: " + InterfaceInfo);
        //Class below is 3 for USB_HID
        if (intf.getInterfaceClass() == 3 && intf.getInterfaceSubclass() == 0 &&
                intf.getInterfaceProtocol() == 0) {
            return intf;
        }
        //....try just returning the interface regardless of class/subclass
        //return intf;
    }

    return null;
} 
 private boolean sendControlTransfer(byte[] dataToSend)
 {
    synchronized (this)
    { 
    if (mConnectionRead != null)
     { 
        //byte[] message = new byte[13];  // or 14?
        byte[] message = dataToSend;
         if (DEBUG == 9)
         {
             Toast.makeText(UsbHidDeviceTesterActivity.this, "Sending Control Transfer", Toast.LENGTH_LONG).show();
         } 

         //first field ox21 is bin 00100001 which splits into 0 01 00001 for direction(1bit)/type(2b)/recipient(5b)
         //To set direction as 'host to Device' we need 0, To set type to HID we need 11 (3), and for recipient we want 00001
         //second field 0x09 is class specific request code, 0x09 is listed as 'reserved for future use'
         //third field 0x200 is value
         //int transfer = mConnectionRead.controlTransfer(0x21, 0x9, 0x200, 0, message, message.length, 0);
         //try with type set to HID
         int transfer = mConnectionRead.controlTransfer(0xC1, 0x9, 0x200, 0, message, message.length, 0);
         if (DEBUG == 10)
         {
             Toast.makeText(UsbHidDeviceTesterActivity.this, "Transfer returned " + transfer, Toast.LENGTH_LONG).show();
         }
     } 
    }
    return true;
 }


private boolean sendInterruptTransfer(byte[] dataToSend)
{ 
    int bufferDataLength = mEndpointWrite.getMaxPacketSize();//The write endpoint is null unless we just copy the read endpoint
    if (DEBUG == 12)
    {
        Toast.makeText(UsbHidDeviceTesterActivity.this, "Max Packet Size: " + bufferDataLength, Toast.LENGTH_LONG).show();
    }

    ByteBuffer buffer = ByteBuffer.allocate(bufferDataLength + 1);
    UsbRequest request = new UsbRequest();
    buffer.put(dataToSend);

    request.initialize(mConnectionWrite, mEndpointWrite);
    request.queue(buffer, bufferDataLength);

    try
    {
        /* only use requestwait on a read
        if (request.equals(mConnectionWrite.requestWait()))
        {
            return true;
        }
        */
    }
    catch (Exception ex)
    {
        // An exception has occurred
        if (DEBUG == 13)
        {
            Toast.makeText(UsbHidDeviceTesterActivity.this, "Caught Write Exception", Toast.LENGTH_LONG).show();
        }
    }

    return true;
}   

questionAnswers(3)

yourAnswerToTheQuestion