Rev 329 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
#include "elevator.h"// FIXME// FIXME// FIXMEvoid debug_puts (const char* s){#ifndef _NDEBUGputs (s);#endif}// FIXME// FIXME// FIXMEElevator::Elevator (int num_floors) : num_floors(num_floors){this->terminate = false;this->pause = false;this->direction = IDLE;this->current_floor = 1.0;this->stop_at_floors = vector<bool> (num_floors+1, false);}Elevator::~Elevator (){this->pause = false;this->terminate = true;}int Elevator::get_direction (){return this->direction;}/*** Return the number of floors above the current one that* are queued to be stopped at.*/int Elevator::floors_above_current (){int i = ((int)current_floor) + 1;int count = 0;for (/* see above */; i<num_floors+1; i++)if (stop_at_floors[i])count++;return count;}/*** Return the number of floors below the current one that* are queued to be stopped at.*/int Elevator::floors_below_current (){int i;int count = 0;if (near_a_floor ())i = (int)current_floor - 1;elsei = (int)current_floor;for (/* see above */; i>0; i--)if (stop_at_floors[i])count++;return count;}void Elevator::push_button (int floor){assert (floor <= num_floors && floor > 0);this->stop_at_floors[floor] = true;}/*** This function is the entry point for a thread.** You must pass the object in, since this is a static function* and we aren't allowed to access the this pointer.*/void Elevator::thread_entry (const Elevator *me){Elevator *pthis = (Elevator*)me;while (!pthis->terminate){/* Implement "pausing" */while (pthis->pause){usleep (ELEVATOR_TIME_PAUSE_USEC);}pthis->run_elevator_logic ();cout << "Current Elevator Position: " << pthis->current_floor << endl;usleep (ELEVATOR_TIME_DELAY_USEC);}}void Elevator::run_elevator_logic (){int i;/* Decide what to do */switch (direction){case IDLE:/* Move towards the direction that has more floors to stop at.* Prefer DOWN if there is a tie. */if (has_floors_to_stop_at ()){direction = (floors_above_current () > floors_below_current ()) ? MOVE_UP : MOVE_DOWN;printf ("changed direction to: %s\n", (direction == MOVE_UP) ? "MOVE_UP" : "MOVE_DOWN");}break;case MOVE_UP:/* Decide if we should stop at the floor we're at */if (should_stop_at_current_floor ()){debug_puts ("stop at a floor -- while going up");stop_at_floors[(int)current_floor] = false;}/* Decide to sit idle if we have no more floors to stop at */if (!has_floors_to_stop_at ()){debug_puts ("decides to sit idle");direction = IDLE;}/* Decide to switch directions if we have no more floors to stop* at in the current direction, but we have floors in the* opposite direction to stop at. */else if (floors_below_current () && !floors_above_current ()){debug_puts ("decides to switch direction to down");direction = MOVE_DOWN;}/* Since nothing else applies, we should keep moving in the* current direction, up. */else{current_floor += ELEVATOR_TIME_MOVE_AMOUNT;debug_puts ("moving up");// TODO: Add a check here to make sure we don't go too high}break;case MOVE_DOWN:/* Decide if we should stop at the floor we're at */if (should_stop_at_current_floor ()){debug_puts ("stop at floor -- while going down");stop_at_floors[(int)current_floor] = false;}/* Decide to sit idle if we have no more floors to stop at */if (!has_floors_to_stop_at ()){debug_puts ("decides to sit idle");direction = IDLE;}/* Decide to switch directions if we have no more floors to stop* at in the current direction, but we have floors in the* opposite direction to stop at. */else if (floors_above_current () && !floors_below_current ()){debug_puts ("decides to switch direction to up");direction = MOVE_UP;}/* Since nothing else applies, we should keep moving in the* current direction, down. */else{current_floor -= ELEVATOR_TIME_MOVE_AMOUNT;debug_puts ("moving down");// TODO: Add a check here to make sure we don't go too low}break;default:debug_puts ("bad value of direction");break;}}/*** Call this to stop the thread from running.*/void Elevator::thread_exit (){this->terminate = true;}/*** Call this to pause the thread without exiting it.*/void Elevator::thread_pause (){this->pause = true;}/*** Call this to unpause the thread.*/void Elevator::thread_unpause (){this->pause = false;}bool Elevator::near_a_floor (){const float range = ELEVATOR_TIME_MOVE_AMOUNT / 4.0;/* This seems somewhat counter-intuitive, but it's really not.* If we are near a floor, then one of the two of these will fail.** Example:* current_floor = 3.001;* first part is: 3 == 3 (true)* second part is: 3 == 2 (false)** Therefore we return true*/if ((int)current_floor == (int)(current_floor + range) &&(int)current_floor == (int)(current_floor - range)){return false;}return true;}bool Elevator::near_floor (int floor){if (near_a_floor () && floor == (int)current_floor)return true;return false;}bool Elevator::has_floors_to_stop_at (){int i;for (i=1; i<=num_floors; i++)if (stop_at_floors[i])return true;return false;}bool Elevator::should_stop_at_current_floor (){int i;for (i=1; i<= num_floors; i++)if (near_floor (i) && stop_at_floors[i] == true)return true;return false;}