/*****************************************************************************

Copyright (c) 2006 Analog Devices, Inc.	All	Rights Reserved. 

This software is proprietary and confidential to Analog	Devices, Inc. 
and	its	licensors.

*****************************************************************************

$RCSfile: VideoInEdgeDetection_Buffers.c,v $
$Revision: 1.2 $
$Date: 2007/06/21 06:01:10 $

Project:	BlackfinSDK (Edge Detection on ITU656 Video In)
Title:		Buffer handling functions
Author(s):	bmk
Revised	by:	

Description:
			Functions to Handle video input/output buffers used for 
			Edge Detection on ITU 656 Video Input

References:
			None

*****************************************************************************
Tab	Setting:			4

Target Processor:		ADSP-BF5xx
Target Tools Revision:	ADSP VisualDSP++ v4.5
******************************************************************************

Modification History:
====================
$Log: VideoInEdgeDetection_Buffers.c,v $
Revision 1.2  2007/06/21 06:01:10  randreol
Added ssl_init changes

Revision 1.1  2007/05/22 18:38:06  gstephan
Creating VDSP 5.00 release folder.  Created from the head copy of
VDSP 4.50 release folder.

Revision 1.4  2006/07/28 05:11:05  bmk
modified code for actual NTSC resolution
Previous rev- 720 x 480, now - 720 x 486

Revision 1.3  2006/07/06 07:26:28  bmk
modified project to use video utility file macros

Revision 1.2  2006/07/04 05:33:19  bmk
added Slide-show mode for BF533

Revision 1.1  2006/06/30 01:33:55  bmk
Initial entry


******************************************************************************
Include files
*****************************************************************************/

#include <sobel.h>							// Sobel edge detection algorithm includes
#include <VideoInEdgeDetection_System.h>	// Video In Edge detection system includes
#include <SDK-ezkitutilities.h>				// EZ-Kit utility definitions
#include <adi_ssl_init.h>           // initialization sizings

/*****************************************************************************
Video Data buffers
*****************************************************************************/
// Define the buffers to handle video data processing
// Because of SDRAM performance, each buffer must be in a different bank.
section("video_sdram_bank0") volatile u8 Video_In_Buf0	[VIDEO_BUF_SIZE];
#if defined(__ADSPBF561__)
section("video_sdram_bank1") volatile u8 Video_In_Buf1	[VIDEO_BUF_SIZE];
#endif
section("video_sdram_bank2") volatile u8 Video_Out_Buf	[VIDEO_BUF_SIZE];

// Sobel Edge detection buffers
section("Sobel_In_buf0") 	volatile u8 Sobel_In_Buf0	[SOBEL_BUF_SIZE];
section("Sobel_In_buf1") 	volatile u8 Sobel_In_Buf1	[SOBEL_BUF_SIZE];
section("Sobel_Out_buf0") 	volatile u8 Sobel_Out_Buf0	[SOBEL_BUF_SIZE];
section("Sobel_Out_buf1") 	volatile u8 Sobel_Out_Buf1	[SOBEL_BUF_SIZE];

#if defined(__ADSPBF561__)
#define	VIDEO_BUFFERS	2		// number of 2D (video) buffers used
#elif defined(__ADSPBF533__)
#define	VIDEO_BUFFERS	1		// number of 2D (video) buffers used
#else
#error "*** ERROR: Application doesnot support this processor yet ***"
#endif

static	ADI_DEV_2D_BUFFER Video_Out_Buffer2D[VIDEO_BUFFERS];		// Video output buffer
static	ADI_DEV_2D_BUFFER Video_In_Buffer2D [VIDEO_BUFFERS];		// Video input buffers

/***********************************
MDMA Handels & data
***********************************/

// DMA Stream Handels
ADI_DMA_STREAM_HANDLE		MDMA_Handle_Stream0;	// MDMA stream for video in buffer to sobel in buffer
ADI_DMA_STREAM_HANDLE		MDMA_Handle_Stream1;	// MDMA stream for sobel out buffer to video out buffer
// MDMA 2D transfer data type
// structures to define video in buffer to sobel in buffer stream
ADI_DMA_2D_TRANSFER			MDMA_Sobel_In_Src;
ADI_DMA_2D_TRANSFER			MDMA_Sobel_In_Des;
// structures to define sobel out buffer to video out buffer stream
ADI_DMA_2D_TRANSFER			MDMA_Sobel_Out_Src;	
ADI_DMA_2D_TRANSFER			MDMA_Sobel_Out_Des;	

/***********************************
Globals
***********************************/

