#ifndef HW_LIB_ST7796_H
#define HW_LIB_ST7796_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>

/**
  * @brief  ST7796 Registers
  */
#define ST7796_NOP                          0x00U  /* No Operation: NOP                           */
#define ST7796_SW_RESET                     0x01U  /* Software reset: SWRESET                     */
#define ST7796_READ_ID                      0x04U  /* Read Display ID: RDDID                      */
#define ST7796_READ_STATUS                  0x09U  /* Read Display Statu: RDDST                   */
#define ST7796_READ_POWER_MODE              0x0AU  /* Read Display Power: RDDPM                   */
#define ST7796_READ_MADCTL                  0x0BU  /* Read Display: RDDMADCTL                     */
#define ST7796_READ_PIXEL_FORMAT            0x0CU  /* Read Display Pixel: RDDCOLMOD               */
#define ST7796_READ_IMAGE_MODE              0x0DU  /* Read Display Image: RDDIM                   */
#define ST7796_READ_SIGNAL_MODE             0x0EU  /* Read Display Signal: RDDSM                  */
#define ST7796_SLEEP_IN                     0x10U  /* Sleep in & booster off: SLPIN               */
#define ST7796_SLEEP_OUT                    0x11U  /* Sleep out & booster on: SLPOUT              */
#define ST7796_PARTIAL_DISPLAY_ON           0x12U  /* Partial mode on: PTLON                      */
#define ST7796_NORMAL_DISPLAY_OFF           0x13U  /* Partial off (Normal): NORON                 */
#define ST7796_DISPLAY_INVERSION_OFF        0x20U  /* Display inversion off: INVOFF               */
#define ST7796_DISPLAY_INVERSION_ON         0x21U  /* Display inversion on: INVON                 */
#define ST7796_GAMMA_SET                    0x26U  /* Gamma curve select: GAMSET                  */
#define ST7796_DISPLAY_OFF                  0x28U  /* Display off: DISPOFF                        */
#define ST7796_DISPLAY_ON                   0x29U  /* Display on: DISPON                          */
#define ST7796_CASET                        0x2AU  /* Column address set: CASET                   */
#define ST7796_RASET                        0x2BU  /* Row address set: RASET                      */
#define ST7796_WRITE_RAM                    0x2CU  /* Memory write: RAMWR                         */
#define ST7796_RGBSET                       0x2DU  /* LUT for 4k,65k,262k color: RGBSET           */
#define ST7796_READ_RAM                     0x2EU  /* Memory read: RAMRD                          */
#define ST7796_PTLAR                        0x30U  /* Partial start/end address set: PTLAR        */
#define ST7796_TE_LINE_OFF                  0x34U  /* Tearing effect line off: TEOFF              */
#define ST7796_TE_LINE_ON                   0x35U  /* Tearing effect mode set & on: TEON          */
#define ST7796_MADCTL                       0x36U  /* Memory data access control: MADCTL          */
#define ST7796_IDLE_MODE_OFF                0x38U  /* Idle mode off: IDMOFF                       */
#define ST7796_IDLE_MODE_ON                 0x39U  /* Idle mode on: IDMON                         */
#define ST7796_COLOR_MODE                   0x3AU  /* Interface pixel format: COLMOD              */
#define ST7796_FRAME_RATE_CTRL1             0xB1U  /* In normal mode (Full colors): FRMCTR1       */
#define ST7796_FRAME_RATE_CTRL2             0xB2U  /* In Idle mode (8-colors): FRMCTR2            */
#define ST7796_FRAME_RATE_CTRL3             0xB3U  /* In partial mode + Full colors: FRMCTR3      */
#define ST7796_FRAME_INVERSION_CTRL         0xB4U  /* Display inversion control: INVCTR           */
#define ST7796_DISPLAY_SETTING              0xB6U  /* Display function setting                    */
#define ST7796_ENTRY_MODE_SET               0xB7U  /* Entry Mode Set: EM                          */
#define ST7796_PWR_CTRL1                    0xC0U  /* Power control setting: PWCTR1               */
#define ST7796_PWR_CTRL2                    0xC1U  /* Power control setting: PWCTR2               */
#define ST7796_PWR_CTRL3                    0xC2U  /* In normal mode (Full colors): PWCTR3        */
#define ST7796_PWR_CTRL4                    0xC3U  /* In Idle mode (8-colors): PWCTR4             */
#define ST7796_PWR_CTRL5                    0xC4U  /* In partial mode + Full colors: PWCTR5       */
#define ST7796_VCOMH_VCOML_CTRL1            0xC5U  /* VCOM control 1: VMCTR1                      */
#define ST7796_VMOF_CTRL                    0xC7U  /* Set VCOM offset control: VMOFCTR            */
#define ST7796_WRID2                        0xD1U  /* Set LCM version code: WRID2                 */
#define ST7796_WRID3                        0xD2U  /* Customer Project code: WRID3                */
#define ST7796_NV_CTRL1                     0xD9U  /* NVM control status: NVCTR1                  */
#define ST7796_READ_ID1                     0xDAU  /* Read ID1: RDID1                             */
#define ST7796_READ_ID2                     0xDBU  /* Read ID2: RDID2                             */
#define ST7796_READ_ID3                     0xDCU  /* Read ID3: RDID3                             */
#define ST7796_READ_ID4                     0xD3U  /* Read ID4: RDID4                             */
#define ST7796_NV_CTRL2                     0xDEU  /* NVM Read Command: NVCTR2                    */
#define ST7796_NV_CTRL3                     0xDFU  /* NVM Write Command: NVCTR3                   */
#define ST7796_PV_GAMMA_CTRL                0xE0U  /* Set Gamma adjustment (+ polarity): GAMCTRP1 */
#define ST7796_NV_GAMMA_CTRL                0xE1U  /* Set Gamma adjustment (- polarity): GAMCTRN1 */
#define ST7796_DISPLAY_OUTPUT_CTRL_ADJUST   0xE8U  /* Display Output Ctrl Adjust: DOCA            */
#define ST7796_EXT_CTRL                     0xF0U  /* Extension command control                   */
#define ST7796_PWR_CTRL6                    0xFCU  /* In partial mode + Idle mode: PWCTR6         */
#define ST7796_VCOM4_LEVEL                  0xFFU  /* VCOM 4 level control                        */

