Project

General

Profile

Statistics
| Revision:

root / trunk / code / projects / libwireless / lib / wl_token_ring.c @ 409

History | View | Annotate | Download (20.1 KB)

1 242 bcoltin
/**
2
 * Copyright (c) 2007 Colony Project
3 397 emarinel
 *
4 242 bcoltin
 * Permission is hereby granted, free of charge, to any person
5
 * obtaining a copy of this software and associated documentation
6
 * files (the "Software"), to deal in the Software without
7
 * restriction, including without limitation the rights to use,
8
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
9
 * copies of the Software, and to permit persons to whom the
10
 * Software is furnished to do so, subject to the following
11
 * conditions:
12 397 emarinel
 *
13 242 bcoltin
 * The above copyright notice and this permission notice shall be
14
 * included in all copies or substantial portions of the Software.
15 397 emarinel
 *
16 242 bcoltin
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
 * OTHER DEALINGS IN THE SOFTWARE.
24
 **/
25
26
/**
27
 * @file wl_token_ring.c
28
 * @brief Token Ring Implementation
29
 *
30
 * Implementation of the token ring packet group.
31
 *
32
 * @author Brian Coltin, Colony Project, CMU Robotics Club
33
 **/
34
35 17 bcoltin
#include <wl_token_ring.h>
36
37
#include <stdlib.h>
38
#include <stdio.h>
39
40
#include <wl_defs.h>
41
#include <wireless.h>
42
#include <sensor_matrix.h>
43
44
#ifdef ROBOT
45 86 bcoltin
#ifndef FIREFLY
46 17 bcoltin
#include <bom.h>
47 86 bcoltin
#endif
48 17 bcoltin
#include <time.h>
49
#endif
50
51
#define DEFAULT_SENSOR_MATRIX_SIZE 20
52
53
/*Ring States*/
54
55
#define NONMEMBER 0
56
#define MEMBER 1
57
#define JOINING 2
58
#define ACCEPTED 3
59
#define LEAVING 4
60
61
/*Frame Types*/
62
#define TOKEN_JOIN_ACCEPT_FRAME 1
63
64
/*Function Prototypes*/
65
66
/*Wireless Library Prototypes*/
67
void wl_token_ring_timeout_handler(void);
68
void wl_token_ring_response_handler(int frame, int received);
69
void wl_token_ring_receive_handler(char type, int source, unsigned char* packet,
70 346 bcoltin
                                                        int length);
71 17 bcoltin
void wl_token_ring_cleanup(void);
72
73
/*Helper Functions*/
74
void wl_token_pass_token(void);
75
int get_token_distance(int robot1, int robot2);
76
void wl_token_get_token(void);
77
78
/*Packet Handling Routines*/
79
void wl_token_pass_receive(int source, char nextRobot, unsigned char* sensorData, int sensorDataLength);
80
void wl_token_bom_on_receive(int source);
81
void wl_token_join_receive(int source);
82
void wl_token_join_accept_receive(int source);
83
84
/*Global Variables*/
85
86
//the sensor matrix
87
SensorMatrix* sensorMatrix;
88
89
//the robot we are waiting to say it has received the token. -1 if unspecified
90
int wl_token_next_robot = -1;
91
92
//true if the robot should be in the token ring, 0 otherwise
93
int ringState = NONMEMBER;
94
//the id of the robot who accepted us into the token ring, only used in ACCEPTED state
95
int acceptor = -1;
96
//id of the robot we are accepting
97
int accepted = -1;
98
99
//the counter for when we assume a robot is dead
100
int deathDelay = -1;
101
//the counter for joining, before we form our own token ring
102
int joinDelay = -1;
103
104 52 bcoltin
//current robot to check in the iterator
105
int iteratorCount = 0;
106
107 196 bcoltin
// the amount of time a robot has had its BOM on for
108
int bom_on_count = 0;
109
110 86 bcoltin
void do_nothing(void) {}
111
int get_nothing(void) {return -1;}
112
113 17 bcoltin
#ifdef ROBOT
114 86 bcoltin
#ifndef FIREFLY
115 17 bcoltin
void (*bom_on_function) (void) = bom_on;
116
void (*bom_off_function) (void) = bom_off;
117
int (*get_max_bom_function) (void) = get_max_bom;
118
#else
119
void (*bom_on_function) (void) = do_nothing;
120
void (*bom_off_function) (void) = do_nothing;
121
int (*get_max_bom_function) (void) = get_nothing;
122
#endif
123 86 bcoltin
#else
124
void (*bom_on_function) (void) = do_nothing;
125
void (*bom_off_function) (void) = do_nothing;
126
int (*get_max_bom_function) (void) = get_nothing;
127
#endif
128 17 bcoltin
129
PacketGroupHandler wl_token_ring_handler =
130 346 bcoltin
                {WL_TOKEN_RING_GROUP, wl_token_ring_timeout_handler,
131
                wl_token_ring_response_handler, wl_token_ring_receive_handler,
132
                wl_token_ring_cleanup};
