Subversion Repositories programming

Rev

Rev 346 | 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));
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
 
332 ira 105
#ifndef QUIET
344 ira 106
        //std::cout << pthis << " Position: " << pthis->current_floor << std::endl;
332 ira 107
#endif
321 ira 108
        usleep (ELEVATOR_TIME_DELAY_USEC);
109
    }
110
}
111
 
329 ira 112
void Elevator::thread_start ()
113
{
334 ira 114
    boost::thread the_thread (boost::bind (this->thread_entry, this));
329 ira 115
}
116
 
321 ira 117
void Elevator::run_elevator_logic ()
118
{
119
    int i;
120
 
121
    /* Decide what to do */
122
    switch (direction)
123
    {
124
        case IDLE:
125
 
126
            /* Move towards the direction that has more floors to stop at.
127
             * Prefer DOWN if there is a tie. */
128
            if (has_floors_to_stop_at ())
129
            {
130
                direction = (floors_above_current () > floors_below_current ()) ? MOVE_UP : MOVE_DOWN;
332 ira 131
 
132
#ifndef QUIET
321 ira 133
                printf ("changed direction to: %s\n", (direction == MOVE_UP) ? "MOVE_UP" : "MOVE_DOWN");
332 ira 134
#endif
321 ira 135
            }
136
 
137
            break;
138
 
139
        case MOVE_UP:
140
 
141
            /* Decide if we should stop at the floor we're at */
142
            if (should_stop_at_current_floor ())
143
            {
340 ira 144
                stop_at_floor (MOVE_UP);
321 ira 145
            }
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 ())
182
            {
340 ira 183
                stop_at_floor (MOVE_DOWN);
321 ira 184
            }
185
 
186
            /* Decide to sit idle if we have no more floors to stop at */
187
            if (!has_floors_to_stop_at ())
188
            {
339 ira 189
#ifndef QUIET
190
                puts ("decides to sit idle");
191
#endif
321 ira 192
                direction = IDLE;
193
            }
194
            /* Decide to switch directions if we have no more floors to stop
195
             * at in the current direction, but we have floors in the
196
             * opposite direction to stop at. */
197
            else if (floors_above_current () && !floors_below_current ())
198
            {
339 ira 199
#ifndef QUIET
200
                puts ("decides to switch direction to up");
201
#endif
321 ira 202
                direction = MOVE_UP;
203
            }
204
            /* Since nothing else applies, we should keep moving in the
205
             * current direction, down. */
206
            else
207
            {
208
                current_floor -= ELEVATOR_TIME_MOVE_AMOUNT;
209
 
339 ira 210
                // Check to make sure we don't go too low
211
                assert (current_floor > -0.1);
321 ira 212
 
213
            }
214
 
215
            break;
216
 
217
        default:
348 ira 218
 
339 ira 219
            assert (false); // bad value of direction
321 ira 220
            break;
221
    }
340 ira 222
 
344 ira 223
    Dispatch_Data data;
224
    data.type = DISPATCH_DATA_UPDATE_LABEL;
225
    data.elev = this;
226
    data.farg = current_floor;
346 ira 227
    data.direc = direction;
344 ira 228
 
229
    controller->push_to_gui_queue (data);
230
 
231
    (*dispatcher)();
321 ira 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
 
340 ira 324
void Elevator::stop_at_floor (int in_direction)
325
{
326
    int the_floor = (int)(current_floor+0.5);
327
 
328
#ifndef QUIET
329
    if (in_direction == MOVE_UP)
330
        printf ("stop at floor %d -- while going up\n", the_floor);
331
    else
332
        printf ("stop at floor %d -- while going down\n", the_floor);
333
#endif
334
    stop_at_floors.at(the_floor) = false;
335
 
344 ira 336
    Dispatch_Data data;
337
    data.type = DISPATCH_DATA_STOP_AT_FLOOR;
338
    data.elev = this;
339
    data.iarg = the_floor;
346 ira 340
    data.direc = in_direction;
344 ira 341
 
342
    controller->push_to_gui_queue (data);
343
 
344
    (*dispatcher)();
340 ira 345
}
346
 
344 ira 347
void Elevator::set_dispatcher (Glib::Dispatcher *d)
348
{
349
    this->dispatcher = d;
350
}
351