SPI: Provide byte[] JNI interfaces.

This avoids a direct byte buffer allocation on every read/write/transaction
for the byte[] variants.

Also change spiGetAccumulatorOutput() to directly set the AccumulatorResult
object, avoiding a ByteBuffer allocation.

Changes HAL SPI interfaces to use const for dataToSend.

Fixes #733.
This commit is contained in:
Peter Johnson
2017-11-14 00:00:45 -08:00
parent df7c1389de
commit 6307d41002
11 changed files with 168 additions and 73 deletions

View File

@@ -22,4 +22,12 @@ public class AccumulatorResult {
*/
@SuppressWarnings("MemberName")
public long count;
/**
* Set the value and count.
*/
public void set(long value, long count) {
this.value = value;
this.count = count;
}
}

View File

@@ -8,7 +8,6 @@
package edu.wpi.first.wpilibj;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
@@ -141,9 +140,10 @@ public class SPI extends SensorBase {
* the transfer into the receive FIFO.
*/
public int write(byte[] dataToSend, int size) {
ByteBuffer dataToSendBuffer = ByteBuffer.allocateDirect(size);
dataToSendBuffer.put(dataToSend);
return SPIJNI.spiWrite(m_port, dataToSendBuffer, (byte) size);
if (dataToSend.length < size) {
throw new IllegalArgumentException("buffer is too small, must be at least " + size);
}
return SPIJNI.spiWriteB(m_port, dataToSend, (byte) size);
}
/**
@@ -152,10 +152,12 @@ public class SPI extends SensorBase {
* <p>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().
* @param dataToSend The buffer containing the data to send.
*/
public int write(ByteBuffer dataToSend, int size) {
if (dataToSend.hasArray()) {
return write(dataToSend.array(), size);
}
if (!dataToSend.isDirect()) {
throw new IllegalArgumentException("must be a direct buffer");
}
@@ -177,16 +179,10 @@ public class SPI extends SensorBase {
* FIFO from a previous write.
*/
public int read(boolean initiate, byte[] dataReceived, int size) {
final int retVal;
ByteBuffer dataReceivedBuffer = ByteBuffer.allocateDirect(size);
ByteBuffer dataToSendBuffer = ByteBuffer.allocateDirect(size);
if (initiate) {
retVal = SPIJNI.spiTransaction(m_port, dataToSendBuffer, dataReceivedBuffer, (byte) size);
} else {
retVal = SPIJNI.spiRead(m_port, dataReceivedBuffer, (byte) size);
if (dataReceived.length < size) {
throw new IllegalArgumentException("buffer is too small, must be at least " + size);
}
dataReceivedBuffer.get(dataReceived);
return retVal;
return SPIJNI.spiReadB(m_port, initiate, dataReceived, (byte) size);
}
/**
@@ -199,22 +195,20 @@ public class SPI extends SensorBase {
* @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 dataReceived The buffer to be filled with the received data. Must be created using
* ByteBuffer.allocateDirect().
* @param dataReceived The buffer to be filled with the received data.
* @param size The length of the transaction, in bytes
*/
public int read(boolean initiate, ByteBuffer dataReceived, int size) {
if (dataReceived.hasArray()) {
return read(initiate, dataReceived.array(), 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);
return SPIJNI.spiRead(m_port, initiate, dataReceived, (byte) size);
}
/**
@@ -225,24 +219,26 @@ public class SPI extends SensorBase {
* @param size The length of the transaction, in bytes
*/
public int transaction(byte[] dataToSend, byte[] dataReceived, int size) {
ByteBuffer dataToSendBuffer = ByteBuffer.allocateDirect(size);
dataToSendBuffer.put(dataToSend);
ByteBuffer dataReceivedBuffer = ByteBuffer.allocateDirect(size);
int retVal = SPIJNI.spiTransaction(m_port, dataToSendBuffer, dataReceivedBuffer, (byte) size);
dataReceivedBuffer.get(dataReceived);
return retVal;
if (dataToSend.length < size) {
throw new IllegalArgumentException("dataToSend is too small, must be at least " + size);
}
if (dataReceived.length < size) {
throw new IllegalArgumentException("dataReceived is too small, must be at least " + size);
}
return SPIJNI.spiTransactionB(m_port, dataToSend, dataReceived, (byte) size);
}
/**
* 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 dataToSend The data to be written out to the device.
* @param dataReceived Buffer to receive data from the device.
* @param size The length of the transaction, in bytes
*/
public int transaction(ByteBuffer dataToSend, ByteBuffer dataReceived, int size) {
if (dataToSend.hasArray() && dataReceived.hasArray()) {
return transaction(dataToSend.array(), dataReceived.array(), size);
}
if (!dataToSend.isDirect()) {
throw new IllegalArgumentException("dataToSend must be a direct buffer");
}
@@ -359,14 +355,6 @@ public class SPI extends SensorBase {
if (result == null) {
throw new IllegalArgumentException("Null parameter `result'");
}
ByteBuffer value = ByteBuffer.allocateDirect(8);
// set the byte order
value.order(ByteOrder.LITTLE_ENDIAN);
ByteBuffer count = ByteBuffer.allocateDirect(8);
// set the byte order
count.order(ByteOrder.LITTLE_ENDIAN);
SPIJNI.spiGetAccumulatorOutput(m_port, value.asLongBuffer(), count.asLongBuffer());
result.value = value.asLongBuffer().get(0);
result.count = count.asLongBuffer().get(0);
SPIJNI.spiGetAccumulatorOutput(m_port, result);
}
}

View File

@@ -7,8 +7,8 @@
package edu.wpi.first.wpilibj.hal;
import edu.wpi.first.wpilibj.AccumulatorResult;
import java.nio.ByteBuffer;
import java.nio.LongBuffer;
@SuppressWarnings("AbbreviationAsWordInName")
public class SPIJNI extends JNIWrapper {
@@ -17,9 +17,16 @@ public class SPIJNI extends JNIWrapper {
public static native int spiTransaction(int port, ByteBuffer dataToSend,
ByteBuffer dataReceived, byte size);
public static native int spiTransactionB(int port, byte[] dataToSend,
byte[] dataReceived, byte size);
public static native int spiWrite(int port, ByteBuffer dataToSend, byte sendSize);
public static native int spiRead(int port, ByteBuffer dataReceived, byte size);
public static native int spiWriteB(int port, byte[] dataToSend, byte sendSize);
public static native int spiRead(int port, boolean initiate, ByteBuffer dataReceived, byte size);
public static native int spiReadB(int port, boolean initiate, byte[] dataReceived, byte size);
public static native void spiClose(int port);
@@ -52,6 +59,5 @@ public class SPIJNI extends JNIWrapper {
public static native double spiGetAccumulatorAverage(int port);
public static native void spiGetAccumulatorOutput(int port, LongBuffer value,
LongBuffer count);
public static native void spiGetAccumulatorOutput(int port, AccumulatorResult result);
}