Project

General

Profile

Statistics
| Revision:

root / branches / wl_dev / code / projects / libwireless / lib / wl_token_ring.c @ 538

History | View | Annotate | Download (21.2 KB)

1
/**
2
 * Copyright (c) 2007 Colony Project
3
 *
4
 * 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
 *
13
 * The above copyright notice and this permission notice shall be
14
 * included in all copies or substantial portions of the Software.
15
 *
16
 * 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
#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
#ifndef FIREFLY
46
#include <bom.h>
47
#endif
48
#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
#define WL_TOKEN_PASS_FRAME        2
64

    
65
/*Function Prototypes*/
66

    
67
/*Wireless Library Prototypes*/
68
static void wl_token_ring_timeout_handler(void);
69
static void wl_token_ring_response_handler(int frame, int received);
70
static void wl_token_ring_receive_handler(char type, int source, unsigned char* packet, int length);
71
static void wl_token_ring_cleanup(void);
72

    
73
/*Helper Functions*/
74
static int wl_token_pass_token(void);
75
static int get_token_distance(int robot1, int robot2);
76
static void wl_token_get_token(void);
77

    
78
/*Packet Handling Routines*/
79
static void wl_token_pass_receive(int source);
80
static void wl_token_sensor_matrix_receive(int source, unsigned char* sensorData, int sensorDataLength);
81
static void wl_token_bom_on_receive(int source);
82
static void wl_token_join_receive(int source);
83
static void wl_token_join_accept_receive(int source);
84

    
85
/*Global Variables*/
86

    
87
//the sensor matrix
88
static SensorMatrix* sensorMatrix;
89

    
90
//the robot we are waiting to say it has received the token. -1 if unspecified
91
static int wl_token_next_robot = -1;
92

    
93
//true if the robot should be in the token ring, 0 otherwise
94
static int ringState = NONMEMBER;
95
//the id of the robot who accepted us into the token ring, only used in ACCEPTED state
96
static int acceptor = -1;
97
//id of the robot we are accepting
98
static int accepted = -1;
99

    
100
//the counter for when we assume a robot is dead
101
static int deathDelay = -1;
102
//the counter for joining, before we form our own token ring
103
static int joinDelay = -1;
104

    
105
//current robot to check in the iterator
106
static int iteratorCount = 0;
107

    
108
// the amount of time a robot has had its BOM on for
109
static int bom_on_count = 0;
110

    
111
#ifndef ROBOT
112
static void do_nothing(void) {}
113
static int get_nothing(void) {return -1;}
114
#endif
115

    
116
#ifdef ROBOT
117
#ifndef FIREFLY
118
static void (*bom_on_function) (void) = bom_on;
119
static void (*bom_off_function) (void) = bom_off;
120
static int (*get_max_bom_function) (void) = get_max_bom;
121
#else
122
static void (*bom_on_function) (void) = do_nothing;
123
static void (*bom_off_function) (void) = do_nothing;
124
static int (*get_max_bom_function) (void) = get_nothing;
125
#endif
126
#else
127
static void (*bom_on_function) (void) = do_nothing;
128
static void (*bom_off_function) (void) = do_nothing;
129
static int (*get_max_bom_function) (void) = get_nothing;
130
#endif
131

    
132
static PacketGroupHandler wl_token_ring_handler =
133
        {WL_TOKEN_RING_GROUP, wl_token_ring_timeout_handler,
134
                wl_token_ring_response_handler, wl_token_ring_receive_handler,
135
                wl_token_ring_cleanup};
136

    
137
/**
138
 * Causes the robot to join an existing token ring, or create one
139
 * if no token ring exists. The token ring uses global and robot to robot
140
 * packets, and does not rely on any PAN.
141
 **/
142
int wl_token_ring_join()
143
{
144
        WL_DEBUG_PRINT("Joining the token ring.\r\n");
145

    
146
        ringState = JOINING;
147
        joinDelay = DEATH_DELAY * 2;
148
        if (wl_send_global_packet(WL_TOKEN_RING_GROUP, WL_TOKEN_JOIN, NULL, 0, 0) != 0) {
149
                return -1;
150
        }
151

    
152
        return 0;
153
}
154

    
155
/**
156
 * Causes the robot to leave the token ring. The robot stops
157
 * alerting others of its location, but continues storing the
158
 * locations of other robots.
159
 **/