int Result;
// Background colour for edge detected output (grey colour-ycbcr format)
static char background[]	= {0x89,0x11,0x89,0x11};

// Pointer to some location in Video_In_Bufx - points next block of data for Sobel_In_Bufx
u8	*pVideoInBuf;		
// Pointer to some location in Video_Out_Buf - points start address to copy next block of Sobel_Out_Buf
u8	*pVideoOutBuf;
// Temp video in pointer
u8	*tpVideoInBuf;
// Temp video out pointer
u8	*tpVideoOutBuf;

SOBEL_FLAGS	SobelFlag;		// Flags used to carryout Sobel Edge Detection
u8	SobelInBlockCount;			// Number of sobel in blocks processed
u8	SobelOutBlockCount;			// Number of sobel out blocks processed
u8	SobelInColumnBlockCount;	// Number of sobel in Columns processed
u8	SobelOutColumnBlockCount;	// Number of sobel out Columns processed

/***********************************
local function prototypes
***********************************/

static void MDMA_Callback0		(void *AppHandle, u32  Event, void *pArg);		// MEMDMA stream callback function (sobel in)
static void MDMA_Callback1		(void *AppHandle, u32  Event, void *pArg);		// MEMDMA stream callback function (sobel out)
void		MDMA_SobelIn		(void);											// MDMA Sobel In buffer update - callback routine
void		MDMA_SobelOut		(void);											// MDMA Sobel Out buffer update - callback routine

/*********************************************************************

    Function:       Format_Video_Out_Frames
    Description:    Formats Sobel video output frames to specified mode

*********************************************************************/
section("sdram_bank1")
void	FormatVideoOutFrames	(void)
{

// Check input video frame type
if (SystemFlag.ITU656_Mode == ITU656_PAL)
{
    // Pause disabled. format video out buffer for video streaming
	// Format memory as PAL interlaced video frame
	adi_video_FrameFormat ((char *)Video_Out_Buf,PAL_IL);
	// Fill the Video out frame with background color
	adi_video_FrameFill ((char *)Video_Out_Buf,PAL_IL,background);	    
}
else 	// format a NTSC video frame
{
   	// Format memory as NTSC interlaced video frame
	adi_video_FrameFormat ((char *)Video_Out_Buf,NTSC_IL);
	// Fill the Video out frame with background color
	adi_video_FrameFill ((char *)Video_Out_Buf,NTSC_IL,background);
}

return;

}

