Project

General

Profile

Statistics
| Revision:

root / branches / lib_additions / code / lib / src / libwireless / xbee.c @ 79

History | View | Annotate | Download (15.5 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
ISR(USART1_RX_vect)
96
{
97
        char c = UDR1;
98
        queue_add(xbee_queue, (void*)(int)c);
99
}
100

    
101
#else
102

    
103
/**
104
 * Thread that listens to the xbee.
105
 **/
106
void* listen_to_xbee(void* x)
107
{
108
        char c;
109
        while (1)
110
        {
111
                xbee_read(&c, 1);
112
                queue_add(xbee_queue, (void*)(int)c);
113
        }
114
        return 0;
115
}
116

    
117
#endif
118

    
119
/**
120
 * Initializes the XBee library so that other functions may be used.
121
 *
122
 * @param pan_id the PAN to join initially. Use XBEE_PAN_DEFAULT
123
 * to leave the PAN as it is initially.
124
 **/
125
void xbee_lib_init(void)
126
{
127
        xbee_queue = queue_create();
128
        
129
        #ifdef ROBOT
130

    
131
        //enable the receiving interrupt
132
        UCSR1B |= _BV(RXCIE);
133
        sei();
134
        #else
135
        xbee_stream = open("/dev/ttyUSB0", O_RDWR);
136
        if (xbee_stream == -1 || lockf(xbee_stream, F_TEST, 0) != 0)
137
                xbee_stream = open("/dev/ttyUSB1", O_RDWR);
138
        if (xbee_stream == -1 || lockf(xbee_stream, F_TEST, 0) != 0)
139
        {
140
                printf("Failed to open connection to XBee.\r\n");
141
                exit(0);
142
        }
143
        lockf(xbee_stream, F_LOCK, 0);
144
        
145
        xbee_listen_thread =
146
                (pthread_t*)malloc(sizeof(pthread_t));
147
        
148
        int ret = pthread_create(xbee_listen_thread, NULL, 
149
                listen_to_xbee, NULL);
150
        if (ret)
151
        {
152
                printf("Failed to create listener thread.\r\n");
153
                exit(0);
154
        }
155
        #endif
156
        xbee_enter_command_mode();
157
        xbee_enter_api_mode();
158
        xbee_exit_command_mode();
159
        xbee_send_read_at_command("MY");
160
        
161
        //wait to return until the address is set
162
        while (xbee_address == 0) xbee_get_packet(NULL);
163
}
164

    
165
/**
166
 * Call when finished using the XBee library. This releases
167
 * all sued resources.
168
 **/
169
void xbee_terminate()
170
{
171
        #ifndef ROBOT
172
        pthread_cancel(*xbee_listen_thread);
173
        free(xbee_listen_thread);
174
        lockf(xbee_stream, F_ULOCK, 0);
175
        close(xbee_stream);
176
        #endif
177
        queue_destroy(xbee_queue);
178
}
179

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

    
210
        //write was interrupted after writing ret bytes
211
        xbee_send(buf + ret, size - ret);
212
        #endif
213
}
214

    
215
/**
216
 * Sends a string to the XBee.
217
 *
218
 * @param c the string to send to the XBEE
219
 **/
220
void xbee_send_string(char* c)
221
{
222
        xbee_send(c, strlen(c));
223
}
224

    
225
#ifndef ROBOT
226
void xbee_read(char* buf, int size)
227
{
228
        if (read(xbee_stream, buf, size) == -1)
229
                printf("Failed to read from xbee.\r\n");
230
}
231
#endif
232

    
233
/**
234
 * Enter into command mode.
235
 **/
236
void xbee_enter_command_mode()
237
{
238
        xbee_send_string("+++");
239
        xbee_wait_for_ok();
240
}
241

    
242
/**
243
 * Exit from command mode.
244
 **/
245
void xbee_exit_command_mode()
246
{
247
        xbee_send_string("ATCN\r");
248
        xbee_wait_for_ok();
249
}
250

    
251
/**
252
 * Enter API mode.
253
 **/
254
void xbee_enter_api_mode()
255
{
256
        xbee_send_string("ATAP 1\r");
257
        xbee_wait_for_ok();
258
}
259

    
260
/**
261
 * Wait until the string "OK\r" is received from the XBee.
262
 **/
263
void xbee_wait_for_ok()
264
{
265
        xbee_wait_for_string("OK\r", 3);
266
}
267

    
268
/**
269
 * Delay until the specified string is received from
270
 * the XBee. Discards all other XBee data.
271
 *
272
 * @param s the string to receive
273
 * @param len the length of the string
274
 **/
