diff --git a/hal/src/main/java/edu/wpi/first/hal/CANAPIJNI.java b/hal/src/main/java/edu/wpi/first/hal/CANAPIJNI.java index 8d805e09e7..029cc6d5e9 100644 --- a/hal/src/main/java/edu/wpi/first/hal/CANAPIJNI.java +++ b/hal/src/main/java/edu/wpi/first/hal/CANAPIJNI.java @@ -18,6 +18,8 @@ public class CANAPIJNI extends JNIWrapper { public static native void writeCANPacketRepeating(int handle, byte[] data, int apiId, int repeatMs); + public static native void writeCANRTRFrame(int handle, int length, int apiId); + public static native void stopCANPacketRepeating(int handle, int apiId); public static native boolean readCANPacketNew(int handle, int apiId, CANData data); diff --git a/hal/src/main/native/athena/CANAPI.cpp b/hal/src/main/native/athena/CANAPI.cpp index e2d351e5b2..44cdb58aa9 100644 --- a/hal/src/main/native/athena/CANAPI.cpp +++ b/hal/src/main/native/athena/CANAPI.cpp @@ -140,6 +140,27 @@ void HAL_WriteCANPacketRepeating(HAL_CANHandle handle, const uint8_t* data, can->periodicSends[apiId] = repeatMs; } +void HAL_WriteCANRTRFrame(HAL_CANHandle handle, int32_t length, int32_t apiId, + int32_t* status) { + auto can = canHandles->Get(handle); + if (!can) { + *status = HAL_HANDLE_ERROR; + return; + } + auto id = CreateCANId(can.get(), apiId); + id |= HAL_CAN_IS_FRAME_REMOTE; + uint8_t data[8]; + std::memset(data, 0, sizeof(data)); + + HAL_CAN_SendMessage(id, data, length, HAL_CAN_SEND_PERIOD_NO_REPEAT, status); + + if (*status != 0) { + return; + } + std::scoped_lock lock(can->mapMutex); + can->periodicSends[apiId] = -1; +} + void HAL_StopCANPacketRepeating(HAL_CANHandle handle, int32_t apiId, int32_t* status) { auto can = canHandles->Get(handle); diff --git a/hal/src/main/native/cpp/jni/CANAPIJNI.cpp b/hal/src/main/native/cpp/jni/CANAPIJNI.cpp index eb958c5e77..7ac7cf66ad 100644 --- a/hal/src/main/native/cpp/jni/CANAPIJNI.cpp +++ b/hal/src/main/native/cpp/jni/CANAPIJNI.cpp @@ -92,6 +92,21 @@ Java_edu_wpi_first_hal_CANAPIJNI_writeCANPacketRepeating CheckStatus(env, status); } +/* + * Class: edu_wpi_first_hal_CANAPIJNI + * Method: writeCANRTRFrame + * Signature: (III)V + */ +JNIEXPORT void JNICALL +Java_edu_wpi_first_hal_CANAPIJNI_writeCANRTRFrame + (JNIEnv* env, jclass, jint handle, jint length, jint apiId) +{ + auto halHandle = static_cast(handle); + int32_t status = 0; + HAL_WriteCANRTRFrame(halHandle, static_cast(length), apiId, &status); + CheckStatus(env, status); +} + /* * Class: edu_wpi_first_hal_CANAPIJNI * Method: stopCANPacketRepeating diff --git a/hal/src/main/native/include/hal/CANAPI.h b/hal/src/main/native/include/hal/CANAPI.h index 2ddd6c69d6..7a6bd88c4b 100644 --- a/hal/src/main/native/include/hal/CANAPI.h +++ b/hal/src/main/native/include/hal/CANAPI.h @@ -73,6 +73,20 @@ void HAL_WriteCANPacketRepeating(HAL_CANHandle handle, const uint8_t* data, int32_t length, int32_t apiId, int32_t repeatMs, int32_t* status); +/** + * Writes an RTR frame of the specified length to the CAN device with the + * specific ID. + * + * By spec, the length must be equal to the length sent by the other device, + * otherwise behavior is unspecified. + * + * @param handle the CAN handle + * @param length the length of data to request (0-8) + * @param apiId the ID to write (0-1023) + */ +void HAL_WriteCANRTRFrame(HAL_CANHandle handle, int32_t length, int32_t apiId, + int32_t* status); + /** * Stops a repeating packet with a specific ID. * diff --git a/hal/src/main/native/sim/CANAPI.cpp b/hal/src/main/native/sim/CANAPI.cpp index 76d5f1493d..08b0989668 100644 --- a/hal/src/main/native/sim/CANAPI.cpp +++ b/hal/src/main/native/sim/CANAPI.cpp @@ -147,6 +147,27 @@ void HAL_WriteCANPacketRepeating(HAL_CANHandle handle, const uint8_t* data, can->periodicSends[apiId] = repeatMs; } +void HAL_WriteCANRTRFrame(HAL_CANHandle handle, int32_t length, int32_t apiId, + int32_t* status) { + auto can = canHandles->Get(handle); + if (!can) { + *status = HAL_HANDLE_ERROR; + return; + } + auto id = CreateCANId(can.get(), apiId); + id |= HAL_CAN_IS_FRAME_REMOTE; + uint8_t data[8]; + std::memset(data, 0, sizeof(data)); + + HAL_CAN_SendMessage(id, data, length, HAL_CAN_SEND_PERIOD_NO_REPEAT, status); + + if (*status != 0) { + return; + } + std::scoped_lock lock(can->mapMutex); + can->periodicSends[apiId] = -1; +} + void HAL_StopCANPacketRepeating(HAL_CANHandle handle, int32_t apiId, int32_t* status) { auto can = canHandles->Get(handle); diff --git a/wpilibc/src/main/native/cpp/CAN.cpp b/wpilibc/src/main/native/cpp/CAN.cpp index 9c81ba6f16..35a926a3af 100644 --- a/wpilibc/src/main/native/cpp/CAN.cpp +++ b/wpilibc/src/main/native/cpp/CAN.cpp @@ -65,6 +65,12 @@ void CAN::WritePacketRepeating(const uint8_t* data, int length, int apiId, wpi_setErrorWithContext(status, HAL_GetErrorMessage(status)); } +void CAN::WriteRTRFrame(int length, int apiId) { + int32_t status = 0; + HAL_WriteCANRTRFrame(m_handle, length, apiId, &status); + wpi_setErrorWithContext(status, HAL_GetErrorMessage(status)); +} + void CAN::StopPacketRepeating(int apiId) { int32_t status = 0; HAL_StopCANPacketRepeating(m_handle, apiId, &status); diff --git a/wpilibc/src/main/native/include/frc/CAN.h b/wpilibc/src/main/native/include/frc/CAN.h index 8c383be63b..ed861fb4a7 100644 --- a/wpilibc/src/main/native/include/frc/CAN.h +++ b/wpilibc/src/main/native/include/frc/CAN.h @@ -83,6 +83,16 @@ class CAN : public ErrorBase { void WritePacketRepeating(const uint8_t* data, int length, int apiId, int repeatMs); + /** + * Write an RTR frame to the CAN device with a specific ID. This ID is 10 + * bits. The length by spec must match what is returned by the responding + * device + * + * @param length The length to request (0 to 8) + * @param apiId The API ID to write. + */ + void WriteRTRFrame(int length, int apiId); + /** * Stop a repeating packet with a specific ID. This ID is 10 bits. * diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/CAN.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/CAN.java index 67d4c1cc2a..759056f872 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/CAN.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/CAN.java @@ -89,6 +89,17 @@ public class CAN implements Closeable { CANAPIJNI.writeCANPacketRepeating(m_handle, data, apiId, repeatMs); } + /** + * Write an RTR frame to the CAN device with a specific ID. This ID is 10 bits. + * The length by spec must match what is returned by the responding device + * + * @param length The length to request (0 to 8) + * @param apiId The API ID to write. + */ + public void writeRTRFrame(int length, int apiId) { + CANAPIJNI.writeCANRTRFrame(m_handle, length, apiId); + } + /** * Stop a repeating packet with a specific ID. This ID is 10 bits. *