diff --git a/hal/src/main/native/sim/Interrupts.cpp b/hal/src/main/native/sim/Interrupts.cpp index 8abf02ff75..e55316d14a 100644 --- a/hal/src/main/native/sim/Interrupts.cpp +++ b/hal/src/main/native/sim/Interrupts.cpp @@ -121,16 +121,18 @@ static void ProcessInterruptDigitalSynchronous(const char* name, void* param, return; } bool retVal = value->data.v_boolean; + auto previousState = interrupt->previousState; + interrupt->previousState = retVal; // If no change in interrupt, return; - if (retVal == interrupt->previousState) { + if (retVal == previousState) { return; } // If its a falling change, and we dont fire on falling return - if (interrupt->previousState && !interrupt->fireOnDown) { + if (previousState && !interrupt->fireOnDown) { return; } // If its a rising change, and we dont fire on rising return. - if (!interrupt->previousState && !interrupt->fireOnUp) { + if (!previousState && !interrupt->fireOnUp) { return; } @@ -174,16 +176,18 @@ static void ProcessInterruptAnalogSynchronous(const char* name, void* param, // Pulse interrupt interruptData->waitCond.notify_all(); } + auto previousState = interrupt->previousState; + interrupt->previousState = retVal; // If no change in interrupt, return; - if (retVal == interrupt->previousState) { + if (retVal == previousState) { return; } // If its a falling change, and we dont fire on falling return - if (interrupt->previousState && !interrupt->fireOnDown) { + if (previousState && !interrupt->fireOnDown) { return; } // If its a rising change, and we dont fire on rising return. - if (!interrupt->previousState && !interrupt->fireOnUp) { + if (!previousState && !interrupt->fireOnUp) { return; } diff --git a/wpilibc/src/test/native/cpp/InterruptTest.cpp b/wpilibc/src/test/native/cpp/InterruptTest.cpp new file mode 100644 index 0000000000..1bf0aa2b7f --- /dev/null +++ b/wpilibc/src/test/native/cpp/InterruptTest.cpp @@ -0,0 +1,45 @@ +// 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 + +#include + +#include "frc/AsynchronousInterrupt.h" +#include "frc/DigitalInput.h" +#include "frc/Timer.h" +#include "frc/simulation/DIOSim.h" +#include "gtest/gtest.h" + +namespace frc { +using namespace frc::sim; +TEST(InterruptTest, AsynchronousInterrupt) { + HAL_Initialize(500, 0); + + std::atomic_int counter{0}; + std::atomic_bool hasFired{false}; + + DigitalInput di{0}; + AsynchronousInterrupt interrupt{di, [&](bool rising, bool falling) { + counter++; + hasFired = true; + }}; + + interrupt.Enable(); + frc::Wait(0.5_s); + DIOSim digitalSim{di}; + digitalSim.SetValue(false); + frc::Wait(20_ms); + digitalSim.SetValue(true); + frc::Wait(10_ms); + + int count = 0; + while (!hasFired) { + frc::Wait(5_ms); + count++; + ASSERT_TRUE(count < 1000); + } + ASSERT_EQ(1, counter.load()); +} +} // namespace frc diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/AsynchronousInterrupt.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/AsynchronousInterrupt.java index 59f6478ef6..1b158f1fb6 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/AsynchronousInterrupt.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/AsynchronousInterrupt.java @@ -66,6 +66,7 @@ public class AsynchronousInterrupt implements AutoCloseable { m_keepRunning.set(true); m_thread = new Thread(this::threadMain); + m_thread.start(); } /** Disables interrupt callbacks. Does nothing if already disabled. */ diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/InterruptTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/InterruptTest.java new file mode 100644 index 0000000000..2eecd66f04 --- /dev/null +++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/InterruptTest.java @@ -0,0 +1,46 @@ +// 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. + +package edu.wpi.first.wpilibj; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import edu.wpi.first.wpilibj.simulation.DIOSim; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.jupiter.api.Test; + +public class InterruptTest { + @Test + void testAsynchronousInterrupt() { + AtomicBoolean hasFired = new AtomicBoolean(false); + AtomicInteger counter = new AtomicInteger(0); + + try (DigitalInput di = new DigitalInput(0); + AsynchronousInterrupt interrupt = + new AsynchronousInterrupt( + di, + (a, b) -> { + counter.incrementAndGet(); + hasFired.set(true); + })) { + interrupt.enable(); + Timer.delay(0.5); + DIOSim digitalSim = new DIOSim(di); + digitalSim.setValue(false); + Timer.delay(0.01); + digitalSim.setValue(true); + Timer.delay(0.01); + + int count = 0; + while (!hasFired.get()) { + Timer.delay(0.005); + count++; + assertTrue(count < 1000); + } + assertEquals(1, counter.get(), "The interrupt did not fire the expected number of times"); + } + } +}