A schema has emerged to describe what is now commonly referred to as an app. The table below gives a high level overview for this scheme.
There is a compelling argument for a Web application that is platform independent and has full unrestricted access to the Operating System and Hardware. Hybrid apps attempt this to various degrees of success and internet giant Facebook have just released a technology for iOS React JS that effectively achieves this. Ports for Android are expected to follow. However as developers we need a diverse toolkit to implement the challenge of application design. The domain of the application extends beyond the Mobile to Robotics, Geomatics and in particular interfacing the embedded system, Mobile or otherwise, with external resources such as advanced Electromagnetic technologies in the Infrared and above, Optical Communications for example.
That interface between the mobile of embedded application is the subject of this article. Here we look at the Java tool JNA and how you can use it to construct a USB interface. First we will illustrate the principles by accessing a native library interface for an embedded video player component, the source code can be found here. Then we will create a template for a USB driver.
In a previous article (link Java Build tools) we saw how we can port JavaFX gui applications to Android and iOS this will keep us developing native code bindings until the much anticipated React JS port for Android materialises.
Java Native Application Architecture
For a Native or Hybrid Application, Java, apart from the GUI thread would be used for communication, processor allocation, task management, sequencing, fault detection, handling, and logging. Then for application tasks that require computational heavy lifting we would make system level calls from the Java layer into the native layer to system or kernel libraries, third party libraries, and accessing the GPU for Video. Another common and important system level call for Mobile apps is to access the USB port.
We make these calls using low-level packages like the Java Native Interface (JNI). JNI is the fastest, but is complex and this complexity can be error prone for beginning developers. Java Native Access (JNA) is the slowest, however JNA is easy to use and is often more platform independent which can be critical for Mobile.
If the speed of JNA is an issue for example when high throughput is required as in processing streaming data then
BridJ and the Simplified Wrapper and Interface Generator (SWIG) (very advanced) are the appropriate options. BridJ is much easier to use and critically can be used without external native libraries on various hardware and operating system platforms. SWIG is more difficult but the extra overhead in developer time is faster code that allows a native library to be compiled for any target.
A GPU can be invoked from Java. This is achieved via a Java library such as JavaCL that invokes an underlying native OpenCL interface to the GPU. Thus a Java application can never be faster than a C application that can utilize the native OpenCL. JavaCL and BridJ are developed by the same group and hence highly compatible. BridJ provides an interface to JavaCL that performs well. Tests using GPU optimized Fast Fourier Transform (FFT) show it takes Java slightly longer to run computations than in C however the difference will be insignificant for most applications.
A Native Application Toolset and Workflow
At the most practical level in our application we often only want to use a Native library. In Java or a JVM based language such as Groovy or Scala it is also often the case that the wrapper has been made available as a dependency in a jar for example. We can bind Windows dll or Linux library using the static methods found in the JNA NativeLibary class. This will always follow the same basic syntax.
1. Add a path to search for the specified library, ahead of any system paths.
NativeLibrary.addSearchPath(<lib name>, <lib path>);
2. Load a library interface from the given shared library, providing the explicit interface
class and a map of options for the library.
<lib class> <instance = (<lib class>) Native.loadLibrary(<lib name>,<lib class>.class);
Where we would use this syntax and JNA in particular is when we want to call a third party native library for a behaviour not well supported or missing from pure Java. Java has always lacked good media support. Using the VLC native libraries to stream multimedia makes sense and works really well with a clean interface using JNA.
The source code here show how you can directly render frames to a Canvas with VLC. Here you can see an example of the implementation of the syntax outlined in 1 and 2 above.
(Platform.is64Bit() ? "c:/Program Files/VideoLAN/VLC/" : "C:/Program Files (x86)/VideoLAN/VLC"));
Here we are looking for the VLC native library and this syntax highlights one of the major issues that need to be overcome. That is the platform dependence introduced. We can often mitigate this dependence by using code like.
(Platform.is64Bit() ? "c:/Program Files/VideoLAN/VLC/" : "C:/Program Files (x86)/VideoLAN/VLC")
Where we test the architecture and inject the correct library path for the architecture in this case differentiating the path for 32 or 64 bit platforms. We could go further than this with the Platform class methods such as isLinux() or isAndroid().
With the code below we load the VLC native library in order to access a LibVlc reference.
Another useful native library that can boost the power of your Java application is libusb. Many third party applications and hardware devices need to be accessed from or have access to the USB port. We will now go through the steps to bootstrap an application development workflow to create a native binding with JNA and BridJ for libusb.
Workflow to produce the native bindings from the libusb source code.
1. Build the source for the JNAerator native bindings generator I have done this if you want to skip this you can find everything for the next steps in the source here
2. Then in the directory use the command line to create the native bindings for the libusb source. It is already available here in the application source and in a terminal in this directory you issue the command.
java -jar jnaerator.jar -library libusb libusb.h -o . -v -noJar -noComp
Now you will have a LibusbLibrary.java top level class. Copy the generated package code to the main source and create a simple test to check you have something functional.
When you run this code you will see an error related to some missing abstract methods. In the generated source LibusbLibrary.java starting at line 700 and below you wull see a series of abstract inner classes. The JNAerator sadly has failed to generate the Callback abstract methods the BridJ code need to successfully bind to the interfaces hence the error. In the main source implementation here you can see the missing lines that resolve the error that is to simply add the missing abstract method definition.
public abstract int apply();
The next error to overcome will be to point your generated library wrapper code to the dll that is to be linked with the java source at runtime A path that resolves to the libusb.dll must be included in the @Library annotation that annotates all the generated source files.
Here is an example using a absolute path for the libusb.dll renamed from the libusb-1.0.dll in the download to avoid package naming conflicts in the generated source.
You could also try a relative path to make the code more portable like
And for deploying in a uber jar
Testing the Generated Library
By convention a USB driver when queried for its version returns a pointer to the version data, Now we can run the static calls
JNAerator is a free tool and its documentation is poor to nonexistent. There are many excellent commercial products for this workflow and he cost can be included in a well-funded application development shop.
To summarise the workflow.
1 Obtain the source for the native library.
2 Run the JNAerator tool on the source as outlined above.
3 Move the generated java code into the main source of your application
4 Test and debug the occasional errors in the generated source for the library.
The class DiscoverUSBHub.java form the source code can be used to debug your usb ports when working with the generated library, it will dump information about a connected usb device and its configuration. It uses the javax extension package usb4java for usb. It is based on the same native libusb 1.0 library we are generating bindings for and uses Java NIO buffers for data exchange between libusb and Java.
The classes JnaLibraryDemo.java and JnaRegisterDemo.java demonstrate the syntax for accessing kernel level system drivers.
Using the JNAeratortool to generate JNA bindings for Native libraries compatible with BridJ
Is difficult but can often be the essential skill that allows a project to progress around a blocking issue. Native libraries offer improvements in speed and hardware access, and allow applications to access a range of critical resources for cpu intensive tasks with real time service guarantees in high end medical, industrial and military applications.
It is hoped the source code can help a developer new to accessing native libraries and source code with JNA and BridJ, bootstrap their developer skillset particularly with respect to the USB interface.