/**
  * @brief  ST7735 ID
  */
#define  ST7796_ID              0xACU

/**
  * @brief  ST7735 4.0 inch Size
  */
#define  ST7796_4_0_WIDTH           320U
#define  ST7796_4_0_HEIGHT          480U

/**
 *  @brief LCD_OrientationTypeDef
 *  Possible values of Display Orientation
 */
#define ST7796_ORIENTATION_PORTRAIT 0x00U /* 液晶屏纵向选择 */
#define ST7796_ORIENTATION_PORTRAIT_ROT180 0x01U /* 纵向旋转 180° 方向 液晶屏选择 */
#define ST7796_ORIENTATION_LANDSCAPE 0x02U /* 液晶屏横向选择 */
#define ST7796_ORIENTATION_LANDSCAPE_ROT180 0x03U /* 横向旋转 180° 方向 液晶屏选择 */

/**
 *  @brief  Possible values of pixel data format (ie color coding)
 */
#define ST7796_FORMAT_RBG444                0x03U /* Pixel format chosen is RGB444 : 12 bpp */
#define ST7796_FORMAT_RBG565                0x55U /* Pixel format chosen is RGB565 : 16 bpp */
#define ST7796_FORMAT_RBG666                0x06U /* Pixel format chosen is RGB666 : 18 bpp */
#define ST7796_FORMAT_DEFAULT               ST7796_FORMAT_RBG565


/**
 *  @brief  LCD RGB or BGR
 */
#define ST7796_RGB                                                        0x00U
#define ST7796_BGR                                                        0x08U

#define ST7796_X_OFFSET 0
#define ST7796_Y_OFFSET 0

#define ST7796_DIR_MASK(dir) st7796dirTab[dir][0] | ST7796_BGR

const uint8_t st7796dirTab[4][2] =
        {
                {0x40U, 0xC0U}, /* 液晶屏纵向选择 */
                {0x80U, 0x00U}, /* 液晶屏纵向旋转 180° 方向选择 */
                {0x20U, 0x60U}, /* 液晶屏横向选择 */
                {0xE0U, 0xA0U}, /* 液晶屏横向旋转 180° 方向选择 */
        };

