Project

General

Profile

Revision 1494

wireless library branch

View differences:

branches/wireless/code/projects/libwireless/lib/xbee.c
1
/**
2
 * Copyright (c) 2007 Colony Project
3
 *
4
 * Permission is hereby granted, free of charge, to any person
5
 * obtaining a copy of this software and associated documentation
6
 * files (the "Software"), to deal in the Software without
7
 * restriction, including without limitation the rights to use,
8
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
9
 * copies of the Software, and to permit persons to whom the
10
 * Software is furnished to do so, subject to the following
11
 * conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be
14
 * included in all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
 * OTHER DEALINGS IN THE SOFTWARE.
24
 **/
25

  
26
/**
27
 * @file xbee.c
28
 * @brief XBee Interface
29
 *
30
 * Implementation of low level communication with the XBee in API mode.
31
 *
32
 * @author Brian Coltin, Colony Project, CMU Robotics Club
33
 **/
34

  
35
#include "xbee.h"
36
#include "wl_defs.h"
37

  
38
#ifndef ROBOT
39

  
40
#include <fcntl.h>
41
#include <unistd.h>
42
#include <pthread.h>
43
#include <errno.h>
44
#include <termios.h>
45
#include <stdio.h>
46
#include <stdlib.h>
47

  
48
#else
49

  
50
#include <serial.h>
51
#include <avr/interrupt.h>
52
#include <util/delay.h>
53

  
54
#endif
55

  
56
#include <string.h>
57

  
58
#define XBEE_FRAME_START 0x7E
59
#define XBEE_GET_PACKET_TIMEOUT 1000
60

  
61
/*Frame Types*/
62
#define XBEE_FRAME_STATUS 0x8A
63
#define XBEE_FRAME_AT_COMMAND 0x08
64
#define XBEE_FRAME_AT_COMMAND_RESPONSE 0x88
65
#define XBEE_FRAME_TX_REQUEST_64 0x00
66
#define XBEE_FRAME_TX_REQUEST_16 0x01
67
#define XBEE_FRAME_TX_STATUS XBEE_TX_STATUS
68
#define XBEE_FRAME_RX_64 0x80
69
#define XBEE_FRAME_RX_16 XBEE_RX
70

  
71
/*Internal Function Prototypes*/
72

  
73
/*I/O Functions*/
74
static int xbee_send(char* buf, int size);
75
static int xbee_send_string(char* c);
76

  
77
#ifndef ROBOT
78
static int xbee_read(char* buf, int size);
79
#endif
80

  
81
/*Command Mode Functions
82
 * Called during initialization.
83
 */
84
static int xbee_enter_command_mode(void);
85
static int xbee_exit_command_mode(void);
86
static int xbee_enter_api_mode(void);
87
static int xbee_exit_api_mode(void);
88
static int xbee_wait_for_string(char* s, int len);
89
static int xbee_wait_for_ok(void);
90

  
91
/*API Mode Functions*/
92

  
93
static int xbee_handle_packet(char* packet, int len);
94
static void xbee_handle_at_command_response(char* command, char result, char* extra, int extraLen);
95
static void xbee_handle_status(char status);
96
static int xbee_verify_checksum(char* packet, int len);
97
static char xbee_compute_checksum(char* packet, int len);
98
static int xbee_send_frame(char* buf, int len);
99
static int xbee_send_read_at_command(char* command);
100
static int xbee_send_modify_at_command(char* command, char* value);
101

  
102
/*Global Variables*/
103

  
104
#ifndef ROBOT
105
static char* xbee_com_port = XBEE_PORT_DEFAULT;
106
static int xbee_stream;
107
static pthread_t* xbee_listen_thread;
108
#endif
109

  
110
// TODO: is this a good size?
111
#define XBEE_BUFFER_SIZE	128
112
#define PACKET_BUFFER_SIZE	108
113
// a buffer for data received from the XBee
114
char arrival_buf[XBEE_BUFFER_SIZE];
115
// location of last unread byte in buffer
116
volatile int buffer_last = 0;
117
// first unread byte in buffer
118
volatile int buffer_first = 0;
119

  
120

  
121
//used to store packets as they are read
122
static char xbee_buf[PACKET_BUFFER_SIZE];
123
static int currentBufPos = 0;
124

  
125
//XBee status
126
static unsigned int xbee_panID = XBEE_PAN_DEFAULT;
127
static unsigned int xbee_pending_panID = XBEE_PAN_DEFAULT;
128
static int xbee_channel = XBEE_CHANNEL_DEFAULT;
129
static int xbee_pending_channel = XBEE_CHANNEL_DEFAULT;
130
static volatile unsigned int xbee_address = 0;
131

  
132
/*Function Implementations*/
133

  
134
#ifdef ROBOT
135

  
136
/**
137
 * Interrupt for the robot. Adds bytes received from the xbee
138
 * to the buffer.
139
 **/
140
#ifndef FIREFLY
141
ISR(USART1_RX_vect)
142
{
143
	char c = UDR1;
144
	arrival_buf[buffer_last] = c;
145
	int t = buffer_last + 1;
146
	if (t == XBEE_BUFFER_SIZE)
147
		t = 0;
148
	if (t == buffer_first)
149
	{
150
		WL_DEBUG_PRINT("\nOut of space in buffer.\n");
151
	}
152
	buffer_last = t;
153
}
154
#else
155
SIGNAL(SIG_USART0_RECV)
156
{
157
	char c = UDR0;
158
	arrival_buf[buffer_last] = c;
159
	int t = buffer_last + 1;
160
	if (t == XBEE_BUFFER_SIZE)
161
		t = 0;
162
	if (t == buffer_first)
163
	{
164
		WL_DEBUG_PRINT("Out of space in buffer.\n");
165
	}
166
	buffer_last = t;
167
}
168
#endif
169

  
170
#else
171

  
172
// Computer code
173

  
174
/**
175
 * Thread that listens to the xbee.
176
 **/
