////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Microsoft Corporation.  All rights reserved.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include <sh7262_touch.h>
#include "..\iodefine.h"
#include "..\VDC3\SH7262_VDC3.h"
extern TOUCH_PANEL_SamplingSettings g_TouchPanel_Sampling_Settings;
struct SH7262TOUCH_Driver g_SH7262TOUCH_Driver;

static unsigned short V_adr = 0;              
static unsigned short H_adr = 0;              
static BOOL stylusDown = FALSE;
static BOOL stylusUp = TRUE;
static int touchEvent = 0;
static int getPointCnt = 0;
static BOOL gettingPoint = FALSE;

/* #define HOKUTO     1 */
#define    WAKAMATSU  1

#define TOUCH_BUFF 512

volatile int TOUCH_Xmin;
volatile int TOUCH_Xmax;
volatile int TOUCH_Ymin;
volatile int TOUCH_Ymax;
volatile int TOUCH_stat;
volatile int TOUCH_PD;
volatile int TOUCH_nPDcnt;
volatile unsigned int TOUCH_X;
volatile unsigned int TOUCH_Y;
volatile unsigned int TOUCH_XY[TOUCH_BUFF];
volatile int TOUCH_XYwp;
volatile int TOUCH_XYrp;

#define TOUCH_Xmindefault   80
#define TOUCH_Ymindefault  908
#define TOUCH_Xmaxdefault  957
#define TOUCH_Ymaxdefault  127

#define LCD_WIDTH 320
#define LCD_HIGHT 240

void SH7262TOUCH_Driver::IRQEnable()
{

}

void SH7262TOUCH_Driver::IRQDisable()
{
}

BOOL SH7262TOUCH_Driver::Enable( GPIO_INTERRUPT_SERVICE_ROUTINE touchIsrProc )
{     
	if (!Initialize())
	{
		return FALSE;
	}
	
	TOUCH_PenDownInitialize();
	
	g_SH7262TOUCH_Driver.m_touchIsrProc = touchIsrProc;	
	
	//Enable the TouchScreen's interrupt.
	IRQEnable();

    return TRUE;
}

BOOL SH7262TOUCH_Driver::Disable()
{
    IRQDisable();
    
    return true;
}

void SH7262TOUCH_Driver::GetPoint( TOUCH_PANEL_SAMPLE_FLAGS* pTipState, int* pSource, int* pUnCalX, int* pUnCalY )
{
    *pTipState = 0;
    *pUnCalX = 0;
    *pUnCalY = 0;
    *pSource = 0;
	
    int x = 0;
    int y = 0;
	int xy = 0;
	int j;
	
    UINT16 totalReads = g_TouchPanel_Sampling_Settings.ReadsToIgnore + g_TouchPanel_Sampling_Settings.ReadsPerSample;	
		
	getPointCnt = 0;
	
	if (totalReads == 0) totalReads=1;
	
	if(stylusDown)
    {
        *pTipState |= TouchSamplePreviousDownFlag;
    }
	
	touchEvent = TOUCH_GetPenDown();
	
	if (touchEvent == -1)		//Touch down or move event
	{
	    for(j = 0; j < totalReads; j++)	
		{
			xy = TOUCH_GetXY(0);
			x += xy & 0xFFF;
			y += (xy >> 16) & 0xFFF;
		}
	}
	
	// Calculate average
	x /= totalReads;
	y /= totalReads;
		
	if (!(touchEvent)) //Touch up
	{	
		if(stylusDown)
		{
			stylusDown = FALSE;
			if (g_SH7262TOUCH_Driver.m_touchIsrProc != NULL)
				g_SH7262TOUCH_Driver.m_touchIsrProc(GPIO_PIN_NONE, FALSE, NULL);
			stylusUp   = TRUE;
			return;
		}
		else 
		{
			if(!stylusDown && stylusUp)
    		{
				stylusDown = TRUE;
				stylusUp   = FALSE;
				*pTipState |= TouchSampleDownFlag;
			}
			*pUnCalX = H_adr;
			*pUnCalY = V_adr;
			*pTipState |= TouchSampleValidFlag;
		}
	}
	else		//Touch down or move event
	{	
		
		stylusDown = TRUE;
		stylusUp = FALSE;
	    *pTipState |= TouchSampleValidFlag;
	    *pTipState |= TouchSampleDownFlag;
		if (touchEvent == -1)
		{
			*pUnCalX = H_adr = x;
			*pUnCalY = V_adr = y;
		}
		else
		{
			*pUnCalX = H_adr;
			*pUnCalY = V_adr;
		}
	}
}

