Question

I'am able to connect to device and ask device specifications:

specs:

Model: /dev/bus/usb/001/002
ID: 1002
Class: 0
Protocol: 0
Vendor ID 1155
Product ID: 22352
Interface count: 1
---------------------------------------
*****     *****
Interface index: 0
Interface ID: 0
Inteface class: 3 USB_CLASS_HID
Interface protocol: 0
Endpoint count: 2 
++++   ++++   ++++
Endpoint index: 0
Attributes: 3
Direction: 128 (device to host)
Number: 1
Interval: 1
Packet size: 64
Type: 3 USB_ENDPOINT_XFER_INT (interrupt endpoint)
++++   ++++   ++++
Endpoint index: 1
Attributes: 3
Direction: 0 (host to device)
Number: 1
Interval: 1
Packet size: 64
Type: 3 USB_ENDPOINT_XFER_INT (interrupt endpoint)
No more devices connected.

I'am also able to send data from host to device, using this method:

    int bufferDataLength = mEndpointOut.getMaxPacketSize();
    ByteBuffer buffer = ByteBuffer.allocate(bufferDataLength + 1);
    UsbRequest request = new UsbRequest();

    buffer.put(DataToSend);

    request.initialize(mDeviceConnection, mEndpointOut);
    request.queue(buffer, bufferDataLength);
    try
    {
        if (request.equals(mDeviceConnection.requestWait()))
        {
            // Read an analyze the incoming data here
            byte[] byteBuffer = new byte[buffer.remaining()];
            buffer.get(byteBuffer, 0, buffer.remaining());
            return true;
        }
    }
    catch (Exception ex)
    {
        Log.e(TAG, "Error sending data: " + ex.toString());
    }
    return false;

But i'am not able to read from device, i've tested several methods without success..

for example this doesn't work:

    int bufferDataLength = mEndpointIn.getMaxPacketSize();
    ByteBuffer buffer = ByteBuffer.allocate(bufferDataLength + 1);

    //Make a request
    UsbRequest request = new UsbRequest();
    request.initialize(mDeviceConnection, mEndpointIn);
    ByteBuffer buffer = ByteBuffer.allocate(bufferDataLength);
    //For IN endpoints, data is read into the buffer
    request.queue(buffer, bufferDataLength);
    //This blocks until the request is successful
    //Make sure the request that finished is the one you need
    if (mDeviceConnection.requestWait() == request) {
     // Read an analyze the incoming data here
        byte[] byteBuffer = new byte[buffer.remaining()];
        buffer.get(byteBuffer, 0, buffer.remaining());
    }

Suggestions?

Was it helpful?

Solution

I resolved my problems using this class, i'm answering to my my question hoping it can help someone else:

/**
 * This class is used for talking to hid of the dongle, connecting, disconnencting and enumerating the devices.
 * @author gai
 */
@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
public class HidBridge {
    private Context _context;
    private int _productId;
    private int _vendorId;


    //private HidBridgeLogSupporter _logSupporter = new HidBridgeLogSupporter();
    private static final String ACTION_USB_PERMISSION =
            "com.example.company.app.testhid.USB_PERMISSION";

    // Locker object that is responsible for locking read/write thread.
    private final Object _locker = new Object();
    private Thread _readingThread = null;
    private boolean _runReadingThread = false;
    private String _deviceName;

    private UsbManager _usbManager;
    private UsbDevice _usbDevice;

    // The queue that contains the read data.
    private Queue<byte[]> _receivedQueue;

    /**
     * Creates a hid bridge to the dongle. Should be created once.
     * @param context is the UI context of Android.
     * @param productId of the device.
     * @param vendorId of the device.
     */
    public HidBridge(Context context, int productId, int vendorId) {
        _context = context;
        _productId = productId;
        _vendorId = vendorId;
        _receivedQueue = new LinkedList<byte[]>();
    }