160
void wl_token_ring_leave()
161
{
162
        ringState = LEAVING;
163
}
164

    
165
/**
166
 * Initialize the token ring packet group and register it with the
167
 * wireless library. The robot will not join a token ring.
168
 **/
169
int wl_token_ring_register()
170
{
171
        if (wl_get_xbee_id() > 0xFF)
172
        {
173
                //Note: if this becomes an issue (unlikely), we could limit sensor information
174
                //to half a byte and use 12 bits for the id
175
                WL_DEBUG_PRINT("XBee ID must be single byte for token ring, is ");
176
                WL_DEBUG_PRINT_INT(wl_get_xbee_id());
177
                WL_DEBUG_PRINT(".\r\n");
178
                return -1;
179
        }
180

    
181
        sensorMatrix = sensor_matrix_create();
182
        //add ourselves to the sensor matrix
183
        sensor_matrix_set_in_ring(sensorMatrix, wl_get_xbee_id(), 0);
184

    
185
        wl_register_packet_group(&wl_token_ring_handler);
186

    
187
        return 0;
188
}
189

    
190
/**
191
 * Removes the packet group from the wireless library.
192
 **/
193
void wl_token_ring_unregister()
194
{
195
        wl_unregister_packet_group(&wl_token_ring_handler);
196
}
197

    
198
/**
199
 * Sets the functions that are called when the BOM ought to be
200
 * turned on or off. This could be used for things such as
201
 * charging stations, which have multiple BOMs.
202
 *
203
 * @param on_function the function to be called when the BOM
204
 * should be turned on
205
 * @param off_function the function to be called when the BOM
206
 * should be turned off
207
 * @param max_bom_function the function to be called when a
208
 * measurement of the maximum BOM reading is needed.
209
 **/
210
void wl_token_ring_set_bom_functions(void (*on_function) (void),
211
        void (*off_function) (void), int (*max_bom_function) (void))
212
{
213
        bom_on_function = on_function;
214
        bom_off_function = off_function;
215
        get_max_bom_function = max_bom_function;
216
}
217

    
218
/**
219
 * Called to cleanup the token ring packet group.
220
 **/
221
static void wl_token_ring_cleanup()
222
{
223
        sensor_matrix_destroy(sensorMatrix);
224
}
225

    
226
/**
227
 * Called approximately every quarter second by the wireless library.
228
 **/
229
static void wl_token_ring_timeout_handler()
230
{
231
        //someone is not responding, assume they are dead
232
        if (deathDelay == 0)
233
        {
234
                //pass the token to the next robot if we think someone has died
235
                //also, declare that person dead, as long as it isn't us
236
                if (wl_token_next_robot != wl_get_xbee_id())
237
                {
238
                        sensor_matrix_set_in_ring(sensorMatrix, wl_token_next_robot, 0);
239
                        WL_DEBUG_PRINT("Robot ");
240
                        WL_DEBUG_PRINT_INT(wl_token_next_robot);
241
                        WL_DEBUG_PRINT(" has died.\r\n");
242
                        wl_token_next_robot = -1;
243
                        deathDelay = DEATH_DELAY;
244
                }
245

    
246
                // we may have been dropped from the ring when this is received
247
                if (ringState == MEMBER) {
248
                        wl_token_pass_token();
249
                }
250
        }
251

    
252
        //we must start our own token ring, no one is responding to us
253
        if (joinDelay == 0)
254
        {
255
                if (sensor_matrix_get_joined(sensorMatrix) == 0)
256
                {
257
                        WL_DEBUG_PRINT("Creating our own token ring, no robots seem to exist.\r\n");
258
                        sensor_matrix_set_in_ring(sensorMatrix, wl_get_xbee_id(), 1);
259
                        ringState = MEMBER;
260
                        //this will make us pass the token to ourself
261
                        //repeatedly, and other robots when they join
262
                        deathDelay = DEATH_DELAY;
263
                        wl_token_next_robot = wl_get_xbee_id();
264
                }
265
                else
266
                {
267
                        WL_DEBUG_PRINT("Attempting to join the token ring again.\r\n");
268
                        //attempt to rejoin with a random delay
269
                        wl_token_ring_join();
270
                        joinDelay = rand() / (RAND_MAX / JOIN_DELAY) + 1;
271
                }
272
        }
273

    
274
        if (deathDelay >= 0) {
275
                deathDelay--;
276
        }
277

    
278
        if (joinDelay >= 0) {
279
                joinDelay--;
280
        }
281

    
282
        if (bom_on_count >= 0) {
283
                bom_on_count++;
284
        }
285
}
286

    
287
/**
288
 * Called when the XBee tells us if a packet we sent has been received.
289
 *
290
 * @param frame the frame number assigned when the packet was sent
291
 * @param received 1 if the packet was received, 0 otherwise
292
 **/