BOOL SH7262TOUCH_Driver::CalibrationPointGet(TOUCH_PANEL_CALIBRATION_POINT *pTCP)
{

    INT32   cDisplayWidth  = pTCP->cDisplayWidth;
    INT32   cDisplayHeight = pTCP->cDisplayHeight;

    int CalibrationRadiusX = cDisplayWidth  / 20;
    int CalibrationRadiusY = cDisplayHeight / 20;

    switch (pTCP -> PointNumber)
    {
    case    0:
        pTCP->CalibrationX = cDisplayWidth  / 2;
        pTCP->CalibrationY = cDisplayHeight / 2;
        break;

    case    1:
        pTCP->CalibrationX = CalibrationRadiusX * 2;
        pTCP->CalibrationY = CalibrationRadiusY * 2;
        break;

    case    2:
        pTCP->CalibrationX = CalibrationRadiusX * 2;
        pTCP->CalibrationY = cDisplayHeight - CalibrationRadiusY * 2;
        break;

    case    3:
        pTCP->CalibrationX = cDisplayWidth  - CalibrationRadiusX * 2;
        pTCP->CalibrationY = cDisplayHeight - CalibrationRadiusY * 2;
        break;

    case    4:
        pTCP->CalibrationX = cDisplayWidth - CalibrationRadiusX * 2;
        pTCP->CalibrationY = CalibrationRadiusY * 2;
        break;

    default:
        pTCP->CalibrationX = cDisplayWidth  / 2;
        pTCP->CalibrationY = cDisplayHeight / 2;
        
        return FALSE;
    }
    
    return TRUE;
}

HRESULT SH7262TOUCH_Driver::GetDeviceCaps(unsigned int iIndex, void* lpOutput)
{
    if ( lpOutput == NULL )
    {
        return FALSE;
    }

    switch ( iIndex )
    {
    case TOUCH_PANEL_SAMPLE_RATE_ID:
        {
            TOUCH_PANEL_SAMPLE_RATE  *pTSR  = (TOUCH_PANEL_SAMPLE_RATE*)lpOutput;    

            pTSR->SamplesPerSecondLow       = g_TouchPanel_Sampling_Settings.SampleRate.SamplesPerSecondLow;
            pTSR->SamplesPerSecondHigh      = g_TouchPanel_Sampling_Settings.SampleRate.SamplesPerSecondHigh;
            pTSR->CurrentSampleRateSetting  = g_TouchPanel_Sampling_Settings.SampleRate.CurrentSampleRateSetting;
            pTSR->MaxTimeForMoveEvent_ticks = g_TouchPanel_Sampling_Settings.SampleRate.MaxTimeForMoveEvent_ticks;
        }
        break; 

    case TOUCH_PANEL_CALIBRATION_POINT_COUNT_ID:
        {
            TOUCH_PANEL_CALIBRATION_POINT_COUNT *pTCPC = (TOUCH_PANEL_CALIBRATION_POINT_COUNT*)lpOutput;            

            pTCPC->flags              = 0;
            pTCPC->cCalibrationPoints = 5;
        }
        break;

    case TOUCH_PANEL_CALIBRATION_POINT_ID:        
        return(CalibrationPointGet((TOUCH_PANEL_CALIBRATION_POINT*)lpOutput));

    default:        
        return FALSE;
    }

    return TRUE;
}

