Subversion Repositories svnkaklik

Rev

Details | Last modification | View Log

Rev Author Line No. Line
268 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: FrameMgr.c
28
	Module Date: 04/10/2004
29
	Module Auth: John Orlando
30
 
31
	Description: This modules is responsible for performing
32
	both medium and high level processing on image data.
33
	This is performed at both the line level as well as
34
	the frame level.  It controls the main flow of the
35
	system, adhering to all the critical timing 
36
	requirements (such as when serial data can be transferred,
37
	etc).
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 processLine() function so 
45
                           it will remove objects less than
46
                           a specified length/width (reduces
47
                           shot noise)
48
*********************************************************/
49
 
50
/*	Includes */
51
#include <stdlib.h>
52
#include <string.h>
53
#include <avr/io.h>
54
#include "Executive.h"
55
#include "UIMgr.h"
56
#include "FrameMgr.h"
57
#include "CamInterface.h"
58
#include "UartInterface.h"
59
#include "Utility.h"
60
#include "I2CInterface.h"
61
#include "CamConfig.h"
62
#include "CommonDefs.h"
63
 
64
/* 	Local Structures and Typedefs */
65
enum
66
{
67
	ST_FrameMgr_idle,
68
	ST_FrameMgr_TrackingFrame,
69
	ST_FrameMgr_DumpingFrame
70
};
71
 
72
typedef unsigned char FrameMgr_State_t;
73
 
74
/*  Definitions */
75
/* The most objects that can be tracked at any one time is 8.  
76
This number is determined by the number of bytes that can be
77
sent out during a frame (one byte per line, 144 lines per frame) 
78
with the number of bytes in a tracked object (7) + some wiggle
79
room :-) ... I guess this could be increased to around 20 if
80
we had enough room and cycles to process objects between lines */
81
#define MAX_TRACKED_OBJECTS	8
82
 
83
/* This defines the number of bytes that make up a trackedObject_t
84
structure... */
85
#define SIZE_OF_TRACKED_OBJECT 8
86
 
87
/* This define is used to turn off the timer overflow interrupt
88
that is generated when the PCLK overflows TIMER1 */
89
#define DISABLE_PCLK_TIMER1_OVERFLOW_BITMASK 0xFB
90
 
91
/* This define is used to determine if a run length is too small
92
to be concerned with.  This helps to reduce the number of false
93
positives. */
94
#define MIN_OBJECT_TRACKING_WIDTH 3
95
 
96
/* This define is used to determine if an object has enough
97
height to be considered worth tracking...it is used to reduce
98
shot noise */
99
#define MIN_OBJECT_TRACKING_HEIGHT 3
100
 
101
/* This define is used to indicate how often the filter routine
102
that removes objects less than MIN_OBJECT_TRACKING_HEIGHT should
103
be executed.  It is measured in a number of lines (7 nominally). */
104
#define RUN_OBJECT_FILTER_MASK 0x07
105
 
106
/* This enum describes the possible colors that can
107
be tracked by the system.  This can't be represented as
108
simple color names (red, brown, etc) due to the fact that
109
the user sets which colors will be associated with which
110
bits.  Remember...after the AND operation of the indexed
111
color map values executes, either a single bit indicating
112
the color should be set, or no bits indicating that the
113
color isn't represented in the color map (notTracked). */
114
enum
115
{
116
	notTracked,
117
	color1,		/* bit 1 color */
118
	color2,		/* bit 2 color */
119
	color3,		/* bit 3 color */
120
	color4,		/* bit 4 color */
121
	color5,		/* bit 5 color */
122
	color6,		/* bit 6 color */
123
	color7,		/* bit 7 color */
124
	color8		/* bit 8 color */
125
};
126
 
127
typedef unsigned char trackedColor_t;
128
 
129
/* This structure defines the info that needs to be
130
maintained for each trackedObject in the trackingTable */
131
typedef struct
132
{
133
	trackedColor_t  color;
134
	unsigned char lastLineXStart;
135
	unsigned char lastLineXFinish;
136
	unsigned char x_upperLeft;
137
	unsigned char y_upperLeft;
138
	unsigned char x_lowerRight;
139
	unsigned char y_lowerRight;
140
	unsigned char objectValid;  /* used to be a fill byte...now it is
141
                                     used to determine if the object is valid
142
                                     or not...it gets invalidated if it is
143
                                     determined that it is too small, or
144
                                     that the object is within another object */
145
} trackedObject_t;
146
 
