// 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. package org.wpilib.command3; import static java.util.Objects.requireNonNull; /** Represents the state of a command as it is executed by the scheduler. */ final class CommandState { // Two billion unique IDs should be enough for anybody. private static int s_lastId = 0; private final Command m_command; private final Command m_parent; private final Coroutine m_coroutine; private final Binding m_binding; private double m_lastRuntimeMs = -1; private double m_totalRuntimeMs; private final int m_id; /** * Creates a new command state object. * * @param command The command being tracked. * @param parent The parent command composition that scheduled the tracked command. Null if the * command was scheduled by a top level construct like trigger bindings or manually scheduled * by a user. For deeply nested compositions, this tracks the direct parent command * that invoked the schedule() call; in this manner, an ancestry tree can be built, where each * {@code CommandState} object references a parent node in the tree. * @param coroutine The coroutine to which the command is bound. * @param binding The binding that caused the command to be scheduled. */ CommandState(Command command, Command parent, Coroutine coroutine, Binding binding) { m_command = requireNonNull(command, "WPILib bug: command state given null command"); m_parent = parent; // allowed to be null m_coroutine = requireNonNull(coroutine, "WPILib bug: command state given null coroutine"); m_binding = requireNonNull(binding, "WPILib bug: command state given null binding"); // This is incredibly non-thread safe, but nobody should be using the command framework across // multiple threads anyway. Worst case scenario, we'll get duplicate IDs for commands scheduled // by different threads and cause bad telemetry data without affecting program correctness. m_id = ++s_lastId; } public Command command() { return m_command; } public Command parent() { return m_parent; } public Coroutine coroutine() { return m_coroutine; } public Binding binding() { return m_binding; } /** * How long the command took to run the last time it executed. Defaults to -1 if the command has * not run at least once. * * @return The runtime, in milliseconds. */ public double lastRuntimeMs() { return m_lastRuntimeMs; } public void setLastRuntimeMs(double lastRuntimeMs) { m_lastRuntimeMs = lastRuntimeMs; m_totalRuntimeMs += lastRuntimeMs; } public double totalRuntimeMs() { return m_totalRuntimeMs; } public int id() { return m_id; } @Override public boolean equals(Object obj) { return obj instanceof CommandState that && m_id == that.m_id; } @Override public int hashCode() { return m_id; } @Override public String toString() { return "CommandState[command=%s, parent=%s, coroutine=%s, id=%d]" .formatted(m_command, m_parent, m_coroutine, m_id); } }