/*
 * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 * 
 * ST7796 TFT LCD Display Driver
 * 
 * ==============================================================================
 * ABOUT THE ST7796 DISPLAY CONTROLLER
 * ==============================================================================
 * 
 * The ST7796 is a single-chip controller/driver for 262K-color, graphic type
 * TFT-LCD displays. It consists of 960 source line and 480 gate line driving
 * circuits. This chip is capable of connecting directly to an external 
 * microprocessor via an 8-bit/9-bit/16-bit/18-bit parallel interface or 
 * Serial Peripheral Interface (SPI).
 * 
 * Key Features:
 * - Resolution: Up to 480RGB x 320 dots
 * - Display Colors: 262K colors (RGB565 format - 16 bits per pixel)
 * - Interface: 4-wire SPI (used in this driver)
 * - Framebuffer: Internal RAM that holds the pixel data (480x320x16bit = 300KB)
 * - Power: 2.5V~3.3V I/O voltage, with internal regulators for LCD drivers
 * 
 * ==============================================================================
 * SPI COMMUNICATION PROTOCOL
 * ==============================================================================
 * 
 * The ST7796 uses a 4-wire SPI interface:
 * 1. SCK (Serial Clock) - Clock signal from MCU
 * 2. MOSI/SDA (Master Out Slave In) - Data signal from MCU to display
 * 3. CS (Chip Select) - Active LOW, selects the display
 * 4. DC (Data/Command) - HIGH for data, LOW for commands
 * 
 * Additional pins:
 * 5. RST (Reset) - Hardware reset, active LOW
 * 6. BL (Backlight) - LED backlight control, HIGH for ON
 * 
 * Communication sequence:
 * 1. Pull CS LOW to select the display
 * 2. Set DC LOW for command, HIGH for data
 * 3. Clock out 8 bits on MOSI while toggling SCK
 * 4. Pull CS HIGH to deselect
 * 
 * ==============================================================================
 * RGB565 COLOR FORMAT
 * ==============================================================================
 * 
 * RGB565 is a 16-bit color format:
 * - Red:   5 bits (bits 15-11) - 32 levels
 * - Green: 6 bits (bits 10-5)  - 64 levels (human eye more sensitive to green)
 * - Blue:  5 bits (bits 4-0)   - 32 levels
 * 
 * Color encoding: RRRR RGGG GGGB BBBB
 * Example: 0xF800 = Red, 0x07E0 = Green, 0x001F = Blue, 0xFFFF = White
 * 
 * ==============================================================================
 * DISPLAY ORIENTATION (MADCTL)
 * ==============================================================================
 * 
 * MADCTL (0x36) controls memory access and display rotation:
 * - MY (bit 7): Row Address Order (flip vertical)
 * - MX (bit 6): Column Address Order (flip horizontal)
 * - MV (bit 5): Row/Column Exchange (swap X/Y for rotation)
 * - ML (bit 4): Vertical Refresh Order
 * - BGR (bit 3): RGB or BGR color order
 * 
 * Current configuration: 0xE0 (MY=1, MX=1, MV=1)
 * This provides landscape mode (480x320) with correct orientation.
 * 
 * ==============================================================================
 * MISSING FEATURES & POTENTIAL IMPROVEMENTS
 * ==============================================================================
 * 
 * Currently NOT implemented (but supported by hardware):
 * 
 * 1. HARDWARE SCROLLING:
 *    - Vertical Scrolling Definition (VSCRDEF) and Vertical Scroll Start Address
 *    - Could enable smooth scrolling without redrawing entire screen
 *    - Useful for: text scrolling, game backgrounds, UI animations
 * 
 * 2. PARTIAL DISPLAY MODE:
 *    - Show only a portion of the display (save power)
 *    - Commands: PTLON (0x12), PTLAR (0x30)
 * 
 * 3. IDLE MODE:
 *    - Reduced color depth (8 colors) for power saving
 *    - Commands: IDMON (0x38), IDMOFF (0x39)
 * 
 * 4. DISPLAY INVERSION:
 *    - Currently set to INVOFF, but INVON available
 *    - Some displays look better with inversion ON
 * 
 * 5. TEAR EFFECT CONTROL:
 *    - TE (Tearing Effect) pin synchronization
 *    - Prevents tearing during screen updates
 *    - Commands: TEON (0x35), TEOFF (0x34)
 * 
 * 6. GAMMA CORRECTION:
 *    - Fine-tune color accuracy and contrast
 *    - Commands: PGC (0xE0), NGC (0xE1)
 * 
 * 7. BRIGHTNESS/CONTRAST CONTROL:
 *    - Software brightness via WRCABCMB command
 *    - Currently only hardware backlight control
 * 
 * 8. POWER CONTROL:
 *    - Deep sleep modes
 *    - Display ON/OFF without re-initialization
 *    - Commands: SLPIN (0x10), SLPOUT (0x11)
 * 
 * 9. DMA SUPPORT:
 *    - Use DMA for SPI transfers instead of blocking writes
 *    - Would significantly improve performance for large updates
 * 
 * 10. DOUBLE BUFFERING:
 *     - Currently single-buffered (direct to framebuffer)
 *     - Could implement software double buffer for tear-free updates
 * 
 * 11. IMAGE/BITMAP LOADING:
 *     - Load images from SD card or flash
 *     - BMP, PNG decoders
 * 
 * 12. TEXT RENDERING:
 *     - Font library for text display
 *     - Variable font sizes
 * 
 * 13. HARDWARE ACCELERATED FEATURES:
 *     - Some displays have built-in shape drawing (not ST7796)
 *     - Window clipping for faster partial updates
 * 
 * Performance Optimization Ideas:
 * - Increase SPI speed beyond 80MHz (try 100-125MHz)
 * - Use DMA for background transfers
 * - Implement dirty rectangle tracking (only update changed areas)
 * - Cache frequently drawn graphics
 * 
 * ==============================================================================
 */

