Project

General

Profile

Statistics
| Revision:

root / trunk / code / projects / libwireless / lib / xbee.c @ 203

History | View | Annotate | Download (16.1 KB)

1 17 bcoltin
#include "xbee.h"
2
#include "wl_defs.h"
3
4
#ifndef ROBOT
5
6
#include <fcntl.h>
7
#include <unistd.h>
8
#include <pthread.h>
9
#include <errno.h>
10
11
#else
12
13
#include <serial.h>
14
#include <avr/interrupt.h>
15
16
#endif
17
18
#include <stdio.h>
19
#include <stdlib.h>
20
#include <string.h>
21
22
#include <queue.h>
23
24
#define XBEE_FRAME_START 0x7E
25
26
/*Frame Types*/
27
#define XBEE_FRAME_STATUS 0x8A
28
#define XBEE_FRAME_AT_COMMAND 0x08
29
#define XBEE_FRAME_AT_COMMAND_RESPONSE 0x88
30
#define XBEE_FRAME_TX_REQUEST_64 0x00
31
#define XBEE_FRAME_TX_REQUEST_16 0x01
32
#define XBEE_FRAME_TX_STATUS XBEE_TX_STATUS
33
#define XBEE_FRAME_RX_64 0x80
34
#define XBEE_FRAME_RX_16 XBEE_RX
35
36
/*Internal Function Prototypes*/
37
38
/*I/O Functions*/
39
void xbee_send(char* buf, int size);
40
void xbee_send_string(char* c);
41
42
#ifndef ROBOT
43
void xbee_read(char* buf, int size);
44
#endif
45
46
/*Command Mode Functions
47
 * Called during initialization.
48
 */
49
void xbee_enter_command_mode(void);
50
void xbee_exit_command_mode(void);
51
void xbee_enter_api_mode(void);
52
void xbee_wait_for_string(char* s, int len);
53
void xbee_wait_for_ok(void);
54
55
/*API Mode Functions*/
56
57
int xbee_handle_packet(char* packet, int len);
58
void xbee_handle_at_command_response(char* command, char result,
59
        char* extra, int extraLen);
60
void xbee_handle_status(char status);
61
int xbee_verify_checksum(char* packet, int len);
62
char xbee_compute_checksum(char* packet, int len);
63
void xbee_send_frame(char* buf, int len);
64
void xbee_send_read_at_command(char* command);
65
void xbee_send_modify_at_command(char* command, char* value);
66
67
/*Global Variables*/
68
69
#ifndef ROBOT
70 203 justin
char* xbee_com_port;
71 17 bcoltin
int xbee_stream;
72
pthread_t* xbee_listen_thread;
73
#endif
74
75
Queue* xbee_queue;
76
77
//used to store packets as they are read
78
char xbee_buf[128];
79
int currentBufPos = 0;
80
81
//XBee status
82
unsigned int xbee_panID = XBEE_PAN_DEFAULT;
83
unsigned int xbee_pending_panID = XBEE_PAN_DEFAULT;
84 60 bcoltin
int xbee_channel = XBEE_CHANNEL_DEFAULT;
85
int xbee_pending_channel = XBEE_CHANNEL_DEFAULT;
86 17 bcoltin
unsigned int xbee_address = 0;
87
88
/*Function Implementations*/
89
90
#ifdef ROBOT
91
92
/**
93
 * Interrupt for the robot. Adds bytes received from the xbee
94
 * to the queue.
95
 **/
96 86 bcoltin
#ifndef FIREFLY
97 17 bcoltin
ISR(USART1_RX_vect)
98
{
99
        char c = UDR1;
100
        queue_add(xbee_queue, (void*)(int)c);
101
}
102 86 bcoltin
#else
103
SIGNAL(SIG_USART0_RECV)
104
{
105
        char c = UDR0;
106
        queue_add(xbee_queue, (void*)(int)c);
107
}
108
#endif
109 17 bcoltin
110
#else
111
112
/**
113
 * Thread that listens to the xbee.
114
 **/
