Subversion Repositories svnkaklik

Rev

Details | Last modification | View Log

Rev Author Line No. Line
151 kaklik 1
/*
2
    Copyright (C) 2004    John Orlando
3
 
4
   AVRcam: a small real-time image processing engine.
5
 
6
    This program is free software; you can redistribute it and/or
7
    modify it under the terms of the GNU General Public
8
    License as published by the Free Software Foundation; either
9
    version 2 of the License, or (at your option) any later version.
10
 
11
    This program is distributed in the hope that it will be useful,
12
    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
    General Public License for more details.
15
 
16
    You should have received a copy of the GNU General Public
17
    License along with this program; if not, write to the Free Software
18
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
 
20
   For more information on the AVRcam, please contact:
21
 
22
   john@jrobot.net
23
 
24
   or go to www.jrobot.net for more details regarding the system.
25
*/
26
/***********************************************************
27
	Module Name: UIMgr.c
28
	Module Date: 04/10/2004
29
	Module Auth: John Orlando
30
 
31
	Description: This module is responsible for providing
32
	the processing to manage the user interface of the
33
	system.  This user interface is provided via the UART.
34
	This module handles the incoming serial commands, and
35
	performs the needed functionality.  It is then
36
	responsible for generating any needed response to
37
	the external entity.
38
 
39
    Revision History:
40
    Date        Rel Ver.    Notes
41
    4/10/2004      0.1     Module created
42
    6/30/2004      1.0     Initial release for Circuit Cellar
43
                           contest.
44
    11/15/2004     1.2     Updated version string to 1.2.
45
    1/16/2005      1.4     Added code to write the colorMap
46
                           to EEPROM one byte at a time, 
47
                           ensuring that the EEPROM is only
48
                           written when the data is different
49
                           than the current value (thus saving
50
                           EEPROM writes).  Updated version
51
                           string to 1.4.
52
***********************************************************/
53
 
54
/*	Includes */
55
#include <avr/io.h>
56
#include <stdlib.h>
57
#include <string.h>
58
#include <avr/eeprom.h>
59
#include "CommonDefs.h"
60
#include "UIMgr.h"
61
#include "UartInterface.h"
62
#include "CamConfig.h"
63
#include "Utility.h"
64
#include "Executive.h"
65
#include "CamInterface.h"
66
 
67
/* 	Local Structures and Typedefs */
68
 
69
typedef enum
70
{
71
	getVersionCmd,
72
	pingCmd,
73
	setCameraRegsCmd,
74
	dumpFrameCmd,
75
	enableTrackingCmd,
76
	disableTrackingCmd,
77
	setColorMapCmd,
78
	resetCameraCmd,
79
	noCmd,
80
	invalidCmd
81
} UIMgr_Cmd_t;
82
 
83
typedef enum
84
{
85
	setRed,
86
	setGreen,
87
	setBlue
88
} setColorState_t;
89
 
90
 
91
/*  Local Variables */
92
static unsigned char charCount = 0; 
93
static unsigned char charIndex = 0;
94
static unsigned char asciiTokenBuffer[MAX_TOKEN_LENGTH+1]; /* +1 to ensure NULL at end */
95
static unsigned char tokenCount = 0;
96
static unsigned char tokenBuffer[MAX_TOKEN_COUNT];
97
static UIMgr_Cmd_t receivedCmd = noCmd;
98
static unsigned char AVRcamVersion[] = "AVRcam v1.4\r";
99
 
100
/*  Local Function Declaration */
101
static unsigned char UIMgr_readRxFifo(void);
102
static unsigned char UIMgr_readTxFifo(void);
103
static unsigned char UIMgr_readRxFifo(void);
104
static void UIMgr_sendNck(void);
105
static void UIMgr_sendAck(void);
106
static void UIMgr_convertTokenToCmd(void);
107
static void UIMgr_convertTokenToValue(void);
108
static void UIMgr_executeCmd(void);
109
 
110
/*  Extern Variables */
111
unsigned char UIMgr_rxFifo[UI_MGR_RX_FIFO_SIZE];
112
unsigned char UIMgr_rxFifoHead=0;
113
unsigned char UIMgr_rxFifoTail=0;
114
 
