root / trunk / code / projects / libwireless / lib / wireless.c @ 1458
History | View | Annotate | Download (12.5 KB)
| 1 | /**
|
|---|---|
| 2 | * Copyright (c) 2007 Colony Project |
| 3 | * |
| 4 | * Permission is hereby granted, free of charge, to any person |
| 5 | * obtaining a copy of this software and associated documentation |
| 6 | * files (the "Software"), to deal in the Software without |
| 7 | * restriction, including without limitation the rights to use, |
| 8 | * copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 9 | * copies of the Software, and to permit persons to whom the |
| 10 | * Software is furnished to do so, subject to the following |
| 11 | * conditions: |
| 12 | * |
| 13 | * The above copyright notice and this permission notice shall be |
| 14 | * included in all copies or substantial portions of the Software. |
| 15 | * |
| 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
| 18 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
| 20 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
| 21 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| 22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
| 23 | * OTHER DEALINGS IN THE SOFTWARE. |
| 24 | **/ |
| 25 | |
| 26 | /**
|
| 27 | * @file wireless.c |
| 28 | * @brief Wireless Library Implementation |
| 29 | * |
| 30 | * Implementation of the wireless library. |
| 31 | * |
| 32 | * @author Brian Coltin, Colony Project, CMU Robotics Club |
| 33 | **/ |
| 34 | |
| 35 | #include "wireless.h" |
| 36 | #include "xbee.h" |
| 37 | |
| 38 | #include <stddef.h> |
| 39 | |
| 40 | #ifdef WL_DEBUG
|
| 41 | #include <stdio.h> |
| 42 | #endif
|
| 43 | |
| 44 | #include "wl_defs.h" |
| 45 | |
| 46 | #ifndef ROBOT
|
| 47 | #include <sys/time.h> |
| 48 | #include <signal.h> |
| 49 | #else
|
| 50 | #include <time.h> |
| 51 | #include <bom.h> |
| 52 | #endif
|
| 53 | |
| 54 | /*Function Prototypes*/
|
| 55 | |
| 56 | static void wl_do_timeout(void); |
| 57 | |
| 58 | //Note: the actual frame sent has group as the first four bits and
|
| 59 | //frame as the last four.
|
| 60 | static int wl_send_packet(char group, char type, char* data, int len, int dest, char options, char frame); |
| 61 | |
| 62 | /*Data Members*/
|
| 63 | |
| 64 | //used to store incoming and outgoing packets
|
| 65 | //TODO: does this need to be 128? can it be smaller to save memory?
|
| 66 | //TODO: this shouldn't be hardcoded as 128. it should be a define.
|
| 67 | static unsigned char wl_buf[128]; |
| 68 | //1 if we have timed out since we last checked, 0 otherwise.
|
| 69 | static int wl_timeout = 0; |
| 70 | |
| 71 | static PacketGroupHandler* wl_packet_groups[WL_MAX_PACKET_GROUPS];
|
| 72 | |
| 73 | #ifndef ROBOT
|
| 74 | |
| 75 | //called when we time out, or receive interrupt
|
| 76 | static void sig_handler(int signo) |
| 77 | {
|
| 78 | switch (signo)
|
| 79 | {
|
| 80 | case SIGALRM: |
| 81 | wl_timeout = 1;
|
| 82 | break;
|
| 83 | case SIGINT: |
| 84 | wl_terminate(); |
| 85 | exit(1);
|
| 86 | break;
|
| 87 | } |
| 88 | return;
|
| 89 | } |
| 90 | #else
|
| 91 | |
| 92 | //called when the timer ticks
|
| 93 | static void timer_handler(void) |
| 94 | {
|
| 95 | wl_timeout = 1;
|
| 96 | } |
| 97 | |
| 98 | #endif
|
| 99 | |
| 100 | /**
|
| 101 | * Initializes the wireless library. Must be called before any |
| 102 | * other function. |
| 103 | * |
| 104 | * @param wl_port File descriptor for wireless port, or NULL for default. |
| 105 | **/ |
| 106 | int wl_init()
|
| 107 | {
|
| 108 | int i;
|
| 109 | //TODO: using memset here instead of this loop, *might* be less instructions and *might* reduce code size but not sure
|
| 110 | for (i = 0; i < WL_MAX_PACKET_GROUPS; i++) |
| 111 | wl_packet_groups[i] = NULL;
|
| 112 | |
| 113 | if (xbee_lib_init() == -1) { |
| 114 | return -1; |
| 115 | } |
| 116 | |
| 117 | //begin timeout timer
|
| 118 | #ifdef ROBOT
|
| 119 | #ifdef FIREFLY
|
| 120 | rtc_init(PRESCALE_DIV_256, 32, &timer_handler);
|
| 121 | #else
|
| 122 | //TODO: FIX THIS
|
| 123 | #ifdef BAYBOARD
|
| 124 | rtc_init(10 * HALF_SECOND, &timer_handler);
|
| 125 | #else
|
| 126 | rtc_init(HALF_SECOND, &timer_handler); |
| 127 | #endif
|
| 128 | #endif
|
| 129 | #else
|
| 130 | |
| 131 | //create our timer
|
| 132 | struct itimerval timer_val;
|
| 133 | struct timeval interval;
|
| 134 | interval.tv_sec = 0;
|
| 135 | interval.tv_usec = 500000;
|
| 136 | struct timeval first_time;
|
| 137 | first_time.tv_sec = 0;
|
| 138 | first_time.tv_usec = 500000;
|
| 139 | timer_val.it_interval = interval; |
| 140 | timer_val.it_value = first_time; |
| 141 | if(setitimer(ITIMER_REAL,&timer_val,NULL)==-1) |
| 142 | {
|
| 143 | WL_DEBUG_PRINT("Error creating a timer.\r\n");
|
| 144 | perror("Failure's cause");
|
| 145 | exit(1);
|
| 146 | } |
| 147 | |
| 148 | //create signal handler
|
| 149 | struct sigaction wl_sig_act;
|
| 150 | wl_sig_act.sa_handler = sig_handler; |
| 151 | wl_sig_act.sa_flags = 0;
|
| 152 | sigemptyset(&wl_sig_act.sa_mask); |
| 153 | sigaction(SIGALRM, &wl_sig_act, 0);
|
| 154 | sigaction(SIGINT, &wl_sig_act, 0);
|
| 155 | #endif
|
| 156 | |
| 157 | return 0; |
| 158 | } |
| 159 | |
| 160 | /**
|
| 161 | * Uninitializes the wireless library. |
| 162 | **/ |
| 163 | void wl_terminate()
|
| 164 | {
|
| 165 | int i;
|
| 166 | for (i = 0; i < WL_MAX_PACKET_GROUPS; i++) { |
| 167 | if (wl_packet_groups[i] != NULL && |
| 168 | wl_packet_groups[i]->unregister != NULL) {
|
| 169 | wl_packet_groups[i]->unregister(); |
| 170 | } |
| 171 | } |
| 172 | |
| 173 | xbee_terminate(); |
| 174 | } |
| 175 | |
| 176 | /**
|
| 177 | * Set the PAN for the XBee to join. |
| 178 | * |
| 179 | * @param pan the new PAN |
| 180 | * |
| 181 | * @see wl_get_pan |
| 182 | **/ |
| 183 | //TODO: this function is so simple, it *may* be beneficial to inline this function. testing of if
|
| 184 | // it reduces code size or not should be done to be sure.
|
| 185 | int wl_set_pan(int pan) |
| 186 | {
|
| 187 | return xbee_set_pan_id(pan);
|
| 188 | } |
| 189 | |
| 190 | /**
|
| 191 | * Get the PAN the XBee is currently part of. |
| 192 | * |
| 193 | * @return the PAN of the XBee |
| 194 | * |
| 195 | * @see wl_set_pan |
| 196 | **/ |
| 197 | //TODO: this function is so simple, it *may* be beneficial to inline this function. testing of if
|
| 198 | // it reduces code size or not should be done to be sure.
|
| 199 | int wl_get_pan(void) |
| 200 | {
|
| 201 | return xbee_get_pan_id();
|
| 202 | } |
| 203 | |
| 204 | /**
|
| 205 | * Set the channel the XBee is listening to. |
| 206 | * |
| 207 | * @param channel the new channel to join |
| 208 | * |
| 209 | * @see wl_get_channel |
| 210 | **/ |
| 211 | //TODO: this function is so simple, it *may* be beneficial to inline this function. testing of if
|
| 212 | // it reduces code size or not should be done to be sure.
|
| 213 | int wl_set_channel(int channel) |
| 214 | {
|
| 215 | return xbee_set_channel(channel);
|
| 216 | } |
| 217 | |
| 218 | /**
|
| 219 | * Get the channel the XBee is part of. |
| 220 | * |
| 221 | * @return the channel the XBee is part of |
| 222 | * |
| 223 | * @see wl_set_channel |
| 224 | **/ |
| 225 | //TODO: this function is so simple, it *may* be beneficial to inline this function. testing of if
|
| 226 | // it reduces code size or not should be done to be sure.
|
| 227 | int wl_get_channel(void) |
| 228 | {
|
| 229 | return xbee_get_channel();
|
| 230 | } |
| 231 | |
| 232 | /**
|
| 233 | * Returns the 16-bit address of the XBee module. |
| 234 | * |
| 235 | * @return the 16-bit address of the XBee module. |
| 236 | **/ |
| 237 | //TODO: this function is so simple, it *may* be beneficial to inline this function. testing of if
|
| 238 | // it reduces code size or not should be done to be sure.
|
| 239 | int wl_get_xbee_id()
|
| 240 | {
|
| 241 | return xbee_get_address();
|
| 242 | } |
| 243 | |
| 244 | /**
|
| 245 | * Send a packet to a specific XBee without specifying a PAN. |
| 246 | * |
| 247 | * @param group the packet group |
| 248 | * @param type the packet type |
| 249 | * @param data the packet data |
| 250 | * @param len the packet length in bytes |
| 251 | * @param dest the 16-bit address of the XBee to send the packet to |
| 252 | * @param frame the frame number to see with a TX_STATUS response |
| 253 | **/ |
| 254 | //TODO: this function is so simple, it *may* be beneficial to inline this function. testing of if
|
| 255 | // it reduces code size or not should be done to be sure.
|
| 256 | int wl_send_robot_to_robot_global_packet(char group, char type, char* data, int len, int dest, char frame) |
| 257 | {
|
| 258 | return wl_send_packet(group, type, data, len, dest, XBEE_OPTIONS_BROADCAST_ALL_PANS, frame);
|
| 259 | } |
| 260 | |
| 261 | /**
|
| 262 | * Send a packet to a specific XBee in the same PAN. |
| 263 | * |
| 264 | * @param group the packet group |
| 265 | * @param type the packet type |
| 266 | * @param data the packet data |
| 267 | * @param len the packet length in bytes |
| 268 | * @param dest the 16-bit address of the XBee to send the packet to |
| 269 | * @param frame the frame number to see with a TX_STATUS response |
| 270 | **/ |
| 271 | //TODO: this function is so simple, it *may* be beneficial to inline this function. testing of if
|
| 272 | // it reduces code size or not should be done to be sure.
|
| 273 | int wl_send_robot_to_robot_packet(char group, char type, char* data, int len, int dest, char frame) |
| 274 | {
|
| 275 | return wl_send_packet(group, type, data, len, dest, XBEE_OPTIONS_NONE, frame);
|
| 276 | } |
| 277 | |
| 278 | /**
|
| 279 | * Send a packet to all XBees in all PANs. |
| 280 | * |
| 281 | * @param group the packet group |
| 282 | * @param type the packet type |
| 283 | * @param data the packet data |
| 284 | * @param len the packet length in bytes |
| 285 | * @param frame the frame number to see with a TX_STATUS response |
| 286 | **/ |
| 287 | //TODO: this function is so simple, it *may* be beneficial to inline this function. testing of if
|
| 288 | // it reduces code size or not should be done to be sure.
|
| 289 | int wl_send_global_packet(char group, char type, char* data, int len, char frame) |
| 290 | {
|
| 291 | return wl_send_packet(group, type, data, len, XBEE_BROADCAST, XBEE_OPTIONS_BROADCAST_ALL_PANS, frame);
|
| 292 | } |
| 293 | |
| 294 | /**
|
| 295 | * Send a packet to all XBee's in the same PAN. |
| 296 | * |
| 297 | * @param group the packet group |
| 298 | * @param type the packet type |
| 299 | * @param data the packet data |
| 300 | * @param len the packet length in bytes |
| 301 | * @param frame the frame number to see with a TX_STATUS response |
| 302 | **/ |
| 303 | //TODO: this function is so simple, it *may* be beneficial to inline this function. testing of if
|
| 304 | // it reduces code size or not should be done to be sure.
|
| 305 | void wl_send_pan_packet(char group, char type, char* data, int len, char frame) |
| 306 | {
|
| 307 | wl_send_packet(group, type, data, len, XBEE_BROADCAST, |
| 308 | XBEE_OPTIONS_NONE, frame); |
| 309 | } |
| 310 | |
| 311 | /**
|
| 312 | * Send a packet. |
| 313 | * |
| 314 | * @param group the packet group |
| 315 | * @param type the packet type |
| 316 | * @param data the packet data |
| 317 | * @param len the packet length in bytes |
| 318 | * @param dest the destination of the packet |
| 319 | * @param options the options for sending the packet |
| 320 | * @param frame the frame number to see with a TX_STATUS response |
| 321 | **/ |
| 322 | int wl_send_packet(char group, char type, char* data, int len, int dest, char options, char frame) |
| 323 | {
|
| 324 | //TODO: does this need to be 128? can it be smaller to save memory?
|
| 325 | //TODO: this shouldn't be hardcoded as 128. it should be a define.
|
| 326 | char buf[128]; |
| 327 | int i;
|
| 328 | if (frame != 0) |
| 329 | frame = (frame & 0x0F) | ((group & 0x0F) << 4); |
| 330 | |
| 331 | buf[0] = group;
|
| 332 | buf[1] = type;
|
| 333 | for (i = 0; i < len; i++) |
| 334 | buf[2 + i] = data[i];
|
| 335 | |
| 336 | return xbee_send_packet(buf, len + 2, dest, options, frame); |
| 337 | } |
| 338 | |
| 339 | /**
|
| 340 | * Register a packet group with the wireless library. The event |
| 341 | * handlers in the packet group will be called whenever an |
| 342 | * event dealing with the packet group's group code occurs. |
| 343 | * |
| 344 | * @param h the PacketGroupHandler to register |
| 345 | **/ |
| 346 | void wl_register_packet_group(PacketGroupHandler* h)
|
| 347 | {
|
| 348 | if (h->groupCode >= WL_MAX_PACKET_GROUPS)
|
| 349 | {
|
| 350 | WL_DEBUG_PRINT("Packet group code too large.\r\n");
|
| 351 | return;
|
| 352 | } |
| 353 | if (wl_packet_groups[h->groupCode] != NULL) |
| 354 | {
|
| 355 | WL_DEBUG_PRINT("Packet group code already registered.\r\n");
|
| 356 | return;
|
| 357 | } |
| 358 | wl_packet_groups[h->groupCode] = h; |
| 359 | } |
| 360 | |
| 361 | /**
|
| 362 | * Unregister a packet group from the wireless library. |
| 363 | * |
| 364 | * @param h the packet group to remove |
| 365 | **/ |
| 366 | void wl_unregister_packet_group(PacketGroupHandler* h)
|
| 367 | {
|
| 368 | unsigned int groupCode = h->groupCode; |
| 369 | PacketGroupHandler* p = wl_packet_groups[groupCode]; |
| 370 | if (p != NULL && p->unregister != NULL) |
| 371 | p->unregister(); |
| 372 | wl_packet_groups[groupCode] = NULL;
|
| 373 | } |
| 374 | |
| 375 | /**
|
| 376 | * Called when the timer is triggered. This calls the timeout |
| 377 | * handlers of all the registered packet groups. |
| 378 | **/ |
| 379 | void wl_do_timeout()
|
| 380 | {
|
| 381 | int i;
|
| 382 | for (i = 0; i < WL_MAX_PACKET_GROUPS; i++) |
| 383 | if (wl_packet_groups[i] != NULL && |
| 384 | wl_packet_groups[i]->timeout_handler != NULL)
|
| 385 | wl_packet_groups[i]->timeout_handler(); |
| 386 | } |
| 387 | |
| 388 | /**
|
| 389 | * Performs wireless library functionality. This function must |
| 390 | * be called frequently for wireless to perform effectively. |
| 391 | * This function will call timeout handlers, as well as |
| 392 | * received packet and transmit status handlers. |
| 393 | **/ |
| 394 | void wl_do()
|
| 395 | {
|
| 396 | if (wl_timeout)
|
| 397 | {
|
| 398 | wl_do_timeout(); |
| 399 | wl_timeout = 0;
|
| 400 | } |
| 401 | |
| 402 | int len = xbee_get_packet(wl_buf);
|
| 403 | if (len < 0)//no packet received |
| 404 | return;
|
| 405 | |
| 406 | if (wl_buf[0] == XBEE_TX_STATUS) |
| 407 | {
|
| 408 | if (len != 3) |
| 409 | {
|
| 410 | WL_DEBUG_PRINT("Transmit Status packet should be of length 3.\r\n");
|
| 411 | return;
|
| 412 | } |
| 413 | |
| 414 | //the first four bits are the packet group
|
| 415 | //this only works with under 16 groups
|
| 416 | int group = (int)(wl_buf[1] >> 4); |
| 417 | int success = 0; |
| 418 | if (wl_buf[2] == 0) |
| 419 | {
|
| 420 | success = 1;
|
| 421 | } |
| 422 | else
|
| 423 | {
|
| 424 | WL_DEBUG_PRINT("No response received.\r\n");
|
| 425 | if (wl_buf[2] == 2) |
| 426 | {
|
| 427 | WL_DEBUG_PRINT("CCA Failure\r\n");
|
| 428 | } |
| 429 | if (wl_buf[2] == 3) |
| 430 | {
|
| 431 | WL_DEBUG_PRINT("Purged\r\n");
|
| 432 | } |
| 433 | } |
| 434 | |
| 435 | if (wl_packet_groups[group] != NULL && wl_packet_groups[group]->handle_response != NULL) |
| 436 | wl_packet_groups[group]->handle_response((int)wl_buf[1] & 0x0F, success); |
| 437 | } |
| 438 | else if (wl_buf[0] == XBEE_RX) |
| 439 | {
|
| 440 | //TODO: what does this 7 represent? It shouldn't be hardcoded. It should be set as a define
|
| 441 | if (len < 7) |
| 442 | {
|
| 443 | WL_DEBUG_PRINT("Packet is too small.\r\n");
|
| 444 | return;
|
| 445 | } |
| 446 | |
| 447 | int source = ((int)wl_buf[1] << 8) + ((int)wl_buf[2]); |
| 448 | |
| 449 | /*
|
| 450 | //unused for now |
| 451 | int signalStrength = wl_buf[3]; |
| 452 | //1 for Address broadcast, 2 for PAN broadcast |
| 453 | int options = wl_buf[4]; |
| 454 | */ |
| 455 | |
| 456 | //TODO: these indices, etc should be defined, not hardcoded
|
| 457 | int group = wl_buf[5]; |
| 458 | int type = wl_buf[6]; |
| 459 | int packetLen = len - 7; |
| 460 | |
| 461 | if (wl_packet_groups[group] != NULL && wl_packet_groups[group]->handle_receive != NULL) { |
| 462 | wl_packet_groups[group]->handle_receive(type, source, wl_buf + 7, packetLen);
|
| 463 | } |
| 464 | } |
| 465 | else
|
| 466 | {
|
| 467 | WL_DEBUG_PRINT("Unexpected packet received from XBee.\r\n");
|
| 468 | #ifdef WL_DEBUG
|
| 469 | #ifndef ROBOT
|
| 470 | printf("0x%2X\n", wl_buf[0]); |
| 471 | printf("%c%c%d\n", wl_buf[2], wl_buf[3], wl_buf[4]); |
| 472 | #endif
|
| 473 | #endif
|
| 474 | } |
| 475 | } |
| 476 | |
| 477 | |
| 478 | #ifndef ROBOT
|
| 479 | //TODO: this function is so simple, it *may* be beneficial to inline this function. testing of if
|
| 480 | // it reduces code size or not should be done to be sure.
|
| 481 | void wl_set_com_port(char* port) |
| 482 | {
|
| 483 | xbee_set_com_port(port); |
| 484 | } |
| 485 | #endif
|
| 486 |