115
void* listen_to_xbee(void* x)
116
{
117
        char c;
118
        while (1)
119
        {
120
                xbee_read(&c, 1);
121
                queue_add(xbee_queue, (void*)(int)c);
122
        }
123
        return 0;
124
}
125
126
#endif
127
128
/**
129
 * Initializes the XBee library so that other functions may be used.
130
 *
131
 * @param pan_id the PAN to join initially. Use XBEE_PAN_DEFAULT
132
 * to leave the PAN as it is initially.
133
 **/
134 60 bcoltin
void xbee_lib_init(void)
135 17 bcoltin
{
136
        xbee_queue = queue_create();
137
138
        #ifdef ROBOT
139
140
        //enable the receiving interrupt
141 86 bcoltin
        #ifdef FIREFLY
142
        UCSR0B |= _BV(RXCIE) | _BV(RXEN);
143
        #else
144 17 bcoltin
        UCSR1B |= _BV(RXCIE);
145 86 bcoltin
        #endif
146 17 bcoltin
        sei();
147
        #else
148 203 justin
        xbee_stream = open(xbee_com_port, O_RDWR);
149 17 bcoltin
        if (xbee_stream == -1 || lockf(xbee_stream, F_TEST, 0) != 0)
150 113 bcoltin
                xbee_stream = open(XBEE_PORT2, O_RDWR);
151 17 bcoltin
        if (xbee_stream == -1 || lockf(xbee_stream, F_TEST, 0) != 0)
152
        {
153 203 justin
                printf("Failed to open connection to XBee on port %s\r\n",xbee_com_port);
154 17 bcoltin
                exit(0);
155
        }
156
        lockf(xbee_stream, F_LOCK, 0);
157
158
        xbee_listen_thread =
159
                (pthread_t*)malloc(sizeof(pthread_t));
160
161
        int ret = pthread_create(xbee_listen_thread, NULL,
162
                listen_to_xbee, NULL);
163
        if (ret)
164
        {
165
                printf("Failed to create listener thread.\r\n");
166
                exit(0);
167
        }
168
        #endif
169
        xbee_enter_command_mode();
170
        xbee_enter_api_mode();
171
        xbee_exit_command_mode();
172
        xbee_send_read_at_command("MY");
173
174
        //wait to return until the address is set
175
        while (xbee_address == 0) xbee_get_packet(NULL);
176
}
177
178
/**
179
 * Call when finished using the XBee library. This releases
180
 * all sued resources.
181
 **/
182
void xbee_terminate()
183
{
184
        #ifndef ROBOT
185
        pthread_cancel(*xbee_listen_thread);
186
        free(xbee_listen_thread);
187
        lockf(xbee_stream, F_ULOCK, 0);
188
        close(xbee_stream);
189
        #endif
190
        queue_destroy(xbee_queue);
191
}
192
193
/**
194
 * Send a buffer buf of size bytes to the XBee.
195
 *
196
 * @param buf the buffer of data to send
197
 * @param size the number of bytes to send
198
 **/
199
void xbee_send(char* buf, int size)
200
{
201
        #ifdef ROBOT
202
        int i;
203
        for (i = 0; i < size; i++)
204
                xbee_putc(buf[i]);
205
        #else
206
        int ret = write(xbee_stream, buf, size);
207
        //success
208
        if (ret == size)
209
                return;
210
        if (ret == -1)
211
        {
212
                //interrupted by system signal, probably timer interrupt.
213
                //just try again
214
                if (errno == 4)
215
                {
216
                        xbee_send(buf, size);
217
                        return;
218
                }
219
                printf("Failed to write to xbee, error %i.\r\n", errno);
220
                return;
221
        }
222
223
        //write was interrupted after writing ret bytes
224
        xbee_send(buf + ret, size - ret);
225
        #endif
226
}
227
228
/**
229
 * Sends a string to the XBee.
230
 *
231
 * @param c the string to send to the XBEE
232
 **/
233
void xbee_send_string(char* c)
234
{
235
        xbee_send(c, strlen(c));
236
}
237
238
#ifndef ROBOT
239
void xbee_read(char* buf, int size)
240
{
241
        if (read(xbee_stream, buf, size) == -1)
242
                printf("Failed to read from xbee.\r\n");
243
}
244
#endif
245
246
/**
247
 * Enter into command mode.
248
 **/
249
void xbee_enter_command_mode()
250
{
251
        xbee_send_string("+++");
252
        xbee_wait_for_ok();
253
}
254
255
/**
256
 * Exit from command mode.
257
 **/
