RIT VEXU Core API
Loading...
Searching...
No Matches
state_machine.h
1#pragma once
2#include <string>
3#include <type_traits>
4#include <utility>
5
34template <typename System, typename IDType, typename Message, int32_t delay_ms, bool do_log = false>
36 static_assert(std::is_enum<Message>::value, "Message should be an enum (it's easier that way)");
37 static_assert(std::is_enum<IDType>::value, "IDType should be an enum (it's easier that way)");
38
39public:
47 public:
51 MaybeMessage() : exists(false) {}
56 MaybeMessage(Message msg) : exists(true), thing(msg) {}
61 bool has_message() { return exists; }
67 Message message() { return thing; }
68
69 private:
70 bool exists;
71 Message thing;
72 };
78 struct State {
79 // run once when we enter the state
80 virtual void entry(System &) {}
81 // run continously while in the state
82 virtual MaybeMessage work(System &) { return {}; }
83 // run once when we exit the state
84 virtual void exit(System &) {}
85 // respond to a message when one comes in
86 virtual State *respond(System &s, Message m) = 0;
87 // Identify
88 virtual IDType id() const = 0;
89
90 // virtual destructor cuz c++
91 virtual ~State() {}
92 };
93
94 // Data that gets passed to the runner thread. Don't worry too much about
95 // this
96 using thread_data = std::pair<State *, StateMachine *>;
97
102 StateMachine(State *initial) : runner(thread_runner, new thread_data{initial, this}) {}
103
109 IDType current_state() const {
110 mut.lock();
111 auto t = cur_type;
112 mut.unlock();
113 return t;
114 }
120 void send_message(Message msg) {
121 mut.lock();
122 incoming_msg = msg;
123 mut.unlock();
124 }
125
126private:
127 vex::task runner;
128 mutable vex::mutex mut;
129 MaybeMessage incoming_msg;
130 IDType cur_type;
131
138 static int thread_runner(void *vptr) {
139 thread_data *ptr = static_cast<thread_data *>(vptr);
140 State *cur_state = ptr->first;
141
142 StateMachine &sys = *ptr->second;
143 System &derived = *static_cast<System *>(&sys);
144
145 cur_state->entry(derived);
146
147 sys.cur_type = cur_state->id();
148
149 auto respond_to_message = [&](Message msg) {
150 if (do_log) {
151 printf("responding to msg: %s\n", to_string(msg).c_str());
152 fflush(stdout);
153 }
154
155 State *next_state = cur_state->respond(derived, msg);
156
157 if (cur_state != next_state) {
158 // switched states
159 sys.mut.lock();
160
161 cur_state->exit(derived);
162 next_state->entry(derived);
163
164 delete cur_state;
165
166 cur_state = next_state;
167 sys.cur_type = cur_state->id();
168
169 sys.mut.unlock();
170 }
171 };
172
173 while (true) {
174 if (do_log) {
175 std::string str = to_string(cur_state->id());
176 std::string str2 = to_string(sys.cur_type);
177
178 printf("state: %s %s\n", str.c_str(), str2.c_str());
179 }
180
181 // Internal Message passed
182 MaybeMessage internal_msg = cur_state->work(derived);
183
184 if (internal_msg.has_message()) {
185 respond_to_message(internal_msg.message());
186 }
187
188 // External Message passed
189 sys.mut.lock();
190 MaybeMessage incoming = sys.incoming_msg;
191 sys.incoming_msg = {};
192 sys.mut.unlock();
193
194 if (incoming.has_message()) {
195 respond_to_message(incoming.message());
196 }
197
198 vexDelay(delay_ms);
199 }
200 return 0;
201 }
202};
MaybeMessage a message of Message type or nothing MaybeMessage m = {}; // empty MaybeMessage m = Mess...
Definition state_machine.h:46
MaybeMessage(Message msg)
Create a maybemessage with a message.
Definition state_machine.h:56
Message message()
Get the message stored. The return value is invalid unless has_message returned true.
Definition state_machine.h:67
bool has_message()
check if the message is here
Definition state_machine.h:61
MaybeMessage()
Empty message - when theres no message.
Definition state_machine.h:51
State Machine :)))))) A fun fun way of controlling stateful subsystems - used in the 2023-2024 Over U...
Definition state_machine.h:35
IDType current_state() const
retrieve the current state of the state machine. This is safe to call from external threads
Definition state_machine.h:109
void send_message(Message msg)
send a message to the state machine from outside
Definition state_machine.h:120
StateMachine(State *initial)
Construct a state machine and immediatly start running it.
Definition state_machine.h:102
Definition state_machine.h:78