Sunday, October 6, 2013

Using Java & JNA to Access an I2C Device on a Beaglebone Black

Having gotten Java 7 installed on my Beaglebone Black, I wanted to find a way to access an I2C device from a Java program.  To keep things simple, I used a TMP102 temperature sensor from Sparkfun.  I started looking into JNI, but I decided to try JNA to access a simple C library to read the TMP102.

I downloaded the 2 JAR files for JNA (jna.jar & jna-platform.jar) from Git Hub and put them in the /usr/share/java directory.

Note (07/02/2014): I am having trouble with this under Java 8.  The code compiles, but it throws the exception NoClassDefFoundError: com/sun/jna/Library, even though the JAR files are included in my classpath.


C Library


The header file for the C library (tmp102.h) consists of a single line declaring the only method in this example:

extern int getTempC();

Here is the code for the library that will compiled into a .so file.

Note that the method returns an integer.  I wanted to used a float or a double, but I found that JNA did not return the correct values.  The values returned were completely nonsensical.  This is apparently related to differences between software and hardware float support. When I tried to return the data from the sensor to the Java program as a char */string, the result was a segment fault.  So, I decided to multiply the reading by 1000 and return the result as an integer (that the Java program can divide to get the temperature). 

#include <stdio.h>
#include <fcntl.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
#include "tmp102.h"

int getTempC() {
        int devHandle;
        int readBytes;
        char b[2];
        // initialize buffer
        b[0] = 0x00;
        int devI2CAddr = 0x48;
        // open device on /dev/i2c-1
        if ((devHandle = open("/dev/i2c-1", O_RDWR)) < 0) {
                printf("Error: Couldn't open device! %d\n", devHandle);
                return 1;
        }
        // connect as i2c slave
        if (ioctl(devHandle, I2C_SLAVE, devI2CAddr) < 0) {
                printf("Error: Couldn't find device on address!\n");
                return 1;
        }
        // begin transmission and request acknowledgement
        readBytes = write(devHandle, b, 1);
        if (readBytes != 1)
        {
                printf("Error: No ACK-Bit, couldn't establish connection!");
        }
        else
        {
                // read response
                readBytes = read(devHandle, b, 2);
                if (readBytes != 2)
                {
                        printf("Error: Received no data!");
                }
                else
                {
                        float t = (((b[0] << 8) | b[1]) >> 4) * 0.0625;
                        return (int)(t*1000);
                }
        }
        // close connection and return
        close(devHandle);
        return 1;
}


The following command compiles the code to a shared library (tmp102.so).

gcc tmp102.c -o tmp102.so -shared

Copy the resulting tmp102.so file to the directory with the JNA JAR files (/usr/share/java).


Java Code


The first part of the Java code is the interface file (Tmp102Library.java):

import com.sun.jna.Library;
import com.sun.jna.Native;

public interface Tmp102Library extends Library {
   Tmp102Library INSTANCE = (Tmp102Library) Native.loadLibrary("tmp102.so",
        Tmp102Library.class);
   int getTempC();
}

Here is the Java code for the program that uses the interface to access the library via JNA:

import com.sun.jna.Library;

public class tmp102 {
        public static void main(String[] args) {
                System.setProperty("jna.library.path","/usr/share/java");
                try {
                        float temp = Tmp102Library.INSTANCE.getTempC()/1000F;
                        System.out.println("Temp: " + Float.toString(temp));
                } catch(Exception e) {
                        e.printStackTrace();
                }
        }

}


The following commands compile the Java files:

javac -cp /usr/share/java/jna-4.0.0.jar:/usr/share/java/jna-platform-4.0.0.jar Tmp102Library.java

javac -cp /usr/share/java/jna-4.0.0.jar:/usr/share/java/jna-platform-4.0.0.jar:. tmp102.java

The following command runs the program:

java -cp /usr/share/java/jna-4.0.0.jar:/usr/share/java/jna-platform-4.0.0.jar:. tmp102

No comments:

Post a Comment