#ifndef LCDCONTROLLERS6D04D2_HPP
#define LCDCONTROLLERS6D04D2_HPP

#include "STM32F4FMC.hpp"
#include <platform/hal/ST/mcu/stm32f4x9/STM32F4HAL.hpp>

#ifdef __cplusplus
extern "C"{
#endif
	/**
		* C functions
		*/
	#include "stm32f4xx.h"
	
#ifdef __cplusplus
}
#endif

/*
 * ***************************************************************************************
 * Display Command Set (DCS) is a set of common commands for controlling
 * the display device in compliance with the DSI standard. Each command
 * is an eight-bit code with 00h to AFh assigned to the User Command Set
 * and all other codes assigned to the Manufacturer Command Set.
 * DCS defined here with prefix DCS_ and MCS with MCS_
 * ***************************************************************************************
 */
#define DCS_NOP                 0x00		//no operation. This is an empty command
#define DCS_SWRESET             0x01    //soft reset
#define DCS_RDNUMED							0x05		//read number of errors on DSI
#define DCS_RDDPM               0x0A    //Read display power mode
#define DCS_RDDMADCTL           0x0B    //Read display MADCTL for column address order, RGB/BGR order etc
#define DCS_RDDCOLMOD           0x0C    //Read display display pixel format
#define DCS_RDDIM               0x0D    //Read display image mode
#define DCS_RDDSM               0x0E    //Read display signal mode
#define DCS_RDDSDR              0x0F    //Read display self-diagnostic result
#define DCS_SLPIN               0x10		//sleep in command to enter the min. power mode
#define DCS_SLPOUT              0x11		//sleep out command to turn off sleep mode
#define DCS_NORON               0x13    //Normal display mode on
#define DCS_INVOFF              0x20		//Display inversion off
#define DCS_INVON               0x21		//Display inversion on
#define DCS_DISPOFF             0x28		//Display off with a blank page inserted. No change of frame memory content
#define DCS_DISPON              0x29		//Display on to recover from Display Off Mode

#define DCS_CASET	          0x2A		//Column Address Set to define area of frame memory where MPU can access
																		//Parameters are inclusive, that means from SC[15:0] = 0 to EC[15:0] = 239
																		//for the panel resolution of 240 pixels in width
#define DCS_PASET           0x2B		//Page Address Set, similar to DCS_CASET, this command for SP[15:0] and EP[15:0]

#define DCS_RAMWR           0x2C    //command to transfer data from MPU to frame memory
																		//It is important to note that when this command is accepted, the column &
																		//page registers are reset to the Start Column/Start Page defined in DCS_CASET &
																		//DCS_PASET

#define DCS_RAMRD           0x2E		//This command is used to transfer data from display's frame memory back to MPU.
																		//When this command is accepted, the column & page registers are reset to the Start
																		//Column.Start Page defined in DCS_CASET & DCS_PASET

#define DCS_TEOFF           0x34		//Tearing effect line OFF

#define DCS_TEON            0x35		//Tearing effect line ON

#define DCS_MADCTL         	0x36    //memory access control for frame buffer scanning direction etc
#define DCS_IDMOFF      		0x38		//This command is used to recover from idle mode on
#define DCS_IDMON		        0x39		//This command is used to enter into idle mode to reduce to 8 color depth
#define DCS_COLMOD          0x3A    //interface pixel format set
#define DCS_RAMWRC          0x3C    //This command continues writing to memory after DCS_RAMWR. When this command
																		//is accepted, no column/page registers are reset. This command is good for
																		//writing data to frame memory in block for speed optimization
#define DCS_RAMRDC			    0x3E		//Counterpart for DCS_RAMWRC to "block read" from frame memory to MPU
#define DCS_RDDDBS					0xA1		//Returns supplier ID
#define DCS_RDDDBC					0xA8		//continue reading supplier's ID after DCS_RDDDBS has been interrupted

//SSD2805 specific registers
#define MCS_CFGR				0xB7	//configuration register
#define MCS_VCR					0xB8	//VC control register to set virtual channel
#define MCS_PCR					0xB9	//PLL control register
#define MCS_PLCR				0xBA	//PLL config register
#define MCS_CCR					0xBB	//Clock control register

#define MCS_PSCR1				0xBC	//Packet size control register 1, specifies the total number of data bytes (in byte)
															//to be transmitted by SSD2805 in the next operation.
