Project

General

Profile

Statistics
| Revision:

root / branches / autonomous_recharging / code / projects / libwireless / lib / wl_token_ring.c @ 706

History | View | Annotate | Download (20.7 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
                #ifdef BAYBOARD
47
                        #include <lbom.h>
48
                #else
49
                        #include <bom.h>
50
                #endif
51
        #endif
52
#include <time.h>
53
#endif
54

    
55
#define DEFAULT_SENSOR_MATRIX_SIZE 20
56

    
57
/*Ring States*/
58

    
59
#define NONMEMBER 0
60
#define MEMBER 1
61
#define JOINING 2
62
#define ACCEPTED 3
63
#define LEAVING 4
64

    
65
/*Frame Types*/
66
#define TOKEN_JOIN_ACCEPT_FRAME 1
67

    
68
/*Function Prototypes*/
69

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

    
76
/*Helper Functions*/
77
static int wl_token_pass_token(void);
78
static int get_token_distance(int robot1, int robot2);
79
static void wl_token_get_token(void);
80

    
81
/*Packet Handling Routines*/
82
static void wl_token_pass_receive(int source, char nextRobot, unsigned char* sensorData, int sensorDataLength);
83
static void wl_token_bom_on_receive(int source);
84
static void wl_token_join_receive(int source);
85
static void wl_token_join_accept_receive(int source);
86

    
87
/*Global Variables*/
88

    
89
//the sensor matrix
90
static SensorMatrix* sensorMatrix;
91

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

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

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

    
107
//current robot to check in the iterator
108
static int iteratorCount = 0;
109

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

    
113
static void do_nothing(void) {}
114
static int get_nothing(void) {return -1;}
115

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

    
138
static PacketGroupHandler wl_token_ring_handler =
139
        {WL_TOKEN_RING_GROUP, wl_token_ring_timeout_handler,
140
                wl_token_ring_response_handler, wl_token_ring_receive_handler,
141
                wl_token_ring_cleanup};
142

    
143
/**
144
 * Causes the robot to join an existing token ring, or create one
145
 * if no token ring exists. The token ring uses global and robot to robot
146
 * packets, and does not rely on any PAN.
147
 **/
148
int wl_token_ring_join()
149
{
150
        WL_DEBUG_PRINT("Joining the token ring.\r\n");
151

    
152
        ringState = JOINING;
153
        joinDelay = DEATH_DELAY * 2;
154
        if (wl_send_global_packet(WL_TOKEN_RING_GROUP, WL_TOKEN_JOIN, NULL, 0, 0) != 0) {
155
                return -1;
156
        }
157

    
158
        return 0;
159
}
160

    
161
/**
162
 * Causes the robot to leave the token ring. The robot stops
163
 * alerting others of its location, but continues storing the
164
 * locations of other robots.
165
 **/
166
void wl_token_ring_leave()
167
{
168
        ringState = LEAVING;
169
}
170

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

    
187
        sensorMatrix = sensor_matrix_create();
188
        //add ourselves to the sensor matrix
189
        sensor_matrix_set_in_ring(sensorMatrix, wl_get_xbee_id(), 0);
190

    
191
        wl_register_packet_group(&wl_token_ring_handler);
192

    
193
        return 0;
194
}
195

    
196
/**
197
 * Removes the packet group from the wireless library.
198
 **/
199
void wl_token_ring_unregister()
200
{
201
        wl_unregister_packet_group(&wl_token_ring_handler);
202
}
203

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

    
224
/**
225
 * Called to cleanup the token ring packet group.
226
 **/
227
static void wl_token_ring_cleanup()
228
{
229
        sensor_matrix_destroy(sensorMatrix);
230
}
231

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

    
252
                // we may have been dropped from the ring when this is received
253
                if (ringState == MEMBER) {
254
                        wl_token_pass_token();
255
                }
256
        }
257

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

    
280
        if (deathDelay >= 0) {
281
                deathDelay--;
282
        }
283

    
284
        if (joinDelay >= 0) {
285
                joinDelay--;
286
        }
287

    
288
        if (bom_on_count >= 0) {
289
                bom_on_count++;
290
        }
291
}
292

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

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

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

    
358
        return -1;
359
}
360

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

    
374

    
375
/**
376
 * Returns the number of robots in the token ring.
377
 *
378
 * @return the number of robots in the token ring
379
 **/
380
int wl_token_get_robots_in_ring(void)
381
{
382
        return sensor_matrix_get_joined(sensorMatrix);
383
}
384

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

    
397
/**
398
 * Begins iterating through the robots in the token ring.
399
 *
400
 * @see wl_token_iterator_has_next, wl_token_iterator_next
401
 **/
