/*******************************************************************************
*
*
* File:        app_tp_st_touch.c信
* Description  ST touch 校准，复位等功能函数
* Version      V0.1
* Date         2023-03-13
* Author       sfy

* Description  ST touch 校准回读功能，开放接口给上位机读取是否成功
* Version      V0.2
* Date         2023-03-22
* Author       sfy

*******************************************************************************/

#include "test_cfg_global.h"
#include "app_tp_transfer.h"
#include "hal_i2c_master.h"
#include "hal_i2c_slave.h"
#include "hal_spi_master.h"
#include "hal_spi_slave.h"
#include "tau_log.h"
#include "tau_delay.h"
#include "app_tp_st_touch.h"

#define  ST_TP_CALIBRATION_SUCCESS				0x5A		 // 校准成功标志

volatile bool s_calibration_flag = false;
static volatile uint8_t s_calibration_correct_flag = false;

st_tp_scan_data  tp_scan_data;

uint8_t st_touch_init_sensor_off[3] 	= {0xA0, 0x00, 0x00}; 		 //2 sensor OFF
uint8_t st_touch_init_sensor_on[3]  	= {0xA0, 0x00, 0x01}; 		 //2 sensor on


uint8_t st_touch_tp_tuning_reset[3] 	= {0xA4, 0x00, 0x00};		    // 3 System Reset
uint8_t st_touch_tp_tuning_FpnlInit[3]  = {0xA4, 0x00, 0x03}; 		 // FPnl Init
uint8_t st_touch_tp_tuning_PnlInit[3] 	= {0xA4, 0x00, 0x02}; 		 // Pnl Init
uint8_t st_touch_tp_tuning_TuneM[4] 	= {0xA4, 0x03, 0x13, 0x00};  	 // TuneM
uint8_t st_touch_tp_tuning_TuneS[4]  	= {0xA4, 0x03, 0x0C, 0x00};	 // TuneS
uint8_t st_touch_tp_tuning_SvCfg[3] 	= {0xA4, 0x05, 0x01}; 		 // SvCfg
uint8_t st_touch_tp_tuning_SvCx[3] 		= {0xA4, 0x05, 0x02}; 		 // SvCx
uint8_t st_touch_tp_tuning_SvPnl[3] 	= {0xA4, 0x05, 0x04}; 		 // SvPnl
uint8_t st_touch_tp_tuning_clearfifo[3] = {0xA4, 0x00, 0x01};		  	 // 1  clear fifo

uint8_t st_touch_tp_tuning_clkreset[3] = {0xA4, 0x00, 0x05};		  	 // clk reset

/**************************************************************************
* @name : ap_tp_st_touch_get_calibration_success_mark
* @brief : st touch 获取触摸校准成功标志
* @param[in] :
* @return :
* @retval :
**************************************************************************/

void ap_tp_st_touch_get_calibration_success_mark(void)
{
    uint8_t cali_send_buff[6] = {0xFA, 0x20, 0x01, 0x00, 0x00, 0x00};
    uint8_t cali_send_buff1[3] = {0xA4, 0x06, 0x01};
    uint8_t cali_read_buff[40] = {0};
    uint8_t i = 0;

    app_tp_m_read(cali_send_buff, 5, cali_read_buff, 4);
    while(!hal_i2c_m_transfer_complate());
    delayMs(1);

    app_tp_m_write(cali_send_buff1, 3);
    while(!hal_i2c_m_transfer_complate());
    delayMs(1);

    app_tp_m_read(cali_send_buff, 5, cali_read_buff, 4);
    while(!hal_i2c_m_transfer_complate());
    delayMs(1);

    app_tp_m_read(cali_send_buff, 5, cali_read_buff, 32);
    while(!hal_i2c_m_transfer_complate());

    if((cali_read_buff[20] == 0xFF) && (cali_read_buff[21] == 0xFF))
    {
        s_calibration_correct_flag = ST_TP_CALIBRATION_SUCCESS;  // 校准成功
    }
    else
    {
        s_calibration_correct_flag = 0x00;	// 校准失败
    }
    /*
    	for(i=0;i<32;i++)
    	{
    		printf("%02x ",cali_read_buff[i]);
    	}
    */
}

/**************************************************************************
* @name : ap_tp_st_touch_calibration
* @brief : st touch 触摸校准指令流程
* @param[in] :
* @return :
* @retval :
**************************************************************************/

