WPILib Reorganization

This is a major restructuring of the WPILib repository to simply build
procedures and remove the remnants of Maven from everything except the
eclipse plugins. Gradle files have been largely simplified or rewritten,
taking advantage of splitting up parts of the build into separate build
files for ease of reading.

The eclipse plugins are now in a separate project, as is ntcore. All
dependencies are resolved via Maven dependencies, with the
Jenkins-maintained WPILib repo. Project structures have also been
simplified: we no longer have separate subprojects inside wpilibc and
wpilibj. Where possible, these changes hav been done with git renames,
to make sure we still have full history for all repositories. Other
unrelated subprojects have also been broken out: OutlineViewer is now a
separate project.

Change-Id: Ib4e2a6e1a2f66427a14f16612b0e0d69ed661878
This commit is contained in:
Fredric Silberberg
2015-09-24 20:26:49 -04:00
parent c20d34c2b6
commit 6d854afb0e
1769 changed files with 2278 additions and 333177 deletions

View File

@@ -0,0 +1,41 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2011. All Rights Reserved.
*/
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include "Buttons/Button.h"
/**
* Specifies the command to run when a button is first pressed
* @param command The pointer to the command to run
*/
void Button::WhenPressed(Command *command) { WhenActive(command); }
/**
* Specifies the command to be scheduled while the button is pressed
* The command will be scheduled repeatedly while the button is pressed and will
* be canceled when the button is released.
* @param command The pointer to the command to run
*/
void Button::WhileHeld(Command *command) { WhileActive(command); }
/**
* Specifies the command to run when the button is released
* The command will be scheduled a single time.
* @param The pointer to the command to run
*/
void Button::WhenReleased(Command *command) { WhenInactive(command); }
/**
* Cancels the specificed command when the button is pressed
* @param The command to be canceled
*/
void Button::CancelWhenPressed(Command *command) { CancelWhenActive(command); }
/**
* Toggle the specified command when the button is pressed
* @param The command to be toggled
*/
void Button::ToggleWhenPressed(Command *command) { ToggleWhenActive(command); }

View File

@@ -0,0 +1,15 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2011. All Rights Reserved.
*/
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include "Buttons/ButtonScheduler.h"
#include "Commands/Scheduler.h"
ButtonScheduler::ButtonScheduler(bool last, Trigger *button, Command *orders)
: m_pressedLast(last), m_button(button), m_command(orders) {}
void ButtonScheduler::Start() { Scheduler::GetInstance()->AddButton(this); }

View File

@@ -0,0 +1,28 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2011. All Rights Reserved.
*/
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include "Buttons/CancelButtonScheduler.h"
#include "Buttons/Button.h"
#include "Commands/Command.h"
CancelButtonScheduler::CancelButtonScheduler(bool last, Trigger *button,
Command *orders)
: ButtonScheduler(last, button, orders) {
pressedLast = m_button->Grab();
}
void CancelButtonScheduler::Execute() {
if (m_button->Grab()) {
if (!pressedLast) {
pressedLast = true;
m_command->Cancel();
}
} else {
pressedLast = false;
}
}

View File

@@ -0,0 +1,27 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2011. All Rights Reserved.
*/
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include "Buttons/HeldButtonScheduler.h"
#include "Buttons/Button.h"
#include "Commands/Command.h"
HeldButtonScheduler::HeldButtonScheduler(bool last, Trigger *button,
Command *orders)
: ButtonScheduler(last, button, orders) {}
void HeldButtonScheduler::Execute() {
if (m_button->Grab()) {
m_pressedLast = true;
m_command->Start();
} else {
if (m_pressedLast) {
m_pressedLast = false;
m_command->Cancel();
}
}
}

View File

@@ -0,0 +1,17 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2011. All Rights Reserved.
*/
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include "Buttons/InternalButton.h"
InternalButton::InternalButton(bool inverted)
: m_pressed(inverted), m_inverted(inverted) {}
void InternalButton::SetInverted(bool inverted) { m_inverted = inverted; }
void InternalButton::SetPressed(bool pressed) { m_pressed = pressed; }
bool InternalButton::Get() { return m_pressed ^ m_inverted; }

View File

@@ -0,0 +1,13 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2011. All Rights Reserved.
*/
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include "Buttons/JoystickButton.h"
JoystickButton::JoystickButton(GenericHID *joystick, int buttonNumber)
: m_joystick(joystick), m_buttonNumber(buttonNumber) {}
bool JoystickButton::Get() { return m_joystick->GetRawButton(m_buttonNumber); }

View File

@@ -0,0 +1,25 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2011. All Rights Reserved.
*/
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include "Buttons/NetworkButton.h"
#include "networktables/NetworkTable.h"
NetworkButton::NetworkButton(const std::string &tableName, const std::string &field)
: // TODO how is this supposed to work???
m_netTable(NetworkTable::GetTable(tableName)),
m_field(field) {}
NetworkButton::NetworkButton(std::shared_ptr<ITable> table, const std::string &field)
: m_netTable(table), m_field(field) {}
bool NetworkButton::Get() {
/*if (m_netTable->isConnected())
return m_netTable->GetBoolean(m_field.c_str());
else
return false;*/
return m_netTable->GetBoolean(m_field, false);
}

View File

@@ -0,0 +1,26 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2011. All Rights Reserved.
*/
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include "Buttons/PressedButtonScheduler.h"
#include "Buttons/Button.h"
#include "Commands/Command.h"
PressedButtonScheduler::PressedButtonScheduler(bool last, Trigger *button,
Command *orders)
: ButtonScheduler(last, button, orders) {}
void PressedButtonScheduler::Execute() {
if (m_button->Grab()) {
if (!m_pressedLast) {
m_pressedLast = true;
m_command->Start();
}
} else {
m_pressedLast = false;
}
}

View File

@@ -0,0 +1,26 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2011. All Rights Reserved.
*/
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include "Buttons/ReleasedButtonScheduler.h"
#include "Buttons/Button.h"
#include "Commands/Command.h"
ReleasedButtonScheduler::ReleasedButtonScheduler(bool last, Trigger *button,
Command *orders)
: ButtonScheduler(last, button, orders) {}
void ReleasedButtonScheduler::Execute() {
if (m_button->Grab()) {
m_pressedLast = true;
} else {
if (m_pressedLast) {
m_pressedLast = false;
m_command->Start();
}
}
}

View File

@@ -0,0 +1,32 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2011. All Rights Reserved.
*/
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include "Buttons/ToggleButtonScheduler.h"
#include "Buttons/Button.h"
#include "Commands/Command.h"
ToggleButtonScheduler::ToggleButtonScheduler(bool last, Trigger *button,
Command *orders)
: ButtonScheduler(last, button, orders) {
pressedLast = m_button->Grab();
}
void ToggleButtonScheduler::Execute() {
if (m_button->Grab()) {
if (!pressedLast) {
pressedLast = true;
if (m_command->IsRunning()) {
m_command->Cancel();
} else {
m_command->Start();
}
}
} else {
pressedLast = false;
}
}

View File

@@ -0,0 +1,62 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2011. All Rights Reserved.
*/
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include "Buttons/Button.h"
#include "Buttons/HeldButtonScheduler.h"
#include "Buttons/PressedButtonScheduler.h"
#include "Buttons/ReleasedButtonScheduler.h"
#include "Buttons/ToggleButtonScheduler.h"
#include "Buttons/CancelButtonScheduler.h"
bool Trigger::Grab() {
if (Get())
return true;
else if (m_table != nullptr) {
// if (m_table->isConnected())//TODO is connected on button?
return m_table->GetBoolean("pressed", false);
/*else
return false;*/
} else
return false;
}
void Trigger::WhenActive(Command *command) {
auto pbs = new PressedButtonScheduler(Grab(), this, command);
pbs->Start();
}
void Trigger::WhileActive(Command *command) {
auto hbs = new HeldButtonScheduler(Grab(), this, command);
hbs->Start();
}
void Trigger::WhenInactive(Command *command) {
auto rbs = new ReleasedButtonScheduler(Grab(), this, command);
rbs->Start();
}
void Trigger::CancelWhenActive(Command *command) {
auto cbs = new CancelButtonScheduler(Grab(), this, command);
cbs->Start();
}
void Trigger::ToggleWhenActive(Command *command) {
auto tbs = new ToggleButtonScheduler(Grab(), this, command);
tbs->Start();
}
std::string Trigger::GetSmartDashboardType() const { return "Button"; }
void Trigger::InitTable(std::shared_ptr<ITable> table) {
m_table = table;
if (m_table != nullptr) {
m_table->PutBoolean("pressed", Get());
}
}
std::shared_ptr<ITable> Trigger::GetTable() const { return m_table; }

View File

