Started using NIO buffers.

This commit is contained in:
Klaus Reimer 2011-01-23 00:03:08 +01:00
parent 7851dfb34e
commit 9b6eb1aa07
7 changed files with 351 additions and 60 deletions

View File

@ -5,7 +5,8 @@
package de.ailis.usb4java;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
@ -24,6 +25,12 @@ import java.io.UnsupportedEncodingException;
public class USB
{
/** The maximum size of a descriptor. */
private static final int MAX_DESCRIPTOR_SIZE = 256;
/** The maximum size of a string. */
private static final int MAX_STRING_SIZE = (MAX_DESCRIPTOR_SIZE - 2) / 2;
// === USB class constants ===============================================
/** Per interface class. */
@ -218,13 +225,11 @@ public class USB
* The language id.
* @param buffer
* The buffer to write the string to.
* @param buflen
* The maximum number of bytes to read.
* @return The number of bytes read or < 0 on error.
*/
public static native int usb_get_string(USB_Dev_Handle handle,
int index, int langid, byte[] buffer, int buflen);
int index, int langid, ByteBuffer buffer);
/**
@ -238,23 +243,35 @@ public class USB
* The language id.
* @param size
* The maximum number of bytes to read.
* @return The string or null if an error occurred.
* @return The string descriptor or null if an error occurred.
*/
public static String usb_get_string(final USB_Dev_Handle handle,
public static USB_String_Descriptor usb_get_string(final USB_Dev_Handle handle,
final int index, final int langid, final int size)
{
final byte[] buffer = new byte[size];
final int len = usb_get_string(handle, index, langid, buffer, size);
final ByteBuffer buffer = ByteBuffer.allocateDirect(size);
final int len = usb_get_string(handle, index, langid, buffer);
if (len < 0) return null;
try
{
return new String(buffer, 0, len, "UTF-8");
}
catch (final UnsupportedEncodingException e)
{
return new String(buffer, 0, len);
}
return new USB_String_Descriptor(buffer);
}
/**
* Returns a string descriptor from a device.
*
* @param handle
* The USB device handle.
* @param index
* The string description index.
* @param langid
* The language id.
* @return The string descriptor or null if an error occurred.
*/
public static USB_String_Descriptor usb_get_string(final USB_Dev_Handle handle,
final int index, final int langid)
{
return usb_get_string(handle, index, langid, MAX_STRING_SIZE * 2);
}
@ -272,40 +289,98 @@ public class USB
* The string description index.
* @param buffer
* The buffer to write the string to.
* @param buflen
* The maximum number of bytes to read.
* @return The number of bytes read or < 0 on error.
*/
public static native int usb_get_string_simple(USB_Dev_Handle handle,
int index, byte[] buffer, int buflen);
int index, ByteBuffer buffer);
/**
* Returns a string descriptor from a device using the first language.
* Unlike the native usb_get_string_simple() function this method returns
* the string in correct unicode encoding.
*
* @param handle
* The USB device handle.
* @param index
* The string description index.
* @param size
* The maximum number of bytes to read.
* The maximum number of characters to read.
* @return The string or null if an error occurred.
*/
public static String usb_get_string_simple(final USB_Dev_Handle handle,
final int index, final int size)
{
final byte[] buffer = new byte[size];
final int len = usb_get_string_simple(handle, index, buffer, size);
if (len < 0) return null;
try
{
return new String(buffer, 0, len, "ISO-8859-15");
}
catch (final UnsupportedEncodingException e)
{
return new String(buffer, 0, len);
}
final short[] languages = usb_get_languages(handle);
if (languages == null) return null;
final short langid = languages.length == 0 ? 0 : languages[0];
final USB_String_Descriptor descriptor = usb_get_string(handle, index, langid, size * 2);
if (descriptor == null) return null;
return descriptor.toString();
}
/**
* Returns a string descriptor from a device using the first language.
* Unlike the native usb_get_string_simple() function this method returns
* the string in correct unicode encoding.
*
* @param handle
* The USB device handle.
* @param index
* The string description index.
* @return The string or null if an error occurred.
*/
public static String usb_get_string_simple(final USB_Dev_Handle handle,
final int index)
{
return usb_get_string_simple(handle, index, MAX_STRING_SIZE);
}
/**
* Returns the languages the specified device supports.
*
* @param handle
* The USB device handle.
* @return Array with supported language codes.
*/
public static short[] usb_get_languages(final USB_Dev_Handle handle)
{
final ByteBuffer buffer = ByteBuffer
.allocateDirect(MAX_DESCRIPTOR_SIZE);
final int len = usb_get_descriptor(handle, USB_DT_STRING, 0, buffer);
if (len < 0) return null;
final short[] languages = new short[(len - 2) / 2];
if (languages.length == 0) return languages;
buffer.position(2);
buffer.order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(languages);
return languages;
}
/**
* Retrieves a descriptor from a device's default control pipe.
*
* usb_get_descriptor retrieves a descriptor from the device identified by
* the type and index of the descriptor from the default control pipe.
* Returns number of bytes read for the descriptor or < 0 on error.
*
* @param handle
* The device handle.
* @param type
* The descriptor type.
* @param index
* The descriptor index.
* @param buffer
* The buffer to put the read bytes in.
* @return Number of bytes read or < 0 on error.
*/
public static native int usb_get_descriptor(USB_Dev_Handle handle,
int type, int index, ByteBuffer buffer);
}

