diff --git a/controls/build.gradle b/controls/build.gradle index 6415c0b..8abe525 100644 --- a/controls/build.gradle +++ b/controls/build.gradle @@ -44,14 +44,13 @@ compileJava.dependsOn 'spotlessApply' dependencies { // Use JUnit Jupiter for testing. testImplementation libs.junit.jupiter - testRuntimeOnly 'org.junit.platform:junit-platform-launcher' - // This dependency is exported to consumers, that is to say found on their compile classpath. api libs.commons.math3 // This dependency is used internally, and not exposed to consumers on their own compile classpath. implementation libs.guava + implementation project(":parameter_tools") } // Apply a specific Java toolchain to ease working on different environments. @@ -66,6 +65,12 @@ tasks.named('test') { useJUnitPlatform() } + + +test { + useJUnitPlatform() +} + compileJava.dependsOn 'spotlessApply' diff --git a/controls/src/main/java/Tunable.java b/controls/src/main/java/coppercore/controls/Tunable.java similarity index 100% rename from controls/src/main/java/Tunable.java rename to controls/src/main/java/coppercore/controls/Tunable.java diff --git a/controls/src/main/java/coppercore/controls/state_machine/StateMachine.java b/controls/src/main/java/coppercore/controls/state_machine/StateMachine.java new file mode 100644 index 0000000..28064a8 --- /dev/null +++ b/controls/src/main/java/coppercore/controls/state_machine/StateMachine.java @@ -0,0 +1,82 @@ +package coppercore.controls.state_machine; + +import coppercore.controls.state_machine.state.StateConfiguration; +import coppercore.controls.state_machine.transition.Transition; +import coppercore.controls.state_machine.transition.TransitionInfo; +import java.util.Optional; + +public class StateMachine { + private final StateMachineConfiguration configuration; + private TransitionInfo transitionInfo; + private State currentState; + + public StateMachine(StateMachineConfiguration config, State initialState) { + configuration = config; + currentState = initialState; + } + + /** + * Method to transition States based on given trigger + * + * @param trigger + */ + public void fire(Trigger trigger) { + transitionInfo = new TransitionInfo<>(currentState, trigger); + Optional> transitionOptional = + configuration.getTransition(currentState, trigger); + if (transitionOptional.isEmpty()) { + transitionInfo.fail(); + return; + } + Transition transition = transitionOptional.get(); + if (!transition.canTransition()) { + transitionInfo.fail(); + return; + } + transitionInfo.setTransition(transition); + if (!transition.isInternal()) { + Optional> currentStateConfigurationOptional = + configuration.getStateConfiguration(currentState); + Optional> nextStateConfigurationOptional = + configuration.getStateConfiguration(transition.getDestination()); + if (currentStateConfigurationOptional.isPresent()) { + StateConfiguration config = currentStateConfigurationOptional.get(); + if (config.doRunDefaultExitAction()) { + configuration.runOnExit(transition); + } else { + config.runOnExit(transition); + } + } else { + configuration.runOnExit(transition); + } + transition.runAction(); + if (nextStateConfigurationOptional.isPresent()) { + StateConfiguration config = nextStateConfigurationOptional.get(); + if (config.doRunDefaultExitAction()) { + configuration.runOnEntry(transition); + } else { + config.runOnEntry(transition); + } + } else { + configuration.runOnEntry(transition); + } + } + currentState = transition.getDestination(); + } + + public State getCurrentState() { + return currentState; + } + + public boolean successfulTransition() { + return !transitionInfo.wasFail(); + } + + public TransitionInfo getTransitionInfo() { + return transitionInfo; + } + + public boolean inState(State state) { + return currentState.equals(state); + } +} diff --git a/controls/src/main/java/coppercore/controls/state_machine/StateMachineConfiguration.java b/controls/src/main/java/coppercore/controls/state_machine/StateMachineConfiguration.java new file mode 100644 index 0000000..18ddee0 --- /dev/null +++ b/controls/src/main/java/coppercore/controls/state_machine/StateMachineConfiguration.java @@ -0,0 +1,113 @@ +package coppercore.controls.state_machine; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.function.Consumer; + +import coppercore.controls.state_machine.state.StateConfiguration; +import coppercore.controls.state_machine.transition.Transition; + +public class StateMachineConfiguration { + private final Map> stateConfigurations; + private Consumer> onEntryAction; + private Consumer> onExitAction; + + public StateMachineConfiguration() { + // temp solution + stateConfigurations = new HashMap<>(); + } + + /** + * Starts configuration of a state returning a StateConfiguration and registers it for the state. + * @param state + * @return + */ + public StateConfiguration configure(State source) { + StateConfiguration configuration = stateConfigurations.get(source); + if (configuration == null) { + configuration = new StateConfiguration<>(source); + stateConfigurations.put(source, configuration); + } + return configuration; + } + + /** + * Gets a StateConfiguration specified by State + * @param state + * @return + */ + public Optional> getStateConfiguration(State source) { + Optional> configurationOptional = Optional.empty(); + + if (stateConfigurations.containsKey(source)) { + StateConfiguration configuration = stateConfigurations.get(source); + if (configuration != null) { + configurationOptional = Optional.of(configuration); + } + } + + return configurationOptional; + } + + /** + * Gets a Transition defined by State and Trigger + * @param state + * @param trigger + * @return + */ + public Optional> getTransition(State state, Trigger trigger) { + Optional> transition = Optional.empty(); + Optional> configurationOptional = + getStateConfiguration(state); + + if (configurationOptional.isPresent()) { + StateConfiguration configuration = configurationOptional.get(); + Optional> transitionOptional = + configuration.getFilteredTransition(trigger); + transition = transition.or(() -> transitionOptional); + } + + return transition; + } + + /** + * Set the default onEntry function. + * @param transition + */ + public StateMachineConfiguration configureDefaultOnEntryAction( + Consumer> action) { + this.onEntryAction = action; + return this; + } + + /** + * Set the default onExit function. + * @param transition + */ + public StateMachineConfiguration configureDefaultOnExitAction( + Consumer> action) { + this.onExitAction = action; + return this; + } + + /** + * Method used by statemachine to handle processing on entry of a state. + * @param transition + */ + public void runOnEntry(Transition transition) { + if (onEntryAction != null) { + onEntryAction.accept(transition); + } + } + + /** + * Method used by statemachine to handle processing on exiting of a state. + * @param transition + */ + public void runOnExit(Transition transition) { + if (onExitAction != null) { + onExitAction.accept(transition); + } + } +} diff --git a/controls/src/main/java/coppercore/controls/state_machine/state/PeriodicStateInterface.java b/controls/src/main/java/coppercore/controls/state_machine/state/PeriodicStateInterface.java new file mode 100644 index 0000000..96af96b --- /dev/null +++ b/controls/src/main/java/coppercore/controls/state_machine/state/PeriodicStateInterface.java @@ -0,0 +1,6 @@ +package coppercore.controls.state_machine.state; + +public interface PeriodicStateInterface extends StateInterface { + + public default void periodic() {} +} diff --git a/controls/src/main/java/coppercore/controls/state_machine/state/StateConfiguration.java b/controls/src/main/java/coppercore/controls/state_machine/state/StateConfiguration.java new file mode 100644 index 0000000..32a8c1f --- /dev/null +++ b/controls/src/main/java/coppercore/controls/state_machine/state/StateConfiguration.java @@ -0,0 +1,163 @@ +package coppercore.controls.state_machine.state; + +import coppercore.controls.state_machine.transition.ConditinalTransition; +import coppercore.controls.state_machine.transition.Transition; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.function.BooleanSupplier; +import java.util.function.Consumer; + +public class StateConfiguration { + + private List> transitions; + private State source; + private Consumer onEntryAction; + private Consumer onExitAction; + private boolean runDefaultEntryAction = true; + private boolean runDefaultExitAction = true; + + public StateConfiguration(State source) { + this.source = source; + // Temp solution + transitions = new ArrayList<>(); + } + + /** + * Create Transition between States + * + * @param trigger + * @param destination + * @return + */ + public StateConfiguration permit(Trigger trigger, State destination) { + if (getFilteredTransition(trigger).isEmpty()) { + transitions.add(new Transition<>(source, destination, trigger, false)); + } + return this; + } + + /** + * Create Transistion between states without trigger the enter or exit functions. + * + * @param trigger + * @param destination + * @return + */ + public StateConfiguration permitInternal(Trigger trigger, State destination) { + if (getFilteredTransition(trigger).isEmpty()) { + transitions.add(new Transition<>(source, destination, trigger, true)); + } + return this; + } + + /** + * Creates a Conditional Transition that only fires if both the right Trigger is fired and the + * check lambda evaluates to true + * + * @param trigger + * @param destination + * @param check + * @return + */ + public StateConfiguration permitIf( + Trigger trigger, State destination, BooleanSupplier check) { + if (getFilteredTransition(trigger).isEmpty()) { + transitions.add(new ConditinalTransition<>(source, destination, trigger, check, false)); + } + return this; + } + + /** + * Creates a Conditional Internal Transition that only fires if both the right Trigger is fired + * and the check lambda evaluates to true. This transition will not trigger the enter or exit + * functions. + * + * @param trigger + * @param destination + * @param check + * @return + */ + public StateConfiguration permitInternalIf( + Trigger trigger, State destination, BooleanSupplier check) { + if (getFilteredTransition(trigger).isEmpty()) { + transitions.add(new ConditinalTransition<>(source, destination, trigger, check, true)); + } + return this; + } + + public List> getTransitions(Trigger trigger) { + List> matchedTransitions = new ArrayList<>(); + if (trigger == null) return matchedTransitions; + for (Transition transition : transitions) { + if (trigger.equals(transition.getTrigger())) { + matchedTransitions.add(transition); + } + } + return matchedTransitions; + } + + private Optional> filterTransitions( + List> transitions) { + Optional> returnOptional = Optional.empty(); + boolean conditinal = false; + for (Transition transition : transitions) { + if (transition instanceof ConditinalTransition) { + if (conditinal + && ((ConditinalTransition) transition).isCheckTrue()) { + return Optional.empty(); + } else { + returnOptional = Optional.of(transition); + conditinal = true; + } + } else if (!conditinal) { + returnOptional = Optional.of(transition); + } + } + return returnOptional; + } + + public Optional> getFilteredTransition(Trigger trigger) { + return filterTransitions(getTransitions(trigger)); + } + + public void runOnEntry(Transition transition) { + if (onEntryAction != null) { + onEntryAction.accept(transition); + } + } + + public void runOnExit(Transition transition) { + if (onExitAction != null) { + onExitAction.accept(transition); + } + } + + public StateConfiguration disableDefualtOnEntry() { + this.runDefaultEntryAction = false; + return this; + } + + public StateConfiguration disableDefualtOnExit() { + this.runDefaultExitAction = false; + return this; + } + + public StateConfiguration configureOnEntryAction(Consumer action) { + this.onEntryAction = action; + return this; + } + + public StateConfiguration configureOnExitAction(Consumer action) { + this.onExitAction = action; + return this; + } + + public boolean doRunDefaultEntryAction() { + return runDefaultEntryAction; + } + + public boolean doRunDefaultExitAction() { + return runDefaultExitAction; + } +} diff --git a/controls/src/main/java/coppercore/controls/state_machine/state/StateContainer.java b/controls/src/main/java/coppercore/controls/state_machine/state/StateContainer.java new file mode 100644 index 0000000..7bf9404 --- /dev/null +++ b/controls/src/main/java/coppercore/controls/state_machine/state/StateContainer.java @@ -0,0 +1,6 @@ +package coppercore.controls.state_machine.state; + +public interface StateContainer { + + public StateInterface getState(); +} diff --git a/controls/src/main/java/coppercore/controls/state_machine/state/StateInterface.java b/controls/src/main/java/coppercore/controls/state_machine/state/StateInterface.java new file mode 100644 index 0000000..4031424 --- /dev/null +++ b/controls/src/main/java/coppercore/controls/state_machine/state/StateInterface.java @@ -0,0 +1,10 @@ +package coppercore.controls.state_machine.state; + +import coppercore.controls.state_machine.transition.Transition; + +public interface StateInterface { + + public default void onEntry(Transition transition) {} + + public default void onExit(Transition transition) {} +} diff --git a/controls/src/main/java/coppercore/controls/state_machine/transition/ConditinalTransition.java b/controls/src/main/java/coppercore/controls/state_machine/transition/ConditinalTransition.java new file mode 100644 index 0000000..9db19d6 --- /dev/null +++ b/controls/src/main/java/coppercore/controls/state_machine/transition/ConditinalTransition.java @@ -0,0 +1,31 @@ +package coppercore.controls.state_machine.transition; + +import java.util.function.BooleanSupplier; + +public class ConditinalTransition extends Transition { + + private final BooleanSupplier check; + + public ConditinalTransition( + State source, State destination, Trigger trigger, BooleanSupplier check) { + this(source, destination, trigger, check, false); + } + + public ConditinalTransition( + State source, + State destination, + Trigger trigger, + BooleanSupplier check, + boolean internalTransition) { + super(source, destination, trigger, internalTransition); + this.check = check; + } + + public boolean canTransition() { + return isCheckTrue(); + } + + public boolean isCheckTrue() { + return check != null && check.getAsBoolean(); + } +} diff --git a/controls/src/main/java/coppercore/controls/state_machine/transition/Transition.java b/controls/src/main/java/coppercore/controls/state_machine/transition/Transition.java new file mode 100644 index 0000000..b823327 --- /dev/null +++ b/controls/src/main/java/coppercore/controls/state_machine/transition/Transition.java @@ -0,0 +1,53 @@ +package coppercore.controls.state_machine.transition; + +import java.util.function.Consumer; + +public class Transition { + private State source; + private State destination; + private Trigger trigger; + private Consumer action; + private boolean internalTransition; + + public Transition(State source, State destination, Trigger trigger) { + this(source, destination, trigger, false); + } + + public Transition( + State source, State destination, Trigger trigger, boolean internalTransition) { + this.source = source; + this.destination = destination; + this.trigger = trigger; + this.internalTransition = internalTransition; + } + + public State getSource() { + return source; + } + + public State getDestination() { + return destination; + } + + public Trigger getTrigger() { + return trigger; + } + + public boolean canTransition() { + return true; + } + + public void runAction() { + if (action != null) { + action.accept(this); + } + } + + public boolean isInternal() { + return internalTransition; + } + + public boolean isReentrant() { + return source != null && source.equals(trigger); + } +} diff --git a/controls/src/main/java/coppercore/controls/state_machine/transition/TransitionInfo.java b/controls/src/main/java/coppercore/controls/state_machine/transition/TransitionInfo.java new file mode 100644 index 0000000..2fcb1e6 --- /dev/null +++ b/controls/src/main/java/coppercore/controls/state_machine/transition/TransitionInfo.java @@ -0,0 +1,47 @@ +package coppercore.controls.state_machine.transition; + +public class TransitionInfo { + private final State currentState; + private State targetState; + private final Trigger trigger; + private boolean failed = false; + private Transition transition; + + public TransitionInfo(State currentState, Trigger trigger) { + this.currentState = currentState; + this.trigger = trigger; + } + + public void setTargetState(State targetState) { + this.targetState = targetState; + } + + public void setTransition(Transition transition) { + targetState = transition.getDestination(); + this.transition = transition; + } + + public State getCurrentState() { + return currentState; + } + + public State getTargetState() { + return targetState; + } + + public Trigger getTrigger() { + return trigger; + } + + public Transition getTransition() { + return transition; + } + + public void fail() { + failed = true; + } + + public boolean wasFail() { + return failed; + } +} diff --git a/controls/src/test/java/coppercore/controls/test/SimpleEnumStateMachineTests.java b/controls/src/test/java/coppercore/controls/test/SimpleEnumStateMachineTests.java new file mode 100644 index 0000000..54f5fe6 --- /dev/null +++ b/controls/src/test/java/coppercore/controls/test/SimpleEnumStateMachineTests.java @@ -0,0 +1,94 @@ +package coppercore.controls.test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import coppercore.controls.state_machine.StateMachine; +import coppercore.controls.state_machine.StateMachineConfiguration; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class SimpleEnumStateMachineTests { + + static enum simpleEnumStates { + IDLE, + READY, + WAITING, + DONE, + SHUTDOWN, + } + + static enum simpleEnumTriggers { + PREPARE, + POLL, + WAITING, + FINISH, + SHUTDOWN, + ERROR + } + + public static StateMachineConfiguration + simpleEnumMachineConfig; + + @BeforeAll + public static void setup() { + simpleEnumMachineConfig = new StateMachineConfiguration<>(); + + simpleEnumMachineConfig + .configure(simpleEnumStates.IDLE) + .permit(simpleEnumTriggers.PREPARE, simpleEnumStates.READY); + + simpleEnumMachineConfig + .configure(simpleEnumStates.READY) + .permit(simpleEnumTriggers.POLL, simpleEnumStates.WAITING); + + simpleEnumMachineConfig + .configure(simpleEnumStates.WAITING) + .permit(simpleEnumTriggers.FINISH, simpleEnumStates.DONE) + .permit(simpleEnumTriggers.ERROR, simpleEnumStates.SHUTDOWN); + + simpleEnumMachineConfig + .configure(simpleEnumStates.DONE) + .permit(simpleEnumTriggers.PREPARE, simpleEnumStates.READY) + .permit(simpleEnumTriggers.SHUTDOWN, simpleEnumStates.SHUTDOWN); + } + + @Test + void stateMachineTransitionNoErrorTest() { + StateMachine stateMachine = + new StateMachine<>(simpleEnumMachineConfig, simpleEnumStates.IDLE); + assertEquals(simpleEnumStates.IDLE, stateMachine.getCurrentState()); + stateMachine.fire(simpleEnumTriggers.PREPARE); + assertEquals(simpleEnumStates.READY, stateMachine.getCurrentState()); + stateMachine.fire(simpleEnumTriggers.POLL); + assertEquals(simpleEnumStates.WAITING, stateMachine.getCurrentState()); + stateMachine.fire(simpleEnumTriggers.FINISH); + assertEquals(simpleEnumStates.DONE, stateMachine.getCurrentState()); + stateMachine.fire(simpleEnumTriggers.PREPARE); + assertEquals(simpleEnumStates.READY, stateMachine.getCurrentState()); + stateMachine.fire(simpleEnumTriggers.POLL); + assertEquals(simpleEnumStates.WAITING, stateMachine.getCurrentState()); + stateMachine.fire(simpleEnumTriggers.FINISH); + assertEquals(simpleEnumStates.DONE, stateMachine.getCurrentState()); + stateMachine.fire(simpleEnumTriggers.SHUTDOWN); + assertEquals(simpleEnumStates.SHUTDOWN, stateMachine.getCurrentState()); + } + + @Test + void stateMachineTransitionErrorTest() { + StateMachine stateMachine = + new StateMachine<>(simpleEnumMachineConfig, simpleEnumStates.IDLE); + assertEquals(simpleEnumStates.IDLE, stateMachine.getCurrentState()); + stateMachine.fire(simpleEnumTriggers.PREPARE); + assertEquals(simpleEnumStates.READY, stateMachine.getCurrentState()); + stateMachine.fire(simpleEnumTriggers.POLL); + assertEquals(simpleEnumStates.WAITING, stateMachine.getCurrentState()); + stateMachine.fire(simpleEnumTriggers.FINISH); + assertEquals(simpleEnumStates.DONE, stateMachine.getCurrentState()); + stateMachine.fire(simpleEnumTriggers.PREPARE); + assertEquals(simpleEnumStates.READY, stateMachine.getCurrentState()); + stateMachine.fire(simpleEnumTriggers.POLL); + assertEquals(simpleEnumStates.WAITING, stateMachine.getCurrentState()); + stateMachine.fire(simpleEnumTriggers.ERROR); + assertEquals(simpleEnumStates.SHUTDOWN, stateMachine.getCurrentState()); + } +} diff --git a/controls/src/test/java/coppercore/controls/test/StateContainerStateMachineTests.java b/controls/src/test/java/coppercore/controls/test/StateContainerStateMachineTests.java new file mode 100644 index 0000000..1338ca6 --- /dev/null +++ b/controls/src/test/java/coppercore/controls/test/StateContainerStateMachineTests.java @@ -0,0 +1,131 @@ +package coppercore.controls.test; + +import coppercore.controls.state_machine.StateMachine; +import coppercore.controls.state_machine.StateMachineConfiguration; +import coppercore.controls.state_machine.state.PeriodicStateInterface; +import coppercore.controls.state_machine.state.StateContainer; +import coppercore.controls.state_machine.transition.Transition; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class StateContainerStateMachineTests { + + static class IdleState implements PeriodicStateInterface { + public static void customOnEntry( + Transition transition) {} + + public static void customOnExit( + Transition transition) {} + + public static void customTransitionAction( + Transition transition) {} + } + ; + + static class ReadyState implements PeriodicStateInterface {} + ; + + static class WaitingState implements PeriodicStateInterface {} + ; + + static class DoneState implements PeriodicStateInterface {} + ; + + static class ShutdownState implements PeriodicStateInterface {} + ; + + static enum testStateContainer implements StateContainer { + IDLE(new IdleState()), + READY(new ReadyState()), + WAITING(new WaitingState()), + DONE(new DoneState()), + SHUTDOWN(new ShutdownState()); + + private final PeriodicStateInterface state; + + testStateContainer(PeriodicStateInterface state) { + this.state = state; + } + + @Override + public PeriodicStateInterface getState() { + return state; + } + } + + static enum testEnumTriggers { + PREPARE, + POLL, + WAITING, + FINISH, + SHUTDOWN, + ERROR + } + + protected static StateMachineConfiguration + stateContainerTestMachineConfig; + + @BeforeAll + public static void setup() { + stateContainerTestMachineConfig = new StateMachineConfiguration<>(); + + stateContainerTestMachineConfig + .configureDefaultOnExitAction( + (Transition transition) -> + transition.getSource().getState().onEntry(transition)) + .configureDefaultOnExitAction( + (Transition transition) -> + transition.getSource().getState().onExit(transition)); + + // stateContainerTestMachineConfig + // .registerBlankParent(testStateContainer.SOME_PARENT_STATE); Not in first + // Implemenation + + // stateContainerTestMachineConfig + // .configure(testStateContainer.SOME_STATE); Not in first Implemenation + + stateContainerTestMachineConfig + .configure(testStateContainer.IDLE) + // .parentState(testStateContainer.SOME_STATE) Not in first Implemenation + .permit(testEnumTriggers.PREPARE, testStateContainer.READY) + .permitInternal(testEnumTriggers.PREPARE, testStateContainer.READY) + .configureOnEntryAction(IdleState::customOnEntry) + .configureOnExitAction(IdleState::customOnExit) + .disableDefualtOnEntry() + .disableDefualtOnExit(); + + stateContainerTestMachineConfig + .configure(testStateContainer.READY) + .permit(testEnumTriggers.POLL, testStateContainer.WAITING); + + stateContainerTestMachineConfig + .configure(testStateContainer.WAITING) + .permit(testEnumTriggers.FINISH, testStateContainer.DONE) + .permit(testEnumTriggers.ERROR, testStateContainer.SHUTDOWN); + + stateContainerTestMachineConfig + .configure(testStateContainer.DONE) + .permit(testEnumTriggers.PREPARE, testStateContainer.READY) + .permit(testEnumTriggers.SHUTDOWN, testStateContainer.SHUTDOWN); + } + + @Test + void stateMachineTransitionNoErrorTest() { + StateMachine stateMachine = + new StateMachine<>(stateContainerTestMachineConfig, testStateContainer.IDLE); + testStateContainer stateContainer = stateMachine.getCurrentState(); + // stateMachine.inState(testStateContainer.SOME_STATE); Not in first Implemenation //True + stateMachine.inState(testStateContainer.IDLE); // True + // stateMachine.inStateExactly(testStateContainer.SOME_STATE); Not in first Implemenation + // //False + // stateMachine.inState(testStateContainer.SOME_PARENT_STATE); Not in first Implemenation + // //False + stateContainer.getState().periodic(); + } + + @Test + void stateMachineTransitionErrorTest() { + StateMachine stateMachine = + new StateMachine<>(stateContainerTestMachineConfig, testStateContainer.IDLE); + } +} diff --git a/wpilib_interface/src/main/java/frc/robot/BuildConstants.java b/wpilib_interface/src/main/java/frc/robot/BuildConstants.java index 09c9ba9..fec0920 100644 --- a/wpilib_interface/src/main/java/frc/robot/BuildConstants.java +++ b/wpilib_interface/src/main/java/frc/robot/BuildConstants.java @@ -5,12 +5,12 @@ public final class BuildConstants { public static final String MAVEN_GROUP = "io.github.team401.coppercore"; public static final String MAVEN_NAME = "wpilib_interface"; public static final String VERSION = "2025.0.0-beta"; - public static final int GIT_REVISION = 42; - public static final String GIT_SHA = "ae92bd015cfea62f3e15e05ecaa129c58aa316b1"; - public static final String GIT_DATE = "2024-12-06 12:09:14 EST"; - public static final String GIT_BRANCH = "64-clamp-measures"; - public static final String BUILD_DATE = "2024-12-07 23:05:47 EST"; - public static final long BUILD_UNIX_TIME = 1733630747090L; + public static final int GIT_REVISION = 60; + public static final String GIT_SHA = "57a9a59be71b97fe6ff7eb6e86b66c0ce85d54d7"; + public static final String GIT_DATE = "2025-01-09 10:07:23 EST"; + public static final String GIT_BRANCH = "StateMachine"; + public static final String BUILD_DATE = "2025-01-10 21:52:31 EST"; + public static final long BUILD_UNIX_TIME = 1736563951605L; public static final int DIRTY = 1; private BuildConstants() {}