177
static void* listen_to_xbee(void* x)
178
{
179
	char c;
180
	while (1)
181
	{
182
		if (xbee_read(&c, 1) != 0) {
183
			WL_DEBUG_PRINT("xbee_read failed.\n");
184
			return NULL;
185
		}
186

  
187
		arrival_buf[buffer_last] = c;
188
		int t = buffer_last + 1;
189
		if (t == XBEE_BUFFER_SIZE)
190
			t = 0;
191
		if (t == buffer_first)
192
		{
193
			WL_DEBUG_PRINT("Out of space in buffer.\n");
194
		}
195
		buffer_last = t;
196

  
197
		usleep(1000);
198
	}
199

  
200
	return NULL;
201
}
202

  
203
#endif
204

  
205
/**
206
 * Initializes the XBee library so that other functions may be used.
207
 **/
208
int xbee_lib_init()
209
{
210
	WL_DEBUG_PRINT("in xbee_init\n");
211
#ifdef ROBOT
212
  // enable basic xbee serial communications
213
  xbee_init();
214

  
215
	// enable the receiving interrupt for USART1
216
#ifdef FIREFLY
217
	UCSR0B |= _BV(RXCIE) | _BV(RXEN);
218
#else
219
#ifdef BAYBOARD
220
	UCSR1B |= _BV(RXCIE1);
221
#else
222
  // dragonfly register 
223
	UCSR1B |= _BV(RXCIE);
224
#endif
225
#endif
226
	sei();
227
#else
228
  // this is computer only code
229
  
230
	xbee_stream = open(xbee_com_port, O_RDWR);
231
	if (xbee_stream == -1/* || lockf(xbee_stream, F_TEST, 0) != 0*/)
232
	{
233
		WL_DEBUG_PRINT("Failed to open connection to XBee on port ");
234
		WL_DEBUG_PRINT_INT(xbee_com_port);
235
		WL_DEBUG_PRINT(".\n");
236
		return -1;
237
	} else {
238
	  WL_DEBUG_PRINT("Successfully opened connection to XBee on port ");
239
		WL_DEBUG_PRINT_INT(xbee_com_port);
240
		WL_DEBUG_PRINT(".\n");
241
	}
242

  
243
	// set baud rate, etc. correctly
244
	struct termios options;
245

  
246
	tcgetattr(xbee_stream, &options);
247
	cfsetispeed(&options, B9600);
248
	cfsetospeed(&options, B9600);
249
	options.c_iflag &= ~ICRNL;
250
	options.c_oflag &= ~OCRNL;
251
	options.c_cflag |= (CLOCAL | CREAD);
252
	options.c_cflag &= ~PARENB;
253
	options.c_cflag &= ~CSTOPB;
254
	options.c_cflag &= ~CSIZE;
255
	options.c_cflag |= CS8;
256
	options.c_lflag &= ~ICANON;
257
	options.c_cc[VMIN] = 1;
258
	options.c_cc[VTIME] = 50;
259

  
260
	if (tcsetattr(xbee_stream, TCSANOW, &options))
261
	{
262
		WL_DEBUG_PRINT("Error setting attributes.\n");
263
		return -1;
264
	}
265

  
266
	xbee_listen_thread = (pthread_t*)malloc(sizeof(pthread_t));
267
	if (xbee_listen_thread == NULL)
268
	{
269
		WL_DEBUG_PRINT("Malloc failed.\n");
270
		return -1;
271
	}
272

  
273
	int ret = pthread_create(xbee_listen_thread, NULL, listen_to_xbee, NULL);
274
	if (ret)
275
	{
276
		WL_DEBUG_PRINT("Failed to create listener thread.\n");
277
		return -1;
278
	}
279
#endif
280

  
281
	WL_DEBUG_PRINT("Entering command mode.\n");
282

  
283
	if (xbee_enter_command_mode() != 0) {
284
		return -1;
285
	}
286

  
287
	WL_DEBUG_PRINT("Entered command mode.\n");
288

  
289
	if (xbee_enter_api_mode() != 0) {
290
		return -1;
291
	}
292

  
293
	WL_DEBUG_PRINT("Entered api mode.\n");
294

  
295
	if (xbee_exit_command_mode() != 0) {
296
	     return -1;
297
	}
298
	
299
	WL_DEBUG_PRINT("Left command mode.\n");
300

  
301
	if (xbee_send_read_at_command("MY")) {
302
		return -1;
303
	}
304
	WL_DEBUG_PRINT("Getting ATMY address.\n");
305

  
306
#ifndef ROBOT
307
	int i;
308
	for (i = 0; xbee_address == 0 && i < XBEE_GET_PACKET_TIMEOUT; i++) {
309
	  ret = xbee_get_packet(NULL);
310

  
311
	  usleep(1000);
312
	  
313
/* 	  if (ret == -1) { */
314
/* 	    WL_DEBUG_PRINT("xbee_get_packet(NULL) failed.\n"); */
315
/* 	    return -1; */
316
/* 	  } */
317
	}
318
#else
319
	//wait to return until the address is set
320
  //TODO: this shouldn't wait indefinitely.  There should be some sort of reasonable timeout
321
  // so if the address is never set right, an error can be returned instead of having the
322
  // robot hang forever
323
	while (xbee_address == 0) {
324
	  xbee_get_packet(NULL);
325
	}
326
#endif
327
	WL_DEBUG_PRINT("Got ATMY address.\n");
328

  
329
#ifndef ROBOT
330
	if (i == XBEE_GET_PACKET_TIMEOUT) { // We timed-out.
331

  
332
	  WL_DEBUG_PRINT("xbee_get_packet timed out.\n");
333
	  return -1;
334
	} else {
335
    
336
    
337
	  return 0;
338
	}
339
#else
340
	return 0;
341
#endif
342
}
343

  
344
/**
345
 * Call when finished using the XBee library. This releases
346
 * all sued resources.
347
 **/
