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) |
||