147
/* These defines are used to index into each individual element in the
148
trackedObject_t structure.  This seems to be MUCH more efficient than
149
accessing the elements in GCC. */
150
#define COLOR_OFFSET                0
151
#define LAST_LINE_X_START_OFFSET    1
152
#define LAST_LINE_X_FINISH_OFFSET   2
153
#define X_UPPER_LEFT_OFFSET         3
154
#define Y_UPPER_LEFT_OFFSET         4
155
#define X_LOWER_RIGHT_OFFSET        5
156
#define Y_LOWER_RIGHT_OFFSET        6
157
#define VALID_OBJECT_OFFSET         7
158
 
159
/*  Local Variables */
160
/* The trackedObjectTable is used to hold up to eight tracked objects
161
while they are being acquired. */
162
static trackedObject_t trackedObjectTable[MAX_TRACKED_OBJECTS];
163
static trackedObject_t *pCurrentTrackedObjectTable = trackedObjectTable;
164
static unsigned char lineCount = 0;
165
static FrameMgr_State_t currentState = ST_FrameMgr_idle;
166
static unsigned char numCurrTrackedObjects = 0;
167
static unsigned char numPrevTrackedObjects = 0;
168
static unsigned char trackedLineCount = 0;
169
 
170
/*  Local Functions  */
171
static void FrameMgr_findConnectedness(void);
172
 
173
/*  Extern Functions */
174
/* These functions are located in assembly files, and thus
175
must be externed here so they can be referenced in the source below. */
176
extern void CamIntAsm_waitForNewTrackingFrame(unsigned char *pBuffer, unsigned char *pMemLookup);
177
extern void CamIntAsm_waitForNewDumpFrame(unsigned char *pCurrBuffer, unsigned char *pPrevBuffer);
178
extern void CamIntAsm_acquireTrackingLine(unsigned char *pBuffer, unsigned char *pMemLookup);
179
extern void CamIntAsm_acquireDumpLine(unsigned char *pCurrBuffer, unsigned char *pPrevBuffer);
180
 
181
/***********************************************************
182
	Function Name: FrameMgr_init
183
	Function Description: This function is responsible
184
	for initializing the FrameMgr.  This includes 
185
	setting up the various buffers and data needed to 
186
	process each frame of image data.
187
	Inputs:  none
188
	Outputs: none
189
***********************************************************/	
190
void FrameMgr_init(void)
191
{
192
	memset(trackedObjectTable,0x00,sizeof(trackedObjectTable));
193
}
194
 
195
 
196
/***********************************************************
197
	Function Name: FrameMgr_dispatchEvent
198
	Function Description: This function is responsible for
199
	taking an incoming event and performing the needed
200
	actions with it as pertains to the FrameMgr.
201
	Inputs:  event - the generated event
202
	Outputs: none
203
***********************************************************/	
204
void FrameMgr_dispatchEvent(unsigned char event)
205
{	
206
	switch(event)
207
	{
208
		case EV_DUMP_FRAME:
209
            /* try re-initializing the camera before we start dumping */
210
 
211
			CamConfig_setCamReg(0x11,0x01);  /* reduce the frame rate for dumping*/
212
			CamConfig_sendFifoCmds();
213
			Utility_delay(1000);		/* allow the new frame rate to settle */
214
			lineCount = 0;
215
			currentState = ST_FrameMgr_DumpingFrame;
216
			//CamIntAsm_waitForNewDumpFrame(currentLineBuffer,previousLineBuffer);
217
            FrameMgr_acquireLine();
218
			break;
219
 
220
		case EV_ENABLE_TRACKING:
221
			currentState = ST_FrameMgr_TrackingFrame;					
222
			FrameMgr_acquireFrame();
223
			break;
224
 
225
		case EV_ACQUIRE_FRAME_COMPLETE:
226
			FrameMgr_processFrame();
227
			break;
228
 
229
		case EV_PROCESS_FRAME_COMPLETE:
230
			FrameMgr_acquireFrame();
231
			break;
232
 
233
		case EV_SERIAL_DATA_RECEIVED:
234
			if (currentState != ST_FrameMgr_idle)
235
			{
236
				/* we need to go back to processing line data, since
237
				serial data reception interrupted us....just trash the
238
				frame and act like the frame has been processed, which
239
				will kick off the system to wait for the next line */
240
				PUBLISH_EVENT(EV_PROCESS_FRAME_COMPLETE);
241
			}
242
			break;
243
 
244
		case EV_DISABLE_TRACKING:
245
			/* tracking needs to be turned off */
246
			currentState = ST_FrameMgr_idle;
247
			break;
248
	}
249
}
250
 
