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 void clear_screen(void)
67 {
68 	int x;
69 	int y;
70 
71 	for (x = 0; x < WIDTH; x += CROSS_DIM) {
72 		for (y = 0; y < HEIGHT; y += CROSS_DIM) {
73 			display_write(display_dev, x, y, &buf_desc, buffer_cross_empty);
74 		}
75 	}
76 }
77 
fill_cross_buffer(void)78 static void fill_cross_buffer(void)
79 {
80 	int i;
81 	int x;
82 	int y;
83 	int index;
84 
85 	for (i = 0; i < BPP; i++) {
86 		for (x = 0; x < CROSS_DIM; x++) {
87 			index = BPP * (CROSS_DIM / 2 * CROSS_DIM + x);
88 			buffer_cross[index + i] = -1;
89 		}
90 		for (y = 0; y < CROSS_DIM; y++) {
91 			index = BPP * (y * CROSS_DIM + CROSS_DIM / 2);
92 			buffer_cross[index + i] = -1;
93 		}
94 	}
95 }
96 
get_draw_position(int value,int upper_bound)97 static int get_draw_position(int value, int upper_bound)
98 {
99 	if (value < CROSS_DIM / 2) {
100 		return 0;
101 	}
102 
103 	if (value + CROSS_DIM / 2 > upper_bound) {
104 		return upper_bound - CROSS_DIM;
105 	}
106 
107 	return value - CROSS_DIM / 2;
108 }
109 
main(void)110 int main(void)
111 {
112 
113 	LOG_INF("Touch sample for touchscreen: %s, dc: %s", touch_dev->name, display_dev->name);
114 
115 	if (!device_is_ready(touch_dev)) {
116 		LOG_ERR("Device %s not found. Aborting sample.", touch_dev->name);
117 		return 0;
118 	}
119 
120 	if (!device_is_ready(display_dev)) {
121 		LOG_ERR("Device %s not found. Aborting sample.", display_dev->name);
122 		return 0;
123 	}
124 
125 	if (BPP == 0 || BPP > 4) {
126 		LOG_ERR("Unsupported BPP=%d", BPP);
127 		return 0;
128 	}
129 	fill_cross_buffer();
130 	display_blanking_off(display_dev);
131 
132 	clear_screen();
133 	touch_point_drawn.x = CROSS_DIM / 2;
134 	touch_point_drawn.y = CROSS_DIM / 2;
135 	touch_point.x = -1;
136 	touch_point.y = -1;
137 
138 	k_sem_init(&sync, 0, 1);
139 
140 	while (1) {
141 		k_msleep(REFRESH_RATE);
142 		k_sem_take(&sync, K_FOREVER);
143 		LOG_INF("TOUCH %s X, Y: (%d, %d)", touch_point.pressed ? "PRESS" : "RELEASE",
144 			touch_point.x, touch_point.y);
145 
146 		display_write(display_dev, get_draw_position(touch_point_drawn.x, WIDTH),
147 			      get_draw_position(touch_point_drawn.y, HEIGHT), &buf_desc,
148 			      buffer_cross_empty);
149 
150 		display_write(display_dev, get_draw_position(touch_point.x, WIDTH),
151 			      get_draw_position(touch_point.y, HEIGHT), &buf_desc, buffer_cross);
152 
153 		touch_point_drawn.x = touch_point.x;
154 		touch_point_drawn.y = touch_point.y;
155 	}
156 	return 0;
157 }
158