/*********************************************************************

    Function:       SubmitVideoOutBuffers
    Description:    Prepares and submits Video Output Buffers (for ADV717x)

*********************************************************************/
section("sdram_bank1")
void	SubmitVideoOutBuffers	(
){
	u8 OutBufCount,i;
	
	OutBufCount	= 1;	// number of output buffers to be submitted	by default

	// if sobel is enabled, submit the original sobel video out buffer
	if (SystemFlag.SobelEnable == TRUE)
	{
		Video_Out_Buffer2D[0].Data 	= (void*)(&Video_Out_Buf[0]);		// Video buffer to be displayed
	}
		
#if defined(__ADSPBF561__)

	else	// display incoming video or paused original frame
	{    
		// check pause flag
		if (SystemFlag.Pause_Frame_Capture == TRUE)
		{
		    
		    // Pause is enabled. so submit paused Video In frame to Video out
			Video_Out_Buffer2D[0].Data 	= (void*)(((ADI_DEV_BUFFER *)pPausedBuffer)->TwoD.Data);
		}
		else	// Stream incoming video
		{
			Video_Out_Buffer2D[0].Data 	= (void*)(&Video_In_Buf0[0]);// Video buffer to be displayed
			Video_Out_Buffer2D[1].Data 	= (void*)(&Video_In_Buf1[0]);// Video buffer to be displayed
			// 2 video in buffers to be submitted for video streaming
			OutBufCount	= 2;	
		}		    
	}

#elif defined(__ADSPBF533__)

	// if sobel is disabled, display captured video frame
	else
	{	    
		// submit captured Video In frame to Video out
		Video_Out_Buffer2D[0].Data 	= (void*)(((ADI_DEV_BUFFER *)pPausedBuffer)->TwoD.Data);
	}
	
#endif

	for (i=0;i<OutBufCount;i++)
	{	    
		// Configure Video Out Buffer 
		Video_Out_Buffer2D[i].ElementWidth 		= DMA_BUS_SIZE;					// 32 bit transfer for BF561/16 bit transfer for BF533
		Video_Out_Buffer2D[i].XModify 			= DMA_BUS_SIZE;					// 4 bytes increment for BF561/2 bytes increment for BF533
		Video_Out_Buffer2D[i].XCount 			= (DataPerLine/DMA_BUS_SIZE);	// Video Data per line
		Video_Out_Buffer2D[i].YCount 			= FrameLines;					// Total number of lines in a frame
		Video_Out_Buffer2D[i].YModify 			= DMA_BUS_SIZE;					// 4 bytes increment for BF561/2 bytes increment for BF533
		Video_Out_Buffer2D[i].CallbackParameter	= &Video_Out_Buffer2D[i];		// call back parameter
		Video_Out_Buffer2D[i].pNext				= NULL;							
	
		// submit the video output buffer to the system
		ezErrorCheck(adi_dev_Write(ADV717xDeviceHandle, ADI_DEV_2D, (ADI_DEV_BUFFER *)&Video_Out_Buffer2D[i]));
	}
	
	return;
}
/*********************************************************************

    Function:       Submit_Video_In_Buffers
    Description:    Prepares and submits Video Input Buffers (for ADV7183)

*********************************************************************/
section("sdram_bank1")
void	SubmitVideoInBuffers	(
){

    u8 i;
    	
	// Configure Video In Buffer(s)
	// Video In Buffer 1
	Video_In_Buffer2D[0].Data 					= (void*)(&Video_In_Buf0[0]);	// start location of 2D Video In buffer0
	
#if defined(__ADSPBF561__)	
	// Video In Buffer 2
	Video_In_Buffer2D[1].Data 					= (void*)(&Video_In_Buf1[0]);	// start location of 2D Video In buffer1
#endif
	
	for (i=0; i<VIDEO_BUFFERS; i++)
	{
		Video_In_Buffer2D[i].ElementWidth 		= DMA_BUS_SIZE;					// 32 bit transfer for BF561/16 bit transfer for BF533
		Video_In_Buffer2D[i].XModify 			= DMA_BUS_SIZE;					// 4 bytes increment for BF561/2 bytes increment for BF533
		Video_In_Buffer2D[i].XCount 			= (DataPerLine/DMA_BUS_SIZE);	// Video Data per line
		Video_In_Buffer2D[i].YCount 			= FrameLines;					// Total number of lines in a frame
		Video_In_Buffer2D[i].YModify 			= DMA_BUS_SIZE;					// 4 bytes increment for BF561/2 bytes increment for BF533
		Video_In_Buffer2D[i].CallbackParameter 	= &Video_In_Buffer2D[i];		// call back parameter
		Video_In_Buffer2D[i].pNext				= NULL;							// Submit both buffers independently
				
		// submit video input buffer(s) to the system
		ezErrorCheck(adi_dev_Read(ADV7183DeviceHandle, ADI_DEV_2D, (ADI_DEV_BUFFER *)&Video_In_Buffer2D[i]));	
	}

	return;
}

