Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (15.8 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
        printf("Using port ");
148
        printf(XBEE_PORT);
149
        printf("\n");
150
        xbee_stream = open(XBEE_PORT, O_RDWR);
151
        if (xbee_stream == -1 || lockf(xbee_stream, F_TEST, 0) != 0)
152
                xbee_stream = open(XBEE_PORT2, O_RDWR);
153
        if (xbee_stream == -1 || lockf(xbee_stream, F_TEST, 0) != 0)
154
        {
155
                printf("Failed to open connection to XBee.\r\n");
156
                exit(0);
157
        }
158
        lockf(xbee_stream, F_LOCK, 0);
159
        
160
        xbee_listen_thread =
161
                (pthread_t*)malloc(sizeof(pthread_t));
162
        
163
        int ret = pthread_create(xbee_listen_thread, NULL, 
164
                listen_to_xbee, NULL);
165
        if (ret)
166
        {
167
                printf("Failed to create listener thread.\r\n");
168
                exit(0);
169
        }
170
        #endif
171
        xbee_enter_command_mode();
172
        xbee_enter_api_mode();
173
        xbee_exit_command_mode();
174
        xbee_send_read_at_command("MY");
175
        
176
        //wait to return until the address is set
177
        while (xbee_address == 0) xbee_get_packet(NULL);
178
}
179

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

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

    
225
        //write was interrupted after writing ret bytes
226
        xbee_send(buf + ret, size - ret);
227
        #endif
228
}
229

    
230
/**
231
 * Sends a string to the XBee.
232
 *
233
 * @param c the string to send to the XBEE
234
 **/
235
void xbee_send_string(char* c)
236
{
237
        xbee_send(c, strlen(c));
238
}
239

    
240
#ifndef ROBOT
241
void xbee_read(char* buf, int size)
242
{
243
        if (read(xbee_stream, buf, size) == -1)
244
                printf("Failed to read from xbee.\r\n");
245
}
246
#endif
247

    
248
/**
249
 * Enter into command mode.
250
 **/
251
void xbee_enter_command_mode()
252
{
253
        xbee_send_string("+++");
254
        xbee_wait_for_ok();
255
}
256

    
257
/**
258
 * Exit from command mode.
259
 **/
260
void xbee_exit_command_mode()
261
{
262
        xbee_send_string("ATCN\r");
263
        xbee_wait_for_ok();
264
}
265

    
266
/**
267
 * Enter API mode.
268
 **/
269
void xbee_enter_api_mode()
270
{
271
        xbee_send_string("ATAP 1\r");
272
        xbee_wait_for_ok();
273
}
274

    
275
/**
276
 * Wait until the string "OK\r" is received from the XBee.
277
 **/
278
void xbee_wait_for_ok()
279
{
280
        xbee_wait_for_string("OK\r", 3);
281
}
282

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

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

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

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

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

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

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

    
436
        if (len > 100)
437
        {
438
                WL_DEBUG_PRINT("Packet is too large.\r\n");
439
                return;
440
        }
441

    
442
        //data for sending request
443
        buf[0] = XBEE_FRAME_TX_REQUEST_16;
444
        buf[1] = frame;
445
        buf[2] = (dest >> 8) & 0xFF;
446
        buf[3] = dest & 0xFF;
447
        buf[4] = options;
448

    
449
        //packet prefix, do this here so we don't need an extra buffer
450
        prefix[0] = XBEE_FRAME_START;
451
        prefix[1] = ((5 + len) & 0xFF00) >> 8;
452
        prefix[2] = (5 + len) & 0xFF;
453

    
454
        for (i = 0; i < 5; i++)
455
                checksum += (unsigned char)buf[i];
456
        for (i = 0; i < len; i++)
457
                checksum += (unsigned char)packet[i];
458
        checksum = 0xFF - checksum;
459
        xbee_send(prefix, 3);
460
        xbee_send(buf, 5);
461
        xbee_send(packet, len);
462
        xbee_send((char*)&checksum, 1);
463
}
464

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

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

    
534
        //we will take care of the packet
535
        if (xbee_handle_packet(xbee_buf + 3, len))
536
                return -1;
537
        
538
        if (dest == NULL)
539
                return -1;
540
        
541
        int i;
542
        for (i = 3; i < len + 3; i++)
543
                dest[i - 3] = xbee_buf[i];
544
        return len;
545
}
546

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

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

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

    
625
                WL_DEBUG_PRINT("XBee address is ");
626
                WL_DEBUG_PRINT_INT(xbee_address);
627
                WL_DEBUG_PRINT(".\r\n");
628

    
629
                if (xbee_address == 0)
630
                {
631
                        WL_DEBUG_PRINT("XBee 16-bit address must be set using ATMY.\r\n");
632
                        exit(0);
633
                }
634
        }
635
}
636

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

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

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

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

    
722
/**
723
 * Returns the channel which the XBee is currently using.
724
 *
725
 * @return the channel the XBee is using
726
 *
727
 * @see xbee_set_channel
728
 **/
729
int xbee_get_channel(void)
730
{
731
        return xbee_channel;
732
}
733

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