115
unsigned char UIMgr_txFifo[UI_MGR_TX_FIFO_SIZE];
116
unsigned char UIMgr_txFifoHead=0;
117
unsigned char UIMgr_txFifoTail=0;
118
 
119
/*  Definitions */
120
#define IS_DATA_IN_TX_FIFO() (!(UIMgr_txFifoHead == UIMgr_txFifoTail))
121
#define IS_DATA_IN_RX_FIFO() (!(UIMgr_rxFifoHead == UIMgr_rxFifoTail))
122
 
123
/* MAX_EEPROM_WRITE_ATTEMPTS limits the number of writes that can be
124
done to a particular EEPROM cell, so that it can't possible just 
125
write to the same cell over and over */
126
#define MAX_EEPROM_WRITE_ATTEMPTS 3
127
 
128
/***********************************************************
129
	Function Name: UIMgr_init
130
	Function Description: This function is responsible for
131
	initializing the UIMgr module.  It sets up the fifo
132
	used to hold incoming data, etc.
133
	Inputs:  none 
134
	Outputs: none
135
***********************************************************/	
136
void UIMgr_init(void)
137
{
138
	memset(asciiTokenBuffer,0x00,MAX_TOKEN_LENGTH+1);
139
	memset(tokenBuffer,0x00,MAX_TOKEN_COUNT);
140
	memset(UIMgr_txFifo,0x00,UI_MGR_TX_FIFO_SIZE);
141
	memset(UIMgr_rxFifo,0x00,UI_MGR_RX_FIFO_SIZE);
142
}
143
 
