4a8e58399efb1c426f6767ab4071370b999c2470
[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         char string[512];
69 };
70
71 struct optstrings {
72         int  type;
73         char opt[512];
74         char desc[512];
75         char arg[512];
76         char ex[512];
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 #define DELIM "!@#^&*+-|,"
97
98 static char*
99 strtostr(char *buf, int len, char *str, char *delim)
100 {
101         char *end;
102         end = strpbrk(str, delim);
103         if (end)
104                 len = ((end - str + 1) < len) ? (end - str + 1) : len;
105         else {
106                 int l = strlen(str);
107                 len = ((l + 1) < len) ? (l + 1) : len;
108         }
109         snprintf(buf, len, "%s", str);
110         return str + len - 1;
111 }
112
113 static void
114 usage(char *app_name)
115 {
116         int type_size = sizeof(typestrs) / sizeof(struct typestrings);
117         int opt_size = sizeof(optstrs) / sizeof(struct optstrings);
118         int t;
119
120         printf("usage: %s \n\n", app_name);
121
122         for (t = 0; t < type_size; t++) {
123                 int o, f = 1;
124
125                 for (o = 0; o < opt_size; o++)
126                         if (optstrs[o].type == typestrs[t].type) {
127                                 if (f == 1)
128                                         printf(" %s options:\n\n", typestrs[t].string);
129                                 printf("\t-%s\t%s\n", optstrs[o].opt, optstrs[o].desc);
130                                 printf("\t\t%s\n", optstrs[o].arg);
131                                 printf("\t\tex) %s\n", optstrs[o].ex);
132                                 f = 0;
133                         }
134         }
135
136         exit(0);
137 }
138
139 //"<output_name>"
140 static void
141 parse_arg_qo(tdm_test_client *data, char *p)
142 {
143         strtostr(data->args.output_name, 512, p, DELIM);
144 }
145
146 //"<output_name>[,<sync>][@<fps>][#<interval>][+<offset>][*fake]"
147 static void
148 parse_arg_v(tdm_test_client *data, char *p)
149 {
150         char *end = p;
151
152         end = strtostr(data->args.output_name, 512, p, DELIM);
153
154         if (*end == ',') {
155                 p = end + 1;
156                 data->args.sync = strtol(p, &end, 10);
157         }
158
159         if (*end == '@') {
160                 p = end + 1;
161                 data->args.fps = strtol(p, &end, 10);
162         }
163
164         if (*end == '#') {
165                 p = end + 1;
166                 data->args.interval = strtol(p, &end, 10);
167         }
168
169         if (*end == '+' || *end == '-') {
170                 p = end;
171                 data->args.offset = strtol(p, &end, 10);
172         }
173
174         if (*end == '*') {
175                 p = end + 1;
176                 data->args.enable_fake= strtol(p, &end, 10);
177         }
178 }
179
180 static void
181 parse_args(tdm_test_client *data, int argc, char *argv[])
182 {
183         int size = sizeof(optstrs) / sizeof(struct optstrings);
184         int i, j = 0;
185
186         if (argc < 2) {
187                 usage(argv[0]);
188                 exit(1);
189         }
190
191         memset(data, 0, sizeof *data);
192         data->args.interval = 1;
193
194         for (i = 1; i < argc; i++) {
195                 for (j = 0; j < size; j++) {
196                         if (!strncmp(argv[i]+1, "qo", 512)) {
197                                 data->do_query = 1;
198                                 parse_arg_qo(data, argv[++i]);
199                                 break;
200                         } else if (!strncmp(argv[i]+1, "v", 512)) {
201                                 data->do_vblank = 1;
202                                 parse_arg_v(data, argv[++i]);
203                                 break;
204                         } else {
205                                 usage(argv[0]);
206                                 exit(1);
207                         }
208                 }
209         }
210 }
211
212 static unsigned long
213 get_time_in_micros(void)
214 {
215         struct timespec tp;
216
217         if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
218                 return (unsigned long)(tp.tv_sec * 1000000) + (tp.tv_nsec / 1000L);
219
220         return 0;
221 }
222
223 static void
224 _client_vblank_handler(tdm_client_vblank *vblank, tdm_error error, unsigned int sequence,
225                                            unsigned int tv_sec, unsigned int tv_usec, void *user_data)
226 {
227         tdm_test_client *data = user_data;
228         unsigned long cur, vbl;
229         static unsigned long p_vbl = 0;
230
231         data->waiting = 0;
232
233         if (error == TDM_ERROR_DPMS_OFF) {
234                 printf("exit: dpms off\n");
235                 exit(1);
236         }
237
238         if (error != TDM_ERROR_NONE) {
239                 printf("exit: error(%d)\n", error);
240                 exit(1);
241         }
242
243         cur = get_time_in_micros();
244         vbl = (unsigned long)tv_sec * (unsigned long)1000000 + (unsigned long)tv_usec;
245
246         printf("vblank              : %ld us vbl(%lu)\n", vbl - p_vbl, vbl);
247
248         if (cur - vbl > 2000) /* 2ms */
249                 printf("kernel -> tdm-client: %ld us\n", cur - vbl);
250
251         p_vbl = vbl;
252 }
253
254 static char *conn_str[3] = {"disconnected", "connected", "mode_setted"};
255 static char *dpms_str[4] = {"on", "standy", "suspend", "off"};
256
257 static void
258 _client_output_handler(tdm_client_output *output, tdm_output_change_type type,
259                                            tdm_value value, void *user_data)
260 {
261         if (type == TDM_OUTPUT_CHANGE_CONNECTION)
262                 printf("output %s.\n", conn_str[value.u32]);
263         else if (type == TDM_OUTPUT_CHANGE_DPMS)
264                 printf("dpms %s.\n", dpms_str[value.u32]);
265 }
266
267 static void
268 do_query(tdm_test_client *data)
269 {
270         tdm_client_output *output;
271         tdm_output_conn_status status;
272         tdm_output_dpms dpms;
273         unsigned int refresh;
274         tdm_error error;
275
276         output = tdm_client_get_output(data->client, NULL, &error);
277         if (error != TDM_ERROR_NONE) {
278                 printf("tdm_client_get_output failed\n");
279                 return;
280         }
281
282         tdm_client_output_get_conn_status(output, &status);
283         tdm_client_output_get_dpms(output, &dpms);
284         tdm_client_output_get_refresh_rate(output, &refresh);
285
286         printf("tdm_output \"%s\"\n", data->args.output_name);
287         printf("\tstatus : %s\n", conn_str[status]);
288         printf("\tdpms : %s\n", dpms_str[dpms]);
289         printf("\trefresh : %d\n", refresh);
290 }
291
292 static void
293 do_vblank(tdm_test_client *data)
294 {
295         tdm_client_output *output;
296         tdm_client_vblank *vblank = NULL;
297         tdm_error error;
298         int fd = -1;
299         struct pollfd fds;
300
301         output = tdm_client_get_output(data->client, data->args.output_name, &error);
302         if (error != TDM_ERROR_NONE) {
303                 printf("tdm_client_get_output failed\n");
304                 return;
305         }
306
307         tdm_client_output_add_change_handler(output, _client_output_handler, NULL);
308
309         vblank = tdm_client_output_create_vblank(output, &error);
310         if (error != TDM_ERROR_NONE) {
311                 printf("tdm_client_output_create_vblank failed\n");
312                 return;
313         }
314
315         tdm_client_vblank_set_enable_fake(vblank, data->args.enable_fake);
316         tdm_client_vblank_set_sync(vblank, data->args.sync);
317         if (data->args.fps > 0)
318                 tdm_client_vblank_set_fps(vblank, data->args.fps);
319         tdm_client_vblank_set_offset(vblank, data->args.offset);
320
321         error = tdm_client_get_fd(data->client, &fd);
322         if (error != TDM_ERROR_NONE || fd < 0) {
323                 printf("tdm_client_get_fd failed\n");
324                 goto done;
325         }
326
327         fds.events = POLLIN;
328         fds.fd = fd;
329         fds.revents = 0;
330
331         while (1) {
332                 int ret;
333
334                 if (!data->waiting) {
335                         error = tdm_client_vblank_wait(vblank, data->args.interval,
336                                                                                    _client_vblank_handler, data);
337                         if (error == TDM_ERROR_DPMS_OFF) {
338                                 printf("tdm_client_vblank_wait failed (dpms off)\n");
339                                 goto done;
340                         }
341                         if (error != TDM_ERROR_NONE) {
342                                 printf("tdm_client_vblank_wait failed (error: %d)\n", error);
343                                 goto done;
344                         }
345                         data->waiting = 1;
346                 }
347
348                 if (!data->args.sync) {
349                         ret = poll(&fds, 1, -1);
350                         if (ret < 0) {
351                                 if (errno == EINTR || errno == EAGAIN)  /* normal case */
352                                         continue;
353                                 else {
354                                         printf("poll failed: %m\n");
355                                         goto done;
356                                 }
357                         }
358
359                         error = tdm_client_handle_events(data->client);
360                         if (error != TDM_ERROR_NONE) {
361                                 printf("tdm_client_handle_events failed\n");
362                                 goto done;
363                         }
364                 }
365         }
366
367 done:
368         if (vblank)
369                 tdm_client_vblank_destroy(vblank);
370 }
371
372 static tdm_test_client ttc_data;
373
374 int
375 main(int argc, char *argv[])
376 {
377         tdm_test_client *data = &ttc_data;
378         tdm_error error;
379
380         parse_args(data, argc, argv);
381
382         printf("sync(%d) fps(%d) interval(%d) offset(%d) enable_fake(%d)\n",
383                    data->args.sync, data->args.fps, data->args.interval,
384                    data->args.offset, data->args.enable_fake);
385
386         data->client = tdm_client_create(&error);
387         if (error != TDM_ERROR_NONE) {
388                 printf("tdm_client_create failed\n");
389                 goto done;
390         }
391
392         if (data->do_query)
393                 do_query(data);
394         if (data->do_vblank)
395                 do_vblank(data);
396
397 done:
398         if (data->client)
399                 tdm_client_destroy(data->client);
400
401         return 0;
402 }