@@ -0,0 +1,392 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2011. All Rights Reserved.
*/
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include "Commands/Command.h"
#include "Commands/CommandGroup.h"
#include "Commands/Scheduler.h"
#include "RobotState.h"
#include "Timer.h"
#include "WPIErrors.h"
#include <typeinfo>
static const std::string kName = "name";
static const std::string kRunning = "running";
static const std::string kIsParented = "isParented";
int Command::m_commandCounter = 0;
/**
* Creates a new command.
* The name of this command will be default.
*/
Command::Command() : Command("", -1.0) {}
/**
* Creates a new command with the given name and no timeout.
* @param name the name for this command
*/
Command::Command(const std::string &name) : Command(name, -1.0) {}
/**
* Creates a new command with the given timeout and a default name.
* @param timeout the time (in seconds) before this command "times out"
* @see Command#isTimedOut() isTimedOut()
*/
Command::Command(double timeout) : Command("", timeout) {}
/**
* Creates a new command with the given name and timeout.
* @param name the name of the command
* @param timeout the time (in seconds) before this command "times out"
* @see Command#isTimedOut() isTimedOut()
*/
Command::Command(const std::string &name, double timeout) {
// We use -1.0 to indicate no timeout.
if (timeout < 0.0 && timeout != -1.0)
wpi_setWPIErrorWithContext(ParameterOutOfRange, "timeout < 0.0");
m_timeout = timeout;
// If name contains an empty string
if (name.length() == 0) {
m_name = std::string("Command_") + std::string(typeid(*this).name());
}
else {
m_name = name;
}
}
Command::~Command() {
if (m_table != nullptr) m_table->RemoveTableListener(this);
}
/**
* Get the ID (sequence number) for this command
* The ID is a unique sequence number that is incremented for each command.
* @return the ID of this command
*/
int Command::GetID() const { return m_commandID; }
/**
* Sets the timeout of this command.
* @param timeout the timeout (in seconds)
* @see Command#isTimedOut() isTimedOut()
*/
void Command::SetTimeout(double timeout) {
if (timeout < 0.0)
wpi_setWPIErrorWithContext(ParameterOutOfRange, "timeout < 0.0");
else
m_timeout = timeout;
}
/**
* Returns the time since this command was initialized (in seconds).
* This function will work even if there is no specified timeout.
* @return the time since this command was initialized (in seconds).
*/
double Command::TimeSinceInitialized() const {
if (m_startTime < 0.0)
return 0.0;
else
return Timer::GetFPGATimestamp() - m_startTime;
}
/**
* This method specifies that the given {@link Subsystem} is used by this
* command.
* This method is crucial to the functioning of the Command System in general.
*
* <p>Note that the recommended way to call this method is in the
* constructor.</p>
*
* @param subsystem the {@link Subsystem} required
* @see Subsystem
*/
void Command::Requires(Subsystem *subsystem) {
if (!AssertUnlocked("Can not add new requirement to command")) return;
if (subsystem != nullptr)
m_requirements.insert(subsystem);
else
wpi_setWPIErrorWithContext(NullParameter, "subsystem");
}
/**
* Called when the command has been removed.
* This will call {@link Command#interrupted() interrupted()} or {@link
* Command#end() end()}.
*/
void Command::Removed() {
if (m_initialized) {
if (IsCanceled()) {
Interrupted();
_Interrupted();
} else {
End();
_End();
}
}
m_initialized = false;
m_canceled = false;
m_running = false;
if (m_table != nullptr) m_table->PutBoolean(kRunning, false);
}
/**
* Starts up the command. Gets the command ready to start.
* <p>Note that the command will eventually start, however it will not
* necessarily
* do so immediately, and may in fact be canceled before initialize is even
* called.</p>
*/
void Command::Start() {
LockChanges();
if (m_parent != nullptr)
wpi_setWPIErrorWithContext(
CommandIllegalUse,
"Can not start a command that is part of a command group");
Scheduler::GetInstance()->AddCommand(this);
}
/**
* The run method is used internally to actually run the commands.
* @return whether or not the command should stay within the {@link Scheduler}.
*/
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::_Initialize() {}
void Command::_Interrupted() {}
void Command::_Execute() {}
void Command::_End() {}
/**
* Called to indicate that the timer should start.
* This is called right before {@link Command#initialize() initialize()} is,
* inside the
* {@link Command#run() run()} method.
*/
void Command::StartTiming() { m_startTime = Timer::GetFPGATimestamp(); }
/**
* Returns whether or not the {@link Command#timeSinceInitialized()
* timeSinceInitialized()}
* method returns a number which is greater than or equal to the timeout for the
* command.
* If there is no timeout, this will always return false.
* @return whether the time has expired
*/
bool Command::IsTimedOut() const {
return m_timeout != -1 && TimeSinceInitialized() >= m_timeout;
}
/**
* Returns the requirements (as an std::set of {@link Subsystem Subsystems}
* pointers) of this command
* @return the requirements (as an std::set of {@link Subsystem Subsystems}
* pointers) of this command
*/
Command::SubsystemSet Command::GetRequirements() const {
return m_requirements;
}
/**
* Prevents further changes from being made
*/
void Command::LockChanges() { m_locked = true; }
/**
* If changes are locked, then this will generate a CommandIllegalUse error.
* @param message the message to report on error (it is appended by a default
* message)
* @return true if assert passed, false if assert failed
*/
bool Command::AssertUnlocked(const std::string &message) {
if (m_locked) {
std::string buf = message + " after being started or being added to a command group";
wpi_setWPIErrorWithContext(CommandIllegalUse, buf);
return false;
}
return true;
}
/**
* Sets the parent of this command. No actual change is made to the group.
* @param parent the parent
*/
void Command::SetParent(CommandGroup *parent) {
if (parent == nullptr) {
wpi_setWPIErrorWithContext(NullParameter, "parent");
} else if (m_parent != nullptr) {
wpi_setWPIErrorWithContext(CommandIllegalUse,
"Can not give command to a command group after "
"already being put in a command group");
} else {
LockChanges();
m_parent = parent;
if (m_table != nullptr) {
m_table->PutBoolean(kIsParented, true);
}
}
}
/**
* This is used internally to mark that the command has been started.
* The lifecycle of a command is:
*
* startRunning() is called.
* run() is called (multiple times potentially)
* removed() is called
*
* It is very important that startRunning and removed be called in order or some
* assumptions
* of the code will be broken.
*/
void Command::StartRunning() {
m_running = true;
m_startTime = -1;
if (m_table != nullptr) m_table->PutBoolean(kRunning, true);
}
/**
* Returns whether or not the command is running.
* This may return true even if the command has just been canceled, as it may
* not have yet called {@link Command#interrupted()}.
* @return whether or not the command is running
*/
bool Command::IsRunning() const { return m_running; }
/**
* This will cancel the current command.
* <p>This will cancel the current command eventually. It can be called
* multiple times.
* And it can be called when the command is not running. If the command is
* running though,
* then the command will be marked as canceled and eventually removed.</p>
* <p>A command can not be canceled
* if it is a part of a command group, you must cancel the command group
* instead.</p>
*/
void Command::Cancel() {
if (m_parent != nullptr)
wpi_setWPIErrorWithContext(
CommandIllegalUse,
"Can not cancel a command that is part of a command group");
_Cancel();
}
/**
* This works like cancel(), except that it doesn't throw an exception if it is
* a part
* of a command group. Should only be called by the parent command group.
*/
void Command::_Cancel() {
if (IsRunning()) m_canceled = true;
}
/**
* Returns whether or not this has been canceled.
* @return whether or not this has been canceled
*/
bool Command::IsCanceled() const { return m_canceled; }
/**
* Returns whether or not this command can be interrupted.
* @return whether or not this command can be interrupted
*/
bool Command::IsInterruptible() const { return m_interruptible; }
/**
* Sets whether or not this command can be interrupted.
* @param interruptible whether or not this command can be interrupted
*/
void Command::SetInterruptible(bool interruptible) {
m_interruptible = interruptible;
}
/**
* Checks if the command requires the given {@link Subsystem}.
* @param system the system
* @return whether or not the subsystem is required (false if given nullptr)
*/
bool Command::DoesRequire(Subsystem *system) const {
return m_requirements.count(system) > 0;
}
/**
* Returns the {@link CommandGroup} that this command is a part of.
* Will return null if this {@link Command} is not in a group.
* @return the {@link CommandGroup} that this command is a part of (or null if
* not in group)
*/
CommandGroup *Command::GetGroup() const { return m_parent; }
/**
* Sets whether or not this {@link Command} should run when the robot is
* disabled.
*
* <p>By default a command will not run when the robot is disabled, and will in
* fact be canceled.</p>
* @param run whether or not this command should run when the robot is disabled
*/
void Command::SetRunWhenDisabled(bool run) { m_runWhenDisabled = run; }
/**
* Returns whether or not this {@link Command} will run when the robot is
* disabled, or if it will cancel itself.
* @return whether or not this {@link Command} will run when the robot is
* disabled, or if it will cancel itself
*/
bool Command::WillRunWhenDisabled() const { return m_runWhenDisabled; }
std::string Command::GetName() const {
return m_name;
}
std::string Command::GetSmartDashboardType() const { return "Command"; }
void Command::InitTable(std::shared_ptr<ITable> table) {
if (m_table != nullptr) m_table->RemoveTableListener(this);
m_table = table;
if (m_table != nullptr) {
m_table->PutString(kName, GetName());
m_table->PutBoolean(kRunning, IsRunning());
m_table->PutBoolean(kIsParented, m_parent != nullptr);
m_table->AddTableListener(kRunning, this, false);
}
}
std::shared_ptr<ITable> Command::GetTable() const { return m_table; }
void Command::ValueChanged(ITable* source, llvm::StringRef key,
std::shared_ptr<nt::Value> value, bool isNew) {
if (!value->IsBoolean()) return;
if (value->GetBoolean()) {
if (!IsRunning()) Start();
} else {
if (IsRunning()) Cancel();
}
}

View File