275
void xbee_wait_for_string(char* s, int len)
276
{
277
        char* curr = s;
278
        while (curr - s < len)
279
        {
280
                if (queue_is_empty(xbee_queue))
281
                        continue;
282
                char c = (char)(int)queue_remove(xbee_queue);
283
                if (c == *curr)
284
                        curr++;
285
                else
286
                        curr = s;
287
        }
288
}
289

    
290
/**
291
 * Verifies that the packets checksum is correct.
292
 * (If the checksum is correct, the sum of the bytes
293
 * is 0xFF.)
294
 *
295
 * @param packet the packet received. This includes the first
296
 * three bytes, which are header information from the XBee.
297
 *
298
 * @param len The length of the packet received from the XBee
299
 *
300
 * @return 0 if the checksum is incorrect, nonzero
301
 * otherwise
302
 **/
303
int xbee_verify_checksum(char* packet, int len)
304
{
305
        unsigned char sum = 0;
306
        int i;
307
        for (i = 3; i < len; i++)
308
                sum += (unsigned char)packet[i];
309
        return sum == 0xFF;
310
}
311

    
312
/**
313
 * Returns the checksum of the given packet.
314
 *
315
 * @param buf the data for the packet to send
316
 * @param len the length of the packet in bytes
317
 *
318
 * @return the checksum of the packet, which will
319
 * become the last byte sent in the packet
320
 **/
321
char xbee_compute_checksum(char* buf, int len)
322
{
323
        int i;
324
        unsigned char sum = 0;
325
        for (i = 0; i < len; i++)
326
                sum += (unsigned char)buf[i];
327
        return 0xFF - sum;
328
}
329

    
330
/**
331
 * Adds header information and checksum to the given
332
 * packet and sends it. Header information includes
333
 * XBEE_FRAME_START and the packet length, as two bytes.
334
 *
335
 * @param buf the packet data
336
 * @param len the size in bytes of the packet data
337
 *
338
 **/
339
void xbee_send_frame(char* buf, int len)
340
{
341
        char prefix[3];
342
        prefix[0] = XBEE_FRAME_START;
343
        prefix[1] = (len & 0xFF00) >> 8;
344
        prefix[2] = len & 0xFF;
345
        char checksum = xbee_compute_checksum(buf, len);
346
        xbee_send(prefix, 3);
347
        xbee_send(buf, len);
348
        xbee_send(&checksum, 1);
349
}
350

    
351
/**
352
 * Sends an AT command to read a parameter.
353
 *
354
 * @param command the AT command to send. For exmaple,
355
 * use ID to read the PAN ID and MY to return the XBee ID.
356
 * See the XBee reference guide for a complete listing.
357
 **/
358
void xbee_send_read_at_command(char* command)
359
{
360
        xbee_send_modify_at_command(command, NULL);
361
}
362

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

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

    
421
        if (len > 100)
422
        {
423
                WL_DEBUG_PRINT("Packet is too large.\r\n");
424
                return;
425
        }
426

    
427
        //data for sending request
428
        buf[0] = XBEE_FRAME_TX_REQUEST_16;
429
        buf[1] = frame;
430
        buf[2] = (dest >> 8) & 0xFF;
431
        buf[3] = dest & 0xFF;
432
        buf[4] = options;
433

    
434
        //packet prefix, do this here so we don't need an extra buffer
435
        prefix[0] = XBEE_FRAME_START;
436
        prefix[1] = ((5 + len) & 0xFF00) >> 8;
437
        prefix[2] = (5 + len) & 0xFF;
438

    
439
        for (i = 0; i < 5; i++)
440
                checksum += (unsigned char)buf[i];
441
        for (i = 0; i < len; i++)
442
                checksum += (unsigned char)packet[i];
443
        checksum = 0xFF - checksum;
444
        xbee_send(prefix, 3);
445
        xbee_send(buf, 5);
446
        xbee_send(packet, len);
447
        xbee_send((char*)&checksum, 1);
448
}
449

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

    
497
        int len = -1;
498
        if (currentBufPos >= 3)
499
                len = (int)xbee_buf[2] + ((int)xbee_buf[1] << 8);
500
                
501
        while (len == -1 //packet length has not been read yet
502
                        || currentBufPos < len + 4)
503
        {
504
                if (currentBufPos == 3)
505
                        len = (int)xbee_buf[2] + ((int)xbee_buf[1] << 8);
506
                if (queue_is_empty(xbee_queue))
507
                        return -1;
508
                xbee_buf[currentBufPos++] = (char)(int)queue_remove(xbee_queue);
509
        }
510
        
511
        currentBufPos = 0;
512
        
513
        if (!xbee_verify_checksum(xbee_buf, len + 4))
