Subversion Repositories programming

Rev

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