133 17 bcoltin
134
/**
135
 * Initialize the token ring packet group and register it with the
136
 * wireless library. The robot will not join a token ring.
137
 **/
138 346 bcoltin
void wl_token_ring_register()
139
{
140
        if (wl_get_xbee_id() > 0xFF)
141
        {
142
                //Note: if this becomes an issue (unlikely), we could limit sensor information
143
                //to half a byte and use 12 bits for the id
144
                WL_DEBUG_PRINT("XBee ID must be single byte for token ring, is ");
145
                WL_DEBUG_PRINT_INT(wl_get_xbee_id());
146
                WL_DEBUG_PRINT(".\r\n");
147
                return;
148
        }
149 397 emarinel
150 346 bcoltin
        sensorMatrix = sensor_matrix_create();
151
        //add ourselves to the sensor matrix
152
        sensor_matrix_set_in_ring(sensorMatrix, wl_get_xbee_id(), 0);
153 17 bcoltin
154 346 bcoltin
        wl_register_packet_group(&wl_token_ring_handler);
155 17 bcoltin
}
156
157
/**
158
 * Removes the packet group from the wireless library.
159
 **/
160 346 bcoltin
void wl_token_ring_unregister()
161
{
162
        wl_unregister_packet_group(&wl_token_ring_handler);
163 17 bcoltin
}
164
165
/**
166
 * Sets the functions that are called when the BOM ought to be
167 397 emarinel
 * turned on or off. This could be used for things such as
168 17 bcoltin
 * charging stations, which have multiple BOMs.
169
 *
170
 * @param on_function the function to be called when the BOM
171
 * should be turned on
172
 * @param off_function the function to be called when the BOM
173
 * should be turned off
174
 * @param max_bom_function the function to be called when a
175
 * measurement of the maximum BOM reading is needed.
176
 **/
177
void wl_token_ring_set_bom_functions(void (*on_function) (void),
178 346 bcoltin
        void (*off_function) (void), int (*max_bom_function) (void))
179
{
180
        bom_on_function = on_function;
181
        bom_off_function = off_function;
182
        get_max_bom_function = max_bom_function;
183 17 bcoltin
}
184
185
/**
186
 * Called to cleanup the token ring packet group.
187
 **/
188 346 bcoltin
void wl_token_ring_cleanup()
189
{
190
        sensor_matrix_destroy(sensorMatrix);
191 17 bcoltin
}
192
193
/**
194
 * Called approximately every quarter second by the wireless library.
195
 **/