void SH7262TOUCH_Driver::TOUCH_ADXstart(void)
{
	ADC.ADCSR.WORD = 0x2000;
}

unsigned short int SH7262TOUCH_Driver::TOUCH_ADXin(void)
{
	unsigned short int value;
	value = ADC.ADCSR.WORD;  
	ADC.ADCSR.WORD = 0x0000; 
	value = ADC.ADDRA;
	return (value>>6);
}

void SH7262TOUCH_Driver::TOUCH_ADYstart(void)
{
	ADC.ADCSR.WORD = 0x2001;
}

unsigned short int SH7262TOUCH_Driver::TOUCH_ADYin(void)
{
	unsigned short int value;
	value = ADC.ADCSR.WORD;  
	ADC.ADCSR.WORD = 0x0001; 
	value = ADC.ADDRB;
	return (value>>6);
}

void SH7262TOUCH_Driver::TOUCH_AllHiZ(void)
{
	PORT.PCIOR0.WORD = (PORT.PCIOR0.WORD & 0xFF1B);
}

void SH7262TOUCH_Driver::TOUCH_X1X2(int i)
{
	if (i) {
		PORT.PCDR0.WORD = (PORT.PCDR0.WORD & 0xFF1B) | 0x0004;
	} else {
		PORT.PCDR0.WORD = (PORT.PCDR0.WORD & 0xFF1B) | 0x0040;
	}
	PORT.PCIOR0.WORD = (PORT.PCIOR0.WORD & 0xFF1B) | 0x0044;
}

void SH7262TOUCH_Driver::TOUCH_Y1Y2(int i)
{
	if (i) {
		PORT.PCDR0.WORD = (PORT.PCDR0.WORD & 0xFF1B) | 0x0020;
	} else {
		PORT.PCDR0.WORD = (PORT.PCDR0.WORD & 0xFF1B) | 0x0080;
	}
	PORT.PCIOR0.WORD = (PORT.PCIOR0.WORD & 0xFF1B) | 0x00A0;
}

void SH7262TOUCH_Driver::TOUCH_PenDownInitialize(void)
{
#ifdef HOKUTO
	PORT.PECR0.WORD 	= PORT.PECR0.WORD  & 0x0FFF;	
	PORT.PEIOR0.WORD	= PORT.PEIOR0.WORD | 0x0008;	
	PORT.PEDR0.WORD 	= PORT.PEDR0.WORD  & 0xFFF7;	
#endif
#ifdef WAKAMATSU	
	PORT.PFCR1.WORD = PORT.PFCR1.WORD  & 0x0FFF;
	PORT.PFIOR0.WORD= PORT.PFIOR0.WORD | 0x0080;
	PORT.PFDR0.WORD = PORT.PFDR0.WORD  & 0xFF7F;
#endif
	/* Y1:PC7='H' Y2:PC5='H' */
	PORT.PCDR0.WORD = (PORT.PCDR0.WORD & 0xFF1B) | 0x00A0;
	/* Y1:PC7 Y2:PC5  PC6,PC2:input */
	PORT.PCIOR0.WORD = (PORT.PCIOR0.WORD & 0xFF1B) | 0x00A0;
}

int SH7262TOUCH_Driver::TOUCH_PenDownCheck(void)
{
	int i = 0;

	i = PORT.PCPR0.WORD & 0x40;		
#ifdef HOKUTO	
#endif
#ifdef WAKAMATSU	
	PORT.PFIOR0.WORD = PORT.PFIOR0.WORD & 0xFF7F;
#endif
	return i;
}


