#include "spb_system.h"
#include "spb_module_main.h"
#include "environment.h"    
#include "timer.h"
#include "master.h"
#include "system_setup.h"
#include "DMAScheduler.h"
#include "data_indicator.h"
#include "image_control.h"
#include "HPI_Controller.h"
#include "srio_master.h"
#include "csl_intcAux.h"

#define BOARD_TIMEOUT						120000

TCPBHWInfo CPBHWInfo[SYSTEM_CPB_COUNT];

#pragma DATA_ALIGN (CPBStatus, 8)
TCPBStatus CPBStatus[SYSTEM_CPB_COUNT];
TProcessingCaptureInfo ProcessingCaptureInfo[SYSTEM_SPB_CAMERA_MAX_COUNT];

unsigned int CPB_StatusList[SYSTEM_CPB_MAX_COUNT];	// read from cpb

int CPBFirstCheck[SYSTEM_CPB_MAX_COUNT];
unsigned int CPBFirstCheckTime[SYSTEM_CPB_MAX_COUNT];

#pragma DATA_ALIGN (Invalidate_Image_Command_Data, 8)
unsigned int Invalidate_Image_Command_Data;

#pragma DATA_ALIGN (CPBCompatibility, 8)
TCPBCompatibility CPBCompatibility;

#define RUN_STEP_INIT							0
#define RUN_STEP_CPB_RESET_LOW_1				1
#define RUN_STEP_CPB_RESET_LOW_1_WAIT		2
#define RUN_STEP_CPB_RESET_HIGH_1				3
#define RUN_STEP_CPB_RESET_HIGH_1_WAIT		4
#define RUN_STEP_CPB_RESET_LOW_2				5
#define RUN_STEP_CPB_RESET_LOW_2_WAIT		6
#define RUN_STEP_CPB_RESET_HIGH_2				7
#define RUN_STEP_CPB_RESET_HIGH_2_WAIT		8
#define RUN_STEP_CPB_SET_PLL					9
#define RUN_STEP_CPB_CLEAR						10
#define RUN_STEP_CPB_CLEAR_WAIT				11
#define RUN_STEP_CPB_RUN						12
#define RUN_STEP_SETUP							13
#define RUN_STEP_COMPLETE						14

#define RUN_SUB_STEP_INIT					0
#define RUN_SUB_STEP_LOAD_PROGRAM		1
#define RUN_SUB_STEP_CPB_DOWNLOAD		2
#define RUN_SUB_STEP_COM_WAIT			3
#define RUN_SUB_STEP_CPB_BOOT				4
#define RUN_SUB_STEP_COMPLETE				5


#define CPB_RESET_LOW_WAITING_TIME		1000
#define CPB_RESET_HIGH_WAITING_TIME		1000

#define _PLL1CTL_ADDR				0x020E0100u
#define _PLL1M_ADDR					0x020E0110u
TRunInfo RunInfo;
TSrioRunInfo SrioRunInfo;
TCPBRunStatus CPBRunStatus;

typedef struct 
{
	unsigned int BoardID;
	unsigned char CPUKind;
	unsigned char dummy[3];
} TCPBBootInfo;

#pragma DATA_SECTION(ProgramBuffer, ".sdram");
#pragma DATA_ALIGN(ProgramBuffer, 1024);
unsigned char ProgramBuffer[DOWNLOAD_MAX_SIZE];
#pragma DATA_SECTION(ProgramBinBuffer, ".sdram");
#pragma DATA_ALIGN(ProgramBinBuffer, 1024);
unsigned char ProgramBinBuffer[CPB_MAX_CODE_SIZE];

#pragma DATA_SECTION(SrioProgramBinBuffer, ".sdram");
#pragma DATA_ALIGN(SrioProgramBinBuffer, 1024);
unsigned char SrioProgramBinBuffer[SYSTEM_MAX_SPB_CLIENT_BOARD_COUNT][CPB_MAX_CODE_SIZE];

#define PROGRAM_COPY_PAGE_SIZE			512

