diff --git a/wpilibc/src/main/native/cpp/framework/OpModeRobot.cpp b/wpilibc/src/main/native/cpp/framework/OpModeRobot.cpp index 791e7a0ca4..6fff49cf3a 100644 --- a/wpilibc/src/main/native/cpp/framework/OpModeRobot.cpp +++ b/wpilibc/src/main/native/cpp/framework/OpModeRobot.cpp @@ -92,7 +92,6 @@ class MonitorThread : public wpi::util::SafeThreadEvent { void OpModeRobotBase::StartCompetition() { fmt::print("********** Robot program startup complete **********\n"); - HAL_ObserveUserProgramStarting(); wpi::util::Event event; struct DSListener { @@ -108,6 +107,7 @@ void OpModeRobotBase::StartCompetition() { HAL_SetNotifierName(m_notifier, "OpModeRobot", &status); int64_t lastModeId = -1; + bool calledObserveUserProgramStarting = false; bool calledDriverStationConnected = false; std::shared_ptr opMode; WPI_EventHandle events[] = {event.GetHandle(), @@ -116,6 +116,16 @@ void OpModeRobotBase::StartCompetition() { for (;;) { // Wait for new data from the driver station, with 50 ms timeout HAL_SetNotifierAlarm(m_notifier, 50000, 0, false, true, &status); + + // Call HAL_ObserveUserProgramStarting() here as a one-shot to ensure it is + // called after the notifier alarm is set. The notifier alarm is set using + // relative time, so tests that wait on the user program to start and then + // step time won't work correctly if we call this before setting the alarm. + if (!calledObserveUserProgramStarting) { + calledObserveUserProgramStarting = true; + HAL_ObserveUserProgramStarting(); + } + auto signaled = wpi::util::WaitForObjects(events, signaledBuf); if (signaled.empty()) { return; // handles destroyed diff --git a/wpilibj/src/main/java/org/wpilib/framework/OpModeRobot.java b/wpilibj/src/main/java/org/wpilib/framework/OpModeRobot.java index 4bd56590bc..1e37b41c0b 100644 --- a/wpilibj/src/main/java/org/wpilib/framework/OpModeRobot.java +++ b/wpilibj/src/main/java/org/wpilib/framework/OpModeRobot.java @@ -566,7 +566,6 @@ public abstract class OpModeRobot extends RobotBase { @Override public final void startCompetition() { System.out.println("********** Robot program startup complete **********"); - DriverStationJNI.observeUserProgramStarting(); int event = WPIUtilJNI.createEvent(false, false); DriverStationJNI.provideNewDataEventHandle(event); @@ -577,11 +576,22 @@ public abstract class OpModeRobot extends RobotBase { try { // Implement the opmode lifecycle long lastModeId = -1; + boolean calledObserveUserProgramStarting = false; boolean calledDriverStationConnected = false; int[] events = {event, m_notifier}; while (true) { // Wait for new data from the driver station, with 50 ms timeout NotifierJNI.setNotifierAlarm(m_notifier, 50000, 0, false, true); + + // Call observeUserProgramStarting() here as a one-shot to ensure it is called after the + // notifier alarm is set. The notifier alarm is set using relative time, so tests that + // wait on the user program to start and then step time won't work correctly if we call + // this before setting the alarm. + if (!calledObserveUserProgramStarting) { + calledObserveUserProgramStarting = true; + DriverStationJNI.observeUserProgramStarting(); + } + try { int[] signaled = WPIUtilJNI.waitForObjects(events); for (int val : signaled) {