514
        {
515
                WL_DEBUG_PRINT("XBee checksum failed.\r\n");
516
                return -1;
517
        }
518

    
519
        //we will take care of the packet
520
        if (xbee_handle_packet(xbee_buf + 3, len))
521
                return -1;
522
        
523
        if (dest == NULL)
524
                return -1;
525
        
526
        int i;
527
        for (i = 3; i < len + 3; i++)
528
                dest[i - 3] = xbee_buf[i];
529
        return len;
530
}
531

    
532
/**
533
 * Handles modem status packets.
534
 *
535
 * @param status the type of status packet received.
536
 **/
537
void xbee_handle_status(char status)
538
{
539
        switch (status)
540
        {
541
                case 0:
542
                        WL_DEBUG_PRINT("XBee hardware reset.\r\n");
543
                        break;
544
                case 1:
545
                        WL_DEBUG_PRINT("Watchdog timer reset.\r\n");
546
                        break;
547
                case 2:
548
                        WL_DEBUG_PRINT("Associated.\r\n");
549
                        break;
550
                case 3:
551
                        WL_DEBUG_PRINT("Disassociated.\r\n");
552
                        break;
553
                case 4:
554
                        WL_DEBUG_PRINT("Synchronization lost.\r\n");
555
                        break;
556
                case 5:
557
                        WL_DEBUG_PRINT("Coordinator realignment.\r\n");
558
                        break;
559
                case 6:
560
                        WL_DEBUG_PRINT("Coordinator started.\r\n");
561
                        break;
562
        }
563
}
564

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

    
594
        if (command[0] == 'C' && command[1] == 'H')
595
        {
596
                xbee_channel = xbee_pending_channel;
597
                WL_DEBUG_PRINT("Channel set to ");
598
                WL_DEBUG_PRINT_INT(xbee_channel);
599
                WL_DEBUG_PRINT(".\r\n");
600
                return;
601
        }
602
        
603
        if (command[0] == 'M' && command[1] == 'Y' && extraLen != 0)
604
        {
605
                xbee_address = 0;
606
                int i;
607
                for (i = 0; i < extraLen; i++)
608
                        xbee_address = (xbee_address << 8) + extra[i];
609

    
610
                WL_DEBUG_PRINT("XBee address is ");
611
                WL_DEBUG_PRINT_INT(xbee_address);
612
                WL_DEBUG_PRINT(".\r\n");
613

    
614
                if (xbee_address == 0)
615
                {
616
                        WL_DEBUG_PRINT("XBee 16-bit address must be set using ATMY.\r\n");
617
                        exit(0);
618
                }
619
        }
620
}
621

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

    
659
/**
660
 * Sets the personal area network id.
661
 *
662
 * @param id the new personal area network (PAN) id
663
 **/
664
void xbee_set_pan_id(int id)
665
{
666
        char s[3];
667
        s[0] = (id >> 8) & 0xFF;
668
        s[1] = id & 0xFF;
669
        s[2] = 0;
670
        xbee_pending_panID = id;
671
        xbee_send_modify_at_command("ID", s);
672
}
673

    
674
/**
675
 * Get the PAN ID for the XBee.
676
 * 
677
 * @return the personal area network id, or
678
 * XBEE_PAN_DEFAULT if it has not yet been set.
679
 **/
680
unsigned int xbee_get_pan_id()
681
{
682
        return xbee_panID;
683
}
684

    
685
/**
686
 * Set the channel the XBee is using.
687
 *
688
 * @param channel the channel the XBee will not use, 
689
 * between 0x0B and 0x1A
690
 *
691
 * @see xbee_get_channel
692
 **/
693
void xbee_set_channel(int channel)
694
{
695
        if (channel < 0x0B || channel > 0x1A)
696
        {
697
                WL_DEBUG_PRINT("Channel out of range.\r\n");
698
                return;
699
        }
700
        char s[3];
701
        s[0] = channel & 0xFF;
702
        s[1] = 0;
703
        xbee_pending_channel = channel;
704
        xbee_send_modify_at_command("CH", s);
705
}
706

    
707
/**
708
 * Returns the channel which the XBee is currently using.
709
 *
710
 * @return the channel the XBee is using
711
 *
712
 * @see xbee_set_channel
713
 **/
714
int xbee_get_channel(void)
715
{
716
        return xbee_channel;
717
}
718

    
719
/**
720
 * Get the 16-bit address of the XBee.
721
 * This is used to specify who to send messages to
722
 * and who messages are from.
723
 *
724
 * @return the 16-bit address of the XBee.
725
 **/
726
unsigned int xbee_get_address()
727
{
728
        return xbee_address;
729
}
730