402
void wl_token_iterator_begin(void)
403
{
404
        int i = 0;
405

    
406
        while (!sensor_matrix_get_in_ring(sensorMatrix, i) && i < sensor_matrix_get_size(sensorMatrix)) {
407
                i++;
408
        }
409

    
410
        if (i == sensor_matrix_get_size(sensorMatrix)) {
411
                i = -1;
412
        }
413

    
414
        iteratorCount = i;
415
}
416

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

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

    
445
        iteratorCount++;
446
        while (!sensor_matrix_get_in_ring(sensorMatrix, iteratorCount)
447
                && iteratorCount < sensor_matrix_get_size(sensorMatrix)) {
448
                iteratorCount++;
449
        }
450

    
451
        if (iteratorCount == sensor_matrix_get_size(sensorMatrix)) {
452
                iteratorCount = -1;
453
        }
454

    
455
        return result;
456
}
457

    
458
/**
459
 * Returns the number of robots currently in the token ring.
460
 *
461
 * @return the number of robots in the token ring
462
 **/
463
int wl_token_get_num_robots(void)
464
{
465
        return sensor_matrix_get_joined(sensorMatrix);
466
}
467

    
468
/**
469
 * Returns the number of robots in the sensor matrix.
470
 *
471
 * @return the number of robots in the sensor matrix
472
 **/
473
int wl_token_get_matrix_size(void)
474
{
475
        return sensor_matrix_get_size(sensorMatrix);
476
}
477

    
478
/**
479
 * This method is called when we receive a token pass packet.
480
 * @param source is the robot it came from
481
 * @param nextRobot is the robot the token was passed to
482
 * @param sensorData a char with an id followed by a char with the sensor
483
 *                reading for that robot, repeated for sensorDataLength bytes
484
 * @param sensorDataLength the length in bytes of sensorData
485
 */
486
static void wl_token_pass_receive(int source, char nextRobot, unsigned char* sensorData, int sensorDataLength)
487
{
488
        int i, j;
489

    
490
        // this prevents two tokens from being passed around at a time (second clause is in case we are joining)
491
        if (source != wl_token_next_robot && bom_on_count <= DEATH_DELAY / 2 &&
492
                ringState != ACCEPTED)
493
        {
494
                WL_DEBUG_PRINT("Received token pass when a robot should not have died yet.\n");
495
                WL_DEBUG_PRINT("There are probably two tokens going around, packet ignored.\n");
496
                return;
497
        }
498

    
499
        bom_on_count = -1;
500
        deathDelay = -1;
501
        WL_DEBUG_PRINT("Received the token from robot");
502
        WL_DEBUG_PRINT_INT(source);
503
        WL_DEBUG_PRINT(", next robot is ");
504
        WL_DEBUG_PRINT_INT((int)nextRobot);
505
        WL_DEBUG_PRINT(" \r\n");
506
        sensor_matrix_set_in_ring(sensorMatrix, source, 1);
507

    
508
        //with this packet, we are passed the id of the next robot in the ring
509
        //and the sensor matrix, a list of id and sensor reading pairs (two bytes for both)
510
        j = 0;
511
        for (i = 0; i < sensor_matrix_get_size(sensorMatrix); i++)
512
        {
513
                if (i == source) {
514
                        continue;
515
                }
516

    
517
                //set the sensor information we receive
518
                if (j < sensorDataLength / 2 && sensorData[2 * j] == i)
519
                {
520
                        //the robot we were going to accept has already been accepted
521
                        if (accepted == i)
522
                        {
523
                                accepted = -1;
524
                                WL_DEBUG_PRINT("Someone accepted the robot we did.\r\n");
525
                        }
526
                        sensor_matrix_set_reading(sensorMatrix, source, i,
527
                                                sensorData[2 * j + 1]);
528
                        sensor_matrix_set_in_ring(sensorMatrix, i, 1);
529
                        j++;
530
                }
531
                else
532
                {
533
                        if (sensor_matrix_get_in_ring(sensorMatrix, i))
534
                        {
535
                                WL_DEBUG_PRINT("Robot ");
536
                                WL_DEBUG_PRINT_INT(i);
537
                                WL_DEBUG_PRINT(" has been removed from the sensor matrix of robot ");
538
                                WL_DEBUG_PRINT_INT(wl_get_xbee_id());
539
                                WL_DEBUG_PRINT(" due to a packet from robot ");
540
                                WL_DEBUG_PRINT_INT(source);
541
                                WL_DEBUG_PRINT(".\r\n");
542
                                sensor_matrix_set_in_ring(sensorMatrix, i, 0);
543
                        }
544

    
545
                        if (i == wl_get_xbee_id() && ringState == MEMBER)
546
                        {
547
                                ringState = NONMEMBER;
548
                                wl_token_ring_join();
549

    
550
                                WL_DEBUG_PRINT("We have been removed from the ring ");
551
                                WL_DEBUG_PRINT("and are rejoining.\r\n");
552
                        }
553

    
554
                        //the person who accepted us is dead... let's ask again
555
                        if (i == acceptor)
556
                        {
557
                                sensor_matrix_set_in_ring(sensorMatrix,
558
                                                wl_get_xbee_id(), 1);
559
                                ringState = NONMEMBER;
560
                                acceptor = -1;
561
                                wl_token_ring_join();
562
                        }
563
                }
564
        }
565

    
566
        wl_token_next_robot = nextRobot;
567

    
568
        deathDelay = get_token_distance(wl_get_xbee_id(), nextRobot) * DEATH_DELAY;
569

    
570
        //we have the token
571
        if (wl_token_next_robot == wl_get_xbee_id()) {
572
                wl_token_get_token();
573
        }
574
}
575

    
576
/**
577
 * Gets the distance in the token ring between two robots.
578
 *
579
 * @param robot1 the first robot
580
 * @param robot2 the second robot
581
 *
582
 * @return the number of passes before the token is expected
583
 * to reach robot2 from robot1
584
 **/