144
/***********************************************************
145
	Function Name: UIMgr_dispatchEvent
146
	Function Description: This function is responsible for
147
	processing events that pertain to the UIMgr.
148
	Inputs:  event - the generated event
149
	Outputs: none
150
***********************************************************/	
151
void UIMgr_dispatchEvent(unsigned char event)
152
{
153
	switch(event)
154
	{
155
		case EV_ACQUIRE_LINE_COMPLETE:
156
			UIMgr_transmitPendingData();
157
			break;
158
 
159
		case EV_SERIAL_DATA_RECEIVED:		
160
			UIMgr_processReceivedData();
161
			break;
162
 
163
		case EV_SERIAL_DATA_PENDING_TX:
164
			UIMgr_flushTxBuffer();
165
			break;
166
	}
167
}
168
/***********************************************************
169
	Function Name: UIMgr_transmitPendingData
170
	Function Description: This function is responsible for
171
	transmitting a single byte of data if data is waiting
172
	to be sent.  Otherwise, if nothing is waiting, the
173
	function just returns.
174
	Inputs:  none 
175
	Outputs: none
176
***********************************************************/
177
void UIMgr_transmitPendingData(void)
178
{
179
	if (IS_DATA_IN_TX_FIFO() == TRUE)
180
	{
181
		/* data is waiting...send a single byte */
182
		UartInt_txByte( UIMgr_readTxFifo() );
183
	}
184
}
185
/***********************************************************
186
	Function Name: UIMgr_processReceivedData
187
	Function Description: This function is responsible for
188
	parsing any serial data waiting in the rx fifo
189
	Inputs:  none 
190
	Outputs: none
191
***********************************************************/
192
void UIMgr_processReceivedData(void)
193
{
194
	unsigned char tmpData = 0;
195
 
196
	/* still need to add a mechanism to handle token counts 
197
	that are excessive!!! FIX ME!!! */
198
 
199
	while(IS_DATA_IN_RX_FIFO() == TRUE)
200
	{
201
		tmpData = UIMgr_readRxFifo();
202
		if (tmpData == '\r') 
203
		{
204
			/* we have reached a token separator */
205
			if (tokenCount == 0)
206
			{
207
				/* convert the command */
208
				UIMgr_convertTokenToCmd();				
209
			}
210
			else
211
			{
212
				/* convert a value */
213
				UIMgr_convertTokenToValue();
214
				tokenCount++;
215
			}
216
			/* either way, it is time to try to process the received
217
			token list since we have reached the end of the cmd. */
218
			Utility_delay(100);
219
			if (receivedCmd == invalidCmd ||
220
			     receivedCmd == noCmd )
221
			{
222
				UIMgr_sendNck();
223
				PUBLISH_EVENT(EV_SERIAL_DATA_PENDING_TX);
224
			}
225
			else
226
			{
227
				UIMgr_sendAck();
228
				/* publish the serial data pending event, so it
229
				will push the ACK out before we execute the cmd */
230
				PUBLISH_EVENT(EV_SERIAL_DATA_PENDING_TX);
231
				UIMgr_executeCmd();
232
			}
233
 
234
			/* reset any necessary data */
235
			tokenCount = 0;
236
			memset(tokenBuffer,0x00,MAX_TOKEN_COUNT);
237
		}
238
		else if (tmpData == ' ')  /* space char */
239
		{
240
			/* the end of a token has been reached */
241
			if (tokenCount == 0)
242
			{
243
				UIMgr_convertTokenToCmd();
244
				tokenCount++;   /* check this...why is this being incremented here??? This
245
                means we have received a token, with tokenCount == 0, which means it is a
246
                command...why is this contributing to tokenCount?
247
                This might cause the set color map command to include too much data, since
248
                it sets the color map based on tokenCount...CHECK*/
249
			}
250
			else
251
			{
252
				/* check to see if this token is going to push
253
				us over the limit...if so, abort the transaction */
254
				if (tokenCount+1 >= MAX_TOKEN_COUNT)
255
				{
256
					/* we received too many tokens, and 
257
					need to NCK this request, since its too
258
					large...reset everything...*/
259
					charCount=0;
260
					charIndex=0;
261
					tokenCount=0;
262
					receivedCmd = invalidCmd;
263
				}
264
				else
265
				{
266
					/* tokenCount is still in range...*/
267
					UIMgr_convertTokenToValue();
268
					tokenCount++;
269
				}
270
			}
271
		}
272
		else if ( (tmpData >= 'A' && tmpData <= 'Z') ||
273
				   (tmpData >= '0' && tmpData <= '9') )
274
		{
275
			/* a valid range of token was received */
276
			asciiTokenBuffer[charIndex] = tmpData;
277
			charCount++;
278
			charIndex++;
279
			if (charCount > MAX_TOKEN_LENGTH)
280
			{
281
				/* we have received a token that cannot be handled...
282
				set the received cmd to an invalid cmd, and wait
283
				for the \r to process it */
284
				receivedCmd = invalidCmd;
285
				charIndex = 0;  /* ...so we won't overwrite memory */
286
			}
287
		}
288
		else
289
		{
290
			/* an invalid character was received */
291
			receivedCmd = invalidCmd;
292
		}
293
	}  /* end while */
294
 
295
	asm volatile("clt"::);  /* clear out the T flag in case it wasn't
296
								 cleared already */
297
}						
298
 