348
void xbee_terminate()
349
{
350
	#ifndef ROBOT
351
	pthread_cancel(*xbee_listen_thread);
352
    pthread_join(*xbee_listen_thread, NULL);
353
	free(xbee_listen_thread);
354
	lockf(xbee_stream, F_ULOCK, 0);
355
	close(xbee_stream);
356
  #else
357
  xbee_exit_api_mode();
358
	#endif
359
}
360

  
361
/**
362
 * Send a buffer buf of size bytes to the XBee.
363
 *
364
 * @param buf the buffer of data to send
365
 * @param size the number of bytes to send
366
 **/
367
static int xbee_send(char* buf, int size)
368
{
369
#ifdef ROBOT
370
	int i;
371
	for (i = 0; i < size; i++) {
372
		xbee_putc(buf[i]);
373
	}
374

  
375
	return 0;
376

  
377
#else
378

  
379
	int ret = write(xbee_stream, buf, size);
380
	//success
381
	if (ret == size)
382
		return 0;
383
	if (ret == -1)
384
	{
385
		//interrupted by system signal, probably timer interrupt.
386
		//just try again
387
		if (errno == 4)
388
		{
389
			return xbee_send(buf, size);
390
		}
391
		WL_DEBUG_PRINT("Failed to write to xbee\r\n");
392
		return -1;
393
	}
394

  
395
	//write was interrupted after writing ret bytes
396
	return xbee_send(buf + ret, size - ret);
397
#endif
398
}
399

  
400
/**
401
 * Sends a string to the XBee.
402
 *
403
 * @param c the string to send to the XBEE
404
 **/
405
static int xbee_send_string(char* c)
406
{
407
	return xbee_send(c, strlen(c));
408
}
409

  
410
#ifndef ROBOT
411
static int xbee_read(char* buf, int size)
412
{
413
	if (read(xbee_stream, buf, size) == -1) {
414
		WL_DEBUG_PRINT("Failed to read from xbee.\r\n");
415
		return -1;
416
	}
417

  
418
	return 0;
419
}
420
#endif
421

  
422
/**
423
 * Enter into command mode.
424
 **/
425
static int xbee_enter_command_mode()
426
{
427
	if (xbee_send_string("+++") != 0) {
428
		return -1;
429
	}
430

  
431
	if (xbee_wait_for_ok() != 0) {
432
	  return -1;
433
	}
434
	  return 0;
435
}
436

  
437
/**
438
 * Exit from command mode.
439
 **/
440
static int xbee_exit_command_mode()
441
{
442
	if (xbee_send_string("ATCN\r") != 0) {
443
		return -1;
444
	}
445

  
446
	xbee_wait_for_ok();
447

  
448
	return 0;
449
}
450

  
451
/**
452
 * Enter API mode.
453
 **/
454
static int xbee_enter_api_mode()
455
{
456
	if (xbee_send_string("ATAP 1\r") != 0) {
457
		return -1;
458
	}
459
	xbee_wait_for_ok();
460

  
461
	return 0;
462
}
463

  
464
/**
465
 * Exit API mode.
466
 **/
467
static int xbee_exit_api_mode()
468
{
469
	if (xbee_send_modify_at_command("AP","0") != 0) {
470
		return -1;
471
	}
472

  
473
	return 0;
474
}
475

  
476
/**
477
 * Wait until the string "OK\r" is received from the XBee.
478
 **/
479
static int xbee_wait_for_ok()
480
{
481
	return xbee_wait_for_string("OK\r", 3);
482
}
483

  
484
/**
485
 * Delay until the specified string is received from
486
 * the XBee. Discards all other XBee data.
487
 *
488
 * @param s the string to receive
489
 * @param len the length of the string
490
 **/
491
static int xbee_wait_for_string(char* s, int len)
492
{
493
	char* curr = s;
494
	while (curr - s < len) {
495
		// check if buffer is empty
496
		if (buffer_last != buffer_first) {
497
			char c = arrival_buf[buffer_first++];
498
			if (buffer_first == XBEE_BUFFER_SIZE) {
499
				buffer_first = 0;
500
			}
501

  
502
			if (c == *curr) {
503
				curr++;
504
			} else {
505
#ifndef ROBOT
506
			  //return -1; // Computer is less forgiving.
507
			  curr = s;
508
#else
509
			  curr = s;
510
#endif
511
			}
512
		} // else buffer is empty.
513

  
514
#ifndef ROBOT
515
		usleep(100);
516
#endif
517
	}
518

  
519
	return 0;
520
}
521

  
522
/**
523
 * Verifies that the packets checksum is correct.
524
 * (If the checksum is correct, the sum of the bytes
525
 * is 0xFF.)
526
 *
527
 * @param packet the packet received. This includes the first
528
 * three bytes, which are header information from the XBee.
529
 *
530
 * @param len The length of the packet received from the XBee
531
 *
532
 * @return 0 if the checksum is incorrect, nonzero
533
 * otherwise
534
 **/
535
int xbee_verify_checksum(char* packet, int len)
536
{
537
	unsigned char sum = 0;
538
	int i;
539
	for (i = 3; i < len; i++)
540
		sum += (unsigned char)packet[i];
541
	return sum == 0xFF;
542
}
543

  
544
/**
545
 * Returns the checksum of the given packet.
546
 *
547
 * @param buf the data for the packet to send
548
 * @param len the length of the packet in bytes
549
 *
550
 * @return the checksum of the packet, which will
551
 * become the last byte sent in the packet
552
 **/
553
char xbee_compute_checksum(char* buf, int len)
554
{
555
	int i;
556
	unsigned char sum = 0;
557
	for (i = 0; i < len; i++)
558
		sum += (unsigned char)buf[i];
559
	return 0xFF - sum;
560
}
561

  
562
/**
563
 * Adds header information and checksum to the given
564
 * packet and sends it. Header information includes
565
 * XBEE_FRAME_START and the packet length, as two bytes.
566
 *
567
 * @param buf the packet data
568
 * @param len the size in bytes of the packet data
569
 *
570
 **/
