studio - Uso de Android para comunicarse con un dispositivo USB HID
android tag (3)
La transferencia de control no muestra ningún descriptor de interfaz y su número de punto final es 0 de forma predeterminada, tanto para la transferencia de entrada como de salida.
Si tiene otras interfaces, el índice de esas interfaces debe comenzar desde 0, es decir, la interfaz de transferencia de control predeterminada no cuenta.
Entonces su interfaz 0 contiene el descriptor del punto final 1. use los métodos UsbEndpoint para encontrar los atributos del punto final, ya sea un tipo de interrupción o no. si es entonces el tipo de punto final por UsbEndpoint.getType () debe devolver 0x03 y el número de punto final por UsbEndpoint.getEndpointNumber () debe devolver 0x81, que es el valor habitual para el punto final 1.
debajo de tu código es incorrecto:
//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);
Los bits de tipo 2 se utilizan para indicar una solicitud específica de clase, es decir, su valor es 01, 0x09 es la solicitud específica de clase HID SET_REPORT, no reservada. valor es el valor de wValue que se utiliza como ID de informe para la clase Hid; en su caso, probablemente sea 0, si tiene solo un informe en su descriptor HID. y el 4º parámetro es wIndex, que debe usarse para indicar el destinatario, en su caso, debe ser 0x01 para la interfaz como destinatario.
Por lo tanto, su código para transferencia de control para dispositivo de lectura o recepción de datos debe ser:
int transfer = mConnectionRead.controlTransfer(0xA1, 0x01, 0x00, 0x01, message, message.length, 0);
donde 0x01 en el segundo parámetro es GET_REPORT es una solicitud específica de llamadas ocultadas.
Y su código de transferencia de control para escritura o envío de datos al dispositivo debe ser:
int transfer = mConnectionWrite.controlTransfer(0x21, 0x09, 0x00, 0x01, message, message.length, 0);
Como solo tiene Interrupción en el punto final 1, la transferencia a granel o Interrupción debe ser como:
int transfer = bulkTransfer (ep1, message, message.length, 0);
para tener el punto final de interrupción de salida, debe haber un descriptor de punto final para eso en el descriptor de la interfaz del firmware de su dispositivo.
Soy nuevo en USB y en Android, así que perdóneme si no me explico claramente.
Tengo un dispositivo USB HID con el que puedo comunicarme en Windows. Estoy tratando de establecer una comunicación utilizando una tableta Acer Iconia A500 con Android 3.1.
Puedo encontrar el dispositivo, enumerarlo, obtener su única interfaz disponible, obtener el único punto final disponible (0) y determinar qué tipo de punto final es (interrumpir la transferencia del dispositivo al host).
Mi comprensión de la especificación USB es que todos los dispositivos HID se requieren en un munimum para tener un punto final de control (punto final 0) y un punto extremo de IN de interrupción. Pero parece que el punto final 0 aquí es la interrupción en el punto final, no el punto final de control.
Sin embargo, para que el dispositivo pueda enumerar, debe transferir con éxito sus datos descriptores a través del punto final de control. Deduzco que, por lo tanto, el punto final de control se debe encontrar (y usar) porque el host, de hecho, enumera el dispositivo.
En la medida en que puedo continuar, como se indicó anteriormente, la única interfaz / punto final que se me presenta a nivel de aplicación es un tipo de interrupción que va del dispositivo al host. No hay un punto final disponible para mi aplicación que va de host a dispositivo, interrupción o control. Entonces, el dispositivo espera que se le diga qué hacer y el host espera que algo suceda en el dispositivo. No muy estimulante.
Tenga en cuenta que este dispositivo responde correctamente cuando está conectado a Windows, por ejemplo, puedo enviar un informe que contiene 13 bytes de datos que hacen que el dispositivo encienda un LED. Así que parece estar cumpliendo con la especificación USB HID. Como un acto de desesperación, he intentado utilizar este único punto final como punto final de control y como punto final de interrupción OUT, utilizando controltransfer () y UsbRequest () para enviar los datos al dispositivo, sin respuesta en ninguno de los casos.
Así que mi pregunta es: "¿Se está utilizando el punto final de transferencia de control (?) Para configurar el dispositivo, ¿por qué no puedo encontrarlo y usarlo?"
Gracias por cualquier información, a continuación está el código relevante, puedo incluir 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;
}
Por lo tanto, he estado investigando cosas similares. No puedo confirmar, pero lo que creo que está sucediendo es:
- Android no lista el punto final de control cuando enumera sus puntos finales. Sólo enumera otros puntos finales.
- Una conexión a cualquier punto final puede enviar transferencias de control al punto final 0, a través del método controlTransfer, que (citando desde la api) "Realiza una transacción de control en el punto final cero para este dispositivo".
- Por lo tanto, en su código anterior, usaría el punto final 0 como un punto final de entrada de interrupción, pero todavía permitirá transferencias de control.
- Un ejemplo de alguien que usa un dispositivo HID es la demostración de Missle Launcher, el dispositivo que utiliza es un dispositivo HID con un punto final de interrupción.
Puede obtener una lista completa de los detalles de interfaces y puntos finales utilizando lo 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.");
}