diff --git a/hal/src/main/native/athena/SPI.cpp b/hal/src/main/native/athena/SPI.cpp index 08fc5530e3..96e0b0cfed 100644 --- a/hal/src/main/native/athena/SPI.cpp +++ b/hal/src/main/native/athena/SPI.cpp @@ -260,7 +260,7 @@ void HAL_InitializeSPI(HAL_SPIPort port, int32_t* status) { * @param size Number of bytes to transfer. [0..7] * @return Number of bytes transferred, -1 for error */ -int32_t HAL_TransactionSPI(HAL_SPIPort port, uint8_t* dataToSend, +int32_t HAL_TransactionSPI(HAL_SPIPort port, const uint8_t* dataToSend, uint8_t* dataReceived, int32_t size) { if (port < 0 || port >= kSpiMaxHandles) { return -1; @@ -286,7 +286,8 @@ int32_t HAL_TransactionSPI(HAL_SPIPort port, uint8_t* dataToSend, * @param sendSize The number of bytes to be written * @return The number of bytes written. -1 for an error */ -int32_t HAL_WriteSPI(HAL_SPIPort port, uint8_t* dataToSend, int32_t sendSize) { +int32_t HAL_WriteSPI(HAL_SPIPort port, const uint8_t* dataToSend, + int32_t sendSize) { if (port < 0 || port >= kSpiMaxHandles) { return -1; } diff --git a/hal/src/main/native/include/HAL/SPI.h b/hal/src/main/native/include/HAL/SPI.h index 65447fd2ab..cd438f45fc 100644 --- a/hal/src/main/native/include/HAL/SPI.h +++ b/hal/src/main/native/include/HAL/SPI.h @@ -24,9 +24,10 @@ extern "C" { #endif void HAL_InitializeSPI(HAL_SPIPort port, int32_t* status); -int32_t HAL_TransactionSPI(HAL_SPIPort port, uint8_t* dataToSend, +int32_t HAL_TransactionSPI(HAL_SPIPort port, const uint8_t* dataToSend, uint8_t* dataReceived, int32_t size); -int32_t HAL_WriteSPI(HAL_SPIPort port, uint8_t* dataToSend, int32_t sendSize); +int32_t HAL_WriteSPI(HAL_SPIPort port, const uint8_t* dataToSend, + int32_t sendSize); int32_t HAL_ReadSPI(HAL_SPIPort port, uint8_t* buffer, int32_t count); void HAL_CloseSPI(HAL_SPIPort port); void HAL_SetSPISpeed(HAL_SPIPort port, int32_t speed); diff --git a/hal/src/main/native/sim/MockData/SPIData.cpp b/hal/src/main/native/sim/MockData/SPIData.cpp index 69228566b9..5ad1d08319 100644 --- a/hal/src/main/native/sim/MockData/SPIData.cpp +++ b/hal/src/main/native/sim/MockData/SPIData.cpp @@ -167,14 +167,15 @@ int32_t SPIData::Read(uint8_t* buffer, int32_t count) { return count; } -int32_t SPIData::Write(uint8_t* dataToSend, int32_t sendSize) { +int32_t SPIData::Write(const uint8_t* dataToSend, int32_t sendSize) { std::lock_guard lock(m_dataMutex); - InvokeCallback(m_writeCallbacks, "Write", dataToSend, sendSize); + InvokeCallback(m_writeCallbacks, "Write", const_cast(dataToSend), + sendSize); return sendSize; } -int32_t SPIData::Transaction(uint8_t* dataToSend, uint8_t* dataReceived, +int32_t SPIData::Transaction(const uint8_t* dataToSend, uint8_t* dataReceived, int32_t size) { std::lock_guard lock(m_dataMutex); return size; diff --git a/hal/src/main/native/sim/MockData/SPIDataInternal.h b/hal/src/main/native/sim/MockData/SPIDataInternal.h index e43f454b81..242cc31783 100644 --- a/hal/src/main/native/sim/MockData/SPIDataInternal.h +++ b/hal/src/main/native/sim/MockData/SPIDataInternal.h @@ -47,8 +47,9 @@ class SPIData { int64_t GetAccumulatorValue(); int32_t Read(uint8_t* buffer, int32_t count); - int32_t Write(uint8_t* dataToSend, int32_t sendSize); - int32_t Transaction(uint8_t* dataToSend, uint8_t* dataReceived, int32_t size); + int32_t Write(const uint8_t* dataToSend, int32_t sendSize); + int32_t Transaction(const uint8_t* dataToSend, uint8_t* dataReceived, + int32_t size); void ResetAccumulator(); void ResetData(); diff --git a/hal/src/main/native/sim/SPI.cpp b/hal/src/main/native/sim/SPI.cpp index 8339cadd94..5b062a67fd 100644 --- a/hal/src/main/native/sim/SPI.cpp +++ b/hal/src/main/native/sim/SPI.cpp @@ -14,11 +14,12 @@ using namespace hal; void HAL_InitializeSPI(HAL_SPIPort port, int32_t* status) { SimSPIData[port].SetInitialized(true); } -int32_t HAL_TransactionSPI(HAL_SPIPort port, uint8_t* dataToSend, +int32_t HAL_TransactionSPI(HAL_SPIPort port, const uint8_t* dataToSend, uint8_t* dataReceived, int32_t size) { return SimSPIData[port].Transaction(dataToSend, dataReceived, size); } -int32_t HAL_WriteSPI(HAL_SPIPort port, uint8_t* dataToSend, int32_t sendSize) { +int32_t HAL_WriteSPI(HAL_SPIPort port, const uint8_t* dataToSend, + int32_t sendSize) { return SimSPIData[port].Write(dataToSend, sendSize); } int32_t HAL_ReadSPI(HAL_SPIPort port, uint8_t* buffer, int32_t count) { diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/AccumulatorResult.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/AccumulatorResult.java index e725aa053c..d5e53b9be9 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/AccumulatorResult.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/AccumulatorResult.java @@ -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; + } } diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/SPI.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/SPI.java index 639ba9a67e..85eb8a82ea 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/SPI.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/SPI.java @@ -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 { *

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); } } diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/SPIJNI.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/SPIJNI.java index f7d59f1e1e..2843c49551 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/SPIJNI.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/hal/SPIJNI.java @@ -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); } diff --git a/wpilibj/src/main/native/cpp/HALUtil.cpp b/wpilibj/src/main/native/cpp/HALUtil.cpp index 6fcf95f306..2680422f79 100644 --- a/wpilibj/src/main/native/cpp/HALUtil.cpp +++ b/wpilibj/src/main/native/cpp/HALUtil.cpp @@ -57,6 +57,7 @@ static JException uncleanStatusExCls; static JClass pwmConfigDataResultCls; static JClass canStatusCls; static JClass matchInfoDataCls; +static JClass accumulatorResultCls; namespace frc { @@ -234,6 +235,14 @@ void SetMatchInfoObject(JNIEnv* env, jobject matchStatus, (jint)matchInfo.matchType); } +void SetAccumulatorResultObject(JNIEnv* env, jobject accumulatorResult, + int64_t value, int64_t count) { + static jmethodID func = env->GetMethodID(accumulatorResultCls, "set", + "(JJ)V"); + + env->CallObjectMethod(accumulatorResult, func, (jlong)value, (jlong)count); +} + } // namespace frc using namespace frc; @@ -292,6 +301,9 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { matchInfoDataCls = JClass(env, "edu/wpi/first/wpilibj/hal/MatchInfoData"); if (!matchInfoDataCls) return JNI_ERR; + accumulatorResultCls = JClass(env, "edu/wpi/first/wpilibj/AccumulatorResult"); + if (!accumulatorResultCls) return JNI_ERR; + return JNI_VERSION_1_6; } diff --git a/wpilibj/src/main/native/cpp/HALUtil.h b/wpilibj/src/main/native/cpp/HALUtil.h index 340aa21b41..9feed50a00 100644 --- a/wpilibj/src/main/native/cpp/HALUtil.h +++ b/wpilibj/src/main/native/cpp/HALUtil.h @@ -63,6 +63,9 @@ void SetCanStatusObject(JNIEnv *env, jobject canStatus, void SetMatchInfoObject(JNIEnv* env, jobject matchStatus, const HAL_MatchInfo& matchInfo); +void SetAccumulatorResultObject(JNIEnv* env, jobject accumulatorResult, + int64_t value, int64_t count); + } // namespace frc #endif // HALUTIL_H diff --git a/wpilibj/src/main/native/cpp/SPIJNI.cpp b/wpilibj/src/main/native/cpp/SPIJNI.cpp index d8dc2dc012..b38c17fb1b 100644 --- a/wpilibj/src/main/native/cpp/SPIJNI.cpp +++ b/wpilibj/src/main/native/cpp/SPIJNI.cpp @@ -13,8 +13,10 @@ #include "HAL/SPI.h" #include "HALUtil.h" +#include "support/jni_util.h" using namespace frc; +using namespace wpi::java; // set the logging level TLogLevel spiJNILogLevel = logWARNING; @@ -66,6 +68,30 @@ JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_SPIJNI_spiTransaction( return retVal; } +/* + * Class: edu_wpi_first_wpilibj_hal_SPIJNI + * Method: spiTransactionB + * Signature: (I[B[BB)I + */ +JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_SPIJNI_spiTransactionB( + JNIEnv *env, jclass, jint port, jbyteArray dataToSend, jbyteArray dataReceived, + jbyte size) { + SPIJNI_LOG(logDEBUG) << "Calling SPIJNI spiTransactionB"; + SPIJNI_LOG(logDEBUG) << "Port = " << (jint)port; + SPIJNI_LOG(logDEBUG) << "Size = " << (jint)size; + llvm::SmallVector recvBuf; + recvBuf.resize(size); + jint retVal = + HAL_TransactionSPI(static_cast(port), + reinterpret_cast( + JByteArrayRef(env, dataToSend).array().data()), + recvBuf.data(), size); + env->SetByteArrayRegion(dataReceived, 0, size, + reinterpret_cast(recvBuf.data())); + SPIJNI_LOG(logDEBUG) << "ReturnValue = " << (jint)retVal; + return retVal; +} + /* * Class: edu_wpi_first_wpilibj_hal_SPIJNI * Method: spiWrite @@ -86,20 +112,73 @@ JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_SPIJNI_spiWrite( return retVal; } +/* + * Class: edu_wpi_first_wpilibj_hal_SPIJNI + * Method: spiWriteB + * Signature: (I[BB)I + */ +JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_SPIJNI_spiWriteB( + JNIEnv *env, jclass, jint port, jbyteArray dataToSend, jbyte size) { + SPIJNI_LOG(logDEBUG) << "Calling SPIJNI spiWriteB"; + SPIJNI_LOG(logDEBUG) << "Port = " << (jint)port; + SPIJNI_LOG(logDEBUG) << "Size = " << (jint)size; + jint retVal = HAL_WriteSPI(static_cast(port), + reinterpret_cast( + JByteArrayRef(env, dataToSend).array().data()), + size); + SPIJNI_LOG(logDEBUG) << "ReturnValue = " << (jint)retVal; + return retVal; +} + /* * Class: edu_wpi_first_wpilibj_hal_SPIJNI * Method: spiRead - * Signature: (ILjava/nio/ByteBuffer;B)I + * Signature: (IZLjava/nio/ByteBuffer;B)I */ JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_SPIJNI_spiRead( - JNIEnv *env, jclass, jint port, jobject dataReceived, jbyte size) { + JNIEnv *env, jclass, jint port, jboolean initiate, jobject dataReceived, jbyte size) { SPIJNI_LOG(logDEBUG) << "Calling SPIJNI spiRead"; SPIJNI_LOG(logDEBUG) << "Port = " << (jint)port; + SPIJNI_LOG(logDEBUG) << "Initiate = " << (jboolean)initiate; uint8_t *dataReceivedPtr = (uint8_t *)env->GetDirectBufferAddress(dataReceived); SPIJNI_LOG(logDEBUG) << "Size = " << (jint)size; SPIJNI_LOG(logDEBUG) << "DataReceivedPtr = " << dataReceivedPtr; - jint retVal = HAL_ReadSPI(static_cast(port), (uint8_t *)dataReceivedPtr, size); + jint retVal; + if (initiate) { + llvm::SmallVector sendBuf; + sendBuf.resize(size); + retVal = HAL_TransactionSPI(static_cast(port), sendBuf.data(), dataReceivedPtr, size); + } else { + retVal = HAL_ReadSPI(static_cast(port), (uint8_t *)dataReceivedPtr, size); + } + SPIJNI_LOG(logDEBUG) << "ReturnValue = " << (jint)retVal; + return retVal; +} + +/* + * Class: edu_wpi_first_wpilibj_hal_SPIJNI + * Method: spiReadB + * Signature: (IZ[BB)I + */ +JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_SPIJNI_spiReadB( + JNIEnv *env, jclass, jint port, jboolean initiate, jbyteArray dataReceived, jbyte size) { + SPIJNI_LOG(logDEBUG) << "Calling SPIJNI spiReadB"; + SPIJNI_LOG(logDEBUG) << "Port = " << (jint)port; + SPIJNI_LOG(logDEBUG) << "Initiate = " << (jboolean)initiate; + SPIJNI_LOG(logDEBUG) << "Size = " << (jint)size; + jint retVal; + llvm::SmallVector recvBuf; + recvBuf.resize(size); + if (initiate) { + llvm::SmallVector sendBuf; + sendBuf.resize(size); + retVal = HAL_TransactionSPI(static_cast(port), sendBuf.data(), recvBuf.data(), size); + } else { + retVal = HAL_ReadSPI(static_cast(port), recvBuf.data(), size); + } + env->SetByteArrayRegion(dataReceived, 0, size, + reinterpret_cast(recvBuf.data())); SPIJNI_LOG(logDEBUG) << "ReturnValue = " << (jint)retVal; return retVal; } @@ -344,29 +423,23 @@ Java_edu_wpi_first_wpilibj_hal_SPIJNI_spiGetAccumulatorAverage( /* * Class: edu_wpi_first_wpilibj_hal_SPIJNI * Method: spiGetAccumulatorOutput - * Signature: (ILjava/nio/LongBuffer;Ljava/nio/LongBuffer;)V + * Signature: (ILedu/wpi/first/wpilibj/AccumulatorResult;)V */ JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_SPIJNI_spiGetAccumulatorOutput( - JNIEnv *env, jclass, jint port, jobject value, jobject count) { + JNIEnv *env, jclass, jint port, jobject accumulatorResult) { SPIJNI_LOG(logDEBUG) << "Calling SPIJNI spiGetAccumulatorOutput"; SPIJNI_LOG(logDEBUG) << "Port = " << (jint)port; int32_t status = 0; + int64_t value = 0; + int64_t count = 0; + HAL_GetSPIAccumulatorOutput(static_cast(port), &value, &count, &status); - jlong *valuePtr = (jlong *)env->GetDirectBufferAddress(value); - jlong *countPtr = (jlong *)env->GetDirectBufferAddress(count); - - int64_t valueInt64; - int64_t countInt64; - - HAL_GetSPIAccumulatorOutput(static_cast(port), &valueInt64, &countInt64, &status); - - *valuePtr = valueInt64; - *countPtr = countInt64; + SetAccumulatorResultObject(env, accumulatorResult, value, count); SPIJNI_LOG(logDEBUG) << "Status = " << status; - SPIJNI_LOG(logDEBUG) << "Value = " << *valuePtr; - SPIJNI_LOG(logDEBUG) << "Count = " << *countPtr; + SPIJNI_LOG(logDEBUG) << "Value = " << value; + SPIJNI_LOG(logDEBUG) << "Count = " << count; CheckStatus(env, status); }