258
void xbee_exit_command_mode()
259
{
260
        xbee_send_string("ATCN\r");
261
        xbee_wait_for_ok();
262
}
263
264
/**
265
 * Enter API mode.
266
 **/
267
void xbee_enter_api_mode()
268
{
269
        xbee_send_string("ATAP 1\r");
270
        xbee_wait_for_ok();
271
}
272
273
/**
274
 * Wait until the string "OK\r" is received from the XBee.
275
 **/
276
void xbee_wait_for_ok()
277
{
278
        xbee_wait_for_string("OK\r", 3);
279
}
280
281
/**
282
 * Delay until the specified string is received from
283
 * the XBee. Discards all other XBee data.
284
 *
285
 * @param s the string to receive
286
 * @param len the length of the string
287
 **/
288
void xbee_wait_for_string(char* s, int len)
289
{
290
        char* curr = s;
291
        while (curr - s < len)
292
        {
293
                if (queue_is_empty(xbee_queue))
294
                        continue;
295
                char c = (char)(int)queue_remove(xbee_queue);
296
                if (c == *curr)
297
                        curr++;
298
                else
299
                        curr = s;
300
        }
301
}
302
303
/**
304
 * Verifies that the packets checksum is correct.
305
 * (If the checksum is correct, the sum of the bytes
306
 * is 0xFF.)
307
 *
308
 * @param packet the packet received. This includes the first
309
 * three bytes, which are header information from the XBee.
310
 *
311
 * @param len The length of the packet received from the XBee
312
 *
313
 * @return 0 if the checksum is incorrect, nonzero
314
 * otherwise
315
 **/
316
int xbee_verify_checksum(char* packet, int len)
317
{
318
        unsigned char sum = 0;
319
        int i;
320
        for (i = 3; i < len; i++)
321
                sum += (unsigned char)packet[i];
322
        return sum == 0xFF;
323
}
324
325
/**
326
 * Returns the checksum of the given packet.
327
 *
328
 * @param buf the data for the packet to send
329
 * @param len the length of the packet in bytes
330
 *
331
 * @return the checksum of the packet, which will
332
 * become the last byte sent in the packet
333
 **/
334
char xbee_compute_checksum(char* buf, int len)
335
{
336
        int i;
337
        unsigned char sum = 0;
338
        for (i = 0; i < len; i++)
339
                sum += (unsigned char)buf[i];
340
        return 0xFF - sum;
341
}
342
343
/**
344
 * Adds header information and checksum to the given
345
 * packet and sends it. Header information includes
346
 * XBEE_FRAME_START and the packet length, as two bytes.
347
 *
348
 * @param buf the packet data
349
 * @param len the size in bytes of the packet data
350
 *
351
 **/
352
void xbee_send_frame(char* buf, int len)
353
{
354
        char prefix[3];
355
        prefix[0] = XBEE_FRAME_START;
356
        prefix[1] = (len & 0xFF00) >> 8;
357
        prefix[2] = len & 0xFF;
358
        char checksum = xbee_compute_checksum(buf, len);
359
        xbee_send(prefix, 3);
360
        xbee_send(buf, len);
361
        xbee_send(&checksum, 1);
362
}
363
364
/**
365
 * Sends an AT command to read a parameter.
366
 *
367
 * @param command the AT command to send. For exmaple,
368
 * use ID to read the PAN ID and MY to return the XBee ID.
369
 * See the XBee reference guide for a complete listing.
370
 **/
371
void xbee_send_read_at_command(char* command)
372
{
373
        xbee_send_modify_at_command(command, NULL);
374
}
375
376
/**
377
 * Sends the given AT command.
378
 *
379
 * @param command the AT command to send (e.g., MY, ID)
380
 * @param value the value to pass as a parameter
381
 * (or NULL if there is no parameter)
382
 **/