#define MCS_PSCR2				0xBD	//Packet size control register 2
#define MCS_PSCR3				0xBE	//Packet size threshold, min=2, max=0x400

#define MCS_TR					0xD6	//Test register

/** GPIO pins
* PD2		------> RESET
* PD7		------> Backlight enable
* PA9		------> TE for vsync synchronization
*/
#define LCD_RST_BASE	GPIOD
#define LCD_RST_PIN		GPIO_Pin_2
#define RCC_AHB1Periph_LCD_RST	RCC_AHB1Periph_GPIOD

#ifdef RELEASE_3
	#define LCD_TE_BASE									GPIOB
	#define LCD_TE_PIN									GPIO_Pin_4
	#define LCD_TE_EXTI_Line						EXTI_Line4											//this is to match GPIOB4, level shifted by a mosfet from 1.8V -> 3.3V
	#define LCD_TE_IRQn									EXTI4_IRQn											//this is to match GPIOB4 interrupt handler number
	#define LCD_EXTI_IRQHandler					EXTI4_IRQHandler								
	#define RCC_AHB1Periph_TE					 	RCC_AHB1Periph_GPIOB
	#define LCD_TE_PortSourceGPIO				EXTI_PortSourceGPIOB
	#define LCD_TE_PinSource						EXTI_PinSource4
#else
	#define LCD_TE_BASE									GPIOA
	#define LCD_TE_PIN									GPIO_Pin_9
	#define LCD_TE_EXTI_Line						EXTI_Line9												//this is to match GPIOA9, level shifted by a mosfet from 1.8V -> 3.3V
	#define LCD_TE_IRQn									EXTI9_5_IRQn											//this is to match GPIOA9 interrupt handler number to line 5 to 9
	#define LCD_EXTI_IRQHandler					EXTI9_5_IRQHandler								
	#define RCC_AHB1Periph_TE					 	RCC_AHB1Periph_GPIOA
	#define LCD_TE_PortSourceGPIO				EXTI_PortSourceGPIOA
	#define LCD_TE_PinSource						EXTI_PinSource9
#endif	//RELEASE_3

#define LCD_BACKLIGHT_BASE	GPIOD
#define LCD_BACKLIGHT_PIN		GPIO_Pin_7
#define RCC_AHB1Periph_LCD_BACKLIGHT	RCC_AHB1Periph_GPIOD

#ifdef RELEASE_3
#define LCD_VDDIOCTRL_BASE	GPIOC
#define LCD_VDDIOCTRL_PIN		GPIO_Pin_8
#define RCC_AHB1Periph_LCD_VDDIOCTRL	RCC_AHB1Periph_GPIOC
#endif

#ifndef FRAME_BUFFER_START
	#define FRAME_BUFFER_START	(uint32_t)(0xd0000000)	//SDRAM address location on STM32F429I-disco
	//#define FRAME_BUFFER_START	(uint32_t)(0x20013dfc)
#endif

/**
* @class LCDController
* @brief Interface for LCD controller S6D04D2 via SSD2805 MIPI Bridge
* 			 Access mode in 8080 16-bit. Inherent from SMT32F4HAL is required to make touch controller work somehow.
*/
class LCDController	: public STM32F4HAL
	{
public :
		LCDController(touchgfx::DMA_Interface& dma, touchgfx::LCD& display, touchgfx::TouchController& tc, uint16_t width, uint16_t height): 
		STM32F4HAL(dma, display, tc, width, height)
		{
			LCDController::init();	//initialize fmc in 16-bit 8080 mode & SSD2805 & S6D04D2
		}
		virtual void init();
		void hardwareReset(bool state);
		void softwareReset();
		void backlightSet(uint8_t intensity);
		void sleepIn();
		void sleepOut();
		void fillRectDirect(const Rect& rect, uint16_t color);
		virtual void flushFrameBuffer();
		virtual void flushFrameBuffer(const Rect& rect);
	
		virtual void disableInterrupts();
		virtual void enableInterrupts();
		virtual void configureInterrupts();
		virtual void enableLCDControllerInterrupt();
protected:
		virtual uint16_t* getTFTFrameBuffer() const;
		virtual void setTFTFrameBuffer(uint16_t* adr)
		{
			//nothing to do for 8080 LCD interface
		}
private:
		void writeReg(uint8_t reg, uint16_t data);
		void writeTDCSize(uint32_t byteSize);
		void delayMs(__IO uint32_t ms);
	};
#endif
