May 202011
 
I worked on a solution to the problem and succeeded in getting the ThinkGear class working from the default package with reflection. This was my first attempt at using the reflection APIs and while the solution was very straight forward, it is very ugly and time consuming. It begins with loading the class from the default package:

private static Class thinkgear = null;
static {
try {
thinkgear = ClassLoader.getSystemClassLoader().loadClass("ThinkGear");
} catch(ClassNotFoundException e) {
e.printStackTrace();
System.exit(-1);
}
}

I then used this object to pass calls to the various methods:

public static double GetValue(int connectionId, int dataType) {
try {
return (Integer) thinkgear.getMethod("GetValue", int.class, int.class)
.invoke(null, connectionId, dataType);
} catch(IllegalAccessException e) {
e.printStackTrace();
System.exit(-1);
}
return 0;
}

This basically makes a wrapper class which passes all functions straight through to the calling program, and crashes the program out if the methods or the class don’t exist. This makes the errors that normally prevent compiling run-time errors, so it was important to avoid typos. I could have checked whether the method existed in the code, but since I was hard coding it to pass through a known API, I wanted to avoid the extra overhead. I wasn’t pleased with this solution, but it got me up and running until NeuroSky got back to me.
NeuroSky responded surprisingly quickly to my request. I received a solution within two business days from Neraj in their support team:
Dear David,
Thank you for contacting us. We are aware of the issue you are mentioning. Attached is a DLL and .java header that puts the “ThinkGear.java” class in the “com.neurosky.thinkgear” package. Please note that this is a pre-release version, so it has not yet been fully tested.
Please let me know if this helps. Thank you,
Neraj
It most certainly did help me! Thank you, Neraj!
What Neraj included was tgcd.v22.110304.zip, containing a new thinkgear.dll, an updated C header and ThinkGear.java with the appropriate package declaration. I dropped these into my project in place of my reflection based class and everything went beautifully! I’m now up and running without the reflection work around and the use of the driver is proving to be a very straightforward process, as I had originally hoped!
Since the library passes the C functions directly into Java, there are a few things that I would like to do to improve the ease of use:
As C libraries, the API is very procedurally oriented, requiring an identifier passed to each call. I would like to wrap this identifier inside an object to avoid the problems this can typically lead to.
  1. Resources must be explicitly freed to avoid memory leaks. This can be handled through dispose and finalize methods, but weak references may be more applicable, as NeuroSky headsets seem to qualify as “scarce resources”.
  2. The collections of related defined values in the API (e.g. BUAD_9600, BAUD_57600, etc.) would be safer/easier to use as enumerations.
  3. As this product appears as a serial port, detecting devices by scanning the COM ports should be packaged in with the basic functions.
  4. The creation of a read thread and data buffering should be hidden away, much as the creation of threads is hidden from users of the Swing API.
I’ll try to resolve a few of these issues as I build out my first test application. I’ll post up my progress Monday night, though I’ll likely leave most of the above goals for a later post.

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(required)

(required)

This site uses Akismet to reduce spam. Learn how your comment data is processed.