383
void xbee_send_modify_at_command(char* command, char* value)
384
{
385
        char buf[16];
386
        int i;
387
388
        buf[0] = XBEE_FRAME_AT_COMMAND;
389
        buf[1] = 1;
390
        buf[2] = command[0];
391
        buf[3] = command[1];
392
        int valueLen = 0;
393
        if (value != NULL)
394
        {
395
                valueLen = strlen(value);
396
                if (valueLen > 8)
397
                {
398
                        WL_DEBUG_PRINT("AT Command too large.\r\n");
399
                        return;
400
                }
401
                for (i = 0; i < valueLen; i++)
402
                        buf[4 + i] = value[i];
403
        }
404
        xbee_send_frame(buf, 4 + valueLen);
405
}
406
407
/**
408
 * Send the specified packet.
409
 *
410
 * @param packet the packet data to send
411
 * @param len the number of bytes in the packet
412
 *
413
 * @param dest the ID of the XBee to send the packet to,
414
 * or XBEE_BROADCAST to send the message to all robots
415
 * in the PAN.
416
 *
417
 * @param options a combination of the flags
418
 * XBEE_OPTIONS_NONE, XBEE_OPTIONS_DISABLE_RESPONSE and
419
 * XBEE_OPTIONS_BROADCAST_ALL_PANS
420
 *
421
 * @param frame the frame number to associate this packet
422
 * with. This will be used to identify the response when
423
 * the XBee alerts us as to whether or not our message
424
 * was received.
425
 **/
426
void xbee_send_packet(char* packet, int len, int dest,
427
        char options, char frame)
428
{
429
        char buf[5];
430
        char prefix[3];
431
        int i;
432
        unsigned char checksum = 0;
433
434
        if (len > 100)
435
        {
436
                WL_DEBUG_PRINT("Packet is too large.\r\n");
437
                return;
438
        }
439
440
        //data for sending request
441
        buf[0] = XBEE_FRAME_TX_REQUEST_16;
442
        buf[1] = frame;
443
        buf[2] = (dest >> 8) & 0xFF;
444
        buf[3] = dest & 0xFF;
445
        buf[4] = options;
446
447
        //packet prefix, do this here so we don't need an extra buffer
448
        prefix[0] = XBEE_FRAME_START;
449
        prefix[1] = ((5 + len) & 0xFF00) >> 8;
450
        prefix[2] = (5 + len) & 0xFF;
451
452
        for (i = 0; i < 5; i++)
453
                checksum += (unsigned char)buf[i];
454
        for (i = 0; i < len; i++)
455
                checksum += (unsigned char)packet[i];
456
        checksum = 0xFF - checksum;
457
        xbee_send(prefix, 3);
458
        xbee_send(buf, 5);
459
        xbee_send(packet, len);
460
        xbee_send((char*)&checksum, 1);
461
}
462
463
/**
464
 * Reads a packet received from the XBee. This function
465
 * is non-blocking. The resulting packet is stored in dest.
466
 * Only returns transmission response packets and
467
 * received packets. The returned packet does not include
468
 * header information or the checksum. This method also
469
 * handles special packets dealt with by the XBee library,
470
 * and so should be called frequently while the XBee is in
471
 * use.<br><br>
472
 *
473
 * The first byte of the packet will be either
474
 * XBEE_TX_STATUS or XBEE_RX to indicated
475
 * a response to a sent message or a received message,
476
 * respectively.<br><br>
477
 *
478
 * For a status response packet:<br>
479
 * The first byte will be XBEE_TX_STATUS.<br>
480
 * The second byte will be the frame number.<br>
481
 * The third byte will be the result. 0 indicates success,
482
 * and nonzero indicates that an error ocurred in
483
 * transmitting the packet.<br><br>
484
 *
485
 * For a received packet:<br>
486
 * The first byte will be XBEE_RX.<br>
487
 * The second and third bytes will be the 16-bit
488
 * address of the packet's sender.<br>
489
 * The fourth byte is the signal strength.<br>
490
 * The fifth byte is 1 if the packet were sent to
491
 * a specific address, and 2 if it is a broadcast packet.<br><br>
492
 *
493
 * @param dest set to the packet data
494
 * @return the length of the packet, or -1 if no packet
495
 * is available
496
 **/