#pragma DATA_ALIGN(HPITempBufferW, 4);
#pragma DATA_ALIGN(HPITempBufferR, 4);
unsigned int HPITempBufferW[PROGRAM_COPY_PAGE_SIZE];
unsigned int HPITempBufferR[PROGRAM_COPY_PAGE_SIZE];

//#define USB_COM_WAITING_TIME			100
//#define USB_COM_WAITING_TIME			0
#define USB_COM_WAITING_TIME			10

int CPBBootEnable;
unsigned int CPBBootStartTime;
unsigned int CPBClearVal;

TSPBSubSystem SPBSubSystem;
extern TTabletCharacter TabletCharacter_SPB;
unsigned int Current50usTime;
unsigned int Current50usCounter;
#define MAX_50US_COUNT				10000000u
#pragma DATA_ALIGN(IdleProcessData, 8)
TIdleProcessData IdleProcessData;

volatile int System_Reset_SW = 0;
unsigned int System_Reset_Trigger_Time;
int hpi_error_cnt;

int cpb_pid;
int w = 3;
int h = 216;

void System_Idle_Process_Init(void);
void RefreshImageArea(unsigned char *srcImage, int *left, int *top, int *width, int *height, int size, int threshold);
//---------------------------------------------------------------------------
void ClearCPBStatus(void)
{
	int cpbIndex;
	for (cpbIndex = 0; cpbIndex < SYSTEM_CPB_MAX_COUNT; cpbIndex++)
	{
		CPB_StatusList[cpbIndex] = 0;
		CPBFirstCheck[cpbIndex] = 0;
		CPBFirstCheckTime[cpbIndex] = 0;
	}

	for (cpbIndex = 0; cpbIndex < SYSTEM_CPB_MAX_COUNT; cpbIndex++)
	{
		SPBSubSystem.CPBInfo[cpbIndex].ProcessingState = CPB_PROCESSING_READY;
	}
}
//---------------------------------------------------------------------------
void InitSPBSystem(void)
{
	int cpbIndex, camIndex;
	for (cpbIndex = 0; cpbIndex < SYSTEM_CPB_MAX_COUNT; cpbIndex++)
	{
		CPB_StatusList[cpbIndex] = 0;
		CPBFirstCheck[cpbIndex] = 0;
		CPBFirstCheckTime[cpbIndex] = 0;
	}
	for (cpbIndex = 0; cpbIndex < SYSTEM_CPB_MAX_COUNT; cpbIndex++)
	{
		CPBStatus[cpbIndex].Status = CPB_STATUS_DISABLED;
		SPBSubSystem.CPBInfo[cpbIndex].ProcessingState = CPB_PROCESSING_READY;
	}

	for (camIndex = 0; camIndex < SYSTEM_SPB_CAMERA_MAX_COUNT; camIndex++)
	{
		ProcessingCaptureInfo[camIndex].Status = PROCESSING_CAPTURE_STATUS_IDLE;
		ProcessingCaptureInfo[camIndex].Enabled = 0;
		ProcessingCaptureInfo[camIndex].CaptureHeight = 0;
		ProcessingCaptureInfo[camIndex].CapturedLineCount = 0;
	}

	RunInfo.RunSW = 0;
	RunInfo.RunMode = 0;
	RunInfo.RunCPB_FFID = 0;
	SrioRunInfo.RunSW = 0;
	SrioRunInfo.RunMode = 0;
	SrioRunInfo.RunCPB_FFID = 0;

	CPBBootEnable = 0;

	System_Reset_SW = FALSE;
	hpi_error_cnt = 0;
	System_Idle_Process_Init();

	memset(VirtualCPBProcessedData, 0, sizeof(TVirtualCPBProcessedData) * 800);
	memset(VirtualSPBProcessedData, 0, sizeof(TVirtualSPBProcessedData) * SPB_TABLET_LIST_COUNT + 1);
}
//---------------------------------------------------------------------------
int IsAvailableCPB(int cpbIndex)
{
	if (!CPBStatus[cpbIndex].IsDown)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

//---------------------------------------------------------------------------
//int Check_Process_Finished(int cpbIndex)
void CPB_Processing_Check(void)
{
	int cpb_processing_status;
	int cpbIndex;

	for (cpbIndex = 0; cpbIndex < SYSTEM_CPB_MAX_COUNT; cpbIndex++)
	{
		if (SPBSubSystem.CPBInfo[cpbIndex].ProcessingState == CPB_PROCESSING_RUNNING)
		{
			cpb_processing_status = CPB_StatusList[cpbIndex];
			if (cpb_processing_status == CPB_PROCESSING_FINISHED)
			{
				CPBFirstCheck[cpbIndex] = 0;
				SPBSubSystem.CPBInfo[cpbIndex].ProcessingState = CPB_PROCESSING_FINISHED;
			}
			else
			{
				Master_Process_CPB(cpbIndex);
			}
		}
	}
}
//---------------------------------------------------------------------------
void ProcessingCapture_Init(void)
{
	int camIndex;

	for (camIndex = 0; camIndex < SYSTEM_SPB_CAMERA_MAX_COUNT; camIndex++)
	{
		ProcessingCaptureInfo[camIndex].Enabled = 0;
	    ProcessingCaptureInfo[camIndex].CaptureHeight = 0;
		//ProcessingCaptureInfo[camIndex].CaptureHeight = SetupInfo.CaptureLength[camIndex];
	    ProcessingCaptureInfo[camIndex].CapturedLineCount = 0;
        ProcessingCaptureInfo[camIndex].Status = PROCESSING_CAPTURE_STATUS_IDLE;
	}
}
//---------------------------------------------------------------------------
void ProcessingCapture_StatusReset(void)
{
	int camIndex;
	for (camIndex = 0; camIndex < SYSTEM_SPB_CAMERA_MAX_COUNT; camIndex++)
	{
        ProcessingCaptureInfo[camIndex].Status = PROCESSING_CAPTURE_STATUS_IDLE;
	}
}
//---------------------------------------------------------------------------
void CPB_Run_Ready(unsigned int runMode, unsigned int runMaskL, unsigned int runMaskH,
	TFFID runCPB_FFID)
{
	if (RunInfo.RunSW == 0)
	{
		RunInfo.RunMode = runMode;
		RunInfo.RunMask[0] = runMaskL;
		RunInfo.RunMask[1] = runMaskH;
		RunInfo.RunCPB_FFID = PID_CPB_TABLET_5;
//		RunInfo.RunCPB_FFID = PID_CPB_CAPSULE_5;
		RunInfo.RunStep = RUN_STEP_INIT;
		RunInfo.RunSW = 1;		
	}
}

//---------------------------------------------------------------------------
void System_Process_Loop(void)
{
	if (CPBBootEnable)
	{
		CPB_Run_Ready(RUN_MODE_RERUN, 0xFFFFFFFF, 0xFFFFFFFF, PID_CPB_TABLET_5);
		CPBBootEnable = 0;
	}
	CPB_Processing_Check();
}
//---------------------------------------------------------------------------
void CPB_Auto_Boot(void)
{	
	if (SrioRunInfo.RunSW == 0)
	{
		SrioRunInfo.RunMode = 0;
		SrioRunInfo.RunCPB_FFID = PID_CPB_TABLET_5;
		SrioRunInfo.RunStep = CPB_BOOT_PROCESS_READY;
		SrioRunInfo.RunSW = 1;		
	}
}
//---------------------------------------------------------------------------
int Request_SendData(unsigned short indicator, void *data_address, int data_size, int cpbIndex, unsigned int dst_address)
{
	int returnValue = 0;
	returnValue = HPI_SendData(PRI_IND_PROCESSING, indicator, data_address, data_size, cpbIndex);
	if (!returnValue)
	{
		//CPBStatus[cpbIndex].IsDown = 1;
	}
	return returnValue;
}
//---------------------------------------------------------------------------
int Request_SendStream(unsigned short indicator, void *data_address, int data_size, int cpbIndex, unsigned int dst_address)
{
	return 0;
}
//---------------------------------------------------------------------------

int Request_SendPartialImage(int camIndex, int captureIndex, int left, int top, int width, int height, int cpbIndex)
{
	int arrangedTopPos;
	int arrangedLeftPos;
	int lineWidth_Word;	
	unsigned char *tempImage;
	unsigned int ImageIndicator;
	int ImageWidth;
	unsigned char *VirtualImage;
	unsigned char *SendImage;
	
	arrangedTopPos = (top + 3) / 4 * 4;
	arrangedLeftPos = (left + 3) / 4 * 4;
	lineWidth_Word = (width + 3) / 4;

	if (SystemSetupData.CameraKind[camIndex] == CAMERA_KIND_NFA_2D)
	{
		if(TabletCharacter_SPB.HighResolutionImage)
		{
			ImageIndicator = IND_IMAGE_BUFFER_1;
			ImageWidth = SYSTEM_CAMERA_HD_WIDTH;		
		}
		else
		{
			ImageIndicator = IND_IMAGE_BUFFER_1;
			ImageWidth = SYSTEM_CAMERA_WIDTH;
		}
	}
	else
	{
		ImageIndicator = IND_IMAGE_BUFFER_3D;
		ImageWidth = SYSTEM_CAMERA_WIDTH_3D;
	}	

	if(VirtualInspectionSW)
	{
		VirtualImage = DummyImage[camIndex];
		
		SendImage = VirtualImage;
		return SRIO_SendData(PRI_IND_PROCESSING, ImageIndicator, (unsigned char *)SendImage + arrangedTopPos * ImageWidth + arrangedLeftPos, 
										lineWidth_Word, cpbIndex, 1, height, ImageWidth - lineWidth_Word * 4, arrangedTopPos * ImageWidth + arrangedLeftPos);		
	}
	else
	{
			if(VirtualInspectionSWFromHCB)
			{
				tempImage = DummyImage[camIndex];			
			}
			else
			{
				tempImage = ProcessingImageInfo.ImageBuffer[captureIndex][camIndex];
			}
		SendImage = tempImage;

		return SRIO_SendData(PRI_IND_PROCESSING, ImageIndicator, (unsigned char *)SendImage + arrangedTopPos * ImageWidth + arrangedLeftPos, 
										lineWidth_Word, cpbIndex, 1, height, ImageWidth - lineWidth_Word * 4, arrangedTopPos * ImageWidth + arrangedLeftPos);		
	}
	return TRUE;
error:
	return FALSE;
}
//---------------------------------------------------------------------------
int Request_ReceiveData(unsigned short indicator, void *data_address, unsigned int data_size, int cpbIndex)
{
	int returnValue;

	return  SRIO_ReceiveData(PRI_IND_PROCESSING, indicator, data_address, data_size, cpbIndex);


}
//---------------------------------------------------------------------------

void  CPBProcessingCheckStart(int cpbIndex)
{
	SPBSubSystem.CPBInfo[cpbIndex].ProcessingState = CPB_PROCESSING_RUNNING;
	CPB_StatusList[cpbIndex] = CPB_PROCESSING_RUNNING;	
}

//---------------------------------------------------------------------------
int Check_Process_Finished(int cpbIndex)
{
	if (SPBSubSystem.CPBInfo[cpbIndex].ProcessingState == CPB_PROCESSING_RUNNING)
	{
		return CPB_PROCESSING_RUNNING;
	}
	else if (SPBSubSystem.CPBInfo[cpbIndex].ProcessingState == CPB_PROCESSING_FINISHED)
	{
		return CPB_PROCESSING_FINISHED;
	}
	else
	{
		return -1;
	}
}
//---------------------------------------------------------------------------
void System_Idle_Process_Init(void)
{
	int listIndex;
	IdleProcessData.CurrentIndex = 0;
	IdleProcessData.CurrentTime = 0;
	for (listIndex = 0; listIndex < IDLE_PROCESS_LIST_COUNT; listIndex++)
	{
		IdleProcessData.Time[listIndex] = 0;
		IdleProcessData.TimeCounter[listIndex] = 0;
		IdleProcessData.Min50usCount[listIndex] = 0;
		IdleProcessData.Max50usCount[listIndex] = MAX_50US_COUNT;
	}      
	Current50usCounter = 0;
	Current50usTime = Board50usTimer;
}
//----------------------------------------------------------
void System_Idle_Process(void)
{	
	if (Current50usTime == Board50usTimer)
	{
		Current50usCounter++;
	}
	else
	{
		if (Board50usTimer - Current50usTime - 1 != 0)
		{
			IdleProcessData.Min50usCount[IdleProcessData.CurrentIndex] = 0;	
		}
		else
		{
			if (IdleProcessData.Min50usCount[IdleProcessData.CurrentIndex] > Current50usCounter)
			{
				IdleProcessData.Min50usCount[IdleProcessData.CurrentIndex] = Current50usCounter;
			}
		}
		if (IdleProcessData.Max50usCount[IdleProcessData.CurrentIndex] < Current50usCounter)
		{
			IdleProcessData.Max50usCount[IdleProcessData.CurrentIndex] = Current50usCounter;
		}
		Current50usCounter = 0;
		Current50usTime = Board50usTimer;
	}

	if (IdleProcessData.CurrentTime == Board100MSTmr)
	{
		IdleProcessData.TimeCounter[IdleProcessData.CurrentIndex]++;
	}
	else
	{
		IdleProcessData.CurrentIndex = (IdleProcessData.CurrentIndex + 1) & IDLE_PROCESS_LIST_MASK;
		IdleProcessData.CurrentTime = Board100MSTmr;
		IdleProcessData.Time[IdleProcessData.CurrentIndex] = Board100MSTmr;
		IdleProcessData.TimeCounter[IdleProcessData.CurrentIndex] = 1;
		IdleProcessData.Min50usCount[IdleProcessData.CurrentIndex] = MAX_50US_COUNT;
		IdleProcessData.Max50usCount[IdleProcessData.CurrentIndex] = 0;
	}
}
//----------------------------------------------------------
void System_Process_20ms(void)
{
	CSL_IntcGlobalEnableState 	state;
	if (System_Reset_SW)
	{
		if ((int)(Board1MSTmr - System_Reset_Trigger_Time) > 100)
		{
//			WHDOG = 1;
			System_Reset_SW = FALSE;

			CSL_intcGlobalDisable(&state);
			jump();	
		}		
	}
}
//----------------------------------------------------------

void RefreshImageArea(unsigned char *srcImage, int *left, int *top, int *width, int *height, int size, int threshold)
{
	int startX, endX, startY, endY;
	int minX, maxX, minY, maxY;
	int x, y;
	
	startX = *left;
	startY = *top;
	endX = *left + *width;
	endY = *top + *height;

	minX = SYSTEM_CAMERA_WIDTH;
	maxX = 0; 
	minY = SYSTEM_CAMERA_HEIGHT; 
	maxY = 0;

	for(y = startY; y < endY; y+=size)
	{
		for(x = startX; x < endX; x+=size)
		{
			if(*(srcImage + SYSTEM_CAMERA_WIDTH * y + x) > threshold)
			{
				if(minX > x) minX = x;
				if(maxX < x) maxX = x;
				if(minY > y) minY = y;
				if(maxY < y) maxY = y;	
			}		
		}
	}

	*left = minX;
	*width = maxX - minX;
	*top = minY;
	*height = maxY - minY;
}

void ThreeDImageFormatConversion(unsigned char *srcImage, unsigned char *dstImage)
{
	const int THREED_WIDTH = 480;
	int y;

	for(y = 0; y < HALF_IMAGE_HEIGHT; y++)
	{
		//while(!ImageDMAIdle);
		QDMAByteConversion(srcImage + THREED_WIDTH * 2 * y + 1, dstImage + THREED_WIDTH * y, THREED_WIDTH * 2);			
	}
}

void Cpb_Boot_Process()
{
	
	int hexSize;
	int cpbIndex;
	int srioportIndex=0;
	TCPBBootInfo cpbBootInfo;
	TSRIOTransferStatus SrioTransferStatus;
	int program_read_complete=0;
	int bError = 0;
	TErrorCode cpb_boot_result;
	int port_boot_complete_flag = 0;
	int boot_complet[4];
	int boot_inttrupt[4] = {1,1,1,1};
	int boot_start_cmd = 0xc8c8;
	unsigned int checkS1,checkS2;
	while(SrioRunInfo.RunSW)
	{
		switch(SrioRunInfo.RunStep)
		{
			case CPB_BOOT_PROCESS_READY:
				{
					for (cpbIndex = 0; cpbIndex < SYSTEM_CPB_MAX_COUNT; cpbIndex++)
					{
						SrioRunInfo.Error[cpbIndex] = 0;
						SrioRunInfo.RunSuccess[cpbIndex] = 0;
						if (SystemSetupData.CPBEnabled[cpbIndex])
						{
							CPBStatus[cpbIndex].Enabled = TRUE;
							CPBStatus[cpbIndex].IsDown = FALSE;							
							CPBStatus[cpbIndex].Status = CPB_STATUS_BOOT_READY;
						}
						else
						{
							CPBStatus[cpbIndex].Enabled = FALSE;
							CPBStatus[cpbIndex].IsDown = TRUE;
							CPBStatus[cpbIndex].Status = CPB_STATUS_DISABLED;
							SrioRunInfo.Error[cpbIndex] = 1;
						}
					}
					
					SrioRunInfo.CurrentCPBIndex = 0;
					SrioRunInfo.RunStep = CPB_BOOT_PROCESS_LOAD_PROGRAM;
				}
				break;			
			case CPB_BOOT_PROCESS_LOAD_PROGRAM:
				{
					SrioRunInfo.TargetCPURev = CPU_KIND_6678;

					if(program_read_complete == 0 )
					{
						cpb_boot_result = ReadFromFlash(SrioRunInfo.RunCPB_FFID, ProgramBuffer, DOWNLOAD_MAX_SIZE, &hexSize);
						checkS1 = CheckSumByte((unsigned char *)&ProgramBuffer,DOWNLOAD_MAX_SIZE);
						cpb_boot_result = ReadFromFlash(SrioRunInfo.RunCPB_FFID, ProgramBuffer, DOWNLOAD_MAX_SIZE, &hexSize);
						checkS2 = CheckSumByte((unsigned char *)&ProgramBuffer,DOWNLOAD_MAX_SIZE);
						if(checkS1 != checkS2)
						{
							ErrorUnit_Put(BoardID, ERROR_TYPE_DEBUG,ERROR_CODE_FLASH_READ,PID_SPB_DB_HEADER,0,0);
							cpb_boot_result = ReadFromFlash(SrioRunInfo.RunCPB_FFID, ProgramBuffer, DOWNLOAD_MAX_SIZE, &hexSize);
						}							
						if(cpb_boot_result)
						{
						 	bError = 1;
						}
						else
						{
							program_read_complete = 1;
						}
					}

					if(bError==0)
					{
						for (cpbIndex = 0; cpbIndex < SYSTEM_MAX_SPB_CLIENT_BOARD_COUNT; cpbIndex++)
						{
							SrioRunInfo.CPBProgram[cpbIndex] = (unsigned char *)&SrioProgramBinBuffer[cpbIndex];
							SrioRunInfo.CPBProgramSize[cpbIndex] = ConvertProgram(ProgramBuffer+(CPB_MAX_CODE_SIZE*cpbIndex), SrioRunInfo.CPBProgram[cpbIndex], CPB_MAX_CODE_SIZE, CPB_HEX_FORMAT_L2SEG+0x100*cpbIndex);	
						}
					}
					else
					{
						SrioRunInfo.RunStep = CPB_BOOT_PROCESS_IDLE;
						SrioRunInfo.RunSW = 0;
						break;
					}
			
					SrioRunInfo.RunStep = CPB_BOOT_PROCESS_DOWNLOAD;
				}
				break;

			case CPB_BOOT_PROCESS_DOWNLOAD:
				{	
					int tryCount = 0;
					int remainDataLength = 0;
					int programAddr = 0;
					int copyLength = 0;
					int i;
					
					cpbIndex = SrioRunInfo.CurrentCPBIndex;
					CPBStatus[cpbIndex].Status = CPB_STATUS_BOOTING;
					if (CPBStatus[cpbIndex].Enabled)
					{
						cpb_boot_result = ERROR_CODE_NONE;
						cpbBootInfo.BoardID = BoardID + cpbIndex + 1;
						cpbBootInfo.CPUKind = SystemSetupData.CPBClockKind[cpbIndex];
						Request_CopyData(SrioRunInfo.CPBProgram[cpbIndex%8], &cpbBootInfo, sizeof(TCPBBootInfo));

						for (tryCount = 0; tryCount < CPB_BOOT_RETRY_COUNT; tryCount++)
						{
							remainDataLength = (SrioRunInfo.CPBProgramSize[cpbIndex%8] + 3) / 4 * 4;
							programAddr = 0;
							
							while(remainDataLength > 0)
							{
								if (remainDataLength > CPB_PROGRAM_TRANSFER_SIZE)
								{
									copyLength = CPB_PROGRAM_TRANSFER_SIZE;
								}
								else
								{
									copyLength = remainDataLength;
								}

								Request_CopyData(HPITempBufferW, (SrioRunInfo.CPBProgram[cpbIndex%8] + programAddr), copyLength);
								Sleep(2);
								Request_SRIO_WriteData(cpbIndex,HPITempBufferW,CPBHWInfo[cpbIndex].BaseL2Addr+programAddr,copyLength/4,&SrioTransferStatus);
								Sleep(2);
								Request_SRIO_ReadData(cpbIndex,HPITempBufferR,CPBHWInfo[cpbIndex].BaseL2Addr+programAddr,copyLength/4,&SrioTransferStatus);	

								for (i = 0; i < copyLength / 4; i ++)
								{
									if (*(HPITempBufferW + i) != *(HPITempBufferR + i))
									{
										ErrorUnit_Put(BoardID + cpbIndex + 1, ERROR_TYPE_MESSAGE, ERROR_CODE_NOTMATCH, *HPI_CTRL(cpbIndex), *(HPITempBufferW + i), *(HPITempBufferR + i));
										bError = 1;
										hpi_error_cnt++;
										break;
									}
								}
								if (bError) 
								{
									break;
								}
								else
								{
									programAddr += copyLength;
									remainDataLength -= copyLength;
								}
							}
							if (!bError) break;
						}
													
						if (tryCount > CPB_BOOT_RETRY_COUNT)
						{	
							cpb_boot_result = ERROR_CODE_NOTMATCH;
						}
												
						if (!bError)	// success
						{
							SrioRunInfo.RunSuccess[cpbIndex] = 1;
							CPBStatus[cpbIndex].Status = CPB_STATUS_IDLE;
//							ErrorUnit_Put(BoardID + cpbIndex + 1, ERROR_TYPE_WARNING, cpb_boot_result, __LINE__, hexSize, SrioRunInfo.CPBProgramSize);
						}
						else	// CPB download failure
						{

							ErrorUnit_Put(BoardID + cpbIndex + 1, ERROR_TYPE_WARNING, cpb_boot_result, __LINE__, hexSize, SrioRunInfo.CPBProgramSize);
							CPBStatus[cpbIndex].Enabled = FALSE;
							CPBStatus[cpbIndex].IsDown = TRUE;
							CPBStatus[cpbIndex].Status = CPB_STATUS_DISABLED;
		
							if(SystemSetupData.CamBootEnabled == 1)		
							{
								NFA_CAMERA_RESET = 0x1;
								Sleep(5000);
								NFA_CAMERA_RESET = 0x0;
								FPGARELOAD = 0x00FA;		
							}		
						}
					}
					SrioRunInfo.CurrentCPBIndex++;					
					if(SrioRunInfo.CurrentCPBIndex == SYSTEM_CPB_MAX_COUNT)
					{
						SrioRunInfo.RunStep = CPB_BOOT_PROCESS_RUN;
					}
						
				}
				break;
			case CPB_BOOT_PROCESS_RUN:
				{
					for(srioportIndex = 0 ; srioportIndex < 4 ;	srioportIndex++)
					{
						Request_SRIO_WriteData(srioportIndex*8,&boot_start_cmd, 0x85000000,1,&SrioTransferStatus);

					}  

					CPBBootStartTime = Board1MSTmr;
					srioportIndex = 0;
					SrioRunInfo.RunStep = CPB_BOOT_PROCESS_COMPLETE;
				}
				break;
			case CPB_BOOT_PROCESS_COMPLETE:
				{
					if(!CPBStatus[srioportIndex*8+1].Enabled)
					{
						for(cpbIndex = srioportIndex*8 ; cpbIndex < srioportIndex*8+8 ;  cpbIndex++)
						{
							CPBStatus[cpbIndex].Enabled = FALSE;
							CPBStatus[cpbIndex].IsDown = TRUE;
							CPBStatus[cpbIndex].Status = CPB_STATUS_DISABLED;
						}
						port_boot_complete_flag |= 0x1<<srioportIndex;
					}
					else
					{
						Request_SRIO_ReadData(srioportIndex*8,&boot_complet[srioportIndex],CPBHWInfo[srioportIndex*8].SrioBootCompleteAddr,1,&SrioTransferStatus);
						Sleep(1);
						if(boot_complet[srioportIndex] == 0xFF)
						{
							for(cpbIndex = srioportIndex*8 ; cpbIndex < srioportIndex*8+8 ;  cpbIndex++)
							{						
								CPBStatus[cpbIndex].Status = CPB_STATUS_IDLE;
							}
							port_boot_complete_flag |= 0x1<<srioportIndex;
						}
						else
						{
							Request_SRIO_WriteData(srioportIndex*8,&boot_start_cmd, 0x85000000,1,&SrioTransferStatus);
							if(CPBBootStartTime + SRIO_BOOT_WAIT_TIME < Board1MSTmr)
							{
								for (cpbIndex = srioportIndex*8; cpbIndex < srioportIndex*8+8; cpbIndex++)
								{
									if(boot_complet[srioportIndex]&(0x1<<(cpbIndex-srioportIndex*8)))
									{
										CPBStatus[cpbIndex].Status = CPB_STATUS_IDLE;
									}
									else
									{
										CPBStatus[cpbIndex].Enabled = FALSE;
										CPBStatus[cpbIndex].IsDown = TRUE;
										CPBStatus[cpbIndex].Status = CPB_STATUS_DISABLED;							
									}
								}
								port_boot_complete_flag |= 0x1<<srioportIndex;	
							}
						}
					
					}

					if(port_boot_complete_flag==0xF)
					{
						for (cpbIndex = 0; cpbIndex < SYSTEM_CPB_MAX_COUNT; cpbIndex++)
						{

							if (CPBStatus[cpbIndex].IsDown)
							{
								CPBStatus[cpbIndex].Enabled = FALSE;
								CPBStatus[cpbIndex].IsDown = TRUE;
								CPBStatus[cpbIndex].Status = CPB_STATUS_DISABLED;

							}
							else
							{
								CPBStatus[cpbIndex].Enabled = TRUE;
								CPBStatus[cpbIndex].IsDown = FALSE;							
								CPBStatus[cpbIndex].Status = CPB_STATUS_IDLE;
							}
						}
						SrioRunInfo.RunStep = CPB_BOOT_PROCESS_IDLE;
						SrioRunInfo.RunSW = 0;				
					}
					srioportIndex++;
					if(srioportIndex >= 4) srioportIndex = 0;
				}
				break;				
		}
	}
}
