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.
|
2016-01-02 03:02:34 -08:00
|
|
|
|
2014-05-02 17:54:01 -04:00
|
|
|
#pragma once
|
2013-12-15 18:30:16 -05:00
|
|
|
|
2019-11-05 21:33:09 -08:00
|
|
|
#include <chrono>
|
2025-12-12 21:25:57 -07:00
|
|
|
#include <string>
|
2016-12-21 21:58:42 -08:00
|
|
|
#include <thread>
|
2016-06-19 00:13:18 -07:00
|
|
|
|
2025-11-07 19:56:21 -05:00
|
|
|
#include "wpi/hal/DriverStation.h"
|
2026-03-13 17:19:39 -07:00
|
|
|
#include "wpi/hal/HAL.h"
|
2025-11-07 19:56:21 -05:00
|
|
|
#include "wpi/hal/Main.h"
|
|
|
|
|
#include "wpi/nt/NetworkTable.hpp"
|
2025-11-07 19:57:55 -05:00
|
|
|
#include "wpi/system/Errors.hpp"
|
|
|
|
|
#include "wpi/system/RuntimeType.hpp"
|
2025-11-07 19:56:21 -05:00
|
|
|
#include "wpi/util/RuntimeCheck.h"
|
|
|
|
|
#include "wpi/util/condition_variable.hpp"
|
|
|
|
|
#include "wpi/util/mutex.hpp"
|
|
|
|
|
#include "wpi/util/string.h"
|
|
|
|
|
|
2025-11-07 20:00:05 -05:00
|
|
|
namespace wpi {
|
2016-11-01 22:33:12 -07:00
|
|
|
|
2018-10-29 12:49:17 -07:00
|
|
|
int RunHALInitialization();
|
|
|
|
|
|
2019-09-28 15:43:24 -07:00
|
|
|
namespace impl {
|
2025-06-02 16:42:56 -07:00
|
|
|
#ifndef __FRC_SYSTEMCORE__
|
2022-10-23 21:59:04 -07:00
|
|
|
void ResetMotorSafety();
|
|
|
|
|
#endif
|
2019-09-28 15:43:24 -07:00
|
|
|
|
|
|
|
|
template <class Robot>
|
2025-11-07 20:00:05 -05:00
|
|
|
void RunRobot(wpi::util::mutex& m, Robot** robot) {
|
2021-04-18 20:35:29 -07:00
|
|
|
try {
|
|
|
|
|
static Robot theRobot;
|
|
|
|
|
{
|
|
|
|
|
std::scoped_lock lock{m};
|
|
|
|
|
*robot = &theRobot;
|
|
|
|
|
}
|
|
|
|
|
theRobot.StartCompetition();
|
2025-11-07 20:00:05 -05:00
|
|
|
} catch (const wpi::RuntimeError& e) {
|
2021-04-18 20:35:29 -07:00
|
|
|
e.Report();
|
2025-11-07 20:00:43 -05:00
|
|
|
WPILIB_ReportError(
|
2022-10-19 10:49:27 -07:00
|
|
|
err::Error,
|
2021-06-17 23:52:48 -07:00
|
|
|
"The robot program quit unexpectedly."
|
|
|
|
|
" This is usually due to a code error.\n"
|
|
|
|
|
" The above stacktrace can help determine where the error occurred.\n"
|
|
|
|
|
" See https://wpilib.org/stacktrace for more information.\n");
|
|
|
|
|
throw;
|
|
|
|
|
} catch (const std::exception& e) {
|
|
|
|
|
HAL_SendError(1, err::Error, 0, e.what(), "", "", 1);
|
2021-04-18 20:35:29 -07:00
|
|
|
throw;
|
2019-11-05 21:33:09 -08:00
|
|
|
}
|
2019-09-28 15:43:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace impl
|
|
|
|
|
|
2018-05-16 19:54:39 -07:00
|
|
|
template <class Robot>
|
|
|
|
|
int StartRobot() {
|
2024-11-05 08:51:48 -08:00
|
|
|
uint32_t foundMajor;
|
|
|
|
|
uint32_t foundMinor;
|
|
|
|
|
uint32_t expectedMajor;
|
|
|
|
|
uint32_t expectedMinor;
|
|
|
|
|
WPI_String runtimePath;
|
|
|
|
|
if (!WPI_IsRuntimeValid(&foundMajor, &foundMinor, &expectedMajor,
|
|
|
|
|
&expectedMinor, &runtimePath)) {
|
|
|
|
|
// We could make this error better, however unlike Java, there is only a
|
|
|
|
|
// single scenario that could be occuring. The entirety of VS is too out
|
|
|
|
|
// of date. In most cases the linker should detect this, but not always.
|
|
|
|
|
fmt::println(
|
|
|
|
|
"Your copy of Visual Studio is out of date. Please update it.\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-29 12:49:17 -07:00
|
|
|
int halInit = RunHALInitialization();
|
|
|
|
|
if (halInit != 0) {
|
|
|
|
|
return halInit;
|
2015-06-25 15:07:55 -04:00
|
|
|
}
|
2019-11-05 21:33:09 -08:00
|
|
|
|
2025-11-07 20:00:05 -05:00
|
|
|
static wpi::util::mutex m;
|
|
|
|
|
static wpi::util::condition_variable cv;
|
2019-11-05 21:33:09 -08:00
|
|
|
static Robot* robot = nullptr;
|
|
|
|
|
static bool exited = false;
|
|
|
|
|
|
2019-09-28 15:43:24 -07:00
|
|
|
if (HAL_HasMain()) {
|
2019-11-05 21:33:09 -08:00
|
|
|
std::thread thr([] {
|
2019-09-28 15:43:24 -07:00
|
|
|
try {
|
2019-11-05 21:33:09 -08:00
|
|
|
impl::RunRobot<Robot>(m, &robot);
|
2019-09-28 15:43:24 -07:00
|
|
|
} catch (...) {
|
|
|
|
|
HAL_ExitMain();
|
2019-11-05 21:33:09 -08:00
|
|
|
{
|
|
|
|
|
std::scoped_lock lock{m};
|
|
|
|
|
robot = nullptr;
|
|
|
|
|
exited = true;
|
|
|
|
|
}
|
|
|
|
|
cv.notify_all();
|
2019-09-28 15:43:24 -07:00
|
|
|
throw;
|
|
|
|
|
}
|
2019-11-05 21:33:09 -08:00
|
|
|
|
2019-09-28 15:43:24 -07:00
|
|
|
HAL_ExitMain();
|
2019-11-05 21:33:09 -08:00
|
|
|
{
|
|
|
|
|
std::scoped_lock lock{m};
|
|
|
|
|
robot = nullptr;
|
|
|
|
|
exited = true;
|
|
|
|
|
}
|
|
|
|
|
cv.notify_all();
|
|
|
|
|
});
|
|
|
|
|
|
2019-09-28 15:43:24 -07:00
|
|
|
HAL_RunMain();
|
2019-11-05 21:33:09 -08:00
|
|
|
|
|
|
|
|
// signal loop to exit
|
2020-12-28 12:58:06 -08:00
|
|
|
if (robot) {
|
|
|
|
|
robot->EndCompetition();
|
|
|
|
|
}
|
2019-11-05 21:33:09 -08:00
|
|
|
|
|
|
|
|
// prefer to join, but detach to exit if it doesn't exit in a timely manner
|
|
|
|
|
using namespace std::chrono_literals;
|
|
|
|
|
std::unique_lock lock{m};
|
2020-12-28 12:58:06 -08:00
|
|
|
if (cv.wait_for(lock, 1s, [] { return exited; })) {
|
2019-11-05 21:33:09 -08:00
|
|
|
thr.join();
|
2020-12-28 12:58:06 -08:00
|
|
|
} else {
|
2019-11-05 21:33:09 -08:00
|
|
|
thr.detach();
|
2020-12-28 12:58:06 -08:00
|
|
|
}
|
2019-09-28 15:43:24 -07:00
|
|
|
} else {
|
2019-11-05 21:33:09 -08:00
|
|
|
impl::RunRobot<Robot>(m, &robot);
|
2019-09-28 15:43:24 -07:00
|
|
|
}
|
2018-05-16 19:54:39 -07:00
|
|
|
|
2025-06-02 16:42:56 -07:00
|
|
|
#ifndef __FRC_SYSTEMCORE__
|
2025-11-07 20:00:05 -05:00
|
|
|
wpi::impl::ResetMotorSafety();
|
2022-10-23 21:59:04 -07:00
|
|
|
#endif
|
2020-09-04 08:59:26 -07:00
|
|
|
HAL_Shutdown();
|
|
|
|
|
|
2018-05-16 19:54:39 -07:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-15 18:30:16 -05:00
|
|
|
/**
|
2023-05-13 00:29:39 -04:00
|
|
|
* Implement a Robot Program framework. The RobotBase class is intended to be
|
|
|
|
|
* subclassed to create a robot program. The user must implement
|
|
|
|
|
* StartCompetition() which will be called once and is not expected to exit. The
|
|
|
|
|
* user must also implement EndCompetition(), which signals to the code in
|
|
|
|
|
* StartCompetition() that it should exit.
|
2017-11-16 00:33:51 -08:00
|
|
|
*
|
2023-05-13 00:29:39 -04:00
|
|
|
* It is not recommended to subclass this class directly - instead subclass
|
|
|
|
|
* IterativeRobotBase or TimedRobot.
|
2013-12-15 18:30:16 -05:00
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
class RobotBase {
|
|
|
|
|
public:
|
2018-05-31 20:47:15 -07:00
|
|
|
/**
|
|
|
|
|
* Determine if the Robot is currently enabled.
|
|
|
|
|
*
|
2023-03-10 22:23:57 -05:00
|
|
|
* @return True if the Robot is currently enabled by the Driver Station.
|
2018-05-31 20:47:15 -07:00
|
|
|
*/
|
2025-12-12 21:25:57 -07:00
|
|
|
static bool IsEnabled();
|
2018-05-31 20:47:15 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Determine if the Robot is currently disabled.
|
|
|
|
|
*
|
2023-03-10 22:23:57 -05:00
|
|
|
* @return True if the Robot is currently disabled by the Driver Station.
|
2018-05-31 20:47:15 -07:00
|
|
|
*/
|
2025-12-12 21:25:57 -07:00
|
|
|
static bool IsDisabled();
|
2018-05-31 20:47:15 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Determine if the robot is currently in Autonomous mode.
|
|
|
|
|
*
|
|
|
|
|
* @return True if the robot is currently operating Autonomously as determined
|
2023-03-10 22:23:57 -05:00
|
|
|
* by the Driver Station.
|
2018-05-31 20:47:15 -07:00
|
|
|
*/
|
2025-12-12 21:25:57 -07:00
|
|
|
static bool IsAutonomous();
|
2018-05-31 20:47:15 -07:00
|
|
|
|
2020-08-29 16:32:19 -04:00
|
|
|
/**
|
|
|
|
|
* Determine if the robot is currently in Autonomous mode and enabled.
|
|
|
|
|
*
|
|
|
|
|
* @return True if the robot us currently operating Autonomously while enabled
|
2023-03-10 22:23:57 -05:00
|
|
|
* as determined by the Driver Station.
|
2020-08-29 16:32:19 -04:00
|
|
|
*/
|
2025-12-12 21:25:57 -07:00
|
|
|
static bool IsAutonomousEnabled();
|
2020-08-29 16:32:19 -04:00
|
|
|
|
2021-08-11 23:04:43 -07:00
|
|
|
/**
|
|
|
|
|
* Determine if the robot is currently in Operator Control mode.
|
|
|
|
|
*
|
|
|
|
|
* @return True if the robot is currently operating in Tele-Op mode as
|
2023-03-10 22:23:57 -05:00
|
|
|
* determined by the Driver Station.
|
2021-08-11 23:04:43 -07:00
|
|
|
*/
|
2025-12-12 21:25:57 -07:00
|
|
|
static bool IsTeleop();
|
2021-08-11 23:04:43 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Determine if the robot is current in Operator Control mode and enabled.
|
|
|
|
|
*
|
|
|
|
|
* @return True if the robot is currently operating in Tele-Op mode while
|
2023-03-10 22:23:57 -05:00
|
|
|
* enabled as determined by the Driver Station.
|
2021-08-11 23:04:43 -07:00
|
|
|
*/
|
2025-12-12 21:25:57 -07:00
|
|
|
static bool IsTeleopEnabled();
|
2021-08-11 23:04:43 -07:00
|
|
|
|
2018-05-31 20:47:15 -07:00
|
|
|
/**
|
|
|
|
|
* Determine if the robot is currently in Test mode.
|
|
|
|
|
*
|
2023-03-10 22:23:57 -05:00
|
|
|
* @return True if the robot is currently running in Test mode as determined
|
|
|
|
|
* by the Driver Station.
|
2018-05-31 20:47:15 -07:00
|
|
|
*/
|
2025-12-12 21:25:57 -07:00
|
|
|
static bool IsTest();
|
2018-05-31 20:47:15 -07:00
|
|
|
|
2023-03-10 22:23:57 -05:00
|
|
|
/**
|
|
|
|
|
* Determine if the robot is current in Test mode and enabled.
|
|
|
|
|
*
|
|
|
|
|
* @return True if the robot is currently operating in Test mode while
|
|
|
|
|
* enabled as determined by the Driver Station.
|
|
|
|
|
*/
|
2025-12-12 21:25:57 -07:00
|
|
|
static bool IsTestEnabled();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Gets the currently selected operating mode of the driver station. Note this
|
|
|
|
|
* does not mean the robot is enabled; use IsEnabled() for that.
|
|
|
|
|
*
|
|
|
|
|
* @return the unique ID provided by the DriverStation::AddOpMode() function;
|
|
|
|
|
* may return 0 or a unique ID not added, so callers should be prepared to
|
|
|
|
|
* handle that case
|
|
|
|
|
*/
|
|
|
|
|
static int64_t GetOpModeId();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Gets the currently selected operating mode of the driver station. Note this
|
|
|
|
|
* does not mean the robot is enabled; use IsEnabled() for that.
|
|
|
|
|
*
|
|
|
|
|
* @return Operating mode string; may return a string not in the list of
|
|
|
|
|
* options, so callers should be prepared to handle that case
|
|
|
|
|
*/
|
|
|
|
|
static std::string GetOpMode();
|
2023-03-10 22:23:57 -05:00
|
|
|
|
2018-05-31 20:47:15 -07:00
|
|
|
/**
|
2024-01-05 07:35:59 -08:00
|
|
|
* Returns the main thread ID.
|
|
|
|
|
*
|
|
|
|
|
* @return The main thread ID.
|
2018-05-31 20:47:15 -07:00
|
|
|
*/
|
2016-12-21 21:58:42 -08:00
|
|
|
static std::thread::id GetThreadId();
|
2018-05-31 20:47:15 -07:00
|
|
|
|
2023-05-13 00:29:39 -04:00
|
|
|
/**
|
|
|
|
|
* Start the main robot code. This function will be called once and should not
|
|
|
|
|
* exit until signalled by EndCompetition()
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
virtual void StartCompetition() = 0;
|
|
|
|
|
|
2023-05-13 00:29:39 -04:00
|
|
|
/** Ends the main loop in StartCompetition(). */
|
2019-11-05 21:33:09 -08:00
|
|
|
virtual void EndCompetition() = 0;
|
|
|
|
|
|
2021-09-13 22:05:38 -07:00
|
|
|
/**
|
|
|
|
|
* Get the current runtime type.
|
|
|
|
|
*
|
|
|
|
|
* @return Current runtime type.
|
|
|
|
|
*/
|
|
|
|
|
static RuntimeType GetRuntimeType();
|
|
|
|
|
|
2020-09-27 10:08:53 +03:00
|
|
|
/**
|
|
|
|
|
* Get if the robot is real.
|
|
|
|
|
*
|
|
|
|
|
* @return If the robot is running in the real world.
|
|
|
|
|
*/
|
2017-12-08 22:47:21 -08:00
|
|
|
static constexpr bool IsReal() {
|
2025-06-02 16:42:56 -07:00
|
|
|
#ifdef __FRC_SYSTEMCORE__
|
2017-12-08 22:47:21 -08:00
|
|
|
return true;
|
|
|
|
|
#else
|
|
|
|
|
return false;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-27 10:08:53 +03:00
|
|
|
/**
|
|
|
|
|
* Get if the robot is a simulation.
|
|
|
|
|
*
|
|
|
|
|
* @return If the robot is running in simulation.
|
|
|
|
|
*/
|
2023-09-15 20:05:16 -07:00
|
|
|
static constexpr bool IsSimulation() {
|
2025-06-02 16:42:56 -07:00
|
|
|
#ifdef __FRC_SYSTEMCORE__
|
2023-09-15 20:05:16 -07:00
|
|
|
return false;
|
|
|
|
|
#else
|
|
|
|
|
return true;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
2017-12-08 22:47:21 -08:00
|
|
|
|
2018-05-31 20:47:15 -07:00
|
|
|
/**
|
|
|
|
|
* Constructor for a generic robot program.
|
|
|
|
|
*
|
2023-05-13 00:29:39 -04:00
|
|
|
* User code can be placed in the constructor that runs before the
|
2018-05-31 20:47:15 -07:00
|
|
|
* Autonomous or Operator Control period starts. The constructor will run to
|
|
|
|
|
* completion before Autonomous is entered.
|
|
|
|
|
*
|
|
|
|
|
* This must be used to ensure that the communications code starts. In the
|
|
|
|
|
* future it would be nice to put this code into it's own task that loads on
|
|
|
|
|
* boot so ensure that it runs.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
RobotBase();
|
2018-05-31 20:47:15 -07:00
|
|
|
|
2021-06-15 23:06:03 -07:00
|
|
|
virtual ~RobotBase() = default;
|
2015-07-21 01:23:34 -07:00
|
|
|
|
2020-01-08 23:17:12 -08:00
|
|
|
protected:
|
2021-06-15 23:06:03 -07:00
|
|
|
RobotBase(RobotBase&&) = default;
|
|
|
|
|
RobotBase& operator=(RobotBase&&) = default;
|
2016-12-21 21:58:42 -08:00
|
|
|
|
|
|
|
|
static std::thread::id m_threadId;
|
2024-11-18 09:16:29 -08:00
|
|
|
NT_Listener connListenerHandle;
|
2013-12-15 18:30:16 -05:00
|
|
|
};
|
2016-11-01 22:33:12 -07:00
|
|
|
|
2025-11-07 20:00:05 -05:00
|
|
|
} // namespace wpi
|