Project

General

Profile

Statistics
| Revision:

root / branches / slam / code / projects / libwireless / lib / xbee.c @ 110

History | View | Annotate | Download (15.6 KB)

1
#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
int xbee_stream;
71
pthread_t* xbee_listen_thread;
72
#endif
73

    
74
Queue* xbee_queue;
75

    
76
//used to store packets as they are read
77
char xbee_buf[128];
78
int currentBufPos = 0;
79

    
80
//XBee status
81
unsigned int xbee_panID = XBEE_PAN_DEFAULT;
82
unsigned int xbee_pending_panID = XBEE_PAN_DEFAULT;
83
int xbee_channel = XBEE_CHANNEL_DEFAULT;
84
int xbee_pending_channel = XBEE_CHANNEL_DEFAULT;
85
unsigned int xbee_address = 0;
86

    
87
/*Function Implementations*/
88

    
89
#ifdef ROBOT
90

    
91
/**
92
 * Interrupt for the robot. Adds bytes received from the xbee
93
 * to the queue.
94
 **/
95
#ifndef FIREFLY
96
ISR(USART1_RX_vect)
97
{
98
        char c = UDR1;
99
        queue_add(xbee_queue, (void*)(int)c);
100
}
101
#else
102
SIGNAL(SIG_USART0_RECV)
103
{
104
        char c = UDR0;
105
        queue_add(xbee_queue, (void*)(int)c);
106
}
107
#endif
108

    
109
#else
110

    
111
/**
112
 * Thread that listens to the xbee.
113
 **/
114
void* listen_to_xbee(void* x)
115
{
116
        char c;
117
        while (1)
118
        {
119
                xbee_read(&c, 1);
120
                queue_add(xbee_queue, (void*)(int)c);
121
        }
122
        return 0;
123
}
124

    
125
#endif
126

    
127
/**
128
 * Initializes the XBee library so that other functions may be used.
129
 *
130
 * @param pan_id the PAN to join initially. Use XBEE_PAN_DEFAULT
131
 * to leave the PAN as it is initially.
132
 **/
133
void xbee_lib_init(void)
134
{
135
        xbee_queue = queue_create();
136
        
137
        #ifdef ROBOT
138

    
139
        //enable the receiving interrupt
140
        #ifdef FIREFLY
141
        UCSR0B |= _BV(RXCIE) | _BV(RXEN);
142
        #else
143
        UCSR1B |= _BV(RXCIE);
144
        #endif
145
        sei();
146
        #else
147
        xbee_stream = open(XBEE_PORT, O_RDWR);
148
        if (xbee_stream == -1 || lockf(xbee_stream, F_TEST, 0) != 0)
149
        {
150
                printf("Failed to open connection to XBee.\r\n");
151
                exit(0);
152
        }
153
        lockf(xbee_stream, F_LOCK, 0);
154
        
155
        xbee_listen_thread =
156
                (pthread_t*)malloc(sizeof(pthread_t));
157
        
158
        int ret = pthread_create(xbee_listen_thread, NULL, 
159
                listen_to_xbee, NULL);
160
        if (ret)
161
        {
162
                printf("Failed to create listener thread.\r\n");
163
                exit(0);
164
        }
165
        #endif
166
        xbee_enter_command_mode();
167
        xbee_enter_api_mode();
168
        xbee_exit_command_mode();
169
        xbee_send_read_at_command("MY");
170
        
171
        //wait to return until the address is set
172
        while (xbee_address == 0) xbee_get_packet(NULL);
173
}
174

    
175
/**
176
 * Call when finished using the XBee library. This releases
177
 * all sued resources.
178
 **/
179
void xbee_terminate()
180
{
181
        #ifndef ROBOT
182
        pthread_cancel(*xbee_listen_thread);
183
        free(xbee_listen_thread);
184
        lockf(xbee_stream, F_ULOCK, 0);
185
        close(xbee_stream);
186
        #endif
187
        queue_destroy(xbee_queue);
188
}
189

    
190
/**
191
 * Send a buffer buf of size bytes to the XBee.
192
 * 
193
 * @param buf the buffer of data to send
194
 * @param size the number of bytes to send
195
 **/
