Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (21.2 KB)

1
#include <wl_token_ring.h>
2

    
3
#include <stdlib.h>
4
#include <stdio.h>
5

    
6
#include <wl_defs.h>
7
#include <wireless.h>
8
#include <sensor_matrix.h>
9
#include <queue.h>
10

    
11
#ifdef ROBOT
12
#ifndef FIREFLY
13
#include <bom.h>
14
#endif
15
#include <time.h>
16
#endif
17

    
18
#define DEFAULT_SENSOR_MATRIX_SIZE 20
19

    
20
/*Ring States*/
21

    
22
#define NONMEMBER 0
23
#define MEMBER 1
24
#define JOINING 2
25
#define ACCEPTED 3
26
#define LEAVING 4
27

    
28
/*Frame Types*/
29
#define TOKEN_JOIN_ACCEPT_FRAME 1
30

    
31
/*Function Prototypes*/
32

    
33
/*Wireless Library Prototypes*/
34
void wl_token_ring_timeout_handler(void);
35
void wl_token_ring_response_handler(int frame, int received);
36
void wl_token_ring_receive_handler(char type, int source, unsigned char* packet,
37
                                                        int length);
38
void wl_token_ring_cleanup(void);
39

    
40
/*Helper Functions*/
41
void wl_token_pass_token(void);
42
int get_token_distance(int robot1, int robot2);
43
void wl_token_get_token(void);
44

    
45
/*Packet Handling Routines*/
46
void wl_token_pass_receive(int source, char nextRobot, unsigned char* sensorData, int sensorDataLength);
47
void wl_token_interrupt_request_receive(int source, int robot);
48
void wl_token_interrupt_pass_receive(int source, int robot);
49
void wl_token_bom_on_receive(int source);
50
void wl_token_join_receive(int source);
51
void wl_token_join_accept_receive(int source);
52

    
53
/*Global Variables*/
54

    
55
//the sensor matrix
56
SensorMatrix* sensorMatrix;
57

    
58
//the robot we are waiting to say it has received the token. -1 if unspecified
59
int wl_token_next_robot = -1;
60

    
61
//true if the robot should be in the token ring, 0 otherwise
62
int ringState = NONMEMBER;
63
//the id of the robot who accepted us into the token ring, only used in ACCEPTED state
64
int acceptor = -1;
65
//id of the robot we are accepting
66
int accepted = -1;
67

    
68
//the counter for when we assume a robot is dead
69
int deathDelay = -1;
70
//the counter for joining, before we form our own token ring
71
int joinDelay = -1;
72
//queue containing ids of interruption requests
73
Queue* interrupting = NULL;
74

    
75
//current robot to check in the iterator
76
int iteratorCount = 0;
77

    
78
void do_nothing(void) {}
79
int get_nothing(void) {return -1;}
80

    
81
#ifdef ROBOT
82
#ifndef FIREFLY
83
void (*bom_on_function) (void) = bom_on;
84
void (*bom_off_function) (void) = bom_off;
85
int (*get_max_bom_function) (void) = get_max_bom;
86
#else
87
void (*bom_on_function) (void) = do_nothing;
88
void (*bom_off_function) (void) = do_nothing;
89
int (*get_max_bom_function) (void) = get_nothing;
90
#endif
91
#else
92
void (*bom_on_function) (void) = do_nothing;
93
void (*bom_off_function) (void) = do_nothing;
94
int (*get_max_bom_function) (void) = get_nothing;
95
#endif
96

    
97
PacketGroupHandler wl_token_ring_handler =
98
                {WL_TOKEN_RING_GROUP, wl_token_ring_timeout_handler,
99
                wl_token_ring_response_handler, wl_token_ring_receive_handler,
100
                wl_token_ring_cleanup};
101

    
102
/**
103
 * Initialize the token ring packet group and register it with the
104
 * wireless library. The robot will not join a token ring.
105
 **/
