diff --git a/hal/src/main/java/edu/wpi/first/hal/SimDeviceJNI.java b/hal/src/main/java/edu/wpi/first/hal/SimDeviceJNI.java index 5dd7dfa344..427991643f 100644 --- a/hal/src/main/java/edu/wpi/first/hal/SimDeviceJNI.java +++ b/hal/src/main/java/edu/wpi/first/hal/SimDeviceJNI.java @@ -352,4 +352,13 @@ public class SimDeviceJNI extends JNIWrapper { public static void setSimValueBoolean(int handle, boolean value) { setSimValueNative(handle, HALValue.kBoolean, value ? 1 : 0, 0.0); } + + /** + * Resets a simulated double or integral value to 0. Has no effect on other value types. Use this + * instead of Set(0) for resetting incremental sensor values like encoder counts or gyro + * accumulated angle to ensure correct behavior in a distributed system (e.g. WebSockets). + * + * @param handle simulated value handle + */ + public static native void resetSimValue(int handle); } diff --git a/hal/src/main/java/edu/wpi/first/hal/SimDouble.java b/hal/src/main/java/edu/wpi/first/hal/SimDouble.java index 5e99ae99d2..508208fad2 100644 --- a/hal/src/main/java/edu/wpi/first/hal/SimDouble.java +++ b/hal/src/main/java/edu/wpi/first/hal/SimDouble.java @@ -32,4 +32,13 @@ public class SimDouble extends SimValue { public void set(double value) { SimDeviceJNI.setSimValueDouble(m_handle, value); } + + /** + * Resets the simulated value to 0. Use this instead of Set(0) for resetting incremental sensor + * values like encoder counts or gyro accumulated angle to ensure correct behavior in a + * distributed system (e.g. WebSockets). + */ + public void reset() { + SimDeviceJNI.resetSimValue(m_handle); + } } diff --git a/hal/src/main/java/edu/wpi/first/hal/SimInt.java b/hal/src/main/java/edu/wpi/first/hal/SimInt.java index 445667b9ab..f2d30ebb98 100644 --- a/hal/src/main/java/edu/wpi/first/hal/SimInt.java +++ b/hal/src/main/java/edu/wpi/first/hal/SimInt.java @@ -32,4 +32,13 @@ public class SimInt extends SimValue { public void set(int value) { SimDeviceJNI.setSimValueInt(m_handle, value); } + + /** + * Resets the simulated value to 0. Use this instead of Set(0) for resetting incremental sensor + * values like encoder counts or gyro accumulated angle to ensure correct behavior in a + * distributed system (e.g. WebSockets). + */ + public void reset() { + SimDeviceJNI.resetSimValue(m_handle); + } } diff --git a/hal/src/main/java/edu/wpi/first/hal/SimLong.java b/hal/src/main/java/edu/wpi/first/hal/SimLong.java index 830e4f34c8..80ad963677 100644 --- a/hal/src/main/java/edu/wpi/first/hal/SimLong.java +++ b/hal/src/main/java/edu/wpi/first/hal/SimLong.java @@ -32,4 +32,13 @@ public class SimLong extends SimValue { public void set(long value) { SimDeviceJNI.setSimValueLong(m_handle, value); } + + /** + * Resets the simulated value to 0. Use this instead of Set(0) for resetting incremental sensor + * values like encoder counts or gyro accumulated angle to ensure correct behavior in a + * distributed system (e.g. WebSockets). + */ + public void reset() { + SimDeviceJNI.resetSimValue(m_handle); + } } 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 03c009f711..36d3388000 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 @@ -60,6 +60,19 @@ public class SimDeviceDataJNI extends JNIWrapper { public static native void cancelSimValueChangedCallback(int uid); + /** + * Register a callback for SimDeviceJNI.resetSimValue(). The callback is called with the old + * value. + * + * @param handle simulated value handle + * @param callback callback + * @param initialNotify ignored (present for consistency) + */ + public static native int registerSimValueResetCallback( + int handle, SimValueCallback2 callback, boolean initialNotify); + + public static native void cancelSimValueResetCallback(int uid); + public static native int getSimValueHandle(int device, String name); public static class SimValueInfo { diff --git a/hal/src/main/native/athena/SimDevice.cpp b/hal/src/main/native/athena/SimDevice.cpp index b92d792819..3a15f46056 100644 --- a/hal/src/main/native/athena/SimDevice.cpp +++ b/hal/src/main/native/athena/SimDevice.cpp @@ -40,6 +40,8 @@ void HAL_GetSimValue(HAL_SimValueHandle handle, struct HAL_Value* value) { void HAL_SetSimValue(HAL_SimValueHandle handle, const struct HAL_Value* value) { } +void HAL_ResetSimValue(HAL_SimValueHandle handle) {} + hal::SimDevice::SimDevice(const char* name, int index) {} hal::SimDevice::SimDevice(const char* name, int index, int channel) {} diff --git a/hal/src/main/native/athena/mockdata/SimDeviceData.cpp b/hal/src/main/native/athena/mockdata/SimDeviceData.cpp index e3ade62587..08bd8ce9b8 100644 --- a/hal/src/main/native/athena/mockdata/SimDeviceData.cpp +++ b/hal/src/main/native/athena/mockdata/SimDeviceData.cpp @@ -63,6 +63,15 @@ int32_t HALSIM_RegisterSimValueChangedCallback(HAL_SimValueHandle handle, void HALSIM_CancelSimValueChangedCallback(int32_t uid) {} +int32_t HALSIM_RegisterSimValueResetCallback(HAL_SimValueHandle handle, + void* param, + HALSIM_SimValueCallback callback, + HAL_Bool initialNotify) { + return 0; +} + +void HALSIM_CancelSimValueResetCallback(int32_t uid) {} + HAL_SimValueHandle HALSIM_GetSimValueHandle(HAL_SimDeviceHandle device, const char* name) { return 0; diff --git a/hal/src/main/native/cpp/jni/SimDeviceJNI.cpp b/hal/src/main/native/cpp/jni/SimDeviceJNI.cpp index fed774b811..e036174eb4 100644 --- a/hal/src/main/native/cpp/jni/SimDeviceJNI.cpp +++ b/hal/src/main/native/cpp/jni/SimDeviceJNI.cpp @@ -225,4 +225,16 @@ Java_edu_wpi_first_hal_SimDeviceJNI_setSimValueNative HAL_SetSimValue(handle, ValueFromJava(type, value1, value2)); } +/* + * Class: edu_wpi_first_hal_SimDeviceJNI + * Method: resetSimValue + * Signature: (I)V + */ +JNIEXPORT void JNICALL +Java_edu_wpi_first_hal_SimDeviceJNI_resetSimValue + (JNIEnv*, jclass, jint handle) +{ + HAL_ResetSimValue(handle); +} + } // extern "C" diff --git a/hal/src/main/native/cpp/jni/simulation/SimDeviceDataJNI.cpp b/hal/src/main/native/cpp/jni/simulation/SimDeviceDataJNI.cpp index a6add4b1a5..5f02ebcbc1 100644 --- a/hal/src/main/native/cpp/jni/simulation/SimDeviceDataJNI.cpp +++ b/hal/src/main/native/cpp/jni/simulation/SimDeviceDataJNI.cpp @@ -600,6 +600,32 @@ Java_edu_wpi_first_hal_simulation_SimDeviceDataJNI_cancelSimValueChangedCallback FreeValueCallback(env, uid, &HALSIM_CancelSimValueChangedCallback); } +/* + * Class: edu_wpi_first_hal_simulation_SimDeviceDataJNI + * Method: registerSimValueResetCallback + * Signature: (ILjava/lang/Object;Z)I + */ +JNIEXPORT jint JNICALL +Java_edu_wpi_first_hal_simulation_SimDeviceDataJNI_registerSimValueResetCallback + (JNIEnv* env, jclass, jint handle, jobject callback, jboolean initialNotify) +{ + return AllocateValueCallback(env, static_cast(handle), + callback, true, initialNotify, + &HALSIM_RegisterSimValueResetCallback); +} + +/* + * Class: edu_wpi_first_hal_simulation_SimDeviceDataJNI + * Method: cancelSimValueResetCallback + * Signature: (I)V + */ +JNIEXPORT void JNICALL +Java_edu_wpi_first_hal_simulation_SimDeviceDataJNI_cancelSimValueResetCallback + (JNIEnv* env, jclass, jint uid) +{ + FreeValueCallback(env, uid, &HALSIM_CancelSimValueResetCallback); +} + /* * Class: edu_wpi_first_hal_simulation_SimDeviceDataJNI * Method: getSimValueHandle diff --git a/hal/src/main/native/include/hal/SimDevice.h b/hal/src/main/native/include/hal/SimDevice.h index 4a79d3a3f9..339bb7df61 100644 --- a/hal/src/main/native/include/hal/SimDevice.h +++ b/hal/src/main/native/include/hal/SimDevice.h @@ -327,6 +327,17 @@ inline void HAL_SetSimValueBoolean(HAL_SimValueHandle handle, HAL_Bool value) { HAL_SetSimValue(handle, &v); } +/** + * Resets a simulated double or integral value to 0. + * Has no effect on other value types. + * Use this instead of Set(0) for resetting incremental sensor values like + * encoder counts or gyro accumulated angle to ensure correct behavior in a + * distributed system (e.g. WebSockets). + * + * @param handle simulated value handle + */ +void HAL_ResetSimValue(HAL_SimValueHandle handle); + /** @} */ #ifdef __cplusplus @@ -420,6 +431,13 @@ class SimInt : public SimValue { * @param value the value to set */ void Set(int32_t value) { HAL_SetSimValueInt(m_handle, value); } + + /** + * Resets the simulated value to 0. Use this instead of Set(0) for resetting + * incremental sensor values like encoder counts or gyro accumulated angle + * to ensure correct behavior in a distributed system (e.g. WebSockets). + */ + void Reset() { HAL_ResetSimValue(m_handle); } }; /** @@ -454,6 +472,13 @@ class SimLong : public SimValue { * @param value the value to set */ void Set(int64_t value) { HAL_SetSimValueLong(m_handle, value); } + + /** + * Resets the simulated value to 0. Use this instead of Set(0) for resetting + * incremental sensor values like encoder counts or gyro accumulated angle + * to ensure correct behavior in a distributed system (e.g. WebSockets). + */ + void Reset() { HAL_ResetSimValue(m_handle); } }; /** @@ -488,6 +513,13 @@ class SimDouble : public SimValue { * @param value the value to set */ void Set(double value) { HAL_SetSimValueDouble(m_handle, value); } + + /** + * Resets the simulated value to 0. Use this instead of Set(0) for resetting + * incremental sensor values like encoder counts or gyro accumulated angle + * to ensure correct behavior in a distributed system (e.g. WebSockets). + */ + void Reset() { HAL_ResetSimValue(m_handle); } }; /** diff --git a/hal/src/main/native/include/hal/simulation/SimDeviceData.h b/hal/src/main/native/include/hal/simulation/SimDeviceData.h index 36750470ef..c4342066c9 100644 --- a/hal/src/main/native/include/hal/simulation/SimDeviceData.h +++ b/hal/src/main/native/include/hal/simulation/SimDeviceData.h @@ -57,6 +57,21 @@ int32_t HALSIM_RegisterSimValueChangedCallback(HAL_SimValueHandle handle, void HALSIM_CancelSimValueChangedCallback(int32_t uid); +/** + * Register a callback for HAL_SimValueReset(). The callback is called with + * the old value. + * + * @param handle simulated value handle + * @param callback callback + * @param initialNotify ignored (present for consistency) + */ +int32_t HALSIM_RegisterSimValueResetCallback(HAL_SimValueHandle handle, + void* param, + HALSIM_SimValueCallback callback, + HAL_Bool initialNotify); + +void HALSIM_CancelSimValueResetCallback(int32_t uid); + HAL_SimValueHandle HALSIM_GetSimValueHandle(HAL_SimDeviceHandle device, const char* name); diff --git a/hal/src/main/native/sim/SimDevice.cpp b/hal/src/main/native/sim/SimDevice.cpp index 9d7ae1c678..3b95555c26 100644 --- a/hal/src/main/native/sim/SimDevice.cpp +++ b/hal/src/main/native/sim/SimDevice.cpp @@ -61,6 +61,10 @@ void HAL_SetSimValue(HAL_SimValueHandle handle, const struct HAL_Value* value) { SimSimDeviceData->SetValue(handle, *value); } +void HAL_ResetSimValue(HAL_SimValueHandle handle) { + SimSimDeviceData->ResetValue(handle); +} + hal::SimDevice::SimDevice(const char* name, int index) { wpi::SmallString<128> fullname; wpi::raw_svector_ostream os(fullname); diff --git a/hal/src/main/native/sim/mockdata/SimDeviceData.cpp b/hal/src/main/native/sim/mockdata/SimDeviceData.cpp index 4f4fdc688d..df7e12f542 100644 --- a/hal/src/main/native/sim/mockdata/SimDeviceData.cpp +++ b/hal/src/main/native/sim/mockdata/SimDeviceData.cpp @@ -220,6 +220,47 @@ void SimDeviceData::SetValue(HAL_SimValueHandle handle, valueImpl->direction, &value); } +void SimDeviceData::ResetValue(HAL_SimValueHandle handle) { + std::scoped_lock lock(m_mutex); + Value* valueImpl = LookupValue(handle); + if (!valueImpl) { + return; + } + + // don't notify reset if we aren't going to actually reset anything + switch (valueImpl->value.type) { + case HAL_INT: + case HAL_LONG: + case HAL_DOUBLE: + break; + default: + return; + } + + // notify reset callbacks (done here so they're called with the old value) + valueImpl->reset(valueImpl->name.c_str(), valueImpl->handle, + valueImpl->direction, &valueImpl->value); + + // set user-facing value to 0 + switch (valueImpl->value.type) { + case HAL_INT: + valueImpl->value.data.v_int = 0; + break; + case HAL_LONG: + valueImpl->value.data.v_long = 0; + break; + case HAL_DOUBLE: + valueImpl->value.data.v_double = 0; + break; + default: + return; + } + + // notify changed callbacks + valueImpl->changed(valueImpl->name.c_str(), valueImpl->handle, + valueImpl->direction, &valueImpl->value); +} + int32_t SimDeviceData::RegisterDeviceCreatedCallback( const char* prefix, void* param, HALSIM_SimDeviceCallback callback, bool initialNotify) { @@ -368,6 +409,35 @@ void SimDeviceData::CancelValueChangedCallback(int32_t uid) { valueImpl->changed.Cancel(uid & 0x7f); } +int32_t SimDeviceData::RegisterValueResetCallback( + HAL_SimValueHandle handle, void* param, HALSIM_SimValueCallback callback, + bool initialNotify) { + std::scoped_lock lock(m_mutex); + Value* valueImpl = LookupValue(handle); + if (!valueImpl) { + return -1; + } + + // register callback + int32_t index = valueImpl->reset.Register(callback, param); + + // encode device and value into uid + return (((handle >> 16) & 0xfff) << 19) | ((handle & 0xfff) << 7) | + (index & 0x7f); +} + +void SimDeviceData::CancelValueResetCallback(int32_t uid) { + if (uid <= 0) { + return; + } + std::scoped_lock lock(m_mutex); + Value* valueImpl = LookupValue(((uid >> 19) << 16) | ((uid >> 7) & 0xfff)); + if (!valueImpl) { + return; + } + valueImpl->reset.Cancel(uid & 0x7f); +} + HAL_SimValueHandle SimDeviceData::GetValueHandle(HAL_SimDeviceHandle device, const char* name) { std::scoped_lock lock(m_mutex); @@ -517,6 +587,18 @@ void HALSIM_CancelSimValueChangedCallback(int32_t uid) { SimSimDeviceData->CancelValueChangedCallback(uid); } +int32_t HALSIM_RegisterSimValueResetCallback(HAL_SimValueHandle handle, + void* param, + HALSIM_SimValueCallback callback, + HAL_Bool initialNotify) { + return SimSimDeviceData->RegisterValueResetCallback(handle, param, callback, + initialNotify); +} + +void HALSIM_CancelSimValueResetCallback(int32_t uid) { + SimSimDeviceData->CancelValueResetCallback(uid); +} + HAL_SimValueHandle HALSIM_GetSimValueHandle(HAL_SimDeviceHandle device, const char* name) { return SimSimDeviceData->GetValueHandle(device, name); diff --git a/hal/src/main/native/sim/mockdata/SimDeviceDataInternal.h b/hal/src/main/native/sim/mockdata/SimDeviceDataInternal.h index 347e61562b..18ac645a4a 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 { std::vector cstrEnumOptions; std::vector enumOptionValues; impl::SimUnnamedCallbackRegistry changed; + impl::SimUnnamedCallbackRegistry reset; }; struct Device { @@ -188,6 +189,7 @@ class SimDeviceData { const HAL_Value& initialValue); HAL_Value GetValue(HAL_SimValueHandle handle); void SetValue(HAL_SimValueHandle handle, const HAL_Value& value); + void ResetValue(HAL_SimValueHandle handle); int32_t RegisterDeviceCreatedCallback(const char* prefix, void* param, HALSIM_SimDeviceCallback callback, @@ -218,6 +220,12 @@ class SimDeviceData { void CancelValueChangedCallback(int32_t uid); + int32_t RegisterValueResetCallback(HAL_SimValueHandle handle, void* param, + HALSIM_SimValueCallback callback, + bool initialNotify); + + void CancelValueResetCallback(int32_t uid); + HAL_SimValueHandle GetValueHandle(HAL_SimDeviceHandle device, const char* name); diff --git a/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_SimDevice.cpp b/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_SimDevice.cpp index 930a78602e..a296c06291 100644 --- a/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_SimDevice.cpp +++ b/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_SimDevice.cpp @@ -71,6 +71,7 @@ void HALSimWSProviderSimDevice::OnNetValueChanged(const wpi::json& json) { break; case HAL_DOUBLE: value.data.v_double = it.value(); + value.data.v_double -= vd->second->doubleOffset; break; case HAL_ENUM: { if (it->is_string()) { @@ -97,9 +98,11 @@ void HALSimWSProviderSimDevice::OnNetValueChanged(const wpi::json& json) { } case HAL_INT: value.data.v_int = it.value(); + value.data.v_int -= vd->second->intOffset; break; case HAL_LONG: value.data.v_long = it.value(); + value.data.v_long -= vd->second->intOffset; break; default: break; @@ -186,7 +189,8 @@ void HALSimWSProviderSimDevice::OnValueChanged(SimDeviceValueData* valueData, ProcessHalCallback({{valueData->key, value->data.v_boolean}}); break; case HAL_DOUBLE: - ProcessHalCallback({{valueData->key, value->data.v_double}}); + ProcessHalCallback( + {{valueData->key, value->data.v_double + valueData->doubleOffset}}); break; case HAL_ENUM: { int v = value->data.v_enum; @@ -198,10 +202,12 @@ void HALSimWSProviderSimDevice::OnValueChanged(SimDeviceValueData* valueData, break; } case HAL_INT: - ProcessHalCallback({{valueData->key, value->data.v_int}}); + ProcessHalCallback( + {{valueData->key, value->data.v_int + valueData->intOffset}}); break; case HAL_LONG: - ProcessHalCallback({{valueData->key, value->data.v_long}}); + ProcessHalCallback( + {{valueData->key, value->data.v_long + valueData->intOffset}}); break; default: break; @@ -209,6 +215,33 @@ void HALSimWSProviderSimDevice::OnValueChanged(SimDeviceValueData* valueData, } } +void HALSimWSProviderSimDevice::OnValueResetStatic( + const char* name, void* param, HAL_SimValueHandle handle, int32_t direction, + const struct HAL_Value* value) { + auto valueData = (reinterpret_cast(param)); + valueData->device->OnValueReset(valueData, value); +} + +void HALSimWSProviderSimDevice::OnValueReset(SimDeviceValueData* valueData, + const struct HAL_Value* value) { + switch (value->type) { + case HAL_BOOLEAN: + case HAL_ENUM: + break; + case HAL_DOUBLE: + valueData->doubleOffset += value->data.v_double; + break; + case HAL_INT: + valueData->intOffset += value->data.v_int; + break; + case HAL_LONG: + valueData->intOffset += value->data.v_long; + break; + default: + break; + } +} + void HALSimWSProviderSimDevice::ProcessHalCallback(const wpi::json& payload) { auto ws = m_ws.lock(); if (ws) { diff --git a/simulation/halsim_ws_core/src/main/native/include/WSProvider_SimDevice.h b/simulation/halsim_ws_core/src/main/native/include/WSProvider_SimDevice.h index ff9314e7ba..6d80467caf 100644 --- a/simulation/halsim_ws_core/src/main/native/include/WSProvider_SimDevice.h +++ b/simulation/halsim_ws_core/src/main/native/include/WSProvider_SimDevice.h @@ -28,6 +28,8 @@ struct SimDeviceValueData { std::vector options; std::vector optionValues; HAL_Type valueType; + double doubleOffset = 0; + int64_t intOffset = 0; }; class HALSimWSProviderSimDevice : public HALSimWSBaseProvider { @@ -63,6 +65,12 @@ class HALSimWSProviderSimDevice : public HALSimWSBaseProvider { void OnValueChanged(SimDeviceValueData* valueData, const struct HAL_Value* value); + static void OnValueResetStatic(const char* name, void* param, + HAL_SimValueHandle handle, int32_t direction, + const struct HAL_Value* value); + void OnValueReset(SimDeviceValueData* valueData, + const struct HAL_Value* value); + void CancelCallbacks(); wpi::StringMap> m_valueHandles; diff --git a/wpilibc/src/main/native/cpp/ADXRS450_Gyro.cpp b/wpilibc/src/main/native/cpp/ADXRS450_Gyro.cpp index cfdccbccda..523c1dfd24 100644 --- a/wpilibc/src/main/native/cpp/ADXRS450_Gyro.cpp +++ b/wpilibc/src/main/native/cpp/ADXRS450_Gyro.cpp @@ -114,10 +114,7 @@ double ADXRS450_Gyro::GetRate() const { void ADXRS450_Gyro::Reset() { if (m_simAngle) { - m_simAngle.Set(0.0); - } - if (m_simRate) { - m_simRate.Set(0.0); + m_simAngle.Reset(); } m_spi.ResetAccumulator(); } diff --git a/wpilibc/src/main/native/include/frc/simulation/SimDeviceSim.h b/wpilibc/src/main/native/include/frc/simulation/SimDeviceSim.h index 142f61dfc3..b1882b56b3 100644 --- a/wpilibc/src/main/native/include/frc/simulation/SimDeviceSim.h +++ b/wpilibc/src/main/native/include/frc/simulation/SimDeviceSim.h @@ -105,6 +105,12 @@ class SimDeviceSim { */ operator HAL_SimDeviceHandle() const { return m_handle; } // NOLINT + /** + * Get all sim devices with the given prefix. + * + * @param prefix the prefix to filter sim devices + * @param callback callback function to call for each sim device + */ template static void EnumerateDevices(const char* prefix, F callback) { return HALSIM_EnumerateSimDevices( diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXRS450_Gyro.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXRS450_Gyro.java index 14480d6455..fcc57b9f18 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXRS450_Gyro.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/ADXRS450_Gyro.java @@ -165,10 +165,7 @@ public class ADXRS450_Gyro extends GyroBase implements Gyro, PIDSource, Sendable @Override public void reset() { if (m_simAngle != null) { - m_simAngle.set(0.0); - } - if (m_simRate != null) { - m_simRate.set(0.0); + m_simAngle.reset(); } if (m_spi != null) { m_spi.resetAccumulator(); diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/SimDeviceSim.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/SimDeviceSim.java index df445eb6fd..ba3d1797f2 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/SimDeviceSim.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/simulation/SimDeviceSim.java @@ -13,6 +13,7 @@ import edu.wpi.first.hal.SimValue; import edu.wpi.first.hal.simulation.SimDeviceCallback; import edu.wpi.first.hal.simulation.SimDeviceDataJNI; import edu.wpi.first.hal.simulation.SimValueCallback; +import edu.wpi.first.hal.simulation.SimValueCallback2; /** Class to control the simulation side of a SimDevice. */ public class SimDeviceSim { @@ -169,6 +170,38 @@ public class SimDeviceSim { return new CallbackStore(uid, SimDeviceDataJNI::cancelSimValueChangedCallback); } + /** + * Register a callback to be run every time a value is changed on this device. + * + * @param callback the callback + * @param initialNotify should the callback be run with the initial state + * @return the {@link CallbackStore} object associated with this callback. Save a reference to + * this object so GC doesn't cancel the callback. + */ + public CallbackStore registerValueChangedCallback2( + SimValue value, SimValueCallback2 callback, boolean initialNotify) { + int uid = + SimDeviceDataJNI.registerSimValueChangedCallback2( + value.getNativeHandle(), callback, initialNotify); + return new CallbackStore(uid, SimDeviceDataJNI::cancelSimValueChangedCallback); + } + + /** + * Register a callback for SimDouble.reset() and similar functions. The callback is called with + * the old value. + * + * @param value simulated value + * @param callback callback + * @param initialNotify ignored (present for consistency) + */ + public CallbackStore registerValueResetCallback( + SimValue value, SimValueCallback2 callback, boolean initialNotify) { + int uid = + SimDeviceDataJNI.registerSimValueResetCallback( + value.getNativeHandle(), callback, initialNotify); + return new CallbackStore(uid, SimDeviceDataJNI::cancelSimValueResetCallback); + } + /** * Get all sim devices with the given prefix. *