196 346 bcoltin
void wl_token_ring_timeout_handler()
197
{
198
        //someone is not responding, assume they are dead
199
        if (deathDelay == 0)
200
        {
201
                //pass the token to the next robot if we think someone has died
202
                //also, declare that person dead, as long as it isn't us
203
                if (wl_token_next_robot != wl_get_xbee_id())
204
                {
205
                        sensor_matrix_set_in_ring(sensorMatrix, wl_token_next_robot, 0);
206
                        WL_DEBUG_PRINT("Robot ");
207
                        WL_DEBUG_PRINT_INT(wl_token_next_robot);
208
                        WL_DEBUG_PRINT(" has died.\r\n");
209
                        wl_token_next_robot = -1;
210
                        deathDelay = DEATH_DELAY;
211
                }
212 397 emarinel
213 346 bcoltin
                // we may have been dropped from the ring when this is received
214
                if (ringState == MEMBER)
215
                        wl_token_pass_token();
216
        }
217 17 bcoltin
218 346 bcoltin
        //we must start our own token ring, no one is responding to us
219
        if (joinDelay == 0)
220
        {
221
                if (sensor_matrix_get_joined(sensorMatrix) == 0)
222
                {
223
                        WL_DEBUG_PRINT("Creating our own token ring, no robots seem to exist.\r\n");
224
                        sensor_matrix_set_in_ring(sensorMatrix, wl_get_xbee_id(), 1);
225
                        ringState = MEMBER;
226
                        //this will make us pass the token to ourself
227
                        //repeatedly, and other robots when they join
228
                        deathDelay = DEATH_DELAY;
229
                        wl_token_next_robot = wl_get_xbee_id();
230
                }
231
                else
232
                {
233
                        WL_DEBUG_PRINT("Attempting to join the token ring again.\r\n");
234
                        //attempt to rejoin with a random delay
235
                        wl_token_ring_join();
236
                        joinDelay = rand() / (RAND_MAX / JOIN_DELAY) + 1;
237
                }
238
        }
239 17 bcoltin
240 346 bcoltin
        if (deathDelay >= 0)
241
                deathDelay--;
242
        if (joinDelay >= 0)
243
                joinDelay--;
244
        if (bom_on_count >= 0)
245
                bom_on_count++;
246 17 bcoltin
}
247
248
/**
249
 * Called when the XBee tells us if a packet we sent has been received.
250 397 emarinel
 *
251 17 bcoltin
 * @param frame the frame number assigned when the packet was sent
252
 * @param received 1 if the packet was received, 0 otherwise
253
 **/
254 346 bcoltin
void wl_token_ring_response_handler(int frame, int received)
255
{
256
        if (!received)
257
        {
258
                WL_DEBUG_PRINT("FAILED.\r\n");
259
        }
260 17 bcoltin
}
261
262
/**
263
 * Called when we recieve a token ring packet.
264
 * @param type the type of the packet
265
 * @param source the id of the robot who sent the packet
266
 * @param packet the data in the packet
267
 * @param length the length of the packet in bytes
268
 **/
269
void wl_token_ring_receive_handler(char type, int source, unsigned char* packet,
270 346 bcoltin
                                                        int length)
271
{
272
        switch (type)
273
        {
274
                case WL_TOKEN_PASS:
275
                        if (length < 1)
276
                        {
277
                                WL_DEBUG_PRINT("Malformed Token Pass packet received.\r\n");
278
                                return;
279
                        }
280
                        wl_token_pass_receive(source, packet[0], packet + 1, length - 1);
281
                        break;
282
                case WL_TOKEN_BOM_ON:
283
                        //add the robot to the sensor matrix if it is not already there
284
                        wl_token_bom_on_receive(source);
285
                        break;
286
                case WL_TOKEN_JOIN:
287
                        wl_token_join_receive(source);
288
                        break;
289
                case WL_TOKEN_JOIN_ACCEPT:
290
                        wl_token_join_accept_receive(source);
291
                        break;
292
                default:
293
                        WL_DEBUG_PRINT("Unimplemented token ring packet received.\r\n");
294
                        break;
295
        }
296 17 bcoltin
}
297
298
/**
299
 * Causes the robot to join an existing token ring, or create one
300
 * if no token ring exists. The token ring uses global and robot to robot
301
 * packets, and does not rely on any PAN.
302
 **/
