com.pi4j.plugin.linuxfs.provider.i2c.LinuxFsI2C Maven / Gradle / Ivy
Show all versions of pi4j-plugin-linuxfs Show documentation
package com.pi4j.plugin.linuxfs.provider.i2c;
/*-
* #%L
* **********************************************************************
* ORGANIZATION : Pi4J
* PROJECT : Pi4J :: PLUGIN :: LinuxFS I/O Providers
* FILENAME : PiGpioI2C.java
*
* This file is part of the Pi4J project. More information about
* this project can be found here: https://pi4j.com/
* **********************************************************************
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.*
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
* #L%
*/
import com.pi4j.io.i2c.I2C;
import com.pi4j.io.i2c.I2CBase;
import com.pi4j.io.i2c.I2CConfig;
import com.pi4j.io.i2c.I2CProvider;
import com.pi4j.plugin.linuxfs.util.SystemUtil;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.util.Objects;
/**
* PiGpioI2C class.
*
* @author Robert Savage (http://www.savagehomeautomation.com)
* @version $Id: $Id
*/
public class LinuxFsI2C extends I2CBase implements I2C {
private final LinuxFsI2CBus i2CBus;
/**
* Constructor for PiGpioI2C.
*
* @param provider
* a {@link I2CProvider} object.
* @param config
* a {@link I2CConfig} object.
*/
public LinuxFsI2C(LinuxFsI2CBus i2CBus, I2CProvider provider, I2CConfig config) {
super(provider, config, i2CBus);
this.i2CBus = i2CBus;
}
// -------------------------------------------------------------------
// RAW DEVICE WRITE FUNCTIONS
// -------------------------------------------------------------------
/**
* {@inheritDoc}
*/
@Override
public int write(byte b) {
return this.i2CBus.execute(this, file -> {
file.write(b);
return 1;
});
}
/**
* {@inheritDoc}
*/
@Override
public int write(byte[] data, int offset, int length) {
Objects.checkFromIndexSize(offset, length, data.length);
return this.i2CBus.execute(this, file -> {
file.write(data, offset, length);
return length;
});
}
// -------------------------------------------------------------------
// RAW DEVICE READ FUNCTIONS
// -------------------------------------------------------------------
/**
* {@inheritDoc}
*/
@Override
public int read() {
return this.i2CBus.execute(this, RandomAccessFile::read);
}
/**
* {@inheritDoc}
*/
@Override
public int read(byte[] buffer, int offset, int length) {
Objects.checkFromIndexSize(offset, length, buffer.length);
return this.i2CBus.execute(this, file -> file.read(buffer, offset, length));
}
// -------------------------------------------------------------------
// DEVICE REGISTER WRITE FUNCTIONS
// -------------------------------------------------------------------
/**
* {@inheritDoc}
*/
@Override
public int writeRegister(int register, byte b) {
return write((byte) register, b);
}
/**
* {@inheritDoc}
*/
@Override
public int writeRegister(int register, byte[] data, int offset, int length) {
Objects.checkFromIndexSize(offset, length, data.length);
byte[] tmp = new byte[length + 1];
tmp[0] = (byte) register;
System.arraycopy(data, offset, tmp, 1, length);
return write(tmp);
}
/**
* {@inheritDoc}
*/
@Override
public int writeRegister(byte[] register, byte[] data, int offset, int length) {
Objects.checkFromIndexSize(offset, length, data.length);
byte[] tmp = new byte[length + register.length];
System.arraycopy(register,0, tmp, 0, register.length);
System.arraycopy(data, offset, tmp, register.length, length);
int rc = write(tmp);
return (rc - register.length); // do not include the register bytes as what was written...
}
// -------------------------------------------------------------------
// DEVICE REGISTER READ FUNCTIONS
// -------------------------------------------------------------------
/**
* {@inheritDoc}
*/
@Override
public int readRegister(int register) {
byte reg[] = new byte[1];
reg[0] = (byte) (register & 0xff);
byte buffer[] = new byte[1];
this.readRegister(reg, buffer,0,buffer.length);
int rVal = buffer[0] & 0xff;
return rVal;
}
/**
* {@inheritDoc}
*/
@Override
public int readRegister(int register, byte[] buffer, int offset, int length) {
Objects.checkFromIndexSize(offset, length, buffer.length);
byte reg[] = new byte[1];
reg[0] = (byte) (register & 0xff);
int rCode = this.readRegister(reg, buffer, offset, length);
return rCode;
}
/**
* {@inheritDoc}
*
* This function uses the IOCTL interface to the LinuxFS. This
* is required so the I2C transaction uses an I2C RESTART.
* The following details explain creating the ByteBuffers used
* to create the 'C" structures for the IOCTL.
* i2c_msg: The space *buf will be used to set a pointer to the data buffer.
* This pointer must be aligned to the machines 4 or 8 byte alignment.
*
*
* This alignment is accomplished when the pointer is 'put' into the
* ByteBuffer
*
*
*
*- struct i2c_msg {
* - __u16 addr;
* - __u16 flags;
* - __u16 len;
* - __u8 *buf; wordSize
* - u8 buffer
* - };
*
*
* The ioctl command is I2CConstants.I2C_RDWR, this command requires
* two i2c_msg entries.
*
* The following describes the ByteBuffer, ioctlData, contents:
*
*
* - two byte address entry one
* - two byte len entry one
* - Possible padding for alignment
* - word size area for pointer to write data buffer
* - two byte address entry two
* - two byte flags entry two
* - two byte len entry two
* - Possible padding for alignment
* - word size area for pointer to read data buffer
* - Bytes required to contain write buffer contents
* - Bytes required to contain read data buffer
*
*
* There is a second byte buffer, offsets, this specifies the
* ByteBuffer offset of any pointer paired with the ByteBuffer offset
* of the data pointed to.
*
* This ByteBuffer contents
*
*- ByteBuffer position start of pointer to write data buffer
*- ByteBuffer position start of write buffer contents
*- ByteBuffer position start of pointer to read data buffer
* - ByteBuffer position start of read buffer contents
*
*
*/
@Override
public int readRegister(byte[] register, byte[] buffer, int offset, int length) {
Objects.checkFromIndexSize(offset, length, buffer.length);
// command I2C_RDWR
long command = I2CConstants.I2C_RDWR;
// create byte buffer containing the i2c messages
// address,flags, number of bytes data, pointer
// First message to write device register
short deviceAddr = (short) (this.config.device()& 0xff);
short writeFlags = (short) (I2CConstants.I2C_SMBUS_WRITE & 0xff);
short writeLength = (short) register.length;
// two pointers will be used so 2 pairs of offset entries
IntBuffer offsets = IntBuffer.allocate(4);
// create ByteBuffer, load with the write details Matches i2c provider
ByteBuffer ioctlData = ByteBuffer.allocate(2048);
// Ensures Pi BCM little_endian
ioctlData.order(ByteOrder.nativeOrder());
ioctlData.putShort(deviceAddr);
ioctlData.putShort(writeFlags);
ioctlData.putShort(writeLength);
// Before creating the pointer entry space, see if we are properly aligned
int wrtAlignValue = ioctlData.position()%SystemUtil.getWordSize();
// test if current position is less than word size, if less move position to word boundary
// If greater than word size set position to next word boundary
if(ioctlData.position() > 8) & 0xff);
byte buff[] = new byte[2];
word = (buff[1] << 8) | buff[0];
return word;
}
}