/*********************************************************************

    Function:       ConfigureMDMA

    Description:    Installs & configures Memory DMA

*********************************************************************/
section("App_Code_L1")
void ConfigureMDMA(
) {

    // Configure MDMA 2D structures

    /*******************************************
    video in buffer to sobel in buffer stream
    *******************************************/

	/**** Sobel In stream destination buffer config ****/
		
    // count to copy a block of size (SOBEL_COLUMN_SIZE+SOBEL_OFFSET) * (SobelRowSize+SOBEL_OFFSET) 
	MDMA_Sobel_In_Des.XCount			= (SOBEL_COLUMN_SIZE+SOBEL_OFFSET);
	// Copy luma values only
	MDMA_Sobel_In_Des.XModify			= 1;	// 1 byte increment
	// count to copy a block of size (SOBEL_COLUMN_SIZE+SOBEL_OFFSET) * (SobelRowSize+SOBEL_OFFSET)
	MDMA_Sobel_In_Des.YCount			= (SobelRowSize+SOBEL_OFFSET);
	// Move to next row
	MDMA_Sobel_In_Des.YModify			= 1;	// same as xmodify
    	
    /**** Sobel In stream source buffer config ****/    	    
	// count to copy a block of size (SOBEL_COLUMN_SIZE+SOBEL_OFFSET) * (SobelRowSize+SOBEL_OFFSET)
	MDMA_Sobel_In_Src.XCount			= (SOBEL_COLUMN_SIZE+SOBEL_OFFSET);
	// Copy luma values only
	MDMA_Sobel_In_Src.XModify			= 2;	// 2 byte increment (alternative data skipped)
	// count to copy a block of size (SOBEL_COLUMN_SIZE+SOBEL_OFFSET) * (SobelRowSize+SOBEL_OFFSET)
	MDMA_Sobel_In_Src.YCount			= (SobelRowSize+SOBEL_OFFSET);
	// Move to next row, point to first luma location minus 2
	MDMA_Sobel_In_Src.YModify			= (DataPerLine - ((SOBEL_COLUMN_SIZE+SOBEL_OFFSET) * 2) + 2);	// finally add xmodify		
	
    /*******************************************
    sobel out buffer to video out buffer stream
    *******************************************/

    /**** Sobel Out stream destination buffer config ****/
    
	// count to copy sobel out valid data only
	MDMA_Sobel_Out_Des.XCount			= SOBEL_COLUMN_SIZE;
	// Copy valid data to luma locations only
	MDMA_Sobel_Out_Des.XModify			= 2;
	// count to copy sobel out valid data only
	MDMA_Sobel_Out_Des.YCount			= SobelRowSize;
	// Move to next row, point to first luma location
	MDMA_Sobel_Out_Des.YModify			= (DataPerLine - (SOBEL_COLUMN_SIZE * 2) + 2);	// finally add xmodify
        
    /**** Sobel Out stream source buffer config *****/

	// count to copy sobel out valid data only
	MDMA_Sobel_Out_Src.XCount			= SOBEL_COLUMN_SIZE;
	// Copy luma values only
	MDMA_Sobel_Out_Src.XModify			= 1;
	// count to copy sobel out valid data only
	MDMA_Sobel_Out_Src.YCount			= SobelRowSize;
	// Move to next row
	MDMA_Sobel_Out_Src.YModify			= 3;	// skip last column data in present row and first column data in next row + xmodify
	
	/*********************************************************
    Install MDMA video in buffer to sobel in buffer stream
    *********************************************************/
    // Open MDMA
#if defined(__ADSPBF533__)
   	// DMA Manager Handle, DMA Controller- MDMA stream 0, Client Handle, Stream Handle, live callback
   	Result = adi_dma_MemoryOpen (adi_dma_ManagerHandle,ADI_DMA_MDMA_0,NULL,&MDMA_Handle_Stream0,NULL);
   	if (Result != 0)
	{
		printf("ADI_DMA_MDMA_0 failed %x\n",Result);
		ezErrorCheck(Result);
	}

   	
#elif defined(__ADSPBF561__)
   	// DMA Manager Handle, DMA Controller 2 - MDMA stream 0, Client Handle, Stream Handle, live callback
   	Result = adi_dma_MemoryOpen (adi_dma_ManagerHandle,ADI_DMA_MDMA2_0,NULL,&MDMA_Handle_Stream0,NULL);
   	if (Result != 0)
	{
		printf("ADI_DMA_MDMA2_0 failed %x\n",Result);
		ezErrorCheck(Result);
	}

#endif
    
	/*********************************************************
    Install MDMA sobel out buffer to video out buffer stream
    *********************************************************/
  	// Open MDMA
#if defined(__ADSPBF533__)
   	// DMA Manager Handle, DMA Controller- MDMA stream 1, Client Handle, Stream Handle, live callback
   	Result = adi_dma_MemoryOpen (adi_dma_ManagerHandle,ADI_DMA_MDMA_1,NULL,&MDMA_Handle_Stream1,NULL);
   	if (Result != 0)
	{
		printf("ADI_DMA_MDMA_1 failed %x\n",Result);
		ezErrorCheck(Result);
	}

#elif defined(__ADSPBF561__)
   	// DMA Manager Handle, DMA Controller 2 - MDMA stream 1, Client Handle, Stream Handle, live callback
   	ezErrorCheck(adi_dma_MemoryOpen (adi_dma_ManagerHandle,ADI_DMA_MDMA2_1,NULL,&MDMA_Handle_Stream1,NULL));
#endif

	return;
}


/*********************************************************************

    Function:       CloseMDMA_Streams

    Description:    Closes Memory DMA streams

*********************************************************************/
section ("sdram_bank1")
void CloseMDMA_Streams (void)
{    
    // Close MDMA stream 0
    ezErrorCheck(adi_dma_MemoryClose (MDMA_Handle_Stream0,FALSE));
    
    // Close MDMA stream 1
    ezErrorCheck(adi_dma_MemoryClose (MDMA_Handle_Stream1,FALSE));
    
}