497
int xbee_get_packet(unsigned char* dest)
498
{
499
        //start reading a packet with XBEE_FRAME_START
500
        if (currentBufPos == 0)
501
        {
502
                do
503
                        if (queue_is_empty(xbee_queue))
504
                                return -1;
505
                while ((char)(int)queue_remove(xbee_queue) != XBEE_FRAME_START);
506
                xbee_buf[0] = XBEE_FRAME_START;
507
                currentBufPos++;
508
        }
509
510
        int len = -1;
511
        if (currentBufPos >= 3)
512
                len = (int)xbee_buf[2] + ((int)xbee_buf[1] << 8);
513
514
        while (len == -1 //packet length has not been read yet
515
                        || currentBufPos < len + 4)
516
        {
517
                if (currentBufPos == 3)
518 190 bcoltin
                {
519 17 bcoltin
                        len = (int)xbee_buf[2] + ((int)xbee_buf[1] << 8);
520 190 bcoltin
                        if (len > 120)
521
                        {
522
                                WL_DEBUG_PRINT("Packet too large. Probably error in XBee transmission.\n");
523
                                currentBufPos = 0;
524
                                return -1;
525
                        }
526
                }
527 17 bcoltin
                if (queue_is_empty(xbee_queue))
528
                        return -1;
529
                xbee_buf[currentBufPos++] = (char)(int)queue_remove(xbee_queue);
530
        }
531
532
        currentBufPos = 0;
533
534
        if (!xbee_verify_checksum(xbee_buf, len + 4))
535
        {
536
                WL_DEBUG_PRINT("XBee checksum failed.\r\n");
537
                return -1;
538
        }
539
540
        //we will take care of the packet
541
        if (xbee_handle_packet(xbee_buf + 3, len))
542
                return -1;
543
544
        if (dest == NULL)
545
                return -1;
546
547
        int i;
548
        for (i = 3; i < len + 3; i++)
549
                dest[i - 3] = xbee_buf[i];
550
        return len;
551
}
552
553
/**
554
 * Handles modem status packets.
555
 *
556
 * @param status the type of status packet received.
557
 **/
558
void xbee_handle_status(char status)
559
{
560
        switch (status)
561
        {
562
                case 0:
563
                        WL_DEBUG_PRINT("XBee hardware reset.\r\n");
564
                        break;
565
                case 1:
566
                        WL_DEBUG_PRINT("Watchdog timer reset.\r\n");
567
                        break;
568
                case 2:
569
                        WL_DEBUG_PRINT("Associated.\r\n");
570
                        break;
571
                case 3:
572
                        WL_DEBUG_PRINT("Disassociated.\r\n");
573
                        break;
574
                case 4:
575
                        WL_DEBUG_PRINT("Synchronization lost.\r\n");
576
                        break;
577
                case 5:
578
                        WL_DEBUG_PRINT("Coordinator realignment.\r\n");
579
                        break;
580
                case 6:
581
                        WL_DEBUG_PRINT("Coordinator started.\r\n");
582
                        break;
583
        }
584
}
585
586
/**
587
 * Handles AT command response packets.
588
 * @param command the two character AT command, e.g. MY or ID
589
 * @param result 0 for success, 1 for an error
590
 * @param extra the hex value of the requested register
591
 * @param extraLen the length in bytes of extra
592
 **/
593
void xbee_handle_at_command_response(char* command, char result,
594
        char* extra, int extraLen)
595
{
596
        if (result == 1)
597
        {
598
                WL_DEBUG_PRINT("Error with AT");
599
                WL_DEBUG_PRINT(command);
600
                WL_DEBUG_PRINT(" packet.\r\n");
601
        }
602
        WL_DEBUG_PRINT("AT");
603
        WL_DEBUG_PRINT(command);
604
        WL_DEBUG_PRINT(" command was successful.\r\n");
605
606
        if (command[0] == 'I' && command[1] == 'D')
607
        {
608
                xbee_panID = xbee_pending_panID;
609
                WL_DEBUG_PRINT("PAN ID set to ");
610
                WL_DEBUG_PRINT_INT(xbee_panID);
611
                WL_DEBUG_PRINT(".\r\n");
612
                return;
613
        }
614 60 bcoltin
615
        if (command[0] == 'C' && command[1] == 'H')
616
        {
617
                xbee_channel = xbee_pending_channel;
618
                WL_DEBUG_PRINT("Channel set to ");
619
                WL_DEBUG_PRINT_INT(xbee_channel);
620
                WL_DEBUG_PRINT(".\r\n");
621
                return;
622
        }
623 17 bcoltin
624
        if (command[0] == 'M' && command[1] == 'Y' && extraLen != 0)
625
        {
626
                xbee_address = 0;
627
                int i;
628
                for (i = 0; i < extraLen; i++)
629
                        xbee_address = (xbee_address << 8) + extra[i];
630
631
                WL_DEBUG_PRINT("XBee address is ");
632
                WL_DEBUG_PRINT_INT(xbee_address);
633
                WL_DEBUG_PRINT(".\r\n");
634
635
                if (xbee_address == 0)
636
                {
637
                        WL_DEBUG_PRINT("XBee 16-bit address must be set using ATMY.\r\n");
638
                        exit(0);
639
                }
640
        }
641
}
642
643
/**
644
 * Attempts to handle the packet if it is dealt with
645
 * by the library.
646
 * We will handle the following packet types:
647
 *    Modem Status
648
 *    AT Command Response
649
 *
650
 * @param packet the packet to handle
651
 * @param len the length of the packet
652
 *
653
 * @return 1 if we have handled the packet, 0 otherwise
654
 */
