// file: M0Main.c

#include "lpc43xx.h"
#include "system_lpc43xx.h"
#include "lpc43xx_scu.h"
#include <AppDefs.h>

#define M0_IS_MEASURE_CPU_USAGE 0

static DS_CamCB SHARERAM s_ccb;

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

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

void IPC_IRQHandler(void)
{
	// clear IPC irq pending bit
	((volatile unsigned long*)(0x40043130))[0] = 0;
	NVIC_EnableIRQ(M0_SGPIO_IRQn);
}


void ATR_RAMCODE SGPIO_IRQHandler(void)                 //Handles all SGPIO interrupts
{
	volatile unsigned long *pixelPTR;
	LPC_SGPIO_Type *pSGP = LPC_SGPIO;
	uint32_t st = 0;										//Variable used to store the interrupt value, what slice had an interrupt.
	//	volatile unsigned int *sgpio_shadow = &LPC_SGPIO->REG_SS[0];
	st = pSGP->STATUS_1;

	if(st & 1)	
	{
		pSGP->CTR_STATUS_1 = 0x1;
		pixelPTR = s_ccb.pBuf;
		if (s_ccb.test == 0)
		{
			*pixelPTR++ = LPC_SGPIO->REG_SS[pin7Slice];
			*pixelPTR++ = LPC_SGPIO->REG_SS[pin6Slice];
			*pixelPTR++ = LPC_SGPIO->REG_SS[pin5Slice];
			*pixelPTR++ = LPC_SGPIO->REG_SS[pin4Slice];
			*pixelPTR++ = LPC_SGPIO->REG_SS[pin3Slice];
			*pixelPTR++ = LPC_SGPIO->REG_SS[pin2Slice];
			*pixelPTR++ = LPC_SGPIO->REG_SS[pin1Slice];
			*pixelPTR++ = LPC_SGPIO->REG_SS[pin0Slice];
		}
		else
		{
			*pixelPTR++ = s_ccb.vsyncCnt ;
			*pixelPTR++ = s_ccb.vsyncCnt ;
			*pixelPTR++ = s_ccb.vsyncCnt ;
			*pixelPTR++ = s_ccb.vsyncCnt ;
			*pixelPTR++ = 0x55555555;
			*pixelPTR++ = 0x66666666;
			*pixelPTR++ = 0x77777777;
			*pixelPTR++ = 0x88888888;
		}
		s_ccb.sgpIntPerFra++;
		// update pointer only if it is not overrun (may caused by some noises or porch settings),
		// in no case it is allowed to damage heap managment block by overflow the buffer!!!
		if (s_ccb.sgpIntPerFra <  CAP_BUF_SIZE / 8 / 4)	// 8 slices per irq, 4 bytes per slice
		{
			s_ccb.pBuf = pixelPTR;			
		}
		else
		{
			// buffer overrun, disable SGPIO irq to wait for next frame
			// NVIC_DisableIRQ(SGPIO_IINT_IRQn);	

		}
	}		
}



// M4 did all required initializations of SGPIO, M0 only need to respond to its IRQ!
void SGPIO_IRQHandlerB (void)                    //Handles all SGPIO interrupts
{
	volatile unsigned long *pixelPTR;
	LPC_SGPIO_Type *pSGP = LPC_SGPIO;
	uint32_t st = 0;										//Variable used to store the interrupt value, what slice had an interrupt.
	//	volatile unsigned int *sgpio_shadow = &LPC_SGPIO->REG_SS[0];
	st = pSGP->STATUS_1;

	if(st & 1)	
	{
		pSGP->CTR_STATUS_1 = 0x1;
		pixelPTR = s_ccb.pBuf;
		if (s_ccb.test == 0)
		{
			*pixelPTR++ = LPC_SGPIO->REG_SS[pin7Slice];
			*pixelPTR++ = LPC_SGPIO->REG_SS[pin6Slice];
			*pixelPTR++ = LPC_SGPIO->REG_SS[pin5Slice];
			*pixelPTR++ = LPC_SGPIO->REG_SS[pin4Slice];
			*pixelPTR++ = LPC_SGPIO->REG_SS[pin3Slice];
			*pixelPTR++ = LPC_SGPIO->REG_SS[pin2Slice];
			*pixelPTR++ = LPC_SGPIO->REG_SS[pin1Slice];
			*pixelPTR++ = LPC_SGPIO->REG_SS[pin0Slice];
		}
		else
		{
			*pixelPTR++ = 0x11111111;
			*pixelPTR++ = 0x22222222;
			*pixelPTR++ = 0x33333333;
			*pixelPTR++ = 0x44444444;
			*pixelPTR++ = 0x55555555;
			*pixelPTR++ = 0x66666666;
			*pixelPTR++ = 0x77777777;
			*pixelPTR++ = 0x88888888;
		}
		// update pointer only if it is not overrun (may caused by some noises or porch settings),
		// in no case it is allowed to damage heap managment block by overflow the buffer!!!
		if (s_ccb.sgpIntPerFra <  CAP_BUF_SIZE / 8 / 4)	// 8 slices per irq, 4 bytes per slice
		{
			s_ccb.pBuf = pixelPTR;
			s_ccb.sgpIntPerFra++;
		}
		else
		{
			// buffer overrun, disable SGPIO irq to wait for next frame
			NVIC_DisableIRQ(M0_SGPIO_IRQn);
			// s_ccb.rcvTglBit ^= 1;
			#if 0 == IS_TWIN_RXBUF
			#else
			// s_ccb.rcvTglBit ^= 1;
			#endif			
		}
	}			
}


// M4 send IPC irq when a 1st edge of VSYNC is detected.
void IPCIrqInit(void)
{
	unsigned long t1;
	volatile unsigned long *pNVIC_IPR0 = (volatile unsigned long*) 0xE000E400;
	volatile unsigned long *pNVIC_ISER0 = (volatile unsigned long*) 0xE000E100;
	// Enable IPC IRQ, Prio set to lowest
	t1 = pNVIC_IPR0[0] & 0xFFFF00FF;
	t1 |= 2 << (6+8);
	pNVIC_IPR0[0] = t1;
	pNVIC_ISER0[0] = 1<<1;
}


int main(void) {
	volatile int i;
	
	__set_PRIMASK(0);
	s_ccb.m0CycCnt = 0;
	s_ccb.vsyncCnt = 0;
	
	IPCIrqInit();
	
	while(1) {
		// if you want to measure consumed M0 power, define M0_IS_MEASURE_CPU_USAGE to non zero
		#if M0_IS_MEASURE_CPU_USAGE == 0
			__WFI();
			s_ccb.m0CycCnt++;	// in this case, m0CycCnt is just the interrupt count
		#else
			Delay(20 * 1000);
			s_ccb.m0CycCnt++;
		#endif
	}
}
