#include "bsp_lcd_ili9225.h"
#include "main.h"

static void bsp_lcd_write_cmd(uint8_t cmd)
{
	HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_RESET);
	HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET);
	HAL_SPI_Transmit(&hspi1, &cmd, 1, 200);
	HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET);
}

static void bsp_lcd_write_register(uint8_t addr, uint16_t reg_val)
{
	HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_RESET);
	HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET);
	HAL_SPI_Transmit(&hspi1, &addr, 1, 200);
	
	HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_SET);
	uint8_t temp = reg_val >> 8;
	HAL_SPI_Transmit(&hspi1, &temp, 1, 200);
	temp = reg_val;
	HAL_SPI_Transmit(&hspi1, &temp, 1, 200);
	
	HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET);
}

static void bsp_lcd_reset(void)
{
	HAL_GPIO_WritePin(LCD_RST_GPIO_Port, LCD_RST_Pin, GPIO_PIN_RESET);
	HAL_Delay(20);
	HAL_GPIO_WritePin(LCD_RST_GPIO_Port, LCD_RST_Pin, GPIO_PIN_SET);
	HAL_Delay(10);
}

void bsp_lcd_init(void)
{
	bsp_lcd_reset();
	
	// LCD Init For 2.2inch LCD Panel with ILI9225.	
	bsp_lcd_write_register(0x10, 0x0000); // Set SAP, DSTB, STB
	bsp_lcd_write_register(0x11, 0x0000); // Set APON, PON, AON, VCI1EN, VC
	bsp_lcd_write_register(0x12, 0x0000); // Set BT, DC1, DC2, DC3
	bsp_lcd_write_register(0x13, 0x0000); // Set GVDD
	bsp_lcd_write_register(0x14, 0x0000); // Set VCOMH/VCOML voltage
	HAL_Delay(20);

	// Please follow this power on sequence
	bsp_lcd_write_register(0x11, 0x0018); // Set APON, PON, AON, VCI1EN, VC
	bsp_lcd_write_register(0x12, 0x1121); // Set BT, DC1, DC2, DC3
	bsp_lcd_write_register(0x13, 0x0063); // Set GVDD
	bsp_lcd_write_register(0x14, 0x3961); // Set VCOMH/VCOML voltage
	bsp_lcd_write_register(0x10, 0x0800); // Set SAP, DSTB, STB
	HAL_Delay(10);
	bsp_lcd_write_register(0x11, 0x1038); // Set APON, PON, AON, VCI1EN, VC
	HAL_Delay(30);

	bsp_lcd_write_register(0x02, 0x0100); // set 1 line inversion

	// R01H:SM=0, GS=0, SS=1 (for details, See the datasheet of ILI9225)
	bsp_lcd_write_register(0x01, 0x011C); // set the display line number and display direction
	//R01H:SM=0, GS=1, SS=0 (for details,See the datasheet of ILI9225)
	//bsp_lcd_write_register(0x01, 0x021C); // set the display line number and display direction
	
	bsp_lcd_write_register(0x03, 0x1030); // set GRAM write direction.

	bsp_lcd_write_register(0x07, 0x0000); // Display off
	bsp_lcd_write_register(0x08, 0x0808); // set the back porch and front porch
	bsp_lcd_write_register(0x0B, 0x1100); // set the clocks number per line
	bsp_lcd_write_register(0x0C, 0x0000); // CPU interface
	bsp_lcd_write_register(0x0F, 0x0501); // Set Osc
	bsp_lcd_write_register(0x15, 0x0020); // Set VCI recycling
	bsp_lcd_write_register(0x20, 0x0000); // RAM Address
	bsp_lcd_write_register(0x21, 0x0000); // RAM Address
	
	//------------------------ Set GRAM area --------------------------------//
	bsp_lcd_write_register(0x30, 0x0000); 
	bsp_lcd_write_register(0x31, 0x00DB); 
	bsp_lcd_write_register(0x32, 0x0000); 
	bsp_lcd_write_register(0x33, 0x0000); 
	bsp_lcd_write_register(0x34, 0x00DB); 
	bsp_lcd_write_register(0x35, 0x0000); 
	bsp_lcd_write_register(0x36, 0x00AF); 
	bsp_lcd_write_register(0x37, 0x0000); 
	bsp_lcd_write_register(0x38, 0x00DB); 
	bsp_lcd_write_register(0x39, 0x0000);
	
	// ---------- Adjust the Gamma 2.2 Curve -------------------//
	bsp_lcd_write_register(0x50, 0x0603); 
	bsp_lcd_write_register(0x51, 0x080D); 
	bsp_lcd_write_register(0x52, 0x0D0C); 
	bsp_lcd_write_register(0x53, 0x0205); 
	bsp_lcd_write_register(0x54, 0x040A); 
	bsp_lcd_write_register(0x55, 0x0703); 
	bsp_lcd_write_register(0x56, 0x0300); 
	bsp_lcd_write_register(0x57, 0x0400); 
	bsp_lcd_write_register(0x58, 0x0B00); 
	bsp_lcd_write_register(0x59, 0x0017); 

	bsp_lcd_write_register(0x0F, 0x0701); // Vertical RAM Address Position
	bsp_lcd_write_register(0x07, 0x0012); // Vertical RAM Address Position
	HAL_Delay(50); // Delay 50 ms
	bsp_lcd_write_register(0x07, 0x1017); // Vertical RAM Address Position
}

