Project

General

Profile

Statistics
| Revision:

root / trunk / code / lib / src / libwireless / xbee.c @ 241

History | View | Annotate | Download (16 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
char* xbee_com_port;
71
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
int xbee_channel = XBEE_CHANNEL_DEFAULT;
85
int xbee_pending_channel = XBEE_CHANNEL_DEFAULT;
86
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
#ifndef FIREFLY
97
ISR(USART1_RX_vect)
98
{
99
        char c = UDR1;
100
        queue_add(xbee_queue, (void*)(int)c);
101
}
102
#else
103
SIGNAL(SIG_USART0_RECV)
104
{
105
        char c = UDR0;
106
        queue_add(xbee_queue, (void*)(int)c);
107
}
108
#endif
109

    
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
void xbee_lib_init(void)
132
{
133
        xbee_queue = queue_create();
134
        
135
        #ifdef ROBOT
136

    
137
        //enable the receiving interrupt
138
        #ifdef FIREFLY
139
        UCSR0B |= _BV(RXCIE) | _BV(RXEN);
140
        #else
141
        UCSR1B |= _BV(RXCIE);
142
        #endif
143
        sei();
144
        #else
145
        xbee_stream = open(xbee_com_port, O_RDWR);
146
        if (xbee_stream == -1 || lockf(xbee_stream, F_TEST, 0) != 0)
147
                xbee_stream = open(XBEE_PORT2, O_RDWR);
148
        if (xbee_stream == -1 || lockf(xbee_stream, F_TEST, 0) != 0)
149
        {
150
                printf("Failed to open connection to XBee on port %s\r\n",xbee_com_port);
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
                {
516
                        len = (int)xbee_buf[2] + ((int)xbee_buf[1] << 8);
517
                        if (len > 120)
518
                        {
519
                                WL_DEBUG_PRINT("Packet too large. Probably error in XBee transmission.\n");
520
                                currentBufPos = 0;
521
                                return -1;
522
                        }
523
                }
524
                if (queue_is_empty(xbee_queue))
525
                        return -1;
526
                xbee_buf[currentBufPos++] = (char)(int)queue_remove(xbee_queue);
527
        }
528
        
529
        currentBufPos = 0;
530
        
531
        if (!xbee_verify_checksum(xbee_buf, len + 4))
532
        {
533
                WL_DEBUG_PRINT("XBee checksum failed.\r\n");
534
                return -1;
535
        }
536

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

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

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

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

    
628
                WL_DEBUG_PRINT("XBee address is ");
629
                WL_DEBUG_PRINT_INT(xbee_address);
630
                WL_DEBUG_PRINT(".\r\n");
631

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

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

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

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

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

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

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

    
749
#ifndef ROBOT
750
void xbee_set_com_port(char* port){
751
  //printf("Port being passed is %s\n",port);
752
  xbee_com_port = malloc(strlen(port));
753
  strcpy(xbee_com_port,port); 
754
}
755
#endif
756