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