123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831 |
- /*
- * Copyright (c) 2006-2025, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2025-05-23 godmial Refactor to conform to RT-Thread coding style.
- */
- #include <board.h>
- #include "gd32f4xx.h"
- #include "gd32f4xx_tli.h"
- #include "drv_lcd.h"
- #include "font.h"
- #if defined(__CC_ARM) || defined(__ARMCC_VERSION)
- /* Keil MDK Compiler */
- uint16_t ltdc_lcd_framebuf0[800][480] __attribute__((at(LCD_FRAME_BUF_ADDR)));
- #elif defined(__GNUC__)
- /* GCC Compiler (used by RT-Thread) */
- uint16_t ltdc_lcd_framebuf0[10][10];
- #endif
- static void tli_gpio_config(void);
- static void tli_config(void);
- static void ipa_config(void);
- static void lcd_disp_en_config(void);
- static void lcd_disp_off(void);
- static void lcd_disp_on(void);
- /**
- * @brief Configure and initialize the LCD display.
- *
- * @note This function enables display power, initializes TLI GPIO and IPA,
- * and sets up TLI and its layer configuration.
- *
- * @param None
- *
- * @return None
- *
- * @warning Should be called during system initialization phase.
- */
- void lcd_disp_config(void)
- {
- lcd_disp_en_config();
- lcd_disp_off();
- /* configure the GPIO of TLI */
- tli_gpio_config();
- lcd_disp_on();
- tli_config();
- tli_layer_enable(LAYER0);
- tli_reload_config(TLI_FRAME_BLANK_RELOAD_EN);
- tli_enable();
- ipa_config();
- }
- /**
- * @brief Initialize the TLI peripheral and layer configuration.
- *
- * @note This function sets up the TLI clock, background color, timing parameters,
- * and layer 0 settings including framebuffer and blending configuration.
- *
- * @param None
- *
- * @return None
- *
- * @warning Must be called after clock and GPIO initialization.
- */
- static void tli_config(void)
- {
- tli_parameter_struct tli_init_struct;
- tli_layer_parameter_struct tli_layer_init_struct;
- rcu_periph_clock_enable(RCU_TLI);
- tli_gpio_config();
- /* configure PLLSAI to generate TLI clock */
- // if(ERROR == rcu_pllsai_config(216, 2, 3)){
- if (ERROR == rcu_pllsai_config(192, 2, 3))
- {
- while (1);
- }
- rcu_tli_clock_div_config(RCU_PLLSAIR_DIV2);
- rcu_osci_on(RCU_PLLSAI_CK);
- if (ERROR == rcu_osci_stab_wait(RCU_PLLSAI_CK))
- {
- while (1);
- }
- /* configure TLI parameter struct */
- tli_init_struct.signalpolarity_hs = TLI_HSYN_ACTLIVE_LOW;
- tli_init_struct.signalpolarity_vs = TLI_VSYN_ACTLIVE_LOW;
- tli_init_struct.signalpolarity_de = TLI_DE_ACTLIVE_LOW;
- tli_init_struct.signalpolarity_pixelck = TLI_PIXEL_CLOCK_TLI;
- /* LCD display timing configuration */
- tli_init_struct.synpsz_hpsz = HORIZONTAL_SYNCHRONOUS_PULSE - 1;
- tli_init_struct.synpsz_vpsz = VERTICAL_SYNCHRONOUS_PULSE - 1;
- tli_init_struct.backpsz_hbpsz = HORIZONTAL_SYNCHRONOUS_PULSE + HORIZONTAL_BACK_PORCH - 1;
- tli_init_struct.backpsz_vbpsz = VERTICAL_SYNCHRONOUS_PULSE + VERTICAL_BACK_PORCH - 1;
- tli_init_struct.activesz_hasz = HORIZONTAL_SYNCHRONOUS_PULSE + HORIZONTAL_BACK_PORCH + ACTIVE_WIDTH - 1;
- tli_init_struct.activesz_vasz = VERTICAL_SYNCHRONOUS_PULSE + VERTICAL_BACK_PORCH + ACTIVE_HEIGHT - 1;
- tli_init_struct.totalsz_htsz = HORIZONTAL_SYNCHRONOUS_PULSE + HORIZONTAL_BACK_PORCH + ACTIVE_WIDTH + HORIZONTAL_FRONT_PORCH - 1;
- tli_init_struct.totalsz_vtsz = VERTICAL_SYNCHRONOUS_PULSE + VERTICAL_BACK_PORCH + ACTIVE_HEIGHT + VERTICAL_FRONT_PORCH - 1;
- /* configure LCD background R,G,B values */
- tli_init_struct.backcolor_red = 0xFF;
- tli_init_struct.backcolor_green = 0xFF;
- tli_init_struct.backcolor_blue = 0xFF;
- tli_init(&tli_init_struct);
- #if 1
- /* TLI layer0 configuration */
- /* TLI window size configuration */
- tli_layer_init_struct.layer_window_leftpos = HORIZONTAL_SYNCHRONOUS_PULSE + HORIZONTAL_BACK_PORCH;
- tli_layer_init_struct.layer_window_rightpos = (ACTIVE_WIDTH + HORIZONTAL_SYNCHRONOUS_PULSE + HORIZONTAL_BACK_PORCH - 1);
- tli_layer_init_struct.layer_window_toppos = VERTICAL_SYNCHRONOUS_PULSE + VERTICAL_BACK_PORCH;
- tli_layer_init_struct.layer_window_bottompos = (ACTIVE_HEIGHT + VERTICAL_SYNCHRONOUS_PULSE + VERTICAL_BACK_PORCH - 1);
- /* TLI window pixel format configuration */
- tli_layer_init_struct.layer_ppf = LAYER_PPF_RGB565;
- /* TLI window specified alpha configuration */
- tli_layer_init_struct.layer_sa = 255;
- /* TLI layer default alpha R,G,B value configuration */
- tli_layer_init_struct.layer_default_blue = 0x00;
- tli_layer_init_struct.layer_default_green = 0x00;
- tli_layer_init_struct.layer_default_red = 0x00;
- tli_layer_init_struct.layer_default_alpha = 0x00;
- /* TLI window blend configuration */
- tli_layer_init_struct.layer_acf1 = LAYER_ACF1_SA;
- tli_layer_init_struct.layer_acf2 = LAYER_ACF2_SA;
- /* TLI layer frame buffer base address configuration */
- tli_layer_init_struct.layer_frame_bufaddr = (uint32_t)ltdc_lcd_framebuf0;
- tli_layer_init_struct.layer_frame_line_length = ((ACTIVE_WIDTH * 2) + 3);
- tli_layer_init_struct.layer_frame_buf_stride_offset = (ACTIVE_WIDTH * 2);
- tli_layer_init_struct.layer_frame_total_line_number = ACTIVE_HEIGHT;
- tli_layer_init(LAYER0, &tli_layer_init_struct);
- tli_dither_config(TLI_DITHER_ENABLE);
- #endif
- }
- /**
- * @brief Initialize the IPA peripheral.
- *
- * @note Enable clock and interrupt for the IPA module.
- *
- * @param None
- *
- * @return None
- */
- static void ipa_config(void)
- {
- rcu_periph_clock_enable(RCU_IPA);
- nvic_irq_enable(IPA_IRQn, 0, 2);
- }
- /**
- * @brief Configure the GPIO pins used for TLI display.
- *
- * @note Includes alternate function mapping and output mode setup
- * for RGB and sync signals.
- *
- * @param None
- *
- * @return None
- */
- static void tli_gpio_config(void)
- {
- /* enable the periphral clock */
- rcu_periph_clock_enable(RCU_GPIOA);
- rcu_periph_clock_enable(RCU_GPIOB);
- rcu_periph_clock_enable(RCU_GPIOC);
- rcu_periph_clock_enable(RCU_GPIOD);
- rcu_periph_clock_enable(RCU_GPIOF);
- rcu_periph_clock_enable(RCU_GPIOG);
- /* configure HSYNC(PC6), VSYNC(PA4), PCLK(PG7), DE(PF10) */
- /* configure LCD_R7(PG6), LCD_R6(PA8), LCD_R5(PA12), LCD_R4(PA11), LCD_R3(PB0),
- LCD_G7(PD3), LCD_G6(PC7), LCD_G5(PB11), LCD_G4(PB10), LCD_G3(PG10), LCD_G2(PA6),
- LCD_B7(PB9), LCD_B6(PB8), LCD_B5(PA3), LCD_B4(PG12), LCD_B3(PG11) */
- gpio_af_set(GPIOA, GPIO_AF_14, GPIO_PIN_3);
- gpio_af_set(GPIOA, GPIO_AF_14, GPIO_PIN_4);
- gpio_af_set(GPIOA, GPIO_AF_14, GPIO_PIN_6);
- gpio_af_set(GPIOA, GPIO_AF_14, GPIO_PIN_8);
- gpio_af_set(GPIOA, GPIO_AF_14, GPIO_PIN_11);
- gpio_af_set(GPIOA, GPIO_AF_14, GPIO_PIN_12);
- gpio_af_set(GPIOB, GPIO_AF_9, GPIO_PIN_0);
- gpio_af_set(GPIOB, GPIO_AF_14, GPIO_PIN_8);
- gpio_af_set(GPIOB, GPIO_AF_14, GPIO_PIN_9);
- gpio_af_set(GPIOB, GPIO_AF_14, GPIO_PIN_10);
- gpio_af_set(GPIOB, GPIO_AF_14, GPIO_PIN_11);
- gpio_af_set(GPIOC, GPIO_AF_14, GPIO_PIN_6);
- gpio_af_set(GPIOC, GPIO_AF_14, GPIO_PIN_7);
- gpio_af_set(GPIOD, GPIO_AF_14, GPIO_PIN_3);
- gpio_af_set(GPIOF, GPIO_AF_14, GPIO_PIN_10);
- gpio_af_set(GPIOG, GPIO_AF_14, GPIO_PIN_6);
- gpio_af_set(GPIOG, GPIO_AF_14, GPIO_PIN_7);
- gpio_af_set(GPIOG, GPIO_AF_9, GPIO_PIN_10);
- gpio_af_set(GPIOG, GPIO_AF_14, GPIO_PIN_11);
- gpio_af_set(GPIOG, GPIO_AF_9, GPIO_PIN_12);
- gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_6 | GPIO_PIN_8 | GPIO_PIN_11 | GPIO_PIN_12);
- gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_6 | GPIO_PIN_8 | GPIO_PIN_11 | GPIO_PIN_12);
- gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_0 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11);
- gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11);
- gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_6 | GPIO_PIN_7);
- gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6 | GPIO_PIN_7);
- gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_3);
- gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3);
- gpio_mode_set(GPIOF, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_10);
- gpio_output_options_set(GPIOF, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
- gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12);
- gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12);
- }
- /**
- * @brief Configure the GPIO pin for DISP enable control.
- *
- * @note This function enables the clock for GPIOD and sets up pin 13
- * as push-pull output to control the display on/off signal.
- *
- * @param None
- *
- * @return None
- *
- * @warning Must be called before attempting to control the LCD display.
- */
- static void lcd_disp_en_config(void)
- {
- /* enable the periphral clock */
- rcu_periph_clock_enable(RCU_GPIOD);
- gpio_mode_set(GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_13);
- gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13);
- }
- /**
- * @brief Turn off the LCD display by resetting the DISP GPIO.
- *
- * @note This function clears the DISP control pin to disable
- * the LCD backlight or power depending on hardware design.
- *
- * @param None
- *
- * @return None
- *
- * @warning Only valid if the DISP GPIO has been previously configured.
- */
- static void lcd_disp_off(void)
- {
- gpio_bit_reset(GPIOD, GPIO_PIN_13);
- }
- /**
- * @brief Turn on the LCD display by setting the DISP GPIO.
- *
- * @note This function sets the DISP control pin to enable
- * the LCD backlight or power depending on hardware design.
- *
- * @param None
- *
- * @return None
- *
- * @warning Only valid if the DISP GPIO has been previously configured.
- */
- static void lcd_disp_on(void)
- {
- gpio_bit_set(GPIOD, GPIO_PIN_13);
- }
- /**
- * @brief Draw a pixel on the LCD at specified coordinates.
- *
- * @note This function writes a color value directly to the framebuffer.
- * Coordinates must be within the valid LCD dimensions.
- *
- * @param x Horizontal coordinate of the pixel.
- * @param y Vertical coordinate of the pixel.
- * @param color Color of the pixel in RGB565 format.
- *
- * @return None
- */
- void tli_draw_point(uint16_t x, uint16_t y, uint16_t color)
- {
- *(ltdc_lcd_framebuf0[0] + (LCD_WIDTH * y + x)) = color;
- }
- /**
- * @brief Draw a straight line between two points.
- *
- * @note Uses Bresenham's line drawing algorithm to connect two points.
- * Coordinates should be within LCD bounds.
- *
- * @param sx Start point X coordinate.
- * @param sy Start point Y coordinate.
- * @param ex End point X coordinate.
- * @param ey End point Y coordinate.
- * @param color Line color in RGB565 format.
- *
- * @return None
- */
- void tli_draw_line(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t color)
- {
- uint16_t t;
- int xerr = 0, yerr = 0, delta_x, delta_y, distance;
- int incx, incy, uRow, uCol;
- delta_x = ex - sx;
- delta_y = ey - sy;
- uRow = sx;
- uCol = sy;
- if (delta_x > 0)
- incx = 1;
- else if (delta_x == 0)
- incx = 0;
- else
- {
- incx = -1;
- delta_x = -delta_x;
- }
- if (delta_y > 0)
- incy = 1;
- else if (delta_y == 0)
- incy = 0;
- else
- {
- incy = -1;
- delta_y = -delta_y;
- }
- if (delta_x > delta_y)
- distance = delta_x;
- else
- distance = delta_y;
- for (t = 0; t <= distance + 1; t++)
- {
- tli_draw_point(uRow, uCol, color);
- xerr += delta_x;
- yerr += delta_y;
- if (xerr > distance)
- {
- xerr -= distance;
- uRow += incx;
- }
- if (yerr > distance)
- {
- yerr -= distance;
- uCol += incy;
- }
- }
- }
- /**
- * @brief Draw a rectangle on the screen, optionally filled.
- *
- * @note The rectangle is defined by top-left and bottom-right corners.
- * If fill is set to 1, the rectangle will be filled with the color.
- *
- * @param sx X coordinate of the top-left corner.
- * @param sy Y coordinate of the top-left corner.
- * @param ex X coordinate of the bottom-right corner.
- * @param ey Y coordinate of the bottom-right corner.
- * @param color Color of the rectangle in RGB565 format.
- * @param fill Fill mode: 1 = filled, 0 = only borders.
- *
- * @return None
- */
- void tli_draw_rectangle(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t color, uint16_t fill)
- {
- int i = 0, j = 0;
- if (fill)
- {
- for (i = sx; i < ex; i++)
- {
- for (j = sy; j < ey; j++)
- {
- tli_draw_point(i, j, color);
- }
- }
- }
- else
- {
- tli_draw_line(sx, sy, ex, sy, color);
- tli_draw_line(sx, sy, sx, ey, color);
- tli_draw_line(sx, ey, ex, ey, color);
- tli_draw_line(ex, sy, ex, ey, color);
- }
- }
- /**
- * @brief Draw eight symmetric points of a circle.
- *
- * @note This function is used internally to draw points in all eight
- * symmetrical positions around a circle center.
- *
- * @param xc X coordinate of the circle center.
- * @param yc Y coordinate of the circle center.
- * @param x Relative X offset from the center.
- * @param y Relative Y offset from the center.
- * @param c Color of the point in RGB565 format.
- *
- * @return None
- */
- static void _draw_circle_8(int xc, int yc, int x, int y, uint16_t c)
- {
- tli_draw_point(xc + x, yc + y, c);
- tli_draw_point(xc - x, yc + y, c);
- tli_draw_point(xc + x, yc - y, c);
- tli_draw_point(xc - x, yc - y, c);
- tli_draw_point(xc + y, yc + x, c);
- tli_draw_point(xc - y, yc + x, c);
- tli_draw_point(xc + y, yc - x, c);
- tli_draw_point(xc - y, yc - x, c);
- }
- /**
- * @brief Draw a circle on the screen with optional fill.
- *
- * @note Uses the midpoint circle algorithm to render the circle.
- * When fill is enabled, the circle is drawn as a filled disk.
- *
- * @param xc X coordinate of the circle center.
- * @param yc Y coordinate of the circle center.
- * @param c Color of the circle in RGB565 format.
- * @param r Radius of the circle.
- * @param fill Fill mode: 1 = filled, 0 = outline only.
- *
- * @return None
- */
- void tli_draw_circle(int xc, int yc, uint16_t c, int r, int fill)
- {
- int x = 0, y = r, yi, d;
- d = 3 - 2 * r;
- if (fill)
- {
- while (x <= y)
- {
- for (yi = x; yi <= y; yi++)
- _draw_circle_8(xc, yc, x, yi, c);
- if (d < 0)
- {
- d = d + 4 * x + 6;
- }
- else
- {
- d = d + 4 * (x - y) + 10;
- y--;
- }
- x++;
- }
- }
- else
- {
- while (x <= y)
- {
- _draw_circle_8(xc, yc, x, y, c);
- if (d < 0)
- {
- d = d + 4 * x + 6;
- }
- else
- {
- d = d + 4 * (x - y) + 10;
- y--;
- }
- x++;
- }
- }
- }
- /**
- * @brief Swap the values of two 16-bit unsigned integers.
- *
- * @note This utility function is used internally to simplify sorting
- * or reordering logic, such as coordinate alignment.
- *
- * @param a Pointer to the first variable.
- * @param b Pointer to the second variable.
- *
- * @return None
- */
- static void _swap(uint16_t *a, uint16_t *b)
- {
- uint16_t tmp;
- tmp = *a;
- *a = *b;
- *b = tmp;
- }
- /**
- * @brief Draw a triangle with optional fill.
- *
- * @note The triangle is defined by three vertex points. When fill is set,
- * it is rendered as a filled triangle using scan-line rasterization.
- *
- * @param x0 X coordinate of the first vertex.
- * @param y0 Y coordinate of the first vertex.
- * @param x1 X coordinate of the second vertex (typically the top).
- * @param y1 Y coordinate of the second vertex.
- * @param x2 X coordinate of the third vertex.
- * @param y2 Y coordinate of the third vertex.
- * @param color Color of the triangle in RGB565 format.
- * @param fill Fill mode: 1 = filled, 0 = outline only.
- *
- * @return None
- */
- void tli_draw_triangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color, uint16_t fill)
- {
- uint16_t a, b, y, last;
- int dx01, dy01, dx02, dy02, dx12, dy12;
- long sa = 0;
- long sb = 0;
- if (fill == 0)
- {
- tli_draw_line(x0, y0, x1, y1, color);
- tli_draw_line(x1, y1, x2, y2, color);
- tli_draw_line(x2, y2, x0, y0, color);
- }
- else
- {
- if (y0 > y1)
- {
- _swap(&y0, &y1);
- _swap(&x0, &x1);
- }
- if (y1 > y2)
- {
- _swap(&y2, &y1);
- _swap(&x2, &x1);
- }
- if (y0 > y1)
- {
- _swap(&y0, &y1);
- _swap(&x0, &x1);
- }
- if (y0 == y2)
- {
- a = b = x0;
- if (x1 < a)
- {
- a = x1;
- }
- else if (x1 > b)
- {
- b = x1;
- }
- if (x2 < a)
- {
- a = x2;
- }
- else if (x2 > b)
- {
- b = x2;
- }
- tli_draw_rectangle(a, y0, b, y0, color, 0);
- return;
- }
- dx01 = x1 - x0;
- dy01 = y1 - y0;
- dx02 = x2 - x0;
- dy02 = y2 - y0;
- dx12 = x2 - x1;
- dy12 = y2 - y1;
- if (y1 == y2)
- {
- last = y1;
- }
- else
- {
- last = y1 - 1;
- }
- for (y = y0; y <= last; y++)
- {
- a = x0 + sa / dy01;
- b = x0 + sb / dy02;
- sa += dx01;
- sb += dx02;
- if (a > b)
- {
- _swap(&a, &b);
- }
- tli_draw_rectangle(a, y, b, y, color, 0);
- }
- sa = dx12 * (y - y1);
- sb = dx02 * (y - y0);
- for (; y <= y2; y++)
- {
- a = x1 + sa / dy12;
- b = x0 + sb / dy02;
- sa += dx12;
- sb += dx02;
- if (a > b)
- {
- _swap(&a, &b);
- }
- tli_draw_rectangle(a, y, b, y, color, 0);
- }
- }
- }
- /**
- * @brief Enlarge a single point by drawing a square block.
- *
- * @note The enlarged point is drawn as a 2D cross pattern made of four
- * rectangles centered at (x, y) with specified magnification.
- *
- * @param x X coordinate of the center point.
- * @param y Y coordinate of the center point.
- * @param color Color to fill the enlarged point.
- * @param magnify Enlargement factor (minimum value is 1).
- *
- * @return None
- */
- void tli_point_enlarge(uint16_t x, uint16_t y, uint16_t color, char magnify)
- {
- tli_draw_rectangle(x - magnify, y - magnify, x, y, color, 1);
- tli_draw_rectangle(x, y - magnify, x + magnify, y, color, 1);
- tli_draw_rectangle(x - magnify, y, x, y + magnify, color, 1);
- tli_draw_rectangle(x, y, x + magnify, y + magnify, color, 1);
- }
- /**
- * @brief Display a single ASCII character at the specified position.
- *
- * @note Uses a fixed-size 16x8 font to render the character with optional
- * enlargement and overlay mode.
- *
- * @param x X coordinate of the character start position.
- * @param y Y coordinate of the character start position.
- * @param fc Foreground color.
- * @param bc Background color.
- * @param num ASCII character to display.
- * @param size Enlargement factor (minimum 1).
- * @param mode Overlay mode: 0 = non-overlay, 1 = overlay.
- *
- * @return None
- */
- void tli_show_char(uint16_t x, uint16_t y, uint16_t fc, uint16_t bc, uint8_t num, uint8_t size, uint8_t mode)
- {
- uint8_t temp;
- uint8_t pos, t;
- uint16_t x0 = 0;
- uint16_t y0 = 0;
- num = num - ' ';
- for (pos = 0; pos < 16; pos++)
- {
- temp = asc2_1608[num][pos];
- for (t = 0; t < 16 / 2; t++)
- {
- if (!mode)
- {
- if (temp & 0x01)
- tli_point_enlarge(x + x0, y + y0, fc, size);
- else
- tli_point_enlarge(x + x0, y + y0, bc, size);
- }
- else
- {
- if (temp & 0x01) tli_point_enlarge(x + x0, y + y0, fc, size);
- }
- temp >>= 1;
- x0 = x0 + size;
- }
- x0 = 0;
- y0 = y0 + size;
- }
- }
- /**
- * @brief Display a null-terminated ASCII string on the screen.
- *
- * @note Automatically handles line boundaries and skips illegal characters.
- *
- * @param x X coordinate of the start position.
- * @param y Y coordinate of the start position.
- * @param fc Foreground color.
- * @param bc Background color.
- * @param size Font enlargement factor (base size is 16x8).
- * @param p Pointer to the string.
- * @param mode Overlay mode: 0 = non-overlay, 1 = overlay.
- *
- * @return None
- */
- void tli_show_string(uint16_t x, uint16_t y, uint16_t fc, uint16_t bc, uint8_t size, uint8_t *p, uint8_t mode)
- {
- while ((*p <= '~') && (*p >= ' '))
- {
- if (x > (LCD_WIDTH - 1) || y > (LCD_HEIGHT - 1)) return;
- tli_show_char(x, y, fc, bc, *p, size, mode);
- x += 16 * size / 2;
- p++;
- }
- }
- /**
- * @brief Display a picture at a specified position on the screen.
- *
- * @note The image data is expected to be in RGB565 format, with each pixel
- * occupying two consecutive bytes in the array.
- *
- * @param x X coordinate of the top-left corner.
- * @param y Y coordinate of the top-left corner.
- * @param w Width of the image in pixels.
- * @param h Height of the image in pixels.
- * @param pic Pointer to the image data array.
- *
- * @return None
- */
- void tli_show_picture(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const unsigned char pic[])
- {
- uint16_t i, j;
- uint32_t k = 0;
- uint16_t x0 = x, y0 = y;
- for (i = y; i < h + y0; i++)
- {
- for (j = x; j < w + x0; j++)
- {
- tli_draw_point(j, i, pic[k * 2] << 8 | pic[k * 2 + 1]);
- k++;
- }
- }
- }
- /**
- * @brief Draw a filled rounded rectangle button.
- *
- * @note This function draws a button with four rounded corners and fills
- * the background. The radius must be less than half of the height.
- *
- * @param x X coordinate of the top-left corner.
- * @param y Y coordinate of the top-left corner.
- * @param width Width of the button.
- * @param height Height of the button.
- * @param radius Radius of the corners.
- * @param color Fill color of the button.
- *
- * @return None
- */
- void tli_show_button(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t radius, uint16_t color)
- {
- int i = 0;
- int j = 0;
- if (radius >= (height / 2)) return;
- tli_draw_circle(x + radius, y + radius, color, radius, 1);
- tli_draw_circle(x + width - radius - 1, y + radius, color, radius, 1);
- tli_draw_circle(x + radius, y + height - radius - 1, color, radius, 1);
- tli_draw_circle(x + width - radius - 1, y + height - radius - 1, color, radius, 1);
- tli_draw_line(x + radius, y, x + width - radius - 1, y, color);
- tli_draw_line(x + radius, y + height - 1, x + width - radius - 1, y + height - 1, color);
- tli_draw_line(x, y + radius, x, y + height - radius - 1, color);
- tli_draw_line(x + width - 1, y + radius, x + width - 1, y + height - radius - 1, color);
- tli_draw_rectangle(x + radius, y + radius, x + width - radius, y + height - radius, color, 1);
- tli_draw_rectangle(x + radius, y, x + width - radius, y + radius, color, 1);
- tli_draw_rectangle(x, y + radius, x + width, y + height - radius, color, 1);
- tli_draw_rectangle(x + radius, y + height - radius, x + width - radius, y + height, color, 1);
- }
- /**
- * @brief Draw a switch (toggle) component with visual state.
- *
- * @note The switch has a rounded rectangle base with a circular knob
- * indicating on or off state. Automatically validates layout rules.
- *
- * @param x X coordinate of the top-left corner.
- * @param y Y coordinate of the top-left corner.
- * @param width Total width of the switch.
- * @param height Total height of the switch.
- * @param on_color Color of the switch when turned on.
- * @param off_color Color of the switch when turned off.
- * @param sw Switch state: 1 = on, 0 = off.
- *
- * @return None
- */
- void tli_show_switch(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t on_color, uint16_t off_color, char sw)
- {
- int radius = height / 2 - 1;
- if (width < 2 * (radius + 1)) return;
- if (sw == 0)
- {
- tli_show_button(x, y, width, height, radius, off_color);
- tli_draw_circle(x + radius, y + radius, WHITE, radius / 2, 1);
- }
- else
- {
- tli_show_button(x, y, width, height, radius, on_color);
- tli_draw_circle(x + width - radius, y + radius, WHITE, radius / 2, 1);
- }
- }
|