void ap_tp_st_touch_calibration(void)
{
    // app_tp_m_write(st_touch_tp_tuning_reset, sizeof(st_touch_tp_tuning_reset));    // System Reset
    // while(!hal_i2c_m_transfer_complate());
    // delayMs(10);
    app_tp_m_write(st_touch_tp_tuning_FpnlInit, sizeof(st_touch_tp_tuning_FpnlInit));     // FPnl Init
    while(!hal_i2c_m_transfer_complate());
    delayMs(1);
    app_tp_m_write(st_touch_tp_tuning_PnlInit, sizeof(st_touch_tp_tuning_PnlInit));     // Pnl Init
    while(!hal_i2c_m_transfer_complate());
    delayMs(1);
    app_tp_m_write(st_touch_tp_tuning_TuneM, sizeof(st_touch_tp_tuning_TuneM));    // TuneM
    while(!hal_i2c_m_transfer_complate());
    delayMs(1);
    app_tp_m_write(st_touch_tp_tuning_TuneS, sizeof(st_touch_tp_tuning_TuneS));    // TuneS
    while(!hal_i2c_m_transfer_complate());
    delayMs(1);
    app_tp_m_write(st_touch_tp_tuning_SvCfg, sizeof(st_touch_tp_tuning_SvCfg));    // SvCfg
    while(!hal_i2c_m_transfer_complate());
    delayMs(1);
    app_tp_m_write(st_touch_tp_tuning_SvCx, sizeof(st_touch_tp_tuning_SvCx));    // SvCx
    while(!hal_i2c_m_transfer_complate());
    delayMs(1);
    app_tp_m_write(st_touch_tp_tuning_SvPnl, sizeof(st_touch_tp_tuning_SvPnl));    // SvPnl
    while(!hal_i2c_m_transfer_complate());
    delayMs(1);
}

const unsigned short wCRCTalbeAbs[] =
{
    0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401,
    0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400,
};

/**************************************************************************
* @name : CRC16_2
* @brief : 计算数组 CRC 值
* @param[in] :pchMsg 数组指针地址; wDataLen 计算CRC 数组长度
* @return : 16位CRC值
* @retval :
**************************************************************************/

unsigned short CRC16_2(unsigned char* pchMsg, unsigned short wDataLen)
{
    unsigned short wCRC = 0xFFFF;
    unsigned short i;
    unsigned char  chChar;

    for(i = 0; i < wDataLen; i++)
    {
        chChar = *pchMsg++;
        wCRC = wCRCTalbeAbs[(chChar ^ wCRC) & 15] ^ (wCRC >> 4);
        wCRC = wCRCTalbeAbs[((chChar >> 4) ^ wCRC) & 15] ^ (wCRC >> 4);
    }

    return wCRC;
}

/**************************************************************************
* @name : ap_set_tp_calibration_04
* @brief : 获取机板04 02命令，执行校准、gamma校准等功能
* @param[in] :handler rx handler; dcs_packet 指令参数和长度等信息结构体
* @return : true
* @retval :
**************************************************************************/

