web-dev-qa-db-fra.com

En utilisant Android pour communiquer avec un périphérique HID USB

Je suis nouveau à usb et à Android Donc, veuillez me pardonner si je ne m'explique pas clairement.

J'ai un appareil USB HID que je peux communiquer avec Windows. J'essaie d'établir une communication à l'aide d'une tablette Acer Iconia A500 en cours d'exécution Android 3.1.

Je suis capable de trouver le périphérique, de l'énumérer, d'obtenir sa seule interface disponible, d'obtenir le seul point final disponible (0) et de déterminer le type de noeud final, il est (transfert interruption de l'appareil à l'hôte).

Ma compréhension de la spécification USB est que tous les périphériques DHI sont nécessaires à un munimum pour avoir un point d'extrémité de contrôle (point final 0) et une interruption en fin d'évaluation. Mais il semble que le point final 0 voici l'interruption en fin d'évaluation, pas le point final de contrôle.

Pourtant, pour que l'appareil soit énumérable, cela doit transférer avec succès ses données de descripteur sur le point d'extrémité de contrôle. Je déduit que le point d'extrémité de contrôle doit donc être trouvé (et utilisé) parce que l'hôte est en fait énumérant l'appareil.

C'est aussi loin que je suis en mesure de procéder, comme indiqué ci-dessus, la seule interface/point final qui m'a été présenté au niveau de l'application est un type d'interruption d'un périphérique à héberger. Aucun novoyal de fin disponible pour mon application passe de l'hôte au périphérique, d'interrompre ou de contrôle. Donc, l'appareil attend quoi faire et l'hôte attend que quelque chose se passe dans l'appareil. Pas très stimulant.

N'oubliez pas que cet appareil répond correctement lorsqu'il est connecté à Windows, par exemple. Je suis capable d'envoyer un rapport contenant 13 octets de données qui provoque une allumage d'une LED. Il semble donc se conformer à la spécification HID USB. En tant qu'autois de désespoir, j'ai essayé d'utiliser ce point d'extrémité d'un point d'extrémité de contrôle et d'un point d'extrémité d'interruption, utilisant ControlTransfer () et USBREQUEST () pour soumettre les données au périphérique, aucune réponse dans les deux cas.

Donc, ma question est la suivante: "Le point final de transfert de contrôle est (?) Étant utilisé pour configurer l'appareil, pourquoi je ne suis pas capable de trouver et d'l'utiliser?"

Merci pour toute idée, ci-dessous est le code concerné, je peux inclure le reste dans son intégralité si nécessaire:

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;
}   
16
DasBoos