299
/***********************************************************
300
	Function Name: UIMgr_executeCmd
301
	Function Description: This function is responsible for
302
	executing whatever cmd is stored in the receivedCmd
303
	object.
304
	Inputs:  none 
305
	Outputs: none
306
***********************************************************/
307
static void UIMgr_executeCmd(void)
308
{
309
	unsigned char i,eepromData, num_writes=0;
310
	unsigned char *pData;
311
    unsigned char eeprom_write_succeeded = FALSE;
312
#if	DEBUG_COLOR_MAP	
313
	unsigned char asciiBuffer[5];
314
#endif
315
 
316
	if (receivedCmd == pingCmd) 
317
	{
318
	}
319
	else if (receivedCmd == getVersionCmd)
320
	{
321
		pData = AVRcamVersion;
322
		while(*pData != 0)
323
		{		
324
			UIMgr_writeTxFifo(*pData++);
325
		}
326
	}		
327
	else if (receivedCmd == resetCameraCmd)
328
	{
329
		CamInt_resetCam();
330
	}
331
	else if (receivedCmd == dumpFrameCmd)
332
	{
333
		/* publish the event that will indicate that
334
		a request has come to dump a frame...this will
335
		be received by the FrameMgr, which will begin
336
		dumping the frame...a short delay is needed
337
		here to keep the Java demo app happy (sometimes
338
		it wouldn't be able to receive the serial data
339
		as quickly as AVRcam can provide it). */
340
		Utility_delay(100);
341
		PUBLISH_EVENT(EV_DUMP_FRAME);
342
	}
343
	else if (receivedCmd == setCameraRegsCmd)
344
	{
345
		/* we need to gather the tokens and
346
		build config cmds to be sent to the camera */
347
		for (i=1; i<tokenCount; i+=2)  /* starts at 1 since first token
348
											is the CR cmd */
349
		{
350
			CamConfig_setCamReg(tokenBuffer[i],tokenBuffer[i+1]);
351
		}
352
		CamConfig_sendFifoCmds();
353
	}
354
	else if (receivedCmd == enableTrackingCmd)
355
	{
356
		/* publish the event...again with a short delay */
357
		Utility_delay(100);
358
		PUBLISH_EVENT(EV_ENABLE_TRACKING);
359
	}
360
	else if (receivedCmd == disableTrackingCmd)
361
	{
362
		PUBLISH_EVENT(EV_DISABLE_TRACKING);
363
	}
364
	else if (receivedCmd == setColorMapCmd)
365
	{
366
		/* copy the received tokens into the color map */
367
		for (i=0; i<tokenCount; i++)
368
		{
369
			colorMap[i] = tokenBuffer[i+1];
370
 
371
            /* write each colorMap byte to EEPROM, but only those
372
            that changed...this will help reduce wear on the EEPROM */
373
            eepromData = eeprom_read_byte( (unsigned char*)(i+1));
374
            if (eepromData != colorMap[i])
375
            {
376
                /* need to actually perform the write because the
377
                data in eeprom is different than the current colorMap */
378
                eeprom_write_succeeded = FALSE;
379
                while(eeprom_write_succeeded == FALSE && num_writes < MAX_EEPROM_WRITE_ATTEMPTS)
380
                {
381
                    eeprom_write_byte((unsigned char*)(i+1),colorMap[i]);
382
                    num_writes++;
383
                    eepromData = eeprom_read_byte( (unsigned char*)(i+1));
384
                    if (eepromData == colorMap[i])
385
                    {
386
                        eeprom_write_succeeded = TRUE;
387
                    }
388
                }
389
                num_writes = 0;
390
            }
391
		}
392
 
393
#if	DEBUG_COLOR_MAP			
394
            			/* for debugging...send out the entire color map */
395
        UIMgr_txBuffer("\r\n",2);
396
		for (i=0; i<NUM_ELEMENTS_IN_COLOR_MAP; i++)
397
		{
398
			memset(asciiBuffer,0x00,5);
399
			itoa(colorMap[i],asciiBuffer,10);
400
			UIMgr_txBuffer(asciiBuffer,3);
401
			UIMgr_txBuffer(" ",1);
402
			if (i==15 || i == 31)
403
			{
404
				/* break up the output */
405
				UIMgr_txBuffer("\r\n",2);
406
			}
407
		}
408
#endif			
409
	}
410
}
411
 
