Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

State machine #34

Merged
merged 26 commits into from
Jan 18, 2025
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
d1a570f
Base Implementation of State Machines
avidraccoon Sep 9, 2024
d83aa7d
Minor Changes to fix logic
avidraccoon Sep 9, 2024
08e5307
Rearranged order of methods for better readability
avidraccoon Sep 10, 2024
8e36b57
Added Json loading
avidraccoon Sep 10, 2024
d587d6e
Basic Test Classes Implementation
avidraccoon Sep 10, 2024
b63ea88
Fixed errors
avidraccoon Sep 12, 2024
9d60bee
Do not push
avidraccoon Sep 16, 2024
5514aae
WIP rewrite of state machine
avidraccoon Nov 10, 2024
3b1a0a3
Added simple tests (Most likly will change soon)
avidraccoon Nov 10, 2024
8833d54
WIP - Added better type support for enums and half complete test. Mig…
avidraccoon Nov 11, 2024
c7db46f
State to figure out new functions and start polishing StateMachine
avidraccoon Nov 19, 2024
efd8ec0
Add more customization
avidraccoon Nov 20, 2024
21040fa
Mostly ready state machine
avidraccoon Nov 21, 2024
51d391e
Merge branch 'main' into StateMachine
avidraccoon Dec 2, 2024
b691820
Merge branch 'main' into StateMachine
avidraccoon Dec 16, 2024
57a9a59
WIP - Adding Javadocs, Fixing Structure, and Finish Implementing cust…
avidraccoon Jan 9, 2025
9f604a4
WIP - Javadocs
avidraccoon Jan 11, 2025
13899a9
Merge branch 'main' into StateMachine
avidraccoon Jan 17, 2025
707209c
More JavaDocs
avidraccoon Jan 17, 2025
590e167
Merge branch 'StateMachine' of https://github.com/team401/coppercore …
avidraccoon Jan 17, 2025
fab07d9
Fixed Building I hope
avidraccoon Jan 17, 2025
9cf1047
more java docs
avidraccoon Jan 18, 2025
ad3ebec
Finished State Machine Javadocs
avidraccoon Jan 18, 2025
99fb614
Merge branch 'main' into StateMachine
avidraccoon Jan 18, 2025
3f81248
.
avidraccoon Jan 18, 2025
4644f4d
Merge branch 'StateMachine' of https://github.com/team401/coppercore …
avidraccoon Jan 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions controls/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -66,6 +65,12 @@ tasks.named('test') {
useJUnitPlatform()
}



test {
useJUnitPlatform()
}

compileJava.dependsOn 'spotlessApply'


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package coppercore.controls;

