#include "st7735.h"
#include "spi.h"
#include "gpio.h"
#include "timer.h"

/*
Pin‑by‑Pin Meaning (ST7735S SPI Module)
GND: Ground
VCC: Power Supply (3.3V)
SCL: Serial Clock (SPI CLK)
SDA: Serial Data (SPI MOSI)
RES: Reset (Active Low)
DC: Data/Command Control (High for Data, Low for Command)   
CS: Chip Select (Active Low)
BLK: Backlight Control (Optional - 3.3V PWM for brightness control)
*/


/***********Local functions Prototypes*******************/
void LCD_ST7735_Cmd(LCD_Driver_t* lcd, uint8_t c);
void LCD_ST7735_CmdBuf(LCD_Driver_t* lcd, uint8_t *cmdBuf, uint8_t *rxDataBuf, uint32_t len);
void LCD_ST7735_Data(LCD_Driver_t* lcd, uint8_t d);
void LCD_ST7735_DataBuf(LCD_Driver_t* lcd, uint8_t *txDataBuf, uint8_t *rxDataBuf, uint32_t len);
//*************************************************************************************
// PUBLIC FUNCTION IMPLEMENTATIONS
//*************************************************************************************

void LCD_ST7735_HAL_Init(LCD_Driver_t* lcd, SPI_TypeDef* spi, 
                        GPIO_TypeDef* cs_Port, uint16_t cs_Pin,
                        GPIO_TypeDef* rst_Port, uint16_t rst_Pin,
                        GPIO_TypeDef* dc_Port, uint16_t dc_Pin)
{
    // 1. Assign the passed SPI and GPIO parameters to the 'lcd' struct members.
    // 2. Initialize the CS, RST, and DC pins as Output pins using your GPIO driver.
    // 3. Set CS High and RST High as their default 'idle' states.
}

void LCD_ST7735_Reset(LCD_Driver_t* lcd)
{
    // 1. Pull the RST pin LOW.
    // 2. Delay for 10ms (Use your Timer_Delay_ms function).
    // 3. Pull the RST pin HIGH.
}

void LCD_ST7735_InitSequence(LCD_Driver_t* lcd, LCD_Rotation_t rot, TIM_TypeDef* _timer)
{
    // 1. Assign the timer to the lcd struct and initialize the ticker.
    // 2. Execute a Hardware Reset using LCD_ST7735_Reset().
    // 3. Delay 120ms.
    // 4. Send Command 0x11 (Sleep Out).
    // 5. Delay 120ms.
    // 6. Send Command 0x36 (Memory Data Access Control), then Data 'rot'.
    // 7. Send Command 0x3A (Interface Pixel Format), then Data 0x05 (16-bit color).
    // 8. Send Command 0x29 (Display ON).
}

void LCD_ST7735_SetAddressWindow(LCD_Driver_t* lcd, uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1)
{
    // 1. Send Command 0x2A (Column Address Set).
    // 2. Send 4 Data bytes: 0x00, x0, 0x00, x1.
    // 3. Send Command 0x2B (Row Address Set).
    // 4. Send 4 Data bytes: 0x00, y0, 0x00, y1.
    // 5. Send Command 0x2C (Memory Write) to prepare the LCD for pixel streaming.
}

void LCD_ST7735_FillScreen(LCD_Driver_t* lcd, uint16_t color)
{
    // 1. Set the address window to the full size of the screen (0, 0, WIDTH-1, HEIGHT-1).
    // 2. Prepare an 8-bit buffer with the 16-bit color (High byte first, then Low byte).
    // 3. Loop through every pixel (Total = WIDTH * HEIGHT).
    // 4. In each iteration, call LCD_ST7735_DataBuf to send your 2-byte color buffer.
}

void LCD_ST7735_DrawPixel(LCD_Driver_t* lcd, uint8_t x, uint8_t y, uint16_t color)
{
    // 1. Set the address window to a single pixel at coordinates (x, y).
    // 2. Split the 16-bit color into a 2-byte buffer (High byte then Low byte).
    // 3. Send that 2-byte buffer using LCD_ST7735_DataBuf.
}