196
void xbee_send(char* buf, int size)
197
{
198
        #ifdef ROBOT
199
        int i;
200
        for (i = 0; i < size; i++)
201
                xbee_putc(buf[i]);
202
        #else
203
        int ret = write(xbee_stream, buf, size);
204
        //success
205
        if (ret == size)
206
                return;
207
        if (ret == -1)
208
        {
209
                //interrupted by system signal, probably timer interrupt.
210
                //just try again
211
                if (errno == 4)
212
                {
213
                        xbee_send(buf, size);
214
                        return;
215
                }
216
                printf("Failed to write to xbee, error %i.\r\n", errno);
217
                return;
218
        }
219

    
220
        //write was interrupted after writing ret bytes
221
        xbee_send(buf + ret, size - ret);
222
        #endif
223
}
224

    
225
/**
226
 * Sends a string to the XBee.
227
 *
228
 * @param c the string to send to the XBEE
229
 **/
230
void xbee_send_string(char* c)
231
{
232
        xbee_send(c, strlen(c));
233
}
234

    
235
#ifndef ROBOT
236
void xbee_read(char* buf, int size)
237
{
238
        if (read(xbee_stream, buf, size) == -1)
239
                printf("Failed to read from xbee.\r\n");
240
}
241
#endif
242

    
243
/**
244
 * Enter into command mode.
245
 **/
246
void xbee_enter_command_mode()
247
{
248
        xbee_send_string("+++");
249
        xbee_wait_for_ok();
250
}
251

    
252
/**
253
 * Exit from command mode.
254
 **/
255
void xbee_exit_command_mode()
256
{
257
        xbee_send_string("ATCN\r");
258
        xbee_wait_for_ok();
259
}
260

    
261
/**
262
 * Enter API mode.
263
 **/
264
void xbee_enter_api_mode()
265
{
266
        xbee_send_string("ATAP 1\r");
267
        xbee_wait_for_ok();
268
}
269

    
270
/**
271
 * Wait until the string "OK\r" is received from the XBee.
272
 **/
273
void xbee_wait_for_ok()
274
{
275
        xbee_wait_for_string("OK\r", 3);
276
}
277

    
278
/**
279
 * Delay until the specified string is received from
280
 * the XBee. Discards all other XBee data.
281
 *
282
 * @param s the string to receive
283
 * @param len the length of the string
284
 **/
285
void xbee_wait_for_string(char* s, int len)
286
{
287
        char* curr = s;
288
        while (curr - s < len)
289
        {
290
                if (queue_is_empty(xbee_queue))
291
                        continue;
292
                char c = (char)(int)queue_remove(xbee_queue);
293
                if (c == *curr)
294
                        curr++;
295
                else
296
                        curr = s;
297
        }
298
}
299

    
300
/**
301
 * Verifies that the packets checksum is correct.
302
 * (If the checksum is correct, the sum of the bytes
303
 * is 0xFF.)
304
 *
305
 * @param packet the packet received. This includes the first
306
 * three bytes, which are header information from the XBee.
307
 *
308
 * @param len The length of the packet received from the XBee
309
 *
310
 * @return 0 if the checksum is incorrect, nonzero
311
 * otherwise
312
 **/
313
int xbee_verify_checksum(char* packet, int len)
314
{
315
        unsigned char sum = 0;
316
        int i;
317
        for (i = 3; i < len; i++)
318
                sum += (unsigned char)packet[i];
319
        return sum == 0xFF;
320
}
321

    
322
/**
323
 * Returns the checksum of the given packet.
324
 *
325
 * @param buf the data for the packet to send
326
 * @param len the length of the packet in bytes
327
 *
328
 * @return the checksum of the packet, which will
329
 * become the last byte sent in the packet
330
 **/
331
char xbee_compute_checksum(char* buf, int len)
332
{
333
        int i;
334
        unsigned char sum = 0;
335
        for (i = 0; i < len; i++)
336
                sum += (unsigned char)buf[i];
337
        return 0xFF - sum;
338
}
339

    
340
/**
341
 * Adds header information and checksum to the given
342
 * packet and sends it. Header information includes
343
 * XBEE_FRAME_START and the packet length, as two bytes.
344
 *
345
 * @param buf the packet data
346
 * @param len the size in bytes of the packet data
347
 *
348
 **/
349
void xbee_send_frame(char* buf, int len)
350
{
351
        char prefix[3];
352
        prefix[0] = XBEE_FRAME_START;
353
        prefix[1] = (len & 0xFF00) >> 8;
354
        prefix[2] = len & 0xFF;
355
        char checksum = xbee_compute_checksum(buf, len);
356
        xbee_send(prefix, 3);
357
        xbee_send(buf, len);
358
        xbee_send(&checksum, 1);
359
}
360

    
361
/**
362
 * Sends an AT command to read a parameter.
363
 *
364
 * @param command the AT command to send. For exmaple,
365
 * use ID to read the PAN ID and MY to return the XBee ID.
366
 * See the XBee reference guide for a complete listing.
367
 **/
