/// <summary> /// Sets the default command. /// </summary> /// <remarks>If this is not called, or is called with null, then there will be no default /// command for the subsystem. /// <para/><b>WARNING:</b> This should <b>NOT</b> be called in a constructor if the /// subsystem is a singleton.</remarks> /// <param name="command">The default command(or null if there should be none.</param> /// <exception cref="IllegalUseOfCommandException">If the command does not require the subsystem.</exception> protected internal void SetDefaultCommand(Command command) { if (command == null) { m_defaultCommand = null; } else { bool found = false; foreach (var s in command.GetRequirements()) { if (s.Equals(this)) found = true; } if (!found) { throw new IllegalUseOfCommandException("A default command must require the subsystem"); } m_defaultCommand = command; } if (Table != null) { if (m_defaultCommand != null) { Table.PutBoolean("hasDefault", true); Table.PutString("default", m_defaultCommand.Name); } else { Table.PutBoolean("hasDefault", false); } } }
/// <summary> /// Adds a <see cref="Command"/> to the scheduler. /// </summary> /// <param name="command">The command to add to the scheduler.</param> public void AddCommand(Command command) { if (command != null) { m_additions.Add(command); } }
/// <summary> /// Adds a new <see cref="Command"/> to the group. /// </summary> /// <remarks> /// The <see cref="Command"/> will be started after all the previously added <see cref="Command">commands</see>. /// <para> /// Note that any requirements thee given <see cref="Command"/> has will be added to the group. For this reason, a /// <see cref="Command">Command's</see> requirements cannot be changed after being added to a group. /// </para> /// <para> /// It is recommended that this method be called in the constructor. /// </para> /// </remarks> /// <param name="command">The <see cref="Command"/> to be added.</param> /// <exception cref="IllegalUseOfCommandException">If the command has been started before or been given to another group.</exception> /// <exception cref="ArgumentNullException">If the given <see cref="Command"/> is null</exception> public void AddSequential(Command command) { lock (m_syncRoot) { Validate("Can not add new command to command group"); if (command == null) throw new ArgumentNullException(nameof(command), "Given null command"); command.SetParent(this); m_commands.Add(new Entry(command, Entry.IN_SEQUENCE)); foreach (var e in command.GetRequirements()) { Requires(e); } } }
private void _Add(Command command) { if (command == null) { return; } if (m_adding) { Console.Error.WriteLine($"WARNING: Cannot start command from cancel method. Ignoring: {command}"); } if (!m_commandTable.ContainsKey(command)) { IEnumerable<Subsystem> requirements = command.GetRequirements(); if (requirements.Any(subsystem => subsystem.GetCurrentCommand() != null && !subsystem.GetCurrentCommand().Interruptible)) { return; } m_adding = true; requirements = command.GetRequirements(); foreach (var subsystem in requirements) { if (subsystem.GetCurrentCommand() != null) { subsystem.GetCurrentCommand().Cancel(); Remove(subsystem.GetCurrentCommand()); } subsystem.SetCurrentCommand(command); } m_adding = false; LinkedListElement element = new LinkedListElement(); element.SetData(command); if (m_firstCommand == null) { m_firstCommand = m_lastCommand = element; } else { m_lastCommand.Add(element); m_lastCommand = element; } m_commandTable.Add(command, element); m_runningCommandsChanged = true; command.StartRunning(); } }
private void _Add(Command command) { if (command == null) { return; } if (m_adding) { Console.Error.WriteLine($"WARNING: Cannot start command from cancel method. Ignoring: {command}"); } if (!m_activeCommands.Contains(command)) { var requirements = command.GetRequirements(); var currentCommands = requirements.Select(subsystem => subsystem.GetCurrentCommand()) .Where(x => x != null); // If there are any non-interruptible commands on the subsystems required for this command if (currentCommands.Any(cmd => !cmd.Interruptible)) { return; } m_adding = true; foreach (var subsystem in requirements) { if (subsystem.GetCurrentCommand() != null) { subsystem.GetCurrentCommand().Cancel(); Remove(subsystem.GetCurrentCommand()); } subsystem.SetCurrentCommand(command); } m_adding = false; m_activeCommands.Add(command); m_runningCommandsChanged = true; command.StartRunning(); } }
internal void Remove(Command command) { if (command == null || !m_commandTable.ContainsKey(command)) { return; } LinkedListElement e = m_commandTable[command]; m_commandTable.Remove(command); if (e.Equals(m_lastCommand)) { m_lastCommand = e.GetPrevious(); } if (e.Equals(m_firstCommand)) { m_firstCommand = e.GetNext(); } e.Remove(); var requirements = command.GetRequirements(); foreach (var requirement in requirements) { requirement.SetCurrentCommand(null); } command.Removed(); }
/// <summary> /// Starts the command when the button is released /// </summary> /// <param name="command">The command to start</param> public void WhenReleased(Command command) { WhenInactive(command); }
internal void SetCurrentCommand(Command command) { m_currentCommand = command; m_currentCommandChanged = true; }
public void SetData(Command newData) { data = newData; }
/// <summary> /// Constantly starts the given command while the button is held. /// </summary><remarks> /// <see cref="Command.Start()"/> will be called repeatedly while the button is held, /// and will be canceled when the button is released. /// </remarks> /// <param name="command">The command to start</param> public void WhileHeld(Command command) { WhileActive(command); }
/// <summary> /// Cancel the command when the button is pressed. /// </summary> /// <param name="command">The command to start</param> public void CancelWhenPressed(Command command) { CancelWhenActive(command); }
private void CancelConflicts(Command command) { for (int i = 0; i < m_children.Count; i++) { Command child = m_children[i].command; foreach (var requirement in command.GetRequirements()) { if (child.DoesRequire(requirement)) { child._Cancel(); child.Removed(); m_children.RemoveAt(i--); } } } }
public void Init(Command command) { this.command = command; }
/// <summary> /// Starts the given command whenever the trigger just becomes active. /// </summary> /// <param name="command">The command to start</param> public void WhenActive(Command command) { new PressedButtonScheduler(Grab(), this, command).Start(); }
public HeldButtonScheduler(bool last, Trigger button, Command orders) : base(last, button, orders) { }
protected ButtonScheduler(bool last, Trigger button, Command orders) { m_pressedLast = last; m_button = button; m_command = orders; }
public void Init(Command command) { Command = command; }
internal void Remove(Command command) { if (command == null || !m_activeCommands.Contains(command)) { return; } m_activeCommands.Remove(command); foreach (var requirement in command.GetRequirements()) { requirement.SetCurrentCommand(null); } command.Removed(); }
internal Entry(Command command, int state, double timeout) { this.command = command; this.state = state; this.timeout = timeout; }
/// <summary> /// Constantly starts the given command while the button is held. /// </summary><remarks> /// <see cref="Command.Start()"/> will be called repeatedly while the button is held, /// and will be canceled when the button is released. /// </remarks> /// <param name="command">The command to start</param> public void WhileActive(Command command) { new HeldButtonScheduler(Grab(), this, command).Start(); }
/// <summary> /// Toggles the command whenever the button is pressed (on then off then on) /// </summary> /// <param name="command">The command to start</param> public void ToggleWhenPressed(Command command) { ToggleWhenActive(command); }
/// <summary> /// Adds a new <see cref="Command"/> to the group with the given timeout. /// </summary> /// <remarks> /// The <see cref="Command"/> will be started after all the previously added <see cref="Command">commands</see>. /// /// <para> /// Once the <see cref="Command"/> is started, it will be run until it finishes or the time expires, whichever is sooner. /// Note that the give <see cref="Command"/> will have no knowledge that it is on a timer. /// </para> /// <para> /// Instead of waiting for the child to finish, a <see cref="CommandGroup"/> will have it run /// at the same time as the subsequent <see cref="Command">Commands</see>. The child wil run /// either until it finishes, a new child with conflicting requirements is started, or the main /// sequence runs a <see cref="Command"/> with conflicting requirements. In the latter two cases, /// the child will be canceled even if it says it can't be interrupted. /// </para> /// <para> /// Note that any requirements thee given <see cref="Command"/> has will be added to the group. For this reason, a /// <see cref="Command">Command's</see> requirements cannot be changed after being added to a group. /// </para> /// <para> /// It is recommended that this method be called in the constructor. /// </para> /// </remarks> /// <param name="command">The <see cref="Command"/> to be added.</param> /// <param name="timeout">The timeout (in seconds).</param> /// <exception cref="IllegalUseOfCommandException">If the command has been started before or been given to another group.</exception> /// <exception cref="ArgumentNullException">If the given <see cref="Command"/> is null</exception> /// <exception cref="ArgumentOutOfRangeException">If the given timeout is negative.</exception> public void AddParallel(Command command, double timeout) { lock (m_syncRoot) { Validate("Can not add new command to command group"); if (command == null) throw new ArgumentNullException(nameof(command), "Given null command"); if (timeout < 0) throw new ArgumentOutOfRangeException(nameof(command), "Can not be given a negative timeout"); command.SetParent(this); m_commands.Add(new Entry(command, Entry.BRANCH_CHILD, timeout)); foreach (Subsystem e in command.GetRequirements()) { Requires(e); } } }
/// <summary> /// Starts the command when the button is released /// </summary> /// <param name="command">The command to start</param> public void WhenInactive(Command command) { new ReleasedButtonScheduler(Grab(), this, command).Start(); }
internal Entry(Command command, int state) { this.command = command; this.state = state; timeout = -1; }
/// <summary> /// Toggles the command whenever the button is pressed (on then off then on) /// </summary> /// <param name="command">The command to start</param> public void ToggleWhenActive(Command command) { new ToggleButtonScheduler(Grab(), this, command).Start(); }
/// <summary> /// Cancel the command when the button is pressed. /// </summary> /// <param name="command">The command to start</param> public void CancelWhenActive(Command command) { new CancelButtonScheduler(Grab(), this, command).Start(); }
/// <summary> /// Starts the given command whenever the button is newly pressed /// </summary> /// <param name="command">The command to start</param> public void WhenPressed(Command command) { WhenActive(command); }