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