Donc, j'ai étudié des choses similaires. Je ne peux pas confirmer, mais ce que je crois me passe est:

  1. Android ne énumère pas le point d'extrémité de contrôle lorsqu'il énumère les points d'extrémité. Il ne répertorie que d'autres points finaux.
  2. Une connexion à tout point final peut envoyer des transferts de contrôle au point de terminaison 0, via la méthode ControlTransfer, qui (citant à partir de l'API) "effectue une transaction de contrôle sur le point d'extrémité zéro pour ce périphérique."
  3. Donc, dans votre code ci-dessus, j'utiliserais le point d'extrémité du 0th comme point d'extrémité d'entrée d'interruption, mais il permettrait toujours des transferts de contrôle.
  4. Un exemple de quelqu'un utilisant un périphérique HID est la démonstration du lanceur d'quisses, l'appareil qu'il utilise est un périphérique HID avec un point final d'interruption.
9
zabuni

Vous pouvez obtenir une liste complète des détails des interfaces et des points finaux en utilisant les éléments suivants:

UsbManager mManager = (UsbManager) getSystemService(Context.USB_SERVICE);
HashMap<String, UsbDevice> deviceList = mManager.getDeviceList();
Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();

while (deviceIterator.hasNext())
    {
        UsbDevice device = deviceIterator.next();
        Log.i(TAG,"Model: " + device.getDeviceName());
        Log.i(TAG,"ID: " + device.getDeviceId());
        Log.i(TAG,"Class: " + device.getDeviceClass());
        Log.i(TAG,"Protocol: " + device.getDeviceProtocol());
        Log.i(TAG,"Vendor ID " + device.getVendorId());
        Log.i(TAG,"Product ID: " + device.getProductId());
        Log.i(TAG,"Interface count: " + device.getInterfaceCount());
        Log.i(TAG,"---------------------------------------");
   // Get interface details
        for (int index = 0; index < device.getInterfaceCount(); index++)
        {
        UsbInterface mUsbInterface = device.getInterface(index);
        Log.i(TAG,"  *****     *****");
        Log.i(TAG,"  Interface index: " + index);
        Log.i(TAG,"  Interface ID: " + mUsbInterface.getId());
        Log.i(TAG,"  Inteface class: " + mUsbInterface.getInterfaceClass());
        Log.i(TAG,"  Interface protocol: " + mUsbInterface.getInterfaceProtocol());
        Log.i(TAG,"  Endpoint count: " + mUsbInterface.getEndpointCount());
    // Get endpoint details 
            for (int epi = 0; epi < mUsbInterface.getEndpointCount(); epi++)
        {
            UsbEndpoint mEndpoint = mUsbInterface.getEndpoint(epi);
            Log.i(TAG,"    ++++   ++++   ++++");
            Log.i(TAG,"    Endpoint index: " + epi);
            Log.i(TAG,"    Attributes: " + mEndpoint.getAttributes());
            Log.i(TAG,"    Direction: " + mEndpoint.getDirection());
            Log.i(TAG,"    Number: " + mEndpoint.getEndpointNumber());
            Log.i(TAG,"    Interval: " + mEndpoint.getInterval());
            Log.i(TAG,"    Packet size: " + mEndpoint.getMaxPacketSize());
            Log.i(TAG,"    Type: " + mEndpoint.getType());
        }
        }
    }
    Log.i(TAG," No more devices connected.");
}
10
user1815293

Le transfert de contrôle ne montre aucun descripteur d'interface et son numéro de point d'extrémité est 0 par défaut, pour le transfert d'entrée et arrière.

si vous avez d'autres interfaces, l'index de ces interfaces doit démarrer à partir de 0 I.e. L'interface de transfert de contrôle par défaut ne compte pas.

Votre interface 0 contient donc le descripteur de terminal 1. Utilisez les méthodes USBendpoint pour trouver les attributs du point final s'il s'agit d'un type d'interruption ou non. S'il est alors le type de point final par USBendPoint.getType () doit renvoyer 0x03 et le numéro de terminal par USBendPoint.getendPointNumber () doit renvoyer 0x81 qui est une valeur habituelle pour l'extrémité 1.

au-dessous de votre code est faux:

//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);

Les bits de type 2 sont utilisés pour indiquer la demande spécifique de la classe, c'est-à-dire que sa valeur est 01, 0x09 est une demande spécifique de classe HID Set_Report, non réservée. La valeur est la WValue qui est utilisée comme identifiant de rapport pour la classe HID, car votre cas est probablement 0, si vous n'avez qu'un seul rapport sur votre descripteur HID. Et le 4 e paramètre est Windex, qui doit être utilisé pour indiquer le destinataire, pour votre cas, il devrait être 0x01 pour l'interface comme destinataire.

Donc, votre code pour le transfert de contrôle pour lire ou recevoir le formulaire de données doit être:

int transfer = mConnectionRead.controlTransfer(0xA1, 0x01, 0x00, 0x01, message, message.length, 0);

où 0x01 dans le deuxième paramètre est GET_REPORT EST DÉPLACE DE DÉPOSITION SPÉCIFIQUE.

Et votre code pour le transfert de contrôle pour écriture ou envoyer des données au périphérique doit être:

int transfer = mConnectionWrite.controlTransfer(0x21, 0x09, 0x00, 0x01, message, message.length, 0);

Puisque vous n'avez qu'une interruption dans l'extrémité 1, le transfert en vrac ou à l'interruption devrait être comme:

int transfer = bulkTransfer (ep1, message, message.length, 0);

pour que le point d'extrémité d'interruption, il devrait y avoir un descripteur de point de terminaison pour celui du descripteur d'interface du micrologiciel de votre appareil.

4
Amin