Add ElevatorController
[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 float Elevator::distance_from (Stop &s) const
96 {
97         Direction d = s.getDirection();
98         Position  p = s.getPosition ();
99
100         /* If direction doesn't matter, then only position does */
101         if (d == ALL || direction_ == IDLE)
102                 return distance_from (p);
103
104         /* If we're not in the same direction, then we're "really far" away */
105         if (d != direction_)
106                 return INT_MAX;
107
108         /* We must be in the correct direction, so pure distance is fine */
109         return distance_from (p);
110 }
111
112 void Elevator::transition_move_up ()
113 {
114         direction_ = UP;
115         position_ += ELEVATOR_STEP;
116
117         // TODO: Call into the GUI to update the position
118         std::cout << "Updating the GUI with our position: " << position_ << std::endl;
119 }
120
121 void Elevator::transition_move_down ()
122 {
123         direction_ = DOWN;
124         position_ -= ELEVATOR_STEP;
125
126         // TODO: Call into the GUI to update the position
127         std::cout << "Updating the GUI with our position: " << position_ << std::endl;
128 }
129
130 void Elevator::transition_move_idle ()
131 {
132         direction_ = IDLE;
133         // do not change position while IDLE
134 }
135
136 void Elevator::transition_open_door ()
137 {
138         /* Calculate the number of Stops above and below our
139          * current position */
140         StopList::const_iterator it;
141         Stop current = Stop(position_, direction_);
142         int stops_above = 0;
143         int stops_below = 0;
144
145         for (it = stops_.begin(); it != stops_.end(); it++)
146         {
147                 if (current < *it)
148                         ++stops_above;
149
150                 if (current > *it)
151                         ++stops_below;
152         }
153
154         /* If we are going to switch direction, clear all stops here,
155          * regardless of direction.
156          *
157          * Otherwise, just clear this stop */
158         if      (direction_ == UP && stops_above == 0)
159                 stops_.remove (Stop(position_, ALL));
160         else if (direction_ == DOWN && stops_below == 0)
161                 stops_.remove (Stop(position_, ALL));
162         else
163                 stops_.remove (Stop(position_, direction_));
164
165         // TODO: Call into the GUI to open the door
166         std::cout << "Opening Door" << std::endl;
167 }
168
169 void Elevator::transition_close_door ()
170 {
171         // TODO: Call into the GUI to close the door
172         std::cout << "Closing Door" << std::endl;
173 }
174
175 void Elevator::transition_begin_wait ()
176 {
177         wait_ = 10;
178 }
179
180 void Elevator::transition_continue_wait ()
181 {
182         --wait_;
183 }
184
185 #include <string>
186 static void debug (const std::string& s)
187 {
188         std::cout << s << std::endl;
189 }
190
191 static std::string get_state_name (State s)
192 {
193         std::string sname;
194
195         switch (s)
196         {
197                 case STATE_IDLE:
198                         sname = "STATE_IDLE";
199                         break;
200                 case STATE_UP:
201                         sname = "STATE_UP";
202                         break;
203                 case STATE_DOWN:
204                         sname = "STATE_DOWN";
205                         break;
206                 case STATE_WAIT:
207                         sname = "STATE_WAIT";
208                         break;
209                 case STATE_OPEN_DOOR:
210                         sname = "STATE_OPEN_DOOR";
211                         break;
212                 case STATE_CLOSE_DOOR:
213                         sname = "STATE_CLOSE_DOOR";
214                         break;
215                 default:
216                         sname = "BAD STATE";
217                         break;
218         }
219
220         return sname;
221 }
222
223 static std::string get_event_name (Event e)
224 {
225         std::string ename;
226
227         switch (e)
228         {
229                 case EVT_IDLE:
230                         ename = "EVT_IDLE";
231                         break;
232                 case EVT_UP:
233                         ename = "EVT_UP";
234                         break;
235                 case EVT_DOWN:
236                         ename = "EVT_DOWN";
237                         break;
238                 case EVT_WAIT:
239                         ename = "EVT_WAIT";
240                         break;
241                 case EVT_OPEN_DOOR:
242                         ename = "EVT_OPEN_DOOR";
243                         break;
244                 case EVT_CLOSE_DOOR:
245                         ename = "EVT_CLOSE_DOOR";
246                         break;
247                 default:
248                         ename = "BAD EVENT";
249                         break;
250         }
251
252         return ename;
253 }
254
255 static void bad_transition (State s, Event e)
256 {
257         std::cout << "Bad State Transition: " << get_state_name (s)
258                           << " -> " << get_event_name (e) << std::endl;
259 }
260
261 Event Elevator::find_next_event () const
262 {
263         /* Calculate the number of Stops above and below our
264          * current position */
265         StopList::const_iterator it;
266         Stop current = Stop(position_, direction_);
267         int stops_above = 0;
268         int stops_below = 0;
269
270         for (it = stops_.begin(); it != stops_.end(); it++)
271         {
272                 if (current < *it)
273                         ++stops_above;
274
275                 if (current > *it)
276                         ++stops_below;
277         }
278
279         /* Now figure out which state transition to make */
280         switch (state_)
281         {
282                 case STATE_IDLE:
283
284                         if (currently_at_stop ())
285                                 return EVT_OPEN_DOOR;
286
287                         if (stops_above > 0)
288                                 return EVT_UP;
289
290                         if (stops_below > 0)
291                                 return EVT_DOWN;
292
293                         return EVT_IDLE;
294
295                         break;
296                 case STATE_UP:
297
298                         if (currently_at_stop ())
299                                 return EVT_OPEN_DOOR;
300
301                         return EVT_UP;
302
303                         break;
304                 case STATE_DOWN:
305
306                         if (currently_at_stop ())
307                                 return EVT_OPEN_DOOR;
308
309                         return EVT_DOWN;
310
311                         break;
312                 case STATE_WAIT:
313
314                         if (wait_ > 0)
315                                 return EVT_WAIT;
316
317                         return EVT_CLOSE_DOOR;
318
319                         break;
320                 case STATE_OPEN_DOOR:
321
322                         return EVT_WAIT;
323
324                         break;
325                 case STATE_CLOSE_DOOR:
326
327                         if (currently_at_stop ())
328                                 return EVT_OPEN_DOOR;
329
330                         if (direction_ == UP && stops_above > 0)
331                                 return EVT_UP;
332
333                         if (direction_ == DOWN && stops_below > 0)
334                                 return EVT_DOWN;
335
336                         /* We need to switch directions */
337                         if (direction_ == UP && stops_above == 0 && stops_below > 0)
338                                 return EVT_DOWN;
339
340                         if (direction_ == DOWN && stops_below == 0 && stops_above > 0)
341                                 return EVT_UP;
342
343                         return EVT_IDLE;
344
345                         break;
346                 default:
347                         std::cout << "find_next_event(): Bad State" << std::endl;
348                         break;
349         }
350 }
351
352 void Elevator::move ()
353 {
354         /* Generate Events */
355         Event e = find_next_event ();
356
357         std::cout << "State Transition: " << get_state_name (state_) << " with "
358                           << get_event_name (e) << std::endl;
359
360         switch (state_)
361         {
362                 case STATE_IDLE:
363                         switch (e)
364                         {
365                                 case EVT_UP:
366                                         state_ = STATE_UP;
367                                         transition_move_up ();
368                                         break;
369                                 case EVT_DOWN:
370                                         state_ = STATE_DOWN;
371                                         transition_move_down ();
372                                         break;
373                                 case EVT_IDLE:
374                                         state_ = STATE_IDLE;
375                                         transition_move_idle ();
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_UP:
388                         switch (e)
389                         {
390                                 case EVT_UP:
391                                         state_ = STATE_UP;
392                                         transition_move_up ();
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_DOWN:
405                         switch (e)
406                         {
407                                 case EVT_DOWN:
408                                         state_ = STATE_DOWN;
409                                         transition_move_down ();
410                                         break;
411                                 case EVT_OPEN_DOOR:
412                                         state_ = STATE_OPEN_DOOR;
413                                         transition_open_door ();
414                                         break;
415                                 default:
416                                         bad_transition (state_, e);
417                                         break;
418                         } // end switch (e)
419                         break;
420
421                 case STATE_WAIT:
422                         switch (e)
423                         {
424                                 case EVT_WAIT:
425                                         state_ = STATE_WAIT;
426                                         transition_continue_wait ();
427                                         break;
428                                 case EVT_CLOSE_DOOR:
429                                         state_ = STATE_CLOSE_DOOR;
430                                         transition_close_door ();
431                                         break;
432                                 default:
433                                         bad_transition (state_, e);
434                                         break;
435                         } // end switch (e)
436                         break;
437
438                 case STATE_OPEN_DOOR:
439                         switch (e)
440                         {
441                                 case EVT_WAIT:
442                                         state_ = STATE_WAIT;
443                                         transition_begin_wait ();
444                                         break;
445                                 default:
446                                         bad_transition (state_, e);
447                                         break;
448                         } // end switch (e)
449                         break;
450
451                 case STATE_CLOSE_DOOR:
452                         switch (e)
453                         {
454                                 case EVT_OPEN_DOOR:
455                                         state_ = STATE_OPEN_DOOR;
456                                         transition_open_door ();
457                                         break;
458                                 case EVT_UP:
459                                         state_ = STATE_UP;
460                                         transition_move_up ();
461                                         break;
462                                 case EVT_DOWN:
463                                         state_ = STATE_DOWN;
464                                         transition_move_down ();
465                                         break;
466                                 case EVT_IDLE:
467                                         state_ = STATE_IDLE;
468                                         transition_move_idle ();
469                                         break;
470                                 default:
471                                         bad_transition (state_, e);
472                                         break;
473                         } // end switch (e)
474                         break;
475
476                 default:
477                         std::cout << "Bad State: " << get_state_name (state_) << std::endl;
478                         break;
479         }
480 }
481
482 bool Elevator::is_idle () const
483 {
484         return direction_ == IDLE;
485 }
486
487 /* vim: set ts=4 sts=4 sw=4 noexpandtab textwidth=112: */