585
static int get_token_distance(int robot1, int robot2)
586
{
587
        int curr = robot1 + 1;
588
        int count = 1;
589
        while (1)
590
        {
591
                if (curr == sensor_matrix_get_size(sensorMatrix))
592
                        curr = 0;
593
                if (curr == robot2)
594
                        break;
595
                if (sensor_matrix_get_in_ring(sensorMatrix, curr))
596
                        count++;
597
                curr++;
598
        }
599
        return count;
600
}
601

    
602
/**
603
 * Passes the token to the next robot in the token ring.
604
 **/
605
static int wl_token_pass_token()
606
{
607
        char nextRobot;
608
        int i = wl_get_xbee_id() + 1;
609
        if (accepted == -1)
610
        {
611
                while (1)
612
                {
613
                        if (i == sensor_matrix_get_size(sensorMatrix)) {
614
                                i = 0;
615
                        }
616

    
617
                        if (sensor_matrix_get_in_ring(sensorMatrix, i))
618
                        {
619
                                nextRobot = (char)i;
620
                                break;
621
                        }
622

    
623
                        i++;
624
                }
625
        }
626
        else
627
        {
628
                WL_DEBUG_PRINT("Accepting new robot, sending it the token.\r\n");
629
                //add a new robot to the token ring
630
                sensor_matrix_set_in_ring(sensorMatrix, accepted, 1);
631
                nextRobot = accepted;
632
                accepted = -1;
633
        }
634

    
635
        //we don't include ourself
636
        int packetSize = 1 + 2 * (sensor_matrix_get_joined(sensorMatrix) - 1);
637
        char* buf = (char*)malloc(packetSize * sizeof(char));
638
        if (!buf)
639
        {
640
                WL_DEBUG_PRINT_INT(packetSize);
641
                WL_DEBUG_PRINT("Out of memory - pass token.\r\n");
642
                free(buf);
643
                return -1;
644
        }
645
        buf[0] = nextRobot;
646

    
647
        int j = 0;
648
        for (i = 0; i < sensor_matrix_get_size(sensorMatrix); i++) {
649
                if (sensor_matrix_get_in_ring(sensorMatrix, i) && i != wl_get_xbee_id())
650
                {
651
                        buf[2*j + 1] = i;
652
                        buf[2*j + 2] = sensor_matrix_get_reading(sensorMatrix, wl_get_xbee_id(), i);
653
                        j++;
654
                }
655
        }
656

    
657
        WL_DEBUG_PRINT("Passing the token to robot ");
658
        WL_DEBUG_PRINT_INT(buf[0]);
659
        WL_DEBUG_PRINT(".\r\n");
660
        if (wl_send_global_packet(WL_TOKEN_RING_GROUP, WL_TOKEN_PASS, buf, packetSize, 3) != 0) {
661
                free(buf);
662
                return -1;
663
        }
664

    
665
        wl_token_next_robot = nextRobot;
666
        deathDelay = DEATH_DELAY;
667
        free(buf);
668

    
669
        return 0;
670
}
671

    
672
/**
673
 * Called when a packet is received stating that another robot has turned
674
 * its BOM on. Our BOM is then read, and the data is added to the sensor
675
 * matrix.
676
 *
677
 * @param source the robot whose BOM is on
678
 **/