int SH7262TOUCH_Driver::TOUCH_ADCConv(void)
{
	MTU2.TSR_2.BIT.TCFV = 0;
	MTU2.TSTR.BYTE &= 0xF9;				// Timer Channel 1 and 2 Stop
	
	switch(TOUCH_stat) {

	case 0 :
		TOUCH_PenDownInitialize();
		TOUCH_stat++;
		break;
	case 1 :
		if (TOUCH_PenDownCheck()) {
			TOUCH_PenDownInitialize();
			TOUCH_stat++;
		} else {
			TOUCH_PD = 0;
			TOUCH_stat = 0;
			TOUCH_AllHiZ();
			gettingPoint = FALSE;
		}
		break;
	case 2 :
		if (TOUCH_PenDownCheck()) {
			TOUCH_X1X2(1);
			//TOUCH_ADYstart();
			TOUCH_stat++;
		} else {
			TOUCH_PD = 0;
			TOUCH_stat = 0;
			TOUCH_AllHiZ();
			gettingPoint = FALSE;
		}
		break;

	case 3 :
		TOUCH_ADYstart();
		TOUCH_stat++;
		break;
	case 4 :
		TOUCH_X = TOUCH_ADYin();
		TOUCH_Y1Y2(1);
		//TOUCH_ADXstart();
		TOUCH_stat++;
		break;
	case 5 :
		TOUCH_ADXstart();
		TOUCH_stat++;
		break;
	case 6 :
		TOUCH_Y = TOUCH_ADXin();
		TOUCH_PenDownInitialize();
		TOUCH_stat++;
		break;
	case 7 :
		if (TOUCH_PenDownCheck()) {
			TOUCH_PenDownInitialize();
			TOUCH_stat++;
		} else {
			TOUCH_PD = 0;
			TOUCH_stat = 0;
			TOUCH_AllHiZ();
			gettingPoint = FALSE;
		}
		break;
	case 8 :
		if (TOUCH_PenDownCheck()) {
			if (TOUCH_XYrp != ((TOUCH_XYwp + 1)&(TOUCH_BUFF - 1))) { 
				//if (TOUCH_PD) TOUCH_XY[TOUCH_XYwp] = (TOUCH_Y << 16) | TOUCH_X | 0x80000000;
				//else          
				TOUCH_XY[TOUCH_XYwp] = (TOUCH_Y << 16) | TOUCH_X;
				TOUCH_XYwp++;
				TOUCH_XYwp = TOUCH_XYwp & (TOUCH_BUFF - 1);
			}
			else {
				TOUCH_PD = 0;
			}
		}
		TOUCH_AllHiZ();
		TOUCH_stat = 0;
		gettingPoint = TRUE;		
		break;
	}
	
	TMU2_ResetCNT();
	
	return 1;
}

BOOL SH7262TOUCH_Driver::Initialize()
{
	PORT.PCCR1.WORD = (PORT.PCCR1.WORD & 0x000F);
	PORT.PCCR0.WORD = (PORT.PCCR0.WORD & 0xF0FF);
	
	TOUCH_AllHiZ();
	
	PORT.PHCR0.WORD = (PORT.PHCR0.WORD & 0xFF00) | 0x0011;
#ifdef HOKUTO
	PORT.PECR0.WORD 	= PORT.PECR0.WORD  & 0x0FFF;
	PORT.PEIOR0.WORD	= PORT.PEIOR0.WORD & 0xFFF7;
	PORT.PEDR0.WORD 	= PORT.PEDR0.WORD  & 0xFFF7;
#endif

#ifdef WAKAMATSU
	PORT.PFCR1.WORD 	= PORT.PFCR1.WORD  & 0x0FFF;
	PORT.PFIOR0.WORD	= PORT.PFIOR0.WORD & 0xFF7F;
	PORT.PFDR0.WORD 	= PORT.PFDR0.WORD  & 0xFF7F;
#endif

	CPG.STBCR3.BYTE= CPG.STBCR3.BYTE & 0xFB;

	TOUCH_Xmin = TOUCH_Xmindefault;
	TOUCH_Xmax = TOUCH_Xmaxdefault;
	TOUCH_Ymin = TOUCH_Ymindefault;
	TOUCH_Ymax = TOUCH_Ymaxdefault;
	TOUCH_stat = 0;
	TOUCH_PD = TOUCH_nPDcnt = 0;
	TOUCH_X = 0;
	TOUCH_Y = 0;

	TOUCH_XYwp = TOUCH_XYrp = 0;
	
	TMU2_Initialize();
	
	return TRUE;
}

