diff --git a/hal/src/main/java/edu/wpi/first/hal/simulation/SimDeviceDataJNI.java b/hal/src/main/java/edu/wpi/first/hal/simulation/SimDeviceDataJNI.java index 8bb15754dd..ea2a9f6066 100644 --- a/hal/src/main/java/edu/wpi/first/hal/simulation/SimDeviceDataJNI.java +++ b/hal/src/main/java/edu/wpi/first/hal/simulation/SimDeviceDataJNI.java @@ -11,6 +11,9 @@ import edu.wpi.first.hal.HALValue; import edu.wpi.first.hal.JNIWrapper; public class SimDeviceDataJNI extends JNIWrapper { + public static native void setSimDeviceEnabled(String prefix, boolean enabled); + public static native boolean isSimDeviceEnabled(String name); + public static native int registerSimDeviceCreatedCallback(String prefix, SimDeviceCallback callback, boolean initialNotify); public static native void cancelSimDeviceCreatedCallback(int uid); diff --git a/hal/src/main/native/include/hal/simulation/SimDeviceData.h b/hal/src/main/native/include/hal/simulation/SimDeviceData.h index 8ab4ba4b9a..bbdd33270a 100644 --- a/hal/src/main/native/include/hal/simulation/SimDeviceData.h +++ b/hal/src/main/native/include/hal/simulation/SimDeviceData.h @@ -23,6 +23,9 @@ typedef void (*HALSIM_SimValueCallback)(const char* name, void* param, extern "C" { #endif +void HALSIM_SetSimDeviceEnabled(const char* prefix, HAL_Bool enabled); +HAL_Bool HALSIM_IsSimDeviceEnabled(const char* name); + int32_t HALSIM_RegisterSimDeviceCreatedCallback( const char* prefix, void* param, HALSIM_SimDeviceCallback callback, HAL_Bool initialNotify); diff --git a/hal/src/main/native/sim/jni/SimDeviceDataJNI.cpp b/hal/src/main/native/sim/jni/SimDeviceDataJNI.cpp index b14e42af18..0b43d24ef6 100644 --- a/hal/src/main/native/sim/jni/SimDeviceDataJNI.cpp +++ b/hal/src/main/native/sim/jni/SimDeviceDataJNI.cpp @@ -303,6 +303,30 @@ void FreeSimDeviceDataJNI(JNIEnv* env) { extern "C" { +/* + * Class: edu_wpi_first_hal_simulation_SimDeviceDataJNI + * Method: setSimDeviceEnabled + * Signature: (Ljava/lang/String;Z)V + */ +JNIEXPORT void JNICALL +Java_edu_wpi_first_hal_simulation_SimDeviceDataJNI_setSimDeviceEnabled + (JNIEnv* env, jclass, jstring prefix, jboolean enabled) +{ + HALSIM_SetSimDeviceEnabled(JStringRef{env, prefix}.c_str(), enabled); +} + +/* + * Class: edu_wpi_first_hal_simulation_SimDeviceDataJNI + * Method: isSimDeviceEnabled + * Signature: (Ljava/lang/String;)Z + */ +JNIEXPORT jboolean JNICALL +Java_edu_wpi_first_hal_simulation_SimDeviceDataJNI_isSimDeviceEnabled + (JNIEnv* env, jclass, jstring name) +{ + return HALSIM_IsSimDeviceEnabled(JStringRef{env, name}.c_str()); +} + /* * Class: edu_wpi_first_hal_simulation_SimDeviceDataJNI * Method: registerSimDeviceCreatedCallback diff --git a/hal/src/main/native/sim/mockdata/SimDeviceData.cpp b/hal/src/main/native/sim/mockdata/SimDeviceData.cpp index 358320aaca..6c0a7f2972 100644 --- a/hal/src/main/native/sim/mockdata/SimDeviceData.cpp +++ b/hal/src/main/native/sim/mockdata/SimDeviceData.cpp @@ -49,12 +49,43 @@ SimDeviceData::Value* SimDeviceData::LookupValue(HAL_SimValueHandle handle) { return deviceImpl->values[handle].get(); } +void SimDeviceData::SetDeviceEnabled(const char* prefix, bool enabled) { + std::scoped_lock lock(m_mutex); + auto it = + std::find_if(m_prefixEnabled.begin(), m_prefixEnabled.end(), + [=](const auto& elem) { return elem.first == prefix; }); + if (it != m_prefixEnabled.end()) { + it->second = enabled; + return; + } + m_prefixEnabled.emplace_back(prefix, enabled); + // keep it sorted by name + // string comparison sorts shorter before longer, so reverse the sort + std::sort(m_prefixEnabled.begin(), m_prefixEnabled.end(), + [](const auto& l, const auto& r) { return l.first >= r.first; }); +} + +bool SimDeviceData::IsDeviceEnabled(const char* name) { + std::scoped_lock lock(m_mutex); + for (const auto& elem : m_prefixEnabled) { + if (wpi::StringRef{name}.startswith(elem.first)) return elem.second; + } + return true; +} + HAL_SimDeviceHandle SimDeviceData::CreateDevice(const char* name) { std::scoped_lock lock(m_mutex); + // don't create if disabled + for (const auto& elem : m_prefixEnabled) { + if (wpi::StringRef{name}.startswith(elem.first)) { + if (elem.second) break; // enabled + return 0; // disabled + } + } + // check for duplicates and don't overwrite them - auto it = m_deviceMap.find(name); - if (it != m_deviceMap.end()) return 0; + if (m_deviceMap.count(name) > 0) return 0; // don't allow more than 4096 devices (limit driven by 12-bit allocation in // value changed callback uid) @@ -326,12 +357,21 @@ void SimDeviceData::ResetData() { std::scoped_lock lock(m_mutex); m_devices.clear(); m_deviceMap.clear(); + m_prefixEnabled.clear(); m_deviceCreated.Reset(); m_deviceFreed.Reset(); } extern "C" { +void HALSIM_SetSimDeviceEnabled(const char* prefix, HAL_Bool enabled) { + SimSimDeviceData->SetDeviceEnabled(prefix, enabled); +} + +HAL_Bool HALSIM_IsSimDeviceEnabled(const char* name) { + return SimSimDeviceData->IsDeviceEnabled(name); +} + int32_t HALSIM_RegisterSimDeviceCreatedCallback( const char* prefix, void* param, HALSIM_SimDeviceCallback callback, HAL_Bool initialNotify) { diff --git a/hal/src/main/native/sim/mockdata/SimDeviceDataInternal.h b/hal/src/main/native/sim/mockdata/SimDeviceDataInternal.h index b71b807575..63c22882e5 100644 --- a/hal/src/main/native/sim/mockdata/SimDeviceDataInternal.h +++ b/hal/src/main/native/sim/mockdata/SimDeviceDataInternal.h @@ -150,6 +150,7 @@ class SimDeviceData { wpi::UidVector, 4> m_devices; wpi::StringMap> m_deviceMap; + std::vector> m_prefixEnabled; wpi::recursive_spinlock m_mutex; @@ -161,6 +162,9 @@ class SimDeviceData { Value* LookupValue(HAL_SimValueHandle handle); public: + void SetDeviceEnabled(const char* prefix, bool enabled); + bool IsDeviceEnabled(const char* name); + HAL_SimDeviceHandle CreateDevice(const char* name); void FreeDevice(HAL_SimDeviceHandle handle); HAL_SimValueHandle CreateValue(HAL_SimDeviceHandle device, const char* name, diff --git a/hal/src/test/native/cpp/mockdata/SimDeviceDataTests.cpp b/hal/src/test/native/cpp/mockdata/SimDeviceDataTests.cpp new file mode 100644 index 0000000000..8f65f5c552 --- /dev/null +++ b/hal/src/test/native/cpp/mockdata/SimDeviceDataTests.cpp @@ -0,0 +1,25 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) 2020 FIRST. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +#include "gtest/gtest.h" +#include "hal/SimDevice.h" +#include "hal/simulation/SimDeviceData.h" + +namespace hal { + +TEST(SimDeviceSimTests, TestEnabled) { + ASSERT_TRUE(HALSIM_IsSimDeviceEnabled("foo")); + HALSIM_SetSimDeviceEnabled("f", false); + HALSIM_SetSimDeviceEnabled("foob", true); + ASSERT_FALSE(HALSIM_IsSimDeviceEnabled("foo")); + ASSERT_TRUE(HALSIM_IsSimDeviceEnabled("foobar")); + ASSERT_TRUE(HALSIM_IsSimDeviceEnabled("bar")); + + ASSERT_EQ(HAL_CreateSimDevice("foo"), 0); +} + +} // namespace hal