    /**
     * Searches for the device and opens it if successful
     * @return true, if connection was successful
     */
    public boolean OpenDevice() {
        _usbManager = (UsbManager) _context.getSystemService(Context.USB_SERVICE);

        HashMap<String, UsbDevice> deviceList = _usbManager.getDeviceList();

        Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
        _usbDevice = null;

        // Iterate all the available devices and find ours.
        while(deviceIterator.hasNext()){
            UsbDevice device = deviceIterator.next();
            if (device.getProductId() == _productId && device.getVendorId() == _vendorId) {
                _usbDevice = device;
                _deviceName = _usbDevice.getDeviceName();
            }
        }

        if (_usbDevice == null) {
            Log("Cannot find the device. Did you forgot to plug it?");
            Log(String.format("\t I search for VendorId: %s and ProductId: %s", _vendorId, _productId));
            return false;
        }

        // Create and intent and request a permission.
        PendingIntent mPermissionIntent = PendingIntent.getBroadcast(_context, 0, new Intent(ACTION_USB_PERMISSION), 0);
        IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
        _context.registerReceiver(mUsbReceiver, filter);

        _usbManager.requestPermission(_usbDevice, mPermissionIntent);
        Log("Found the device");
        return true;
    }

    /**
     * Closes the reading thread of the device.
     */
    public void CloseTheDevice() {
        try 
        {
            StopReadingThread();
            _context.unregisterReceiver(mUsbReceiver);
        }
        catch(RuntimeException e)
        {
            Log("Error happend while closing device. Usb reciver not connected.");
        }
    }

    /**
     * Starts the thread that continuously reads the data from the device. 
     * Should be called in order to be able to talk with the device.
     */
    public void StartReadingThread() {
        if (_readingThread == null) {
            _runReadingThread = true;
            _readingThread = new Thread(readerReceiver);
            _readingThread.start();
        } else {
            Log("Reading thread already started");
        }
    }

    /**
     * Stops the thread that continuously reads the data from the device.
     * If it is stopped - talking to the device would be impossible.
     */
    public void StopReadingThread() {
        if (_readingThread != null) {
            // Just kill the thread. It is better to do that fast if we need that asap.
            _runReadingThread = false;
            _readingThread = null;
        } else {
            Log("No reading thread to stop");
        }
    }

    /**
     * Write data to the usb hid. Data is written as-is, so calling method is responsible for adding header data.
     * @param bytes is the data to be written.
     * @return true if succeed.
     */
    public boolean WriteData(byte[] bytes) {
        try
        {
            // Lock that is common for read/write methods.
            synchronized (_locker) {
                UsbInterface writeIntf = _usbDevice.getInterface(0);
                UsbEndpoint writeEp = writeIntf.getEndpoint(1);
                UsbDeviceConnection writeConnection = _usbManager.openDevice(_usbDevice); 

                // Lock the usb interface.
                writeConnection.claimInterface(writeIntf, true);

                // Write the data as a bulk transfer with defined data length.
                int r = writeConnection.bulkTransfer(writeEp, bytes, bytes.length, 0);
                if (r != -1) {  
                    Log(String.format("Written %s bytes to the dongle. Data written: %s", r, composeString(bytes)));
                } else {
                    Log("Error happened while writing data. No ACK");
                }

                // Release the usb interface.
                writeConnection.releaseInterface(writeIntf);
                writeConnection.close();
            }

        } catch(NullPointerException e)
        {
            Log("Error happend while writing. Could not connect to the device or interface is busy?");
            Log.e("HidBridge", Log.getStackTraceString(e));
            return false;
        }
        return true;
    }

    /**
     * @return true if there are any data in the queue to be read.
     */
    public boolean IsThereAnyReceivedData() {
        synchronized(_locker) {
            return !_receivedQueue.isEmpty();
        }
    }

    /**
     * Queue the data from the read queue.
     * @return queued data.
     */
    public byte[] GetReceivedDataFromQueue() {
        synchronized(_locker) {
            return _receivedQueue.poll();
        }
    }