251
/***********************************************************
252
	Function Name: FrameMgr_acquireFrame
253
	Function Description: This function is responsible for
254
	beginning of the acquisition of a new frame of data
255
	from the camera interface. The acquisition of this line 
256
	depends on the current state of the FrameMgr.
257
	Inputs:  none
258
	Outputs: none
259
***********************************************************/	
260
void FrameMgr_acquireFrame(void)
261
{
262
	if (currentState == ST_FrameMgr_TrackingFrame)
263
	{
264
		trackedLineCount = 0;
265
		numPrevTrackedObjects = numCurrTrackedObjects;
266
		numCurrTrackedObjects = 0;
267
 
268
		/* clear out the tracking table, and wait for the new frame
269
		to start */
270
		memset(trackedObjectTable,0x00,sizeof(trackedObjectTable));
271
		//CamIntAsm_waitForNewTrackingFrame(currentLineBuffer,colorMap);
272
        WAIT_FOR_VSYNC_HIGH();
273
        CamIntAsm_acquireTrackingLine(currentLineBuffer,colorMap);
274
	}
275
}
276
 
277
/***********************************************************
278
	Function Name: FrameMgr_acquireLine
279
	Function Description: This function is responsible for
280
	acquiring a line of data from the camera interface.
281
	The acquisition of this line depends on the current
282
	state of the FrameMgr.
283
	Inputs:  none
284
	Outputs: none
285
***********************************************************/	
286
void FrameMgr_acquireLine(void)
287
{
288
	unsigned char tmpLineCount;
289
 
290
	/* clearing out the buffers takes too long...we should
291
	just overwrite the data here without a problem when
292
	we start acquiring...at no point do we check for 
293
	a 0x00 value in the current or previous lineBuffers,
294
	so it was a bit excessive :-)  */
295
 
296
	/* check which state we are in and proceed as needed */
297
	if (currentState == ST_FrameMgr_DumpingFrame)
298
	{
299
		tmpLineCount = lineCount*2;
300
 
301
        /* clearing out the line data in dump mode is ok, and actually
302
        is needed, since it is possible for the first dump line in
303
        a frame to come back with the last line captured of the
304
        last capture session...*/
305
        memset(currentLineBuffer,0x00,LENGTH_OF_LINE_BUFFER);
306
        memset(previousLineBuffer,0x00,LENGTH_OF_LINE_BUFFER);
307
		/* wait for another VSYNC so we know which frame to use 
308
		to start looking for a line to receive */
309
		WAIT_FOR_VSYNC_HIGH();  
310
		WAIT_FOR_VSYNC_LOW();
311
 
312
		/* look at lineCount to determine how many HREFs we should
313
		wait before we start sampling */
314
		while(tmpLineCount != 0)
315
		{
316
			WAIT_FOR_HREF_HIGH(); 
317
			tmpLineCount--;
318
			WAIT_FOR_HREF_LOW(); 
319
		}
320
 
321
		/*  we should now be ready to sample our line...*/
322
		CamIntAsm_acquireDumpLine(currentLineBuffer,previousLineBuffer);
323
	}		
324
	else if (currentState == ST_FrameMgr_TrackingFrame)
325
	{
326
		WAIT_FOR_HREF_LOW();
327
		CamIntAsm_acquireTrackingLine(currentLineBuffer,colorMap);
328
	}
329
}
330
 
