Project

General

Profile

Statistics
| Revision:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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