571
static int xbee_send_frame(char* buf, int len)
572
{
573
	char prefix[3];
574
	prefix[0] = XBEE_FRAME_START;
575
	prefix[1] = (len & 0xFF00) >> 8;
576
	prefix[2] = len & 0xFF;
577
	char checksum = xbee_compute_checksum(buf, len);
578

  
579
	if (xbee_send(prefix, 3) != 0) {
580
		return -1;
581
	}
582

  
583
	if (xbee_send(buf, len) != 0) {
584
		return -1;
585
	}
586

  
587
	if (xbee_send(&checksum, 1) != 0) {
588
		return -1;
589
	}
590

  
591
	return 0;
592
}
593

  
594
/**
595
 * Resets the XBee Modem (including baud rate when on robot)
596
 * 
597
 * Used for launching bootloader
598
 **/
599
int xbee_reset(void)
600
{
601
#ifdef ROBOT
602
	xbee_send_modify_at_command("BD", "3");
603
#endif
604
	xbee_send_read_at_command("FR");
605
    // delay 150 ms to wait for reset
606
#ifndef ROBOT
607
	usleep(150000);
608
#else
609
	_delay_ms(150);
610
#endif
611

  
612
	return 0;
613
}
614

  
615
/**
616
 * Sends an AT command to read a parameter.
617
 *
618
 * @param command the AT command to send. For exmaple,
619
 * use ID to read the PAN ID and MY to return the XBee ID.
620
 * See the XBee reference guide for a complete listing.
621
 **/
622
static int xbee_send_read_at_command(char* command)
623
{
624
	return xbee_send_modify_at_command(command, NULL);
625
}
626

  
627
/**
628
 * Sends the given AT command.
629
 *
630
 * @param command the AT command to send (e.g., MY, ID)
631
 * @param value the value to pass as a parameter
632
 * (or NULL if there is no parameter)
633
 **/
634
static int xbee_send_modify_at_command(char* command, char* value)
635
{
636
	char buf[16];
637
	int i;
638

  
639
	buf[0] = XBEE_FRAME_AT_COMMAND;
640
	buf[1] = 1;
641
	buf[2] = command[0];
642
	buf[3] = command[1];
643
	int valueLen = 0;
644
	if (value != NULL)
645
	{
646
		valueLen = strlen(value);
647
		if (valueLen > 8)
648
		{
649
			WL_DEBUG_PRINT("AT Command too large.\r\n");
650
			return -1;
651
		}
652

  
653
		for (i = 0; i < valueLen; i++) {
654
			buf[4 + i] = value[i];
655
		}
656
	}
657

  
658
	return xbee_send_frame(buf, 4 + valueLen);
659
}
660

  
661
/**
662
 * Send the specified packet.
663
 *
664
 * @param packet the packet data to send
665
 * @param len the number of bytes in the packet
666
 *
667
 * @param dest the ID of the XBee to send the packet to,
668
 * or XBEE_BROADCAST to send the message to all robots
669
 * in the PAN.
670
 *
671
 * @param options a combination of the flags
672
 * XBEE_OPTIONS_NONE, XBEE_OPTIONS_DISABLE_RESPONSE and
673
 * XBEE_OPTIONS_BROADCAST_ALL_PANS
674
 *
675
 * @param frame the frame number to associate this packet
676
 * with. This will be used to identify the response when
677
 * the XBee alerts us as to whether or not our message
678
 * was received.
679
 **/
680
int xbee_send_packet(char* packet, int len, int dest, char options, char frame)
681
{
682
	char buf[5];
683
	char prefix[3];
684
	int i;
685
	unsigned char checksum = 0;
686

  
687
	if (len > 100)
688
	{
689
		WL_DEBUG_PRINT("Packet is too large.\r\n");
690
		return -1;
691
	}
692

  
693
	//data for sending request
694
	buf[0] = XBEE_FRAME_TX_REQUEST_16;
695
	buf[1] = frame;
696
	buf[2] = (dest >> 8) & 0xFF;
697
	buf[3] = dest & 0xFF;
698
	buf[4] = options;
699

  
700
	//packet prefix, do this here so we don't need an extra buffer
701
	prefix[0] = XBEE_FRAME_START;
702
	prefix[1] = ((5 + len) & 0xFF00) >> 8;
703
	prefix[2] = (5 + len) & 0xFF;
704

  
705
	for (i = 0; i < 5; i++)
706
		checksum += (unsigned char)buf[i];
707
	for (i = 0; i < len; i++)
708
		checksum += (unsigned char)packet[i];
709
	checksum = 0xFF - checksum;
710

  
711
	if (xbee_send(prefix, 3) != 0) {
712
		return -1;
713
	}
714

  
715
	if (xbee_send(buf, 5) != 0) {
716
		return -1;
717
	}
718

  
719
	if (xbee_send(packet, len) != 0) {
720
		return -1;
721
	}
722

  
723
	if (xbee_send((char*)&checksum, 1) != 0) {
724
		return -1;
725
	}
726

  
727
	return 0;
728
}
729

  
730
/**
731
 * Reads a packet received from the XBee. This function
732
 * is non-blocking. The resulting packet is stored in dest.
733
 * Only returns transmission response packets and
734
 * received packets. The returned packet does not include
735
 * header information or the checksum. This method also
736
 * handles special packets dealt with by the XBee library,
737
 * and so should be called frequently while the XBee is in
738
 * use.<br><br>
739
 *
740
 * The first byte of the packet will be either
741
 * XBEE_TX_STATUS or XBEE_RX to indicated
742
 * a response to a sent message or a received message,
743
 * respectively.<br><br>
744
 *
745
 * For a status response packet:<br>
746
 * The first byte will be XBEE_TX_STATUS.<br>
747
 * The second byte will be the frame number.<br>
748
 * The third byte will be the result. 0 indicates success,
749
 * and nonzero indicates that an error ocurred in
750
 * transmitting the packet.<br><br>
751
 *
752
 * For a received packet:<br>
753
 * The first byte will be XBEE_RX.<br>
754
 * The second and third bytes will be the 16-bit
755
 * address of the packet's sender.<br>
756
 * The fourth byte is the signal strength.<br>
757
 * The fifth byte is 1 if the packet were sent to
758
 * a specific address, and 2 if it is a broadcast packet.<br><br>
759
 *
760
 * @param dest set to the packet data
761
 * @return the length of the packet, or -1 if no packet
762
 * is available
763
 **/