106
void wl_token_ring_register()
107
{
108
        if (wl_get_xbee_id() > 0xFF)
109
        {
110
                //Note: if this becomes an issue (unlikely), we could limit sensor information
111
                //to half a byte and use 12 bits for the id
112
                WL_DEBUG_PRINT("XBee ID must be single byte for token ring, is ");
113
                WL_DEBUG_PRINT_INT(wl_get_xbee_id());
114
                WL_DEBUG_PRINT(".\r\n");
115
                return;
116
        }
117
        
118
        sensorMatrix = sensor_matrix_create();
119
        interrupting = queue_create();
120
        //add ourselves to the sensor matrix
121
        sensor_matrix_set_in_ring(sensorMatrix, wl_get_xbee_id(), 0);
122

    
123
        wl_register_packet_group(&wl_token_ring_handler);
124
}
125

    
126
/**
127
 * Removes the packet group from the wireless library.
128
 **/
129
void wl_token_ring_unregister()
130
{
131
        wl_unregister_packet_group(&wl_token_ring_handler);
132
}
133

    
134
/**
135
 * Sets the functions that are called when the BOM ought to be
136
 * turned on or off. This could be used for things such as 
137
 * charging stations, which have multiple BOMs.
138
 *
139
 * @param on_function the function to be called when the BOM
140
 * should be turned on
141
 * @param off_function the function to be called when the BOM
142
 * should be turned off
143
 * @param max_bom_function the function to be called when a
144
 * measurement of the maximum BOM reading is needed.
145
 **/
146
void wl_token_ring_set_bom_functions(void (*on_function) (void),
147
        void (*off_function) (void), int (*max_bom_function) (void))
148
{
149
        bom_on_function = on_function;
150
        bom_off_function = off_function;
151
        get_max_bom_function = max_bom_function;
152
}
153

    
154
/**
155
 * Called to cleanup the token ring packet group.
156
 **/
157
void wl_token_ring_cleanup()
158
{
159
        sensor_matrix_destroy(sensorMatrix);
160
        queue_destroy(interrupting);
161
}
162

    
163
/**
164
 * Called approximately every quarter second by the wireless library.
165
 **/
166
void wl_token_ring_timeout_handler()
167
{
168
        //someone is not responding, assume they are dead
169
        if (deathDelay == 0)
170
        {
171
                //pass the token to the next robot if we think someone has died
172
                //also, declare that person dead, as long as it isn't us
173
                if (wl_token_next_robot != wl_get_xbee_id())
174
                {
175
                        sensor_matrix_set_in_ring(sensorMatrix, wl_token_next_robot, 0);
176
                        WL_DEBUG_PRINT("Robot ");
177
                        WL_DEBUG_PRINT_INT(wl_token_next_robot);
178
                        WL_DEBUG_PRINT(" has died.\r\n");
179
                        wl_token_next_robot = -1;
180
                        deathDelay = DEATH_DELAY;
181
                }
182
                
183
                // we may have been dropped from the ring when this is received
184
                if (ringState == MEMBER)
185
                        wl_token_pass_token();
186
        }
187

    
188
        //we must start our own token ring, no one is responding to us
189
        if (joinDelay == 0)
190
        {
191
                if (sensor_matrix_get_joined(sensorMatrix) == 0)
192
                {
193
                        WL_DEBUG_PRINT("Creating our own token ring, no robots seem to exist.\r\n");
194
                        sensor_matrix_set_in_ring(sensorMatrix, wl_get_xbee_id(), 1);
195
                        ringState = MEMBER;
196
                        //this will make us pass the token to ourself
197
                        //repeatedly, and other robots when they join
198
                        deathDelay = DEATH_DELAY;
199
                        wl_token_next_robot = wl_get_xbee_id();
200
                }
201
                else
202
                {
203
                        WL_DEBUG_PRINT("Attempting to join the token ring again.\r\n");
204
                        //attempt to rejoin with a random delay
205
                        wl_token_ring_join();
206
                        joinDelay = rand() / (RAND_MAX / JOIN_DELAY) + 1;
207
                }
208
        }
209

    
210
        if (deathDelay >= 0)
211
                deathDelay--;
212
        if (joinDelay >= 0)
213
                joinDelay--;
214
}
215

    
216
/**
217
 * Called when the XBee tells us if a packet we sent has been received.
218
 * 
219
 * @param frame the frame number assigned when the packet was sent
220
 * @param received 1 if the packet was received, 0 otherwise
221
 **/
