#ifndef HW_LIB_TFT_H
#define HW_LIB_TFT_H
#ifdef __cplusplus
extern "C" {
#endif

#include <stdbool.h>
#include "stdint.h"
#include "stdlib.h"

/*功能配置区*/
//#define REFRESH_CALL_ENABLE 1 //使用DMA或者整体刷新函数
#define HZK_FONT              //使用HZK 12/16 字体 tools下可自由生成
#define UTF8_TO_UNICODE       //启用UTF8转换显示
//#define LVGL_FONT           //启用LVGL字体

/*启用设备配置区*/
#define TFT_ST7735 0x5CU
#define TFT_ST7796 0x1E74U

typedef struct TFT_Dev TFT_T;

/**
 * @brief   写寄存器数据函数指针类型
 * @param   reg: [输入]     寄存器地址
 * @param   pdata: [输入]   数据缓冲区指针
 * @param   ldata: [输入]   数据长度
 * @return  uint8_t         返回状态
 * @example write_status = TFT_WRITE_REG(reg_addr, data_buffer, data_length);
 **/
typedef uint8_t (*TFT_WRITE_REG_t)(uint8_t reg, uint8_t *pdata, size_t ldata);

/**
 * @brief   读寄存器数据函数指针类型
 * @param   reg: [输入]     寄存器地址
 * @param   pdata: [输出]   数据缓冲区指针
 * @param   ldata: [输入]   数据长度
 * @return  uint8_t         返回状态
 * @example read_status = TFT_READ_REG(reg_addr, data_buffer, data_length);
 **/
typedef uint8_t (*TFT_READ_REG_t)(uint8_t reg, uint8_t *pdata, size_t ldata);

/**
 * @brief   发送数据函数指针类型
 * @param   data: [输入]    数据缓冲区指针
 * @param   len: [输入]     数据长度
 * @return  uint8_t         返回状态
 * @example send_status = TFT_SEND_DATA(data_buffer, data_length);
 **/
typedef uint8_t (*TFT_SEND_DATA_t)(uint8_t *data, size_t len);

/**
 * @brief   接收数据函数指针类型
 * @param   data: [输出]    数据缓冲区指针
 * @param   len: [输入]     数据长度
 * @return  uint8_t         返回状态
 * @example recv_status = TFT_RECV_DATA(data_buffer, data_length);
 **/
typedef uint8_t (*TFT_RECV_DATA_t)(uint8_t *data, size_t len);

/**
 * @brief   TFT背光控制函数指针类型
 * @param   data: [输入] 数据
 * @return  uint8_t 返回值
 */
typedef uint8_t (*TFT_BLACKLIGHT_t)(uint8_t data);

/**
 * @brief   TFT延迟函数指针类型
 * @param   ms: [输入] 毫秒延迟
 * @return  uint8_t 返回值
 */
typedef void (*TFT_DELAY_t)(uint32_t ms);

#if REFRESH_CALL_ENABLE

/**
 * @brief   TFT 刷新函数指针类型
 */
typedef void (*TFT_REFRESH_t)(TFT_T *dev);

#endif

/**
* @brief   TFT状态枚举
*/
typedef enum {
    TFT_ERROR,/**< 错误状态 */
    TFT_IDLE, /**< 空闲状态 */
    TFT_WRITE, /**< 写入状态 */
    TFT_REFRESH, /**< 刷新状态 */
} TFT_STATE_T;

typedef enum {
    LONGITUDINAL = 0x01U,/* 液晶屏纵向选择 */
    LONGITUDINAL_180,/* 液晶屏纵向旋转 180° 方向选择 */
    HORIZONTAL,/* 液晶屏横向选择 */
    HORIZONTAL_180,/* 液晶屏横向旋转 180° 方向选择 */
} TFT_DIR_T;

typedef union TFT_Color {
    uint16_t color;
    uint16_t u16;
    uint8_t u8[2];
} TFT_Color_t;

/**
 * @brief   TFT设备结构体
 */
struct TFT_Dev {
    uint32_t id;                   /**< TFT设备ID */
    uint8_t setxcmd;               /**< 设置X坐标命令 */
    uint8_t setycmd;               /**< 设置Y坐标命令 */
    uint8_t wgramcmd;              /**< 写GRAM命令 */
    TFT_DIR_T dir: 4;              /**< 显示方向,占4位 */
    TFT_STATE_T state: 4;          /**< TFT状态,占4位 */
    uint16_t width;                /**< 显示宽度 */
    uint16_t height;               /**< 显示高度 */
    TFT_WRITE_REG_t writeReg;      /**< 写寄存器函数指针 */
    TFT_READ_REG_t readReg;        /**< 读寄存器函数指针 */
    TFT_SEND_DATA_t sendData;      /**< 发送数据函数指针 */
    TFT_RECV_DATA_t recvData;      /**< 接收数据函数指针 */
    TFT_BLACKLIGHT_t blacklight;   /**< TFT背光控制函数指针 */
    TFT_DELAY_t delay;             /**< TFT延迟函数指针类型 */
#if REFRESH_CALL_ENABLE
    TFT_REFRESH_t call;            /**< TFT刷新函数指针,仅在REFRESH_CALL_ENABLE宏定义启用时有效 */
#endif
};

/**
 * @brief   初始化TFT显示屏
 * @param   dev: [输入] TFT设备结构体指针
 * @return  void
 * @example TFT_Init(&myTFT);
**/
void TFT_Init(TFT_T *dev);

/**
 * @brief   读取TFT显示屏ID
 * @param   dev: [输入] TFT设备结构体
 * @return  uint32_t ID值
 * @example TFT_ReadID(myTFT);
**/
uint32_t TFT_ReadID(TFT_T *dev);

/**
 * @brief   设置TFT显示方向
 * @param   dev: [输入] TFT设备结构体指针
 * @param   dir: [输入] 显示方向
 * @return  void
 * @example TFT_SetDir(&myTFT, TFT_DIR_LANDSCAPE);
**/
void TFT_SetDir(TFT_T *dev, TFT_DIR_T dir);

/**
 * @brief   设置TFT显示当前像素位置
 * @param   dev: [输入] TFT设备结构体指针
 * @param   x: [输入] X坐标
 * @param   y: [输入] Y坐标
 * @return  void
 * @example TFT_SetCur(&myTFT, 100, 50);
**/
void TFT_SetCur(TFT_T *dev, uint16_t x, uint16_t y);

/**
 * @brief   设置前景色和背景色
 * @param   pcolor: [输入] 前景色
 * @param   bcolor: [输入] 背景色
 * @return  void
 * @example TFT_SetColor(0xFFFF, 0x0000);
**/
void TFT_SetColor(uint16_t pcolor, uint16_t bcolor);

/**
 * @brief   设置TFT显示窗口
 * @param   dev: [输入] TFT设备结构体指针
 * @param   x: [输入] 窗口起始X坐标
 * @param   y: [输入] 窗口起始Y坐标
 * @param   width: [输入] 窗口宽度
 * @param   height: [输入] 窗口高度
 * @return  void
 * @example TFT_SetWindow(&myTFT, 10, 10, 100, 80);
**/
void TFT_SetWindow(TFT_T *dev, uint16_t x, uint16_t y, uint16_t width, uint16_t height);

/**
 * @brief   获取指定像素的颜色值
 * @param   dev: [输入] TFT设备结构体指针
 * @param   x: [输入] X坐标
 * @param   y: [输入] Y坐标
 * @return  TFT_Color_t 像素颜色值
 * @example TFT_GetPixel(&myTFT, 20, 30);
**/
TFT_Color_t TFT_GetPixel(TFT_T *dev, uint16_t x, uint16_t y);

/**
 * @brief   设置指定像素的颜色值
 * @param   dev: [输入] TFT设备结构体指针
 * @param   x: [输入] X坐标
 * @param   y: [输入] Y坐标
 * @param   color: [输入] 要设置的颜色值
 * @return  void
 * @example TFT_SetPixel(&myTFT, 50, 60, TFT_COLOR_RED);
**/
void TFT_SetPixel(TFT_T *dev, uint16_t x, uint16_t y, TFT_Color_t color);

/**
 * @brief   设置TFT显示背光亮度
 * @param   dev: [输入] TFT设备结构体指针
 * @param   value: [输入] 背光亮度值
 * @return  void
 * @example TFT_SetBacklight(&myTFT, 50);
**/
void TFT_SetBacklight(TFT_T *dev, uint8_t value);

/**
 * @brief   在TFT显示屏上填充矩形区域
 * @param   dev: [输入] TFT设备结构体指针
 * @param   x: [输入] 矩形起始X坐标
 * @param   y: [输入] 矩形起始Y坐标
 * @param   width: [输入] 矩形宽度
 * @param   height: [输入] 矩形高度
 * @param   color: [输入] 填充颜色数组指针
 * @return  void
 * @example TFT_FillRect(&myTFT, 20, 30, 100, 80, &color_array);
**/
void TFT_FillRect(TFT_T *dev, uint16_t x, uint16_t y, uint16_t width, uint16_t height, TFT_Color_t *color);

/**
 * @brief   在TFT显示屏上填充矩形区域
 * @param   dev: [输入] TFT设备结构体指针
 * @param   x: [输入] 矩形起始X坐标
 * @param   y: [输入] 矩形起始Y坐标
 * @param   width: [输入] 矩形宽度
 * @param   height: [输入] 矩形高度
 * @param   color: [输入] 填充颜色
 * @return  void
 * @example TFT_Fill(&myTFT, 20, 30, 100, 80, TFT_COLOR_BLUE);
**/
void TFT_Fill(TFT_T *dev, uint16_t x, uint16_t y, uint16_t width, uint16_t height, TFT_Color_t color);

/**
 * @brief   在TFT显示屏上填充整个屏幕区域
 * @param   dev: [输入] TFT设备结构体指针
 * @param   color: [输入] 填充颜色
 * @return  void
 * @example TFT_FillColor(&myTFT, TFT_COLOR_WHITE);
**/
void TFT_FillColor(TFT_T *dev, TFT_Color_t color);

/**
 * @brief   在TFT显示屏上绘制直线
 * @param   dev: [输入] TFT设备结构体指针
 * @param   x1: [输入] 起始点X坐标
 * @param   y1: [输入] 起始点Y坐标
 * @param   x2: [输入] 结束点X坐标
 * @param   y2: [输入] 结束点Y坐标
 * @return  void
 * @example TFT_DrawLine(&myTFT, 10, 20, 100, 120);
**/
void TFT_DrawLine(TFT_T *dev, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);

/**
 * @brief   在TFT显示屏上绘制矩形
 * @param   dev: [输入] TFT设备结构体指针
 * @param   x1: [输入] 矩形左上角X坐标
 * @param   y1: [输入] 矩形左上角Y坐标
 * @param   x2: [输入] 矩形右下角X坐标
 * @param   y2: [输入] 矩形右下角Y坐标
 * @return  void
 * @example TFT_DrawRect(&myTFT, 10, 20, 100, 80);
**/
void TFT_DrawRect(TFT_T *dev, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);

/**
 * @brief   在TFT显示屏上绘制圆形
 * @param   dev: [输入] TFT设备结构体指针
 * @param   x: [输入] 圆心X坐标
 * @param   y: [输入] 圆心Y坐标
 * @param   r: [输入] 圆半径
 * @return  void
 * @example TFT_DrawCircle(&myTFT, 50, 50, 30);
**/
void TFT_DrawCircle(TFT_T *dev, uint16_t x, uint16_t y, uint16_t r);

void TFT_DrawArc(TFT_T *dev, uint16_t x0, uint16_t y0, uint16_t radius, int start_angle, int end_angle);

/**
 * @brief   在TFT显示屏上显示单个字符
 * @param   dev: [输入] TFT设备结构体指针
 * @param   x: [输入] 字符显示起始X坐标
 * @param   y: [输入] 字符显示起始Y坐标
 * @param   chr: [输入] 要显示的字符
 * @param   size: [输入] 字体大小
 * @param   mode: [输入] 显示方式 叠加(1)非叠加(0)
 * @return  void
 * @example TFT_ShowChar(&myTFT, 30, 40, 'A', 2);
**/
void TFT_ShowChar(TFT_T *dev, uint16_t x, uint16_t y, uint8_t chr, uint16_t size, bool mode);

/**
 * @brief   在TFT显示屏上显示字符串
 * @param   dev: [输入] TFT设备结构体指针
 * @param   x: [输入] 字符串显示起始X坐标
 * @param   y: [输入] 字符串显示起始Y坐标
 * @param   str: [输入] 要显示的字符串数组指针
 * @param   size: [输入] 字体大小
 * @param   mode: [输入] 显示方式 叠加(1)非叠加(0)
 * @return  void
 * @example TFT_ShowString(&myTFT, 20, 30, "Hello", 1);
**/
void TFT_ShowString(TFT_T *dev, uint16_t x, uint16_t y, uint8_t *str, uint16_t size, bool mode);

#ifdef HZK_FONT
/**
 * @brief   在TFT显示屏上显示中文字符串
 * @param   dev: [输入] TFT设备结构体指针
 * @param   x: [输入] 字符串显示起始X坐标
 * @param   y: [输入] 字符串显示起始Y坐标
 * @param   str: [输入] 要显示的中文字符串数组指针
 * @param   mode: [输入] 显示方式 叠加(1)非叠加(0)
 * @return  void
 * @example TFT_ShowCHString(&myTFT, 20, 30, "你好");
**/
void TFT_ShowCHString(TFT_T *dev, uint16_t x, uint16_t y, uint8_t *str, bool mode);
#endif
/**
 * @brief   在TFT显示屏上显示数字
 * @param   dev: [输入] TFT设备结构体指针
 * @param   x: [输入] 数字显示起始X坐标
 * @param   y: [输入] 数字显示起始Y坐标
 * @param   num: [输入] 要显示的数字
 * @param   len: [输入] 数字长度
 * @param   size: [输入] 字体大小
 * @return  void
 * @example TFT_ShowNum(&myTFT, 20, 30, 12345, 5, 2);
**/
void TFT_ShowNum(TFT_T *dev, uint16_t x, uint16_t y, uint32_t num, uint16_t len, uint8_t size);

/**
 * @brief   在TFT显示屏上显示图片
 * @param   dev: [输入] TFT设备结构体指针
 * @param   x0: [输入] 图片左上角X坐标
 * @param   y0: [输入] 图片左上角Y坐标
 * @param   w: [输入] 图片宽度
 * @param   h: [输入] 图片高度
 * @param   bmp: [输入] 图片数据数组指针
 * @return  void
 * @example TFT_ShowPic(&myTFT, 10, 20, 80, 60, &image_data);
**/
void TFT_ShowPic(TFT_T *dev, uint16_t x0, uint16_t y0, uint16_t w, uint16_t h, TFT_Color_t *bmp);

/**
 * @brief   在屏幕上绘制一个十字交叉线
 * @param   dev: [输入] TFT设备指针
 * @param   x: [输入] 十字交叉线中心点x坐标
 * @param   y: [输入] 十字交叉线中心点y坐标
 * @param   r: [输入] 十字交叉线长度的一半(即从中心点到横竖线的长度)
 * @return  void
 * @example TFT_DrawCross(&tft_dev, 100, 80, 5);
**/
void TFT_DrawCross(TFT_T *dev, uint16_t x, uint16_t y, uint8_t r);

/**
 * @brief   在屏幕上绘制一个X字交叉线
 * @param   dev: [输入] TFT设备指针
 * @param   x: [输入] 十字交叉线中心点x坐标
 * @param   y: [输入] 十字交叉线中心点y坐标
 * @param   r: [输入] 十字交叉线长度的一半(即从中心点到横竖线的长度)
 * @return  void
 * @example TFT_DrawCross(&tft_dev, 100, 80, 5);
**/
void TFT_DrawXCross(TFT_T *dev, uint16_t x, uint16_t y, uint8_t r);

/**
 * @brief   在屏幕上显示进度条
 * @param   dev: [输入] TFT设备指针
 * @param   x: [输入] 进度条左上角x坐标
 * @param   y: [输入] 进度条左上角y坐标
 * @param   width: [输入] 进度条宽度
 * @param   height: [输入] 进度条高度
 * @param   progress: [输入] 进度值,范围[0.0, 1.0]
 * @return  void
 * @example TFT_ShowBar(&tft_device, 10, 20, 100, 10, 0.75);
**/
void TFT_ShowBar(TFT_T *dev, uint16_t x, uint16_t y, uint16_t width, uint16_t height, float progress);

/**
 * @brief   绘制带圆角的矩形
 * @param   dev: [输入] TFT设备指针
 * @param   x: [输入] 矩形左上角x坐标
 * @param   y: [输入] 矩形左上角y坐标
 * @param   width: [输入] 矩形宽度
 * @param   height: [输入] 矩形高度
 * @param   radius: [输入] 圆角半径
 * @return  void
**/
void TFT_DrawRoundedRect(TFT_T *dev, uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t radius);

#ifdef LVGL_FONT

#include "lvgl_font.h"

/**
 * @brief   在TFT上显示字符串
 * @param   dev: [输入] TFT设备结构体指针
 * @param   font: [输入] 字体信息
 * @param   s: [输入] 要显示的字符串
 * @param   x: [输入] 字符串左上角 x 坐标
 * @param   y: [输入] 字符串左上角 y 坐标
 * @param   mode: [输入] 显示方式 叠加(1)非叠加(0)
 * @return  void
 * @example TFT_DisplayString(&oled_device, &font_arial_16, "Hello World", 10, 20,bool mode);
**/
void TFT_DisplayString(TFT_T *dev, const lv_font_t *font, uint8_t *s, uint16_t x, uint16_t y);
#endif


#define ARGB_TO_RGB565(...) \
    _ARGB_TO_RGB565_NARG(__VA_ARGS__, _ARGB_TO_RGB565_4, _ARGB_TO_RGB565_1)(__VA_ARGS__)

#define _ARGB_TO_RGB565_NARG(...) _ARGB_TO_RGB565_NARG_(__VA_ARGS__, _ARGB_TO_RGB565_RSEQ_N())
#define _ARGB_TO_RGB565_NARG_(...) _ARGB_TO_RGB565_ARG_N(__VA_ARGS__)

#define _ARGB_TO_RGB565_ARG_N(_1, _2, _3, _4, N, ...) N
#define _ARGB_TO_RGB565_RSEQ_N() 4, 3, 2, 1, 0

#define _ARGB_TO_RGB565_1(argb) (((((argb) >> 8) & 0xF800) | (((argb) >> 5) & 0x07E0) | ((argb) >> 3) & 0x001F)

#define _ARGB_TO_RGB565_4(a, r, g, b) (((((a) & 0xFF) >> 3) << 11) | ((((r) & 0xFF) >> 2) << 5) | (((g) & 0xFF) >> 3))

#ifdef __cplusplus
}
#endif
#endif //HW_LIB_TFT_H