bool ap_set_tp_calibration_04(hal_dsi_rx_ctrl_handle_t* handler, hal_dcs_packet_t* dcs_packet)
{
    uint8_t i, crch, crcl, command, param[30] = {0};
    unsigned short crc;

    // 计算CRC值
    for(i = 0; i < dcs_packet->param_length; i++)
    {
        param[i + 1] = dcs_packet->packet_param[i];
//		printf("%02x ",dcs_packet->packet_param[i]);
    }

    param[0] = 0x04;
    crc = CRC16_2(param, dcs_packet->param_length - 1);
    crch = (crc >> 8);
    crcl = crc;

    // CRC校验判断
//	if(crch == dcs_packet->packet_param[dcs_packet->param_length-2] && crcl == dcs_packet->packet_param[dcs_packet->param_length-1])
    {
        command = param[3];
        switch(command)
        {
        case CMD_TP_CABLIBRATION:	// Touch校准
            if((param[4] == 0x01) && (param[5] == 0x01) && (param[6] == 0x01))
            {
                s_calibration_flag = true;
                s_calibration_correct_flag = false;

            }
            /*			if( (param[4] == 0xA5) && (param[5] == 0x5A) && (param[6] == 0xA5) )
            		    {
            		    	if(s_calibration_correct_flag)	// 校准成功
            		    	{
            		    		hal_dsi_rx_ctrl_send_ack_cmd(handler,
            									 DSI_ACK_DT_GEN_LONG_RESPONSE,     //xxx
            									 DSI_VC_0,
            									 0x7, 0x04,0x02,0x07,0x2A,ST_TP_CALIBRATION_SUCCESS,0x00,0x00);
            					printf("cali. send ok ");
            		    	}
            				else	// 校准失败
            				{
            					hal_dsi_rx_ctrl_send_ack_cmd(handler,
            									 DSI_ACK_DT_GEN_LONG_RESPONSE,     //xxx
            									 DSI_VC_0,
            									 0x7, 0x04,0x02,0x07,0x2A,0x00,0x00,0x00);
            				}
            		    	printf("%02x ",s_calibration_correct_flag);
            		    }
            */
            break;
        case CMD_SET_IMAGE_RGB:		// Image RGB发送
            break;
        case CMD_SEND_COMMAND:		// Command Send
            break;
        case CMD_WRITE_GAMMA:		// Gamma校正写入
            break;
        case CMD_START_GAMMA:
            break;
        default:
            break;
        }
    }

    // 兼容旧版本tp calibration
    if((dcs_packet->packet_param[0] == 0x01) && (dcs_packet->packet_param[1] == 0x01) && (dcs_packet->packet_param[2] == 0x01))
    {
        s_calibration_flag = true;
        s_calibration_correct_flag = false;
    }
    /*
    	if( (dcs_packet->packet_param[0] == 0xA5) && (dcs_packet->packet_param[1] == 0x5A) && (dcs_packet->packet_param[2] == 0xA5) )
        {
        	if(s_calibration_correct_flag)	// 校准成功
        	{
        		hal_dsi_rx_ctrl_send_ack_cmd(handler,
    							 DSI_ACK_DT_GEN_LONG_RESPONSE,     //xxx
    							 DSI_VC_0,
    							 0x7, 0x04,0x02,0x07,0x2A,ST_TP_CALIBRATION_SUCCESS,0x00,0x00);
        	}
    		else	// 校准失败
    		{
    			hal_dsi_rx_ctrl_send_ack_cmd(handler,
    							 DSI_ACK_DT_GEN_LONG_RESPONSE,     //xxx
    							 DSI_VC_0,
    							 0x7, 0x04,0x02,0x07,0x2A,0x00,0x00,0x00);
    		}
        }
    */
    return true;
}


/**************************************************************************
* @name : ap_get_tp_calibration_status_01
* @brief : 获取触摸校准状态
* @param[in] :param 01命令参数
* @return : true
* @retval :
**************************************************************************/

bool ap_get_tp_calibration_status_01(hal_dsi_rx_ctrl_handle_t* handler, uint8_t param)
{
//	if( param == 0x5A )
    {
        if(s_calibration_correct_flag)	// 校准成功
        {
            hal_dsi_rx_ctrl_send_ack_cmd(handler,
                                         DSI_ACK_DT_DSC_SHORT_RESPONSE_1B,     //xxx
                                         DSI_VC_0,
                                         1, ST_TP_CALIBRATION_SUCCESS);
        }
        else	// 校准失败
        {
            hal_dsi_rx_ctrl_send_ack_cmd(handler,
                                         DSI_ACK_DT_DSC_SHORT_RESPONSE_1B,     //xxx
                                         DSI_VC_0,
                                         1, 0x00);
        }
    }

    return true;
}

/**************************************************************************
* @name : app_tp_calibration_exec
* @brief : st touch 触摸校准执行函数
* @param[in] :
* @return :
* @retval :
**************************************************************************/

void app_tp_calibration_exec(void)
{
    uint8_t i = 0;

    if(s_calibration_flag)
    {
        s_calibration_flag = false;
        for(i = 0; i < 3; i++)
        {
            ap_tp_st_touch_calibration();
            delayMs(4000);
            ap_tp_st_touch_get_calibration_success_mark();
            if(s_calibration_correct_flag == ST_TP_CALIBRATION_SUCCESS)
            {
                TAU_LOGD("calibration successful \n");
                break;
            }
            else
            {
                TAU_LOGD("calibration failure \n");
            }
        }

    }
}