    // The thread that continuously receives data from the dongle and put it to the queue.
    private Runnable readerReceiver = new Runnable() {
        public void run() {
            if (_usbDevice == null) {
                Log("No device to read from");
                return;
            }

            UsbEndpoint readEp;
            UsbDeviceConnection readConnection = null;
            UsbInterface readIntf = null;
            boolean readerStartedMsgWasShown = false;

            // We will continuously ask for the data from the device and store it in the queue.
            while (_runReadingThread) {
                // Lock that is common for read/write methods.
                synchronized (_locker) {
                    try
                    {
                        if (_usbDevice == null) {
                            OpenDevice();
                            Log("No device. Recheking in 10 sec...");

                            Sleep(10000);
                            continue;
                        }

                        readIntf = _usbDevice.getInterface(0);
                        readEp = readIntf.getEndpoint(0);
                        if (!_usbManager.getDeviceList().containsKey(_deviceName)) {
                            Log("Failed to connect to the device. Retrying to acquire it.");
                            OpenDevice();
                            if (!_usbManager.getDeviceList().containsKey(_deviceName)) {
                                Log("No device. Recheking in 10 sec...");

                                Sleep(10000);
                                continue;
                            }
                        }

                        try
                        {

                            readConnection = _usbManager.openDevice(_usbDevice); 

                            if (readConnection == null) {
                                Log("Cannot start reader because the user didn't gave me permissions or the device is not present. Retrying in 2 sec...");
                                Sleep(2000);
                                continue;
                            }

                            // Claim and lock the interface in the android system.
                            readConnection.claimInterface(readIntf, true);
                        }
                        catch (SecurityException e) {
                            Log("Cannot start reader because the user didn't gave me permissions. Retrying in 2 sec...");

                            Sleep(2000);
                            continue;
                        }

                        // Show the reader started message once.
                        if (!readerStartedMsgWasShown) {
                            Log("!!! Reader was started !!!");
                            readerStartedMsgWasShown = true;
                        }

                        // Read the data as a bulk transfer with the size = MaxPacketSize
                        int packetSize = readEp.getMaxPacketSize();
                        byte[] bytes = new byte[packetSize];
                        int r = readConnection.bulkTransfer(readEp, bytes, packetSize, 50);
                        if (r >= 0) {
                            byte[] trancatedBytes = new byte[r - 1]; // Truncate bytes in the honor of r

                            int i=0; 
                            for (byte b : bytes) {
                                if (i > 0)
                                    trancatedBytes[i - 1] = b;
                                i++;
                            }

                            _receivedQueue.add(trancatedBytes); // Store received data
                            Log(String.format("Message received of lengths %s and content: %s", r, composeString(bytes)));
                        }

                        // Release the interface lock.
                        readConnection.releaseInterface(readIntf);
                        readConnection.close();
                        } 

                    catch (NullPointerException e) {
                        Log("Error happened while reading. No device or the connection is busy");
                        Log.e("HidBridge", Log.getStackTraceString(e));
                    }
                    catch (ThreadDeath e) {
                        if (readConnection != null) {
                            readConnection.releaseInterface(readIntf);
                            readConnection.close();
                        }

                        throw e;
                    }
                }

                // Sleep for 10 ms to pause, so other thread can write data or anything. 
                // As both read and write data methods lock each other - they cannot be run in parallel.
                // Looks like Android is not so smart in planning the threads, so we need to give it a small time
                // to switch the thread context.
                Sleep(10);
            }
        }
    };

    private void Sleep(int milliseconds) {
        try {
            Thread.sleep(milliseconds);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {

        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (ACTION_USB_PERMISSION.equals(action)) {
                synchronized (this) {
                    UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);

                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                        if(device != null){
                          //call method to set up device communication
                       }
                    } 
                    else {
                        Log.d("TAG", "permission denied for the device " + device);
                    }
                }
            }
        }
    };

    /**
     * Logs the message from HidBridge.
     * @param message to log.
     */
    private void Log(String message) {
        //LogHandler logHandler = LogHandler.getInstance();
        //logHandler.WriteMessage("HidBridge: " + message, LogHandler.GetNormalColor());
        Log.i("HidBridge: ", message);
    }

    /**
     * Composes a string from byte array.
     */
    private String composeString(byte[] bytes) {
        StringBuilder builder = new StringBuilder();
        for (byte b: bytes) {
            builder.append(b);
            builder.append(" ");
        }

        return builder.toString();
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top