Project

General

Profile

Statistics
| Revision:

root / branches / autonomous_recharging / code / projects / autonomous_recharging / charging_station / charging.c @ 790

History | View | Annotate | Download (8.94 KB)

1
#include "charging.h"
2
#include "charging_defs.h"
3
#include "bays.h"
4

    
5
#include <stdlib.h>
6
#include <serial.h>
7

    
8
#include <wl_token_ring.h>
9
#include "wl_charging_station.h"
10

    
11
#define BATTERY_LOWV 152
12

    
13
//set this to the number of bays
14
#define NUM_BAYS 2
15

    
16
//Function prototypes
17
void charging_bom_on(void);
18
void charging_bom_off(void);
19
int charging_bom_read(void);
20

    
21
//Structures
22
typedef struct
23
{
24
        int state;
25
        int bay;
26
        int verifyCount;
27
        int battery;
28
} ChargingRobot;
29

    
30
ChargingRobot** robots;
31
int robotsSize = 0;
32
int numRobots = 0;
33
int iteratorPos = 0;
34

    
35
int bays[NUM_BAYS];
36

    
37
int is_seeking = 0;
38

    
39
/**
40
 * Call this function to initialize charging.
41
 * wl_token_ring_register must be called before
42
 * this function.
43
 **/
44
void charging_init(void)
45
{
46
        robots = malloc(robotsSize * sizeof(ChargingRobot*));
47
        if (!robots)
48
        {
49
                STATION_DEBUG_PRINT("Out of memory.\n");
50
                return;
51
        }
52
        
53
        int i;
54
        for (i = 0; i < robotsSize; i++)
55
                robots[i] = NULL;
56

    
57
        for (i = 0; i < NUM_BAYS; i++)
58
                bays[i] = -1;
59

    
60
        bays_init();
61

    
62
        // call our own special function to set the BOM
63
        wl_token_ring_set_bom_functions(charging_bom_on,
64
                charging_bom_off, charging_bom_read);
65
        wl_station_register();
66
}
67

    
68
/**
69
 * Initializes the iterator through the robots
70
 * which are using the charging station.
71
 **/
72
void charging_robot_iterator_init(void)
73
{
74
        iteratorPos = 0;
75
}
76

    
77
/**
78
 * Returns zero if the iterator has gone through
79
 * all robots that are using the charging station
80
 * since the last call to charging_robot_iterator_init,
81
 * nonzero otherwise.
82
 *
83
 * @return if the iterator has gone through all the robots
84
 **/
85
int charging_robot_iterator_has_next(void)
86
{
87
        while (iteratorPos < robotsSize)
88
        {
89
                if (robots[iteratorPos] != NULL)
90
                        return 1;
91
                iteratorPos++;
92
        }
93
        return 0;
94
}
95

    
96
/**
97
 * Returns the id of the next robot in the iterator
98
 * of robots that are using the charging station.
99
 *
100
 * @return the id of a robot using the station
101
 **/
102
int charging_robot_iterator_next(void)
103
{
104
        while (iteratorPos < robotsSize)
105
        {
106
                if (robots[iteratorPos] != NULL)
107
                {
108
                        iteratorPos++;
109
                        return iteratorPos - 1;
110
                }
111
        }
112
        
113
        return -1;
114
}
115

    
116
/**
117
 * Return the verification count for a robot
118
 * using the station. If the count is zero,
119
 * then the robot is probably dead.
120
 *
121
 * @param robot the id of the robot to check
122
 * 
123
 * @return the verify count for robot robot
124
 **/
125
int charging_get_verify_count(int robot)
126
{
127
        if (robot >= robotsSize || robot < 0)
128
        {
129
                STATION_DEBUG_PRINT("Index out of range.\n");
130
                return -1;
131
        }
132
        if (robots[robot] == NULL)
133
        {
134
                STATION_DEBUG_PRINT("Robot not known to charging station.\n");
135
                return -1;
136
        }
137

    
138
        return robots[robot]->verifyCount;
139
}
140

    
141
/**
142
 * Sets the verify count for the specified robot.
143
 *
144
 * @param robot the robot to specify the count for
145
 * @param count the new verify count
146
 **/
147
void charging_set_verify_count(int robot, int count)
148
{
149
        if (robot >= robotsSize || robot < 0)
150
        {
151
                STATION_DEBUG_PRINT("Index out of range.\n");
152
                return;
153
        }
154
        if (robots[robot] == NULL)
155
        {
156
                STATION_DEBUG_PRINT("Robot not known to charging station.\n");
157
                return;
158
        }
159

    
160
        robots[robot]->verifyCount = count;
161
}
162

    
163
/**
164
 * Called when charging has been cancelled for a 
165
 * specific robot.
166
 *
167
 * @param robot the robot to cancel charging for
168
 **/
