Subversion Repositories programming

Rev

Rev 340 | 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:
339 ira 218
 
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;
227
 
228
    controller->push_to_gui_queue (data);
229
 
230
    (*dispatcher)();
321 ira 231
}
232
 
233
/**
234
 * Call this to stop the thread from running.
235
 */
331 ira 236
void Elevator::thread_stop ()
321 ira 237
{
238
    this->terminate = true;
239
}
240
 
241
/**
242
 * Call this to pause the thread without exiting it.
243
 */
244
void Elevator::thread_pause ()
245
{
246
    this->pause = true;
247
}
248
 
249
/**
250
 * Call this to unpause the thread.
251
 */
252
void Elevator::thread_unpause ()
253
{
254
    this->pause = false;
255
}
256
 
257
bool Elevator::near_a_floor ()
258
{
330 ira 259
    int i;
321 ira 260
 
334 ira 261
    for (i=0; i<num_floors; i++)
330 ira 262
        if (near_floor (i))
263
            return true;
321 ira 264
 
330 ira 265
    return false;
321 ira 266
}
267
 
268
bool Elevator::near_floor (int floor)
269
{
337 ira 270
    assert (floor >= 0);
271
    assert (floor < num_floors);
272
 
330 ira 273
    const float thresh  = ELEVATOR_TIME_MOVE_AMOUNT / 2.0;
274
    const float greater = floor + thresh;
275
    const float lower   = floor - thresh;
276
 
277
    if (current_floor > lower && current_floor < greater)
321 ira 278
        return true;
279
 
280
    return false;
281
}
282
 
283
bool Elevator::has_floors_to_stop_at ()
284
{
285
    int i;
286
 
334 ira 287
    for (i=0; i<num_floors; i++)
335 ira 288
        if (stop_at_floors.at(i))
321 ira 289
            return true;
290
 
291
    return false;
292
}
293
 
294
bool Elevator::should_stop_at_current_floor ()
295
{
296
    int i;
297
 
334 ira 298
    for (i=0; i<num_floors; i++)
335 ira 299
        if (near_floor (i) && stop_at_floors.at(i) == true)
321 ira 300
            return true;
301
 
302
    return false;
303
}
304
 
328 ira 305
bool Elevator::button_is_pushed (int floor)
306
{
334 ira 307
    assert (floor < num_floors);
308
    assert (floor >= 0);
328 ira 309
 
335 ira 310
    return stop_at_floors.at(floor);
328 ira 311
}
312
 
313
float Elevator::get_current_floor ()
314
{
315
    return current_floor;
316
}
317
 
331 ira 318
void Elevator::set_controller (Controller *c)
319
{
320
    this->controller = c;
321
}
322
 
340 ira 323
void Elevator::stop_at_floor (int in_direction)
324
{
325
    int the_floor = (int)(current_floor+0.5);
326
 
327
#ifndef QUIET
328
    if (in_direction == MOVE_UP)
329
        printf ("stop at floor %d -- while going up\n", the_floor);
330
    else
331
        printf ("stop at floor %d -- while going down\n", the_floor);
332
#endif
333
    stop_at_floors.at(the_floor) = false;
334
 
344 ira 335
    Dispatch_Data data;
336
    data.type = DISPATCH_DATA_STOP_AT_FLOOR;
337
    data.elev = this;
338
    data.iarg = the_floor;
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