[hal] Add CAN Stream API to Java through JNI bindings (#4193)

The CAN Stream API allows defining an buffer to receive an
arbitrary set of CAN messages, based on an ID and a mask. Messages
are added to this queue separate of other CAN APIs. This means the
messages can be receive without impacting other APIs such as
vendor APIs.

This enables things like detection of what devices are on the
bus, or custom decoding, without using vendor APIs.

Co-authored-by: Thad House <thadhouse1@gmail.com>
This commit is contained in:
William Toth
2022-12-06 23:58:09 -06:00
committed by GitHub
parent be27171236
commit b300518bd1
5 changed files with 147 additions and 0 deletions

View File

@@ -91,4 +91,90 @@ Java_edu_wpi_first_hal_can_CANJNI_getCANStatus
txFullCount, receiveErrorCount, transmitErrorCount);
}
/*
* Class: edu_wpi_first_hal_can_CANJNI
* Method: openCANStreamSession
* Signature: (III)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_can_CANJNI_openCANStreamSession
(JNIEnv* env, jclass, jint messageID, jint messageIDMask, jint maxMessages)
{
uint32_t handle = 0;
int32_t status = 0;
HAL_CAN_OpenStreamSession(&handle, static_cast<uint32_t>(messageID),
static_cast<uint32_t>(messageIDMask),
static_cast<uint32_t>(maxMessages), &status);
if (!CheckStatus(env, status)) {
return static_cast<jint>(0);
}
return static_cast<jint>(handle);
}
/*
* Class: edu_wpi_first_hal_can_CANJNI
* Method: closeCANStreamSession
* Signature: (I)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_can_CANJNI_closeCANStreamSession
(JNIEnv* env, jclass, jint sessionHandle)
{
HAL_CAN_CloseStreamSession(static_cast<uint32_t>(sessionHandle));
}
/*
* Class: edu_wpi_first_hal_can_CANJNI
* Method: readCANStreamSession
* Signature: (I[Ljava/lang/Object;I)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_can_CANJNI_readCANStreamSession
(JNIEnv* env, jclass, jint sessionHandle, jobjectArray messages,
jint messagesToRead)
{
uint32_t handle = static_cast<uint32_t>(sessionHandle);
uint32_t messagesRead = 0;
wpi::SmallVector<HAL_CANStreamMessage, 16> messageBuffer;
messageBuffer.resize_for_overwrite(messagesToRead);
int32_t status = 0;
HAL_CAN_ReadStreamSession(handle, messageBuffer.begin(),
static_cast<uint32_t>(messagesToRead),
&messagesRead, &status);
if (status == HAL_ERR_CANSessionMux_MessageNotFound || messagesRead == 0) {
return 0;
}
if (!CheckStatus(env, status)) {
return 0;
}
for (int i = 0; i < static_cast<int>(messagesRead); i++) {
struct HAL_CANStreamMessage* msg = &messageBuffer[i];
JLocal<jobject> elem{
env, static_cast<jstring>(env->GetObjectArrayElement(messages, i))};
if (!elem) {
// TODO decide if should throw
continue;
}
JLocal<jbyteArray> toSetArray{
env, SetCANStreamObject(env, elem, msg->dataSize, msg->messageID,
msg->timeStamp)};
auto javaLen = env->GetArrayLength(toSetArray);
if (javaLen < msg->dataSize) {
msg->dataSize = javaLen;
}
env->SetByteArrayRegion(toSetArray, 0, msg->dataSize,
reinterpret_cast<jbyte*>(msg->data));
}
return static_cast<jint>(messagesRead);
}
} // extern "C"