#ifndef _PICO_ST7796_H_
#define _PICO_ST7796_H_

#include "hardware/spi.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief Configuration structure for ST7796 display
 * 
 * This structure holds all the pin mappings and SPI interface configuration
 * needed to communicate with the display. All GPIO pins should be valid
 * Raspberry Pi Pico pins, except gpio_cs which can be -1 to disable CS control.
 */
struct st7796_config {
    spi_inst_t* spi;      // SPI instance (spi0 or spi1)
    uint gpio_din;        // MOSI/SDA pin (data out from MCU)
    uint gpio_clk;        // SCK pin (clock)
    int gpio_cs;          // CS pin (chip select, -1 to disable)
    uint gpio_dc;         // DC pin (data/command select)
    uint gpio_rst;        // RST pin (hardware reset)
    uint gpio_bl;         // Backlight pin (LED control)
};

/**
 * @brief Initialize the ST7796 display
 * 
 * This function performs the complete initialization sequence:
 * 1. Configures all GPIO pins (SPI, CS, DC, RST, BL)
 * 2. Initializes SPI at 80-100 MHz
 * 3. Performs hardware reset
 * 4. Sends initialization commands to the display
 * 5. Sets up RGB565 color mode and landscape orientation
 * 6. Turns on backlight and display
 * 
 * @param config Pointer to st7796_config structure with pin mappings
 * @param width Display width in pixels (typically 480 for landscape)
 * @param height Display height in pixels (typically 320 for landscape)
 * 
 * Note: After this call, display is ready but blank. Call st7796_fill()
 * to clear with a color, or start drawing primitives.
 */
void st7796_init(const struct st7796_config *config, uint16_t width, uint16_t height);

/**
 * @brief Fill entire display with a single color
 * 
 * This is the fastest way to clear the screen or set a background.
 * Uses optimized 512-byte buffering for maximum SPI throughput.
 * 
 * @param color RGB565 color value (e.g., 0x0000=black, 0xFFFF=white)
 * 
 * Performance: ~15ms at 80MHz SPI for full 480x320 screen
 */
void st7796_fill(uint16_t color);

/**
 * @brief Write a single pixel at current cursor position
 * 
 * Writes one pixel without changing the drawing window. Use after
 * st7796_set_cursor() to position the write location. Rarely used
 * directly - most applications use st7796_draw_pixel() instead.
 * 
 * @param color RGB565 color value
 */
void st7796_put(uint16_t color);

/**
 * @brief Set cursor position for subsequent writes
 * 
 * Sets the drawing window starting at (x, y) and extending to the
 * bottom-right of the display. Subsequent calls to st7796_put()
 * will write pixels starting from this position.
 * 
 * @param x X coordinate (0 to width-1)
 * @param y Y coordinate (0 to height-1)
 */
void st7796_set_cursor(uint16_t x, uint16_t y);

