1 /*
2 * Copyright (c) 2011-2012 - Mauro Carvalho Chehab
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation version 2
7 * of the License.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
18 *
19 */
20
21 #include "libdvbv5/dvb-file.h"
22 #include "libdvbv5/dvb-dev.h"
23 #include <argp.h>
24 #include <signal.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <unistd.h>
28
29 #ifdef ENABLE_NLS
30 # define _(string) gettext(string)
31 # include "gettext.h"
32 # include <locale.h>
33 # include <langinfo.h>
34 # include <iconv.h>
35 #else
36 # define _(string) string
37 #endif
38
39 # define N_(string) string
40
41 #define PROGRAM_NAME "dvb-fe-tool"
42
43 const char *argp_program_version = PROGRAM_NAME " version " V4L_UTILS_VERSION;
44 const char *argp_program_bug_address = "Mauro Carvalho Chehab <mchehab@kernel.org>";
45
46 static const char doc[] = N_(
47 "\nA DVB frontend tool using API version 5\n"
48 "\nOn the options below, the arguments are:\n"
49 " ADAPTER - the dvb adapter to control\n"
50 " FRONTEND - the dvb frontend to control\n"
51 " SERVER - server address which is running the dvb5-daemon\n"
52 " PORT - server port used by the dvb5-daemon\n");
53
54 static const struct argp_option options[] = {
55 {"verbose", 'v', 0, 0, N_("enables debug messages"), 0},
56 {"adapter", 'a', N_("ADAPTER"), 0, N_("dvb adapter"), 0},
57 {"frontend", 'f', N_("FRONTEND"), 0, N_("dvb frontend"), 0},
58 {"set-delsys", 'd', N_("PARAMS"), 0, N_("set delivery system"), 0},
59 {"femon", 'm', 0, 0, N_("monitors frontend stats on an streaming frontend"), 0},
60 {"acoustical", 'A', 0, 0, N_("beeps if signal quality is good. Also enables femon mode. Please notice that console beep should be enabled on your wm."), 0},
61 #if 0 /* Currently not implemented */
62 {"set", 's', N_("PARAMS"), 0, N_("set frontend"), 0},
63 #endif
64 {"get", 'g', 0, 0, N_("get frontend"), 0},
65 {"server", 'H', N_("SERVER"), 0, N_("dvbv5-daemon host IP address"), 0},
66 {"tcp-port", 'T', N_("PORT"), 0, N_("dvbv5-daemon host tcp port"), 0},
67 {"device-mon", 'D', 0, 0, N_("monitors device insert/removal"), 0},
68 {"count", 'c', N_("COUNT"), 0, N_("samples to take (default 0 = infinite)"), 0},
69 {"help", '?', 0, 0, N_("Give this help list"), -1},
70 {"usage", -3, 0, 0, N_("Give a short usage message")},
71 {"version", 'V', 0, 0, N_("Print program version"), -1},
72 { 0, 0, 0, 0, 0, 0 }
73 };
74
75 static int adapter = 0;
76 static int frontend = 0;
77 static unsigned get = 0;
78 static char *set_params = NULL;
79 static char *server = NULL;
80 static unsigned port = 0;
81 static int verbose = 0;
82 static int delsys = 0;
83 static int femon = 0;
84 static int acoustical = 0;
85 static int timeout_flag = 0;
86 static int device_mon = 0;
87 static int count = 0;
88
do_timeout(int x)89 static void do_timeout(int x)
90 {
91 (void)x;
92
93 if (timeout_flag == 0) {
94 timeout_flag = 1;
95 alarm(2);
96 signal(SIGALRM, do_timeout);
97 } else {
98 /* something has gone wrong ... exit */
99 exit(1);
100 }
101 }
102
103 #define ERROR(x...) \
104 do { \
105 fprintf(stderr, _("ERROR: ")); \
106 fprintf(stderr, x); \
107 fprintf(stderr, "\n"); \
108 } while (0)
109
110
parse_opt(int k,char * arg,struct argp_state * state)111 static error_t parse_opt(int k, char *arg, struct argp_state *state)
112 {
113 switch (k) {
114 case 'a':
115 adapter = atoi(arg);
116 break;
117 case 'f':
118 frontend = atoi(arg);
119 break;
120 case 'd':
121 delsys = dvb_parse_delsys(arg);
122 if (delsys < 0)
123 return ARGP_ERR_UNKNOWN;
124 break;
125 case 'm':
126 femon++;
127 break;
128 case 'A':
129 femon++;
130 acoustical++;
131 break;
132 #if 0
133 case 's':
134 set_params = arg;
135 break;
136 #endif
137 case 'g':
138 get++;
139 break;
140 case 'D':
141 device_mon++;
142 break;
143 case 'H':
144 server = arg;
145 break;
146 case 'T':
147 port = atoi(arg);
148 break;
149 case 'v':
150 verbose ++;
151 break;
152 case 'c':
153 count = atoi(arg);
154 break;
155 case '?':
156 argp_state_help(state, state->out_stream,
157 ARGP_HELP_SHORT_USAGE | ARGP_HELP_LONG
158 | ARGP_HELP_DOC);
159 fprintf(state->out_stream, _("\nReport bugs to %s.\n"), argp_program_bug_address);
160 exit(0);
161 case 'V':
162 fprintf (state->out_stream, "%s\n", argp_program_version);
163 exit(0);
164 case -3:
165 argp_state_help(state, state->out_stream, ARGP_HELP_USAGE);
166 exit(0);
167 default:
168 return ARGP_ERR_UNKNOWN;
169 }
170 return 0;
171 }
172
173 static struct argp argp = {
174 .options = options,
175 .parser = parse_opt,
176 .doc = doc,
177 };
178
print_frontend_stats(FILE * fd,struct dvb_v5_fe_parms * parms)179 static int print_frontend_stats(FILE *fd,
180 struct dvb_v5_fe_parms *parms)
181 {
182 char buf[512], *p;
183 int rc, i, len, show, n_status_lines = 0;
184
185 rc = dvb_fe_get_stats(parms);
186 if (rc) {
187 ERROR(_("dvb_fe_get_stats failed"));
188 return -1;
189 }
190
191 p = buf;
192 len = sizeof(buf);
193 dvb_fe_snprintf_stat(parms, DTV_STATUS, NULL, 0, &p, &len, &show);
194
195 for (i = 0; i < MAX_DTV_STATS; i++) {
196 show = 1;
197
198 dvb_fe_snprintf_stat(parms, DTV_QUALITY, _("Quality"),
199 i, &p, &len, &show);
200
201 dvb_fe_snprintf_stat(parms, DTV_STAT_SIGNAL_STRENGTH, _("Signal"),
202 i, &p, &len, &show);
203
204 dvb_fe_snprintf_stat(parms, DTV_STAT_CNR, _("C/N"),
205 i, &p, &len, &show);
206
207 dvb_fe_snprintf_stat(parms, DTV_STAT_ERROR_BLOCK_COUNT, _("UCB"),
208 i, &p, &len, &show);
209
210 dvb_fe_snprintf_stat(parms, DTV_BER, _("postBER"),
211 i, &p, &len, &show);
212
213 dvb_fe_snprintf_stat(parms, DTV_PRE_BER, _("preBER"),
214 i, &p, &len, &show);
215
216 dvb_fe_snprintf_stat(parms, DTV_PER, _("PER"),
217 i, &p, &len, &show);
218 if (p != buf) {
219 if (isatty(fileno(fd))) {
220 enum dvb_quality qual;
221 int color;
222
223 qual = dvb_fe_retrieve_quality(parms, 0);
224
225 switch (qual) {
226 case DVB_QUAL_POOR:
227 color = 31;
228 break;
229 case DVB_QUAL_OK:
230 color = 36;
231 break;
232 case DVB_QUAL_GOOD:
233 color = 32;
234 break;
235 case DVB_QUAL_UNKNOWN:
236 default:
237 color = 0;
238 break;
239 }
240 fprintf(fd, "\033[%dm", color);
241 /*
242 * It would be great to change the BELL
243 * tone depending on the quality. The legacy
244 * femon used to to that, but this doesn't
245 * work anymore with modern Linux distros.
246 *
247 * So, just print a bell if quality is good.
248 *
249 * The console audio should be enabled
250 * at the window manater for this to
251 * work.
252 */
253 if (acoustical) {
254 if (qual == DVB_QUAL_GOOD)
255 fprintf(fd, "\a");
256 }
257 }
258
259 if (n_status_lines)
260 fprintf(fd, "\t%s\n", buf);
261 else
262 fprintf(fd, "%s\n", buf);
263
264 n_status_lines++;
265
266 p = buf;
267 len = sizeof(buf);
268 }
269 }
270
271 fflush(fd);
272
273 return 0;
274 }
275
get_show_stats(struct dvb_v5_fe_parms * parms)276 static void get_show_stats(struct dvb_v5_fe_parms *parms)
277 {
278 int rc;
279
280 signal(SIGTERM, do_timeout);
281 signal(SIGINT, do_timeout);
282
283 do {
284 rc = dvb_fe_get_stats(parms);
285 if (!rc)
286 print_frontend_stats(stderr, parms);
287 if (count > 0 && !--count)
288 break;
289 if (!timeout_flag)
290 usleep(1000000);
291 } while (!timeout_flag);
292 }
293
294 static const char * const event_type[] = {
295 [DVB_DEV_ADD] = "added",
296 [DVB_DEV_CHANGE] = "changed",
297 [DVB_DEV_REMOVE] = "removed",
298 };
299
dev_change_monitor(char * sysname,enum dvb_dev_change_type type,void * user_priv)300 static int dev_change_monitor(char *sysname,
301 enum dvb_dev_change_type type, void *user_priv)
302 {
303 if (type >= ARRAY_SIZE(event_type))
304 printf("unknown event on device %s\n", sysname);
305 else
306 printf("device %s was %s\n", sysname, event_type[type]);
307 free(sysname);
308
309 return 0;
310 }
311
main(int argc,char * argv[])312 int main(int argc, char *argv[])
313 {
314 struct dvb_device *dvb;
315 struct dvb_dev_list *dvb_dev;
316 struct dvb_v5_fe_parms *parms;
317 int ret, fe_flags = O_RDWR;
318
319 #ifdef ENABLE_NLS
320 setlocale (LC_ALL, "");
321 bindtextdomain (PACKAGE, LOCALEDIR);
322 textdomain (PACKAGE);
323 #endif
324
325 if (argp_parse(&argp, argc, argv, ARGP_NO_HELP | ARGP_NO_EXIT, 0, 0)) {
326 argp_help(&argp, stderr, ARGP_HELP_SHORT_USAGE, PROGRAM_NAME);
327 return -1;
328 }
329
330 /*
331 * If called without any option, be verbose, to print the
332 * DVB frontend information.
333 */
334 if (!get && !delsys && !set_params && !femon)
335 verbose++;
336
337 if (!delsys && !set_params)
338 fe_flags = O_RDONLY;
339
340 dvb = dvb_dev_alloc();
341 if (!dvb)
342 return -1;
343
344 if (server && port) {
345 printf(_("Connecting to %s:%d\n"), server, port);
346 ret = dvb_dev_remote_init(dvb, server, port);
347 if (ret < 0)
348 return -1;
349 }
350
351 dvb_dev_set_log(dvb, verbose, NULL);
352 if (device_mon) {
353 dvb_dev_find(dvb, &dev_change_monitor, NULL);
354 while (1) {
355 usleep(1000000);
356 }
357 }
358 dvb_dev_find(dvb, NULL, NULL);
359 parms = dvb->fe_parms;
360
361 dvb_dev = dvb_dev_seek_by_adapter(dvb, adapter, frontend,
362 DVB_DEVICE_FRONTEND);
363 if (!dvb_dev)
364 return -1;
365
366 if (!dvb_dev_open(dvb, dvb_dev->sysname, fe_flags))
367 return -1;
368
369 if (delsys) {
370 printf(_("Changing delivery system to: %s\n"),
371 delivery_system_name[delsys]);
372 dvb_set_sys(parms, delsys);
373 goto ret;
374 }
375
376 #if 0
377 if (set_params)
378 do_something();
379 #endif
380 if (get) {
381 dvb_fe_get_parms(parms);
382 dvb_fe_prt_parms(parms);
383 }
384
385 if (femon)
386 get_show_stats(parms);
387
388 ret:
389 dvb_dev_free(dvb);
390
391 return 0;
392 }
393