368
void xbee_send_read_at_command(char* command)
369
{
370
        xbee_send_modify_at_command(command, NULL);
371
}
372

    
373
/**
374
 * Sends the given AT command.
375
 *
376
 * @param command the AT command to send (e.g., MY, ID)
377
 * @param value the value to pass as a parameter
378
 * (or NULL if there is no parameter)
379
 **/
380
void xbee_send_modify_at_command(char* command, char* value)
381
{
382
        char buf[16];
383
        int i;
384
        
385
        buf[0] = XBEE_FRAME_AT_COMMAND;
386
        buf[1] = 1;
387
        buf[2] = command[0];
388
        buf[3] = command[1];
389
        int valueLen = 0;
390
        if (value != NULL)
391
        {
392
                valueLen = strlen(value);
393
                if (valueLen > 8)
394
                {
395
                        WL_DEBUG_PRINT("AT Command too large.\r\n");
396
                        return;
397
                }
398
                for (i = 0; i < valueLen; i++)
399
                        buf[4 + i] = value[i];
400
        }
401
        xbee_send_frame(buf, 4 + valueLen);
402
}
403

    
404
/**
405
 * Send the specified packet.
406
 * 
407
 * @param packet the packet data to send
408
 * @param len the number of bytes in the packet
409
 * 
410
 * @param dest the ID of the XBee to send the packet to,
411
 * or XBEE_BROADCAST to send the message to all robots
412
 * in the PAN.
413
 * 
414
 * @param options a combination of the flags
415
 * XBEE_OPTIONS_NONE, XBEE_OPTIONS_DISABLE_RESPONSE and 
416
 * XBEE_OPTIONS_BROADCAST_ALL_PANS
417
 *
418
 * @param frame the frame number to associate this packet
419
 * with. This will be used to identify the response when
420
 * the XBee alerts us as to whether or not our message
421
 * was received.
422
 **/
423
void xbee_send_packet(char* packet, int len, int dest,
424
        char options, char frame)
425
{
426
        char buf[5];
427
        char prefix[3];
428
        int i;
429
        unsigned char checksum = 0;
430

    
431
        if (len > 100)
432
        {
433
                WL_DEBUG_PRINT("Packet is too large.\r\n");
434
                return;
435
        }
436

    
437
        //data for sending request
438
        buf[0] = XBEE_FRAME_TX_REQUEST_16;
439
        buf[1] = frame;
440
        buf[2] = (dest >> 8) & 0xFF;
441
        buf[3] = dest & 0xFF;
442
        buf[4] = options;
443

    
444
        //packet prefix, do this here so we don't need an extra buffer
445
        prefix[0] = XBEE_FRAME_START;
446
        prefix[1] = ((5 + len) & 0xFF00) >> 8;
447
        prefix[2] = (5 + len) & 0xFF;
448

    
449
        for (i = 0; i < 5; i++)
450
                checksum += (unsigned char)buf[i];
451
        for (i = 0; i < len; i++)
452
                checksum += (unsigned char)packet[i];
453
        checksum = 0xFF - checksum;
454
        xbee_send(prefix, 3);
455
        xbee_send(buf, 5);
456
        xbee_send(packet, len);
457
        xbee_send((char*)&checksum, 1);
458
}
459

    
460
/**
461
 * Reads a packet received from the XBee. This function
462
 * is non-blocking. The resulting packet is stored in dest.
463
 * Only returns transmission response packets and
464
 * received packets. The returned packet does not include
465
 * header information or the checksum. This method also
466
 * handles special packets dealt with by the XBee library,
467
 * and so should be called frequently while the XBee is in
468
 * use.<br><br>
469
 *
470
 * The first byte of the packet will be either
471
 * XBEE_TX_STATUS or XBEE_RX to indicated
472
 * a response to a sent message or a received message, 
473
 * respectively.<br><br>
474
 *
475
 * For a status response packet:<br>
476
 * The first byte will be XBEE_TX_STATUS.<br>
477
 * The second byte will be the frame number.<br>
478
 * The third byte will be the result. 0 indicates success,
479
 * and nonzero indicates that an error ocurred in 
480
 * transmitting the packet.<br><br>
481
 *
482
 * For a received packet:<br>
483
 * The first byte will be XBEE_RX.<br>
484
 * The second and third bytes will be the 16-bit
485
 * address of the packet's sender.<br>
486
 * The fourth byte is the signal strength.<br>
487
 * The fifth byte is 1 if the packet were sent to
488
 * a specific address, and 2 if it is a broadcast packet.<br><br>
489
 * 
490
 * @param dest set to the packet data
491
 * @return the length of the packet, or -1 if no packet
492
 * is available
493
 **/