303 397 emarinel
int wl_token_ring_join()
304 346 bcoltin
{
305
        WL_DEBUG_PRINT("Joining the token ring.\r\n");
306
        ringState = JOINING;
307
        joinDelay = DEATH_DELAY * 2;
308 397 emarinel
        if (wl_send_global_packet(WL_TOKEN_RING_GROUP, WL_TOKEN_JOIN, NULL, 0, 0) != 0) {
309
                return -1;
310
        }
311
312
        return 0;
313 17 bcoltin
}
314
315
/**
316
 * Causes the robot to leave the token ring. The robot stops
317
 * alerting others of its location, but continues storing the
318
 * locations of other robots.
319
 **/
320 346 bcoltin
void wl_token_ring_leave()
321
{
322
        ringState = LEAVING;
323 17 bcoltin
}
324
325
/**
326
 * Returns the BOM reading robot source has for robot dest.
327
 *
328
 * @param source the robot that made the BOM reading
329
 * @param dest the robot whose relative location is returned
330
 *
331
 * @return a BOM reading from robot source to robot dest,
332
 * in the range 0-15, or -1 if it is unknown
333
 **/
334 346 bcoltin
int wl_token_get_sensor_reading(int source, int dest)
335
{
336
        if (wl_token_is_robot_in_ring(dest) &&
337
                        (source == wl_get_xbee_id() || wl_token_is_robot_in_ring(source)))
338
                return sensor_matrix_get_reading(sensorMatrix, source, dest);
339
        return -1;
340 17 bcoltin
}
341
342
/**
343
 * Returns the BOM reading we have for robot dest.
344 397 emarinel
 *
345 17 bcoltin
 * @param dest the robot whose relative location is returned
346
 *
347
 * @return a BOM reading from us to robot dest, in the range
348
 * 0-15, or -1 if it is unkown
349
 **/
350 346 bcoltin
int wl_token_get_my_sensor_reading(int dest)
351
{
352
        return wl_token_get_sensor_reading(wl_get_xbee_id(), dest);
353 17 bcoltin
}
354
355
/**
356
 * This method is called when we receive a token pass packet.
357
 * @param source is the robot it came from
358
 * @param nextRobot is the robot the token was passed to
359
 * @param sensorData a char with an id followed by a char with the sensor
360
 *                reading for that robot, repeated for sensorDataLength bytes
361
 * @param sensorDataLength the length in bytes of sensorData
362
 */