679
static void wl_token_bom_on_receive(int source)
680
{
681
        WL_DEBUG_PRINT("Robot ");
682
        WL_DEBUG_PRINT_INT(source);
683
        WL_DEBUG_PRINT(" has flashed its bom.\r\n");
684

    
685
        bom_on_count = 0;
686

    
687
        sensor_matrix_set_reading(sensorMatrix, wl_get_xbee_id(),
688
                source, get_max_bom_function());
689
}
690

    
691
/**
692
 * This method is called when we receive the token. Upon receiving
693
 * the token, we must send a BOM_ON packet, flash the BOM, and send
694
 * the token to the next robot.
695
 *
696
 * If there is a pending request for the token, this is processed first.
697
 **/
698
static void wl_token_get_token()
699
{
700
        WL_DEBUG_PRINT("We have the token.\r\n");
701
        if (ringState == ACCEPTED)
702
        {
703
                sensor_matrix_set_in_ring(sensorMatrix, wl_get_xbee_id(), 1);
704
                WL_DEBUG_PRINT("Now a member of the token ring.\r\n");
705
                ringState = MEMBER;
706
                joinDelay = -1;
707
        }
708

    
709
        if (ringState == LEAVING || ringState == NONMEMBER)
710
        {
711
                sensor_matrix_set_in_ring(sensorMatrix, wl_get_xbee_id(), 0);
712
                if (ringState == NONMEMBER)
713
                {
714
                        WL_DEBUG_PRINT("We should have left the token ring, but didn't.\r\n");
715
                }
716
                return;
717
        }
718

    
719
        WL_DEBUG_PRINT("Our BOM has been flashed.\r\n");
720
        wl_send_global_packet(WL_TOKEN_RING_GROUP, WL_TOKEN_BOM_ON, NULL, 0, 0);
721

    
722
        bom_on_function();
723
        #ifdef ROBOT
724
        delay_ms(BOM_DELAY);
725
        #endif
726
        bom_off_function();
727

    
728
        if (!sensor_matrix_get_in_ring(sensorMatrix, wl_get_xbee_id()))
729
        {
730
                WL_DEBUG_PRINT("Removed from sensor matrix while flashing BOM.\r\n");
731
                return;
732
        }
733

    
734
        wl_token_pass_token();
735
}
736

    
737
/**
738
 * Called when a request to join the token ring is received.
739
 * If we are the robot preceding the requester in the ring,
740
 * we respond with a JOIN_ACCEPT packet and pass the token to
741
 * this robot when we receive the token.
742
 *
743
 * @param source the robot who requested to join
744
 **/
745
static void wl_token_join_receive(int source)
746
{
747
        WL_DEBUG_PRINT("Received joining request from robot ");
748
        WL_DEBUG_PRINT_INT(source);
749
        WL_DEBUG_PRINT(".\r\n");
750

    
751
        //we cannot accept the request if we are not a member
752
        if (ringState != MEMBER)
753
                return;
754
        //if they didn't get our response, see if we should respond again
755
        if (accepted == source)
756
                accepted = -1;
757
        //we can only accept one request at a time
758
        if (accepted != -1)
759
                return;
760

    
761
        //check if we are the preceding robot in the token ring
762
        int i = source - 1;
763
        while (1)
764
        {
765
                if (i < 0)
766
                        i = sensor_matrix_get_size(sensorMatrix) - 1;
767
                //we must send a join acceptance
768
                if (i == wl_get_xbee_id())
769
                        break;
770

    
771
                //another robot will handle it
772
                if (sensor_matrix_get_in_ring(sensorMatrix, i))
773
                        return;
774
                i--;
775
        }
776

    
777
        accepted = source;
778
        wl_send_robot_to_robot_global_packet(WL_TOKEN_RING_GROUP, WL_TOKEN_JOIN_ACCEPT,
779
                NULL, 0, source, TOKEN_JOIN_ACCEPT_FRAME);
780

    
781
        WL_DEBUG_PRINT("Accepting robot ");
782
        WL_DEBUG_PRINT_INT(source);
783
        WL_DEBUG_PRINT(" into the token ring.\r\n");
784

    
785
        // the token ring has not started yet
786
        if (sensor_matrix_get_joined(sensorMatrix) == 1)
787
                wl_token_pass_token();
788
}
789

    
790
/**
791
 * Called when we receive a JOIN_ACCEPT packet in attempting to join
792
 * the token ring.
793
 * Our attempt to join the ring is stopped, and we wait for the token.
794
 *
795
 * @param source the robot who accepted us
796
 **/
797
static void wl_token_join_accept_receive(int source)
798
{
799
        WL_DEBUG_PRINT("Accepted into the token ring by robot ");
800
        WL_DEBUG_PRINT_INT(source);
801
        WL_DEBUG_PRINT(".\r\n");
802
        joinDelay = JOIN_DELAY;
803
        ringState = ACCEPTED;
804
        acceptor = source;
805

    
806
        //add ourselves to the token ring
807
        sensor_matrix_set_in_ring(sensorMatrix, wl_get_xbee_id(), 1);
808
}