222
void wl_token_ring_response_handler(int frame, int received)
223
{
224
        if (!received)
225
        {
226
                WL_DEBUG_PRINT("FAILED.\r\n");
227
        }
228
}
229

    
230
/**
231
 * Called when we recieve a token ring packet.
232
 * @param type the type of the packet
233
 * @param source the id of the robot who sent the packet
234
 * @param packet the data in the packet
235
 * @param length the length of the packet in bytes
236
 **/
237
void wl_token_ring_receive_handler(char type, int source, unsigned char* packet,
238
                                                        int length)
239
{
240
        switch (type)
241
        {
242
                case WL_TOKEN_PASS:
243
                        if (length < 1)
244
                        {
245
                                WL_DEBUG_PRINT("Malformed Token Pass packet received.\r\n");
246
                                return;
247
                        }
248
                        wl_token_pass_receive(source, packet[0], packet + 1, length - 1);
249
                        break;
250
                case WL_TOKEN_BOM_ON:
251
                        //add the robot to the sensor matrix if it is not already there
252
                        wl_token_bom_on_receive(source);
253
                        break;
254
                case WL_TOKEN_INTERRUPT_REQUEST:
255
                        wl_token_interrupt_request_receive(source, packet[0]);
256
                        break;
257
                case WL_TOKEN_INTERRUPT_PASS:
258
                        wl_token_interrupt_pass_receive(source, packet[0]);
259
                        break;
260
                case WL_TOKEN_JOIN:
261
                        wl_token_join_receive(source);
262
                        break;
263
                case WL_TOKEN_JOIN_ACCEPT:
264
                        wl_token_join_accept_receive(source);
265
                        break;
266
                default:
267
                        WL_DEBUG_PRINT("Unimplemented token ring packet received.\r\n");
268
                        break;
269
        }
270
}
271

    
272
/**
273
 * Causes the robot to join an existing token ring, or create one
274
 * if no token ring exists. The token ring uses global and robot to robot
275
 * packets, and does not rely on any PAN.
276
 **/
277
void wl_token_ring_join()
278
{
279
        WL_DEBUG_PRINT("Joining the token ring.\r\n");
280
        ringState = JOINING;
281
        joinDelay = JOIN_DELAY;
282
        wl_send_global_packet(WL_TOKEN_RING_GROUP, WL_TOKEN_JOIN,
283
                NULL, 0, 0);
284
}
285

    
286
/**
287
 * Causes the robot to leave the token ring. The robot stops
288
 * alerting others of its location, but continues storing the
289
 * locations of other robots.
290
 **/
291
void wl_token_ring_leave()
292
{
293
        ringState = LEAVING;
294
}
295

    
296
/**
297
 * Requests that the specified robot be given the token and
298
 * allowed to flash its BOM. After its BOM is flashed, the
299
 * token will return to the robot who sent it.
300
 *
301
 * @param robot the ID of the robot which should flash its BOM
302
 **/
303
void wl_token_request(int robot)
304
{
305
        char buf[1];
306
        buf[0] = robot;
307
        wl_send_global_packet(WL_TOKEN_RING_GROUP, WL_TOKEN_INTERRUPT_REQUEST,
308
                buf, 1, 0);
309
}
310

    
311
/**
312
 * Returns the BOM reading robot source has for robot dest.
313
 *
314
 * @param source the robot that made the BOM reading
315
 * @param dest the robot whose relative location is returned
316
 *
317
 * @return a BOM reading from robot source to robot dest,
318
 * in the range 0-15, or -1 if it is unknown
319
 **/
