
#include "stdio.h"
#include "systick.h"
#include "USART1.h"
#include "mylcd.h"
#include "mytouch.h"
#include "math.h"

_m_tp_dev tp_dev=
{
	TP_Init,
	TP_Scan,
	TP_Adjust,
	0,
	0,
 	0,
	0,
	0,
	0,
	0,
	0,	  	 		
	0,
	0,	  	 		
};
				
//默认为touchtype=0的数据.
u8 CMD_RDX=0XD0;
u8 CMD_RDY=0X90;

u8 flag_adjust=0 ;
 	 			    					   
//SPI写数据
//向触摸屏IC写入1byte数据    
//num:要写入的数据
void TP_Write_Byte(u8 num)    
{  
	u8 count=0;   
	for(count=0;count<8;count++)  
	{ 	  
		if(num&0x80)GPIO_SetBits(GPIOF,GPIO_Pin_9); 	   
		else GPIO_ResetBits(GPIOF,GPIO_Pin_9);   
		num<<=1;    
		GPIO_ResetBits(GPIOF,GPIO_Pin_11); 	 
		GPIO_SetBits(GPIOF,GPIO_Pin_11);		//上升沿有效	        
	}	        		 			    
}  		 
//SPI读数据 
//从触摸屏IC读取adc值
//CMD:指令
//返回值:读到的数据	   
u16 TP_Read_AD(u8 CMD)	  
{ 	 
	u8 count=0; 	  
	u16 Num=0; 
	GPIO_ResetBits(GPIOF,GPIO_Pin_11); 	//先拉低时钟 	 
	GPIO_SetBits(GPIOF,GPIO_Pin_9);  	//拉低数据线
	GPIO_ResetBits(GPIOF,GPIO_Pin_7); 		//选中触摸屏IC
	TP_Write_Byte(CMD);//发送命令字
	delay_us(6);//ADS7846的转换时间最长为6us
	GPIO_ResetBits(GPIOF,GPIO_Pin_11); 	     	    
	delay_us(1);    	   
	GPIO_SetBits(GPIOF,GPIO_Pin_11); 	//给1个时钟，清除BUSY	    	    
	GPIO_ResetBits(GPIOF,GPIO_Pin_11); 	     	    
	for(count=0;count<16;count++)//读出16位数据,只有高12位有效 
	{ 				  
		Num<<=1; 	 
		GPIO_ResetBits(GPIOF,GPIO_Pin_11); 	//下降沿有效  	    	   
		GPIO_SetBits(GPIOF,GPIO_Pin_11); 
		if(DOUT)Num++; 		 
	}  	
	Num>>=4;   	//只有高12位有效.
	GPIO_SetBits(GPIOF,GPIO_Pin_7); 		//释放片选	 
	return(Num); 
}
//读取一个坐标值(x或者y)
//连续读取READ_TIMES次数据,对这些数据升序排列,
//然后去掉最低和最高LOST_VAL个数,取平均值 
//xy:指令（CMD_RDX/CMD_RDY）
//返回值:读到的数据
#define READ_TIMES 5 	//读取次数
#define LOST_VAL 1	  	//丢弃值
u16 TP_Read_XOY(u8 xy)
{
	u16 i, j;
	u16 buf[READ_TIMES];
	u16 sum=0;
	u16 temp;
	for(i=0;i<READ_TIMES;i++)buf[i]=TP_Read_AD(xy);		 		    
	for(i=0;i<READ_TIMES-1; i++)//排序
	{
		for(j=i+1;j<READ_TIMES;j++)
		{
			if(buf[i]>buf[j])//升序排列
			{
				temp=buf[i];
				buf[i]=buf[j];
				buf[j]=temp;
			}
		}
	}	  
	sum=0;
	for(i=LOST_VAL;i<READ_TIMES-LOST_VAL;i++)sum+=buf[i];
	temp=sum/(READ_TIMES-2*LOST_VAL);
	return temp;    
}  
//读取x,y坐标
//最小值不能少于100.
//x,y:读取到的坐标值
//返回值:0,失败;1,成功。
u8 TP_Read_XY(u16 *x,u16 *y)
{
	u16 xtemp,ytemp;			 	 		  
	xtemp=TP_Read_XOY(CMD_RDX);
	ytemp=TP_Read_XOY(CMD_RDY);	  												   
	*x=xtemp;
	*y=ytemp;
	return 1;//读数成功
}
//连续2次读取触摸屏IC,且这两次的偏差不能超过
//ERR_RANGE,满足条件,则认为读数正确,否则读数错误.	   
//该函数能大大提高准确度
//x,y:读取到的坐标值
//返回值:0,失败;1,成功。
#define ERR_RANGE 50 //误差范围 
u8 TP_Read_XY2(u16 *x,u16 *y) 
{
	u16 x1,y1;
 	u16 x2,y2;
 	u8 flag;    
    flag=TP_Read_XY(&x1,&y1);   
    if(flag==0)return(0);
    flag=TP_Read_XY(&x2,&y2);	   
    if(flag==0)return(0);   
    if(((x2<=x1&&x1<x2+ERR_RANGE)||(x1<=x2&&x2<x1+ERR_RANGE))//前后两次采样在+-50内
    &&((y2<=y1&&y1<y2+ERR_RANGE)||(y1<=y2&&y2<y1+ERR_RANGE)))
    {
        *x=(x1+x2)/2;
        *y=(y1+y2)/2;
        return 1;
    }else return 0;	  
}  