655
int xbee_handle_packet(char* packet, int len)
656
{
657
        char command[3] = {1, 2, 3};
658
        if (len <= 0) //this should not happend
659
        {
660
                WL_DEBUG_PRINT("Non-positive packet length.\r\n");
661
                return 0;
662
        }
663
664
        switch ((unsigned char)packet[0]) //packet type
665
        {
666
                case XBEE_FRAME_STATUS:
667
                        xbee_handle_status(packet[1]);
668
                        return 1;
669
                case XBEE_FRAME_AT_COMMAND_RESPONSE:
670
                        command[0] = packet[2];
671
                        command[1] = packet[3];
672
                        command[2] = 0;
673
                        xbee_handle_at_command_response(command,
674
                                packet[4], packet + 5, len - 5);
675
                        return 1;
676
        }
677
        return 0;
678
}
679
680
/**
681
 * Sets the personal area network id.
682
 *
683
 * @param id the new personal area network (PAN) id
684
 **/
685
void xbee_set_pan_id(int id)
686
{
687
        char s[3];
688
        s[0] = (id >> 8) & 0xFF;
689
        s[1] = id & 0xFF;
690
        s[2] = 0;
691
        xbee_pending_panID = id;
692
        xbee_send_modify_at_command("ID", s);
693
}
694
695
/**
696
 * Get the PAN ID for the XBee.
697
 *
698
 * @return the personal area network id, or
699
 * XBEE_PAN_DEFAULT if it has not yet been set.
700
 **/
701
unsigned int xbee_get_pan_id()
702
{
703
        return xbee_panID;
704
}
705
706
/**
707 60 bcoltin
 * Set the channel the XBee is using.
708
 *
709
 * @param channel the channel the XBee will not use,
710
 * between 0x0B and 0x1A
711
 *
712
 * @see xbee_get_channel
713
 **/
714
void xbee_set_channel(int channel)
715
{
716
        if (channel < 0x0B || channel > 0x1A)
717
        {
718
                WL_DEBUG_PRINT("Channel out of range.\r\n");
719
                return;
720
        }
721
        char s[3];
722
        s[0] = channel & 0xFF;
723
        s[1] = 0;
724
        xbee_pending_channel = channel;
725
        xbee_send_modify_at_command("CH", s);
726
}
727
728
/**
729
 * Returns the channel which the XBee is currently using.
730
 *
731
 * @return the channel the XBee is using
732
 *
733
 * @see xbee_set_channel
734
 **/
735
int xbee_get_channel(void)
736
{
737
        return xbee_channel;
738
}
739
740
/**
741 17 bcoltin
 * Get the 16-bit address of the XBee.
742
 * This is used to specify who to send messages to
743
 * and who messages are from.
744
 *
745
 * @return the 16-bit address of the XBee.
746
 **/
747
unsigned int xbee_get_address()
748
{
749
        return xbee_address;
750
}
751
752 203 justin
#ifndef ROBOT
753
void xbee_set_com_port(char* port){
754
  //printf("Port being passed is %s\n",port);
755
  xbee_com_port = malloc(strlen(port));
756
  strcpy(xbee_com_port,port);
757
}
758
#endif