package version up to 1.5.1
[platform/core/uifw/libtdm.git] / tools / tdm_test_client.c
1 /**************************************************************************
2  *
3  * libtdm
4  *
5  * Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
6  *
7  * Contact: Eunchul Kim <chulspro.kim@samsung.com>,
8  *          JinYoung Jeon <jy0.jeon@samsung.com>,
9  *          Taeheon Kim <th908.kim@samsung.com>,
10  *          YoungJun Cho <yj44.cho@samsung.com>,
11  *          SooChan Lim <sc1.lim@samsung.com>,
12  *          Boram Park <sc1.lim@samsung.com>
13  *
14  * Permission is hereby granted, free of charge, to any person obtaining a
15  * copy of this software and associated documentation files (the
16  * "Software"), to deal in the Software without restriction, including
17  * without limitation the rights to use, copy, modify, merge, publish,
18  * distribute, sub license, and/or sell copies of the Software, and to
19  * permit persons to whom the Software is furnished to do so, subject to
20  * the following conditions:
21  *
22  * The above copyright notice and this permission notice (including the
23  * next paragraph) shall be included in all copies or substantial portions
24  * of the Software.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
27  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
29  * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
30  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
31  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
32  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33  *
34 **************************************************************************/
35
36 #include <stdio.h>
37 #include <string.h>
38 #include <stdlib.h>
39 #include <poll.h>
40 #include <errno.h>
41 #include <time.h>
42 #include <stdint.h>
43
44 #include <tdm_client.h>
45 #include "tdm_macro.h"
46
47 typedef struct _tdm_test_client_arg {
48         char output_name[512];
49         int fps;
50         int sync;
51         int interval;
52         int offset;
53         int enable_fake;
54 } tdm_test_client_arg;
55
56 typedef struct _tdm_test_client {
57         tdm_test_client_arg args;
58
59         int do_query;
60         int do_vblank;
61         int waiting;
62
63         tdm_client *client;
64 } tdm_test_client;
65
66 struct typestrings {
67         int type;
68         const char *string;
69 };
70
71 struct optstrings {
72         int  type;
73         const char *opt;
74         const char *desc;
75         const char *arg;
76         const char *ex;
77 };
78
79 enum {
80         OPT_QRY,
81         OPT_TST,
82         OPT_GNR,
83 };
84
85 static struct typestrings typestrs[] = {
86         {OPT_QRY, "Query"},
87         {OPT_TST, "Test"},
88         {OPT_GNR, "General"},
89 };
90
91 static struct optstrings optstrs[] = {
92         {OPT_QRY, "qo", "output objects info", "<output_name>", "primary"},
93         {OPT_TST, "v", "vblank test", "<output_name>[,<sync>][@<fps>][~<interval>][+<offset>][*fake]", "primary,0@60~1+0*1"},
94 };
95
96 static void
97 usage(char *app_name)
98 {
99         int type_size = sizeof(typestrs) / sizeof(struct typestrings);
100         int opt_size = sizeof(optstrs) / sizeof(struct optstrings);
101         int t;
102
103         printf("usage: %s \n\n", app_name);
104
105         for (t = 0; t < type_size; t++) {
106                 int o, f = 1;
107
108                 for (o = 0; o < opt_size; o++)
109                         if (optstrs[o].type == typestrs[t].type) {
110                                 if (f == 1)
111                                         printf(" %s options:\n\n", typestrs[t].string);
112                                 printf("\t-%s\t%s\n", optstrs[o].opt, optstrs[o].desc);
113                                 if (optstrs[o].arg)
114                                         printf("\t\t  %s\n", optstrs[o].arg);
115                                 if (optstrs[o].ex)
116                                         printf("\t\t  ex) %s\n", optstrs[o].ex);
117                                 f = 0;
118                         }
119                 printf("\n");
120         }
121
122         exit(0);
123 }
124
125 //"<output_name>"
126 static void
127 parse_arg_qo(tdm_test_client *data, char *arg)
128 {
129         strtostr(data->args.output_name, 512, arg, TDM_DELIM);
130 }
131
132 //"<output_name>[,<sync>][@<fps>][~<interval>][+<offset>][*fake]"
133 static void
134 parse_arg_v(tdm_test_client *data, char *arg)
135 {
136         char *end = arg;
137
138         end = strtostr(data->args.output_name, 512, arg, TDM_DELIM);
139
140         if (*end == ',') {
141                 arg = end + 1;
142                 data->args.sync = strtol(arg, &end, 10);
143         }
144
145         if (*end == '@') {
146                 arg = end + 1;
147                 data->args.fps = strtol(arg, &end, 10);
148         }
149
150         if (*end == '~') {
151                 arg = end + 1;
152                 data->args.interval = strtol(arg, &end, 10);
153         }
154
155         if (*end == '+' || *end == '-') {
156                 arg = end;
157                 data->args.offset = strtol(arg, &end, 10);
158         }
159
160         if (*end == '*') {
161                 arg = end + 1;
162                 data->args.enable_fake = strtol(arg, &end, 10);
163         }
164 }
165
166 static void
167 parse_args(tdm_test_client *data, int argc, char *argv[])
168 {
169         int i;
170
171         if (argc < 3) {
172                 usage(argv[0]);
173                 exit(0);
174         }
175
176         memset(data, 0, sizeof *data);
177         data->args.interval = 1;
178
179         for (i = 1; i < argc; i++) {
180                 if (!strncmp(argv[i]+1, "qo", 2)) {
181                         data->do_query = 1;
182                         parse_arg_qo(data, argv[++i]);
183                 } else if (!strncmp(argv[i]+1, "v", 1)) {
184                         data->do_vblank = 1;
185                         parse_arg_v(data, argv[++i]);
186                 } else {
187                         usage(argv[0]);
188                         exit(0);
189                 }
190         }
191 }
192
193 static double
194 get_time(void)
195 {
196         struct timespec tp;
197
198         if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
199                 return (double)tp.tv_sec + ((double)tp.tv_nsec) / 1000000000.0;
200
201         return 0;
202 }
203
204 static void
205 _client_vblank_handler(tdm_client_vblank *vblank, tdm_error error, unsigned int sequence,
206                                            unsigned int tv_sec, unsigned int tv_usec, void *user_data)
207 {
208         tdm_test_client *data = user_data;
209         double cur, vbl;
210         static double p_vbl = 0;
211
212         data->waiting = 0;
213
214         if (error == TDM_ERROR_DPMS_OFF) {
215                 printf("exit: dpms off\n");
216                 exit(0);
217         }
218
219         if (error != TDM_ERROR_NONE) {
220                 printf("exit: error(%d)\n", error);
221                 exit(0);
222         }
223
224         cur = get_time();
225         vbl = (double)tv_sec + ((double)tv_usec) / 1000000.0;
226
227         printf("vblank              : %.6f us vbl(%.6f)\n", vbl - p_vbl, vbl);
228
229         if (cur - vbl > 0.002) /* 2ms */
230                 printf("kernel -> tdm-client: %.0f us\n", (cur - vbl) * 1000000.0);
231
232         p_vbl = vbl;
233 }
234
235 static char *conn_str[3] = {"disconnected", "connected", "mode_setted"};
236 static char *dpms_str[4] = {"on", "standy", "suspend", "off"};
237
238 static void
239 _client_output_handler(tdm_client_output *output, tdm_output_change_type type,
240                                            tdm_value value, void *user_data)
241 {
242         if (type == TDM_OUTPUT_CHANGE_CONNECTION)
243                 printf("output %s.\n", conn_str[value.u32]);
244         else if (type == TDM_OUTPUT_CHANGE_DPMS)
245                 printf("dpms %s.\n", dpms_str[value.u32]);
246 }
247
248 static void
249 do_query(tdm_test_client *data)
250 {
251         tdm_client_output *output;
252         tdm_output_conn_status status;
253         tdm_output_dpms dpms;
254         unsigned int refresh;
255         tdm_error error;
256
257         output = tdm_client_get_output(data->client, NULL, &error);
258         if (error != TDM_ERROR_NONE) {
259                 printf("tdm_client_get_output failed\n");
260                 return;
261         }
262
263         tdm_client_output_get_conn_status(output, &status);
264         tdm_client_output_get_dpms(output, &dpms);
265         tdm_client_output_get_refresh_rate(output, &refresh);
266
267         printf("tdm_output \"%s\"\n", data->args.output_name);
268         printf("\tstatus : %s\n", conn_str[status]);
269         printf("\tdpms : %s\n", dpms_str[dpms]);
270         printf("\trefresh : %d\n", refresh);
271 }
272
273 static void
274 do_vblank(tdm_test_client *data)
275 {
276         tdm_client_output *output;
277         tdm_client_vblank *vblank = NULL;
278         tdm_error error;
279         int fd = -1;
280         struct pollfd fds;
281
282         output = tdm_client_get_output(data->client, data->args.output_name, &error);
283         if (error != TDM_ERROR_NONE) {
284                 printf("tdm_client_get_output failed\n");
285                 return;
286         }
287
288         tdm_client_output_add_change_handler(output, _client_output_handler, NULL);
289
290         vblank = tdm_client_output_create_vblank(output, &error);
291         if (error != TDM_ERROR_NONE) {
292                 printf("tdm_client_output_create_vblank failed\n");
293                 return;
294         }
295
296         tdm_client_vblank_set_enable_fake(vblank, data->args.enable_fake);
297         tdm_client_vblank_set_sync(vblank, data->args.sync);
298         if (data->args.fps > 0)
299                 tdm_client_vblank_set_fps(vblank, data->args.fps);
300         tdm_client_vblank_set_offset(vblank, data->args.offset);
301
302         error = tdm_client_get_fd(data->client, &fd);
303         if (error != TDM_ERROR_NONE || fd < 0) {
304                 printf("tdm_client_get_fd failed\n");
305                 goto done;
306         }
307
308         fds.events = POLLIN;
309         fds.fd = fd;
310         fds.revents = 0;
311
312         while (1) {
313                 int ret;
314
315                 if (!data->waiting) {
316                         error = tdm_client_vblank_wait(vblank, data->args.interval,
317                                                                                    _client_vblank_handler, data);
318                         if (error == TDM_ERROR_DPMS_OFF) {
319                                 printf("tdm_client_vblank_wait failed (dpms off)\n");
320                                 goto done;
321                         }
322                         if (error != TDM_ERROR_NONE) {
323                                 printf("tdm_client_vblank_wait failed (error: %d)\n", error);
324                                 goto done;
325                         }
326                         data->waiting = 1;
327                 }
328
329                 if (!data->args.sync) {
330                         ret = poll(&fds, 1, -1);
331                         if (ret < 0) {
332                                 if (errno == EINTR || errno == EAGAIN)  /* normal case */
333                                         continue;
334                                 else {
335                                         printf("poll failed: %m\n");
336                                         goto done;
337                                 }
338                         }
339
340                         error = tdm_client_handle_events(data->client);
341                         if (error != TDM_ERROR_NONE) {
342                                 printf("tdm_client_handle_events failed\n");
343                                 goto done;
344                         }
345                 }
346         }
347
348 done:
349         if (vblank)
350                 tdm_client_vblank_destroy(vblank);
351 }
352
353 static tdm_test_client ttc_data;
354
355 int
356 main(int argc, char *argv[])
357 {
358         tdm_test_client *data = &ttc_data;
359         tdm_error error;
360
361 #if 1 /* for testing */
362         const char *xdg = (const char*)getenv("XDG_RUNTIME_DIR");
363         if (!xdg) {
364                 char buf[32];
365                 snprintf(buf, sizeof(buf), "/run");
366                 int ret = setenv("XDG_RUNTIME_DIR", (const char*)buf, 1);
367                 if (ret != 0)
368                         exit(0);
369         }
370 #endif
371
372         parse_args(data, argc, argv);
373
374         printf("sync(%d) fps(%d) interval(%d) offset(%d) enable_fake(%d)\n",
375                    data->args.sync, data->args.fps, data->args.interval,
376                    data->args.offset, data->args.enable_fake);
377
378         data->client = tdm_client_create(&error);
379         if (error != TDM_ERROR_NONE) {
380                 printf("tdm_client_create failed\n");
381                 goto done;
382         }
383
384         if (data->do_query)
385                 do_query(data);
386         if (data->do_vblank)
387                 do_vblank(data);
388
389 done:
390         if (data->client)
391                 tdm_client_destroy(data->client);
392
393         return 0;
394 }