320
int wl_token_get_sensor_reading(int source, int dest)
321
{
322
        return sensor_matrix_get_reading(sensorMatrix, source, dest);
323
}
324

    
325
/**
326
 * Returns the BOM reading we have for robot dest.
327
 * 
328
 * @param dest the robot whose relative location is returned
329
 *
330
 * @return a BOM reading from us to robot dest, in the range
331
 * 0-15, or -1 if it is unkown
332
 **/
333
int wl_token_get_my_sensor_reading(int dest)
334
{
335
        return wl_token_get_sensor_reading(wl_get_xbee_id(), dest);
336
}
337

    
338
/**
339
 * This method is called when we receive a token pass packet.
340
 * @param source is the robot it came from
341
 * @param nextRobot is the robot the token was passed to
342
 * @param sensorData a char with an id followed by a char with the sensor
343
 *                reading for that robot, repeated for sensorDataLength bytes
344
 * @param sensorDataLength the length in bytes of sensorData
345
 */
346
void wl_token_pass_receive(int source, char nextRobot, unsigned char* sensorData, int sensorDataLength)
347
{
348
        int i, j;
349
        deathDelay = -1;
350

    
351
        WL_DEBUG_PRINT("Received the token from robot");
352
        WL_DEBUG_PRINT_INT(source);
353
        WL_DEBUG_PRINT(", next robot is ");
354
        WL_DEBUG_PRINT_INT((int)nextRobot);
355
        WL_DEBUG_PRINT(" \r\n");
356
        sensor_matrix_set_in_ring(sensorMatrix, source, 1);
357

    
358
        //with this packet, we are passed the id of the next robot in the ring
359
        //and the sensor matrix, a list of id and sensor reading pairs (two bytes for both)
360
        j = 0;
361
        for (i = 0; i < sensor_matrix_get_size(sensorMatrix); i++)
362
        {
363
                if (i == source)
364
                        continue;
365
                
366
                //set the sensor information we receive
367
                if (j < sensorDataLength / 2 && sensorData[2 * j] == i)
368
                {
369
                        //the robot we were going to accept has already been accepted
370
                        if (accepted == i)
371
                        {
372
                                accepted = -1;
373
                                WL_DEBUG_PRINT("Someone accepted the robot we did.\r\n");
374
                        }
375
                        sensor_matrix_set_reading(sensorMatrix, source, i,
376
                                                sensorData[2 * j + 1]);
377
                        sensor_matrix_set_in_ring(sensorMatrix, i, 1);
378
                        j++;
379
                }
380
                else
381
                {
382
                        if (sensor_matrix_get_in_ring(sensorMatrix, i))
383
                        {
384
                                WL_DEBUG_PRINT("Robot ");
385
                                WL_DEBUG_PRINT_INT(i);
386
                                WL_DEBUG_PRINT(" has been removed from the sensor matrix of robot ");
387
                                WL_DEBUG_PRINT_INT(wl_get_xbee_id());
388
                                WL_DEBUG_PRINT(" due to a packet from robot ");
389
                                WL_DEBUG_PRINT_INT(source);
390
                                WL_DEBUG_PRINT(".\r\n");
391
                                sensor_matrix_set_in_ring(sensorMatrix, i, 0);
392
                        }
393

    
394
                        if (i == wl_get_xbee_id() && ringState == MEMBER)
395
                        {
396
                                ringState = NONMEMBER;
397
                                wl_token_ring_join();
398
                                
399
                                WL_DEBUG_PRINT("We have been removed from the ring ");
400
                                WL_DEBUG_PRINT("and are rejoining.\r\n");
401
                        }
402
                        
403
                        //the person who accepted us is dead... let's ask again
404
                        if (i == acceptor)
405
                        {
406
                                sensor_matrix_set_in_ring(sensorMatrix,
407
                                                wl_get_xbee_id(), 1);
408
                                ringState = NONMEMBER;
409
                                acceptor = -1;
410
                                wl_token_ring_join();
411
                        }
412
                }
413
        }
414

    
415
        wl_token_next_robot = nextRobot;
416
        
417
        deathDelay = get_token_distance(wl_get_xbee_id(), nextRobot) * DEATH_DELAY;
418
        
419
        //we have the token
420
        if (wl_token_next_robot == wl_get_xbee_id())
421
                wl_token_get_token();
422
}
423

    
424
/**
425
 * Gets the distance in the token ring between two robots.
426
 *
427
 * @param robot1 the first robot
428
 * @param robot2 the second robot
429
 *
430
 * @return the number of passes before the token is expected
431
 * to reach robot2 from robot1
432
 **/