293
static void wl_token_ring_response_handler(int frame, int received)
294
{
295
        if (!received)
296
        {
297
                WL_DEBUG_PRINT("FAILED.\r\n");
298
        }
299
}
300

    
301
/**
302
 * Called when we recieve a token ring packet.
303
 * @param type the type of the packet
304
 * @param source the id of the robot who sent the packet
305
 * @param packet the data in the packet
306
 * @param length the length of the packet in bytes
307
 **/
308
static void wl_token_ring_receive_handler(char type, int source, unsigned char* packet, int length)
309
{
310
        switch (type)
311
        {
312
                case WL_TOKEN_PASS:
313
                        wl_token_pass_receive(source);
314
                        break;
315
                case WL_TOKEN_SENSOR_MATRIX:
316
                        if (length < 1)
317
                        {
318
                                WL_DEBUG_PRINT("Malformed Token Pass packet received.\r\n");
319
                                return;
320
                        }
321
                        wl_token_sensor_matrix_receive(source, packet, length);
322
                case WL_TOKEN_BOM_ON:
323
                        //add the robot to the sensor matrix if it is not already there
324
                        wl_token_bom_on_receive(source);
325
                        break;
326
                case WL_TOKEN_JOIN:
327
                        wl_token_join_receive(source);
328
                        break;
329
                case WL_TOKEN_JOIN_ACCEPT:
330
                        wl_token_join_accept_receive(source);
331
                        break;
332
                default:
333
                        WL_DEBUG_PRINT("Unimplemented token ring packet received.\r\n");
334
                        break;
335
        }
336
}
337

    
338
/**
339
 * Returns the BOM reading robot source has for robot dest.
340
 *
341
 * @param source the robot that made the BOM reading
342
 * @param dest the robot whose relative location is returned
343
 *
344
 * @return a BOM reading from robot source to robot dest,
345
 * in the range 0-15, or -1 if it is unknown
346
 **/
347
int wl_token_get_sensor_reading(int source, int dest)
348
{
349
        if (wl_token_is_robot_in_ring(dest) &&
350
                        (source == wl_get_xbee_id() || wl_token_is_robot_in_ring(source))) {
351
                return sensor_matrix_get_reading(sensorMatrix, source, dest);
352
        }
353

    
354
        return -1;
355
}
356

    
357
/**
358
 * Returns the BOM reading we have for robot dest.
359
 *
360
 * @param dest the robot whose relative location is returned
361
 *
362
 * @return a BOM reading from us to robot dest, in the range
363
 * 0-15, or -1 if it is unkown
364
 **/
365
int wl_token_get_my_sensor_reading(int dest)
366
{
367
        return wl_token_get_sensor_reading(wl_get_xbee_id(), dest);
368
}
369

    
370

    
371
/**
372
 * Returns the number of robots in the token ring.
373
 *
374
 * @return the number of robots in the token ring
375
 **/
376
int wl_token_get_robots_in_ring(void)
377
{
378
        return sensor_matrix_get_joined(sensorMatrix);
379
}
380

    
381
/**
382
 * Returns true if the specified robot is in the token ring, false
383
 * otherwise.
384
 *
385
 * @param robot the robot to check for whether it is in the token ring
386
 * @return nonzero if the robot is in the token ring, zero otherwise
387
 **/
