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