433
int get_token_distance(int robot1, int robot2)
434
{
435
        int curr = robot1 + 1;
436
        int count = 1;
437
        while (1)
438
        {
439
                if (curr == sensor_matrix_get_size(sensorMatrix))
440
                        curr = 0;
441
                if (curr == robot2)
442
                        break;
443
                if (sensor_matrix_get_in_ring(sensorMatrix, curr))
444
                        count++;
445
                curr++;
446
        }
447
        return count;
448
}
449

    
450
/**
451
 * Passes the token to the next robot in the token ring.
452
 **/
453
void wl_token_pass_token()
454
{
455
        char nextRobot;
456
        int i = wl_get_xbee_id() + 1;
457
        if (accepted == -1)
458
        {
459
                while (1)
460
                {
461
                        if (i == sensor_matrix_get_size(sensorMatrix))
462
                                i = 0;
463
                        if (sensor_matrix_get_in_ring(sensorMatrix, i))
464
                        {
465
                                nextRobot = (char)i;
466
                                break;
467
                        }
468
                        i++;
469
                }
470
        }
471
        else
472
        {
473
                WL_DEBUG_PRINT("Accepting new robot, sending it the token.\r\n");
474
                //add a new robot to the token ring
475
                sensor_matrix_set_in_ring(sensorMatrix, accepted, 1);
476
                nextRobot = accepted;
477
                accepted = -1;
478
        }
479

    
480
        //we don't include ourself
481
        int packetSize = 1 + 2 * (sensor_matrix_get_joined(sensorMatrix) - 1);
482
        char* buf = (char*)malloc(packetSize * sizeof(char));
483
        if (!buf)
484
        {
485
                WL_DEBUG_PRINT_INT(packetSize);
486
                WL_DEBUG_PRINT("Out of memory - pass token.\r\n");
487
                return;
488
        }
489
        buf[0] = nextRobot;
490

    
491
        int j = 0;
492
        for (i = 0; i < sensor_matrix_get_size(sensorMatrix); i++)
493
                if (sensor_matrix_get_in_ring(sensorMatrix, i) && i != wl_get_xbee_id())
494
                {
495
                        buf[2*j + 1] = i;
496
                        buf[2*j + 2] = sensor_matrix_get_reading(sensorMatrix, wl_get_xbee_id(), i);
497
                        j++;
498
                }
499
        
500
        WL_DEBUG_PRINT("Passing the token to robot ");
501
        WL_DEBUG_PRINT_INT(buf[0]);
502
        WL_DEBUG_PRINT(".\r\n");
503
        wl_send_global_packet(WL_TOKEN_RING_GROUP, WL_TOKEN_PASS,
504
                buf, packetSize, 3);
505

    
506
        wl_token_next_robot = nextRobot;
507
        deathDelay = DEATH_DELAY;
508
        free(buf);
509
}
510

    
511
/**
512
 * Called when a packet is received stating that another robot has turned
513
 * its BOM on. Our BOM is then read, and the data is added to the sensor
514
 * matrix.
515
 *
516
 * @param source the robot whose BOM is on
517
 **/
