![JAR search and dependency download from the Maven repository](/logo.png)
com.diozero.api.I2CSMBusInterface Maven / Gradle / Ivy
package com.diozero.api;
/*
* #%L
* Organisation: diozero
* Project: diozero - Core
* Filename: I2CSMBusInterface.java
*
* This file is part of the diozero project. More information about this project
* can be found at https://www.diozero.com/.
* %%
* Copyright (C) 2016 - 2024 diozero
* %%
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
* #L%
*/
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import com.diozero.util.BitManipulation;
/**
* I2C device interface
* Linux SMBus
* interface
*/
public interface I2CSMBusInterface extends DeviceInterface {
int MAX_I2C_BLOCK_SIZE = 32;
int getController();
int getAddress();
ByteOrder getByteOrder();
/**
* Probe this I2C device to see if it is connected
*
* @param mode Probe mode
* @return True if the probe is successful and the device is connected
* @throws RuntimeIOException if an I/O error occurs
*/
boolean probe(I2CDevice.ProbeMode mode) throws RuntimeIOException;
/**
*
* SMBus Quick Command
*
*
* This sends a single bit to the device, at the place of the Rd/Wr bit.
*
*
*
* A Addr Rd/Wr [A] P
*
*
* @param bit The bit to write
* @throws RuntimeIOException if an I/O error occurs
*/
void writeQuick(byte bit) throws RuntimeIOException;
/**
*
* SMBus Receive Byte: i2c_smbus_read_byte()
*
*
* This reads a single byte from a device, without specifying a device register. Some
* devices are so simple that this interface is enough; for others, it is a shorthand if
* you want to read the same register as in the previous SMBus command.
*
*
*
* S Addr Rd [A] [Data] NA P
*
*
* @return The byte data read (note caller needs to handle conversion to unsigned)
* @throws RuntimeIOException if an I/O error occurs
*/
byte readByte() throws RuntimeIOException;
/**
*
* SMBus Send Byte: i2c_smbus_write_byte()
*
*
* This operation is the reverse of Receive Byte: it sends a single byte to a device. See
* Receive Byte for more information.
*
*
*
* S Addr Wr [A] Data [A] P
*
*
* @param data value to write
* @throws RuntimeIOException if an I/O error occurs
*/
void writeByte(byte data) throws RuntimeIOException;
/**
*
* SMBus Read Byte: i2c_smbus_read_byte_data()
*
*
* This reads a single byte from a device, from a designated register. The register is
* specified through the Comm byte.
*
*
*
* S Addr Wr [A] Comm [A] S Addr Rd [A] [Data] NA P
*
*
* @param register the register to read from
* @return data read as byte (note caller needs to handle conversion to unsigned)
* @throws RuntimeIOException if an I/O error occurs
*/
byte readByteData(int register) throws RuntimeIOException;
/**
*
* SMBus Write Byte: i2c_smbus_write_byte_data()
*
*
* This writes a single byte to a device, to a designated register. The register is
* specified through the Comm byte. This is the opposite of the Read Byte operation.
*
*
*
* S Addr Wr [A] Comm [A] Data [A] P
*
*
* @param register the register to write to
* @param data value to write
* @throws RuntimeIOException if an I/O error occurs
*/
void writeByteData(int register, byte data) throws RuntimeIOException;
/**
*
* SMBus Read Word: i2c_smbus_read_word_data()
*
*
* This operation is very like Read Byte; again, data is read from a device, from a
* designated register that is specified through the Comm byte. But this time, the data is
* a complete word (16 bits) in {@link java.nio.ByteOrder#LITTLE_ENDIAN Little Endian}
* order as per the SMBus specification.
*
*
*
* S Addr Wr [A] Comm [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P
*
*
* @param register the register to read from
* @return data read as a signed short in {@link java.nio.ByteOrder#LITTLE_ENDIAN Little
* Endian} byte order
* @throws RuntimeIOException if an I/O error occurs
*/
short readWordData(int register) throws RuntimeIOException;
/**
*
* SMBus Write Word: i2c_smbus_write_word_data()
*
*
* This is the opposite of the Read Word operation. 16 bits of data is written to a
* device, to the designated register that is specified through the Comm byte. Note that
* the data is written in {@link java.nio.ByteOrder#LITTLE_ENDIAN Little Endian} byte
* order as per the SMBus specification.
*
*
*
* S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] P
*
*
* @param register the register to write to
* @param data value to write in {@link java.nio.ByteOrder#LITTLE_ENDIAN Little
* Endian} byte order
* @throws RuntimeIOException if an I/O error occurs
*/
void writeWordData(int register, short data) throws RuntimeIOException;
/**
*
* SMBus Process Call
*
*
* This command selects a device register (through the Comm byte), sends 16 bits of data
* to it, and reads 16 bits of data in return.
*
*
*
* S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A]
* S Addr Rd [A] [DataLow] A [DataHigh] NA P
*
*
* @param register the register to write to / read from
* @param data value to write
* @return the value read
* @throws RuntimeIOException if an I/O error occurs
*/
short processCall(int register, short data) throws RuntimeIOException;
/**
*
* SMBus Block Read: i2c_smbus_read_block_data()
*
*
* This command reads a block of up to 32 bytes from a device, from a designated register
* that is specified through the Comm byte. The amount of data is specified by the device
* in the Count byte.
*
*
*
* S Addr Wr [A] Comm [A]
* S Addr Rd [A] [Count] A [Data] A [Data] A ... A [Data] NA P
*
*
* @param register the register to read from
* @return the data read up to 32 bytes in length
* @throws RuntimeIOException if an I/O error occurs
*/
byte[] readBlockData(int register) throws RuntimeIOException;
/**
*
* SMBus Block Write: i2c_smbus_write_block_data()
*
*
* The opposite of the Block Read command, this writes up to 32 bytes to a device, to a
* designated register that is specified through the Comm byte. The amount of data is
* specified in the Count byte.
*
*
*
* S Addr Wr [A] Comm [A] Count [A] Data [A] Data [A] ... [A] Data [A] P
*
*
* @param register the register to write to
* @param data the data to write (up to 32 bytes)
* @throws RuntimeIOException if an I/O error occurs
*/
void writeBlockData(int register, byte... data) throws RuntimeIOException;
/**
*
* SMBus Block Write - Block Read Process Call
*
*
* SMBus Block Write - Block Read Process Call was introduced in Revision 2.0 of the
* specification.
* This command selects a device register (through the Comm byte), sends 1 to 31 bytes of
* data to it, and reads 1 to 31 bytes of data in return.
*
*
*
* S Addr Wr [A] Comm [A] Count [A] Data [A] ...
* S Addr Rd [A] [Count] A [Data] ... A P
*
*
* @param register the register to write to and read from
* @param txData the byte array from which the data is written (up to 32 bytes)
* @return the data read (up to 32 bytes)
* @throws RuntimeIOException if an I/O error occurs
*/
byte[] blockProcessCall(int register, byte... txData) throws RuntimeIOException;
/*-
* I2C Block Transactions
* ======================
* The following I2C block transactions are supported by the SMBus layer and
* are described here for completeness. They are *NOT* defined by the SMBus
* specification. I2C block transactions do not limit the number of bytes
* transferred but the SMBus layer places a limit of 32 bytes.
*/
/**
*
* I2C Block Read: i2c_smbus_read_i2c_block_data()
*
*
* This command reads a block of up to 32 bytes from a device, using the specified
* register address.
*
*
* I2C commands:
*
*
* S Addr Wr [A] Comm [A]
* S Addr Rd [A] [Data] A [Data] A ... A [Data] NA P
*
*
* @param register the register to read from
* @param buffer the buffer to read the data into, the buffer length specifies the
* number of bytes to read up to a maximum of 32 bytes
* @return the number of bytes actually read
* @throws RuntimeIOException if an I/O error occurs
*/
int readI2CBlockData(int register, byte[] buffer) throws RuntimeIOException;
/**
*
* I2C Block Write: i2c_smbus_write_i2c_block_data()
*
*
* The opposite of the Block Read command, this writes up to 32 bytes of data to a device,
* to the specified register address.
*
*
*
*
* S Addr Wr [A] Comm [A] Data [A] Data [A] ... [A] Data [A] P
*
*
*
* Note that command lengths of 0, 2, or more bytes are supported as they are
* indistinguishable from data.
*
*
* @param register the register to write to
* @param data values to write with a maximum length of 32 bytes
* @throws RuntimeIOException if an I/O error occurs
*/
void writeI2CBlockData(int register, byte... data) throws RuntimeIOException;
//
// Utility methods
//
/**
* Probe this I2C device using {@link I2CDevice.ProbeMode#AUTO Auto} probe mode
*
* @return True if the probe is successful
* @throws RuntimeIOException if an I/O error occurs
*/
default boolean probe() throws RuntimeIOException {
return probe(I2CDevice.ProbeMode.AUTO);
}
/**
*
* SMBus Read Word Swapped: i2c_smbus_read_word_swapped()
*
*
* This operation is very like Read Byte; again, data is read from a device, from a
* designated register that is specified through the Comm byte. But this time, the data is
* a complete word (16 bits). Note this is the convenience function for reads where the
* two data bytes are the other way around (not SMBus compliant, but very popular.)
*
*
*
* S Addr Wr [A] Comm [A] S Addr Rd [A] [DataHigh] A [DataLow] NA P
*
*
* @param register the register to read from
* @return data read as a signed short in {@link java.nio.ByteOrder#BIG_ENDIAN Big Endian}
* byte order
* @throws RuntimeIOException if an I/O error occurs
*/
default short readWordSwapped(int register) throws RuntimeIOException {
short value = readWordData(register);
return (short) (((value & 0x00ff) << 8) | ((value & 0xff00) >> 8));
}
/**
*
* SMBus Write Word Swapped: i2c_smbus_write_word_swapped()
*
*
* This is the opposite of the Read Word operation. 16 bits of data is written to a
* device, to the designated register that is specified through the Comm byte. Note that
* this is the convenience function for writes where the two data bytes are the other way
* around (not SMBus compliant, but very popular.)
*
*
*
* S Addr Wr [A] Comm [A] DataHigh [A] DataLow [A] P
*
*
* @param register the register to write to
* @param data value to write in {@link java.nio.ByteOrder#BIG_ENDIAN Big Endian} byte
* order
* @throws RuntimeIOException if an I/O error occurs
*/
default void writeWordSwapped(int register, short data) throws RuntimeIOException {
short swapped = (short) (((data & 0x00ff) << 8) | ((data & 0xff00) >> 8));
writeWordData(register, swapped);
}
/**
* Utility method that simply casts the int data parameter to byte and calls
* {@link I2CDevice#writeByteData(int, byte)}
*
* @see I2CDevice#writeByteData(int, byte)
*
* @param register the register to write to
* @param data value to write
* @throws RuntimeIOException if an I/O error occurs
*/
default void writeByteData(int register, int data) throws RuntimeIOException {
writeByteData(register, (byte) data);
}
/**
* Utility method that simply converts the response from
* {@link I2CDevice#readByteData(int)} to an unsigned byte. A short is returned to ensure
* that the returned value is unsigned
*
* @see I2CDevice#readByteData(int)
*
* @param register the register to read from
* @return byte data returned converted to unsigned byte (represented as a short)
* @throws RuntimeIOException if an I/O error occurs
*/
default short readUByte(int register) throws RuntimeIOException {
return (short) (readByteData(register) & 0xff);
}
/**
* Utility method that wraps {@link I2CDevice#readI2CBlockData(int, byte[])} to read the
* specified number of bytes and return as a new byte array.
*
* @see I2CDevice#readI2CBlockData(int, byte[])
*
* @param register the register to read from
* @param length the number of bytes to read
* @return the data read
* @throws RuntimeIOException if an I/O error occurs
*/
default byte[] readI2CBlockDataByteArray(int register, int length) throws RuntimeIOException {
byte[] data = new byte[length];
int read = readI2CBlockData(register, data);
if (read == length) {
return data;
}
// Shrink the byte array to the size of data actually read
byte[] rx_data = new byte[read];
System.arraycopy(data, 0, rx_data, 0, read);
return rx_data;
}
/**
* Utility method that wraps {@link I2CDevice#readI2CBlockData(int, byte[])} to read the
* specified number of bytes and return as a {@link ByteBuffer} using the {@link ByteOrder
* byte order} specified in the device constructor.
*
* @see I2CDevice#readI2CBlockData(int, byte[])
* @see ByteBuffer#wrap(byte[])
*
* @param register the register to read from
* @param length the number of bytes to read
* @return the data read
* @throws RuntimeIOException if an I/O error occurs
*/
default ByteBuffer readI2CBlockDataByteBuffer(int register, int length) throws RuntimeIOException {
byte[] data = new byte[length];
readI2CBlockData(register, data);
ByteBuffer buffer = ByteBuffer.wrap(data);
buffer.order(getByteOrder());
return buffer;
}
/**
* Utility method that invokes either {@link I2CDevice#readWordData(int)} or
* {@link I2CDevice#readWordSwapped(int)} to read a signed short value from the requested
* register in the {@link ByteOrder byte order} specified in the constructor.
*
* @see I2CDevice#readWordData(int)
* @see I2CDevice#readWordSwapped(int)
*
* @param register register to read from
* @return the signed short value read
* @throws RuntimeIOException if an I/O error occurs
*/
default short readShort(int register) throws RuntimeIOException {
if (getByteOrder().equals(ByteOrder.LITTLE_ENDIAN)) {
return readWordData(register);
}
return readWordSwapped(register);
}
/**
* Utility method that wraps {@link I2CDevice#readShort(int)} to read an unsigned short
* value from the requested register using the {@link ByteOrder byte order} specified in
* the constructor.
*
* @see I2CDevice#readShort(int)
*
* @param register register to read from
* @return the unsigned short value read
* @throws RuntimeIOException if an I/O error occurs
*/
default int readUShort(int register) throws RuntimeIOException {
return readShort(register) & 0xffff;
}
/**
* Utility method that wraps {@link I2CDevice#readI2CBlockDataByteBuffer(int, int)} to
* read a signed int value from the requested register using the {@link ByteOrder byte
* order} specified in the constructor.
*
* @see I2CDevice#readI2CBlockDataByteBuffer(int, int)
*
* @param register register to read from
* @return the signed int value read
* @throws RuntimeIOException if an I/O error occurs
*/
default int readInt(int register) throws RuntimeIOException {
return readI2CBlockDataByteBuffer(register, 4).getInt();
}
/**
* Utility method that wraps {@link I2CDevice#readInt(int)} to read an unsigned int value
* from the requested register using the {@link ByteOrder byte order} specified in the
* constructor.
*
* @see I2CDevice#readInt(int)
*
* @param register register to read from
* @return the unsigned int value read
* @throws RuntimeIOException if an I/O error occurs
*/
default long readUInt(int register) throws RuntimeIOException {
return readInt(register) & 0xffffffffL;
}
/**
* Utility method that wraps {@link I2CDevice#readI2CBlockDataByteArray(int, int)} to read
* an unsigned int value on the specified length from the requested register using the
* {@link ByteOrder byte order} specified in the constructor.
*
* @see I2CDevice#readI2CBlockDataByteArray(int, int)
*
* @param register register to read from
* @param numBytes number of bytes to read (1..4)
* @return the unsigned int value read
* @throws RuntimeIOException if an I/O error occurs
*/
default long readUInt(int register, int numBytes) throws RuntimeIOException {
if (numBytes < 1 || numBytes > 4) {
throw new IllegalArgumentException("Maximum int length is 4 bytes - you requested " + numBytes);
}
if (numBytes == 4) {
return readUInt(getAddress());
}
byte[] data = readI2CBlockDataByteArray(register, numBytes);
long val = 0;
for (int i = 0; i < numBytes; i++) {
val |= (data[getByteOrder().equals(ByteOrder.LITTLE_ENDIAN) ? numBytes - i - 1 : i] & 0xff) << (8
* (numBytes - i - 1));
}
return val;
}
/**
* Utility method that wraps {@link I2CDevice#readByteData(int)} to check if the specified
* bit number is set.
*
* @see BitManipulation#isBitSet(byte, int)
* @see I2CDevice#readByteData(int)
*
* @param register the register to read
* @param bit the bit number to check
* @return true if the specified bit number is set
* @throws RuntimeIOException if an I/O error occurs
*/
default boolean readBit(int register, int bit) throws RuntimeIOException {
return BitManipulation.isBitSet(readByteData(register), bit);
}
/**
* Utility method that wraps {@link I2CDevice#readByteData(int)} and
* {@link I2CDevice#writeByteData(int, byte)} to update the specified bit number
*
* @see I2CDevice#readByteData(int)
* @see BitManipulation#setBitValue(byte, int, boolean)
*
* @param register the register to update
* @param bit the bit number to set
* @param value the value to set the bit to
* @throws RuntimeIOException if an I/O error occurs
*/
default void writeBit(int register, int bit, boolean value) throws RuntimeIOException {
byte cur_val = readByteData(register);
writeByteData(register, BitManipulation.setBitValue(cur_val, bit, value));
}
}