@@ -0,0 +1,338 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2011. All Rights Reserved.
*/
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include "Commands/CommandGroup.h"
#include "WPIErrors.h"
/**
* Creates a new {@link CommandGroup CommandGroup} with the given name.
* @param name the name for this command group
*/
CommandGroup::CommandGroup(const std::string &name) : Command(name) {}
/**
* Adds a new {@link Command Command} to the group. The {@link Command Command}
* will be started after
* all the previously added {@link Command Commands}.
*
* <p>Note that any requirements the given {@link Command Command} has will be
* added to the
* group. For this reason, a {@link Command Command's} requirements can not be
* changed after
* being added to a group.</p>
*
* <p>It is recommended that this method be called in the constructor.</p>
*
* @param command The {@link Command Command} to be added
*/
void CommandGroup::AddSequential(Command *command) {
if (command == nullptr) {
wpi_setWPIErrorWithContext(NullParameter, "command");
return;
}
if (!AssertUnlocked("Cannot add new command to command group")) return;
command->SetParent(this);
m_commands.push_back(
CommandGroupEntry(command, CommandGroupEntry::kSequence_InSequence));
// Iterate through command->GetRequirements() and call Requires() on each
// required subsystem
Command::SubsystemSet requirements = command->GetRequirements();
auto iter = requirements.begin();
for (; iter != requirements.end(); iter++) Requires(*iter);
}
/**
* Adds a new {@link Command Command} to the group with a given timeout.
* The {@link Command Command} will be started after all the previously added
* commands.
*
* <p>Once the {@link Command Command} is started, it will be run until it
* finishes or the time
* expires, whichever is sooner. Note that the given {@link Command Command}
* will have no
* knowledge that it is on a timer.</p>
*
* <p>Note that any requirements the given {@link Command Command} has will be
* added to the
* group. For this reason, a {@link Command Command's} requirements can not be
* changed after
* being added to a group.</p>
*
* <p>It is recommended that this method be called in the constructor.</p>
*
* @param command The {@link Command Command} to be added
* @param timeout The timeout (in seconds)
*/
void CommandGroup::AddSequential(Command *command, double timeout) {
if (command == nullptr) {
wpi_setWPIErrorWithContext(NullParameter, "command");
return;
}
if (!AssertUnlocked("Cannot add new command to command group")) return;
if (timeout < 0.0) {
wpi_setWPIErrorWithContext(ParameterOutOfRange, "timeout < 0.0");
return;
}
command->SetParent(this);
m_commands.push_back(CommandGroupEntry(
command, CommandGroupEntry::kSequence_InSequence, timeout));
// Iterate through command->GetRequirements() and call Requires() on each
// required subsystem
Command::SubsystemSet requirements = command->GetRequirements();
auto iter = requirements.begin();
for (; iter != requirements.end(); iter++) Requires(*iter);
}
/**
* Adds a new child {@link Command} to the group. The {@link Command} will be
* started after
* all the previously added {@link Command Commands}.
*
* <p>Instead of waiting for the child to finish, a {@link CommandGroup} will
* have it
* run at the same time as the subsequent {@link Command Commands}. The child
* will run until either
* it finishes, a new child with conflicting requirements is started, or
* the main sequence runs a {@link Command} with conflicting requirements. In
* the latter
* two cases, the child will be canceled even if it says it can't be
* interrupted.</p>
*
* <p>Note that any requirements the given {@link Command Command} has will be
* added to the
* group. For this reason, a {@link Command Command's} requirements can not be
* changed after
* being added to a group.</p>
*
* <p>It is recommended that this method be called in the constructor.</p>
*
* @param command The command to be added
*/
void CommandGroup::AddParallel(Command *command) {
if (command == nullptr) {
wpi_setWPIErrorWithContext(NullParameter, "command");
return;
}
if (!AssertUnlocked("Cannot add new command to command group")) return;
command->SetParent(this);
m_commands.push_back(
CommandGroupEntry(command, CommandGroupEntry::kSequence_BranchChild));
// Iterate through command->GetRequirements() and call Requires() on each
// required subsystem
Command::SubsystemSet requirements = command->GetRequirements();
auto iter = requirements.begin();
for (; iter != requirements.end(); iter++) Requires(*iter);
}
/**
* Adds a new child {@link Command} to the group with the given timeout. The
* {@link Command} will be started after
* all the previously added {@link Command Commands}.
*
* <p>Once the {@link Command Command} is started, it will run until it
* finishes, is interrupted,
* or the time expires, whichever is sooner. Note that the given {@link Command
* Command} will have no
* knowledge that it is on a timer.</p>
*
* <p>Instead of waiting for the child to finish, a {@link CommandGroup} will
* have it
* run at the same time as the subsequent {@link Command Commands}. The child
* will run until either
* it finishes, the timeout expires, a new child with conflicting requirements
* is started, or
* the main sequence runs a {@link Command} with conflicting requirements. In
* the latter
* two cases, the child will be canceled even if it says it can't be
* interrupted.</p>
*
* <p>Note that any requirements the given {@link Command Command} has will be
* added to the
* group. For this reason, a {@link Command Command's} requirements can not be
* changed after
* being added to a group.</p>
*
* <p>It is recommended that this method be called in the constructor.</p>
*
* @param command The command to be added
* @param timeout The timeout (in seconds)
*/
void CommandGroup::AddParallel(Command *command, double timeout) {
if (command == nullptr) {
wpi_setWPIErrorWithContext(NullParameter, "command");
return;
}
if (!AssertUnlocked("Cannot add new command to command group")) return;
if (timeout < 0.0) {
wpi_setWPIErrorWithContext(ParameterOutOfRange, "timeout < 0.0");
return;
}
command->SetParent(this);
m_commands.push_back(CommandGroupEntry(
command, CommandGroupEntry::kSequence_BranchChild, timeout));
// Iterate through command->GetRequirements() and call Requires() on each
// required subsystem
Command::SubsystemSet requirements = command->GetRequirements();
auto iter = requirements.begin();
for (; iter != requirements.end(); iter++) Requires(*iter);
}
void CommandGroup::_Initialize() { m_currentCommandIndex = -1; }
void CommandGroup::_Execute() {
CommandGroupEntry entry;
Command *cmd = nullptr;
bool firstRun = false;
if (m_currentCommandIndex == -1) {
firstRun = true;
m_currentCommandIndex = 0;
}
while ((unsigned)m_currentCommandIndex < m_commands.size()) {
if (cmd != nullptr) {
if (entry.IsTimedOut()) cmd->_Cancel();
if (cmd->Run()) {
break;
} else {
cmd->Removed();
m_currentCommandIndex++;
firstRun = true;
cmd = nullptr;
continue;
}
}
entry = m_commands[m_currentCommandIndex];
cmd = nullptr;
switch (entry.m_state) {
case CommandGroupEntry::kSequence_InSequence:
cmd = entry.m_command;
if (firstRun) {
cmd->StartRunning();
CancelConflicts(cmd);
firstRun = false;
}
break;
case CommandGroupEntry::kSequence_BranchPeer:
m_currentCommandIndex++;
entry.m_command->Start();
break;
case CommandGroupEntry::kSequence_BranchChild:
m_currentCommandIndex++;
CancelConflicts(entry.m_command);
entry.m_command->StartRunning();
m_children.push_back(entry);
break;
}
}
// Run Children
auto iter = m_children.begin();
for (; iter != m_children.end();) {
entry = *iter;
Command *child = entry.m_command;
if (entry.IsTimedOut()) child->_Cancel();
if (!child->Run()) {
child->Removed();
iter = m_children.erase(iter);
} else {
iter++;
}
}
}
void CommandGroup::_End() {
// Theoretically, we don't have to check this, but we do if teams override the
// IsFinished method
if (m_currentCommandIndex != -1 &&
(unsigned)m_currentCommandIndex < m_commands.size()) {
Command *cmd = m_commands[m_currentCommandIndex].m_command;
cmd->_Cancel();
cmd->Removed();
}
auto iter = m_children.begin();
for (; iter != m_children.end(); iter++) {
Command *cmd = iter->m_command;
cmd->_Cancel();
cmd->Removed();
}
m_children.clear();
}
void CommandGroup::_Interrupted() { _End(); }
// Can be overwritten by teams
void CommandGroup::Initialize() {}
// Can be overwritten by teams
void CommandGroup::Execute() {}
// Can be overwritten by teams
void CommandGroup::End() {}
// Can be overwritten by teams
void CommandGroup::Interrupted() {}
bool CommandGroup::IsFinished() {
return (unsigned)m_currentCommandIndex >= m_commands.size() &&
m_children.empty();
}
bool CommandGroup::IsInterruptible() const {
if (!Command::IsInterruptible()) return false;
if (m_currentCommandIndex != -1 &&
(unsigned)m_currentCommandIndex < m_commands.size()) {
Command *cmd = m_commands[m_currentCommandIndex].m_command;
if (!cmd->IsInterruptible()) return false;
}
auto iter = m_children.cbegin();
for (; iter != m_children.cend(); iter++) {
if (!iter->m_command->IsInterruptible()) return false;
}
return true;
}
void CommandGroup::CancelConflicts(Command *command) {
auto childIter = m_children.begin();
for (; childIter != m_children.end();) {
Command *child = childIter->m_command;
bool erased = false;
Command::SubsystemSet requirements = command->GetRequirements();
auto requirementIter = requirements.begin();
for (; requirementIter != requirements.end(); requirementIter++) {
if (child->DoesRequire(*requirementIter)) {
child->_Cancel();
child->Removed();
childIter = m_children.erase(childIter);
erased = true;
break;
}
}
if (!erased) childIter++;
}
}
int CommandGroup::GetSize() const { return m_children.size(); }

View File

@@ -0,0 +1,21 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2011. All Rights Reserved.
*/
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include "Commands/CommandGroupEntry.h"
#include "Commands/Command.h"
CommandGroupEntry::CommandGroupEntry(Command *command, Sequence state,
double timeout)
: m_timeout(timeout), m_command(command), m_state(state) {}
bool CommandGroupEntry::IsTimedOut() const {
if (m_timeout < 0.0) return false;
double time = m_command->TimeSinceInitialized();
if (time == 0.0) return false;
return time >= m_timeout;
}

View File

