//
//  s95160_t1.c		Touch screen part, layer 1 (Physical device interface)
//  Graphic LCD module "SUCCESS ELECTRONIC S95160" I/O library
//  Copyright(C)2013-2018 Toyohiko Togashi tog001@nifty.com
//
//
//  This program is free software; you can redistribute it and/or modify it under the terms of the
//  GNU General Public License as published by the Free Software Foundation; either version 3
//  of the License, or (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
//  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//  See the GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License along with this program.
//  If not, see <http://www.gnu.org/licenses/>
//
//
//    Update history
//    ---------- ----- -------------------------------------------
//    2013.01.24 v0.0  First cording
//    2013.05.19 v0.0  Analog port x4 -> x2
//    2013.11.02 v0.1  Support of ADC_NOBLOCK_MODE (Conversion wait cut)
//    2013.12.23 v0.1  SMA Filter
//    2017.04.15 v0.3  Supported a System Workbench for STM32 and STM32CubeF4
//    2017.04.15 v0.3  Supported a STM32 NUCLEO F446RE
//    2018.01.14 v0.3a Bug fix
//


//---------------------------------------------------------------------
//
//						STM32Cube HAL Drivers
//
//---------------------------------------------------------------------
#ifdef USE_HAL_DRIVER					// ADD START 2017.04.15
#include <stm32f4xx.h>
#include <stm32f4xx_hal_gpio.h>
#include <stm32f4xx_hal_rcc.h>
#include <stm32f4xx_hal_adc.h>
#include "s95160_t1.h"
#define ADC_SAMPLE_TIME		ADC_SAMPLETIME_3CYCLES
#define ADC_TIMEOUT			0			// ADC convert wait time[ms]
#define SCAN_PERIOD_MIN		100			// [ms]

//
// Hardware config
//
#if defined(STM32F4DISCOVERY)
#define LCD_CONF_ADC			ADC2
#define LCD_CONF_YN_GPIO		GPIOC
#define LCD_CONF_YN_PIN			GPIO_PIN_1
#define LCD_CONF_YN_ADCH		ADC_CHANNEL_11
#define LCD_CONF_XN_GPIO		GPIOC
#define LCD_CONF_XN_PIN			GPIO_PIN_2
#define LCD_CONF_XN_ADCH		ADC_CHANNEL_12
#define LCD_CONF_YP_GPIO		GPIOD
#define LCD_CONF_YP_PIN			GPIO_PIN_10
#define LCD_CONF_XP_GPIO		GPIOD
#define LCD_CONF_XP_PIN			GPIO_PIN_11
#define LCD_CONF_RCCINIT_T1()	{\
								__HAL_RCC_ADC2_CLK_ENABLE();\
								__HAL_RCC_GPIOB_CLK_ENABLE();\
								__HAL_RCC_GPIOC_CLK_ENABLE();\
								}
#elif defined(NUCLEO_F446RE)
#define LCD_CONF_ADC			ADC2
#define LCD_CONF_YN_GPIO		GPIOB
#define LCD_CONF_YN_PIN			GPIO_PIN_0
#define LCD_CONF_YN_ADCH		ADC_CHANNEL_8
#define LCD_CONF_XN_GPIO		GPIOB
#define LCD_CONF_XN_PIN			GPIO_PIN_1
#define LCD_CONF_XN_ADCH		ADC_CHANNEL_9
#define LCD_CONF_YP_GPIO		GPIOB
#define LCD_CONF_YP_PIN			GPIO_PIN_2
#define LCD_CONF_XP_GPIO		GPIOB
#define LCD_CONF_XP_PIN			GPIO_PIN_3
#define LCD_CONF_RCCINIT_T1()	{\
								HAL_Init();\
								__HAL_RCC_ADC2_CLK_ENABLE();\
								__HAL_RCC_GPIOB_CLK_ENABLE();\
								}
#else
#error "Not supported"
#endif
#define HAL_GPIO_SetPin(port, pin)		port->BSRR = pin
#define HAL_GPIO_ResetPin(port, pin)	port->BSRR = (uint32_t)pin << 16U

//
//	I/O Port define
//
ADC_HandleTypeDef	lcd_tp_init = {
	LCD_CONF_ADC,
	{
		ADC_CLOCK_SYNC_PCLK_DIV2,
		ADC_RESOLUTION_12B,
		ADC_DATAALIGN_RIGHT,
		DISABLE,	// ScanConvMode
		ADC_EOC_SINGLE_CONV,
		DISABLE,	// ContinuousConvMode
		1,			// NbrOfConversion
		DISABLE,	// DiscontinuousConvMode
		0,			// NbrOfDiscConversion
		ADC_SOFTWARE_START,
		ADC_EXTERNALTRIGCONVEDGE_NONE,
		DISABLE,	// DMAContinuousRequests
	},
	1,
};

const struct {
	GPIO_TypeDef*			yn_gpio;
	GPIO_InitTypeDef		yn_analog;
	GPIO_InitTypeDef		yn_output;
	ADC_ChannelConfTypeDef	yn_adch;

	GPIO_TypeDef*			xn_gpio;
	GPIO_InitTypeDef		xn_analog;
	GPIO_InitTypeDef		xn_output;
	ADC_ChannelConfTypeDef	xn_adch;

	GPIO_TypeDef*			yp_gpio;
	GPIO_InitTypeDef		yp_input;
	GPIO_InitTypeDef		yp_output;

	GPIO_TypeDef*			xp_gpio;
	GPIO_InitTypeDef		xp_input;
	GPIO_InitTypeDef		xp_output;

} lcd_tp = {
	 LCD_CONF_YN_GPIO,
	{LCD_CONF_YN_PIN, GPIO_MODE_ANALOG,    GPIO_NOPULL, GPIO_SPEED_FREQ_HIGH},
	{LCD_CONF_YN_PIN, GPIO_MODE_OUTPUT_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_HIGH},
	{LCD_CONF_YN_ADCH, 1, ADC_SAMPLE_TIME},

	 LCD_CONF_XN_GPIO,
	{LCD_CONF_XN_PIN, GPIO_MODE_ANALOG,    GPIO_NOPULL, GPIO_SPEED_FREQ_HIGH},
	{LCD_CONF_XN_PIN, GPIO_MODE_OUTPUT_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_HIGH},
	{LCD_CONF_XN_ADCH, 1, ADC_SAMPLE_TIME},

	 LCD_CONF_YP_GPIO,
	{LCD_CONF_YP_PIN, GPIO_MODE_INPUT,     GPIO_NOPULL, GPIO_SPEED_FREQ_HIGH},
	{LCD_CONF_YP_PIN, GPIO_MODE_OUTPUT_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_HIGH},

	 LCD_CONF_XP_GPIO,
	{LCD_CONF_XP_PIN, GPIO_MODE_INPUT,     GPIO_NOPULL, GPIO_SPEED_FREQ_HIGH},
	{LCD_CONF_XP_PIN, GPIO_MODE_OUTPUT_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_HIGH},

};

//
//	Open
//
void lcd_tpStart(void) {
	LCD_CONF_RCCINIT_T1();
	HAL_GPIO_Init(lcd_tp.yn_gpio, (GPIO_InitTypeDef *)&lcd_tp.yn_analog);
	HAL_GPIO_Init(lcd_tp.xn_gpio, (GPIO_InitTypeDef *)&lcd_tp.xn_analog);
	HAL_GPIO_Init(lcd_tp.yp_gpio, (GPIO_InitTypeDef *)&lcd_tp.yp_input);
	HAL_GPIO_Init(lcd_tp.xp_gpio, (GPIO_InitTypeDef *)&lcd_tp.xp_input);
	HAL_ADC_Init(&lcd_tp_init);
	return;
}

//
//	Dynamic curcuit configurate and measure	(Non block mode)
//
void lcd_tpGetXYZ(short point[3]){
	static enum {
		SCAN_STATE_IDLE = 0,
		SCAN_STATE_Z_START,
		SCAN_STATE_Z_NEG,
		SCAN_STATE_Z_POS,
		SCAN_STATE_Y_START,
		SCAN_STATE_Y,
		SCAN_STATE_X_START,
		SCAN_STATE_X,
		SCAN_STATE_END
	}	scanState;
	static short	z1;
	static short	z2;
	static short	y;
	static short	x;
	static short	z;
	static uint32_t	scanPeriod;

	//
	// State machine
	//
	switch(scanState){
	case SCAN_STATE_IDLE:
		// Change circuit
		HAL_GPIO_Init(lcd_tp.yp_gpio, (GPIO_InitTypeDef *)&lcd_tp.yp_output);
		HAL_GPIO_Init(lcd_tp.xp_gpio, (GPIO_InitTypeDef *)&lcd_tp.xp_output);
		HAL_GPIO_SetPin(  lcd_tp.yp_gpio, lcd_tp.yp_output.Pin);
		HAL_GPIO_ResetPin(lcd_tp.xp_gpio, lcd_tp.xp_output.Pin);
		scanState  = SCAN_STATE_Z_START;
		scanPeriod = HAL_GetTick() + SCAN_PERIOD_MIN;
		break;

	case SCAN_STATE_Z_START:
		HAL_ADC_ConfigChannel(&lcd_tp_init, (ADC_ChannelConfTypeDef *)&lcd_tp.yn_adch);
		HAL_ADC_Start(&lcd_tp_init);
		scanState = SCAN_STATE_Z_NEG;
		break;

	case SCAN_STATE_Z_NEG:
		if (HAL_ADC_PollForConversion(&lcd_tp_init, ADC_TIMEOUT)) {
			z1 = HAL_ADC_GetValue(&lcd_tp_init);
			HAL_ADC_Stop(&lcd_tp_init);

			HAL_ADC_ConfigChannel(&lcd_tp_init, (ADC_ChannelConfTypeDef *)&lcd_tp.xn_adch);
			HAL_ADC_Start(&lcd_tp_init);
			scanState = SCAN_STATE_Z_POS;
		}
		break;

	case SCAN_STATE_Z_POS:
		if (HAL_ADC_PollForConversion(&lcd_tp_init, ADC_TIMEOUT)) {
			z2 = HAL_ADC_GetValue(&lcd_tp_init);
			HAL_ADC_Stop(&lcd_tp_init);			// ADD 2018.01.14

			z = ADC_RESOLUTION - (z1-z2) - 1;	// Reverse
			if (z <= ADC_NOCONTACT) {
				scanState = SCAN_STATE_IDLE;
			} else {
				// Change circuit
				HAL_GPIO_Init(lcd_tp.yp_gpio, (GPIO_InitTypeDef *)&lcd_tp.yp_input);
				HAL_GPIO_Init(lcd_tp.xp_gpio, (GPIO_InitTypeDef *)&lcd_tp.xp_input);

				HAL_GPIO_Init(lcd_tp.yn_gpio, (GPIO_InitTypeDef *)&lcd_tp.yn_output);
				HAL_GPIO_Init(lcd_tp.yp_gpio, (GPIO_InitTypeDef *)&lcd_tp.yp_output);
				HAL_GPIO_ResetPin(lcd_tp.yn_gpio, lcd_tp.yn_output.Pin);
				HAL_GPIO_SetPin  (lcd_tp.yp_gpio, lcd_tp.yp_output.Pin);
				scanState = SCAN_STATE_Y_START;
			}
		}
		break;

	case SCAN_STATE_Y_START:
		HAL_ADC_ConfigChannel(&lcd_tp_init, (ADC_ChannelConfTypeDef *)&lcd_tp.xn_adch);
		HAL_ADC_Start(&lcd_tp_init);
		scanState = SCAN_STATE_Y;
		break;

	case SCAN_STATE_Y:
		if (HAL_ADC_PollForConversion(&lcd_tp_init, ADC_TIMEOUT)) {
			y = HAL_ADC_GetValue(&lcd_tp_init);
			y = ADC_RESOLUTION - y;				// Reverse
			// Change circuit
			HAL_GPIO_Init(lcd_tp.yn_gpio, (GPIO_InitTypeDef *)&lcd_tp.yn_analog);
			HAL_GPIO_Init(lcd_tp.yp_gpio, (GPIO_InitTypeDef *)&lcd_tp.yp_input);
			HAL_GPIO_Init(lcd_tp.xn_gpio, (GPIO_InitTypeDef *)&lcd_tp.xn_output);
			HAL_GPIO_Init(lcd_tp.xp_gpio, (GPIO_InitTypeDef *)&lcd_tp.xp_output);
			HAL_GPIO_ResetPin(lcd_tp.xn_gpio, lcd_tp.xn_output.Pin);
			HAL_GPIO_SetPin(  lcd_tp.xp_gpio, lcd_tp.xp_output.Pin);
			scanState = SCAN_STATE_X_START;
		}
		break;

	case SCAN_STATE_X_START:
		HAL_ADC_ConfigChannel(&lcd_tp_init, (ADC_ChannelConfTypeDef *)&lcd_tp.yn_adch);
		HAL_ADC_Start(&lcd_tp_init);
		scanState = SCAN_STATE_X;
		break;

	case SCAN_STATE_X:
		if (HAL_ADC_PollForConversion(&lcd_tp_init, ADC_TIMEOUT)) {
			x = HAL_ADC_GetValue(&lcd_tp_init);
			HAL_GPIO_Init(lcd_tp.xn_gpio, (GPIO_InitTypeDef *)&lcd_tp.xn_analog);
			HAL_GPIO_Init(lcd_tp.xp_gpio, (GPIO_InitTypeDef *)&lcd_tp.xp_input);

			HAL_GPIO_Init(lcd_tp.yp_gpio, (GPIO_InitTypeDef *)&lcd_tp.yp_output);
			HAL_GPIO_Init(lcd_tp.xp_gpio, (GPIO_InitTypeDef *)&lcd_tp.xp_output);
			HAL_GPIO_SetPin(  lcd_tp.yp_gpio, lcd_tp.yp_output.Pin);
			HAL_GPIO_ResetPin(lcd_tp.xp_gpio, lcd_tp.xp_output.Pin);
			scanState = SCAN_STATE_END;
		}
		break;

	case SCAN_STATE_END:
		if (scanPeriod < HAL_GetTick()) {
			scanState = SCAN_STATE_IDLE;
		}
		break;

	default:
		scanState = SCAN_STATE_IDLE;
		break;
	}

	//
	// Return values
	//
	{
		static short	ax = 0;
		static short	ay = 0;
		static short	az = 0;

		if (scanState == SCAN_STATE_IDLE) {
			static short	maxz = 0;
			int				f;

#ifdef ADC_AVERAGE						// ADD START 2013.12.23
			{							// Filter: Simple Moving Average
				static short	samp[ADC_AVERAGE][3];
				static short	pos = 0;
				int				i;
				int				sumx;
				int				sumy;
				int				sumz;

				samp[pos][0] = x;
				samp[pos][1] = y;
				samp[pos][2] = z;
				if (++pos >= ADC_AVERAGE) {
					pos = 0;
				}
				sumx = 0;
				sumy = 0;
				sumz = 0;
				for(i = 0; i < ADC_AVERAGE; i++) {
					sumx += samp[pos][0];
					sumy += samp[pos][1];
					sumz += samp[pos][2];
				}
				x = sumx / ADC_AVERAGE;
				y = sumy / ADC_AVERAGE;
				z = sumz / ADC_AVERAGE;
			}
#endif									// ADD END 2013.12.23
			f = 0;
			if (z > ADC_NOCONTACT) {
				if (z >= maxz) {
					maxz = z;
					f = 1;
				} else if (z > (maxz * 100 / ADC_NOCONTACT)) {
					f = 1;
				}
			} else {
				maxz = 0;
			}

			if (f) {
				ax = x;
				ay = y;
				az = z;
			} else {
				ax = 0;
				ay = 0;
				az = -1;
			}
		}

		point[0] = ax;
		point[1] = ay;
		point[2] = az;
	}
	return;
}

//---------------------------------------------------------------------
//
//						StdPeriph_Driver
//
//---------------------------------------------------------------------
#else	// USE_HAL_DRIVER				//
#include "stm32f4xx_gpio.h"				// Public library
#include "stm32f4xx_adc.h"				// Public library
#include "stm32f4xx_rcc.h"				// Public library
#include "s95160_t1.h"

//
//	Parameter
//
#define ADC_TIMEOUT			10						// ADC convert wait time
#define ADC_NOBLOCK_MODE							// ADD 2013.11.02

//
// Hardware config
//
#define LCD_CONF_ADC			ADC2
#define LCD_CONF_YN_GPIO		GPIOC
#define LCD_CONF_YN_PIN			GPIO_Pin_1
#define LCD_CONF_YN_ADCH		ADC_Channel_11
#define LCD_CONF_XN_GPIO		GPIOC
#define LCD_CONF_XN_PIN			GPIO_Pin_2
#define LCD_CONF_XN_ADCH		ADC_Channel_12
#define LCD_CONF_YP_GPIO		GPIOB
#define LCD_CONF_YP_PIN			GPIO_Pin_11
#define LCD_CONF_XP_GPIO		GPIOB
#define LCD_CONF_XP_PIN			GPIO_Pin_12
#define LCD_CONF_RCCINIT_T1()	{\
								RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);\
								RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);\
								RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);\
								}

#define ADC_SAMPLE_TIME		ADC_SampleTime_56Cycles
//#define ADC_SAMPLE_TIME	ADC_SampleTime_3Cycles
//#define ADC_SAMPLE_TIME	ADC_SampleTime_144Cycles
//#define ADC_SAMPLE_TIME	ADC_SampleTime_480Cycles
										// ADD END 2017.04.15


//
//	I/O Port define		(See "s95160_t1.h")
//
const struct {
	ADC_InitTypeDef			init;
	ADC_CommonInitTypeDef	comm;
	ADC_TypeDef*			adc;

	GPIO_TypeDef*			yn_gpio;
	GPIO_InitTypeDef		yn_analog;
	GPIO_InitTypeDef		yn_output;
	uint8_t					yn_adch;

	GPIO_TypeDef*			xn_gpio;
	GPIO_InitTypeDef		xn_analog;
	GPIO_InitTypeDef		xn_output;
	uint8_t					xn_adch;

	GPIO_TypeDef*			yp_gpio;
	GPIO_InitTypeDef		yp_analog;
	GPIO_InitTypeDef		yp_output;
//	uint8_t					yp_adch;	// DEL 2013.05.19

	GPIO_TypeDef*			xp_gpio;
	GPIO_InitTypeDef		xp_analog;
	GPIO_InitTypeDef		xp_output;
//	uint8_t					xp_adch;	// DEL 2013.05.19

} lcd_tp = {
	{	// ADC_InitTypeDef
		ADC_Resolution_12b,
		DISABLE,
		DISABLE,
		ADC_ExternalTrigConvEdge_None,
		ADC_ExternalTrigConv_T1_CC1,
		ADC_DataAlign_Right,
		1
	},
	{	// ADC_CommonInitTypeDef
		ADC_Mode_Independent,
		ADC_Prescaler_Div2,
		ADC_DMAAccessMode_Disabled,
		ADC_TwoSamplingDelay_5Cycles
	},
	LCD_CONF_ADC,

	 LCD_CONF_YN_GPIO,
	{LCD_CONF_YN_PIN, GPIO_Mode_AN,  GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL},
	{LCD_CONF_YN_PIN, GPIO_Mode_OUT, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL},
	 LCD_CONF_YN_ADCH,

	 LCD_CONF_XN_GPIO,
	{LCD_CONF_XN_PIN, GPIO_Mode_AN,  GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL},
	{LCD_CONF_XN_PIN, GPIO_Mode_OUT, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL},
	 LCD_CONF_XN_ADCH,

	 LCD_CONF_YP_GPIO,
//	{LCD_CONF_YP_PIN, GPIO_Mode_AN,  GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL},	// DEL 2013.05.19
	{LCD_CONF_YP_PIN, GPIO_Mode_IN,  GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL},	// ADD 2013.05.19
	{LCD_CONF_YP_PIN, GPIO_Mode_OUT, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL},
//	 LCD_CONF_YP_ADCH,																		// DEL 2013.05.19

	 LCD_CONF_XP_GPIO,
//	{LCD_CONF_XP_PIN, GPIO_Mode_AN,  GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL},	// DEL 2013.05.19
	{LCD_CONF_XP_PIN, GPIO_Mode_IN,  GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL},	// ADD 2013.05.19
	{LCD_CONF_XP_PIN, GPIO_Mode_OUT, GPIO_Speed_100MHz, GPIO_OType_PP, GPIO_PuPd_NOPULL},
//	 LCD_CONF_XP_ADCH,																		// DEL 2013.05.19

};

//
//	Open
//
void lcd_tpStart(void) {
	LCD_CONF_RCCINIT_T1();

	GPIO_Init(lcd_tp.yn_gpio, (GPIO_InitTypeDef *)&lcd_tp.yn_analog);
	GPIO_Init(lcd_tp.xn_gpio, (GPIO_InitTypeDef *)&lcd_tp.xn_analog);
	GPIO_Init(lcd_tp.yp_gpio, (GPIO_InitTypeDef *)&lcd_tp.yp_analog);
	GPIO_Init(lcd_tp.xp_gpio, (GPIO_InitTypeDef *)&lcd_tp.xp_analog);

	ADC_CommonInit((ADC_CommonInitTypeDef *)&lcd_tp.comm);
	ADC_Init(lcd_tp.adc, (ADC_InitTypeDef *)&lcd_tp.init);
	ADC_Cmd(lcd_tp.adc, ENABLE);

	return;
}

#ifndef ADC_NOBLOCK_MODE				// DEL START 2013.11.02
//
// A/D conversion
//
short lcd_tpGetPinLevel(uint8_t adc_ch) {
	int	v;
	int	i;
	int t;

	ADC_RegularChannelConfig(lcd_tp.adc, adc_ch, 1, ADC_SampleTime_3Cycles);
	v = 0;
	for(i = 0; i < ADC_AVERAGE; i++) {
		ADC_ClearFlag(lcd_tp.adc, ADC_FLAG_EOC);
		ADC_SoftwareStartConv(lcd_tp.adc);
		for(t = 0; t < ADC_TIMEOUT; t++){
			if (ADC_GetFlagStatus(lcd_tp.adc, ADC_FLAG_EOC)) break;
		}
		if (t < ADC_TIMEOUT) {
			v += ADC_GetConversionValue(lcd_tp.adc);
		} else {
			v = -1 * ADC_AVERAGE;
			break;
		}
	}
	return(v / ADC_AVERAGE);
}
//
// Dynamic curcuit configurate and measure
//
void lcd_tpGetXYZ(short point[3]){
	short	x;
	short	y;
	short	z;

	// Push force		(Y+ = Vdd, X+ = Gnd curcuit => Y- or X- voltage capture)
	//
	GPIO_Init(lcd_tp.yp_gpio, (GPIO_InitTypeDef *)&lcd_tp.yp_output);
	GPIO_Init(lcd_tp.xp_gpio, (GPIO_InitTypeDef *)&lcd_tp.xp_output);
	GPIO_SetBits(  lcd_tp.yp_gpio, lcd_tp.yp_output.GPIO_Pin);
	GPIO_ResetBits(lcd_tp.xp_gpio, lcd_tp.xp_output.GPIO_Pin);
	z = lcd_tpGetPinLevel(lcd_tp.yn_adch) - lcd_tpGetPinLevel(lcd_tp.xn_adch);
	GPIO_Init(lcd_tp.yp_gpio, (GPIO_InitTypeDef *)&lcd_tp.yp_analog);
	GPIO_Init(lcd_tp.xp_gpio, (GPIO_InitTypeDef *)&lcd_tp.xp_analog);
	z = ADC_RESOLUTION - z - 1;				// Reverse

	// Contact
	//
	if (z > ADC_NOCONTACT) {
		// Get Y		(Y+ = Vdd, Y- = Gnd curcuit => X+ or X- voltage capture)
		//
		GPIO_Init(lcd_tp.yn_gpio, (GPIO_InitTypeDef *)&lcd_tp.yn_output);
		GPIO_Init(lcd_tp.yp_gpio, (GPIO_InitTypeDef *)&lcd_tp.yp_output);
		GPIO_ResetBits(lcd_tp.yn_gpio, lcd_tp.yn_output.GPIO_Pin);
		GPIO_SetBits(lcd_tp.yp_gpio, lcd_tp.yp_output.GPIO_Pin);
//		y = lcd_tpGetPinLevel(lcd_tp.xp_adch);			// DEL 2013.05.19
		y = lcd_tpGetPinLevel(lcd_tp.xn_adch);			// ADD 2013.05.19
		GPIO_Init(lcd_tp.yn_gpio, (GPIO_InitTypeDef *)&lcd_tp.yn_analog);
		GPIO_Init(lcd_tp.yp_gpio, (GPIO_InitTypeDef *)&lcd_tp.yp_analog);
		y = ADC_RESOLUTION - y;			// Reverse

		// Get X		(X+ = Vdd, X- = Gnd curcuit => Y+ or Y- voltage capture)
		//
		GPIO_Init(lcd_tp.xn_gpio, (GPIO_InitTypeDef *)&lcd_tp.xn_output);
		GPIO_Init(lcd_tp.xp_gpio, (GPIO_InitTypeDef *)&lcd_tp.xp_output);
		GPIO_ResetBits(lcd_tp.xn_gpio, lcd_tp.xn_output.GPIO_Pin);
		GPIO_SetBits(lcd_tp.xp_gpio, lcd_tp.xp_output.GPIO_Pin);
//		x = lcd_tpGetPinLevel(lcd_tp.yp_adch);			// DEL 2013.05.19
		x = lcd_tpGetPinLevel(lcd_tp.yn_adch);			// ADD 2013.05.19
		GPIO_Init(lcd_tp.xn_gpio, (GPIO_InitTypeDef *)&lcd_tp.xn_analog);
		GPIO_Init(lcd_tp.xp_gpio, (GPIO_InitTypeDef *)&lcd_tp.xp_analog);
	} else {
		x = -1;
		y = -1;
		z = 0;
	}

	point[0] = x;
	point[1] = y;
	point[2] = z;
	return;
}

#else									// DEL END, ADD START 2013.11.02

//
//	Dynamic curcuit configurate and measure	(Non block mode)
//
void lcd_tpGetXYZ(short point[3]){
	static enum {
		SCAN_STATE_IDLE = 0,
		SCAN_STATE_Z_START,
		SCAN_STATE_Z_NEG,
		SCAN_STATE_Z_POS,
		SCAN_STATE_Y_START,
		SCAN_STATE_Y,
		SCAN_STATE_X_START,
		SCAN_STATE_X,
		SCAN_STATE_END
	}	scanState;
	static short	z1;
	static short	z2;
	static short	y;
	static short	x;
	static short	z;

	//
	// State machine
	//
	switch(scanState){
	case SCAN_STATE_IDLE:
		// Change circuit
		GPIO_Init(lcd_tp.yp_gpio, (GPIO_InitTypeDef *)&lcd_tp.yp_output);
		GPIO_Init(lcd_tp.xp_gpio, (GPIO_InitTypeDef *)&lcd_tp.xp_output);
		GPIO_SetBits(  lcd_tp.yp_gpio, lcd_tp.yp_output.GPIO_Pin);
		GPIO_ResetBits(lcd_tp.xp_gpio, lcd_tp.xp_output.GPIO_Pin);
		scanState = SCAN_STATE_Z_START;
		break;

	case SCAN_STATE_Z_START:
		ADC_RegularChannelConfig(lcd_tp.adc, lcd_tp.yn_adch, 1, ADC_SAMPLE_TIME);
		ADC_ClearFlag(lcd_tp.adc, ADC_FLAG_EOC);
		ADC_SoftwareStartConv(lcd_tp.adc);
		scanState = SCAN_STATE_Z_NEG;
		break;

	case SCAN_STATE_Z_NEG:
		if (ADC_GetFlagStatus(lcd_tp.adc, ADC_FLAG_EOC)) {
			z1 = ADC_GetConversionValue(lcd_tp.adc);

			ADC_RegularChannelConfig(lcd_tp.adc, lcd_tp.xn_adch, 1, ADC_SAMPLE_TIME);
			ADC_ClearFlag(lcd_tp.adc, ADC_FLAG_EOC);
			ADC_SoftwareStartConv(lcd_tp.adc);
			scanState = SCAN_STATE_Z_POS;
		}
		break;

	case SCAN_STATE_Z_POS:
		if (ADC_GetFlagStatus(lcd_tp.adc, ADC_FLAG_EOC)) {
			z2 = ADC_GetConversionValue(lcd_tp.adc);
			z = ADC_RESOLUTION - (z1-z2) - 1;	// Reverse
			if (z <= ADC_NOCONTACT) {
				scanState = SCAN_STATE_IDLE;
			} else {
				// Change circuit
				GPIO_Init(lcd_tp.yp_gpio, (GPIO_InitTypeDef *)&lcd_tp.yp_analog);
				GPIO_Init(lcd_tp.xp_gpio, (GPIO_InitTypeDef *)&lcd_tp.xp_analog);

				GPIO_Init(lcd_tp.yn_gpio, (GPIO_InitTypeDef *)&lcd_tp.yn_output);
				GPIO_Init(lcd_tp.yp_gpio, (GPIO_InitTypeDef *)&lcd_tp.yp_output);
				GPIO_ResetBits(lcd_tp.yn_gpio, lcd_tp.yn_output.GPIO_Pin);
				GPIO_SetBits(lcd_tp.yp_gpio, lcd_tp.yp_output.GPIO_Pin);
				scanState = SCAN_STATE_Y_START;
			}
		}
		break;

	case SCAN_STATE_Y_START:
		ADC_RegularChannelConfig(lcd_tp.adc, lcd_tp.xn_adch, 1, ADC_SAMPLE_TIME);
		ADC_ClearFlag(lcd_tp.adc, ADC_FLAG_EOC);
		ADC_SoftwareStartConv(lcd_tp.adc);
		scanState = SCAN_STATE_Y;
		break;

	case SCAN_STATE_Y:
		if (ADC_GetFlagStatus(lcd_tp.adc, ADC_FLAG_EOC)) {
			y = ADC_GetConversionValue(lcd_tp.adc);
			y = ADC_RESOLUTION - y;				// Reverse
			// Change circuit
			GPIO_Init(lcd_tp.yn_gpio, (GPIO_InitTypeDef *)&lcd_tp.yn_analog);
			GPIO_Init(lcd_tp.yp_gpio, (GPIO_InitTypeDef *)&lcd_tp.yp_analog);
			GPIO_Init(lcd_tp.xn_gpio, (GPIO_InitTypeDef *)&lcd_tp.xn_output);
			GPIO_Init(lcd_tp.xp_gpio, (GPIO_InitTypeDef *)&lcd_tp.xp_output);
			GPIO_ResetBits(lcd_tp.xn_gpio, lcd_tp.xn_output.GPIO_Pin);
			GPIO_SetBits(lcd_tp.xp_gpio, lcd_tp.xp_output.GPIO_Pin);
			scanState = SCAN_STATE_X_START;
		}
		break;

	case SCAN_STATE_X_START:
		ADC_RegularChannelConfig(lcd_tp.adc, lcd_tp.yn_adch, 1, ADC_SAMPLE_TIME);
		ADC_ClearFlag(lcd_tp.adc, ADC_FLAG_EOC);
		ADC_SoftwareStartConv(lcd_tp.adc);
		scanState = SCAN_STATE_X;
		break;

	case SCAN_STATE_X:
		if (ADC_GetFlagStatus(lcd_tp.adc, ADC_FLAG_EOC)) {
			x = ADC_GetConversionValue(lcd_tp.adc);
			GPIO_Init(lcd_tp.xn_gpio, (GPIO_InitTypeDef *)&lcd_tp.xn_analog);
			GPIO_Init(lcd_tp.xp_gpio, (GPIO_InitTypeDef *)&lcd_tp.xp_analog);

			GPIO_Init(lcd_tp.yp_gpio, (GPIO_InitTypeDef *)&lcd_tp.yp_output);
			GPIO_Init(lcd_tp.xp_gpio, (GPIO_InitTypeDef *)&lcd_tp.xp_output);
			GPIO_SetBits(  lcd_tp.yp_gpio, lcd_tp.yp_output.GPIO_Pin);
			GPIO_ResetBits(lcd_tp.xp_gpio, lcd_tp.xp_output.GPIO_Pin);
			scanState = SCAN_STATE_END;
		}
		break;

	case SCAN_STATE_END:
	default:
		scanState = SCAN_STATE_IDLE;
		break;
	}

	//
	// Return values
	//
	{
		static short	ax = 0;
		static short	ay = 0;
		static short	az = 0;

		if (scanState == SCAN_STATE_IDLE) {
			static short	maxz = 0;
			int				f;

#ifdef ADC_AVERAGE						// ADD START 2013.12.23
			{							// Filter: Simple Moving Average
				static short	samp[ADC_AVERAGE][3];
				static short	pos = 0;
				int				i;
				int				sumx;
				int				sumy;
				int				sumz;

				samp[pos][0] = x;
				samp[pos][1] = y;
				samp[pos][2] = z;
				if (++pos >= ADC_AVERAGE) {
					pos = 0;
				}
				sumx = 0;
				sumy = 0;
				sumz = 0;
				for(i = 0; i < ADC_AVERAGE; i++) {
					sumx += samp[pos][0];
					sumy += samp[pos][1];
					sumz += samp[pos][2];
				}
				x = sumx / ADC_AVERAGE;
				y = sumy / ADC_AVERAGE;
				z = sumz / ADC_AVERAGE;
			}
#endif									// ADD END 2013.12.23
			f = 0;
			if (z > ADC_NOCONTACT) {
				if (z >= maxz) {
					maxz = z;
					f = 1;
				} else if (z > (maxz * 100 / ADC_NOCONTACT)) {
					f = 1;
				}
			} else {
				maxz = 0;
			}

			if (f) {
				ax = x;
				ay = y;
				az = z;
			} else {
				ax = 0;
				ay = 0;
				az = -1;
			}
		}

		point[0] = ax;
		point[1] = ay;
		point[2] = az;
	}
	return;
}

#endif									// ADD END 2013.11.02

#endif	// USE_HAL_DRIVER				// ADD 2017.04.15
