forked from esp-cpp/espp
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathseeed_studio_round_display_example.cpp
More file actions
175 lines (155 loc) · 6.55 KB
/
seeed_studio_round_display_example.cpp
File metadata and controls
175 lines (155 loc) · 6.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#include <chrono>
#include <deque>
#include <stdlib.h>
#include <vector>
#include "seeed-studio-round-display.hpp"
using namespace std::chrono_literals;
static constexpr size_t MAX_CIRCLES = 100;
static std::deque<lv_obj_t *> circles;
static std::recursive_mutex lvgl_mutex;
static void draw_circle(int x0, int y0, int radius);
static void clear_circles();
static void on_rotate_pressed(lv_event_t *event);
static void on_clear_pressed(lv_event_t *event);
extern "C" void app_main(void) {
espp::Logger logger(
{.tag = "Seeed Studio Round Display Example", .level = espp::Logger::Verbosity::INFO});
logger.info("Starting example!");
//! [seeed studio round display example]
#if CONFIG_EXAMPLE_HARDWARE_XIAOS3
logger.info("Using XiaoS3 hardware configuration");
espp::SsRoundDisplay::set_pin_config(espp::SsRoundDisplay::XiaoS3Config);
#elif CONFIG_EXAMPLE_HARDWARE_QTPYS3
logger.info("Using QtpyS3 hardware configuration");
espp::SsRoundDisplay::set_pin_config(espp::SsRoundDisplay::QtpyS3Config);
#else
#error "Please select a hardware configuration"
#endif
espp::SsRoundDisplay &round_display = espp::SsRoundDisplay::get();
auto touch_callback = [&](const auto &touch) {
// NOTE: since we're directly using the touchpad data, and not using the
// TouchpadInput + LVGL, we'll need to ensure the touchpad data is
// converted into proper screen coordinates instead of simply using the
// raw values.
static auto previous_touchpad_data = round_display.touchpad_convert(touch);
auto touchpad_data = round_display.touchpad_convert(touch);
if (touchpad_data != previous_touchpad_data) {
logger.info("Touch: {}", touchpad_data);
previous_touchpad_data = touchpad_data;
// if the button is pressed, clear the circles
if (touchpad_data.btn_state) {
clear_circles();
}
// if there is a touch point, draw a circle
if (touchpad_data.num_touch_points > 0) {
draw_circle(touchpad_data.x, touchpad_data.y, 10);
}
}
};
// initialize the LCD
if (!round_display.initialize_lcd()) {
logger.error("Failed to initialize LCD!");
return;
}
// set the pixel buffer to be 50 lines high
static constexpr size_t pixel_buffer_size = round_display.lcd_width() * 50;
// initialize the LVGL display for the seeed-studio-round-display
if (!round_display.initialize_display(pixel_buffer_size)) {
logger.error("Failed to initialize display!");
return;
}
// initialize the touchpad
if (!round_display.initialize_touch(touch_callback)) {
logger.error("Failed to initialize touchpad!");
return;
}
// set the background color to black
lv_obj_t *bg = lv_obj_create(lv_screen_active());
lv_obj_set_size(bg, round_display.lcd_width(), round_display.lcd_height());
lv_obj_set_style_bg_color(bg, lv_color_make(0, 0, 0), 0);
// add text in the center of the screen
lv_obj_t *label = lv_label_create(lv_screen_active());
lv_label_set_text(label, "Touch the screen!");
lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0);
// add a button in the top middel which (when pressed) will rotate the display
// through 0, 90, 180, 270 degrees
lv_obj_t *btn = lv_btn_create(lv_screen_active());
lv_obj_set_size(btn, 50, 50);
lv_obj_align(btn, LV_ALIGN_TOP_MID, 0, 0);
lv_obj_t *label_btn = lv_label_create(btn);
lv_label_set_text(label_btn, LV_SYMBOL_REFRESH);
lv_obj_align(label_btn, LV_ALIGN_CENTER, 0, 0);
lv_obj_add_event_cb(btn, on_rotate_pressed, LV_EVENT_PRESSED, nullptr);
// add a button in the bottom middle which (when pressed) will clear the
// circles
lv_obj_t *btn_clear = lv_btn_create(lv_screen_active());
lv_obj_set_size(btn_clear, 50, 50);
lv_obj_align(btn_clear, LV_ALIGN_BOTTOM_MID, 0, 0);
lv_obj_add_state(btn_clear, LV_STATE_CHECKED); // make the button red
lv_obj_t *label_btn_clear = lv_label_create(btn_clear);
lv_label_set_text(label_btn_clear, LV_SYMBOL_TRASH);
lv_obj_align(label_btn_clear, LV_ALIGN_CENTER, 0, 0);
lv_obj_add_event_cb(btn_clear, on_clear_pressed, LV_EVENT_PRESSED, nullptr);
// disable scrolling on the screen (so that it doesn't behave weirdly when
// rotated and drawing with your finger)
lv_obj_set_scrollbar_mode(lv_screen_active(), LV_SCROLLBAR_MODE_OFF);
lv_obj_clear_flag(lv_screen_active(), LV_OBJ_FLAG_SCROLLABLE);
// start a simple thread to do the lv_task_handler every 16ms
espp::Task lv_task({.callback = [](std::mutex &m, std::condition_variable &cv) -> bool {
{
std::lock_guard<std::recursive_mutex> lock(lvgl_mutex);
lv_task_handler();
}
std::unique_lock<std::mutex> lock(m);
cv.wait_for(lock, 16ms);
return false;
},
.task_config = {
.name = "lv_task",
}});
lv_task.start();
// set the display brightness to be 75%
round_display.brightness(75.0f);
// loop forever
while (true) {
std::this_thread::sleep_for(1s);
}
//! [seeed studio round display example]
}
static void on_rotate_pressed(lv_event_t *event) {
clear_circles();
std::lock_guard<std::recursive_mutex> lock(lvgl_mutex);
static auto rotation = LV_DISPLAY_ROTATION_0;
rotation = static_cast<lv_display_rotation_t>((static_cast<int>(rotation) + 1) % 4);
lv_display_t *disp = lv_display_get_default();
lv_disp_set_rotation(disp, rotation);
}
// cppcheck-suppress constParameterCallback
static void on_clear_pressed(lv_event_t *event) { clear_circles(); }
static void draw_circle(int x0, int y0, int radius) {
std::lock_guard<std::recursive_mutex> lock(lvgl_mutex);
// if the number of circles is greater than the max, remove the oldest circle
if (circles.size() > MAX_CIRCLES) {
lv_obj_delete(circles.front());
circles.pop_front();
}
lv_obj_t *my_Cir = lv_obj_create(lv_screen_active());
lv_obj_set_scrollbar_mode(my_Cir, LV_SCROLLBAR_MODE_OFF);
lv_obj_set_size(my_Cir, radius * 2, radius * 2);
lv_obj_set_pos(my_Cir, x0 - radius, y0 - radius);
lv_obj_set_style_radius(my_Cir, LV_RADIUS_CIRCLE, 0);
// ensure the circle ignores touch events (so things behind it can still be
// interacted with)
lv_obj_clear_flag(my_Cir, LV_OBJ_FLAG_CLICKABLE);
circles.push_back(my_Cir);
}
static void clear_circles() {
std::lock_guard<std::recursive_mutex> lock(lvgl_mutex);
// remove the circles from lvgl
for (auto circle : circles) {
lv_obj_delete(circle);
}
// clear the vector
circles.clear();
}