Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (20.7 KB)

1 340 bcoltin
/**
2
 * Copyright (c) 2007 Colony Project
3 668 bcoltin
 *
4 340 bcoltin
 * Permission is hereby granted, free of charge, to any person
5
 * obtaining a copy of this software and associated documentation
6
 * files (the "Software"), to deal in the Software without
7
 * restriction, including without limitation the rights to use,
8
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
9
 * copies of the Software, and to permit persons to whom the
10
 * Software is furnished to do so, subject to the following
11
 * conditions:
12 668 bcoltin
 *
13 340 bcoltin
 * The above copyright notice and this permission notice shall be
14
 * included in all copies or substantial portions of the Software.
15 668 bcoltin
 *
16 340 bcoltin
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
 * OTHER DEALINGS IN THE SOFTWARE.
24
 **/
25
26
/**
27
 * @file wl_token_ring.c
28
 * @brief Token Ring Implementation
29
 *
30
 * Implementation of the token ring packet group.
31
 *
32
 * @author Brian Coltin, Colony Project, CMU Robotics Club
33
 **/
34
35 17 bcoltin
#include <wl_token_ring.h>
36
37
#include <stdlib.h>
38
#include <stdio.h>
39
40
#include <wl_defs.h>
41
#include <wireless.h>
42
#include <sensor_matrix.h>
43
44
#ifdef ROBOT
45 706 abuchan
        #ifndef FIREFLY
46
                #ifdef BAYBOARD
47
                        #include <lbom.h>
48
                #else
49
                        #include <bom.h>
50
                #endif
51
        #endif
52 17 bcoltin
#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 668 bcoltin
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 17 bcoltin
76
/*Helper Functions*/
77 668 bcoltin
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 17 bcoltin
81
/*Packet Handling Routines*/
82 668 bcoltin
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 17 bcoltin
87
/*Global Variables*/
88
89
//the sensor matrix
90 668 bcoltin
static SensorMatrix* sensorMatrix;
91 17 bcoltin
92
//the robot we are waiting to say it has received the token. -1 if unspecified
93 668 bcoltin
static int wl_token_next_robot = -1;
94 17 bcoltin
95
//true if the robot should be in the token ring, 0 otherwise
96 668 bcoltin
static int ringState = NONMEMBER;
97 17 bcoltin
//the id of the robot who accepted us into the token ring, only used in ACCEPTED state
98 668 bcoltin
static int acceptor = -1;
99 17 bcoltin
//id of the robot we are accepting
100 668 bcoltin
static int accepted = -1;
101 17 bcoltin
102
//the counter for when we assume a robot is dead
103 668 bcoltin
static int deathDelay = -1;
104 17 bcoltin
//the counter for joining, before we form our own token ring
105 668 bcoltin
static int joinDelay = -1;
106 17 bcoltin
107 52 bcoltin
//current robot to check in the iterator
108 668 bcoltin
static int iteratorCount = 0;
109 52 bcoltin
110 340 bcoltin
// the amount of time a robot has had its BOM on for
111 668 bcoltin
static int bom_on_count = 0;
112 340 bcoltin
113 668 bcoltin
static void do_nothing(void) {}
114
static int get_nothing(void) {return -1;}
115 86 bcoltin
116 17 bcoltin
#ifdef ROBOT
117 86 bcoltin
#ifndef FIREFLY
118 706 abuchan
#ifdef BAYBOARD
119 668 bcoltin
static void (*bom_on_function) (void) = bom_on;
120
static void (*bom_off_function) (void) = bom_off;
121 706 abuchan
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 668 bcoltin
static int (*get_max_bom_function) (void) = get_max_bom;
126 706 abuchan
#endif
127 17 bcoltin
#else
128 668 bcoltin
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 17 bcoltin
#endif
132 86 bcoltin
#else
133 668 bcoltin
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 86 bcoltin
#endif
137 17 bcoltin
138 668 bcoltin
static PacketGroupHandler wl_token_ring_handler =
139
        {WL_TOKEN_RING_GROUP, wl_token_ring_timeout_handler,
140 17 bcoltin
                wl_token_ring_response_handler, wl_token_ring_receive_handler,
141
                wl_token_ring_cleanup};
142
143
/**
144 668 bcoltin
 * 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 17 bcoltin
 * Initialize the token ring packet group and register it with the
173
 * wireless library. The robot will not join a token ring.
174
 **/
175 668 bcoltin
int wl_token_ring_register()
176 17 bcoltin
{
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 668 bcoltin
                return -1;
185 17 bcoltin
        }
186 668 bcoltin
187 17 bcoltin
        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 668 bcoltin
193
        return 0;
194 17 bcoltin
}
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 668 bcoltin
 * turned on or off. This could be used for things such as
207 17 bcoltin
 * 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 668 bcoltin
static void wl_token_ring_cleanup()
228 17 bcoltin
{
229
        sensor_matrix_destroy(sensorMatrix);
230
}
231
232
/**
233
 * Called approximately every quarter second by the wireless library.
234
 **/
235 668 bcoltin
static void wl_token_ring_timeout_handler()
236 17 bcoltin
{
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 340 bcoltin
                        wl_token_next_robot = -1;
249
                        deathDelay = DEATH_DELAY;
250 17 bcoltin
                }
251 668 bcoltin
252 43 bcoltin
                // we may have been dropped from the ring when this is received
253 668 bcoltin
                if (ringState == MEMBER) {
254 43 bcoltin
                        wl_token_pass_token();
255 668 bcoltin
                }
256 17 bcoltin
        }
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 668 bcoltin
        if (deathDelay >= 0) {
281 17 bcoltin
                deathDelay--;
282 668 bcoltin
        }
283
284
        if (joinDelay >= 0) {
285 17 bcoltin
                joinDelay--;
286 668 bcoltin
        }
287
288
        if (bom_on_count >= 0) {
289 340 bcoltin
                bom_on_count++;
290 668 bcoltin
        }
291 17 bcoltin
}
292
293
/**
294
 * Called when the XBee tells us if a packet we sent has been received.
295 668 bcoltin
 *
296 17 bcoltin
 * @param frame the frame number assigned when the packet was sent
297
 * @param received 1 if the packet was received, 0 otherwise
298
 **/
299 668 bcoltin
static void wl_token_ring_response_handler(int frame, int received)
300 17 bcoltin
{
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 668 bcoltin
static void wl_token_ring_receive_handler(char type, int source, unsigned char* packet, int length)
315 17 bcoltin
{
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 340 bcoltin
        if (wl_token_is_robot_in_ring(dest) &&
354 668 bcoltin
                        (source == wl_get_xbee_id() || wl_token_is_robot_in_ring(source))) {
355 340 bcoltin
                return sensor_matrix_get_reading(sensorMatrix, source, dest);
356 668 bcoltin
        }
357
358 340 bcoltin
        return -1;
359 17 bcoltin
}
360
361
/**
362
 * Returns the BOM reading we have for robot dest.
363 668 bcoltin
 *
364 17 bcoltin
 * @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 668 bcoltin
375 17 bcoltin
/**
376 668 bcoltin
 * 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)