diff --git a/CMakeLists.txt b/CMakeLists.txt index 6d64bb8250..2da616a3be 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,11 +53,11 @@ if (NOT ${IS_BARE_METAL}) add_subdirectory(hal) add_subdirectory(middleware) add_subdirectory(targets) - add_subdirectory(thirdparty) + #add_subdirectory(thirdparty) endif() -if(${MSDK_TEST_EXAMPLES} MATCHES "true") add_subdirectory(tests) +if(${MSDK_TEST_EXAMPLES} MATCHES "true") endif() ## Deploy build is used for testing compiler specific issues. diff --git a/middleware/CMakeLists.txt b/middleware/CMakeLists.txt index bf14ac8052..44609a7f32 100644 --- a/middleware/CMakeLists.txt +++ b/middleware/CMakeLists.txt @@ -47,3 +47,6 @@ add_subdirectory(hw) ## LCD library. add_subdirectory(lcd) + +## GLCD library +add_subdirectory(glcd) diff --git a/middleware/glcd/CMakeLists.txt b/middleware/glcd/CMakeLists.txt new file mode 100644 index 0000000000..8e9b5fa71c --- /dev/null +++ b/middleware/glcd/CMakeLists.txt @@ -0,0 +1,2 @@ +## ./middleware/glcd/CMakeLists.txt +add_subdirectory(lib) \ No newline at end of file diff --git a/middleware/glcd/ReadMe.txt b/middleware/glcd/ReadMe.txt new file mode 100644 index 0000000000..f0e08cf1bc --- /dev/null +++ b/middleware/glcd/ReadMe.txt @@ -0,0 +1,14 @@ +Glcd Implementation on EasyMxPRO v7A + +Completed : + +Turning on and off the display +Functions to write and show data into the display +Basic geometric functions +Commentary of the code + + +TODO : + +Touch implementation +Optimization of the code diff --git a/middleware/glcd/lib/CMakeLists.txt b/middleware/glcd/lib/CMakeLists.txt new file mode 100644 index 0000000000..ce467076d0 --- /dev/null +++ b/middleware/glcd/lib/CMakeLists.txt @@ -0,0 +1,32 @@ +## ./middleware/glcd/lib/CMakeLists.txt +cmake_minimum_required(VERSION 3.11) + +## Add GLCD as a library. +mikrosdk_add_library(lib_glcd MikroSDK.GLCD + ## Common. + src/glcd.c + include/glcd.h +) + +## Link MikroE Core, Board and GPIO Out libraries. +target_link_libraries(lib_glcd PUBLIC + MikroC.Core + MikroSDK.Board + MikroSDK.Driver.GPIO.Out + MikroSDK.Driver.GPIO.Port +) + +## Include search paths. +target_include_directories(lib_glcd + PRIVATE + include + PUBLIC + $ + $ +) + +## Then generate library with `MikroSDK.GLCD` alias and generic `glcd.h` header file. +mikrosdk_install(MikroSDK.GLCD) +install_headers(${CMAKE_INSTALL_PREFIX}/include/middleware/glcd MikroSDK.GLCD include/glcd.h) + +## END ## diff --git a/middleware/glcd/lib/include/glcd.h b/middleware/glcd/lib/include/glcd.h new file mode 100644 index 0000000000..af0a871494 --- /dev/null +++ b/middleware/glcd/lib/include/glcd.h @@ -0,0 +1,808 @@ +/**************************************************************************** +** +** Copyright (C) ${COPYRIGHT_YEAR} MikroElektronika d.o.o. +** Contact: https://www.mikroe.com/contact +** +** This file is part of the mikroSDK package +** +** Commercial License Usage +** +** Licensees holding valid commercial NECTO compilers AI licenses may use this +** file in accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The MikroElektronika Company. +** For licensing terms and conditions see +** https://www.mikroe.com/legal/software-license-agreement. +** For further information use the contact form at +** https://www.mikroe.com/contact. +** +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used for +** non-commercial projects under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +** OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT +** OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +** OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ + +/*! + * @file glcd.h + * @brief GLCD (Graphic Liquid Crystal Display) Driver. + */ + +#include +#include + +#include "drv_digital_out.h" +#include "drv_digital_in.h" +#include "drv_port.h" +#include "board.h" + +typedef enum { + GLCD_DISPLAY_ON = 0x3F, + GLCD_DISPLAY_OFF = 0x3E +} glcd_display_cfg_t; + +/** + * @brief Enumeration for line drawing directions. + * @details This enumeration defines the possible directions for drawing lines on the glcd. + * It includes vertical, horizontal, and diagonal directions. + */ +typedef enum { + VERTICAL_LINE, + HORIZONTAL_LINE, + DIAGONAL +} glcd_line_dir_t; + +/** + * @brief Enumeration for rectangle drawing modes. + * @details This enumeration defines the modes for drawing rectangles on the glcd. + * It includes center dimensions, corner dimensions, and three points mode. + */ +typedef enum { + CENTER_DIMENSIONS, + CORNER_DIMENSIONS, + THREE_POINTS +} glcd_rect_mode_t; + +/** + * @brief Enumeration for polygon drawing modes. + * @details This enumeration defines the number of sides for regular polygons that can be drawn on the glcd. + * It includes modes for triangles, rectangles, pentagons, hexagons, heptagons, octagons, nonagons, and decagons. + * + * @note The user can specify the number of sides when drawing polygons using the glcd_Draw_Regular_Polygon function. + * He can also use glcd_Draw_Shape to draw custom shapes defined by segments. + */ +typedef enum { + TRIANGLE = 3, + RECTANGLE = 4, + PENTAGON = 5, + HEXAGON = 6, + HEPTAGON = 7, + OCTAGON = 8, + NONAGON = 9, + DECAGON = 10 +} glcd_polygon_mode_t; + +/** + * @brief Enumeration for circle drawing modes. + * @details This enumeration defines the precision levels for drawing circles on the glcd. + * It includes fast, default, and high precision modes, which determine the number of points used to approximate the circle. + */ +typedef enum { + FAST = 15, + DEFAULT = 100, + PRECISION = 3000 +} glcd_circle_mode_t; + +#define PI ( 3.14159265359 ) +#define CS_SIZE ( 2 ) +#define PAGE_SIZE ( 8 ) +#define COL_PER_CHIP ( 64 ) +#define ROW_SIZE ( CS_SIZE * COL_PER_CHIP ) + + +/** + * @brief Enumeration for GLCD control pins. + * @details This enumeration defines the pin names used for controlling the GLCD. + * + * @param GLCD_E_PIN : ( pin_name_t ) Enable pin. + * @param GLCD_RW_PIN : ( pin_name_t ) Read/Write 2 pin. + * @param GLCD_RS_PIN : ( pin_name_t ) Data/Instruction pin. + * @param GLCD_CS1_PIN : ( pin_name_t ) CS1 pin. + * @param GLCD_CS2_PIN : ( pin_name_t ) CS2 pin. + * @param GLCD_RESET_PIN : ( pin_name_t ) Reset control pin. + * + * @note The user can define these pins in the glcd_cfg_t structure to match their hardware setup. + */ +typedef struct { + /** + * @brief GLCD control pins. + */ + pin_name_t GLCD_E_PIN; /*!< Chip select 1 pin. */ + pin_name_t GLCD_RW_PIN; /*!< Chip select 2 pin. */ + pin_name_t GLCD_RS_PIN; /*!< Enable pin. */ + pin_name_t GLCD_CS1_PIN; /*!< Reset pin. */ + pin_name_t GLCD_CS2_PIN; /*!< Register select (data/instruction) pin. */ + pin_name_t GLCD_RESET_PIN; /*!< Read/write control pin. */ + + /** + * @brief GLCD data pins. + */ + port_name_t data_out; /*!< Port used for data output to the glcd (1 byte) */ +} glcd_cfg_t; + +/** + * @brief Main glcd structure for managing configuration, GPIO control and frame buffer buffer. + * + * @param data_out : ( port_t ) Port used for data output to the glcd (1 byte) + * @param cs1d : ( digital_out_t ) Chip select 1 control + * @param cs2d : ( digital_out_t ) Chip select 2 control + * @param ed : ( digital_out_t ) Enable signal + * @param resetd : ( digital_out_t ) Reset signal + * @param rsd : ( digital_out_t ) Register select (data/instruction) + * @param rwd : ( digital_out_t ) Read/write control signal + * @param buffer : ( uint8_t[][][] ) Frame buffer: 2 chips with 8 pages and 64 columns + * + * @note The user must initialize this structure using glcd_init() before use. + */ + +typedef struct glcd +{ + glcd_cfg_t config; /*!< Configuration structure. */ + + digital_out_t cs1d; + digital_out_t cs2d; + digital_out_t ed; + digital_out_t resetd; + digital_out_t rsd; + digital_out_t rwd; + port_t data_out; + + uint8_t buffer[CS_SIZE][PAGE_SIZE][COL_PER_CHIP]; +} glcd_t; + +/* glcd Structure context/config creation and basic geometry (point, segment, rect, ...) structure*/ +/** + * @name point + * @brief A structure representing a 2D point on the glcd screen. + * + * @param x : ( uint8_t ) X-coordinate (0–127) + * @param y : ( uint8_t ) Y-coordinate (0–63) + */ +typedef struct point { + uint8_t x; + uint8_t y; +} glcd_point_t; + +/** + * @name segment + * @brief A structure representing a segment (line) defined by two points and a line thickness. + * + * @param pts : ( point[2] ) Two endpoints of the segment + * @param line_size : ( uint8_t ) Thickness of the segment + */ +typedef struct segment { + glcd_point_t pts[2]; + uint8_t line_size; +} glcd_segment_t; + +/** + * @name rect + * @brief A rectangle structure that defines dimensions, border thickness, and style. + * + * @param w : ( uint8_t ) Width of the rectangle (0-127) + * @param h : ( uint8_t ) Height of the rectangle (0-63) + * @param line_size : ( uint8_t ) Thickness of the rectangle border (0-63) + * @param filled : ( bool ) If true, the rectangle will be filled + * @param rounded : ( bool ) If true, rounded corners will be drawn (not yet implemented) + * + * @note The user must define this structure manually before passing it to drawing functions. + */ +typedef struct rect { + uint8_t w; + uint8_t h; + uint8_t line_size; + bool filled; + bool rounded; +} glcd_rect_t; + +/** + * @name circle + * @brief A circle structure that encapsulates the essential parameters required for rendering. + * + * @param o : ( point ) Origin (center) of the circle + * @param r : ( uint8_t ) Radius of the circle + * @param line_size : ( uint8_t ) Line thickness + * @param filled : ( bool ) If true, fills the circle + * + * @note The user needs to define this structure before using it in the glcd_Draw_Circle function. + * You cannot fill a cricle which has a radius greater than (32), as it would exceed the GLCD's vertical limits. + */ +typedef struct circle { + glcd_point_t o; + uint8_t r; + uint8_t line_size; + bool filled; +} glcd_circle_t; + +/** + * @name ellipse + * @brief A structure representing an ellipse defined by its foci, semi-major axis, and style options. + * + * @param mid_foci : ( point[2] ) Two focal points of the ellipse + * @param a : ( float ) Semi-major axis length + * @param line_size : ( uint8_t ) Thickness of the ellipse's contour + * @param filled : ( bool ) If true, the ellipse will be filled + * + * @note The two focal points must be distinct but a is calculated regarless + */ +typedef struct ellipse { + glcd_point_t mid_foci[2]; + float a; + uint8_t line_size; + bool filled; +} glcd_ellipse_t; + +/** + * @name char_def + * @brief A character font structure that maps an ASCII character to its 8x8 bitmap. + * + * @param c : ( char ) The character symbol + * @param bitmap_code : ( uint64_t ) 8x8 bitmap representation of the character (column-wise) + * + * @note Used internally by glcd_Write_Char and glcd_Write_Text functions. + */ +typedef struct char_def { + char c; + uint64_t bitmap_code; +} glcd_char_def_t; + + +/* -------------------------------------------------- Initialize functions -------------------------------------------------- */ +/** + * @name glcd_config_default + * @brief Initializes the GLCD configuration structure with default values. + * + * @details This function sets the default pin configurations for the GLCD control signals + * and data output port. It should be called before initializing the GLCD hardware. + * + * @param ( glcd_cfg_t* ) glcd_cfg : Pointer to the GLCD configuration structure to be initialized. + * @return Nothing + * + * @note This function is typically called at the beginning of the glcd_init() function to ensure + * that the GLCD is configured with the correct pin mappings. + */ +void glcd_config_default ( glcd_t* glcd_cfg ); + +/** + * @name glcd_port_init + * @brief Initializes the GLCD port and control pins. + * + * @details This function sets up the data output port and initializes all required + * digital output pins for controlling the GLCD, including chip select, + * enable, reset, register select, and read/write pins. + * + * @param ( glcd_t* ) Pointer to the GLCD structure containing pin configurations. + * @return Nothing + * + * @note This function is called automatically by glcd_init() to prepare the GLCD for operation. + * It should not be called directly unless you need to reinitialize the port. + */ +void glcd_port_init ( glcd_t* glcd ); + +/** + * @name glcd_init + * @brief Initializes the GLCD hardware and sets the initial pin states. + * + * @details This function configures the GLCD port and sets the control pins to their + * initial states required for proper operation. It performs the following steps: + * - Initializes the GLCD port. + * - Sets the enable, chip select 1, chip select 2, and reset pins to high. + * - Sets the register select pin to low. + * - Sets the read/write pin to high. + * - Applies the changes to the hardware. + * + * @param ( glcd_t* ) glcd : to the glcd_t structure containing GLCD configuration and pin mappings. + * @return Nothing + * + * @note This function must be called before any other GLCD operations to ensure the hardware is ready. + * It initializes the GLCD and prepares it for further commands and data transmission. + */ +void glcd_init ( glcd_t* glcd ); + +/** + * @name glcd_set_page + * @brief Sets the current page for GLCD operations. + * + * @details This function sets the page address for the GLCD, which determines + * the vertical position on the screen where subsequent data will be written. + * The page value must be between 0 and 7 (inclusive). + * + * @param ( glcd_t* ) glcd : Pointer to the glcd_t structure containing GLCD configuration and pin mappings. + * @param ( uint8_t ) page : The page number to set (0-7). + * @return Nothing + * + * @note This function should be called before writing data to a specific page. But the user isn't supposed + * to use this function directly, instead it should use GLCD_Write() which will handle the page setting automatically. + * If the page number is out of range (greater than 7), the function will return immediately without making any changes. + */ +void glcd_set_page ( glcd_t* glcd, uint8_t page ); + +/** + * @name glcd_set_y + * @brief Sets the Y position (line) for GLCD operations. + * + * @details This function sets the Y position on the GLCD, which determines the + * horizontal line where subsequent data will be written. The Y position + * must be between 0 and 64 (inclusive). + * + * @param ( glcd_t* ) glcd : Pointer to the glcd_t structure containing GLCD configuration and pin mappings. + * @param ( uint8_t ) y_pos : The Y position to set (0-64). + * @return Nothing + * + * @note This function should be called before writing data to a specific line, and is done automatically by GLCD_Write(). + * If the Y position is out of range (greater than 64), the function will return immediately without making any changes. + */ +void glcd_set_y ( glcd_t* glcd, uint8_t y_pos ); + +/** + * @name glcd_clear + * @brief Clears the GLCD buffer by writing zeros to all pages and columns. + * + * @details This function iterates through all pages and columns of the GLCD + * and writes zero to each position, effectively clearing the display. + * + * @param ( glcd_t* ) glcd : Pointer to the glcd_t structure containing GLCD configuration and pin mappings. + * @return Nothing + * + * @note This function writes zeros to the GLCD register for each page and column, + * which will result in a blank display when the buffer is displayed. The data (because of the GLCD_Write function) + * is written to the buffer as well. + */ +void glcd_clear ( glcd_t *glcd ); + +/** + * @name glcd_display + * @brief Turns the GLCD display on or off. + * + * @details This function controls the display state of the GLCD by setting the + * appropriate control signals. It can turn the display on or off based on the + * provided parameter. + * + * @param ( glcd_t* ) glcd : Pointer to the glcd_t structure containing GLCD configuration and pin mappings. + * @param ( uint8_t ) turn_on_off : The state to set (ON or OFF). + * @return Nothing + * + * @note This function should be called to toggle the display state. It uses the CS_Config function to select the chip, + * and applies changes to the control signals. + */ +void glcd_display ( glcd_t* glcd, glcd_display_cfg_t turn_on_off ); + +/** + * @name apply_changes + * @brief Applies changes to the GLCD by toggling the enable pin. + * + * @details This function toggles the enable pin of the GLCD to apply any changes made + * to the data or control signals. It ensures that the GLCD registers are updated with + * the latest values. This chip uses a pulse on the enable pin to latch the data (according to the datasheet). + * + * @param ( glcd_t* ) glcd : Pointer to the glcd_t structure containing GLCD configuration and pin mappings. + * @return Nothing + * + * @note This function should be called after writing data or control signals to the GLCD + * to ensure that the changes take effect. + */ +void apply_changes ( glcd_t* glcd ); + +/** + * @name cs_config + * @brief Configures the chip select pins for the GLCD. + * + * @details This function sets the chip select pins (CS1 and CS2) to either high or low + * based on the provided parameters. It is used to select which chip (if multiple chips are used) + * will respond to the GLCD commands. + * + * @param ( glcd_t* ) glcd : Pointer to the glcd_t structure containing GLCD configuration and pin mappings. + * @param ( bool ) cs1 : State for chip select 1 (true for low, false for high). + * @param ( bool ) cs2 : State for chip select 2 (true for low, false for high). + * @return Nothing + * + * @note This function should be called before writing data to the GLCD to ensure that the correct chip is selected + * and is of course, called in GLCD_Write() function. The CS logic is inverted, so a value of 1 means the chip + * is selected (active low). + */ +void cs_config ( glcd_t* glcd, bool cs1, bool cs2 ); + +/* -------------------------------------------------- Read and Write functions -------------------------------------------------- */ +/** + * @name glcd_read + * @brief Reads a byte from the GLCD buffer at the specified page and column. + * + * @details This function retrieves a byte from the GLCD buffer based on the specified + * page and column indices. It checks if the indices are within valid ranges before accessing + * the buffer. + * + * @param ( glcd_t* ) glcd : Pointer to the glcd_t structure containing GLCD configuration and pin mappings. + * @param ( uint8_t ) page : The page number (0-7). + * @param ( uint8_t ) column : The column number (0-127). + * @return ( uint8_t ) The byte read from the GLCD buffer, or 0 if indices are out of range. + * + * @note This function is used to read data from the GLCD buffer without affecting the display. + * Although it is a software read, it is mainly used to access the frame buffer buffer for further + * processing or display updates (because the Read_LL a.k.a Low Level Read) is imprecise + * and slower than this function. This should be a improvment for the next version of this library. + */ +uint8_t glcd_read ( glcd_t* glcd, uint8_t page, uint8_t lign ); + +/** + * @name glcd_read_ll + * @brief Reads a byte from the GLCD at the specified page and column using low-level access. + * + * @details This function performs a low-level read operation on the GLCD by configuring + * the necessary control signals and reading the data from the specified page and column. + * It is used for direct hardware access to retrieve data from the GLCD. + * + * @param ( glcd_t* ) glcd : Pointer to the glcd_t structure containing GLCD configuration and pin mappings. + * @param ( uint8_t ) page : The page number (0-7). + * @param ( uint8_t ) column : The column number (0-127). + * @return ( uint8_t ) The byte read from the GLCD, or 0 if indices are out of range. + * + * @note This function is used for low-level access to read data directly from the GLCD hardware. + * It should be used with caution as it bypasses the buffer and directly interacts with the GLCD. + */ +uint8_t glcd_read_ll ( glcd_t* glcd, uint8_t page, uint8_t column ); + +/** + * @name glcd_write + * @brief Writes a byte to the GLCD at the specified page and line. + * + * @details This function writes a byte of data to the GLCD at the specified page and line. + * It handles the chip selection based on the line number (0-63 for CS1, 64-127 for CS2). + * The data is also stored in the GLCD buffer for later retrieval. + * + * @param ( glcd_t* ) glcd : Pointer to the glcd_t structure containing GLCD configuration and pin mappings. + * @param ( uint8_t ) page : The page number (0-7). + * @param ( uint8_t ) line : The line number (0-127). + * @param ( uint8_t ) data_to_write : The byte of data to write to the GLCD. + * @return Nothing + * + * @note This function should be called to write data to the GLCD. It automatically selects the appropriate chip + * based on the line number and updates both the GLCD display and the internal buffer. + */ +void glcd_write ( glcd_t *glcd, uint8_t page, uint8_t column, uint8_t data_to_write ); + +/** + * @name glcd_write_char + * @brief Writes a character to the GLCD at the specified position. + * + * @details This function writes a single character to the GLCD at the specified position + * (x, y). It retrieves the character's bitmap from a predefined font array and writes it + * to the GLCD in a column-wise manner. + * + * @param ( glcd_t* ) glcd : Pointer to the glcd_t structure containing GLCD configuration and pin mappings. + * @param ( glcd_point_t* ) p : Pointer to a point structure defining the position (x, y) on the GLCD. + * @param ( char ) c : The character to write to the GLCD. + * @return Nothing + * + * @note This function is used to display individual characters on the GLCD. It calculates + * the page and line based on the provided point and writes each byte of the character's bitmap + * to the GLCD buffer. + */ +void glcd_write_char ( glcd_t* glcd, glcd_point_t* p, char c ); + +/** + * @name glcd_write_text + * @brief Writes a string of text to the GLCD at the specified position. + * + * @details This function writes a null-terminated string to the GLCD starting from + * the specified point (x, y). It iterates through each character in the string and + * calls GLCD_Write_Char to write each character to the GLCD. + * + * @param ( glcd_t* ) glcd : Pointer to the glcd_t structure containing GLCD configuration and pin mappings. + * @param ( glcd_point_t* ) p : Pointer to a point structure defining the starting position (x, y) on the GLCD. + * @param ( const char* ) c : Pointer to a null-terminated string to write to the GLCD. + * @return Nothing + * + * @note This function is used to display text on the GLCD. It automatically handles line wrapping + * by moving to the next line when the end of a page is reached. If the text exceeds the available space, + * it stops writing further characters. + */ +void glcd_write_text ( glcd_t* glcd, glcd_point_t* p, const char* c ); + +/* -------------------------------------------------- Drawing functions -------------------------------------------------- */ +/** + * @name glcd_fill_screen + * @brief Fills the entire GLCD screen with a specified pattern. + * + * @details This function fills the entire GLCD screen by writing a specified pattern + * to each page and column. The pattern is repeated across the entire display. + * + * @param ( glcd_t* ) glcd : Pointer to the glcd_t structure containing GLCD configuration and pin mappings. + * @param ( uint8_t ) pattern : The byte pattern to fill the screen with. + * @return Nothing + * + * @note This function is used to quickly fill the entire GLCD screen with a specific pattern, + * which can be useful for clearing the display or creating background effects. + */ +void glcd_fill_screen ( glcd_t* glcd, uint8_t pattern ); + +/** + * @name glcd_draw_dots + * @brief Draws multiple dots on the GLCD at specified points. + * + * @details This function draws dots on the GLCD at the specified points with a given size. + * Each point is represented by a structure containing x and y coordinates. The dot size + * determines how many pixels will be filled around each point. + * + * @param ( glcd_t* ) glcd : Pointer to the glcd_t structure containing GLCD configuration and pin mappings. + * @param ( const glcd_point_t* ) pts : Pointer to an array of points where dots will be drawn. + * @param ( uint8_t ) size : The number of points in the array. + * @param ( uint8_t ) dot_size : The size of each dot (1-8). + * @return Nothing + * + * @note This function is used to draw multiple dots on the GLCD. It iterates through each point + * and fills the corresponding pixels based on the specified dot size. If the dot size is out of range, + * it returns without making any changes. + */ +void glcd_draw_dots ( glcd_t* glcd, const glcd_point_t* pts, + uint8_t size, uint8_t dot_size ); + +/** + * @name glcd_draw_line + * @brief Draws a line on the GLCD based on the specified segment and direction. + * + * @details This function draws a line on the GLCD using Bresenham's algorithm for diagonal lines, + * and simple loops for horizontal and vertical lines. The segment is defined by two points, and the + * direction determines how the line is drawn (vertical, horizontal, or diagonal). + * + * @param ( glcd_t* ) glcd : Pointer to the glcd_t structure containing GLCD configuration and pin mappings. + * @param ( const glcd_segment_t* ) s : An array of segment(s) to plot. + * @param ( glcd_line_dir_t ) direction : The direction of the line (VERTICAL_LINE, HORIZONTAL_LINE, DIAGONAL). + * @return Nothing + * + * @note This function handles drawing lines of varying sizes and directions. It checks if the points are within + * valid ranges before attempting to draw. If the points are out of bounds, it returns without making any changes. + */ +void glcd_draw_line ( glcd_t* glcd, const glcd_segment_t* s, + uint8_t s_size, glcd_line_dir_t direction ); + +/** + * @name glcd_draw_rect + * @brief Draws rectangles on the GLCD based on specified points and rectangle sizes. + * + * @details This function draws rectangles on the GLCD at specified points with given sizes. + * Each rectangle is defined by a point (top-left corner) and a size (width, height). + * It can also fill the rectangle if specified. + * + * @param ( glcd_t* ) glcd : Pointer to the glcd_t structure containing GLCD configuration and pin mappings. + * @param ( const glcd_point_t* ) p : Pointer to an array of points defining the top-left corners of rectangles. + * @param ( uint16_t ) psize : The number of points in the array. + * @param ( const glcd_rect_t* ) r : Pointer to an array of rectangles defining their sizes and properties. + * @param ( uint16_t ) rsize : The number of rectangles in the array. + * @return Nothing + * + * @note This function is used to draw multiple rectangles on the GLCD. It iterates through each point and rectangle, + * drawing lines for each side of the rectangle and filling it if specified. If the sizes do not match or if any input + * is invalid, it returns without making any changes. + */ +void glcd_draw_rect ( glcd_t* glcd, const glcd_point_t* p, + uint16_t psize, const glcd_rect_t* r, uint16_t rsize ); + +/** + * @name glcd_draw_shape + * @brief Draws a polygon on the GLCD based on the specified edges and size. + * + * @details This function draws a polygon on the GLCD by connecting the edges defined in the input array. + * It can fill the polygon if specified and can also round the edges if required. + * + * @param ( glcd_t* ) glcd : Pointer to the glcd_t structure containing GLCD configuration and pin mappings. + * @param ( const glcd_segment_t* ) edges : Pointer to an array of segments defining the edges of the polygon. + * @param ( uint8_t ) size : The number of edges in the polygon. + * @param ( bool ) is_filled : Whether to fill the polygon or not. + * @param ( bool ) round_edges : Whether to round the edges of the polygon or not. + * @return Nothing + * + * @note This function is used to draw polygons with varying numbers of edges. It sorts the points + * using a nearest neighbor algorithm and draws lines between them. If filling is enabled, + * it calls Fill_Polygon to fill the area inside the polygon. + */ +void glcd_draw_shape ( glcd_t* glcd, const glcd_segment_t* edges, + uint8_t size, bool is_filled, bool round_edges ); + +/** + * @name glcd_draw_regular_Polygon + * @brief Draws regular polygons on the GLCD based on specified parameters. + * + * @details This function draws regular polygons on the GLCD using a specified number of sides and properties. + * It can also fill the polygon if specified. The polygons are defined by their origin point and properties. + * + * @param ( glcd_t* ) glcd : Pointer to the glcd_t structure containing GLCD configuration and pin mappings. + * @param ( const glcd_point_t* ) ori : Pointer to an array of points defining the origin of each polygon. + * @param ( uint8_t ) num_of_ori : The number of origins in the array. + * @param ( const glcd_polygon_mode_t* ) pol : Pointer to an array of polygon modes defining properties like number of sides, size, and filling. + * @param ( uint8_t ) num_of_pol : The number of polygons in the array. + * @param ( bool ) is_filled : Whether to fill the polygon or not. + * @return Nothing + * + * @note This function is used to draw multiple regular polygons on the GLCD. It calculates the vertices of each polygon + * based on the origin and properties, and draws lines between them. If filling is enabled, it calls Fill_Polygon to fill + * the area inside the polygon. + */ +void glcd_draw_regular_Polygon ( glcd_t* glcd, const glcd_point_t* ori, + uint8_t num_of_ori, const glcd_polygon_mode_t* pol, + uint8_t num_of_pol, bool is_filled ); + +/** + * @name glcd_draw_circle + * @brief Draws circles on the GLCD based on specified circle parameters. + * + * @details This function draws circles on the GLCD using a specified precision for the circle approximation. + * It can also fill the circle if specified. The circles are defined by their center point and radius. + * + * @param ( glcd_t* ) glcd : Pointer to the glcd_t structure containing GLCD configuration and pin mappings. + * @param ( const glcd_circle_t* ) c : Pointer to an array of circles defining their center points, radii, and properties. + * @param ( uint16_t ) csize : The number of circles in the array. + * @param ( glcd_circle_mode_t ) precision : The precision for circle approximation (15-3000 numbers of points). + * @return Nothing + * + * @note This function is used to draw multiple circles on the GLCD. It approximates each circle + * using trigonometric functions and draws lines between points on the circle's circumference. + * If filling is enabled, it calls Fill_Circle to fill the area inside the circle. + */ +void glcd_draw_circle ( glcd_t* glcd, const glcd_circle_t* c, + uint16_t csize, glcd_circle_mode_t precision ); + +/** + * @name glcd_draw_ellipse + * @brief Draws ellipses on the GLCD based on specified ellipse parameters. + * + * @param ( glcd_t* ) glcd : Pointer to the glcd_t structure containing GLCD configuration and pin mappings. + * @param ( const glcd_ellipse_t* ) e : Pointer to an array of ellipses defining their mid-foci, semi-major axis, and properties. + * @param ( uint16_t ) esize : The number of ellipses in the array. + * @param ( glcd_circle_mode_t ) precision : The precision for ellipse approximation (15-3000). + * @return Nothing + * + * @details This function draws ellipses on the GLCD using a specified precision for the ellipse approximation. + * + * @todo This function seems to be incomplete in a sense that sometimes, even if a is changed, the ellipse stays the same. + */ +void glcd_draw_ellipse ( glcd_t* glcd, const glcd_ellipse_t* e, + uint16_t esize, glcd_circle_mode_t precision ); + +/* -------------------------------------------------- Utils -------------------------------------------------- */ +/** + * @name distance + * @brief Calculates the Euclidean distance between two points. + * + * This function computes the straight-line distance between point 'a' and point 'b' + * using the Pythagorean theorem. + * + * @param ( glcd_point_t ) a : The first point with x and y coordinates. + * @param ( glcd_point_t ) b : The second point with x and y coordinates. + * @return ( float ) The Euclidean distance as a float. + * + * @note This function is used to calculate the distance between two points in a 2D space. + * It is commonly used in algorithms that require distance calculations, such as nearest neighbor searches. + */ +float distance ( glcd_point_t a, glcd_point_t b ); + +/** + * @name sort_points_nearest_neighbor + * @brief Sorts points using the nearest neighbor algorithm. + * + * This function sorts an array of segments based on the distance from the origin (0, 0) + * and then arranges them in a sequence that connects each segment to the next closest one. + * + * @param ( const glcd_segment_t* ) input : Pointer to the input array of segments. + * @param ( glcd_segment_t* ) output : Pointer to the output array where sorted segments will be stored. + * @param ( uint8_t ) size : The number of segments in the input array. + * @return Nothing + * + * @note This function is used to sort segments based on their proximity to each other, which can + * be useful in graphical applications where segments need to be drawn in a specific order. + * It uses a nearest neighbor approach to find the optimal order of segments. It assumes that the + * input segments are valid and that the output array has enough space to hold the sorted segments. + */ +void sort_points_nearest_neighbor ( const glcd_segment_t* input, glcd_segment_t* output, uint8_t size ); + +/** + * @name fill_polygon + * @brief Fills a polygon on the GLCD based on the specified edges and size. + * + * @details This function fills a polygon on the GLCD by determining the intersections of the edges + * at each horizontal line and drawing filled segments between these intersections. + * + * @param ( glcd_t* ) glcd : Pointer to the glcd_t structure containing GLCD configuration and pin mappings. + * @param ( const glcd_segment_t* ) edges : Pointer to an array of segments defining the edges of the polygon. + * @param ( uint8_t ) size : The number of edges in the polygon. + * @return Nothing + * + * @note This function is used to fill polygons with a specified size. It sorts the points using a nearest neighbor algorithm, + * determines the intersections for each horizontal line, and fills the area between these intersections. If the input is invalid, + * it returns without making any changes. + */ +void fill_polygon ( glcd_t* glcd, const glcd_segment_t* edges, uint8_t size ); + +/** + * @name fill_circle + * @brief Fills a circle on the GLCD based on the specified contour and precision. + * + * @details This function fills a circle on the GLCD by determining the intersections of the contour + * at each horizontal line and drawing filled segments between these intersections. + * + * @param ( glcd_t* ) glcd : Pointer to the glcd_t structure containing GLCD configuration and pin mappings. + * @param ( const glcd_point_t* ) contour : Pointer to an array of points defining the contour of the circle. + * @param ( uint16_t ) precision : The precision for circle approximation (15-3000). + * @param ( uint8_t ) dot_size : The size of each dot in the filled circle. + * @return Nothing + * + * @note This function is used to fill circles with a specified precision. It calculates intersections + * for each horizontal line, sorts them, and fills the area between these intersections. + * If the input is invalid, it returns without making any changes. + */ +void fill_circle ( glcd_t* glcd, const glcd_point_t* contour, + uint16_t precision, uint8_t dot_size ); + +/** + * @name dot_product + * @brief Calculates the dot product of two vectors defined by three points. + * + * @param ( glcd_point_t ) a : The first point, which serves as the origin for the vectors. + * @param ( glcd_point_t ) b : The second point, which defines the first vector from point 'a'. + * @param ( glcd_point_t ) c : The third point, which defines the second vector from point 'a'. + * @return ( static int ) The dot product of the two vectors as an integer. + * + * @details This function computes the dot product of two vectors defined by the points 'b' and 'c' relative to the origin 'a'. + * The dot product is calculated as the sum of the products of the corresponding components of the vectors. + * It is commonly used in geometry and physics to determine the angle between two vectors or to check if they are orthogonal. + */ +static int dot_product (glcd_point_t a, glcd_point_t b, glcd_point_t c); + +/** + * @name transpose_Word + * @brief Transposes a 64-bit word by swapping its rows and columns. + * + * @param ( uint64_t ) word : The 64-bit word to be transposed. + * @return ( uint64_t ) The transposed 64-bit word. + * + * @details This function takes a 64-bit word and transposes it by swapping its rows and columns. + * It iterates through each bit of the word and rearranges them to create a new word. + */ +uint64_t transpose_word ( uint64_t word ); + +/** + * @name find_matching_char_from_bitmap + * @brief Finds the bitmap code for a given character in the font array. + * + * @param ( char ) c : The character to find in the font array. + * @return ( uint64_t ) The bitmap code corresponding to the character, or 0 if not found. + * + * @details This function searches through the font array for a character and returns its associated bitmap code. + * If the character is not found, it returns 0. The font array is assumed to be defined elsewhere in the code. + */ +uint64_t find_matching_char_from_bitmap ( char c ); + +/** + * @name reverse_byte + * @brief Reverses the bits in a byte. + * + * @param ( uint8_t ) b : The byte to be reversed. + * @return ( uint8_t ) The byte with its bits reversed. + * + * @details This function takes a byte and reverses its bits by performing bitwise operations. + * It shifts the bits to their opposite positions, effectively reversing the order of the bits. + */ +uint8_t reverse_byte ( uint8_t b ); \ No newline at end of file diff --git a/middleware/glcd/lib/src/glcd.c b/middleware/glcd/lib/src/glcd.c new file mode 100644 index 0000000000..1d3dcff1be --- /dev/null +++ b/middleware/glcd/lib/src/glcd.c @@ -0,0 +1,789 @@ +#include "glcd.h" + +const glcd_char_def_t font[] = { + { ' ', 0x0000 }, // 0 + { '!', 0x0808080800080000 }, // 1 + { '"', 0x2828000000000000 }, // 2 + { '#', 0x287C287C28000000 }, // 3 + { '$', 0x081E281C0A3C0800 }, // 4 + { '%', 0x6094681629060000 }, // 5 + { '&', 0x1C20201926190000 }, // 6 + { '\'', 0x0808000000000000 }, // 7 + { '(', 0x0810202010080000 }, // 8 + { ')', 0x1008040408100000 }, // 9 + { '*', 0x2A1C3E1C2A000000 }, // 10 + { '+', 0x08083E0808000000 }, // 11 + { ',', 0x0000000000810000 }, // 12 + { '-', 0x003C000000000000 }, // 13 + { '.', 0x0000000000800000 }, // 14 + { '/', 0x2040810204000000 }, // 15 + { '0', 0x1824424224180000 }, // 16 + { '1', 0x08180808081C0000 }, // 17 + { '2', 0x3C420418207E0000 }, // 18 + { '3', 0x3C420418423C0000 }, // 19 + { '4', 0x081828487C080000 }, // 20 + { '5', 0x7E407C02423C0000 }, // 21 + { '6', 0x3C407C42423C0000 }, // 22 + { '7', 0x7E04081020400000 }, // 23 + { '8', 0x3C423C42423C0000 }, // 24 + { '9', 0x3C42423E023C0000 }, // 25 + { ':', 0x0000000800008000 }, // 26 + { ';', 0x0000000800010000 }, // 27 + { '<', 0x0618601806000000 }, // 28 + { '=', 0x007E00007E000000 }, // 29 + { '>', 0x6018061860000000 }, // 30 + { '?', 0x3844041800100000 }, // 31 + { '@', 0x3C449C945C201C00 }, // 32 + { 'A', 0x1818243C42420000 }, // 33 + { 'B', 0x7844784444780000 }, // 34 + { 'C', 0x3844808044380000 }, // 35 + { 'D', 0x7844444444780000 }, // 36 + { 'E', 0x7C407840407C0000 }, // 37 + { 'F', 0x7C40784040400000 }, // 38 + { 'G', 0x3844809C44380000 }, // 39 + { 'H', 0x42427E4242420000 }, // 40 + { 'I', 0x3E080808083E0000 }, // 41 + { 'J', 0x1C04040444380000 }, // 42 + { 'K', 0x4448507048440000 }, // 43 + { 'L', 0x40404040407E0000 }, // 44 + { 'M', 0x4163554941410000 }, // 45 + { 'N', 0x4262524A46420000 }, // 46 + { 'O', 0x1C222222221C0000 }, // 47 + { 'P', 0x7844784040400000 }, // 48 + { 'Q', 0x1C222222221C0200 }, // 49 + { 'R', 0x7844785048440000 }, // 50 + { 'S', 0x1C22100C221C0000 }, // 51 + { 'T', 0x7F08080808080000 }, // 52 + { 'U', 0x42424242423C0000 }, // 53 + { 'V', 0x8142422424180000 }, // 54 + { 'W', 0x4141495563410000 }, // 55 + { 'X', 0x4224181824420000 }, // 56 + { 'Y', 0x4122140808080000 }, // 57 + { 'Z', 0x7E040810207E0000 }, // 58 + { '[', 0x3820202020380000 }, // 59 + { '\\', 0x4020100804020000 }, // 60 + { ']', 0x3808080808380000 }, // 61 + { '^', 0x1028000000000000 }, // 62 + { '_', 0x00000000007E0000 }, // 63 + { '`', 0x1008000000000000 }, // 64 + { 'a', 0x003C023E463A0000 }, // 65 + { 'b', 0x40407C42625C0000 }, // 66 + { 'c', 0x001C20201C000000 }, // 67 + { 'd', 0x0008080838483800 }, // 68 + { 'e', 0x003C427E403C0000 }, // 69 + { 'f', 0x0018103810100000 }, // 70 + { 'g', 0x00344C4434043800 }, // 71 + { 'h', 0x2020382424240000 }, // 72 + { 'i', 0x0008001808080800 }, // 73 + { 'j', 0x0008001808283800 }, // 74 + { 'k', 0x20202428302C0000 }, // 75 + { 'l', 0x1010101010180000 }, // 76 + { 'm', 0x00665A4242000000 }, // 77 + { 'n', 0x002E322222000000 }, // 78 + { 'o', 0x003C42423C000000 }, // 79 + { 'p', 0x005C62427C404000 }, // 80 + { 'q', 0x003A46423E020200 }, // 81 + { 'r', 0x002C322020000000 }, // 82 + { 's', 0x001C201804380000 }, // 83 + { 't', 0x00103C1010180000 }, // 84 + { 'u', 0x002222261A000000 }, // 85 + { 'v', 0x0042422418000000 }, // 86 + { 'w', 0x0081815A66000000 }, // 87 + { 'x', 0x0042241866000000 }, // 88 + { 'y', 0x0042211408106000 }, // 89 + { 'z', 0x003C08103C000000 }, // 90 + { '{', 0x1C103030101C0000 }, // 91 + { '|', 0x0808080808080800 }, // 92 + { '}', 0x38080C0C08380000 }, // 93 + { '~', 0x0000324C00000000 }, // 94 +}; + +void glcd_config_default( glcd_t* glcd_cfg ) +{ + glcd_cfg->config.GLCD_E_PIN = TFT_E; + glcd_cfg->config.GLCD_RW_PIN = TFT_R_W; + glcd_cfg->config.GLCD_RS_PIN = TFT_RS; + glcd_cfg->config.GLCD_CS2_PIN = TFT_CS2; + glcd_cfg->config.GLCD_CS1_PIN = TFT_CS1; + glcd_cfg->config.GLCD_RESET_PIN = TFT_RST; + + glcd_cfg->config.data_out = TFT_8BIT_DATA_PORT_CH0; // Default port for data output +} + +void glcd_port_init( glcd_t* glcd ) +{ + port_init( &glcd->data_out, glcd->config.data_out, 0xFF, HAL_LL_GPIO_DIGITAL_OUTPUT ); + digital_out_init( &glcd->cs1d, glcd->config.GLCD_CS1_PIN ); + digital_out_init( &glcd->cs2d, glcd->config.GLCD_CS2_PIN ); + digital_out_init( &glcd->ed, glcd->config.GLCD_E_PIN ); + digital_out_init( &glcd->resetd, glcd->config.GLCD_RESET_PIN ); + digital_out_init( &glcd->rsd, glcd->config.GLCD_RS_PIN ); + digital_out_init( &glcd->rwd, glcd->config.GLCD_RW_PIN ); +} + +void glcd_init( glcd_t* glcd ) +{ + glcd_config_default( glcd ); + glcd_port_init( glcd ); + + digital_out_high( &glcd->ed ); + digital_out_high( &glcd->cs1d ); + digital_out_high( &glcd->cs2d ); + digital_out_high( &glcd->resetd ); + digital_out_low( &glcd->rsd ); + digital_out_high( &glcd->rwd ); + apply_changes(glcd); +} + +void glcd_set_page( glcd_t* glcd, uint8_t page ) +{ + if ( !glcd || page > 7 ) return; + + digital_out_low( &glcd->rsd ); // RS = 0 (instruction) + digital_out_low( &glcd->rwd ); // RW = 0 (write) + port_write( &glcd->data_out, (0xB8 | (page & 0x07)) ); // We only care about the lower 3 bits for page address + apply_changes(glcd); +} + +void glcd_set_y( glcd_t* glcd, uint8_t y_pos ) +{ + if ( !glcd || y_pos > 64 ) return; + + digital_out_low( &glcd->rsd ); // RS = 0 (instruction) + digital_out_low( &glcd->rwd ); // RW = 0 (write) + port_write( &glcd->data_out, (0x40 | (y_pos & 0x3F)) ); + apply_changes(glcd); +} + +void glcd_clear(glcd_t *glcd) +{ + if (!glcd) return; + + for (uint8_t page = 0; page < PAGE_SIZE; page++) + for (uint8_t col = 0; col <= ROW_SIZE; col++) + glcd_write(glcd, page, col, 0x00); +} + +void glcd_display( glcd_t* glcd, glcd_display_cfg_t turn_on_off ) +{ + if ( !glcd || (turn_on_off != GLCD_DISPLAY_ON && turn_on_off != GLCD_DISPLAY_OFF )) { return; } + + for (uint8_t k = 0; k < 2; k++) + { + cs_config( glcd, k%2, (k+1)%2 ); + digital_out_low( &glcd->rsd ); // RS = 0 (instruction) + digital_out_low( &glcd->rwd ); // RW = 0 (write) + port_write( &glcd->data_out, turn_on_off ); + apply_changes(glcd); + } +} + +void apply_changes( glcd_t* glcd ) +{ + digital_out_high( &glcd->ed ); + Delay_us(10); + digital_out_low( &glcd->ed ); + Delay_us(10); +} + +void cs_config(glcd_t* glcd, bool cs1, bool cs2) +{ + if (!glcd) return; + digital_out_write(&glcd->cs1d, (cs1 == 1) ? 0 : 1); + digital_out_write(&glcd->cs2d, (cs2 == 1) ? 0 : 1); +} + +/* -------------------------------------------------- Read and Write functions -------------------------------------------------- */ +uint8_t glcd_read( glcd_t* glcd, uint8_t page, uint8_t column ) +{ + if (!glcd || page >= PAGE_SIZE || column >= ROW_SIZE) return 0; + + uint8_t chip = (column < 64) ? 0 : 1; + uint8_t col_in_chip = column % 64; + return glcd->buffer[chip][page][col_in_chip]; +} + +uint8_t glcd_reqd_ll( glcd_t* glcd, uint8_t page, uint8_t column ) +{ + if (!glcd || page >= PAGE_SIZE || column >= ROW_SIZE) return 0; + + port_init( &glcd->data_out, PORT_E, 0xFF, HAL_LL_GPIO_DIGITAL_INPUT ); + uint8_t chip = (column < 64) ? 0 : 1; + uint8_t col_in_chip = column % 64; + + cs_config(glcd, chip == 0, chip == 1); + glcd_set_y(glcd, col_in_chip); + glcd_set_page(glcd, page); + + digital_out_high(&glcd->rsd); + digital_out_high(&glcd->rwd); + + // Dummy read (necessary for the GLCD to prepare for reading) + digital_out_high(&glcd->ed); // E = 1 + Delay_us(1); // tWH ≥ 450 ns (from datasheet) + digital_out_low(&glcd->ed); // E = 0 + Delay_us(1); + + uint8_t data_readed = port_read(&glcd->data_out); + port_init( &glcd->data_out, PORT_E, 0xFF, HAL_LL_GPIO_DIGITAL_OUTPUT ); + apply_changes(glcd); + + return data_readed; +} + +void glcd_write( glcd_t *glcd, uint8_t page, uint8_t line, uint8_t data_to_write ) +{ + if (!glcd || page > PAGE_SIZE || line > ROW_SIZE) return; + + if (line < 64) + { + cs_config(glcd, 1, 0); + glcd_set_y(glcd, line); + glcd_set_page(glcd, page); + } + else + { + cs_config(glcd, 0, 1); + glcd_set_y(glcd, line-64); + glcd_set_page(glcd, page); + } + digital_out_low(&glcd->ed); + digital_out_high(&glcd->rsd); + digital_out_low(&glcd->rwd); + port_write(&glcd->data_out, data_to_write); + apply_changes(glcd); + + glcd->buffer[(line < 64) ? 0 : 1][page][line % 64] = data_to_write; +} + +void glcd_write_char( glcd_t* glcd, glcd_point_t* p, char c ) +{ + uint8_t page = p->y / 8; + uint8_t line = p->x % 128; + uint64_t res = transpose_word(find_matching_char_from_bitmap(c)); + + for (uint8_t i = 0; i < 8; i++) + { + uint8_t byte = (res >> (8 * (7 - i))) & 0xFF; + byte = reverse_byte(byte); + glcd_write(glcd, page, line + i, byte); + } +} + +void glcd_write_text( glcd_t* glcd, glcd_point_t* p, const char* c ) +{ + if (!glcd || !p || !c) return; + + glcd_point_t pos = *p; + size_t len = strlen(c); + for (size_t i = 0; i < len; i++) + { + glcd_write_char(glcd, &pos, c[i]); + pos.x += 8; + + if (pos.x >= 128) { + pos.x = 0; + pos.y += 8; + if (pos.y >= 64) break; + } + } +} + +/* -------------------------------------------------- Drawing functions -------------------------------------------------- */ +void glcd_fill_screen( glcd_t* glcd, uint8_t pattern ) +{ + if (!glcd) return; + + for (uint8_t page = 0; page < PAGE_SIZE; page++) + for (uint8_t col = 0; col <= ROW_SIZE; col++) + glcd_write(glcd, page, col, pattern); +} + +void glcd_draw_dots( glcd_t* glcd, const glcd_point_t* pts, uint8_t size, uint8_t dot_size ) +{ + if (!glcd || !pts || dot_size == 0 || dot_size > 8) return; + + for (uint8_t i = 0; i < size; i++) + { + uint8_t x = pts[i].x; + uint8_t y = pts[i].y; + + if (x >= 128 || y >= 64) continue; + + uint8_t page = y / 8; + uint8_t y_offset = y % 8; + + for (uint8_t dx = 0; dx < dot_size; dx++) + { + if (x + dx >= 128) continue; + for (uint8_t dy = 0; dy < dot_size; dy++) + { + uint8_t current_y = y + dy; + if (current_y >= 64) continue; + + uint8_t current_page = current_y / 8; + uint8_t bit_in_page = current_y % 8; + + uint8_t prev = glcd_read(glcd, current_page, x + dx); + prev |= (1 << bit_in_page); + glcd_write(glcd, current_page, x + dx, prev); + } + } + } +} + +void glcd_draw_line( glcd_t* glcd, const glcd_segment_t* s, uint8_t s_size, glcd_line_dir_t direction ) +{ + if (!glcd || !s) return; + + for (uint8_t i = 0; i < s_size; i++) + { + glcd_point_t p0 = s[i].pts[0], p1 = s[i].pts[1]; + uint8_t thickness = s[i].line_size; + + if (p0.x >= 128 || p1.x >= 128 || p0.y >= 64 || p1.y >= 64 || + p0.x < 0 || p1.x < 0 || p0.y < 0 || p1.y < 0) + continue; + + switch (direction) + { + case VERTICAL_LINE: + { + if (p0.x != p1.x) break; + int x = p0.x; + int y0 = (p0.y < p1.y) ? p0.y : p1.y; + int y1 = (p0.y > p1.y) ? p0.y : p1.y; + + for (int y = y0; y <= y1 && y < 64; y++) + { + for (uint8_t dx = 0; dx < thickness; dx++) + { + int cx = x + dx; + if (cx >= 128) continue; + + uint8_t page = y / 8; + uint8_t bit_in_page = 1 << (y % 8); + uint8_t val = glcd_read(glcd, page, cx); + glcd_write(glcd, page, cx, val | bit_in_page); + } + } + break; + } + + case HORIZONTAL_LINE: + { + if (p0.y != p1.y) break; + int y = p0.y; + int x0 = (p0.x < p1.x) ? p0.x : p1.x; + int x1 = (p0.x > p1.x) ? p0.x : p1.x; + + for (int x = x0; x <= x1 && x < 128; x++) + { + for (uint8_t dy = 0; dy < thickness; dy++) + { + int cy = y + dy; + if (cy >= 64) continue; + + uint8_t page = cy / 8; + uint8_t bit_in_page = 1 << (cy % 8); + uint8_t val = glcd_read(glcd, page, x); + glcd_write(glcd, page, x, val | bit_in_page); + } + } + break; + } + + case DIAGONAL: + { + int x0 = p0.x, y0 = p0.y; + int x1 = p1.x, y1 = p1.y; + int dx = abs(x1 - x0), dy = abs(y1 - y0); + int sx = (x0 < x1) ? 1 : -1; + int sy = (y0 < y1) ? 1 : -1; + int err = dx - dy; + + while (1) + { + for (uint8_t dy_dot = 0; dy_dot < thickness; dy_dot++) + { + for (uint8_t dx_dot = 0; dx_dot < thickness; dx_dot++) + { + int x = x0 + dx_dot; + int y = y0 + dy_dot; + if (x < 0 || x >= 128 || y < 0 || y >= 64) continue; + + uint8_t page = y / 8; + uint8_t bit_in_page = 1 << (y % 8); + uint8_t val = glcd_read(glcd, page, x); + glcd_write(glcd, page, x, val | bit_in_page); + } + } + + if (x0 == x1 && y0 == y1) break; + + int e2 = 2 * err; + if (e2 > -dy) { err -= dy; x0 += sx; } + if (e2 < dx) { err += dx; y0 += sy; } + } + break; + } + } + } +} + +void glcd_draw_rect( glcd_t* glcd, const glcd_point_t* p, uint16_t psize, const glcd_rect_t* r, uint16_t rsize ) +{ + if (!glcd || !r || !p || psize != rsize ) return; + + for (uint16_t i=0; i 10) continue; + + glcd_point_t polygon_points[10]; + glcd_segment_t edges[10]; + + for (uint8_t i = 0; i < sides; i++) + { + float angle = (2 * PI * i) / sides; + int16_t x = ori[p].x + (int16_t)(20 * cos(angle)); + int16_t y = ori[p].y + (int16_t)(20 * sin(angle)); + + polygon_points[i].x = x; + polygon_points[i].y = y ; + } + + for (uint8_t i = 0; i < sides; i++) + { + edges[i].pts[0] = polygon_points[i]; + edges[i].pts[1] = polygon_points[(i + 1) % sides]; + edges[i].line_size = 2; + } + + glcd_draw_line(glcd, edges, sides, DIAGONAL); + if (is_filled) fill_polygon(glcd, edges, sides); + } +} + +void glcd_draw_circle( glcd_t* glcd, const glcd_circle_t* c, uint16_t csize, glcd_circle_mode_t precision ) +{ + if ( !glcd || !c ) return; + + glcd_point_t circle_approx[5000]; + for (uint16_t i = 0; i < csize; i++) + { + uint8_t radius = c[i].r, dot_size = c[i].line_size; + glcd_point_t origin = c[i].o; + + for (uint16_t j = 0; j < precision; j++) + { + circle_approx[j].x = origin.x + (int16_t)(radius * cos((2 * PI * j) / precision)); + circle_approx[j].y = origin.y + (int16_t)(radius * sin((2 * PI * j) / precision)); + } + + for (uint16_t j = 0; j < precision; j++) + { + glcd_segment_t s = { + { + {circle_approx[j].x, circle_approx[j].y}, + {circle_approx[(j + 1) % precision].x, circle_approx[(j + 1) % precision].y} + }, + dot_size + }; + glcd_draw_line(glcd, &s, 1, DIAGONAL); + } + if (c[i].filled) { fill_circle(glcd, circle_approx, precision, dot_size); } + } +} + +void glcd_draw_ellipse( glcd_t* glcd, const glcd_ellipse_t* e, uint16_t esize, glcd_circle_mode_t precision ) +{ + if (!glcd || !e || esize == 0 || precision < 3 || precision > 5000) return; + + for (uint16_t i = 0; i < esize; i++) + { + float cx = e[i].mid_foci[0].x, cy = e[i].mid_foci[0].y; + float fx = e[i].mid_foci[1].x, fy = e[i].mid_foci[1].y; + float dx = fx - cx, dy = fy - cy; + float c_val = sqrt(dx * dx + dy * dy); + float a = e[i].a; + if (a <= c_val) a = c_val + 5; // Ensure valid ellipse + float b = sqrt(a * a - c_val * c_val); + + float theta_axis = atan2(dy, dx); + uint8_t dot_size = e[i].line_size; + bool is_filled = e[i].filled; + + glcd_point_t ellipse_points[5000]; + for (uint16_t j = 0; j < precision; j++) + { + float theta = (2.0f * PI * j) / precision; + float x_local = a * cos(theta); + float y_local = b * sin(theta); + float x_rot = x_local * cos(theta_axis) - y_local * sin(theta_axis); + float y_rot = x_local * sin(theta_axis) + y_local * cos(theta_axis); + float x = cx + x_rot; + float y = cy + y_rot; + + ellipse_points[j].x = (uint8_t)(x + 0.5f); + ellipse_points[j].y = (uint8_t)(y + 0.5f); + } + + for (uint16_t k = 0; k < precision; k++) + { + glcd_segment_t s = { + { + { ellipse_points[k].x, ellipse_points[k].y }, + { ellipse_points[(k + 1) % precision].x, ellipse_points[(k + 1) % precision].y } + }, + dot_size + }; + glcd_draw_line(glcd, &s, 1, DIAGONAL); + } + if (is_filled) { fill_circle(glcd, ellipse_points, precision, dot_size); } + } +} +/* +void dvd_animation( glcd_t* glcd ) {} +*/ + + +/* -------------------------------------------------- Utils -------------------------------------------------- */ +float distance( glcd_point_t a, glcd_point_t b ) +{ + int dx = a.x - b.x; + int dy = a.y - b.y; + return sqrt(dx * dx + dy * dy); +} + +void sort_points_nearest_neighbor( const glcd_segment_t* input, glcd_segment_t* output, uint8_t size ) +{ + if (!input || !output || size == 0) return; + + bool visited[64] = { false }; + uint8_t current = 0; + + float min_dist = 1e9; + for (uint8_t i = 0; i < size; i++) + { + float d = distance((glcd_point_t){0, 0}, input[i].pts[0]); + if (d < min_dist) { min_dist = d; current = i; } + } + + output[0] = input[current]; + visited[current] = true; + + for (uint8_t i = 1; i < size; i++) + { + float best_dist = 1e9; + uint8_t next = 0; + for (uint8_t j = 0; j < size; j++) + { + if (!visited[j]) + { + float d = distance(output[i - 1].pts[1], input[j].pts[0]); + if (d < best_dist) { best_dist = d; next = j; } + } + } + output[i] = input[next]; + visited[next] = true; + } +} + +void fill_polygon( glcd_t* glcd, const glcd_segment_t* edges, uint8_t size ) +{ + if (!glcd || !edges || size < 3) return; + + for (uint8_t i = 0; i < size; i++) { if (edges[i].line_size != edges[(i+1)%size].line_size) return; } + uint8_t min_y = 255, max_y = 0, dot_size = edges[0].line_size; + for (uint8_t i = 0; i < size; i++) + { + if (edges[i].pts[0].y < min_y) min_y = edges[i].pts[0].y; + if (edges[i].pts[0].y > max_y) max_y = edges[i].pts[0].y; + if (edges[i].pts[1].y < min_y) min_y = edges[i].pts[1].y; + if (edges[i].pts[1].y > max_y) max_y = edges[i].pts[1].y; + } + + glcd_segment_t sorted[64]; + sort_points_nearest_neighbor(edges, sorted, size); + + for (uint8_t y = min_y; y <= max_y; y++) + { + uint8_t x_intersections[64]; + uint8_t nb_x = 0; + + for (uint8_t i = 0; i < size; i++) + { + glcd_point_t p1 = sorted[i].pts[0], p2 = sorted[i].pts[1]; + if (p1.y == p2.y) continue; + if (p1.y > p2.y) { glcd_point_t temp = p1; p1 = p2; p2 = temp; } + + if (y >= p1.y && y < p2.y) + { + int16_t dx = p2.x - p1.x; + int16_t dy = p2.y - p1.y; + uint8_t x = p1.x + (dx * (y - p1.y)) / dy; + if (nb_x < 64) x_intersections[nb_x++] = x; + } + } + + // Bubble sorting + for (uint8_t i = 0; i < nb_x - 1; i++) + { + for (uint8_t j = 0; j < nb_x - i - 1; j++) + { + if (x_intersections[j] > x_intersections[j + 1]) + { + uint8_t tmp = x_intersections[j]; + x_intersections[j] = x_intersections[j + 1]; + x_intersections[j + 1] = tmp; + } + } + } + + for (uint8_t i = 0; i + 1 < nb_x; i += 2) + { + glcd_segment_t s = { { { x_intersections[i], y }, { x_intersections[i + 1], y } }, dot_size }; + glcd_draw_line(glcd, &s, 1, HORIZONTAL_LINE); + } + } +} + +void fill_circle( glcd_t* glcd, const glcd_point_t* contour, uint16_t precision, uint8_t dot_size ) +{ + if (!glcd || !contour || dot_size == 0) return; + + uint8_t min_y = 255, max_y = 0; + for (uint16_t i = 0; i < precision; i++) + { + if (contour[i].y < min_y) min_y = contour[i].y; + if (contour[i].y > max_y) max_y = contour[i].y; + } + + for (uint8_t y = min_y; y <= max_y; y++) + { + uint8_t x_intersections[128]; + uint8_t count_x = 0; + + for (uint16_t i = 0; i < precision; i++) + { + glcd_point_t p1 = contour[i]; + glcd_point_t p2 = contour[(i + 1) % precision]; + + if (p1.y == p2.y) continue; + if (p1.y > p2.y) + { + glcd_point_t tmp = p1; + p1 = p2; + p2 = tmp; + } + + if (y >= p1.y && y < p2.y) + { + float dx = p2.x - p1.x; + float dy = p2.y - p1.y; + float x = p1.x + dx * (float)(y - p1.y) / dy; + if (count_x < 128) + x_intersections[count_x++] = (uint8_t)(x + 0.5f); + } + } + + for (uint8_t j = 0; j < count_x - 1; j++) + { + for (uint8_t k = 0; k < count_x - j - 1; k++) + { + if (x_intersections[k] > x_intersections[k + 1]) + { + uint8_t temp = x_intersections[k]; + x_intersections[k] = x_intersections[k + 1]; + x_intersections[k + 1] = temp; + } + } + } + + for (uint8_t j = 0; j + 1 < count_x; j += 2) + { + glcd_segment_t s = { {{ x_intersections[j], y }, { x_intersections[j + 1], y }}, dot_size }; + glcd_draw_line(glcd, &s, 1, DIAGONAL); + } + } +} + +static int dot_product( glcd_point_t a, glcd_point_t b, glcd_point_t c ) +{ + int ux = b.x - a.x; + int uy = b.y - a.y; + int vx = c.x - a.x; + int vy = c.y - a.y; + return ux * vx + uy * vy; +} + +uint64_t transpose_word(uint64_t word) +{ + uint64_t result = 0; + + for (uint8_t row = 0; row < 8; row++) + for (uint8_t col = 0; col < 8; col++) + if (word & (1ULL << (col * 8 + row))) + result |= (1ULL << (row * 8 + col)); + + return result; +} + + +uint64_t find_matching_char_from_bitmap(char c) +{ + uint8_t size = sizeof(font) / sizeof(font[0]); + for (uint8_t i=0; i> 4 | (b & 0x0F) << 4; + b = (b & 0xCC) >> 2 | (b & 0x33) << 2; + b = (b & 0xAA) >> 1 | (b & 0x55) << 1; + return b; +} \ No newline at end of file diff --git a/middleware/lcd/lib/include/drivers/lcd_controllers.h b/middleware/lcd/lib/include/drivers/lcd_controllers.h index 6b02056877..3f224978ce 100644 --- a/middleware/lcd/lib/include/drivers/lcd_controllers.h +++ b/middleware/lcd/lib/include/drivers/lcd_controllers.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) ${COPYRIGHT_YEAR} MikroElektronika d.o.o. +** Copyright (C) MikroElektronika d.o.o. ** Contact: https://www.mikroe.com/contact ** ** Commercial License Usage diff --git a/targets/arm/mikroe/common/include/flatten_me.h b/targets/arm/mikroe/common/include/flatten_me.h new file mode 100644 index 0000000000..446641823e --- /dev/null +++ b/targets/arm/mikroe/common/include/flatten_me.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) MikroElektronika d.o.o. +** Contact: https://www.mikroe.com/contact +** +** Commercial License Usage +** +** Licensees holding valid commercial NECTO compilers AI licenses may use this +** file in accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The MikroElektronika Company. +** For licensing terms and conditions see +** https://www.mikroe.com/legal/software-license-agreement. +** For further information use the contact form at +** https://www.mikroe.com/contact. +** +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used for +** non-commercial projects under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** The above copyright notice and this permission notice shall be +** included in all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +** OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT +** OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +** OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************/ +/*! + * @file flatten_me.h + * @brief mikroSDK code flattener level selection. + */ + +#ifndef __FLATTEN_ME_H__ +#define __FLATTEN_ME_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Flattening levels. + * @ref FLATTEN_ME_LEVEL_NONE - no code flattening done. + * @ref FLATTEN_ME_LEVEL_LOW - flatten only HAL_LL APIs. + * @ref FLATTEN_ME_LEVEL_MID - flatten only HAL_LL and HAL APIs. + * @ref FLATTEN_ME_LEVEL_HIGH - flatten all layered APIs (HAL_LL, HAL and DRV). + */ +#define FLATTEN_ME_LEVEL_NONE (0) +#define FLATTEN_ME_LEVEL_LOW (1) +#define FLATTEN_ME_LEVEL_MID (2) +#define FLATTEN_ME_LEVEL_HIGH (3) + +// Flatten code or not? +#define FLATTEN_ME + +// Flatten level selection. +#define FLATTEN_ME_LEVEL FLATTEN_ME_LEVEL_HIGH + +#ifdef __cplusplus +} +#endif + +#endif // __FLATTEN_ME_H__ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ad027b29c7..abab1451e8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -107,7 +107,7 @@ endif() memory_sdk_test_check(memory_issue 12288 2048) find_package(MikroSDK.Driver.CAN) -if(MikroSDK.Driver.CAN\_FOUND) +if(MikroSDK.Driver.CAN_FOUND) if (${memory_issue} STREQUAL "FALSE") add_subdirectory(can) else() @@ -117,14 +117,16 @@ endif() add_subdirectory(one_wire) -add_subdirectory(lcd) +# add_subdirectory(lcd) + +add_subdirectory(glcd) if (_MSDK_TFT_BOARD_) ## MikroE GL find_package(MikroSDK.GraphicLibrary) - if (MikroSDK.GraphicLibrary\_FOUND) + if (MikroSDK.GraphicLibrary_FOUND) find_package(Components.TftBoard8) - if (Components.TftBoard8\_FOUND) + if (Components.TftBoard8_FOUND) add_subdirectory(gl) endif() endif() @@ -148,7 +150,7 @@ endif() memory_sdk_test_check(memory_issue 12288 2048) find_package(MikroSDK.Driver.DMA) -if(MikroSDK.Driver.DMA\_FOUND) +if(MikroSDK.Driver.DMA_FOUND) if (${memory_issue} STREQUAL "FALSE") add_subdirectory(dma) else() diff --git a/tests/glcd/CMakeLists.txt b/tests/glcd/CMakeLists.txt new file mode 100644 index 0000000000..309182190c --- /dev/null +++ b/tests/glcd/CMakeLists.txt @@ -0,0 +1,12 @@ +## ./tests/glcd/CMakeLists.txt +add_executable(test_glcd + src/main.c + ReadMe.txt +) + + +target_link_libraries(test_glcd PUBLIC + MikroC.Core + MikroSDK.GLCD + MikroSDK.Board +) diff --git a/tests/glcd/ReadMe.txt b/tests/glcd/ReadMe.txt new file mode 100644 index 0000000000..ffc90a84ec --- /dev/null +++ b/tests/glcd/ReadMe.txt @@ -0,0 +1,3 @@ +Example is meant for testing GLCD module using mikroSDK 2.0 + +Go step by step through the example and follow instructions for testing. diff --git a/tests/glcd/src/main.c b/tests/glcd/src/main.c new file mode 100644 index 0000000000..a8f9a788ad --- /dev/null +++ b/tests/glcd/src/main.c @@ -0,0 +1,183 @@ +// ------------------------------------------------------------------ INCLUDES + +/** + * Any initialization code needed for MCU to function properly. + * Do not remove this line or clock might not be set correctly. + */ +#ifdef PREINIT_SUPPORTED +#include "preinit.h" +#endif + +#include "glcd.h" + +/** + * @brief Main function for GLCD test. + * @details Initializes the GLCD and displays a simple pattern (dots, segements). + * @return Nothing. + */ +static void test1( void ); + +/** + * @brief Secondary test function. + * @details This function can be used to test additional GLCD functionalities (circle, rectangles, ellipses). + * @return Nothing. + */ +static void test2( void ); + +/** + * @brief Third test function. + * @details This function can be used to test additional GLCD functionalities (character and text writing). + * @return Nothing. + */ +static void test3( void ); + +int main(void) +{ + /* Do not remove this line or clock might not be set correctly. */ + #ifdef PREINIT_SUPPORTED + preinit(); + #endif + + while (1) + { + // Run the first test to initialize GLCD and display some patterns. + test1(); + + // Run the second test to draw circles and ellipses. + test2(); + + // Run the third test to write characters and text on GLCD. + test3(); + + } + return 0; +} + +static void test1( void ) +{ + glcd_t glcd; + glcd_init(&glcd); + glcd_display(&glcd, GLCD_DISPLAY_ON); + glcd_clear(&glcd); + + glcd_point_t pts[] = { {10, 10}, {20, 20}, {30, 30} }; + glcd_draw_dots(&glcd, pts, sizeof(pts) / sizeof(pts[0]), 2); + + Delay_ms(1000); + glcd_clear(&glcd); + + glcd_segment_t s = { {{10, 10}, {50, 50}}, 2 }; + glcd_draw_line(&glcd, &s, 1, DIAGONAL); + Delay_ms(1000); + glcd_clear(&glcd); +} + +static void test2( void ) +{ + glcd_t glcd; + glcd_init(&glcd); + glcd_display(&glcd, GLCD_DISPLAY_ON); + glcd_clear(&glcd); + + glcd_point_t d = {32, 32}; + glcd_rect_t r = { 80, 30, 2, false, false }; + glcd_draw_rect(&glcd, &d, 1, &r, 1); + Delay_ms(1000); + glcd_clear(&glcd); + + glcd_circle_t c = { {64, 32}, 20, 2, true }; + glcd_draw_circle(&glcd, &c, 1, DEFAULT); + Delay_ms(1000); + glcd_clear(&glcd); + + glcd_ellipse_t e = { {{64, 32}, {80, 32}}, 30.0f, 2, true }; + glcd_draw_ellipse(&glcd, &e, 1, DEFAULT); + Delay_ms(1000); + glcd_clear(&glcd); + + glcd_point_t p[10] = { + { 10, 10 }, { 20, 20 }, { 30, 30 }, { 40, 40 }, + { 50, 50 }, { 60, 60 }, { 70, 70 }, { 80, 80 }, + { 90, 90 }, {100,100} + }; + glcd_rect_t r2[10] = { + { 10, 20, 2, false, false }, + { 20, 30, 2, false, false }, + { 30, 40, 2, false, false }, + { 40, 50, 2, false, false }, + { 50, 60, 2, false, false }, + { 60, 70, 2, false, false }, + { 70, 80, 2, false, false }, + { 80, 90, 2, false, false }, + { 90, 100, 2, false, false }, + { 100, 110, 2, false, false } + }; + for (uint8_t i = 0; i < 10; i++) { + glcd_draw_rect(&glcd, &p[i], 1, &r2[i], 1); + Delay_ms(1000); + glcd_clear(&glcd); + } + + glcd_circle_t c2[10] = { + { {64, 32}, 10, 2, true }, + { {64, 32}, 15, 2, false }, + { {64, 32}, 20, 2, true }, + { {64, 32}, 25, 2, false }, + { {64, 32}, 30, 2, true }, + { {64, 32}, 35, 2, false }, + { {64, 32}, 40, 2, false }, + { {64, 32}, 45, 2, false }, + { {64, 32}, 50, 2, false }, + { {64, 32}, 55, 2, false } + }; + for (uint8_t i = 0; i < 10; i++) { + glcd_draw_circle(&glcd, &c2[i], 1, DEFAULT); + Delay_ms(500); + glcd_clear(&glcd); + } + + glcd_ellipse_t e2[10] = { + { {{64, 32}, {100, 32}}, 20.0f, 2, true }, + { {{64, 32}, {100, 32}}, 25.0f, 2, false }, + { {{64, 32}, {100, 32}}, 30.0f, 2, true }, + { {{64, 32}, {100, 32}}, 35.0f, 2, false }, + { {{64, 32}, {100, 32}}, 40.0f, 2, false }, + { {{64, 32}, {100, 32}}, 45.0f, 2, false }, + { {{64, 32}, {100, 32}}, 50.0f, 2, false }, + { {{64, 32}, {100, 32}}, 55.0f, 2, false }, + { {{64, 32}, {100, 32}}, 60.0f, 2, false }, + { {{64, 32}, {100, 32}}, 65.0f, 2, false } + }; + for (uint8_t i = 0; i < 10; i++) { + glcd_draw_ellipse(&glcd, &e2[i], 1, DEFAULT); + Delay_ms(500); + glcd_clear(&glcd); + } +} + +static void test3( void ) +{ + glcd_t glcd; + glcd_init(&glcd); + glcd_display(&glcd, GLCD_DISPLAY_ON); + glcd_clear(&glcd); + + glcd_point_t p = { 10, 10 }; + glcd_write_char(&glcd, &p, 'A'); + Delay_ms(500); + p.x += 8; // Move to next character position + glcd_write_char(&glcd, &p, 'B'); + Delay_ms(500); + p.x += 8; // Move to next character position + glcd_write_char(&glcd, &p, 'C'); + Delay_ms(500); + + const char* text = "Hello GLCD!"; + p.x = 10; // Reset x position + p.y += 16; // Move to next line + glcd_write_text(&glcd, &p, text); + Delay_ms(500); + glcd_clear(&glcd); +} + +// ----------------------------------------------------------------------- END