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