412
/***********************************************************
413
	Function Name: UIMgr_convertTokenToValue
414
	Function Description: This function is responsible for
415
	converting a received token to a hex value It will
416
	access the asciiTokenBuffer directly, and store the
417
	result in the appropriate token buffer.
418
	Inputs:  none 
419
	Outputs: none
420
***********************************************************/	
421
static void UIMgr_convertTokenToValue(void)
422
{
423
	unsigned int newValue;
424
 
425
	newValue = atoi(asciiTokenBuffer);
426
	if (newValue > 255)
427
	{
428
		/* the value is too large */
429
		receivedCmd = invalidCmd;
430
		tokenBuffer[tokenCount] = 0xFF;  /* to indicate an error */
431
	}
432
	else
433
	{
434
		/* copy the value into the tokenBuffer */
435
		tokenBuffer[tokenCount] = newValue;
436
	}
437
	memset(asciiTokenBuffer,0x00,MAX_TOKEN_LENGTH);
438
	charIndex = 0;
439
	charCount = 0;
440
}
441
/***********************************************************
442
	Function Name: UIMgr_convertTokenToCmd
443
	Function Description: This function is responsible for
444
	parsing a received 2-character command.  It will
445
	access the asciiTokenBuffer directly.
446
	Inputs:  none 
447
	Outputs: none
448
***********************************************************/	
449
static void UIMgr_convertTokenToCmd(void)
450
{
451
	if ( (asciiTokenBuffer[0] == 'P') &&
452
		 (asciiTokenBuffer[1] == 'G') )
453
	{
454
		/* we got a "ping" command...but we still need to see
455
		if we are going to get the \r */
456
		receivedCmd = pingCmd;
457
	}
458
	else if ( (asciiTokenBuffer[0] == 'G') &&
459
			   (asciiTokenBuffer[1] == 'V') )
460
	{
461
		/* we got the "get version" command */
462
		receivedCmd = getVersionCmd;
463
	}
464
	else if ( (asciiTokenBuffer[0] == 'D') &&
465
			   (asciiTokenBuffer[1] == 'F') )
466
	{
467
		/* we should go into frame dump mode */
468
		receivedCmd = dumpFrameCmd;	
469
	}
470
	else if ( (asciiTokenBuffer[0] == 'C') &&
471
	           (asciiTokenBuffer[1] == 'R') )
472
	{
473
		/* the user wants to set registers in the OV6620 */
474
		receivedCmd = setCameraRegsCmd;
475
	}
476
	else if ( (asciiTokenBuffer[0] == 'E') &&
477
			   (asciiTokenBuffer[1] == 'T') )
478
	{
479
		/* the user wants to enable tracking */
480
		receivedCmd = enableTrackingCmd;
481
	}
482
	else if ( (asciiTokenBuffer[0] == 'S') &&
483
			   (asciiTokenBuffer[1] == 'M') )
484
	{
485
		/* the user wants to set the color map */
486
		receivedCmd = setColorMapCmd;
487
	}
488
	else if ( (asciiTokenBuffer[0] == 'D') &&
489
			   (asciiTokenBuffer[1] == 'T') )
490
	{
491
		receivedCmd = disableTrackingCmd;
492
	}
493
	else if ( (asciiTokenBuffer[0] == 'R') &&
494
			   (asciiTokenBuffer[1] == 'S') )
495
	{
496
		receivedCmd = resetCameraCmd;
497
	}
498
	else
499
	{
500
		/* don't recognize the cmd */
501
		receivedCmd = invalidCmd;
502
	}
503
	memset(asciiTokenBuffer,0x00,MAX_TOKEN_LENGTH);
504
	charIndex = 0;
505
	charCount = 0;
506
}
507
/***********************************************************
508
	Function Name: UIMgr_sendAck
509
	Function Description: This function is responsible for
510
	queuing up an ACK to be sent to the user.
511
	Inputs:  none 
512
	Outputs: none
513
***********************************************************/	
514
static void UIMgr_sendAck(void)
515
{
516
	UIMgr_writeTxFifo('A');
517
	UIMgr_writeTxFifo('C');
518
	UIMgr_writeTxFifo('K');
519
	UIMgr_writeTxFifo('\r');
520
}
521
 
522
/***********************************************************
523
	Function Name: UIMgr_sendNck
524
	Function Description: This function is responsible for
525
	queueing up an NCK to be sent to the user.
526
	Inputs:  none 
527
	Outputs: none
528
***********************************************************/	
529
static void UIMgr_sendNck(void)
530
{
531
		UIMgr_writeTxFifo('N');
532
		UIMgr_writeTxFifo('C');
533
		UIMgr_writeTxFifo('K');
534
		UIMgr_writeTxFifo('\r');
535
}
536
 
537
 
538
/***********************************************************
539
	Function Name: UIMgr_writeBufferToTxFifo
540
	Function Description: This function is responsible for
541
	placing "length" bytes into the tx FIFO.
542
	Inputs:  pData -  a pointer to the data to send
543
	         length - the number of bytes to send
544
	Outputs: none
545
***********************************************************/	
546
void UIMgr_writeBufferToTxFifo(unsigned char *pData, unsigned char length)
547
{
548
	unsigned char tmpHead;
549
	if (length == 0)
550
	{
551
		return;
552
	}
553
 
554
	DISABLE_INTS();
555
	while(length-- != 0)
556
	{
557
		UIMgr_txFifo[UIMgr_txFifoHead] = *pData++;
558
 
559
		/* now move the head up */
560
		tmpHead = (UIMgr_txFifoHead + 1) & (UI_MGR_TX_FIFO_MASK);
561
		UIMgr_txFifoHead = tmpHead;
562
	}
563
	ENABLE_INTS();
564
}
565
 
