/*----------------------------------------------------------------------------*/ /* Copyright (c) 2008-2018 FIRST. All Rights Reserved. */ /* Open Source Software - may be modified and shared by FRC teams. The code */ /* must be accompanied by the FIRST BSD license file in the root directory of */ /* the project. */ /*----------------------------------------------------------------------------*/ #pragma once #include #include #include #include #include #include #include #include #include #include #include "ErrorBase.h" #include "RobotState.h" namespace frc { struct MatchInfoData; class MatchDataSender; /** * Provide access to the network communication data to / from the Driver * Station. */ class DriverStation : public ErrorBase, public RobotStateInterface { public: enum Alliance { kRed, kBlue, kInvalid }; enum MatchType { kNone, kPractice, kQualification, kElimination }; ~DriverStation() override; /** * Return a reference to the singleton DriverStation. * * @return Reference to the DS instance */ static DriverStation& GetInstance(); /** * Report an error to the DriverStation messages window. * * The error is also printed to the program console. */ static void ReportError(const wpi::Twine& error); /** * Report a warning to the DriverStation messages window. * * The warning is also printed to the program console. */ static void ReportWarning(const wpi::Twine& error); /** * Report an error to the DriverStation messages window. * * The error is also printed to the program console. */ static void ReportError(bool isError, int code, const wpi::Twine& error, const wpi::Twine& location, const wpi::Twine& stack); 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. */ 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. */ 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. */ 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. */ 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. */ 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. */ int GetStickButtons(int stick) const; /** * 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 */ int GetStickAxisCount(int stick) const; /** * 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 */ int GetStickPOVCount(int stick) const; /** * 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 */ int GetStickButtonCount(int stick) const; /** * 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. */ bool GetJoystickIsXbox(int stick) const; /** * 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 */ int GetJoystickType(int stick) const; /** * 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 */ std::string GetJoystickName(int stick) const; /** * Returns the types of Axes on a given joystick port. * * @param stick The joystick port number and the target axis * @return What type of axis the axis is reporting to be */ int GetJoystickAxisType(int stick, int axis) const; /** * Check if the DS has enabled the robot. * * @return True if the robot is enabled and the DS is connected */ bool IsEnabled() const override; /** * Check if the robot is disabled. * * @return True if the robot is explicitly disabled or the DS is not connected */ bool IsDisabled() const override; /** * Check if the DS is commanding autonomous mode. * * @return True if the robot is being commanded to be in autonomous mode */ bool IsAutonomous() const override; /** * Check if the DS is commanding teleop mode. * * @return True if the robot is being commanded to be in teleop mode */ bool IsOperatorControl() const override; /** * Check if the DS is commanding test mode. * * @return True if the robot is being commanded to be in test mode */ bool IsTest() const override; /** * Check if the DS is attached. * * @return True if the DS is connected to the robot */ bool IsDSAttached() const; /** * Has a new control packet from the driver station arrived since the last * time this function was called? * * Warning: If you call this function from more than one place at the same * time, you will not get the intended behavior. * * @return True if the control data has been updated since the last call. */ bool IsNewControlData() const; /** * 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 */ bool IsFMSAttached() const; /** * Check if the FPGA outputs are enabled. * * The outputs may be disabled if the robot is disabled or e-stopped, the * watchdog has expired, or if the roboRIO browns out. * * @return True if the FPGA outputs are enabled. * @deprecated Use RobotController static class method */ WPI_DEPRECATED("Use RobotController static class method") bool IsSysActive() const; /** * Check if the system is browned out. * * @return True if the system is browned out * @deprecated Use RobotController static class method */ WPI_DEPRECATED("Use RobotController static class method") bool IsBrownedOut() const; std::string GetGameSpecificMessage() const; std::string GetEventName() const; MatchType GetMatchType() const; int GetMatchNumber() const; int GetReplayNumber() const; /** * 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) */ Alliance GetAlliance() const; /** * 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) */ int GetLocation() const; /** * Wait until a new packet comes from the driver station. * * This blocks on a semaphore, so the waiting is efficient. * * This is a good way to delay processing until there is new driver station * data to act on. */ void WaitForData(); /** * Wait until a new packet comes from the driver station, or wait for a * timeout. * * If the timeout is less then or equal to 0, wait indefinitely. * * Timeout is in milliseconds * * This blocks on a semaphore, so the waiting is efficient. * * This is a good way to delay processing until there is new driver station * data to act on. * * @param timeout Timeout time in seconds * * @return true if new data, otherwise false */ bool WaitForData(double timeout); /** * 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 behaviour seen on * the field. * * @return Time remaining in current match period (auto or teleop) */ double GetMatchTime() const; /** * Read the battery voltage. * * @return The battery voltage in Volts. */ double GetBatteryVoltage() const; /** * Only to be used to tell the Driver Station what code you claim to be * executing for diagnostic purposes only. * * @param entering If true, starting disabled code; if false, leaving disabled * code. */ void InDisabled(bool entering) { m_userInDisabled = entering; } /** * Only to be used to tell the Driver Station what code you claim to be * executing for diagnostic purposes only. * * @param entering If true, starting autonomous code; if false, leaving * autonomous code. */ void InAutonomous(bool entering) { m_userInAutonomous = entering; } /** * Only to be used to tell the Driver Station what code you claim to be * executing for diagnostic purposes only. * * @param entering If true, starting teleop code; if false, leaving teleop * code. */ void InOperatorControl(bool entering) { m_userInTeleop = entering; } /** * Only to be used to tell the Driver Station what code you claim to be * executing for diagnostic purposes only. * * @param entering If true, starting test code; if false, leaving test code. */ void InTest(bool entering) { m_userInTest = entering; } protected: /** * Copy data from the DS task for the user. * * If no new data exists, it will just be returned, otherwise * the data will be copied from the DS polling loop. */ void GetData(); private: /** * DriverStation constructor. * * This is only called once the first time GetInstance() is called */ DriverStation(); /** * Reports errors related to unplugged joysticks. * * Throttles the errors so that they don't overwhelm the DS. */ void ReportJoystickUnpluggedError(const wpi::Twine& message); /** * Reports errors related to unplugged joysticks. * * Throttles the errors so that they don't overwhelm the DS. */ void ReportJoystickUnpluggedWarning(const wpi::Twine& message); void Run(); /** * Gets ControlWord data from the cache. If 50ms has passed, or the force * parameter is set, the cached data is updated. Otherwise the data is just * copied from the cache. * * @param force True to force an update to the cache, otherwise update if 50ms * have passed. * @param controlWord Structure to put the return control word data into. */ void UpdateControlWord(bool force, HAL_ControlWord& controlWord) const; void SendMatchData(); // Joystick User Data std::unique_ptr m_joystickAxes; std::unique_ptr m_joystickPOVs; std::unique_ptr m_joystickButtons; std::unique_ptr m_joystickDescriptor; std::unique_ptr m_matchInfo; // Joystick Cached Data std::unique_ptr m_joystickAxesCache; std::unique_ptr m_joystickPOVsCache; std::unique_ptr m_joystickButtonsCache; std::unique_ptr m_joystickDescriptorCache; std::unique_ptr m_matchInfoCache; std::unique_ptr m_matchDataSender; // Joystick button rising/falling edge flags std::array m_joystickButtonsPressed; std::array m_joystickButtonsReleased; // Internal Driver Station thread std::thread m_dsThread; std::atomic m_isRunning{false}; wpi::mutex m_waitForDataMutex; wpi::condition_variable m_waitForDataCond; int m_waitForDataCounter; mutable wpi::mutex m_cacheDataMutex; // Robot state status variables bool m_userInDisabled = false; bool m_userInAutonomous = false; bool m_userInTeleop = false; bool m_userInTest = false; // Control word variables mutable HAL_ControlWord m_controlWordCache; mutable std::chrono::steady_clock::time_point m_lastControlWordUpdate; mutable wpi::mutex m_controlWordMutex; double m_nextMessageTime = 0; }; } // namespace frc