/* -------------------------------------------------------------------------
 * 文件名: lcd.c
 * 模块职责:
 *   提供 LCD 显存（framebuffer）的最小抽象接口：
 *   1) 初始化显存
 *   2) 单像素写入
 *   3) 单像素读取
 *   4) 获取显存首地址（供上层批量处理）
 *
 * 设计说明:
 *   - 当前实现是“内存模拟 LCD”：用一段线性数组表示屏幕像素。
 *   - 坐标系采用左上角原点：
 *       x: [0, LCD_SIZE_X-1]，向右递增
 *       y: [0, LCD_SIZE_Y-1]，向下递增
 *   - 像素索引映射关系：
 *       index = y * LCD_LINE_SIZE + x
 *   - 越界策略：
 *       写操作：直接忽略（安全返回）
 *       读操作：返回 0（黑色/默认值）
 * ------------------------------------------------------------------------- */
#include "lcd.h"
#include <string.h>

/* LCD 显存数组（模块私有）：
 * - static 限定作用域在本翻译单元内，避免外部直接访问破坏封装
 * - 每个元素对应一个像素点，大小为 LCD_DISPLAYMEMORYSIZE
 */
static uint8_t lcd_memory[LCD_DISPLAYMEMORYSIZE];

/* -------------------------------------------------------------------------
 * 函数名: Lcd_Init
 * 功能:
 *   初始化 LCD 显存，将所有像素清为 0（黑色背景）。
 *
 * 实现细节:
 *   - 使用 memset 一次性清零整个显存，时间复杂度 O(N)。
 *   - sizeof(lcd_memory) 保证长度与数组实际大小一致，避免硬编码。
 *
 * 输入参数:
 *   无
 * 返回值:
 *   无
 * ------------------------------------------------------------------------- */
void Lcd_Init(void)
{
    memset(lcd_memory, 0, sizeof(lcd_memory));
}

/* -------------------------------------------------------------------------
 * 函数名: Lcd_SetPixel
 * 功能:
 *   设置指定坐标 (x, y) 的像素值。
 *
 * 参数:
 *   x     - 像素横坐标
 *   y     - 像素纵坐标
 *   color - 要写入的颜色值（单字节）
 *
 * 边界处理:
 *   - 若 x 或 y 越界，函数返回 LCD_ERR_OUT_OF_RANGE，不做任何写入。
 *   - 这样可防止数组越界访问导致内存破坏，并允许上层检测错误。
 *
 * 说明:
 *   - 本函数对颜色值做白名单校验，仅允许 LCD_FONT / LCD_BACK。
 * 返回值:
 *   - LCD_OK (0): 写入成功
 *   - LCD_ERR_OUT_OF_RANGE (-1): 坐标越界
 *   - LCD_ERR_INVALID_COLOR (-2): 非法颜色值
 * ------------------------------------------------------------------------- */
int8_t Lcd_SetPixel(uint16_t x, uint16_t y, uint8_t color)
{
    /* 坐标越界保护：超出屏幕范围返回错误码 */
    if (x >= LCD_SIZE_X || y >= LCD_SIZE_Y)
    {
        return LCD_ERR_OUT_OF_RANGE;
    }

    /* 颜色值白名单：仅允许前景色与背景色 */
    if (color != LCD_FONT && color != LCD_BACK)
    {
        return LCD_ERR_INVALID_COLOR;
    }

    /* 二维坐标转线性索引并写入像素 */
    lcd_memory[y * LCD_LINE_SIZE + x] = color;
    return LCD_OK;
}

/* -------------------------------------------------------------------------
 * 函数名: Lcd_GetPixel
 * 功能:
 *   读取指定坐标 (x, y) 的像素值。
 *
 * 参数:
 *   x - 像素横坐标
 *   y - 像素纵坐标
 *
 * 返回值:
 *   - 0~255: 合法坐标对应的像素值
 *   - LCD_ERR_OUT_OF_RANGE (-1): 坐标越界
 *
 * 设计考虑:
 *   - 使用错误码让调用方可显式区分“黑色像素(0)”与“越界读取(-1)”。
 *   - 与 Lcd_SetPixel 的错误码风格保持一致，便于统一测试和上层处理。
 * ------------------------------------------------------------------------- */
int16_t Lcd_GetPixel(uint16_t x, uint16_t y)
{
    /* 越界读取保护：返回错误码 */
    if (x >= LCD_SIZE_X || y >= LCD_SIZE_Y)
    {
        return LCD_ERR_OUT_OF_RANGE;
    }

    /* 二维坐标转线性索引并返回像素值 */
    return lcd_memory[y * LCD_LINE_SIZE + x];
}

/* -------------------------------------------------------------------------
 * 函数名: Lcd_GetFrameBuffer
 * 功能:
 *   返回 LCD 显存首地址，供上层进行批量处理（如反显、整屏传输等）。
 *
 * 返回值:
 *   uint8_t* - 指向 lcd_memory[0] 的指针
 *
 * 使用约束:
 *   - 调用方应保证访问范围不超过 LCD_DISPLAYMEMORYSIZE。
 *   - 该接口暴露底层内存，适合高性能场景，但需调用方自律维护边界。
 * ------------------------------------------------------------------------- */
uint8_t* Lcd_GetFrameBuffer(void)
{
    return lcd_memory;
}
