[hal,tests] Use waitForProgramStart in tests (#8429)

Change setProgramStarted to accept a boolean so it can be set back to
false by tests. This allows properly waiting for program start in tests.
This commit is contained in:
Peter Johnson
2025-11-29 10:10:01 -08:00
committed by GitHub
parent 32d3ec0218
commit a4aad63dd4
23 changed files with 84 additions and 49 deletions

View File

@@ -12,7 +12,7 @@ public class SimulatorJNI extends JNIWrapper {
public static native void waitForProgramStart();
public static native void setProgramStarted();
public static native void setProgramStarted(boolean started);
public static native boolean getProgramStarted();

View File

@@ -138,13 +138,13 @@ Java_org_wpilib_hardware_hal_simulation_SimulatorJNI_waitForProgramStart
/*
* Class: org_wpilib_hardware_hal_simulation_SimulatorJNI
* Method: setProgramStarted
* Signature: ()V
* Signature: (Z)V
*/
JNIEXPORT void JNICALL
Java_org_wpilib_hardware_hal_simulation_SimulatorJNI_setProgramStarted
(JNIEnv*, jclass)
(JNIEnv*, jclass, jboolean started)
{
HALSIM_SetProgramStarted();
HALSIM_SetProgramStarted(started);
}
/*

View File

@@ -10,7 +10,7 @@
extern "C" {
void HALSIM_SetRuntimeType(HAL_RuntimeType type);
void HALSIM_WaitForProgramStart(void);
void HALSIM_SetProgramStarted(void);
void HALSIM_SetProgramStarted(HAL_Bool started);
HAL_Bool HALSIM_GetProgramStarted(void);
void HALSIM_RestartTiming(void);
void HALSIM_PauseTiming(void);

View File

@@ -22,7 +22,6 @@
#include "wpi/hal/cpp/fpga_clock.h"
#include "wpi/hal/simulation/MockHooks.h"
#include "wpi/util/EventVector.hpp"
#include "wpi/util/condition_variable.hpp"
#include "wpi/util/mutex.hpp"
static wpi::util::mutex msgMutex;
@@ -368,7 +367,7 @@ int32_t HAL_GetMatchInfo(HAL_MatchInfo* info) {
}
void HAL_ObserveUserProgramStarting(void) {
HALSIM_SetProgramStarted();
HALSIM_SetProgramStarted(true);
}
void HAL_ObserveUserProgramDisabled(void) {

View File

@@ -68,8 +68,8 @@ double GetFPGATimestamp() {
return GetFPGATime() * 1.0e-6;
}
void SetProgramStarted() {
programStarted = true;
void SetProgramStarted(bool started) {
programStarted = started;
}
bool GetProgramStarted() {
return programStarted;
@@ -83,13 +83,15 @@ void HALSIM_WaitForProgramStart(void) {
int count = 0;
while (!programStarted) {
count++;
wpi::util::print("Waiting for program start signal: {}\n", count);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
if (count % 10 == 0) {
wpi::util::print("Waiting for program start signal: {}\n", count);
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
void HALSIM_SetProgramStarted(void) {
SetProgramStarted();
void HALSIM_SetProgramStarted(HAL_Bool started) {
SetProgramStarted(started);
}
HAL_Bool HALSIM_GetProgramStarted(void) {

View File

@@ -10,7 +10,7 @@ void HALSIM_SetRuntimeType(HAL_RuntimeType type) {}
void HALSIM_WaitForProgramStart(void) {}
void HALSIM_SetProgramStarted(void) {}
void HALSIM_SetProgramStarted(HAL_Bool started) {}
HAL_Bool HALSIM_GetProgramStarted(void) {
return false;

View File

@@ -16,8 +16,8 @@ void WaitForProgramStart() {
HALSIM_WaitForProgramStart();
}
void SetProgramStarted() {
HALSIM_SetProgramStarted();
void SetProgramStarted(bool started) {
HALSIM_SetProgramStarted(started);
}
bool GetProgramStarted() {

View File

@@ -18,10 +18,23 @@ namespace wpi::sim {
*/
void SetRuntimeType(HAL_RuntimeType type);
/**
* Waits until the user program has started.
*/
void WaitForProgramStart();
void SetProgramStarted();
/**
* Sets flag that indicates if the user program has started.
*
* @param started true if started
*/
void SetProgramStarted(bool started);
/**
* Returns true if the user program has started.
*
* @return True if the user program has started.
*/
bool GetProgramStarted();
/**

View File

@@ -21,7 +21,10 @@ inline constexpr auto kPeriod = 20_ms;
namespace {
class TimedRobotTest : public ::testing::Test {
protected:
void SetUp() override { wpi::sim::PauseTiming(); }
void SetUp() override {
wpi::sim::PauseTiming();
wpi::sim::SetProgramStarted(false);
}
void TearDown() override { wpi::sim::ResumeTiming(); }
};
@@ -84,10 +87,10 @@ TEST_F(TimedRobotTest, DisabledMode) {
MockRobot robot;
std::thread robotThread{[&] { robot.StartCompetition(); }};
wpi::sim::WaitForProgramStart();
wpi::sim::DriverStationSim::SetEnabled(false);
wpi::sim::DriverStationSim::NotifyNewData();
wpi::sim::StepTiming(0_ms); // Wait for Notifiers
EXPECT_EQ(1u, robot.m_simulationInitCount);
EXPECT_EQ(0u, robot.m_disabledInitCount);
@@ -155,12 +158,12 @@ TEST_F(TimedRobotTest, AutonomousMode) {
MockRobot robot;
std::thread robotThread{[&] { robot.StartCompetition(); }};
wpi::sim::WaitForProgramStart();
wpi::sim::DriverStationSim::SetEnabled(true);
wpi::sim::DriverStationSim::SetAutonomous(true);
wpi::sim::DriverStationSim::SetTest(false);
wpi::sim::DriverStationSim::NotifyNewData();
wpi::sim::StepTiming(0_ms); // Wait for Notifiers
EXPECT_EQ(1u, robot.m_simulationInitCount);
EXPECT_EQ(0u, robot.m_disabledInitCount);
@@ -228,12 +231,12 @@ TEST_F(TimedRobotTest, TeleopMode) {
MockRobot robot;
std::thread robotThread{[&] { robot.StartCompetition(); }};
wpi::sim::WaitForProgramStart();
wpi::sim::DriverStationSim::SetEnabled(true);
wpi::sim::DriverStationSim::SetAutonomous(false);
wpi::sim::DriverStationSim::SetTest(false);
wpi::sim::DriverStationSim::NotifyNewData();
wpi::sim::StepTiming(0_ms); // Wait for Notifiers
EXPECT_EQ(1u, robot.m_simulationInitCount);
EXPECT_EQ(0u, robot.m_disabledInitCount);
@@ -300,12 +303,12 @@ TEST_F(TimedRobotTest, TeleopMode) {
TEST_F(TimedRobotTest, TestMode) {
MockRobot robot;
std::thread robotThread{[&] { robot.StartCompetition(); }};
wpi::sim::WaitForProgramStart();
wpi::sim::DriverStationSim::SetEnabled(true);
wpi::sim::DriverStationSim::SetAutonomous(false);
wpi::sim::DriverStationSim::SetTest(true);
wpi::sim::DriverStationSim::NotifyNewData();
wpi::sim::StepTiming(0_ms); // Wait for Notifiers
EXPECT_EQ(1u, robot.m_simulationInitCount);
EXPECT_EQ(0u, robot.m_disabledInitCount);
@@ -397,13 +400,13 @@ TEST_F(TimedRobotTest, ModeChange) {
MockRobot robot;
std::thread robotThread{[&] { robot.StartCompetition(); }};
wpi::sim::WaitForProgramStart();
// Start in disabled
wpi::sim::DriverStationSim::SetEnabled(false);
wpi::sim::DriverStationSim::SetAutonomous(false);
wpi::sim::DriverStationSim::SetTest(false);
wpi::sim::DriverStationSim::NotifyNewData();
wpi::sim::StepTiming(0_ms); // Wait for Notifiers
EXPECT_EQ(0u, robot.m_disabledInitCount);
EXPECT_EQ(0u, robot.m_autonomousInitCount);
@@ -510,10 +513,10 @@ TEST_F(TimedRobotTest, AddPeriodic) {
robot.AddPeriodic([&] { callbackCount++; }, kPeriod / 2.0);
std::thread robotThread{[&] { robot.StartCompetition(); }};
wpi::sim::WaitForProgramStart();
wpi::sim::DriverStationSim::SetEnabled(false);
wpi::sim::DriverStationSim::NotifyNewData();
wpi::sim::StepTiming(0_ms); // Wait for Notifiers
EXPECT_EQ(0u, robot.m_disabledInitCount);
EXPECT_EQ(0u, robot.m_disabledPeriodicCount);
@@ -549,10 +552,10 @@ TEST_F(TimedRobotTest, AddPeriodicWithOffset) {
// 2p | 1.25p
std::thread robotThread{[&] { robot.StartCompetition(); }};
wpi::sim::WaitForProgramStart();
wpi::sim::DriverStationSim::SetEnabled(false);
wpi::sim::DriverStationSim::NotifyNewData();
wpi::sim::StepTiming(0_ms); // Wait for Notifiers
EXPECT_EQ(0u, robot.m_disabledInitCount);
EXPECT_EQ(0u, robot.m_disabledPeriodicCount);

View File

@@ -19,7 +19,10 @@ using namespace wpi;
namespace {
class TimesliceRobotTest : public ::testing::Test {
protected:
void SetUp() override { wpi::sim::PauseTiming(); }
void SetUp() override {
wpi::sim::PauseTiming();
wpi::sim::SetProgramStarted(false);
}
void TearDown() override { wpi::sim::ResumeTiming(); }
};
@@ -51,10 +54,10 @@ TEST_F(TimesliceRobotTest, Schedule) {
robot.Schedule([&] { callbackCount2++; }, 1_ms);
std::thread robotThread{[&] { robot.StartCompetition(); }};
wpi::sim::WaitForProgramStart();
wpi::sim::DriverStationSim::SetEnabled(false);
wpi::sim::DriverStationSim::NotifyNewData();
wpi::sim::StepTiming(0_ms); // Wait for Notifiers
// Functions scheduled with addPeriodic() are delayed by one period before
// their first run (5 ms for this test's callbacks here and 20 ms for

View File

@@ -31,9 +31,10 @@ class ArmSimulationTest : public testing::TestWithParam<wpi::units::degree_t> {
public:
void SetUp() override {
wpi::sim::PauseTiming();
wpi::sim::SetProgramStarted(false);
m_thread = std::thread([&] { m_robot.StartCompetition(); });
wpi::sim::StepTiming(0.0_ms); // Wait for Notifiers
wpi::sim::WaitForProgramStart();
}
void TearDown() override {

View File

@@ -25,11 +25,11 @@ class DigitalCommunicationTest : public testing::TestWithParam<T> {
void SetUp() override {
wpi::sim::PauseTiming();
wpi::sim::SetProgramStarted(false);
wpi::sim::DriverStationSim::ResetData();
m_thread = std::thread([&] { m_robot.StartCompetition(); });
wpi::sim::StepTiming(0.0_ms);
// SimHooks.stepTiming(0.0); // Wait for Notifiers
wpi::sim::WaitForProgramStart();
}
void TearDown() override {

View File

@@ -33,9 +33,10 @@ class ElevatorSimulationTest : public testing::Test {
public:
void SetUp() override {
wpi::sim::PauseTiming();
wpi::sim::SetProgramStarted(false);
m_thread = std::thread([&] { m_robot.StartCompetition(); });
wpi::sim::StepTiming(0.0_ms); // Wait for Notifiers
wpi::sim::WaitForProgramStart();
}
void TearDown() override {

View File

@@ -32,13 +32,14 @@ class I2CCommunicationTest : public testing::TestWithParam<T> {
void SetUp() override {
gString = std::string();
wpi::sim::PauseTiming();
wpi::sim::SetProgramStarted(false);
wpi::sim::DriverStationSim::ResetData();
m_port = static_cast<int32_t>(Robot::kPort);
m_callback = HALSIM_RegisterI2CWriteCallback(m_port, &callback, nullptr);
m_thread = std::thread([&] { m_robot.StartCompetition(); });
wpi::sim::StepTiming(0.0_ms); // Wait for Notifiers
wpi::sim::WaitForProgramStart();
}
void TearDown() override {

View File

@@ -68,6 +68,7 @@ class PotentiometerPIDTest : public testing::Test {
void SetUp() override {
wpi::sim::PauseTiming();
wpi::sim::SetProgramStarted(false);
wpi::sim::DriverStationSim::ResetData();
m_joystickSim.SetButtonsMaximumIndex(12);
@@ -76,7 +77,7 @@ class PotentiometerPIDTest : public testing::Test {
HALSIM_RegisterSimPeriodicBeforeCallback(CallSimPeriodicBefore, this);
m_thread = std::thread([&] { m_robot.StartCompetition(); });
wpi::sim::StepTiming(0.0_ms); // Wait for Notifiers
wpi::sim::WaitForProgramStart();
}
void TearDown() override {

View File

@@ -24,9 +24,13 @@ public final class SimHooks {
SimulatorJNI.waitForProgramStart();
}
/** Sets that the user program has started. */
public static void setProgramStarted() {
SimulatorJNI.setProgramStarted();
/**
* Sets flag that indicates if the user program has started.
*
* @param started true if started
*/
public static void setProgramStarted(boolean started) {
SimulatorJNI.setProgramStarted(started);
}
/**

View File

@@ -119,6 +119,7 @@ class TimedRobotTest {
@BeforeEach
void setup() {
SimHooks.pauseTiming();
SimHooks.setProgramStarted(false);
DriverStationSim.resetData();
}
@@ -134,10 +135,10 @@ class TimedRobotTest {
Thread robotThread = new Thread(robot::startCompetition);
robotThread.start();
SimHooks.waitForProgramStart();
DriverStationSim.setEnabled(false);
DriverStationSim.notifyNewData();
SimHooks.stepTiming(0.0); // Wait for Notifiers
assertEquals(1, robot.m_simulationInitCount.get());
assertEquals(0, robot.m_disabledInitCount.get());
@@ -214,12 +215,12 @@ class TimedRobotTest {
Thread robotThread = new Thread(robot::startCompetition);
robotThread.start();
SimHooks.waitForProgramStart();
DriverStationSim.setEnabled(true);
DriverStationSim.setAutonomous(true);
DriverStationSim.setTest(false);
DriverStationSim.notifyNewData();
SimHooks.stepTiming(0.0); // Wait for Notifiers
assertEquals(1, robot.m_simulationInitCount.get());
assertEquals(0, robot.m_disabledInitCount.get());
@@ -296,12 +297,12 @@ class TimedRobotTest {
Thread robotThread = new Thread(robot::startCompetition);
robotThread.start();
SimHooks.waitForProgramStart();
DriverStationSim.setEnabled(true);
DriverStationSim.setAutonomous(false);
DriverStationSim.setTest(false);
DriverStationSim.notifyNewData();
SimHooks.stepTiming(0.0); // Wait for Notifiers
assertEquals(1, robot.m_simulationInitCount.get());
assertEquals(0, robot.m_disabledInitCount.get());
@@ -378,12 +379,12 @@ class TimedRobotTest {
Thread robotThread = new Thread(robot::startCompetition);
robotThread.start();
SimHooks.waitForProgramStart();
DriverStationSim.setEnabled(true);
DriverStationSim.setAutonomous(false);
DriverStationSim.setTest(true);
DriverStationSim.notifyNewData();
SimHooks.stepTiming(0.0); // Wait for Notifiers
assertEquals(1, robot.m_simulationInitCount.get());
assertEquals(0, robot.m_disabledInitCount.get());
@@ -485,13 +486,13 @@ class TimedRobotTest {
Thread robotThread = new Thread(robot::startCompetition);
robotThread.start();
SimHooks.waitForProgramStart();
// Start in disabled
DriverStationSim.setEnabled(false);
DriverStationSim.setAutonomous(false);
DriverStationSim.setTest(false);
DriverStationSim.notifyNewData();
SimHooks.stepTiming(0.0); // Wait for Notifiers
assertEquals(0, robot.m_disabledInitCount.get());
assertEquals(0, robot.m_autonomousInitCount.get());
@@ -607,10 +608,10 @@ class TimedRobotTest {
Thread robotThread = new Thread(robot::startCompetition);
robotThread.start();
SimHooks.waitForProgramStart();
DriverStationSim.setEnabled(false);
DriverStationSim.notifyNewData();
SimHooks.stepTiming(0.0); // Wait for Notifiers
assertEquals(0, robot.m_disabledInitCount.get());
assertEquals(0, robot.m_disabledPeriodicCount.get());
@@ -657,10 +658,10 @@ class TimedRobotTest {
Thread robotThread = new Thread(robot::startCompetition);
robotThread.start();
SimHooks.waitForProgramStart();
DriverStationSim.setEnabled(false);
DriverStationSim.notifyNewData();
SimHooks.stepTiming(0.0); // Wait for Notifiers
assertEquals(0, robot.m_disabledInitCount.get());
assertEquals(0, robot.m_disabledPeriodicCount.get());

View File

@@ -32,6 +32,7 @@ class TimesliceRobotTest {
@BeforeEach
void setup() {
SimHooks.pauseTiming();
SimHooks.setProgramStarted(false);
}
@AfterEach
@@ -59,10 +60,10 @@ class TimesliceRobotTest {
Thread robotThread = new Thread(robot::startCompetition);
robotThread.start();
SimHooks.waitForProgramStart();
DriverStationSim.setEnabled(false);
DriverStationSim.notifyNewData();
SimHooks.stepTiming(0.0); // Wait for Notifiers
// Functions scheduled with addPeriodic() are delayed by one period before
// their first run (5 ms for this test's callbacks here and 20 ms for

View File

@@ -35,6 +35,7 @@ class ArmSimulationTest {
void startThread() {
HAL.initialize(500, 0);
SimHooks.pauseTiming();
SimHooks.setProgramStarted(false);
DriverStationSim.resetData();
m_robot = new Robot();
m_thread = new Thread(m_robot::startCompetition);
@@ -43,7 +44,7 @@ class ArmSimulationTest {
m_joystickSim = new JoystickSim(Constants.kJoystickPort);
m_thread.start();
SimHooks.stepTiming(0.0); // Wait for Notifiers
SimHooks.waitForProgramStart();
}
@AfterEach

View File

@@ -33,11 +33,12 @@ class DigitalCommunicationTest {
void startThread() {
HAL.initialize(500, 0);
SimHooks.pauseTiming();
SimHooks.setProgramStarted(false);
DriverStationSim.resetData();
m_robot = new Robot();
m_thread = new Thread(m_robot::startCompetition);
m_thread.start();
SimHooks.stepTiming(0.0); // Wait for Notifiers
SimHooks.waitForProgramStart();
}
@AfterEach

View File

@@ -32,6 +32,7 @@ class ElevatorSimulationTest {
void startThread() {
HAL.initialize(500, 0);
SimHooks.pauseTiming();
SimHooks.setProgramStarted(false);
DriverStationSim.resetData();
m_robot = new Robot();
m_thread = new Thread(m_robot::startCompetition);
@@ -40,7 +41,7 @@ class ElevatorSimulationTest {
m_joystickSim = new JoystickSim(Constants.kJoystickPort);
m_thread.start();
SimHooks.stepTiming(0.0); // Wait for Notifiers
SimHooks.waitForProgramStart();
}
@AfterEach

View File

@@ -36,6 +36,7 @@ class I2CCommunicationTest {
void startThread() {
HAL.initialize(500, 0);
SimHooks.pauseTiming();
SimHooks.setProgramStarted(false);
DriverStationSim.resetData();
m_future = new CompletableFuture<>();
m_callback =
@@ -44,7 +45,7 @@ class I2CCommunicationTest {
m_robot = new Robot();
m_thread = new Thread(m_robot::startCompetition);
m_thread.start();
SimHooks.stepTiming(0.0); // Wait for Notifiers
SimHooks.waitForProgramStart();
}
@AfterEach

View File

@@ -43,6 +43,7 @@ class PotentiometerPIDTest {
void startThread() {
HAL.initialize(500, 0);
SimHooks.pauseTiming();
SimHooks.setProgramStarted(false);
DriverStationSim.resetData();
m_robot = new Robot();
m_thread = new Thread(m_robot::startCompetition);
@@ -78,7 +79,7 @@ class PotentiometerPIDTest {
});
m_thread.start();
SimHooks.stepTiming(0.0); // Wait for Notifiers
SimHooks.waitForProgramStart();
}
@AfterEach