These tutorials explains how to use foreign (as in non-Java) code in your Reactive Block application. Another term for foreign is native, because embedding non-Java code usually introduces platform and portability issues.
Make sure you have read the intro foreign-code-intro to prepare what you need for this tutorial.
Download the tutorial named “(Level 3) Foreign code v4: JNI”
Contrary to the JNA and BridJ tutorials where we take C/C++ and generate Java code from it, with JNI we work the opposite way by converting a Java file to a C header file.
Look at the project in the Package Explorer view. You will see the src directory. Inside there you will
WatchdogInterface.java. Note package definition, you will need it later.
You should also look at
wd-jni.h inside the solution directory. That is the file that contains the C library we are going to interface.
The functions in Java that we are going to make in C are:
public native static void setWdDeviceName(String deviceName);: Set filename of watchdog device.
public native static String getWdErrorMessage();: Gets most recent error message. The message is allocated in C heap and copied into a Java String when returned.
public native static void clearWdErrorMessage();: Clear last error message and release memory.
public native static int enableWd(int timeout);: Enable watchdog, parameter is timeout value.
public native static int getWdRemainingTime();: Returns remaining time until watchdog fires, this is similar to the stupid countdown timer on all atomic bombs in old James Bond movies.
public native static int getWdTimeout();: Return current timeout value.
public native static int disableWd();: Disable watchdog
public native static int heartbeatWd();: Send heartbeat to reset watchdog counter.
public native static void closeWd();: Close files and release memory.
All int return values < 0 indicates error.
Note that all the functions have a C counterpart in
The block is shown in the image above and with exception of the init and stop pin, all functions the same as in the Java library. In addition we have added a state check to query if watchdog is enabled.
We will take a closer look at some functions:
Stringas parameters and return values, but must convert them in the C-code later.
stop()method closes file and releases memory in the C-code.
Execute the following steps to generate the C header file we will use for to make the C-code
mkdir -p com/bitreactive/tutorial/foreigncode/jni/wdjni/
WatchdogInterface.javafrom your computer to to
mv WatchdogInterface.java com/bitreactive/tutorial/foreigncode/jni/wdjni/
Now comes the hard part with JNI, we need to make the C-Code that can be compiled and linked to become the wanted shared library.
Different from BridJ and JNA all memory allocation and deallocation takes places on the (native) C side.
Each call will have two parameters in addition the the parameters defined in the function itself, see the example below where the functions
getWdErrorMessage() are highlighted both in Java and in the C header file.
JNIenv *env: This is interface to the Java VM. It includes all of the functions necessary to interact with the JVM and to work with Java objects.
jclass *class: This is a reference to the object where the native method has been declared.
You need to implement all all functions in the generated C header file.
More about JNI here.
A ready made solution is available in the folder solution in the project you downloaded earlier.
Make sure to not overwrite your own work in
See Part 1 for download and transfer instructions.
Once you have downloaded these three or four files you can generate the shared library with these two commands:
chmod +x buildall.sh
The header file is generated with
gcc is used to compile and link the shared library.
./buildall.sh is a text file (script) that can be edited. You should look at the contents.
com.bitreactive.tutorial.foreigncode.jna.testwdjni_exe) as Runnable JAR and transfer to your Raspberry-Pi to the same directory as the shared library you generated in part 5.