@@ -0,0 +1,71 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2011. All Rights Reserved.
*/
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include "Commands/PIDCommand.h"
#include "float.h"
PIDCommand::PIDCommand(const std::string &name, double p, double i, double d, double f,
double period)
: Command(name) {
m_controller = std::make_shared<PIDController>(p, i, d, this, this, period);
}
PIDCommand::PIDCommand(double p, double i, double d, double f, double period) {
m_controller = std::make_shared<PIDController>(p, i, d, f, this, this, period);
}
PIDCommand::PIDCommand(const std::string &name, double p, double i, double d)
: Command(name) {
m_controller = std::make_shared<PIDController>(p, i, d, this, this);
}
PIDCommand::PIDCommand(const std::string &name, double p, double i, double d,
double period)
: Command(name) {
m_controller = std::make_shared<PIDController>(p, i, d, this, this, period);
}
PIDCommand::PIDCommand(double p, double i, double d) {
m_controller = std::make_shared<PIDController>(p, i, d, this, this);
}
PIDCommand::PIDCommand(double p, double i, double d, double period) {
m_controller = std::make_shared<PIDController>(p, i, d, this, this, period);
}
void PIDCommand::_Initialize() { m_controller->Enable(); }
void PIDCommand::_End() { m_controller->Disable(); }
void PIDCommand::_Interrupted() { _End(); }
void PIDCommand::SetSetpointRelative(double deltaSetpoint) {
SetSetpoint(GetSetpoint() + deltaSetpoint);
}
void PIDCommand::PIDWrite(float output) { UsePIDOutput(output); }
double PIDCommand::PIDGet() { return ReturnPIDInput(); }
std::shared_ptr<PIDController> PIDCommand::GetPIDController() const {
return m_controller;
}
void PIDCommand::SetSetpoint(double setpoint) {
m_controller->SetSetpoint(setpoint);
}
double PIDCommand::GetSetpoint() const { return m_controller->GetSetpoint(); }
double PIDCommand::GetPosition() { return ReturnPIDInput(); }
std::string PIDCommand::GetSmartDashboardType() const { return "PIDCommand"; }
void PIDCommand::InitTable(std::shared_ptr<ITable> table) {
m_controller->InitTable(table);
Command::InitTable(table);
}

View File

@@ -0,0 +1,225 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2011. All Rights Reserved.
*/
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include "Commands/PIDSubsystem.h"
#include "PIDController.h"
#include "float.h"
/**
* Instantiates a {@link PIDSubsystem} that will use the given p, i and d
* values.
* @param name the name
* @param p the proportional value
* @param i the integral value
* @param d the derivative value
*/
PIDSubsystem::PIDSubsystem(const std::string &name, double p, double i, double d)
: Subsystem(name) {
m_controller = std::make_shared<PIDController>(p, i, d, this, this);
}
/**
* Instantiates a {@link PIDSubsystem} that will use the given p, i and d
* values.
* @param name the name
* @param p the proportional value
* @param i the integral value
* @param d the derivative value
* @param f the feedforward value
*/
PIDSubsystem::PIDSubsystem(const std::string &name, double p, double i, double d,
double f)
: Subsystem(name) {
m_controller = std::make_shared<PIDController>(p, i, d, f, this, this);
}
/**
* Instantiates a {@link PIDSubsystem} that will use the given p, i and d
* values. It will also space the time
* between PID loop calculations to be equal to the given period.
* @param name the name
* @param p the proportional value
* @param i the integral value
* @param d the derivative value
* @param f the feedfoward value
* @param period the time (in seconds) between calculations
*/
PIDSubsystem::PIDSubsystem(const std::string &name, double p, double i, double d,
double f, double period)
: Subsystem(name) {
m_controller = std::make_shared<PIDController>(p, i, d, f, this, this, period);
}
/**
* Instantiates a {@link PIDSubsystem} that will use the given p, i and d
* values.
* It will use the class name as its name.
* @param p the proportional value
* @param i the integral value
* @param d the derivative value
*/
PIDSubsystem::PIDSubsystem(double p, double i, double d)
: Subsystem("PIDSubsystem") {
m_controller = std::make_shared<PIDController>(p, i, d, this, this);
}
/**
* Instantiates a {@link PIDSubsystem} that will use the given p, i and d
* values.
* It will use the class name as its name.
* @param p the proportional value
* @param i the integral value
* @param d the derivative value
* @param f the feedforward value
*/
PIDSubsystem::PIDSubsystem(double p, double i, double d, double f)
: Subsystem("PIDSubsystem") {
m_controller = std::make_shared<PIDController>(p, i, d, f, this, this);
}
/**
* Instantiates a {@link PIDSubsystem} that will use the given p, i and d
* values.
* It will use the class name as its name.
* It will also space the time
* between PID loop calculations to be equal to the given period.
* @param p the proportional value
* @param i the integral value
* @param d the derivative value
* @param f the feedforward value
* @param period the time (in seconds) between calculations
*/
PIDSubsystem::PIDSubsystem(double p, double i, double d, double f,
double period)
: Subsystem("PIDSubsystem") {
m_controller = std::make_shared<PIDController>(p, i, d, f, this, this, period);
}
/**
* Enables the internal {@link PIDController}
*/
void PIDSubsystem::Enable() { m_controller->Enable(); }
/**
* Disables the internal {@link PIDController}
*/
void PIDSubsystem::Disable() { m_controller->Disable(); }
/**
* Returns the {@link PIDController} used by this {@link PIDSubsystem}.
* Use this if you would like to fine tune the pid loop.
*
* @return the {@link PIDController} used by this {@link PIDSubsystem}
*/
std::shared_ptr<PIDController> PIDSubsystem::GetPIDController() {
return m_controller;
}
/**
* Sets the setpoint to the given value. If {@link PIDCommand#SetRange(double,
* double) SetRange(...)}
* was called,
* then the given setpoint
* will be trimmed to fit within the range.
* @param setpoint the new setpoint
*/
void PIDSubsystem::SetSetpoint(double setpoint) {
m_controller->SetSetpoint(setpoint);
}
/**
* Adds the given value to the setpoint.
* If {@link PIDCommand#SetRange(double, double) SetRange(...)} was used,
* then the bounds will still be honored by this method.
* @param deltaSetpoint the change in the setpoint
*/
void PIDSubsystem::SetSetpointRelative(double deltaSetpoint) {
SetSetpoint(GetSetpoint() + deltaSetpoint);
}
/**
* Return the current setpoint
* @return The current setpoint
*/
double PIDSubsystem::GetSetpoint() { return m_controller->GetSetpoint(); }
/**
* Sets the maximum and minimum values expected from the input.
*
* @param minimumInput the minimum value expected from the input
* @param maximumInput the maximum value expected from the output
*/
void PIDSubsystem::SetInputRange(float minimumInput, float maximumInput) {
m_controller->SetInputRange(minimumInput, maximumInput);
}
/**
* Sets the maximum and minimum values to write.
*
* @param minimumOutput the minimum value to write to the output
* @param maximumOutput the maximum value to write to the output
*/
void PIDSubsystem::SetOutputRange(float minimumOutput, float maximumOutput) {
m_controller->SetOutputRange(minimumOutput, maximumOutput);
}
/*
* Set the absolute error which is considered tolerable for use with
* OnTarget.
* @param percentage error which is tolerable
*/
void PIDSubsystem::SetAbsoluteTolerance(float absValue) {
m_controller->SetAbsoluteTolerance(absValue);
}
/*
* Set the percentage error which is considered tolerable for use with
* OnTarget.
* @param percentage error which is tolerable
*/
void PIDSubsystem::SetPercentTolerance(float percent) {
m_controller->SetPercentTolerance(percent);
}
/*
* Return true if the error is within the percentage of the total input range,
* determined by SetTolerance. This asssumes that the maximum and minimum input
* were set using SetInput. Use OnTarget() in the IsFinished() method of
* commands
* that use this subsystem.
*
* Currently this just reports on target as the actual value passes through the
* setpoint.
* Ideally it should be based on being within the tolerance for some period of
* time.
*
* @return true if the error is within the percentage tolerance of the input
* range
*/
bool PIDSubsystem::OnTarget() const { return m_controller->OnTarget(); }
/**
* Returns the current position
* @return the current position
*/
double PIDSubsystem::GetPosition() { return ReturnPIDInput(); }
/**
* Returns the current rate
* @return the current rate
*/
double PIDSubsystem::GetRate() { return ReturnPIDInput(); }
void PIDSubsystem::PIDWrite(float output) { UsePIDOutput(output); }
double PIDSubsystem::PIDGet() { return ReturnPIDInput(); }
std::string PIDSubsystem::GetSmartDashboardType() const { return "PIDCommand"; }
void PIDSubsystem::InitTable(std::shared_ptr<ITable> table) {
m_controller->InitTable(table);
Subsystem::InitTable(table);
}

View File

@@ -0,0 +1,28 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2011. All Rights Reserved.
*/
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include "Commands/PrintCommand.h"
#include "stdio.h"
#include <sstream>
PrintCommand::PrintCommand(const std::string &message)
: Command(((std::stringstream &)(std::stringstream("Print \"") << message
<< "\""))
.str()
.c_str()) {
m_message = message;
}
void PrintCommand::Initialize() { printf("%s", m_message.c_str()); }
void PrintCommand::Execute() {}
bool PrintCommand::IsFinished() { return true; }
void PrintCommand::End() {}
void PrintCommand::Interrupted() {}

View File