/*********************************************************************

    Function:       MDMA_Callback0

    Description:    Memory DMA callback dunction (sobel in)

*********************************************************************/
section ("Callback_Code_L1")
static void MDMA_Callback0( 
	void    *AppHandle,
	u32     Event,
	void    *pArg   
){
    // Case of (event type)
    switch (Event) {
        
        // Case descriptor processed 
        case ADI_DMA_EVENT_DESCRIPTOR_PROCESSED:
        
        	// Check if sobel out is enabled
        	if (!SobelFlag.InitSobelOut)
        	{
        	    // if not, enable Sobel Out MDMA stream
            	SobelFlag.SobelOutMDMALock	= FALSE;
            	// Sobel Out MDMA has been initialised
            	SobelFlag.InitSobelOut	 	= TRUE;	
        	}
        
        	// check sobel in bufx id that generated callback
   			if (SobelFlag.SobelInBufID)
   			{
   			    // Callback generated by Sobel_In_Buf1. Clear flag - indicates buffer already has luma values
				SobelFlag.SobelInBuf1Done	= FALSE;
   			}
			else
			{
			    // Callback generated by Sobel_In_Buf_0. Clear flag - indicates buffer already has luma values
				SobelFlag.SobelInBuf0Done	= FALSE;	
			}
			
			// Mark as Video in bufx to sobel in bufx MDMA is ready for next data stream
			SobelFlag.SobelInMDMALock	= FALSE;
       	
        	break;
        	
        // Case DMA Error
        case ADI_DEV_EVENT_DMA_ERROR_INTERRUPT:

         	// turn on all LEDs and wait for help
            ezTurnOnAllLEDs();
            while (1) ;
                      
		default:	// other events
         	// turn on all LEDs and wait for help
            ezTurnOnAllLEDs();
            while (1) ;

    }
}

/*********************************************************************

    Function:       MDMA_Callback1

    Description:    Memory DMA callback function (sobel out)

*********************************************************************/
section ("Callback_Code_L1")
static void MDMA_Callback1( 
	void    *AppHandle,
	u32     Event,
	void    *pArg   
){
    // Case of (event type)
    switch (Event) {
        
        // Case descriptor processed 
        case ADI_DMA_EVENT_DESCRIPTOR_PROCESSED:        	
        	
        	// check Sobel_Out_Bufx id that generated callback
    		if (SobelFlag.SobelOutBufID)
    		{
    		    // callback generated by Sobel_Out_Buf1
    		    // Clear flag - indicates buffer is ready to accept edge detected output
				SobelFlag.SobelOutBuf1Done	= FALSE;	
    		}
			else
			{
			    // callback generated by Sobel_Out_Buf0
			    // Clear flag - indicates buffer is ready to accept edge detected output
				SobelFlag.SobelOutBuf0Done	= FALSE;
			}

			// Mark as Sobel_Out_Bufx to Video_Out_Buf MDMA is ready for data streaming
			SobelFlag.SobelOutMDMALock	= FALSE;
			
        	break;                        

        // Case DMA Error
        case ADI_DEV_EVENT_DMA_ERROR_INTERRUPT:

         	// turn on all LEDs and wait for help
            ezTurnOnAllLEDs();
            while (1) ;
                      
		default:	// other events
         	// turn on all LEDs and wait for help
            ezTurnOnAllLEDs();
            while (1) ;

    }
}