const uint8_t st7796initcmd[] = {
        0x81, ST7796_SW_RESET,
        0x81, ST7796_SW_RESET,
        2, ST7796_SLEEP_OUT, 0x00,
        2, ST7796_EXT_CTRL, 0xc3,
        2, ST7796_EXT_CTRL, 0x96,
        2, ST7796_MADCTL, 0x48,
        2, ST7796_COLOR_MODE, ST7796_FORMAT_DEFAULT,
        2, ST7796_FRAME_INVERSION_CTRL, 0x01,
        2, ST7796_ENTRY_MODE_SET, 0xC6,
        9, ST7796_DISPLAY_OUTPUT_CTRL_ADJUST, 0x40, 0x8a, 0x00, 0x00, 0x29, 0x19, 0xa5, 0x33,
        2, ST7796_PWR_CTRL2, 0x06,
        2, ST7796_PWR_CTRL3, 0xa7,
        2, ST7796_VCOMH_VCOML_CTRL1, 0x18,
        15, ST7796_PV_GAMMA_CTRL, 0xf0, 0x09, 0x0b, 0x06, 0x04, 0x15, 0x2f, 0x54, 0x42, 0x3c, 0x17, 0x14, 0x18, 0x1b,
        15, ST7796_NV_GAMMA_CTRL, 0xf0, 0x09, 0x0b, 0x06, 0x04, 0x03, 0x2d, 0x43, 0x42, 0x3b, 0x16, 0x14, 0x17, 0x1b,
        2, ST7796_EXT_CTRL, 0x3c,
        2, ST7796_EXT_CTRL, 0x69,
        0x81, ST7796_DISPLAY_INVERSION_ON,
        0x81, ST7796_DISPLAY_ON,
        0x00
};

#define ST7796_ReadID(dev, id) do{\
    if (dev->id==ST7796_ID){                 \
    uint8_t tmp[3] = {};\
    dev->writeReg(ST7796_READ_ID1,&tmp[0],1);\
    dev->writeReg(ST7796_READ_ID2,&tmp[1],1);\
    dev->writeReg(ST7796_READ_ID3,&tmp[2],1);\
    id = ((uint32_t) tmp[2]) << 0 | ((uint32_t) tmp[1]) << 8 | ((uint32_t) tmp[0]) << 16;}\
}while(0)

#define ST7796_SetDir(dev, dir)  do{\
    if (dev->id==ST7796_ID){                             \
    if((dir == ST7796_ORIENTATION_PORTRAIT) || (dir == ST7796_ORIENTATION_PORTRAIT_ROT180))\
    {\
        dev->width  = ST7796_4_0_WIDTH;\
        dev->height = ST7796_4_0_HEIGHT;\
    }\
    else\
    {\
        dev->width  =  ST7796_4_0_HEIGHT;\
        dev->height =  ST7796_4_0_WIDTH;\
    }                             \
    tmp = ST7796_DIR_MASK(dir);\
    dev->writeReg(ST7796_MADCTL,&tmp,1);}               \
}while(0)

#define ST7796_OFFSET(dev, x, y) do{ \
    if (dev->id==ST7735_ID){\
    if (dev->dir <= LONGITUDINAL_180) { \
        x += ST7796_X_OFFSET;\
        y += ST7796_Y_OFFSET;\
    } else {\
        x += ST7796_Y_OFFSET;\
        y += ST7796_X_OFFSET;\
    }\
    }\
}while(0)

#define ST7796_ReadRam(dev, rec) do{ \
    if(dev->id==ST7796_ID){                    \
        dev->readReg(ST7796_READ_RAM,&tmp,1);\
        dev->recvData(&tmp,1);\
        dev->recvData(&pixel_lsb,1);\
        dev->recvData(&pixel_msb,1);\
        rec.color=((uint32_t)(pixel_lsb)) + ((uint32_t)(pixel_msb) << 8);\
    }\
}while(0)
#ifdef __cplusplus
}
#endif
#endif //HW_LIB_ST7796_H
