Rev 346 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
/******************************************************************************** elevator.cpp** Implementation for the Elevator class.** Copyright 2006, Ira W. Snyder (devel@irasnyder.com)******************************************************************************/#include "elevator.h"Elevator::Elevator (int num_floors) : num_floors(num_floors){int i;this->terminate = false;this->pause = false;this->direction = IDLE;this->current_floor = 0.0;this->controller = NULL;this->stop_at_floors.reserve (num_floors);for (i=0; i<num_floors; i++)this->stop_at_floors.push_back(bool(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; i++)if (stop_at_floors.at(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.at(i))count++;return count;}void Elevator::push_button (int floor){assert (floor < num_floors);assert (floor >= 0);this->stop_at_floors.at(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){assert (me != NULL);Elevator *pthis = (Elevator*)me;while (!pthis->terminate){/* Implement "pausing" */while (pthis->pause){usleep (ELEVATOR_TIME_PAUSE_USEC);}pthis->run_elevator_logic ();#ifndef QUIET//std::cout << pthis << " Position: " << pthis->current_floor << std::endl;#endifusleep (ELEVATOR_TIME_DELAY_USEC);}}void Elevator::thread_start (){boost::thread the_thread (boost::bind (this->thread_entry, this));}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;#ifndef QUIETprintf ("changed direction to: %s\n", (direction == MOVE_UP) ? "MOVE_UP" : "MOVE_DOWN");#endif}break;case MOVE_UP:/* Decide if we should stop at the floor we're at */if (should_stop_at_current_floor ()){stop_at_floor (MOVE_UP);}/* Decide to sit idle if we have no more floors to stop at */if (!has_floors_to_stop_at ()){#ifndef QUIETputs ("decides to sit idle");#endifdirection = 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 ()){#ifndef QUIETputs ("decides to switch direction to down");#endifdirection = MOVE_DOWN;}/* Since nothing else applies, we should keep moving in the* current direction, up. */else{current_floor += ELEVATOR_TIME_MOVE_AMOUNT;// Check to make sure we don't go too highassert (current_floor < (num_floors * 1.0));}break;case MOVE_DOWN:/* Decide if we should stop at the floor we're at */if (should_stop_at_current_floor ()){stop_at_floor (MOVE_DOWN);}/* Decide to sit idle if we have no more floors to stop at */if (!has_floors_to_stop_at ()){#ifndef QUIETputs ("decides to sit idle");#endifdirection = 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 ()){#ifndef QUIETputs ("decides to switch direction to up");#endifdirection = MOVE_UP;}/* Since nothing else applies, we should keep moving in the* current direction, down. */else{current_floor -= ELEVATOR_TIME_MOVE_AMOUNT;// Check to make sure we don't go too lowassert (current_floor > -0.1);}break;default:assert (false); // bad value of directionbreak;}Dispatch_Data data;data.type = DISPATCH_DATA_UPDATE_LABEL;data.elev = this;data.farg = current_floor;data.direc = direction;controller->push_to_gui_queue (data);(*dispatcher)();}/*** Call this to stop the thread from running.*/void Elevator::thread_stop (){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 (){int i;for (i=0; i<num_floors; i++)if (near_floor (i))return true;return false;}bool Elevator::near_floor (int floor){assert (floor >= 0);assert (floor < num_floors);const float thresh = ELEVATOR_TIME_MOVE_AMOUNT / 2.0;const float greater = floor + thresh;const float lower = floor - thresh;if (current_floor > lower && current_floor < greater)return true;return false;}bool Elevator::has_floors_to_stop_at (){int i;for (i=0; i<num_floors; i++)if (stop_at_floors.at(i))return true;return false;}bool Elevator::should_stop_at_current_floor (){int i;for (i=0; i<num_floors; i++)if (near_floor (i) && stop_at_floors.at(i) == true)return true;return false;}bool Elevator::button_is_pushed (int floor){assert (floor < num_floors);assert (floor >= 0);return stop_at_floors.at(floor);}float Elevator::get_current_floor (){return current_floor;}void Elevator::set_controller (Controller *c){this->controller = c;}void Elevator::stop_at_floor (int in_direction){int the_floor = (int)(current_floor+0.5);#ifndef QUIETif (in_direction == MOVE_UP)printf ("stop at floor %d -- while going up\n", the_floor);elseprintf ("stop at floor %d -- while going down\n", the_floor);#endifstop_at_floors.at(the_floor) = false;Dispatch_Data data;data.type = DISPATCH_DATA_STOP_AT_FLOOR;data.elev = this;data.iarg = the_floor;data.direc = in_direction;controller->push_to_gui_queue (data);(*dispatcher)();}void Elevator::set_dispatcher (Glib::Dispatcher *d){this->dispatcher = d;}