Subversion Repositories programming

Rev

Rev 338 | Rev 340 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
338 ira 1
/*******************************************************************************
2
 * elevator.cpp
3
 *
4
 * Implementation for the Elevator class.
5
 *
6
 * Copyright 2006, Ira W. Snyder (devel@irasnyder.com)
7
 ******************************************************************************/
321 ira 8
 
9
#include "elevator.h"
10
 
11
Elevator::Elevator (int num_floors) : num_floors(num_floors)
12
{
332 ira 13
    int i;
14
 
321 ira 15
    this->terminate = false;
16
    this->pause = false;
17
    this->direction = IDLE;
334 ira 18
    this->current_floor = 0.0;
331 ira 19
    this->controller = NULL;
321 ira 20
 
334 ira 21
    this->stop_at_floors.reserve (num_floors);
332 ira 22
 
334 ira 23
    for (i=0; i<num_floors; i++)
24
        this->stop_at_floors.push_back(bool(false));
332 ira 25
 
26
    printf ("created elevator 0x%x-- numfloors=%d\n", this, this->num_floors);
321 ira 27
}
28
 
29
Elevator::~Elevator ()
30
{
31
    this->pause = false;
32
    this->terminate = true;
33
}
34
 
35
int Elevator::get_direction ()
36
{
37
    return this->direction;
38
}
39
 
40
/**
41
 * Return the number of floors above the current one that
42
 * are queued to be stopped at.
43
 */
44
int Elevator::floors_above_current ()
45
{
46
    int i = ((int)current_floor) + 1;
47
    int count = 0;
48
 
334 ira 49
    for (/* see above */; i<num_floors; i++)
335 ira 50
        if (stop_at_floors.at(i))
321 ira 51
            count++;
52
 
53
    return count;
54
}
55
 
56
/**
57
 * Return the number of floors below the current one that
58
 * are queued to be stopped at.
59
 */
60
int Elevator::floors_below_current ()
61
{
62
    int i;
63
    int count = 0;
64
 
65
    if (near_a_floor ())
66
        i = (int)current_floor - 1;
67
    else
68
        i = (int)current_floor;
69
 
335 ira 70
    for (/* see above */; i>=0; i--)
71
        if (stop_at_floors.at(i))
321 ira 72
            count++;
73
 
74
    return count;
75
}
76
 
77
void Elevator::push_button (int floor)
78
{
334 ira 79
    assert (floor < num_floors);
80
    assert (floor >= 0);
321 ira 81
 
335 ira 82
    this->stop_at_floors.at(floor) = true;
321 ira 83
}
84
 
85
/**
86
 * This function is the entry point for a thread.
87
 *
88
 * You must pass the object in, since this is a static function
89
 * and we aren't allowed to access the this pointer.
90
 */
91
void Elevator::thread_entry (const Elevator *me)
92
{
337 ira 93
    assert (me != NULL);
94
 
321 ira 95
    Elevator *pthis = (Elevator*)me;
96
 
97
    while (!pthis->terminate)
98
    {
99
        /* Implement "pausing" */
100
        while (pthis->pause)
101
        {
102
            usleep (ELEVATOR_TIME_PAUSE_USEC);
103
        }
104
 
105
        pthis->run_elevator_logic ();
106
 
332 ira 107
#ifndef QUIET
329 ira 108
        std::cout << pthis << " Position: " << pthis->current_floor << std::endl;
332 ira 109
#endif
321 ira 110
        usleep (ELEVATOR_TIME_DELAY_USEC);
111
    }
112
}
113
 
329 ira 114
void Elevator::thread_start ()
115
{
334 ira 116
    boost::thread the_thread (boost::bind (this->thread_entry, this));
329 ira 117
}
118
 