/**************************************************************************
* @name : ap_tp_st_touch_scan_point_init
* @brief : st touch tp_scan_data结构体初始化
* @param[in] :
* @return :
* @retval :
**************************************************************************/

void ap_tp_st_touch_scan_point_init(void)
{
    uint8_t i = 0;

    for(i = 0; i < ST_TP_SCAN_POINT_NUMBER_MAX; i++)
        tp_scan_data.tp_point_buffer[i] = 0;
    tp_scan_data.tp_point_up_error_flag = 0;
    tp_scan_data.tp_read_point_counter = 0;
    tp_scan_data.tp_point_error_time_counter = 0;
}


/**************************************************************************
* @name : ap_tp_st_touch_simulate_finger_release_event
* @brief : st touch 模拟ST 手指释放事件给到处理函数
* @param[in] :
* @return :
* @retval :
**************************************************************************/

void ap_tp_st_touch_simulate_finger_release_event(void)
{
    uint8_t i, temp = 0, ap_tp_release_buf[8] = {0x33, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

    for(i = 0; i < 5; i++)
    {
        temp = i;
        ap_tp_release_buf[1] = (temp << 4) | 0x01;

        app_tp_screen_analysis_int(0, ap_tp_release_buf, 8);

        delayMs(6);
    }
}

/**************************************************************************
* @name : ap_tp_st_touch_software_reset
* @brief : st touch 触摸芯片软件复位指令
* @param[in] :
* @return :
* @retval :
**************************************************************************/

void ap_tp_st_touch_software_reset(void)
{
    TAU_LOGD("st_touch_software_reset \n");
    ap_tp_st_touch_simulate_finger_release_event();
    ap_tp_st_touch_scan_point_init();

    app_tp_m_write(st_touch_tp_tuning_clkreset, sizeof(st_touch_tp_tuning_clkreset));    // clk reset
    while(!hal_i2c_m_transfer_complate());
    delayMs(5);

    app_tp_m_write(st_touch_tp_tuning_reset, sizeof(st_touch_tp_tuning_reset));    // System Reset  A4 00 00
    while(!hal_i2c_m_transfer_complate());
    delayMs(5);

    app_tp_m_write(st_touch_tp_tuning_clearfifo, sizeof(st_touch_tp_tuning_clearfifo));//0xA4,0x00,0x01
    while(!hal_i2c_m_transfer_complate());
    delayMs(5);

    app_tp_m_write(st_touch_init_sensor_on, sizeof(st_touch_init_sensor_on));//0xA0,0x00,0x01
    while(!hal_i2c_m_transfer_complate());
    delayMs(5);

//	app_tp_screen_reset();
}


/**************************************************************************
* @name : app_tp_st_touch_hardware_reset
* @brief : st touch 触摸芯片硬件复位指令
* @param[in] :
* @return :
* @retval :
**************************************************************************/
void ap_tp_st_touch_hardware_reset(void)
{
    TAU_LOGD("st_touch_hardware_reset \n");
    ap_tp_st_touch_simulate_finger_release_event();
    ap_tp_st_touch_scan_point_init();
    hal_gpio_set_output_data(g_screen_input_rst_pad, IO_LVL_HIGH);
    delayMs(2);
    hal_gpio_set_output_data(g_screen_input_rst_pad, IO_LVL_LOW);
    delayMs(2);
    hal_gpio_set_output_data(g_screen_input_rst_pad, IO_LVL_HIGH);
    delayMs(2);

    app_tp_m_write(st_touch_tp_tuning_clearfifo, sizeof(st_touch_tp_tuning_clearfifo));//0xA4,0x00,0x01}
    while(!hal_i2c_m_transfer_complate());
    delayMs(5);
    app_tp_m_write(st_touch_init_sensor_off, sizeof(st_touch_init_sensor_off));//0xA0,0x00,0x00
    while(!hal_i2c_m_transfer_complate());
    delayMs(5);
    app_tp_m_write(st_touch_init_sensor_on, sizeof(st_touch_init_sensor_on));//0xA0,0x00,0x01
    while(!hal_i2c_m_transfer_complate());
    delayMs(5);
}

/**************************************************************************
* @name : ap_tp_st_touch_scan_point_record_event
* @brief : st touch 记录报点事件
* @param[in] : screendata 报点数据buf；len 报点数据长度
* @return :
* @retval :
**************************************************************************/

void ap_tp_st_touch_scan_point_record_event(uint8_t* screendata, uint8_t len)
{
    uint8_t i = 0, j, flag = 0, eventdata = 0, eventid = 0;

    for(i = 0; i < len; i++)
    {
        eventdata = screendata[i];
        eventid = (screendata[i + 1] >> 4) + 1;
        i += 7;

        if(eventdata == 0x13)	// 按下事件
        {
            for(j = 0; j < ST_TP_SCAN_POINT_NUMBER_MAX; j++)
            {
                if(tp_scan_data.tp_point_buffer[j] == eventid)
                {
                    flag = 1;
                    break;
                }
            }

            if(flag == 0)		// 轮询没有该ID，需要保存
            {
                for(j = 0; j < ST_TP_SCAN_POINT_NUMBER_MAX; j++) //寻找空位
                {
                    if(tp_scan_data.tp_point_buffer[j] == 0x00)
                    {
                        tp_scan_data.tp_point_buffer[j] = eventid;
                        tp_scan_data.tp_read_point_counter++;
                        break;
                    }
                }

            }
        }

        if(eventdata == 0x33 && (tp_scan_data.tp_read_point_counter > 0))	// 释放事件
        {
            for(j = 0; j < ST_TP_SCAN_POINT_NUMBER_MAX; j++)
            {
                if(tp_scan_data.tp_point_buffer[j] == eventid)  // 有该事件需要释放
                {
                    tp_scan_data.tp_point_buffer[j] = 0;
                    tp_scan_data.tp_read_point_counter--;
                    break;
                }
            }

            tp_scan_data.tp_point_up_error_flag = 1;
            tp_scan_data.tp_point_error_time_counter = 0;
        }

        if(eventdata == 0x23)	// 移动MOVE事件
        {
            tp_scan_data.tp_point_up_error_flag = 1;
            tp_scan_data.tp_point_error_time_counter = 0;
        }
    }
}

/**************************************************************************
* @name : ap_tp_st_touch_scan_point_record_event_exec
* @brief : st touch 报点如有残留点，超时检测执行函数。需要放在主函数while(1)中执行
* @param[in] :
* @return :
* @retval :
**************************************************************************/

void ap_tp_st_touch_scan_point_record_event_exec(void)
{
    if(tp_scan_data.tp_point_up_error_flag == 1)
    {
        if(tp_scan_data.tp_point_error_time_counter < (65536 / 10)) // 65536*3 = 900ms  65536/10 = 30ms
        {
            tp_scan_data.tp_point_error_time_counter ++;
        }
        else	// 没有收到move 或者release 时间超时
        {
            if(tp_scan_data.tp_read_point_counter > 0)	// 有残留点
            {
//				printf("release finger %2d\n",tp_scan_data.tp_read_point_counter);
                tp_scan_data.tp_read_point_counter = 0;
                ap_tp_st_touch_simulate_finger_release_event();
            }
            ap_tp_st_touch_scan_point_init();
        }
    }
}

/**************************************************************************
* @name : ap_tp_st_touch_error_handler_F3
* @brief : st touch 异常报错 F3 02 处理函数
* @param[in] : screendata 触摸报点数据
* @return :
* @retval :
**************************************************************************/

void ap_tp_st_touch_error_handler_F3(uint8_t* screendata)
{
    // 收到 TP 异常回复 0xF3 0x02 0x00 0x00 0x00 0x00 0x00 0x00
    if(screendata[0] == 0xF3 && screendata[1] == 0x02 && screendata[2] == 0x00)
    {
        ap_tp_st_touch_software_reset();
    }

//	if(screendata[0] == 0xF3 && screendata[1] == 0x91 && screendata[2] == 0x00)
//	{
//		ap_tp_st_touch_software_reset();
//	}
}

/**************************************************************************
* @name : ap_tp_st_touch_error_handler_F3
* @brief : st touch 异常报错 FF FF 处理函数
* @param[in] : screendata 触摸报点数据
* @return :
* @retval :
**************************************************************************/

void ap_tp_st_touch_error_handler_FF(uint8_t* screendata)
{
    // 收到 TP 异常回复 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
    if(screendata[1] == 0xFF && screendata[2] == 0xFF && screendata[3] == 0xFF && screendata[4] == 0xFF)
    {
        ap_tp_st_touch_software_reset();
    }
}