518
void wl_token_bom_on_receive(int source)
519
{
520
        WL_DEBUG_PRINT("Robot ");
521
        WL_DEBUG_PRINT_INT(source);
522
        WL_DEBUG_PRINT(" has flashed its bom.\r\n");
523

    
524
        //make sure we don't declare the robot dead if it's
525
        //flashing its BOM
526
        if (source == wl_token_next_robot)
527
                deathDelay = DEATH_DELAY;
528
        sensor_matrix_set_reading(sensorMatrix, wl_get_xbee_id(), 
529
                source, get_max_bom_function());
530
}
531

    
532
/**
533
 * This method is called when we receive the token. Upon receiving
534
 * the token, we must send a BOM_ON packet, flash the BOM, and send
535
 * the token to the next robot.
536
 * 
537
 * If there is a pending request for the token, this is processed first.
538
 **/
539
void wl_token_get_token()
540
{
541
        WL_DEBUG_PRINT("We have the token.\r\n");
542
        if (ringState == ACCEPTED)
543
        {
544
                sensor_matrix_set_in_ring(sensorMatrix,
545
                        wl_get_xbee_id(), 1);
546
                WL_DEBUG_PRINT("Now a member of the token ring.\r\n");
547
                ringState = MEMBER;
548
        }
549

    
550
        if (ringState == LEAVING || ringState == NONMEMBER)
551
        {
552
                sensor_matrix_set_in_ring(sensorMatrix, wl_get_xbee_id(), 0);
553
                if (ringState == NONMEMBER)
554
                {
555
                        WL_DEBUG_PRINT("We should have left the token ring, but didn't.\r\n");
556
                }
557
                return;
558
        }
559
        
560
        //check for interruption requests
561
        if (queue_size(interrupting) > 0)
562
        {
563
                char buf[1];
564
                buf[0] = (char)(int)queue_remove(interrupting);
565
                
566
                //in case this robot has requested multiple times
567
                queue_remove_all(interrupting, (void*)(int)buf[0]);
568

    
569
                wl_send_global_packet(WL_TOKEN_RING_GROUP, WL_TOKEN_INTERRUPT_PASS,
570
                        buf, 1, 0);
571

    
572
                deathDelay = DEATH_DELAY;
573
                wl_token_next_robot = buf[0];
574
                return;
575
        }
576

    
577
        WL_DEBUG_PRINT("Our BOM has been flashed.\r\n");
578
        wl_send_global_packet(WL_TOKEN_RING_GROUP, WL_TOKEN_BOM_ON,
579
                NULL, 0, 0);
580

    
581
        bom_on_function();
582
        #ifdef ROBOT
583
        delay_ms(BOM_DELAY);
584
        #endif
585
        bom_off_function();
586
        
587
        if (!sensor_matrix_get_in_ring(sensorMatrix, wl_get_xbee_id()))
588
        {
589
                WL_DEBUG_PRINT("Removed from sensor matrix while flashing BOM.\r\n");
590
                return;
591
        }
592
        
593
        wl_token_pass_token();
594
}
595

    
596
/**
597
 * Called when a request to join the token ring is received.
598
 * If we are the robot preceding the requester in the ring,
599
 * we respond with a JOIN_ACCEPT packet and pass the token to
600
 * this robot when we receive the token.
601
 *
602
 * @param source the robot who requested to join
603
 **/