331
/***********************************************************
332
	Function Name: FrameMgr_processLine
333
	Function Description: This function is responsible for
334
	parsing the received image line and performing either
335
	connected region mapping (if in the Tracking state) or
336
	sending out the raw sampled data (if in the Dumping
337
	state).
338
	Inputs:  none
339
	Outputs: none
340
***********************************************************/	
341
void FrameMgr_processLine(void)
342
{
343
	unsigned char i;
344
	volatile unsigned char dataToSend;
345
	unsigned char *pTrackedObjectData = (unsigned char *)pCurrentTrackedObjectTable;
346
#ifdef DEBUG_TRACKED_LINE    
347
	unsigned char *pSendData;
348
    unsigned char asciiBuffer[5];
349
    unsigned char pixelCount = 0;
350
#endif    
351
 
352
	if (currentState == ST_FrameMgr_DumpingFrame)
353
	{
354
		/* we want to sit in a tight loop and send the acquired data
355
		sitting in current and previous line buffers out the serial
356
		port...it is sent out the serial port immediately instead
357
		of going into the UIMgr tx fifo because we can't do anything
358
		until its sent out anyway...may as well just get it out now	*/
359
 
360
		/* currentLineBuffer is getting "g" previousLineBuffer is getting "b-r" */
361
		UartInt_txByte(0x0B);			/* send the header byte */
362
		UartInt_txByte(lineCount);		/* send the line count */
363
		for (i=0; i<NUM_PIXELS_IN_A_DUMP_LINE; i+=2)
364
		{
365
			/* when a dump line is sampled, the upper byte can potentially
366
			have garbage in it...we don't have time to mask it off as we're
367
			sampling, so it is done here before we send it out...we also
368
			combine the samples together so we really are sending up a
369
			sample for line N as well as line N+1 */
370
			dataToSend = currentLineBuffer[i];
371
			dataToSend &= 0x0F;
372
			dataToSend <<= 4;
373
			dataToSend |= (previousLineBuffer[i] & 0x0F);
374
 
375
			/* dataToSend should be packed now */
376
			UartInt_txByte(dataToSend);
377
 
378
			/* flip the colors around since we are doing all G on Y and BR on UV */
379
			dataToSend = previousLineBuffer[i+1];
380
			dataToSend &= 0x0F;
381
			dataToSend <<= 4;
382
			dataToSend |= (currentLineBuffer[i+1] & 0x0F);
383
 
384
			/* dataToSend should be packed now */
385
			UartInt_txByte(dataToSend);
386
		}
387
		UartInt_txByte(0x0F);  /* send line end */
388
		/* once all the data is sent, increment out line count by 2 since
389
		we really get 2 lines worth of pixels on each pass */
390
		/* Update...increment only by 1, but only send 72 double-lines */
391
		lineCount++;
392
 
393
		/* check to see if we have retrieved all of the needed lines */
394
		if (lineCount >= 72)  /* half 144, since we send two lines at a time */
395
		{
396
			/* we're done, so send the dump complete?...nope, just change
397
			states and we should be fine */
398
			lineCount = 0;
399
			currentState = ST_FrameMgr_idle;
400
 
401
			/* disable the PCLK counting overflow interrupt */
402
			TIMSK &= DISABLE_PCLK_TIMER1_OVERFLOW_BITMASK;
403
 
404
			CamConfig_setCamReg(0x11,0x00);  /* reset the frame rate to normal*/
405
			CamConfig_sendFifoCmds();
406
		}
407
		else
408
		{
409
			/* we have more lines to acquire in this frame, so keep on truckin...*/
410
			PUBLISH_FAST_EVENT(FEV_PROCESS_LINE_COMPLETE);
411
		}
412
	}
413
	else if (currentState == ST_FrameMgr_TrackingFrame)
414
	{
415
#ifdef DEBUG_TRACKED_LINE	
416
		/* send the received line over serial...this should only send
417
		until a pixelCount == 176 */
418
		pSendData = currentLineBuffer;
419
		itoa(trackedLineCount,asciiBuffer,10);
420
		UIMgr_txBuffer(asciiBuffer,3);
421
		UIMgr_txBuffer(" ",1);
422
		while(pixelCount < ACTUAL_NUM_PIXELS_IN_A_LINE)  
423
		{
424
			memset(asciiBuffer,0x00,5);
425
			itoa(*pSendData++,asciiBuffer,10);	/* color is first byte */
426
			UIMgr_txBuffer(asciiBuffer,3); /* 3 ascii bytes for data */
427
			UIMgr_txBuffer(" ",1);
428
 
429
			pixelCount += *pSendData;	/* run-length is second byte */
430
			memset(asciiBuffer,0x00,5);
431
			itoa(*pSendData++,asciiBuffer,10);
432
			UIMgr_txBuffer(asciiBuffer,3);
433
			UIMgr_txBuffer(" ",1);
434
		}
435
		UIMgr_txBuffer("\n\r",2);
436
 
437
		trackedLineCount++;
438
		if (trackedLineCount == 144)
439
		{
440
			UIMgr_txBuffer("  FC  \n\r",8);
441
			trackedLineCount = 0;
442
			PUBLISH_EVENT(EV_PROCESS_FRAME_COMPLETE);
443
		}
444
		else
445
		{
446
			PUBLISH_EVENT(EV_PROCESS_LINE_COMPLETE);
447
		}	
448
#else
449
        /* determine if any of the RLE blocks overlap */
450
		FrameMgr_findConnectedness();
451
 
452
        /* we also want to remove any objects that are less than
453
        a minimum height...we already removed portions of the 
454
        run-length that are less than MIN_PIXEL_WIDTH in the
455
        findConnectedness() routine...doing it here instead of 
456
        a function to speed things up...this may end up slowing down the
457
        frame rate slightly, and can be removed if this isn't needed */
458
 
459
        /* run this routine once every 8 lines */       
460
        if ( (trackedLineCount & RUN_OBJECT_FILTER_MASK) == RUN_OBJECT_FILTER_MASK)
461
        {
462
            for (i=0; i<MAX_TRACKED_OBJECTS; i++)
463
            {
464
                if ( *(pTrackedObjectData + VALID_OBJECT_OFFSET) == TRUE)
465
                {
466
                    /* check to see if the object is already in
467
                    our past...i.e., its last */
468
                    if ( (*(pTrackedObjectData + Y_LOWER_RIGHT_OFFSET) - 
469
                          *(pTrackedObjectData + Y_UPPER_LEFT_OFFSET)) < MIN_OBJECT_TRACKING_HEIGHT)
470
                    {
471
                        /* the object is less than the minimum height...see if it is adjacent
472
                        to the current line we just processed...if so, leave it here...otherwise,
473
                        it needs to be invalidated since its too small */
474
                        if ( trackedLineCount - *(pTrackedObjectData + Y_LOWER_RIGHT_OFFSET) > 2)
475
                        {
476
                            /* invalidate the object */
477
                            *(pTrackedObjectData + VALID_OBJECT_OFFSET) = FALSE;
478
                            numCurrTrackedObjects--;
479
                        }
480
                    }
481
                }
482
                pTrackedObjectData += SIZE_OF_TRACKED_OBJECT;
483
            }
484
        }     
485
 
486
		trackedLineCount++;
487
		if (trackedLineCount == ACTUAL_NUM_LINES_IN_A_FRAME)
488
		{
489
			/* an entire frame of tracking data has been acquired, so
490
			publish an event letting the system know this fact */
491
			PUBLISH_EVENT(EV_ACQUIRE_FRAME_COMPLETE);
492
			/* disable the PCLK counting overflow interrupt */
493
			TIMSK &= DISABLE_PCLK_TIMER1_OVERFLOW_BITMASK;
494
			trackedLineCount = 0;
495
		}
496
		else
497
		{
498
			PUBLISH_FAST_EVENT(FEV_PROCESS_LINE_COMPLETE);
499
		}
500
#endif		
501
	}
502
	else
503
	{
504
		/* ...and here? */
505
	}
506
}
507
 