363 346 bcoltin
void wl_token_pass_receive(int source, char nextRobot, unsigned char* sensorData, int sensorDataLength)
364
{
365
        int i, j;
366 196 bcoltin
367 346 bcoltin
        // this prevents two tokens from being passed around at a time (second clause is in case we are joining)
368
        if (source != wl_token_next_robot && bom_on_count <= DEATH_DELAY / 2 &&
369
                ringState != ACCEPTED)
370
        {
371
                WL_DEBUG_PRINT("Received token pass when a robot should not have died yet.\n");
372
                WL_DEBUG_PRINT("There are probably two tokens going around, packet ignored.\n");
373
                return;
374
        }
375 196 bcoltin
376 346 bcoltin
        bom_on_count = -1;
377
        deathDelay = -1;
378
        WL_DEBUG_PRINT("Received the token from robot");
379
        WL_DEBUG_PRINT_INT(source);
380
        WL_DEBUG_PRINT(", next robot is ");
381
        WL_DEBUG_PRINT_INT((int)nextRobot);
382
        WL_DEBUG_PRINT(" \r\n");
383
        sensor_matrix_set_in_ring(sensorMatrix, source, 1);
384 17 bcoltin
385 346 bcoltin
        //with this packet, we are passed the id of the next robot in the ring
386
        //and the sensor matrix, a list of id and sensor reading pairs (two bytes for both)
387
        j = 0;
388
        for (i = 0; i < sensor_matrix_get_size(sensorMatrix); i++)
389
        {
390
                if (i == source)
391
                        continue;
392 397 emarinel
393 346 bcoltin
                //set the sensor information we receive
394
                if (j < sensorDataLength / 2 && sensorData[2 * j] == i)
395
                {
396
                        //the robot we were going to accept has already been accepted
397
                        if (accepted == i)
398
                        {
399
                                accepted = -1;
400
                                WL_DEBUG_PRINT("Someone accepted the robot we did.\r\n");
401
                        }
402
                        sensor_matrix_set_reading(sensorMatrix, source, i,
403
                                                sensorData[2 * j + 1]);
404
                        sensor_matrix_set_in_ring(sensorMatrix, i, 1);
405
                        j++;
406
                }
407
                else
408
                {
409
                        if (sensor_matrix_get_in_ring(sensorMatrix, i))
410
                        {
411
                                WL_DEBUG_PRINT("Robot ");
412
                                WL_DEBUG_PRINT_INT(i);
413
                                WL_DEBUG_PRINT(" has been removed from the sensor matrix of robot ");
414
                                WL_DEBUG_PRINT_INT(wl_get_xbee_id());
415
                                WL_DEBUG_PRINT(" due to a packet from robot ");
416
                                WL_DEBUG_PRINT_INT(source);
417
                                WL_DEBUG_PRINT(".\r\n");
418
                                sensor_matrix_set_in_ring(sensorMatrix, i, 0);
419
                        }
420 17 bcoltin
421 346 bcoltin
                        if (i == wl_get_xbee_id() && ringState == MEMBER)
422
                        {
423
                                ringState = NONMEMBER;
424
                                wl_token_ring_join();
425 397 emarinel
426 346 bcoltin
                                WL_DEBUG_PRINT("We have been removed from the ring ");
427
                                WL_DEBUG_PRINT("and are rejoining.\r\n");
428
                        }
429 397 emarinel
430 346 bcoltin
                        //the person who accepted us is dead... let's ask again
431
                        if (i == acceptor)
432
                        {
433
                                sensor_matrix_set_in_ring(sensorMatrix,
434
                                                wl_get_xbee_id(), 1);
435
                                ringState = NONMEMBER;
436
                                acceptor = -1;
437
                                wl_token_ring_join();
438
                        }
439
                }
440
        }
441 17 bcoltin
442 346 bcoltin
        wl_token_next_robot = nextRobot;
443 397 emarinel
444 346 bcoltin
        deathDelay = get_token_distance(wl_get_xbee_id(), nextRobot) * DEATH_DELAY;
445 397 emarinel
446 346 bcoltin
        //we have the token
447
        if (wl_token_next_robot == wl_get_xbee_id())
448
                wl_token_get_token();
449 17 bcoltin
}
450
451
/**
452
 * Gets the distance in the token ring between two robots.
453
 *
454
 * @param robot1 the first robot
455
 * @param robot2 the second robot
456
 *
457
 * @return the number of passes before the token is expected
458
 * to reach robot2 from robot1
459
 **/
460 346 bcoltin
int get_token_distance(int robot1, int robot2)
461
{
462
        int curr = robot1 + 1;
463
        int count = 1;
464
        while (1)
465
        {
466
                if (curr == sensor_matrix_get_size(sensorMatrix))
467
                        curr = 0;
468
                if (curr == robot2)
469
                        break;
470
                if (sensor_matrix_get_in_ring(sensorMatrix, curr))
471
                        count++;
472
                curr++;
473
        }
474
        return count;
475 17 bcoltin
}
476
477
/**
478
 * Passes the token to the next robot in the token ring.
479
 **/