void bsp_lcd_set_region(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1)
{
	bsp_lcd_write_register(0x36, x1);
	bsp_lcd_write_register(0x37, x0);
	bsp_lcd_write_register(0x38, y1);
	bsp_lcd_write_register(0x39, y0); // Set coordinate of left-top corner and right-bottom corner of the box
	
	bsp_lcd_write_register(0x20, x0);
	bsp_lcd_write_register(0x21, y0); // Set position of the pointer
}

/*
void bsp_lcd_fill(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint16_t color)
{
	bsp_lcd_set_region(x0, y0, x1, y1);
	bsp_lcd_write_cmd(0x22); // Start to write pixel data
	
	HAL_SPI_DeInit(&hspi1);
	hspi1.Init.DataSize = SPI_DATASIZE_16BIT;
	HAL_SPI_Init(&hspi1); // switch SPI to 16bit mode

	HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_SET);
	HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET);
	
	for (uint16_t i = 0; i < (y1 - y0 + 1) * (x1 - x0 + 1); i ++) {
		HAL_SPI_Transmit(&hspi1, (uint8_t*)&color, 1, 200);
	}
	
	HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET);
	
	HAL_SPI_DeInit(&hspi1);
	hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
	HAL_SPI_Init(&hspi1);
}

void bsp_lcd_draw_bitmap(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, const uint16_t *color)
{
	bsp_lcd_set_region(x0, y0, x1, y1);
	bsp_lcd_write_cmd(0x22); // Start to write pixel data
	
	HAL_SPI_DeInit(&hspi1);
	hspi1.Init.DataSize = SPI_DATASIZE_16BIT;
	HAL_SPI_Init(&hspi1); // switch SPI to 16bit mode

	HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_SET);
	HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET);
	
	for (uint16_t i = 0; i < (y1 - y0 + 1) * (x1 - x0 + 1); i ++) {
		HAL_SPI_Transmit(&hspi1, (uint8_t*)&color[i], 1, 200);
	}
	
	HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET);
	
	HAL_SPI_DeInit(&hspi1);
	hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
	HAL_SPI_Init(&hspi1);
}
*/

void bsp_lcd_fill(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint16_t color)
{
	bsp_lcd_set_region(x0, y0, x1, y1);
  
	bsp_lcd_write_cmd(0x22); // Start to write pixel data
	
	HAL_SPI_DeInit(&hspi1);
	hspi1.Init.DataSize = SPI_DATASIZE_16BIT;
	HAL_SPI_Init(&hspi1); // switch SPI to 16bit mode
  
  HAL_DMA_DeInit(&hdma_spi1_tx);
  hdma_spi1_tx.Init.MemInc = DMA_MINC_DISABLE;
  HAL_DMA_Init(&hdma_spi1_tx);
  
	HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_SET);
	HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET);
	
  HAL_SPI_Transmit_DMA(&hspi1, (uint8_t*)&color, (y1 - y0 + 1) * (x1 - x0 + 1));
  HAL_DMA_PollForTransfer(&hdma_spi1_tx, HAL_DMA_FULL_TRANSFER, 200);
	
	HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET);
	
  HAL_DMA_DeInit(&hdma_spi1_tx);
  hdma_spi1_tx.Init.MemInc = DMA_MINC_ENABLE;
  HAL_DMA_Init(&hdma_spi1_tx);
  
	HAL_SPI_DeInit(&hspi1);
	hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
	HAL_SPI_Init(&hspi1);
}

void bsp_lcd_draw_bitmap(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, const uint16_t *color)
{
	bsp_lcd_set_region(x0, y0, x1, y1);
  
	bsp_lcd_write_cmd(0x22); // Start to write pixel data
	
	HAL_SPI_DeInit(&hspi1);
	hspi1.Init.DataSize = SPI_DATASIZE_16BIT;
	HAL_SPI_Init(&hspi1); // switch SPI to 16bit mode

	HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_SET);
	HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET);
	
  HAL_SPI_Transmit_DMA(&hspi1, (uint8_t*)color, (y1 - y0 + 1) * (x1 - x0 + 1));
  HAL_DMA_PollForTransfer(&hdma_spi1_tx, HAL_DMA_FULL_TRANSFER, 200);
	
	HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET);
	
	HAL_SPI_DeInit(&hspi1);
	hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
	HAL_SPI_Init(&hspi1);
}
