blob: 8420a9e4437b83f7e852d9fa46bc222bb5667b48 [file] [log] [blame]
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2017. 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. */
/*----------------------------------------------------------------------------*/
#include "frc971/wpilib/ahal/DriverStation.h"
#include <chrono>
#include "FRC_NetworkCommunication/FRCComm.h"
#include "aos/make_unique.h"
#include "frc971/wpilib/ahal/AnalogInput.h"
#include "frc971/wpilib/ahal/Utility.h"
#include "frc971/wpilib/ahal/WPIErrors.h"
#include "hal/HAL.h"
#include "hal/Power.h"
#include "wpi/SmallString.h"
using namespace frc;
#define WPI_LIB_FATAL(error_tag) \
do { \
} while (false)
const int DriverStation::kJoystickPorts;
DriverStation::~DriverStation() {}
/**
* Return a pointer to the singleton DriverStation.
*
* @return Pointer to the DS instance
*/
DriverStation &DriverStation::GetInstance() {
static DriverStation instance;
return instance;
}
/**
* Report an error to the DriverStation messages window.
*
* The error is also printed to the program console.
*/
void DriverStation::ReportError(const wpi::Twine &error) {
wpi::SmallString<128> temp;
HAL_SendError(1, 1, 0, error.toNullTerminatedStringRef(temp).data(), "", "",
1);
}
/**
* Report a warning to the DriverStation messages window.
*
* The warning is also printed to the program console.
*/
void DriverStation::ReportWarning(const wpi::Twine &error) {
wpi::SmallString<128> temp;
HAL_SendError(0, 1, 0, error.toNullTerminatedStringRef(temp).data(), "", "",
1);
}
/**
* Report an error to the DriverStation messages window.
*
* The error is also printed to the program console.
*/
void DriverStation::ReportError(bool is_error, int32_t code,
const wpi::Twine &error,
const wpi::Twine &location,
const wpi::Twine &stack) {
wpi::SmallString<128> errorTemp;
wpi::SmallString<128> locationTemp;
wpi::SmallString<128> stackTemp;
HAL_SendError(is_error, code, 0,
error.toNullTerminatedStringRef(errorTemp).data(),
location.toNullTerminatedStringRef(locationTemp).data(),
stack.toNullTerminatedStringRef(stackTemp).data(), 1);
}
/**
* 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 DriverStation::GetStickAxis(int stick, int axis) {
if (stick >= kJoystickPorts) {
WPI_LIB_FATAL(BadJoystickIndex);
return 0;
}
if (axis >= m_joystickAxes[stick].count) {
if (axis >= HAL_kMaxJoystickAxes) WPI_LIB_FATAL(BadJoystickAxis);
return 0.0;
}
return m_joystickAxes[stick].axes[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 DriverStation::GetStickPOV(int stick, int pov) {
if (stick >= kJoystickPorts) {
WPI_LIB_FATAL(BadJoystickIndex);
return -1;
}
if (pov >= m_joystickPOVs[stick].count) {
if (pov >= HAL_kMaxJoystickPOVs) WPI_LIB_FATAL(BadJoystickAxis);
return -1;
}
return m_joystickPOVs[stick].povs[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 DriverStation::GetStickButtons(int stick) const {
if (stick >= kJoystickPorts) {
WPI_LIB_FATAL(BadJoystickIndex);
return 0;
}
return m_joystickButtons[stick].buttons;
}
/**
* 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 DriverStation::GetStickButton(int stick, int button) {
if (stick >= kJoystickPorts) {
WPI_LIB_FATAL(BadJoystickIndex);
return false;
}
if (button == 0) {
return false;
}
if (button > m_joystickButtons[stick].count) {
return false;
}
return ((0x1 << (button - 1)) & m_joystickButtons[stick].buttons) != 0;
}
/**
* 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 DriverStation::GetStickAxisCount(int stick) const {
if (stick >= kJoystickPorts) {
WPI_LIB_FATAL(BadJoystickIndex);
return 0;
}
return m_joystickAxes[stick].count;
}
/**
* 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 DriverStation::GetStickPOVCount(int stick) const {
if (stick >= kJoystickPorts) {
WPI_LIB_FATAL(BadJoystickIndex);
return 0;
}
return m_joystickPOVs[stick].count;
}
/**
* 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 DriverStation::GetStickButtonCount(int stick) const {
if (stick >= kJoystickPorts) {
WPI_LIB_FATAL(BadJoystickIndex);
return 0;
}
return m_joystickButtons[stick].count;
}
/**
* 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 DriverStation::GetJoystickIsXbox(int stick) const {
if (stick >= kJoystickPorts) {
WPI_LIB_FATAL(BadJoystickIndex);
return false;
}
return static_cast<bool>(m_joystickDescriptor[stick].isXbox);
}
/**
* 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 DriverStation::GetJoystickType(int stick) const {
if (stick >= kJoystickPorts) {
WPI_LIB_FATAL(BadJoystickIndex);
return -1;
}
return static_cast<int>(m_joystickDescriptor[stick].type);
}
/**
* 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 DriverStation::GetJoystickName(int stick) const {
if (stick >= kJoystickPorts) {
WPI_LIB_FATAL(BadJoystickIndex);
}
std::string retVal(m_joystickDescriptor[stick].name);
return retVal;
}
/**
* 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 DriverStation::GetJoystickAxisType(int stick, int axis) const {
if (stick >= kJoystickPorts) {
WPI_LIB_FATAL(BadJoystickIndex);
return -1;
}
return m_joystickDescriptor[stick].axisTypes[axis];
}
/**
* 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.
*/
bool DriverStation::IsSysActive() const {
int32_t status = 0;
bool retVal = HAL_GetSystemActive(&status);
wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
return retVal;
}
/**
* Check if the system is browned out.
*
* @return True if the system is browned out
*/
bool DriverStation::IsBrownedOut() const {
int32_t status = 0;
bool retVal = HAL_GetBrownedOut(&status);
wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
return retVal;
}
/**
* 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)
*/
DriverStation::Alliance DriverStation::GetAlliance() const {
int32_t status = 0;
auto allianceStationID = HAL_GetAllianceStation(&status);
switch (allianceStationID) {
case HAL_AllianceStationID_kRed1:
case HAL_AllianceStationID_kRed2:
case HAL_AllianceStationID_kRed3:
return kRed;
case HAL_AllianceStationID_kBlue1:
case HAL_AllianceStationID_kBlue2:
case HAL_AllianceStationID_kBlue3:
return kBlue;
default:
return kInvalid;
}
}
/**
* 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 DriverStation::GetLocation() const {
int32_t status = 0;
auto allianceStationID = HAL_GetAllianceStation(&status);
switch (allianceStationID) {
case HAL_AllianceStationID_kRed1:
case HAL_AllianceStationID_kBlue1:
return 1;
case HAL_AllianceStationID_kRed2:
case HAL_AllianceStationID_kBlue2:
return 2;
case HAL_AllianceStationID_kRed3:
case HAL_AllianceStationID_kBlue3:
return 3;
default:
return 0;
}
}
/**
* 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 DriverStation::GetMatchTime() const {
int32_t status;
return HAL_GetMatchTime(&status);
}
/**
* Read the battery voltage.
*
* @return The battery voltage in Volts.
*/
double DriverStation::GetBatteryVoltage() const {
int32_t status = 0;
double voltage = HAL_GetVinVoltage(&status);
wpi_setErrorWithContext(status, "getVinVoltage");
return voltage;
}
/**
* 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 DriverStation::GetData() {
// Get the status of all of the joysticks, and save to the cache
for (uint8_t stick = 0; stick < kJoystickPorts; stick++) {
HAL_GetJoystickAxes(stick, &m_joystickAxesCache[stick]);
HAL_GetJoystickPOVs(stick, &m_joystickPOVsCache[stick]);
HAL_GetJoystickButtons(stick, &m_joystickButtonsCache[stick]);
HAL_GetJoystickDescriptor(stick, &m_joystickDescriptorCache[stick]);
}
m_joystickAxes.swap(m_joystickAxesCache);
m_joystickPOVs.swap(m_joystickPOVsCache);
m_joystickButtons.swap(m_joystickButtonsCache);
m_joystickDescriptor.swap(m_joystickDescriptorCache);
HAL_ControlWord control_word;
HAL_GetControlWord(&control_word);
is_enabled_ = control_word.enabled;
is_autonomous_ = control_word.autonomous;
is_test_mode_ = control_word.test;
is_fms_attached_ = control_word.fmsAttached;
}
/**
* DriverStation constructor.
*
* This is only called once the first time GetInstance() is called
*/
DriverStation::DriverStation() {
// The HAL_Observe* functions let the Driver Station know that the
// robot code is alive (this influences the Robot Code status light on the
// DS, and if the DS thinks you don't have robot code, then you can't enable).
HAL_ObserveUserProgramStarting();
m_joystickAxes = aos::make_unique<HAL_JoystickAxes[]>(kJoystickPorts);
m_joystickPOVs = aos::make_unique<HAL_JoystickPOVs[]>(kJoystickPorts);
m_joystickButtons = aos::make_unique<HAL_JoystickButtons[]>(kJoystickPorts);
m_joystickDescriptor =
aos::make_unique<HAL_JoystickDescriptor[]>(kJoystickPorts);
m_joystickAxesCache = aos::make_unique<HAL_JoystickAxes[]>(kJoystickPorts);
m_joystickPOVsCache = aos::make_unique<HAL_JoystickPOVs[]>(kJoystickPorts);
m_joystickButtonsCache =
aos::make_unique<HAL_JoystickButtons[]>(kJoystickPorts);
m_joystickDescriptorCache =
aos::make_unique<HAL_JoystickDescriptor[]>(kJoystickPorts);
// All joysticks should default to having zero axes, povs and buttons, so
// uninitialized memory doesn't get sent to speed controllers.
for (unsigned int i = 0; i < kJoystickPorts; i++) {
m_joystickAxes[i].count = 0;
m_joystickPOVs[i].count = 0;
m_joystickButtons[i].count = 0;
m_joystickDescriptor[i].isXbox = 0;
m_joystickDescriptor[i].type = -1;
m_joystickDescriptor[i].name[0] = '\0';
m_joystickAxesCache[i].count = 0;
m_joystickPOVsCache[i].count = 0;
m_joystickButtonsCache[i].count = 0;
m_joystickDescriptorCache[i].isXbox = 0;
m_joystickDescriptorCache[i].type = -1;
m_joystickDescriptorCache[i].name[0] = '\0';
}
}
void DriverStation::RunIteration(std::function<void()> on_data) {
HAL_WaitForDSData();
GetData();
// We have to feed some sort of watchdog so that the driver's station knows
// that the robot code is still alive. HAL_ObserveUserProgramStarting must be
// called during initialization (currently called in the constructor of this
// class).
if (!IsEnabled()) {
HAL_ObserveUserProgramDisabled();
} else if (IsAutonomous()) {
HAL_ObserveUserProgramAutonomous();
} else if (IsTestMode()) {
HAL_ObserveUserProgramTest();
} else {
HAL_ObserveUserProgramTeleop();
}
on_data();
}