Subversion Repositories programming

Rev

Rev 334 | Rev 337 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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