604
void wl_token_join_receive(int source)
605
{
606
        WL_DEBUG_PRINT("Received joining request from robot ");
607
        WL_DEBUG_PRINT_INT(source);
608
        WL_DEBUG_PRINT(".\r\n");
609

    
610
        //we cannot accept the request if we are not a member
611
        if (ringState != MEMBER)
612
                return;
613
        //if they didn't get our response, see if we should respond again
614
        if (accepted == source)
615
                accepted = -1;
616
        //we can only accept one request at a time
617
        if (accepted != -1)
618
                return;
619
        
620
        //check if we are the preceding robot in the token ring
621
        int i = source - 1;
622
        while (1)
623
        {
624
                if (i < 0)
625
                        i = sensor_matrix_get_size(sensorMatrix) - 1;
626
                //we must send a join acceptance
627
                if (i == wl_get_xbee_id())
628
                        break;
629

    
630
                //another robot will handle it
631
                if (sensor_matrix_get_in_ring(sensorMatrix, i))
632
                        return;
633
                i--;
634
        }
635

    
636
        accepted = source;
637
        wl_send_robot_to_robot_global_packet(WL_TOKEN_RING_GROUP, WL_TOKEN_JOIN_ACCEPT,
638
                NULL, 0, source, TOKEN_JOIN_ACCEPT_FRAME);
639
        
640
        WL_DEBUG_PRINT("Accepting robot ");
641
        WL_DEBUG_PRINT_INT(source);
642
        WL_DEBUG_PRINT(" into the token ring.\r\n");
643

    
644
        joinDelay = -1;
645
        
646
        // the token ring has not started yet
647
        if (sensor_matrix_get_joined(sensorMatrix) == 1)
648
                wl_token_pass_token();
649
}
650

    
651
/**
652
 * Called when we receive a JOIN_ACCEPT packet in attempting to join
653
 * the token ring.
654
 * Our attempt to join the ring is stopped, and we wait for the token.
655
 *
656
 * @param source the robot who accepted us
657
 **/
658
void wl_token_join_accept_receive(int source)
659
{
660
        WL_DEBUG_PRINT("Accepted into the token ring by robot ");
661
        WL_DEBUG_PRINT_INT(source);
662
        WL_DEBUG_PRINT(".\r\n");
663
        joinDelay = -1;
664
        ringState = ACCEPTED;
665
        acceptor = source;
666

    
667
        //add ourselves to the token ring
668
        sensor_matrix_set_in_ring(sensorMatrix, wl_get_xbee_id(), 1);
669
}
670

    
671
/**
672
 * Called when we receive a packet passing the token and interrupting
673
 * the token ring.
674
 * If the token has been passed to us, we flash our BOM
675
 * and pass it back.
676
 *
677
 * @param source the robot who sent the interrupt packet
678
 * @param robot the robot the token has been passed to
679
 **/
680
void wl_token_interrupt_pass_receive(int source, int robot)
681
{
682
        if (wl_get_xbee_id() != robot)
683
        {
684
                queue_remove_all(interrupting, (void*)robot);
685
                wl_token_next_robot = robot;
686
                deathDelay = DEATH_DELAY + rand() / (RAND_MAX / (2 * DEATH_DELAY));
687
                return;
688
        }
689
        wl_send_global_packet(WL_TOKEN_RING_GROUP, WL_TOKEN_BOM_ON,
690
                NULL, 0, 0);
691
        
692
        bom_on_function();
693
        #ifdef ROBOT
694
        delay_ms(BOM_DELAY);
695
        #endif
696
        bom_off_function();
697

    
698
        //we don't include ourself, only if we are in the ring
699
        int packetSize = 1 + 2 * (sensor_matrix_get_joined(sensorMatrix) - 1);
700
        if (!sensor_matrix_get_in_ring(sensorMatrix, wl_get_xbee_id()))
701
                packetSize += 2;
702
        char* buf = (char*)malloc(packetSize * sizeof(char));
703
        if (!buf)
704
        {
705
                WL_DEBUG_PRINT("Out of memory - pass_receive.\r\n");
706
                return;
707
        }
708
        
709
        //return the token to where we got it from
710
        buf[0] = source;
711

    
712
        int i = 0, j = 0;
713
        for (i = 0; i < sensor_matrix_get_size(sensorMatrix); i++)
714
                if (sensor_matrix_get_in_ring(sensorMatrix, i) && i != wl_get_xbee_id())
715
                {
716
                        buf[2*j + 1] = i;
717
                        buf[2*j + 2] = sensor_matrix_get_reading(sensorMatrix, wl_get_xbee_id(), i);
718
                        j++;
719
                }
720
        
721
        wl_send_global_packet(WL_TOKEN_RING_GROUP, WL_TOKEN_PASS,
722
                buf, packetSize, 0);
723

    
724
        wl_token_next_robot = source;
725
        deathDelay = DEATH_DELAY;
726
        free(buf);
727
}
728

    
729
/**
730
 * Returns the number of robots in the token ring.
731
 *
732
 * @return the number of robots in the token ring
733
 **/
