Soy nuevo con USB y Android, así que por favor me perdone si no me explico con claridad.

Tengo un USB dispositivo HID que me puedo comunicar con en Windows. Estoy tratando de establecer comunicación a través de una Acer Iconia A500 tablet con Android 3.1.

Soy capaz de encontrar el dispositivo, enumerar, conseguir su único interfaz disponibles, obtenga la única disponible extremo (0), y determinar qué tipo de extremo es (transferencia de interrupción del dispositivo al host).

Mi comprensión de la USB especificación es que todos los dispositivos HID son necesarios en un munimum para tener un control de punto final (Endpoint 0) y una interrupción EN el extremo. Pero parece que el endpoint 0 aquí es la interrupción En extremo, no el control de endpoint.

Sin embargo, para que el dispositivo para enumerar debe transferir con éxito su descriptor de datos a través del control de endpoint. Deduzco que el extremo del control, por lo que debe llegar encontrado (y se usa) porque el host no, de hecho, enumerar el dispositivo.

Esto es como lo que yo soy capaz de proceder, como se indicó anteriormente, la única interfaz/extremo que se me presentan en el nivel de aplicación es un tipo de interrupción que va desde el dispositivo host. No hay extremo a disposición de mi aplicación que va desde el host al dispositivo, interrumpir o de control. Para que el dispositivo se espera que se le diga qué hacer y el anfitrión espera a que suceda algo en el dispositivo. No es muy estimulante.

Tener en cuenta que este dispositivo no responde correctamente cuando se conecta a Windows, por ejemplo, soy capaz de enviar un informe que contiene 13 bytes de datos que hace que el dispositivo a la luz de un LED. Por lo que parece estar en concordancia con el USB HID spec. Como un acto de desesperación he intentado usar este extremo como un control extremo y como una interrupción a CABO extremo, el uso de controltransfer() y UsbRequest() para enviar los datos al dispositivo, no hay respuesta en cualquiera de los casos.

Así que mi pregunta es: «El control de transferencia de extremo (?) se utiliza para configurar el dispositivo, ¿por qué no soy capaz de encontrar & utilizar?»

Gracias por la información, a continuación se muestra el código correspondiente, puedo incluya el resto en su totalidad si es necesario:

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

OriginalEl autor DasBoos | 2012-11-08

3 Comentarios

  1. 9

    Así, he estado investigando cosas similares. No puedo confirmar, pero lo que yo creo que está sucediendo es:

    1. Android no muestra el extremo de control cuando se enumera que los extremos. Sólo las listas de otros extremos.
    2. Una conexión a cualquier extremo puede enviar transferencias de control de endpoint 0, a través de la controlTransfer método, que (citando a partir de la api) «Realiza una transacción de control en el extremo de cero para este dispositivo».
    3. Así, en el código anterior, me gustaría utilizar el 0 extremo como una interrupción de la entrada de extremo, pero aún así se permiten transferencias de control.
    4. Un ejemplo de alguien a través de un dispositivo HID es la Missle Lanzador de demostración, el dispositivo utiliza un dispositivo HID con una interrupción extremo.
    usted está exactamente correcto, aunque el único extremo (EP0) fue identificado como una interrupción extremo, si me trata como una escritura de todos modos y se realiza un control de la transferencia, entonces funcionó.

    OriginalEl autor zabuni

  2. 10

    Usted puede obtener una lista completa de los detalles de las interfaces y extremo utilizando el siguiente:

    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.");
    }
    Gracias por la respuesta. El código es una versión mucho más limpio de la Depura de que los que se habían dispersado a lo largo de mi código. Sin embargo, cuando ejecuto el código se confirma lo que yo ya había encontrado: que sólo hay 1 interfaz con un solo extremo, y que el extremo es un tipo de interrupción que se ejecuta en la dirección del dispositivo al servidor. Así que en resumen: En Android no se me dé un extremo en el que enviar un mensaje al dispositivo. Sin embargo, sé que el extremo debe existir porque está disponible y funciona en Windows. Por lo tanto, Android no debe ser compatible con USB HID
    Si es un control extremo o una interrupción extremo que no está disponible no está claro. Cualquier otra visión de este problema, sería muy apreciado, incluso si es sólo para corroborar o contradecir mis resultados.

    OriginalEl autor user1815293

  3. 4

    De Control de transferencia no muestra ninguna interfaz de descriptor y su extremo número es el valor predeterminado es 0, por tanto dentro como fuera de la transferencia.

    si usted tiene otras interfaces el índice de los interfaces deben empezar desde 0 es decir, por defecto de control de transferencia de la interfaz no cuenta.

    Por lo que su interfaz 0 sostiene el extremo 1 descriptor. el uso de la UsbEndpoint métodos para encontrar los atributos de la estación si es el tipo de interrupción o no. si es así, tipo de extremo por UsbEndpoint.getType() debe devolver 0x03 de estaciones de trabajo y número de UsbEndpoint.getEndpointNumber() debe devolver 0x81 que es habitual valor extremo 1.

    a continuación el código está mal:

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

    Tipo 2 bits que se utiliza para indicar la clase a la petición específica, es decir, su valor es 01,
    0x09 es Hid solicitud específica SET_REPORT, no reservados.
    valor es el wValue que se utiliza como ID de Informe para Hid, para su caso, es probable que 0, si usted tiene un único informe en el que se ESCONDIÓ en el descriptor.
    y el 4º parámetro es wIndex que debe utilizarse para indicar el destinatario, para que su caso debe ser 0x01 para la interfaz como destinatario.

    Por lo tanto el código para el control de transferencia para Leer o recibir los datos de forma que el dispositivo debería ser:

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

    donde 0x01 en segundo parámetro es GET_REPORT se Escondió llamadas de solicitud específica.

    Y el código de control de transferencia para Escribir o enviar datos a un dispositivo debe ser:

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

    Ya que sólo tienes Interrupción EN el extremo 1, a Granel o en la Interrupción de la transferencia debe ser como:

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

    tener la interrupción Fuera de extremo no debe ser un extremo descriptor para que en el descriptor de interfaz de firmware de su dispositivo.

    Gran resumen. Gracias por esto!

    OriginalEl autor Amin

Dejar respuesta

Please enter your comment!
Please enter your name here