/*********************************************************************

    Function:       Sobel_In_Init

    Description:    Initialises Vidio In to Sobel In streaming

*********************************************************************/
section ("Callback_Code_L1")
void SobelInInit (
	u32		*pBuffer
){
	
	/***********************************************
    Initialise Video In/Out buffer address pointers

    Video In Start address - init to point first 
    luma value minus 2 of Video_In_Bufx Active Field1
    to account for sobel algorithim invaild data, 
    pass extra 2 rows per block & 2 columns per row
    
    Video Out Start address - init to point first 
    luma value of Video_Out_Buf Active Field1
    ***********************************************/
	
	if (pBuffer == (u32 *) (&Video_In_Buffer2D[0]))		// implies Video_In_Buf0 ready for sobel conversion
	{
	    // Start address - init to point the first luma value minus 2 of Video_In_Buf0 Active Field1
		pVideoInBuf		= (u8 *)(&Video_In_Buf0[0] + (Field1Skip + ActiveVideoSkip - (DataPerLine + ITU_Y_OFFSET)));	
	}
	
#if defined(__ADSPBF561__)	
	else if (pBuffer == (u32 *) (&Video_In_Buffer2D[1]))	// implies Video_In_Buf1 ready for sobel conversion
	{
	    // Start address - init to point the first luma value minus 2 of Video_In_Buf1 Active Field1	    
		pVideoInBuf		= (u8 *)(&Video_In_Buf1[0] + (Field1Skip + ActiveVideoSkip - (DataPerLine + ITU_Y_OFFSET)));
	}
#endif

	else
		return;			// this buffer is not for us

	// Video out start address - init to point the first luma value of Video_Out_Buf Active Field1
	pVideoOutBuf	= (u8 *)(&Video_Out_Buf[0] + (Field1Skip + ActiveVideoSkip + ITU_Y_OFFSET));		
				
	tpVideoInBuf 	= NULL;			// clear the temp video in buffer pointer
	tpVideoOutBuf 	= NULL;			// clear the temp video out buffer pointer

	/***********************************************
	Init Sobel Buffer management Flags & Counters
	***********************************************/
	
    SobelFlag.SobelInBufID		= 1;		// start loading luma values to Sobel_In_Buf0
    SobelFlag.SobelOutBufID		= 1;		// start loading processed luma values to Sobel_Out_Buf0
	SobelFlag.SobelInBuf0Done	= TRUE;		// Sobel_In_Buf0 is ready to get a block of luma
	SobelFlag.SobelInBuf1Done	= TRUE;		// Sobel_In_Buf1 is ready to get a block of luma
	SobelFlag.SobelInMDMALock	= FALSE;	// Unlock Video In buffer to Sobel In buffer MDMA stream	
	SobelFlag.SobelOutBuf0Done	= FALSE;	// Mark as both Sobel out buffers are ready to get edge detected data
	SobelFlag.SobelOutBuf1Done	= FALSE;
	SobelFlag.SobelOutMDMALock	= TRUE;		// Lock Sobel out to Video out MDMA as no edge detected data is available to process
	SobelFlag.InitSobelOut		= FALSE;	// Sobel Out function not initialised	

	SobelInBlockCount			= 0;		// sobel buf sized block (Block 0 of Active frame 1) will be read from Video in bufx    
	SobelInColumnBlockCount		= 1;		// Processing Column 1 sobel blocks	
	SobelOutBlockCount			= 0;		// Block 0 of Active frame 1 - will be copied to Video_Out_Bifx after edge detection
	SobelOutColumnBlockCount 	= 1;		// Processing Column 1 sobel blocks	
	
   	return;
}

/*********************************************************************

    Function:       MDMA_SobelIn

    Description:    MDMA Sobel In buffer update - callback routine

*********************************************************************/
section ("App_Code_L1")
void MDMA_SobelIn(void)
{
   	
	/*******************************************
    video in buffer to sobel in buffer stream
    *******************************************/

	/**** Sobel In stream destination buffer config ****/	
	// Check previously used Sobel In buffer ID
	// If the previous buffer was Sobel_In_Buf1, then Sobel_In_Buf0 should be used next
	if (SobelFlag.SobelInBufID)	
	{
	    // check if Sobel_In_Buf0 is ready
		if (SobelFlag.SobelInBuf0Done)
    	{
    		// then prepare the sobel in buf 0 with video in bufx luma values
			MDMA_Sobel_In_Des.StartAddress	= (void *) (&Sobel_In_Buf0[0]);
			// Sobel_In_Buf0 will be loaded with luma values
			SobelFlag.SobelInBufID			=	0;
    	}   
    	else	// return as Sobel_In_Buf0 is not ready yet
       		return;
   	}
   	else	// Previous buffer was Sobel_In_Buf0. So Sobel_In_Buf1 should be used next
   	{
    	if (SobelFlag.SobelInBuf1Done)	// check if Sobel_In_Buf1 is ready
   		{
     		// then load sobel in buf 1 with video in luma values
			MDMA_Sobel_In_Des.StartAddress	= (void *) (&Sobel_In_Buf1[0]);
			// Sobel_In_Buf1 will be loaded with luma values
			SobelFlag.SobelInBufID			=	1;
    	}
		else	// return as Sobel_In_Buf1 is not ready yet
       		return;
   	}

	++SobelInBlockCount;	// next sobel block number to build

	// Check if this is the first sobel block
    // if yes, load the pVideoInBuf value
    if (tpVideoInBuf == NULL)	
    {
    	tpVideoInBuf = pVideoInBuf;
    	SobelInBlockCount = 0;	// Sobel is processing block 0
    }
	// Check if Active Field 1 is done. if so, process Video_In_Bufx Active field 2
    else if (!(SobelInBlockCount % SobelBlockCount))
    {
        // pVideoInBuf points to first luma value minus 2 of Video_In_Bufx Active Field1 
        // with sobel algorithm offset of extra 2 rows per block & 2 columns per row
        
        // update pVideoInBuf & temp pointer to point to first luma value of the above buffer's Active Field2
        // with sobel algorithm offset of extra 2 rows per block & 2 columns per row
        pVideoInBuf				= (pVideoInBuf + (Field2Skip - Field1Skip));	
        tpVideoInBuf 			= pVideoInBuf;
        SobelInColumnBlockCount = 1;	// move to column 1 of sobel block
    }    
    else if (!(SobelInBlockCount % SobelFieldBlocks))		// move to the next column block
    {      
        // pVideoInBuf always to first luma value of Video_In_Bufx Active Field1 or Field2
        // with sobel algorithm offset of extra 2 rows per block & 2 columns per row
        
        tpVideoInBuf = (pVideoInBuf + (SOBEL_COLUMN_SIZE * 2 * SobelInColumnBlockCount));
        SobelInColumnBlockCount++;			// move to next column in the sobel block        
    }
    else		// move to next row in sobel block
    {
        tpVideoInBuf = (tpVideoInBuf + (DataPerLine * SobelRowSize));
    }
          
    // Load the Source start address
	MDMA_Sobel_In_Src.StartAddress 	= (void *) tpVideoInBuf;

	// lock video in to sobel in MDMA until this transfer is finished		
	SobelFlag.SobelInMDMALock		= TRUE;
	
   	// Start MDMA 2D copy (video in buffer to sobel in buffer stream)
   	// MDMA stream handle, 2D destination config, 2D source config, Element width (1 byte), Callback function
   	ezErrorCheck(adi_dma_MemoryCopy2D (MDMA_Handle_Stream0,&MDMA_Sobel_In_Des,&MDMA_Sobel_In_Src,1,MDMA_Callback0));	
   	
   	return;
}

