001// Copyright (c) FIRST and other WPILib contributors. 002// Open Source Software; you can modify and/or share it under the terms of 003// the WPILib BSD license file in the root directory of this project. 004 005package edu.wpi.first.wpilibj2.command; 006 007import java.util.Collections; 008import java.util.HashSet; 009import java.util.Set; 010 011/** 012 * A composition that runs a set of commands in parallel, ending when any one of the commands ends 013 * and interrupting all the others. 014 * 015 * <p>The rules for command compositions apply: command instances that are passed to it cannot be 016 * added to any other composition or scheduled individually, and the composition requires all 017 * subsystems its components require. 018 * 019 * <p>This class is provided by the NewCommands VendorDep 020 */ 021@SuppressWarnings("removal") 022public class ParallelRaceGroup extends CommandGroupBase { 023 private final Set<Command> m_commands = new HashSet<>(); 024 private boolean m_runWhenDisabled = true; 025 private boolean m_finished = true; 026 private InterruptionBehavior m_interruptBehavior = InterruptionBehavior.kCancelIncoming; 027 028 /** 029 * Creates a new ParallelCommandRace. The given commands will be executed simultaneously, and will 030 * "race to the finish" - the first command to finish ends the entire command, with all other 031 * commands being interrupted. 032 * 033 * @param commands the commands to include in this composition. 034 */ 035 public ParallelRaceGroup(Command... commands) { 036 addCommands(commands); 037 } 038 039 @Override 040 public final void addCommands(Command... commands) { 041 if (!m_finished) { 042 throw new IllegalStateException( 043 "Commands cannot be added to a composition while it's running!"); 044 } 045 046 CommandScheduler.getInstance().registerComposedCommands(commands); 047 048 for (Command command : commands) { 049 if (!Collections.disjoint(command.getRequirements(), m_requirements)) { 050 throw new IllegalArgumentException( 051 "Multiple commands in a parallel composition cannot require the same subsystems"); 052 } 053 m_commands.add(command); 054 m_requirements.addAll(command.getRequirements()); 055 m_runWhenDisabled &= command.runsWhenDisabled(); 056 if (command.getInterruptionBehavior() == InterruptionBehavior.kCancelSelf) { 057 m_interruptBehavior = InterruptionBehavior.kCancelSelf; 058 } 059 } 060 } 061 062 @Override 063 public final void initialize() { 064 m_finished = false; 065 for (Command command : m_commands) { 066 command.initialize(); 067 } 068 } 069 070 @Override 071 public final void execute() { 072 for (Command command : m_commands) { 073 command.execute(); 074 if (command.isFinished()) { 075 m_finished = true; 076 } 077 } 078 } 079 080 @Override 081 public final void end(boolean interrupted) { 082 for (Command command : m_commands) { 083 command.end(!command.isFinished()); 084 } 085 } 086 087 @Override 088 public final boolean isFinished() { 089 return m_finished; 090 } 091 092 @Override 093 public boolean runsWhenDisabled() { 094 return m_runWhenDisabled; 095 } 096 097 @Override 098 public InterruptionBehavior getInterruptionBehavior() { 099 return m_interruptBehavior; 100 } 101}