//画一个触摸点
//用来校准用的
//x,y:坐标
//color:颜色
void TP_Drow_Touch_Point(u16 x,u16 y,u16 color)
{
	POINT_COLOR=color;
	LCD_DrawLine(x-12,y,x+13,y);//横线
	LCD_DrawLine(x,y-12,x,y+13);//竖线
	LCD_DrawPoint(x+1,y+1);
	LCD_DrawPoint(x-1,y+1);
	LCD_DrawPoint(x+1,y-1);
	LCD_DrawPoint(x-1,y-1);
	Draw_Circle(x,y,6);//画中心圈
}	  
//画一个大点(2*2的点)		   
//x,y:坐标
//color:颜色
void TP_Draw_Big_Point(u16 x,u16 y,u16 color)
{	    
	POINT_COLOR=color;
	LCD_DrawPoint(x,y);//中心点 
	LCD_DrawPoint(x+1,y);
	LCD_DrawPoint(x,y+1);
	LCD_DrawPoint(x+1,y+1);	 	  	
}	

u8 TP_Init(void)
{			    		   						  
	GPIO_InitTypeDef GPIO_InitStructure;
  	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF , ENABLE);

  	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_10;
  	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  	GPIO_Init(GPIOF , &GPIO_InitStructure);

  	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7|GPIO_Pin_9|GPIO_Pin_11;
  	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  	GPIO_Init(GPIOF , &GPIO_InitStructure);

	GPIOF->ODR|=0x0000f800;    //PF8-11全部上拉	 
			
	return 1; 									 								 
}

void TP_Scan(void)
{		
	if(PEN==0)
	{
		delay_ms(20);
		if(PEN==0)
		{	
			TP_Read_XY2(&tp_dev.x,&tp_dev.y);//读取物理坐标
	
			printf("\r\n  tp_dev.x=%d \r\n",tp_dev.x) ;
			printf("\r\n  tp_dev.y=%d \r\n",tp_dev.y) ;	  

		}
	  	while(PEN==0) ;
	}
	else
	{
		
	}
}