@@ -0,0 +1,273 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2011. All Rights Reserved.
*/
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include "Commands/Scheduler.h"
#include "Buttons/ButtonScheduler.h"
#include "Commands/Subsystem.h"
#include "HLUsageReporting.h"
#include "WPIErrors.h"
#include <iostream>
#include <set>
#include <algorithm>
Scheduler::Scheduler() {
HLUsageReporting::ReportScheduler();
}
/**
* Returns the {@link Scheduler}, creating it if one does not exist.
* @return the {@link Scheduler}
*/
Scheduler *Scheduler::GetInstance() {
static Scheduler instance;
return &instance;
}
void Scheduler::SetEnabled(bool enabled) { m_enabled = enabled; }
/**
* Add a command to be scheduled later.
* In any pass through the scheduler, all commands are added to the additions
* list, then
* at the end of the pass, they are all scheduled.
* @param command The command to be scheduled
*/
void Scheduler::AddCommand(Command *command) {
std::lock_guard<priority_mutex> sync(m_additionsLock);
if (std::find(m_additions.begin(), m_additions.end(), command) !=
m_additions.end())
return;
m_additions.push_back(command);
}
void Scheduler::AddButton(ButtonScheduler *button) {
std::lock_guard<priority_mutex> sync(m_buttonsLock);
m_buttons.push_back(button);
}
void Scheduler::ProcessCommandAddition(Command *command) {
if (command == nullptr) return;
// Check to make sure no adding during adding
if (m_adding) {
wpi_setWPIErrorWithContext(IncompatibleState,
"Can not start command from cancel method");
return;
}
// Only add if not already in
auto found = m_commands.find(command);
if (found == m_commands.end()) {
// Check that the requirements can be had
Command::SubsystemSet requirements = command->GetRequirements();
Command::SubsystemSet::iterator iter;
for (iter = requirements.begin(); iter != requirements.end(); iter++) {
Subsystem *lock = *iter;
if (lock->GetCurrentCommand() != nullptr &&
!lock->GetCurrentCommand()->IsInterruptible())
return;
}
// Give it the requirements
m_adding = true;
for (iter = requirements.begin(); iter != requirements.end(); iter++) {
Subsystem *lock = *iter;
if (lock->GetCurrentCommand() != nullptr) {
lock->GetCurrentCommand()->Cancel();
Remove(lock->GetCurrentCommand());
}
lock->SetCurrentCommand(command);
}
m_adding = false;
m_commands.insert(command);
command->StartRunning();
m_runningCommandsChanged = true;
}
}
/**
* Runs a single iteration of the loop. This method should be called often in
* order to have a functioning
* {@link Command} system. The loop has five stages:
*
* <ol>
* <li> Poll the Buttons </li>
* <li> Execute/Remove the Commands </li>
* <li> Send values to SmartDashboard </li>
* <li> Add Commands </li>
* <li> Add Defaults </li>
* </ol>
*/
void Scheduler::Run() {
// Get button input (going backwards preserves button priority)
{
if (!m_enabled) return;
std::lock_guard<priority_mutex> sync(m_buttonsLock);
auto rButtonIter = m_buttons.rbegin();
for (; rButtonIter != m_buttons.rend(); rButtonIter++) {
(*rButtonIter)->Execute();
}
}
m_runningCommandsChanged = false;
// Loop through the commands
auto commandIter = m_commands.begin();
for (; commandIter != m_commands.end();) {
Command *command = *commandIter;
// Increment before potentially removing to keep the iterator valid
commandIter++;
if (!command->Run()) {
Remove(command);
m_runningCommandsChanged = true;
}
}
// Add the new things
{
std::lock_guard<priority_mutex> sync(m_additionsLock);
auto additionsIter = m_additions.begin();
for (; additionsIter != m_additions.end(); additionsIter++) {
ProcessCommandAddition(*additionsIter);
}
m_additions.clear();
}
// Add in the defaults
auto subsystemIter = m_subsystems.begin();
for (; subsystemIter != m_subsystems.end(); subsystemIter++) {
Subsystem *lock = *subsystemIter;
if (lock->GetCurrentCommand() == nullptr) {
ProcessCommandAddition(lock->GetDefaultCommand());
}
lock->ConfirmCommand();
}
UpdateTable();
}
/**
* Registers a {@link Subsystem} to this {@link Scheduler}, so that the {@link
* Scheduler} might know
* if a default {@link Command} needs to be run. All {@link Subsystem
* Subsystems} should call this.
* @param system the system
*/
void Scheduler::RegisterSubsystem(Subsystem *subsystem) {
if (subsystem == nullptr) {
wpi_setWPIErrorWithContext(NullParameter, "subsystem");
return;
}
m_subsystems.insert(subsystem);
}
/**
* Removes the {@link Command} from the {@link Scheduler}.
* @param command the command to remove
*/
void Scheduler::Remove(Command *command) {
if (command == nullptr) {
wpi_setWPIErrorWithContext(NullParameter, "command");
return;
}
if (!m_commands.erase(command)) return;
Command::SubsystemSet requirements = command->GetRequirements();
auto iter = requirements.begin();
for (; iter != requirements.end(); iter++) {
Subsystem *lock = *iter;
lock->SetCurrentCommand(nullptr);
}
command->Removed();
}
void Scheduler::RemoveAll() {
while (m_commands.size() > 0) {
Remove(*m_commands.begin());
}
}
/**
* Completely resets the scheduler. Undefined behavior if running.
*/
void Scheduler::ResetAll() {
RemoveAll();
m_subsystems.clear();
m_buttons.clear();
m_additions.clear();
m_commands.clear();
m_table = nullptr;
}
/**
* Update the network tables associated with the Scheduler object on the
* SmartDashboard
*/
void Scheduler::UpdateTable() {
CommandSet::iterator commandIter;
if (m_table != nullptr) {
// Get the list of possible commands to cancel
auto new_toCancel = m_table->GetValue("Cancel");
if (new_toCancel)
toCancel = new_toCancel->GetDoubleArray();
else
toCancel.resize(0);
// m_table->RetrieveValue("Ids", *ids);
// cancel commands that have had the cancel buttons pressed
// on the SmartDashboad
if (!toCancel.empty()) {
for (commandIter = m_commands.begin(); commandIter != m_commands.end();
++commandIter) {
for (unsigned i = 0; i < toCancel.size(); i++) {
Command *c = *commandIter;
if (c->GetID() == toCancel[i]) {
c->Cancel();
}
}
}
toCancel.resize(0);
m_table->PutValue("Cancel", nt::Value::MakeDoubleArray(toCancel));
}
// Set the running commands
if (m_runningCommandsChanged) {
commands.resize(0);
ids.resize(0);
for (commandIter = m_commands.begin(); commandIter != m_commands.end();
++commandIter) {
Command *c = *commandIter;
commands.push_back(c->GetName());
ids.push_back(c->GetID());
}
m_table->PutValue("Names", nt::Value::MakeStringArray(commands));
m_table->PutValue("Ids", nt::Value::MakeDoubleArray(ids));
}
}
}
std::string Scheduler::GetName() const { return "Scheduler"; }
std::string Scheduler::GetType() const { return "Scheduler"; }
std::string Scheduler::GetSmartDashboardType() const { return "Scheduler"; }
void Scheduler::InitTable(std::shared_ptr<ITable> subTable) {
m_table = subTable;
m_table->PutValue("Names", nt::Value::MakeStringArray(commands));
m_table->PutValue("Ids", nt::Value::MakeDoubleArray(ids));
m_table->PutValue("Cancel", nt::Value::MakeDoubleArray(toCancel));
}
std::shared_ptr<ITable> Scheduler::GetTable() const { return m_table; }

View File

@@ -0,0 +1,22 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2011. All Rights Reserved.
*/
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include "Commands/StartCommand.h"
StartCommand::StartCommand(Command *commandToStart) : Command("StartCommand") {
m_commandToFork = commandToStart;
}
void StartCommand::Initialize() { m_commandToFork->Start(); }
void StartCommand::Execute() {}
void StartCommand::End() {}
void StartCommand::Interrupted() {}
bool StartCommand::IsFinished() { return true; }

View File

@@ -0,0 +1,147 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2011. All Rights Reserved.
*/
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include "Commands/Subsystem.h"
#include "Commands/Command.h"
#include "Commands/Scheduler.h"
#include "WPIErrors.h"
/**
* Creates a subsystem with the given name
* @param name the name of the subsystem
*/
Subsystem::Subsystem(const std::string &name) {
m_name = name;
Scheduler::GetInstance()->RegisterSubsystem(this);
}
/**
* Initialize the default command for this subsystem
* This is meant to be the place to call SetDefaultCommand in a subsystem and
* will be called
* on all the subsystems by the CommandBase method before the program starts
* running by using
* the list of all registered Subsystems inside the Scheduler.
*
* This should be overridden by a Subsystem that has a default Command
*/
void Subsystem::InitDefaultCommand() {}
/**
* Sets the default command. If this is not called or is called with null,
* then there will be no default command for the subsystem.
*
* <p><b>WARNING:</b> This should <b>NOT</b> be called in a constructor if the
* subsystem is a
* singleton.</p>
*
* @param command the default command (or null if there should be none)
*/
void Subsystem::SetDefaultCommand(Command *command) {
if (command == nullptr) {
m_defaultCommand = nullptr;
} else {
bool found = false;
Command::SubsystemSet requirements = command->GetRequirements();
auto iter = requirements.begin();
for (; iter != requirements.end(); iter++) {
if (*iter == this) {
found = true;
break;
}
}
if (!found) {
wpi_setWPIErrorWithContext(
CommandIllegalUse, "A default command must require the subsystem");
return;
}
m_defaultCommand = command;
}
if (m_table != nullptr) {
if (m_defaultCommand != nullptr) {
m_table->PutBoolean("hasDefault", true);
m_table->PutString("default", m_defaultCommand->GetName());
} else {
m_table->PutBoolean("hasDefault", false);
}
}
}
/**
* Returns the default command (or null if there is none).
* @return the default command
*/
Command *Subsystem::GetDefaultCommand() {
if (!m_initializedDefaultCommand) {
m_initializedDefaultCommand = true;
InitDefaultCommand();
}
return m_defaultCommand;
}
/**
* Sets the current command
* @param command the new current command
*/
void Subsystem::SetCurrentCommand(Command *command) {
m_currentCommand = command;
m_currentCommandChanged = true;
}
/**
* Returns the command which currently claims this subsystem.
* @return the command which currently claims this subsystem
*/
Command *Subsystem::GetCurrentCommand() const { return m_currentCommand; }
/**
* Call this to alert Subsystem that the current command is actually the
* command.
* Sometimes, the {@link Subsystem} is told that it has no command while the
* {@link Scheduler}
* is going through the loop, only to be soon after given a new one. This will
* avoid that situation.
*/
void Subsystem::ConfirmCommand() {
if (m_currentCommandChanged) {
if (m_table != nullptr) {
if (m_currentCommand != nullptr) {
m_table->PutBoolean("hasCommand", true);
m_table->PutString("command", m_currentCommand->GetName());
} else {
m_table->PutBoolean("hasCommand", false);
}
}
m_currentCommandChanged = false;
}
}
std::string Subsystem::GetName() const { return m_name; }
std::string Subsystem::GetSmartDashboardType() const { return "Subsystem"; }
void Subsystem::InitTable(std::shared_ptr<ITable> table) {
m_table = table;
if (m_table != nullptr) {
if (m_defaultCommand != nullptr) {
m_table->PutBoolean("hasDefault", true);
m_table->PutString("default", m_defaultCommand->GetName());
} else {
m_table->PutBoolean("hasDefault", false);
}
if (m_currentCommand != nullptr) {
m_table->PutBoolean("hasCommand", true);
m_table->PutString("command", m_currentCommand->GetName());
} else {
m_table->PutBoolean("hasCommand", false);
}
}
}
std::shared_ptr<ITable> Subsystem::GetTable() const { return m_table; }

