Rev 329 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
#include "elevator.h"
// FIXME
// FIXME
// FIXME
void debug_puts (const char* s)
{
#ifndef _NDEBUG
puts (s);
#endif
}
// FIXME
// FIXME
// FIXME
Elevator::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;
else
i = (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;
}