321 ira 119
void Elevator::run_elevator_logic ()
120
{
121
    int i;
122
 
123
    /* Decide what to do */
124
    switch (direction)
125
    {
126
        case IDLE:
127
 
128
            /* Move towards the direction that has more floors to stop at.
129
             * Prefer DOWN if there is a tie. */
130
            if (has_floors_to_stop_at ())
131
            {
132
                direction = (floors_above_current () > floors_below_current ()) ? MOVE_UP : MOVE_DOWN;
332 ira 133
 
134
#ifndef QUIET
321 ira 135
                printf ("changed direction to: %s\n", (direction == MOVE_UP) ? "MOVE_UP" : "MOVE_DOWN");
332 ira 136
#endif
321 ira 137
            }
138
 
139
            break;
140
 
141
        case MOVE_UP:
142
 
143
            /* Decide if we should stop at the floor we're at */
144
            if (should_stop_at_current_floor ())
145
            {
334 ira 146
#ifndef QUIET
147
                printf ("stop at floor %d -- while going up\n", (int)(current_floor+0.5));
148
#endif
335 ira 149
                stop_at_floors.at((int)(current_floor+0.5)) = false;
331 ira 150
                have_user_enter_buttons ();
321 ira 151
            }
152
 
153
            /* Decide to sit idle if we have no more floors to stop at */
154
            if (!has_floors_to_stop_at ())
155
            {
339 ira 156
#ifndef QUIET
157
                puts ("decides to sit idle");
158
#endif
321 ira 159
                direction = IDLE;
160
            }
161
            /* Decide to switch directions if we have no more floors to stop
162
             * at in the current direction, but we have floors in the
163
             * opposite direction to stop at. */
164
            else if (floors_below_current () && !floors_above_current ())
165
            {
339 ira 166
#ifndef QUIET
167
                puts ("decides to switch direction to down");
168
#endif
321 ira 169
                direction = MOVE_DOWN;
170
            }
171
            /* Since nothing else applies, we should keep moving in the
172
             * current direction, up. */
173
            else
174
            {
175
                current_floor += ELEVATOR_TIME_MOVE_AMOUNT;
176
 
339 ira 177
                // Check to make sure we don't go too high
178
                assert (current_floor < (num_floors * 1.0));
321 ira 179
 
180
            }
181
 
182
            break;
183
 
184
        case MOVE_DOWN:
185
 
186
            /* Decide if we should stop at the floor we're at */
187
            if (should_stop_at_current_floor ())
188
            {
334 ira 189
#ifndef QUIET
190
                printf ("stop at floor %d -- while going down\n", (int)(current_floor+0.5));
191
#endif
335 ira 192
                stop_at_floors.at((int)(current_floor+0.5)) = false;
331 ira 193
                have_user_enter_buttons ();
321 ira 194
            }
195
 
196
            /* Decide to sit idle if we have no more floors to stop at */
197
            if (!has_floors_to_stop_at ())
198
            {
339 ira 199
#ifndef QUIET
200
                puts ("decides to sit idle");
201
#endif
321 ira 202
                direction = IDLE;
203
            }
204
            /* Decide to switch directions if we have no more floors to stop
205
             * at in the current direction, but we have floors in the
206
             * opposite direction to stop at. */
207
            else if (floors_above_current () && !floors_below_current ())
208
            {
339 ira 209
#ifndef QUIET
210
                puts ("decides to switch direction to up");
211
#endif
321 ira 212
                direction = MOVE_UP;
213
            }
214
            /* Since nothing else applies, we should keep moving in the
215
             * current direction, down. */
216
            else
217
            {
218
                current_floor -= ELEVATOR_TIME_MOVE_AMOUNT;
219
 
339 ira 220
                // Check to make sure we don't go too low
221
                assert (current_floor > -0.1);
321 ira 222
 
223
            }
224
 
225
            break;
226
 
227
        default:
339 ira 228
 
229
            assert (false); // bad value of direction
321 ira 230
            break;
231
    }
232
}
233
 
234
/**
235
 * Call this to stop the thread from running.
236
 */
331 ira 237
void Elevator::thread_stop ()
321 ira 238
{
239
    this->terminate = true;
240
}
241
 
242
/**
243
 * Call this to pause the thread without exiting it.
244
 */
245
void Elevator::thread_pause ()
246
{
247
    this->pause = true;
248
}
249
 
250
/**
251
 * Call this to unpause the thread.
252
 */
253
void Elevator::thread_unpause ()
254
{
255
    this->pause = false;
256
}
257
 
258
bool Elevator::near_a_floor ()
259
{
330 ira 260
    int i;
321 ira 261
 
334 ira 262
    for (i=0; i<num_floors; i++)
330 ira 263
        if (near_floor (i))
264
            return true;
321 ira 265
 
330 ira 266
    return false;
321 ira 267
}
268
 
269
bool Elevator::near_floor (int floor)
270
{
337 ira 271
    assert (floor >= 0);
272
    assert (floor < num_floors);
273
 
330 ira 274
    const float thresh  = ELEVATOR_TIME_MOVE_AMOUNT / 2.0;
275
    const float greater = floor + thresh;
276
    const float lower   = floor - thresh;
277
 
278
    if (current_floor > lower && current_floor < greater)
321 ira 279
        return true;
280
 
281
    return false;
282
}
283
 
284
bool Elevator::has_floors_to_stop_at ()
285
{
286
    int i;
287
 
334 ira 288
    for (i=0; i<num_floors; i++)
335 ira 289
        if (stop_at_floors.at(i))
321 ira 290
            return true;
291
 
292
    return false;
293
}
294
 
295
bool Elevator::should_stop_at_current_floor ()
296
{
297
    int i;
298
 
334 ira 299
    for (i=0; i<num_floors; i++)
335 ira 300
        if (near_floor (i) && stop_at_floors.at(i) == true)
321 ira 301
            return true;
302
 
303
    return false;
304
}
305
 
328 ira 306
bool Elevator::button_is_pushed (int floor)
307
{
334 ira 308
    assert (floor < num_floors);
309
    assert (floor >= 0);
328 ira 310
 
335 ira 311
    return stop_at_floors.at(floor);
328 ira 312
}
313
 
314
float Elevator::get_current_floor ()
315
{
316
    return current_floor;
317
}
318
 
331 ira 319
void Elevator::set_controller (Controller *c)
320
{
321
    this->controller = c;
322
}
323
 
324
void Elevator::have_user_enter_buttons ()
325
{
326
    controller->pause_all_elevators ();
334 ira 327
    usleep (10000);
331 ira 328
 
329
    std::string s;
330
 
331
    std::cout << "Enter floors to stop at for elevator (space seperated): ";
332
    getline (std::cin, s);
338 ira 333
 
331 ira 334
    typedef std::vector<std::string> split_vector_type;
335
    split_vector_type SplitVec;
336
    boost::split (SplitVec, s, boost::is_any_of(" "));
337
 
338
    int i, val;
339
    for (i=0; i<SplitVec.size(); i++)
340
    {
341
        val = atoi (SplitVec[i].c_str());
342
 
334 ira 343
        // Ignore values that are outside of range
344
        if (val >= 0 && val < num_floors)
331 ira 345
            this->push_button (val);
346
    }
347
 
348
    controller->unpause_all_elevators ();
349
}
350