494
int xbee_get_packet(unsigned char* dest)
495
{
496
        //start reading a packet with XBEE_FRAME_START
497
        if (currentBufPos == 0)
498
        {
499
                do
500
                        if (queue_is_empty(xbee_queue))
501
                                return -1;
502
                while ((char)(int)queue_remove(xbee_queue) != XBEE_FRAME_START);
503
                xbee_buf[0] = XBEE_FRAME_START;
504
                currentBufPos++;
505
        }
506

    
507
        int len = -1;
508
        if (currentBufPos >= 3)
509
                len = (int)xbee_buf[2] + ((int)xbee_buf[1] << 8);
510
                
511
        while (len == -1 //packet length has not been read yet
512
                        || currentBufPos < len + 4)
513
        {
514
                if (currentBufPos == 3)
515
                        len = (int)xbee_buf[2] + ((int)xbee_buf[1] << 8);
516
                if (queue_is_empty(xbee_queue))
517
                        return -1;
518
                xbee_buf[currentBufPos++] = (char)(int)queue_remove(xbee_queue);
519
        }
520
        
521
        currentBufPos = 0;
522
        
523
        if (!xbee_verify_checksum(xbee_buf, len + 4))
524
        {
525
                WL_DEBUG_PRINT("XBee checksum failed.\r\n");
526
                return -1;
527
        }
528

    
529
        //we will take care of the packet
530
        if (xbee_handle_packet(xbee_buf + 3, len))
531
                return -1;
532
        
533
        if (dest == NULL)
534
                return -1;
535
        
536
        int i;
537
        for (i = 3; i < len + 3; i++)
538
                dest[i - 3] = xbee_buf[i];
539
        return len;
540
}
541

    
542
/**
543
 * Handles modem status packets.
544
 *
545
 * @param status the type of status packet received.
546
 **/
547
void xbee_handle_status(char status)
548
{
549
        switch (status)
550
        {
551
                case 0:
552
                        WL_DEBUG_PRINT("XBee hardware reset.\r\n");
553
                        break;
554
                case 1:
555
                        WL_DEBUG_PRINT("Watchdog timer reset.\r\n");
556
                        break;
557
                case 2:
558
                        WL_DEBUG_PRINT("Associated.\r\n");
559
                        break;
560
                case 3:
561
                        WL_DEBUG_PRINT("Disassociated.\r\n");
562
                        break;
563
                case 4:
564
                        WL_DEBUG_PRINT("Synchronization lost.\r\n");
565
                        break;
566
                case 5:
567
                        WL_DEBUG_PRINT("Coordinator realignment.\r\n");
568
                        break;
569
                case 6:
570
                        WL_DEBUG_PRINT("Coordinator started.\r\n");
571
                        break;
572
        }
573
}
574

    
575
/**
576
 * Handles AT command response packets.
577
 * @param command the two character AT command, e.g. MY or ID
578
 * @param result 0 for success, 1 for an error
579
 * @param extra the hex value of the requested register
580
 * @param extraLen the length in bytes of extra
581
 **/
582
void xbee_handle_at_command_response(char* command, char result,
583
        char* extra, int extraLen)
