/**
 *******************************************************************************
 * @file      tsc2013_driver.c
 * @version   V1.0.0    
 * @date      2013.05.20
 * @brief     tsc2013 driver for Tananis.	
 *            Resources: 
 *            None, call I2C_transfer function
 *
 *******************************************************************************
 * @author    - Adela 
 *            - Robert Zhang <armner@gmail.com>
 *            - 
 *
 */
 
#include "stm32f4xx.h"
#include "tsc2013_driver.h"
#include "interrupt.h"
#include "FreeRTOS.h"
#include "semphr.h"
#include "i2c_dma_driver.h"
#include "stdlib.h"
#include "string.h"

#include "i2c_tsc2013.h"

#define MAX_FINGER_NUM  2
volatile uint16_t g_touch_detected =0;

uint16_t tsc2013_touch_status;
tsc2013_data_block  data_block;

static xSemaphoreHandle tsc2013_sema=NULL;
int touchread_mode=0;


uint16_t finger_pos_x[MAX_FINGER_NUM];
uint16_t finger_pos_y[MAX_FINGER_NUM];

void swap(uint8_t *high_byte, uint8_t *low_byte)
{
	uint8_t temp;

	temp = *high_byte;
	*high_byte = *low_byte;
	*low_byte = temp;
}


static void delay_01us(uint16_t nCount)
{
	uint32_t index = 0; 
	for(index = (10 * nCount); index != 0; index--)
	{
	}
}

static void EXTILine2_Config(void)
{
	EXTI_InitTypeDef EXTI_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE);
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);
	
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN;
	GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;	
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

	GPIO_Init(GPIOE,&GPIO_InitStructure);

	vSemaphoreCreateBinary(tsc2013_sema);
	if(tsc2013_sema ==NULL)
	{
		return;
	}  
	xSemaphoreTake(tsc2013_sema,portMAX_DELAY);


	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource2);
	
	EXTI_InitStructure.EXTI_Line = EXTI_Line2;
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;  	

	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);

	NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 9;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
}
void Reset_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);

	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;

	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT;
	GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;	
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	GPIO_SetBits(GPIOA, GPIO_Pin_1);	

	delay_01us(20);

	GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}

void tsc2013_read_touch_status(void)
{
	tsc2013_register reg;

	TSC2013_ReadDataBuffer(REG_STATUS_RD,(uint8_t*)&reg.value,2);

	swap(&reg.bytes.high_byte,&reg.bytes.low_byte); 

	tsc2013_touch_status =reg.value;
}

void tsc2013_read_touch_data(void)
{
	uint8_t i;

	TSC2013_ReadDataBuffer(REG_X1_RD,data_block.buffer,16);

	for(i=0;i<8;i++)
	{
		swap(&data_block.buffer[i * 2],&data_block.buffer[i * 2 + 1]);
	}

}

int tsc2013_write_ConfigValue()
{
	
	uint16_t configvalue=0;
	uint16_t RegValue=0;
	uint8_t IOE_BufferRX[4];  

	configvalue = CFR0_PSM_1 |               
				  CFR0_STS_0 | 
				  CFR0_RESOLUTION_12_BIT | 
				  CFR0_CONVERSION_CLOCK_4MHz |
				  CFR0_PANEL_VOLTAGE_STABILIZATION_TIME_3 |  //1ms
				  CFR0_PRECHARGE_TIME_4 |    //1.044ms
				  CFR0_SENSE_TIME_3 | 		//608us
				  CFR0_DTW_DISABLED |
				  CFR0_LSM_DISABLED;
	TSC2013_WriteDeviceRegister(REG_CFR0_WR, configvalue);

	configvalue =CFR1_BTD_0;
	
	TSC2013_WriteDeviceRegister(REG_CFR1_WR,configvalue);

	TSC2013_ReadDataBuffer(REG_CFR1_RD, &IOE_BufferRX,4);
	
    RegValue = (IOE_BufferRX[0]<<8)|(IOE_BufferRX[1]&0xff);
	
	if(RegValue!=configvalue)
	{
		return 0x01;
	}

	configvalue = CFR2_PINTS_2 |  
              CFR2_M_3 |     //M
              CFR2_W_2 |     //W
              CFR2_MAVE_X_ENABLED |
              CFR2_MAVE_Y_ENABLED |
              CFR2_MAVE_Z_ENABLED |
              CFR2_MAVE_AUX_DISABLED;
    TSC2013_WriteDeviceRegister(REG_CFR2_WR, configvalue);
  
	TSC2013_ReadDataBuffer(REG_CFR2_RD,  &IOE_BufferRX,4);

	RegValue = (IOE_BufferRX[0]<<8)|(IOE_BufferRX[1]&0xff);
   
	if(RegValue!=configvalue)
	{
		return 0x02;
	}

	return 0;	
}

