Project

General

Profile

Statistics
| Revision:

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

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
                }
180
                
181
                // we may have been dropped from the ring when this is received
182
                if (ringState == MEMBER)
183
                        wl_token_pass_token();
184
        }
185

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

    
208
        if (deathDelay >= 0)
209
                deathDelay--;
210
        if (joinDelay >= 0)
211
                joinDelay--;
212
}
213

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
504
        wl_token_next_robot = nextRobot;
505
        deathDelay = DEATH_DELAY;
506
        free(buf);
507
}
508

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

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

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

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

    
567
                wl_send_global_packet(WL_TOKEN_RING_GROUP, WL_TOKEN_INTERRUPT_PASS,
568
                        buf, 1, 0);
569

    
570
                deathDelay = DEATH_DELAY;
571
                wl_token_next_robot = buf[0];
572
                return;
573
        }
574

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

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

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

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

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

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

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

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

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

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

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

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

    
722
        wl_token_next_robot = source;
723
        deathDelay = DEATH_DELAY;
724
        free(buf);
725
}
726

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

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

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

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

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

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

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

    
816
int wl_token_get_num_robots(void){
817
  return sensor_matrix_get_joined(sensorMatrix);
818
}
819

    
820
int wl_token_get_matrix_size(void){
821
  return sensor_matrix_get_size(sensorMatrix);
822
}