480 346 bcoltin
void wl_token_pass_token()
481
{
482
        char nextRobot;
483
        int i = wl_get_xbee_id() + 1;
484
        if (accepted == -1)
485
        {
486
                while (1)
487
                {
488
                        if (i == sensor_matrix_get_size(sensorMatrix))
489
                                i = 0;
490
                        if (sensor_matrix_get_in_ring(sensorMatrix, i))
491
                        {
492
                                nextRobot = (char)i;
493
                                break;
494
                        }
495
                        i++;
496
                }
497
        }
498
        else
499
        {
500
                WL_DEBUG_PRINT("Accepting new robot, sending it the token.\r\n");
501
                //add a new robot to the token ring
502
                sensor_matrix_set_in_ring(sensorMatrix, accepted, 1);
503
                nextRobot = accepted;
504
                accepted = -1;
505
        }
506 17 bcoltin
507 346 bcoltin
        //we don't include ourself
508
        int packetSize = 1 + 2 * (sensor_matrix_get_joined(sensorMatrix) - 1);
509
        char* buf = (char*)malloc(packetSize * sizeof(char));
510
        if (!buf)
511
        {
512
                WL_DEBUG_PRINT_INT(packetSize);
513
                WL_DEBUG_PRINT("Out of memory - pass token.\r\n");
514
                return;
515
        }
516
        buf[0] = nextRobot;
517 17 bcoltin
518 346 bcoltin
        int j = 0;
519
        for (i = 0; i < sensor_matrix_get_size(sensorMatrix); i++)
520
                if (sensor_matrix_get_in_ring(sensorMatrix, i) && i != wl_get_xbee_id())
521
                {
522
                        buf[2*j + 1] = i;
523
                        buf[2*j + 2] = sensor_matrix_get_reading(sensorMatrix, wl_get_xbee_id(), i);
524
                        j++;
525
                }
526 397 emarinel
527 346 bcoltin
        WL_DEBUG_PRINT("Passing the token to robot ");
528
        WL_DEBUG_PRINT_INT(buf[0]);
529
        WL_DEBUG_PRINT(".\r\n");
530
        wl_send_global_packet(WL_TOKEN_RING_GROUP, WL_TOKEN_PASS,
531
                buf, packetSize, 3);
532 17 bcoltin
533 346 bcoltin
        wl_token_next_robot = nextRobot;
534
        deathDelay = DEATH_DELAY;
535
        free(buf);
536 17 bcoltin
}
537
538
/**
539
 * Called when a packet is received stating that another robot has turned
540
 * its BOM on. Our BOM is then read, and the data is added to the sensor
541
 * matrix.
542
 *
543
 * @param source the robot whose BOM is on
544
 **/
545 346 bcoltin
void wl_token_bom_on_receive(int source)
546
{
547
        WL_DEBUG_PRINT("Robot ");
548
        WL_DEBUG_PRINT_INT(source);
549
        WL_DEBUG_PRINT(" has flashed its bom.\r\n");
550 397 emarinel
551 346 bcoltin
        bom_on_count = 0;
552 138 bcoltin
553 397 emarinel
        sensor_matrix_set_reading(sensorMatrix, wl_get_xbee_id(),
554 346 bcoltin
                source, get_max_bom_function());
555 17 bcoltin
}
556
557
/**
558
 * This method is called when we receive the token. Upon receiving
559
 * the token, we must send a BOM_ON packet, flash the BOM, and send
560
 * the token to the next robot.
561 397 emarinel
 *
562 17 bcoltin
 * If there is a pending request for the token, this is processed first.
563
 **/
