
net.freeutils.scrollphat.JNADevDevice Maven / Gradle / Ivy
/*
* Copyright © 2016 Amichai Rothman
*
* This file is part of JScrollPhat - the Java Scroll pHAT package.
*
* JScrollPhat is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* JScrollPhat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with JScrollPhat. If not, see .
*
* For additional info see http://www.freeutils.net/source/jscrollphat/
*/
package net.freeutils.scrollphat;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import com.sun.jna.NativeLibrary;
import com.sun.jna.Platform;
/**
* A device implementation that uses the /dev/i2c-* device interface
* for the I2C communications with the device, and JNA for ioctl calls.
*
* This implementation requires the i2c-dev kernel module to be loaded,
* and the JNA library to be available on the classpath, including its
* native libjnidispatch.so library which can also be specified using
* the java.library.path system property or LD_LIBRARY_PATH environment
* variable.
*
* The implementation works with the current Sun/Oracle JVM on Linux,
* but may not work on other systems.
*
* @see
* Linux kernel I2C Documentation
*/
public class JNADevDevice extends Device {
protected FileOutputStream out;
protected byte[] buf = new byte[257];
/**
* Returns the native file descriptor associated with the Java file descriptor.
*
* @param fd the Java file descriptor
* @return the native file descriptor associated with the Java file descriptor
* @throws IOException if an error occurs
*/
protected int getNativeFileDescriptor(FileDescriptor fd) throws IOException {
try {
Field field = FileDescriptor.class.getDeclaredField("fd");
field.setAccessible(true);
return (Integer)field.get(fd);
} catch (Exception e) {
throw new IOException("error getting native file descriptor: " + e);
}
}
/**
* Invokes the native ioctl function.
*
* @param fd the file descriptor
* @param request the ioctl request type constant
* @param data the data for the request
* @throws IOException if an error occurs
*/
protected void ioctl(int fd, int request, int data) throws IOException {
try {
Object[] args = { fd, request, data };
NativeLibrary library = NativeLibrary.getInstance(Platform.C_LIBRARY_NAME);
int res = library.getFunction("ioctl").invokeInt(args);
if (res != 0)
throw new IOException("ioctl returned " + res);
} catch (Throwable t) {
throw new IOException("error invoking ioctl: " + t);
}
}
@Override
protected Device openImpl(int busNumber, int address) throws IOException {
out = new FileOutputStream("/dev/i2c-" + busNumber);
int fd = getNativeFileDescriptor(out.getFD());
ioctl(fd, 0x0703, address); // I2C_SLAVE to set device address
return this;
}
@Override
protected void closeImpl() throws IOException {
if (out != null) {
reset();
out.close();
out = null;
}
}
@Override
protected void writeImpl(byte register, int data) throws IOException {
buf[0] = register;
buf[1] = (byte)data;
out.write(buf, 0, 2); // register + data must be written together
}
@Override
protected void writeImpl(byte register, byte[] data, int offset, int length) throws IOException {
if (length >= buf.length)
buf = new byte[length + 1];
buf[0] = register;
System.arraycopy(data, offset, buf, 1, length);
out.write(buf, 0, length + 1); // register + data must be written together
}
}