Files
allwpilib/wpilibc/src/main/native/include/frc/DriverStation.h
Thad House 4a401b89d7 [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

341 lines
9.1 KiB
C++

// 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.
#pragma once
#include <string>
#include <units/time.h>
#include <wpi/Synchronization.h>
namespace wpi::log {
class DataLog;
} // namespace wpi::log
namespace frc {
/**
* Provide access to the network communication data to / from the Driver
* Station.
*/
class DriverStation final {
public:
enum Alliance { kRed, kBlue, kInvalid };
enum MatchType { kNone, kPractice, kQualification, kElimination };
static constexpr int kJoystickPorts = 6;
/**
* The state of one joystick button. %Button indexes begin at 1.
*
* @param stick The joystick to read.
* @param button The button index, beginning at 1.
* @return The state of the joystick button.
*/
static bool GetStickButton(int stick, int button);
/**
* Whether one joystick button was pressed since the last check. %Button
* indexes begin at 1.
*
* @param stick The joystick to read.
* @param button The button index, beginning at 1.
* @return Whether the joystick button was pressed since the last check.
*/
static bool GetStickButtonPressed(int stick, int button);
/**
* Whether one joystick button was released since the last check. %Button
* indexes begin at 1.
*
* @param stick The joystick to read.
* @param button The button index, beginning at 1.
* @return Whether the joystick button was released since the last check.
*/
static bool GetStickButtonReleased(int stick, int button);
/**
* Get the value of the axis on a joystick.
*
* This depends on the mapping of the joystick connected to the specified
* port.
*
* @param stick The joystick to read.
* @param axis The analog axis value to read from the joystick.
* @return The value of the axis on the joystick.
*/
static double GetStickAxis(int stick, int axis);
/**
* Get the state of a POV on the joystick.
*
* @return the angle of the POV in degrees, or -1 if the POV is not pressed.
*/
static int GetStickPOV(int stick, int pov);
/**
* The state of the buttons on the joystick.
*
* @param stick The joystick to read.
* @return The state of the buttons on the joystick.
*/
static int GetStickButtons(int stick);
/**
* Returns the number of axes on a given joystick port.
*
* @param stick The joystick port number
* @return The number of axes on the indicated joystick
*/
static int GetStickAxisCount(int stick);
/**
* Returns the number of POVs on a given joystick port.
*
* @param stick The joystick port number
* @return The number of POVs on the indicated joystick
*/
static int GetStickPOVCount(int stick);
/**
* Returns the number of buttons on a given joystick port.
*
* @param stick The joystick port number
* @return The number of buttons on the indicated joystick
*/
static int GetStickButtonCount(int stick);
/**
* Returns a boolean indicating if the controller is an xbox controller.
*
* @param stick The joystick port number
* @return A boolean that is true if the controller is an xbox controller.
*/
static bool GetJoystickIsXbox(int stick);
/**
* Returns the type of joystick at a given port.
*
* @param stick The joystick port number
* @return The HID type of joystick at the given port
*/
static int GetJoystickType(int stick);
/**
* Returns the name of the joystick at the given port.
*
* @param stick The joystick port number
* @return The name of the joystick at the given port
*/
static std::string GetJoystickName(int stick);
/**
* Returns the types of Axes on a given joystick port.
*
* @param stick The joystick port number and the target axis
* @param axis The analog axis value to read from the joystick.
* @return What type of axis the axis is reporting to be
*/
static int GetJoystickAxisType(int stick, int axis);
/**
* Returns if a joystick is connected to the Driver Station.
*
* This makes a best effort guess by looking at the reported number of axis,
* buttons, and POVs attached.
*
* @param stick The joystick port number
* @return true if a joystick is connected
*/
static bool IsJoystickConnected(int stick);
/**
* Check if the DS has enabled the robot.
*
* @return True if the robot is enabled and the DS is connected
*/
static bool IsEnabled();
/**
* Check if the robot is disabled.
*
* @return True if the robot is explicitly disabled or the DS is not connected
*/
static bool IsDisabled();
/**
* Check if the robot is e-stopped.
*
* @return True if the robot is e-stopped
*/
static bool IsEStopped();
/**
* Check if the DS is commanding autonomous mode.
*
* @return True if the robot is being commanded to be in autonomous mode
*/
static bool IsAutonomous();
/**
* Check if the DS is commanding autonomous mode and if it has enabled the
* robot.
*
* @return True if the robot is being commanded to be in autonomous mode and
* enabled.
*/
static bool IsAutonomousEnabled();
/**
* Check if the DS is commanding teleop mode.
*
* @return True if the robot is being commanded to be in teleop mode
*/
static bool IsTeleop();
/**
* Check if the DS is commanding teleop mode and if it has enabled the robot.
*
* @return True if the robot is being commanded to be in teleop mode and
* enabled.
*/
static bool IsTeleopEnabled();
/**
* Check if the DS is commanding test mode.
*
* @return True if the robot is being commanded to be in test mode
*/
static bool IsTest();
/**
* Check if the DS is attached.
*
* @return True if the DS is connected to the robot
*/
static bool IsDSAttached();
/**
* Is the driver station attached to a Field Management System?
*
* @return True if the robot is competing on a field being controlled by a
* Field Management System
*/
static bool IsFMSAttached();
/**
* Returns the game specific message provided by the FMS.
*
* @return A string containing the game specific message.
*/
static std::string GetGameSpecificMessage();
/**
* Returns the name of the competition event provided by the FMS.
*
* @return A string containing the event name
*/
static std::string GetEventName();
/**
* Returns the type of match being played provided by the FMS.
*
* @return The match type enum (kNone, kPractice, kQualification,
* kElimination)
*/
static MatchType GetMatchType();
/**
* Returns the match number provided by the FMS.
*
* @return The number of the match
*/
static int GetMatchNumber();
/**
* Returns the number of times the current match has been replayed from the
* FMS.
*
* @return The number of replays
*/
static int GetReplayNumber();
/**
* Return the alliance that the driver station says it is on.
*
* This could return kRed or kBlue.
*
* @return The Alliance enum (kRed, kBlue or kInvalid)
*/
static Alliance GetAlliance();
/**
* Return the driver station location on the field.
*
* This could return 1, 2, or 3.
*
* @return The location of the driver station (1-3, 0 for invalid)
*/
static int GetLocation();
/**
* Return the approximate match time.
*
* The FMS does not send an official match time to the robots, but does send
* an approximate match time. The value will count down the time remaining in
* the current period (auto or teleop).
*
* Warning: This is not an official time (so it cannot be used to dispute ref
* calls or guarantee that a function will trigger before the match ends).
*
* The Practice Match function of the DS approximates the behavior seen on
* the field.
*
* @return Time remaining in current match period (auto or teleop)
*/
static double GetMatchTime();
/**
* Read the battery voltage.
*
* @return The battery voltage in Volts.
*/
static double GetBatteryVoltage();
static void RefreshData();
static void ProvideRefreshedDataEventHandle(WPI_EventHandle handle);
static void RemoveRefreshedDataEventHandle(WPI_EventHandle handle);
/**
* Allows the user to specify whether they want joystick connection warnings
* to be printed to the console. This setting is ignored when the FMS is
* connected -- warnings will always be on in that scenario.
*
* @param silence Whether warning messages should be silenced.
*/
static void SilenceJoystickConnectionWarning(bool silence);
/**
* Returns whether joystick connection warnings are silenced. This will
* always return false when connected to the FMS.
*
* @return Whether joystick connection warnings are silenced.
*/
static bool IsJoystickConnectionWarningSilenced();
/**
* Starts logging DriverStation data to data log. Repeated calls are ignored.
*
* @param log data log
* @param logJoysticks if true, log joystick data
*/
static void StartDataLog(wpi::log::DataLog& log, bool logJoysticks = true);
private:
DriverStation() = default;
};
} // namespace frc