/***********************************************************************
 * $Id: main.c 3858 2012-09-25 15:33:12Z nxp39054 $
 *
 * Project: SGPIO Cammera Demo
 *
 * Description: main module
 *
 * Copyright(C) 2012, NXP Semiconductor
 * All rights reserved.
 *
 ***********************************************************************
 * Software that is described herein is for illustrative purposes only
 * which provides customers with programming information regarding the
 * products. This software is supplied "AS IS" without any warranties.
 * NXP Semiconductors assumes no responsibility or liability for the
 * use of the software, conveys no license or title under any patent,
 * copyright, or mask work right to the product. NXP Semiconductors
 * reserves the right to make changes in the software without
 * notification. NXP Semiconductors also make no representation or
 * warranty that such application will be suitable for the specified
 * use without further testing or modification.
 **********************************************************************/

/******************************************************************************
 * header files
 *****************************************************************************/
#include "LPC43xx.h"
#include "lpc43xx_cgu.h"
#include <stdio.h>
#include <string.h>
#include "GLCD.h"
#include "lpc43xx_i2c.h"
#include "AppDefs.h"
#include "FraBufQ.h"


#if 0 == IS_CFG_DONE
#error "Please configure in "AppCfg.h" first! Then change the IS_CFG_DONE macro to non-zero"
#endif

#ifndef CAMERA_SEL
#error "You must select a camera part in Appdefs.h, define CAMERA_SEL!"
#endif


/* Mode switch timeout variable */
volatile unsigned int g_msCnt;
volatile unsigned int g_procKeyPnd;
/* GLCD string buffer */
#define STRINGBUF_LEN   21

char StringBuf[STRINGBUF_LEN];

/* Extern variables */

int g_adVal;
volatile unsigned int t1;
volatile unsigned int g_free;
volatile unsigned int g_rfrshCnt = 0;
volatile unsigned int g_fps;

// define LCD frame buffers

extern DS_CamCB s_ccb;

/*-----------------------------------------------------------------------------
  SysTick IRQ Handler @ 250us
 *----------------------------------------------------------------------------*/
volatile unsigned int g_250usTick;
volatile unsigned int g_newTickCnt;
void SysTick_Handler (void) {	
	static unsigned long prevM0Cyc = 0, prevRfrshCnt = 0;
	if (!(++g_250usTick & (4-1)))
	{
		g_msCnt++;
		if (0 == (g_msCnt % 1000))
		{
			g_procKeyPnd++;
			g_free = (g_free >> 1) + ((s_ccb.m0CycCnt - prevM0Cyc) >> 1);
			g_fps = (g_fps >> 1) + ((g_rfrshCnt - prevRfrshCnt) >> 1);
			
			prevM0Cyc = s_ccb.m0CycCnt;
			prevRfrshCnt = g_rfrshCnt;
		}
	}
	g_newTickCnt++;
}

void LCD_IRQHandler(void)
{
	static unsigned int cnt;
	static BOOL32 ls_isFraBufChanged;
	LPC_LCD_Type *pLCD = LPC_LCD;
	
	if (ISBVSET(pLCD->INTSTAT, 2))
	{	
		US_VersatilePointer ptrNewFraBuf;
		cnt++;	
		if (ls_isFraBufChanged)
			{
				FBQ_ConsumeDone();
				
			}
			ls_isFraBufChanged = 0;
			FBQ_GetConsumeIndex(&ptrNewFraBuf.pv);
			if ((void*)0 != ptrNewFraBuf.pv)
			{
				pLCD->UPBASE = ptrNewFraBuf.addr;
				ls_isFraBufChanged = 1;
			}
	
	}
	// clear all flags
	pLCD->INTCLR = pLCD->INTRAW;
}