566
/***********************************************************
567
	Function Name: UIMgr_txBuffer
568
	Function Description: This function is responsible for
569
	sending 'length' bytes out using the UartInterface 
570
	module.
571
	Inputs:  pData -  a pointer to the data to send
572
	         length - the number of bytes to send
573
	Outputs: none
574
***********************************************************/	
575
void UIMgr_txBuffer(unsigned char *pData, unsigned char length)
576
{
577
	while(length-- != 0)
578
	{
579
		UartInt_txByte(*pData++); 
580
	}
581
}
582
 
583
/***********************************************************
584
	Function Name: UIMgr_flushTxBuffer
585
	Function Description: This function is responsible for
586
	sending all data currently in the serial tx buffer
587
	to the user.
588
	Inputs:  none
589
	Outputs: none
590
***********************************************************/	
591
void UIMgr_flushTxBuffer(void)
592
{
593
	while(IS_DATA_IN_TX_FIFO() == TRUE)
594
	{
595
		UartInt_txByte(UIMgr_readTxFifo() );
596
	}
597
}
598
 
599
/***********************************************************
600
	Function Name: UIMgr_readRxFifo
601
	Function Description: This function is responsible for
602
	reading a single byte of data from the rx fifo, and
603
	updating the appropriate pointers.
604
	Inputs:  none 
605
	Outputs: unsigned char-the data read
606
***********************************************************/	
607
static unsigned char UIMgr_readRxFifo(void)
608
{
609
	unsigned char dataByte, tmpTail;
610
 
611
	/* just return the current tail from the rx fifo */
612
	DISABLE_INTS();
613
	dataByte = UIMgr_rxFifo[UIMgr_rxFifoTail];	
614
	tmpTail = (UIMgr_rxFifoTail+1) & (UI_MGR_RX_FIFO_MASK);
615
	UIMgr_rxFifoTail = tmpTail;
616
	ENABLE_INTS();
617
 
618
	return(dataByte);
619
}
620
 
621
/***********************************************************
622
	Function Name: UIMgr_readTxFifo
623
	Function Description: This function is responsible for
624
	reading a single byte of data from the tx fifo, and
625
	updating the appropriate pointers.
626
	Inputs:  none 
627
	Outputs: unsigned char-the data read
628
***********************************************************/	
629
static unsigned char UIMgr_readTxFifo(void)
630
{
631
	unsigned char dataByte, tmpTail;
632
 
633
	/* just return the current tail from the tx fifo */
634
	DISABLE_INTS();
635
	dataByte = UIMgr_txFifo[UIMgr_txFifoTail];	
636
	tmpTail = (UIMgr_txFifoTail+1) & (UI_MGR_TX_FIFO_MASK);
637
	UIMgr_txFifoTail = tmpTail;
638
	ENABLE_INTS();
639
 
640
	return(dataByte);
641
}
642
 
643
/***********************************************************
644
	Function Name: UIMgr_writeTxFifo
645
	Function Description: This function is responsible for
646
	writing a single byte to the TxFifo and
647
	updating the appropriate pointers.
648
	Inputs:  data - the byte to write to the Fifo 
649
	Outputs: none
650
***********************************************************/	
651
void UIMgr_writeTxFifo(unsigned char data)
652
{
653
	unsigned char tmpHead;
654
 
655
	DISABLE_INTS();
656
	UIMgr_txFifo[UIMgr_txFifoHead] = data;
657
 
658
    /* now move the head up */
659
    tmpHead = (UIMgr_txFifoHead + 1) & (UI_MGR_TX_FIFO_MASK);
660
    UIMgr_txFifoHead = tmpHead;
661
	ENABLE_INTS();
662
 
663
}
664