2

I'm trying to use usb4java (low-level API) to communicate with a USB-connected scientific instrument set up as an HID device on Windows (both x86 and x86_64). There is a very old C++ application for it that works fine, but I'm trying to replace it with pure Java for a variety of reasons.

I can get device descriptors and determine the interface/endpoint, but asynchronous transfers never happen (checked by Device Monitoring Studio) and the callbacks are never called. No exceptions are thrown by usb4java and don't know if I can access any logs at the level of libusb (if it's even possible). I'm a complete novice in dealing with hardware, so it may well be something really basic that I'm missing.

There is only one endpoint and I'm not sure how the C++ code managed a bidirectional communication. There is no explicit mention of transfer types in the code, since all the details are buried in a third party library.

I installed the libusbK driver and I did try the high-level implementation (javax-usb). Transfers still don't get through.

Below is the output from the endpoint descriptor dump, as well as the abbreviated version of the code.

    Endpoint Descriptor:
  bLength                  7
  bDescriptorType          5
  bEndpointAddress      0x81  EP 1 IN
  bmAttributes             3
    Transfer Type             Interrupt
    Synch Type                None
    Usage Type                Data
  wMaxPacketSize           8
  bInterval              100
  extralen                 0
  extra:

Here's the code:

import java.nio.*;
import java.util.*;
import org.usb4java.*;


/**
 * This class is intended to test USB communication using usb4java
 *
 */
public class Test {

    private static final String vendorId = "VVV";
    private static final String productId = "PPP";

    private Context context;
    private Device device;
    private Handle handle;

    static volatile boolean exit = false;
    Object synchObj = new Object();
    boolean readCompleted = false;

    private static final int BUFFER_SIZE = 8;

    private final byte[] idQuery = new byte[]{ 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };

    public Test(){

        initialize();

        if (device == null){
            System.out.println("No target devices found");
            System.exit(0);
        }

        boolean loop = true;

        //claim interface 0
        int result = LibUsb.claimInterface(handle, 0);
        if (result != LibUsb.SUCCESS)   throw new LibUsbException("Unable to claim interface", result);

        //this code doesn't get executed because the transfer never completes correctly
        final TransferCallback readCallback = new TransferCallback(){
            public void processTransfer(Transfer transfer){
                System.out.println(transfer.actualLength() + " bytes sent");

                //read the response here

                synchronized (synchObj){
                    readCompleted = true;
                    synchObj.notify();
                }
            }
        };

        //initial request writing the device identification query
        write(handle, idQuery, readCallback);

        //waiting for the write/response to complete
        while (loop){           
            synchronized (synchObj){
                while (!readCompleted){
                    try{
                        synchObj.wait();
                    }
                    catch (InterruptedException ex){
                        ex.printStackTrace();
                    }
                }
            }
            readCompleted = false;
            loop = false;
            System.out.println("Completed reading");
        }

        result = LibUsb.releaseInterface(handle, 0);
        LibUsb.close(handle);

    }

    private void initialize(){
        try{
            context = new Context();
            int result = LibUsb.init(context);
            if (result != LibUsb.SUCCESS) throw new LibUsbException("Unable to initialize libusb.", result);    

            DeviceList deviceList = new DeviceList();
            result = LibUsb.getDeviceList(context, deviceList);
            if (result < 0) throw new LibUsbException("Unable to get device list.", result);

            for (int i = 0; i < deviceList.getSize(); i++){
                Device dev = deviceList.get(i);

                DeviceHandle h = new DeviceHandle();
                int res = LibUsb.open(dev, h);
                if (res != LibUsb.SUCCESS) continue;

                DeviceDescriptor descriptor = new DeviceDescriptor();
                result = LibUsb.getDeviceDescriptor(dev, descriptor);
                if (result != LibUsb.SUCCESS) throw new LibUsbException("Unable to read device descriptor", result);

                String dump = descriptor.dump(h);               
                if (dump.indexOf("PPP") > -1){
                    device = dev;
                    handle = h;
                    System.out.println("Found target device");
                    break;
                }
            }

        }
        catch (Exception ex){
            ex.printStackTrace();
        }
    }

    public static void write(DeviceHandle handle, byte[] data, TransferCallback callback){
        ByteBuffer buffer = BufferUtils.allocateByteBuffer(data.length);
        buffer.put(data);
        Transfer transfer = LibUsb.allocTransfer();
        LibUsb.fillInterruptTransfer(transfer, handle, (byte)0x81, buffer, callback, null, 1000);
        System.out.println("Sending " + data.length + " bytes to device");
        int result = LibUsb.submitTransfer(transfer);
        if (result != LibUsb.SUCCESS) throw new LibUsbException("Unable to submit transfer", result);
    }

    public static void main(String[] args){
        Test app = new Test();
    }
}

Thanks in advance for any suggestions.

Sasha
  • 93
  • 9

1 Answers1

1

First of: If you're not into fiddling and meddling I suggest you better just live with the software already provided. Theres a mountain of work ahead and since this is a scientific device this has the potential to mess up your readings.

Now to why this can not work: The interesting thing is this piece bEndpointAddress 0x81 EP 1 IN. What it tells us is, that there is an endpoint that can send data to the host. Yes, you can not write to this endpoint. This will wait until the device has data to send and simply overwrite your data in the buffer you provided.

As to why this is the case: You are dealing with HID. Better read up about it because you won't get simply ASCII buffers back but specially formatted byte arrays that have to be interpreted according to the HID protocol.

The only way to send data to this device is using control transfer on endpoint 0x00.

The easiest way to get started is using the c++ software with an usb sniffer and trying to make sense of the data going back and forth.

dryman
  • 660
  • 6
  • 16