All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ociweb.pronghorn.iot.i2c.impl.I2CNativeLinuxBacking Maven / Gradle / Ivy

package com.ociweb.pronghorn.iot.i2c.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ociweb.pronghorn.iot.i2c.I2CBacking;

/**
 * Native I2C backing implementation for a GrovePi using ioctl.h.
 *
 * @author Brandon Sanders [[email protected]]
 */
public class I2CNativeLinuxBacking implements I2CBacking {

    private static final byte[] EMPTY = new byte[]{};

    private static final Logger logger = LoggerFactory.getLogger(I2CNativeLinuxBacking.class);

    //Highest value for an I2C address. TODO: Is this the right value?
    private static final int I2C_MAX_ADDRESSES = 0x77;

    //Native C library.
    private static final UnixIoctlLib c = UnixIoctlLib.instance;

    private boolean configured = false;

    //Native I2C file handle.
    private int i2cFile = -1;

    //Most recent address we've handled in order to restrict duplicat IOCTL calls.
    private byte lastAddress = (byte) -127;

    /**
     * Configures I2C to communicate with the specified byte address.
     *
     * @param address Byte address of the I2C device to configure for.
     */
    private boolean ensureI2CDevice(byte address) {
        if (lastAddress == address) {
            return true;
        }
        return checkNewAddress(address);
    }

    private boolean checkNewAddress(byte address) {
        if (address > 0 && address <= I2C_MAX_ADDRESSES) {
            /**
             * IOCTL will return -1 if it fails for any reason.
             */
            if (c.ioctl(i2cFile, UnixIoctlLib.I2C_SLAVE_FORCE, address) >= 0) {
                lastAddress = address;
                logger.debug("IOCTL configured for I2C device at {}", address);
                return true;
            } else {
                throw new RuntimeException(
                        "Could not configure IOCTL for I2C device at 0x" + Integer.toHexString(address));
            }
        } else {
            throw new RuntimeException(
                    "I2C Device 0x" + Integer.toHexString(address) + " is outside of the possible I2C address range.");
        }
    }

    @Override
    public I2CNativeLinuxBacking configure(byte bus) {
        if (configured) {
            throw new IllegalStateException("Bus is already configured.");
        } else {
            configured = true;
        }

        String device = "/dev/i2c-" + bus;

        //Get the I2C file.
        i2cFile = c.open(device, UnixIoctlLib.O_RDWR);

        //Make sure it worked....
        if (i2cFile < 0) {
            logger.debug("unable to open {}", device);
            throw new RuntimeException("Could not open " + device);
        } else {
            logger.debug("Successfully opened {}", device);
        }

        //Close the file when the application shuts down.
        Runtime.getRuntime().addShutdownHook(new Thread() {
            public void run() {
                if (i2cFile >= 0) {
                    c.close(i2cFile);
                }
            }
        });

        return this;
    }

    @Override
    public byte[] read(byte address, byte[] target, int bufferSize) {
        if (!configured) {
            throw new IllegalStateException("Bus is not configured yet.");
        }

        //Check if we need to load the address into memory.
        if (ensureI2CDevice(address)) {
            int result = c.read(i2cFile, target, bufferSize);
            if (result != bufferSize) {//did not read so flag this as an error
                target[0] = -2;
            }
            return target;
        } else {
            return EMPTY;
        }
    }

    @Override
    public boolean write(byte address, byte[] message, int length) {
        if (!configured) {
            throw new IllegalStateException("Bus is not configured yet.");
        }

        assert (length >= 0);
        //System.out.println("write to address:"+ Integer.toHexString(address));

        //Check if we need to load the address into memory.
        ensureI2CDevice(address); //throws on failure
        return -1 != c.write(i2cFile, message, length);

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy