Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (14.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
unsigned int xbee_address = 0;
84

    
85
/*Function Implementations*/
86

    
87
#ifdef ROBOT
88

    
89
/**
90
 * Interrupt for the robot. Adds bytes received from the xbee
91
 * to the queue.
92
 **/
93
ISR(USART1_RX_vect)
94
{
95
        char c = UDR1;
96
        queue_add(xbee_queue, (void*)(int)c);
97
}
98

    
99
#else
100

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

    
115
#endif
116

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

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

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

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

    
214
        //write was interrupted after writing ret bytes
215
        xbee_send(buf + ret, size - ret);
216
        #endif
217
}
218

    
219
/**
220
 * Sends a string to the XBee.
221
 *
222
 * @param c the string to send to the XBEE
223
 **/
224
void xbee_send_string(char* c)
225
{
226
        xbee_send(c, strlen(c));
227
}
228

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

    
237
/**
238
 * Enter into command mode.
239
 **/
240
void xbee_enter_command_mode()
241
{
242
        xbee_send_string("+++");
243
        xbee_wait_for_ok();
244
}
245

    
246
/**
247
 * Exit from command mode.
248
 **/
249
void xbee_exit_command_mode()
250
{
251
        xbee_send_string("ATCN\r");
252
        xbee_wait_for_ok();
253
}
254

    
255
/**
256
 * Enter API mode.
257
 **/
258
void xbee_enter_api_mode()
259
{
260
        xbee_send_string("ATAP 1\r");
261
        xbee_wait_for_ok();
262
}
263

    
264
/**
265
 * Wait until the string "OK\r" is received from the XBee.
266
 **/
267
void xbee_wait_for_ok()
268
{
269
        xbee_wait_for_string("OK\r", 3);
270
}
271

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

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

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

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

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

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

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

    
425
        if (len > 100)
426
        {
427
                WL_DEBUG_PRINT("Packet is too large.\r\n");
428
                return;
429
        }
430

    
431
        //data for sending request
432
        buf[0] = XBEE_FRAME_TX_REQUEST_16;
433
        buf[1] = frame;
434
        buf[2] = (dest >> 8) & 0xFF;
435
        buf[3] = dest & 0xFF;
436
        buf[4] = options;
437

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

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

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

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

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

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

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

    
605
                WL_DEBUG_PRINT("XBee address is ");
606
                WL_DEBUG_PRINT_INT(xbee_address);
607
                WL_DEBUG_PRINT(".\r\n");
608

    
609
                if (xbee_address == 0)
610
                {
611
                        WL_DEBUG_PRINT("XBee 16-bit address must be set using ATMY.\r\n");
612
                        exit(0);
613
                }
614
        }
615
}
616

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

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

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

    
680
/**
681
 * Get the 16-bit address of the XBee.
682
 * This is used to specify who to send messages to
683
 * and who messages are from.
684
 *
685
 * @return the 16-bit address of the XBee.
686
 **/
687
unsigned int xbee_get_address()
688
{
689
        return xbee_address;
690
}
691