void PinInit(void)
{
	DS_PinMux2D *pm = (DS_PinMux2D*) LPC_SCU;
	LPC_GPIO_PORT_Type *pGP = LPC_GPIO_PORT;

	pm->a2d[SPT_MCLK][SPN_MCLK]				= ALT_MCLK | SPNCFG_OUT_HSPD;	

	// LEO_EN, CHIP_EN, VSYNC use GPIO (LDO_EN and CHIP_EN is not used in PixArt's 6180 cam sensor)
	pm->a2d[SPT_LDO_EN][SPN_LDO_EN] 		= ALT_LDO_EN| SPNCFG_OUT_GNRC | /* 20mA drive */ 3UL<<8;
	pm->a2d[SPT_CHIP_ENB][SPN_CHIP_ENB] = ALT_CHIP_ENB | SPNCFG_OUT_GNRC;
	

	
	//! D0-D7, Use SGPIO

	pm->a2d[SPT_SGPD0][SPN_SGPD0] = ALT_SGPD0 | SPNCFG_IN_GNRC;
	pm->a2d[SPT_SGPD1][SPN_SGPD1] = ALT_SGPD1 | SPNCFG_IN_GNRC;
	pm->a2d[SPT_SGPD2][SPN_SGPD2] = ALT_SGPD2 | SPNCFG_IN_GNRC;
	pm->a2d[SPT_SGPD3][SPN_SGPD3] = ALT_SGPD3 | SPNCFG_IN_GNRC;
	pm->a2d[SPT_SGPD4][SPN_SGPD4] = ALT_SGPD4 | SPNCFG_IN_GNRC;
	pm->a2d[SPT_SGPD5][SPN_SGPD5] = ALT_SGPD5 | SPNCFG_IN_GNRC;

	pm->a2d[SPT_SGPD6][SPN_SGPD6] = ALT_SGPD6 | SPNCFG_IN_GNRC;
	pm->a2d[SPT_SGPD7][SPN_SGPD7] = ALT_SGPD7 | SPNCFG_IN_GNRC;

	//! PxClk and HSync, connected to SGPIO
	pm->a2d[SPT_SGPPXCLK][SPN_SGPPXCLK] = ALT_SGPPXCLK | SPNCFG_IN_GNRC;
	pm->a2d[SPT_SGPHSYNC][SPN_SGPHSYNC] = ALT_SGPHSYNC | SPNCFG_IN_GNRC;
	
	// VSync is used as GPIO
	pm->a2d[SPT_VSYNC][SPN_VSYNC] = GLT_VSYNC | SPNCFG_IN_GNRC;


	//! Configure misc GPIO pins
	pGP->DIR[GPT_LDO_EN] 		|= 1UL<<GPN_LDO_EN;
	LPC_GPIO_PORT->CLR[GPT_LDO_EN] = 1UL<<GPN_LDO_EN;
	LPC_GPIO_PORT->SET[GPT_LDO_EN] = 1UL<<GPN_LDO_EN;
	pGP->DIR[GPT_CHIP_ENB] 		|= 1UL<<GPN_CHIP_ENB;
	pGP->DIR[GPT_VSYNC]			&= ~(1UL<<GPN_VSYNC);
}


const int cg_tabCnctOrd[8] = 
{
	sliceA, sliceI, sliceE, sliceJ, sliceC, sliceK, sliceF, sliceL,
};


void SGPGetRdyToGo(void)
{
	LPC_SGPIO_Type *pSGP = LPC_SGPIO;
	unsigned int i, idx;
	//LPC_SGPIO->CTRL_ENABLED = (1<<0) | (1<<8) | (1<<4) | (1<<9)
		//					| (1<<2) | (1<<10) | (1<<5) | (1<<11) ;
	
	pSGP->CTR_STATUS_1 = 0x1;	// clear old swap flag of slice A
	for (i=0; i<8; i++)
	{
		idx = cg_tabCnctOrd[i];
		pSGP->SGPIO_MUX_CFG[idx] |= 3UL<<5; // select pin as clk
		pSGP->POS[idx] = (32UL-1) | (32UL-1)<<8;
	}
}

