From 5a52b514435e3d8f09d105a0c245ffa7d70c771c Mon Sep 17 00:00:00 2001 From: Ryan Blue Date: Fri, 9 Dec 2022 00:58:55 -0500 Subject: [PATCH] [hal] Add RobotController.getSerialNumber() (#4783) --- .../main/java/edu/wpi/first/hal/HALUtil.java | 2 + .../first/hal/simulation/RoboRioDataJNI.java | 4 ++ hal/src/main/native/athena/HAL.cpp | 17 ++++++ .../native/athena/mockdata/RoboRioData.cpp | 13 +++++ hal/src/main/native/cpp/jni/HALUtil.cpp | 14 +++++ .../cpp/jni/simulation/RoboRioDataJNI.cpp | 31 ++++++++++ hal/src/main/native/include/hal/HALBase.h | 15 +++++ .../include/hal/simulation/RoboRioData.h | 11 ++++ hal/src/main/native/sim/HAL.cpp | 4 ++ .../main/native/sim/mockdata/RoboRioData.cpp | 56 +++++++++++++++++++ .../native/sim/mockdata/RoboRioDataInternal.h | 20 +++++++ .../src/main/native/cpp/RobotController.cpp | 9 +++ .../main/native/cpp/simulation/RoboRioSim.cpp | 10 ++++ .../main/native/include/frc/RobotController.h | 9 +++ .../include/frc/simulation/RoboRioSim.h | 15 +++++ .../native/cpp/simulation/RoboRioSimTest.cpp | 17 ++++++ .../wpi/first/wpilibj/RobotController.java | 9 +++ .../first/wpilibj/simulation/RoboRioSim.java | 18 ++++++ .../wpilibj/simulation/RoboRioSimTest.java | 18 ++++++ 19 files changed, 292 insertions(+) diff --git a/hal/src/main/java/edu/wpi/first/hal/HALUtil.java b/hal/src/main/java/edu/wpi/first/hal/HALUtil.java index 6a672aaa0b..ac91a6cec3 100644 --- a/hal/src/main/java/edu/wpi/first/hal/HALUtil.java +++ b/hal/src/main/java/edu/wpi/first/hal/HALUtil.java @@ -22,6 +22,8 @@ public final class HALUtil extends JNIWrapper { public static native int getFPGARevision(); + public static native String getSerialNumber(); + public static native long getFPGATime(); public static native int getHALRuntimeType(); diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/RoboRioDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/simulation/RoboRioDataJNI.java index 16309be341..c7294654b8 100644 --- a/hal/src/main/java/edu/wpi/first/hal/simulation/RoboRioDataJNI.java +++ b/hal/src/main/java/edu/wpi/first/hal/simulation/RoboRioDataJNI.java @@ -151,5 +151,9 @@ public class RoboRioDataJNI extends JNIWrapper { public static native void setBrownoutVoltage(double brownoutVoltage); + public static native String getSerialNumber(); + + public static native void setSerialNumber(String serialNumber); + public static native void resetData(); } diff --git a/hal/src/main/native/athena/HAL.cpp b/hal/src/main/native/athena/HAL.cpp index 0bd967c5f0..fd85319235 100644 --- a/hal/src/main/native/athena/HAL.cpp +++ b/hal/src/main/native/athena/HAL.cpp @@ -18,6 +18,9 @@ #include #include #include +#include +#include +#include #include #include @@ -270,6 +273,20 @@ int64_t HAL_GetFPGARevision(int32_t* status) { return global->readRevision(status); } +size_t HAL_GetSerialNumber(char* buffer, size_t size) { + const char* serialNum = std::getenv("serialnum"); + if (serialNum) { + std::strncpy(buffer, serialNum, size); + buffer[size - 1] = '\0'; + return std::strlen(buffer); + } else { + if (size > 0) { + buffer[0] = '\0'; + } + return 0; + } +} + uint64_t HAL_GetFPGATime(int32_t* status) { hal::init::CheckInit(); if (!global) { diff --git a/hal/src/main/native/athena/mockdata/RoboRioData.cpp b/hal/src/main/native/athena/mockdata/RoboRioData.cpp index 9f6683aaa1..9436629e8d 100644 --- a/hal/src/main/native/athena/mockdata/RoboRioData.cpp +++ b/hal/src/main/native/athena/mockdata/RoboRioData.cpp @@ -29,6 +29,19 @@ DEFINE_CAPI(int32_t, UserFaults5V, 0) DEFINE_CAPI(int32_t, UserFaults3V3, 0) DEFINE_CAPI(double, BrownoutVoltage, 6.75) +int32_t HALSIM_RegisterRoboRioSerialNumberCallback( + HAL_RoboRioStringCallback callback, void* param, HAL_Bool initialNotify) { + return 0; +} +void HALSIM_CancelRoboRioSerialNumberCallback(int32_t uid) {} +size_t HALSIM_GetRoboRioSerialNumber(char* buffer, size_t size) { + if (size > 0) { + buffer[0] = '\0'; + } + return 0; +} +void HALSIM_SetRoboRioSerialNumber(const char* buffer, size_t size) {} + void HALSIM_RegisterRoboRioAllCallbacks(HAL_NotifyCallback callback, void* param, HAL_Bool initialNotify) {} } // extern "C" diff --git a/hal/src/main/native/cpp/jni/HALUtil.cpp b/hal/src/main/native/cpp/jni/HALUtil.cpp index a2f080b872..4f4ed3f97a 100644 --- a/hal/src/main/native/cpp/jni/HALUtil.cpp +++ b/hal/src/main/native/cpp/jni/HALUtil.cpp @@ -456,6 +456,20 @@ Java_edu_wpi_first_hal_HALUtil_getFPGARevision return returnValue; } +/* + * Class: edu_wpi_first_hal_HALUtil + * Method: getSerialNumber + * Signature: ()Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL +Java_edu_wpi_first_hal_HALUtil_getSerialNumber + (JNIEnv* env, jclass) +{ + char serialNum[9]; + size_t len = HAL_GetSerialNumber(serialNum, sizeof(serialNum)); + return MakeJString(env, std::string_view(serialNum, len)); +} + /* * Class: edu_wpi_first_hal_HALUtil * Method: getFPGATime diff --git a/hal/src/main/native/cpp/jni/simulation/RoboRioDataJNI.cpp b/hal/src/main/native/cpp/jni/simulation/RoboRioDataJNI.cpp index 03bb0c5665..289f9b017c 100644 --- a/hal/src/main/native/cpp/jni/simulation/RoboRioDataJNI.cpp +++ b/hal/src/main/native/cpp/jni/simulation/RoboRioDataJNI.cpp @@ -4,11 +4,14 @@ #include +#include + #include "CallbackStore.h" #include "edu_wpi_first_hal_simulation_RoboRioDataJNI.h" #include "hal/simulation/RoboRioData.h" using namespace hal; +using namespace wpi::java; extern "C" { @@ -825,6 +828,34 @@ Java_edu_wpi_first_hal_simulation_RoboRioDataJNI_setBrownoutVoltage HALSIM_SetRoboRioBrownoutVoltage(value); } +/* + * Class: edu_wpi_first_hal_simulation_RoboRioDataJNI + * Method: getSerialNumber + * Signature: ()Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL +Java_edu_wpi_first_hal_simulation_RoboRioDataJNI_getSerialNumber + (JNIEnv* env, jclass) +{ + char serialNum[9]; + size_t len = HALSIM_GetRoboRioSerialNumber(serialNum, sizeof(serialNum)); + return MakeJString(env, std::string_view(serialNum, len)); +} + +/* + * Class: edu_wpi_first_hal_simulation_RoboRioDataJNI + * Method: setSerialNumber + * Signature: (Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL +Java_edu_wpi_first_hal_simulation_RoboRioDataJNI_setSerialNumber + (JNIEnv* env, jclass, jstring serialNumber) +{ + JStringRef serialNumberJString{env, serialNumber}; + HALSIM_SetRoboRioSerialNumber(serialNumberJString.c_str(), + serialNumberJString.size()); +} + /* * Class: edu_wpi_first_hal_simulation_RoboRioDataJNI * Method: resetData diff --git a/hal/src/main/native/include/hal/HALBase.h b/hal/src/main/native/include/hal/HALBase.h index b31ec75013..d2e97cdb21 100644 --- a/hal/src/main/native/include/hal/HALBase.h +++ b/hal/src/main/native/include/hal/HALBase.h @@ -6,6 +6,14 @@ #include +#ifdef __cplusplus +#include +#else + +#include // NOLINT(build/include_order) + +#endif + #include "hal/Types.h" /** @@ -66,6 +74,13 @@ int32_t HAL_GetFPGAVersion(int32_t* status); */ int64_t HAL_GetFPGARevision(int32_t* status); +/** + * Returns the serial number. + * + * @return Serial number. + */ +size_t HAL_GetSerialNumber(char* buffer, size_t size); + /** * Returns the runtime type of the HAL. * diff --git a/hal/src/main/native/include/hal/simulation/RoboRioData.h b/hal/src/main/native/include/hal/simulation/RoboRioData.h index 8f33bc587d..9c12bd55ff 100644 --- a/hal/src/main/native/include/hal/simulation/RoboRioData.h +++ b/hal/src/main/native/include/hal/simulation/RoboRioData.h @@ -4,9 +4,14 @@ #pragma once +#include + #include "hal/Types.h" #include "hal/simulation/NotifyListener.h" +typedef void (*HAL_RoboRioStringCallback)(const char* name, void* param, + const char* str, size_t size); + #ifdef __cplusplus extern "C" { #endif @@ -121,6 +126,12 @@ void HALSIM_CancelRoboRioBrownoutVoltageCallback(int32_t uid); double HALSIM_GetRoboRioBrownoutVoltage(void); void HALSIM_SetRoboRioBrownoutVoltage(double brownoutVoltage); +int32_t HALSIM_RegisterRoboRioSerialNumberCallback( + HAL_RoboRioStringCallback callback, void* param, HAL_Bool initialNotify); +void HALSIM_CancelRoboRioSerialNumberCallback(int32_t uid); +size_t HALSIM_GetRoboRioSerialNumber(char* buffer, size_t size); +void HALSIM_SetRoboRioSerialNumber(const char* serialNumber, size_t size); + void HALSIM_RegisterRoboRioAllCallbacks(HAL_NotifyCallback callback, void* param, HAL_Bool initialNotify); diff --git a/hal/src/main/native/sim/HAL.cpp b/hal/src/main/native/sim/HAL.cpp index eca7c2578b..e7d5a348ae 100644 --- a/hal/src/main/native/sim/HAL.cpp +++ b/hal/src/main/native/sim/HAL.cpp @@ -280,6 +280,10 @@ int64_t HAL_GetFPGARevision(int32_t* status) { return 0; // TODO: Find a better number to return; } +size_t HAL_GetSerialNumber(char* buffer, size_t size) { + return HALSIM_GetRoboRioSerialNumber(buffer, size); +} + uint64_t HAL_GetFPGATime(int32_t* status) { return hal::GetFPGATime(); } diff --git a/hal/src/main/native/sim/mockdata/RoboRioData.cpp b/hal/src/main/native/sim/mockdata/RoboRioData.cpp index 6932620bb3..32f8c3db9f 100644 --- a/hal/src/main/native/sim/mockdata/RoboRioData.cpp +++ b/hal/src/main/native/sim/mockdata/RoboRioData.cpp @@ -32,6 +32,44 @@ void RoboRioData::ResetData() { userFaults5V.Reset(0); userFaults3V3.Reset(0); brownoutVoltage.Reset(6.75); + m_serialNumber = ""; +} + +int32_t RoboRioData::RegisterSerialNumberCallback( + HAL_RoboRioStringCallback callback, void* param, HAL_Bool initialNotify) { + std::scoped_lock lock(m_serialNumberMutex); + int32_t uid = m_serialNumberCallbacks.Register(callback, param); + if (initialNotify) { + callback(GetSerialNumberName(), param, m_serialNumber.c_str(), + m_serialNumber.size()); + } + return uid; +} + +void RoboRioData::CancelSerialNumberCallback(int32_t uid) { + m_serialNumberCallbacks.Cancel(uid); +} + +size_t RoboRioData::GetSerialNumber(char* buffer, size_t size) { + std::scoped_lock lock(m_serialNumberMutex); + size_t copied = m_serialNumber.copy(buffer, size); + // Null terminate + if (copied == size) { + copied -= 1; + } + buffer[copied] = '\0'; + return copied; +} + +void RoboRioData::SetSerialNumber(const char* serialNumber, size_t size) { + // Limit serial number to 8 characters internally- serialnum environment + // variable is always 8 characters + if (size > 8) { + size = 8; + } + std::scoped_lock lock(m_serialNumberMutex); + m_serialNumber = std::string(serialNumber, size); + m_serialNumberCallbacks(m_serialNumber.c_str(), m_serialNumber.size()); } extern "C" { @@ -60,6 +98,24 @@ DEFINE_CAPI(int32_t, UserFaults5V, userFaults5V) DEFINE_CAPI(int32_t, UserFaults3V3, userFaults3V3) DEFINE_CAPI(double, BrownoutVoltage, brownoutVoltage) +int32_t HALSIM_RegisterRoboRioSerialNumberCallback( + HAL_RoboRioStringCallback callback, void* param, HAL_Bool initialNotify) { + return SimRoboRioData->RegisterSerialNumberCallback(callback, param, + initialNotify); +} +void HALSIM_CancelRoboRioSerialNumberCallback(int32_t uid) { + return SimRoboRioData->CancelSerialNumberCallback(uid); +} +size_t HALSIM_GetRoboRioSerialNumber(char* buffer, size_t size) { + return SimRoboRioData->GetSerialNumber(buffer, size); +} +void HALSIM_SetRoboRioSerialNumber(const char* serialNumber, size_t size) { + SimRoboRioData->SetSerialNumber(serialNumber, size); +} + +void HALSIM_RegisterRoboRioAllCallbacks(HAL_NotifyCallback callback, + void* param, HAL_Bool initialNotify); + #define REGISTER(NAME) \ SimRoboRioData->NAME.RegisterCallback(callback, param, initialNotify) diff --git a/hal/src/main/native/sim/mockdata/RoboRioDataInternal.h b/hal/src/main/native/sim/mockdata/RoboRioDataInternal.h index 99e61eaa65..7638b722f1 100644 --- a/hal/src/main/native/sim/mockdata/RoboRioDataInternal.h +++ b/hal/src/main/native/sim/mockdata/RoboRioDataInternal.h @@ -4,6 +4,11 @@ #pragma once +#include +#include + +#include + #include "hal/simulation/RoboRioData.h" #include "hal/simulation/SimDataValue.h" @@ -26,6 +31,8 @@ class RoboRioData { HAL_SIMDATAVALUE_DEFINE_NAME(UserFaults3V3) HAL_SIMDATAVALUE_DEFINE_NAME(BrownoutVoltage) + HAL_SIMCALLBACKREGISTRY_DEFINE_NAME(SerialNumber) + public: SimDataValue fpgaButton{false}; SimDataValue vInVoltage{12.0}; @@ -50,7 +57,20 @@ class RoboRioData { SimDataValue brownoutVoltage{ 6.75}; + int32_t RegisterSerialNumberCallback(HAL_RoboRioStringCallback callback, + void* param, HAL_Bool initialNotify); + void CancelSerialNumberCallback(int32_t uid); + size_t GetSerialNumber(char* buffer, size_t size); + void SetSerialNumber(const char* serialNumber, size_t size); + virtual void ResetData(); + + private: + wpi::spinlock m_serialNumberMutex; + std::string m_serialNumber; + + SimCallbackRegistry + m_serialNumberCallbacks; }; extern RoboRioData* SimRoboRioData; } // namespace hal diff --git a/wpilibc/src/main/native/cpp/RobotController.cpp b/wpilibc/src/main/native/cpp/RobotController.cpp index a800452960..5beccde07f 100644 --- a/wpilibc/src/main/native/cpp/RobotController.cpp +++ b/wpilibc/src/main/native/cpp/RobotController.cpp @@ -4,6 +4,8 @@ #include "frc/RobotController.h" +#include + #include #include #include @@ -26,6 +28,13 @@ int64_t RobotController::GetFPGARevision() { return revision; } +std::string RobotController::GetSerialNumber() { + // Serial number is 8 characters + char serialNum[9]; + size_t len = HAL_GetSerialNumber(serialNum, sizeof(serialNum)); + return std::string(serialNum, len); +} + uint64_t RobotController::GetFPGATime() { int32_t status = 0; uint64_t time = HAL_GetFPGATime(&status); diff --git a/wpilibc/src/main/native/cpp/simulation/RoboRioSim.cpp b/wpilibc/src/main/native/cpp/simulation/RoboRioSim.cpp index d05bba9c74..19efb0cb10 100644 --- a/wpilibc/src/main/native/cpp/simulation/RoboRioSim.cpp +++ b/wpilibc/src/main/native/cpp/simulation/RoboRioSim.cpp @@ -284,6 +284,16 @@ void RoboRioSim::SetBrownoutVoltage(units::volt_t vInVoltage) { HALSIM_SetRoboRioBrownoutVoltage(vInVoltage.value()); } +std::string RoboRioSim::GetSerialNumber() { + char serialNum[9]; + size_t len = HALSIM_GetRoboRioSerialNumber(serialNum, sizeof(serialNum)); + return std::string(serialNum, len); +} + +void RoboRioSim::SetSerialNumber(std::string_view serialNumber) { + HALSIM_SetRoboRioSerialNumber(serialNumber.data(), serialNumber.size()); +} + void RoboRioSim::ResetData() { HALSIM_ResetRoboRioData(); } diff --git a/wpilibc/src/main/native/include/frc/RobotController.h b/wpilibc/src/main/native/include/frc/RobotController.h index e9750f01ba..2355139f1b 100644 --- a/wpilibc/src/main/native/include/frc/RobotController.h +++ b/wpilibc/src/main/native/include/frc/RobotController.h @@ -6,6 +6,8 @@ #include +#include + #include namespace frc { @@ -42,6 +44,13 @@ class RobotController { */ static int64_t GetFPGARevision(); + /** + * Returns the serial number of the roboRIO. + * + * @return The serial number of the roboRIO. + */ + static std::string GetSerialNumber(); + /** * Read the microsecond-resolution timer on the FPGA. * diff --git a/wpilibc/src/main/native/include/frc/simulation/RoboRioSim.h b/wpilibc/src/main/native/include/frc/simulation/RoboRioSim.h index 10951061fc..5fbc72217b 100644 --- a/wpilibc/src/main/native/include/frc/simulation/RoboRioSim.h +++ b/wpilibc/src/main/native/include/frc/simulation/RoboRioSim.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include #include @@ -418,6 +419,20 @@ class RoboRioSim { */ static void SetBrownoutVoltage(units::volt_t brownoutVoltage); + /** + * Get the serial number. + * + * @return The serial number. + */ + static std::string GetSerialNumber(); + + /** + * Set the serial number. + * + * @param serialNumber The serial number. + */ + static void SetSerialNumber(std::string_view serialNumber); + /** * Reset all simulation data. */ diff --git a/wpilibc/src/test/native/cpp/simulation/RoboRioSimTest.cpp b/wpilibc/src/test/native/cpp/simulation/RoboRioSimTest.cpp index c6e93d4eec..406e56fa53 100644 --- a/wpilibc/src/test/native/cpp/simulation/RoboRioSimTest.cpp +++ b/wpilibc/src/test/native/cpp/simulation/RoboRioSimTest.cpp @@ -207,4 +207,21 @@ TEST(RoboRioSimTest, Set3V3) { EXPECT_EQ(kTestFaults, RobotController::GetFaultCount3V3()); } +TEST(RoboRioSimTest, SetSerialNumber) { + const std::string kSerialNum = "Hello"; + + RoboRioSim::ResetData(); + + RoboRioSim::SetSerialNumber(kSerialNum); + EXPECT_EQ(kSerialNum, RoboRioSim::GetSerialNumber()); + EXPECT_EQ(kSerialNum, RobotController::GetSerialNumber()); + + const std::string kSerialNumberOverflow = "SerialNumber"; + const std::string kSerialNumberTruncated = kSerialNumberOverflow.substr(0, 8); + + RoboRioSim::SetSerialNumber(kSerialNumberOverflow); + EXPECT_EQ(kSerialNumberTruncated, RoboRioSim::GetSerialNumber()); + EXPECT_EQ(kSerialNumberTruncated, RobotController::GetSerialNumber()); +} + } // namespace frc::sim diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotController.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotController.java index c0d2705b4b..4f5da38885 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotController.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotController.java @@ -36,6 +36,15 @@ public final class RobotController { return (long) HALUtil.getFPGARevision(); } + /** + * Return the serial number of the roboRIO. + * + * @return The serial number of the roboRIO. + */ + public static String getSerialNumber() { + return HALUtil.getSerialNumber(); + } + /** * Read the microsecond timer from the FPGA. * diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/RoboRioSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/RoboRioSim.java index fc341dc90f..3888ed562f 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/RoboRioSim.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/RoboRioSim.java @@ -525,6 +525,24 @@ public final class RoboRioSim { RoboRioDataJNI.setBrownoutVoltage(vInVoltage); } + /** + * Get the serial number. + * + * @return The serial number. + */ + public static String getSerialNumber() { + return RoboRioDataJNI.getSerialNumber(); + } + + /** + * Set the serial number. + * + * @param serialNumber The serial number. + */ + public static void setSerialNumber(String serialNumber) { + RoboRioDataJNI.setSerialNumber(serialNumber); + } + /** Reset all simulation data. */ public static void resetData() { RoboRioDataJNI.resetData(); diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/RoboRioSimTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/RoboRioSimTest.java index c1988b3e37..3bba249f98 100644 --- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/RoboRioSimTest.java +++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/simulation/RoboRioSimTest.java @@ -208,4 +208,22 @@ class RoboRioSimTest { assertEquals(kTestFaults, RobotController.getFaultCount3V3()); } } + + @Test + void testSerialNumber() { + RoboRioSim.resetData(); + + final String kSerialNumber = "Hello"; + + RoboRioSim.setSerialNumber(kSerialNumber); + assertEquals(kSerialNumber, RoboRioSim.getSerialNumber()); + assertEquals(kSerialNumber, RobotController.getSerialNumber()); + + // Make sure it truncates at 8 characters properly + final String kSerialNumberOverflow = "SerialNumber"; + final String kSerialNumberTruncated = kSerialNumberOverflow.substring(0, 8); + RoboRioSim.setSerialNumber(kSerialNumberOverflow); + assertEquals(kSerialNumberTruncated, RoboRioSim.getSerialNumber()); + assertEquals(kSerialNumberTruncated, RobotController.getSerialNumber()); + } }