388
int wl_token_is_robot_in_ring(int robot)
389
{
390
        return sensor_matrix_get_in_ring(sensorMatrix, robot);
391
}
392

    
393
/**
394
 * Begins iterating through the robots in the token ring.
395
 *
396
 * @see wl_token_iterator_has_next, wl_token_iterator_next
397
 **/
398
void wl_token_iterator_begin(void)
399
{
400
        int i = 0;
401

    
402
        while (!sensor_matrix_get_in_ring(sensorMatrix, i) && i < sensor_matrix_get_size(sensorMatrix)) {
403
                i++;
404
        }
405

    
406
        if (i == sensor_matrix_get_size(sensorMatrix)) {
407
                i = -1;
408
        }
409

    
410
        iteratorCount = i;
411
}
412

    
413
/**
414
 * Returns true if there are more robots in the token ring
415
 * to iterate through, and false otherwise.
416
 *
417
 * @return nonzero if there are more robots to iterate through,
418
 * zero otherwise
419
 *
420
 * @see wl_token_iterator_begin, wl_token_iterator_next
421
 **/
422
int wl_token_iterator_has_next(void)
423
{
424
        return iteratorCount != -1;
425
}
426

    
427
/**
428
 * Returns the next robot ID in the token ring.
429
 *
430
 * @return the next robot ID in the token ring, or -1 if none exists
431
 *
432
 * @see wl_token_iterator_begin, wl_token_iterator_has_next
433
 **/
434
int wl_token_iterator_next(void)
435
{
436
        int result = iteratorCount;
437
        if (result < 0) {
438
                return result;
439
        }
440

    
441
        iteratorCount++;
442
        while (!sensor_matrix_get_in_ring(sensorMatrix, iteratorCount)
443
                && iteratorCount < sensor_matrix_get_size(sensorMatrix)) {
444
                iteratorCount++;
445
        }
446

    
447
        if (iteratorCount == sensor_matrix_get_size(sensorMatrix)) {
448
                iteratorCount = -1;
449
        }
450

    
451
        return result;
452
}
453

    
454
/**
455
 * Returns the number of robots currently in the token ring.
456
 *
457
 * @return the number of robots in the token ring
458
 **/
459
int wl_token_get_num_robots(void)
460
{
461
        return sensor_matrix_get_joined(sensorMatrix);
462
}
463

    
464
/**
465
 * Returns the number of robots in the sensor matrix.
466
 *
467
 * @return the number of robots in the sensor matrix
468
 **/
469
int wl_token_get_matrix_size(void)
470
{
471
        return sensor_matrix_get_size(sensorMatrix);
472
}
473

    
474
/**
475
 * This method is called when we receive a token pass packet.
476
 *
477
 * @param source the robot who passed the token to us.
478
 **/
479
static void wl_token_pass_receive(int source)
480
{
481
        // this prevents two tokens from being passed around at a time (second clause is in case we are joining)
482
        if (source != wl_token_next_robot && bom_on_count <= DEATH_DELAY / 2 &&
483
                ringState != ACCEPTED)
484
        {
485
                WL_DEBUG_PRINT("Received token pass when a robot should not have died yet.\n");
486
                WL_DEBUG_PRINT("There are probably two tokens going around, packet ignored.\n");
487
                return;
488
        }
489
        bom_on_count = -1;
490
        deathDelay = -1;
491
        sensor_matrix_set_in_ring(sensorMatrix, source, 1);
492
        wl_token_get_token();
493
}
494

    
495
/**
496
 * This method is called when we receive a token pass packet.
497
 * @param source is the robot it came from
498
 * @param nextRobot is the robot the token was passed to
499
 * @param sensorData a char with an id followed by a char with the sensor
500
 *                reading for that robot, repeated for sensorDataLength bytes
501
 * @param sensorDataLength the length in bytes of sensorData
502
 */
