00001 #ifndef STATE_MACHINE_IMPLEMENTATION_FILE
00002 #define STATE_MACHINE_IMPLEMENTATION_FILE
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "mechanisms_implementation_only.h"
00019 #include "state_machine.h"
00020 #include "time_stamp.h"
00021
00022 #include <basis/array.cpp>
00023 #include <basis/function.h>
00024 #include <basis/guards.h>
00025 #include <basis/istring.h>
00026 #include <basis/portable.h>
00027
00029
00030
00031
00032
00033
00034 #undef LOG
00035 #ifndef DEBUG_STATE_MACHINE
00036 #define LOG(to_print) CLASS_EMERGENCY_LOG(program_wide_logger(), to_print)
00037 #else
00038 #define LOG(to_print) {}
00039 #endif
00040
00042
00043
00044 #define CHECK_VALID(m) \
00045 if (!m._current) return false; \
00046 if (!m._last) return false
00047
00048
00049 #define CHECK_STATES \
00050 if (!current) return false; \
00051 if (!next) return false; \
00052 int indy = state_index(current); \
00053 if (negative(indy)) return false; \
00054 if (negative(state_index(next))) return false
00055
00056
00057 #define MOVE_STATE(m, next, type, trigger) \
00058 m._last = m._current; \
00059 m._current = next; \
00060 m._type = type; \
00061 m._trig = trigger; \
00062 m._start->reset()
00063
00064
00065 #define FIND_STATE(state) \
00066 int indy = state_index(state); \
00067 if (negative(indy)) return
00068
00070
00071 struct override { int current; int next; int duration;
00072 override(int _current = 0, int _next = 0, int _duration = 0)
00073 : current(_current), next(_next), duration(_duration) {}
00074 };
00075
00076 struct transition_info {
00077 enum transition_type { SIMPLE, RANGE, TIMED };
00078 transition_type type;
00079 int next_state;
00080 int low_trigger, high_trigger;
00081 int time_span;
00082
00083 transition_info() {}
00084 transition_info(int next) : type(SIMPLE), next_state(next) {}
00085 transition_info(int next, int time) : type(TIMED), next_state(next),
00086 time_span(time) {}
00087 transition_info(int next, int low, int high) : type(RANGE),
00088 next_state(next), low_trigger(low), high_trigger(high) {}
00089 };
00090
00091 struct state_info {
00092 int state_id;
00093 array<transition_info> transitions;
00094
00095 state_info() : state_id(0) {}
00096 state_info(int state_id_in) : state_id(state_id_in) {}
00097 };
00098
00100
00101 class state_machine_override_array : public array<override> {};
00102 class state_machine_state_array : public array<state_info> {};
00103
00105
00106 state_machine::state_machine()
00107 : _current(0),
00108 _last(0),
00109 _trig(0),
00110 _type(SIMPLE),
00111 _start(new time_stamp()),
00112 _name(new istring()),
00113 _overrides(new state_machine_override_array)
00114 {}
00115
00116 state_machine::state_machine(const state_machine &to_copy)
00117 : object_base(),
00118 _current(0),
00119 _last(0),
00120 _trig(0),
00121 _type(SIMPLE),
00122 _start(new time_stamp()),
00123 _name(new istring()),
00124 _overrides(new state_machine_override_array)
00125 { *this = to_copy; }
00126
00127 state_machine::~state_machine()
00128 {
00129 WHACK(_start);
00130 WHACK(_name);
00131 WHACK(_overrides);
00132 }
00133
00134 int state_machine::update() { return 0; }
00135
00136 void state_machine::set_name(const istring &name) { *_name = name; }
00137
00138 istring state_machine::get_name() const { return *_name; }
00139
00140 state_machine &state_machine::operator = (const state_machine &to_copy)
00141 {
00142 if (&to_copy == this) return *this;
00143 _current = to_copy._current;
00144 _last = to_copy._last;
00145 _trig = to_copy._trig;
00146 _type = to_copy._type;
00147 *_start = *to_copy._start;
00148 *_name = *to_copy._name;
00149 *_overrides = *to_copy._overrides;
00150
00151 return *this;
00152 }
00153
00154 int state_machine::duration_index(int current, int next) const
00155 {
00156 for (int i = 0; i < _overrides->length(); i++)
00157 if ( ((*_overrides)[i].current == current)
00158 && ((*_overrides)[i].next == next) )
00159 return i;
00160 return common::NOT_FOUND;
00161 }
00162
00163 void state_machine::set_state(int new_current, int new_last, int trigger,
00164 transition_types type)
00165 {
00166 _current = new_current;
00167 _last = new_last;
00168 _trig = trigger;
00169 _type = type;
00170 _start->reset();
00171 }
00172
00173 void state_machine::override_timing(int current, int next, int duration)
00174 {
00175 int indy = duration_index(current, next);
00176 if (non_negative(indy)) {
00177
00178 if (!duration) {
00179
00180 _overrides->zap(indy, indy);
00181 return;
00182 }
00183
00184 (*_overrides)[indy].duration = duration;
00185 return;
00186 }
00187
00188 *_overrides += override(current, next, duration);
00189 }
00190
00191 int state_machine::duration_override(int current, int next) const
00192 {
00193 int indy = duration_index(current, next);
00194 if (negative(indy)) return 0;
00195 return (*_overrides)[indy].duration;
00196 }
00197
00198 time_stamp state_machine::start() const { return *_start; }
00199
00201
00202 transition_map::transition_map()
00203 : _valid(false),
00204 _start_state(0),
00205 _state_list(new state_machine_state_array)
00206 {}
00207
00208 transition_map::~transition_map()
00209 {
00210 _valid = false;
00211 WHACK(_state_list);
00212 }
00213
00214
00215
00216 int transition_map::states() const { return _state_list->length(); }
00217
00218 int transition_map::state_index(int state_id) const
00219 {
00220 for (int i = 0; i < states(); i++)
00221 if ((*_state_list)[i].state_id == state_id) return i;
00222 return common::NOT_FOUND;
00223 }
00224
00225 int transition_map::transition_index(int state_index, int next, int &start)
00226 {
00227 bounds_return(state_index, 0, states() - 1, common::BAD_INPUT);
00228 state_info &state = (*_state_list)[state_index];
00229 bounds_return(start, 0, state.transitions.length() - 1, common::BAD_INPUT);
00230
00231 for (start = start; start < state.transitions.length(); start++)
00232 if (state.transitions[start].next_state == next) {
00233 start++;
00234 return start - 1;
00235 }
00236 return common::NOT_FOUND;
00237 }
00238
00239
00240
00241 void transition_map::reconfigure() { _valid = false; }
00242
00243 outcome transition_map::validate(int &examine)
00244 {
00245
00246 examine = _start_state;
00247 FIND_STATE(_start_state) BAD_START;
00248
00249 if (!check_reachability(examine)) return UNREACHABLE;
00250
00251 if (!check_overlapping(examine)) return OVERLAPPING_RANGES;
00252
00253 _valid = true;
00254 return OKAY;
00255 }
00256
00257 bool transition_map::add_state(int state_number)
00258 {
00259 if (valid()) return false;
00260 if (!state_number) return false;
00261 if (non_negative(state_index(state_number))) return false;
00262 *_state_list += state_info(state_number);
00263 return true;
00264 }
00265
00266 bool transition_map::set_start(int starting_state)
00267 {
00268 if (valid()) return false;
00269 if (!starting_state) return false;
00270
00271 FIND_STATE(starting_state) false;
00272
00273 _start_state = starting_state;
00274 return true;
00275 }
00276
00277 bool transition_map::add_simple_transition(int current, int next)
00278 {
00279 if (valid()) return false;
00280 CHECK_STATES;
00281 (*_state_list)[indy].transitions += transition_info(next);
00282 return true;
00283 }
00284
00285 bool transition_map::add_range_transition(int current, int next, int low, int high)
00286 {
00287 if (valid()) return false;
00288 CHECK_STATES;
00289 (*_state_list)[indy].transitions += transition_info(next, low, high);
00290 return true;
00291 }
00292
00293 bool transition_map::add_timed_transition(int current, int next, int length)
00294 {
00295 if (valid()) return false;
00296 CHECK_STATES;
00297 state_info &found = (*_state_list)[indy];
00298
00299 for (int i = 0; i < found.transitions.length(); i++)
00300 if (found.transitions[i].type == transition_info::TIMED) {
00301 found.transitions[i] = transition_info(next, length);
00302 return true;
00303 }
00304
00305 (*_state_list)[indy].transitions += transition_info(next, length);
00306 return true;
00307 }
00308
00309
00310
00311 bool transition_map::make_transition(state_machine &m, int next)
00312 {
00313 if (!valid()) return false;
00314 CHECK_VALID(m);
00315 #ifdef DEBUG_STATE_MACHINE
00316 if (negative(state_index(m._current)))
00317 LOG(istring("(%s) transition_map::make_transition: bad logic error; machine's "
00318 "state is missing.", m._name->s()));
00319 if (negative(state_index(next)))
00320 LOG(istring("(%s) transition_map::make_transition: next state parameter is invalid.",
00321 m._name->s()));
00322 #endif
00323 FIND_STATE(m._current) false;
00324 int start = 0;
00325 if (negative(transition_index(indy, next, start))) return false;
00326
00327 MOVE_STATE(m, next, state_machine::SIMPLE, 0);
00328 int trig = m.update();
00329 if (trig) return pulse(m, trig);
00330 return true;
00331 }
00332
00333 bool transition_map::pulse(state_machine &m, int trigger)
00334 {
00335 if (!valid()) return false;
00336 CHECK_VALID(m);
00337 #ifdef DEBUG_STATE_MACHINE
00338 if (negative(state_index(m._current)))
00339 LOG(istring("(%s) transition_map::pulse: bad logic error; state is missing.", m._name->s()));
00340 #endif
00341 FIND_STATE(m._current) false;
00342 state_info &found = (*_state_list)[indy];
00343 for (int i = 0; i < found.transitions.length(); i++) {
00344 if (found.transitions[i].type == transition_info::RANGE) {
00345
00346 transition_info &tran = found.transitions[i];
00347 if ( (tran.low_trigger <= trigger)
00348 && (tran.high_trigger >= trigger) ) {
00349
00350 MOVE_STATE(m, tran.next_state, state_machine::RANGE, trigger);
00351 int trig = m.update();
00352 if (trig) return pulse(m, trig);
00353 return true;
00354 }
00355 }
00356 }
00357 return false;
00358 }
00359
00360 bool transition_map::time_slice(state_machine &m)
00361 {
00362 if (!valid()) return false;
00363 CHECK_VALID(m);
00364
00365 #ifdef DEBUG_STATE_MACHINE
00366 if (negative(state_index(m._current)))
00367 LOG(istring("(%s) transition_map::time_slice: bad logic error; state "
00368 "is missing.", m._name->s()));
00369 #endif
00370 FIND_STATE(m._current) false;
00371
00372 state_info &found = (*_state_list)[indy];
00373 for (int i = 0; i < found.transitions.length(); i++) {
00374 if (found.transitions[i].type == transition_info::TIMED) {
00375
00376 transition_info &tran = found.transitions[i];
00377 int duration = tran.time_span;
00378 int override = m.duration_override(m._current, tran.next_state);
00379 if (override) duration = override;
00380 if (*m._start < time_stamp(-duration)) {
00381
00382 MOVE_STATE(m, tran.next_state, state_machine::TIMED, 0);
00383 int trig = m.update();
00384 if (trig) return pulse(m, trig);
00385 return true;
00386 }
00387 }
00388 }
00389 return false;
00390 }
00391
00392 bool transition_map::reset(state_machine &m)
00393 {
00394 if (!valid()) return false;
00395 m._current = _start_state;
00396 m._last = _start_state;
00397 m._trig = 0;
00398 m._type = state_machine::SIMPLE;
00399 m._start->reset();
00400 return true;
00401 }
00402
00403 bool transition_map::check_overlapping(int &examine)
00404 {
00405 FUNCDEF("check_overlapping");
00406 examine = 0;
00407 for (int i = 0; i < states(); i++) {
00408 examine = i;
00409 for (int j = 0; j < (*_state_list)[i].transitions.length(); j++) {
00410 transition_info &a = (*_state_list)[i].transitions[j];
00411 if (a.type != transition_info::RANGE) continue;
00412 for (int k = j + 1; k < (*_state_list)[i].transitions.length(); k++) {
00413 transition_info &b = (*_state_list)[i].transitions[k];
00414 if (b.type != transition_info::RANGE) continue;
00415 if ( (b.low_trigger <= a.low_trigger)
00416 && (b.high_trigger >= a.low_trigger) ) {
00417 LOG("intersecting range on low end!");
00418 return false;
00419 }
00420 if ( (b.low_trigger <= a.high_trigger)
00421 && (b.high_trigger >= a.high_trigger) ) {
00422 LOG("intersecting range on high end!");
00423 return false;
00424 }
00425 }
00426 }
00427 }
00428 return true;
00429 }
00430
00431 bool transition_map::check_reachability(int &examine)
00432 {
00433 FUNCDEF("check_reachability");
00434 examine = 0;
00435
00436
00437
00438 int_array list_to_add;
00439 list_to_add += _start_state;
00440
00441
00442
00443 array<bool> already_checked(states());
00444 for (int i = 0; i < already_checked.length(); i++)
00445 already_checked[i] = false;
00446
00447 while (list_to_add.length()) {
00448
00449
00450 examine = list_to_add[0];
00451 int indy = state_index(examine);
00452 if (negative(indy)) {
00453 LOG(isprintf("bad state index for state %d!", examine));
00454 return false;
00455 }
00456 #ifdef DEBUG_STATE_MACHINE
00457 LOG(isprintf("state to add is %d, list size=%d.", examine,
00458 list_to_add.length()));
00459 #endif
00460
00461 list_to_add.zap(0, 0);
00462
00463
00464
00465 if (already_checked[indy]) continue;
00466
00467
00468
00469 already_checked[indy] = true;
00470
00471 state_info &found = (*_state_list)[indy];
00472
00473
00474 for (int i = 0; i < found.transitions.length(); i++) {
00475 #ifdef DEBUG_STATE_MACHINE
00476 LOG(istring("checking transition %d: ", i));
00477 #endif
00478 int now_reachable = found.transitions[i].next_state;
00479 #ifdef DEBUG_STATE_MACHINE
00480 LOG(istring("now reaching %d.", now_reachable));
00481 #endif
00482 if (now_reachable == examine) continue;
00483 else {
00484 int indy = state_index(now_reachable);
00485 if (already_checked[indy]) continue;
00486 }
00487 list_to_add += now_reachable;
00488 }
00489 }
00490 #ifdef DEBUG_STATE_MACHINE
00491 LOG("done checking reachability.");
00492 #endif
00493 for (int j = 0; j < already_checked.length(); j++)
00494 if (!already_checked.get(j)) {
00495 examine = (*_state_list)[j].state_id;
00496 LOG(isprintf("state %d is not reachable", examine));
00497 return false;
00498 }
00499 return true;
00500 }
00501
00502
00503 #endif //STATE_MACHINE_IMPLEMENTATION_FILE
00504