Files
allwpilib/wpilibOldCommands/src/main/native/cpp/commands/Command.cpp

313 lines
6.7 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/commands/Command.h"
#include <typeinfo>
#include "frc/Errors.h"
#include "frc/RobotState.h"
#include "frc/Timer.h"
#include "frc/commands/CommandGroup.h"
#include "frc/commands/Scheduler.h"
#include "frc/livewindow/LiveWindow.h"
#include "frc/smartdashboard/SendableBuilder.h"
#include "frc/smartdashboard/SendableRegistry.h"
using namespace frc;
int Command::m_commandCounter = 0;
Command::Command() : Command("", -1.0) {}
Command::Command(const wpi::Twine& name) : Command(name, -1.0) {}
Command::Command(double timeout) : Command("", timeout) {}
Command::Command(Subsystem& subsystem) : Command("", -1.0) {
Requires(&subsystem);
}
Command::Command(const wpi::Twine& name, double timeout) {
// We use -1.0 to indicate no timeout.
if (timeout < 0.0 && timeout != -1.0) {
2021-05-23 19:33:33 -07:00
throw FRC_MakeError(err::ParameterOutOfRange, "timeout {} < 0.0", timeout);
}
m_timeout = timeout;
// If name contains an empty string
if (name.isTriviallyEmpty() ||
(name.isSingleStringRef() && name.getSingleStringRef().empty())) {
SendableRegistry::GetInstance().Add(
this, "Command_" + wpi::Twine(typeid(*this).name()));
} else {
SendableRegistry::GetInstance().Add(this, name);
}
}
Command::Command(const wpi::Twine& name, Subsystem& subsystem)
: Command(name, -1.0) {
Requires(&subsystem);
}
Command::Command(double timeout, Subsystem& subsystem) : Command("", timeout) {
Requires(&subsystem);
}
Command::Command(const wpi::Twine& name, double timeout, Subsystem& subsystem)
: Command(name, timeout) {
Requires(&subsystem);
}
double Command::TimeSinceInitialized() const {
if (m_startTime < 0.0) {
return 0.0;
} else {
return Timer::GetFPGATimestamp() - m_startTime;
}
}
void Command::Requires(Subsystem* subsystem) {
if (!AssertUnlocked("Can not add new requirement to command")) {
return;
}
if (subsystem != nullptr) {
m_requirements.insert(subsystem);
} else {
2021-05-23 19:33:33 -07:00
throw FRC_MakeError(err::NullParameter, "{}", "subsystem");
}
}
void Command::Start() {
LockChanges();
if (m_parent != nullptr) {
throw FRC_MakeError(
2021-05-23 19:33:33 -07:00
err::CommandIllegalUse, "{}",
"Can not start a command that is part of a command group");
}
m_completed = false;
Scheduler::GetInstance()->AddCommand(this);
}
bool Command::Run() {
if (!m_runWhenDisabled && m_parent == nullptr && RobotState::IsDisabled()) {
Cancel();
}
if (IsCanceled()) {
return false;
}
if (!m_initialized) {
m_initialized = true;
StartTiming();
_Initialize();
Initialize();
}
_Execute();
Execute();
return !IsFinished();
}
void Command::Cancel() {
if (m_parent != nullptr) {
throw FRC_MakeError(
2021-05-23 19:33:33 -07:00
err::CommandIllegalUse, "{}",
"Can not cancel a command that is part of a command group");
}
_Cancel();
}
bool Command::IsRunning() const {
return m_running;
}
bool Command::IsInitialized() const {
return m_initialized;
}
bool Command::IsCompleted() const {
return m_completed;
}
bool Command::IsCanceled() const {
return m_canceled;
}
bool Command::IsInterruptible() const {
return m_interruptible;
}
void Command::SetInterruptible(bool interruptible) {
m_interruptible = interruptible;
}
bool Command::DoesRequire(Subsystem* system) const {
return m_requirements.count(system) > 0;
}
const Command::SubsystemSet& Command::GetRequirements() const {
return m_requirements;
}
CommandGroup* Command::GetGroup() const {
return m_parent;
}
void Command::SetRunWhenDisabled(bool run) {
m_runWhenDisabled = run;
}
bool Command::WillRunWhenDisabled() const {
return m_runWhenDisabled;
}
int Command::GetID() const {
return m_commandID;
}
void Command::SetTimeout(double timeout) {
if (timeout < 0.0) {
2021-05-23 19:33:33 -07:00
throw FRC_MakeError(err::ParameterOutOfRange, "timeout {} < 0.0", timeout);
} else {
m_timeout = timeout;
}
}
bool Command::IsTimedOut() const {
return m_timeout != -1 && TimeSinceInitialized() >= m_timeout;
}
bool Command::AssertUnlocked(const std::string& message) {
if (m_locked) {
throw FRC_MakeError(
err::CommandIllegalUse,
2021-05-23 19:33:33 -07:00
"{} after being started or being added to a command group", message);
}
return true;
}
void Command::SetParent(CommandGroup* parent) {
if (parent == nullptr) {
2021-05-23 19:33:33 -07:00
throw FRC_MakeError(err::NullParameter, "{}", "parent");
} else if (m_parent != nullptr) {
2021-05-23 19:33:33 -07:00
throw FRC_MakeError(err::CommandIllegalUse, "{}",
"Can not give command to a command group after "
"already being put in a command group");
} else {
LockChanges();
m_parent = parent;
}
}
bool Command::IsParented() const {
return m_parent != nullptr;
}
void Command::ClearRequirements() {
m_requirements.clear();
}
void Command::Initialize() {}
void Command::Execute() {}
void Command::End() {}
void Command::Interrupted() {
End();
}
void Command::_Initialize() {
m_completed = false;
}
void Command::_Interrupted() {
m_completed = true;
}
void Command::_Execute() {}
void Command::_End() {
m_completed = true;
}
void Command::_Cancel() {
if (IsRunning()) {
m_canceled = true;
}
}
void Command::LockChanges() {
m_locked = true;
}
void Command::Removed() {
if (m_initialized) {
if (IsCanceled()) {
Interrupted();
_Interrupted();
} else {
End();
_End();
}
}
m_initialized = false;
m_canceled = false;
m_running = false;
m_completed = true;
}
void Command::StartRunning() {
m_running = true;
m_startTime = -1;
m_completed = false;
}
void Command::StartTiming() {
m_startTime = Timer::GetFPGATimestamp();
}
std::string Command::GetName() const {
return SendableRegistry::GetInstance().GetName(this);
}
void Command::SetName(const wpi::Twine& name) {
SendableRegistry::GetInstance().SetName(this, name);
}
std::string Command::GetSubsystem() const {
return SendableRegistry::GetInstance().GetSubsystem(this);
}
void Command::SetSubsystem(const wpi::Twine& name) {
SendableRegistry::GetInstance().SetSubsystem(this, name);
}
void Command::InitSendable(SendableBuilder& builder) {
builder.SetSmartDashboardType("Command");
builder.AddStringProperty(
".name", [=]() { return SendableRegistry::GetInstance().GetName(this); },
nullptr);
builder.AddBooleanProperty(
"running", [=]() { return IsRunning(); },
[=](bool value) {
if (value) {
if (!IsRunning()) {
Start();
}
} else {
if (IsRunning()) {
Cancel();
}
}
});
builder.AddBooleanProperty(
".isParented", [=]() { return IsParented(); }, nullptr);
}