public interface PeriodicStateInterface extends StateInterface {

public default void periodic() {}
}
151 changes: 151 additions & 0 deletions controls/src/main/java/state_machine/State/StateConfiguration.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package coppercore.controls;

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<State, Trigger> {

private List<Transition<State, Trigger>> transitions;
private State source;
private Consumer<Transition> onEntryAction;
private Consumer<Transition> onExitAction;
private Consumer<Transition> transitionAction;
private boolean runDefaultTransitionAction = true;
private boolean runDefaultEntryAction = true;
private boolean runDefaultExitAction = true;

public StateConfiguration(State source) {
this.source = source;
// Temp solution
transitions = new ArrayList<>();
}

public StateConfiguration<State, Trigger> permit(Trigger trigger, State destination) {
if (getFilteredTransition(trigger).isEmpty()) {
transitions.add(new Transition<>(source, destination, trigger, false));
}
return this;
}

public StateConfiguration<State, Trigger> permitInternal(Trigger trigger, State destination) {
if (getFilteredTransition(trigger).isEmpty()) {
transitions.add(new Transition<>(source, destination, trigger, true));
}
return this;
}

public StateConfiguration<State, Trigger> permitIf(
Trigger trigger, State destination, BooleanSupplier check) {
if (getFilteredTransition(trigger).isEmpty()) {
transitions.add(new ConditinalTransition<>(source, destination, trigger, check, false));
}
return this;
}

public StateConfiguration<State, Trigger> permitInternalIf(
Trigger trigger, State destination, BooleanSupplier check) {
if (getFilteredTransition(trigger).isEmpty()) {
transitions.add(new ConditinalTransition<>(source, destination, trigger, check, true));
}
return this;
}

public List<Transition<State, Trigger>> getTransitions(Trigger trigger) {
List<Transition<State, Trigger>> matchedTransitions = new ArrayList<>();
if (trigger == null) return matchedTransitions;
for (Transition<State, Trigger> transition : transitions) {
if (trigger.equals(transition.getTrigger())) {
matchedTransitions.add(transition);
}
}
return matchedTransitions;
}

private Optional<Transition<State, Trigger>> filterTransitions(
List<Transition<State, Trigger>> transitions) {
Optional<Transition<State, Trigger>> returnOptional = Optional.empty();
boolean conditinal = false;
for (Transition<State, Trigger> transition : transitions) {
if (transition instanceof ConditinalTransition) {
if (conditinal
&& ((ConditinalTransition<State, Trigger>) transition).isCheckTrue()) {
return Optional.empty();
} else {
returnOptional = Optional.of(transition);
conditinal = true;
}
} else if (!conditinal) {
returnOptional = Optional.of(transition);
}
}
return returnOptional;
}

public Optional<Transition<State, Trigger>> 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 void runTransition(Transition transition) {
if (transitionAction != null) {
transitionAction.accept(transition);
}
}

public StateConfiguration<State, Trigger> disableDefaultTransitionAction(){
this.runDefaultTransitionAction = false;
return this;
}

public StateConfiguration<State, Trigger> disableDefualtOnEntry(){
this.runDefaultEntryAction = false;
return this;
}

public StateConfiguration<State, Trigger> disableDefualtOnExit(){
this.runDefaultExitAction = false;
return this;
}

public StateConfiguration<State, Trigger> configureOnEntryAction(Consumer<Transition> action){
this.onEntryAction = action;
return this;
}

public StateConfiguration<State, Trigger> configureOnExitAction(Consumer<Transition> action){
this.onExitAction = action;
return this;
}

public StateConfiguration<State, Trigger> configureTransitionAction(Consumer<Transition> action){
this.transitionAction = action;
return this;
}

public boolean doRunDefaultEntryAction(){
return runDefaultEntryAction;
}

public boolean doRunDefaultExitAction(){
return runDefaultExitAction;
}

public boolean doRunDefaultTransitionAction(){
return runDefaultTransitionAction;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package coppercore.controls;

public interface StateContainer {

public StateInterface getState();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package coppercore.controls;

public interface StateInterface {

public default void onEntry(Transition transition) {}

public default void onExit(Transition transition) {}
}
60 changes: 60 additions & 0 deletions controls/src/main/java/state_machine/StateMachine.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package coppercore.controls;

import java.util.Optional;

public class StateMachine<State, Trigger> {
private StateMachineConfiguration configuration;
private TransitionInfo transitionInfo;
private State currentState;

public StateMachine(StateMachineConfiguration config, State initialState) {
configuration = config;
currentState = initialState;
}

public void fire(Trigger trigger) {
transitionInfo = new TransitionInfo(currentState, trigger);
Optional<Transition<State, Trigger>> transitionOptional =
configuration.getTransition(currentState, trigger);
if (transitionOptional.isEmpty()) {
transitionInfo.fail();
return;
}
Transition<State, Trigger> transition = transitionOptional.get();
if (!transition.canTransition()) {
transitionInfo.fail();
return;
}
transitionInfo.setTransition(transition);
if (!transition.isInternal()) {
Optional<StateConfiguration> currentStateConfigurationOptional =
configuration.getStateConfiguration(currentState);
Optional<StateConfiguration> nextStateConfigurationOptional =
configuration.getStateConfiguration(transition.getDestination());
if (currentStateConfigurationOptional.isPresent()) {
currentStateConfigurationOptional.get().runOnEntry(transition);
}
transition.runAction();
if (nextStateConfigurationOptional.isPresent()) {
nextStateConfigurationOptional.get().runOnExit(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);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package coppercore.controls;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.BiConsumer;

public class StateMachineConfiguration<State, Trigger> {
private Map<State, StateConfiguration<State, Trigger>> stateConfigurations;
private BiConsumer<State, Transition> onEntryAction;
private BiConsumer<State, Transition> onExitAction;
private BiConsumer<State, Transition> transitionAction;

public StateMachineConfiguration() {
// temp solution
stateConfigurations = new HashMap<>();
}

public StateConfiguration<State, Trigger> configure(State source) {
StateConfiguration<State, Trigger> configuration = stateConfigurations.get(source);
if (configuration == null) {
configuration = new StateConfiguration<>(source);
stateConfigurations.put(source, configuration);
}

return configuration;
}

public Optional<StateConfiguration<State, Trigger>> getStateConfiguration(State source) {
Optional<StateConfiguration<State, Trigger>> configurationOptional = Optional.empty();

if (stateConfigurations.containsKey(source)) {
StateConfiguration<State, Trigger> configuration = stateConfigurations.get(source);
if (configuration != null) {
configurationOptional = Optional.of(configuration);
}
}

return configurationOptional;
}

public Optional<Transition<State, Trigger>> getTransition(State state, Trigger trigger) {
Optional<Transition<State, Trigger>> transition = Optional.empty();
Optional<StateConfiguration<State, Trigger>> configurationOptional =
getStateConfiguration(state);

if (configurationOptional.isPresent()) {
StateConfiguration<State, Trigger> configuration = configurationOptional.get();
Optional<Transition<State, Trigger>> transitionOptional =
configuration.getFilteredTransition(trigger);
transition = transition.or(() -> transitionOptional);
}

return transition;
}

public StateMachineConfiguration<State, Trigger> configureDefaultOnEntryAction(BiConsumer<State, Transition> action){
this.onEntryAction = action;
return this;
}

public StateMachineConfiguration<State, Trigger> configureDefaultOnExitAction(BiConsumer<State, Transition> action){
this.onExitAction = action;
return this;
}

public StateMachineConfiguration<State, Trigger> configureDefaultTransitionAction(BiConsumer<State, Transition> action){
this.transitionAction = action;
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package coppercore.controls;

import java.util.function.BooleanSupplier;

public class ConditinalTransition<State, Trigger> extends Transition<State, Trigger> {

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();
}
}
Loading
Loading