Files
allwpilib/wpilibc/src/main/native/cppcs/RobotBase.cpp

271 lines
8.4 KiB
C++
Raw Normal View History

// 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.
#include "frc/RobotBase.h"
#ifdef __FRC_ROBORIO__
#include <dlfcn.h>
#endif
#include <cstdio>
#include <cameraserver/CameraServerShared.h>
#include <fmt/format.h>
#include <hal/FRCUsageReporting.h>
#include <hal/HALBase.h>
#include <networktables/NetworkTableInstance.h>
#include <wpi/timestamp.h>
#include <wpimath/MathShared.h>
#include "WPILibVersion.h"
#include "frc/DriverStation.h"
#include "frc/Errors.h"
#include "frc/Notifier.h"
#include "frc/RobotState.h"
#include "frc/livewindow/LiveWindow.h"
#include "frc/smartdashboard/SmartDashboard.h"
static_assert(frc::RuntimeType::kRoboRIO ==
static_cast<frc::RuntimeType>(HAL_Runtime_RoboRIO));
static_assert(frc::RuntimeType::kRoboRIO2 ==
static_cast<frc::RuntimeType>(HAL_Runtime_RoboRIO2));
static_assert(frc::RuntimeType::kSimulation ==
static_cast<frc::RuntimeType>(HAL_Runtime_Simulation));
using SetCameraServerSharedFP = void (*)(frc::CameraServerShared*);
using namespace frc;
int frc::RunHALInitialization() {
if (!HAL_Initialize(500, 0)) {
std::puts("FATAL ERROR: HAL could not be initialized");
return -1;
}
DriverStation::RefreshData();
HAL_Report(HALUsageReporting::kResourceType_Language,
HALUsageReporting::kLanguage_CPlusPlus, 0, GetWPILibVersion());
if (!frc::Notifier::SetHALThreadPriority(true, 40)) {
FRC_ReportError(warn::Warning,
"Setting HAL Notifier RT priority to 40 failed\n");
}
std::puts("\n********** Robot program starting **********");
return 0;
}
std::thread::id RobotBase::m_threadId;
2018-04-29 13:29:07 -07:00
namespace {
class WPILibCameraServerShared : public frc::CameraServerShared {
public:
void ReportUsbCamera(int id) override {
HAL_Report(HALUsageReporting::kResourceType_UsbCamera, id);
2018-04-29 13:29:07 -07:00
}
void ReportAxisCamera(int id) override {
HAL_Report(HALUsageReporting::kResourceType_AxisCamera, id);
}
void ReportVideoServer(int id) override {
HAL_Report(HALUsageReporting::kResourceType_PCVideoServer, id);
}
void SetCameraServerErrorV(fmt::string_view format,
fmt::format_args args) override {
ReportErrorV(err::CameraServerError, __FILE__, __LINE__, __FUNCTION__,
format, args);
2018-04-29 13:29:07 -07:00
}
void SetVisionRunnerErrorV(fmt::string_view format,
fmt::format_args args) override {
ReportErrorV(err::Error, __FILE__, __LINE__, __FUNCTION__, format, args);
2018-04-29 13:29:07 -07:00
}
void ReportDriverStationErrorV(fmt::string_view format,
fmt::format_args args) override {
ReportErrorV(err::Error, __FILE__, __LINE__, __FUNCTION__, format, args);
2018-04-29 13:29:07 -07:00
}
std::pair<std::thread::id, bool> GetRobotMainThreadId() const override {
return std::make_pair(RobotBase::GetThreadId(), true);
}
};
class WPILibMathShared : public wpi::math::MathShared {
public:
void ReportErrorV(fmt::string_view format, fmt::format_args args) override {
frc::ReportErrorV(err::Error, __FILE__, __LINE__, __FUNCTION__, format,
args);
}
void ReportWarningV(fmt::string_view format, fmt::format_args args) override {
frc::ReportErrorV(warn::Warning, __FILE__, __LINE__, __FUNCTION__, format,
args);
}
void ReportUsage(wpi::math::MathUsageId id, int count) override {
switch (id) {
case wpi::math::MathUsageId::kKinematics_DifferentialDrive:
HAL_Report(HALUsageReporting::kResourceType_Kinematics,
HALUsageReporting::kKinematics_DifferentialDrive);
break;
case wpi::math::MathUsageId::kKinematics_MecanumDrive:
HAL_Report(HALUsageReporting::kResourceType_Kinematics,
HALUsageReporting::kKinematics_MecanumDrive);
break;
case wpi::math::MathUsageId::kKinematics_SwerveDrive:
HAL_Report(HALUsageReporting::kResourceType_Kinematics,
HALUsageReporting::kKinematics_SwerveDrive);
break;
case wpi::math::MathUsageId::kTrajectory_TrapezoidProfile:
HAL_Report(HALUsageReporting::kResourceType_TrapezoidProfile, count);
break;
case wpi::math::MathUsageId::kFilter_Linear:
HAL_Report(HALUsageReporting::kResourceType_LinearFilter, count);
break;
case wpi::math::MathUsageId::kOdometry_DifferentialDrive:
HAL_Report(HALUsageReporting::kResourceType_Odometry,
HALUsageReporting::kOdometry_DifferentialDrive);
break;
case wpi::math::MathUsageId::kOdometry_SwerveDrive:
HAL_Report(HALUsageReporting::kResourceType_Odometry,
HALUsageReporting::kOdometry_SwerveDrive);
break;
case wpi::math::MathUsageId::kOdometry_MecanumDrive:
HAL_Report(HALUsageReporting::kResourceType_Odometry,
HALUsageReporting::kOdometry_MecanumDrive);
break;
case wpi::math::MathUsageId::kController_PIDController2:
HAL_Report(HALUsageReporting::kResourceType_PIDController2, count);
break;
case wpi::math::MathUsageId::kController_ProfiledPIDController:
HAL_Report(HALUsageReporting::kResourceType_ProfiledPIDController,
count);
break;
}
}
units::second_t GetTimestamp() override {
return units::second_t{wpi::Now() * 1.0e-6};
}
};
2018-04-29 13:29:07 -07:00
} // namespace
static void SetupCameraServerShared() {
#ifdef __FRC_ROBORIO__
#ifdef DYNAMIC_CAMERA_SERVER
#ifdef DYNAMIC_CAMERA_SERVER_DEBUG
auto cameraServerLib = dlopen("libcameraserverd.so", RTLD_NOW);
#else
auto cameraServerLib = dlopen("libcameraserver.so", RTLD_NOW);
#endif
if (!cameraServerLib) {
std::puts("Camera Server Library Not Found");
std::fflush(stdout);
return;
}
auto symbol = dlsym(cameraServerLib, "CameraServer_SetCameraServerShared");
if (symbol) {
auto setCameraServerShared = (SetCameraServerSharedFP)symbol;
setCameraServerShared(new WPILibCameraServerShared{});
} else {
std::puts("Camera Server Shared Symbol Missing");
std::fflush(stdout);
}
#else
CameraServer_SetCameraServerShared(new WPILibCameraServerShared{});
#endif
#else
std::puts("Not loading CameraServerShared");
std::fflush(stdout);
#endif
2018-04-29 13:29:07 -07:00
}
static void SetupMathShared() {
wpi::math::MathSharedStore::SetMathShared(
std::make_unique<WPILibMathShared>());
}
bool RobotBase::IsEnabled() const {
return DriverStation::IsEnabled();
}
bool RobotBase::IsDisabled() const {
return DriverStation::IsDisabled();
}
bool RobotBase::IsAutonomous() const {
return DriverStation::IsAutonomous();
}
bool RobotBase::IsAutonomousEnabled() const {
return DriverStation::IsAutonomousEnabled();
}
bool RobotBase::IsTeleop() const {
return DriverStation::IsTeleop();
}
bool RobotBase::IsTeleopEnabled() const {
return DriverStation::IsTeleopEnabled();
}
bool RobotBase::IsTest() const {
return DriverStation::IsTest();
}
bool RobotBase::IsTestEnabled() const {
return DriverStation::IsTestEnabled();
}
std::thread::id RobotBase::GetThreadId() {
return m_threadId;
}
RuntimeType RobotBase::GetRuntimeType() {
return static_cast<RuntimeType>(HAL_GetRuntimeType());
}
RobotBase::RobotBase() {
m_threadId = std::this_thread::get_id();
2018-04-29 13:29:07 -07:00
SetupCameraServerShared();
SetupMathShared();
2018-04-29 13:29:07 -07:00
auto inst = nt::NetworkTableInstance::GetDefault();
2023-02-26 15:06:37 -08:00
// subscribe to "" to force persistent values to propagate to local
2022-10-08 10:01:31 -07:00
nt::SubscribeMultiple(inst.GetHandle(), {{std::string_view{}}});
#ifdef __FRC_ROBORIO__
2022-10-08 10:01:31 -07:00
inst.StartServer("/home/lvuser/networktables.json");
#else
inst.StartServer();
#endif
2022-10-08 10:01:31 -07:00
// wait for the NT server to actually start
int count = 0;
while ((inst.GetNetworkMode() & NT_NET_MODE_STARTING) != 0) {
using namespace std::chrono_literals;
std::this_thread::sleep_for(10ms);
++count;
if (count > 100) {
fmt::print(stderr, "timed out while waiting for NT server to start\n");
break;
2022-10-08 10:01:31 -07:00
}
}
SmartDashboard::init();
if (IsReal()) {
std::FILE* file = nullptr;
file = std::fopen("/tmp/frc_versions/FRC_Lib_Version.ini", "w");
if (file != nullptr) {
std::fputs("C++ ", file);
std::fputs(GetWPILibVersion(), file);
std::fclose(file);
}
}
2017-07-08 10:50:56 -04:00
[hal, wpilib] New DS thread model and implementation (#3787) The current DS thread model has some pretty major issues. It makes it difficult to know if all data is from the same remote packet, and if the data changes while the robot loop is running. Additionally, the DS thread is used for a few other things (MotorSafety and State Tracking for EducationalRobot). This also makes sim difficult, as user code has to wait for the thread to know it has new data. This change completely rethinks how threading works in the driver station model. First, the DS HAL system receives a new data callback, either from Netcomm or DriverStationSim. Inside the context of this callback, all the low latency data is read and put into a cache. Doing some investigation on the robot side, this is perfectly safe to do, and also ensures a ds packet will not be parsed before we finish reading the current packet data. After all data is read, the cache is swapped with a 2nd buffer. This buffer just stores the data, none of the HAL DS calls read from this buffer. An event is then fired, stating there is new data ready to go. Robot code calls HAL_UpdateDSData(). This swaps the 2nd buffer with a 3rd buffer, which always contains the current data. This data will not be updated until HAL_UpdateDSData is called again. Which solves the state problem. The high level driver station classes have. an updateData() call, which calls HAL_UpdateDSData, and then update button state variables, then data log and update the NT FMS data table (Java also caches across the JNI boundary here, but that could trivially be removed). An extra event provider is provided, allowing other threads to know when this call has been completed. IterativeRobotBase calls DS.updateData() at the beginning of each loop, and only once per loop. This means all commands will always have the same state. All of this means there is no longer a DS thread. Everything happens synchronously. This means Sim and testing is easier, as you can just call DriverStationSim.NotifyNewData(), and then DriverStation.UpdateData(), and you can guarantee that all the DriverStation.*** data is up to date. As for Motor Safety and Educational Robot State Handling, those can all be handled by their own threads. The Educational Thread only needs to run under EducationalRobot, and MotorSafety will only be started if there is a motor safety object enabled.
2022-10-21 22:01:55 -07:00
// Call DriverStation::RefreshData() to kick things off
DriverStation::RefreshData();
2017-07-08 10:50:56 -04:00
// First and one-time initialization
LiveWindow::SetEnabled(false);
}