Subversion Repositories programming

Rev

Rev 339 | Rev 344 | 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
            {
340 ira 146
                stop_at_floor (MOVE_UP);
321 ira 147
            }
148
 
149
            /* Decide to sit idle if we have no more floors to stop at */
150
            if (!has_floors_to_stop_at ())
151
            {
339 ira 152
#ifndef QUIET
153
                puts ("decides to sit idle");
154
#endif
321 ira 155
                direction = IDLE;
156
            }
157
            /* Decide to switch directions if we have no more floors to stop
158
             * at in the current direction, but we have floors in the
159
             * opposite direction to stop at. */
160
            else if (floors_below_current () && !floors_above_current ())
161
            {
339 ira 162
#ifndef QUIET
163
                puts ("decides to switch direction to down");
164
#endif
321 ira 165
                direction = MOVE_DOWN;
166
            }
167
            /* Since nothing else applies, we should keep moving in the
168
             * current direction, up. */
169
            else
170
            {
171
                current_floor += ELEVATOR_TIME_MOVE_AMOUNT;
172
 
339 ira 173
                // Check to make sure we don't go too high
174
                assert (current_floor < (num_floors * 1.0));
321 ira 175
 
176
            }
177
 
178
            break;
179
 
180
        case MOVE_DOWN:
181
 
182
            /* Decide if we should stop at the floor we're at */
183
            if (should_stop_at_current_floor ())
184
            {
340 ira 185
                stop_at_floor (MOVE_DOWN);
321 ira 186
            }
187
 
188
            /* Decide to sit idle if we have no more floors to stop at */
189
            if (!has_floors_to_stop_at ())
190
            {
339 ira 191
#ifndef QUIET
192
                puts ("decides to sit idle");
193
#endif
321 ira 194
                direction = IDLE;
195
            }
196
            /* Decide to switch directions if we have no more floors to stop
197
             * at in the current direction, but we have floors in the
198
             * opposite direction to stop at. */
199
            else if (floors_above_current () && !floors_below_current ())
200
            {
339 ira 201
#ifndef QUIET
202
                puts ("decides to switch direction to up");
203
#endif
321 ira 204
                direction = MOVE_UP;
205
            }
206
            /* Since nothing else applies, we should keep moving in the
207
             * current direction, down. */
208
            else
209
            {
210
                current_floor -= ELEVATOR_TIME_MOVE_AMOUNT;
211
 
339 ira 212
                // Check to make sure we don't go too low
213
                assert (current_floor > -0.1);
321 ira 214
 
215
            }
216
 
217
            break;
218
 
219
        default:
339 ira 220
 
221
            assert (false); // bad value of direction
321 ira 222
            break;
223
    }
340 ira 224
 
225
    controller->update_elevator_position (this);
321 ira 226
}
227
 
228
/**
229
 * Call this to stop the thread from running.
230
 */
331 ira 231
void Elevator::thread_stop ()
321 ira 232
{
233
    this->terminate = true;
234
}
235
 
236
/**
237
 * Call this to pause the thread without exiting it.
238
 */
239
void Elevator::thread_pause ()
240
{
241
    this->pause = true;
242
}
243
 
244
/**
245
 * Call this to unpause the thread.
246
 */
247
void Elevator::thread_unpause ()
248
{
249
    this->pause = false;
250
}
251
 
252
bool Elevator::near_a_floor ()
253
{
330 ira 254
    int i;
321 ira 255
 
334 ira 256
    for (i=0; i<num_floors; i++)
330 ira 257
        if (near_floor (i))
258
            return true;
321 ira 259
 
330 ira 260
    return false;
321 ira 261
}
262
 
263
bool Elevator::near_floor (int floor)
264
{
337 ira 265
    assert (floor >= 0);
266
    assert (floor < num_floors);
267
 
330 ira 268
    const float thresh  = ELEVATOR_TIME_MOVE_AMOUNT / 2.0;
269
    const float greater = floor + thresh;
270
    const float lower   = floor - thresh;
271
 
272
    if (current_floor > lower && current_floor < greater)
321 ira 273
        return true;
274
 
275
    return false;
276
}
277
 
278
bool Elevator::has_floors_to_stop_at ()
279
{
280
    int i;
281
 
334 ira 282
    for (i=0; i<num_floors; i++)
335 ira 283
        if (stop_at_floors.at(i))
321 ira 284
            return true;
285
 
286
    return false;
287
}
288
 
289
bool Elevator::should_stop_at_current_floor ()
290
{
291
    int i;
292
 
334 ira 293
    for (i=0; i<num_floors; i++)
335 ira 294
        if (near_floor (i) && stop_at_floors.at(i) == true)
321 ira 295
            return true;
296
 
297
    return false;
298
}
299
 
328 ira 300
bool Elevator::button_is_pushed (int floor)
301
{
334 ira 302
    assert (floor < num_floors);
303
    assert (floor >= 0);
328 ira 304
 
335 ira 305
    return stop_at_floors.at(floor);
328 ira 306
}
307
 
308
float Elevator::get_current_floor ()
309
{
310
    return current_floor;
311
}
312
 
331 ira 313
void Elevator::set_controller (Controller *c)
314
{
315
    this->controller = c;
316
}
317
 
318
void Elevator::have_user_enter_buttons ()
319
{
320
    controller->pause_all_elevators ();
334 ira 321
    usleep (10000);
331 ira 322
 
323
    std::string s;
324
 
325
    std::cout << "Enter floors to stop at for elevator (space seperated): ";
326
    getline (std::cin, s);
338 ira 327
 
331 ira 328
    typedef std::vector<std::string> split_vector_type;
329
    split_vector_type SplitVec;
330
    boost::split (SplitVec, s, boost::is_any_of(" "));
331
 
332
    int i, val;
333
    for (i=0; i<SplitVec.size(); i++)
334
    {
335
        val = atoi (SplitVec[i].c_str());
336
 
334 ira 337
        // Ignore values that are outside of range
338
        if (val >= 0 && val < num_floors)
331 ira 339
            this->push_button (val);
340
    }
341
 
342
    controller->unpause_all_elevators ();
343
}
344
 
340 ira 345
void Elevator::stop_at_floor (int in_direction)
346
{
347
    int the_floor = (int)(current_floor+0.5);
348
 
349
#ifndef QUIET
350
    if (in_direction == MOVE_UP)
351
        printf ("stop at floor %d -- while going up\n", the_floor);
352
    else
353
        printf ("stop at floor %d -- while going down\n", the_floor);
354
#endif
355
    stop_at_floors.at(the_floor) = false;
356
    //have_user_enter_buttons ();
357
 
358
    controller->stop_at_floor (this, the_floor);
359
}
360