Rev 344 | Rev 347 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
/******************************************************************************** controller.cpp** Implementation for the Controller class.** Copyright 2006, Ira W. Snyder (devel@irasnyder.com)******************************************************************************/#include "controller.h"Controller::Controller (int num_floors, int num_elevators) : num_floors (num_floors), num_elevators (num_elevators){assert (num_floors > 2);assert (num_elevators > 0);// Connect to the dispatcherdispatcher.connect (sigc::mem_fun (*this, &Controller::dispatch_handler));// Create all of the elevatorselevator.reserve (num_elevators);for (int i=0; i<num_elevators; i++){elevator.push_back (new Elevator (num_floors));elevator.at(i) -> set_controller (this);elevator.at(i) -> set_dispatcher (&dispatcher);}// Seed the RNGsrandom (time(NULL));}Controller::~Controller (){}void Controller::request_elevator (int on_floor, int direction){assert (on_floor < num_floors);assert (on_floor >= 0);assert (direction == MOVE_UP || direction == MOVE_DOWN);float distance = INT_MAX;int elevator_number;// check that there is not already an elevator requested// to this floor. If there is already one, ignore this// request.if (floor_already_requested (on_floor))return;// find elevator that is closest, AND NOT moving away// "push" it's buttonelevator_number = find_closest_elevator (on_floor, direction);elevator.at(elevator_number) -> push_button (on_floor);//printf ("elevator[%d] gets queued for floor: %d\n", elevator_number, on_floor);}/*** Check if there is an elevator already in the queue to stop* at the floor given as a parameter.*/bool Controller::floor_already_requested (int on_floor){assert (on_floor >= 0);assert (on_floor < num_floors);int i;for (i=0; i<num_elevators; i++)if (elevator.at(i) -> button_is_pushed (on_floor))return true;return false;}/*** Return the number of the closest elevator to the* floor given as a parameter.** We only want to choose elevators that are close and* heading in the right direction, or the closest elevator* if it is sitting idle.*/int Controller::find_closest_elevator (int to_floor, int in_direction){assert (to_floor >= 0);assert (to_floor < num_floors);assert (in_direction == MOVE_UP || in_direction == MOVE_DOWN);int i;float distance = INT_MAX;float temp_distance;int answer = -1;float cur_floor;int cur_direction;//printf ("finding closest elevator: to_floor=%d -- in_direction=%d\n", to_floor, in_direction);for (i=0; i<num_elevators; i++){cur_floor = elevator.at(i) -> get_current_floor ();cur_direction = elevator.at(i) -> get_direction ();temp_distance = fabsf (cur_floor - to_floor);//printf ("cur_floor=%e -- direc=%d -- t_dist=%e\n", cur_floor, cur_direction, temp_distance);// Automatically discard elevators that are moving in the wrong// direction, but DO consider ones that are idle.if (cur_direction == MOVE_DOWN && in_direction == MOVE_UP){//printf ("type 1: skipped elevator[%d]\n", i);continue;}if (cur_direction == MOVE_UP && in_direction == MOVE_DOWN){//printf ("type 2: skipped elevator[%d]\n", i);continue;}if (cur_floor < to_floor && cur_direction == MOVE_UP){//printf ("good cantidate type 1\n");// GOOD CANTIDATEif (temp_distance < distance){answer = i;distance = temp_distance;}}if (cur_floor > to_floor && cur_direction == MOVE_DOWN){//printf ("good cantidate type 2\n");// GOOD CANTIDATEif (temp_distance < distance){answer = i;distance = temp_distance;}}if (cur_direction == IDLE && temp_distance < distance){//printf ("idle cantidate\n");answer = i;distance = temp_distance;}}// If we failed to find an elevator, then we need to// pick at random.if (answer == -1){// Pick a random number in the range [0,num_elevators-1]answer = (int) (0.0 + ((num_elevators - 1.0) * (random() / (RAND_MAX + 1.0))));printf ("picked at random: %d\n", answer);assert (answer >= 0);assert (answer < num_elevators);}return answer;}void Controller::start_all_elevators (){int i;for (i=0; i<num_elevators; i++)elevator.at(i) -> thread_start ();}void Controller::stop_all_elevators (){int i;for (i=0; i<num_elevators; i++)elevator.at(i) -> thread_stop ();}void Controller::pause_all_elevators (){int i;for (i=0; i<num_elevators; i++)elevator.at(i) -> thread_pause ();}void Controller::unpause_all_elevators (){int i;for (i=0; i<num_elevators; i++)elevator.at(i) -> thread_unpause ();}int Controller::which_elevator_is (Elevator *e){int i;for (i=0; i<num_elevators; i++)if (elevator.at (i) == e)return i;return -1;}void Controller::stop_at_floor (Elevator *e, int floor, int direction){int elevator_num = which_elevator_is (e);assert (elevator_num != -1);pause_all_elevators ();// Open the elevator doorgui->open_elevator_at (num_floors-(floor+1), elevator_num);// FIXME -- always unsets up buttonif (floor >= 0 && floor <= 8)gui->unset_up_button (floor);// FIXME -- always unsets down buttonif (floor >= 1 && floor <= 9)gui->unset_down_button (floor-1);// Get the floors from the usergui->get_floors_from_user (elevator_num);// Close the elevator doorgui->close_elevator_at (num_floors-(floor+1), elevator_num);unpause_all_elevators ();}void Controller::set_gui (Elevator_Window *gui){this->gui = gui;}void Controller::update_elevator_position (Elevator *e, float new_floor){std::ostringstream strstrm;int elevator_num = which_elevator_is (e);assert (elevator_num != -1);// Create the labelstrstrm << std::setiosflags (std::ios_base::showpoint | std::ios_base::fixed)<< std::setprecision (1) << new_floor;gui->set_label (elevator_num, strstrm.str());}void Controller::push_to_gui_queue (Dispatch_Data data){gui_events.push (data);}void Controller::dispatch_handler (){assert (gui_events.empty() == false);// Pop the first variable off of the queueDispatch_Data temp = gui_events.front ();gui_events.pop ();switch (temp.type){case DISPATCH_DATA_STOP_AT_FLOOR:stop_at_floor (temp.elev, temp.iarg, temp.direc);break;case DISPATCH_DATA_UPDATE_LABEL:update_elevator_position (temp.elev, temp.farg);break;default:std::cout << "Bad value in dispatch_handler()" << std::endl;break;}}void Controller::push_button_in_elevator (int elevator_num, int floor){assert (elevator_num < num_elevators);assert (elevator_num >= 0);assert (floor < num_floors);assert (floor >= 0);elevator.at (elevator_num)->push_button (floor);}