void TP_Adjust(void)
{	
	u16 Adjust_coor[4][2] ;
	static	u8 i=0 ;

	u8 flag_calculate=0 ;

	u32 temp1=0 ;
	u32 temp2=0 ;

	u32 relative_line1=0 ;
	u32 relative_line2=0 ;

	float	length_Precision1 ;
	float	length_Precision2 ;
	float	length_Precision3 ;

	u8 relative_success = 1 ;
	u8 y_success = 1 ;
	u8 x_success = 1 ;

	if(PEN==0)
	{
		delay_ms(20);
		if(PEN==0)
		{	
			TP_Read_XY2(&tp_dev.x,&tp_dev.y);//读取物理坐标
			i++ ; 

			switch(i)
			{
				case 1 :		//左上
						Adjust_coor[0][0]=tp_dev.x ;
						Adjust_coor[0][1]=tp_dev.y ;

						TP_Drow_Touch_Point(15,15,WHITE);				//清除左上 
				  		TP_Drow_Touch_Point(305,15,RED); //画校准点3 		   右上						

						printf("\r\n  左上=%d \r\n",Adjust_coor[0][0]) ;
						printf("\r\n  左上=%d \r\n",Adjust_coor[0][1]) ;	 

						break ;

				case 2 :	     //右上
						Adjust_coor[1][0]=tp_dev.x ;
						Adjust_coor[1][1]=tp_dev.y ;

						TP_Drow_Touch_Point(305,15,WHITE);				//清除右上 
						TP_Drow_Touch_Point(305,465,RED);//画校准点4		   右下

						printf("\r\n  右上=%d \r\n",Adjust_coor[1][0]) ;
						printf("\r\n  右上=%d \r\n",Adjust_coor[1][1]) ;	 

						break ;

				case 3 :		 //右下
						Adjust_coor[2][0]=tp_dev.x ;
						Adjust_coor[2][1]=tp_dev.y ;

						TP_Drow_Touch_Point(305,465,WHITE);				//清除右下 
						TP_Drow_Touch_Point(15,465,RED); //画校准点2 		   左下

						printf("\r\n  右下=%d \r\n",Adjust_coor[2][0]) ;
						printf("\r\n  右下=%d \r\n",Adjust_coor[2][1]) ;	 

						break ;

				case 4 :		 //左下
						Adjust_coor[3][0]=tp_dev.x ;
						Adjust_coor[3][1]=tp_dev.y ;



						TP_Drow_Touch_Point(15,465,WHITE);				//清除左下 						
					
						printf("\r\n  左下=%d \r\n",Adjust_coor[3][0]) ;
						printf("\r\n  左下=%d \r\n",Adjust_coor[3][1]) ;	 

						flag_calculate=1 ;

						break ;						
				
				default :		break ;
				}
				
		}
		while(PEN==0) ;
	}
	if(flag_calculate==1)
	{	 															
		//计算对角线1的长度，左上与右下
		temp1=fabs(Adjust_coor[0][0]-Adjust_coor[2][0]);
		temp2=fabs(Adjust_coor[0][1]-Adjust_coor[2][1]);	
		temp1=temp1*temp1 ;
		temp2=temp2*temp2 ;	
		relative_line1=sqrt(temp1+temp2) ;
		
		 //计算对角线2的长度，右上与左下
		temp1=fabs(Adjust_coor[1][0]-Adjust_coor[3][0]);
		temp2=fabs(Adjust_coor[1][1]-Adjust_coor[3][1]);	
		temp1=temp1*temp1 ;
		temp2=temp2*temp2 ;	
		relative_line2=sqrt(temp1+temp2) ;
		
		//对角线1与对角线2的长度比，精度
		length_Precision1=(float)relative_line1/relative_line2 ;		
		printf("\r\n length_Precision1=%f \r\n",length_Precision1) ;		
		
		//对角线1与对角线2不相等
		if((length_Precision1<0.95)||(length_Precision1>1.05)||(relative_line1==0)||(relative_line2==0))
		{
			relative_success =0 ;
		}	
		
		//计算左边Y的长度，
		temp1=fabs(Adjust_coor[0][0]-Adjust_coor[3][0]);
		temp2=fabs(Adjust_coor[0][1]-Adjust_coor[3][1]);	
		temp1=temp1*temp1 ;
		temp2=temp2*temp2 ;	
		relative_line1=sqrt(temp1+temp2) ;
		
		//计算右边Y的长度，
		temp1=fabs(Adjust_coor[1][0]-Adjust_coor[2][0]);
		temp2=fabs(Adjust_coor[1][1]-Adjust_coor[2][1]);	
		temp1=temp1*temp1 ;
		temp2=temp2*temp2 ;	
		relative_line2=sqrt(temp1+temp2) ;
		
		//左边Y1与右边Y2的长度比，精度
		length_Precision2=(float)relative_line1/relative_line2 ;	
		printf("\r\n length_Precision2=%f \r\n",length_Precision2) ;
				
		//左、右边的Y的长度不相等
		if((length_Precision2<0.95)||(length_Precision2>1.05)||(relative_line1==0)||(relative_line2==0))
		{
			y_success =0 ;				
		}
		
		//计算上面X的长度，
		temp1=fabs(Adjust_coor[0][0]-Adjust_coor[1][0]);
		temp2=fabs(Adjust_coor[0][1]-Adjust_coor[1][1]);	
		temp1=temp1*temp1 ;
		temp2=temp2*temp2 ;	
		relative_line1=sqrt(temp1+temp2) ;
		
		//计算下面X的长度，
		temp1=fabs(Adjust_coor[2][0]-Adjust_coor[3][0]);
		temp2=fabs(Adjust_coor[2][1]-Adjust_coor[3][1]);	
		temp1=temp1*temp1 ;
		temp2=temp2*temp2 ;	
		relative_line2=sqrt(temp1+temp2) ;
		
		//上面X1与下面X2的长度比，精度
		length_Precision3=(float)relative_line1/relative_line2 ;	
		printf("\r\n length_Precision3=%f \r\n",length_Precision3) ;
				
		//上面X1与下面X2的长度不相等
		if((length_Precision3<0.95)||(length_Precision3>1.05)||(relative_line1==0)||(relative_line2==0))
		{
			 x_success =0;	
		}
		
		if((relative_success==1)&&(y_success==1)&&(x_success==1))
		{
			printf("\r\n 校准成功 \r\n") ;

			POINT_COLOR=RED;
			LCD_Clear(WHITE);					
			LCD_ShowString(10,100,320,16,16,"Touch Screen Adjust SUCCESS!");//校正完成
		
			flag_adjust=1 ;			
		}
		else
		{
			i=0;

			POINT_COLOR=RED;
			LCD_Clear(WHITE);					
			LCD_ShowString(10,100,320,16,16,"Touch Screen Adjust FAILED!");//校正失败	
			delay_ms(1000) ;			

			LCD_Clear(WHITE);

			printf("\r\n 校准失败 \r\n") ;		
			TP_Drow_Touch_Point(15,15,RED);  //画校准点1 		   左上								
		}						
	}

}
