Menu

problem with LibusbJava.usb_open???

Help
mike
2007-04-11
2012-12-06
  • mike

    mike - 2007-04-11

    Hi,

    Using Java libusb, I've created a Java version of the C program "testLibusb.c" that is distributed in the libusb-0.1.12 release. When I created this program, TestLibUsbJava.java, I tried to stay as close as possible to the original C code in hopes that I would get the exact same results. Unfortunately, I did not. The first difference I noticed is that the Java version seemed to find the root devices of a bus while the C version did not. This is a plus, so no problem there. The next two differences occurred when specifying the -v command line argument (verbose mode). The first is that the Java version printed some values of -1 for bInterval and bInterfaceClass, while the C version printed those values as 255. I don't think this is a big deal. However, the next difference I think is more of a problem. The C program prints out the manufacturer, product, and serial number info (when available); whereas, the Java version does not. For example:

    The C program prints out:

       Dev #0: Logitech - Apple Optical USB Mouse

    while the Java program prints out:

       Dev #0: 05AC - 0306

    My first thought was there was a problem with

    LibusbJava.usb_get_string_simple
     
    However, a little debugging makes me think the problem lies with the value returned by LibusbJava.usb_open. It returned the same value for all devices.

    Anyway, I figure this problem is one of:

      1. an error in my code,
      2. an error in my Mac build of the libusbJava,
      3. or an error in Java libusb
     

    Below is my code, so if anyone can shed some light on this problem I would appreciate it.

    -- Mike

    -----------------------------------------------------------------

    /**
    * @(#)TestLibUsbJava.java
    *
    *
    * This software is not designed or intended for use in on-line control
    * of aircraft, air traffic, aircraft navigation or aircraft
    * communications; or in the design, construction, operation or
    * maintenance of any nuclear facility.
    */
    import ch.ntb.usb.*;

    import java.io.*;

    /**
    * This class replicates the code from testlibusb.c supplied in the libusb-0.1.12 release.
    */
    public class TestLibUsbJava {
      static boolean verbose;

      /**
       * prints out endpoint info
       *
       * @param endpoint The end point.
       */
      private static void printEndpoint(Usb_Endpoint_Descriptor endpoint) {
        System.out.print(String.format("      bEndpointAddress: %02xh\n", endpoint.getBEndpointAddress()));
        System.out.print(String.format("      bmAttributes:     %02xh\n", endpoint.getBmAttributes()));
        System.out.print(String.format("      wMaxPacketSize:   %d\n", endpoint.getWMaxPacketSize()));
        System.out.print(String.format("      bInterval:        %d\n", endpoint.getBInterval()));
        System.out.print(String.format("      bRefresh:         %d\n", endpoint.getBRefresh()));
        System.out.print(String.format("      bSynchAddress:    %d\n", endpoint.getBSynchAddress()));
      }

      /**
       * prints out the interface descriptor
       *
       * @param interfaceDescript The interface descriptor.
       */
      private static void printAltsetting(Usb_Interface_Descriptor interfaceDescript) {
        System.out.print(String.format("    bInterfaceNumber:   %d\n",
                                       interfaceDescript.getBInterfaceNumber()));
        System.out.print(String.format("    bAlternateSetting:  %d\n",
                                       interfaceDescript.getBAlternateSetting()));
        System.out.print(String.format("    bNumEndpoints:      %d\n",
                                       interfaceDescript.getBNumEndpoints()));
        System.out.print(String.format("    bInterfaceClass:    %d\n",
                                       interfaceDescript.getBInterfaceClass()));
        System.out.print(String.format("    bInterfaceSubClass: %d\n",
                                       interfaceDescript.getBInterfaceSubClass()));
        System.out.print(String.format("    bInterfaceProtocol: %d\n",
                                       interfaceDescript.getBInterfaceProtocol()));
        System.out.print(String.format("    iInterface:         %d\n", interfaceDescript.getIInterface()));

        for (int i = 0; i < interfaceDescript.getBNumEndpoints(); i++) {
          printEndpoint(interfaceDescript.getEndpoint()[i]);
        }
      }

      /**
       * prints out interface
       *
       * @param usbInterface The interface.
       */
      private static void printInterface(Usb_Interface usbInterface) {
        for (int i = 0; i < usbInterface.getNumAltsetting(); i++) {
          printAltsetting(usbInterface.getAltsetting()[i]);
        }
      }

      /**
       * prints out configuration
       *
       * @param config The configuration.
       */
      private static void printConfiguration(Usb_Config_Descriptor config) {
        System.out.print(String.format("  wTotalLength:         %d\n", config.getWTotalLength()));
        System.out.print(String.format("  bNumInterfaces:       %d\n", config.getBNumInterfaces()));
        System.out.print(String.format("  bConfigurationValue:  %d\n", config.getBConfigurationValue()));
        System.out.print(String.format("  iConfiguration:       %d\n", config.getIConfiguration()));
        System.out.print(String.format("  bmAttributes:         %02xh\n", config.getBmAttributes()));
        System.out.print(String.format("  MaxPower:             %d\n", config.getMaxPower()));

        for (int i = 0; i < config.getBNumInterfaces(); i++) {
          printInterface(config.getInterface()[i]);
        }
      }

      private static int printDevice(Usb_Device dev, int level) {
        int udev;
        String mfr;
        String product;
        String sn;
        String spaces;
        String descript;

        spaces = "                                ";

        udev = LibusbJava.usb_open(dev);

        if (udev != 0) {
          if (dev.getDescriptor().getIManufacturer() != 0) {
            mfr = LibusbJava.usb_get_string_simple(udev, dev.getDescriptor().getIManufacturer());

            if (mfr != null) {
              descript = String.format("%s - ", mfr);
            } else {
              descript = String.format("%04X - ", dev.getDescriptor().getIdVendor());
            }
          } else {
            descript = String.format("%04X - ", dev.getDescriptor().getIdVendor());
          }

          if (dev.getDescriptor().getIProduct() != 0) {
            product = LibusbJava.usb_get_string_simple(udev, dev.getDescriptor().getIProduct());

            if (product != null) {
              descript = descript + String.format("%s", product);
            } else {
              descript = descript + String.format("%04X", dev.getDescriptor().getIdProduct());
            }
          } else {
            descript = descript + String.format("%04X", dev.getDescriptor().getIdProduct());
          }
        } else {
          descript = String.format("%04X - %04X", dev.getDescriptor().getIdVendor(),
                                   dev.getDescriptor().getIdProduct());
        }

        System.out.print(String.format("%sDev #%d: %s\n", spaces.substring(0, level * 2),
                                       dev.getDevnum(), descript));

        if ((udev != 0) && verbose) {
          if (dev.getDescriptor().getISerialNumber() != 0) {
            sn = LibusbJava.usb_get_string_simple(udev, dev.getDescriptor().getISerialNumber());

            if (sn != null) {
              System.out.print(String.format("%s  - Serial Number: %s\n",
                                             spaces.substring(0, level * 2), sn));
            }
          }
        }

        if (udev != 0) {
          LibusbJava.usb_close(udev);
        }

        if (verbose) {
          if (dev.getConfig().length == 0) {
            System.out.print("  Couldn't retrieve descriptors\n");

            return 0;
          }

          for (int i = 0; i < dev.getDescriptor().getBNumConfigurations(); i++) {
            printConfiguration(dev.getConfig()[i]);
          }
        } else {
          Usb_Device childDev = null;

          for (int i = 0; i < dev.getNumChildren(); i++) {
            if (i == 0) {
              childDev = dev.getChildren();
            } else {
              childDev = childDev.getNext();
            }

            printDevice(childDev, level + 1);
          }
        }

        return 0;
      }  // end of printDevice method

      /**
       * The main method.
       *
       * @param args The command line arguments.
       */
      public static void main(String args[]) throws Exception {
        if ((args.length > 0) && (args[0].equals("-v"))) {
          verbose = true;
        } else {
          verbose = false;
        }

        // used for debugging. 0 = no debugging.
        //
        LibusbJava.usb_set_debug(0);

        LibusbJava.usb_init();

        LibusbJava.usb_find_busses();
        LibusbJava.usb_find_devices();

        for (Usb_Bus bus = LibusbJava.usb_get_busses(); bus != null; bus = bus.getNext()) {
          if ((bus.getRootDev() != null) && !verbose) {
            printDevice(bus.getRootDev(), 0);
          } else {
            for (Usb_Device dev = bus.getDevices(); dev != null; dev = dev.getNext()) {
              printDevice(dev, 0);
            }
          }
        }
      }  // end main
    }  // end of TestLibUsbJava class

     
    • andi

      andi - 2007-04-11

      Hi Mike

      What do you mean by "find the root devices of a bus"? Did the Java version display more devices than the C test program?

      The second problem is a Java - C difference. Java doesn't have unsigned values. These values (bInterval and bInterfaceClass) are defined as 'unsigned char' in C which maps to byte (signed, because there is only signed byte) in Java. If used in an expression in Java it will be expanded to int. If the value is -1 that won't expand to 255 but to 0xffffffff (-1, 32 bit). So you can use 'signedByteValue && 0xff' to get the unsigned value which results in 255 (32 bit).

      I ran your program on my Windows PC to see if I get any differences to the testlibusb.exe program. But it shows exactly the same information as your Java equivalent.
      I don't see an obvious reason why your getting differences. You could try to insert some debug information (some printf's) in the share library to see if you really always get the same device handle on usb_open(). That should't be the case, if you're opening different devices. You could also compare the handles to the ones in the C test program. They should be the same, because the shared library does the same calls as the C program.

      The values you're getting (05AC - 0306), are these the vendor and product IDs of your device? Maybe there's some offset problem in the shared library and the wrong values are read. usb_get_string_simple() is converting a C UTF8 string to a Java UTF8 string. Maybe if it gets the wrong value and this value is 0-terminated, this will just output a correct string read from a wrong offset (not really sure if that's correct).

      Regards, Andreas

       
    • mike

      mike - 2007-04-11

      Hi Andreas,

      Thanks for help.

      ---------------------------------------------------

      Regarding the root device:

      When executing the programs without the "-v" argument, I believe that

      bus.getRootDev() return a non-null value in the Java version, and that
      bus->root_dev returns a null (or 0) value in the C version of the program.

      Output from Java version of the program

      Dev #0: 05AC - 8005
      Dev #0: 05AC - 8005
      Dev #0: 05AC - 8005
      Dev #0: 05AC - 8005
      Dev #0: 05AC - 8005
      Dev #0: 05AC - 8005

      Output from the C version of the program

      Dev #0: 05AC - 8005
      Dev #0: 05AC - 8005
      Dev #0: 05AC - 8005
      Dev #0: 05AC - 8005
      Dev #0: Griffin Technology, Inc - iMic USB audio system
      Dev #0: 05AC - 8005
      Dev #0: Mitsumi Electric - Hub in Apple Extended USB Keyboard
      Dev #0: Mitsumi Electric - Apple Extended USB Keyboard
      Dev #0: Logitech - Apple Optical USB Mouse
      Dev #0: 05AC - 8005
      Dev #0: Keyspan, a division of InnoSys Inc. - Keyspan USA-28
      ---------------------------------------------------

      Regarding the -1 vs 255:

      I thought it was probably something like that.

      ---------------------------------------------------

      Regarding the last problem:

      I think I've homed in on the problem.

      I believe that LibusbJava.usb_open(Usb_Device dev) (see below excerpt from LibusbJava.cpp) looks-up dev's corresponding device number and then uses it to open the device and return the corresponding int. Unfortunately, all my devices return a value of 0 for their device number. This is true, using both the TestLibUsbJava.java and testlibusb.c programs, as can be seen above. Since all my devices return the same device number (0) the int returned by LibusbJava.open_usb is the same for each device. Furthermore, it must be opening the same device each time. Since the program works on your machine, it sounds like it's a Mac specific problem, and is probably a bug with libusb.

      Any thoughts?

      -- Mike

      /*
      * Class:     ch_ntb_usb_LibusbJava
      * Method:    usb_open
      * Signature: (Lch/ntb/usb/Usb_Device;)I
      */
      JNIEXPORT jint JNICALL Java_ch_ntb_usb_LibusbJava_usb_1open
        (JNIEnv *env, jclass obj, jobject dev)
        {
            if (busses == NULL) {    return -1;     }
           
            unsigned char devnum = env->GetByteField(dev, usb_devFID_devnum);
            struct usb_bus *tmpBus;
           
            for (tmpBus = busses; tmpBus; tmpBus = tmpBus->next) {
                struct usb_device *device;
              for (device = tmpBus->devices; device; device = device->next) {
                    if (device->devnum == devnum){
                        return (jint) usb_open(device);
                    }
              }
            }
            return -3;
        }

       
      • andi

        andi - 2007-04-12

        Hi Mike

        Hmm - yes, that's possibly the reason. Because the dev struct (which is used in usb_open of the C-Version) must be mapped to the Java Device object somehow, the device number (devnum) is used. If that's not correct (= 0), it will always open the same device.

        What can be said for sure is, that the device numbers must be ascending or at least different from each other.

        Did you compile the source yourself or do you use some binary package?
        You could checkout the trunk version or build the latest release of libusb again. I hope that fixes the problem.

        Regards, Andreas

         

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.