void SH7262TOUCH_Driver::TMU2_Initialize(void)
{
	CPG.STBCR3.BYTE = CPG.STBCR3.BYTE & (~(1 <<5));

	INTC.IPR12.WORD = (INTC.IPR12.WORD & 0xFFF0) | (13 << 0);
	
	MTU2.TSTR.BYTE &= 0xF9;				// Timer Channel 1 and 2 Stop
			
	MTU2.TCR_2.BIT.TPSC = 0x0;			// PClk/4
	MTU2.TCR_2.BIT.CKEG = 0x1;
	MTU2.TCR_2.BIT.CCLR = 0x0;
	MTU2.TIOR_2.BIT.IOA = 0x4;
	MTU2.TIER_2.BIT.TCIEV = 1;
	MTU2.TICCR.BIT.I2AE = 0x1;
		
	MTU2.TCNT_2 = 0xffff/2;
	
	MTU2.TSTR.BYTE = 0x4;			// Timer Channel 2 Start
}

void SH7262TOUCH_Driver::TMU2_ResetCNT()
{
	MTU2.TCNT_2 = 0xffff/2;
	MTU2.TSTR.BYTE = 0x4;			// Timer Channel 2 Start
}

int SH7262TOUCH_Driver::TOUCH_GetPenDown(void)
{
	if (TOUCH_XYwp != TOUCH_XYrp) return -1; 
	else 
		if(gettingPoint)return -2; 
		else return 0;
}

unsigned int SH7262TOUCH_Driver::TOUCH_GetXY(int mode)
{
	int x, y, f;
	double xd, yd;

	if (mode) {	
		f = TOUCH_XY[TOUCH_XYrp];
		if (TOUCH_XYwp != TOUCH_XYrp) {	
			TOUCH_XYrp++;
			TOUCH_XYrp = TOUCH_XYrp & (TOUCH_BUFF - 1);
		}
		return f;

	} else {	
		f = TOUCH_XY[TOUCH_XYrp] & 0x80000000;
		xd = (double)((TOUCH_XY[TOUCH_XYrp]      ) & 0x03FF);
		yd = (double)((TOUCH_XY[TOUCH_XYrp] >> 16) & 0x03FF);
		if (TOUCH_XYwp != TOUCH_XYrp) {	
			TOUCH_XYrp++;
			TOUCH_XYrp = TOUCH_XYrp & (TOUCH_BUFF - 1);
		}
		xd = ((xd - TOUCH_Xmin) / (TOUCH_Xmax - TOUCH_Xmin)) * 320;
		yd = ((yd - TOUCH_Ymin) / (TOUCH_Ymax - TOUCH_Ymin)) * 240;
		x = (int)xd;
		if (x < 0) x = 0;
		if (x > (LCD_WIDTH - 1)) x = (LCD_WIDTH - 1);
		y = (int)yd;
		if (y < 0) y = 0;
		if (y > (LCD_HIGHT - 1)) y = (LCD_HIGHT - 1);
		return f | (y << 16) | x;
	}
}

void SH7262_TOUCH_ISR(void)
{		
	if (SH7262TOUCH_Driver::TOUCH_GetPenDown())
	{
		getPointCnt++;
		
		if((stylusDown == FALSE))
		{
			if (g_SH7262TOUCH_Driver.m_touchIsrProc != NULL) 
				g_SH7262TOUCH_Driver.m_touchIsrProc(GPIO_PIN_NONE, TRUE, NULL);
		}
		else if((getPointCnt == 0x10) && (stylusDown == TRUE))
		{
			TOUCH_XYrp = TOUCH_XYwp;
			if (g_SH7262TOUCH_Driver.m_touchIsrProc != NULL) 
				g_SH7262TOUCH_Driver.m_touchIsrProc(GPIO_PIN_NONE, FALSE, NULL);
			stylusUp   = TRUE;
		}
	}
}