void SGPStop(void)
{
	LPC_SGPIO_Type *pSGP = LPC_SGPIO;
	unsigned int i, idx, t;
	// disable clk for all 8 slices
	
	for (i=0; i<8; i++)
	{
		idx = cg_tabCnctOrd[i];
		t = pSGP->SGPIO_MUX_CFG[idx] & ~(3UL<<5);
		t |= 1UL<<5;	// disable clock
		pSGP->SGPIO_MUX_CFG[idx] = t;
	}
	//LPC_SGPIO->CTRL_ENABLED = 0 ;
}

// GPIO IRQ slot 6 is used by VSync IRQ, common to all cameras
void ATR_RAMCODE GPIO6_IRQHandler(void)
{
	LPC_GPIO_PIN_INT_Type *pPinInt = LPC_GPIO_PIN_INT;	
	// leave M0 to process GPIO6 int
	if (pPinInt->RISE & BVON(PIQ_VSYNC))
	{
		// rising edge
		// previous frame is completed
		pPinInt->RISE = BVON(PIQ_VSYNC);
		NVIC_DisableIRQ(SGPIO_IINT_IRQn);
		SGPStop();
		s_ccb.vsyncCnt++;
		// judge whether is the previous frame is received		
		if (s_ccb.sgpIntPerFra != 0)
		{
			__set_PRIMASK(1);
			s_ccb.rdyRxBufCnt++;
			#if 0 == IS_TWIN_RXBUF
			#else
			s_ccb.rcvTglBit ^= 1;
			#endif			
			__set_PRIMASK(0);
			s_ccb.vsyncEffCnt++;			
			s_ccb.sgpIrqCntInPrevFra = s_ccb.sgpIntPerFra;			
		}
		s_ccb.sgpIntPerFra = 0;
		if (s_ccb.freeRxBufCnt)
		{
			s_ccb.freeRxBufCnt--;			
			#if 0 == IS_TWIN_RXBUF
				s_ccb.pBuf = s_ccb.pRcvDbBuf->aa32[0];
			#else
				s_ccb.pBuf = s_ccb.pRcvDbBuf->aa32[s_ccb.rcvTglBit];
			#endif
			s_ccb.pBufEnd = s_ccb.pBuf + (CAP_BUF_SIZE / 4);
			SGPGetRdyToGo();
		
				__sev();
			
		}		
	}
}

void HardFault_Handler(void)
{
	// Unexpected vector fetch bus fault
	if (SCB->HFSR & SCB_HFSR_VECTTBL_Msk)
		SCB->HFSR = SCB_HFSR_VECTTBL_Msk;
	else
	{
		// Unexpected precise and imprecise bus fault
		if (SCB->CFSR & 3UL<<9)
		{
			SCB->CFSR = 3UL << 9;
		}
	}
	SCB->HFSR = SCB_HFSR_FORCED_Msk;
}





