• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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