/*********************************************************************

    Function:       MDMA_SobelOut

    Description:    MDMA Sobel Out buffer update - callback routine

*********************************************************************/
section ("App_Code_L1")
void MDMA_SobelOut()
{
    if (SystemFlag.SobelDone)		// Sobel conversion of Video In Bufx is done. wait until next Video In Buf is ready
   		return;
   		
	/*******************************************
    Sobel out buffer to video out buffer stream
    *******************************************/

	/**** Sobel Out stream Source buffer config ****/	
	// Start address - init to point the first VALID location in Sobel_Out_Buf1
    // always first and last row in a sobel out buffer is invalid
    // always first and last column in each sobel out buffer row is invalid
    
    // Check previously used Sobel Out buffer ID 
   	if (SobelFlag.SobelOutBufID)		// If the previous buffer was Sobel_Out_Buf1, then Sobel_Out_Buf0 should be used next
	{
		if (SobelFlag.SobelOutBuf0Done)		// check if Sobel_Out_Buf0 is ready
    	{
    		// Sobel_Out_Buf0 has sobel edge detected values
			MDMA_Sobel_Out_Src.StartAddress		= (void *) (&Sobel_Out_Buf0[0] + SOBEL_COLUMN_SIZE + SOBEL_OFFSET + 1);
			// Sobel_Out_Buf0 will be copied to Video_Out_Buf
			SobelFlag.SobelOutBufID	=	0;
   		}
   		else
       		return;		// return as Sobel_Out_Buf1 is not ready yet
	}	
    else 		// Previous buffer was Sobel_Out_Buf0. So Sobel_Out_Buf1 should be used next
    {
    	if (SobelFlag.SobelOutBuf1Done)		// check if Sobel_Out_Buf1 is ready
   		{
	     	// Sobel_Out_Buf1 has sobel edge detected values
			MDMA_Sobel_Out_Src.StartAddress		= (void *) (&Sobel_Out_Buf1[0] + SOBEL_COLUMN_SIZE + SOBEL_OFFSET + 1);
			SobelFlag.SobelOutBufID	=	1;		// Sobel_Out_Buf1 will be copied to Video_Out_Buf
   		}
		else
       		return;		// return as Sobel_Out_Buf0 is not ready yet
    }
    
	++SobelOutBlockCount;		// next sobel block number to build
    
    // Check if this is the first sobel block
    // if yes, load the pVideoOutBuf value (pVideoOutBuf points to first luma value of Video_In_Bufx Active Field1)
    if (tpVideoOutBuf == NULL)	
    {
    	tpVideoOutBuf = pVideoOutBuf;
    	SobelOutBlockCount = 0;	// Sobel is processing block 0
    }
    // Check if Active Field 1 is done. 
   	else if (!(SobelOutBlockCount % SobelBlockCount))	// if yes, process Video_In_Bufx Active field 2
    {
       	// pVideoOutBuf is pointing to first luma value of Video_In_Bufx Active Field1 
      
       	// update pVideoOutBuf & temp pointer to point to first luma value of the above buffer's Active Field2
       	pVideoOutBuf 	= (pVideoOutBuf + (Field2Skip - Field1Skip));
       	tpVideoOutBuf 	= pVideoOutBuf;
       	SobelOutColumnBlockCount = 1;	// move to column 1 of sobel block
    }
    else if (!(SobelOutBlockCount % SobelFieldBlocks))		// move to the next column block
    {       
        // pVideoOutBuf points to first luma value of Video_In_Bufx Active Field1 or Field2
        
        tpVideoOutBuf = (pVideoOutBuf + (SOBEL_COLUMN_SIZE * 2 * SobelOutColumnBlockCount));
        SobelOutColumnBlockCount++;			// move to next column in the sobel block        
    }
    else		// move to next row in sobel block
    {
       	tpVideoOutBuf = (tpVideoOutBuf + (DataPerLine * SobelRowSize));
    }
    
    // completed processing whole video in bufx frame
    if ((SobelOutBlockCount+1) >= (SobelBlockCount * 2))
    {
        // Sobel conversion of Video_In_Bufx is done. wait until next Video_In_Bufx is ready
       	SystemFlag.SobelDone		= TRUE;	
    }  
               
    // Load the Destination start address
	MDMA_Sobel_Out_Des.StartAddress		= (void *) tpVideoOutBuf;
	
	// lock sobel out to video out MDMA until this transfer is finished
	SobelFlag.SobelOutMDMALock	= TRUE;	
	
   	// Start MDMA 2D copy (Sobel Out Bufx to Video Out Bufx data stream)
   	// MDMA stream handle, 2D destination config, 2D source config, Element width (1 byte), Callback function
   	ezErrorCheck(adi_dma_MemoryCopy2D (MDMA_Handle_Stream1,&MDMA_Sobel_Out_Des,&MDMA_Sobel_Out_Src,1,MDMA_Callback1));	
   	
   	return;
}	