View File

@@ -0,0 +1,29 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2011. All Rights Reserved.
*/
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include "Commands/WaitCommand.h"
#include <sstream>
WaitCommand::WaitCommand(double timeout)
: Command(
((std::stringstream &)(std::stringstream("Wait(") << timeout << ")"))
.str()
.c_str(),
timeout) {}
WaitCommand::WaitCommand(const std::string &name, double timeout)
: Command(name, timeout) {}
void WaitCommand::Initialize() {}
void WaitCommand::Execute() {}
bool WaitCommand::IsFinished() { return IsTimedOut(); }
void WaitCommand::End() {}
void WaitCommand::Interrupted() {}

View File

@@ -0,0 +1,27 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2011. All Rights Reserved.
*/
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include "Commands/WaitForChildren.h"
#include "Commands/CommandGroup.h"
WaitForChildren::WaitForChildren(double timeout)
: Command("WaitForChildren", timeout) {}
WaitForChildren::WaitForChildren(const std::string &name, double timeout)
: Command(name, timeout) {}
void WaitForChildren::Initialize() {}
void WaitForChildren::Execute() {}
void WaitForChildren::End() {}
void WaitForChildren::Interrupted() {}
bool WaitForChildren::IsFinished() {
return GetGroup() == nullptr || GetGroup()->GetSize() == 0;
}

View File

@@ -0,0 +1,38 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2011. All Rights Reserved.
*/
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include "Commands/WaitUntilCommand.h"
#include "Timer.h"
/**
* A {@link WaitCommand} will wait until a certain match time before finishing.
* This will wait until the game clock reaches some value, then continue to the
* next command.
* @see CommandGroup
*/
WaitUntilCommand::WaitUntilCommand(double time)
: Command("WaitUntilCommand", time) {
m_time = time;
}
WaitUntilCommand::WaitUntilCommand(const std::string &name, double time)
: Command(name, time) {
m_time = time;
}
void WaitUntilCommand::Initialize() {}
void WaitUntilCommand::Execute() {}
/**
* Check if we've reached the actual finish time.
*/
bool WaitUntilCommand::IsFinished() { return Timer::GetMatchTime() >= m_time; }
void WaitUntilCommand::End() {}
void WaitUntilCommand::Interrupted() {}

View File

@@ -0,0 +1,97 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008. All Rights Reserved.
*/
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include "Error.h"
#include <iostream>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <stdint.h>
#include "DriverStation.h"
#include "Timer.h"
#include "Utility.h"
void Error::Clone(const Error& error) {
m_code = error.m_code;
m_message = error.m_message;
m_filename = error.m_filename;
m_function = error.m_function;
m_lineNumber = error.m_lineNumber;
m_originatingObject = error.m_originatingObject;
m_timestamp = error.m_timestamp;
}
Error::Code Error::GetCode() const { return m_code; }
std::string Error::GetMessage() const { return m_message; }
std::string Error::GetFilename() const { return m_filename; }
std::string Error::GetFunction() const { return m_function; }
uint32_t Error::GetLineNumber() const { return m_lineNumber; }
const ErrorBase* Error::GetOriginatingObject() const {
return m_originatingObject;
}
double Error::GetTimestamp() const { return m_timestamp; }
void Error::Set(Code code, const std::string& contextMessage,
const std::string& filename, const std::string& function,
uint32_t lineNumber, const ErrorBase* originatingObject) {
bool report = true;
if (code == m_code && GetTime() - m_timestamp < 1) {
report = false;
}
m_code = code;
m_message = contextMessage;
m_filename = filename;
m_function = function;
m_lineNumber = lineNumber;
m_originatingObject = originatingObject;
if (report) {
m_timestamp = GetTime();
Report();
}
}
void Error::Report() {
std::stringstream errorStream;
errorStream << "Error on line " << m_lineNumber << " ";
#if defined(_UNIX)
errorStream << "of " << basename(m_filename.c_str()) << ": ";
#elif defined(_WIN32)
const int MAX_DIR = 100;
char basename[MAX_DIR];
_splitpath_s(m_filename.c_str(), NULL, 0, basename, MAX_DIR, NULL, 0, NULL, 0);
errorStream << "of " << basename << ": ";
#endif
errorStream << m_message << std::endl;
errorStream << GetStackTrace(4);
std::string error = errorStream.str();
DriverStation::ReportError(error);
}
void Error::Clear() {
m_code = 0;
m_message = "";
m_filename = "";
m_function = "";
m_lineNumber = 0;
m_originatingObject = nullptr;
m_timestamp = 0.0;
}

View File

@@ -0,0 +1,195 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008. All Rights Reserved.
*/
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include "ErrorBase.h"
#define WPI_ERRORS_DEFINE_STRINGS
#include "WPIErrors.h"
#include <errno.h>
#include <cstring>
#include <cstdio>
#include <sstream>
priority_mutex ErrorBase::_globalErrorMutex;
Error ErrorBase::_globalError;
/**
* @brief Retrieve the current error.
* Get the current error information associated with this sensor.
*/
Error& ErrorBase::GetError() { return m_error; }
const Error& ErrorBase::GetError() const { return m_error; }
/**
* @brief Clear the current error information associated with this sensor.
*/
void ErrorBase::ClearError() const { m_error.Clear(); }
/**
* @brief Set error information associated with a C library call that set an
* error to the "errno" global variable.
*
* @param contextMessage A custom message from the code that set the error.
* @param filename Filename of the error source
* @param function Function of the error source
* @param lineNumber Line number of the error source
*/
void ErrorBase::SetErrnoError(const std::string& contextMessage,
const std::string& filename,
const std::string& function,
uint32_t lineNumber) const {
std::string err;
int errNo = errno;
if (errNo == 0) {
err = "OK: " + contextMessage;
} else {
char buf[256];
snprintf(buf, 256, "%s (0x%08X): %s", strerror(errNo), errNo,
contextMessage.c_str());
err = buf;
}
// Set the current error information for this object.
m_error.Set(-1, err, filename, function, lineNumber, this);
// Update the global error if there is not one already set.
std::lock_guard<priority_mutex> mutex(_globalErrorMutex);
if (_globalError.GetCode() == 0) {
_globalError.Clone(m_error);
}
}
/**
* @brief Set the current error information associated from the nivision Imaq
* API.
*
* @param success The return from the function
* @param contextMessage A custom message from the code that set the error.
* @param filename Filename of the error source
* @param function Function of the error source
* @param lineNumber Line number of the error source
*/
void ErrorBase::SetImaqError(int success, const std::string& contextMessage,
const std::string& filename,
const std::string& function,
uint32_t lineNumber) const {
// If there was an error
if (success <= 0) {
std::stringstream err;
err << success << ": " << contextMessage;
// Set the current error information for this object.
m_error.Set(success, err.str(), filename, function, lineNumber, this);
// Update the global error if there is not one already set.
std::lock_guard<priority_mutex> mutex(_globalErrorMutex);
if (_globalError.GetCode() == 0) {
_globalError.Clone(m_error);
}
}
}
/**
* @brief Set the current error information associated with this sensor.
*
* @param code The error code
* @param contextMessage A custom message from the code that set the error.
* @param filename Filename of the error source
* @param function Function of the error source
* @param lineNumber Line number of the error source
*/
void ErrorBase::SetError(Error::Code code, const std::string& contextMessage,
const std::string& filename,
const std::string& function,
uint32_t lineNumber) const {
// If there was an error
if (code != 0) {
// Set the current error information for this object.
m_error.Set(code, contextMessage, filename, function, lineNumber, this);
// Update the global error if there is not one already set.
std::lock_guard<priority_mutex> mutex(_globalErrorMutex);
if (_globalError.GetCode() == 0) {
_globalError.Clone(m_error);
}
}
}
/**
* @brief Set the current error information associated with this sensor.
*
* @param errorMessage The error message from WPIErrors.h
* @param contextMessage A custom message from the code that set the error.
* @param filename Filename of the error source
* @param function Function of the error source
* @param lineNumber Line number of the error source
*/
void ErrorBase::SetWPIError(const std::string& errorMessage, Error::Code code,
const std::string& contextMessage,
const std::string& filename,
const std::string& function,
uint32_t lineNumber) const {
std::string err = errorMessage + ": " + contextMessage;
// Set the current error information for this object.
m_error.Set(code, err, filename, function, lineNumber, this);
// Update the global error if there is not one already set.
std::lock_guard<priority_mutex> mutex(_globalErrorMutex);
if (_globalError.GetCode() == 0) {
_globalError.Clone(m_error);
}
}
void ErrorBase::CloneError(const ErrorBase& rhs) const {
m_error.Clone(rhs.GetError());
}
/**
@brief Check if the current error code represents a fatal error.
@return true if the current error is fatal.
*/
bool ErrorBase::StatusIsFatal() const { return m_error.GetCode() < 0; }
void ErrorBase::SetGlobalError(Error::Code code,
const std::string& contextMessage,
const std::string& filename,
const std::string& function,
uint32_t lineNumber) {
// If there was an error
if (code != 0) {
std::lock_guard<priority_mutex> mutex(_globalErrorMutex);
// Set the current error information for this object.
_globalError.Set(code, contextMessage, filename, function, lineNumber,
nullptr);
}
}
void ErrorBase::SetGlobalWPIError(const std::string& errorMessage,
const std::string& contextMessage,
const std::string& filename,
const std::string& function,
uint32_t lineNumber) {
std::string err = errorMessage + ": " + contextMessage;
std::lock_guard<priority_mutex> mutex(_globalErrorMutex);
if (_globalError.GetCode() != 0) {
_globalError.Clear();
}
_globalError.Set(-1, err, filename, function, lineNumber, nullptr);
}
/**
* Retrieve the current global error.
*/
Error& ErrorBase::GetGlobalError() {
std::lock_guard<priority_mutex> mutex(_globalErrorMutex);
return _globalError;
}

