Skip to content

Commit f011d04

Browse files
committed
Add a SDL-based host app 'simulator' for the stm32-lvgl demo
1 parent f7abba5 commit f011d04

File tree

9 files changed

+322
-96
lines changed

9 files changed

+322
-96
lines changed

stm32-lvgl/Makefile

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ SWIFT_BUILD_ARGS := \
2525
--configuration release \
2626
--triple $(TARGET) \
2727
--toolset $(TOOLSET) \
28-
--disable-local-rpath
28+
--product Application
2929
BUILDROOT := $(shell $(SWIFT_BUILD) $(SWIFT_BUILD_ARGS) --show-bin-path)
3030

3131
.PHONY: build
@@ -74,6 +74,26 @@ build:
7474
flash:
7575
@echo "flashing..."
7676
st-flash --reset --format ihex write $(BUILDROOT)/Application.hex
77+
78+
simulator:
79+
mkdir -p .build
80+
81+
@echo "configuring LVGL..."
82+
cmake -B .build/lvgl-host -G Ninja ./lvgl \
83+
-DCMAKE_EXPORT_COMPILE_COMMANDS=On \
84+
-DLV_CONF_PATH=../Sources/CLVGL/include/lv_conf.h
85+
86+
@echo "building LVGL..."
87+
cmake --build .build/lvgl-host
88+
89+
@echo "building..."
90+
$(SWIFT_BUILD) \
91+
--configuration release \
92+
--product HostSDLApp \
93+
--verbose
94+
95+
@echo "running..."
96+
$(PWD)/.build/release/HostSDLApp
7797

7898
.PHONY: clean
7999
clean:

stm32-lvgl/Package.resolved

Lines changed: 10 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