764
int xbee_get_packet(unsigned char* dest)
765
{
766
     int ret;
767
	//start reading a packet with XBEE_FRAME_START
768
	if (currentBufPos == 0)
769
	{
770
		do
771
		{
772
			if (buffer_first == XBEE_BUFFER_SIZE)
773
				buffer_first = 0;
774
			// check if buffer is empty
775
			if (buffer_first == buffer_last) {
776
				return -1;
777
			}
778
		} while (arrival_buf[buffer_first++] != XBEE_FRAME_START);
779

  
780
		if (buffer_first == XBEE_BUFFER_SIZE) {
781
			buffer_first = 0;
782
		}
783
		xbee_buf[0] = XBEE_FRAME_START;
784
		currentBufPos++;
785
	}
786

  
787
	int len = -1;
788
	if (currentBufPos >= 3) {
789
		len = (int)xbee_buf[2] + ((int)xbee_buf[1] << 8);
790
	}
791

  
792
	while (len == -1 //packet length has not been read yet
793
		|| currentBufPos < len + 4)
794
	{
795
		if (currentBufPos == 3)
796
		{
797
			len = (int)xbee_buf[2] + ((int)xbee_buf[1] << 8);
798
			if (len > 120)
799
			{
800
				WL_DEBUG_PRINT("Packet too large. Probably error in XBee transmission.\n");
801
				currentBufPos = 0;
802
				return -1;
803
			}
804
		}
805

  
806
		// check if buffer is empty
807
		if (buffer_first == buffer_last) {
808
			return -1;
809
		}
810
		xbee_buf[currentBufPos++] = arrival_buf[buffer_first++];
811
		if (buffer_first == XBEE_BUFFER_SIZE) {
812
			buffer_first = 0;
813
		}
814
	}
815

  
816
	currentBufPos = 0;
817

  
818
	if (!xbee_verify_checksum(xbee_buf, len + 4))
819
	{
820
		WL_DEBUG_PRINT("XBee checksum failed.\r\n");
821
		return -1;
822
	}
823

  
824
	//we will take care of the packet
825
	
826
	ret = xbee_handle_packet(xbee_buf+3, len);
827
	if (ret == 1) {
828
		return 3;
829
	}
830
	
831
	if (dest == NULL) {
832
		return -1;
833
	}
834

  
835
	int i;
836
	for (i = 3; i < len + 3; i++) {
837
		dest[i - 3] = xbee_buf[i];
838
	}
839
	return len;
840
}
841

  
842
/**
843
 * Handles modem status packets.
844
 *
845
 * @param status the type of status packet received.
846
 **/
847
void xbee_handle_status(char status)
848
{
849
	switch (status)
850
	{
851
		case 0:
852
			WL_DEBUG_PRINT("XBee hardware reset.\r\n");
853
			break;
854
		case 1:
855
			WL_DEBUG_PRINT("Watchdog timer reset.\r\n");
856
			break;
857
		case 2:
858
			WL_DEBUG_PRINT("Associated.\r\n");
859
			break;
860
		case 3:
861
			WL_DEBUG_PRINT("Disassociated.\r\n");
862
			break;
863
		case 4:
864
			WL_DEBUG_PRINT("Synchronization lost.\r\n");
865
			break;
866
		case 5:
867
			WL_DEBUG_PRINT("Coordinator realignment.\r\n");
868
			break;
869
		case 6:
870
			WL_DEBUG_PRINT("Coordinator started.\r\n");
871
			break;
872
	}
873
}
874

  
875
/**
876
 * Handles AT command response packets.
877
 * @param command the two character AT command, e.g. MY or ID
878
 * @param result 0 for success, 1 for an error
879
 * @param extra the hex value of the requested register
880
 * @param extraLen the length in bytes of extra
881
 **/
882
static void xbee_handle_at_command_response(char* command, char result, char* extra, int extraLen)
883
{
884
	if (result == 1)
885
	{
886
		WL_DEBUG_PRINT("Error with AT");
887
		WL_DEBUG_PRINT(command);
888
		WL_DEBUG_PRINT(" packet.\r\n");
889
	}
890
	WL_DEBUG_PRINT("AT");
891
	WL_DEBUG_PRINT(command);
892
	WL_DEBUG_PRINT(" command was successful.\r\n");
893

  
894
	if (command[0] == 'I' && command[1] == 'D')
895
	{
896
		xbee_panID = xbee_pending_panID;
897
		WL_DEBUG_PRINT("PAN ID set to ");
898
		WL_DEBUG_PRINT_INT(xbee_panID);
899
		WL_DEBUG_PRINT(".\r\n");
900
		return;
901
	}
902

  
903
	if (command[0] == 'C' && command[1] == 'H')
904
	{
905
		xbee_channel = xbee_pending_channel;
906
		WL_DEBUG_PRINT("Channel set to ");
907
		WL_DEBUG_PRINT_INT(xbee_channel);
908
		WL_DEBUG_PRINT(".\r\n");
909
		return;
910
	}
911

  
912
	if (command[0] == 'M' && command[1] == 'Y' && extraLen != 0)
913
	{
914
		xbee_address = 0;
915
		int i;
916
		for (i = 0; i < extraLen; i++) {
917
			xbee_address = (xbee_address << 8) + extra[i];
918
		}
919

  
920
		WL_DEBUG_PRINT("XBee address is ");
921
		WL_DEBUG_PRINT_INT(xbee_address);
922
		WL_DEBUG_PRINT(".\r\n");
923

  
924
		if (xbee_address == 0)
925
		{
926
			WL_DEBUG_PRINT("XBee 16-bit address must be set using ATMY.\r\n");
927
			#ifndef ROBOT
928
			exit(0);
929
			#endif
930
		}
931
	}
932
}
933

  
934
/**
935
 * Attempts to handle the packet if it is dealt with
936
 * by the library.
937
 * We will handle the following packet types:
938
 *    Modem Status
939
 *    AT Command Response
940
 *
941
 * @param packet the packet to handle
942
 * @param len the length of the packet
943
 *
944
 * @return 1 if we have handled the packet, 0 otherwise
945
 */