503
static void wl_token_sensor_matrix_receive(int source, unsigned char* sensorData, int sensorDataLength)
504
{
505
        int i, j;
506
        // get the next robot in the token ring
507
        char nextRobot;
508
        i = source + 1;
509
        while (1)
510
        {
511
                if (i == sensor_matrix_get_size(sensorMatrix)) {
512
                        i = 0;
513
                }
514

    
515
                if (sensor_matrix_get_in_ring(sensorMatrix, i))
516
                {
517
                        nextRobot = (char)i;
518
                        break;
519
                }
520

    
521
                i++;
522
        }
523

    
524
        bom_on_count = -1;
525
        deathDelay = -1;
526
        sensor_matrix_set_in_ring(sensorMatrix, source, 1);
527

    
528
        //with this packet, we are passed the id of the next robot in the ring
529
        //and the sensor matrix, a list of id and sensor reading pairs (two bytes for both)
530
        j = 0;
531
        for (i = 0; i < sensor_matrix_get_size(sensorMatrix); i++)
532
        {
533
                if (i == source) {
534
                        continue;
535
                }
536

    
537
                //set the sensor information we receive
538
                if (j < sensorDataLength / 2 && sensorData[2 * j] == i)
539
                {
540
                        //the robot we were going to accept has already been accepted
541
                        if (accepted == i)
542
                        {
543
                                accepted = -1;
544
                                WL_DEBUG_PRINT("Someone accepted the robot we did.\r\n");
545
                        }
546
                        sensor_matrix_set_reading(sensorMatrix, source, i,
547
                                                sensorData[2 * j + 1]);
548
                        sensor_matrix_set_in_ring(sensorMatrix, i, 1);
549
                        j++;
550
                }
551
                else
552
                {
553
                        if (sensor_matrix_get_in_ring(sensorMatrix, i))
554
                        {
555
                                WL_DEBUG_PRINT("Robot ");
556
                                WL_DEBUG_PRINT_INT(i);
557
                                WL_DEBUG_PRINT(" has been removed from the sensor matrix of robot ");
558
                                WL_DEBUG_PRINT_INT(wl_get_xbee_id());
559
                                WL_DEBUG_PRINT(" due to a packet from robot ");
560
                                WL_DEBUG_PRINT_INT(source);
561
                                WL_DEBUG_PRINT(".\r\n");
562
                                sensor_matrix_set_in_ring(sensorMatrix, i, 0);
563
                        }
564

    
565
                        if (i == wl_get_xbee_id() && ringState == MEMBER)
566
                        {
567
                                ringState = NONMEMBER;
568
                                wl_token_ring_join();
569

    
570
                                WL_DEBUG_PRINT("We have been removed from the ring ");
571
                                WL_DEBUG_PRINT("and are rejoining.\r\n");
572
                        }
573

    
574
                        //the person who accepted us is dead... let's ask again
575
                        if (i == acceptor)
576
                        {
577
                                sensor_matrix_set_in_ring(sensorMatrix,
578
                                                wl_get_xbee_id(), 1);
579
                                ringState = NONMEMBER;
580
                                acceptor = -1;
581
                                wl_token_ring_join();
582
                        }
583
                }
584
        }
585

    
586
        wl_token_next_robot = nextRobot;
587

    
588
        deathDelay = get_token_distance(wl_get_xbee_id(), nextRobot) * DEATH_DELAY;
589

    
590
        if (sensor_matrix_get_size(sensorMatrix) == 0 && ringState == JOINING)
591
                wl_send_robot_to_robot_packet(WL_TOKEN_RING_GROUP, WL_TOKEN_PASS, NULL, 0, nextRobot, WL_TOKEN_PASS_FRAME);
592
}
593

    
594
/**
595
 * Gets the distance in the token ring between two robots.
596
 *
597
 * @param robot1 the first robot
598
 * @param robot2 the second robot
599
 *
600
 * @return the number of passes before the token is expected
601
 * to reach robot2 from robot1
602
 **/
603
static int get_token_distance(int robot1, int robot2)
604
{
605
        int curr = robot1 + 1;
606
        int count = 1;
607
        while (1)
608
        {
609
                if (curr == sensor_matrix_get_size(sensorMatrix))
610
                        curr = 0;
611
                if (curr == robot2)
612
                        break;
613
                if (sensor_matrix_get_in_ring(sensorMatrix, curr))
614
                        count++;
615
                curr++;
616
        }
617
        return count;
618
}
619

    
620
/**
621
 * Passes the token to the next robot in the token ring.
622
 **/
