// Copyright (c) FIRST and other WPILib contributors. // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. #pragma once #include #include #include #include #include #include #include #include #include #include #include "frc2/command/Command.h" #include "frc2/command/CommandScheduler.h" namespace frc2 { class Command; /** * This class is a command-based wrapper around {@link frc::BooleanEvent}, * providing an easy way to link commands to inputs. * * This class is provided by the NewCommands VendorDep * * @see Button */ class Trigger { public: /** * Creates a new trigger with the given condition determining whether it is * active. * *

Polled by the default scheduler button loop. * * @param isActive returns whether or not the trigger should be active */ explicit Trigger(std::function isActive) : m_event{CommandScheduler::GetInstance().GetDefaultButtonLoop(), std::move(isActive)} {} /** * Create a new trigger that is active when the given condition is true. * * @param loop The loop instance that polls this trigger. * @param isActive Whether the trigger is active. */ Trigger(frc::EventLoop* loop, std::function isActive) : m_event{loop, std::move(isActive)} {} /** * Create a new trigger that is never active (default constructor) - activity * can be further determined by subclass code. */ Trigger() : Trigger([] { return false; }) {} Trigger(const Trigger& other); /** * Starts the given command whenever the signal rises from `false` to `true`. * *

Takes a raw pointer, and so is non-owning; users are responsible for the * lifespan of the command. * * @param command the command to start * @return this trigger, so calls can be chained * @see #Rising() */ Trigger OnTrue(Command* command); /** * Starts the given command whenever the signal rises from `false` to `true`. * Moves command ownership to the button scheduler. * * @param command The command to bind. * @return The trigger, for chained calls. */ Trigger OnTrue(CommandPtr&& command); /** * Starts the given command whenever the signal falls from `true` to `false`. * *

Takes a raw pointer, and so is non-owning; users are responsible for the * lifespan of the command. * * @param command the command to start * @return this trigger, so calls can be chained * @see #Falling() */ Trigger OnFalse(Command* command); /** * Starts the given command whenever the signal falls from `true` to `false`. * * @param command The command to bind. * @return The trigger, for chained calls. */ Trigger OnFalse(CommandPtr&& command); /** * Starts the given command when the signal rises to `true` and cancels it * when the signal falls to `false`. * *

Doesn't re-start the command in-between. * *

Takes a raw pointer, and so is non-owning; users are responsible for the * lifespan of the command. * * @param command the command to start * @return this trigger, so calls can be chained */ Trigger WhileTrue(Command* command); /** * Starts the given command when the signal rises to `true` and cancels it * when the signal falls to `false`. Moves command ownership to the button * scheduler. * * @param command The command to bind. * @return The trigger, for chained calls. */ Trigger WhileTrue(CommandPtr&& command); /** * Starts the given command when the signal falls to `false` and cancels * it when the signal rises. * *

Doesn't re-start the command in-between. * *

Takes a raw pointer, and so is non-owning; users are responsible for the * lifespan of the command. * * @param command the command to start * @return this trigger, so calls can be chained */ Trigger WhileFalse(Command* command); /** * Starts the given command when the signal falls to `false` and cancels * it when the signal rises. Moves command ownership to the button * scheduler. * * @param command The command to bind. * @return The trigger, for chained calls. */ Trigger WhileFalse(CommandPtr&& command); /** * Toggles a command when the signal rises from `false` to the high * state. * *

Takes a raw pointer, and so is non-owning; users are responsible for the * lifespan of the command. * * @param command the command to toggle * @return this trigger, so calls can be chained */ Trigger ToggleOnTrue(Command* command); /** * Toggles a command when the signal rises from `false` to the high * state. * *

Takes a raw pointer, and so is non-owning; users are responsible for the * lifespan of the command. * * @param command the command to toggle * @return this trigger, so calls can be chained */ Trigger ToggleOnTrue(CommandPtr&& command); /** * Toggles a command when the signal falls from `true` to the low * state. * *

Takes a raw pointer, and so is non-owning; users are responsible for the * lifespan of the command. * * @param command the command to toggle * @return this trigger, so calls can be chained */ Trigger ToggleOnFalse(Command* command); /** * Toggles a command when the signal falls from `true` to the low * state. * *

Takes a raw pointer, and so is non-owning; users are responsible for the * lifespan of the command. * * @param command the command to toggle * @return this trigger, so calls can be chained */ Trigger ToggleOnFalse(CommandPtr&& command); /** * Binds a command to start when the trigger becomes active. Takes a * raw pointer, and so is non-owning; users are responsible for the lifespan * of the command. * * @param command The command to bind. * @return The trigger, for chained calls. * @deprecated Use OnTrue(Command) instead */ WPI_DEPRECATED("Use OnTrue(Command) instead") Trigger WhenActive(Command* command); /** * Binds a command to start when the trigger becomes active. Transfers * command ownership to the button scheduler, so the user does not have to * worry about lifespan - rvalue refs will be *moved*, lvalue refs will be * *copied.* * * @param command The command to bind. * @return The trigger, for chained calls. * @deprecated Use OnTrue(Command) instead */ template >>> WPI_DEPRECATED("Use OnTrue(Command) instead") Trigger WhenActive(T&& command) { m_event.Rising().IfHigh( [command = std::make_unique>( std::forward(command))] { command->Schedule(); }); return *this; } /** * Binds a runnable to execute when the trigger becomes active. * * @param toRun the runnable to execute. * @param requirements the required subsystems. * @deprecated Use OnTrue(Command) instead and construct the InstantCommand * manually */ WPI_DEPRECATED( "Use OnTrue(Command) instead and construct the InstantCommand manually") Trigger WhenActive(std::function toRun, std::initializer_list requirements); /** * Binds a runnable to execute when the trigger becomes active. * * @param toRun the runnable to execute. * @param requirements the required subsystems. * @deprecated Use OnTrue(Command) instead and construct the InstantCommand * manually */ WPI_DEPRECATED( "Use OnTrue(Command) instead and construct the InstantCommand manually") Trigger WhenActive(std::function toRun, std::span requirements = {}); /** * Binds a command to be started repeatedly while the trigger is active, and * canceled when it becomes inactive. Takes a raw pointer, and so is * non-owning; users are responsible for the lifespan of the command. * * @param command The command to bind. * @return The trigger, for chained calls. * @deprecated Use WhileTrue(Command) with RepeatCommand, or bind command::Schedule with IfHigh(std::function). */ WPI_DEPRECATED( "Use WhileTrue(Command) with RepeatCommand, or bind command::Schedule " "with IfHigh(std::function).") Trigger WhileActiveContinous(Command* command); /** * Binds a command to be started repeatedly while the trigger is active, and * canceled when it becomes inactive. Transfers command ownership to the * button scheduler, so the user does not have to worry about lifespan - * rvalue refs will be *moved*, lvalue refs will be *copied.* * * @param command The command to bind. * @return The trigger, for chained calls. * @deprecated Use WhileTrue(Command) with RepeatCommand, or bind command::Schedule with IfHigh(std::function). */ template >>> WPI_DEPRECATED( "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(); }); return *this; } /** * Binds a runnable to execute repeatedly while the trigger is active. * * @param toRun the runnable to execute. * @param requirements the required subsystems. * @deprecated Use WhileTrue(Command) and construct a RunCommand manually */ WPI_DEPRECATED("Use WhileTrue(Command) and construct a RunCommand manually") Trigger WhileActiveContinous(std::function toRun, std::initializer_list requirements); /** * Binds a runnable to execute repeatedly while the trigger is active. * * @param toRun the runnable to execute. * @param requirements the required subsystems. * @deprecated Use WhileTrue(Command) and construct a RunCommand manually */ WPI_DEPRECATED("Use WhileTrue(Command) and construct a RunCommand manually") Trigger WhileActiveContinous(std::function toRun, std::span requirements = {}); /** * Binds a command to be started when the trigger becomes active, and * canceled when it becomes inactive. Takes a raw pointer, and so is * non-owning; users are responsible for the lifespan of the command. * * @param command The command to bind. * @return The trigger, for chained calls. * @deprecated Use WhileTrue(Command) instead. */ WPI_DEPRECATED("Use WhileTrue(Command) instead.") Trigger WhileActiveOnce(Command* command); /** * Binds a command to be started when the trigger becomes active, and * canceled when it becomes inactive. Transfers command ownership to the * button scheduler, so the user does not have to worry about lifespan - * rvalue refs will be *moved*, lvalue refs will be *copied.* * * @param command The command to bind. * @return The trigger, for chained calls. * @deprecated Use WhileTrue(Command) instead. */ template >>> WPI_DEPRECATED("Use WhileTrue(Command) instead.") Trigger WhileActiveOnce(T&& command) { std::shared_ptr ptr = std::make_shared>(std::forward(command)); m_event.Rising().IfHigh([ptr] { ptr->Schedule(); }); m_event.Falling().IfHigh([ptr] { ptr->Cancel(); }); return *this; } /** * Binds a command to start when the trigger becomes inactive. Takes a * raw pointer, and so is non-owning; users are responsible for the lifespan * of the command. * * @param command The command to bind. * @return The trigger, for chained calls. * @deprecated Use OnFalse(Command) instead. */ WPI_DEPRECATED("Use OnFalse(Command) instead.") Trigger WhenInactive(Command* command); /** * Binds a command to start when the trigger becomes inactive. Transfers * command ownership to the button scheduler, so the user does not have to * worry about lifespan - rvalue refs will be *moved*, lvalue refs will be * *copied.* * * @param command The command to bind. * @return The trigger, for chained calls. * @deprecated Use OnFalse(Command) instead. */ template >>> WPI_DEPRECATED("Use OnFalse(Command) instead.") Trigger WhenInactive(T&& command) { m_event.Falling().IfHigh( [command = std::make_unique>( std::forward(command))] { command->Schedule(); }); return *this; } /** * Binds a runnable to execute when the trigger becomes inactive. * * @param toRun the runnable to execute. * @param requirements the required subsystems. * @deprecated Use OnFalse(Command) instead and construct the InstantCommand * manually */ WPI_DEPRECATED( "Use OnFalse(Command) instead and construct the InstantCommand manually") Trigger WhenInactive(std::function toRun, std::initializer_list requirements); /** * Binds a runnable to execute when the trigger becomes inactive. * * @param toRun the runnable to execute. * @param requirements the required subsystems. * @deprecated Use OnFalse(Command) instead and construct the InstantCommand * manually */ WPI_DEPRECATED( "Use OnFalse(Command) instead and construct the InstantCommand manually") Trigger WhenInactive(std::function toRun, std::span requirements = {}); /** * Binds a command to start when the trigger becomes active, and be canceled * when it again becomes active. Takes a raw pointer, and so is non-owning; * users are responsible for the lifespan of the command. * * @param command The command to bind. * @return The trigger, for chained calls. * @deprecated Use ToggleOnTrue(Command) instead. */ WPI_DEPRECATED("Use ToggleOnTrue(Command) instead.") Trigger ToggleWhenActive(Command* command); /** * Binds a command to start when the trigger becomes active, and be canceled * when it again becomes active. Transfers command ownership to the button * scheduler, so the user does not have to worry about lifespan - rvalue refs * will be *moved*, lvalue refs will be *copied.* * * @param command The command to bind. * @return The trigger, for chained calls. * @deprecated Use ToggleOnTrue(Command) instead. */ template >>> 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(); } }); return *this; } /** * Binds a command to be canceled when the trigger becomes active. Takes a * raw pointer, and so is non-owning; users are responsible for the lifespan * and scheduling of the command. * * @param command The command to bind. * @return The trigger, for chained calls. * @deprecated Use Rising() as a command end condition with Until() instead. */ WPI_DEPRECATED( "Use Rising() 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(); } /** * Composes two triggers with logical AND. * * @return A trigger which is active when both component triggers are active. */ Trigger operator&&(Trigger& rhs) { return (m_event && rhs.m_event).CastTo(); } /** * Composes two triggers with logical OR. * * @return A trigger which is active when either component trigger is active. */ Trigger operator||(std::function rhs) { return m_event.operator||(rhs).CastTo(); } /** * Composes two triggers with logical OR. * * @return A trigger which is active when either component trigger is active. */ Trigger operator||(Trigger& rhs) { return (m_event || rhs.m_event).CastTo(); } /** * Composes a trigger with logical NOT. * * @return A trigger which is active when the component trigger is inactive, * and vice-versa. */ Trigger operator!() { return m_event.operator!().CastTo(); } /** * 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 debounceTime The debounce period. * @param type The debounce type. * @return The debounced 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; private: frc::BooleanEvent m_event; }; } // namespace frc2