169
void charging_cancel(int robot)
170
{
171
        if (robot < 0 || robot >= robotsSize || robots[robot] == NULL)
172
        {
173
                STATION_DEBUG_PRINT("Attempted to cancel charging for an ");
174
                STATION_DEBUG_PRINT("unknown robot.\n");
175
                return;
176
        }
177

    
178
        STATION_DEBUG_PRINT("Cancelling charging for robot ");
179
        STATION_DEBUG_PUTI(robot);
180
        STATION_DEBUG_PRINT(".\n");
181

    
182
        //allow other robots to seek
183
        if (robots[robot]->state == STATE_SEEKING)
184
        {
185
                bay_disable();
186
                is_seeking = 0;
187
        }
188

    
189
        //free the bay
190
        bays[robots[robot]->bay] = -1;
191

    
192
        free(robots[robot]);
193
        robots[robot] = NULL;
194
        numRobots--;
195
}
196

    
197
/**
198
 * Assigns a bay to a specific robot.
199
 *
200
 * @param robot the robot to assign the bay to
201
 *
202
 * @return the identifier for the assigned bay
203
 **/
204
int assign_bay(int robot)
205
{
206
        int bay = 0;
207

    
208
        //TODO: use better algorithm based on distance
209
        for (bay = 0; bay < NUM_BAYS; bay++)
210
                if (bays[bay] == -1)
211
                        break;
212

    
213
        if (bay == NUM_BAYS)
214
        {
215
                STATION_DEBUG_PRINT("Attempted to assign a bay when all ");
216
                STATION_DEBUG_PRINT("are full.\n");
217
        }
218

    
219
        bays[bay] = robot;
220
        return bay;
221
}
222

    
223
/**
224
 * Called when a robot begins seeking.
225
 *
226
 * @param robot the robot which has begun seeking
227
 **/
228
void charging_begin_seeking(int robot)
229
{
230
        STATION_DEBUG_PRINT("Robot ");
231
        STATION_DEBUG_PUTI(robot);
232
        STATION_DEBUG_PRINT(" has begun seeking.\n");
233
        
234
        if (robot > robotsSize)
235
        {
236
                int nextSize = robot + 1;
237
                ChargingRobot** temp = malloc(nextSize * sizeof(ChargingRobot*));
238
                if (temp == NULL)
239
                {
240
                        STATION_DEBUG_PRINT("Out of memory.\n");
241
                        return;
242
                }
243
                int i;
244
                for (i = 0; i < robotsSize; i++)
245
                        temp[i] = robots[i];
246
                for (; i < nextSize; i++)
247
                        temp[i] = NULL;
248
                free(robots);
249
                robots = temp;
250
                robotsSize = nextSize;
251
        }
252

    
253
        if (charging_is_robot_seeking())
254
        {
255
                STATION_DEBUG_PRINT("A robot is already seeking.\n");
256
                return;
257
        }
258

    
259
        //check if robot has reverted from docking to seeking
260
        if (robots[robot] != NULL)
261
        {
262
                switch (robots[robot]->state)
263
                {
264
                        case STATE_SEEKING:
265
                                //do nothing
266
                                STATION_DEBUG_PRINT("Robot is already ");
267
                                STATION_DEBUG_PRINT("seeking.\n");
268
                                break;
269
                        case STATE_DOCKED:
270
                                if (is_seeking)
271
                                {
272
                                        //we can only allow one robot to seek
273
                                        robots[robot]->state = STATE_NOT_CHARGING;
274
                                        bays[robots[robot]->bay] = -1;
275
                                        robots[robot]->bay = -1;
276
                                        break;
277
                                }
278
                                robots[robot]->state = STATE_SEEKING;
279
                                is_seeking = 1;
280
                                bay_enable(robots[robot]->bay);
281
                                break;
282
                        default:
283
                                STATION_DEBUG_PRINT("Robot is in an ");
284
                                STATION_DEBUG_PRINT("unexpected state.\n");
285
                                break;
286
                }
287
                return;
288
        }
289

    
290
        if (!charging_is_space_available())
291
        {
292
                STATION_DEBUG_PRINT("No bays are available for charging.\n");
293
                return;
294
        }
295

    
296
        ChargingRobot* r = malloc(sizeof(ChargingRobot));
297
        if (!r)
298
        {
299
                STATION_DEBUG_PRINT("Out of memory.\n");
300
                return;
301
        }
302

    
303
        r->state = STATE_SEEKING;
304
        r->bay = assign_bay(robot);
305
        r->verifyCount = VERIFY_DELAY;
306
        r->battery = 0;
307
        robots[robot] = r;
308
        numRobots++;
309
        is_seeking = 1;
310
        bay_enable(r->bay);
311
}
312

    
313
/**
314
 * Called when a robot has docked.
315
 *
316
 * @param robot the robot which has docked
317
 **/
