Project

General

Profile

Statistics
| Revision:

root / branches / autonomous_recharging / code / projects / autonomous_recharging / charging_station / xbee.c @ 116

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
        xbee_stream = open("/dev/ttyUSB0", O_RDWR);
148
        if (xbee_stream == -1 || lockf(xbee_stream, F_TEST, 0) != 0)
149
                xbee_stream = open("/dev/ttyUSB1", 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
        usb_puts("Entering command mode.\n");
169
        xbee_enter_command_mode();
170
        usb_puts("Entered command mode.\n");
171
        xbee_enter_api_mode();
172
        xbee_exit_command_mode();
173
        xbee_send_read_at_command("MY");
174
        
175
        //wait to return until the address is set
176
        while (xbee_address == 0) xbee_get_packet(NULL);
177
}
178

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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