#include "elevator.hpp"
+#include "main.hpp"
-Elevator::Elevator ()
- : door_(CLOSED)
+Elevator::Elevator (int elevator_number)
+ : state_(STATE_IDLE)
+ , wait_(0)
, direction_(IDLE)
- , current_position_()
+ , position_()
, stops_()
- , ELEVATOR_STEP(0.1)
+ , number_(elevator_number)
+{
+ // Intentionally Left Empty
+}
+
+Elevator::Elevator (int starting_floor, int elevator_number)
+ : state_(STATE_IDLE)
+ , wait_(0)
+ , direction_(IDLE)
+ , position_(starting_floor)
+ , stops_()
+ , number_(elevator_number)
{
// Intentionally Left Empty
}
bool Elevator::currently_at_stop () const
{
StopList::const_iterator it;
- Stop current(current_position_, direction_);
+ Stop current(position_, direction_);
+
+ /* Calculate the number of Stops above and below our current position */
+ int stops_above = 0;
+ int stops_below = 0;
+
+ for (it = stops_.begin(); it != stops_.end(); it++)
+ {
+ if (current < *it)
+ ++stops_above;
+
+ if (current > *it)
+ ++stops_below;
+ }
+
+ /* Check if we are at the top. If so, only the position needs to match */
+ if (direction_ == UP && stops_above == 0)
+ {
+ for (it = stops_.begin (); it != stops_.end (); it++)
+ if (it->getPosition() == position_)
+ return true;
+ }
+ /* Check if we are at the bottom. If so, only the position needs to match */
+ if (direction_ == DOWN && stops_below == 0)
+ {
+ for (it = stops_.begin (); it != stops_.end (); it++)
+ if (it->getPosition() == position_)
+ return true;
+ }
+
+ /* Check if we match exactly */
for (it = stops_.begin (); it != stops_.end (); it++)
if (*it == current)
return true;
+ /* Check if we are IDLE. If so, only the position needs to match */
+ if (direction_ == IDLE)
+ {
+ for (it = stops_.begin (); it != stops_.end (); it++)
+ if (it->getPosition() == position_)
+ return true;
+ }
+
+ /* No match */
return false;
}
float Elevator::distance_from (Position &pos) const
{
- if (current_position_ > pos)
- return current_position_ - pos;
+ if (position_ > pos)
+ return position_ - pos;
- return pos - current_position_;
+ return pos - position_;
}
-void Elevator::move ()
+float Elevator::distance_from (Stop &s) const
{
- static int wait = 0;
+ Direction d = s.getDirection();
+ Position p = s.getPosition ();
- /* Wait around if we need to.
- *
- * This is an artificial delay to make the elevators work in a
- * much more natural fashion. This allows some delay to leave the
- * doors open, or for the user to press floor selection buttons
- * before the elevator starts moving
- */
- if (wait > 0)
- {
- --wait;
- return;
- }
+ /* If direction doesn't matter, then only position does */
+ if (d == ALL || direction_ == IDLE)
+ return distance_from (p);
- /* close the door if it is open. This is a requirement to move */
- if (door_ != CLOSED)
- {
- wait = 10;
- close_door ();
- return;
- }
+ /* If we're not in the same direction, then we're "really far" away */
+ if (d != direction_)
+ return INT_MAX;
- if (currently_at_stop ())
- {
- wait = 10; // delay around for 10 steps
- stops_.remove (Stop(current_position_, direction_));
- open_door (); // call into the GUI to open the door
- return;
- }
+ /* We must be in the correct direction, so pure distance is fine */
+ return distance_from (p);
+}
+void Elevator::transition_move_up ()
+{
+ direction_ = UP;
+ position_ += ELEVATOR_STEP;
+
+ // TODO: Call into the GUI to update the position
+ gui_update_position_label (number_, (float)position_);
+ std::cout << "Updating the GUI with our position: " << position_ << std::endl;
+}
+
+void Elevator::transition_move_down ()
+{
+ direction_ = DOWN;
+ position_ -= ELEVATOR_STEP;
+
+ // TODO: Call into the GUI to update the position
+ gui_update_position_label (number_, (float)position_);
+ std::cout << "Updating the GUI with our position: " << position_ << std::endl;
+}
+
+void Elevator::transition_move_idle ()
+{
+ direction_ = IDLE;
+ // do not change position while IDLE
+}
+
+void Elevator::transition_open_door ()
+{
/* Calculate the number of Stops above and below our
* current position */
StopList::const_iterator it;
- Stop current = Stop(current_position_, direction_);
+ Stop current = Stop(position_, direction_);
int stops_above = 0;
int stops_below = 0;
- for (it = stops_.begin(); it != stops_.begin(); it++)
+ for (it = stops_.begin(); it != stops_.end(); it++)
{
if (current < *it)
++stops_above;
++stops_below;
}
- /* Check if we need to change direction */
- if (direction_ == UP && stops_above == 0 && stops_below > 0)
- direction_ = DOWN;
+ /* If we are going to switch direction, clear all stops here,
+ * regardless of direction.
+ *
+ * Otherwise, just clear this stop */
+ if (direction_ == UP && stops_above == 0)
+ {
+ stops_.remove (Stop(position_, ALL));
+ gui_unpress_request_button (number_, (int)position_);
+ gui_unpress_call_button ((int)position_, UP);
+ gui_unpress_call_button ((int)position_, DOWN);
+ }
+ else if (direction_ == DOWN && stops_below == 0)
+ {
+ stops_.remove (Stop(position_, ALL));
+ gui_unpress_request_button (number_, (int)position_);
+ gui_unpress_call_button ((int)position_, UP);
+ gui_unpress_call_button ((int)position_, DOWN);
+ }
+ else if (direction_ == IDLE)
+ {
+ stops_.remove (Stop(position_, ALL));
+ gui_unpress_request_button (number_, (int)position_);
+ gui_unpress_call_button ((int)position_, UP);
+ gui_unpress_call_button ((int)position_, DOWN);
+ }
+ else
+ {
+ stops_.remove (Stop(position_, direction_));
+ gui_unpress_call_button ((int)position_, direction_);
+ gui_unpress_request_button (number_, (int)position_);
+ }
- if (direction_ == DOWN && stops_below == 0 && stops_above > 0)
- direction_ = UP;
+ // TODO: Call into the GUI to open the door
+ gui_open_door (number_, (int)position_);
+ std::cout << "Opening Door" << std::endl;
+}
- if (stops_above == 0 && stops_below == 0)
- direction_ = IDLE;
+void Elevator::transition_close_door ()
+{
+ // TODO: Call into the GUI to close the door
+ gui_close_door (number_, (int)position_);
+ std::cout << "Closing Door" << std::endl;
+}
+
+void Elevator::transition_begin_wait ()
+{
+ wait_ = 10;
+}
+
+void Elevator::transition_continue_wait ()
+{
+ --wait_;
+}
+
+#include <string>
+static void debug (const std::string& s)
+{
+ std::cout << s << std::endl;
+}
+static std::string get_state_name (State s)
+{
+ std::string sname;
- /* Move in the correct direction */
- switch (direction_)
+ switch (s)
{
- case IDLE:
+ case STATE_IDLE:
+ sname = "STATE_IDLE";
+ break;
+ case STATE_UP:
+ sname = "STATE_UP";
+ break;
+ case STATE_DOWN:
+ sname = "STATE_DOWN";
break;
- case UP:
- current_position_ += ELEVATOR_STEP;
+ case STATE_WAIT:
+ sname = "STATE_WAIT";
break;
- case DOWN:
- current_position_ -= ELEVATOR_STEP;
+ case STATE_OPEN_DOOR:
+ sname = "STATE_OPEN_DOOR";
+ break;
+ case STATE_CLOSE_DOOR:
+ sname = "STATE_CLOSE_DOOR";
break;
default:
- std::cout << __FILE__ << ":" << __LINE__ << " Unhandled Elevator Position" << std::endl;
+ sname = "BAD STATE";
break;
}
- /* Call the GUI with our updated position */
- update_position ();
+ return sname;
}
-bool Elevator::is_idle () const
+static std::string get_event_name (Event e)
{
- return direction_ == IDLE;
+ std::string ename;
+
+ switch (e)
+ {
+ case EVT_IDLE:
+ ename = "EVT_IDLE";
+ break;
+ case EVT_UP:
+ ename = "EVT_UP";
+ break;
+ case EVT_DOWN:
+ ename = "EVT_DOWN";
+ break;
+ case EVT_WAIT:
+ ename = "EVT_WAIT";
+ break;
+ case EVT_OPEN_DOOR:
+ ename = "EVT_OPEN_DOOR";
+ break;
+ case EVT_CLOSE_DOOR:
+ ename = "EVT_CLOSE_DOOR";
+ break;
+ default:
+ ename = "BAD EVENT";
+ break;
+ }
+
+ return ename;
}
-void Elevator::update_position () const
+static void bad_transition (State s, Event e)
{
- std::cout << "Updating the GUI with our position" << std::endl;
+ std::cout << "Bad State Transition: " << get_state_name (s)
+ << " -> " << get_event_name (e) << std::endl;
}
-void Elevator::open_door () const
+Event Elevator::find_next_event () const
{
- std::cout << "Opening Door" << std::endl;
+ /* Calculate the number of Stops above and below our
+ * current position */
+ StopList::const_iterator it;
+ Stop current = Stop(position_, direction_);
+ int stops_above = 0;
+ int stops_below = 0;
+
+ for (it = stops_.begin(); it != stops_.end(); it++)
+ {
+ if (current < *it)
+ ++stops_above;
+
+ if (current > *it)
+ ++stops_below;
+ }
+
+ /* Now figure out which state transition to make */
+ switch (state_)
+ {
+ case STATE_IDLE:
+
+ if (currently_at_stop ())
+ return EVT_OPEN_DOOR;
+
+ if (stops_above > 0)
+ return EVT_UP;
+
+ if (stops_below > 0)
+ return EVT_DOWN;
+
+ return EVT_IDLE;
+
+ break;
+ case STATE_UP:
+
+ if (currently_at_stop ())
+ return EVT_OPEN_DOOR;
+
+ return EVT_UP;
+
+ break;
+ case STATE_DOWN:
+
+ if (currently_at_stop ())
+ return EVT_OPEN_DOOR;
+
+ return EVT_DOWN;
+
+ break;
+ case STATE_WAIT:
+
+ if (wait_ > 0)
+ return EVT_WAIT;
+
+ return EVT_CLOSE_DOOR;
+
+ break;
+ case STATE_OPEN_DOOR:
+
+ return EVT_WAIT;
+
+ break;
+ case STATE_CLOSE_DOOR:
+
+ if (currently_at_stop ())
+ return EVT_OPEN_DOOR;
+
+ if (direction_ == UP && stops_above > 0)
+ return EVT_UP;
+
+ if (direction_ == DOWN && stops_below > 0)
+ return EVT_DOWN;
+
+ /* We need to switch directions */
+ if (direction_ == UP && stops_above == 0 && stops_below > 0)
+ return EVT_DOWN;
+
+ if (direction_ == DOWN && stops_below == 0 && stops_above > 0)
+ return EVT_UP;
+
+ return EVT_IDLE;
+
+ break;
+ default:
+ std::cout << "find_next_event(): Bad State" << std::endl;
+ break;
+ }
}
-void Elevator::close_door () const
+void Elevator::move ()
{
- std::cout << "Closing Door" << std::endl;
-}
+ /* Generate Events */
+ Event e = find_next_event ();
+ std::cout << "State Transition: " << get_state_name (state_) << " with "
+ << get_event_name (e) << std::endl;
+ switch (state_)
+ {
+ case STATE_IDLE:
+ switch (e)
+ {
+ case EVT_UP:
+ state_ = STATE_UP;
+ transition_move_up ();
+ break;
+ case EVT_DOWN:
+ state_ = STATE_DOWN;
+ transition_move_down ();
+ break;
+ case EVT_IDLE:
+ state_ = STATE_IDLE;
+ transition_move_idle ();
+ break;
+ case EVT_OPEN_DOOR:
+ state_ = STATE_OPEN_DOOR;
+ transition_open_door ();
+ break;
+ default:
+ bad_transition (state_, e);
+ break;
+ } // end switch (e)
+ break;
+
+ case STATE_UP:
+ switch (e)
+ {
+ case EVT_UP:
+ state_ = STATE_UP;
+ transition_move_up ();
+ break;
+ case EVT_OPEN_DOOR:
+ state_ = STATE_OPEN_DOOR;
+ transition_open_door ();
+ break;
+ default:
+ bad_transition (state_, e);
+ break;
+ } // end switch (e)
+ break;
+
+ case STATE_DOWN:
+ switch (e)
+ {
+ case EVT_DOWN:
+ state_ = STATE_DOWN;
+ transition_move_down ();
+ break;
+ case EVT_OPEN_DOOR:
+ state_ = STATE_OPEN_DOOR;
+ transition_open_door ();
+ break;
+ default:
+ bad_transition (state_, e);
+ break;
+ } // end switch (e)
+ break;
+
+ case STATE_WAIT:
+ switch (e)
+ {
+ case EVT_WAIT:
+ state_ = STATE_WAIT;
+ transition_continue_wait ();
+ break;
+ case EVT_CLOSE_DOOR:
+ state_ = STATE_CLOSE_DOOR;
+ transition_close_door ();
+ break;
+ default:
+ bad_transition (state_, e);
+ break;
+ } // end switch (e)
+ break;
+
+ case STATE_OPEN_DOOR:
+ switch (e)
+ {
+ case EVT_WAIT:
+ state_ = STATE_WAIT;
+ transition_begin_wait ();
+ break;
+ default:
+ bad_transition (state_, e);
+ break;
+ } // end switch (e)
+ break;
+ case STATE_CLOSE_DOOR:
+ switch (e)
+ {
+ case EVT_OPEN_DOOR:
+ state_ = STATE_OPEN_DOOR;
+ transition_open_door ();
+ break;
+ case EVT_UP:
+ state_ = STATE_UP;
+ transition_move_up ();
+ break;
+ case EVT_DOWN:
+ state_ = STATE_DOWN;
+ transition_move_down ();
+ break;
+ case EVT_IDLE:
+ state_ = STATE_IDLE;
+ transition_move_idle ();
+ break;
+ default:
+ bad_transition (state_, e);
+ break;
+ } // end switch (e)
+ break;
+
+ default:
+ std::cout << "Bad State: " << get_state_name (state_) << std::endl;
+ break;
+ }
+}
+bool Elevator::is_idle () const
+{
+ return direction_ == IDLE;
+}
/* vim: set ts=4 sts=4 sw=4 noexpandtab textwidth=112: */