/*********************************************************************

    Function:       do_SobelEdgeDetection

    Description:    Performs sobel edge detection on incoming video
    				and displays the result in a video monitor

*********************************************************************/
section ("App_Code_L1")
void do_SobelEdgeDetection (void)
{
   
    // start next sobel conversion only if this falg is cleared
	if (!SystemFlag.SobelDone)
    {   
        // check if previous video in to sobel in streaming is done
    	if (!SobelFlag.SobelInMDMALock)
       	{
       	    // load next set of luma values from Video_In_Bufx to Sobel_In_Bufx
			MDMA_SobelIn ();
       	}
       		
        // Check if Sobel_In_Buf0 & Sobel_Out_Buf0 are ready
        if ((!SobelFlag.SobelInBuf0Done) && (!SobelFlag.SobelOutBuf0Done))
        {
            // if so, start sobel conversion with sobel in/out bufs 0
        	// call Sobel edge detection routine
           	// Sobel threshold empirically set to 100
			sobel_fast(&Sobel_In_Buf0[0], (SobelRowSize+SOBEL_OFFSET), (SOBEL_COLUMN_SIZE+SOBEL_OFFSET), &Sobel_Out_Buf0[0], 2);
			// Sobel_Out_Buf0 has Sobel out values to copy to Video_Out_Buf
			SobelFlag.SobelOutBuf0Done	= TRUE;
			// Sobel_In_Buf0 is ready to get next block of luma
			SobelFlag.SobelInBuf0Done	= TRUE;
      	}
            
        // Check if Sobel_In_Buf1 & Sobel_Out_Buf1 are ready
        else if ((!SobelFlag.SobelInBuf1Done) && (!SobelFlag.SobelOutBuf1Done))
        {
            // if so, start sobel conversion with sobel in/out bufs 1
          	// call Sobel edge detection routine
           	// Sobel threshold empirically set to 100
			sobel_fast(&Sobel_In_Buf1[0], (SobelRowSize+SOBEL_OFFSET), (SOBEL_COLUMN_SIZE+SOBEL_OFFSET), &Sobel_Out_Buf1[0], 2);
			// Sobel_Out_Buf1 has Sobel out values to copy to Video_Out_Buf
			SobelFlag.SobelOutBuf1Done	= TRUE;
			// Sobel_In_Buf1 is ready to get next block of luma
			SobelFlag.SobelInBuf1Done	= TRUE;
      	}
		// check if previous sobel out to video out streaming is done      	
		if (!SobelFlag.SobelOutMDMALock)
       	{
       	    // start Sobel_Out_Bufx to Video_Out_Buf streaming
			MDMA_SobelOut();
       	}       		       		
	}
	
	return;
}    

	
/*****/
