1 /*
2 * Copyright (c) 2011-2012 - Mauro Carvalho Chehab
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation version 2.1 of the License.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
17 */
18 #include <sys/types.h>
19
20 #include "dvb-fe-priv.h"
21 #include "dvb-v5.h"
22 #include <libdvbv5/dvb-dev.h>
23 #include <libdvbv5/countries.h>
24 #include <libdvbv5/dvb-v5-std.h>
25
26 #include <inttypes.h>
27 #include <math.h>
28 #include <stddef.h>
29 #include <time.h>
30 #include <unistd.h>
31 #include <stdarg.h>
32
33 #ifdef ENABLE_NLS
34 # include "gettext.h"
35 # include <libintl.h>
36 # define _(string) dgettext(LIBDVBV5_DOMAIN, string)
37 # define P_(singular, plural, n) dngettext(LIBDVBV5_DOMAIN, singular, plural, n)
38
39 static int libdvbv5_initialized = 0;
40
41 #else
42 # define _(string) string
43 # define P_(singular, plural, n) ((n) == 1 ? (singular) : (plural))
44 #endif
45
46 # define N_(string) string
47
48 #define MAX_TIME 10 /* 1.0 seconds */
49
50 #define xioctl(fh, request, arg...) ({ \
51 int __rc; \
52 struct timespec __start, __end; \
53 \
54 clock_gettime(CLOCK_MONOTONIC, &__start); \
55 do { \
56 __rc = ioctl(fh, request, ##arg); \
57 if (__rc != -1) \
58 break; \
59 if ((errno != EINTR) && (errno != EAGAIN)) \
60 break; \
61 clock_gettime(CLOCK_MONOTONIC, &__end); \
62 if (__end.tv_sec * 10 + __end.tv_nsec / 100000000 > \
63 __start.tv_sec * 10 + __start.tv_nsec / 100000000 + \
64 MAX_TIME) \
65 break; \
66 } while (1); \
67 \
68 __rc; \
69 })
70
libdvbv5_initialize(void)71 static void libdvbv5_initialize(void)
72 {
73 #ifdef ENABLE_NLS
74 if (libdvbv5_initialized)
75 return;
76 bindtextdomain(LIBDVBV5_DOMAIN, LOCALEDIR);
77 libdvbv5_initialized = 1;
78 #endif
79 }
80
dvb_v5_free(struct dvb_v5_fe_parms_priv * parms)81 void dvb_v5_free(struct dvb_v5_fe_parms_priv *parms)
82 {
83 if (parms->fname)
84 free(parms->fname);
85
86 free(parms);
87 }
88
dvb_fe_dummy(void)89 struct dvb_v5_fe_parms *dvb_fe_dummy(void)
90 {
91 struct dvb_v5_fe_parms_priv *parms = NULL;
92
93 libdvbv5_initialize();
94
95 parms = calloc(sizeof(*parms), 1);
96 if (!parms)
97 return NULL;
98 parms->p.logfunc = dvb_default_log;
99 parms->fd = -1;
100 parms->p.default_charset = "iso-8859-1";
101 parms->p.output_charset = "utf-8";
102 parms->p.lna = LNA_AUTO;
103 parms->p.sat_number = -1;
104 parms->p.abort = 0;
105 parms->country = COUNTRY_UNKNOWN;
106
107 return &parms->p;
108 }
109
dvb_fe_open(int adapter,int frontend,unsigned verbose,unsigned use_legacy_call)110 struct dvb_v5_fe_parms *dvb_fe_open(int adapter, int frontend,
111 unsigned verbose,
112 unsigned use_legacy_call)
113 {
114 return dvb_fe_open_flags(adapter, frontend, verbose, use_legacy_call,
115 NULL, O_RDWR);
116
117 }
118
dvb_fe_open2(int adapter,int frontend,unsigned verbose,unsigned use_legacy_call,dvb_logfunc logfunc)119 struct dvb_v5_fe_parms *dvb_fe_open2(int adapter, int frontend,
120 unsigned verbose, unsigned use_legacy_call,
121 dvb_logfunc logfunc)
122 {
123 return dvb_fe_open_flags(adapter, frontend, verbose, use_legacy_call,
124 logfunc, O_RDWR);
125 }
126
dvb_fe_open_flags(int adapter,int frontend,unsigned verbose,unsigned use_legacy_call,dvb_logfunc logfunc,int flags)127 struct dvb_v5_fe_parms *dvb_fe_open_flags(int adapter, int frontend,
128 unsigned verbose,
129 unsigned use_legacy_call,
130 dvb_logfunc logfunc,
131 int flags)
132 {
133 int ret;
134 char *fname;
135 struct dvb_device *dvb;
136 struct dvb_dev_list *dvb_dev;
137 struct dvb_v5_fe_parms_priv *parms = NULL;
138
139 libdvbv5_initialize();
140
141 if (logfunc == NULL)
142 logfunc = dvb_default_log;
143
144 dvb = dvb_dev_alloc();
145 dvb_dev_find(dvb, NULL, NULL);
146 dvb_dev = dvb_dev_seek_by_adapter(dvb, adapter, frontend,
147 DVB_DEVICE_FRONTEND);
148 if (!dvb_dev) {
149 logfunc(LOG_ERR, _("adapter %d, frontend %d not found"),
150 adapter, frontend);
151 dvb_dev_free(dvb);
152 return NULL;
153 }
154 fname = strdup(dvb_dev->path);
155
156 if (!strcmp(dvb_dev->bus_addr, "platform:dvbloopback")) {
157 logfunc(LOG_WARNING, _("Detected dvbloopback"));
158 flags |= O_NONBLOCK;
159 }
160
161 dvb_dev_free(dvb);
162 if (!fname) {
163 logfunc(LOG_ERR, _("fname calloc: %s"), strerror(errno));
164 return NULL;
165 }
166 parms = calloc(sizeof(*parms), 1);
167 if (!parms) {
168 logfunc(LOG_ERR, _("parms calloc: %s"), strerror(errno));
169 free(fname);
170 return NULL;
171 }
172 parms->p.verbose = verbose;
173 parms->p.default_charset = "iso-8859-1";
174 parms->p.output_charset = "utf-8";
175 parms->p.logfunc = logfunc;
176 parms->p.lna = LNA_AUTO;
177 parms->p.sat_number = -1;
178 parms->p.abort = 0;
179 parms->country = COUNTRY_UNKNOWN;
180
181 if (use_legacy_call)
182 parms->p.legacy_fe = 1;
183
184 ret = dvb_fe_open_fname(parms, fname, flags);
185 if (ret < 0) {
186 dvb_v5_free(parms);
187 return NULL;
188 }
189
190 return &parms->p;
191 }
192
193 static int __dvb_fe_snprintf_eng(char *buf, int len, float val, int metric);
194
dvb_fe_open_fname(struct dvb_v5_fe_parms_priv * parms,char * fname,int flags)195 int dvb_fe_open_fname(struct dvb_v5_fe_parms_priv *parms, char *fname,
196 int flags)
197 {
198 struct dtv_properties dtv_prop;
199 int fd, i;
200
201 fd = open(fname, flags, 0);
202 if (fd == -1) {
203 dvb_logerr(_("%s while opening %s"), strerror(errno), fname);
204 free(fname);
205 return -errno;
206 }
207
208 if (xioctl(fd, FE_GET_INFO, &parms->p.info) == -1) {
209 dvb_perror("FE_GET_INFO");
210 close(fd);
211 return -errno;
212 }
213
214 if (parms->p.verbose) {
215 fe_caps_t caps = parms->p.info.caps;
216
217 dvb_log(_("Device %s (%s) capabilities:"),
218 parms->p.info.name, fname);
219 for (i = 0; i < ARRAY_SIZE(fe_caps_name); i++) {
220 if (caps & fe_caps_name[i].idx)
221 dvb_log (" %s", fe_caps_name[i].name);
222 }
223 }
224
225 parms->fname = fname;
226 parms->fd = fd;
227 parms->fe_flags = flags;
228 parms->dvb_prop[0].cmd = DTV_API_VERSION;
229 parms->dvb_prop[1].cmd = DTV_DELIVERY_SYSTEM;
230
231 dtv_prop.num = 2;
232 dtv_prop.props = parms->dvb_prop;
233
234 /* Detect a DVBv3 device */
235 if (parms->p.legacy_fe || xioctl(fd, FE_GET_PROPERTY, &dtv_prop) == -1) {
236 parms->dvb_prop[0].u.data = 0x300;
237 parms->dvb_prop[1].u.data = SYS_UNDEFINED;
238 }
239
240 parms->p.version = parms->dvb_prop[0].u.data;
241 parms->p.current_sys = parms->dvb_prop[1].u.data;
242 if (parms->p.verbose)
243 dvb_log (_("DVB API Version %d.%d%s, Current v5 delivery system: %s"),
244 parms->p.version / 256,
245 parms->p.version % 256,
246 parms->p.legacy_fe ? _(" (forcing DVBv3 calls)") : "",
247 delivery_system_name[parms->p.current_sys]);
248
249 if (parms->p.version < 0x500)
250 parms->p.legacy_fe = 1;
251
252 if (parms->p.version >= 0x50a)
253 parms->p.has_v5_stats = 1;
254 else
255 parms->p.has_v5_stats = 0;
256
257 if (parms->p.legacy_fe || parms->p.version < 0x505) {
258 parms->p.legacy_fe = 1;
259 switch(parms->p.info.type) {
260 case FE_QPSK:
261 parms->p.current_sys = SYS_DVBS;
262 parms->p.systems[parms->p.num_systems++] = parms->p.current_sys;
263 if (parms->p.version < 0x0500)
264 break;
265 if (parms->p.info.caps & FE_CAN_2G_MODULATION)
266 parms->p.systems[parms->p.num_systems++] = SYS_DVBS2;
267 if (parms->p.info.caps & FE_CAN_TURBO_FEC)
268 parms->p.systems[parms->p.num_systems++] = SYS_TURBO;
269 break;
270 case FE_QAM:
271 parms->p.current_sys = SYS_DVBC_ANNEX_A;
272 parms->p.systems[parms->p.num_systems++] = parms->p.current_sys;
273 break;
274 case FE_OFDM:
275 parms->p.current_sys = SYS_DVBT;
276 parms->p.systems[parms->p.num_systems++] = parms->p.current_sys;
277 if (parms->p.version < 0x0500)
278 break;
279 if (parms->p.info.caps & FE_CAN_2G_MODULATION)
280 parms->p.systems[parms->p.num_systems++] = SYS_DVBT2;
281 break;
282 case FE_ATSC:
283 if (parms->p.info.caps & (FE_CAN_8VSB | FE_CAN_16VSB))
284 parms->p.systems[parms->p.num_systems++] = SYS_ATSC;
285 if (parms->p.info.caps & (FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_QAM_AUTO))
286 parms->p.systems[parms->p.num_systems++] = SYS_DVBC_ANNEX_B;
287 parms->p.current_sys = parms->p.systems[0];
288 break;
289 }
290 if (!parms->p.num_systems) {
291 dvb_logerr(_("delivery system not detected"));
292 close(fd);
293 return -EINVAL;
294 }
295 } else {
296 parms->dvb_prop[0].cmd = DTV_ENUM_DELSYS;
297 parms->n_props = 1;
298 dtv_prop.num = 1;
299 dtv_prop.props = parms->dvb_prop;
300 if (xioctl(fd, FE_GET_PROPERTY, &dtv_prop) == -1) {
301 dvb_perror("FE_GET_PROPERTY");
302 close(fd);
303 return -errno;
304 }
305 parms->p.num_systems = parms->dvb_prop[0].u.buffer.len;
306 for (i = 0; i < parms->p.num_systems; i++)
307 parms->p.systems[i] = parms->dvb_prop[0].u.buffer.data[i];
308
309 if (parms->p.num_systems == 0) {
310 dvb_logerr(_("driver returned 0 supported delivery systems!"));
311 close(fd);
312 return -EINVAL;
313 }
314 }
315
316 if (parms->p.verbose) {
317 dvb_log(P_("Supported delivery system: ", "Supported delivery systems: ", parms->p.num_systems));
318 for (i = 0; i < parms->p.num_systems; i++) {
319 if (parms->p.systems[i] == parms->p.current_sys)
320 dvb_log (" [%s]",
321 delivery_system_name[parms->p.systems[i]]);
322 else
323 dvb_log (" %s",
324 delivery_system_name[parms->p.systems[i]]);
325 }
326 if (parms->p.legacy_fe || parms->p.version < 0x505)
327 dvb_log(_("Warning: new delivery systems like ISDB-T, ISDB-S, DMB-TH, DSS, ATSC-MH will be miss-detected by a DVBv5.4 or earlier API call"));
328 }
329
330 /*
331 * Fix a bug at some DVB drivers
332 */
333 if (parms->p.current_sys == SYS_UNDEFINED)
334 parms->p.current_sys = parms->p.systems[0];
335
336 /* Prepare to use the delivery system */
337 parms->n_props = dvb_add_parms_for_sys(&parms->p, parms->p.current_sys);
338
339 if ((flags & O_ACCMODE) == O_RDWR)
340 dvb_set_sys(&parms->p, parms->p.current_sys);
341
342 if (parms->p.verbose) {
343 char buf[256];
344 uint32_t frq_min, frq_max, frq_stp, frq_tol;
345
346 frq_min = parms->p.info.frequency_min;
347 frq_max = parms->p.info.frequency_max;
348 frq_stp = parms->p.info.frequency_stepsize;
349 frq_tol = parms->p.info.frequency_tolerance;
350 if (parms->p.info.type == FE_QPSK) {
351 /* For Satellite, frequencies are in kHz */
352 frq_min *= 1000;
353 frq_max *= 1000;
354 frq_stp *= 1000;
355 frq_tol *= 1000;
356 }
357
358 dvb_log(_("Frequency range for the current standard: "));
359
360 __dvb_fe_snprintf_eng(buf, sizeof(buf), frq_min, 1);
361 dvb_log(_("From: %11sHz"), buf);
362 __dvb_fe_snprintf_eng(buf, sizeof(buf), frq_max, 1);
363 dvb_log(_("To: %11sHz"), buf);
364 if (frq_stp) {
365 __dvb_fe_snprintf_eng(buf, sizeof(buf), frq_stp, 1);
366 dvb_log(_("Step: %11sHz"), buf);
367 }
368 if (frq_tol) {
369 __dvb_fe_snprintf_eng(buf, sizeof(buf), frq_tol, 1);
370 dvb_log(_("Tolerance: %11sHz"), buf);
371 }
372
373 if (parms->p.info.type == FE_QPSK || parms->p.info.type == FE_QAM) {
374 dvb_log(_("Symbol rate ranges for the current standard: "));
375 __dvb_fe_snprintf_eng(buf, sizeof(buf), parms->p.info.symbol_rate_min, 1);
376 dvb_log(_("From: %11sBauds"), buf);
377 __dvb_fe_snprintf_eng(buf, sizeof(buf), parms->p.info.symbol_rate_max, 1);
378 dvb_log(_("To: %11sBauds"), buf);
379 if (parms->p.info.symbol_rate_tolerance) {
380 __dvb_fe_snprintf_eng(buf, sizeof(buf), parms->p.info.symbol_rate_tolerance, 1);
381 dvb_log(_("Tolerance: %11sBauds"), buf);
382 }
383 }
384 }
385
386 /*
387 * Prepare the status struct - DVBv5.10 parameters should
388 * come first, as they'll be read together.
389 */
390 parms->stats.prop[0].cmd = DTV_STAT_SIGNAL_STRENGTH;
391 parms->stats.prop[1].cmd = DTV_STAT_CNR;
392 parms->stats.prop[2].cmd = DTV_STAT_PRE_ERROR_BIT_COUNT;
393 parms->stats.prop[3].cmd = DTV_STAT_PRE_TOTAL_BIT_COUNT;
394 parms->stats.prop[4].cmd = DTV_STAT_POST_ERROR_BIT_COUNT;
395 parms->stats.prop[5].cmd = DTV_STAT_POST_TOTAL_BIT_COUNT;
396 parms->stats.prop[6].cmd = DTV_STAT_ERROR_BLOCK_COUNT;
397 parms->stats.prop[7].cmd = DTV_STAT_TOTAL_BLOCK_COUNT;
398
399 /* Now, status and the calculated stats */
400 parms->stats.prop[8].cmd = DTV_STATUS;
401 parms->stats.prop[9].cmd = DTV_BER;
402 parms->stats.prop[10].cmd = DTV_PER;
403 parms->stats.prop[11].cmd = DTV_QUALITY;
404 parms->stats.prop[12].cmd = DTV_PRE_BER;
405
406 return 0;
407 }
408
409
dvb_fe_is_satellite(uint32_t delivery_system)410 int dvb_fe_is_satellite(uint32_t delivery_system)
411 {
412 switch (delivery_system) {
413 case SYS_DVBS:
414 case SYS_DVBS2:
415 case SYS_TURBO:
416 case SYS_ISDBS:
417 return 1;
418 default:
419 return 0;
420
421 }
422 }
423
__dvb_fe_close(struct dvb_v5_fe_parms_priv * parms)424 void __dvb_fe_close(struct dvb_v5_fe_parms_priv *parms)
425 {
426 if (!parms || parms->fd < 0)
427 return;
428
429 /* Disable LNBf power */
430 if (dvb_fe_is_satellite(parms->p.current_sys))
431 dvb_fe_sec_voltage(&parms->p, 0, 0);
432
433 close(parms->fd);
434 parms->fd = -1;
435 }
436
dvb_fe_close(struct dvb_v5_fe_parms * p)437 void dvb_fe_close(struct dvb_v5_fe_parms *p)
438 {
439 struct dvb_v5_fe_parms_priv *parms = (void *)p;
440
441 if (!parms)
442 return;
443
444 if (parms->fd < 0) {
445 dvb_v5_free(parms);
446 return;
447 }
448
449 /* Disable LNBf power */
450 if (dvb_fe_is_satellite(parms->p.current_sys))
451 dvb_fe_sec_voltage(&parms->p, 0, 0);
452
453 close(parms->fd);
454
455 dvb_v5_free(parms);
456 }
457
458
dvb_add_parms_for_sys(struct dvb_v5_fe_parms * p,fe_delivery_system_t sys)459 int dvb_add_parms_for_sys(struct dvb_v5_fe_parms *p,
460 fe_delivery_system_t sys)
461 {
462 struct dvb_v5_fe_parms_priv *parms = (void *)p;
463 struct dtv_property *dvb_prop = parms->dvb_prop;
464 unsigned max_size = ARRAY_SIZE(parms->dvb_prop);
465 const unsigned int *sys_props;
466 int n;
467
468 /* Make dvb properties reflect the current standard */
469
470 sys_props = dvb_v5_delivery_system[sys];
471 if (!sys_props)
472 return -EINVAL;
473
474 n = 0;
475 while (sys_props[n] && n < max_size - 1) {
476 dvb_prop[n].cmd = sys_props[n];
477 dvb_prop[n].u.data = 0;
478 n++;
479 }
480 dvb_prop[n].cmd = DTV_DELIVERY_SYSTEM;
481 dvb_prop[n].u.data = sys;
482 n++;
483
484 return n;
485 }
486
__dvb_set_sys(struct dvb_v5_fe_parms * p,fe_delivery_system_t sys)487 int __dvb_set_sys(struct dvb_v5_fe_parms *p, fe_delivery_system_t sys)
488 {
489 struct dvb_v5_fe_parms_priv *parms = (void *)p;
490 struct dtv_property dvb_prop[1];
491 struct dtv_properties prop;
492 struct dvb_frontend_info new_info;
493 int rc;
494
495 if (sys != parms->p.current_sys) {
496 /* Disable LNBf power */
497 if (dvb_fe_is_satellite(parms->p.current_sys) &&
498 !dvb_fe_is_satellite(sys))
499 dvb_fe_sec_voltage(&parms->p, 0, 0);
500
501 /* Can't change standard with the legacy FE support */
502 if (parms->p.legacy_fe)
503 return -EINVAL;
504
505 dvb_prop[0].cmd = DTV_DELIVERY_SYSTEM;
506 dvb_prop[0].u.data = sys;
507 prop.num = 1;
508 prop.props = dvb_prop;
509
510 if (xioctl(parms->fd, FE_SET_PROPERTY, &prop) == -1) {
511 dvb_perror(_("Set delivery system"));
512 return -errno;
513 }
514 }
515
516 /*
517 * This should not happen frequently, as this ioctl is pretty
518 * straight forward. However, if it happens, it is better
519 * to print an error message and ignore the error, as it
520 * may still work.
521 */
522 if (xioctl(parms->fd, FE_GET_INFO, &new_info) == -1)
523 dvb_perror(_("Can't retrieve DVB information for the new delivery system."));
524 else
525 parms->p.info = new_info;
526
527 rc = dvb_add_parms_for_sys(&parms->p, sys);
528 if (rc < 0)
529 return -EINVAL;
530
531 parms->p.current_sys = sys;
532 parms->n_props = rc;
533
534 return 0;
535 }
536
dvbv3_type(uint32_t delivery_system)537 static enum dvbv3_emulation_type dvbv3_type(uint32_t delivery_system)
538 {
539 switch (delivery_system) {
540 case SYS_DVBC_ANNEX_A:
541 case SYS_DVBC_ANNEX_C:
542 return DVBV3_QAM;
543 case SYS_DVBS:
544 case SYS_DVBS2:
545 case SYS_TURBO:
546 case SYS_ISDBS:
547 case SYS_DSS:
548 return DVBV3_QPSK;
549 case SYS_DVBT:
550 case SYS_DVBT2:
551 case SYS_ISDBT:
552 case SYS_DTMB:
553 return DVBV3_OFDM;
554 case SYS_ATSC:
555 case SYS_ATSCMH:
556 case SYS_DVBC_ANNEX_B:
557 return DVBV3_ATSC;
558 default:
559 return DVBV3_UNKNOWN;
560 }
561 };
562
is_dvbv3_delsys(uint32_t delsys)563 static int is_dvbv3_delsys(uint32_t delsys)
564 {
565 int status;
566
567 status = (delsys == SYS_DVBT) || (delsys == SYS_DVBC_ANNEX_A) ||
568 (delsys == SYS_DVBS) || (delsys == SYS_ATSC);
569
570 return status;
571 }
572
dvb_set_compat_delivery_system(struct dvb_v5_fe_parms * p,uint32_t desired_system)573 int dvb_set_compat_delivery_system(struct dvb_v5_fe_parms *p,
574 uint32_t desired_system)
575 {
576 struct dvb_v5_fe_parms_priv *parms = (void *)p;
577 int i;
578 uint32_t delsys = SYS_UNDEFINED;
579 enum dvbv3_emulation_type type;
580
581 /* Check if the desired delivery system is supported */
582 for (i = 0; i < parms->p.num_systems; i++) {
583 if (parms->p.systems[i] == desired_system) {
584 dvb_set_sys(&parms->p, desired_system);
585 return 0;
586 }
587 }
588
589 /*
590 * Find the closest DVBv3 system that matches the delivery
591 * system.
592 */
593 type = dvbv3_type(desired_system);
594
595 /*
596 * Get the last non-DVBv3 delivery system that has the same type
597 * of the desired system
598 */
599 for (i = 0; i < parms->p.num_systems; i++) {
600 if ((dvbv3_type(parms->p.systems[i]) == type) &&
601 !is_dvbv3_delsys(parms->p.systems[i]))
602 delsys = parms->p.systems[i];
603 }
604
605 if (delsys == SYS_UNDEFINED)
606 return -EINVAL;
607
608 dvb_log(_("Using a DVBv3 compat file for %s"), delivery_system_name[delsys]);
609
610 dvb_set_sys(&parms->p, delsys);
611
612 /* Put ISDB-T into auto mode */
613 if (delsys == SYS_ISDBT) {
614 dvb_fe_store_parm(&parms->p, DTV_BANDWIDTH_HZ, 6000000);
615 dvb_fe_store_parm(&parms->p, DTV_ISDBT_PARTIAL_RECEPTION, 0);
616 dvb_fe_store_parm(&parms->p, DTV_ISDBT_SOUND_BROADCASTING, 0);
617 dvb_fe_store_parm(&parms->p, DTV_ISDBT_SB_SUBCHANNEL_ID, 0);
618 dvb_fe_store_parm(&parms->p, DTV_ISDBT_SB_SEGMENT_IDX, 0);
619 dvb_fe_store_parm(&parms->p, DTV_ISDBT_SB_SEGMENT_COUNT, 0);
620 dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYER_ENABLED, 7);
621 dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERA_FEC, FEC_AUTO);
622 dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERB_FEC, FEC_AUTO);
623 dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERC_FEC, FEC_AUTO);
624 dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERA_MODULATION, QAM_AUTO);
625 dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERB_MODULATION, QAM_AUTO);
626 dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERC_MODULATION, QAM_AUTO);
627 dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERA_SEGMENT_COUNT, 0);
628 dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERA_TIME_INTERLEAVING, 0);
629 dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERB_SEGMENT_COUNT, 0);
630 dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERB_TIME_INTERLEAVING, 0);
631 dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERC_SEGMENT_COUNT, 0);
632 dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 0);
633 }
634 return 0;
635 }
636
dvb_cmd_name(int cmd)637 const char *dvb_cmd_name(int cmd)
638 {
639 if (cmd >= 0 && cmd < ARRAY_SIZE(dvb_v5_name))
640 return dvb_v5_name[cmd];
641 if (cmd >= DTV_USER_COMMAND_START && cmd <= DTV_MAX_USER_COMMAND)
642 return dvb_user_name[cmd - DTV_USER_COMMAND_START];
643 if (cmd >= DTV_STAT_COMMAND_START && cmd <= DTV_MAX_STAT_COMMAND)
644 return dvb_stat_name[cmd - DTV_STAT_COMMAND_START];
645 return NULL;
646 }
647
dvb_attr_names(int cmd)648 const char *const *dvb_attr_names(int cmd)
649 {
650 if (cmd >= 0 && cmd < DTV_MAX_COMMAND)
651 return dvb_v5_attr_names[cmd];
652
653 if (cmd >= DTV_USER_COMMAND_START && cmd <= DTV_MAX_USER_COMMAND)
654 return dvb_user_attr_names[cmd - DTV_USER_COMMAND_START];
655 return NULL;
656 }
657
dvb_fe_prt_parms(const struct dvb_v5_fe_parms * p)658 void dvb_fe_prt_parms(const struct dvb_v5_fe_parms *p)
659 {
660 struct dvb_v5_fe_parms_priv *parms = (void *)p;
661 int i;
662
663 for (i = 0; i < parms->n_props; i++) {
664 const char * const *attr_name = dvb_attr_names(parms->dvb_prop[i].cmd);
665 if (attr_name) {
666 int j;
667
668 for (j = 0; j < parms->dvb_prop[i].u.data; j++) {
669 if (!*attr_name)
670 break;
671 attr_name++;
672 }
673 }
674
675 if (!attr_name || !*attr_name)
676 dvb_log("%s = %u",
677 dvb_cmd_name(parms->dvb_prop[i].cmd),
678 parms->dvb_prop[i].u.data);
679 else
680 dvb_log("%s = %s",
681 dvb_cmd_name(parms->dvb_prop[i].cmd),
682 *attr_name);
683 }
684 };
685
dvb_fe_retrieve_parm(const struct dvb_v5_fe_parms * p,unsigned cmd,uint32_t * value)686 int dvb_fe_retrieve_parm(const struct dvb_v5_fe_parms *p,
687 unsigned cmd, uint32_t *value)
688 {
689 struct dvb_v5_fe_parms_priv *parms = (void *)p;
690 int i;
691 for (i = 0; i < parms->n_props; i++) {
692 if (parms->dvb_prop[i].cmd != cmd)
693 continue;
694 *value = parms->dvb_prop[i].u.data;
695 return 0;
696 }
697 dvb_logerr(_("command %s (%d) not found during retrieve"),
698 dvb_cmd_name(cmd), cmd);
699
700 return -EINVAL;
701 }
702
dvb_fe_store_parm(struct dvb_v5_fe_parms * p,unsigned cmd,uint32_t value)703 int dvb_fe_store_parm(struct dvb_v5_fe_parms *p,
704 unsigned cmd, uint32_t value)
705 {
706 struct dvb_v5_fe_parms_priv *parms = (void *)p;
707 int i;
708 for (i = 0; i < parms->n_props; i++) {
709 if (parms->dvb_prop[i].cmd != cmd)
710 continue;
711 parms->dvb_prop[i].u.data = value;
712 return 0;
713 }
714 dvb_logerr(_("command %s (%d) not found during store"),
715 dvb_cmd_name(cmd), cmd);
716
717 return -EINVAL;
718 }
719
dvb_copy_fe_props(const struct dtv_property * from,int n,struct dtv_property * to)720 static int dvb_copy_fe_props(const struct dtv_property *from, int n, struct dtv_property *to)
721 {
722 int i, j;
723 for (i = 0, j = 0; i < n; i++)
724 if (from[i].cmd < DTV_USER_COMMAND_START)
725 to[j++] = from[i];
726 return j;
727 }
728
__dvb_fe_get_parms(struct dvb_v5_fe_parms * p)729 int __dvb_fe_get_parms(struct dvb_v5_fe_parms *p)
730 {
731 struct dvb_v5_fe_parms_priv *parms = (void *)p;
732 int i, n = 0;
733 const unsigned int *sys_props;
734 struct dtv_properties prop;
735 struct dvb_frontend_parameters v3_parms = { 0 };
736 uint32_t bw;
737
738 sys_props = dvb_v5_delivery_system[parms->p.current_sys];
739 if (!sys_props)
740 return -EINVAL;
741
742 while (sys_props[n]) {
743 parms->dvb_prop[n].cmd = sys_props[n];
744 n++;
745 }
746 parms->dvb_prop[n].cmd = DTV_DELIVERY_SYSTEM;
747 parms->dvb_prop[n].u.data = parms->p.current_sys;
748 n++;
749
750 /* Keep it ready for set */
751 parms->dvb_prop[n].cmd = DTV_TUNE;
752 parms->n_props = n;
753
754 struct dtv_property fe_prop[DTV_MAX_COMMAND];
755 n = dvb_copy_fe_props(parms->dvb_prop, n, fe_prop);
756
757 prop.props = fe_prop;
758 prop.num = n;
759 if (!parms->p.legacy_fe) {
760 if (xioctl(parms->fd, FE_GET_PROPERTY, &prop) == -1) {
761 dvb_perror("FE_GET_PROPERTY");
762 return -errno;
763 }
764
765 /* copy back params from temporary fe_prop */
766 for (i = 0; i < n; i++) {
767 if (fe_prop[i].cmd == DTV_FREQUENCY) {
768 fe_prop[i].u.data = dvb_sat_real_freq(p, fe_prop[i].u.data);
769 if (!fe_prop[i].u.data)
770 return -EINVAL;
771 }
772 dvb_fe_store_parm(&parms->p, fe_prop[i].cmd, fe_prop[i].u.data);
773 }
774
775 if (parms->p.verbose) {
776 dvb_log(_("Got parameters for %s:"),
777 delivery_system_name[parms->p.current_sys]);
778 dvb_fe_prt_parms(&parms->p);
779 }
780 return 0;
781 }
782 /* DVBv3 call */
783 if (xioctl(parms->fd, FE_GET_FRONTEND, &v3_parms) == -1) {
784 dvb_perror("FE_GET_FRONTEND");
785 return -EINVAL;
786 }
787
788 dvb_fe_store_parm(&parms->p, DTV_FREQUENCY, v3_parms.frequency);
789 dvb_fe_store_parm(&parms->p, DTV_INVERSION, v3_parms.inversion);
790 switch (parms->p.current_sys) {
791 case SYS_DVBS:
792 dvb_fe_store_parm(&parms->p, DTV_SYMBOL_RATE, v3_parms.u.qpsk.symbol_rate);
793 dvb_fe_store_parm(&parms->p, DTV_INNER_FEC, v3_parms.u.qpsk.fec_inner);
794 break;
795 case SYS_DVBC_ANNEX_A:
796 dvb_fe_store_parm(&parms->p, DTV_SYMBOL_RATE, v3_parms.u.qam.symbol_rate);
797 dvb_fe_store_parm(&parms->p, DTV_INNER_FEC, v3_parms.u.qam.fec_inner);
798 dvb_fe_store_parm(&parms->p, DTV_MODULATION, v3_parms.u.qam.modulation);
799 break;
800 case SYS_ATSC:
801 case SYS_ATSCMH:
802 case SYS_DVBC_ANNEX_B:
803 dvb_fe_store_parm(&parms->p, DTV_MODULATION, v3_parms.u.vsb.modulation);
804 break;
805 case SYS_DVBT:
806 if (v3_parms.u.ofdm.bandwidth < ARRAY_SIZE(fe_bandwidth_name) -1)
807 bw = fe_bandwidth_name[v3_parms.u.ofdm.bandwidth];
808 else bw = 0;
809 dvb_fe_store_parm(&parms->p, DTV_BANDWIDTH_HZ, bw);
810 dvb_fe_store_parm(&parms->p, DTV_CODE_RATE_HP, v3_parms.u.ofdm.code_rate_HP);
811 dvb_fe_store_parm(&parms->p, DTV_CODE_RATE_LP, v3_parms.u.ofdm.code_rate_LP);
812 dvb_fe_store_parm(&parms->p, DTV_MODULATION, v3_parms.u.ofdm.constellation);
813 dvb_fe_store_parm(&parms->p, DTV_TRANSMISSION_MODE, v3_parms.u.ofdm.transmission_mode);
814 dvb_fe_store_parm(&parms->p, DTV_GUARD_INTERVAL, v3_parms.u.ofdm.guard_interval);
815 dvb_fe_store_parm(&parms->p, DTV_HIERARCHY, v3_parms.u.ofdm.hierarchy_information);
816 break;
817 default:
818 return -EINVAL;
819 }
820
821 return 0;
822 }
823
824 /* set the delsys default/fixed parameters and replace DVBv5 default values */
dvb_setup_delsys_default(struct dvb_v5_fe_parms * p)825 static void dvb_setup_delsys_default(struct dvb_v5_fe_parms *p)
826 {
827 struct dvb_v5_fe_parms_priv *parms = (void *)p;
828 uint32_t cc;
829
830 switch (p->current_sys) {
831 case SYS_ISDBT:
832 /* Set country code. */
833 /* if the default country is not known, fallback to BR */
834 cc = COUNTRY_UNKNOWN;
835 dvb_fe_retrieve_parm(p, DTV_COUNTRY_CODE, &cc);
836 if (cc == COUNTRY_UNKNOWN) {
837 cc = (parms->country == COUNTRY_UNKNOWN)
838 ? BR : parms->country;
839 dvb_fe_store_parm(p, DTV_COUNTRY_CODE, cc);
840 }
841 switch (cc) {
842 case JP:
843 p->default_charset = "arib-std-b24";
844 dvb_fe_store_parm(p, DTV_BANDWIDTH_HZ, 6000000);
845 break;
846 /* Americas (SBTVD) */
847 case AR:
848 case BO:
849 case BR:
850 case CL:
851 case CR:
852 case EC:
853 case GT:
854 case HN:
855 case NI:
856 case PE:
857 case PY:
858 case UY:
859 case VE:
860 p->default_charset = "iso8859-15";
861 break;
862 }
863 break;
864 case SYS_ISDBS:
865 p->default_charset = "arib-std-b24";
866 if (!p->lnb)
867 p->lnb = dvb_sat_get_lnb(dvb_sat_search_lnb("110BS"));
868 break;
869 default:
870 break;
871 }
872 }
873
__dvb_fe_set_parms(struct dvb_v5_fe_parms * p)874 int __dvb_fe_set_parms(struct dvb_v5_fe_parms *p)
875 {
876 struct dvb_v5_fe_parms_priv *parms = (void *)p;
877 /* Use a temporary copy of the parameters so we can safely perform
878 * adjustments for satellite */
879 struct dvb_v5_fe_parms_priv tmp_parms = *parms;
880
881 struct dtv_properties prop;
882 struct dvb_frontend_parameters v3_parms;
883 uint32_t bw;
884
885 if (parms->p.lna != LNA_AUTO && !parms->p.legacy_fe) {
886 struct dvb_v5_fe_parms_priv tmp_lna_parms;
887
888 memset(&prop, 0, sizeof(prop));
889 prop.props = tmp_lna_parms.dvb_prop;
890
891 prop.props[0].cmd = DTV_LNA;
892 prop.props[0].u.data = parms->p.lna;
893 prop.num = 1;
894 if (xioctl(parms->fd, FE_SET_PROPERTY, &prop) == -1) {
895 dvb_perror(_("Setting LNA"));
896 parms->p.lna = LNA_AUTO;
897 } else if (parms->p.lna != LNA_AUTO && parms->p.verbose)
898 dvb_logdbg(_("LNA is %s"), parms->p.lna ? _("ON") : _("OFF"));
899 }
900
901 if (dvb_fe_is_satellite(tmp_parms.p.current_sys)) {
902 dvb_sat_set_parms(&tmp_parms.p);
903 /*
904 * even though the frequncy prop is kept un-modified here,
905 * a later call to dvb_fe_get_parms() issues FE_GET_PROPERTY
906 * ioctl and overwrites it with the offset-ed value from
907 * the FE. So we need to save the offset here and
908 * re-add it in dvb_fe_get_parms().
909 * note that dvbv5-{scan,zap} utilities call dvb_fe_get_parms()
910 * indirectly from check_frontend() via dvb_fe_get_stats().
911 */
912 parms->freq_offset = tmp_parms.freq_offset;
913 }
914
915 dvb_setup_delsys_default(p);
916
917 /* Filter out any user DTV_foo property such as DTV_POLARIZATION */
918 tmp_parms.n_props = dvb_copy_fe_props(tmp_parms.dvb_prop,
919 tmp_parms.n_props,
920 tmp_parms.dvb_prop);
921
922 memset(&prop, 0, sizeof(prop));
923 prop.props = tmp_parms.dvb_prop;
924 prop.num = tmp_parms.n_props;
925 prop.props[prop.num].cmd = DTV_TUNE;
926 prop.num++;
927
928 if (!parms->p.legacy_fe) {
929 if (xioctl(parms->fd, FE_SET_PROPERTY, &prop) == -1) {
930 dvb_perror("FE_SET_PROPERTY");
931 if (parms->p.verbose)
932 dvb_fe_prt_parms(&parms->p);
933 return -errno;
934 }
935 return 0;
936 }
937 /* DVBv3 call */
938 dvb_fe_retrieve_parm(&tmp_parms.p, DTV_FREQUENCY, &v3_parms.frequency);
939 dvb_fe_retrieve_parm(&tmp_parms.p, DTV_INVERSION, &v3_parms.inversion);
940 switch (tmp_parms.p.current_sys) {
941 case SYS_DVBS:
942 dvb_fe_retrieve_parm(&tmp_parms.p, DTV_SYMBOL_RATE, &v3_parms.u.qpsk.symbol_rate);
943 dvb_fe_retrieve_parm(&tmp_parms.p, DTV_INNER_FEC, &v3_parms.u.qpsk.fec_inner);
944 break;
945 case SYS_DVBC_ANNEX_AC:
946 dvb_fe_retrieve_parm(&tmp_parms.p, DTV_SYMBOL_RATE, &v3_parms.u.qam.symbol_rate);
947 dvb_fe_retrieve_parm(&tmp_parms.p, DTV_INNER_FEC, &v3_parms.u.qam.fec_inner);
948 dvb_fe_retrieve_parm(&tmp_parms.p, DTV_MODULATION, &v3_parms.u.qam.modulation);
949 break;
950 case SYS_ATSC:
951 case SYS_ATSCMH:
952 case SYS_DVBC_ANNEX_B:
953 dvb_fe_retrieve_parm(&tmp_parms.p, DTV_MODULATION, &v3_parms.u.vsb.modulation);
954 break;
955 case SYS_DVBT:
956 for (bw = 0; fe_bandwidth_name[bw] != 0; bw++) {
957 if (fe_bandwidth_name[bw] == v3_parms.u.ofdm.bandwidth)
958 break;
959 }
960 dvb_fe_retrieve_parm(&tmp_parms.p, DTV_BANDWIDTH_HZ, &bw);
961 dvb_fe_retrieve_parm(&tmp_parms.p, DTV_CODE_RATE_HP, &v3_parms.u.ofdm.code_rate_HP);
962 dvb_fe_retrieve_parm(&tmp_parms.p, DTV_CODE_RATE_LP, &v3_parms.u.ofdm.code_rate_LP);
963 dvb_fe_retrieve_parm(&tmp_parms.p, DTV_MODULATION, &v3_parms.u.ofdm.constellation);
964 dvb_fe_retrieve_parm(&tmp_parms.p, DTV_TRANSMISSION_MODE, &v3_parms.u.ofdm.transmission_mode);
965 dvb_fe_retrieve_parm(&tmp_parms.p, DTV_GUARD_INTERVAL, &v3_parms.u.ofdm.guard_interval);
966 dvb_fe_retrieve_parm(&tmp_parms.p, DTV_HIERARCHY, &v3_parms.u.ofdm.hierarchy_information);
967 break;
968 default:
969 return -EINVAL;
970 }
971 if (xioctl(tmp_parms.fd, FE_SET_FRONTEND, &v3_parms) == -1) {
972 dvb_perror("FE_SET_FRONTEND");
973 if (tmp_parms.p.verbose)
974 dvb_fe_prt_parms(&tmp_parms.p);
975 return -errno;
976 }
977
978 return 0;
979 }
980
dvb_fe_store_stats(struct dvb_v5_fe_parms_priv * parms,unsigned cmd,enum fecap_scale_params scale,unsigned layer,uint32_t value)981 static struct dtv_stats *dvb_fe_store_stats(struct dvb_v5_fe_parms_priv *parms,
982 unsigned cmd,
983 enum fecap_scale_params scale,
984 unsigned layer,
985 uint32_t value)
986 {
987 int i;
988
989 for (i = 0; i < DTV_NUM_STATS_PROPS; i++) {
990 if (parms->stats.prop[i].cmd != cmd)
991 continue;
992 parms->stats.prop[i].u.st.stat[layer].scale = scale;
993 parms->stats.prop[i].u.st.stat[layer].uvalue = value;
994 if (parms->stats.prop[i].u.st.len < layer + 1)
995 parms->stats.prop[i].u.st.len = layer + 1;
996 return &parms->stats.prop[i].u.st.stat[layer];
997 }
998 dvb_logerr(_("%s not found on store"), dvb_cmd_name(cmd));
999
1000 return NULL;
1001 }
1002
calculate_postBER(struct dvb_v5_fe_parms_priv * parms,unsigned layer)1003 static float calculate_postBER(struct dvb_v5_fe_parms_priv *parms, unsigned layer)
1004 {
1005 uint64_t n, d;
1006
1007 if (!parms->stats.has_post_ber[layer])
1008 return -EINVAL;
1009
1010 d = parms->stats.cur[layer].post_bit_count - parms->stats.prev[layer].post_bit_count;
1011 if (!d)
1012 return -EINVAL;
1013
1014 n = parms->stats.cur[layer].post_bit_error - parms->stats.prev[layer].post_bit_error;
1015
1016 return ((float)n)/d;
1017 }
1018
calculate_preBER(struct dvb_v5_fe_parms_priv * parms,unsigned layer)1019 static float calculate_preBER(struct dvb_v5_fe_parms_priv *parms, unsigned layer)
1020 {
1021 uint64_t n, d;
1022
1023 if (!parms->stats.has_pre_ber[layer])
1024 return -EINVAL;
1025
1026 d = parms->stats.cur[layer].pre_bit_count - parms->stats.prev[layer].pre_bit_count;
1027 if (!d)
1028 return -EINVAL;
1029
1030 n = parms->stats.cur[layer].pre_bit_error - parms->stats.prev[layer].pre_bit_error;
1031
1032 return ((float)n)/d;
1033 }
1034
dvb_fe_retrieve_v5_BER(struct dvb_v5_fe_parms_priv * parms,unsigned layer)1035 static struct dtv_stats *dvb_fe_retrieve_v5_BER(struct dvb_v5_fe_parms_priv *parms,
1036 unsigned layer)
1037 {
1038 float ber;
1039 uint64_t ber64;
1040
1041 ber = calculate_postBER(parms, layer);
1042 if (ber < 0)
1043 return NULL;
1044
1045 /*
1046 * Put BER into some DVBv3 compat scale. The thing is that DVBv3 has no
1047 * defined scale for BER. So, let's use 10^-7.
1048 */
1049
1050 ber64 = 10000000 * ber;
1051 return dvb_fe_store_stats(parms, DTV_BER, FE_SCALE_COUNTER, layer, ber64);
1052 }
1053
dvb_fe_retrieve_stats_layer(struct dvb_v5_fe_parms * p,unsigned cmd,unsigned layer)1054 struct dtv_stats *dvb_fe_retrieve_stats_layer(struct dvb_v5_fe_parms *p,
1055 unsigned cmd, unsigned layer)
1056 {
1057 struct dvb_v5_fe_parms_priv *parms = (void *)p;
1058 int i;
1059
1060 if (cmd == DTV_BER && parms->p.has_v5_stats)
1061 return dvb_fe_retrieve_v5_BER(parms, layer);
1062
1063 for (i = 0; i < DTV_NUM_STATS_PROPS; i++) {
1064 if (parms->stats.prop[i].cmd != cmd)
1065 continue;
1066 if (layer >= parms->stats.prop[i].u.st.len)
1067 return NULL;
1068 return &parms->stats.prop[i].u.st.stat[layer];
1069 }
1070 dvb_logerr(_("%s not found on retrieve"), dvb_cmd_name(cmd));
1071
1072 return NULL;
1073 }
1074
dvb_fe_retrieve_stats(struct dvb_v5_fe_parms * p,unsigned cmd,uint32_t * value)1075 int dvb_fe_retrieve_stats(struct dvb_v5_fe_parms *p,
1076 unsigned cmd, uint32_t *value)
1077 {
1078 struct dvb_v5_fe_parms_priv *parms = (void *)p;
1079 struct dtv_stats *stat;
1080 enum fecap_scale_params scale;
1081
1082 stat = dvb_fe_retrieve_stats_layer(&parms->p, cmd, 0);
1083 if (!stat) {
1084 if (parms->p.verbose)
1085 dvb_logdbg(_("%s not found on retrieve"), dvb_cmd_name(cmd));
1086 return -EINVAL;
1087 }
1088
1089 scale = stat->scale;
1090 if (scale == FE_SCALE_NOT_AVAILABLE) {
1091 if (parms->p.verbose)
1092 dvb_logdbg(_("%s not available"), dvb_cmd_name(cmd));
1093 return -EINVAL;
1094 }
1095
1096 *value = stat->uvalue;
1097
1098 if (parms->p.verbose > 1)
1099 dvb_logdbg(_("Stats for %s = %d"), dvb_cmd_name(cmd), *value);
1100
1101 return 0;
1102 }
1103
dvb_fe_retrieve_ber(struct dvb_v5_fe_parms * p,unsigned layer,enum fecap_scale_params * scale)1104 float dvb_fe_retrieve_ber(struct dvb_v5_fe_parms *p, unsigned layer,
1105 enum fecap_scale_params *scale)
1106 {
1107 struct dvb_v5_fe_parms_priv *parms = (void *)p;
1108 float ber;
1109 uint32_t ber32;
1110
1111 if (parms->p.has_v5_stats) {
1112 ber = calculate_postBER(parms, layer);
1113 if (ber >= 0)
1114 *scale = FE_SCALE_COUNTER;
1115 else
1116 *scale = FE_SCALE_NOT_AVAILABLE;
1117 return ber;
1118 }
1119
1120 if (layer) {
1121 *scale = FE_SCALE_NOT_AVAILABLE;
1122 return -EINVAL;
1123 }
1124
1125 if (dvb_fe_retrieve_stats(&parms->p, DTV_BER, &ber32))
1126 *scale = FE_SCALE_NOT_AVAILABLE;
1127 else
1128 *scale = FE_SCALE_RELATIVE;
1129
1130 return ber32;
1131 }
1132
dvb_fe_retrieve_per(struct dvb_v5_fe_parms * p,unsigned layer)1133 float dvb_fe_retrieve_per(struct dvb_v5_fe_parms *p, unsigned layer)
1134 {
1135 struct dvb_v5_fe_parms_priv *parms = (void *)p;
1136 uint64_t n, d;
1137
1138 if (!parms->stats.has_per[layer]) {
1139 return -EINVAL;
1140 }
1141
1142 d = parms->stats.cur[layer].block_count - parms->stats.prev[layer].block_count;
1143 if (!d) {
1144 return -EINVAL;
1145 }
1146
1147 n = parms->stats.cur[layer].block_error - parms->stats.prev[layer].block_error;
1148
1149 return ((float)n)/d;
1150 }
1151
1152 struct cnr_to_qual_s {
1153 uint32_t modulation; /* use QAM_AUTO if it doesn't matter */
1154 uint32_t fec; /* Use FEC_NONE if it doesn't matter */
1155 float cnr_ok, cnr_good;
1156 };
1157
cnr_arr_to_qual(uint32_t modulation,uint32_t fec,float cnr,struct cnr_to_qual_s * arr,unsigned len)1158 static enum dvb_quality cnr_arr_to_qual(uint32_t modulation,
1159 uint32_t fec,
1160 float cnr,
1161 struct cnr_to_qual_s *arr,
1162 unsigned len)
1163 {
1164 int i;
1165
1166 for (i = 0; i < len; i++) {
1167 if (modulation == arr[i].modulation) {
1168 if (cnr < arr[i].cnr_ok)
1169 return DVB_QUAL_POOR;
1170
1171 if (cnr < arr[i].cnr_good)
1172 return DVB_QUAL_OK;
1173
1174 return DVB_QUAL_GOOD;
1175
1176 }
1177 }
1178
1179 return DVB_QUAL_UNKNOWN;
1180 }
1181
1182 /* Source: http://www.maxpeak.tv/articles/Maxpeak_Article_2.pdf */
1183 struct cnr_to_qual_s dvb_c_cnr_2_qual[] = {
1184 { QAM_256, FEC_NONE, 34., 38.},
1185 { QAM_64, FEC_NONE, 30., 34.},
1186 };
1187
1188 /*
1189 * Base reference: http://www.maxpeak.tv/articles/Maxpeak_Article_2.pdf
1190 * Used http://www.nws.noaa.gov/noaaport/html/DVB%20S2%20Satellite%20Receiver%20Specs.pdf
1191 * to estimate the missing FEC's
1192 */
1193 struct cnr_to_qual_s dvb_s_cnr_2_qual[] = {
1194 { QPSK, FEC_1_2, 7., 10.},
1195
1196 { QPSK, FEC_2_3, 9., 12.},
1197 { QPSK, FEC_3_4, 10., 13.},
1198 { QPSK, FEC_5_6, 11., 14.},
1199
1200 { QPSK, FEC_7_8, 12., 15.},
1201 };
1202
1203 struct cnr_to_qual_s dvb_s2_cnr_2_qual[] = {
1204 { QPSK, FEC_1_2, 9., 12.},
1205 { QPSK, FEC_2_3, 11., 14.},
1206 { QPSK, FEC_3_4, 12., 15.},
1207 { QPSK, FEC_5_6, 12., 15.},
1208 { QPSK, FEC_8_9, 13., 16.},
1209 { QPSK, FEC_9_10, 13.5, 16.5},
1210 { PSK_8, FEC_2_3, 14.5, 17.5},
1211 { PSK_8, FEC_3_4, 16., 19.},
1212 { PSK_8, FEC_5_6, 17.5, 20.5},
1213 { PSK_8, FEC_8_9, 19., 22.},
1214 };
1215
1216 /*
1217 * Minimum values from ARIB STD-B21 for DVB_QUAL_OK.
1218 * As ARIB doesn't define a max value, assume +2dB for DVB_QUAL_GOOD
1219 */
1220 static struct cnr_to_qual_s isdb_t_cnr_2_qual[] = {
1221 { DQPSK, FEC_1_2, 6.2, 8.2},
1222 { DQPSK, FEC_2_3, 7.7, 9.7},
1223 { DQPSK, FEC_3_4, 8.7, 10.7},
1224 { DQPSK, FEC_5_6, 9.6, 11.6},
1225 { DQPSK, FEC_7_8, 10.4, 12.4},
1226
1227 { QPSK, FEC_1_2, 4.9, 6.9},
1228 { QPSK, FEC_2_3, 6.6, 8.6},
1229 { QPSK, FEC_3_4, 7.5, 9.5},
1230 { QPSK, FEC_5_6, 8.5, 10.5},
1231 { QPSK, FEC_7_8, 9.1, 11.5},
1232
1233 { QAM_16, FEC_1_2, 11.5, 13.5},
1234 { QAM_16, FEC_2_3, 13.5, 15.5},
1235 { QAM_16, FEC_3_4, 14.6, 16.6},
1236 { QAM_16, FEC_5_6, 15.6, 17.6},
1237 { QAM_16, FEC_7_8, 16.2, 18.2},
1238
1239 { QAM_64, FEC_1_2, 16.5, 18.5},
1240 { QAM_64, FEC_2_3, 18.7, 21.7},
1241 { QAM_64, FEC_3_4, 20.1, 22.1},
1242 { QAM_64, FEC_5_6, 21.3, 23.3},
1243 { QAM_64, FEC_7_8, 22.0, 24.0},
1244 };
1245
1246 /*
1247 * Values obtained from table A.1 of ETSI EN 300 744 v1.6.1
1248 * OK corresponds to Ricean fading; Good to Rayleigh fading
1249 */
1250 static struct cnr_to_qual_s dvb_t_cnr_2_qual[] = {
1251 { QPSK, FEC_1_2, 4.1, 5.9},
1252 { QPSK, FEC_2_3, 6.1, 9.6},
1253 { QPSK, FEC_3_4, 7.2, 12.4},
1254 { QPSK, FEC_5_6, 8.5, 15.6},
1255 { QPSK, FEC_7_8, 9.2, 17.5},
1256
1257 { QAM_16, FEC_1_2, 9.8, 11.8},
1258 { QAM_16, FEC_2_3, 12.1, 15.3},
1259 { QAM_16, FEC_3_4, 13.4, 18.1},
1260 { QAM_16, FEC_5_6, 14.8, 21.3},
1261 { QAM_16, FEC_7_8, 15.7, 23.6},
1262
1263 { QAM_64, FEC_1_2, 14.0, 16.0},
1264 { QAM_64, FEC_2_3, 19.9, 25.4},
1265 { QAM_64, FEC_3_4, 24.9, 27.9},
1266 { QAM_64, FEC_5_6, 21.3, 23.3},
1267 { QAM_64, FEC_7_8, 22.0, 24.0},
1268 };
1269
dvbv_fe_cnr_to_quality(struct dvb_v5_fe_parms_priv * parms,struct dtv_stats * cnr)1270 static enum dvb_quality dvbv_fe_cnr_to_quality(struct dvb_v5_fe_parms_priv *parms,
1271 struct dtv_stats *cnr)
1272 {
1273 uint32_t modulation, fec;
1274 enum dvb_quality qual = DVB_QUAL_UNKNOWN;
1275
1276 switch (cnr->scale) {
1277 case FE_SCALE_RELATIVE:
1278 if (cnr->uvalue == 65535)
1279 return DVB_QUAL_GOOD;
1280 else if (cnr->uvalue >= 65535 / 2)
1281 return DVB_QUAL_OK;
1282 else
1283 return DVB_QUAL_POOR;
1284 return qual;
1285 case FE_SCALE_DECIBEL:
1286 break;
1287 default:
1288 return DVB_QUAL_UNKNOWN;
1289 }
1290
1291 switch (parms->p.current_sys) {
1292 case SYS_DVBC_ANNEX_A:
1293 case SYS_DVBC_ANNEX_C:
1294 dvb_fe_retrieve_parm(&parms->p, DTV_MODULATION, &modulation);
1295 if (modulation == QAM_AUTO)
1296 modulation = QAM_64; /* Assume worse case */
1297 qual = cnr_arr_to_qual(modulation, FEC_NONE, cnr->svalue,
1298 dvb_c_cnr_2_qual,
1299 ARRAY_SIZE(dvb_c_cnr_2_qual));
1300 break;
1301 case SYS_DVBS:
1302 dvb_fe_retrieve_parm(&parms->p, DTV_INNER_FEC, &fec);
1303 qual = cnr_arr_to_qual(QPSK, fec, cnr->svalue,
1304 dvb_s_cnr_2_qual,
1305 ARRAY_SIZE(dvb_s_cnr_2_qual));
1306 break;
1307 case SYS_DVBS2:
1308 dvb_fe_retrieve_parm(&parms->p, DTV_MODULATION, &modulation);
1309 dvb_fe_retrieve_parm(&parms->p, DTV_INNER_FEC, &fec);
1310 qual = cnr_arr_to_qual(modulation, fec, cnr->svalue,
1311 dvb_s2_cnr_2_qual,
1312 ARRAY_SIZE(dvb_s2_cnr_2_qual));
1313 break;
1314 case SYS_ISDBT:
1315 dvb_fe_retrieve_parm(&parms->p, DTV_ISDBT_LAYERA_MODULATION, &modulation);
1316 dvb_fe_retrieve_parm(&parms->p, DTV_ISDBT_LAYERA_FEC, &fec);
1317 if (modulation == QAM_AUTO)
1318 modulation = QAM_64; /* Assume worse case */
1319 qual = cnr_arr_to_qual(modulation, fec, cnr->svalue,
1320 isdb_t_cnr_2_qual,
1321 ARRAY_SIZE(isdb_t_cnr_2_qual));
1322 break;
1323 case SYS_DVBT:
1324 dvb_fe_retrieve_parm(&parms->p, DTV_MODULATION, &modulation);
1325 dvb_fe_retrieve_parm(&parms->p, DTV_CODE_RATE_LP, &fec);
1326 qual = cnr_arr_to_qual(modulation, fec, cnr->svalue,
1327 dvb_t_cnr_2_qual,
1328 ARRAY_SIZE(dvb_t_cnr_2_qual));
1329 break;
1330 case SYS_DVBT2:
1331 case SYS_TURBO:
1332 case SYS_ISDBS:
1333 case SYS_DSS:
1334 case SYS_DTMB:
1335 case SYS_ATSC:
1336 case SYS_ATSCMH:
1337 case SYS_DVBC_ANNEX_B:
1338 default:
1339 /* Quality unknown */
1340 break;
1341 }
1342
1343 return qual;
1344 };
1345
dvb_fe_retrieve_quality(struct dvb_v5_fe_parms * p,unsigned layer)1346 enum dvb_quality dvb_fe_retrieve_quality(struct dvb_v5_fe_parms *p,
1347 unsigned layer)
1348 {
1349 struct dvb_v5_fe_parms_priv *parms = (void *)p;
1350 float ber, per;
1351 struct dtv_stats *cnr;
1352 enum dvb_quality qual = DVB_QUAL_UNKNOWN;
1353
1354 per = dvb_fe_retrieve_per(&parms->p, layer);
1355 if (per >= 0) {
1356 if (per > 1e-6)
1357 qual = DVB_QUAL_POOR;
1358 else if (per > 1e-7)
1359 return DVB_QUAL_OK;
1360 else
1361 return DVB_QUAL_GOOD;
1362 }
1363
1364 ber = dvb_fe_retrieve_per(&parms->p, layer);
1365 if (ber >= 0) {
1366
1367 if (ber > 1e-3) /* FIXME: good enough???? */
1368 return DVB_QUAL_POOR;
1369
1370 if (ber <= 2e-4) /* BER = 10^-11 at TS */
1371 return DVB_QUAL_GOOD;
1372
1373 qual = DVB_QUAL_OK; /* OK or good */
1374 }
1375
1376 cnr = dvb_fe_retrieve_stats_layer(&parms->p, DTV_STAT_CNR, layer);
1377 if (cnr)
1378 dvbv_fe_cnr_to_quality(parms, cnr);
1379
1380 return qual;
1381 }
1382
dvb_fe_update_counters(struct dvb_v5_fe_parms_priv * parms)1383 static void dvb_fe_update_counters(struct dvb_v5_fe_parms_priv *parms)
1384 {
1385 struct dtv_stats *error, *count;
1386 int i;
1387
1388 for (i = 0; i < MAX_DTV_STATS; i++) {
1389 count = dvb_fe_retrieve_stats_layer(&parms->p, DTV_STAT_POST_TOTAL_BIT_COUNT, i);
1390 if (count && count->scale != FE_SCALE_NOT_AVAILABLE) {
1391 error = dvb_fe_retrieve_stats_layer(&parms->p, DTV_STAT_POST_ERROR_BIT_COUNT, i);
1392 if (!error || error->scale == FE_SCALE_NOT_AVAILABLE) {
1393 parms->stats.has_post_ber[i] = 0;
1394 } else if(count->uvalue != parms->stats.cur[i].post_bit_count) {
1395 parms->stats.prev[i].post_bit_count = parms->stats.cur[i].post_bit_count;
1396 parms->stats.cur[i].post_bit_count = count->uvalue;
1397
1398 parms->stats.prev[i].post_bit_error = parms->stats.cur[i].post_bit_error;
1399 parms->stats.cur[i].post_bit_error = error->uvalue;
1400
1401 parms->stats.has_post_ber[i] = 1;
1402 }
1403 } else
1404 parms->stats.has_post_ber[i] = 0;
1405 count = dvb_fe_retrieve_stats_layer(&parms->p, DTV_STAT_PRE_TOTAL_BIT_COUNT, i);
1406 if (count && count->scale != FE_SCALE_NOT_AVAILABLE) {
1407 error = dvb_fe_retrieve_stats_layer(&parms->p, DTV_STAT_PRE_ERROR_BIT_COUNT, i);
1408 if (!error || error->scale == FE_SCALE_NOT_AVAILABLE) {
1409 parms->stats.has_pre_ber[i] = 0;
1410 } else if(count->uvalue != parms->stats.cur[i].pre_bit_count) {
1411 parms->stats.prev[i].pre_bit_count = parms->stats.cur[i].pre_bit_count;
1412 parms->stats.cur[i].pre_bit_count = count->uvalue;
1413
1414 parms->stats.prev[i].pre_bit_error = parms->stats.cur[i].pre_bit_error;
1415 parms->stats.cur[i].pre_bit_error = error->uvalue;
1416
1417 parms->stats.has_pre_ber[i] = 1;
1418 }
1419 } else
1420 parms->stats.has_pre_ber[i] = 0;
1421 count = dvb_fe_retrieve_stats_layer(&parms->p, DTV_STAT_TOTAL_BLOCK_COUNT, i);
1422 if (count && count->scale != FE_SCALE_NOT_AVAILABLE) {
1423 error = dvb_fe_retrieve_stats_layer(&parms->p, DTV_STAT_ERROR_BLOCK_COUNT, i);
1424 if (!error || error->scale == FE_SCALE_NOT_AVAILABLE) {
1425 parms->stats.has_per[i] = 0;
1426 } else if (count->uvalue != parms->stats.cur[i].block_count) {
1427 parms->stats.prev[i].block_count = parms->stats.cur[i].block_count;
1428 parms->stats.cur[i].block_count = count->uvalue;
1429
1430 parms->stats.prev[i].block_error = parms->stats.cur[i].block_error;
1431 parms->stats.cur[i].block_error = error->uvalue;
1432
1433 parms->stats.has_per[i] = 1;
1434 }
1435 } else
1436 parms->stats.has_per[i] = 0;
1437 }
1438 }
1439
__dvb_fe_get_stats(struct dvb_v5_fe_parms * p)1440 int __dvb_fe_get_stats(struct dvb_v5_fe_parms *p)
1441 {
1442 struct dvb_v5_fe_parms_priv *parms = (void *)p;
1443 fe_status_t status = 0;
1444 uint32_t ber= 0, ucb = 0;
1445 uint16_t strength = 0, snr = 0;
1446 int i;
1447 enum fecap_scale_params scale;
1448
1449 if (xioctl(parms->fd, FE_READ_STATUS, &status) == -1) {
1450 dvb_perror("FE_READ_STATUS");
1451 return -EINVAL;
1452 }
1453 dvb_fe_store_stats(parms, DTV_STATUS, FE_SCALE_RELATIVE, 0, status);
1454
1455 /* if lock has obtained, get DVB parameters */
1456 if (status != parms->stats.prev_status) {
1457 if ((status & FE_HAS_LOCK) &&
1458 parms->stats.prev_status != status)
1459 dvb_fe_get_parms(&parms->p);
1460 parms->stats.prev_status = status;
1461 }
1462
1463 if (parms->p.has_v5_stats) {
1464 struct dtv_properties props;
1465
1466 props.num = DTV_NUM_KERNEL_STATS;
1467 props.props = parms->stats.prop;
1468
1469 /* Do a DVBv5.10 stats call */
1470 if (ioctl(parms->fd, FE_GET_PROPERTY, &props) == -1) {
1471 if (errno == EAGAIN)
1472 return 0;
1473 goto dvbv3_fallback;
1474 }
1475
1476 /*
1477 * All props with len=0 mean that this device doesn't have any
1478 * dvbv5 stats. Try the legacy stats instead.
1479 */
1480 for (i = 0; i < props.num; i++)
1481 if (parms->stats.prop[i].u.st.len)
1482 break;
1483 if (i == props.num)
1484 goto dvbv3_fallback;
1485
1486 dvb_fe_update_counters(parms);
1487
1488 return 0;
1489 }
1490
1491 dvbv3_fallback:
1492 /* DVB v3 stats */
1493 parms->p.has_v5_stats = 0;
1494
1495 if (ioctl(parms->fd, FE_READ_BER, &ber) == -1)
1496 scale = FE_SCALE_NOT_AVAILABLE;
1497 else
1498 scale = FE_SCALE_RELATIVE;
1499
1500 /*
1501 * BER scale on DVBv3 is not defined - different drivers use
1502 * different scales, even weird ones, like multiples of 1/65280
1503 */
1504 dvb_fe_store_stats(parms, DTV_BER, scale, 0, ber);
1505
1506 if (ioctl(parms->fd, FE_READ_SIGNAL_STRENGTH, &strength) == -1)
1507 scale = FE_SCALE_NOT_AVAILABLE;
1508 else
1509 scale = FE_SCALE_RELATIVE;
1510
1511 dvb_fe_store_stats(parms, DTV_STAT_SIGNAL_STRENGTH, scale, 0, strength);
1512
1513 if (ioctl(parms->fd, FE_READ_SNR, &snr) == -1)
1514 scale = FE_SCALE_NOT_AVAILABLE;
1515 else
1516 scale = FE_SCALE_RELATIVE;
1517 dvb_fe_store_stats(parms, DTV_STAT_CNR, scale, 0, snr);
1518
1519 if (ioctl(parms->fd, FE_READ_UNCORRECTED_BLOCKS, &ucb) == -1)
1520 scale = FE_SCALE_NOT_AVAILABLE;
1521 else
1522 scale = FE_SCALE_COUNTER;
1523 dvb_fe_store_stats(parms, DTV_STAT_ERROR_BLOCK_COUNT, scale, 0, snr);
1524
1525 if (parms->p.verbose > 1) {
1526 dvb_log(_("Status: "));
1527 for (i = 0; i < ARRAY_SIZE(fe_status_name); i++) {
1528 if (status & fe_status_name[i].idx)
1529 dvb_log (" %s", fe_status_name[i].name);
1530 }
1531 dvb_log(_("BER: %d, Strength: %d, SNR: %d, UCB: %d"),
1532 ber, strength, snr, ucb);
1533 }
1534 return 0;
1535 }
1536
1537
dvb_fe_get_event(struct dvb_v5_fe_parms * p)1538 int dvb_fe_get_event(struct dvb_v5_fe_parms *p)
1539 {
1540 struct dvb_v5_fe_parms_priv *parms = (void *)p;
1541 struct dvb_frontend_event event;
1542 fe_status_t status;
1543 int i;
1544
1545 if (!parms->p.legacy_fe) {
1546 dvb_fe_get_parms(&parms->p);
1547 return dvb_fe_get_stats(&parms->p);
1548 }
1549
1550 if (xioctl(parms->fd, FE_GET_EVENT, &event) == -1) {
1551 dvb_perror("FE_GET_EVENT");
1552 return -errno;
1553 }
1554 status = event.status;
1555 if (parms->p.verbose > 1) {
1556 dvb_log(_("Status: "));
1557 for (i = 0; i < ARRAY_SIZE(fe_status_name); i++) {
1558 if (status & fe_status_name[i].idx)
1559 dvb_log (" %s", fe_status_name[i].name);
1560 }
1561 }
1562 dvb_fe_store_stats(parms, DTV_STATUS, FE_SCALE_RELATIVE, 0, status);
1563
1564 dvb_fe_retrieve_parm(&parms->p, DTV_FREQUENCY, &event.parameters.frequency);
1565 dvb_fe_retrieve_parm(&parms->p, DTV_INVERSION, &event.parameters.inversion);
1566 switch (parms->p.current_sys) {
1567 case SYS_DVBS:
1568 dvb_fe_retrieve_parm(&parms->p, DTV_SYMBOL_RATE, &event.parameters.u.qpsk.symbol_rate);
1569 dvb_fe_retrieve_parm(&parms->p, DTV_INNER_FEC, &event.parameters.u.qpsk.fec_inner);
1570 break;
1571 case SYS_DVBC_ANNEX_AC:
1572 dvb_fe_retrieve_parm(&parms->p, DTV_SYMBOL_RATE, &event.parameters.u.qam.symbol_rate);
1573 dvb_fe_retrieve_parm(&parms->p, DTV_INNER_FEC, &event.parameters.u.qam.fec_inner);
1574 dvb_fe_retrieve_parm(&parms->p, DTV_MODULATION, &event.parameters.u.qam.modulation);
1575 break;
1576 case SYS_ATSC:
1577 case SYS_ATSCMH:
1578 case SYS_DVBC_ANNEX_B:
1579 dvb_fe_retrieve_parm(&parms->p, DTV_MODULATION, &event.parameters.u.vsb.modulation);
1580 break;
1581 case SYS_DVBT:
1582 dvb_fe_retrieve_parm(&parms->p, DTV_BANDWIDTH_HZ, &event.parameters.u.ofdm.bandwidth);
1583 dvb_fe_retrieve_parm(&parms->p, DTV_CODE_RATE_HP, &event.parameters.u.ofdm.code_rate_HP);
1584 dvb_fe_retrieve_parm(&parms->p, DTV_CODE_RATE_LP, &event.parameters.u.ofdm.code_rate_LP);
1585 dvb_fe_retrieve_parm(&parms->p, DTV_MODULATION, &event.parameters.u.ofdm.constellation);
1586 dvb_fe_retrieve_parm(&parms->p, DTV_TRANSMISSION_MODE, &event.parameters.u.ofdm.transmission_mode);
1587 dvb_fe_retrieve_parm(&parms->p, DTV_GUARD_INTERVAL, &event.parameters.u.ofdm.guard_interval);
1588 dvb_fe_retrieve_parm(&parms->p, DTV_HIERARCHY, &event.parameters.u.ofdm.hierarchy_information);
1589 break;
1590 default:
1591 return -EINVAL;
1592 }
1593
1594 return dvb_fe_get_stats(&parms->p);
1595 }
1596
1597 struct metric_prefixes {
1598 int multiply_factor;
1599 char *symbol;
1600 };
1601
1602 static struct metric_prefixes prefixes[] = {
1603 { 24, "Y" },
1604 { 21, "Z" },
1605 { 18, "E" },
1606 { 15, "P" },
1607 { 12, "T" },
1608 { 9, "G" },
1609 { 6, "M" },
1610 { 3, "k" },
1611 { -3, "m" },
1612 { -6, "μ" },
1613 { -9, "n" },
1614 { -12, "p" },
1615 { -15, "f" },
1616 { -18, "a" },
1617 { -21, "z" },
1618 { -24, "y" },
1619 };
1620
__dvb_fe_snprintf_eng(char * buf,int len,float val,int metric)1621 static int __dvb_fe_snprintf_eng(char *buf, int len, float val, int metric)
1622 {
1623 int digits = 3;
1624 int exp, signal = 1, i;
1625
1626 /* If value is zero, nothing to do */
1627 if (val == 0.)
1628 return snprintf(buf, len, " 0");
1629
1630 /* Take the absolute value */
1631 if (val < 0.) {
1632 signal = -1;
1633 val = -val;
1634 }
1635
1636 /*
1637 * Converts the number into an expoent and a
1638 * value between 0 and 1000, exclusive
1639 */
1640 exp = (int)log10f(val);
1641 if (exp > 0)
1642 exp = (exp / 3) * 3;
1643 else
1644 exp = (-exp + 3) / 3 * (-3);
1645
1646 val *= pow(10, -exp);
1647
1648 if (val >= 1000.) {
1649 val /= 1000.0;
1650 exp += 3;
1651 } else if(val >= 100.0)
1652 digits -= 2;
1653 else if(val >= 10.0)
1654 digits -= 1;
1655
1656 if (exp) {
1657 if (metric) {
1658 for (i = 0; i < ARRAY_SIZE(prefixes); i++) {
1659 if (exp == prefixes[i].multiply_factor)
1660 return snprintf(buf, len, " %.*f %s", digits - 1,
1661 val, prefixes[i].symbol);
1662 }
1663 /* Fall back to normal handling */
1664 }
1665 if (signal > 0)
1666 return snprintf(buf, len, " %.*fx10^%d", digits - 1,
1667 val, exp);
1668
1669 return snprintf(buf, len, " -%.*fx10^%d", digits - 1,
1670 val, exp);
1671 }
1672
1673 if (signal > 0)
1674 return snprintf(buf, len, " %.*f", digits - 1, val);
1675
1676 return snprintf(buf, len, " -%.*f", digits - 1, val);
1677 }
1678
dvb_fe_snprintf_eng(char * buf,int len,float val)1679 int dvb_fe_snprintf_eng(char *buf, int len, float val)
1680 {
1681 return __dvb_fe_snprintf_eng(buf, len, val, 0);
1682 }
1683
1684 static char *sig_bits[7] = {
1685 [0] = N_("RF"),
1686 [1] = N_("Carrier"),
1687 [2] = N_("Viterbi"),
1688 [3] = N_("Sync"),
1689 [4] = N_("Lock"),
1690 [5] = N_("Timeout"),
1691 [6] = N_("Reinit"),
1692 };
1693
1694 static char *qual_name[] = {
1695 [DVB_QUAL_POOR] = N_("Poor"),
1696 [DVB_QUAL_OK] = N_("Ok"),
1697 [DVB_QUAL_GOOD] = N_("Good"),
1698 };
1699
dvb_fe_snprintf_stat(struct dvb_v5_fe_parms * p,uint32_t cmd,char * display_name,int layer,char ** buf,int * len,int * show_layer_name)1700 int dvb_fe_snprintf_stat(struct dvb_v5_fe_parms *p, uint32_t cmd,
1701 char *display_name, int layer,
1702 char **buf, int *len, int *show_layer_name)
1703 {
1704 struct dvb_v5_fe_parms_priv *parms = (void *)p;
1705 struct dtv_stats *stat = NULL;
1706 enum dvb_quality qual = DVB_QUAL_UNKNOWN;
1707 enum fecap_scale_params scale;
1708 float val = -1;
1709 int initial_len = *len;
1710 int size, i;
1711
1712 /* Print status, if layer == 0, as there is only global status */
1713 if (cmd == DTV_STATUS) {
1714 fe_status_t status;
1715
1716 if (layer)
1717 return 0;
1718
1719 if (dvb_fe_retrieve_stats(&parms->p, DTV_STATUS, &status)) {
1720 dvb_logerr (_("Error: no adapter status"));
1721 return -EINVAL;
1722 }
1723 if (display_name) {
1724 size = snprintf(*buf, *len, " %s=", display_name);
1725 *buf += size;
1726 *len -= size;
1727 }
1728
1729 /* Get the name of the highest status bit */
1730 for (i = ARRAY_SIZE(sig_bits) - 1; i >= 0 ; i--) {
1731 if ((1 << i) & status) {
1732 size = snprintf(*buf, *len, _("%-7s"), _(sig_bits[i]));
1733 *buf += size;
1734 *len -= size;
1735 break;
1736 }
1737 }
1738 if (i < 0) {
1739 size = snprintf(*buf, *len, _("%7s"), "");
1740 *buf += size;
1741 *len -= size;
1742 }
1743
1744 /* Add the status bits */
1745 size = snprintf(*buf, *len, "(0x%02x)", status);
1746 *buf += size;
1747 *len -= size;
1748
1749 return initial_len - *len;
1750 }
1751
1752 /* Retrieve the statistics */
1753 switch (cmd) {
1754 case DTV_PRE_BER:
1755 val = calculate_preBER(parms, layer);
1756 if (val < 0)
1757 return 0;
1758 scale = FE_SCALE_COUNTER;
1759 break;
1760 case DTV_BER:
1761 val = dvb_fe_retrieve_ber(&parms->p, layer, &scale);
1762 if (scale == FE_SCALE_NOT_AVAILABLE)
1763 return 0;
1764 break;
1765 case DTV_PER:
1766 val = dvb_fe_retrieve_per(&parms->p, layer);
1767 if (val < 0)
1768 return 0;
1769 scale = FE_SCALE_COUNTER;
1770 break;
1771 case DTV_QUALITY:
1772 qual = dvb_fe_retrieve_quality(&parms->p, layer);
1773 if (qual == DVB_QUAL_UNKNOWN)
1774 return 0;
1775 break;
1776 default:
1777 stat = dvb_fe_retrieve_stats_layer(&parms->p, cmd, layer);
1778 if (!stat || stat->scale == FE_SCALE_NOT_AVAILABLE)
1779 return 0;
1780 }
1781
1782 /* If requested, prints the layer name */
1783 if (*show_layer_name && layer) {
1784 size = snprintf(*buf, *len, _(" Layer %c:"), 'A' + layer - 1);
1785 *buf += size;
1786 *len -= size;
1787 *show_layer_name = 0;
1788 }
1789 if (display_name) {
1790 size = snprintf(*buf, *len, " %s=", display_name);
1791 *buf += size;
1792 *len -= size;
1793 }
1794
1795 /* Quality measure */
1796 if (qual != DVB_QUAL_UNKNOWN) {
1797 size = snprintf(*buf, *len, " %-4s", _(qual_name[qual]));
1798 *buf += size;
1799 *len -= size;
1800 return initial_len - *len;
1801 }
1802
1803
1804 /* Special case: float point measures like BER/PER */
1805 if (!stat) {
1806 switch (scale) {
1807 case FE_SCALE_RELATIVE:
1808 size = snprintf(*buf, *len, " %u", (unsigned int)val);
1809 break;
1810 case FE_SCALE_COUNTER:
1811 size = dvb_fe_snprintf_eng(*buf, *len, val);
1812 break;
1813 default:
1814 size = 0;
1815 }
1816 *buf += size;
1817 *len -= size;
1818 return initial_len - *len;
1819 }
1820
1821 /* Prints the scale */
1822 switch (stat->scale) {
1823 case FE_SCALE_DECIBEL:
1824 if (cmd == DTV_STAT_SIGNAL_STRENGTH)
1825 size = snprintf(*buf, *len, " %.2fdBm", stat->svalue / 1000.);
1826 else
1827 size = snprintf(*buf, *len, " %.2fdB", stat->svalue / 1000.);
1828 break;
1829 case FE_SCALE_RELATIVE:
1830 size = snprintf(*buf, *len, " %3.2f%%", (100 * stat->uvalue) / 65535.);
1831 break;
1832 case FE_SCALE_COUNTER:
1833 size = snprintf(*buf, *len, " %" PRIu64, (uint64_t)stat->uvalue);
1834 break;
1835 default:
1836 size = 0;
1837 }
1838 *buf += size;
1839 *len -= size;
1840
1841 return initial_len - *len;
1842 }
1843
1844 /*
1845 * Implement SEC/LNB/DISEqC specific functions
1846 * For now, DVBv5 API doesn't support those commands. So, use the DVBv3
1847 * version.
1848 */
1849
dvb_fe_sec_voltage(struct dvb_v5_fe_parms * p,int on,int v18)1850 int dvb_fe_sec_voltage(struct dvb_v5_fe_parms *p, int on, int v18)
1851 {
1852 struct dvb_v5_fe_parms_priv *parms = (void *)p;
1853 fe_sec_voltage_t v;
1854 int rc;
1855
1856 if (!on) {
1857 v = SEC_VOLTAGE_OFF;
1858 if (parms->p.verbose)
1859 dvb_log(_("SEC: set voltage to OFF"));
1860 } else {
1861 v = v18 ? SEC_VOLTAGE_18 : SEC_VOLTAGE_13;
1862 if (parms->p.verbose)
1863 dvb_log(_("SEC: set voltage to %sV"), v18 ? "18" : "13");
1864 }
1865 rc = xioctl(parms->fd, FE_SET_VOLTAGE, v);
1866 if (rc == -1) {
1867 if (errno == ENOTSUP) {
1868 dvb_logerr("FE_SET_VOLTAGE: driver doesn't support it!");
1869 } else {
1870 dvb_perror("FE_SET_VOLTAGE");
1871 }
1872 return -errno;
1873 }
1874 return rc;
1875 }
1876
dvb_fe_sec_tone(struct dvb_v5_fe_parms * p,fe_sec_tone_mode_t tone)1877 int dvb_fe_sec_tone(struct dvb_v5_fe_parms *p, fe_sec_tone_mode_t tone)
1878 {
1879 struct dvb_v5_fe_parms_priv *parms = (void *)p;
1880 int rc;
1881 if (parms->p.verbose)
1882 dvb_log( _("DiSEqC TONE: %s"), fe_tone_name[tone] );
1883 rc = xioctl(parms->fd, FE_SET_TONE, tone);
1884 if (rc == -1) {
1885 dvb_perror("FE_SET_TONE");
1886 return -errno;
1887 }
1888 return rc;
1889 }
1890
dvb_fe_lnb_high_voltage(struct dvb_v5_fe_parms * p,int on)1891 int dvb_fe_lnb_high_voltage(struct dvb_v5_fe_parms *p, int on)
1892 {
1893 struct dvb_v5_fe_parms_priv *parms = (void *)p;
1894 int rc;
1895
1896 if (on) on = 1;
1897 if (parms->p.verbose)
1898 dvb_log( _("DiSEqC HIGH LNB VOLTAGE: %s"), on ? _("ON") : _("OFF") );
1899 rc = xioctl(parms->fd, FE_ENABLE_HIGH_LNB_VOLTAGE, on);
1900 if (rc == -1) {
1901 dvb_perror("FE_ENABLE_HIGH_LNB_VOLTAGE");
1902 return -errno;
1903 }
1904 return rc;
1905 }
1906
dvb_fe_diseqc_burst(struct dvb_v5_fe_parms * p,int mini_b)1907 int dvb_fe_diseqc_burst(struct dvb_v5_fe_parms *p, int mini_b)
1908 {
1909 struct dvb_v5_fe_parms_priv *parms = (void *)p;
1910 fe_sec_mini_cmd_t mini;
1911 int rc;
1912
1913 mini = mini_b ? SEC_MINI_B : SEC_MINI_A;
1914
1915 if (parms->p.verbose)
1916 dvb_log( _("DiSEqC BURST: %s"), mini_b ? "SEC_MINI_B" : "SEC_MINI_A" );
1917 rc = xioctl(parms->fd, FE_DISEQC_SEND_BURST, mini);
1918 if (rc == -1) {
1919 dvb_perror("FE_DISEQC_SEND_BURST");
1920 return -errno;
1921 }
1922 return rc;
1923 }
1924
dvb_fe_diseqc_cmd(struct dvb_v5_fe_parms * p,const unsigned len,const unsigned char * buf)1925 int dvb_fe_diseqc_cmd(struct dvb_v5_fe_parms *p, const unsigned len,
1926 const unsigned char *buf)
1927 {
1928 struct dvb_v5_fe_parms_priv *parms = (void *)p;
1929 struct dvb_diseqc_master_cmd msg;
1930 int rc;
1931
1932 if (len > 6)
1933 return -EINVAL;
1934
1935 msg.msg_len = len;
1936 memcpy(msg.msg, buf, len);
1937
1938 if (parms->p.verbose) {
1939 int i;
1940 char log[len * 3 + 20], *p = log;
1941
1942 p += sprintf(p, _("DiSEqC command: "));
1943 for (i = 0; i < len; i++)
1944 p += sprintf (p, "%02x ", buf[i]);
1945 dvb_log("%s", log);
1946 }
1947
1948 rc = xioctl(parms->fd, FE_DISEQC_SEND_MASTER_CMD, &msg);
1949 if (rc == -1) {
1950 dvb_perror("FE_DISEQC_SEND_MASTER_CMD");
1951 return -errno;
1952 }
1953 return rc;
1954 }
1955
dvb_fe_diseqc_reply(struct dvb_v5_fe_parms * p,unsigned * len,char * buf,int timeout)1956 int dvb_fe_diseqc_reply(struct dvb_v5_fe_parms *p, unsigned *len, char *buf,
1957 int timeout)
1958 {
1959 struct dvb_v5_fe_parms_priv *parms = (void *)p;
1960 struct dvb_diseqc_slave_reply reply;
1961 int rc;
1962
1963 if (*len > 4)
1964 *len = 4;
1965
1966 reply.timeout = timeout;
1967 reply.msg_len = *len;
1968
1969 if (parms->p.verbose)
1970 dvb_log("DiSEqC FE_DISEQC_RECV_SLAVE_REPLY");
1971
1972 rc = xioctl(parms->fd, FE_DISEQC_RECV_SLAVE_REPLY, reply);
1973 if (rc == -1) {
1974 dvb_perror("FE_DISEQC_RECV_SLAVE_REPLY");
1975 return -errno;
1976 }
1977
1978 *len = reply.msg_len;
1979 memcpy(buf, reply.msg, reply.msg_len);
1980
1981 return 0;
1982 }
1983
dvb_fe_set_default_country(struct dvb_v5_fe_parms * p,const char * cc)1984 int dvb_fe_set_default_country(struct dvb_v5_fe_parms *p, const char *cc)
1985 {
1986 struct dvb_v5_fe_parms_priv *parms = (void *)p;
1987
1988 if (!cc) {
1989 parms->country = dvb_guess_user_country();
1990 if (parms->p.verbose) {
1991 if (parms->country != COUNTRY_UNKNOWN)
1992 dvb_log(_("Assuming you're in %s.\n"),
1993 dvb_country_to_2letters(parms->country));
1994 else
1995 dvb_log(_("Failed to guess country from the current locale setting.\n"));
1996 }
1997 return 0;
1998 }
1999
2000 parms->country = dvb_country_a2_to_id(cc);
2001 return (parms->country == COUNTRY_UNKNOWN) ? -EINVAL : 0;
2002 }
2003
dvb_get_log_priv(struct dvb_v5_fe_parms * p,void ** priv)2004 dvb_logfunc_priv dvb_get_log_priv(struct dvb_v5_fe_parms *p, void **priv)
2005 {
2006 struct dvb_v5_fe_parms_priv *parms = (void *)p;
2007 *priv = parms->logpriv;
2008 return parms->logfunc_priv;
2009 }
2010