Subversion Repositories programming

Rev

Rev 321 | Rev 329 | 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
{
9
#ifndef _NDEBUG
10
    puts (s);
11
#endif
12
}
13
// FIXME
14
// FIXME
15
// FIXME
16
 
17
Elevator::Elevator (int num_floors) : num_floors(num_floors)
18
{
19
    this->terminate = false;
20
    this->pause = false;
21
    this->direction = IDLE;
22
    this->current_floor = 1.0;
23
 
328 ira 24
    this->stop_at_floors = std::vector<bool> (num_floors+1, 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
 
47
    for (/* see above */; i<num_floors+1; i++)
48
        if (stop_at_floors[i])
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
 
68
    for (/* see above */; i>0; i--)
69
        if (stop_at_floors[i])
70
            count++;
71
 
72
    return count;
73
}
74
 
75
void Elevator::push_button (int floor)
76
{
77
    assert (floor <= num_floors && floor > 0);
78
 
79
    this->stop_at_floors[floor] = true;
80
}
81
 
82
/**
83
 * This function is the entry point for a thread.
84
 *
85
 * You must pass the object in, since this is a static function
86
 * and we aren't allowed to access the this pointer.
87
 */
88
void Elevator::thread_entry (const Elevator *me)
89
{
90
    Elevator *pthis = (Elevator*)me;
91
 
92
    while (!pthis->terminate)
93
    {
94
        /* Implement "pausing" */
95
        while (pthis->pause)
96
        {
97
            usleep (ELEVATOR_TIME_PAUSE_USEC);
98
        }
99
 
100
        pthis->run_elevator_logic ();
101
 
328 ira 102
        std::cout << "Current Elevator Position: " << pthis->current_floor << std::endl;
321 ira 103
        usleep (ELEVATOR_TIME_DELAY_USEC);
104
    }
105
}
106
 
107
void Elevator::run_elevator_logic ()
108
{
109
    int i;
110
 
111
    /* Decide what to do */
112
    switch (direction)
113
    {
114
        case IDLE:
115
 
116
            /* Move towards the direction that has more floors to stop at.
117
             * Prefer DOWN if there is a tie. */
118
            if (has_floors_to_stop_at ())
119
            {
120
                direction = (floors_above_current () > floors_below_current ()) ? MOVE_UP : MOVE_DOWN;
121
                printf ("changed direction to: %s\n", (direction == MOVE_UP) ? "MOVE_UP" : "MOVE_DOWN");
122
            }
123
 
124
            break;
125
 
126
        case MOVE_UP:
127
 
128
            /* Decide if we should stop at the floor we're at */
129
            if (should_stop_at_current_floor ())
130
            {
131
                debug_puts ("stop at a floor -- while going up");
132
                stop_at_floors[(int)current_floor] = false;
133
            }
134
 
135
            /* Decide to sit idle if we have no more floors to stop at */
136
            if (!has_floors_to_stop_at ())
137
            {
138
                debug_puts ("decides to sit idle");
139
                direction = IDLE;
140
            }
141
            /* Decide to switch directions if we have no more floors to stop
142
             * at in the current direction, but we have floors in the
143
             * opposite direction to stop at. */
144
            else if (floors_below_current () && !floors_above_current ())
145
            {
146
                debug_puts ("decides to switch direction to down");
147
                direction = MOVE_DOWN;
148
            }
149
            /* Since nothing else applies, we should keep moving in the
150
             * current direction, up. */
151
            else
152
            {
153
                current_floor += ELEVATOR_TIME_MOVE_AMOUNT;
154
                debug_puts ("moving up");
155
 
156
                // TODO: Add a check here to make sure we don't go too high
157
 
158
            }
159
 
160
            break;
161
 
162
        case MOVE_DOWN:
163
 
164
            /* Decide if we should stop at the floor we're at */
165
            if (should_stop_at_current_floor ())
166
            {
167
                debug_puts ("stop at floor -- while going down");
168
                stop_at_floors[(int)current_floor] = false;
169
            }
170
 
171
            /* Decide to sit idle if we have no more floors to stop at */
172
            if (!has_floors_to_stop_at ())
173
            {
174
                debug_puts ("decides to sit idle");
175
                direction = IDLE;
176
            }
177
            /* Decide to switch directions if we have no more floors to stop
178
             * at in the current direction, but we have floors in the
179
             * opposite direction to stop at. */
180
            else if (floors_above_current () && !floors_below_current ())
181
            {
182
                debug_puts ("decides to switch direction to up");
183
                direction = MOVE_UP;
184
            }
185
            /* Since nothing else applies, we should keep moving in the
186
             * current direction, down. */
187
            else
188
            {
189
                current_floor -= ELEVATOR_TIME_MOVE_AMOUNT;
190
                debug_puts ("moving down");
191
 
192
                // TODO: Add a check here to make sure we don't go too low
193
 
194
            }
195
 
196
            break;
197
 
198
        default:
199
 
200
            debug_puts ("bad value of direction");
201
            break;
202
    }
203
}
204
 
205
/**
206
 * Call this to stop the thread from running.
207
 */
208
void Elevator::thread_exit ()
209
{
210
    this->terminate = true;
211
}
212
 
213
/**
214
 * Call this to pause the thread without exiting it.
215
 */
216
void Elevator::thread_pause ()
217
{
218
    this->pause = true;
219
}
220
 
221
/**
222
 * Call this to unpause the thread.
223
 */
224
void Elevator::thread_unpause ()
225
{
226
    this->pause = false;
227
}
228
 
229
bool Elevator::near_a_floor ()
230
{
231
    const float range = ELEVATOR_TIME_MOVE_AMOUNT / 4.0;
232
 
233
    /* This seems somewhat counter-intuitive, but it's really not.
234
     * If we are near a floor, then one of the two of these will fail.
235
     *
236
     * Example:
237
     * current_floor = 3.001;
238
     * first part is: 3 == 3   (true)
239
     * second part is: 3 == 2  (false)
240
     *
241
     * Therefore we return true
242
     */
243
    if ((int)current_floor == (int)(current_floor + range) &&
244
        (int)current_floor == (int)(current_floor - range))
245
    {
246
        return false;
247
    }
248
 
249
    return true;
250
}
251
 
252
bool Elevator::near_floor (int floor)
253
{
254
    if (near_a_floor () && floor == (int)current_floor)
255
        return true;
256
 
257
    return false;
258
}
259
 
260
bool Elevator::has_floors_to_stop_at ()
261
{
262
    int i;
263
 
264
    for (i=1; i<=num_floors; i++)
265
        if (stop_at_floors[i])
266
            return true;
267
 
268
    return false;
269
}
270
 
271
bool Elevator::should_stop_at_current_floor ()
272
{
273
    int i;
274
 
275
    for (i=1; i<= num_floors; i++)
276
        if (near_floor (i) && stop_at_floors[i] == true)
277
            return true;
278
 
279
    return false;
280
}
281
 
328 ira 282
bool Elevator::button_is_pushed (int floor)
283
{
284
    assert (floor <= num_floors);
285
    assert (floor > 0);
286
 
287
    return stop_at_floors[floor];
288
}
289
 
290
float Elevator::get_current_floor ()
291
{
292
    return current_floor;
293
}
294