734
int wl_token_get_robots_in_ring(void)
735
{
736
        return sensor_matrix_get_joined(sensorMatrix);
737
}
738

    
739
/**
740
 * Returns true if the specified robot is in the token ring, false
741
 * otherwise.
742
 *
743
 * @param robot the robot to check for whether it is in the token ring
744
 * @return nonzero if the robot is in the token ring, zero otherwise
745
 **/
746
int wl_token_is_robot_in_ring(int robot)
747
{
748
        return sensor_matrix_get_in_ring(sensorMatrix, robot);
749
}
750

    
751
/**
752
 * Begins iterating through the robots in the token ring.
753
 *
754
 * @see wl_token_iterator_has_next, wl_token_iterator_next
755
 **/
756
void wl_token_iterator_begin(void)
757
{
758
        int i = 0;
759
        iteratorCount = 0;
760
        while (!sensor_matrix_get_in_ring(sensorMatrix, i) &&
761
                        i < sensor_matrix_get_size(sensorMatrix))
762
                i++;
763
        if (i == sensor_matrix_get_size(sensorMatrix))
764
                i = -1;
765
        iteratorCount = i;
766
}
767

    
768
/**
769
 * Returns true if there are more robots in the token ring
770
 * to iterate through, and false otherwise.
771
 *
772
 * @return nonzero if there are more robots to iterate through,
773
 * zero otherwise
774
 *
775
 * @see wl_token_iterator_begin, wl_token_iterator_next
776
 **/
777
int wl_token_iterator_has_next(void)
778
{
779
        return iteratorCount != -1;
780
}
781

    
782
/**
783
 * Returns the next robot ID in the token ring.
784
 *
785
 * @return the next robot ID in the token ring, or -1 if none exists
786
 *
787
 * @see wl_token_iterator_begin, wl_token_iterator_has_next
788
 **/
789
int wl_token_iterator_next(void)
790
{
791
        int result = iteratorCount;
792
        if (result < 0)
793
                return result;
794

    
795
        iteratorCount++;
796
        while (!sensor_matrix_get_in_ring(sensorMatrix, iteratorCount) &&
797
                iteratorCount < sensor_matrix_get_size(sensorMatrix))
798
                iteratorCount++;
799
        if (iteratorCount == sensor_matrix_get_size(sensorMatrix))
800
                iteratorCount = -1;
801
        return result;
802
}
803

    
804
/**
805
 * Called when we receive a request to interrupt the token ring.
806
 * We add the robot to our list of interrupt requests,
807
 * and will send the token to this robot when we next receive the
808
 * token, unless someone else does so first.
809
 *
810
 * @param source the robot requesting interruption
811
 * @param robt the robot requested to interrupt the token ring
812
 **/
813
void wl_token_interrupt_request_receive(int source, int robot)
814
{
815
        queue_add(interrupting, (void*)robot);
816
}
817

    
818
int wl_token_get_num_robots(void){
819
  return sensor_matrix_get_joined(sensorMatrix);
820
}
821

    
822
int wl_token_get_matrix_size(void){
823
  return sensor_matrix_get_size(sensorMatrix);
824
}