diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/CommandScheduler.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/CommandScheduler.java
index e286a74229..84850a03b4 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/CommandScheduler.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/CommandScheduler.java
@@ -158,7 +158,7 @@ public final class CommandScheduler implements NTSendable, AutoCloseable {
*/
@Deprecated(since = "2023")
public void addButton(Runnable button) {
- m_activeButtonLoop.bind(() -> true, requireNonNullParam(button, "button", "addButton"));
+ m_activeButtonLoop.bind(requireNonNullParam(button, "button", "addButton"));
}
/**
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/Button.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/Button.java
index 60917d049f..4e748ced32 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/Button.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/Button.java
@@ -159,8 +159,7 @@ public class Button extends Trigger {
*
* @param command the command to start
* @return this button, so calls can be chained
- * @deprecated Instead, pass {@link #rising()} as an end condition to {@link
- * Command#until(BooleanSupplier)}.
+ * @deprecated Instead, pass this as an end condition to {@link Command#until(BooleanSupplier)}.
*/
@Deprecated
public Button cancelWhenPressed(final Command command) {
diff --git a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/Trigger.java b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/Trigger.java
index 3513ab6c1a..e3e0e224a2 100644
--- a/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/Trigger.java
+++ b/wpilibNewCommands/src/main/java/edu/wpi/first/wpilibj2/command/button/Trigger.java
@@ -13,7 +13,6 @@ import edu.wpi.first.wpilibj2.command.Command;
import edu.wpi.first.wpilibj2.command.CommandScheduler;
import edu.wpi.first.wpilibj2.command.InstantCommand;
import edu.wpi.first.wpilibj2.command.Subsystem;
-import java.util.function.BiFunction;
import java.util.function.BooleanSupplier;
/**
@@ -28,7 +27,8 @@ import java.util.function.BooleanSupplier;
*
This class is provided by the NewCommands VendorDep
*/
public class Trigger implements BooleanSupplier {
- private final BooleanEvent m_event;
+ private final BooleanSupplier m_condition;
+ private final EventLoop m_loop;
/**
* Creates a new trigger based on the given condition.
@@ -37,18 +37,8 @@ public class Trigger implements BooleanSupplier {
* @param condition the condition represented by this trigger
*/
public Trigger(EventLoop loop, BooleanSupplier condition) {
- m_event = new BooleanEvent(loop, condition);
- }
-
- /**
- * Copies the BooleanEvent into a Trigger object.
- *
- * @param toCast the BooleanEvent
- * @return a Trigger wrapping the given BooleanEvent
- * @see BooleanEvent#castTo(BiFunction)
- */
- public static Trigger cast(BooleanEvent toCast) {
- return toCast.castTo(Trigger::new);
+ m_loop = requireNonNullParam(loop, "loop", "Trigger");
+ m_condition = requireNonNullParam(condition, "condition", "Trigger");
}
/**
@@ -73,11 +63,24 @@ public class Trigger implements BooleanSupplier {
*
* @param command the command to start
* @return this trigger, so calls can be chained
- * @see #rising()
*/
public Trigger onTrue(Command command) {
requireNonNullParam(command, "command", "onRising");
- m_event.rising().ifHigh(command::schedule);
+ m_loop.bind(
+ new Runnable() {
+ private boolean m_pressedLast = m_condition.getAsBoolean();
+
+ @Override
+ public void run() {
+ boolean pressed = m_condition.getAsBoolean();
+
+ if (!m_pressedLast && pressed) {
+ command.schedule();
+ }
+
+ m_pressedLast = pressed;
+ }
+ });
return this;
}
@@ -86,11 +89,24 @@ public class Trigger implements BooleanSupplier {
*
* @param command the command to start
* @return this trigger, so calls can be chained
- * @see #falling()
*/
public Trigger onFalse(Command command) {
requireNonNullParam(command, "command", "onFalling");
- m_event.falling().ifHigh(command::schedule);
+ m_loop.bind(
+ new Runnable() {
+ private boolean m_pressedLast = m_condition.getAsBoolean();
+
+ @Override
+ public void run() {
+ boolean pressed = m_condition.getAsBoolean();
+
+ if (m_pressedLast && !pressed) {
+ command.schedule();
+ }
+
+ m_pressedLast = pressed;
+ }
+ });
return this;
}
@@ -106,8 +122,23 @@ public class Trigger implements BooleanSupplier {
*/
public Trigger whileTrue(Command command) {
requireNonNullParam(command, "command", "whileHigh");
- m_event.rising().ifHigh(command::schedule);
- m_event.falling().ifHigh(command::cancel);
+ m_loop.bind(
+ new Runnable() {
+ private boolean m_pressedLast = m_condition.getAsBoolean();
+
+ @Override
+ public void run() {
+ boolean pressed = m_condition.getAsBoolean();
+
+ if (!m_pressedLast && pressed) {
+ command.schedule();
+ } else if (m_pressedLast && !pressed) {
+ command.cancel();
+ }
+
+ m_pressedLast = pressed;
+ }
+ });
return this;
}
@@ -123,8 +154,23 @@ public class Trigger implements BooleanSupplier {
*/
public Trigger whileFalse(Command command) {
requireNonNullParam(command, "command", "whileLow");
- m_event.falling().ifHigh(command::schedule);
- m_event.rising().ifHigh(command::cancel);
+ m_loop.bind(
+ new Runnable() {
+ private boolean m_pressedLast = m_condition.getAsBoolean();
+
+ @Override
+ public void run() {
+ boolean pressed = m_condition.getAsBoolean();
+
+ if (m_pressedLast && !pressed) {
+ command.schedule();
+ } else if (!m_pressedLast && pressed) {
+ command.cancel();
+ }
+
+ m_pressedLast = pressed;
+ }
+ });
return this;
}
@@ -136,16 +182,25 @@ public class Trigger implements BooleanSupplier {
*/
public Trigger toggleOnTrue(Command command) {
requireNonNullParam(command, "command", "toggleOnRising");
- m_event
- .rising()
- .ifHigh(
- () -> {
- if (!command.isScheduled()) {
- command.schedule();
- } else {
+ m_loop.bind(
+ new Runnable() {
+ private boolean m_pressedLast = m_condition.getAsBoolean();
+
+ @Override
+ public void run() {
+ boolean pressed = m_condition.getAsBoolean();
+
+ if (!m_pressedLast && pressed) {
+ if (command.isScheduled()) {
command.cancel();
+ } else {
+ command.schedule();
}
- });
+ }
+
+ m_pressedLast = pressed;
+ }
+ });
return this;
}
@@ -157,16 +212,25 @@ public class Trigger implements BooleanSupplier {
*/
public Trigger toggleOnFalse(Command command) {
requireNonNullParam(command, "command", "toggleOnFalling");
- m_event
- .falling()
- .ifHigh(
- () -> {
- if (!command.isScheduled()) {
- command.schedule();
- } else {
+ m_loop.bind(
+ new Runnable() {
+ private boolean m_pressedLast = m_condition.getAsBoolean();
+
+ @Override
+ public void run() {
+ boolean pressed = m_condition.getAsBoolean();
+
+ if (m_pressedLast && !pressed) {
+ if (command.isScheduled()) {
command.cancel();
+ } else {
+ command.schedule();
}
- });
+ }
+
+ m_pressedLast = pressed;
+ }
+ });
return this;
}
@@ -181,7 +245,21 @@ public class Trigger implements BooleanSupplier {
public Trigger whenActive(final Command command) {
requireNonNullParam(command, "command", "whenActive");
- m_event.rising().ifHigh(command::schedule);
+ m_loop.bind(
+ new Runnable() {
+ private boolean m_pressedLast = m_condition.getAsBoolean();
+
+ @Override
+ public void run() {
+ boolean pressed = m_condition.getAsBoolean();
+
+ if (!m_pressedLast && pressed) {
+ command.schedule();
+ }
+
+ m_pressedLast = pressed;
+ }
+ });
return this;
}
@@ -215,8 +293,23 @@ public class Trigger implements BooleanSupplier {
public Trigger whileActiveContinuous(final Command command) {
requireNonNullParam(command, "command", "whileActiveContinuous");
- m_event.ifHigh(command::schedule);
- m_event.falling().ifHigh(command::cancel);
+ m_loop.bind(
+ new Runnable() {
+ private boolean m_pressedLast = m_condition.getAsBoolean();
+
+ @Override
+ public void run() {
+ boolean pressed = m_condition.getAsBoolean();
+
+ if (pressed) {
+ command.schedule();
+ } else if (m_pressedLast) {
+ command.cancel();
+ }
+
+ m_pressedLast = pressed;
+ }
+ });
return this;
}
@@ -246,9 +339,23 @@ public class Trigger implements BooleanSupplier {
public Trigger whileActiveOnce(final Command command) {
requireNonNullParam(command, "command", "whileActiveOnce");
- m_event.rising().ifHigh(command::schedule);
- m_event.falling().ifHigh(command::cancel);
+ m_loop.bind(
+ new Runnable() {
+ private boolean m_pressedLast = m_condition.getAsBoolean();
+ @Override
+ public void run() {
+ boolean pressed = m_condition.getAsBoolean();
+
+ if (!m_pressedLast && pressed) {
+ command.schedule();
+ } else if (m_pressedLast && !pressed) {
+ command.cancel();
+ }
+
+ m_pressedLast = pressed;
+ }
+ });
return this;
}
@@ -263,7 +370,21 @@ public class Trigger implements BooleanSupplier {
public Trigger whenInactive(final Command command) {
requireNonNullParam(command, "command", "whenInactive");
- m_event.falling().ifHigh(command::schedule);
+ m_loop.bind(
+ new Runnable() {
+ private boolean m_pressedLast = m_condition.getAsBoolean();
+
+ @Override
+ public void run() {
+ boolean pressed = m_condition.getAsBoolean();
+
+ if (m_pressedLast && !pressed) {
+ command.schedule();
+ }
+
+ m_pressedLast = pressed;
+ }
+ });
return this;
}
@@ -292,16 +413,25 @@ public class Trigger implements BooleanSupplier {
public Trigger toggleWhenActive(final Command command) {
requireNonNullParam(command, "command", "toggleWhenActive");
- m_event
- .rising()
- .ifHigh(
- () -> {
+ m_loop.bind(
+ new Runnable() {
+ private boolean m_pressedLast = m_condition.getAsBoolean();
+
+ @Override
+ public void run() {
+ boolean pressed = m_condition.getAsBoolean();
+
+ if (!m_pressedLast && pressed) {
if (command.isScheduled()) {
command.cancel();
} else {
command.schedule();
}
- });
+ }
+
+ m_pressedLast = pressed;
+ }
+ });
return this;
}
@@ -311,57 +441,94 @@ public class Trigger implements BooleanSupplier {
*
* @param command the command to cancel
* @return this trigger, so calls can be chained
- * @deprecated Instead, pass {@link #rising()} as an end condition to {@link
- * Command#until(BooleanSupplier)}.
+ * @deprecated Instead, pass this as an end condition to {@link Command#until(BooleanSupplier)}.
*/
@Deprecated
public Trigger cancelWhenActive(final Command command) {
requireNonNullParam(command, "command", "cancelWhenActive");
- m_event.rising().ifHigh(command::cancel);
+ m_loop.bind(
+ new Runnable() {
+ private boolean m_pressedLast = m_condition.getAsBoolean();
+
+ @Override
+ public void run() {
+ boolean pressed = m_condition.getAsBoolean();
+
+ if (!m_pressedLast && pressed) {
+ command.cancel();
+ }
+
+ m_pressedLast = pressed;
+ }
+ });
return this;
}
- /**
- * Get the wrapped BooleanEvent.
- *
- * @return the wrapped BooleanEvent instance.
- */
- public BooleanEvent getEvent() {
- return m_event;
- }
-
@Override
public boolean getAsBoolean() {
- return m_event.getAsBoolean();
+ return m_condition.getAsBoolean();
}
+ /**
+ * Composes two triggers with logical OR.
+ *
+ * @param trigger the condition to compose with
+ * @return A trigger which is active when either component trigger is active.
+ */
public Trigger and(BooleanSupplier trigger) {
- return cast(m_event.and(trigger));
+ return new Trigger(() -> m_condition.getAsBoolean() && trigger.getAsBoolean());
}
+ /**
+ * Composes two triggers with logical OR.
+ *
+ * @param trigger the condition to compose with
+ * @return A trigger which is active when either component trigger is active.
+ */
public Trigger or(BooleanSupplier trigger) {
- return cast(m_event.or(trigger));
+ return new Trigger(() -> m_condition.getAsBoolean() || trigger.getAsBoolean());
}
+ /**
+ * Creates a new trigger that is active when this trigger is inactive, i.e. that acts as the
+ * negation of this trigger.
+ *
+ * @return the negated trigger
+ */
public Trigger negate() {
- return cast(m_event.negate());
+ return new Trigger(() -> !m_condition.getAsBoolean());
}
+ /**
+ * Creates a new debounced trigger from this trigger - it will become active when this trigger has
+ * been active for longer than the specified period.
+ *
+ * @param seconds The debounce period.
+ * @return The debounced trigger (rising edges debounced only)
+ */
public Trigger debounce(double seconds) {
return debounce(seconds, Debouncer.DebounceType.kRising);
}
+ /**
+ * Creates a new debounced trigger from this trigger - it will become active when this trigger has
+ * been active for longer than the specified period.
+ *
+ * @param seconds The debounce period.
+ * @param type The debounce type.
+ * @return The debounced trigger.
+ */
public Trigger debounce(double seconds, Debouncer.DebounceType type) {
- return cast(m_event.debounce(seconds, type));
- }
+ return new Trigger(
+ new BooleanSupplier() {
+ final Debouncer m_debouncer = new Debouncer(seconds, type);
- public Trigger rising() {
- return cast(m_event.rising());
- }
-
- public Trigger falling() {
- return cast(m_event.falling());
+ @Override
+ public boolean getAsBoolean() {
+ return m_debouncer.calculate(m_condition.getAsBoolean());
+ }
+ });
}
}
diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/button/Trigger.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/button/Trigger.cpp
index dc225aca33..3908daf13b 100644
--- a/wpilibNewCommands/src/main/native/cpp/frc2/command/button/Trigger.cpp
+++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/button/Trigger.cpp
@@ -14,101 +14,200 @@ using namespace frc2;
Trigger::Trigger(const Trigger& other) = default;
Trigger Trigger::OnTrue(Command* command) {
- m_event.Rising().IfHigh([command] { command->Schedule(); });
+ m_loop->Bind(
+ [condition = m_condition, previous = m_condition(), command]() mutable {
+ bool current = condition();
+
+ if (!previous && current) {
+ command->Schedule();
+ }
+
+ previous = current;
+ });
return *this;
}
Trigger Trigger::OnTrue(CommandPtr&& command) {
- m_event.Rising().IfHigh(
- [command = std::move(command)] { command.Schedule(); });
+ m_loop->Bind([condition = m_condition, previous = m_condition(),
+ command = std::move(command)]() mutable {
+ bool current = condition();
+
+ if (!previous && current) {
+ command.Schedule();
+ }
+
+ previous = current;
+ });
return *this;
}
Trigger Trigger::OnFalse(Command* command) {
- m_event.Falling().IfHigh([command] { command->Schedule(); });
+ m_loop->Bind(
+ [condition = m_condition, previous = m_condition(), command]() mutable {
+ bool current = condition();
+
+ if (previous && !current) {
+ command->Schedule();
+ }
+
+ previous = current;
+ });
return *this;
}
Trigger Trigger::OnFalse(CommandPtr&& command) {
- m_event.Falling().IfHigh(
- [command = std::move(command)] { command.Schedule(); });
+ m_loop->Bind([condition = m_condition, previous = m_condition(),
+ command = std::move(command)]() mutable {
+ bool current = condition();
+
+ if (previous && !current) {
+ command.Schedule();
+ }
+
+ previous = current;
+ });
return *this;
}
Trigger Trigger::WhileTrue(Command* command) {
- m_event.Rising().IfHigh([command] { command->Schedule(); });
- m_event.Falling().IfHigh([command] { command->Cancel(); });
+ m_loop->Bind(
+ [condition = m_condition, previous = m_condition(), command]() mutable {
+ bool current = condition();
+
+ if (!previous && current) {
+ command->Schedule();
+ } else if (previous && !current) {
+ command->Cancel();
+ }
+
+ previous = current;
+ });
return *this;
}
Trigger Trigger::WhileTrue(CommandPtr&& command) {
- auto ptr = std::make_shared(std::move(command));
- m_event.Rising().IfHigh([ptr] { ptr->Schedule(); });
- m_event.Falling().IfHigh([ptr] { ptr->Cancel(); });
+ m_loop->Bind([condition = m_condition, previous = m_condition(),
+ command = std::move(command)]() mutable {
+ bool current = condition();
+
+ if (!previous && current) {
+ command.Schedule();
+ } else if (previous && !current) {
+ command.Cancel();
+ }
+
+ previous = current;
+ });
return *this;
}
Trigger Trigger::WhileFalse(Command* command) {
- m_event.Falling().IfHigh([command] { command->Schedule(); });
- m_event.Rising().IfHigh([command] { command->Cancel(); });
+ m_loop->Bind(
+ [condition = m_condition, previous = m_condition(), command]() mutable {
+ bool current = condition();
+
+ if (previous && !current) {
+ command->Schedule();
+ } else if (!previous && current) {
+ command->Cancel();
+ }
+
+ previous = current;
+ });
return *this;
}
Trigger Trigger::WhileFalse(CommandPtr&& command) {
- auto ptr = std::make_shared(std::move(command));
- m_event.Falling().IfHigh([ptr] { ptr->Schedule(); });
- m_event.Rising().IfHigh([ptr] { ptr->Cancel(); });
+ m_loop->Bind([condition = m_condition, previous = m_condition(),
+ command = std::move(command)]() mutable {
+ bool current = condition();
+
+ if (!previous && current) {
+ command.Schedule();
+ } else if (previous && !current) {
+ command.Cancel();
+ }
+
+ previous = current;
+ });
return *this;
}
Trigger Trigger::ToggleOnTrue(Command* command) {
- m_event.Rising().IfHigh([command] {
- if (command->IsScheduled()) {
- command->Cancel();
- } else {
- command->Schedule();
+ m_loop->Bind([condition = m_condition, previous = m_condition(),
+ command = command]() mutable {
+ bool current = condition();
+
+ if (!previous && current) {
+ if (command->IsScheduled()) {
+ command->Cancel();
+ } else {
+ command->Schedule();
+ }
}
+
+ previous = current;
});
return *this;
}
Trigger Trigger::ToggleOnTrue(CommandPtr&& command) {
- m_event.Rising().IfHigh([command = std::move(command)] {
- if (command.IsScheduled()) {
- command.Cancel();
- } else {
- command.Schedule();
+ m_loop->Bind([condition = m_condition, previous = m_condition(),
+ command = std::move(command)]() mutable {
+ bool current = condition();
+
+ if (!previous && current) {
+ if (command.IsScheduled()) {
+ command.Cancel();
+ } else {
+ command.Schedule();
+ }
}
+
+ previous = current;
});
return *this;
}
Trigger Trigger::ToggleOnFalse(Command* command) {
- m_event.Falling().IfHigh([command] {
- if (command->IsScheduled()) {
- command->Cancel();
- } else {
- command->Schedule();
+ m_loop->Bind([condition = m_condition, previous = m_condition(),
+ command = command]() mutable {
+ bool current = condition();
+
+ if (previous && !current) {
+ if (command->IsScheduled()) {
+ command->Cancel();
+ } else {
+ command->Schedule();
+ }
}
+
+ previous = current;
});
return *this;
}
Trigger Trigger::ToggleOnFalse(CommandPtr&& command) {
- m_event.Falling().IfHigh([command = std::move(command)] {
- if (command.IsScheduled()) {
- command.Cancel();
- } else {
- command.Schedule();
+ m_loop->Bind([condition = m_condition, previous = m_condition(),
+ command = std::move(command)]() mutable {
+ bool current = condition();
+
+ if (previous && !current) {
+ if (command.IsScheduled()) {
+ command.Cancel();
+ } else {
+ command.Schedule();
+ }
}
+
+ previous = current;
});
return *this;
}
WPI_IGNORE_DEPRECATED
Trigger Trigger::WhenActive(Command* command) {
- m_event.Rising().IfHigh([command] { command->Schedule(); });
- return *this;
+ return OnTrue(command);
}
Trigger Trigger::WhenActive(std::function toRun,
@@ -123,8 +222,18 @@ Trigger Trigger::WhenActive(std::function toRun,
}
Trigger Trigger::WhileActiveContinous(Command* command) {
- m_event.IfHigh([command] { command->Schedule(); });
- m_event.Falling().IfHigh([command] { command->Cancel(); });
+ m_loop->Bind([condition = m_condition, previous = m_condition(),
+ command = std::move(command)]() mutable {
+ bool current = condition();
+
+ if (current) {
+ command->Schedule();
+ } else if (previous && !current) {
+ command->Cancel();
+ }
+
+ previous = current;
+ });
return *this;
}
@@ -141,13 +250,32 @@ Trigger Trigger::WhileActiveContinous(
}
Trigger Trigger::WhileActiveOnce(Command* command) {
- m_event.Rising().IfHigh([command] { command->Schedule(); });
- m_event.Falling().IfHigh([command] { command->Cancel(); });
+ m_loop->Bind(
+ [condition = m_condition, previous = m_condition(), command]() mutable {
+ bool current = condition();
+
+ if (!previous && current) {
+ command->Schedule();
+ } else if (previous && !current) {
+ command->Cancel();
+ }
+
+ previous = current;
+ });
return *this;
}
Trigger Trigger::WhenInactive(Command* command) {
- m_event.Falling().IfHigh([command] { command->Schedule(); });
+ m_loop->Bind(
+ [condition = m_condition, previous = m_condition(), command]() mutable {
+ bool current = condition();
+
+ if (previous && !current) {
+ command->Schedule();
+ }
+
+ previous = current;
+ });
return *this;
}
@@ -163,22 +291,42 @@ Trigger Trigger::WhenInactive(std::function toRun,
}
Trigger Trigger::ToggleWhenActive(Command* command) {
- m_event.Rising().IfHigh([command] {
- if (command->IsScheduled()) {
- command->Cancel();
- } else {
- command->Schedule();
+ m_loop->Bind([condition = m_condition, previous = m_condition(),
+ command = command]() mutable {
+ bool current = condition();
+
+ if (!previous && current) {
+ if (command->IsScheduled()) {
+ command->Cancel();
+ } else {
+ command->Schedule();
+ }
}
+
+ previous = current;
});
return *this;
}
Trigger Trigger::CancelWhenActive(Command* command) {
- m_event.Rising().IfHigh([command] { command->Cancel(); });
+ m_loop->Bind([condition = m_condition, previous = m_condition(),
+ command = std::move(command)]() mutable {
+ bool current = condition();
+
+ if (!previous && current) {
+ command->Cancel();
+ }
+
+ previous = current;
+ });
return *this;
}
WPI_UNIGNORE_DEPRECATED
-BooleanEvent Trigger::GetEvent() const {
- return m_event;
+Trigger Trigger::Debounce(units::second_t debounceTime,
+ frc::Debouncer::DebounceType type) {
+ return Trigger(m_loop, [debouncer = frc::Debouncer(debounceTime, type),
+ condition = m_condition]() mutable {
+ return debouncer.Calculate(condition());
+ });
}
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/button/Button.h b/wpilibNewCommands/src/main/native/include/frc2/command/button/Button.h
index bb19ee9d16..8a9794409c 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/button/Button.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/button/Button.h
@@ -266,10 +266,9 @@ class Button : public Trigger {
*
* @param command The command to bind.
* @return The button, for chained calls.
- * @deprecated Use Rising() as a command end condition with Until() instead.
+ * @deprecated Pass this as a command end condition with Until() instead.
*/
- WPI_DEPRECATED(
- "Use Rising() as a command end condition with Until() instead.")
+ WPI_DEPRECATED("Pass this as a command end condition with Until() instead.")
Button CancelWhenPressed(Command* command);
};
} // namespace frc2
diff --git a/wpilibNewCommands/src/main/native/include/frc2/command/button/Trigger.h b/wpilibNewCommands/src/main/native/include/frc2/command/button/Trigger.h
index 4a7cecc042..c3a5e86b5c 100644
--- a/wpilibNewCommands/src/main/native/include/frc2/command/button/Trigger.h
+++ b/wpilibNewCommands/src/main/native/include/frc2/command/button/Trigger.h
@@ -42,7 +42,7 @@ class Trigger {
* @param condition the condition represented by this trigger
*/
explicit Trigger(std::function condition)
- : m_event{CommandScheduler::GetInstance().GetDefaultButtonLoop(),
+ : Trigger{CommandScheduler::GetInstance().GetDefaultButtonLoop(),
std::move(condition)} {}
/**
@@ -52,7 +52,7 @@ class Trigger {
* @param condition the condition represented by this trigger
*/
Trigger(frc::EventLoop* loop, std::function condition)
- : m_event{loop, std::move(condition)} {}
+ : m_loop{loop}, m_condition{std::move(condition)} {}
/**
* Create a new trigger that is always `false`.
@@ -70,7 +70,6 @@ class Trigger {
*
* @param command the command to start
* @return this trigger, so calls can be chained
- * @see #Rising()
*/
Trigger OnTrue(Command* command);
@@ -92,7 +91,6 @@ class Trigger {
*
* @param command the command to start
* @return this trigger, so calls can be chained
- * @see #Falling()
*/
Trigger OnFalse(Command* command);
@@ -233,10 +231,17 @@ class Trigger {
Command, std::remove_reference_t>>>
WPI_DEPRECATED("Use OnTrue(Command) instead")
Trigger WhenActive(T&& command) {
- m_event.Rising().IfHigh(
- [command = std::make_unique>(
- std::forward(command))] { command->Schedule(); });
+ m_loop->Bind([condition = m_condition, previous = m_condition(),
+ command = std::make_unique>(
+ std::forward(command))]() mutable {
+ bool current = condition();
+ if (!previous && current) {
+ command->Schedule();
+ }
+
+ previous = current;
+ });
return *this;
}
@@ -298,10 +303,19 @@ class Trigger {
"Use WhileTrue(Command) with RepeatCommand, or bind command::Schedule "
"with IfHigh(std::function).")
Trigger WhileActiveContinous(T&& command) {
- std::shared_ptr ptr =
- std::make_shared>(std::forward(command));
- m_event.IfHigh([ptr] { ptr->Schedule(); });
- m_event.Falling().IfHigh([ptr] { ptr->Cancel(); });
+ m_loop->Bind([condition = m_condition, previous = m_condition(),
+ command = std::make_unique>(
+ std::forward(command))]() mutable {
+ bool current = condition();
+
+ if (current) {
+ command->Schedule();
+ } else if (previous && !current) {
+ command->Cancel();
+ }
+
+ previous = current;
+ });
return *this;
}
@@ -354,12 +368,19 @@ class Trigger {
Command, std::remove_reference_t>>>
WPI_DEPRECATED("Use WhileTrue(Command) instead.")
Trigger WhileActiveOnce(T&& command) {
- std::shared_ptr ptr =
- std::make_shared>(std::forward(command));
+ m_loop->Bind([condition = m_condition, previous = m_condition(),
+ command = std::make_unique>(
+ std::forward(command))]() mutable {
+ bool current = condition();
- m_event.Rising().IfHigh([ptr] { ptr->Schedule(); });
- m_event.Falling().IfHigh([ptr] { ptr->Cancel(); });
+ if (!previous && current) {
+ command->Schedule();
+ } else if (previous && !current) {
+ command->Cancel();
+ }
+ previous = current;
+ });
return *this;
}
@@ -389,10 +410,17 @@ class Trigger {
Command, std::remove_reference_t>>>
WPI_DEPRECATED("Use OnFalse(Command) instead.")
Trigger WhenInactive(T&& command) {
- m_event.Falling().IfHigh(
- [command = std::make_unique>(
- std::forward(command))] { command->Schedule(); });
+ m_loop->Bind([condition = m_condition, previous = m_condition(),
+ command = std::make_unique>(
+ std::forward(command))]() mutable {
+ bool current = condition();
+ if (previous && !current) {
+ command->Schedule();
+ }
+
+ previous = current;
+ });
return *this;
}
@@ -448,15 +476,21 @@ class Trigger {
Command, std::remove_reference_t>>>
WPI_DEPRECATED("Use ToggleOnTrue(Command) instead.")
Trigger ToggleWhenActive(T&& command) {
- m_event.Rising().IfHigh(
- [command = std::make_unique>(
- std::forward(command))] {
- if (!command->IsScheduled()) {
- command->Schedule();
- } else {
- command->Cancel();
- }
- });
+ m_loop->Bind([condition = m_condition, previous = m_condition(),
+ command = std::make_unique>(
+ std::forward(command))]() mutable {
+ bool current = condition();
+
+ if (!previous && current) {
+ if (command->IsScheduled()) {
+ command->Cancel();
+ } else {
+ command->Schedule();
+ }
+ }
+
+ previous = current;
+ });
return *this;
}
@@ -468,33 +502,20 @@ class Trigger {
*
* @param command The command to bind.
* @return The trigger, for chained calls.
- * @deprecated Use Rising() as a command end condition with Until() instead.
+ * @deprecated Pass this as a command end condition with Until() instead.
*/
- WPI_DEPRECATED(
- "Use Rising() as a command end condition with Until() instead.")
+ WPI_DEPRECATED("Pass this as a command end condition with Until() instead.")
Trigger CancelWhenActive(Command* command);
- /**
- * Get a new event that events only when this one newly changes to true.
- *
- * @return a new event representing when this one newly changes to true.
- */
- Trigger Rising() { return m_event.Rising().CastTo(); }
-
- /**
- * Get a new event that triggers only when this one newly changes to false.
- *
- * @return a new event representing when this one newly changes to false.
- */
- Trigger Falling() { return m_event.Falling().CastTo(); }
-
/**
* Composes two triggers with logical AND.
*
* @return A trigger which is active when both component triggers are active.
*/
Trigger operator&&(std::function rhs) {
- return m_event.operator&&(rhs).CastTo();
+ return Trigger(m_loop, [condition = m_condition, rhs = std::move(rhs)] {
+ return condition() && rhs();
+ });
}
/**
@@ -502,8 +523,10 @@ class Trigger {
*
* @return A trigger which is active when both component triggers are active.
*/
- Trigger operator&&(Trigger& rhs) {
- return (m_event && rhs.m_event).CastTo();
+ Trigger operator&&(Trigger rhs) {
+ return Trigger(m_loop, [condition = m_condition, rhs] {
+ return condition() && rhs.m_condition();
+ });
}
/**
@@ -512,7 +535,9 @@ class Trigger {
* @return A trigger which is active when either component trigger is active.
*/
Trigger operator||(std::function rhs) {
- return m_event.operator||(rhs).CastTo();
+ return Trigger(m_loop, [condition = m_condition, rhs = std::move(rhs)] {
+ return condition() || rhs();
+ });
}
/**
@@ -520,8 +545,10 @@ class Trigger {
*
* @return A trigger which is active when either component trigger is active.
*/
- Trigger operator||(Trigger& rhs) {
- return (m_event || rhs.m_event).CastTo();
+ Trigger operator||(Trigger rhs) {
+ return Trigger(m_loop, [condition = m_condition, rhs] {
+ return condition() || rhs.m_condition();
+ });
}
/**
@@ -530,7 +557,9 @@ class Trigger {
* @return A trigger which is active when the component trigger is inactive,
* and vice-versa.
*/
- Trigger operator!() { return m_event.operator!().CastTo(); }
+ Trigger operator!() {
+ return Trigger(m_loop, [condition = m_condition] { return !condition(); });
+ }
/**
* Creates a new debounced trigger from this trigger - it will become active
@@ -542,16 +571,10 @@ class Trigger {
*/
Trigger Debounce(units::second_t debounceTime,
frc::Debouncer::DebounceType type =
- frc::Debouncer::DebounceType::kRising) {
- return m_event.Debounce(debounceTime, type).CastTo();
- }
-
- /**
- * Get the wrapped BooleanEvent instance.
- */
- frc::BooleanEvent GetEvent() const;
+ frc::Debouncer::DebounceType::kRising);
private:
- frc::BooleanEvent m_event;
+ frc::EventLoop* m_loop;
+ std::function m_condition;
};
} // namespace frc2
diff --git a/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/button/TriggerTest.java b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/button/TriggerTest.java
index 106e066135..82d359c3aa 100644
--- a/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/button/TriggerTest.java
+++ b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/button/TriggerTest.java
@@ -178,7 +178,7 @@ class TriggerTest extends CommandTestBase {
InternalButton button = new InternalButton();
Command command1 =
new StartEndCommand(startCounter::incrementAndGet, endCounter::incrementAndGet)
- .until(button.rising());
+ .until(button);
button.setPressed(false);
command1.schedule();
diff --git a/wpilibc/src/main/native/cpp/event/BooleanEvent.cpp b/wpilibc/src/main/native/cpp/event/BooleanEvent.cpp
index 28ab0fca14..5b8ce63d68 100644
--- a/wpilibc/src/main/native/cpp/event/BooleanEvent.cpp
+++ b/wpilibc/src/main/native/cpp/event/BooleanEvent.cpp
@@ -17,8 +17,12 @@ bool BooleanEvent::GetAsBoolean() const {
return m_condition();
}
-void BooleanEvent::IfHigh(wpi::unique_function action) {
- m_loop->Bind(m_condition, std::move(action));
+void BooleanEvent::IfHigh(std::function action) {
+ m_loop->Bind([condition = m_condition, action = std::move(action)] {
+ if (condition()) {
+ action();
+ }
+ });
}
BooleanEvent BooleanEvent::operator!() {
diff --git a/wpilibc/src/main/native/cpp/event/EventLoop.cpp b/wpilibc/src/main/native/cpp/event/EventLoop.cpp
index 71cff7066c..5af79c96d3 100644
--- a/wpilibc/src/main/native/cpp/event/EventLoop.cpp
+++ b/wpilibc/src/main/native/cpp/event/EventLoop.cpp
@@ -8,20 +8,13 @@ using namespace frc;
EventLoop::EventLoop() {}
-void EventLoop::Binding::Poll() {
- if (condition()) {
- action();
- }
-}
-
-void EventLoop::Bind(std::function condition,
- wpi::unique_function action) {
- m_bindings.emplace_back(Binding{condition, std::move(action)});
+void EventLoop::Bind(wpi::unique_function action) {
+ m_bindings.emplace_back(std::move(action));
}
void EventLoop::Poll() {
- for (Binding& binding : m_bindings) {
- binding.Poll();
+ for (wpi::unique_function& action : m_bindings) {
+ action();
}
}
diff --git a/wpilibc/src/main/native/include/frc/event/BooleanEvent.h b/wpilibc/src/main/native/include/frc/event/BooleanEvent.h
index d550543e47..745a53c095 100644
--- a/wpilibc/src/main/native/include/frc/event/BooleanEvent.h
+++ b/wpilibc/src/main/native/include/frc/event/BooleanEvent.h
@@ -19,7 +19,7 @@ namespace frc {
/**
* This class provides an easy way to link actions to inputs. Each object
* represents a boolean condition to which callback actions can be bound using
- * {@link #IfHigh(wpi::unique_function)}.
+ * {@link #IfHigh(std::function)}.
*
* These events can easily be composed using factories such as {@link
* #operator!},
@@ -51,7 +51,7 @@ class BooleanEvent {
*
* @param action the action to run if this event is active.
*/
- void IfHigh(wpi::unique_function action);
+ void IfHigh(std::function action);
operator std::function(); // NOLINT
diff --git a/wpilibc/src/main/native/include/frc/event/EventLoop.h b/wpilibc/src/main/native/include/frc/event/EventLoop.h
index 11ead4fadc..d18fac3fe3 100644
--- a/wpilibc/src/main/native/include/frc/event/EventLoop.h
+++ b/wpilibc/src/main/native/include/frc/event/EventLoop.h
@@ -20,13 +20,11 @@ class EventLoop {
EventLoop& operator=(const EventLoop&) = delete;
/**
- * Bind a new action to run whenever the condition is true.
+ * Bind a new action to run.
*
- * @param condition the condition to listen to.
* @param action the action to run.
*/
- void Bind(std::function condition,
- wpi::unique_function action);
+ void Bind(wpi::unique_function action);
/**
* Poll all bindings.
@@ -39,12 +37,6 @@ class EventLoop {
void Clear();
private:
- struct Binding {
- std::function condition;
- wpi::unique_function action;
-
- void Poll();
- };
- std::vector m_bindings;
+ std::vector> m_bindings;
};
} // namespace frc
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/event/BooleanEvent.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/event/BooleanEvent.java
index 742a7a8b30..a810006563 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/event/BooleanEvent.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/event/BooleanEvent.java
@@ -54,7 +54,12 @@ public class BooleanEvent implements BooleanSupplier {
* @param action the action to run if this event is active.
*/
public final void ifHigh(Runnable action) {
- m_loop.bind(m_signal, action);
+ m_loop.bind(
+ () -> {
+ if (m_signal.getAsBoolean()) {
+ action.run();
+ }
+ });
}
/**
diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/event/EventLoop.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/event/EventLoop.java
index 88eed86044..3e92c019ab 100644
--- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/event/EventLoop.java
+++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/event/EventLoop.java
@@ -6,45 +6,27 @@ package edu.wpi.first.wpilibj.event;
import java.util.Collection;
import java.util.LinkedHashSet;
-import java.util.function.BooleanSupplier;
/** The loop polling {@link BooleanEvent} objects and executing the actions bound to them. */
public final class EventLoop {
- private final Collection m_bindings = new LinkedHashSet<>();
+ private final Collection m_bindings = new LinkedHashSet<>();
/**
* Bind a new action to run whenever the condition is true.
*
- * @param condition the condition to listen to.
* @param action the action to run.
*/
- public void bind(BooleanSupplier condition, Runnable action) {
- m_bindings.add(new Binding(condition, action));
+ public void bind(Runnable action) {
+ m_bindings.add(action);
}
/** Poll all bindings. */
public void poll() {
- m_bindings.forEach(Binding::poll);
+ m_bindings.forEach(Runnable::run);
}
/** Clear all bindings. */
public void clear() {
m_bindings.clear();
}
-
- private static class Binding {
- private final BooleanSupplier m_condition;
- private final Runnable m_action;
-
- private Binding(BooleanSupplier condition, Runnable action) {
- this.m_condition = condition;
- this.m_action = action;
- }
-
- void poll() {
- if (m_condition.getAsBoolean()) {
- m_action.run();
- }
- }
- }
}
diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/event/EventLoopTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/event/EventLoopTest.java
index 7f0bb1e95e..ea3c569e65 100644
--- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/event/EventLoopTest.java
+++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/event/EventLoopTest.java
@@ -16,8 +16,8 @@ class EventLoopTest {
var counterTrue = new AtomicInteger(0);
var counterFalse = new AtomicInteger(0);
var loop = new EventLoop();
- loop.bind(() -> true, counterTrue::incrementAndGet);
- loop.bind(() -> false, counterFalse::incrementAndGet);
+ new BooleanEvent(loop, () -> true).ifHigh(counterTrue::incrementAndGet);
+ new BooleanEvent(loop, () -> false).ifHigh(counterFalse::incrementAndGet);
assertEquals(0, counterTrue.get());
assertEquals(0, counterFalse.get());
@@ -40,7 +40,7 @@ class EventLoopTest {
var loop = new EventLoop();
// first ensure binding works
- loop.bind(condition::get, counter::incrementAndGet);
+ new BooleanEvent(loop, condition::get).ifHigh(counter::incrementAndGet);
condition.set(false);
loop.poll();