508
/***********************************************************
509
	Function Name: FrameMgr_processFrame
510
	Function Description: This function is responsible for
511
	parsing the completed frame and performing all actions
512
	needed at this level.
513
	Inputs:  none
514
	Outputs: none
515
***********************************************************/	
516
void FrameMgr_processFrame(void)
517
{
518
	unsigned char i,k,color;
519
#if DEBUG_FRAME_DATA    
520
	unsigned char asciiBuffer[5];
521
    unsigned char j;
522
#endif    
523
	unsigned char *pTableData = (unsigned char *)pCurrentTrackedObjectTable;
524
	unsigned char tmpUpperLeftX,tmpUpperLeftY,tmpLowerRightX,tmpLowerRightY;
525
 
526
#if DEBUG_FRAME_DATA	
527
	/* we want to send all of the currently tracked table out
528
	the serial port for debugging */
529
	for (i=0; i<numCurrTrackedObjects; i++)
530
	{
531
		UIMgr_txBuffer("----------\r\n",12);
532
		for (j=0; j<SIZE_OF_TRACKED_OBJECT; j++)
533
		{
534
			memset(asciiBuffer,0x00,5);
535
			itoa(*pTableData++,asciiBuffer,10);
536
			UIMgr_txBuffer(asciiBuffer,3); /* 3 ascii bytes for data
537
														+ 1 space */
538
			UIMgr_txBuffer("\r\n",2);
539
		}
540
	}
541
 
542
	/* finally, send a new line */
543
	UIMgr_txBuffer("\r\n",2);
544
 
545
	memset(asciiBuffer,0x00,5);
546
	itoa(numCurrTrackedObjects,asciiBuffer,10);
547
	UIMgr_txBuffer(asciiBuffer,3);
548
	UIMgr_txBuffer(" PFC\r\n",5);
549
 
550
#else	
551
	/* we only send tracking packets if there are tracked objects */	        
552
 
553
	if (numCurrTrackedObjects > 0)
554
	{		
555
		UIMgr_writeTxFifo(0x0A);					/* header byte for a tracking packet */
556
        /* reset the pointer */
557
        pTableData = (unsigned char *)pCurrentTrackedObjectTable;
558
 
559
		UIMgr_writeTxFifo(numCurrTrackedObjects);	/* num of objects tracked */
560
		for (i=0; i<MAX_TRACKED_OBJECTS; i++)
561
		{
562
            /* we only want to process objects that have their objectValid flag
563
            set to TRUE */
564
            if ( *(pTableData + VALID_OBJECT_OFFSET) == TRUE)
565
            {
566
                /* the object is valid...convert the color from bit position to value...remember, 
567
                each bit in the "color" byte corresponds to a color */
568
                k=0;
569
                color = *(pTableData + COLOR_OFFSET);
570
                if (color == 128) k=0;
571
                else if (color == 64) k=1;
572
                else if (color == 32) k=2;
573
                else if (color == 16) k=3;
574
                else if (color == 8)  k=4;
575
                else if (color == 4)  k=5;
576
                else if (color == 2)  k=6;
577
                else if (color == 1)  k=7;
578
 
579
                tmpUpperLeftX = *(pTableData + X_UPPER_LEFT_OFFSET);	    /* get the upper left X */
580
                tmpUpperLeftY = *(pTableData + Y_UPPER_LEFT_OFFSET);		/* get the upper left Y */		
581
                tmpLowerRightX = *(pTableData + X_LOWER_RIGHT_OFFSET);		/* get the lower right X */
582
                tmpLowerRightY = *(pTableData + Y_LOWER_RIGHT_OFFSET);		/* get the lower right Y */	                
583
 
584
                UIMgr_writeTxFifo(k);				  	/* send the color first */
585
                UIMgr_writeTxFifo(tmpUpperLeftX);
586
                UIMgr_writeTxFifo(tmpUpperLeftY);
587
                UIMgr_writeTxFifo(tmpLowerRightX);
588
                UIMgr_writeTxFifo(tmpLowerRightY);			
589
            }
590
 
591
            /* move our pointer up to the beginning of the next object */
592
            pTableData += SIZE_OF_TRACKED_OBJECT;
593
        }
594
 
595
		/* all done...send the end of tracking packets char */
596
		UIMgr_writeTxFifo(0xFF);
597
	}	
598
#endif	
599
 
600
    /* the tracked object table will be cleared out right before we start
601
    to wait for VSYNC to indicate a new frame...so it doesn't need to be
602
    done now */
603
 
604
	/* schedule the next action to acquire a new frame */	
605
	PUBLISH_EVENT(EV_PROCESS_FRAME_COMPLETE);
606
}
607
 
