mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-07-03 03:01:44 +00:00
Add ByteBuffer interfaces to I2C and SPI.
Use these interfaces in ADXL345_I2C and ADXL345_SPI. Change-Id: I62d37e80eb71cec9019dd095f3721e0e5d60bf3f
This commit is contained in:
@@ -6,6 +6,9 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
package edu.wpi.first.wpilibj;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import edu.wpi.first.wpilibj.communication.FRCNetworkCommunicationsLibrary.tInstances;
|
||||
import edu.wpi.first.wpilibj.communication.FRCNetworkCommunicationsLibrary.tResourceType;
|
||||
import edu.wpi.first.wpilibj.communication.UsageReporting;
|
||||
@@ -121,17 +124,12 @@ public class ADXL345_I2C extends SensorBase implements Accelerometer, LiveWindow
|
||||
* @return Acceleration of the ADXL345 in Gs.
|
||||
*/
|
||||
public double getAcceleration(Axes axis) {
|
||||
byte[] rawAccel = new byte[2];
|
||||
m_i2c.read(kDataRegister + axis.value, rawAccel.length, rawAccel);
|
||||
ByteBuffer rawAccel = ByteBuffer.allocateDirect(2);
|
||||
m_i2c.read(kDataRegister + axis.value, 2, rawAccel);
|
||||
|
||||
// Sensor is little endian... swap bytes
|
||||
return accelFromBytes(rawAccel[0], rawAccel[1]);
|
||||
}
|
||||
|
||||
private double accelFromBytes(byte first, byte second) {
|
||||
short tempLow = (short) (first & 0xff);
|
||||
short tempHigh = (short) ((second << 8) & 0xff00);
|
||||
return (tempLow | tempHigh) * kGsPerLSB;
|
||||
rawAccel.order(ByteOrder.LITTLE_ENDIAN);
|
||||
return rawAccel.getShort(0) * kGsPerLSB;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -142,13 +140,14 @@ public class ADXL345_I2C extends SensorBase implements Accelerometer, LiveWindow
|
||||
*/
|
||||
public AllAxes getAccelerations() {
|
||||
AllAxes data = new AllAxes();
|
||||
byte[] rawData = new byte[6];
|
||||
m_i2c.read(kDataRegister, rawData.length, rawData);
|
||||
ByteBuffer rawData = ByteBuffer.allocateDirect(6);
|
||||
m_i2c.read(kDataRegister, 6, rawData);
|
||||
|
||||
// Sensor is little endian... swap bytes
|
||||
data.XAxis = accelFromBytes(rawData[0], rawData[1]);
|
||||
data.YAxis = accelFromBytes(rawData[2], rawData[3]);
|
||||
data.ZAxis = accelFromBytes(rawData[4], rawData[5]);
|
||||
rawData.order(ByteOrder.LITTLE_ENDIAN);
|
||||
data.XAxis = rawData.getShort(0) * kGsPerLSB;
|
||||
data.YAxis = rawData.getShort(2) * kGsPerLSB;
|
||||
data.ZAxis = rawData.getShort(4) * kGsPerLSB;
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
@@ -155,14 +155,13 @@ public class ADXL345_SPI extends SensorBase implements Accelerometer, LiveWindow
|
||||
* @return Acceleration of the ADXL345 in Gs.
|
||||
*/
|
||||
public double getAcceleration(ADXL345_SPI.Axes axis) {
|
||||
byte[] transferBuffer = new byte[3];
|
||||
transferBuffer[0] = (byte) ((kAddress_Read | kAddress_MultiByte | kDataRegister) + axis.value);
|
||||
ByteBuffer transferBuffer = ByteBuffer.allocateDirect(3);
|
||||
transferBuffer.put(0, (byte) ((kAddress_Read | kAddress_MultiByte | kDataRegister) + axis.value));
|
||||
m_spi.transaction(transferBuffer, transferBuffer, 3);
|
||||
ByteBuffer rawAccel = ByteBuffer.wrap(transferBuffer, 1, 2);
|
||||
// Sensor is little endian
|
||||
rawAccel.order(ByteOrder.LITTLE_ENDIAN);
|
||||
transferBuffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
return rawAccel.getShort() * kGsPerLSB;
|
||||
return transferBuffer.getShort(1) * kGsPerLSB;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,18 +172,17 @@ public class ADXL345_SPI extends SensorBase implements Accelerometer, LiveWindow
|
||||
*/
|
||||
public ADXL345_SPI.AllAxes getAccelerations() {
|
||||
ADXL345_SPI.AllAxes data = new ADXL345_SPI.AllAxes();
|
||||
byte dataBuffer[] = new byte[7];
|
||||
if (m_spi != null) {
|
||||
ByteBuffer dataBuffer = ByteBuffer.allocateDirect(7);
|
||||
// Select the data address.
|
||||
dataBuffer[0] = (byte) (kAddress_Read | kAddress_MultiByte | kDataRegister);
|
||||
dataBuffer.put(0, (byte) (kAddress_Read | kAddress_MultiByte | kDataRegister));
|
||||
m_spi.transaction(dataBuffer, dataBuffer, 7);
|
||||
ByteBuffer rawData = ByteBuffer.wrap(dataBuffer, 1, 6);
|
||||
// Sensor is little endian... swap bytes
|
||||
rawData.order(ByteOrder.LITTLE_ENDIAN);
|
||||
dataBuffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
data.XAxis = rawData.getShort() * kGsPerLSB;
|
||||
data.YAxis = rawData.getShort() * kGsPerLSB;
|
||||
data.ZAxis = rawData.getShort() * kGsPerLSB;
|
||||
data.XAxis = dataBuffer.getShort(1) * kGsPerLSB;
|
||||
data.YAxis = dataBuffer.getShort(3) * kGsPerLSB;
|
||||
data.ZAxis = dataBuffer.getShort(5) * kGsPerLSB;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -88,6 +88,36 @@ public class I2C extends SensorBase {
|
||||
return aborted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic transaction.
|
||||
*
|
||||
* This is a lower-level interface to the I2C hardware giving you more control
|
||||
* over each transaction.
|
||||
*
|
||||
* @param dataToSend Buffer of data to send as part of the transaction. Must
|
||||
* be allocated using ByteBuffer.allocateDirect().
|
||||
* @param sendSize Number of bytes to send as part of the transaction.
|
||||
* @param dataReceived Buffer to read data into. Must be allocated using
|
||||
* ByteBuffer.allocateDirect().
|
||||
* @param receiveSize Number of bytes to read from the device.
|
||||
* @return Transfer Aborted... false for success, true for aborted.
|
||||
*/
|
||||
public synchronized boolean transaction(ByteBuffer dataToSend, int sendSize, ByteBuffer dataReceived,
|
||||
int receiveSize) {
|
||||
boolean aborted = true;
|
||||
|
||||
if (!dataToSend.isDirect())
|
||||
throw new IllegalArgumentException("dataToSend must be a direct buffer");
|
||||
if (dataToSend.capacity() < sendSize)
|
||||
throw new IllegalArgumentException("dataToSend is too small, must be at least " + sendSize);
|
||||
if (!dataReceived.isDirect())
|
||||
throw new IllegalArgumentException("dataReceived must be a direct buffer");
|
||||
if (dataReceived.capacity() < receiveSize)
|
||||
throw new IllegalArgumentException("dataReceived is too small, must be at least " + receiveSize);
|
||||
|
||||
return I2CJNI.i2CTransaction((byte) m_port.getValue(), (byte) m_deviceAddress, dataToSend, (byte) sendSize, dataReceived, (byte) receiveSize) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to address a device on the I2C bus.
|
||||
*
|
||||
@@ -97,7 +127,7 @@ public class I2C extends SensorBase {
|
||||
* @return Transfer Aborted... false for success, true for aborted.
|
||||
*/
|
||||
public boolean addressOnly() {
|
||||
return transaction(null, (byte) 0, null, (byte) 0);
|
||||
return transaction((byte[]) null, (byte) 0, (byte[]) null, (byte) 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,6 +168,25 @@ public class I2C extends SensorBase {
|
||||
(byte) data.length) < 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a write transaction with the device.
|
||||
*
|
||||
* Write multiple bytes to a register on a device and wait until the
|
||||
* transaction is complete.
|
||||
*
|
||||
* @param data The data to write to the device. Must be created using
|
||||
* ByteBuffer.allocateDirect().
|
||||
*/
|
||||
public synchronized boolean writeBulk(ByteBuffer data, int size) {
|
||||
if (!data.isDirect())
|
||||
throw new IllegalArgumentException("must be a direct buffer");
|
||||
if (data.capacity() < size)
|
||||
throw new IllegalArgumentException("buffer is too small, must be at least " + size);
|
||||
|
||||
return I2CJNI.i2CWrite((byte) m_port.getValue(), (byte) m_deviceAddress, data,
|
||||
(byte) size) < 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a read transaction with the device.
|
||||
*
|
||||
@@ -166,6 +215,36 @@ public class I2C extends SensorBase {
|
||||
return transaction(registerAddressArray, registerAddressArray.length, buffer, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a read transaction with the device.
|
||||
*
|
||||
* Read bytes from a device. Most I2C devices will auto-increment the
|
||||
* register pointer internally allowing you to read consecutive
|
||||
* registers on a device in a single transaction.
|
||||
*
|
||||
* @param registerAddress The register to read first in the transaction.
|
||||
* @param count The number of bytes to read in the transaction.
|
||||
* @param buffer A buffer to store the data read from the device. Must be
|
||||
* created using ByteBuffer.allocateDirect().
|
||||
* @return Transfer Aborted... false for success, true for aborted.
|
||||
*/
|
||||
public boolean read(int registerAddress, int count, ByteBuffer buffer) {
|
||||
if (count < 1) {
|
||||
throw new BoundaryException("Value must be at least 1, " + count +
|
||||
" given");
|
||||
}
|
||||
|
||||
if (!buffer.isDirect())
|
||||
throw new IllegalArgumentException("must be a direct buffer");
|
||||
if (buffer.capacity() < count)
|
||||
throw new IllegalArgumentException("buffer is too small, must be at least " + count);
|
||||
|
||||
ByteBuffer dataToSendBuffer = ByteBuffer.allocateDirect(1);
|
||||
dataToSendBuffer.put(0, (byte) registerAddress);
|
||||
|
||||
return transaction(dataToSendBuffer, 1, buffer, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a read only transaction with the device.
|
||||
*
|
||||
@@ -196,6 +275,32 @@ public class I2C extends SensorBase {
|
||||
return retVal < 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a read only transaction with the device.
|
||||
*
|
||||
* Read bytes from a device. This method does not write any data to prompt
|
||||
* the device.
|
||||
*
|
||||
* @param buffer A pointer to the array of bytes to store the data read from
|
||||
* the device. Must be created using ByteBuffer.allocateDirect().
|
||||
* @param count The number of bytes to read in the transaction.
|
||||
* @return Transfer Aborted... false for success, true for aborted.
|
||||
*/
|
||||
public boolean readOnly(ByteBuffer buffer, int count) {
|
||||
if (count < 1) {
|
||||
throw new BoundaryException("Value must be at least 1, " + count +
|
||||
" given");
|
||||
}
|
||||
|
||||
if (!buffer.isDirect())
|
||||
throw new IllegalArgumentException("must be a direct buffer");
|
||||
if (buffer.capacity() < count)
|
||||
throw new IllegalArgumentException("buffer is too small, must be at least " + count);
|
||||
|
||||
return I2CJNI.i2CRead((byte) m_port.getValue(), (byte) m_deviceAddress, buffer,
|
||||
(byte) count) < 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a broadcast write to all devices on the I2C bus.
|
||||
*
|
||||
@@ -223,18 +328,21 @@ public class I2C extends SensorBase {
|
||||
*/
|
||||
public boolean verifySensor(int registerAddress, int count, byte[] expected) {
|
||||
// TODO: Make use of all 7 read bytes
|
||||
byte[] deviceData = new byte[4];
|
||||
ByteBuffer dataToSendBuffer = ByteBuffer.allocateDirect(1);
|
||||
|
||||
ByteBuffer deviceData = ByteBuffer.allocateDirect(4);
|
||||
for (int i = 0, curRegisterAddress = registerAddress; i < count; i += 4, curRegisterAddress +=
|
||||
4) {
|
||||
int toRead = count - i < 4 ? count - i : 4;
|
||||
// Read the chunk of data. Return false if the sensor does not
|
||||
// respond.
|
||||
if (read(curRegisterAddress, toRead, deviceData)) {
|
||||
dataToSendBuffer.put(0, (byte) curRegisterAddress);
|
||||
if (transaction(dataToSendBuffer, 1, deviceData, toRead)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (byte j = 0; j < toRead; j++) {
|
||||
if (deviceData[j] != expected[i + j]) {
|
||||
if (deviceData.get(j) != expected[i + j]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,11 +143,27 @@ public class SPI extends SensorBase {
|
||||
* MISO input during the transfer into the receive FIFO.
|
||||
*/
|
||||
public int write(byte[] dataToSend, int size) {
|
||||
int retVal = 0;
|
||||
ByteBuffer dataToSendBuffer = ByteBuffer.allocateDirect(size);
|
||||
dataToSendBuffer.put(dataToSend);
|
||||
retVal = SPIJNI.spiWrite(m_port, dataToSendBuffer, (byte) size);
|
||||
return retVal;
|
||||
return SPIJNI.spiWrite(m_port, dataToSendBuffer, (byte) size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data to the slave device. Blocks until there is space in the output
|
||||
* FIFO.
|
||||
*
|
||||
* If not running in output only mode, also saves the data received on the
|
||||
* MISO input during the transfer into the receive FIFO.
|
||||
*
|
||||
* @param dataToSend The buffer containing the data to send. Must be created
|
||||
* using ByteBuffer.allocateDirect().
|
||||
*/
|
||||
public int write(ByteBuffer dataToSend, int size) {
|
||||
if (!dataToSend.isDirect())
|
||||
throw new IllegalArgumentException("must be a direct buffer");
|
||||
if (dataToSend.capacity() < size)
|
||||
throw new IllegalArgumentException("buffer is too small, must be at least " + size);
|
||||
return SPIJNI.spiWrite(m_port, dataToSend, (byte) size);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -174,6 +190,33 @@ public class SPI extends SensorBase {
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a word from the receive FIFO.
|
||||
*
|
||||
* Waits for the current transfer to complete if the receive FIFO is empty.
|
||||
*
|
||||
* If the receive FIFO is empty, there is no active transfer, and initiate is
|
||||
* false, errors.
|
||||
*
|
||||
* @param initiate If true, this function pushes "0" into the transmit buffer
|
||||
* and initiates a transfer. If false, this function assumes that data
|
||||
* is already in the receive FIFO from a previous write.
|
||||
*
|
||||
* @param received The buffer to be filled with the received data. Must be
|
||||
* created using ByteBuffer.allocateDirect().
|
||||
*/
|
||||
public int read(boolean initiate, ByteBuffer dataReceived, int size) {
|
||||
if (!dataReceived.isDirect())
|
||||
throw new IllegalArgumentException("must be a direct buffer");
|
||||
if (dataReceived.capacity() < size)
|
||||
throw new IllegalArgumentException("buffer is too small, must be at least " + size);
|
||||
if (initiate) {
|
||||
ByteBuffer dataToSendBuffer = ByteBuffer.allocateDirect(size);
|
||||
return SPIJNI.spiTransaction(m_port, dataToSendBuffer, dataReceived, (byte) size);
|
||||
}
|
||||
return SPIJNI.spiRead(m_port, dataReceived, (byte) size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a simultaneous read/write transaction with the device
|
||||
*
|
||||
@@ -182,12 +225,32 @@ public class SPI extends SensorBase {
|
||||
* @param size The length of the transaction, in bytes
|
||||
*/
|
||||
public int transaction(byte[] dataToSend, byte[] dataReceived, int size) {
|
||||
int retVal = 0;
|
||||
ByteBuffer dataToSendBuffer = ByteBuffer.allocateDirect(size);
|
||||
dataToSendBuffer.put(dataToSend);
|
||||
ByteBuffer dataReceivedBuffer = ByteBuffer.allocateDirect(size);
|
||||
retVal = SPIJNI.spiTransaction(m_port, dataToSendBuffer, dataReceivedBuffer, (byte) size);
|
||||
int retVal = SPIJNI.spiTransaction(m_port, dataToSendBuffer, dataReceivedBuffer, (byte) size);
|
||||
dataReceivedBuffer.get(dataReceived);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a simultaneous read/write transaction with the device
|
||||
*
|
||||
* @param dataToSend The data to be written out to the device. Must be
|
||||
* created using ByteBuffer.allocateDirect().
|
||||
* @param dataReceived Buffer to receive data from the device. Must be
|
||||
* created using ByteBuffer.allocateDirect().
|
||||
* @param size The length of the transaction, in bytes
|
||||
*/
|
||||
public int transaction(ByteBuffer dataToSend, ByteBuffer dataReceived, int size) {
|
||||
if (!dataToSend.isDirect())
|
||||
throw new IllegalArgumentException("dataToSend must be a direct buffer");
|
||||
if (dataToSend.capacity() < size)
|
||||
throw new IllegalArgumentException("dataToSend is too small, must be at least " + size);
|
||||
if (!dataReceived.isDirect())
|
||||
throw new IllegalArgumentException("dataReceived must be a direct buffer");
|
||||
if (dataReceived.capacity() < size)
|
||||
throw new IllegalArgumentException("dataReceived is too small, must be at least " + size);
|
||||
return SPIJNI.spiTransaction(m_port, dataToSend, dataReceived, (byte) size);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user