/**
 * @brief Write multiple pixels at current cursor position
 * 
 * Writes an array of RGB565 color values starting at the current
 * cursor position. Advances the cursor automatically.
 * 
 * @param data Pointer to array of RGB565 color values
 * @param len Number of pixels to write
 * 
 * Note: Less efficient than fill_rect for solid colors due to
 * per-pixel conversion overhead.
 */
void st7796_write(const uint16_t *data, size_t len);

/**
 * @brief Draw a single pixel at specified coordinates
 * 
 * Draws one pixel at (x, y) with the specified color. This function
 * sets up a 1x1 drawing window, so it's slower than batch operations.
 * Use fill_rect() or other primitives when possible.
 * 
 * @param x X coordinate (0 to width-1)
 * @param y Y coordinate (0 to height-1)
 * @param color RGB565 color value
 * 
 * Performance: ~100-200 pixels/second due to window setup overhead
 */
void st7796_draw_pixel(uint16_t x, uint16_t y, uint16_t color);

/**
 * @brief Draw a rectangle outline
 * 
 * Draws a hollow rectangle with 1-pixel thick borders. Implemented
 * as 4 calls to fill_rect() for efficiency.
 * 
 * @param x Top-left X coordinate
 * @param y Top-left Y coordinate
 * @param w Width in pixels
 * @param h Height in pixels
 * @param color RGB565 color value
 */
void st7796_draw_rect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color);

/**
 * @brief Draw a filled rectangle
 * 
 * Draws a solid rectangle. This is one of the fastest drawing operations
 * due to optimized 512-byte buffering.
 * 
 * @param x Top-left X coordinate
 * @param y Top-left Y coordinate
 * @param w Width in pixels
 * @param h Height in pixels
 * @param color RGB565 color value
 * 
 * Performance: Can draw full screen in ~15ms at 80MHz SPI
 */
void st7796_fill_rect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color);

/**
 * @brief Draw a circle outline
 * 
 * Draws a hollow circle using the midpoint circle algorithm (Bresenham).
 * Draws 8 symmetric points per iteration for efficiency.
 * 
 * @param x0 Center X coordinate
 * @param y0 Center Y coordinate
 * @param r Radius in pixels
 * @param color RGB565 color value
 * 
 * Note: Implemented as individual pixel draws, so performance is
 * O(r) with ~100-200 pixels/second throughput.
 */
void st7796_draw_circle(uint16_t x0, uint16_t y0, uint16_t r, uint16_t color);

/**
 * @brief Draw a filled circle
 * 
 * Draws a solid circle using midpoint circle algorithm with horizontal
 * line fills. Much faster than drawing individual pixels.
 * 
 * @param x0 Center X coordinate
 * @param y0 Center Y coordinate
 * @param r Radius in pixels
 * @param color RGB565 color value
 * 
 * Performance: Better than draw_circle due to fill_rect optimization
 */
void st7796_fill_circle(uint16_t x0, uint16_t y0, uint16_t r, uint16_t color);

/**
 * @brief Draw a line between two points
 * 
 * Draws a line using Bresenham's line algorithm. Works for any angle.
 * 
 * @param x0 Start point X coordinate
 * @param y0 Start point Y coordinate
 * @param x1 End point X coordinate
 * @param y1 End point Y coordinate
 * @param color RGB565 color value
 * 
 * Performance: O(max(dx, dy)) with ~100-200 pixels/second throughput
 */
void st7796_draw_line(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color);

/**
 * @brief Draw a triangle outline
 * 
 * Draws a hollow triangle by connecting three points with lines.
 * 
 * @param x0 First vertex X coordinate
 * @param y0 First vertex Y coordinate
 * @param x1 Second vertex X coordinate
 * @param y1 Second vertex Y coordinate
 * @param x2 Third vertex X coordinate
 * @param y2 Third vertex Y coordinate
 * @param color RGB565 color value
 */
void st7796_draw_triangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color);

/**
 * @brief Draw a filled triangle
 * 
 * Draws a solid triangle using scanline fill algorithm. Sorts vertices
 * by Y coordinate and fills horizontal spans.
 * 
 * @param x0 First vertex X coordinate
 * @param y0 First vertex Y coordinate
 * @param x1 Second vertex X coordinate
 * @param y1 Second vertex Y coordinate
 * @param x2 Third vertex X coordinate
 * @param y2 Third vertex Y coordinate
 * @param color RGB565 color value
 * 
 * Performance: Better than draw_triangle due to fill_rect optimization
 */
void st7796_fill_triangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color);

#ifdef __cplusplus
}
#endif

#endif
