Using Java JNA for control of I2C bus

I am using JNA library to call native C on a BeagleBone for communication to the I2C bus. Communication to I2C bus requires low level file actions such as open, ioctl, close, read, and write. I am able to open the bus file no problem but I cannot get ioctl to work. If I could get this working I believe I would have I2C function working on either BeagleBone Black or Raspberry Pi. Here is my code

`

import java.io.IOException;

import java.util.Arrays;

import java.util.List;

import com.sun.jna.*;

public class Main {

static Linux_C_lib_DirectMapping libC = new Linux_C_lib_DirectMapping();

public static int O_RDWR = 0x00000002;

public static void main(String[] args) {

new Main();

}

public Main(){

System.setProperty(“jna.library.path”,"/usr/lib/cgi-bin/jna");

//Open I2C Bus 1 file

String fileName = “/dev/i2c-1”;

int file = libC.open(fileName, O_RDWR);

if(file<0){

System.out.println(“Error opening file”);

return;

}else{

System.out.println(“File open for reading and writing”);

}

//Print out returned value from file open

System.out.println(file);

//initiate connection to chip. I2C chip I am using mounts on 0x21

int[] addr = {0x21};

int i2c_slave = 0x0703;

//This is what fails. I always get -1 back.

int iocntl = libC.ioctl(file, i2c_slave, addr);

//Print returned value after ioctl action

System.out.println("fcntl = "+iocntl);

if(iocntl<0){

System.out.println(“error on libC.ioctl”);

libC.close(file);

return;

}else{

System.out.println(“ioctl complete”);

}

//Initialize communication to chip

byte[] buf = {0,0};

if(libC.write(file, buf, 2) != 2){

System.out.println(“error writing”);

libC.close(file);

return;

}else{

System.out.println(“I2C chip initialized”);

}

while(true){

if(turnOnAllRelays(file)){

try {

Thread.sleep(1000);

turnOffAllRelays(file);

Thread.sleep(1000);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

public boolean turnOnAllRelays(int file){

byte[] buffer = {0xA,0xF};

if(libC.write(file, buffer, 2) != 2){

System.out.println(“all relays on”);

return true;

}else{

System.out.println(“failed to turn all relays on”);

libC.close(file);

return false;

}

}

public boolean turnOffAllRelays(int file){

byte[] buffer = {0xA, 0x0};

if(libC.write(file, buffer, 2) != 2){

System.out.println(“all relays off”);

return true;

}else{

System.out.println(“failed to turn all relays off”);

libC.close(file);

return false;

}

}

public interface Linux_C_lib extends com.sun.jna.Library {

public long memcpy(int[] dst, short[] src, long n);

public int memcpy(int[] dst, short[] src, int n);

public int pipe(int[] fds);

public int tcdrain(int fd);

public int fcntl(int fd, int cmd, int arg);

public int ioctl(int fd, int cmd, int[] arg);

public int open(String path, int flags);

public int close(int fd);

public int write(int fd, byte[] buffer, int count);

public int read(int fd, byte[] buffer, int count);

public long write(int fd, byte[] buffer, long count);

public long read(int fd, byte[] buffer, long count);

public int select(int n, int[] read, int[] write, int[] error, timeval timeout);

public int poll(int[] fds, int nfds, int timeout);

public int tcflush(int fd, int qs);

public void perror(String msg);

public int tcsendbreak(int fd, int duration);

static public class timeval extends Structure {

public NativeLong tv_sec;

public NativeLong tv_usec;

@Override

protected List getFieldOrder() {

return Arrays.asList(//

“tv_sec”,//

“tv_usec”//

);

}

public timeval(jtermios.TimeVal timeout) {

tv_sec = new NativeLong(timeout.tv_sec);

tv_usec = new NativeLong(timeout.tv_usec);

}

}

}

public static class Linux_C_lib_DirectMapping implements Linux_C_lib {

native public long memcpy(int[] dst, short[] src, long n);

native public int memcpy(int[] dst, short[] src, int n);

native public int pipe(int[] fds);

native public int tcdrain(int fd);

native public int fcntl(int fd, int cmd, int arg);

native public int ioctl(int fd, int cmd, int[] arg);

native public int open(String path, int flags);

native public int close(int fd);

native public int write(int fd, byte[] buffer, int count);

native public int read(int fd, byte[] buffer, int count);

native public long write(int fd, byte[] buffer, long count);

native public long read(int fd, byte[] buffer, long count);

native public int select(int n, int[] read, int[] write, int[] error, timeval timeout);

native public int poll(int[] fds, int nfds, int timeout);

native public int tcflush(int fd, int qs);

native public void perror(String msg);

native public int tcsendbreak(int fd, int duration);

static {

try {

Native.register(“c”);

System.out.println(“registered to c library”);

} catch (Exception e) {

e.printStackTrace();

}

}

}

}

`

While the open call does work through JNA calling ioctl always returns -1. I am not familiar with this function since I have not done much C programming but accordingly to the example code from Linux here it means the function failed:http://elinux.org/Interfacing_with_I2C_Devices

I should note that I got the idea to use JNA for these functions from the developer of purjavacomm who seemed to use it successfully.

Anyone have any ideas where I am going wrong here?

What is int i2c_slave = 0x0703; Is it a command/request?
man ioctl.h shows it should be a macro.
http://man7.org/linux/man-pages/man2/ioctl.2.html

It may be because i2c_slave is an int and ioctl() requires an unsigned long.

Hi @cody,

This page is the Linux documentation on communicating to I2C devices on linux ARM processors. All examples are in standard C so I have to use JNA to make native C function calls. JNA does some conversion I believe because the ioctl JNA function looks like this:

`
public int ioctl(int fd, int cmd, int[] arg);

`
It does not take longs as arguments. Any ideas?