mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
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>
181 lines
5.1 KiB
C++
181 lines
5.1 KiB
C++
// Copyright (c) FIRST and other WPILib contributors.
|
|
// Open Source Software; you can modify and/or share it under the terms of
|
|
// the WPILib BSD license file in the root directory of this project.
|
|
|
|
#include <jni.h>
|
|
|
|
#include <cassert>
|
|
|
|
#include <wpi/jni_util.h>
|
|
|
|
#include "HALUtil.h"
|
|
#include "edu_wpi_first_hal_can_CANJNI.h"
|
|
#include "hal/CAN.h"
|
|
|
|
using namespace hal;
|
|
using namespace wpi::java;
|
|
|
|
extern "C" {
|
|
|
|
/*
|
|
* Class: edu_wpi_first_hal_can_CANJNI
|
|
* Method: FRCNetCommCANSessionMuxSendMessage
|
|
* Signature: (I[BI)V
|
|
*/
|
|
JNIEXPORT void JNICALL
|
|
Java_edu_wpi_first_hal_can_CANJNI_FRCNetCommCANSessionMuxSendMessage
|
|
(JNIEnv* env, jclass, jint messageID, jbyteArray data, jint periodMs)
|
|
{
|
|
JByteArrayRef dataArray{env, data};
|
|
|
|
const uint8_t* dataBuffer =
|
|
reinterpret_cast<const uint8_t*>(dataArray.array().data());
|
|
uint8_t dataSize = dataArray.array().size();
|
|
|
|
int32_t status = 0;
|
|
HAL_CAN_SendMessage(messageID, dataBuffer, dataSize, periodMs, &status);
|
|
CheckCANStatus(env, status, messageID);
|
|
}
|
|
|
|
/*
|
|
* Class: edu_wpi_first_hal_can_CANJNI
|
|
* Method: FRCNetCommCANSessionMuxReceiveMessage
|
|
* Signature: (Ljava/lang/Object;ILjava/lang/Object;)[B
|
|
*/
|
|
JNIEXPORT jbyteArray JNICALL
|
|
Java_edu_wpi_first_hal_can_CANJNI_FRCNetCommCANSessionMuxReceiveMessage
|
|
(JNIEnv* env, jclass, jobject messageID, jint messageIDMask,
|
|
jobject timeStamp)
|
|
{
|
|
uint32_t* messageIDPtr =
|
|
reinterpret_cast<uint32_t*>(env->GetDirectBufferAddress(messageID));
|
|
uint32_t* timeStampPtr =
|
|
reinterpret_cast<uint32_t*>(env->GetDirectBufferAddress(timeStamp));
|
|
|
|
uint8_t dataSize = 0;
|
|
uint8_t buffer[8];
|
|
|
|
int32_t status = 0;
|
|
HAL_CAN_ReceiveMessage(messageIDPtr, messageIDMask, buffer, &dataSize,
|
|
timeStampPtr, &status);
|
|
|
|
if (!CheckCANStatus(env, status, *messageIDPtr)) {
|
|
return nullptr;
|
|
}
|
|
return MakeJByteArray(env, {buffer, static_cast<size_t>(dataSize)});
|
|
}
|
|
|
|
/*
|
|
* Class: edu_wpi_first_hal_can_CANJNI
|
|
* Method: getCANStatus
|
|
* Signature: (Ljava/lang/Object;)V
|
|
*/
|
|
JNIEXPORT void JNICALL
|
|
Java_edu_wpi_first_hal_can_CANJNI_getCANStatus
|
|
(JNIEnv* env, jclass, jobject canStatus)
|
|
{
|
|
float percentBusUtilization = 0;
|
|
uint32_t busOffCount = 0;
|
|
uint32_t txFullCount = 0;
|
|
uint32_t receiveErrorCount = 0;
|
|
uint32_t transmitErrorCount = 0;
|
|
int32_t status = 0;
|
|
HAL_CAN_GetCANStatus(&percentBusUtilization, &busOffCount, &txFullCount,
|
|
&receiveErrorCount, &transmitErrorCount, &status);
|
|
|
|
if (!CheckStatus(env, status)) {
|
|
return;
|
|
}
|
|
|
|
SetCanStatusObject(env, canStatus, percentBusUtilization, busOffCount,
|
|
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"
|