2020-12-26 14:12:05 -08:00
|
|
|
// 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.
|
2017-07-08 10:50:56 -04:00
|
|
|
|
|
|
|
|
package edu.wpi.first.wpilibj;
|
|
|
|
|
|
[hal, wpilib] New DS thread model and implementation (#3787)
The current DS thread model has some pretty major issues. It makes it difficult to know if all data is from the same remote packet, and if the data changes while the robot loop is running. Additionally, the DS thread is used for a few other things (MotorSafety and State Tracking for EducationalRobot). This also makes sim difficult, as user code has to wait for the thread to know it has new data.
This change completely rethinks how threading works in the driver station model.
First, the DS HAL system receives a new data callback, either from Netcomm or DriverStationSim. Inside the context of this callback, all the low latency data is read and put into a cache. Doing some investigation on the robot side, this is perfectly safe to do, and also ensures a ds packet will not be parsed before we finish reading the current packet data.
After all data is read, the cache is swapped with a 2nd buffer. This buffer just stores the data, none of the HAL DS calls read from this buffer. An event is then fired, stating there is new data ready to go.
Robot code calls HAL_UpdateDSData(). This swaps the 2nd buffer with a 3rd buffer, which always contains the current data. This data will not be updated until HAL_UpdateDSData is called again. Which solves the state problem.
The high level driver station classes have. an updateData() call, which calls HAL_UpdateDSData, and then update button state variables, then data log and update the NT FMS data table (Java also caches across the JNI boundary here, but that could trivially be removed). An extra event provider is provided, allowing other threads to know when this call has been completed.
IterativeRobotBase calls DS.updateData() at the beginning of each loop, and only once per loop. This means all commands will always have the same state.
All of this means there is no longer a DS thread. Everything happens synchronously. This means Sim and testing is easier, as you can just call DriverStationSim.NotifyNewData(), and then DriverStation.UpdateData(), and you can guarantee that all the DriverStation.*** data is up to date.
As for Motor Safety and Educational Robot State Handling, those can all be handled by their own threads. The Educational Thread only needs to run under EducationalRobot, and MotorSafety will only be started if there is a motor safety object enabled.
2022-10-21 22:01:55 -07:00
|
|
|
import edu.wpi.first.hal.DriverStationJNI;
|
2018-09-20 21:59:46 -07:00
|
|
|
import edu.wpi.first.hal.HAL;
|
2020-12-12 23:16:50 -08:00
|
|
|
import edu.wpi.first.networktables.NetworkTableInstance;
|
2017-12-26 17:18:02 -06:00
|
|
|
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
|
2017-07-08 10:50:56 -04:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* IterativeRobotBase implements a specific type of robot program framework, extending the RobotBase
|
|
|
|
|
* class.
|
|
|
|
|
*
|
|
|
|
|
* <p>The IterativeRobotBase class does not implement startCompetition(), so it should not be used
|
|
|
|
|
* by teams directly.
|
|
|
|
|
*
|
|
|
|
|
* <p>This class provides the following functions which are called by the main loop,
|
|
|
|
|
* startCompetition(), at the appropriate times:
|
|
|
|
|
*
|
2023-06-21 14:53:34 -07:00
|
|
|
* <p>driverStationConnected() -- provide for initialization the first time the DS is connected
|
|
|
|
|
*
|
2020-12-29 22:45:16 -08:00
|
|
|
* <p>init() functions -- each of the following functions is called once when the appropriate mode
|
2021-08-05 19:08:29 -07:00
|
|
|
* is entered:
|
2017-07-08 10:50:56 -04:00
|
|
|
*
|
2021-08-05 19:08:29 -07:00
|
|
|
* <ul>
|
|
|
|
|
* <li>disabledInit() -- called each and every time disabled is entered from another mode
|
|
|
|
|
* <li>autonomousInit() -- called each and every time autonomous is entered from another mode
|
|
|
|
|
* <li>teleopInit() -- called each and every time teleop is entered from another mode
|
|
|
|
|
* <li>testInit() -- called each and every time test is entered from another mode
|
|
|
|
|
* </ul>
|
|
|
|
|
*
|
|
|
|
|
* <p>periodic() functions -- each of these functions is called on an interval:
|
|
|
|
|
*
|
|
|
|
|
* <ul>
|
|
|
|
|
* <li>robotPeriodic()
|
|
|
|
|
* <li>disabledPeriodic()
|
|
|
|
|
* <li>autonomousPeriodic()
|
|
|
|
|
* <li>teleopPeriodic()
|
|
|
|
|
* <li>testPeriodic()
|
|
|
|
|
* </ul>
|
|
|
|
|
*
|
2022-06-18 17:02:36 -05:00
|
|
|
* <p>exit() functions -- each of the following functions is called once when the appropriate mode
|
2021-08-05 19:08:29 -07:00
|
|
|
* is exited:
|
|
|
|
|
*
|
|
|
|
|
* <ul>
|
|
|
|
|
* <li>disabledExit() -- called each and every time disabled is exited
|
|
|
|
|
* <li>autonomousExit() -- called each and every time autonomous is exited
|
|
|
|
|
* <li>teleopExit() -- called each and every time teleop is exited
|
|
|
|
|
* <li>testExit() -- called each and every time test is exited
|
|
|
|
|
* </ul>
|
2017-07-08 10:50:56 -04:00
|
|
|
*/
|
|
|
|
|
public abstract class IterativeRobotBase extends RobotBase {
|
|
|
|
|
private enum Mode {
|
|
|
|
|
kNone,
|
|
|
|
|
kDisabled,
|
|
|
|
|
kAutonomous,
|
|
|
|
|
kTeleop,
|
|
|
|
|
kTest
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-11 18:05:07 -07:00
|
|
|
private final DSControlWord m_word = new DSControlWord();
|
2017-07-08 10:50:56 -04:00
|
|
|
private Mode m_lastMode = Mode.kNone;
|
2019-04-13 14:26:42 -07:00
|
|
|
private final double m_period;
|
2018-06-24 02:29:21 -05:00
|
|
|
private final Watchdog m_watchdog;
|
2022-10-08 10:01:31 -07:00
|
|
|
private boolean m_ntFlushEnabled = true;
|
2023-06-21 14:53:34 -07:00
|
|
|
private boolean m_calledDsConnected;
|
2018-06-24 02:29:21 -05:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Constructor for IterativeRobotBase.
|
|
|
|
|
*
|
|
|
|
|
* @param period Period in seconds.
|
|
|
|
|
*/
|
|
|
|
|
protected IterativeRobotBase(double period) {
|
|
|
|
|
m_period = period;
|
|
|
|
|
m_watchdog = new Watchdog(period, this::printLoopOverrunMessage);
|
|
|
|
|
}
|
2017-07-08 10:50:56 -04:00
|
|
|
|
2020-12-29 22:45:16 -08:00
|
|
|
/** Provide an alternate "main loop" via startCompetition(). */
|
2018-06-03 10:00:53 -07:00
|
|
|
@Override
|
2017-07-08 10:50:56 -04:00
|
|
|
public abstract void startCompetition();
|
|
|
|
|
|
|
|
|
|
/* ----------- Overridable initialization code ----------------- */
|
|
|
|
|
|
2023-06-21 14:53:34 -07:00
|
|
|
/**
|
|
|
|
|
* Code that needs to know the DS state should go here.
|
|
|
|
|
*
|
|
|
|
|
* <p>Users should override this method for initialization that needs to occur after the DS is
|
|
|
|
|
* connected, such as needing the alliance information.
|
|
|
|
|
*/
|
|
|
|
|
public void driverStationConnected() {}
|
|
|
|
|
|
2020-02-19 02:05:16 -05:00
|
|
|
/**
|
|
|
|
|
* Robot-wide simulation initialization code should go here.
|
|
|
|
|
*
|
2020-12-29 22:45:16 -08:00
|
|
|
* <p>Users should override this method for default Robot-wide simulation related initialization
|
|
|
|
|
* which will be called when the robot is first started. It will be called exactly one time after
|
2025-09-08 21:17:37 -07:00
|
|
|
* the robot class constructor is called only when the robot is in simulation.
|
2020-02-19 02:05:16 -05:00
|
|
|
*/
|
2021-08-05 23:54:50 -07:00
|
|
|
public void simulationInit() {}
|
2020-02-19 02:05:16 -05:00
|
|
|
|
2017-07-08 10:50:56 -04:00
|
|
|
/**
|
|
|
|
|
* Initialization code for disabled mode should go here.
|
|
|
|
|
*
|
|
|
|
|
* <p>Users should override this method for initialization code which will be called each time the
|
|
|
|
|
* robot enters disabled mode.
|
|
|
|
|
*/
|
2021-08-05 23:54:50 -07:00
|
|
|
public void disabledInit() {}
|
2017-07-08 10:50:56 -04:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Initialization code for autonomous mode should go here.
|
|
|
|
|
*
|
|
|
|
|
* <p>Users should override this method for initialization code which will be called each time the
|
|
|
|
|
* robot enters autonomous mode.
|
|
|
|
|
*/
|
2021-08-05 23:54:50 -07:00
|
|
|
public void autonomousInit() {}
|
2017-07-08 10:50:56 -04:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Initialization code for teleop mode should go here.
|
|
|
|
|
*
|
|
|
|
|
* <p>Users should override this method for initialization code which will be called each time the
|
|
|
|
|
* robot enters teleop mode.
|
|
|
|
|
*/
|
2021-08-05 23:54:50 -07:00
|
|
|
public void teleopInit() {}
|
2017-07-08 10:50:56 -04:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Initialization code for test mode should go here.
|
|
|
|
|
*
|
|
|
|
|
* <p>Users should override this method for initialization code which will be called each time the
|
|
|
|
|
* robot enters test mode.
|
|
|
|
|
*/
|
2021-08-05 23:54:50 -07:00
|
|
|
public void testInit() {}
|
2017-07-08 10:50:56 -04:00
|
|
|
|
|
|
|
|
/* ----------- Overridable periodic code ----------------- */
|
|
|
|
|
|
|
|
|
|
private boolean m_rpFirstRun = true;
|
|
|
|
|
|
2020-12-29 22:45:16 -08:00
|
|
|
/** Periodic code for all robot modes should go here. */
|
2017-07-08 10:50:56 -04:00
|
|
|
public void robotPeriodic() {
|
|
|
|
|
if (m_rpFirstRun) {
|
2019-01-25 00:45:05 -06:00
|
|
|
System.out.println("Default robotPeriodic() method... Override me!");
|
2017-07-08 10:50:56 -04:00
|
|
|
m_rpFirstRun = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-19 02:05:16 -05:00
|
|
|
private boolean m_spFirstRun = true;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Periodic simulation code should go here.
|
|
|
|
|
*
|
|
|
|
|
* <p>This function is called in a simulated robot after user code executes.
|
|
|
|
|
*/
|
|
|
|
|
public void simulationPeriodic() {
|
|
|
|
|
if (m_spFirstRun) {
|
|
|
|
|
System.out.println("Default simulationPeriodic() method... Override me!");
|
|
|
|
|
m_spFirstRun = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-08 10:50:56 -04:00
|
|
|
private boolean m_dpFirstRun = true;
|
|
|
|
|
|
2020-12-29 22:45:16 -08:00
|
|
|
/** Periodic code for disabled mode should go here. */
|
2017-07-08 10:50:56 -04:00
|
|
|
public void disabledPeriodic() {
|
|
|
|
|
if (m_dpFirstRun) {
|
2019-01-25 00:45:05 -06:00
|
|
|
System.out.println("Default disabledPeriodic() method... Override me!");
|
2017-07-08 10:50:56 -04:00
|
|
|
m_dpFirstRun = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean m_apFirstRun = true;
|
|
|
|
|
|
2020-12-29 22:45:16 -08:00
|
|
|
/** Periodic code for autonomous mode should go here. */
|
2017-07-08 10:50:56 -04:00
|
|
|
public void autonomousPeriodic() {
|
|
|
|
|
if (m_apFirstRun) {
|
2019-01-25 00:45:05 -06:00
|
|
|
System.out.println("Default autonomousPeriodic() method... Override me!");
|
2017-07-08 10:50:56 -04:00
|
|
|
m_apFirstRun = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean m_tpFirstRun = true;
|
|
|
|
|
|
2020-12-29 22:45:16 -08:00
|
|
|
/** Periodic code for teleop mode should go here. */
|
2017-07-08 10:50:56 -04:00
|
|
|
public void teleopPeriodic() {
|
|
|
|
|
if (m_tpFirstRun) {
|
2019-01-25 00:45:05 -06:00
|
|
|
System.out.println("Default teleopPeriodic() method... Override me!");
|
2017-07-08 10:50:56 -04:00
|
|
|
m_tpFirstRun = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean m_tmpFirstRun = true;
|
|
|
|
|
|
2020-12-29 22:45:16 -08:00
|
|
|
/** Periodic code for test mode should go here. */
|
2017-07-08 10:50:56 -04:00
|
|
|
public void testPeriodic() {
|
|
|
|
|
if (m_tmpFirstRun) {
|
2019-01-25 00:45:05 -06:00
|
|
|
System.out.println("Default testPeriodic() method... Override me!");
|
2017-07-08 10:50:56 -04:00
|
|
|
m_tmpFirstRun = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-05 19:08:29 -07:00
|
|
|
/**
|
|
|
|
|
* Exit code for disabled mode should go here.
|
|
|
|
|
*
|
|
|
|
|
* <p>Users should override this method for code which will be called each time the robot exits
|
|
|
|
|
* disabled mode.
|
|
|
|
|
*/
|
|
|
|
|
public void disabledExit() {}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Exit code for autonomous mode should go here.
|
|
|
|
|
*
|
|
|
|
|
* <p>Users should override this method for code which will be called each time the robot exits
|
|
|
|
|
* autonomous mode.
|
|
|
|
|
*/
|
|
|
|
|
public void autonomousExit() {}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Exit code for teleop mode should go here.
|
|
|
|
|
*
|
|
|
|
|
* <p>Users should override this method for code which will be called each time the robot exits
|
|
|
|
|
* teleop mode.
|
|
|
|
|
*/
|
|
|
|
|
public void teleopExit() {}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Exit code for test mode should go here.
|
|
|
|
|
*
|
|
|
|
|
* <p>Users should override this method for code which will be called each time the robot exits
|
|
|
|
|
* test mode.
|
|
|
|
|
*/
|
|
|
|
|
public void testExit() {}
|
|
|
|
|
|
2020-12-12 23:16:50 -08:00
|
|
|
/**
|
2022-10-08 10:01:31 -07:00
|
|
|
* Enables or disables flushing NetworkTables every loop iteration. By default, this is enabled.
|
2020-12-12 23:16:50 -08:00
|
|
|
*
|
|
|
|
|
* @param enabled True to enable, false to disable
|
2024-08-11 02:27:09 -04:00
|
|
|
* @deprecated Deprecated without replacement.
|
2020-12-12 23:16:50 -08:00
|
|
|
*/
|
2024-08-11 02:27:09 -04:00
|
|
|
@Deprecated(forRemoval = true, since = "2025")
|
2020-12-12 23:16:50 -08:00
|
|
|
public void setNetworkTablesFlushEnabled(boolean enabled) {
|
|
|
|
|
m_ntFlushEnabled = enabled;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-10 20:46:47 -07:00
|
|
|
/**
|
|
|
|
|
* Gets time period between calls to Periodic() functions.
|
|
|
|
|
*
|
|
|
|
|
* @return The time period between calls to Periodic() functions.
|
|
|
|
|
*/
|
2019-04-13 14:26:42 -07:00
|
|
|
public double getPeriod() {
|
|
|
|
|
return m_period;
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-05 07:35:59 -08:00
|
|
|
/** Loop function. */
|
2017-07-08 10:50:56 -04:00
|
|
|
protected void loopFunc() {
|
[hal, wpilib] New DS thread model and implementation (#3787)
The current DS thread model has some pretty major issues. It makes it difficult to know if all data is from the same remote packet, and if the data changes while the robot loop is running. Additionally, the DS thread is used for a few other things (MotorSafety and State Tracking for EducationalRobot). This also makes sim difficult, as user code has to wait for the thread to know it has new data.
This change completely rethinks how threading works in the driver station model.
First, the DS HAL system receives a new data callback, either from Netcomm or DriverStationSim. Inside the context of this callback, all the low latency data is read and put into a cache. Doing some investigation on the robot side, this is perfectly safe to do, and also ensures a ds packet will not be parsed before we finish reading the current packet data.
After all data is read, the cache is swapped with a 2nd buffer. This buffer just stores the data, none of the HAL DS calls read from this buffer. An event is then fired, stating there is new data ready to go.
Robot code calls HAL_UpdateDSData(). This swaps the 2nd buffer with a 3rd buffer, which always contains the current data. This data will not be updated until HAL_UpdateDSData is called again. Which solves the state problem.
The high level driver station classes have. an updateData() call, which calls HAL_UpdateDSData, and then update button state variables, then data log and update the NT FMS data table (Java also caches across the JNI boundary here, but that could trivially be removed). An extra event provider is provided, allowing other threads to know when this call has been completed.
IterativeRobotBase calls DS.updateData() at the beginning of each loop, and only once per loop. This means all commands will always have the same state.
All of this means there is no longer a DS thread. Everything happens synchronously. This means Sim and testing is easier, as you can just call DriverStationSim.NotifyNewData(), and then DriverStation.UpdateData(), and you can guarantee that all the DriverStation.*** data is up to date.
As for Motor Safety and Educational Robot State Handling, those can all be handled by their own threads. The Educational Thread only needs to run under EducationalRobot, and MotorSafety will only be started if there is a motor safety object enabled.
2022-10-21 22:01:55 -07:00
|
|
|
DriverStation.refreshData();
|
2018-06-24 02:29:21 -05:00
|
|
|
m_watchdog.reset();
|
|
|
|
|
|
[hal, wpilib] New DS thread model and implementation (#3787)
The current DS thread model has some pretty major issues. It makes it difficult to know if all data is from the same remote packet, and if the data changes while the robot loop is running. Additionally, the DS thread is used for a few other things (MotorSafety and State Tracking for EducationalRobot). This also makes sim difficult, as user code has to wait for the thread to know it has new data.
This change completely rethinks how threading works in the driver station model.
First, the DS HAL system receives a new data callback, either from Netcomm or DriverStationSim. Inside the context of this callback, all the low latency data is read and put into a cache. Doing some investigation on the robot side, this is perfectly safe to do, and also ensures a ds packet will not be parsed before we finish reading the current packet data.
After all data is read, the cache is swapped with a 2nd buffer. This buffer just stores the data, none of the HAL DS calls read from this buffer. An event is then fired, stating there is new data ready to go.
Robot code calls HAL_UpdateDSData(). This swaps the 2nd buffer with a 3rd buffer, which always contains the current data. This data will not be updated until HAL_UpdateDSData is called again. Which solves the state problem.
The high level driver station classes have. an updateData() call, which calls HAL_UpdateDSData, and then update button state variables, then data log and update the NT FMS data table (Java also caches across the JNI boundary here, but that could trivially be removed). An extra event provider is provided, allowing other threads to know when this call has been completed.
IterativeRobotBase calls DS.updateData() at the beginning of each loop, and only once per loop. This means all commands will always have the same state.
All of this means there is no longer a DS thread. Everything happens synchronously. This means Sim and testing is easier, as you can just call DriverStationSim.NotifyNewData(), and then DriverStation.UpdateData(), and you can guarantee that all the DriverStation.*** data is up to date.
As for Motor Safety and Educational Robot State Handling, those can all be handled by their own threads. The Educational Thread only needs to run under EducationalRobot, and MotorSafety will only be started if there is a motor safety object enabled.
2022-10-21 22:01:55 -07:00
|
|
|
m_word.refresh();
|
|
|
|
|
|
2021-08-05 19:08:29 -07:00
|
|
|
// Get current mode
|
|
|
|
|
Mode mode = Mode.kNone;
|
2021-08-11 18:05:07 -07:00
|
|
|
if (m_word.isDisabled()) {
|
2021-08-05 19:08:29 -07:00
|
|
|
mode = Mode.kDisabled;
|
2021-08-11 18:05:07 -07:00
|
|
|
} else if (m_word.isAutonomous()) {
|
2021-08-05 19:08:29 -07:00
|
|
|
mode = Mode.kAutonomous;
|
2021-08-11 18:05:07 -07:00
|
|
|
} else if (m_word.isTeleop()) {
|
2021-08-05 19:08:29 -07:00
|
|
|
mode = Mode.kTeleop;
|
2021-08-11 18:05:07 -07:00
|
|
|
} else if (m_word.isTest()) {
|
2021-08-05 19:08:29 -07:00
|
|
|
mode = Mode.kTest;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-21 14:53:34 -07:00
|
|
|
if (!m_calledDsConnected && m_word.isDSAttached()) {
|
|
|
|
|
m_calledDsConnected = true;
|
|
|
|
|
driverStationConnected();
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-05 19:08:29 -07:00
|
|
|
// If mode changed, call mode exit and entry functions
|
|
|
|
|
if (m_lastMode != mode) {
|
|
|
|
|
// Call last mode's exit function
|
2024-06-05 00:09:10 -04:00
|
|
|
switch (m_lastMode) {
|
|
|
|
|
case kDisabled -> disabledExit();
|
|
|
|
|
case kAutonomous -> autonomousExit();
|
|
|
|
|
case kTeleop -> teleopExit();
|
2025-01-25 10:52:19 -08:00
|
|
|
case kTest -> testExit();
|
2024-06-05 00:09:10 -04:00
|
|
|
default -> {
|
|
|
|
|
// NOP
|
2022-12-01 23:28:06 +02:00
|
|
|
}
|
2017-07-08 10:50:56 -04:00
|
|
|
}
|
2018-06-24 02:29:21 -05:00
|
|
|
|
2021-08-05 19:08:29 -07:00
|
|
|
// Call current mode's entry function
|
2024-06-05 00:09:10 -04:00
|
|
|
switch (mode) {
|
|
|
|
|
case kDisabled -> {
|
|
|
|
|
disabledInit();
|
|
|
|
|
m_watchdog.addEpoch("disabledInit()");
|
|
|
|
|
}
|
|
|
|
|
case kAutonomous -> {
|
|
|
|
|
autonomousInit();
|
|
|
|
|
m_watchdog.addEpoch("autonomousInit()");
|
|
|
|
|
}
|
|
|
|
|
case kTeleop -> {
|
|
|
|
|
teleopInit();
|
|
|
|
|
m_watchdog.addEpoch("teleopInit()");
|
|
|
|
|
}
|
|
|
|
|
case kTest -> {
|
|
|
|
|
testInit();
|
|
|
|
|
m_watchdog.addEpoch("testInit()");
|
|
|
|
|
}
|
|
|
|
|
default -> {
|
|
|
|
|
// NOP
|
2022-12-01 23:28:06 +02:00
|
|
|
}
|
2017-07-08 10:50:56 -04:00
|
|
|
}
|
2018-06-24 02:29:21 -05:00
|
|
|
|
2021-08-05 19:08:29 -07:00
|
|
|
m_lastMode = mode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Call the appropriate function depending upon the current robot mode
|
2024-06-05 00:09:10 -04:00
|
|
|
switch (mode) {
|
|
|
|
|
case kDisabled -> {
|
|
|
|
|
DriverStationJNI.observeUserProgramDisabled();
|
|
|
|
|
disabledPeriodic();
|
|
|
|
|
m_watchdog.addEpoch("disabledPeriodic()");
|
|
|
|
|
}
|
|
|
|
|
case kAutonomous -> {
|
|
|
|
|
DriverStationJNI.observeUserProgramAutonomous();
|
|
|
|
|
autonomousPeriodic();
|
|
|
|
|
m_watchdog.addEpoch("autonomousPeriodic()");
|
|
|
|
|
}
|
|
|
|
|
case kTeleop -> {
|
|
|
|
|
DriverStationJNI.observeUserProgramTeleop();
|
|
|
|
|
teleopPeriodic();
|
|
|
|
|
m_watchdog.addEpoch("teleopPeriodic()");
|
|
|
|
|
}
|
|
|
|
|
case kTest -> {
|
|
|
|
|
DriverStationJNI.observeUserProgramTest();
|
|
|
|
|
testPeriodic();
|
|
|
|
|
m_watchdog.addEpoch("testPeriodic()");
|
|
|
|
|
}
|
|
|
|
|
default -> {
|
|
|
|
|
// NOP
|
|
|
|
|
}
|
2017-07-08 10:50:56 -04:00
|
|
|
}
|
2018-06-24 02:29:21 -05:00
|
|
|
|
2017-07-08 10:50:56 -04:00
|
|
|
robotPeriodic();
|
2018-06-24 02:29:21 -05:00
|
|
|
m_watchdog.addEpoch("robotPeriodic()");
|
|
|
|
|
|
2019-04-27 22:23:21 -07:00
|
|
|
SmartDashboard.updateValues();
|
|
|
|
|
m_watchdog.addEpoch("SmartDashboard.updateValues()");
|
2020-02-19 02:05:16 -05:00
|
|
|
|
|
|
|
|
if (isSimulation()) {
|
2020-11-30 23:55:36 -08:00
|
|
|
HAL.simPeriodicBefore();
|
2020-02-19 02:05:16 -05:00
|
|
|
simulationPeriodic();
|
2020-11-30 23:55:36 -08:00
|
|
|
HAL.simPeriodicAfter();
|
2020-02-19 02:05:16 -05:00
|
|
|
m_watchdog.addEpoch("simulationPeriodic()");
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-27 22:23:21 -07:00
|
|
|
m_watchdog.disable();
|
2018-06-24 02:29:21 -05:00
|
|
|
|
2020-12-12 23:16:50 -08:00
|
|
|
// Flush NetworkTables
|
|
|
|
|
if (m_ntFlushEnabled) {
|
2022-10-08 10:01:31 -07:00
|
|
|
NetworkTableInstance.getDefault().flushLocal();
|
2020-12-12 23:16:50 -08:00
|
|
|
}
|
|
|
|
|
|
2018-06-24 02:29:21 -05:00
|
|
|
// Warn on loop time overruns
|
|
|
|
|
if (m_watchdog.isExpired()) {
|
|
|
|
|
m_watchdog.printEpochs();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-05 01:19:36 +08:00
|
|
|
/** Prints list of epochs added so far and their times. */
|
|
|
|
|
public void printWatchdogEpochs() {
|
|
|
|
|
m_watchdog.printEpochs();
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-24 02:29:21 -05:00
|
|
|
private void printLoopOverrunMessage() {
|
|
|
|
|
DriverStation.reportWarning("Loop time of " + m_period + "s overrun\n", false);
|
2017-07-08 10:50:56 -04:00
|
|
|
}
|
|
|
|
|
}
|