void Delay(unsigned int n) {
	while (n--) ;
}


	// warning: only 4kB is left to M0 RO+RW+ZI : from 0x10080000 to 0x10080FFF
	#ifndef IFLH_ALL
	#define M0IMGATTR 
	#define M0IMGFILE	"M0Img.c"
	#else
	#define M0IMGATTR __attribute__((section("SECT_M0Img")))
	#define M0IMGFILE	"M0ImgIFlhAll.c"
	#endif

	// Import M0 image
	/* fromelf.exe always generates an unsigned char LR0[] type of array */
	const M0IMGATTR /* DO NOT REMOVE THIS CONST QUALIFIER, IS USED TO PLACE THE IMAGE IN M4¡¯s RO segment */
	#include M0IMGFILE
	// the last two line makes Source Insight 3.5 can't high light syntax

	void IPC_HoldM0(void) {
		volatile uint32_t u32REG, u32Val;
		// Check if M0 is reset by reading status
		u32REG = LPC_RGU->RESET_ACTIVE_STATUS1;			
		// If the M0 has reset not asserted, hold it under reset... 
		// in u32REG, status register, 1 = no reset
		while ((u32REG & (1u << 24))) {
			u32Val = ~u32REG | (1 << 24);
			LPC_RGU->RESET_CTRL1 = u32Val;
			u32REG = LPC_RGU->RESET_ACTIVE_STATUS1;			
		}
	}

	void IPC_DownloadM0Image(unsigned char *pDst, const unsigned char *pImg, unsigned int cbSize) {	
		memcpy(pDst, pImg, cbSize);	
		// Set Slave shadow pointer to begining of rom (where application is located) 
		*(unsigned char**)0x40043404 = pDst;	// Configure M0AppMemMap to map pDst as M0¡¯s 0 address
	}

	void IPC_ReleaseM0(void) {
		volatile uint32_t u32REG, u32Val;
		// Release Slave from reset, first read status 
		u32REG = LPC_RGU->RESET_ACTIVE_STATUS1;			
		// If the M0 is being held in reset, release it... 
		// 1 = no reset, 0 = reset
		while(!(u32REG & (1u << 24))) {
			u32Val = (~(u32REG) & (~(1 << 24)));
			LPC_RGU->RESET_CTRL1 = u32Val;
			u32REG = LPC_RGU->RESET_ACTIVE_STATUS1;
		}
	}



extern signed int VideoRefresh(void);
extern void SystemInit (void);

int main(int zsi)
{
	signed int ret = ret;
	int stallCnt;
	DECLARE_GLOBAL_CRITICAL_SECTION();
	// CGU_Init();
	SystemInit();
    __set_PRIMASK(0);
    __set_FAULTMASK(0);    
 
    GLCD_Init();                          /* Graphical Display Init             */

// ------------------------------ lcd initial ----------------------------------------------
	GLCD_Clear (White);
	GLCD_SetBackColor  (DarkGreen);
	GLCD_SetTextColor  (White);
	GLCD_DisplayString (0, 0, 1, "       NXP SGPIO      ");
  GLCD_DisplayString (1, 0, 1, "     Camera Demo    ");

  GLCD_SetBackColor  (White);
  GLCD_SetTextColor  (0x04F5);

  GLCD_DisplayString (3, 0, 1, "   Please wait...   ");
	
	GLCD_DisplayString (5, 0, 1, "OmniVision OV7670");
	
	
	FBQ_Init(FRABUF_Q_CAPACITY);
	CamInit();
	__set_PRIMASK(0);
  __set_FAULTMASK(0);
	

	LPC_CCU1->CLK_M4_M0APP_CFG = 1UL;	
	IPC_HoldM0();
	IPC_DownloadM0Image((unsigned char*) 0x10080000, LR0, sizeof(LR0));
	IPC_ReleaseM0();

	NVIC_EnableIRQ(LCD_IRQn);

	stallCnt = 0;
	
  while (1)
  {
		ERRCODE err = E_GNRC;


		if (s_ccb.rdyRxBufCnt && !FBQ_IsFull())
		{					
			err = VideoRefresh();
			
			ENTER_GLOBAL_CRITICAL();
			
			if (err >= E_OK)
			{
				g_rfrshCnt++;
				
				if (s_ccb.rdyRxBufCnt != 0)
					s_ccb.rdyRxBufCnt--;
				
			}
			// inc freeRxBufCnt regardless of whether refresh is OK, don't allow accumulate the received image!!!
			s_ccb.freeRxBufCnt++;
			
			LEAVE_GLOBAL_CRITICAL();
		}
		else
		{
			if (++stallCnt > 5)
			{
				if (0 == s_ccb.freeRxBufCnt)
					s_ccb.freeRxBufCnt = 1;
			}
		}
		__WFI();
	}
}