608
/***********************************************************
609
	Function Name: FrameMgr_findConnectedness
610
	Function Description: This function is responsible for
611
	finding the connectedness between two particular run-
612
	length encoded lines of pixel data.  It updates the
613
	trackingTable as needed.
614
	Inputs:  none
615
	Outputs: none
616
***********************************************************/	
617
static void FrameMgr_findConnectedness(void)
618
{
619
	trackedColor_t currColor;
620
	unsigned char *pCurrLineColorInfo = currentLineBuffer;
621
	unsigned char *pTrackedObjectData;
622
	register unsigned char currPixelRunStart=0;
623
	register unsigned char currPixelRunFinish=0; 
624
	register unsigned char lastLineXStart=0;
625
	register unsigned char lastLineXFinish=0;  
626
	register unsigned char runLength=1;
627
	unsigned char i;
628
	bool_t colorConnected;	
629
 
630
	do
631
	{
632
		/* grab both the current color and the number of pixels
633
		in the run...remember, pixels start at 1, not 0! */
634
		colorConnected = FALSE;
635
		currColor = *pCurrLineColorInfo++;
636
		currPixelRunStart += runLength;
637
		runLength = *pCurrLineColorInfo++;
638
		currPixelRunFinish += runLength;
639
 
640
        /* make sure that the run-length is at least as wide as
641
        the minimum horizontal tracking width, and we care about the color */ 
642
 
643
		if ( (currColor != notTracked) && (runLength > MIN_OBJECT_TRACKING_WIDTH) )
644
		{			
645
            /* this run contains a color we care about, so 
646
			either it will begin a new tracked object, or it
647
			is connected to a currently tracked object...
648
			compare it with each object in the tracking
649
			table...we can't just look at the numTrackedObjects because
650
            it is entirely possible that the first couple of objects could
651
            be invalid...
652
 
653
            NOTE: Instead of accessing each element in the trackedObjectTable
654
            through the 'i' index, and then accessing the fields in each structure,
655
            a pointer to each entry is established each time through the loop, followed
656
            by accessing the elements through specified offsets.  GCC seems to be
657
            able to optimize this code much better than simply accessing the elements
658
            of each structure in the array the more normal way...*/
659
 
660
            pTrackedObjectData = (unsigned char *)pCurrentTrackedObjectTable;
661
			for (i=0; i<MAX_TRACKED_OBJECTS; i++)
662
			{
663
				if ( (currColor == *(pTrackedObjectData + COLOR_OFFSET)) && 
664
                     (*(pTrackedObjectData + VALID_OBJECT_OFFSET) == TRUE) &&
665
                     (*(pTrackedObjectData + Y_LOWER_RIGHT_OFFSET) == trackedLineCount - 1) &&
666
                    /* add a check to limit the vertical size of object to 18 pixels...this will help segment the
667
                       image for the purpose of tracking a line for the Chibots contest */
668
                     ( (*(pTrackedObjectData + Y_LOWER_RIGHT_OFFSET) - (*(pTrackedObjectData + Y_UPPER_LEFT_OFFSET) ) ) < 18) )                       
669
				{
670
					/* found a color match and the object is valid...check to see if there is
671
					connectedness */
672
					lastLineXStart = *(pTrackedObjectData + LAST_LINE_X_START_OFFSET);
673
					lastLineXFinish = *(pTrackedObjectData + LAST_LINE_X_FINISH_OFFSET);
674
 
675
					/* Check for the 5 following types of line connectedness:
676
					---------------------
677
					|                   |
678
					---------------------
679
					         -------------------------
680
							 |                       |
681
							 -------------------------  */
682
					if ( (	(currPixelRunStart >= lastLineXStart) &&
683
							(currPixelRunStart <= lastLineXFinish) )  ||
684
 
685
					/*               ---------------------
686
					                 |                   |
687
									 ---------------------
688
						-------------------
689
						|                 |
690
						-------------------  
691
						                   OR
692
						     ------------------------------
693
							 |                            |
694
							 ------------------------------
695
							              ---------
696
										  |       |
697
										  ---------  */
698
						 (	(currPixelRunFinish >= lastLineXStart) && 
699
							(currPixelRunFinish <= lastLineXFinish) ) ||
700
 
701
 
702
					/*     -------------------------------
703
					       |                             |
704
						   -------------------------------
705
						   -------------------------------
706
						   |                             |
707
						   -------------------------------
708
						                  OR
709
								     -------------
710
									 |           |
711
									 -------------
712
							-------------------------------
713
							|                             |
714
							-------------------------------   */
715
						 (  (currPixelRunStart <= lastLineXStart) &&
716
							(currPixelRunFinish >= lastLineXFinish) ) )
717
					{
718
						/* THERE IS CONNECTEDNESS...update the lastLineXStart and lastLineXFinish
719
						data pointed to by pTrackedObjectData */
720
						*(pTrackedObjectData + LAST_LINE_X_START_OFFSET) = currPixelRunStart;
721
						*(pTrackedObjectData + LAST_LINE_X_FINISH_OFFSET) = currPixelRunFinish;
722
 
723
						/* check if the bounding box needs to be updated */
724
						if (*(pTrackedObjectData + X_UPPER_LEFT_OFFSET) > currPixelRunStart)
725
						{
726
							/* need to update the bounding box for the upper left point to 
727
							enclose this new left-most point...we never have to update the
728
							upper left Y point, since each scan line we process moves from
729
							top to bottom */
730
							*(pTrackedObjectData + X_UPPER_LEFT_OFFSET) = currPixelRunStart;
731
						}
732
 
733
						if ( *(pTrackedObjectData + X_LOWER_RIGHT_OFFSET) < currPixelRunFinish)
734
						{
735
							/* need to update the bounding box for the lower right X point to
736
							enclose this new right-most point */
737
							*(pTrackedObjectData + X_LOWER_RIGHT_OFFSET) = currPixelRunFinish;
738
						}
739
 
740
						/* the lower right 'y' point always gets updated when connectedness is found */
741
						*(pTrackedObjectData + Y_LOWER_RIGHT_OFFSET) = trackedLineCount;
742
 
743
						/* set a flag indicating that that color run is part of another
744
						object and thus doesn't need to be added as a new entry into the
745
						tracking table */
746
						colorConnected = TRUE;
747
						break;
748
					}
749
				}
750
 
751
                /* go to the next object */
752
                pTrackedObjectData += SIZE_OF_TRACKED_OBJECT;
753
			}
754
 
755
			if (colorConnected == FALSE)
756
			{
757
				/* a new entry needs to be made to the tracking table, since we have
758
				a run-length with a color, and it isn't connected to anything...but we
759
				can only do this if there is space left in the trackedObject table */
760
				if (numCurrTrackedObjects < MAX_TRACKED_OBJECTS)
761
				{                
762
                    /* space is available...add the object...but first we need to find an
763
                    invalid object in the object tracking table */
764
                    pTrackedObjectData = (unsigned char *)pCurrentTrackedObjectTable;
765
                    for (i=0; i<MAX_TRACKED_OBJECTS; i++)
766
                    {
767
                        if ( *(pTrackedObjectData + VALID_OBJECT_OFFSET) == FALSE)  break;
768
 
769
                        /* if we haven't broken above, then the object must have been valid...
770
                        go ahead and move the pointer to the next object to check it */
771
                        pTrackedObjectData += SIZE_OF_TRACKED_OBJECT;
772
                    }
773
 
774
 
775
					/* now that we have a pointer to the tracked object to be updated, update all
776
					the fields */
777
					*(pTrackedObjectData + COLOR_OFFSET)                = currColor;			/* color */
778
					*(pTrackedObjectData + LAST_LINE_X_START_OFFSET)    = currPixelRunStart; 	/* lastLineXStart */
779
					*(pTrackedObjectData + LAST_LINE_X_FINISH_OFFSET)   = currPixelRunFinish;	/* lastLineXFinish */
780
					*(pTrackedObjectData + X_UPPER_LEFT_OFFSET)         = currPixelRunStart;	/* x_upperLeft */
781
					*(pTrackedObjectData + Y_UPPER_LEFT_OFFSET)         = trackedLineCount;	/* y_upperLeft */
782
					*(pTrackedObjectData + X_LOWER_RIGHT_OFFSET)        = currPixelRunFinish;	/* x_lowerRight */
783
					*(pTrackedObjectData + Y_LOWER_RIGHT_OFFSET)        = trackedLineCount;	/* y_lowerRight */
784
                    *(pTrackedObjectData + VALID_OBJECT_OFFSET)         = TRUE;                /* objectValid flag */
785
 
786
					numCurrTrackedObjects++;
787
				}
788
			}
789
 
790
            /* move the pointer to the beginning of the next tracked object */
791
            pTrackedObjectData += SIZE_OF_TRACKED_OBJECT;
792
		}
793
	} while(currPixelRunFinish < ACTUAL_NUM_PIXELS_IN_A_LINE);
794
}
795