Subversion Repositories programming

Rev

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