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>
|
2016-12-21 21:58:42 -08:00
|
|
|
#include <thread>
|
2016-06-19 00:13:18 -07:00
|
|
|
|
2020-09-04 08:59:26 -07:00
|
|
|
#include <hal/HALBase.h>
|
2019-09-28 15:43:24 -07:00
|
|
|
#include <hal/Main.h>
|
2019-11-05 21:33:09 -08:00
|
|
|
#include <wpi/condition_variable.h>
|
|
|
|
|
#include <wpi/mutex.h>
|
2017-08-27 00:11:52 -07:00
|
|
|
|
2021-04-18 20:35:29 -07:00
|
|
|
#include "frc/Errors.h"
|
2013-12-15 18:30:16 -05:00
|
|
|
|
2016-11-01 22:33:12 -07:00
|
|
|
namespace frc {
|
|
|
|
|
|
2013-12-15 18:30:16 -05:00
|
|
|
class DriverStation;
|
|
|
|
|
|
2018-10-29 12:49:17 -07:00
|
|
|
int RunHALInitialization();
|
|
|
|
|
|
2019-09-28 15:43:24 -07:00
|
|
|
namespace impl {
|
|
|
|
|
|
|
|
|
|
template <class Robot>
|
2019-11-05 21:33:09 -08:00
|
|
|
void RunRobot(wpi::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();
|
|
|
|
|
} catch (const frc::RuntimeError& e) {
|
|
|
|
|
e.Report();
|
|
|
|
|
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() {
|
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
|
|
|
|
|
|
|
|
static wpi::mutex m;
|
|
|
|
|
static wpi::condition_variable cv;
|
|
|
|
|
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
|
|
|
|
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
|
|
|
/**
|
|
|
|
|
* Implement a Robot Program framework.
|
2017-11-16 00:33:51 -08:00
|
|
|
*
|
2015-06-25 15:07:55 -04:00
|
|
|
* The RobotBase class is intended to be subclassed by a user creating a robot
|
2016-05-20 17:30:37 -07:00
|
|
|
* program. Overridden Autonomous() and OperatorControl() methods are called at
|
|
|
|
|
* the appropriate time as the match proceeds. In the current implementation,
|
|
|
|
|
* the Autonomous code will run to completion before the OperatorControl code
|
|
|
|
|
* could start. In the future the Autonomous code might be spawned as a task,
|
|
|
|
|
* then killed at the end of the Autonomous period.
|
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.
|
|
|
|
|
*
|
|
|
|
|
* @return True if the Robot is currently enabled by the field controls.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
bool IsEnabled() const;
|
2018-05-31 20:47:15 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Determine if the Robot is currently disabled.
|
|
|
|
|
*
|
|
|
|
|
* @return True if the Robot is currently disabled by the field controls.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
bool IsDisabled() const;
|
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
|
|
|
|
|
* by the field controls.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
bool IsAutonomous() const;
|
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
|
|
|
|
|
* as determined by the field controls.
|
|
|
|
|
*/
|
|
|
|
|
bool IsAutonomousEnabled() const;
|
|
|
|
|
|
2018-05-31 20:47:15 -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
|
|
|
|
|
* determined by the field controls.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
bool IsOperatorControl() const;
|
2018-05-31 20:47:15 -07:00
|
|
|
|
2020-08-29 16:32:19 -04: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
|
|
|
|
|
* wnabled as determined by the field-controls.
|
|
|
|
|
*/
|
|
|
|
|
bool IsOperatorControlEnabled() const;
|
|
|
|
|
|
2018-05-31 20:47:15 -07:00
|
|
|
/**
|
|
|
|
|
* Determine if the robot is currently in Test mode.
|
|
|
|
|
*
|
|
|
|
|
* @return True if the robot is currently running tests as determined by the
|
|
|
|
|
* field controls.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
bool IsTest() const;
|
2018-05-31 20:47:15 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Indicates if new data is available from the driver station.
|
|
|
|
|
*
|
|
|
|
|
* @return Has new data arrived over the network since the last time this
|
|
|
|
|
* function was called?
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
bool IsNewDataAvailable() const;
|
2018-05-31 20:47:15 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Gets the ID of the main robot thread.
|
|
|
|
|
*/
|
2016-12-21 21:58:42 -08:00
|
|
|
static std::thread::id GetThreadId();
|
2018-05-31 20:47:15 -07:00
|
|
|
|
2015-06-25 15:07:55 -04:00
|
|
|
virtual void StartCompetition() = 0;
|
|
|
|
|
|
2019-11-05 21:33:09 -08:00
|
|
|
virtual void EndCompetition() = 0;
|
|
|
|
|
|
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() {
|
|
|
|
|
#ifdef __FRC_ROBORIO__
|
|
|
|
|
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.
|
|
|
|
|
*/
|
2017-12-08 22:47:21 -08:00
|
|
|
static constexpr bool IsSimulation() { return !IsReal(); }
|
|
|
|
|
|
2018-05-31 20:47:15 -07:00
|
|
|
/**
|
|
|
|
|
* Constructor for a generic robot program.
|
|
|
|
|
*
|
|
|
|
|
* User code should be placed in the constructor that runs before the
|
|
|
|
|
* 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;
|
2013-12-15 18:30:16 -05:00
|
|
|
};
|
2016-11-01 22:33:12 -07:00
|
|
|
|
|
|
|
|
} // namespace frc
|