View File

@@ -0,0 +1,20 @@
#include "HLUsageReporting.h"
HLUsageReportingInterface* HLUsageReporting::impl = nullptr;
void HLUsageReporting::SetImplementation(HLUsageReportingInterface* i) {
impl = i;
}
void HLUsageReporting::ReportScheduler() {
if (impl != nullptr) {
impl->ReportScheduler();
}
}
void HLUsageReporting::ReportSmartDashboard() {
if (impl != nullptr) {
impl->ReportSmartDashboard();
}
}

View File

@@ -0,0 +1,227 @@
#include "LiveWindow/LiveWindow.h"
#include "networktables/NetworkTable.h"
#include <algorithm>
#include <sstream>
/**
* Get an instance of the LiveWindow main class
* This is a singleton to guarantee that there is only a single instance
* regardless of
* how many times GetInstance is called.
*/
LiveWindow *LiveWindow::GetInstance() {
static LiveWindow instance;
return &instance;
}
/**
* LiveWindow constructor.
* Allocate the necessary tables.
*/
LiveWindow::LiveWindow() : m_scheduler(Scheduler::GetInstance()) {
m_liveWindowTable = NetworkTable::GetTable("LiveWindow");
m_statusTable = m_liveWindowTable->GetSubTable("~STATUS~");
}
/**
* Change the enabled status of LiveWindow
* If it changes to enabled, start livewindow running otherwise stop it
*/
void LiveWindow::SetEnabled(bool enabled) {
if (m_enabled == enabled) return;
if (enabled) {
if (m_firstTime) {
InitializeLiveWindowComponents();
m_firstTime = false;
}
m_scheduler->SetEnabled(false);
m_scheduler->RemoveAll();
for (auto& elem : m_components) {
elem.first->StartLiveWindowMode();
}
} else {
for (auto& elem : m_components) {
elem.first->StopLiveWindowMode();
}
m_scheduler->SetEnabled(true);
}
m_enabled = enabled;
m_statusTable->PutBoolean("LW Enabled", m_enabled);
}
/**
* @name AddSensor(subsystem, name, component)
* Add a Sensor associated with the subsystem and call it by the given name.
* @param subsystem The subsystem this component is part of.
* @param name The name of this component.
* @param component A LiveWindowSendable component that represents a sensor.
*/
//@{
/**
* @brief Use a STL smart pointer to share ownership of component.
*/
void LiveWindow::AddSensor(const std::string &subsystem, const std::string &name,
std::shared_ptr<LiveWindowSendable> component) {
m_components[component].subsystem = subsystem;
m_components[component].name = name;
m_components[component].isSensor = true;
}
/**
* @brief Pass a reference to LiveWindow and retain ownership of the component.
*/
void LiveWindow::AddSensor(const std::string &subsystem,
const std::string &name,
LiveWindowSendable &component) {
AddSensor(subsystem, name, std::shared_ptr<LiveWindowSendable>(
&component, [](LiveWindowSendable*){}));
}
/**
* @brief Use a raw pointer to the LiveWindow.
* @deprecated Prefer smart pointers or references.
*/
void LiveWindow::AddSensor(const std::string &subsystem,
const std::string &name,
LiveWindowSendable *component) {
AddSensor(subsystem, name, std::shared_ptr<LiveWindowSendable>(
component, NullDeleter<LiveWindowSendable>()));
}
//@}
/**
* @name AddActuator(subsystem, name, component)
* Add an Actuator associated with the subsystem and call it by the given name.
* @param subsystem The subsystem this component is part of.
* @param name The name of this component.
* @param component A LiveWindowSendable component that represents a actuator.
*/
//@{
/**
* @brief Use a STL smart pointer to share ownership of component.
*/
void LiveWindow::AddActuator(const std::string &subsystem, const std::string &name,
std::shared_ptr<LiveWindowSendable> component) {
m_components[component].subsystem = subsystem;
m_components[component].name = name;
m_components[component].isSensor = false;
}
/**
* @brief Pass a reference to LiveWindow and retain ownership of the component.
*/
void LiveWindow::AddActuator(const std::string &subsystem,
const std::string &name,
LiveWindowSendable &component) {
AddActuator(subsystem, name, std::shared_ptr<LiveWindowSendable>(
&component, [](LiveWindowSendable*){}));
}
/**
* @brief Use a raw pointer to the LiveWindow.
* @deprecated Prefer smart pointers or references.
*/
void LiveWindow::AddActuator(const std::string &subsystem, const std::string &name,
LiveWindowSendable *component) {
AddActuator(subsystem, name,
std::shared_ptr<LiveWindowSendable>(
component, NullDeleter<LiveWindowSendable>()));
}
//@}
/**
* Meant for internal use in other WPILib classes.
*/
void LiveWindow::AddSensor(std::string type, int channel,
LiveWindowSendable *component) {
std::ostringstream oss;
oss << type << "[" << channel << "]";
std::string types(oss.str());
auto cc = new char[types.size() + 1];
types.copy(cc, types.size());
cc[types.size()] = '\0';
AddSensor("Ungrouped", cc, component);
std::shared_ptr<LiveWindowSendable> component_stl(
component, NullDeleter<LiveWindowSendable>());
if (std::find(m_sensors.begin(), m_sensors.end(), component_stl) ==
m_sensors.end())
m_sensors.push_back(component_stl);
}
/**
* Meant for internal use in other WPILib classes.
*/
void LiveWindow::AddActuator(std::string type, int channel,
LiveWindowSendable *component) {
std::ostringstream oss;
oss << type << "[" << channel << "]";
std::string types(oss.str());
auto cc = new char[types.size() + 1];
types.copy(cc, types.size());
cc[types.size()] = '\0';
AddActuator("Ungrouped", cc, std::shared_ptr<LiveWindowSendable>(
component, [](LiveWindowSendable *) {}));
}
/**
* Meant for internal use in other WPILib classes.
*/
void LiveWindow::AddActuator(std::string type, int module, int channel,
LiveWindowSendable *component) {
std::ostringstream oss;
oss << type << "[" << module << "," << channel << "]";
std::string types(oss.str());
auto cc = new char[types.size() + 1];
types.copy(cc, types.size());
cc[types.size()] = '\0';
AddActuator("Ungrouped", cc, std::shared_ptr<LiveWindowSendable>(
component, [](LiveWindowSendable *) {}));
}
/**
* Tell all the sensors to update (send) their values
* Actuators are handled through callbacks on their value changing from the
* SmartDashboard widgets.
*/
void LiveWindow::UpdateValues() {
for (auto& elem : m_sensors) {
elem->UpdateTable();
}
}
/**
* This method is called periodically to cause the sensors to send new values
* to the SmartDashboard.
*/
void LiveWindow::Run() {
if (m_enabled) {
UpdateValues();
}
}
/**
* Initialize all the LiveWindow elements the first time we enter LiveWindow
* mode. By holding off creating the NetworkTable entries, it allows them to be
* redefined before the first time in LiveWindow mode. This allows default
* sensor and actuator values to be created that are replaced with the custom
* names from users calling addActuator and addSensor.
*/
void LiveWindow::InitializeLiveWindowComponents() {
for (auto& elem : m_components) {
std::shared_ptr<LiveWindowSendable> component = elem.first;
LiveWindowComponent c = elem.second;
std::string subsystem = c.subsystem;
std::string name = c.name;
m_liveWindowTable->GetSubTable(subsystem)
->PutString("~TYPE~", "LW Subsystem");
std::shared_ptr<ITable> table(
m_liveWindowTable->GetSubTable(subsystem)->GetSubTable(name));
table->PutString("~TYPE~", component->GetSmartDashboardType());
table->PutString("Name", name);
table->PutString("Subsystem", subsystem);
component->InitTable(table);
if (c.isSensor) {
m_sensors.push_back(component);
}
}
}

View File

@@ -0,0 +1,6 @@
#include "LiveWindow/LiveWindowStatusListener.h"
#include "Commands/Scheduler.h"
void LiveWindowStatusListener::ValueChanged(ITable *source, llvm::StringRef key,
std::shared_ptr<nt::Value> value,
bool isNew) {}

View File

@@ -0,0 +1,21 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008. All Rights Reserved.
*/
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include "PIDSource.h"
/**
* Set which parameter you are using as a process control variable.
*
* @param pidSource An enum to select the parameter.
*/
void PIDSource::SetPIDSourceType(PIDSourceType pidSource) {
m_pidSource = pidSource;
}
PIDSourceType PIDSource::GetPIDSourceType() const {
return m_pidSource;
}

View File

