Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
500Foods committed Jun 18, 2024
2 parents fdabde4 + b689cab commit 6347693
Show file tree
Hide file tree
Showing 9 changed files with 508 additions and 6 deletions.
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,19 +57,19 @@ There are countless tools, frameworks, coding styles, conventions, languages, an
[![Count Lines of Code](https://github.com/500Foods/Template/actions/workflows/main.yml/badge.svg)](https://github.com/500Foods/Template/actions/workflows/main.yml)
<!--CLOC-START -->
```
Last updated at 2024-06-16 20:21:38 UTC
Last updated at 2024-06-18 08:11:23 UTC
-------------------------------------------------------------------------------
Language files blank comment code
-------------------------------------------------------------------------------
C 13 499 87 2573
Markdown 22 127 2 1231
C/C++ Header 9 53 9 172
C 16 574 106 2858
Markdown 23 135 2 1259
C/C++ Header 11 68 9 204
Bourne Shell 3 28 56 79
Text 1 0 0 75
make 2 23 15 39
make 3 35 16 66
YAML 2 8 13 35
-------------------------------------------------------------------------------
SUM: 52 738 182 4204
SUM: 59 848 202 4576
-------------------------------------------------------------------------------
6 Files (without source code) were skipped
```
Expand Down
5 changes: 5 additions & 0 deletions elements/007-nitrogen/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,8 @@ This is a small self-contained test project that takes an inventory of local net
wireless interfaces, it displays all the available SSIDs. This is likely to be incorporated into nitrogen elements. Imagine starting the equivalent of KlipperScreen
on a device that has not yet been connected to a network. This kind of information is used to feed the UI so the user can select a network interface to configure
and in the case of WiFi, select an SSID for the connection.

## Prototyping: lvgldemo
This is a small self-contained test project that uses LVGL to display a gradient background and some text. Nothing too fancy, just enough to demonstrate that LVGL
is working in our code, and can display something non-trivial. Well, it's trivial but a white screen or a black screen could be displayed with all the driver stuff
horribly wrong.
40 changes: 40 additions & 0 deletions elements/007-nitrogen/lvgldemo/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
CC = gcc
CFLAGS = -std=c17 -Wall -Wextra -I./libs/lvgl -I./src -g
LDFLAGS = -lm -lpthread -lGL -lSDL2

SRC_DIR = src
LIB_DIR = libs
BUILD_DIR = build

# Exclude sdltest.c from SOURCES
SOURCES = $(filter-out $(SRC_DIR)/sdltest.c, $(wildcard $(SRC_DIR)/*.c))
LVGL_SOURCES = $(shell find $(LIB_DIR)/lvgl/src -name '*.c')

OBJECTS = $(patsubst $(SRC_DIR)/%.c,$(BUILD_DIR)/%.o,$(SOURCES))
LVGL_OBJECTS = $(patsubst $(LIB_DIR)/%.c,$(BUILD_DIR)/%.o,$(LVGL_SOURCES))

TARGET = lvgldemo
SDL_TEST = sdltest

.PHONY: all clean

all: $(TARGET) $(SDL_TEST)

$(TARGET): $(OBJECTS) $(LVGL_OBJECTS)
$(CC) $^ -o $@ $(LDFLAGS)

$(SDL_TEST): $(BUILD_DIR)/sdltest.o
$(CC) $< -o $@ $(LDFLAGS)

$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c | $(BUILD_DIR)
$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/%.o: $(LIB_DIR)/%.c | $(BUILD_DIR)
@mkdir -p $(dir $@)
$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR):
mkdir -p $@

clean:
rm -rf $(BUILD_DIR) $(TARGET) $(SDL_TEST)
31 changes: 31 additions & 0 deletions elements/007-nitrogen/lvgldemo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# lvgldemo
The purpose of this program is just to demonstrate that LVGL is working, as the very first step of fashioning our low-level UI, ultimately to replace KlipperScreen or run on an RP2040 with an SPI/I2C touch display.

For development, this is a C program that uses an SDL driver on Linux, which should work well enough. Tested on Fedora/KDE/X11 and while it took a bit to get it sorted, it ultimately worked. A future test will run on a BTT-CB1 and
an HDMI display (a Troodon printer) as well as an RP2040.

## Dependencies
As low-level as possible was the goal here, so just straight-up LVGL and the SDL driver are all that is required.

## Files
Not very many files are needed as this is really just a test.

- Makefile - Compiles and builds lvgldemo and sdltest
- libs/lvgl - Clone the LVGL repository from GitHub
- src/main.c - The main() component of lvgldemo
- src/display.h - Header for lvgldemo
- src/display.c - Implementation for lvgldemo
- src/lv_conf.h - Contains configuration settings for LVGL
- src/sdltest.c - Contains the sdltest implementation

## Additional Notes
- Like other projects, this is a C program compiled with -std=C17
- If you change src/lv_conf.h be sure to do a 'make clean && make' to pick up the changes
- Fonts need to be included with a #define before they can be used
- Most of the time on this project was spent debugging SDL issues
- Rotating an object in LVGL seems to be broken currently

## Example
This is it. This is all it does. But it is enough to get our proverbial foot in the LVGL door. If you close the window, it should exit normally and not crash.

![image](https://github.com/500Foods/Philement/assets/41052272/fc4655ae-0e7f-413e-8047-107302280c9e)
172 changes: 172 additions & 0 deletions elements/007-nitrogen/lvgldemo/src/display.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
#include "display.h"
#include "lv_conf.h"
#include "lvgl.h"
#include <SDL2/SDL.h>
#include <stdio.h>

#define DISP_HOR_RES 800
#define DISP_VER_RES 600

static SDL_Window *window;
static SDL_Renderer *renderer;
static SDL_Texture *texture;


static void sdl_display_flush(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map)
{
printf("Flush called for area: (%d,%d) to (%d,%d)\n", area->x1, area->y1, area->x2, area->y2);

SDL_Rect rect;
rect.x = area->x1;
rect.y = area->y1;
rect.w = lv_area_get_width(area);
rect.h = lv_area_get_height(area);

SDL_UpdateTexture(texture, &rect, px_map, rect.w * sizeof(uint32_t));
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderPresent(renderer);

lv_display_flush_ready(disp);
}

lv_display_t *display_init(void)
{
printf("Initializing display...\n");

if (SDL_Init(SDL_INIT_VIDEO) != 0) {
printf("SDL_Init failed: %s\n", SDL_GetError());
return NULL;
}

window = SDL_CreateWindow("LVGL Demo",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
DISP_HOR_RES, DISP_VER_RES, SDL_WINDOW_SHOWN);
if (window == NULL) {
printf("SDL_CreateWindow failed: %s\n", SDL_GetError());
SDL_Quit();
return NULL;
}

renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if (renderer == NULL) {
printf("SDL_CreateRenderer failed: %s\n", SDL_GetError());
SDL_DestroyWindow(window);
SDL_Quit();
return NULL;
}

texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING,
DISP_HOR_RES, DISP_VER_RES);
if (texture == NULL) {
printf("SDL_CreateTexture failed: %s\n", SDL_GetError());
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return NULL;
}

// Initial render to show a black screen
// SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
// SDL_RenderClear(renderer);
// SDL_RenderPresent(renderer);

lv_display_t *disp = lv_display_create(DISP_HOR_RES, DISP_VER_RES);
lv_display_set_flush_cb(disp, sdl_display_flush);

static lv_color_t buf1[DISP_HOR_RES * DISP_VER_RES];
static lv_color_t buf2[DISP_HOR_RES * DISP_VER_RES];
lv_display_set_buffers(disp, buf1, buf2, sizeof(buf1), LV_DISPLAY_RENDER_MODE_PARTIAL);

printf("Display initialization complete\n");
return disp;
}


void display_deinit(void)
{
printf("Deinitializing display...\n");
if (texture) {
SDL_DestroyTexture(texture);
}
if (renderer) {
SDL_DestroyRenderer(renderer);
}
if (window) {
SDL_DestroyWindow(window);
}
SDL_Quit();
printf("Display deinitialization complete\n");
}

void create_splash_screen(void)
{
printf("Creating splash screen\n");

lv_obj_t *scr = lv_scr_act();

// Set the screen's background color to black
lv_obj_set_style_bg_color(scr, lv_color_black(), 0);

// Get the screen dimensions
lv_coord_t screen_width = lv_obj_get_width(scr);
lv_coord_t screen_height = lv_obj_get_height(scr);

// Create gradient styles for top and bottom
static lv_style_t gradient_style_top;
static lv_style_t gradient_style_bottom;
lv_style_init(&gradient_style_top);
lv_style_init(&gradient_style_bottom);

// Set the gradient colors and directions
lv_style_set_bg_color(&gradient_style_top, lv_color_make(255, 0, 0)); // Red at the top
lv_style_set_bg_grad_color(&gradient_style_top, lv_color_black()); // Black at the bottom
lv_style_set_bg_grad_dir(&gradient_style_top, LV_GRAD_DIR_VER); // Vertical gradient

lv_style_set_bg_color(&gradient_style_bottom, lv_color_black()); // Black at the top
lv_style_set_bg_grad_color(&gradient_style_bottom, lv_color_make(255, 0, 0)); // Red at the bottom
lv_style_set_bg_grad_dir(&gradient_style_bottom, LV_GRAD_DIR_VER); // Vertical gradient

// Remove any border and rounding for both styles
lv_style_set_border_width(&gradient_style_top, 0);
lv_style_set_radius(&gradient_style_top, 0);
lv_style_set_border_width(&gradient_style_bottom, 0);
lv_style_set_radius(&gradient_style_bottom, 0);

// Create the four gradient rectangles
lv_obj_t *rect_tl = lv_obj_create(scr);
lv_obj_set_size(rect_tl, screen_width / 2, screen_height / 2);
lv_obj_set_pos(rect_tl, 0, 0);
lv_obj_add_style(rect_tl, &gradient_style_top, 0);

lv_obj_t *rect_tr = lv_obj_create(scr);
lv_obj_set_size(rect_tr, screen_width / 2, screen_height / 2);
lv_obj_set_pos(rect_tr, screen_width / 2, 0);
lv_obj_add_style(rect_tr, &gradient_style_top, 0);

lv_obj_t *rect_bl = lv_obj_create(scr);
lv_obj_set_size(rect_bl, screen_width / 2, screen_height / 2);
lv_obj_set_pos(rect_bl, 0, screen_height / 2);
lv_obj_add_style(rect_bl, &gradient_style_bottom, 0);

lv_obj_t *rect_br = lv_obj_create(scr);
lv_obj_set_size(rect_br, screen_width / 2, screen_height / 2);
lv_obj_set_pos(rect_br, screen_width / 2, screen_height / 2);
lv_obj_add_style(rect_br, &gradient_style_bottom, 0);

// Create title label
lv_obj_t *title_label = lv_label_create(scr);
lv_label_set_text(title_label, "Nitrogen LVGL Demo");
lv_obj_set_style_text_font(title_label, &lv_font_montserrat_32, 0);
lv_obj_set_style_text_color(title_label, lv_color_white(), 0);
lv_obj_align(title_label, LV_ALIGN_CENTER, 0, -20); // 20 pixels above center

// Create subtitle label
lv_obj_t *subtitle_label = lv_label_create(scr);
lv_label_set_text(subtitle_label, "Part of the Philement Project");
lv_obj_set_style_text_font(subtitle_label, &lv_font_montserrat_20, 0);
lv_obj_set_style_text_color(subtitle_label, lv_color_white(), 0);
lv_obj_align(subtitle_label, LV_ALIGN_CENTER, 0, 20); // 20 pixels below center

printf("Splash screen creation complete\n");
}
10 changes: 10 additions & 0 deletions elements/007-nitrogen/lvgldemo/src/display.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#ifndef DISPLAY_H
#define DISPLAY_H

#include "lvgl.h"

lv_display_t *display_init(void);
void display_deinit(void);
void create_splash_screen(void);

#endif // DISPLAY_H
37 changes: 37 additions & 0 deletions elements/007-nitrogen/lvgldemo/src/lv_conf.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#ifndef LV_CONF_H
#define LV_CONF_H

#include <stdint.h>

#define LV_USE_DEV_VERSION

#define LV_COLOR_DEPTH 32
#define LV_COLOR_16_SWAP 0
#define LV_BIG_ENDIAN_SYSTEM 0

#define LV_TICK_CUSTOM 1

#define LV_USE_LOG 1
#define LV_LOG_LEVEL LV_LOG_LEVEL_WARN

#define LV_FONT_MONTSERRAT_14 1

#define LV_USE_PERF_MONITOR 0

#define LV_USE_DRAW_SW 1
#define LV_DRAW_SW_GRADIENT 1

#define LV_USE_SDL 1

#define LV_FONT_MONTSERRAT_32 1
#define LV_FONT_MONTSERRAT_20 1

#define LV_USE_SHADOW 1
#define LV_USE_OUTLINE 1
#define LV_USE_PATTERN 1
#define LV_USE_VALUE_STR 1
#define LV_USE_BLEND_MODES 1
#define LV_USE_OPA_SCALE 1
#define LV_USE_TRANSFORM 1

#endif
Loading

0 comments on commit 6347693

Please sign in to comment.