stm32-lvgl/Package.swift

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,20 @@ import PackageDescription
55
let package = Package(
66
name: "stm32-lvgl",
77
platforms: [
8-
.macOS(.v10_15)
8+
.macOS(.v11)
99
],
1010
products: [
1111
.executable(name: "Application", targets: ["Application"])
1212
],
1313
dependencies: [
14-
.package(url: "https://github.com/apple/swift-mmio", branch: "main")
14+
.package(url: "https://github.com/apple/swift-mmio", branch: "main"),
15+
.package(url: "https://github.com/ctreffs/SwiftSDL2.git", from: "1.4.0"),
1516
],
1617
targets: [
18+
//
19+
// FIRMWARE TARGETS
20+
//
21+
1722
.executableTarget(
1823
name: "Application",
1924
dependencies: [
@@ -38,4 +43,15 @@ let package = Package(
3843
.target(name: "Support"),
3944

4045
.target(name: "CLVGL"),
46+
47+
//
48+
// HOST TARGETS
49+
//
50+
51+
.executableTarget(name: "HostSDLApp", dependencies: [
52+
.product(name: "SDL", package: "SwiftSDL2"),
53+
"CLVGL"
54+
],
55+
swiftSettings: [.enableExperimentalFeature("Extern")],
56+
linkerSettings: [.unsafeFlags(["-L.build/lvgl-host/lib", "-llvgl", "-llvgl_demos"])]),
4157
])

stm32-lvgl/Sources/Application/Main.swift

Lines changed: 5 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,6 @@ struct Main {
9797
fillAndCheckWithIndexXor(pattern: 0xFFFF_FFFF)
9898
}
9999

100-
static var clickCount = 0
101-
static var button: OpaquePointer! = nil
102-
static var buttonLabel: OpaquePointer! = nil
103-
104100
static func lvglDemo() {
105101
lv_init()
106102
lv_tick_set_cb({ UInt32(uptimeInMs) })
@@ -151,88 +147,8 @@ struct Main {
151147
}
152148
})
153149

154-
// Get the active screen
155-
let screen = lv_screen_active()
156-
157-
// Create a gradient background
158-
var style = lv_style_t()
159-
lv_style_init(&style)
160-
161-
// Create gradient colors (blue to red)
162-
var gradient = lv_grad_dsc_t()
163-
gradient.dir = LV_GRAD_DIR_VER
164-
gradient.stops_count = 2
165-
gradient.stops.0.color = lv_color_make(0, 0, 0) // Black
166-
gradient.stops.0.opa = UInt8(LV_OPA_COVER)
167-
gradient.stops.0.frac = 0
168-
gradient.stops.1.color = lv_color_make(255, 0, 0) // Red
169-
gradient.stops.1.opa = UInt8(LV_OPA_COVER)
170-
gradient.stops.1.frac = 255
171-
172-
// Apply gradient to the style background
173-
lv_style_set_bg_grad(&style, &gradient)
174-
lv_style_set_bg_opa(&style, UInt8(LV_OPA_COVER))
175-
176-
// Apply the style to the screen
177-
lv_obj_add_style(screen, &style, 0)
178-
179-
// Create a button in the top right
180-
button = lv_button_create(screen)
181-
lv_obj_set_size(button, 120, 50)
182-
lv_obj_align(button, LV_ALIGN_TOP_RIGHT, -10, 10)
183-
buttonLabel = lv_label_create(button)
184-
lv_label_set_text(buttonLabel, "Click me")
185-
lv_obj_center(buttonLabel)
186-
lv_obj_add_event_cb(
187-
button,
188-
{ event in
189-
Self.clickCount += 1
190-
lv_label_set_text(Self.buttonLabel, "Clicked \(Self.clickCount)")
191-
}, LV_EVENT_CLICKED, nil)
192-
193-
// Create a label
194-
let label = lv_label_create(screen)
195-
lv_label_set_text(label, "Hello LVGL!")
196-
lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 20)
197-
198-
// Make the label white for better visibility
199-
var labelStyle = lv_style_t()
200-
lv_style_init(&labelStyle)
201-
lv_style_set_text_color(&labelStyle, lv_color_white())
202-
lv_obj_add_style(label, &labelStyle, 0)
203-
204-
// Create a spinner
205-
let spinner = lv_spinner_create(screen)
206-
207-
// Set spinner size
208-
lv_obj_set_size(spinner, 100, 100)
209-
210-
// Center the spinner on screen
211-
lv_obj_align(spinner, LV_ALIGN_CENTER, 0, 0)
212-
213-
// Configure spinner animation
214-
lv_spinner_set_anim_params(spinner, 2_000, 200) // anim time, angle
215-
216-
// Create a dropdown menu
217-
let dropdown = lv_dropdown_create(screen)
218-
lv_dropdown_set_options(dropdown, "Option 1\nOption 2\nOption 3\nOption 4")
219-
lv_obj_set_size(dropdown, 150, 40)
220-
lv_obj_align(dropdown, LV_ALIGN_TOP_LEFT, 10, 10)
221-
222-
// Add event handler for dropdown selection
223-
lv_obj_add_event_cb(
224-
dropdown,
225-
{ event in
226-
let dropdown = lv_event_get_target_obj(event)
227-
let selectedIndex = lv_dropdown_get_selected(dropdown)
228-
print("Selected option \(selectedIndex)")
229-
}, LV_EVENT_VALUE_CHANGED, nil)
230-
231-
// Add a label under the spinner
232-
let spinnerLabel = lv_label_create(screen)
233-
lv_label_set_text(spinnerLabel, "Loading...")
234-
lv_obj_align(spinnerLabel, LV_ALIGN_BOTTOM_MID, 0, -20)
235-
lv_obj_add_style(spinnerLabel, &labelStyle, 0)
150+
// Add UI of application logic
151+
UIAppLogic.createUI()
236152

237153
log("LVGL setup done, starting render loop")
238154

@@ -242,9 +158,9 @@ struct Main {
242158
while lcdInterruptVerticalSyncHandler != nil { /* busy wait */ nop() }
243159

244160
lv_timer_handler()
245-
frameCounter += 1
246-
lv_label_set_text(
247-
spinnerLabel, "Uptime (ms): \(uptimeInMs)\nFrames: \(frameCounter)")
161+
162+
// Update UI of application logic
163+
UIAppLogic.updateFrame()
248164
}
249165
}
250166
}
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift open source project
4+
//
5+
// Copyright (c) 2023 Apple Inc. and the Swift project authors.
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
//
10+
//===----------------------------------------------------------------------===//
11+
12+
import CLVGL
13+
14+
// This is shared code (via a symlink) between the firmware build and the host
15+
// SDL-based "simulator" app. No platform/firmware specific logic to stay
16+
// portable.
17+
enum UIAppLogic {
18+
static var clickCount = 0
19+
static var button: OpaquePointer! = nil
20+
static var buttonLabel: OpaquePointer! = nil
21+
static var spinnerLabel: OpaquePointer! = nil
22+
23+
static var frameCounter = 0
24+
25+
// Keep styles persistent for the lifetime of the application
26+
static var style = lv_style_t()
27+
static var labelStyle = lv_style_t()
28+
static var gradient = lv_grad_dsc_t()
29+
30+
static var widgetDemoScreen: OpaquePointer! = nil
31+
32+
static func createUI() {
33+
// Get the active screen
34+
let screen = lv_screen_active()
35+
36+
// Create a gradient background
37+
lv_style_init(&style)
38+
39+
// Create gradient colors (blue to red)
40+
gradient.dir = LV_GRAD_DIR_VER
41+
gradient.stops_count = 2
42+
gradient.stops.0.color = lv_color_make(0, 0, 0) // Black
43+
gradient.stops.0.opa = UInt8(LV_OPA_COVER)
44+
gradient.stops.0.frac = 0
45+
gradient.stops.1.color = lv_color_make(255, 0, 0) // Red
46+
gradient.stops.1.opa = UInt8(LV_OPA_COVER)
47+
gradient.stops.1.frac = 255
48+
49+
// Apply gradient to the style background
50+
lv_style_set_bg_grad(&style, &gradient)
51+
lv_style_set_bg_opa(&style, UInt8(LV_OPA_COVER))
52+
53+
// Apply the style to the screen
54+
lv_obj_add_style(screen, &style, 0)
55+
56+
// Create a button in the top right
57+
button = lv_button_create(screen)
58+
lv_obj_set_size(button, 120, 50)
59+
lv_obj_align(button, LV_ALIGN_TOP_RIGHT, -10, 10)
60+
buttonLabel = lv_label_create(button)
61+
lv_label_set_text(buttonLabel, "Click me")
62+
lv_obj_center(buttonLabel)
63+
lv_obj_add_event_cb(button, { event in
64+
Self.clickCount += 1
65+
lv_label_set_text(Self.buttonLabel, "Clicked \(Self.clickCount)")
66+
}, LV_EVENT_CLICKED, nil)
67+
68+
// Create a 'Demo' button in the bottom right
69+
let demoButton = lv_button_create(screen)
70+
lv_obj_set_size(demoButton, 120, 50)
71+
lv_obj_align(demoButton, LV_ALIGN_BOTTOM_RIGHT, -10, -10)
72+
let demoButtonLabel = lv_label_create(demoButton)
73+
lv_label_set_text(demoButtonLabel, "Widget Demo")
74+
lv_obj_center(demoButtonLabel)
75+
lv_obj_add_event_cb(demoButton, { event in
76+
lv_screen_load(Self.widgetDemoScreen)
77+
}, LV_EVENT_CLICKED, nil)
78+
79+
// Create a label
80+
let label = lv_label_create(screen)
81+
lv_label_set_text(label, "Hello LVGL!")
82+
lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 20)
83+
84+
// Make the label white for better visibility
85+
lv_style_init(&labelStyle)
86+
lv_style_set_text_color(&labelStyle, lv_color_white())
87+
lv_obj_add_style(label, &labelStyle, 0)
88+
89+
// Create a spinner
90+
let spinner = lv_spinner_create(screen)
91+
92+
// Set spinner size
93+
lv_obj_set_size(spinner, 60, 60)
94+
95+
// Center the spinner on screen
96+
lv_obj_align(spinner, LV_ALIGN_CENTER, 0, 0)
97+
98+
// Configure spinner animation
99+
lv_spinner_set_anim_params(spinner, 2_000, 200) // anim time, angle
100+
101+
// Create a dropdown menu
102+
let dropdown = lv_dropdown_create(screen)
103+
lv_dropdown_set_options(dropdown, "Option 1\nOption 2\nOption 3\nOption 4")
104+
lv_obj_set_size(dropdown, 150, 40)
105+
lv_obj_align(dropdown, LV_ALIGN_TOP_LEFT, 10, 10)
106+
107+
// Add event handler for dropdown selection
108+
lv_obj_add_event_cb(
109+
dropdown,
110+
{ event in
111+
let dropdown = lv_event_get_target_obj(event)
112+
let selectedIndex = lv_dropdown_get_selected(dropdown)
113+
print("Selected option \(selectedIndex)")
114+
}, LV_EVENT_VALUE_CHANGED, nil)
115+
116+
// Add a label under the spinner
117+
spinnerLabel = lv_label_create(screen)
118+
lv_label_set_text(spinnerLabel, "Loading...")
119+
lv_obj_align(spinnerLabel, LV_ALIGN_BOTTOM_LEFT, 20, -20)
120+
lv_obj_add_style(spinnerLabel, &labelStyle, 0)
121+
122+
// Create a 2nd screen with the widgets demo app from LVGL, then switch back
123+
// to the original screen.
124+
widgetDemoScreen = lv_obj_create(nil)
125+
lv_screen_load(widgetDemoScreen)
126+
@_extern(c) func lv_demo_widgets()
127+
lv_demo_widgets()
128+
lv_screen_load(screen)
129+
}
130+
131+
static func updateFrame() {
132+
frameCounter += 1
133+
lv_label_set_text(spinnerLabel, "Uptime (ms): \(uptimeInMs)\nFrames: \(frameCounter)")
134+
}
135+
}

