#include "bsp_lcd_st7735s.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_data(uint8_t data)
{
  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(&hspi1, &data, 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(10);
  HAL_GPIO_WritePin(LCD_RST_GPIO_Port, LCD_RST_Pin, GPIO_PIN_SET);
  HAL_Delay(10);
}

void bsp_lcd_init(void)
{
  bsp_lcd_reset();

  bsp_lcd_write_cmd(0x11);//Sleep exit
  HAL_Delay(50);
  
  //ST7735R Frame Rate
  bsp_lcd_write_cmd(0xB1);
  bsp_lcd_write_data(0x01);
  bsp_lcd_write_data(0x2C);
  bsp_lcd_write_data(0x2D);

  bsp_lcd_write_cmd(0xB2);
  bsp_lcd_write_data(0x01);
  bsp_lcd_write_data(0x2C);
  bsp_lcd_write_data(0x2D);

  bsp_lcd_write_cmd(0xB3);
  bsp_lcd_write_data(0x01);
  bsp_lcd_write_data(0x2C);
  bsp_lcd_write_data(0x2D);
  bsp_lcd_write_data(0x01);
  bsp_lcd_write_data(0x2C);
  bsp_lcd_write_data(0x2D);

  bsp_lcd_write_cmd(0xB4); //Column inversion
  bsp_lcd_write_data(0x07);

  //ST7735R Power Sequence
  bsp_lcd_write_cmd(0xC0);
  bsp_lcd_write_data(0xA2);
  bsp_lcd_write_data(0x02);
  bsp_lcd_write_data(0x84);
  bsp_lcd_write_cmd(0xC1);
  bsp_lcd_write_data(0xC5);

  bsp_lcd_write_cmd(0xC2);
  bsp_lcd_write_data(0x0A);
  bsp_lcd_write_data(0x00);

  bsp_lcd_write_cmd(0xC3);
  bsp_lcd_write_data(0x8A);
  bsp_lcd_write_data(0x2A);
  bsp_lcd_write_cmd(0xC4);
  bsp_lcd_write_data(0x8A);
  bsp_lcd_write_data(0xEE);

  bsp_lcd_write_cmd(0xC5); //VCOM
  bsp_lcd_write_data(0x0E);

  bsp_lcd_write_cmd(0x36); //MX, MY, RGB mode
  bsp_lcd_write_data(0xC8);

  //ST7735R Gamma Sequence
  bsp_lcd_write_cmd(0xe0);
  bsp_lcd_write_data(0x0f);
  bsp_lcd_write_data(0x1a);
  bsp_lcd_write_data(0x0f);
  bsp_lcd_write_data(0x18);
  bsp_lcd_write_data(0x2f);
  bsp_lcd_write_data(0x28);
  bsp_lcd_write_data(0x20);
  bsp_lcd_write_data(0x22);
  bsp_lcd_write_data(0x1f);
  bsp_lcd_write_data(0x1b);
  bsp_lcd_write_data(0x23);
  bsp_lcd_write_data(0x37);
  bsp_lcd_write_data(0x00);
  bsp_lcd_write_data(0x07);
  bsp_lcd_write_data(0x02);
  bsp_lcd_write_data(0x10);

  bsp_lcd_write_cmd(0xe1);
  bsp_lcd_write_data(0x0f);
  bsp_lcd_write_data(0x1b);
  bsp_lcd_write_data(0x0f);
  bsp_lcd_write_data(0x17);
  bsp_lcd_write_data(0x33);
  bsp_lcd_write_data(0x2c);
  bsp_lcd_write_data(0x29);
  bsp_lcd_write_data(0x2e);
  bsp_lcd_write_data(0x30);
  bsp_lcd_write_data(0x30);
  bsp_lcd_write_data(0x39);
  bsp_lcd_write_data(0x3f);
  bsp_lcd_write_data(0x00);
  bsp_lcd_write_data(0x07);
  bsp_lcd_write_data(0x03);
  bsp_lcd_write_data(0x10);

  bsp_lcd_write_cmd(0x2a);
  bsp_lcd_write_data(0x00);
  bsp_lcd_write_data(0x00);
  bsp_lcd_write_data(0x00);
  bsp_lcd_write_data(0x7f);

  bsp_lcd_write_cmd(0x2b);
  bsp_lcd_write_data(0x00);
  bsp_lcd_write_data(0x00);
  bsp_lcd_write_data(0x00);
  bsp_lcd_write_data(0x9f);

  bsp_lcd_write_cmd(0xF0); //Enable test command
  bsp_lcd_write_data(0x01);
  bsp_lcd_write_cmd(0xF6); //Disable ram power save mode
  bsp_lcd_write_data(0x00);

  bsp_lcd_write_cmd(0x3A); //65k mode
  bsp_lcd_write_data(0x05);
  bsp_lcd_write_cmd(0x29);//Display on

  bsp_lcd_write_cmd(0x36);
  bsp_lcd_write_data(0xC8); //竖屏
}

void bsp_lcd_set_region(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1)
{
  y0 += 32; y1 += 32; //纵向偏移32像素

  bsp_lcd_write_cmd(0x2A);
  bsp_lcd_write_data(x0 >> 8);
  bsp_lcd_write_data(x0 & 0xFF);
  bsp_lcd_write_data(x1 >> 8);
  bsp_lcd_write_data(x1 & 0xFF);

  bsp_lcd_write_cmd(0x2B);
  bsp_lcd_write_data(y0 >> 8);
  bsp_lcd_write_data(y0 & 0xFF);
  bsp_lcd_write_data(y1 >> 8);
  bsp_lcd_write_data(y1 & 0xFF);

	bsp_lcd_write_cmd(0x2C);
}

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);

  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);

  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);
}