946
static int xbee_handle_packet(char* packet, int len)
947
{
948

  
949
	char command[3] = {1, 2, 3};
950
	if (len <= 0) //this should not happend
951
	{
952
		WL_DEBUG_PRINT("Non-positive packet length.\r\n");
953
		return 0;
954
	}
955

  
956
	switch ((unsigned char)packet[0]) //packet type
957
	{
958
		case XBEE_FRAME_STATUS:
959
			xbee_handle_status(packet[1]);
960
			return 1;
961
		case XBEE_FRAME_AT_COMMAND_RESPONSE:
962
			command[0] = packet[2];
963
			command[1] = packet[3];
964
			command[2] = 0;
965
			xbee_handle_at_command_response(command, packet[4], packet + 5, len - 5);
966
			return 1;
967
	}
968
	return 0;
969
}
970

  
971
/**
972
 * Sets the personal area network id.
973
 *
974
 * @param id the new personal area network (PAN) id
975
 **/
976
int xbee_set_pan_id(int id)
977
{
978
	char s[3];
979
	s[0] = (id >> 8) & 0xFF;
980
	s[1] = id & 0xFF;
981
	s[2] = 0;
982
	xbee_pending_panID = id;
983
	return xbee_send_modify_at_command("ID", s);
984
}
985

  
986
/**
987
 * Get the PAN ID for the XBee.
988
 *
989
 * @return the personal area network id, or
990
 * XBEE_PAN_DEFAULT if it has not yet been set.
991
 **/
992
unsigned int xbee_get_pan_id()
993
{
994
	return xbee_panID;
995
}
996

  
997
/**
998
 * Set the channel the XBee is using.
999
 *
1000
 * @param channel the channel the XBee will not use,
1001
 * between 0x0B and 0x1A
1002
 *
1003
 * @see xbee_get_channel
1004
 **/
1005
int xbee_set_channel(int channel)
1006
{
1007
	if (channel < 0x0B || channel > 0x1A)
1008
	{
1009
		WL_DEBUG_PRINT("Channel out of range.\r\n");
1010
		return -1;
1011
	}
1012

  
1013
	char s[3];
1014
	s[0] = channel & 0xFF;
1015
	s[1] = 0;
1016
	xbee_pending_channel = channel;
1017

  
1018
	return xbee_send_modify_at_command("CH", s);
1019
}
1020

  
1021
/**
1022
 * Returns the channel which the XBee is currently using.
1023
 *
1024
 * @return the channel the XBee is using
1025
 *
1026
 * @see xbee_set_channel
1027
 **/
1028
int xbee_get_channel(void)
1029
{
1030
	return xbee_channel;
1031
}
1032

  
1033
/**
1034
 * Get the 16-bit address of the XBee.
1035
 * This is used to specify who to send messages to
1036
 * and who messages are from.
1037
 *
1038
 * @return the 16-bit address of the XBee.
1039
 **/
1040
unsigned int xbee_get_address()
1041
{
1042
	return xbee_address;
1043
}
1044

  
1045
#ifndef ROBOT
1046
void xbee_set_com_port(char* port)
1047
{
1048
	xbee_com_port = port;
1049
}
1050
#endif
branches/wireless/code/projects/libwireless/lib/wl_defs.h
1
/**
2
 * Copyright (c) 2007 Colony Project
3
 * 
4
 * Permission is hereby granted, free of charge, to any person
5
 * obtaining a copy of this software and associated documentation
6
 * files (the "Software"), to deal in the Software without
7
 * restriction, including without limitation the rights to use,
8
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
9
 * copies of the Software, and to permit persons to whom the
10
 * Software is furnished to do so, subject to the following
11
 * conditions:
12
 * 
13
 * The above copyright notice and this permission notice shall be
14
 * included in all copies or substantial portions of the Software.
15
 * 
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
 * OTHER DEALINGS IN THE SOFTWARE.
24
 **/
25

  
26
/**
27
 * @file wl_defs.h
28
 * @brief Definitions for Wireless
29
 *
30
 * Contains definitions for wireless packet groups, packet types,
31
 * debugging information, etc.
32
 *
33
 * @author Brian Coltin, Colony Project, CMU Robotics Club
34
 **/
35

  
36
#ifndef WL_DEFS_H
37
#define WL_DEFS_H
38

  
39
//comment out this line if using a computer hooked up to an xbee
40
//#define ROBOT
41

  
42
//uncomment this line for debug information
43
//#define WL_DEBUG
44

  
45
//return value definitions
46
/** @brief Error code for init failure **/
47
#define WL_ERROR_INIT_FAILED 1
48
/** @brief Error code for duplicate init calls **/
49
#define WL_ERROR_INIT_ALREADY_INITD 2
50
/** @brief Error code for not calling init **/
51
#define WL_ERROR_LIBRARY_NOT_INITD 3
52

  
53
// Packet Groups and Types
54

  
55
// Error group
56
#define WL_ERROR_GROUP 1
57

  
58
#define WL_ERROR_STRING_TYPE 1
59

  
60
// Token Ring group
61
#define WL_TOKEN_RING_GROUP 2
62

  
63
#define WL_TOKEN_PASS 1
64
#define WL_TOKEN_SENSOR_MATRIX 2
65
#define WL_TOKEN_BOM_ON 3
66
#define WL_TOKEN_JOIN 4
67
#define WL_TOKEN_JOIN_ACCEPT 5
68

  
69
// timing constants
70
#ifndef FIREFLY
71
#define BOM_DELAY 100
72
#else
73
#define BOM_DELAY 200
74
#endif
75

  
76
#define DEATH_DELAY 4
77
#define JOIN_DELAY 8
78

  
79
#ifdef WL_DEBUG
80

  
81
#ifdef ROBOT
82
#include <serial.h>
83
#endif
84

  
85
#ifdef ROBOT
86
#define WL_DEBUG_PRINT( s ) usb_puts( s )
87
#else
88
#define WL_DEBUG_PRINT( s ) printf( s )
89
#endif
90

  
91
#ifdef ROBOT
92
#define WL_DEBUG_PRINT_INT( i ) usb_puti(i)
93
#else
94
#define WL_DEBUG_PRINT_INT( i ) printf("%i", i)
95
#endif
96

  
97
#else
98

  
99
#define WL_DEBUG_PRINT( s )
100
#define WL_DEBUG_PRINT_INT( i )
101

  
102
#endif
103

  
104
#endif
105

  
branches/wireless/code/projects/libwireless/lib/wl_token_ring.c
1
/**
2
 * Copyright (c) 2007 Colony Project
3
 *
4
 * Permission is hereby granted, free of charge, to any person
5
 * obtaining a copy of this software and associated documentation
6
 * files (the "Software"), to deal in the Software without
7
 * restriction, including without limitation the rights to use,
8
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
9
 * copies of the Software, and to permit persons to whom the
10
 * Software is furnished to do so, subject to the following
11
 * conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be
14
 * included in all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
 * OTHER DEALINGS IN THE SOFTWARE.
24
 **/