stm32-lvgl/Sources/CLVGL/include/lv_conf.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@
88
/** Color depth: 1 (I1), 8 (L8), 16 (RGB565), 24 (RGB888), 32 (XRGB8888) */
99
#define LV_COLOR_DEPTH 32
1010

11+
/*********************
12+
* DEMO USAGE
13+
*********************/
14+
15+
#define LV_USE_DEMO_WIDGETS 1
16+
1117
/*=========================
1218
STDLIB WRAPPER SETTINGS
1319
*=========================*/
@@ -48,7 +54,7 @@
4854

4955
#if LV_USE_STDLIB_MALLOC == LV_STDLIB_BUILTIN
5056
/** Size of memory available for `lv_malloc()` in bytes (>= 2kB) */
51-
#define LV_MEM_SIZE (64 * 1024U) /**< [bytes] */
57+
#define LV_MEM_SIZE (96 * 1024U) /**< [bytes] */
5258

5359
/** Size of the memory expand for `lv_malloc()` in bytes */
5460
#define LV_MEM_POOL_EXPAND_SIZE 0
@@ -331,7 +337,7 @@
331337
*-----------*/
332338

333339
/** Enable log module */
334-
#define LV_USE_LOG 0
340+
#define LV_USE_LOG 1
335341
#if LV_USE_LOG
336342
/** Set value to one of the following levels of logging detail:
337343
* - LV_LOG_LEVEL_TRACE Log detailed information.

0 commit comments

Comments
 (0)