623
static int wl_token_pass_token()
624
{
625
        char nextRobot = 0xFF;
626
        int i = wl_get_xbee_id() + 1;
627
        if (accepted == -1)
628
        {
629
                while (1)
630
                {
631
                        if (i == sensor_matrix_get_size(sensorMatrix)) {
632
                                i = 0;
633
                        }
634

    
635
                        if (sensor_matrix_get_in_ring(sensorMatrix, i))
636
                        {
637
                                nextRobot = (char)i;
638
                                break;
639
                        }
640

    
641
                        i++;
642
                }
643
        }
644
        else
645
        {
646
                WL_DEBUG_PRINT("Accepting new robot, sending it the token.\r\n");
647
                //add a new robot to the token ring
648
                sensor_matrix_set_in_ring(sensorMatrix, accepted, 1);
649
                nextRobot = accepted;
650
                accepted = -1;
651
        }
652

    
653
        //we don't include ourself
654
        int packetSize = 2 * (sensor_matrix_get_joined(sensorMatrix) - 1);
655
        char* buf = (char*)malloc(packetSize * sizeof(char));
656
        if (!buf)
657
        {
658
                WL_DEBUG_PRINT_INT(packetSize);
659
                WL_DEBUG_PRINT("Out of memory - pass token.\r\n");
660
                free(buf);
661
                return -1;
662
        }
663

    
664
        int j = 0;
665
        for (i = 0; i < sensor_matrix_get_size(sensorMatrix); i++) {
666
                if (sensor_matrix_get_in_ring(sensorMatrix, i) && i != wl_get_xbee_id())
667
                {
668
                        buf[2*j] = i;
669
                        buf[2*j + 1] = sensor_matrix_get_reading(sensorMatrix, wl_get_xbee_id(), i);
670
                        j++;
671
                }
672
        }
673

    
674
        WL_DEBUG_PRINT("Passing the token to robot ");
675
        WL_DEBUG_PRINT_INT(nextRobot);
676
        WL_DEBUG_PRINT(".\r\n");
677
        if (wl_send_global_packet(WL_TOKEN_RING_GROUP, WL_TOKEN_SENSOR_MATRIX, buf, packetSize, 0) != 0) {
678
                free(buf);
679
                return -1;
680
        }
681
        if (wl_send_robot_to_robot_packet(WL_TOKEN_RING_GROUP, WL_TOKEN_PASS, NULL, 0, nextRobot, WL_TOKEN_PASS_FRAME))
682
        {
683
                free(buf);
684
                return -1;
685
        }
686

    
687
        wl_token_next_robot = nextRobot;
688
        deathDelay = DEATH_DELAY;
689
        free(buf);
690

    
691
        return 0;
692
}
693

    
694
/**
695
 * Called when a packet is received stating that another robot has turned
696
 * its BOM on. Our BOM is then read, and the data is added to the sensor
697
 * matrix.
698
 *
699
 * @param source the robot whose BOM is on
700
 **/
701
static void wl_token_bom_on_receive(int source)
702
{
703
        WL_DEBUG_PRINT("Robot ");
704
        WL_DEBUG_PRINT_INT(source);
705
        WL_DEBUG_PRINT(" has flashed its bom.\r\n");
706

    
707
        bom_on_count = 0;
708

    
709
        sensor_matrix_set_reading(sensorMatrix, wl_get_xbee_id(),
710
                source, get_max_bom_function());
711
}
712

    
713
/**
714
 * This method is called when we receive the token. Upon receiving
715
 * the token, we must send a BOM_ON packet, flash the BOM, and send
716
 * the token to the next robot.
717
 *
718
 * If there is a pending request for the token, this is processed first.
719
 **/