584
{
585
        if (result == 1)
586
        {
587
                WL_DEBUG_PRINT("Error with AT");
588
                WL_DEBUG_PRINT(command);
589
                WL_DEBUG_PRINT(" packet.\r\n");
590
        }
591
        WL_DEBUG_PRINT("AT");
592
        WL_DEBUG_PRINT(command);
593
        WL_DEBUG_PRINT(" command was successful.\r\n");
594
                
595
        if (command[0] == 'I' && command[1] == 'D')
596
        {
597
                xbee_panID = xbee_pending_panID;
598
                WL_DEBUG_PRINT("PAN ID set to ");
599
                WL_DEBUG_PRINT_INT(xbee_panID);
600
                WL_DEBUG_PRINT(".\r\n");
601
                return;
602
        }
603

    
604
        if (command[0] == 'C' && command[1] == 'H')
605
        {
606
                xbee_channel = xbee_pending_channel;
607
                WL_DEBUG_PRINT("Channel set to ");
608
                WL_DEBUG_PRINT_INT(xbee_channel);
609
                WL_DEBUG_PRINT(".\r\n");
610
                return;
611
        }
612
        
613
        if (command[0] == 'M' && command[1] == 'Y' && extraLen != 0)
614
        {
615
                xbee_address = 0;
616
                int i;
617
                for (i = 0; i < extraLen; i++)
618
                        xbee_address = (xbee_address << 8) + extra[i];
619

    
620
                WL_DEBUG_PRINT("XBee address is ");
621
                WL_DEBUG_PRINT_INT(xbee_address);
622
                WL_DEBUG_PRINT(".\r\n");
623

    
624
                if (xbee_address == 0)
625
                {
626
                        WL_DEBUG_PRINT("XBee 16-bit address must be set using ATMY.\r\n");
627
                        exit(0);
628
                }
629
        }
630
}
631

    
632
/**
633
 * Attempts to handle the packet if it is dealt with
634
 * by the library.
635
 * We will handle the following packet types:
636
 *    Modem Status
637
 *    AT Command Response
638
 *
639
 * @param packet the packet to handle
640
 * @param len the length of the packet
641
 * 
642
 * @return 1 if we have handled the packet, 0 otherwise
643
 */
644
int xbee_handle_packet(char* packet, int len)
645
{
646
        char command[3] = {1, 2, 3};
647
        if (len <= 0) //this should not happend
648
        {
649
                WL_DEBUG_PRINT("Non-positive packet length.\r\n");
650
                return 0;
651
        }
652
        
653
        switch ((unsigned char)packet[0]) //packet type
654
        {
655
                case XBEE_FRAME_STATUS:
656
                        xbee_handle_status(packet[1]);
657
                        return 1;
658
                case XBEE_FRAME_AT_COMMAND_RESPONSE:
659
                        command[0] = packet[2];
660
                        command[1] = packet[3];
661
                        command[2] = 0;
662
                        xbee_handle_at_command_response(command,
663
                                packet[4], packet + 5, len - 5);
664
                        return 1;
665
        }
666
        return 0;
667
}
668

    
669
/**
670
 * Sets the personal area network id.
671
 *
672
 * @param id the new personal area network (PAN) id
673
 **/
674
void xbee_set_pan_id(int id)
675
{
676
        char s[3];
677
        s[0] = (id >> 8) & 0xFF;
678
        s[1] = id & 0xFF;
679
        s[2] = 0;
680
        xbee_pending_panID = id;
681
        xbee_send_modify_at_command("ID", s);
682
}
683

    
684
/**
685
 * Get the PAN ID for the XBee.
686
 * 
687
 * @return the personal area network id, or
688
 * XBEE_PAN_DEFAULT if it has not yet been set.
689
 **/
690
unsigned int xbee_get_pan_id()
691
{
692
        return xbee_panID;
693
}
694

    
695
/**
696
 * Set the channel the XBee is using.
697
 *
698
 * @param channel the channel the XBee will not use, 
699
 * between 0x0B and 0x1A
700
 *
701
 * @see xbee_get_channel
702
 **/
703
void xbee_set_channel(int channel)
704
{
705
        if (channel < 0x0B || channel > 0x1A)
706
        {
707
                WL_DEBUG_PRINT("Channel out of range.\r\n");
708
                return;
709
        }
710
        char s[3];
711
        s[0] = channel & 0xFF;
712
        s[1] = 0;
713
        xbee_pending_channel = channel;
714
        xbee_send_modify_at_command("CH", s);
715
}
716

    
717
/**
718
 * Returns the channel which the XBee is currently using.
719
 *
720
 * @return the channel the XBee is using
721
 *
722
 * @see xbee_set_channel
723
 **/
724
int xbee_get_channel(void)
725
{
726
        return xbee_channel;
727
}
728

    
729
/**
730
 * Get the 16-bit address of the XBee.
731
 * This is used to specify who to send messages to
732
 * and who messages are from.
733
 *
734
 * @return the 16-bit address of the XBee.
735
 **/
736
unsigned int xbee_get_address()
737
{
738
        return xbee_address;
739
}
740