correct email address
[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 <boram1288.park@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;
49         int fps;
50         int sync;
51         int interval;
52         int offset;
53         int enable_fake;
54         int pid;
55         char *vblank_name;
56 } tdm_test_client_arg;
57
58 typedef struct _tdm_test_client {
59         tdm_test_client_arg args;
60
61         int do_query;
62         int do_vblank;
63         int waiting;
64
65         tdm_client *client;
66 } tdm_test_client;
67
68 struct typestrings {
69         int type;
70         const char *string;
71 };
72
73 struct optstrings {
74         int  type;
75         const char *opt;
76         const char *desc;
77         const char *arg;
78         const char *ex;
79 };
80
81 enum {
82         OPT_QRY,
83         OPT_TST,
84         OPT_GNR,
85 };
86
87 static struct typestrings typestrs[] = {
88         {OPT_QRY, "Query"},
89         {OPT_TST, "Test"},
90         {OPT_GNR, "General"},
91 };
92
93 static struct optstrings optstrs[] = {
94         {OPT_QRY, "qo", "output objects info", "<output_name>", "primary"},
95         {OPT_TST, "v", "vblank test", "<output_name>[,<sync>][@<fps>][~<interval>][+<offset>][*fake][^vblank_name]", "primary,0@60~1+0*1^test"},
96 };
97
98 static void
99 usage(char *app_name)
100 {
101         int type_size = sizeof(typestrs) / sizeof(struct typestrings);
102         int opt_size = sizeof(optstrs) / sizeof(struct optstrings);
103         int t;
104
105         printf("usage: %s \n\n", app_name);
106
107         for (t = 0; t < type_size; t++) {
108                 int o, f = 1;
109
110                 for (o = 0; o < opt_size; o++)
111                         if (optstrs[o].type == typestrs[t].type) {
112                                 if (f == 1)
113                                         printf(" %s options:\n\n", typestrs[t].string);
114                                 printf("\t-%s\t%s\n", optstrs[o].opt, optstrs[o].desc);
115                                 if (optstrs[o].arg)
116                                         printf("\t\t  %s\n", optstrs[o].arg);
117                                 if (optstrs[o].ex)
118                                         printf("\t\t  ex) %s\n", optstrs[o].ex);
119                                 f = 0;
120                         }
121                 printf("\n");
122         }
123
124         exit(0);
125 }
126
127 //"<output_name>"
128 static void
129 parse_arg_qo(tdm_test_client *data, char *arg)
130 {
131         char name[TDM_NAME_LEN];
132         strtostr(name, TDM_NAME_LEN, arg, TDM_DELIM);
133         data->args.output_name = strndup(name, TDM_NAME_LEN);
134 }
135
136 //"<output_name>[,<sync>][@<fps>][~<interval>][+<offset>][*fake]"
137 static void
138 parse_arg_v(tdm_test_client *data, char *arg)
139 {
140         char *end = arg;
141         char name[TDM_NAME_LEN];
142
143         end = strtostr(name, TDM_NAME_LEN, arg, TDM_DELIM);
144         data->args.output_name = strndup(name, TDM_NAME_LEN);
145
146         if (*end == ',') {
147                 arg = end + 1;
148                 data->args.sync = strtol(arg, &end, 10);
149         }
150
151         if (*end == '@') {
152                 arg = end + 1;
153                 data->args.fps = strtol(arg, &end, 10);
154         }
155
156         if (*end == '~') {
157                 arg = end + 1;
158                 data->args.interval = strtol(arg, &end, 10);
159         }
160
161         if (*end == '+' || *end == '-') {
162                 arg = end;
163                 data->args.offset = strtol(arg, &end, 10);
164         }
165
166         if (*end == '*') {
167                 arg = end + 1;
168                 data->args.enable_fake = strtol(arg, &end, 10);
169         }
170
171         if (*end == '^') {
172                 char name[TDM_NAME_LEN];
173                 arg = end + 1;
174                 end = strtostr(name, TDM_NAME_LEN, arg, TDM_DELIM);
175                 data->args.vblank_name = strndup(name, TDM_NAME_LEN);
176         }
177 }
178
179 static void
180 parse_args(tdm_test_client *data, int argc, char *argv[])
181 {
182         int i;
183
184         if (argc < 3) {
185                 usage(argv[0]);
186                 exit(0);
187         }
188
189         memset(data, 0, sizeof *data);
190         data->args.interval = 1;
191
192         for (i = 1; i < argc; i++) {
193                 if (!strncmp(argv[i] + 1, "qo", 2)) {
194                         data->do_query = 1;
195                         parse_arg_qo(data, argv[++i]);
196                 } else if (!strncmp(argv[i] + 1, "v", 1)) {
197                         data->do_vblank = 1;
198                         parse_arg_v(data, argv[++i]);
199                 } else {
200                         usage(argv[0]);
201                         exit(0);
202                 }
203         }
204 }
205
206 static double
207 get_time(void)
208 {
209         struct timespec tp;
210
211         if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
212                 return (double)tp.tv_sec + ((double)tp.tv_nsec) / 1000000000.0;
213
214         return 0;
215 }
216
217 static void
218 _client_vblank_handler(tdm_client_vblank *vblank, tdm_error error, unsigned int sequence,
219                                            unsigned int tv_sec, unsigned int tv_usec, void *user_data)
220 {
221         tdm_test_client *data = user_data;
222         double cur, vbl;
223         static double p_vbl = 0;
224
225         data->waiting = 0;
226
227         if (error == TDM_ERROR_DPMS_OFF) {
228                 printf("exit: dpms off\n");
229                 exit(0);
230         }
231
232         if (error != TDM_ERROR_NONE) {
233                 printf("exit: error(%d)\n", error);
234                 exit(0);
235         }
236
237         cur = get_time();
238         vbl = (double)tv_sec + ((double)tv_usec) / 1000000.0;
239
240         printf("vblank              : %.6f us vbl(%.6f)\n", vbl - p_vbl, vbl);
241
242         if (cur - vbl > 0.002) /* 2ms */
243                 printf("kernel -> tdm-client: %.0f us\n", (cur - vbl) * 1000000.0);
244
245         p_vbl = vbl;
246 }
247
248 static char *conn_str[3] = {"disconnected", "connected", "mode_setted"};
249 static char *dpms_str[4] = {"on", "standy", "suspend", "off"};
250
251 static void
252 _client_output_handler(tdm_client_output *output, tdm_output_change_type type,
253                                            tdm_value value, void *user_data)
254 {
255         if (type == TDM_OUTPUT_CHANGE_CONNECTION)
256                 printf("output %s.\n", conn_str[value.u32]);
257         else if (type == TDM_OUTPUT_CHANGE_DPMS)
258                 printf("dpms %s.\n", dpms_str[value.u32]);
259 }
260
261 static void
262 do_query(tdm_test_client *data)
263 {
264         tdm_client_output *output;
265         tdm_output_conn_status status;
266         tdm_output_dpms dpms;
267         unsigned int refresh;
268         tdm_error error;
269
270         output = tdm_client_get_output(data->client, NULL, &error);
271         if (error != TDM_ERROR_NONE) {
272                 printf("tdm_client_get_output failed\n");
273                 return;
274         }
275
276         error = tdm_client_output_get_conn_status(output, &status);
277         TDM_WARNING_IF_FAIL(error == TDM_ERROR_NONE);
278         error = tdm_client_output_get_dpms(output, &dpms);
279         TDM_WARNING_IF_FAIL(error == TDM_ERROR_NONE);
280         error = tdm_client_output_get_refresh_rate(output, &refresh);
281         TDM_WARNING_IF_FAIL(error == TDM_ERROR_NONE);
282
283         printf("tdm_output \"%s\"\n", data->args.output_name);
284         printf("\tstatus : %s\n", conn_str[status]);
285         printf("\tdpms : %s\n", dpms_str[dpms]);
286         printf("\trefresh : %d\n", refresh);
287 }
288
289 static void
290 do_vblank(tdm_test_client *data)
291 {
292         tdm_client_output *output;
293         tdm_client_vblank *vblank = NULL;
294         tdm_error error;
295         int fd = -1;
296         struct pollfd fds;
297
298         output = tdm_client_get_output(data->client, data->args.output_name, &error);
299         if (error != TDM_ERROR_NONE) {
300                 printf("tdm_client_get_output failed\n");
301                 return;
302         }
303
304         error = tdm_client_output_add_change_handler(output, _client_output_handler, NULL);
305         TDM_WARNING_IF_FAIL(error == TDM_ERROR_NONE);
306
307         vblank = tdm_client_output_create_vblank(output, &error);
308         if (error != TDM_ERROR_NONE) {
309                 printf("tdm_client_output_create_vblank failed\n");
310                 return;
311         }
312
313         error = tdm_client_vblank_set_name(vblank, data->args.vblank_name);
314         TDM_WARNING_IF_FAIL(error == TDM_ERROR_NONE);
315         error = tdm_client_vblank_set_enable_fake(vblank, data->args.enable_fake);
316         TDM_WARNING_IF_FAIL(error == TDM_ERROR_NONE);
317         error = tdm_client_vblank_set_sync(vblank, data->args.sync);
318         TDM_WARNING_IF_FAIL(error == TDM_ERROR_NONE);
319         if (data->args.fps > 0) {
320                 error = tdm_client_vblank_set_fps(vblank, data->args.fps);
321                 TDM_WARNING_IF_FAIL(error == TDM_ERROR_NONE);
322         }
323         error = tdm_client_vblank_set_offset(vblank, data->args.offset);
324         TDM_WARNING_IF_FAIL(error == TDM_ERROR_NONE);
325
326         error = tdm_client_get_fd(data->client, &fd);
327         if (error != TDM_ERROR_NONE || fd < 0) {
328                 printf("tdm_client_get_fd failed\n");
329                 goto done;
330         }
331
332         fds.events = POLLIN;
333         fds.fd = fd;
334         fds.revents = 0;
335
336         while (1) {
337                 int ret;
338
339                 if (!data->waiting) {
340                         error = tdm_client_vblank_wait(vblank, data->args.interval,
341                                                                                    _client_vblank_handler, data);
342                         if (error == TDM_ERROR_DPMS_OFF) {
343                                 printf("tdm_client_vblank_wait failed (dpms off)\n");
344                                 goto done;
345                         }
346                         if (error != TDM_ERROR_NONE) {
347                                 printf("tdm_client_vblank_wait failed (error: %d)\n", error);
348                                 goto done;
349                         }
350                         data->waiting = 1;
351                 }
352
353                 if (!data->args.sync) {
354                         ret = poll(&fds, 1, -1);
355                         if (ret < 0) {
356                                 if (errno == EINTR || errno == EAGAIN)  /* normal case */
357                                         continue;
358                                 else {
359                                         printf("poll failed: %m\n");
360                                         goto done;
361                                 }
362                         }
363
364                         error = tdm_client_handle_events(data->client);
365                         if (error != TDM_ERROR_NONE) {
366                                 printf("tdm_client_handle_events failed\n");
367                                 goto done;
368                         }
369                 }
370         }
371
372 done:
373         if (vblank)
374                 tdm_client_vblank_destroy(vblank);
375 }
376
377 static tdm_test_client ttc_data;
378
379 int
380 main(int argc, char *argv[])
381 {
382         tdm_test_client *data = &ttc_data;
383         tdm_error error;
384
385 #if 1 /* for testing */
386         const char *xdg = (const char*)getenv("XDG_RUNTIME_DIR");
387         if (!xdg) {
388                 char buf[32];
389                 snprintf(buf, sizeof(buf), "/run");
390                 int ret = setenv("XDG_RUNTIME_DIR", (const char*)buf, 1);
391                 if (ret != 0)
392                         exit(0);
393         }
394 #endif
395
396         parse_args(data, argc, argv);
397
398         printf("sync(%d) fps(%d) interval(%d) offset(%d) enable_fake(%d) pid(%d)\n",
399                    data->args.sync, data->args.fps, data->args.interval,
400                    data->args.offset, data->args.enable_fake, data->args.pid);
401
402         data->client = tdm_client_create(&error);
403         if (error != TDM_ERROR_NONE) {
404                 printf("tdm_client_create failed\n");
405                 goto done;
406         }
407
408         if (data->do_query)
409                 do_query(data);
410         if (data->do_vblank)
411                 do_vblank(data);
412
413 done:
414         if (data->args.output_name)
415                 free(data->args.output_name);
416         if (data->args.vblank_name)
417                 free(data->args.vblank_name);
418         if (data->client)
419                 tdm_client_destroy(data->client);
420
421         return 0;
422 }