1 /*
2 * Copyright (c) 2024 Antmicro <www.antmicro.com>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/logging/log.h>
8 #include <zephyr/kernel.h>
9 #include <zephyr/device.h>
10 #include <zephyr/input/input.h>
11 #include <zephyr/drivers/display.h>
12 #include <zephyr/sys/util.h>
13
14 LOG_MODULE_REGISTER(sample, LOG_LEVEL_INF);
15
16 #if !DT_NODE_EXISTS(DT_CHOSEN(zephyr_touch))
17 #error "Unsupported board: zephyr,touch is not assigned"
18 #endif
19
20 #if !DT_NODE_EXISTS(DT_CHOSEN(zephyr_display))
21 #error "Unsupported board: zephyr,display is not assigned"
22 #endif
23
24 #define WIDTH (DT_PROP(DT_CHOSEN(zephyr_display), width))
25 #define HEIGHT (DT_PROP(DT_CHOSEN(zephyr_display), height))
26 #define CROSS_DIM (WIDTH / CONFIG_SCREEN_WIDTH_TO_CROSS_DIM)
27
28 #define PIXEL_FORMAT (DT_PROP_OR(DT_CHOSEN(zephyr_display), pixel_format, PIXEL_FORMAT_ARGB_8888))
29 #define BPP ((DISPLAY_BITS_PER_PIXEL(PIXEL_FORMAT)) / BITS_PER_BYTE)
30
31 #define BUFFER_SIZE (CROSS_DIM * CROSS_DIM * BPP)
32 #define REFRESH_RATE 100
33
34 static const struct device *const display_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display));
35 static const struct device *const touch_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_touch));
36 static struct display_buffer_descriptor buf_desc = {
37 .buf_size = BUFFER_SIZE, .pitch = CROSS_DIM, .width = CROSS_DIM, .height = CROSS_DIM};
38
39 static uint8_t buffer_cross[BUFFER_SIZE];
40 static const uint8_t buffer_cross_empty[BUFFER_SIZE];
41 static struct k_sem sync;
42
43 static struct {
44 size_t x;
45 size_t y;
46 bool pressed;
47 } touch_point, touch_point_drawn;
48
touch_event_callback(struct input_event * evt,void * user_data)49 static void touch_event_callback(struct input_event *evt, void *user_data)
50 {
51 if (evt->code == INPUT_ABS_X) {
52 touch_point.x = evt->value;
53 }
54 if (evt->code == INPUT_ABS_Y) {
55 touch_point.y = evt->value;
56 }
57 if (evt->code == INPUT_BTN_TOUCH) {
58 touch_point.pressed = evt->value;
59 }
60 if (evt->sync) {
61 k_sem_give(&sync);
62 }
63 }
64 INPUT_CALLBACK_DEFINE(touch_dev, touch_event_callback, NULL);
65
clear_screen(void)66 static int clear_screen(void)
67 {
68 int x;
69 int y;
70 int ret;
71
72 for (x = 0; x < WIDTH; x += CROSS_DIM) {
73 for (y = 0; y < HEIGHT; y += CROSS_DIM) {
74 struct display_buffer_descriptor ddesc = buf_desc;
75 uint16_t rem_w = WIDTH - x;
76 uint16_t rem_h = HEIGHT - y;
77
78 ddesc.width = MIN(buf_desc.width, rem_w);
79 ddesc.height = MIN(buf_desc.height, rem_h);
80 ddesc.buf_size = ddesc.width * ddesc.height * BPP;
81
82 ret = display_write(display_dev, x, y, &ddesc, buffer_cross_empty);
83 if (ret < 0) {
84 LOG_ERR("Failed to write to display (error %d)", ret);
85 return ret;
86 }
87 }
88 }
89
90 return 0;
91 }
92
fill_cross_buffer(void)93 static void fill_cross_buffer(void)
94 {
95 int i;
96 int x;
97 int y;
98 int index;
99
100 for (i = 0; i < BPP; i++) {
101 for (x = 0; x < CROSS_DIM; x++) {
102 index = BPP * (CROSS_DIM / 2 * CROSS_DIM + x);
103 buffer_cross[index + i] = -1;
104 }
105 for (y = 0; y < CROSS_DIM; y++) {
106 index = BPP * (y * CROSS_DIM + CROSS_DIM / 2);
107 buffer_cross[index + i] = -1;
108 }
109 }
110 }
111
get_draw_position(int value,int upper_bound)112 static int get_draw_position(int value, int upper_bound)
113 {
114 if (value < CROSS_DIM / 2) {
115 return 0;
116 }
117
118 if (value + CROSS_DIM / 2 > upper_bound) {
119 return upper_bound - CROSS_DIM;
120 }
121
122 return value - CROSS_DIM / 2;
123 }
124
main(void)125 int main(void)
126 {
127 int ret;
128
129 LOG_INF("Touch sample for touchscreen: %s, dc: %s", touch_dev->name, display_dev->name);
130
131 if (!device_is_ready(touch_dev)) {
132 LOG_ERR("Device %s not found. Aborting sample.", touch_dev->name);
133 return 0;
134 }
135
136 if (!device_is_ready(display_dev)) {
137 LOG_ERR("Device %s not found. Aborting sample.", display_dev->name);
138 return 0;
139 }
140
141 if (BPP == 0 || BPP > 4) {
142 LOG_ERR("Unsupported BPP=%d", BPP);
143 return 0;
144 }
145 fill_cross_buffer();
146 ret = display_blanking_off(display_dev);
147 if (ret < 0 && ret != -ENOSYS) {
148 LOG_ERR("Failed to turn blanking off (error %d)", ret);
149 return 0;
150 }
151
152 ret = clear_screen();
153 if (ret < 0) {
154 LOG_ERR("Failed to clear the screen");
155 return 0;
156 }
157
158 touch_point_drawn.x = CROSS_DIM / 2;
159 touch_point_drawn.y = CROSS_DIM / 2;
160 touch_point.x = -1;
161 touch_point.y = -1;
162
163 k_sem_init(&sync, 0, 1);
164
165 while (1) {
166 k_msleep(REFRESH_RATE);
167 k_sem_take(&sync, K_FOREVER);
168 LOG_INF("TOUCH %s X, Y: (%d, %d)", touch_point.pressed ? "PRESS" : "RELEASE",
169 touch_point.x, touch_point.y);
170
171 ret = display_write(display_dev, get_draw_position(touch_point_drawn.x, WIDTH),
172 get_draw_position(touch_point_drawn.y, HEIGHT), &buf_desc,
173 buffer_cross_empty);
174 if (ret < 0) {
175 LOG_ERR("Failed to write to display (error %d)", ret);
176 return 0;
177 }
178
179 ret = display_write(display_dev, get_draw_position(touch_point.x, WIDTH),
180 get_draw_position(touch_point.y, HEIGHT), &buf_desc,
181 buffer_cross);
182 if (ret < 0) {
183 LOG_ERR("Failed to write to display (error %d)", ret);
184 return 0;
185 }
186
187 touch_point_drawn.x = touch_point.x;
188 touch_point_drawn.y = touch_point.y;
189 }
190 return 0;
191 }
192