#include "lcd_2inch.h"
#include "lcd_gui.h"
#include "tim.h"
extern SPI_HandleTypeDef hspi1; 
extern void SPI_SetSpeed(SPI_HandleTypeDef *hspi, uint32_t Prescaler);
_lcd_dev lcddev;
static void Spi_write_byte_noneCS(uint8_t data)
	{
    HAL_SPI_Transmit(&hspi1, &data, 1, 10);
}

/**
 * @brief  Reset the LCD module by toggling the reset pin.
 *         The reset sequence: high -> low -> high with delays.
 */
static void Lcd_Reset(void)
{
    LCD_RST_1;
    HAL_Delay(50);
    LCD_RST_0;
    HAL_Delay(50);
    LCD_RST_1;
    HAL_Delay(150);
}
void BlackLight_SetValue(uint16_t value)
{		
    TIM_OC_InitTypeDef sConfigOC={0};
	
    sConfigOC.OCMode = TIM_OCMODE_PWM1;
    sConfigOC.Pulse = value;
    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
    sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
    HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2);
    HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);  
}
/**
 * @brief  Send a command byte to the LCD via SPI.
 * @param  data: Command byte to send.
 * @note   Sets DC low to indicate command, CS low during transfer.
 */
void Spi_write_cmd(uint8_t data)
{
    LCD_CS_0;
    LCD_DC_0;
    Spi_write_byte_noneCS(data);
    LCD_CS_1;
}

/**
 * @brief  Send a data byte to the LCD via SPI.
 * @param  data: Data byte to send.
 * @note   Sets DC high to indicate data, CS low during transfer.
 */
void Spi_write_data(uint8_t data)
{
    LCD_CS_0;
    LCD_DC_1;
    Spi_write_byte_noneCS(data);
    LCD_CS_1;
}

/**
 * @brief  Send a 16-bit word (color data) to the LCD via SPI.
 * @param  data: 16-bit data to send (MSB first).
 * @note   Splits into two bytes and transmits consecutively.
 */
void Spi_write_word(uint16_t data)
{
    uint8_t buf[2];
    buf[0] = data >> 8;
    buf[1] = data & 0xFF;
    
    LCD_CS_0;
    LCD_DC_1;
    HAL_SPI_Transmit(&hspi1, buf, 2, 10);
    LCD_CS_1;
}

/**
 * @brief  Initialize the LCD controller with the required command sequence.
 *         Sets up pixel format, memory access control, and display on.
 * @note   Also clears the screen to white after initialization.
 */
void Lcd_Init(void)
{
    Lcd_Reset();
	
		HAL_Delay(100);
		Spi_write_cmd(0x01); 
		HAL_Delay(150);      
    Spi_write_cmd(0x11); 
	  HAL_Delay(120); // Sleep Out

    Spi_write_cmd(0x3A); 
	  Spi_write_data(0x05); // 16bit/pixel

    Spi_write_cmd(0x36); 
	  Spi_write_data(0x70); //(0x00, 0xC0, 0x70, 0xA0)

    Spi_write_cmd(0xB2); 
	  Spi_write_data(0x0C); 
	  Spi_write_data(0x0C); 
	  Spi_write_data(0x00); 
	  Spi_write_data(0x33);
   	Spi_write_data(0x33);
    Spi_write_cmd(0xB7); 
	  Spi_write_data(0x35);
    Spi_write_cmd(0xBB); 
		Spi_write_data(0x32);
    Spi_write_cmd(0xC2); 
		Spi_write_data(0x01);
    Spi_write_cmd(0xC3); 
		Spi_write_data(0x15);
    Spi_write_cmd(0xC4); 
		Spi_write_data(0x20);
    Spi_write_cmd(0xC6); 
		Spi_write_data(0x0F);
    Spi_write_cmd(0xD0); 
		Spi_write_data(0xA4); 
		Spi_write_data(0xA1);

    Spi_write_cmd(0x21); // Display Inversion On
    Spi_write_cmd(0x29); // Display On

    lcddev.width = LCD_H;  // 320
    lcddev.height = LCD_W; // 240
    lcddev.wramcmd = 0x2C;
    lcddev.setxcmd = 0x2A;
    lcddev.setycmd = 0x2B;
    BlackLight_SetValue(800);   //Turn on the backlight
    

}

/**
 * @brief  Set the drawing cursor to a specific coordinate.
 * @param  x: X coordinate (0..width-1)
 * @param  y: Y coordinate (0..height-1)
 * @note   Sends column and page address commands before data write.
 */
void LCD_Set_Cursor(uint16_t x, uint16_t y) {
    LCD_CS_0; 

    LCD_DC_0; Spi_write_byte_noneCS(lcddev.setxcmd);
    LCD_DC_1;
    Spi_write_byte_noneCS(x >> 8);
    Spi_write_byte_noneCS(x & 0xFF);
    Spi_write_byte_noneCS((lcddev.width - 1) >> 8);
    Spi_write_byte_noneCS((lcddev.width - 1) & 0xFF);

    LCD_DC_0; Spi_write_byte_noneCS(lcddev.setycmd);
    LCD_DC_1;
    Spi_write_byte_noneCS(y >> 8);
    Spi_write_byte_noneCS(y & 0xFF);
    Spi_write_byte_noneCS((lcddev.height - 1) >> 8);
    Spi_write_byte_noneCS((lcddev.height - 1) & 0xFF);

    LCD_DC_0; Spi_write_byte_noneCS(lcddev.wramcmd);
    LCD_CS_1;
}

void Draw_Point(uint16_t x, uint16_t y, uint16_t color)
{
    LCD_Set_Cursor(x, y);
    Spi_write_word(color);
}


void LCD_Clear(uint16_t color)
{

    uint16_t i, j;

    Spi_write_cmd(lcddev.setxcmd); 
	  Spi_write_data(0); 
	  Spi_write_data(0); 
	  Spi_write_data((lcddev.width-1)>>8); 
	  Spi_write_data((lcddev.width-1)&0xFF);
    Spi_write_cmd(lcddev.setycmd); 
	  Spi_write_data(0); 
	  Spi_write_data(0); 
	  Spi_write_data((lcddev.height-1)>>8); 
	  Spi_write_data((lcddev.height-1)&0xFF);
    Spi_write_cmd(lcddev.wramcmd);

    LCD_CS_0;
    LCD_DC_1;
    
    uint8_t line_buff[2] = {color >> 8, color & 0xFF};
    for(i = 0; i < lcddev.width; i++)
    {
        for(j = 0; j < lcddev.height; j++)
        {
             HAL_SPI_Transmit(&hspi1, line_buff, 2, 10);
        }
    }
    LCD_CS_1;
}
