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.
|
2013-12-15 18:30:16 -05:00
|
|
|
|
2018-07-20 00:03:45 -07:00
|
|
|
#include "frc/DriverStation.h"
|
2016-09-14 20:52:06 -07:00
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
#include <stdint.h>
|
|
|
|
|
|
|
|
|
|
#include <array>
|
|
|
|
|
#include <atomic>
|
2016-10-09 11:46:01 -07:00
|
|
|
#include <chrono>
|
2020-11-15 13:48:54 -05:00
|
|
|
#include <string>
|
2021-05-26 17:44:18 -07:00
|
|
|
#include <string_view>
|
2021-06-15 23:06:03 -07:00
|
|
|
#include <thread>
|
2020-11-15 13:48:54 -05:00
|
|
|
#include <type_traits>
|
2016-10-09 11:46:01 -07:00
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
#include <fmt/format.h>
|
2019-11-08 22:53:20 -08:00
|
|
|
#include <hal/DriverStation.h>
|
2021-06-15 23:06:03 -07:00
|
|
|
#include <hal/DriverStationTypes.h>
|
2019-11-08 22:53:20 -08:00
|
|
|
#include <hal/HALBase.h>
|
2018-07-20 00:03:45 -07:00
|
|
|
#include <hal/Power.h>
|
2018-01-18 23:17:28 -08:00
|
|
|
#include <networktables/NetworkTable.h>
|
|
|
|
|
#include <networktables/NetworkTableEntry.h>
|
|
|
|
|
#include <networktables/NetworkTableInstance.h>
|
2022-01-27 00:15:43 -08:00
|
|
|
#include <wpi/DataLog.h>
|
2021-06-15 23:06:03 -07:00
|
|
|
#include <wpi/condition_variable.h>
|
|
|
|
|
#include <wpi/mutex.h>
|
2022-01-27 00:15:43 -08:00
|
|
|
#include <wpi/timestamp.h>
|
2017-08-27 00:11:52 -07:00
|
|
|
|
2021-04-18 20:35:29 -07:00
|
|
|
#include "frc/Errors.h"
|
2018-12-29 16:19:23 -08:00
|
|
|
#include "frc/MotorSafety.h"
|
2018-07-20 00:03:45 -07:00
|
|
|
#include "frc/Timer.h"
|
2014-01-06 10:12:21 -05:00
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
using namespace frc;
|
|
|
|
|
|
|
|
|
|
namespace {
|
2020-11-15 13:48:54 -05:00
|
|
|
// A simple class which caches the previous value written to an NT entry
|
|
|
|
|
// Used to prevent redundant, repeated writes of the same value
|
|
|
|
|
template <class T>
|
|
|
|
|
class MatchDataSenderEntry {
|
|
|
|
|
public:
|
|
|
|
|
MatchDataSenderEntry(const std::shared_ptr<nt::NetworkTable>& table,
|
2021-05-26 17:44:18 -07:00
|
|
|
std::string_view key, const T& initialVal) {
|
2020-11-27 22:06:08 -08:00
|
|
|
static_assert(std::is_same_v<T, bool> || std::is_same_v<T, double> ||
|
|
|
|
|
std::is_same_v<T, std::string>,
|
|
|
|
|
"Invalid type for MatchDataSenderEntry - must be "
|
|
|
|
|
"to bool, double or std::string");
|
2020-11-15 13:48:54 -05:00
|
|
|
|
|
|
|
|
ntEntry = table->GetEntry(key);
|
2020-11-27 22:06:08 -08:00
|
|
|
if constexpr (std::is_same_v<T, bool>) {
|
2020-11-15 13:48:54 -05:00
|
|
|
ntEntry.ForceSetBoolean(initialVal);
|
2020-11-27 22:06:08 -08:00
|
|
|
} else if constexpr (std::is_same_v<T, double>) {
|
2020-11-15 13:48:54 -05:00
|
|
|
ntEntry.ForceSetDouble(initialVal);
|
2020-11-27 22:06:08 -08:00
|
|
|
} else if constexpr (std::is_same_v<T, std::string>) {
|
2020-11-15 13:48:54 -05:00
|
|
|
ntEntry.ForceSetString(initialVal);
|
|
|
|
|
}
|
|
|
|
|
prevVal = initialVal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Set(const T& val) {
|
|
|
|
|
if (val != prevVal) {
|
|
|
|
|
SetValue(val);
|
|
|
|
|
prevVal = val;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
nt::NetworkTableEntry ntEntry;
|
|
|
|
|
T prevVal;
|
|
|
|
|
|
|
|
|
|
void SetValue(bool val) { ntEntry.SetBoolean(val); }
|
|
|
|
|
void SetValue(double val) { ntEntry.SetDouble(val); }
|
2021-05-26 17:44:18 -07:00
|
|
|
void SetValue(std::string_view val) { ntEntry.SetString(val); }
|
2020-11-15 13:48:54 -05:00
|
|
|
};
|
2018-01-18 23:17:28 -08:00
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
struct MatchDataSender {
|
|
|
|
|
std::shared_ptr<nt::NetworkTable> table =
|
|
|
|
|
nt::NetworkTableInstance::GetDefault().GetTable("FMSInfo");
|
|
|
|
|
MatchDataSenderEntry<std::string> typeMetaData{table, ".type", "FMSInfo"};
|
|
|
|
|
MatchDataSenderEntry<std::string> gameSpecificMessage{
|
|
|
|
|
table, "GameSpecificMessage", ""};
|
|
|
|
|
MatchDataSenderEntry<std::string> eventName{table, "EventName", ""};
|
|
|
|
|
MatchDataSenderEntry<double> matchNumber{table, "MatchNumber", 0.0};
|
|
|
|
|
MatchDataSenderEntry<double> replayNumber{table, "ReplayNumber", 0.0};
|
|
|
|
|
MatchDataSenderEntry<double> matchType{table, "MatchType", 0.0};
|
|
|
|
|
MatchDataSenderEntry<bool> alliance{table, "IsRedAlliance", true};
|
|
|
|
|
MatchDataSenderEntry<double> station{table, "StationNumber", 1.0};
|
|
|
|
|
MatchDataSenderEntry<double> controlWord{table, "FMSControlData", 0.0};
|
2018-01-18 23:17:28 -08:00
|
|
|
};
|
2017-11-09 19:59:29 -08:00
|
|
|
|
2022-01-27 00:15:43 -08:00
|
|
|
class JoystickLogSender {
|
|
|
|
|
public:
|
|
|
|
|
void Init(wpi::log::DataLog& log, unsigned int stick, int64_t timestamp);
|
|
|
|
|
void Send(uint64_t timestamp);
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void AppendButtons(HAL_JoystickButtons buttons, uint64_t timestamp);
|
|
|
|
|
void AppendPOVs(const HAL_JoystickPOVs& povs, uint64_t timestamp);
|
|
|
|
|
|
|
|
|
|
unsigned int m_stick;
|
|
|
|
|
HAL_JoystickButtons m_prevButtons;
|
|
|
|
|
HAL_JoystickAxes m_prevAxes;
|
|
|
|
|
HAL_JoystickPOVs m_prevPOVs;
|
|
|
|
|
wpi::log::BooleanArrayLogEntry m_logButtons;
|
|
|
|
|
wpi::log::FloatArrayLogEntry m_logAxes;
|
|
|
|
|
wpi::log::IntegerArrayLogEntry m_logPOVs;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class DataLogSender {
|
|
|
|
|
public:
|
|
|
|
|
void Init(wpi::log::DataLog& log, bool logJoysticks, int64_t timestamp);
|
|
|
|
|
void Send(uint64_t timestamp);
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
std::atomic_bool m_initialized{false};
|
|
|
|
|
|
|
|
|
|
HAL_ControlWord m_prevControlWord;
|
|
|
|
|
wpi::log::BooleanLogEntry m_logEnabled;
|
|
|
|
|
wpi::log::BooleanLogEntry m_logAutonomous;
|
|
|
|
|
wpi::log::BooleanLogEntry m_logTest;
|
|
|
|
|
wpi::log::BooleanLogEntry m_logEstop;
|
|
|
|
|
|
|
|
|
|
bool m_logJoysticks;
|
|
|
|
|
std::array<JoystickLogSender, DriverStation::kJoystickPorts> m_joysticks;
|
|
|
|
|
};
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
struct Instance {
|
|
|
|
|
Instance();
|
|
|
|
|
~Instance();
|
|
|
|
|
|
|
|
|
|
MatchDataSender matchDataSender;
|
2022-01-27 00:15:43 -08:00
|
|
|
std::atomic<DataLogSender*> dataLogSender{nullptr};
|
2021-06-15 23:06:03 -07:00
|
|
|
|
|
|
|
|
// Joystick button rising/falling edge flags
|
|
|
|
|
wpi::mutex buttonEdgeMutex;
|
|
|
|
|
std::array<HAL_JoystickButtons, DriverStation::kJoystickPorts>
|
|
|
|
|
previousButtonStates;
|
|
|
|
|
std::array<uint32_t, DriverStation::kJoystickPorts> joystickButtonsPressed;
|
|
|
|
|
std::array<uint32_t, DriverStation::kJoystickPorts> joystickButtonsReleased;
|
|
|
|
|
|
|
|
|
|
// Internal Driver Station thread
|
|
|
|
|
std::thread dsThread;
|
|
|
|
|
std::atomic<bool> isRunning{false};
|
|
|
|
|
|
|
|
|
|
mutable wpi::mutex waitForDataMutex;
|
|
|
|
|
wpi::condition_variable waitForDataCond;
|
|
|
|
|
int waitForDataCounter = 0;
|
|
|
|
|
|
|
|
|
|
bool silenceJoystickWarning = false;
|
|
|
|
|
|
|
|
|
|
// Robot state status variables
|
|
|
|
|
bool userInDisabled = false;
|
|
|
|
|
bool userInAutonomous = false;
|
|
|
|
|
bool userInTeleop = false;
|
|
|
|
|
bool userInTest = false;
|
|
|
|
|
|
|
|
|
|
units::second_t nextMessageTime = 0_s;
|
|
|
|
|
};
|
|
|
|
|
} // namespace
|
2016-11-01 22:33:12 -07:00
|
|
|
|
2021-05-28 22:06:59 -07:00
|
|
|
static constexpr auto kJoystickUnpluggedMessageInterval = 1_s;
|
2013-12-15 18:30:16 -05:00
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
static Instance& GetInstance() {
|
|
|
|
|
static Instance instance;
|
|
|
|
|
return instance;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void Run();
|
|
|
|
|
static void SendMatchData();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Reports errors related to unplugged joysticks.
|
|
|
|
|
*
|
|
|
|
|
* Throttles the errors so that they don't overwhelm the DS.
|
|
|
|
|
*/
|
|
|
|
|
static void ReportJoystickUnpluggedErrorV(fmt::string_view format,
|
|
|
|
|
fmt::format_args args);
|
|
|
|
|
|
|
|
|
|
template <typename S, typename... Args>
|
|
|
|
|
static inline void ReportJoystickUnpluggedError(const S& format,
|
|
|
|
|
Args&&... args) {
|
|
|
|
|
ReportJoystickUnpluggedErrorV(
|
|
|
|
|
format, fmt::make_args_checked<Args...>(format, args...));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Reports errors related to unplugged joysticks.
|
|
|
|
|
*
|
|
|
|
|
* Throttles the errors so that they don't overwhelm the DS.
|
|
|
|
|
*/
|
|
|
|
|
static void ReportJoystickUnpluggedWarningV(fmt::string_view format,
|
|
|
|
|
fmt::format_args args);
|
|
|
|
|
|
|
|
|
|
template <typename S, typename... Args>
|
|
|
|
|
static inline void ReportJoystickUnpluggedWarning(const S& format,
|
|
|
|
|
Args&&... args) {
|
|
|
|
|
ReportJoystickUnpluggedWarningV(
|
|
|
|
|
format, fmt::make_args_checked<Args...>(format, args...));
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-13 21:57:54 -07:00
|
|
|
static int& GetDSLastCount() {
|
|
|
|
|
// There is a rollover error condition here. At Packet# = n * (uintmax), this
|
|
|
|
|
// will return false when instead it should return true. However, this at a
|
|
|
|
|
// 20ms rate occurs once every 2.7 years of DS connected runtime, so not
|
|
|
|
|
// worth the cycles to check.
|
|
|
|
|
thread_local int lastCount{0};
|
|
|
|
|
return lastCount;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
Instance::Instance() {
|
|
|
|
|
HAL_Initialize(500, 0);
|
|
|
|
|
|
|
|
|
|
// All joysticks should default to having zero axes, povs and buttons, so
|
2021-09-08 22:09:08 -07:00
|
|
|
// uninitialized memory doesn't get sent to motor controllers.
|
2021-06-15 23:06:03 -07:00
|
|
|
for (unsigned int i = 0; i < DriverStation::kJoystickPorts; i++) {
|
|
|
|
|
joystickButtonsPressed[i] = 0;
|
|
|
|
|
joystickButtonsReleased[i] = 0;
|
|
|
|
|
previousButtonStates[i].count = 0;
|
|
|
|
|
previousButtonStates[i].buttons = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dsThread = std::thread(&Run);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Instance::~Instance() {
|
|
|
|
|
isRunning = false;
|
2017-11-28 19:12:05 -08:00
|
|
|
// Trigger a DS mutex release in case there is no driver station running.
|
|
|
|
|
HAL_ReleaseDSMutex();
|
2021-06-15 23:06:03 -07:00
|
|
|
dsThread.join();
|
2022-01-27 00:15:43 -08:00
|
|
|
|
|
|
|
|
if (dataLogSender) {
|
|
|
|
|
delete dataLogSender.load();
|
|
|
|
|
}
|
2013-12-15 18:30:16 -05:00
|
|
|
}
|
|
|
|
|
|
2017-10-27 21:45:56 -07:00
|
|
|
bool DriverStation::GetStickButton(int stick, int button) {
|
2018-05-16 00:13:52 -07:00
|
|
|
if (stick < 0 || stick >= kJoystickPorts) {
|
2021-05-23 19:33:33 -07:00
|
|
|
FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
|
2017-10-27 21:45:56 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
2018-05-16 00:13:52 -07:00
|
|
|
if (button <= 0) {
|
2017-10-27 21:45:56 -07:00
|
|
|
ReportJoystickUnpluggedError(
|
2021-05-24 23:36:26 -07:00
|
|
|
"Joystick Button {} index out of range; indexes begin at 1", button);
|
2017-10-27 21:45:56 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
2018-05-16 00:13:52 -07:00
|
|
|
|
2018-07-18 22:22:41 -07:00
|
|
|
HAL_JoystickButtons buttons;
|
|
|
|
|
HAL_GetJoystickButtons(stick, &buttons);
|
|
|
|
|
|
|
|
|
|
if (button > buttons.count) {
|
2017-10-27 21:45:56 -07:00
|
|
|
ReportJoystickUnpluggedWarning(
|
2021-05-24 23:36:26 -07:00
|
|
|
"Joystick Button {} missing (max {}), check if all controllers are "
|
|
|
|
|
"plugged in",
|
|
|
|
|
button, buttons.count);
|
2017-10-27 21:45:56 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-18 22:22:41 -07:00
|
|
|
return buttons.buttons & 1 << (button - 1);
|
2017-10-27 21:45:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DriverStation::GetStickButtonPressed(int stick, int button) {
|
2018-05-16 00:13:52 -07:00
|
|
|
if (stick < 0 || stick >= kJoystickPorts) {
|
2021-05-23 19:33:33 -07:00
|
|
|
FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
|
2017-10-27 21:45:56 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
2018-05-16 00:13:52 -07:00
|
|
|
if (button <= 0) {
|
2017-10-27 21:45:56 -07:00
|
|
|
ReportJoystickUnpluggedError(
|
2021-05-24 23:36:26 -07:00
|
|
|
"Joystick Button {} index out of range; indexes begin at 1", button);
|
2017-10-27 21:45:56 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
2018-05-16 00:13:52 -07:00
|
|
|
|
2018-07-18 22:22:41 -07:00
|
|
|
HAL_JoystickButtons buttons;
|
|
|
|
|
HAL_GetJoystickButtons(stick, &buttons);
|
|
|
|
|
|
|
|
|
|
if (button > buttons.count) {
|
2017-10-27 21:45:56 -07:00
|
|
|
ReportJoystickUnpluggedWarning(
|
2021-05-24 23:36:26 -07:00
|
|
|
"Joystick Button {} missing (max {}), check if all controllers are "
|
|
|
|
|
"plugged in",
|
|
|
|
|
button, buttons.count);
|
2017-10-27 21:45:56 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
2021-06-15 23:06:03 -07:00
|
|
|
auto& inst = ::GetInstance();
|
|
|
|
|
std::unique_lock lock(inst.buttonEdgeMutex);
|
2017-10-27 21:45:56 -07:00
|
|
|
// If button was pressed, clear flag and return true
|
2021-06-15 23:06:03 -07:00
|
|
|
if (inst.joystickButtonsPressed[stick] & 1 << (button - 1)) {
|
|
|
|
|
inst.joystickButtonsPressed[stick] &= ~(1 << (button - 1));
|
2017-10-27 21:45:56 -07:00
|
|
|
return true;
|
|
|
|
|
}
|
2021-06-15 23:06:03 -07:00
|
|
|
return false;
|
2017-10-27 21:45:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DriverStation::GetStickButtonReleased(int stick, int button) {
|
2018-05-16 00:13:52 -07:00
|
|
|
if (stick < 0 || stick >= kJoystickPorts) {
|
2021-05-23 19:33:33 -07:00
|
|
|
FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
|
2017-10-27 21:45:56 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
2018-12-07 01:31:14 -05:00
|
|
|
if (button <= 0) {
|
2017-10-27 21:45:56 -07:00
|
|
|
ReportJoystickUnpluggedError(
|
2021-05-24 23:36:26 -07:00
|
|
|
"Joystick Button {} index out of range; indexes begin at 1", button);
|
2017-10-27 21:45:56 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
2018-05-16 00:13:52 -07:00
|
|
|
|
2018-07-18 22:22:41 -07:00
|
|
|
HAL_JoystickButtons buttons;
|
|
|
|
|
HAL_GetJoystickButtons(stick, &buttons);
|
|
|
|
|
|
|
|
|
|
if (button > buttons.count) {
|
2017-10-27 21:45:56 -07:00
|
|
|
ReportJoystickUnpluggedWarning(
|
2021-05-24 23:36:26 -07:00
|
|
|
"Joystick Button {} missing (max {}), check if all controllers are "
|
|
|
|
|
"plugged in",
|
|
|
|
|
button, buttons.count);
|
2017-10-27 21:45:56 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
2021-06-15 23:06:03 -07:00
|
|
|
auto& inst = ::GetInstance();
|
|
|
|
|
std::unique_lock lock(inst.buttonEdgeMutex);
|
2017-10-27 21:45:56 -07:00
|
|
|
// If button was released, clear flag and return true
|
2021-06-15 23:06:03 -07:00
|
|
|
if (inst.joystickButtonsReleased[stick] & 1 << (button - 1)) {
|
|
|
|
|
inst.joystickButtonsReleased[stick] &= ~(1 << (button - 1));
|
2017-10-27 21:45:56 -07:00
|
|
|
return true;
|
|
|
|
|
}
|
2021-06-15 23:06:03 -07:00
|
|
|
return false;
|
2017-10-27 21:45:56 -07:00
|
|
|
}
|
|
|
|
|
|
2016-11-20 07:25:03 -08:00
|
|
|
double DriverStation::GetStickAxis(int stick, int axis) {
|
2018-05-16 00:13:52 -07:00
|
|
|
if (stick < 0 || stick >= kJoystickPorts) {
|
2021-05-23 19:33:33 -07:00
|
|
|
FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
|
2018-05-16 00:13:52 -07:00
|
|
|
return 0.0;
|
|
|
|
|
}
|
2018-12-07 01:31:14 -05:00
|
|
|
if (axis < 0 || axis >= HAL_kMaxJoystickAxes) {
|
2021-05-23 19:33:33 -07:00
|
|
|
FRC_ReportError(warn::BadJoystickAxis, "axis {} out of range", axis);
|
2018-05-16 00:13:52 -07:00
|
|
|
return 0.0;
|
2015-06-25 15:07:55 -04:00
|
|
|
}
|
2018-05-16 00:13:52 -07:00
|
|
|
|
2018-07-18 22:22:41 -07:00
|
|
|
HAL_JoystickAxes axes;
|
|
|
|
|
HAL_GetJoystickAxes(stick, &axes);
|
|
|
|
|
|
|
|
|
|
if (axis >= axes.count) {
|
2018-05-16 00:13:52 -07:00
|
|
|
ReportJoystickUnpluggedWarning(
|
2021-05-24 23:36:26 -07:00
|
|
|
"Joystick Axis {} missing (max {}), check if all controllers are "
|
|
|
|
|
"plugged in",
|
|
|
|
|
axis, axes.count);
|
2016-11-20 07:25:03 -08:00
|
|
|
return 0.0;
|
2016-07-14 20:50:38 -07:00
|
|
|
}
|
|
|
|
|
|
2018-07-18 22:22:41 -07:00
|
|
|
return axes.axes[axis];
|
2014-12-05 20:13:23 -05:00
|
|
|
}
|
|
|
|
|
|
2016-09-06 00:01:45 -07:00
|
|
|
int DriverStation::GetStickPOV(int stick, int pov) {
|
2018-05-16 00:13:52 -07:00
|
|
|
if (stick < 0 || stick >= kJoystickPorts) {
|
2021-05-23 19:33:33 -07:00
|
|
|
FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
|
2016-07-14 20:50:38 -07:00
|
|
|
return -1;
|
2015-06-25 15:07:55 -04:00
|
|
|
}
|
2018-12-07 01:31:14 -05:00
|
|
|
if (pov < 0 || pov >= HAL_kMaxJoystickPOVs) {
|
2021-05-23 19:33:33 -07:00
|
|
|
FRC_ReportError(warn::BadJoystickAxis, "POV {} out of range", pov);
|
2018-05-16 00:13:52 -07:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-18 22:22:41 -07:00
|
|
|
HAL_JoystickPOVs povs;
|
|
|
|
|
HAL_GetJoystickPOVs(stick, &povs);
|
|
|
|
|
|
|
|
|
|
if (pov >= povs.count) {
|
2018-05-16 00:13:52 -07:00
|
|
|
ReportJoystickUnpluggedWarning(
|
2021-05-24 23:36:26 -07:00
|
|
|
"Joystick POV {} missing (max {}), check if all controllers are "
|
|
|
|
|
"plugged in",
|
|
|
|
|
pov, povs.count);
|
2016-07-14 20:50:38 -07:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-18 22:22:41 -07:00
|
|
|
return povs.povs[pov];
|
2015-06-15 12:34:57 -04:00
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
int DriverStation::GetStickButtons(int stick) {
|
2018-05-16 00:13:52 -07:00
|
|
|
if (stick < 0 || stick >= kJoystickPorts) {
|
2021-05-23 19:33:33 -07:00
|
|
|
FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
|
2016-07-14 20:50:38 -07:00
|
|
|
return 0;
|
2015-06-25 15:07:55 -04:00
|
|
|
}
|
2018-05-16 00:13:52 -07:00
|
|
|
|
2018-07-18 22:22:41 -07:00
|
|
|
HAL_JoystickButtons buttons;
|
|
|
|
|
HAL_GetJoystickButtons(stick, &buttons);
|
|
|
|
|
|
|
|
|
|
return buttons.buttons;
|
2015-06-15 12:34:57 -04:00
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
int DriverStation::GetStickAxisCount(int stick) {
|
2018-05-16 00:13:52 -07:00
|
|
|
if (stick < 0 || stick >= kJoystickPorts) {
|
2021-05-23 19:33:33 -07:00
|
|
|
FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
|
2016-07-14 20:50:38 -07:00
|
|
|
return 0;
|
2015-06-25 15:07:55 -04:00
|
|
|
}
|
2018-05-16 00:13:52 -07:00
|
|
|
|
2018-07-18 22:22:41 -07:00
|
|
|
HAL_JoystickAxes axes;
|
|
|
|
|
HAL_GetJoystickAxes(stick, &axes);
|
|
|
|
|
|
|
|
|
|
return axes.count;
|
2015-06-15 12:34:57 -04:00
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
int DriverStation::GetStickPOVCount(int stick) {
|
2018-05-16 00:13:52 -07:00
|
|
|
if (stick < 0 || stick >= kJoystickPorts) {
|
2021-05-23 19:33:33 -07:00
|
|
|
FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
|
2015-06-25 15:07:55 -04:00
|
|
|
return 0;
|
|
|
|
|
}
|
2018-05-16 00:13:52 -07:00
|
|
|
|
2018-07-18 22:22:41 -07:00
|
|
|
HAL_JoystickPOVs povs;
|
|
|
|
|
HAL_GetJoystickPOVs(stick, &povs);
|
|
|
|
|
|
|
|
|
|
return povs.count;
|
2014-12-05 20:13:23 -05:00
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
int DriverStation::GetStickButtonCount(int stick) {
|
2018-05-16 00:13:52 -07:00
|
|
|
if (stick < 0 || stick >= kJoystickPorts) {
|
2021-05-23 19:33:33 -07:00
|
|
|
FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
|
2015-06-25 15:07:55 -04:00
|
|
|
return 0;
|
|
|
|
|
}
|
2018-05-16 00:13:52 -07:00
|
|
|
|
2018-07-18 22:22:41 -07:00
|
|
|
HAL_JoystickButtons buttons;
|
|
|
|
|
HAL_GetJoystickButtons(stick, &buttons);
|
|
|
|
|
|
|
|
|
|
return buttons.count;
|
2014-12-05 20:13:23 -05:00
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
bool DriverStation::GetJoystickIsXbox(int stick) {
|
2018-05-16 00:13:52 -07:00
|
|
|
if (stick < 0 || stick >= kJoystickPorts) {
|
2021-05-23 19:33:33 -07:00
|
|
|
FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
|
2016-07-14 20:50:38 -07:00
|
|
|
return false;
|
2015-06-25 15:07:55 -04:00
|
|
|
}
|
2018-05-16 00:13:52 -07:00
|
|
|
|
2018-07-18 22:22:41 -07:00
|
|
|
HAL_JoystickDescriptor descriptor;
|
|
|
|
|
HAL_GetJoystickDescriptor(stick, &descriptor);
|
|
|
|
|
|
|
|
|
|
return static_cast<bool>(descriptor.isXbox);
|
2013-12-15 18:30:16 -05:00
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
int DriverStation::GetJoystickType(int stick) {
|
2018-05-16 00:13:52 -07:00
|
|
|
if (stick < 0 || stick >= kJoystickPorts) {
|
2021-05-23 19:33:33 -07:00
|
|
|
FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
|
2015-06-25 15:07:55 -04:00
|
|
|
return -1;
|
|
|
|
|
}
|
2018-05-16 00:13:52 -07:00
|
|
|
|
2018-07-18 22:22:41 -07:00
|
|
|
HAL_JoystickDescriptor descriptor;
|
|
|
|
|
HAL_GetJoystickDescriptor(stick, &descriptor);
|
|
|
|
|
|
|
|
|
|
return static_cast<int>(descriptor.type);
|
2014-10-17 14:46:25 -04:00
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
std::string DriverStation::GetJoystickName(int stick) {
|
2018-05-16 00:13:52 -07:00
|
|
|
if (stick < 0 || stick >= kJoystickPorts) {
|
2021-05-23 19:33:33 -07:00
|
|
|
FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
|
2015-06-25 15:07:55 -04:00
|
|
|
}
|
2018-05-16 00:13:52 -07:00
|
|
|
|
2018-07-18 22:22:41 -07:00
|
|
|
HAL_JoystickDescriptor descriptor;
|
|
|
|
|
HAL_GetJoystickDescriptor(stick, &descriptor);
|
|
|
|
|
|
|
|
|
|
return descriptor.name;
|
2014-12-18 10:57:11 -05:00
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
int DriverStation::GetJoystickAxisType(int stick, int axis) {
|
2018-05-16 00:13:52 -07:00
|
|
|
if (stick < 0 || stick >= kJoystickPorts) {
|
2021-05-23 19:33:33 -07:00
|
|
|
FRC_ReportError(warn::BadJoystickIndex, "stick {} out of range", stick);
|
2016-07-14 20:50:38 -07:00
|
|
|
return -1;
|
2015-06-25 15:07:55 -04:00
|
|
|
}
|
2022-05-18 14:36:11 -07:00
|
|
|
if (axis < 0 || axis >= HAL_kMaxJoystickAxes) {
|
|
|
|
|
FRC_ReportError(warn::BadJoystickAxis, "axis {} out of range", axis);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2018-05-16 00:13:52 -07:00
|
|
|
|
2018-07-18 22:22:41 -07:00
|
|
|
HAL_JoystickDescriptor descriptor;
|
|
|
|
|
HAL_GetJoystickDescriptor(stick, &descriptor);
|
|
|
|
|
|
2022-05-18 14:36:11 -07:00
|
|
|
return descriptor.axisTypes[axis];
|
2013-12-15 18:30:16 -05:00
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
bool DriverStation::IsJoystickConnected(int stick) {
|
2020-11-13 14:11:10 -05:00
|
|
|
return GetStickAxisCount(stick) > 0 || GetStickButtonCount(stick) > 0 ||
|
|
|
|
|
GetStickPOVCount(stick) > 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
bool DriverStation::IsEnabled() {
|
2016-07-09 00:24:26 -07:00
|
|
|
HAL_ControlWord controlWord;
|
2018-07-18 22:22:41 -07:00
|
|
|
HAL_GetControlWord(&controlWord);
|
2015-06-25 15:07:55 -04:00
|
|
|
return controlWord.enabled && controlWord.dsAttached;
|
2013-12-15 18:30:16 -05:00
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
bool DriverStation::IsDisabled() {
|
2016-07-09 00:24:26 -07:00
|
|
|
HAL_ControlWord controlWord;
|
2018-07-18 22:22:41 -07:00
|
|
|
HAL_GetControlWord(&controlWord);
|
2015-06-25 15:07:55 -04:00
|
|
|
return !(controlWord.enabled && controlWord.dsAttached);
|
2013-12-15 18:30:16 -05:00
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
bool DriverStation::IsEStopped() {
|
2019-07-16 09:18:23 -05:00
|
|
|
HAL_ControlWord controlWord;
|
|
|
|
|
HAL_GetControlWord(&controlWord);
|
|
|
|
|
return controlWord.eStop;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
bool DriverStation::IsAutonomous() {
|
2016-07-09 00:24:26 -07:00
|
|
|
HAL_ControlWord controlWord;
|
2018-07-18 22:22:41 -07:00
|
|
|
HAL_GetControlWord(&controlWord);
|
2015-06-25 15:07:55 -04:00
|
|
|
return controlWord.autonomous;
|
2013-12-15 18:30:16 -05:00
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
bool DriverStation::IsAutonomousEnabled() {
|
2020-08-29 16:32:19 -04:00
|
|
|
HAL_ControlWord controlWord;
|
|
|
|
|
HAL_GetControlWord(&controlWord);
|
|
|
|
|
return controlWord.autonomous && controlWord.enabled;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-11 23:04:43 -07:00
|
|
|
bool DriverStation::IsTeleop() {
|
2016-07-09 00:24:26 -07:00
|
|
|
HAL_ControlWord controlWord;
|
2018-07-18 22:22:41 -07:00
|
|
|
HAL_GetControlWord(&controlWord);
|
2015-06-25 15:07:55 -04:00
|
|
|
return !(controlWord.autonomous || controlWord.test);
|
2013-12-15 18:30:16 -05:00
|
|
|
}
|
|
|
|
|
|
2021-08-11 23:04:43 -07:00
|
|
|
bool DriverStation::IsTeleopEnabled() {
|
2020-08-29 16:32:19 -04:00
|
|
|
HAL_ControlWord controlWord;
|
|
|
|
|
HAL_GetControlWord(&controlWord);
|
|
|
|
|
return !controlWord.autonomous && !controlWord.test && controlWord.enabled;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
bool DriverStation::IsTest() {
|
2016-07-09 00:24:26 -07:00
|
|
|
HAL_ControlWord controlWord;
|
2018-07-18 22:22:41 -07:00
|
|
|
HAL_GetControlWord(&controlWord);
|
2015-06-25 15:07:55 -04:00
|
|
|
return controlWord.test;
|
2013-12-15 18:30:16 -05:00
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
bool DriverStation::IsDSAttached() {
|
2016-07-09 00:24:26 -07:00
|
|
|
HAL_ControlWord controlWord;
|
2018-07-18 22:22:41 -07:00
|
|
|
HAL_GetControlWord(&controlWord);
|
2015-06-25 15:07:55 -04:00
|
|
|
return controlWord.dsAttached;
|
2014-11-18 10:56:25 -05:00
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
bool DriverStation::IsNewControlData() {
|
|
|
|
|
auto& inst = ::GetInstance();
|
|
|
|
|
std::unique_lock lock(inst.waitForDataMutex);
|
2020-07-13 21:57:54 -07:00
|
|
|
int& lastCount = GetDSLastCount();
|
2021-06-15 23:06:03 -07:00
|
|
|
int currentCount = inst.waitForDataCounter;
|
2020-12-28 12:58:06 -08:00
|
|
|
if (lastCount == currentCount) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2020-07-13 21:57:54 -07:00
|
|
|
lastCount = currentCount;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2016-07-14 20:50:38 -07:00
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
bool DriverStation::IsFMSAttached() {
|
2016-07-14 20:50:38 -07:00
|
|
|
HAL_ControlWord controlWord;
|
2018-07-18 22:22:41 -07:00
|
|
|
HAL_GetControlWord(&controlWord);
|
2016-07-14 20:50:38 -07:00
|
|
|
return controlWord.fmsAttached;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
std::string DriverStation::GetGameSpecificMessage() {
|
2018-07-18 22:22:41 -07:00
|
|
|
HAL_MatchInfo info;
|
|
|
|
|
HAL_GetMatchInfo(&info);
|
|
|
|
|
return std::string(reinterpret_cast<char*>(info.gameSpecificMessage),
|
|
|
|
|
info.gameSpecificMessageSize);
|
2017-11-09 19:59:29 -08:00
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
std::string DriverStation::GetEventName() {
|
2018-07-18 22:22:41 -07:00
|
|
|
HAL_MatchInfo info;
|
|
|
|
|
HAL_GetMatchInfo(&info);
|
|
|
|
|
return info.eventName;
|
2017-11-09 19:59:29 -08:00
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
DriverStation::MatchType DriverStation::GetMatchType() {
|
2018-07-18 22:22:41 -07:00
|
|
|
HAL_MatchInfo info;
|
|
|
|
|
HAL_GetMatchInfo(&info);
|
|
|
|
|
return static_cast<DriverStation::MatchType>(info.matchType);
|
2017-11-09 19:59:29 -08:00
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
int DriverStation::GetMatchNumber() {
|
2018-07-18 22:22:41 -07:00
|
|
|
HAL_MatchInfo info;
|
|
|
|
|
HAL_GetMatchInfo(&info);
|
|
|
|
|
return info.matchNumber;
|
2017-11-09 19:59:29 -08:00
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
int DriverStation::GetReplayNumber() {
|
2018-07-18 22:22:41 -07:00
|
|
|
HAL_MatchInfo info;
|
|
|
|
|
HAL_GetMatchInfo(&info);
|
|
|
|
|
return info.replayNumber;
|
2017-11-09 19:59:29 -08:00
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
DriverStation::Alliance DriverStation::GetAlliance() {
|
2016-07-10 16:24:57 -07:00
|
|
|
int32_t status = 0;
|
|
|
|
|
auto allianceStationID = HAL_GetAllianceStation(&status);
|
2015-06-25 15:07:55 -04:00
|
|
|
switch (allianceStationID) {
|
2016-07-09 00:24:26 -07:00
|
|
|
case HAL_AllianceStationID_kRed1:
|
|
|
|
|
case HAL_AllianceStationID_kRed2:
|
|
|
|
|
case HAL_AllianceStationID_kRed3:
|
2015-06-25 15:07:55 -04:00
|
|
|
return kRed;
|
2016-07-09 00:24:26 -07:00
|
|
|
case HAL_AllianceStationID_kBlue1:
|
|
|
|
|
case HAL_AllianceStationID_kBlue2:
|
|
|
|
|
case HAL_AllianceStationID_kBlue3:
|
2015-06-25 15:07:55 -04:00
|
|
|
return kBlue;
|
|
|
|
|
default:
|
|
|
|
|
return kInvalid;
|
|
|
|
|
}
|
2013-12-15 18:30:16 -05:00
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
int DriverStation::GetLocation() {
|
2016-07-10 16:24:57 -07:00
|
|
|
int32_t status = 0;
|
|
|
|
|
auto allianceStationID = HAL_GetAllianceStation(&status);
|
2015-06-25 15:07:55 -04:00
|
|
|
switch (allianceStationID) {
|
2016-07-09 00:24:26 -07:00
|
|
|
case HAL_AllianceStationID_kRed1:
|
|
|
|
|
case HAL_AllianceStationID_kBlue1:
|
2015-06-25 15:07:55 -04:00
|
|
|
return 1;
|
2016-07-09 00:24:26 -07:00
|
|
|
case HAL_AllianceStationID_kRed2:
|
|
|
|
|
case HAL_AllianceStationID_kBlue2:
|
2015-06-25 15:07:55 -04:00
|
|
|
return 2;
|
2016-07-09 00:24:26 -07:00
|
|
|
case HAL_AllianceStationID_kRed3:
|
|
|
|
|
case HAL_AllianceStationID_kBlue3:
|
2015-06-25 15:07:55 -04:00
|
|
|
return 3;
|
|
|
|
|
default:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2013-12-15 18:30:16 -05:00
|
|
|
}
|
|
|
|
|
|
2020-12-28 12:58:06 -08:00
|
|
|
void DriverStation::WaitForData() {
|
2021-05-28 22:06:59 -07:00
|
|
|
WaitForData(0_s);
|
2020-12-28 12:58:06 -08:00
|
|
|
}
|
2016-10-09 11:46:01 -07:00
|
|
|
|
2021-05-28 22:06:59 -07:00
|
|
|
bool DriverStation::WaitForData(units::second_t timeout) {
|
2021-06-15 23:06:03 -07:00
|
|
|
auto& inst = ::GetInstance();
|
2021-05-28 22:06:59 -07:00
|
|
|
auto timeoutTime = std::chrono::steady_clock::now() +
|
|
|
|
|
std::chrono::steady_clock::duration{timeout};
|
2018-01-18 21:54:33 -08:00
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
std::unique_lock lock(inst.waitForDataMutex);
|
2020-07-13 21:57:54 -07:00
|
|
|
int& lastCount = GetDSLastCount();
|
2021-06-15 23:06:03 -07:00
|
|
|
int currentCount = inst.waitForDataCounter;
|
2020-07-13 21:57:54 -07:00
|
|
|
if (lastCount != currentCount) {
|
|
|
|
|
lastCount = currentCount;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2021-06-15 23:06:03 -07:00
|
|
|
while (inst.waitForDataCounter == currentCount) {
|
2021-05-28 22:06:59 -07:00
|
|
|
if (timeout > 0_s) {
|
2021-06-15 23:06:03 -07:00
|
|
|
auto timedOut = inst.waitForDataCond.wait_until(lock, timeoutTime);
|
2018-01-18 21:54:33 -08:00
|
|
|
if (timedOut == std::cv_status::timeout) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2021-06-15 23:06:03 -07:00
|
|
|
inst.waitForDataCond.wait(lock);
|
2018-01-18 21:54:33 -08:00
|
|
|
}
|
|
|
|
|
}
|
2021-06-15 23:06:03 -07:00
|
|
|
lastCount = inst.waitForDataCounter;
|
2018-01-18 21:54:33 -08:00
|
|
|
return true;
|
2013-12-15 18:30:16 -05:00
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
double DriverStation::GetMatchTime() {
|
2021-06-08 21:18:59 -07:00
|
|
|
int32_t status = 0;
|
2016-07-10 16:24:57 -07:00
|
|
|
return HAL_GetMatchTime(&status);
|
2013-12-15 18:30:16 -05:00
|
|
|
}
|
2014-10-20 17:19:28 -04:00
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
double DriverStation::GetBatteryVoltage() {
|
2016-07-14 20:50:38 -07:00
|
|
|
int32_t status = 0;
|
2016-11-20 07:25:03 -08:00
|
|
|
double voltage = HAL_GetVinVoltage(&status);
|
2021-05-23 19:33:33 -07:00
|
|
|
FRC_CheckErrorStatus(status, "{}", "getVinVoltage");
|
2016-07-14 20:50:38 -07:00
|
|
|
|
|
|
|
|
return voltage;
|
2016-02-04 22:29:11 -08:00
|
|
|
}
|
2015-06-25 15:07:55 -04:00
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
void DriverStation::InDisabled(bool entering) {
|
|
|
|
|
::GetInstance().userInDisabled = entering;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DriverStation::InAutonomous(bool entering) {
|
|
|
|
|
::GetInstance().userInAutonomous = entering;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-11 23:04:43 -07:00
|
|
|
void DriverStation::InTeleop(bool entering) {
|
2021-06-15 23:06:03 -07:00
|
|
|
::GetInstance().userInTeleop = entering;
|
2019-11-05 21:33:09 -08:00
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
void DriverStation::InTest(bool entering) {
|
|
|
|
|
::GetInstance().userInTest = entering;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DriverStation::WakeupWaitForData() {
|
|
|
|
|
auto& inst = ::GetInstance();
|
|
|
|
|
std::scoped_lock waitLock(inst.waitForDataMutex);
|
|
|
|
|
// Nofify all threads
|
|
|
|
|
inst.waitForDataCounter++;
|
|
|
|
|
inst.waitForDataCond.notify_all();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 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() {
|
|
|
|
|
auto& inst = ::GetInstance();
|
2018-01-18 23:17:28 -08:00
|
|
|
{
|
2018-07-18 22:22:41 -07:00
|
|
|
// Compute the pressed and released buttons
|
|
|
|
|
HAL_JoystickButtons currentButtons;
|
2021-06-15 23:06:03 -07:00
|
|
|
std::unique_lock lock(inst.buttonEdgeMutex);
|
2018-01-18 23:17:28 -08:00
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
for (int32_t i = 0; i < DriverStation::kJoystickPorts; i++) {
|
2018-07-18 22:22:41 -07:00
|
|
|
HAL_GetJoystickButtons(i, ¤tButtons);
|
|
|
|
|
|
2018-01-18 23:17:28 -08:00
|
|
|
// If buttons weren't pressed and are now, set flags in m_buttonsPressed
|
2021-06-15 23:06:03 -07:00
|
|
|
inst.joystickButtonsPressed[i] |=
|
|
|
|
|
~inst.previousButtonStates[i].buttons & currentButtons.buttons;
|
2017-10-27 21:45:56 -07:00
|
|
|
|
2018-01-18 23:17:28 -08:00
|
|
|
// If buttons were pressed and aren't now, set flags in m_buttonsReleased
|
2021-06-15 23:06:03 -07:00
|
|
|
inst.joystickButtonsReleased[i] |=
|
|
|
|
|
inst.previousButtonStates[i].buttons & ~currentButtons.buttons;
|
2018-01-18 23:17:28 -08:00
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
inst.previousButtonStates[i] = currentButtons;
|
2018-07-18 22:22:41 -07:00
|
|
|
}
|
2017-10-27 21:45:56 -07:00
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
DriverStation::WakeupWaitForData();
|
2018-01-18 23:17:28 -08:00
|
|
|
SendMatchData();
|
2022-01-27 00:15:43 -08:00
|
|
|
if (auto sender = inst.dataLogSender.load()) {
|
|
|
|
|
sender->Send(wpi::Now());
|
|
|
|
|
}
|
2016-02-04 22:29:11 -08:00
|
|
|
}
|
|
|
|
|
|
2020-11-14 15:00:56 -05:00
|
|
|
void DriverStation::SilenceJoystickConnectionWarning(bool silence) {
|
2021-06-15 23:06:03 -07:00
|
|
|
::GetInstance().silenceJoystickWarning = silence;
|
2020-11-14 15:00:56 -05:00
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
bool DriverStation::IsJoystickConnectionWarningSilenced() {
|
|
|
|
|
return !IsFMSAttached() && ::GetInstance().silenceJoystickWarning;
|
2016-07-14 20:50:38 -07:00
|
|
|
}
|
|
|
|
|
|
2022-01-27 00:15:43 -08:00
|
|
|
void DriverStation::StartDataLog(wpi::log::DataLog& log, bool logJoysticks) {
|
|
|
|
|
auto& inst = ::GetInstance();
|
|
|
|
|
// Note: cannot safely replace, because we wouldn't know when to delete the
|
|
|
|
|
// "old" one. Instead do a compare and exchange with nullptr. We check first
|
|
|
|
|
// with a simple load to avoid the new in the common case.
|
|
|
|
|
if (inst.dataLogSender.load()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
DataLogSender* oldSender = nullptr;
|
|
|
|
|
DataLogSender* newSender = new DataLogSender;
|
|
|
|
|
inst.dataLogSender.compare_exchange_strong(oldSender, newSender);
|
|
|
|
|
if (oldSender) {
|
|
|
|
|
delete newSender; // already had a sender
|
|
|
|
|
} else {
|
|
|
|
|
newSender->Init(log, logJoysticks, wpi::Now());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
void ReportJoystickUnpluggedErrorV(fmt::string_view format,
|
|
|
|
|
fmt::format_args args) {
|
|
|
|
|
auto& inst = GetInstance();
|
2021-05-28 22:06:59 -07:00
|
|
|
auto currentTime = Timer::GetFPGATimestamp();
|
2021-06-15 23:06:03 -07:00
|
|
|
if (currentTime > inst.nextMessageTime) {
|
2021-05-24 23:36:26 -07:00
|
|
|
ReportErrorV(err::Error, "", 0, "", format, args);
|
2021-06-15 23:06:03 -07:00
|
|
|
inst.nextMessageTime = currentTime + kJoystickUnpluggedMessageInterval;
|
2016-07-14 20:50:38 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
void ReportJoystickUnpluggedWarningV(fmt::string_view format,
|
|
|
|
|
fmt::format_args args) {
|
|
|
|
|
auto& inst = GetInstance();
|
|
|
|
|
if (DriverStation::IsFMSAttached() || !inst.silenceJoystickWarning) {
|
2021-05-28 22:06:59 -07:00
|
|
|
auto currentTime = Timer::GetFPGATimestamp();
|
2021-06-15 23:06:03 -07:00
|
|
|
if (currentTime > inst.nextMessageTime) {
|
2021-05-24 23:36:26 -07:00
|
|
|
ReportErrorV(warn::Warning, "", 0, "", format, args);
|
2021-06-15 23:06:03 -07:00
|
|
|
inst.nextMessageTime = currentTime + kJoystickUnpluggedMessageInterval;
|
2020-11-14 15:00:56 -05:00
|
|
|
}
|
2016-07-14 20:50:38 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
void Run() {
|
|
|
|
|
auto& inst = GetInstance();
|
|
|
|
|
inst.isRunning = true;
|
2018-12-29 16:19:23 -08:00
|
|
|
int safetyCounter = 0;
|
2021-06-15 23:06:03 -07:00
|
|
|
while (inst.isRunning) {
|
2016-07-14 20:50:38 -07:00
|
|
|
HAL_WaitForDSData();
|
|
|
|
|
GetData();
|
|
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
if (DriverStation::IsDisabled()) {
|
2020-12-28 12:58:06 -08:00
|
|
|
safetyCounter = 0;
|
|
|
|
|
}
|
2018-12-29 16:19:23 -08:00
|
|
|
|
|
|
|
|
if (++safetyCounter >= 4) {
|
|
|
|
|
MotorSafety::CheckMotors();
|
|
|
|
|
safetyCounter = 0;
|
|
|
|
|
}
|
2021-06-15 23:06:03 -07:00
|
|
|
if (inst.userInDisabled) {
|
2020-12-28 12:58:06 -08:00
|
|
|
HAL_ObserveUserProgramDisabled();
|
|
|
|
|
}
|
2021-06-15 23:06:03 -07:00
|
|
|
if (inst.userInAutonomous) {
|
2020-12-28 12:58:06 -08:00
|
|
|
HAL_ObserveUserProgramAutonomous();
|
|
|
|
|
}
|
2021-06-15 23:06:03 -07:00
|
|
|
if (inst.userInTeleop) {
|
2020-12-28 12:58:06 -08:00
|
|
|
HAL_ObserveUserProgramTeleop();
|
|
|
|
|
}
|
2021-06-15 23:06:03 -07:00
|
|
|
if (inst.userInTest) {
|
2020-12-28 12:58:06 -08:00
|
|
|
HAL_ObserveUserProgramTest();
|
|
|
|
|
}
|
2016-07-14 20:50:38 -07:00
|
|
|
}
|
2014-10-20 17:19:28 -04:00
|
|
|
}
|
2016-07-15 13:39:26 -07:00
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
void SendMatchData() {
|
2018-05-31 20:47:15 -07:00
|
|
|
int32_t status = 0;
|
|
|
|
|
HAL_AllianceStationID alliance = HAL_GetAllianceStation(&status);
|
|
|
|
|
bool isRedAlliance = false;
|
|
|
|
|
int stationNumber = 1;
|
|
|
|
|
switch (alliance) {
|
|
|
|
|
case HAL_AllianceStationID::HAL_AllianceStationID_kBlue1:
|
|
|
|
|
isRedAlliance = false;
|
|
|
|
|
stationNumber = 1;
|
|
|
|
|
break;
|
|
|
|
|
case HAL_AllianceStationID::HAL_AllianceStationID_kBlue2:
|
|
|
|
|
isRedAlliance = false;
|
|
|
|
|
stationNumber = 2;
|
|
|
|
|
break;
|
|
|
|
|
case HAL_AllianceStationID::HAL_AllianceStationID_kBlue3:
|
|
|
|
|
isRedAlliance = false;
|
|
|
|
|
stationNumber = 3;
|
|
|
|
|
break;
|
|
|
|
|
case HAL_AllianceStationID::HAL_AllianceStationID_kRed1:
|
|
|
|
|
isRedAlliance = true;
|
|
|
|
|
stationNumber = 1;
|
|
|
|
|
break;
|
|
|
|
|
case HAL_AllianceStationID::HAL_AllianceStationID_kRed2:
|
|
|
|
|
isRedAlliance = true;
|
|
|
|
|
stationNumber = 2;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
isRedAlliance = true;
|
|
|
|
|
stationNumber = 3;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-18 22:22:41 -07:00
|
|
|
HAL_MatchInfo tmpDataStore;
|
|
|
|
|
HAL_GetMatchInfo(&tmpDataStore);
|
2018-05-31 20:47:15 -07:00
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
auto& inst = GetInstance();
|
|
|
|
|
inst.matchDataSender.alliance.Set(isRedAlliance);
|
|
|
|
|
inst.matchDataSender.station.Set(stationNumber);
|
|
|
|
|
inst.matchDataSender.eventName.Set(tmpDataStore.eventName);
|
|
|
|
|
inst.matchDataSender.gameSpecificMessage.Set(
|
2018-07-18 22:22:41 -07:00
|
|
|
std::string(reinterpret_cast<char*>(tmpDataStore.gameSpecificMessage),
|
|
|
|
|
tmpDataStore.gameSpecificMessageSize));
|
2021-06-15 23:06:03 -07:00
|
|
|
inst.matchDataSender.matchNumber.Set(tmpDataStore.matchNumber);
|
|
|
|
|
inst.matchDataSender.replayNumber.Set(tmpDataStore.replayNumber);
|
|
|
|
|
inst.matchDataSender.matchType.Set(static_cast<int>(tmpDataStore.matchType));
|
2018-05-31 20:47:15 -07:00
|
|
|
|
|
|
|
|
HAL_ControlWord ctlWord;
|
2018-07-18 22:22:41 -07:00
|
|
|
HAL_GetControlWord(&ctlWord);
|
2018-05-31 20:47:15 -07:00
|
|
|
int32_t wordInt = 0;
|
|
|
|
|
std::memcpy(&wordInt, &ctlWord, sizeof(wordInt));
|
2021-06-15 23:06:03 -07:00
|
|
|
inst.matchDataSender.controlWord.Set(wordInt);
|
2018-05-31 20:47:15 -07:00
|
|
|
}
|
2022-01-27 00:15:43 -08:00
|
|
|
|
|
|
|
|
void JoystickLogSender::Init(wpi::log::DataLog& log, unsigned int stick,
|
|
|
|
|
int64_t timestamp) {
|
|
|
|
|
m_stick = stick;
|
|
|
|
|
|
|
|
|
|
m_logButtons = wpi::log::BooleanArrayLogEntry{
|
|
|
|
|
log, fmt::format("DS:joystick{}/buttons", stick), timestamp};
|
|
|
|
|
m_logAxes = wpi::log::FloatArrayLogEntry{
|
|
|
|
|
log, fmt::format("DS:joystick{}/axes", stick), timestamp};
|
|
|
|
|
m_logPOVs = wpi::log::IntegerArrayLogEntry{
|
|
|
|
|
log, fmt::format("DS:joystick{}/povs", stick), timestamp};
|
|
|
|
|
|
|
|
|
|
HAL_GetJoystickButtons(m_stick, &m_prevButtons);
|
|
|
|
|
HAL_GetJoystickAxes(m_stick, &m_prevAxes);
|
|
|
|
|
HAL_GetJoystickPOVs(m_stick, &m_prevPOVs);
|
|
|
|
|
AppendButtons(m_prevButtons, timestamp);
|
|
|
|
|
m_logAxes.Append(
|
|
|
|
|
wpi::span<const float>{m_prevAxes.axes,
|
|
|
|
|
static_cast<size_t>(m_prevAxes.count)},
|
|
|
|
|
timestamp);
|
|
|
|
|
AppendPOVs(m_prevPOVs, timestamp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void JoystickLogSender::Send(uint64_t timestamp) {
|
|
|
|
|
HAL_JoystickButtons buttons;
|
|
|
|
|
HAL_GetJoystickButtons(m_stick, &buttons);
|
|
|
|
|
if (buttons.count != m_prevButtons.count ||
|
|
|
|
|
buttons.buttons != m_prevButtons.buttons) {
|
|
|
|
|
AppendButtons(buttons, timestamp);
|
|
|
|
|
}
|
|
|
|
|
m_prevButtons = buttons;
|
|
|
|
|
|
|
|
|
|
HAL_JoystickAxes axes;
|
|
|
|
|
HAL_GetJoystickAxes(m_stick, &axes);
|
|
|
|
|
if (axes.count != m_prevAxes.count ||
|
|
|
|
|
std::memcmp(axes.axes, m_prevAxes.axes,
|
|
|
|
|
sizeof(axes.axes[0]) * axes.count) != 0) {
|
|
|
|
|
m_logAxes.Append(
|
|
|
|
|
wpi::span<const float>{axes.axes, static_cast<size_t>(axes.count)},
|
|
|
|
|
timestamp);
|
|
|
|
|
}
|
|
|
|
|
m_prevAxes = axes;
|
|
|
|
|
|
|
|
|
|
HAL_JoystickPOVs povs;
|
|
|
|
|
HAL_GetJoystickPOVs(m_stick, &povs);
|
|
|
|
|
if (povs.count != m_prevPOVs.count ||
|
|
|
|
|
std::memcmp(povs.povs, m_prevPOVs.povs,
|
|
|
|
|
sizeof(povs.povs[0]) * povs.count) != 0) {
|
|
|
|
|
AppendPOVs(povs, timestamp);
|
|
|
|
|
}
|
|
|
|
|
m_prevPOVs = povs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void JoystickLogSender::AppendButtons(HAL_JoystickButtons buttons,
|
|
|
|
|
uint64_t timestamp) {
|
|
|
|
|
uint8_t buttonsArr[32];
|
|
|
|
|
for (unsigned int i = 0; i < buttons.count; ++i) {
|
|
|
|
|
buttonsArr[i] = (buttons.buttons & (1u << i)) != 0;
|
|
|
|
|
}
|
|
|
|
|
m_logButtons.Append(wpi::span<const uint8_t>{buttonsArr, buttons.count},
|
|
|
|
|
timestamp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void JoystickLogSender::AppendPOVs(const HAL_JoystickPOVs& povs,
|
|
|
|
|
uint64_t timestamp) {
|
|
|
|
|
int64_t povsArr[HAL_kMaxJoystickPOVs];
|
|
|
|
|
for (int i = 0; i < povs.count; ++i) {
|
|
|
|
|
povsArr[i] = povs.povs[i];
|
|
|
|
|
}
|
|
|
|
|
m_logPOVs.Append(
|
|
|
|
|
wpi::span<const int64_t>{povsArr, static_cast<size_t>(povs.count)},
|
|
|
|
|
timestamp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DataLogSender::Init(wpi::log::DataLog& log, bool logJoysticks,
|
|
|
|
|
int64_t timestamp) {
|
|
|
|
|
m_logEnabled = wpi::log::BooleanLogEntry{log, "DS:enabled", timestamp};
|
|
|
|
|
m_logAutonomous = wpi::log::BooleanLogEntry{log, "DS:autonomous", timestamp};
|
|
|
|
|
m_logTest = wpi::log::BooleanLogEntry{log, "DS:test", timestamp};
|
|
|
|
|
m_logEstop = wpi::log::BooleanLogEntry{log, "DS:estop", timestamp};
|
|
|
|
|
|
|
|
|
|
// append initial control word values
|
|
|
|
|
HAL_GetControlWord(&m_prevControlWord);
|
|
|
|
|
m_logEnabled.Append(m_prevControlWord.enabled, timestamp);
|
|
|
|
|
m_logAutonomous.Append(m_prevControlWord.autonomous, timestamp);
|
|
|
|
|
m_logTest.Append(m_prevControlWord.test, timestamp);
|
|
|
|
|
m_logEstop.Append(m_prevControlWord.eStop, timestamp);
|
|
|
|
|
|
|
|
|
|
m_logJoysticks = logJoysticks;
|
|
|
|
|
if (logJoysticks) {
|
|
|
|
|
unsigned int i = 0;
|
|
|
|
|
for (auto&& joystick : m_joysticks) {
|
|
|
|
|
joystick.Init(log, i++, timestamp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_initialized = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DataLogSender::Send(uint64_t timestamp) {
|
|
|
|
|
if (!m_initialized) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// append control word value changes
|
|
|
|
|
HAL_ControlWord ctlWord;
|
|
|
|
|
HAL_GetControlWord(&ctlWord);
|
|
|
|
|
if (ctlWord.enabled != m_prevControlWord.enabled) {
|
|
|
|
|
m_logEnabled.Append(ctlWord.enabled, timestamp);
|
|
|
|
|
}
|
|
|
|
|
if (ctlWord.autonomous != m_prevControlWord.autonomous) {
|
|
|
|
|
m_logAutonomous.Append(ctlWord.autonomous, timestamp);
|
|
|
|
|
}
|
|
|
|
|
if (ctlWord.test != m_prevControlWord.test) {
|
|
|
|
|
m_logTest.Append(ctlWord.test, timestamp);
|
|
|
|
|
}
|
|
|
|
|
if (ctlWord.eStop != m_prevControlWord.eStop) {
|
|
|
|
|
m_logEstop.Append(ctlWord.eStop, timestamp);
|
|
|
|
|
}
|
|
|
|
|
m_prevControlWord = ctlWord;
|
|
|
|
|
|
|
|
|
|
if (m_logJoysticks) {
|
|
|
|
|
// append joystick value changes
|
|
|
|
|
for (auto&& joystick : m_joysticks) {
|
|
|
|
|
joystick.Send(timestamp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|