@@ -0,0 +1,101 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008. All Rights Reserved.
*/
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include "Resource.h"
#include "WPIErrors.h"
#include "ErrorBase.h"
priority_recursive_mutex Resource::m_createLock;
/**
* Allocate storage for a new instance of Resource.
* Allocate a bool array of values that will get initialized to indicate that no
* resources
* have been allocated yet. The indicies of the resources are [0 .. elements -
* 1].
*/
Resource::Resource(uint32_t elements) {
std::lock_guard<priority_recursive_mutex> sync(m_createLock);
m_isAllocated = std::vector<bool>(elements, false);
}
/**
* Factory method to create a Resource allocation-tracker *if* needed.
*
* @param r -- address of the caller's Resource pointer. If *r == nullptr, this
* will construct a Resource and make *r point to it. If *r != nullptr, i.e.
* the caller already has a Resource instance, this won't do anything.
* @param elements -- the number of elements for this Resource allocator to
* track, that is, it will allocate resource numbers in the range
* [0 .. elements - 1].
*/
/*static*/ void Resource::CreateResourceObject(std::unique_ptr<Resource>& r,
uint32_t elements) {
std::lock_guard<priority_recursive_mutex> sync(m_createLock);
if (!r) {
r = std::make_unique<Resource>(elements);
}
}
/**
* Allocate a resource.
* When a resource is requested, mark it allocated. In this case, a free
* resource value
* within the range is located and returned after it is marked allocated.
*/
uint32_t Resource::Allocate(const std::string &resourceDesc) {
std::lock_guard<priority_recursive_mutex> sync(m_allocateLock);
for (uint32_t i = 0; i < m_isAllocated.size(); i++) {
if (!m_isAllocated[i]) {
m_isAllocated[i] = true;
return i;
}
}
wpi_setWPIErrorWithContext(NoAvailableResources, resourceDesc);
return std::numeric_limits<uint32_t>::max();
}
/**
* Allocate a specific resource value.
* The user requests a specific resource value, i.e. channel number and it is
* verified
* unallocated, then returned.
*/
uint32_t Resource::Allocate(uint32_t index, const std::string &resourceDesc) {
std::lock_guard<priority_recursive_mutex> sync(m_allocateLock);
if (index >= m_isAllocated.size()) {
wpi_setWPIErrorWithContext(ChannelIndexOutOfRange, resourceDesc);
return std::numeric_limits<uint32_t>::max();
}
if (m_isAllocated[index]) {
wpi_setWPIErrorWithContext(ResourceAlreadyAllocated, resourceDesc);
return std::numeric_limits<uint32_t>::max();
}
m_isAllocated[index] = true;
return index;
}
/**
* Free an allocated resource.
* After a resource is no longer needed, for example a destructor is called for
* a channel assignment
* class, Free will release the resource value so it can be reused somewhere
* else in the program.
*/
void Resource::Free(uint32_t index) {
std::unique_lock<priority_recursive_mutex> sync(m_allocateLock);
if (index == std::numeric_limits<uint32_t>::max()) return;
if (index >= m_isAllocated.size()) {
wpi_setWPIError(NotAllocated);
return;
}
if (!m_isAllocated[index]) {
wpi_setWPIError(NotAllocated);
return;
}
m_isAllocated[index] = false;
}

View File

@@ -0,0 +1,50 @@
#include "RobotState.h"
#include "Base.h"
std::shared_ptr<RobotStateInterface> RobotState::impl = nullptr;
void RobotState::SetImplementation(RobotStateInterface& i) {
impl = std::shared_ptr<RobotStateInterface>(
&i, NullDeleter<RobotStateInterface>());
}
void RobotState::SetImplementation(
std::shared_ptr<RobotStateInterface> i) {
impl = i;
}
bool RobotState::IsDisabled() {
if (impl != nullptr) {
return impl->IsDisabled();
}
return true;
}
bool RobotState::IsEnabled() {
if (impl != nullptr) {
return impl->IsEnabled();
}
return false;
}
bool RobotState::IsOperatorControl() {
if (impl != nullptr) {
return impl->IsOperatorControl();
}
return true;
}
bool RobotState::IsAutonomous() {
if (impl != nullptr) {
return impl->IsAutonomous();
}
return false;
}
bool RobotState::IsTest() {
if (impl != nullptr) {
return impl->IsTest();
}
return false;
}

View File

@@ -0,0 +1,72 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2011. All Rights Reserved.
*/
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include "SmartDashboard/SendableChooser.h"
#include <stdio.h>
static const std::string kDefault = "default";
static const std::string kOptions = "options";
static const std::string kSelected = "selected";
/**
* Adds the given object to the list of options. On the {@link SmartDashboard}
* on the desktop,
* the object will appear as the given name.
* @param name the name of the option
* @param object the option
*/
void SendableChooser::AddObject(const std::string &name, void *object) {
m_choices[name] = object;
}
/**
* Add the given object to the list of options and marks it as the default.
* Functionally, this is very close to {@link SendableChooser#AddObject(const
* char *name, void *object) AddObject(...)}
* except that it will use this as the default option if none other is
* explicitly selected.
* @param name the name of the option
* @param object the option
*/
void SendableChooser::AddDefault(const std::string &name, void *object) {
m_defaultChoice = name;
AddObject(name, object);
}
/**
* Returns the selected option. If there is none selected, it will return the
* default. If there is none selected
* and no default, then it will return {@code nullptr}.
* @return the option selected
*/
void *SendableChooser::GetSelected() {
std::string selected = m_table->GetString(kSelected, m_defaultChoice);
if (selected == "")
return nullptr;
else
return m_choices[selected];
}
void SendableChooser::InitTable(std::shared_ptr<ITable> subtable) {
std::vector<std::string> keys;
m_table = subtable;
if (m_table != nullptr) {
std::map<std::string, void *>::iterator iter;
for (iter = m_choices.begin(); iter != m_choices.end(); iter++) {
keys.push_back(iter->first);
}
m_table->PutValue(kOptions, nt::Value::MakeStringArray(std::move(keys)));
m_table->PutString(kDefault, m_defaultChoice);
}
}
std::shared_ptr<ITable> SendableChooser::GetTable() const { return m_table; }
std::string SendableChooser::GetSmartDashboardType() const {
return "String Chooser";
}

View File

@@ -0,0 +1,165 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2011. All Rights Reserved.
*/
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include "SmartDashboard/SmartDashboard.h"
//#include "NetworkCommunication/UsageReporting.h"
#include "SmartDashboard/NamedSendable.h"
#include "WPIErrors.h"
#include "networktables/NetworkTable.h"
#include "HLUsageReporting.h"
std::shared_ptr<ITable> SmartDashboard::m_table = nullptr;
std::map<std::shared_ptr<ITable> , Sendable *> SmartDashboard::m_tablesToData;
void SmartDashboard::init() {
m_table = NetworkTable::GetTable("SmartDashboard");
HLUsageReporting::ReportSmartDashboard();
}
/**
* Maps the specified key to the specified value in this table.
* The key can not be nullptr.
* The value can be retrieved by calling the get method with a key that is equal
* to the original key.
* @param keyName the key
* @param value the value
*/
void SmartDashboard::PutData(llvm::StringRef key, Sendable *data) {
if (data == nullptr) {
wpi_setGlobalWPIErrorWithContext(NullParameter, "value");
return;
}
std::shared_ptr<ITable> dataTable(m_table->GetSubTable(key));
dataTable->PutString("~TYPE~", data->GetSmartDashboardType());
data->InitTable(dataTable);
m_tablesToData[dataTable] = data;
}
/**
* Maps the specified key (where the key is the name of the {@link
* SmartDashboardNamedData}
* to the specified value in this table.
* The value can be retrieved by calling the get method with a key that is equal
* to the original key.
* @param value the value
*/
void SmartDashboard::PutData(NamedSendable *value) {
if (value == nullptr) {
wpi_setGlobalWPIErrorWithContext(NullParameter, "value");
return;
}
PutData(value->GetName(), value);
}
/**
* Returns the value at the specified key.
* @param keyName the key
* @return the value
*/
Sendable *SmartDashboard::GetData(llvm::StringRef key) {
std::shared_ptr<ITable> subtable(m_table->GetSubTable(key));
Sendable *data = m_tablesToData[subtable];
if (data == nullptr) {
wpi_setGlobalWPIErrorWithContext(SmartDashboardMissingKey, key);
return nullptr;
}
return data;
}
/**
* Maps the specified key to the specified complex value (such as an array) in
* this table.
* The key can not be nullptr.
* The value can be retrieved by calling the RetrieveValue method with a key
* that is equal to the original key.
* @param keyName the key
* @param value the value
*/
void SmartDashboard::PutValue(llvm::StringRef keyName,
std::shared_ptr<nt::Value> value) {
m_table->PutValue(keyName, value);
}
/**
* Retrieves the complex value (such as an array) in this table into the complex
* data object
* The key can not be nullptr.
* @param keyName the key
* @param value the object to retrieve the value into
*/
std::shared_ptr<nt::Value> SmartDashboard::GetValue(llvm::StringRef keyName) {
return m_table->GetValue(keyName);
}
/**
* Maps the specified key to the specified value in this table.
* The key can not be nullptr.
* The value can be retrieved by calling the get method with a key that is equal
* to the original key.
* @param keyName the key
* @param value the value
*/
void SmartDashboard::PutBoolean(llvm::StringRef keyName, bool value) {
m_table->PutBoolean(keyName, value);
}
/**
* Returns the value at the specified key. If the key is not found, returns the
* default value.
* @param keyName the key
* @return the value
*/
bool SmartDashboard::GetBoolean(llvm::StringRef keyName, bool defaultValue) {
return m_table->GetBoolean(keyName, defaultValue);
}
/**
* Maps the specified key to the specified value in this table.
* The key can not be nullptr.
* The value can be retrieved by calling the get method with a key that is equal
* to the original key.
* @param keyName the key
* @param value the value
*/
void SmartDashboard::PutNumber(llvm::StringRef keyName, double value) {
m_table->PutNumber(keyName, value);
}
/**
* Returns the value at the specified key. If the key is not found, returns the
* default value.
* @param keyName the key
* @return the value
*/
double SmartDashboard::GetNumber(llvm::StringRef keyName, double defaultValue) {
return m_table->GetNumber(keyName, defaultValue);
}
/**
* Maps the specified key to the specified value in this table.
* Neither the key nor the value can be nullptr.
* The value can be retrieved by calling the get method with a key that is equal
* to the original key.
* @param keyName the key
* @param value the value
*/
void SmartDashboard::PutString(llvm::StringRef keyName, llvm::StringRef value) {
m_table->PutString(keyName, value);
}
/**
* Returns the value at the specified key. If the key is not found, returns the
* default value.
* @param keyName the key
* @return the value
*/
std::string SmartDashboard::GetString(llvm::StringRef keyName,
llvm::StringRef defaultValue) {
return m_table->GetString(keyName, defaultValue);
}

View File

@@ -0,0 +1,15 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2015. All Rights Reserved.
*/
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include <interfaces/Potentiometer.h>
#include <Utility.h>
void Potentiometer::SetPIDSourceType(PIDSourceType pidSource) {
if (wpi_assert(pidSource == PIDSourceType::kDisplacement)) {
m_pidSource = pidSource;
}
}