720
static void wl_token_get_token()
721
{
722
        WL_DEBUG_PRINT("We have the token.\r\n");
723
        if (ringState == ACCEPTED)
724
        {
725
                sensor_matrix_set_in_ring(sensorMatrix, wl_get_xbee_id(), 1);
726
                WL_DEBUG_PRINT("Now a member of the token ring.\r\n");
727
                ringState = MEMBER;
728
                joinDelay = -1;
729
        }
730

    
731
        if (ringState == LEAVING || ringState == NONMEMBER)
732
        {
733
                sensor_matrix_set_in_ring(sensorMatrix, wl_get_xbee_id(), 0);
734
                if (ringState == NONMEMBER)
735
                {
736
                        WL_DEBUG_PRINT("We should have left the token ring, but didn't.\r\n");
737
                }
738
                return;
739
        }
740

    
741
        WL_DEBUG_PRINT("Our BOM has been flashed.\r\n");
742
        wl_send_global_packet(WL_TOKEN_RING_GROUP, WL_TOKEN_BOM_ON, NULL, 0, 0);
743

    
744
        bom_on_function();
745
        #ifdef ROBOT
746
        delay_ms(BOM_DELAY);
747
        #endif
748
        bom_off_function();
749

    
750
        if (!sensor_matrix_get_in_ring(sensorMatrix, wl_get_xbee_id()))
751
        {
752
                WL_DEBUG_PRINT("Removed from sensor matrix while flashing BOM.\r\n");
753
                return;
754
        }
755

    
756
        wl_token_pass_token();
757
}
758

    
759
/**
760
 * Called when a request to join the token ring is received.
761
 * If we are the robot preceding the requester in the ring,
762
 * we respond with a JOIN_ACCEPT packet and pass the token to
763
 * this robot when we receive the token.
764
 *
765
 * @param source the robot who requested to join
766
 **/
767
static void wl_token_join_receive(int source)
768
{
769
        WL_DEBUG_PRINT("Received joining request from robot ");
770
        WL_DEBUG_PRINT_INT(source);
771
        WL_DEBUG_PRINT(".\r\n");
772

    
773
        //we cannot accept the request if we are not a member
774
        if (ringState != MEMBER)
775
                return;
776
        //if they didn't get our response, see if we should respond again
777
        if (accepted == source)
778
                accepted = -1;
779
        //we can only accept one request at a time
780
        if (accepted != -1)
781
                return;
782

    
783
        //check if we are the preceding robot in the token ring
784
        int i = source - 1;
785
        while (1)
786
        {
787
                if (i < 0)
788
                        i = sensor_matrix_get_size(sensorMatrix) - 1;
789
                //we must send a join acceptance
790
                if (i == wl_get_xbee_id())
791
                        break;
792

    
793
                //another robot will handle it
794
                if (sensor_matrix_get_in_ring(sensorMatrix, i))
795
                        return;
796
                i--;
797
        }
798

    
799
        accepted = source;
800
        wl_send_robot_to_robot_global_packet(WL_TOKEN_RING_GROUP, WL_TOKEN_JOIN_ACCEPT,
801
                NULL, 0, source, TOKEN_JOIN_ACCEPT_FRAME);
802

    
803
        WL_DEBUG_PRINT("Accepting robot ");
804
        WL_DEBUG_PRINT_INT(source);
805
        WL_DEBUG_PRINT(" into the token ring.\r\n");
806

    
807
        // the token ring has not started yet
808
        if (sensor_matrix_get_joined(sensorMatrix) == 1)
809
                wl_token_pass_token();
810
}
811

    
812
/**
813
 * Called when we receive a JOIN_ACCEPT packet in attempting to join
814
 * the token ring.
815
 * Our attempt to join the ring is stopped, and we wait for the token.
816
 *
817
 * @param source the robot who accepted us
818
 **/
819
static void wl_token_join_accept_receive(int source)
820
{
821
        WL_DEBUG_PRINT("Accepted into the token ring by robot ");
822
        WL_DEBUG_PRINT_INT(source);
823
        WL_DEBUG_PRINT(".\r\n");
824
        joinDelay = JOIN_DELAY;
825
        ringState = ACCEPTED;
826
        acceptor = source;
827

    
828
        //add ourselves to the token ring
829
        sensor_matrix_set_in_ring(sensorMatrix, wl_get_xbee_id(), 1);
830
}