X-Git-Url: https://irasnyder.com/gitweb/?a=blobdiff_plain;f=elevator.cpp;h=cbf9775e860babd1d5530d5eac8d4bf9032b427e;hb=2172ce055533d5865d58538ee00bf609e59b0f99;hp=3be175d79a6f948cff112c4da259f73f39f212ff;hpb=5c28697247e009e93b8b03bec8cdee88339d3226;p=cs356-p1-elevator.git diff --git a/elevator.cpp b/elevator.cpp index 3be175d..cbf9775 100644 --- a/elevator.cpp +++ b/elevator.cpp @@ -1,11 +1,24 @@ #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 } @@ -13,12 +26,51 @@ Elevator::Elevator () 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; } @@ -45,53 +97,67 @@ void Elevator::stop_at (Stop &stop) 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_, direction_); + 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_, direction_); + std::cout << "Updating the GUI with our position: " << position_ << std::endl; +} + +void Elevator::transition_move_idle () +{ + direction_ = IDLE; + // TODO: Call into the GUI to update the position + gui_update_position_label (number_, (float)position_, direction_); + // 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; @@ -100,59 +166,363 @@ void Elevator::move () ++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 +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 +{ + if (stops_.size() != 0) + return false; + return direction_ == IDLE; +} /* vim: set ts=4 sts=4 sw=4 noexpandtab textwidth=112: */