25

  
26
/**
27
 * @file wl_token_ring.c
28
 * @brief Token Ring Implementation
29
 *
30
 * Implementation of the token ring packet group.
31
 *
32
 * @author Brian Coltin, Colony Project, CMU Robotics Club
33
 **/
34

  
35
#include <wl_token_ring.h>
36

  
37
#include <stdlib.h>
38

  
39
#include <wl_defs.h>
40
#include <wireless.h>
41
#include <sensor_matrix.h>
42

  
43
#ifdef ROBOT
44
#ifndef FIREFLY
45
#include <bom.h>
46
#endif
47
#include <time.h>
48
#endif
49

  
50

  
51
//#define DEFAULT_SENSOR_MATRIX_SIZE 20
52

  
53
/*Ring States*/
54

  
55
#define NONMEMBER 0
56
#define MEMBER 1
57
#define JOINING 2
58
#define ACCEPTED 3
59
#define LEAVING 4
60

  
61
/*Frame Types*/
62
#define TOKEN_JOIN_ACCEPT_FRAME	1
63
#define WL_TOKEN_PASS_FRAME	2
64

  
65
/*Function Prototypes*/
66

  
67
/*Wireless Library Prototypes*/
68
static void wl_token_ring_timeout_handler(void);
69
static void wl_token_ring_response_handler(int frame, int received);
70
static void wl_token_ring_receive_handler(char type, int source, unsigned char* packet, int length);
71
static void wl_token_ring_cleanup(void);
72

  
73
/*Helper Functions*/
74
static int wl_token_pass_token(void);
75
static int get_token_distance(int robot1, int robot2);
76
static void wl_token_get_token(void);
77

  
78
/*Packet Handling Routines*/
79
static void wl_token_pass_receive(int source);
80
static void wl_token_sensor_matrix_receive(int source, unsigned char* sensorData, int sensorDataLength);
81
static void wl_token_bom_on_receive(int source);
82
static void wl_token_join_receive(int source);
83
static void wl_token_join_accept_receive(int source);
84

  
85
/*Global Variables*/
86

  
87
//the robot we are waiting to say it has received the token. -1 if unspecified
88
static int wl_token_next_robot = -1;
89

  
90
//true if the robot should be in the token ring, 0 otherwise
91
static int ringState = NONMEMBER;
92
//the id of the robot who accepted us into the token ring, only used in ACCEPTED state
93
static int acceptor = -1;
94
//id of the robot we are accepting
95
static int accepted = -1;
96

  
97
//the counter for when we assume a robot is dead
98
static int deathDelay = -1;
99
//the counter for joining, before we form our own token ring
100
static int joinDelay = -1;
101

  
102
//current robot to check in the iterator
103
static int iteratorCount = 0;
104

  
105
// the amount of time a robot has had its BOM on for
106
static int bom_on_count = 0;
107

  
108
#ifndef ROBOT
109
static void do_nothing(void) {}
110
static int get_nothing(void) {return -1;}
111
#endif
112

  
113
#ifdef ROBOT
114
#ifndef FIREFLY
115
static void (*bom_on_function) (void) = bom_on;
116
static void (*bom_off_function) (void) = bom_off;
117
static int (*get_max_bom_function) (void) = get_max_bom;
118
#else
119
static void (*bom_on_function) (void) = do_nothing;
120
static void (*bom_off_function) (void) = do_nothing;
121
static int (*get_max_bom_function) (void) = get_nothing;
122
#endif
123
#else
124
static void (*bom_on_function) (void) = do_nothing;
125
static void (*bom_off_function) (void) = do_nothing;
126
static int (*get_max_bom_function) (void) = get_nothing;
127
#endif
128

  
129
static PacketGroupHandler wl_token_ring_handler =
130
	{WL_TOKEN_RING_GROUP, wl_token_ring_timeout_handler,
131
		wl_token_ring_response_handler, wl_token_ring_receive_handler,
132
		wl_token_ring_cleanup};
133

  
134
/**
135
 * Causes the robot to join an existing token ring, or create one
136
 * if no token ring exists. The token ring uses global and robot to robot
137
 * packets, and does not rely on any PAN.
138
 **/
139
int wl_token_ring_join()
140
{
141
	WL_DEBUG_PRINT("Joining the token ring.\r\n");
142

  
143
	ringState = JOINING;
144
	joinDelay = DEATH_DELAY * 2;
145
	if (wl_send_global_packet(WL_TOKEN_RING_GROUP, WL_TOKEN_JOIN, NULL, 0, 0) != 0) {
146
		return -1;
147
	}
148

  
149
	return 0;
150
}
151

  
152
/**
153
 * Causes the robot to leave the token ring. The robot stops
154
 * alerting others of its location, but continues storing the
155
 * locations of other robots.
156
 **/