564 346 bcoltin
void wl_token_get_token()
565
{
566
        WL_DEBUG_PRINT("We have the token.\r\n");
567
        if (ringState == ACCEPTED)
568
        {
569
                sensor_matrix_set_in_ring(sensorMatrix,
570
                        wl_get_xbee_id(), 1);
571
                WL_DEBUG_PRINT("Now a member of the token ring.\r\n");
572
                ringState = MEMBER;
573
                joinDelay = -1;
574
        }
575 17 bcoltin
576 346 bcoltin
        if (ringState == LEAVING || ringState == NONMEMBER)
577
        {
578
                sensor_matrix_set_in_ring(sensorMatrix, wl_get_xbee_id(), 0);
579
                if (ringState == NONMEMBER)
580
                {
581
                        WL_DEBUG_PRINT("We should have left the token ring, but didn't.\r\n");
582
                }
583
                return;
584
        }
585 397 emarinel
586 346 bcoltin
        WL_DEBUG_PRINT("Our BOM has been flashed.\r\n");
587
        wl_send_global_packet(WL_TOKEN_RING_GROUP, WL_TOKEN_BOM_ON,
588
                NULL, 0, 0);
589 17 bcoltin
590 346 bcoltin
        bom_on_function();
591
        #ifdef ROBOT
592
        delay_ms(BOM_DELAY);
593
        #endif
594
        bom_off_function();
595 397 emarinel
596 346 bcoltin
        if (!sensor_matrix_get_in_ring(sensorMatrix, wl_get_xbee_id()))
597
        {
598
                WL_DEBUG_PRINT("Removed from sensor matrix while flashing BOM.\r\n");
599
                return;
600
        }
601 397 emarinel
602 346 bcoltin
        wl_token_pass_token();
603 17 bcoltin
}
604
605
/**
606
 * Called when a request to join the token ring is received.
607
 * If we are the robot preceding the requester in the ring,
608
 * we respond with a JOIN_ACCEPT packet and pass the token to
609
 * this robot when we receive the token.
610
 *
611
 * @param source the robot who requested to join
612
 **/
613 346 bcoltin
void wl_token_join_receive(int source)
614
{
615
        WL_DEBUG_PRINT("Received joining request from robot ");
616
        WL_DEBUG_PRINT_INT(source);
617
        WL_DEBUG_PRINT(".\r\n");
618 17 bcoltin
619 346 bcoltin
        //we cannot accept the request if we are not a member
620
        if (ringState != MEMBER)
621
                return;
622
        //if they didn't get our response, see if we should respond again
623
        if (accepted == source)
624
                accepted = -1;
625
        //we can only accept one request at a time
626
        if (accepted != -1)
627
                return;
628 397 emarinel
629 346 bcoltin
        //check if we are the preceding robot in the token ring
630
        int i = source - 1;
631
        while (1)
632
        {
633
                if (i < 0)
634
                        i = sensor_matrix_get_size(sensorMatrix) - 1;
635
                //we must send a join acceptance
636
                if (i == wl_get_xbee_id())
637
                        break;
638 17 bcoltin
639 346 bcoltin
                //another robot will handle it
640
                if (sensor_matrix_get_in_ring(sensorMatrix, i))
641
                        return;
642
                i--;
643
        }
644 17 bcoltin
645 346 bcoltin
        accepted = source;
646
        wl_send_robot_to_robot_global_packet(WL_TOKEN_RING_GROUP, WL_TOKEN_JOIN_ACCEPT,
647
                NULL, 0, source, TOKEN_JOIN_ACCEPT_FRAME);
648 397 emarinel
649 346 bcoltin
        WL_DEBUG_PRINT("Accepting robot ");
650
        WL_DEBUG_PRINT_INT(source);
651
        WL_DEBUG_PRINT(" into the token ring.\r\n");
652 17 bcoltin
653 346 bcoltin
        // the token ring has not started yet
654
        if (sensor_matrix_get_joined(sensorMatrix) == 1)
655
                wl_token_pass_token();
656 17 bcoltin
}
657
658
/**
659
 * Called when we receive a JOIN_ACCEPT packet in attempting to join
660
 * the token ring.
661
 * Our attempt to join the ring is stopped, and we wait for the token.
662
 *
663
 * @param source the robot who accepted us
664
 **/
665 346 bcoltin
void wl_token_join_accept_receive(int source)
666
{
667
        WL_DEBUG_PRINT("Accepted into the token ring by robot ");
668
        WL_DEBUG_PRINT_INT(source);
669
        WL_DEBUG_PRINT(".\r\n");
670
        joinDelay = JOIN_DELAY;
671
        ringState = ACCEPTED;
672
        acceptor = source;
673 17 bcoltin
674 346 bcoltin
        //add ourselves to the token ring
675
        sensor_matrix_set_in_ring(sensorMatrix, wl_get_xbee_id(), 1);
676 17 bcoltin
}
677
678
/**
679 52 bcoltin
 * Returns the number of robots in the token ring.
680
 *
681
 * @return the number of robots in the token ring
682
 **/
683 346 bcoltin
int wl_token_get_robots_in_ring(void)
684
{
685
        return sensor_matrix_get_joined(sensorMatrix);
686 52 bcoltin
}
687
688
/**
689
 * Returns true if the specified robot is in the token ring, false
690
 * otherwise.
691
 *
692
 * @param robot the robot to check for whether it is in the token ring
693
 * @return nonzero if the robot is in the token ring, zero otherwise
694
 **/
695 346 bcoltin
int wl_token_is_robot_in_ring(int robot)
696
{
697
        return sensor_matrix_get_in_ring(sensorMatrix, robot);
698 52 bcoltin
}
699
700
/**
701
 * Begins iterating through the robots in the token ring.
702
 *
703
 * @see wl_token_iterator_has_next, wl_token_iterator_next
704
 **/
705 346 bcoltin
void wl_token_iterator_begin(void)
706
{
707
        int i = 0;
708
        iteratorCount = 0;
709
        while (!sensor_matrix_get_in_ring(sensorMatrix, i) &&
710
                        i < sensor_matrix_get_size(sensorMatrix))
711
                i++;
712
        if (i == sensor_matrix_get_size(sensorMatrix))
713
                i = -1;
714
        iteratorCount = i;
715 52 bcoltin
}
716
717
/**
718
 * Returns true if there are more robots in the token ring
719
 * to iterate through, and false otherwise.
720
 *
721
 * @return nonzero if there are more robots to iterate through,
722
 * zero otherwise
723
 *
724
 * @see wl_token_iterator_begin, wl_token_iterator_next
725
 **/
726 346 bcoltin
int wl_token_iterator_has_next(void)
727
{
728
        return iteratorCount != -1;
729 52 bcoltin
}
730
731
/**
732
 * Returns the next robot ID in the token ring.
733
 *
734
 * @return the next robot ID in the token ring, or -1 if none exists
735
 *
736
 * @see wl_token_iterator_begin, wl_token_iterator_has_next
737
 **/
738 346 bcoltin
int wl_token_iterator_next(void)
739
{
740
        int result = iteratorCount;
741
        if (result < 0)
742
                return result;
743 52 bcoltin
744 346 bcoltin
        iteratorCount++;
745
        while (!sensor_matrix_get_in_ring(sensorMatrix, iteratorCount) &&
746
                iteratorCount < sensor_matrix_get_size(sensorMatrix))
747
                iteratorCount++;
748
        if (iteratorCount == sensor_matrix_get_size(sensorMatrix))
749
                iteratorCount = -1;
750
        return result;
751 52 bcoltin
}
752
753
/**
754 188 bcoltin
 * Returns the number of robots currently in the token ring.
755 17 bcoltin
 *
756 188 bcoltin
 * @return the number of robots in the token ring
757 17 bcoltin
 **/
758 346 bcoltin
int wl_token_get_num_robots(void)
759
{
760
        return sensor_matrix_get_joined(sensorMatrix);
761 17 bcoltin
}
762
763 188 bcoltin
/**
764
 * Returns the number of robots in the sensor matrix.
765
 *
766
 * @return the number of robots in the sensor matrix
767
 **/
768 346 bcoltin
int wl_token_get_matrix_size(void)
769
{
770
        return sensor_matrix_get_size(sensorMatrix);
771 48 jscheine
}