void calculate_finger_pos(void)
{
	if(data_block.values.X1 >= data_block.values.X2)
	{
		finger_pos_x[0] = data_block.values.X2 + ((data_block.values.X1 - data_block.values.X2) >> 1);
	}
	else
	{
		finger_pos_x[0] = data_block.values.X1 + ((data_block.values.X2 - data_block.values.X1) >> 1);         
	}

	if(data_block.values.Y1 >= data_block.values.Y2)
	{
		finger_pos_y[0] = data_block.values.Y2 + ((data_block.values.Y1 - data_block.values.Y2) >> 1);
	}
	else
	{
		finger_pos_y[0] = data_block.values.Y1 + ((data_block.values.Y2 - data_block.values.Y1) >> 1);         
	}

	finger_pos_x[0] = 4096 - finger_pos_x[0];
	finger_pos_y[0] = 4096 - finger_pos_y[0];  
}


int  tsc2013_open( Driver *driver)
{

	I2C_transfer_block i2c_block[2];
	int reat=1;
	uint8_t IOE_BufferRX[4]; 

	I2Cx_init();
  	Reset_Init();
	reat = tsc2013_write_ConfigValue();
	TSC2013_WriteDeviceByte(0x84);
	
	TSC2013_ReadDataBuffer(REG_CFR1_RD, &IOE_BufferRX,2);

   	EXTILine2_Config();

	return 0;

}

int tsc2013_write(Driver *driver,void *buffer,int len,OFFSET offset1)
{

	return 0;
}

int tsc2013_read(Driver *driver,void *buffer,int len,OFFSET offset1)
{
    uint16_t *pBuffer;
	

	pBuffer = (uint16_t*)buffer;
	if(!touchread_mode)
	{
		xSemaphoreTake(tsc2013_sema,portMAX_DELAY);  //interrupt mode
		tsc2013_read_touch_data();
	}
	else
	{
		touchread_mode=1;
		tsc2013_read_touch_status();	
		if((tsc2013_touch_status & 0xf000) == 0xf000)
		{
			tsc2013_read_touch_data(); 			
		}
		else
		{
			touchread_mode=0;
			return -1;
		}

	}
	calculate_finger_pos();
	pBuffer[0] = finger_pos_x[0];
	pBuffer[1] = finger_pos_y[0];

	return 0;
}
int tsc2013_io_control(Driver *driver,int cmd ,int data)
{
	if(!cmd)
	{
		touchread_mode=0;
	}
	else
	{
		touchread_mode=1;
	}
	return 0;
}

int tsc2013_close(Driver *driver)
{
	return 0;
}


void EXTI2_IRQHandler(void)
{
	signed portBASE_TYPE xHigherPriorityTaskWoken;

	if(EXTI_GetITStatus(EXTI_Line2) != RESET)
	{		
		EXTI_ClearITPendingBit(EXTI_Line2);
		if(!touchread_mode)
		{
			xHigherPriorityTaskWoken =pdFALSE;
			
			xSemaphoreGiveFromISR(tsc2013_sema, &xHigherPriorityTaskWoken);
			if(xHigherPriorityTaskWoken == pdTRUE)
			{
				portEND_SWITCHING_ISR(1);
			}

		}
	}
	else
	{
		return;
	}
}

Driver tsc2013_driver =
{
    &tsc2013_open,
    &tsc2013_write,
    &tsc2013_read,
    &tsc2013_io_control,
    &tsc2013_close
};