318
void charging_dock(int robot)
319
{
320
        STATION_DEBUG_PRINT("Robot ");
321
        STATION_DEBUG_PUTI(robot);
322
        STATION_DEBUG_PRINT(" has docked with the station.\n");
323

    
324
        if (robots[robot] == NULL)
325
        {
326
                STATION_DEBUG_PRINT("Should not proceed from not ");
327
                STATION_DEBUG_PRINT("charging to docked.\n");
328
                return;
329
        }
330

    
331
        if (robots[robot]->state == STATE_DOCKED)
332
        {
333
                STATION_DEBUG_PRINT("Robot is already docked.\n");
334
                return;
335
        }
336

    
337
        //robot was seeking before
338
        is_seeking = 0;
339
        bay_disable();
340
        robots[robot]->state = STATE_DOCKED;
341
}
342

    
343
/**
344
 * Checks if there are any available bays
345
 * for a robot to occupy.
346
 *
347
 * @return nonzero if there are bays available,
348
 * and zero otherwise.
349
 **/
350
int charging_is_space_available(void)
351
{
352
        return numRobots < NUM_BAYS;
353
}
354

    
355
/**
356
 * Checks if there is a robot which
357
 * is currently seeking the station.
358
 *
359
 * @return nonzero if a robot is seeking the
360
 * station, zero otherwise.
361
 **/
362
int charging_is_robot_seeking(void)
363
{
364
        return is_seeking;
365
}
366

    
367
/**
368
 * Returns the state of the specified robot.
369
 *
370
 * @param robot the robot to get the state of
371
 *
372
 * @return either STATE_NOT_CHARGING, STATE_SEEKING, or STATE_DOCKED
373
 **/
374
int charging_get_robot_state(int robot)
375
{
376
        if (robot >= robotsSize || robots[robot] == NULL)
377
                return STATE_NOT_CHARGING;
378
        return robots[robot]->state;
379
}
380

    
381
/**
382
 * Update battery reading of a robot
383
 *
384
 * @param robot the robot to update battery reading
385
 * @param battery battery level of that robot
386
 **/
387
void update_battery(int robot, int battery)
388
{
389
        if (robot < robotsSize && robots[robot] != NULL)
390
                robots[robot]->battery = battery;
391
}
392

    
393
/**
394
 * Kick off charging robots for robot with lower battery level
395
 *
396
 * @param robot the robot that needs to be charged
397
 * @param battery battery level of that robot
398
 **/
399
void check_battery(int robot, int battery)
400
{
401
        if (charging_is_space_available()) return;
402
        // there's no way to read the voltage of a charging robot
403
        // so just eject the seeking robot if there's one, or the last charging robot
404
        charging_robot_iterator_init();
405
        int r,b;
406
        while (charging_robot_iterator_has_next())
407
        {
408
                r = charging_robot_iterator_next();
409
                b = robots[r]->battery;
410
                if (robots[r]->state==STATE_SEEKING) break;
411
        }
412
        if (battery<=BATTERY_LOWV&&b>BATTERY_LOWV)
413
        {
414
                //cancel robot r
415
                wl_charging_send_cancel(r);
416
                charging_cancel(r);
417
                //tell robot that charging station is now available
418
                wl_charging_send_station_available(robot);
419
        }
420
}
421

    
422
/**
423
 * Called when the BOM needs to be turned on for the 
424
 * token ring. If a robot is seeking, only the BOM of
425
 * the bay that is being sought will turn on. If no
426
 * robot is seeking, the BOM for all of the bays will
427
 * turn on.
428
 **/
429
void charging_bom_on(void)
430
{
431
        lbom_on();
432
}
433

    
434
/**
435
 * Called when the BOM needs to be turned off for the
436
 * token ring. Turns off the BOM for all bays.
437
 **/
438
void charging_bom_off(void)
439
{
440
        lbom_off();
441
}
442

    
443
/**
444
 * The charging station BOM can only emit, so
445
 * we just return -1.
446
 **/
447
int charging_bom_read(void)
448
{
449
        return -1;
450
}
451