157
void wl_token_ring_leave()
158
{
159
	ringState = LEAVING;
160
}
161

  
162
/**
163
 * Initialize the token ring packet group and register it with the
164
 * wireless library. The robot will not join a token ring.
165
 **/
166
int wl_token_ring_register()
167
{
168
	if (wl_get_xbee_id() > 0xFF)
169
	{
170
		//Note: if this becomes an issue (unlikely), we could limit sensor information
171
		//to half a byte and use 12 bits for the id
172
		WL_DEBUG_PRINT("XBee ID must be single byte for token ring, is ");
173
		WL_DEBUG_PRINT_INT(wl_get_xbee_id());
174
		WL_DEBUG_PRINT(".\r\n");
175
		return -1;
176
	}
177

  
178
	sensor_matrix_create();
179
	//add ourselves to the sensor matrix
180
	sensor_matrix_set_in_ring(wl_get_xbee_id(), 0);
181

  
182
	wl_register_packet_group(&wl_token_ring_handler);
183

  
184
	return 0;
185
}
186

  
187
/**
188
 * Removes the packet group from the wireless library.
189
 **/
190
void wl_token_ring_unregister()
191
{
192
	wl_unregister_packet_group(&wl_token_ring_handler);
193
}
194

  
195
/**
196
 * Sets the functions that are called when the BOM ought to be
197
 * turned on or off. This could be used for things such as
198
 * charging stations, which have multiple BOMs.
199
 *
200
 * @param on_function the function to be called when the BOM
201
 * should be turned on
202
 * @param off_function the function to be called when the BOM
203
 * should be turned off
204
 * @param max_bom_function the function to be called when a
205
 * measurement of the maximum BOM reading is needed.
206
 **/
207
void wl_token_ring_set_bom_functions(void (*on_function) (void),
208
	void (*off_function) (void), int (*max_bom_function) (void))
209
{
210
	bom_on_function = on_function;
211
	bom_off_function = off_function;
212
	get_max_bom_function = max_bom_function;
213
}
214

  
215
/**
216
 * Called to cleanup the token ring packet group.
217
 **/
218
static void wl_token_ring_cleanup()
219
{
220
}
221

  
222
/**
223
 * Called approximately every quarter second by the wireless library.
224
 **/
225
static void wl_token_ring_timeout_handler()
226
{
227
	//someone is not responding, assume they are dead
228
	if (deathDelay == 0)
229
	{
230
		//pass the token to the next robot if we think someone has died
231
		//also, declare that person dead, as long as it isn't us
232
		if (wl_token_next_robot != wl_get_xbee_id())
233
		{
234
			sensor_matrix_set_in_ring(wl_token_next_robot, 0);
235
			WL_DEBUG_PRINT("Robot ");
236
			WL_DEBUG_PRINT_INT(wl_token_next_robot);
237
			WL_DEBUG_PRINT(" has died.\r\n");
238
			wl_token_next_robot = -1;
239
			deathDelay = DEATH_DELAY;
240
		}
241

  
242
		// we may have been dropped from the ring when this is received
243
		if (ringState == MEMBER) {
244
			wl_token_pass_token();
245
		}
246
	}
247

  
248
	//we must start our own token ring, no one is responding to us
249
	if (joinDelay == 0)
250
	{
251
		if (sensor_matrix_get_joined() == 0)
252
		{
253
			WL_DEBUG_PRINT("Creating our own token ring, no robots seem to exist.\r\n");
254
			sensor_matrix_set_in_ring(wl_get_xbee_id(), 1);
255
			ringState = MEMBER;
256
			//this will make us pass the token to ourself
257
			//repeatedly, and other robots when they join
258
			deathDelay = DEATH_DELAY;
259
			wl_token_next_robot = wl_get_xbee_id();
260
		}
261
		else
262
		{
263
			WL_DEBUG_PRINT("Attempting to join the token ring again.\r\n");
264
			//attempt to rejoin with a random delay
265
      //TODO: should we use the constant JOIN_DELAY ?
266
			wl_token_ring_join();
267
			joinDelay = rand() / (RAND_MAX / JOIN_DELAY) + 1;
268
		}
269
	}
270

  
271
	if (deathDelay >= 0) {
272
		deathDelay--;
273
	}
274

  
275
	if (joinDelay >= 0) {
276
		joinDelay--;
277
	}
278

  
279
	if (bom_on_count >= 0) {
280
		bom_on_count++;
281
	}
282
}
283

  
284
/**
285
 * Called when the XBee tells us if a packet we sent has been received.
286
 *
287
 * @param frame the frame number assigned when the packet was sent
288
 * @param received 1 if the packet was received, 0 otherwise
289
 **/
290
static void wl_token_ring_response_handler(int frame, int received)
291
{
292
	if (!received)
293
	{
294
		WL_DEBUG_PRINT("FAILED.\r\n");
295
	}
296
}
297

  
298
/**
299
 * Called when we recieve a token ring packet.
300
 * @param type the type of the packet
301
 * @param source the id of the robot who sent the packet
302
 * @param packet the data in the packet
303
 * @param length the length of the packet in bytes
304
 **/
305
static void wl_token_ring_receive_handler(char type, int source, unsigned char* packet, int length)
306
{
307
	switch (type)
308
	{
309
		case WL_TOKEN_PASS:
310
			wl_token_pass_receive(source);
311
			break;
312
		case WL_TOKEN_SENSOR_MATRIX:
313
			wl_token_sensor_matrix_receive(source, packet, length);
314
			break;
315
		case WL_TOKEN_BOM_ON:
316
			//add the robot to the sensor matrix if it is not already there
317
			wl_token_bom_on_receive(source);
318
			break;
319
		case WL_TOKEN_JOIN:
320
			wl_token_join_receive(source);
321
			break;
322
		case WL_TOKEN_JOIN_ACCEPT:
323
			wl_token_join_accept_receive(source);
324
			break;
325
		default:
326
			WL_DEBUG_PRINT("Unimplemented token ring packet received.\r\n");
327
			break;
328
	}
329
}
330

  
331
/**
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff