/******************************************************************************
 *
 * @brief     This file is part of the TouchGFX 4.4.1 evaluation distribution.
 *
 * @author    Draupner Graphics A/S <http://www.touchgfx.com>
 *
 ******************************************************************************
 *
 * @section Copyright
 *
 * Copyright (C) 2014 Draupner Graphics A/S <http://www.touchgfx.com>.
 * All rights reserved.
 *
 * TouchGFX is protected by international copyright laws and the knowledge of
 * this source code may not be used to write a similar product. This file may
 * only be used in accordance with a license and should not be re-
 * distributed in any way without the prior permission of Draupner Graphics.
 *
 * This is licensed software for evaluation use, any use must strictly comply
 * with the evaluation license agreement provided with delivery of the
 * TouchGFX software.
 *
 * The evaluation license agreement can be seen on www.touchgfx.com
 *
 * @section Disclaimer
 *
 * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Draupner Graphics A/S has
 * no obligation to support this software. Draupner Graphics A/S is providing
 * the software "AS IS", with no express or implied warranties of any kind,
 * including, but not limited to, any implied warranties of merchantability
 * or fitness for any particular purpose or warranties against infringement
 * of any proprietary rights of a third party.
 *
 * Draupner Graphics A/S can not be held liable for any consequential,
 * incidental, or special damages, or any other relief, or for any claim by
 * any third party, arising from your use of this software.
 *
 *****************************************************************************/
 
 /**
 * Port SSD2541 CTP controller to TouchGFX.
 * Date: 7th Dec 2015
 * Programmer: John Leung @ TechToys Co.
 */
#ifndef SSD2541TOUCHCONTROLLER_HPP
#define SSD2541TOUCHCONTROLLER_HPP

#include <platform/driver/touch/TouchController.hpp>
#include "stm32f4xx.h"


#ifdef RELEASE_3
	#define CTP_I2C_CH						I2C3
	#define CTP_SCL_BASE					GPIOA
	#define CTP_SCL_PIN						GPIO_Pin_8
	#define CTP_SCL_SOURCE				GPIO_PinSource8
	#define CTP_SDA_BASE					GPIOC
	#define CTP_SDA_PIN						GPIO_Pin_9
	#define CTP_SDA_SOURCE				GPIO_PinSource9
	//#define CTP_IRQ_BASE					GPIOG				//not used in touchGFX
	//#define CTP_IRQ_PIN						GPIO_Pin_2	
	#define CTP_RST_BASE					GPIOC
	#define CTP_RST_PIN						GPIO_Pin_13
	
	#define RCC_APB1Periph_I2Cn		RCC_APB1Periph_I2C3
	#define RCC_AHB1Periph_SCL		RCC_AHB1Periph_GPIOA
	#define RCC_AHB1Periph_SDA		RCC_AHB1Periph_GPIOC
	#define RCC_AHB1Periph_RST		RCC_AHB1Periph_GPIOC
#else
	#define CTP_I2C_CH						I2C3
	#define CTP_SCL_BASE					GPIOA
	#define CTP_SCL_PIN						GPIO_Pin_8
	#define CTP_SCL_SOURCE				GPIO_PinSource8
	#define CTP_SDA_BASE					GPIOC
	#define CTP_SDA_PIN						GPIO_Pin_9
	#define CTP_SDA_SOURCE				GPIO_PinSource9
	//#define CTP_IRQ_BASE					GPIOA
	//#define CTP_IRQ_PIN						GPIO_Pin_10
	//Reset pin of CTP controller SSD2541 shared with SSD2805 in previous hardware version	

	#define RCC_APB1Periph_I2Cn		RCC_APB1Periph_I2C3
	#define RCC_AHB1Periph_SCL		RCC_AHB1Periph_GPIOA
	#define RCC_AHB1Periph_SDA		RCC_AHB1Periph_GPIOC
#endif



#define I2C_ADDR	0x48												//slave address of SSD2541
#define MASK_NR_OF_FINGERS	0xF0							//limit to 4 fingers 
//Gestures
/*
#define REG_NO_GESTURE           0x00
#define REG_SINGLE_TOUCH_TAP     0x01
#define SINGLE_TOUCH_DOUBLE_TAP  0x02
#define SINGLE_TOUCH_SLIDE_UP    0x03
#define SINGLE_TOUCH_SLIDE_DOWN  0x04
#define SINGLE_TOUCH_SLIDE_LEFT  0x05
#define SINGLE_TOUCH_SLIDE_RIGHT 0x06
#define TWO_FINGER_SLIDE_UP      0x07
#define TWO_FINGER_SLIDE_DOWN    0x08
#define TWO_FINGER_SLIDE_LEFT    0x09
#define TWO_FINGER_SLIDE_RIGHT   0x0A
#define PINCH_IN                 0x0B
#define PINCH_OUT                0x0C
*/

/**
* @struct Initialization map for SSD2541QN6
* @brief	This array is sent to SSD2541 by I2C after low level I2C module setup
*/
typedef struct {
	uint8_t 	command;
	uint16_t 	val;
} InitMap;

/**
 * @struct Finger SSD2541TouchController.hpp /platform/driver/thirdparty/SSD2541TouchController.hpp
 *
 * @brief Represents the coordinates of a finger on the display.
 *        
 *        Represents the coordinates of a finger on the display.
 */
typedef struct {
  int16_t x; ///< x coordinate
  int16_t y; ///< y coordinate
  int16_t z; ///< z coordinate
} Finger;

/**
 * @typedef enum TransformationType
 *
 * @brief Defines the transformation types.
 */
typedef enum
{
  NO_TRANSFORM = 0, ///< No transformation
  FLIP_X_AXIS,      ///< Swap along the x axis
  FLIP_Y_AXIS       ///< Swap along the y axis
} TransformationType;

/**
 * Register table of SSD2541
 */
#define REG_NOP					0x00
#define REG_SW_RESET		0x01
#define REG_DEVICE_ID		0x02
#define REG_SLEEP_OUT		0x04
#define REG_SLEEP_IN		0x05
#define REG_DRIVE_SENSE_NO	0x06
#define REG_DRIVE_LINE0		0x07
#define REG_DRIVE_LINE1		0x08
#define REG_DRIVE_LINE2		0x09
#define REG_DRIVE_LINE3		0x0A
#define REG_DRIVE_LINE4		0x0B
#define REG_DRIVE_LINE5		0x0C
#define REG_DRIVE_LINE6		0x0D
#define REG_DRIVE_LINE7		0x0E
#define REG_DRIVE_LINE8		0x0F
#define REG_DRIVE_LINE9		0x10
#define REG_DRIVE_LINE10	0x11
#define REG_DRIVE_LINE11	0x12
#define REG_DRIVE_LINE12	0x13
#define REG_DRIVE_LINE13	0x14
#define REG_DRIVE_LINE14	0x15
#define REG_DRIVE_LINE15	0x16
#define REG_DRIVE_LINE16	0x17
#define REG_DRIVE_LINE17	0x18
#define REG_DRIVE_LINE18	0x19
#define REG_DRIVE_LINE19	0x1A
#define REG_DRIVE_LINE20	0x1B
#define REG_DRIVE_LINE21	0x1C
#define REG_DRIVE_LINE22	0x1D
#define REG_OP_MODE				0x25
#define REG_FREQ_HOPPING	0x27
#define REG_SENSE_OFFSET	0x28
#define REG_INT_TIMING		0x30
#define REG_MIN_AREA			0x33
#define REG_MIN_LEVEL			0x34
#define REG_MIN_WEIGHT		0x35
#define REG_MAX_AREA			0x36
#define REG_CG_METHOD				0x3A
#define REG_EDGE_SUPPRESS1	0x47
#define REG_EDGE_SUPPRESS2	0x48
#define REG_EDGE_SUPPRESS3	0x49
#define REG_EDGE_SUPPRESS4	0x4A
#define REG_HOP_LEVEL			0x50
#define REG_PRESS_SCALE		0x57
#define REG_ORIENTATION		0x65
#define REG_X_SCALING		0x66
#define REG_Y_SCALING		0x67
#define REG_X_OFFSET		0x68
#define REG_Y_OFFSET		0x69
#define REG_TOUCH_STATUS	0x79
#define REG_EVENT_MASK		0x7A
#define REG_IRQ_MSK			0x7B
#define REG_FINGER00		0x7C
#define REG_FINGER01		0x7D
#define REG_FINGER02		0x7E
#define REG_FINGER03		0x7F
#define REG_FINGER04		0x80
#define REG_FINGER05		0x81
#define REG_FINGER06		0x82
#define REG_FINGER07		0x83
#define REG_FINGER08		0x84
#define REG_FINGER09		0x85
#define REG_EDGE_REMAP	0x8B
#define REG_INIT_RST		0xA2
#define REG_DRIVE_LEVEL		0xD5
#define REG_ADC_RANGE_SEL	0xD7
#define REG_BIAS_RES		0xD8
#define REG_INTG_CAP		0xDB


//Map from Gavin on 2015-06-25, higher SNR at around 400
const InitMap SSD2541CfgTbl[]=
{
			{REG_SW_RESET, 			0x0000},	 //sw reset
			{REG_NOP,				0x012C},	 //wait for 300ms (0x12C=300), use NO Operation command for a delay
	    {REG_DRIVE_SENSE_NO, 	0x0505},     //Drive/Sense number set 6 for 1.54" CTP (register value = number -1)
	    {REG_SENSE_OFFSET, 		0x0002},     //offset for sense line, hardware dependent
	    {REG_DRIVE_LINE0, 		0x000B},     //Select Drive11 as Tx1 for Drive Line 0
	    {REG_DRIVE_LINE1, 		0x000C},     //Drive 12 > Drive Line 1
	    {REG_DRIVE_LINE2, 		0x000D},     //Drive 13 > Drive Line 2
	    {REG_DRIVE_LINE3, 		0x000E},     //Drive 14 > Drive Line 3
	    {REG_DRIVE_LINE4, 		0x000F},     //Drive 15 > Drive Line 4
	    {REG_DRIVE_LINE5, 		0x0010},     //Drive 16 > Drive Line 5
	    {0xC1, 					0x0002},     //magic number, reserved
	    {REG_DRIVE_LEVEL,		0x0000},     //Drive Voltage Level, set vout = 5.5V
	    {REG_INT_TIMING,		0x0609},
	    {REG_MIN_LEVEL,			0xA664},
	    {REG_ADC_RANGE_SEL,	0x0004},
	    {REG_BIAS_RES,			0x0004},
	    {REG_INTG_CAP,			0x0007},
	    {0x2a,					0x700F},	//magic number
			{0x2b, 					0x17DD},	//new magic number
			{0x37,					0x07C4},	//new magic number
	    {0x38,					0x0002},
	    {0x56,					0x8010},
	    {0x59,					0xFF31},
	    {REG_EVENT_MASK,		0xffff},
	    {REG_IRQ_MSK,			0xFFE3},	//how many fingers to detect? it was 0x0003 from Joe's code
	    {0x40,					0x10C8},
	    {0x41,					0x0050},
	    {0x42,					0x001C},
	    {0x43,					0x0050},
	    {0x44,					0x001C},
	    {0x45,					0x0050},
	    {0x46,					0x101F},
	    {REG_ORIENTATION,		0x0003},
	    {REG_X_SCALING,			0x2800},	//REG_X_SCALING & REG_Y_SCALING are scaling factors for screen resolution 240x240
	    {REG_Y_SCALING,			0x2800},
	    {0x8a,							0x0002},
	    {REG_OP_MODE,				0x0008},
};


namespace touchgfx
{
	class SSD2541TouchController : public TouchController
	{
		typedef void (*TransformFuncPtr)(int32_t&, int32_t&, Finger&);

		public:
			//default constructor
		SSD2541TouchController(int16_t width, int16_t height, TransformationType transType = NO_TRANSFORM, TransformFuncPtr pFunc=0):
		transformFunc(pFunc), linearTransform(transType), displayWidth(width), displayHeight(height)
			{
			}			
			virtual void init();
			virtual bool sampleTouch(int32_t& x, int32_t& y);
			void hardwareReset(bool state);
		private:
			void writeRegister(uint8_t addr, uint8_t reg, uint16_t val);
			void readRegister(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t cnt);
			uint8_t touchDetected();
			bool getSample (Finger *touchData);
			void transformTouchData(int32_t& x, int32_t& y);
			void delayMs(__IO uint32_t ms);
		
			TransformFuncPtr   transformFunc;
			TransformationType linearTransform;
		  int16_t            displayWidth;    ///< Store width of display
			int16_t            displayHeight;   ///< Store height of display
	};
}

#endif /* SSD2541TOUCHCONTROLLER_HPP */