void LCD_ST7735_DrawChar(LCD_Driver_t* lcd, uint8_t x, uint8_t y, char c, uint16_t color, uint16_t bg)
{
// 1. BOUNDARY CHECK: 
    // The font array only contains characters from ASCII 32 (' ') to ASCII 127 ('~').
    // If 'c' is outside this range, change 'c' to a default character (e.g., '?').

    // 2. GET THE FONT DATA:
    // Create a pointer to the specific character's 5-byte array.
    // Example: const uint8_t *bitmap = font5x7[c - 32];
    // (We subtract 32 because ASCII 32 is at index 0 in our array).

    // 3. OUTER LOOP: Iterate through the 5 columns (Width)
    // Create a 'for' loop using a variable 'col' from 0 to 4.
    // {
        // a. Grab the current column's byte from the bitmap: 
        //    uint8_t line = bitmap[col];
        
        // b. INNER LOOP: Iterate through the 8 bits of this column (Height)
        //    Create a 'for' loop using a variable 'row' from 0 to 7.
        //    {
            // i. Check if the lowest bit is a 1:  if (line & 0x01)
            //    - If TRUE: Call LCD_ST7735_DrawPixel at (x + col, y + row) with 'color'.
            //    - If FALSE: Call LCD_ST7735_DrawPixel at (x + col, y + row) with 'bg'.
            
            // ii. Shift the 'line' variable right by 1 bit (line >>= 1) 
            //     so the next bit is ready for the next iteration of the inner loop.
        //    }
    // }

    // 4. CHARACTER SPACING:
    // After the outer loop finishes, the character is drawn! 
    // But we need a 1-pixel gap between this character and the next one.
    // Create one final loop from row = 0 to 7, and draw a vertical line of pixels
    // at x-coordinate (x + 5) using the background color 'bg'.
}

void LCD_ST7735_DrawString(LCD_Driver_t* lcd, uint8_t x, uint8_t y, const char *str, uint16_t color, uint16_t bg)
{
    // 1. While the current character in the string is not the null terminator ('\0'):
    // 2. Call LCD_ST7735_DrawChar at the current (x, y).
    // 3. Increment 'x' by 6 pixels (5 for char width + 1 for spacing).
    // 4. Move to the next character pointer in the string.
}

/******************Private functions**********************/
void LCD_ST7735_Cmd(LCD_Driver_t* lcd, uint8_t c) 
{
    // 1. Set the Data/Command (DC) pin LOW to indicate a Command is being sent.
    // 2. Set Chip Select (CS) LOW to talk to the LCD.
    // 3. Use your SPI driver to transmit the single byte 'c'.
    // 4. Set Chip Select (CS) HIGH to finish the communication.
}

//-------------------------------------------------------------------------------------
void LCD_ST7735_CmdBuf(LCD_Driver_t* lcd, uint8_t *cmdBuf, uint8_t *rxDataBuf, uint32_t len)
{
    // 1. Set the Data/Command (DC) pin LOW to indicate a Command is being sent.
    // 2. Set Chip Select (CS) LOW to talk to the LCD.
    // 3. Use your SPI driver's "TransmitReceive" function to send the 'txDataBuf'  of length 'len'. 
    // 4. Set Chip Select (CS) HIGH to finish the communication.
}
//-------------------------------------------------------------------------------------
void LCD_ST7735_Data(LCD_Driver_t* lcd, uint8_t d) 
{
    // 1. Set the Data/Command (DC) pin HIGH to indicate Data is being sent.
    // 2. Set Chip Select (CS) LOW to talk to the LCD.
    // 3. Use your SPI driver to transmit the single byte 'd'.
    // 4. Set Chip Select (CS) HIGH to finish the communication.
}
//-------------------------------------------------------------------------------------
void LCD_ST7735_DataBuf(LCD_Driver_t* lcd, uint8_t *txDataBuf, uint8_t *rxDataBuf, uint32_t len)
{
    // 1. Set the Data/Command (DC) pin HIGH.
    // 2. Set Chip Select (CS) LOW.
    // 3. Use your SPI driver's "TransmitReceive" function to send the 'txDataBuf'  of length 'len'. 
    // 4. Set Chip Select (CS) HIGH.
}


//-------------------------------------------------------------------------------------

