Use Finite State Machine to manage Elevator movement
[cs356-p1-elevator.git] / elevator.cpp
1 #include "elevator.hpp"
2
3 Elevator::Elevator ()
4         : state_(STATE_IDLE)
5         , wait_(0)
6         , direction_(IDLE)
7         , position_()
8         , stops_()
9 {
10         // Intentionally Left Empty
11 }
12
13 Elevator::Elevator (int starting_floor)
14         : state_(STATE_IDLE)
15         , wait_(0)
16         , direction_(IDLE)
17         , position_(starting_floor)
18         , stops_()
19 {
20         // Intentionally Left Empty
21 }
22
23 bool Elevator::currently_at_stop () const
24 {
25         StopList::const_iterator it;
26         Stop current(position_, direction_);
27
28         /* Calculate the number of Stops above and below our current position */
29         int stops_above = 0;
30         int stops_below = 0;
31
32         for (it = stops_.begin(); it != stops_.end(); it++)
33         {
34                 if (current < *it)
35                         ++stops_above;
36
37                 if (current > *it)
38                         ++stops_below;
39         }
40
41         /* Check if we are at the top. If so, only the position needs to match */
42         if (direction_ == UP && stops_above == 0)
43         {
44                 for (it = stops_.begin (); it != stops_.end (); it++)
45                         if (it->getPosition() == position_)
46                                 return true;
47         }
48
49         /* Check if we are at the bottom. If so, only the position needs to match */
50         if (direction_ == DOWN && stops_below == 0)
51         {
52                 for (it = stops_.begin (); it != stops_.end (); it++)
53                         if (it->getPosition() == position_)
54                                 return true;
55         }
56
57         /* Check if we match exactly */
58         for (it = stops_.begin (); it != stops_.end (); it++)
59                 if (*it == current)
60                         return true;
61
62         /* No match */
63         return false;
64 }
65
66 void Elevator::stop_at (Stop &stop)
67 {
68         StopList::iterator it;
69
70         /* If this is an "ALL" Stop, it supercedes all others */
71         if (stop.getDirection() == ALL)
72         {
73                 stops_.remove (stop);
74                 stops_.push_back (stop);
75                 return;
76         }
77
78         /* Check if this stop already exists. If so, just leave */
79         for (it = stops_.begin(); it != stops_.end(); it++)
80                 if (*it == stop)
81                         return;
82
83         /* The stop did not already exist, so add it */
84         stops_.push_back (stop);
85 }
86
87 float Elevator::distance_from (Position &pos) const
88 {
89         if (position_ > pos)
90                 return position_ - pos;
91
92         return pos - position_;
93 }
94
95 void Elevator::transition_move_up ()
96 {
97         direction_ = UP;
98         position_ += ELEVATOR_STEP;
99
100         // TODO: Call into the GUI to update the position
101         std::cout << "Updating the GUI with our position: " << position_ << std::endl;
102 }
103
104 void Elevator::transition_move_down ()
105 {
106         direction_ = DOWN;
107         position_ -= ELEVATOR_STEP;
108
109         // TODO: Call into the GUI to update the position
110         std::cout << "Updating the GUI with our position: " << position_ << std::endl;
111 }
112
113 void Elevator::transition_move_idle ()
114 {
115         direction_ = IDLE;
116         // do not change position while IDLE
117 }
118
119 void Elevator::transition_open_door ()
120 {
121         /* Calculate the number of Stops above and below our
122          * current position */
123         StopList::const_iterator it;
124         Stop current = Stop(position_, direction_);
125         int stops_above = 0;
126         int stops_below = 0;
127
128         for (it = stops_.begin(); it != stops_.end(); it++)
129         {
130                 if (current < *it)
131                         ++stops_above;
132
133                 if (current > *it)
134                         ++stops_below;
135         }
136
137         /* If we are going to switch direction, clear all stops here,
138          * regardless of direction.
139          *
140          * Otherwise, just clear this stop */
141         if      (direction_ == UP && stops_above == 0)
142                 stops_.remove (Stop(position_, ALL));
143         else if (direction_ == DOWN && stops_below == 0)
144                 stops_.remove (Stop(position_, ALL));
145         else
146                 stops_.remove (Stop(position_, direction_));
147
148         // TODO: Call into GUI to open the door
149         std::cout << "Opening Door" << std::endl;
150 }
151
152 void Elevator::transition_close_door ()
153 {
154         // TODO: Call into the GUI to close the door
155         std::cout << "Closing Door" << std::endl;
156 }
157
158 void Elevator::transition_begin_wait ()
159 {
160         wait_ = 10;
161 }
162
163 void Elevator::transition_continue_wait ()
164 {
165         --wait_;
166 }
167
168 #include <string>
169 static void debug (const std::string& s)
170 {
171         std::cout << s << std::endl;
172 }
173
174 static std::string get_state_name (State s)
175 {
176         std::string sname;
177
178         switch (s)
179         {
180                 case STATE_IDLE:
181                         sname = "STATE_IDLE";
182                         break;
183                 case STATE_UP:
184                         sname = "STATE_UP";
185                         break;
186                 case STATE_DOWN:
187                         sname = "STATE_DOWN";
188                         break;
189                 case STATE_WAIT:
190                         sname = "STATE_WAIT";
191                         break;
192                 case STATE_OPEN_DOOR:
193                         sname = "STATE_OPEN_DOOR";
194                         break;
195                 case STATE_CLOSE_DOOR:
196                         sname = "STATE_CLOSE_DOOR";
197                         break;
198                 default:
199                         sname = "BAD STATE";
200                         break;
201         }
202
203         return sname;
204 }
205
206 static std::string get_event_name (Event e)
207 {
208         std::string ename;
209
210         switch (e)
211         {
212                 case EVT_IDLE:
213                         ename = "EVT_IDLE";
214                         break;
215                 case EVT_UP:
216                         ename = "EVT_UP";
217                         break;
218                 case EVT_DOWN:
219                         ename = "EVT_DOWN";
220                         break;
221                 case EVT_WAIT:
222                         ename = "EVT_WAIT";
223                         break;
224                 case EVT_OPEN_DOOR:
225                         ename = "EVT_OPEN_DOOR";
226                         break;
227                 case EVT_CLOSE_DOOR:
228                         ename = "EVT_CLOSE_DOOR";
229                         break;
230                 default:
231                         ename = "BAD EVENT";
232                         break;
233         }
234
235         return ename;
236 }
237
238 static void bad_transition (State s, Event e)
239 {
240         std::cout << "Bad State Transition: " << get_state_name (s)
241                           << " -> " << get_event_name (e) << std::endl;
242 }
243
244 Event Elevator::find_next_event () const
245 {
246         /* Calculate the number of Stops above and below our
247          * current position */
248         StopList::const_iterator it;
249         Stop current = Stop(position_, direction_);
250         int stops_above = 0;
251         int stops_below = 0;
252
253         for (it = stops_.begin(); it != stops_.end(); it++)
254         {
255                 if (current < *it)
256                         ++stops_above;
257
258                 if (current > *it)
259                         ++stops_below;
260         }
261
262         /* Now figure out which state transition to make */
263         switch (state_)
264         {
265                 case STATE_IDLE:
266
267                         if (currently_at_stop ())
268                                 return EVT_OPEN_DOOR;
269
270                         if (stops_above > 0)
271                                 return EVT_UP;
272
273                         if (stops_below > 0)
274                                 return EVT_DOWN;
275
276                         return EVT_IDLE;
277
278                         break;
279                 case STATE_UP:
280
281                         if (currently_at_stop ())
282                                 return EVT_OPEN_DOOR;
283
284                         return EVT_UP;
285
286                         break;
287                 case STATE_DOWN:
288
289                         if (currently_at_stop ())
290                                 return EVT_OPEN_DOOR;
291
292                         return EVT_DOWN;
293
294                         break;
295                 case STATE_WAIT:
296
297                         if (wait_ > 0)
298                                 return EVT_WAIT;
299
300                         return EVT_CLOSE_DOOR;
301
302                         break;
303                 case STATE_OPEN_DOOR:
304
305                         return EVT_WAIT;
306
307                         break;
308                 case STATE_CLOSE_DOOR:
309
310                         if (currently_at_stop ())
311                                 return EVT_OPEN_DOOR;
312
313                         if (direction_ == UP && stops_above > 0)
314                                 return EVT_UP;
315
316                         if (direction_ == DOWN && stops_below > 0)
317                                 return EVT_DOWN;
318
319                         /* We need to switch directions */
320                         if (direction_ == UP && stops_above == 0 && stops_below > 0)
321                                 return EVT_DOWN;
322
323                         if (direction_ == DOWN && stops_below == 0 && stops_above > 0)
324                                 return EVT_UP;
325
326                         return EVT_IDLE;
327
328                         break;
329                 default:
330                         std::cout << "find_next_event(): Bad State" << std::endl;
331                         break;
332         }
333 }
334
335 void Elevator::move ()
336 {
337         /* Generate Events */
338         Event e = find_next_event ();
339
340         std::cout << "State Transition: " << get_state_name (state_) << " with "
341                           << get_event_name (e) << std::endl;
342
343         switch (state_)
344         {
345                 case STATE_IDLE:
346                         switch (e)
347                         {
348                                 case EVT_UP:
349                                         state_ = STATE_UP;
350                                         transition_move_up ();
351                                         break;
352                                 case EVT_DOWN:
353                                         state_ = STATE_DOWN;
354                                         transition_move_down ();
355                                         break;
356                                 case EVT_IDLE:
357                                         state_ = STATE_IDLE;
358                                         transition_move_idle ();
359                                         break;
360                                 case EVT_OPEN_DOOR:
361                                         state_ = STATE_OPEN_DOOR;
362                                         transition_open_door ();
363                                         break;
364                                 default:
365                                         bad_transition (state_, e);
366                                         break;
367                         } // end switch (e)
368                         break;
369
370                 case STATE_UP:
371                         switch (e)
372                         {
373                                 case EVT_UP:
374                                         state_ = STATE_UP;
375                                         transition_move_up ();
376                                         break;
377                                 case EVT_OPEN_DOOR:
378                                         state_ = STATE_OPEN_DOOR;
379                                         transition_open_door ();
380                                         break;
381                                 default:
382                                         bad_transition (state_, e);
383                                         break;
384                         } // end switch (e)
385                         break;
386
387                 case STATE_DOWN:
388                         switch (e)
389                         {
390                                 case EVT_DOWN:
391                                         state_ = STATE_DOWN;
392                                         transition_move_down ();
393                                         break;
394                                 case EVT_OPEN_DOOR:
395                                         state_ = STATE_OPEN_DOOR;
396                                         transition_open_door ();
397                                         break;
398                                 default:
399                                         bad_transition (state_, e);
400                                         break;
401                         } // end switch (e)
402                         break;
403
404                 case STATE_WAIT:
405                         switch (e)
406                         {
407                                 case EVT_WAIT:
408                                         state_ = STATE_WAIT;
409                                         transition_continue_wait ();
410                                         break;
411                                 case EVT_CLOSE_DOOR:
412                                         state_ = STATE_CLOSE_DOOR;
413                                         transition_close_door ();
414                                         break;
415                                 default:
416                                         bad_transition (state_, e);
417                                         break;
418                         } // end switch (e)
419                         break;
420
421                 case STATE_OPEN_DOOR:
422                         switch (e)
423                         {
424                                 case EVT_WAIT:
425                                         state_ = STATE_WAIT;
426                                         transition_begin_wait ();
427                                         break;
428                                 default:
429                                         bad_transition (state_, e);
430                                         break;
431                         } // end switch (e)
432                         break;
433
434                 case STATE_CLOSE_DOOR:
435                         switch (e)
436                         {
437                                 case EVT_OPEN_DOOR:
438                                         state_ = STATE_OPEN_DOOR;
439                                         transition_open_door ();
440                                         break;
441                                 case EVT_UP:
442                                         state_ = STATE_UP;
443                                         transition_move_up ();
444                                         break;
445                                 case EVT_DOWN:
446                                         state_ = STATE_DOWN;
447                                         transition_move_down ();
448                                         break;
449                                 case EVT_IDLE:
450                                         state_ = STATE_IDLE;
451                                         transition_move_idle ();
452                                         break;
453                                 default:
454                                         bad_transition (state_, e);
455                                         break;
456                         } // end switch (e)
457                         break;
458
459                 default:
460                         std::cout << "Bad State: " << get_state_name (state_) << std::endl;
461                         break;
462         }
463 }
464
465 bool Elevator::is_idle () const
466 {
467         return direction_ == IDLE;
468 }
469
470 /* vim: set ts=4 sts=4 sw=4 noexpandtab textwidth=112: */