View File

@ -0,0 +1,60 @@
/*
* Copyright (C) 2011 Klaus Reimer <k@ailis.de>
* See LICENSE.txt for licensing information.
*/
package de.ailis.usb4java;
import java.nio.ByteBuffer;
/**
* All standard descriptors have the two fields bLength and bDescriptorType
* in common. So this base class implements them.
*
* @author Klaus Reimer (k@ailis.de)
*/
public abstract class USB_Descriptor_Header2
{
/** The descriptor data. */
protected final ByteBuffer data;
/**
* Constructor.
*
* @param data
* The descriptor data.
*/
public USB_Descriptor_Header2(final ByteBuffer data)
{
this.data = data;
this.data.limit(bLength());
}
/**
* Returns the size of the descriptor in bytes.
*
* @return The size of the descriptor in bytes (unsigned byte).
*/
public final int bLength()
{
return this.data.get(0) & 0xff;
}
/**
* Returns the interface descriptor type.
*
* @return The interface descriptor type (unsigned byte).
*/
public final int bDescriptorType()
{
return this.data.get(1) & 0xff;
}
}

View File

@ -0,0 +1,60 @@
/*
* Copyright (C) 2011 Klaus Reimer <k@ailis.de>
* See LICENSE.txt for licensing information.
*/
package de.ailis.usb4java;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.CharBuffer;
/**
* A string descriptor.
*
* @author Klaus Reimer (k@ailis.de)
*/
public class USB_String_Descriptor extends USB_Descriptor_Header2
{
/**
* Constructor.
*
* @param data
* The descriptor data.
*/
USB_String_Descriptor(final ByteBuffer data)
{
super(data);
}
/**
* Returns the string data in UTF-16 encoding.
*
* @return The string data.
*/
public char[] wData()
{
this.data.position(2);
final CharBuffer chars = this.data.order(ByteOrder.LITTLE_ENDIAN)
.asCharBuffer();
final char[] output = new char[chars.remaining()];
chars.get(output);
return output;
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString()
{
return new String(wData());
}
}

View File

@ -213,12 +213,23 @@ public class Dump
dump_device_descriptor(device.descriptor());
level--;
final USB_Dev_Handle handle = usb_open(device);
final String manufacturer = usb_get_string_simple(handle, device.descriptor().iManufacturer(), 255);
final String manufacturer = usb_get_string_simple(handle, device.descriptor().iManufacturer());
indent(); System.out.format("Manufacturer: %s\n", manufacturer != null ? manufacturer : "Unknown");
final String product = usb_get_string_simple(handle, device.descriptor().iProduct(), 255);
final String product = usb_get_string_simple(handle, device.descriptor().iProduct());
indent(); System.out.format("Product: %s\n", product != null ? product : "Unknown");
final String serialNumber = usb_get_string_simple(handle, device.descriptor().iSerialNumber(), 255);
final String serialNumber = usb_get_string_simple(handle, device.descriptor().iSerialNumber());
indent(); System.out.format("Serial: %s\n", serialNumber != null ? serialNumber : "Unknown");
indent(); System.out.print("Languages:");
final short[] languages = USB.usb_get_languages(handle);
if (languages != null)
{
for (final short language: languages)
System.out.format(" 0x%04x", language);
System.out.println();
}
else
System.out.println("Unknown");
usb_close(handle);
indent(); System.out.format("config descriptors:\n");
level++;

View File

@ -12,5 +12,6 @@ libusb4java_la_SOURCES = \
USB_Dev_Handle.c \
USB_Interface.c \
USB_Interface_Descriptor.c \
USB_Endpoint_Descriptor.c
USB_Endpoint_Descriptor.c \
USB_String_Descriptor.c

View File

@ -105,41 +105,48 @@ JNIEXPORT jint JNICALL METHOD_NAME(USB, usb_1close)
JNIEXPORT jint JNICALL METHOD_NAME(USB, usb_1get_1string)
(
JNIEnv *env, jclass class, jobject handle, jint index, jint langid,
jbyteArray buffer, jint buflen
jobject buffer
)
{
char *buf = (char*) malloc(buflen);
int result = usb_get_string(unwrap_usb_dev_handle(env, handle),
index, langid, buf, buflen);
if (result >= 0)
{
(*env)->SetByteArrayRegion(env, buffer, 0, result,
(const jbyte *) buf);
}
free(buf);
return result;
void *buf = (*env)->GetDirectBufferAddress(env, buffer);
if (!buf) return -1;
jlong buflen = (*env)->GetDirectBufferCapacity(env, buffer);
return usb_get_string(unwrap_usb_dev_handle(env, handle),
index, langid, buf, buflen);
}
/**
* int usb_get_simple_string(USB_Handle handle, int index, byte[] buffer,
* int buflen)
* int usb_get_simple_string(USB_Handle handle, int index, ByteBuffer buffer)
*/
JNIEXPORT jint JNICALL METHOD_NAME(USB, usb_1get_1string_1simple)
(
JNIEnv *env, jclass class, jobject handle, jint index, jbyteArray buffer,
jint buflen
JNIEnv *env, jclass class, jobject handle, jint index, jobject buffer
)
{
char *buf = (char*) malloc(buflen);
int result = usb_get_string_simple(unwrap_usb_dev_handle(env, handle),
index, buf, buflen);
if (result >= 0)
{
(*env)->SetByteArrayRegion(env, buffer, 0, result,
(const jbyte *) buf);
}
free(buf);
return result;
void *buf = (*env)->GetDirectBufferAddress(env, buffer);
if (!buf) return -1;
jlong buflen = (*env)->GetDirectBufferCapacity(env, buffer);
return usb_get_string_simple(unwrap_usb_dev_handle(env, handle),
index, buf, buflen);
}
/**
* int usb_get_descriptor(USB_Dev_Handle handle, int type, int index,
* ByteBuffer buffer);
*/
JNIEXPORT jint JNICALL METHOD_NAME(USB, usb_1get_1descriptor)
(
JNIEnv *env, jclass class, jobject handle, int type, int index,
jobject buffer
)
{
void *buf = (*env)->GetDirectBufferAddress(env, buffer);
if (!buf) return -1;
jlong buflen = (*env)->GetDirectBufferCapacity(env, buffer);
return usb_get_descriptor(unwrap_usb_dev_handle(env, handle),
type, index, buf, buflen);
}

View File

@ -0,0 +1,77 @@
/*
* Copyright (C) 2011 Klaus Reimer (k@ailis.de)
* See COPYING file for copying conditions
*/
/**
* @name USB_String_Descriptor
*
* Native methods for the USB_String_Descriptor class.
*
* @author Klaus Reimer <k@ailis.de>
*/
#include <jni.h>
#include <usb.h>
#include "usb4java.h"
/**
* Creates and returns a new USB string descriptor wrapper object.
*
* @param env
* The JNI environment.
* @param device
* The USB string descriptor.
* @return The USB string descriptor wrapper object.
*/
jobject wrap_usb_string_descriptor(JNIEnv *env,
struct usb_string_descriptor *descriptor)
{
if (!descriptor) return NULL;
jclass cls = (*env)->FindClass(env,
PACKAGE_DIR"/USB_String_Descriptor");
if (cls == NULL) return NULL;
jmethodID constructor = (*env)->GetMethodID(env, cls, "<init>", "(J)V");
if (constructor == NULL) return NULL;
return (*env)->NewObject(env, cls, constructor, (long) descriptor);
}
/**
* Returns the wrapped USB string descriptor object from the specified
* wrapper object.
*
* @param env
* The JNI environment.
* @param obj
* The USB string descriptor wrapper object.
* @return The USB string descriptor object.
*/
struct usb_string_descriptor *unwrap_usb_string_descriptor(JNIEnv *env,
jobject obj)
{
jclass cls = (*env)->GetObjectClass(env, obj);
jfieldID field = (*env)->GetFieldID(env, cls, "pointer", "J");
return (struct usb_string_descriptor *) ((*env)->GetLongField(env,
obj, field));
}
/**
* char[] wData()
*/
JNIEXPORT jcharArray JNICALL METHOD_NAME(USB_1String_1Descriptor, wData)
(
JNIEnv *env, jobject this
)
{
struct usb_string_descriptor *descriptor = unwrap_usb_string_descriptor(env, this);
int size = (descriptor->bLength - 2) / 2;
jcharArray array = (*env)->NewByteArray(env, size);
(*env)->SetCharArrayRegion(env, array, 0, size,
(const jchar *) descriptor->wData);
return array;
}